diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 4c9293853..2120e8c78 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -7,4 +7,7 @@ Please briefly describe the documentation you have written in the following cate * what documentation you have added to the website for users of Silver * what documentation you have added to the website for developers of Silver -*Please remove all the prefilled text after the "Documentation" heading before submitting your pull request.* +# Testing +Please briefly describe the tests you have written for the changes included in this pull request, or why it is not possible to test the changes. + +*Please remove all the prefilled text other than the headings before submitting your pull request.* diff --git a/.vscode/settings.json b/.vscode/settings.json index 719b5cdf3..f00dd1501 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,5 @@ { - "silver.jvmArgs": "-Xmx10G -Xss40M" + "silver.jvmArgs": "-Xmx10G -Xss40M", + "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx2G -Xms100m -Xlog:disable", + "silver.compilerJar": "jars/silver.compiler.composed.Default.jar" } \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index e0e10db02..244f36da9 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -21,10 +21,17 @@ melt.trynode('silver') { if (source == 'develop') { source = "${silver.SILVER_WORKSPACE}/jars" } - // Obtain jars from specified location - sh "mkdir -p jars" - sh "cp ${source}/* jars/" - melt.annotate("Jars overridden.") + String branchJob = "/melt-umn/silver/${hudson.Util.rawEncode(source)}" + if(melt.doesJobExist(branchJob)) { + // Obtain jars from specified branch + melt.annotate("Jars overidden from branch.") + copyArtifacts(projectName: branchJob, selector: lastCompleted()) + } else { + // Obtain jars from specified location + melt.annotate("Jars overridden from path.") + sh "mkdir -p jars" + sh "cp ${source}/* jars/" + } } else { // We start by obtaining normal jars, but we potentially overwrite them: // (This is the least annoying way to go about this...) @@ -74,18 +81,30 @@ melt.trynode('silver') { sh "./deep-clean -delete" // Generate docs sh "./make-docs" - // Package - sh "rm -rf silver-latest* || true" // Robustness to past failures - sh "./make-dist latest" // Upon succeeding at initial build, archive for future builds archiveArtifacts(artifacts: "jars/*.jar", fingerprint: true) melt.archiveCommitArtifacts("jars/*.jar") } + stage("Language server") { + sh "./make-vscode-extension" + archiveArtifacts(artifacts: "support/vs-code/silverlsp/*.vsix", fingerprint: true) + melt.archiveCommitArtifacts("support/vs-code/silverlsp/*.vsix") + } + + stage("Package") { + sh "rm -rf silver-latest* || true" // Robustness to past failures + sh "./make-dist latest" + } + stage("Modular Analyses") { sh "./self-compile --clean --mwda --dont-translate" } + // Avoid deadlock condition from all executor slots being filled with builds + // that are waiting for downstream builds to finish. + waitUntil { melt.isExecutorAvailable() } + stage("Test") { // These test cases and tutorials are run as seperate tasks to allow for parallelism def tests = ["silver_features", "copper_features", "patt", "flow", "stdlib", "performance", "csterrors", "silver_construction", "origintracking", "implicit_monads"] @@ -110,14 +129,20 @@ melt.trynode('silver') { sh "rm -rf silver-latest" } + // Avoid deadlock condition from all executor slots being filled with builds + // that are waiting for downstream builds to finish. + waitUntil { melt.isExecutorAvailable() } + stage("Integration") { // Projects with 'develop' as main branch, we'll try to build specific branch names if they exist - def github_projects = ["/melt-umn/ableC", "/melt-umn/Oberon0", "/melt-umn/ableJ14", "/melt-umn/meta-ocaml-lite", + def github_projects = ["/melt-umn/ableC", "/melt-umn/Oberon0", "/melt-umn/meta-ocaml-lite", "/melt-umn/lambda-calculus", "/melt-umn/rewriting-regex-matching", "/melt-umn/rewriting-optimization-demo", - "/internal/ring", "/melt-umn/caml-light"] + "/melt-umn/caml-light"] + // These are not currently maintened: "/internal/ring" // Specific other jobs to build - def specific_jobs = ["/internal/matlab/master", "/internal/metaII/master", "/internal/simple/master"] + def specific_jobs = ["/internal/matlab/master"] // AbleP is now downstream from Silver-AbleC, so we don't need to build it here: "/melt-umn/ableP/master" + // These are not currently maintened: "/internal/simple/master" def tasks = [:] tasks << github_projects.collectEntries { t -> @@ -144,6 +169,7 @@ melt.trynode('silver') { sh "cp silver-latest.tar.gz ${melt.ARTIFACTS}/" sh "cp jars/*.jar ${melt.ARTIFACTS}/" + sh "cp support/vs-code/silverlsp/silverlsp-latest.vsix ${melt.ARTIFACTS}/" build "/melt-umn/melt-website/master" } diff --git a/deep-clean b/deep-clean index 9344fe23e..aecc985ee 100755 --- a/deep-clean +++ b/deep-clean @@ -32,6 +32,7 @@ find "silver.testing.bin.jar" $1 find ./runtime/lsp4j/target $1 find ./language-server/langserver/target $1 find ./language-server/launcher/target $1 +find ./support/vs-code/silverlsp/out $1 if [ "$2" == "all" ]; then rm -rf generated/src/* generated/bin/* runtime/java/bin/* generated/doc/* diff --git a/deep-rebuild b/deep-rebuild index 331a0ed9e..efc6777d5 100755 --- a/deep-rebuild +++ b/deep-rebuild @@ -3,7 +3,7 @@ set -eu export SILVER_HOME=$(pwd) -JVM_ARGS="-Xss16M -Xmx5G -jar ../jars/silver.compiler.composed.Default.jar" +JVM_ARGS="-Xss20M -Xmx6G -jar ../jars/silver.compiler.composed.Default.jar" export ANT_OPTS=-Xss10M # just run this script, no parameters or options. diff --git a/fetch-jars b/fetch-jars index 54f2f5f5c..629002200 100755 --- a/fetch-jars +++ b/fetch-jars @@ -2,36 +2,90 @@ set -eu -# Usage: ./fetch-jars [rev-name] [--copper] +# Usage: ./fetch-jars [rev-name] [--unstable] [--copper] +# If a revision is not specified, the script fetches the latest jars from the current branch, +# falling back to develop. +# If --unstable is specified, always fetch from commit artifacts on foundry. +# If --copper is specified, only fetch the Copper jars. +# Parse command line argumants. +# Hacky, but getopts seems like overkill for this... +rev_name="" +for arg in "$@"; do + if [[ $arg != -* ]]; then + rev_name=$arg + break + fi +done -if [[ $* != *--copper* && $# -gt 0 || $# -gt 1 ]]; then - rev=$(git rev-parse $1) - echo "Warning: Fetching unstable jars! (commit $rev)" +COMMIT_ARTIFACTS="https://foundry.remexre.xyz/commit-artifacts/" - LOCAL_STORE= - REMOTE_STORE="https://foundry.remexre.xyz/commit-artifacts/$rev" - JARS_BAK="JARS-BAK/$rev" +function has_jars { + wget --spider -q "$COMMIT_ARTIFACTS/$1" +} + +rev="" + +# Look for jars in the specified revision +if [[ -n $rev_name ]]; then + rev=$(git rev-parse "$rev_name") +fi + +# Get the hash of the latest commit on develop. +# This always gives the latest commit regardless of if the repo is up to date, +# and works in a Jenkins checkout. +DEVELOP=$(git ls-remote https://github.com/melt-umn/silver develop | cut -f1) + +# Look for jars in the current commit and its parents. +# First, check that we are inside a git repo. +if [[ -z $rev ]] && git rev-parse --is-inside-work-tree 1> /dev/null 2> /dev/null; then + # Walk the history in topological order, fully exploring each chain of commits + # before newer commits from other merged chain. + for commit in $(git rev-list --topo-order HEAD "^$DEVELOP"); do + echo "Looking for jars from past commit $commit" + if has_jars "$commit"; then + echo "Found jars from past commit" + rev=$commit + break + fi + done +fi + +# Figure out how to obtain the jars from the revision we chose. +if [[ $* != *--unstable* && (-z $rev || $rev == "$DEVELOP") ]]; then + echo "Fetching latest stable jars..." + LOCAL_STORE=/web/research/melt.cs.umn.edu/downloads/silver-dev/jars + REMOTE_STORE="https://melt.cs.umn.edu/downloads/silver-dev/jars" + JARS_BAK=JARS-BAK else - LOCAL_STORE=/web/research/melt.cs.umn.edu/downloads/silver-dev/jars - REMOTE_STORE="https://melt.cs.umn.edu/downloads/silver-dev/jars" - JARS_BAK=JARS-BAK + git --no-pager show --quiet "$rev" + if ! has_jars "$rev"; then + echo "Cound not find jars for commit" + exit 1 + fi + echo "Warning: Fetching unstable jars!" + LOCAL_STORE= + REMOTE_STORE="$COMMIT_ARTIFACTS/$rev" + JARS_BAK="JARS-BAK/$rev" fi if [[ $* == *--copper* ]]; then - # Only fetch the Copper jars, if requested - FILES="CopperCompiler.jar" + # Only fetch the Copper jars, if requested + FILES="CopperCompiler.jar" else - FILES="CopperCompiler.jar commonmark-0.17.1.jar silver.compiler.composed.Default.jar SilverRuntime.jar" + FILES="CopperCompiler.jar commonmark-0.17.1.jar silver.compiler.composed.Default.jar SilverRuntime.jar" fi + mkdir -p jars if [[ -n "$LOCAL_STORE" && -d $LOCAL_STORE ]]; then + # We have downloaded the jars before, just go copy them. for file in $FILES; do - cp $LOCAL_STORE/$file jars/ + cp "$LOCAL_STORE/$file" jars/ done else + # Download the jars. # There's probably a better way to do this! # Using -r causes lots of pointless downloads of variations of the index.html # even if -A.jar is used they still get downloaded... @@ -42,16 +96,15 @@ else done # We're going to download them to here - mkdir -p $JARS_BAK + mkdir -p "$JARS_BAK" # -N Pay attention to timestamps, to avoid needless redownloads. # -P jars/ Put the files in jars/ # -nv Don't be so verbose! - wget -N -P $JARS_BAK/ -nv $URLS + wget -N -P "$JARS_BAK/" -nv $URLS # Always overwrite all the files in jars. for file in $FILES; do - cp $JARS_BAK/$file jars/ + cp "$JARS_BAK/$file" jars/ done fi - diff --git a/grammars/silver/compiler/analysis/typechecking/core/AspectDcl.sv b/grammars/silver/compiler/analysis/typechecking/core/AspectDcl.sv index 2a7dc1b3f..8e62b515d 100644 --- a/grammars/silver/compiler/analysis/typechecking/core/AspectDcl.sv +++ b/grammars/silver/compiler/analysis/typechecking/core/AspectDcl.sv @@ -1,6 +1,7 @@ grammar silver:compiler:analysis:typechecking:core; attribute upSubst, downSubst, finalSubst occurs on AspectProductionSignature, AspectProductionLHS, AspectRHS, AspectRHSElem, AspectFunctionSignature, AspectFunctionLHS; +propagate finalSubst on AspectProductionSignature, AspectProductionLHS, AspectRHS, AspectRHSElem, AspectFunctionSignature, AspectFunctionLHS; aspect production aspectProductionDcl top::AGDcl ::= 'aspect' 'production' id::QName ns::AspectProductionSignature body::ProductionBody diff --git a/grammars/silver/compiler/analysis/typechecking/core/AttributeDcl.sv b/grammars/silver/compiler/analysis/typechecking/core/AttributeDcl.sv index ef6021ef2..4e140ad9c 100644 --- a/grammars/silver/compiler/analysis/typechecking/core/AttributeDcl.sv +++ b/grammars/silver/compiler/analysis/typechecking/core/AttributeDcl.sv @@ -12,3 +12,9 @@ top::AGDcl ::= 'synthesized' 'attribute' a::Name tl::BracketedOptTypeExprs '::' top.errors <- te.errorsKindStar; } +aspect production attributeDclTrans +top::AGDcl ::= 'translation' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr ';' +{ + top.errors <- te.errorsKindStar; +} + diff --git a/grammars/silver/compiler/analysis/typechecking/core/Checking.sv b/grammars/silver/compiler/analysis/typechecking/core/Checking.sv index 5c07fe5d6..29076fd83 100644 --- a/grammars/silver/compiler/analysis/typechecking/core/Checking.sv +++ b/grammars/silver/compiler/analysis/typechecking/core/Checking.sv @@ -27,7 +27,7 @@ top::TypeCheck ::= l::Type r::Type } abstract production checkNonterminal -top::TypeCheck ::= e::Decorated Env allowDecorableSkolems::Boolean l::Type +top::TypeCheck ::= e::Env allowDecorableSkolems::Boolean l::Type { local refined :: Type = performSubstitution(l, top.downSubst); @@ -57,7 +57,7 @@ top::TypeCheck ::= l::Type top.rightpp = "a decorated nonterminal"; } abstract production checkDecorable -top::TypeCheck ::= e::Decorated Env l::Type +top::TypeCheck ::= e::Env l::Type { local refined :: Type = performSubstitution(l, top.downSubst); diff --git a/grammars/silver/compiler/analysis/typechecking/core/Context.sv b/grammars/silver/compiler/analysis/typechecking/core/Context.sv index 81c17d709..db5c2e7c7 100644 --- a/grammars/silver/compiler/analysis/typechecking/core/Context.sv +++ b/grammars/silver/compiler/analysis/typechecking/core/Context.sv @@ -1,5 +1,6 @@ grammar silver:compiler:analysis:typechecking:core; +import silver:compiler:definition:flow:env only getFlowTypeSpecFor, flowEnv; import silver:compiler:analysis:warnings:flow only inhDepsForSynOnType; import silver:util:treeset as set; diff --git a/grammars/silver/compiler/analysis/typechecking/core/Expr.sv b/grammars/silver/compiler/analysis/typechecking/core/Expr.sv index 3e7c9d443..b121d0131 100644 --- a/grammars/silver/compiler/analysis/typechecking/core/Expr.sv +++ b/grammars/silver/compiler/analysis/typechecking/core/Expr.sv @@ -1,5 +1,7 @@ grammar silver:compiler:analysis:typechecking:core; +import silver:compiler:definition:flow:env; + attribute upSubst, downSubst, finalSubst occurs on Expr, ExprInhs, ExprInh, Exprs, AppExprs, AppExpr, AnnoExpr, AnnoAppExprs; propagate upSubst, downSubst @@ -7,18 +9,21 @@ propagate upSubst, downSubst excluding undecoratedAccessHandler, forwardAccess, decoratedAccessHandler, and, or, notOp, ifThenElse, plus, minus, multiply, divide, modulus, - decorateExprWith, exprInh, presentAppExpr, + decorateExprWith, exprInh, presentAppExpr, decorationSiteExpr, terminalConstructor, noteAttachment; +propagate finalSubst on Expr, ExprInhs, ExprInh, Exprs, AppExprs, AppExpr, AnnoExpr, AnnoAppExprs; +attribute finalType occurs on Expr; attribute contexts occurs on Expr; aspect default production top::Expr ::= { + top.finalType = performSubstitution(top.typerep, top.finalSubst); top.contexts = []; } aspect production productionReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { contexts.contextLoc = q.location; contexts.contextSource = "the use of " ++ q.name; @@ -27,7 +32,7 @@ top::Expr ::= q::PartiallyDecorated QName } aspect production functionReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { contexts.contextLoc = q.location; contexts.contextSource = "the use of " ++ q.name; @@ -36,7 +41,7 @@ top::Expr ::= q::PartiallyDecorated QName } aspect production globalValueReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { contexts.contextLoc = q.location; contexts.contextSource = "the use of " ++ q.name; @@ -45,7 +50,7 @@ top::Expr ::= q::PartiallyDecorated QName } aspect production classMemberReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { instHead.contextLoc = q.location; instHead.contextSource = "the use of " ++ q.name; @@ -69,16 +74,17 @@ top::Expr ::= e::Expr '(' es::AppExprs ',' anns::AnnoAppExprs ')' infContexts.flowEnv = top.flowEnv; thread downSubst, upSubst on top, e, es, anns, infContexts, forward; + propagate finalSubst; } aspect production access top::Expr ::= e::Expr '.' q::QNameAttrOccur { - propagate upSubst, downSubst; + propagate upSubst, downSubst, finalSubst; } aspect production undecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { -- We might have gotten here via a 'ntOrDec' type. So let's make certain we're UNdecorated, -- ensuring that type's specialization, otherwise we could end up in trouble! @@ -96,9 +102,9 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur } aspect production accessBouncer -top::Expr ::= target::(Expr ::= PartiallyDecorated Expr PartiallyDecorated QNameAttrOccur Location) e::Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= target::(Expr ::= Decorated! Expr Decorated! QNameAttrOccur Location) e::Expr q::Decorated! QNameAttrOccur { - propagate upSubst, downSubst; + propagate upSubst, downSubst, finalSubst; } aspect production forwardAccess @@ -116,7 +122,7 @@ top::Expr ::= e::Expr '.' 'forward' } aspect production decoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { -- We might have gotten here via a 'ntOrDec' type. So let's make certain we're decorated, -- ensuring that type's specialization, otherwise we could end up in trouble! @@ -142,7 +148,7 @@ top::Expr ::= 'attachNote' note::Expr 'on' e::Expr 'end' thread downSubst, upSubst on top, note, e, errCheck1, top; - errCheck1 = check(note.typerep, nonterminalType("silver:core:OriginNote", [], false)); + errCheck1 = check(note.typerep, nonterminalType("silver:core:OriginNote", [], true, false)); top.errors <- if errCheck1.typeerror then [err(top.location, "First argument to attachNote must be OriginNote, was " ++ errCheck1.leftpp)] @@ -237,9 +243,9 @@ top::Expr ::= e1::Expr '+' e2::Expr else []; top.errors <- - if performSubstitution(e1.typerep, top.finalSubst).instanceNum + if e1.finalType.instanceNum then [] - else [err(top.location, "Operands to + must be concrete types Integer or Float. Instead they are of type " ++ prettyType(performSubstitution(e1.typerep, top.finalSubst)))]; + else [err(top.location, "Operands to + must be concrete types Integer or Float. Instead they are of type " ++ prettyType(e1.finalType))]; } aspect production minus @@ -256,9 +262,9 @@ top::Expr ::= e1::Expr '-' e2::Expr else []; top.errors <- - if performSubstitution(e1.typerep, top.finalSubst).instanceNum + if e1.finalType.instanceNum then [] - else [err(top.location, "Operands to - must be concrete types Integer or Float. Instead they are of type " ++ prettyType(performSubstitution(e1.typerep, top.finalSubst)))]; + else [err(top.location, "Operands to - must be concrete types Integer or Float. Instead they are of type " ++ prettyType(e1.finalType))]; } aspect production multiply top::Expr ::= e1::Expr '*' e2::Expr @@ -274,9 +280,9 @@ top::Expr ::= e1::Expr '*' e2::Expr else []; top.errors <- - if performSubstitution(e1.typerep, top.finalSubst).instanceNum + if e1.finalType.instanceNum then [] - else [err(top.location, "Operands to * must be concrete types Integer or Float. Instead they are of type " ++ prettyType(performSubstitution(e1.typerep, top.finalSubst)))]; + else [err(top.location, "Operands to * must be concrete types Integer or Float. Instead they are of type " ++ prettyType(e1.finalType))]; } aspect production divide top::Expr ::= e1::Expr '/' e2::Expr @@ -292,9 +298,9 @@ top::Expr ::= e1::Expr '/' e2::Expr else []; top.errors <- - if performSubstitution(e1.typerep, top.finalSubst).instanceNum + if e1.finalType.instanceNum then [] - else [err(top.location, "Operands to / must be concrete types Integer or Float. Instead they are of type " ++ prettyType(performSubstitution(e1.typerep, top.finalSubst)))]; + else [err(top.location, "Operands to / must be concrete types Integer or Float. Instead they are of type " ++ prettyType(e1.finalType))]; } aspect production modulus top::Expr ::= e1::Expr '%' e2::Expr @@ -310,18 +316,18 @@ top::Expr ::= e1::Expr '%' e2::Expr else []; top.errors <- - if performSubstitution(e1.typerep, top.finalSubst).instanceNum + if e1.finalType.instanceNum then [] - else [err(top.location, "Operands to % must be concrete types Integer or Float. Instead they are of type " ++ prettyType(performSubstitution(e1.typerep, top.finalSubst)))]; + else [err(top.location, "Operands to % must be concrete types Integer or Float. Instead they are of type " ++ prettyType(e1.finalType))]; } aspect production neg top::Expr ::= '-' e1::Expr { top.errors <- - if performSubstitution(e1.typerep, top.finalSubst).instanceNum + if e1.finalType.instanceNum then [] - else [err(top.location, "Operand to unary - must be concrete types Integer or Float. Instead it is of type " ++ prettyType(performSubstitution(e1.typerep, top.finalSubst)))]; + else [err(top.location, "Operand to unary - must be concrete types Integer or Float. Instead it is of type " ++ prettyType(e1.finalType))]; } aspect production terminalConstructor @@ -333,7 +339,7 @@ top::Expr ::= 'terminal' '(' t::TypeExpr ',' es::Expr ',' el::Expr ')' thread downSubst, upSubst on top, es, el, errCheck1, errCheck2, top; errCheck1 = check(es.typerep, stringType()); - errCheck2 = check(el.typerep, nonterminalType("silver:core:Location", [], false)); + errCheck2 = check(el.typerep, nonterminalType("silver:core:Location", [], true, false)); top.errors <- if errCheck1.typeerror then [err(es.location, "Second operand to 'terminal(type,lexeme,location)' must be a String, instead it is " ++ errCheck1.leftpp)] @@ -360,7 +366,21 @@ top::Expr ::= 'decorate' e::Expr 'with' '{' inh::ExprInhs '}' errCheck1 = checkDecorable(top.env, e.typerep); top.errors <- if errCheck1.typeerror - then [err(top.location, "Operand to decorate must be a nonterminal or partially decorated type. Instead it is of type " ++ errCheck1.leftpp)] + then [err(top.location, "Operand to decorate must be a decorable type. Instead it is of type " ++ errCheck1.leftpp)] + else []; +} + +aspect production decorationSiteExpr +top::Expr ::= '@' e::Expr +{ + local attribute errCheck1 :: TypeCheck; errCheck1.finalSubst = top.finalSubst; + + thread downSubst, upSubst on top, e, errCheck1, top; + + errCheck1 = check(e.typerep, uniqueDecoratedType(freshType(), inhSetType([]))); + top.errors <- + if errCheck1.typeerror + then [err(top.location, "Operand to @ must be a unique reference with no inherited attributes. Instead it is of type " ++ errCheck1.leftpp)] else []; } @@ -394,5 +414,5 @@ top::AppExpr ::= e::Expr " but argument is of type " ++ errCheck1.leftpp)]; } --- See documentation for major restriction on use of exprRef. +-- See documentation for major restriction on use of @. -- Essentially, the referred expression MUST have already been type checked. diff --git a/grammars/silver/compiler/analysis/typechecking/core/OccursDcl.sv b/grammars/silver/compiler/analysis/typechecking/core/OccursDcl.sv new file mode 100644 index 000000000..f2d35f790 --- /dev/null +++ b/grammars/silver/compiler/analysis/typechecking/core/OccursDcl.sv @@ -0,0 +1,14 @@ +grammar silver:compiler:analysis:typechecking:core; + +aspect production defaultAttributionDcl +top::AGDcl ::= at::Decorated! QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs +{ + local checkNT::TypeCheck = checkNonterminal(top.env, false, protoatty); + checkNT.downSubst = emptySubst(); + checkNT.finalSubst = emptySubst(); + + top.errors <- + if at.lookupAttribute.found && at.lookupAttribute.dcl.isTranslation && checkNT.typeerror + then [err(top.location, s"Occurrence of translation attribute ${at.lookupAttribute.fullName} must have a nonterminal type. Instead it is of type " ++ checkNT.leftpp)] + else []; +} diff --git a/grammars/silver/compiler/analysis/typechecking/core/ProductionBody.sv b/grammars/silver/compiler/analysis/typechecking/core/ProductionBody.sv index 3b84102fc..22fbff098 100644 --- a/grammars/silver/compiler/analysis/typechecking/core/ProductionBody.sv +++ b/grammars/silver/compiler/analysis/typechecking/core/ProductionBody.sv @@ -3,7 +3,8 @@ grammar silver:compiler:analysis:typechecking:core; attribute upSubst, downSubst, finalSubst occurs on ProductionStmt, ForwardInhs, ForwardInh, ForwardLHSExpr; propagate upSubst, downSubst on ProductionStmt, ForwardInhs, ForwardInh, ForwardLHSExpr - excluding productionStmtAppend, attachNoteStmt, forwardsTo, forwardInh, returnDef, synthesizedAttributeDef, inheritedAttributeDef, localValueDef; + excluding productionStmtAppend, attachNoteStmt, forwardsTo, forwardInh, undecoratesTo, returnDef, synthesizedAttributeDef, inheritedAttributeDef, localValueDef; +propagate finalSubst on ProductionStmt, ForwardInhs, ForwardInh, ForwardLHSExpr excluding productionStmtAppend; {-- - These need an initial state only due to aspects (I think? maybe not. Investigate someday.) @@ -74,6 +75,19 @@ top::ForwardInh ::= lhs::ForwardLHSExpr '=' e::Expr ';' else []; } +aspect production undecoratesTo +top::ProductionStmt ::= 'undecorates' 'to' e::Expr ';' +{ + local attribute errCheck1 :: TypeCheck; errCheck1.finalSubst = top.finalSubst; + + thread downSubst, upSubst on top, e, errCheck1, top; + + errCheck1 = check(e.typerep, top.frame.signature.outputElement.typerep); + top.errors <- if errCheck1.typeerror + then [err(e.location, "Undecorates's expected type is " ++ errCheck1.rightpp ++ ", but the actual type supplied is " ++ errCheck1.leftpp)] + else []; +} + aspect production attachNoteStmt top::ProductionStmt ::= 'attachNote' e::Expr ';' { @@ -81,7 +95,7 @@ top::ProductionStmt ::= 'attachNote' e::Expr ';' thread downSubst, upSubst on top, e, errCheck1, top; - errCheck1 = check(e.typerep, nonterminalType("silver:core:OriginNote", [], false)); + errCheck1 = check(e.typerep, nonterminalType("silver:core:OriginNote", [], true, false)); top.errors <- if errCheck1.typeerror then [err(top.location, "Origin note must have type silver:core:OriginNote, but the expression has actual type " ++ errCheck1.leftpp)] @@ -103,7 +117,7 @@ top::ProductionStmt ::= 'return' e::Expr ';' } aspect production synthesizedAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { local attribute errCheck1 :: TypeCheck; errCheck1.finalSubst = top.finalSubst; @@ -117,7 +131,7 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated } aspect production inheritedAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { local attribute errCheck1 :: TypeCheck; errCheck1.finalSubst = top.finalSubst; @@ -131,23 +145,23 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated } aspect production errorAttributeDef -top::ProductionStmt ::= msg::[Message] dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= msg::[Message] dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { - propagate downSubst, upSubst; + propagate downSubst, upSubst, finalSubst; } aspect production childDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName { top.errors <- if isDecorable(top.typerep, top.env) then [] - else [err(top.location, s"Inherited attributes can only be defined on (undecorated) nonterminal and partially decorated types, not ${prettyType(top.typerep)}.")]; + else [err(top.location, s"Inherited attributes can only be defined on (undecorated) nonterminal and unique decorated types, not ${prettyType(top.typerep)}.")]; } aspect production localDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName { top.errors <- if isDecorable(top.typerep, top.env) then [] - else [err(top.location, s"Inherited attributes can only be defined on (undecorated) nonterminal and partially decorated types, not ${prettyType(top.typerep)}.")]; + else [err(top.location, s"Inherited attributes can only be defined on (undecorated) nonterminal and unique decorated types, not ${prettyType(top.typerep)}.")]; } aspect production localAttributeDcl @@ -163,7 +177,7 @@ top::ProductionStmt ::= 'production' 'attribute' a::Name '::' te::TypeExpr ';' } aspect production localValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { local attribute errCheck1 :: TypeCheck; errCheck1.finalSubst = top.finalSubst; diff --git a/grammars/silver/compiler/analysis/typechecking/core/Project.sv b/grammars/silver/compiler/analysis/typechecking/core/Project.sv index a2f3c6c78..a092b62cd 100644 --- a/grammars/silver/compiler/analysis/typechecking/core/Project.sv +++ b/grammars/silver/compiler/analysis/typechecking/core/Project.sv @@ -10,7 +10,10 @@ imports silver:compiler:definition:type; threaded attribute downSubst, upSubst :: Substitution; {-- The complete, final substitution context -} -autocopy attribute finalSubst :: Substitution; +inherited attribute finalSubst :: Substitution; + +{-- typerep after applying finalSubst, for convinence -} +synthesized attribute finalType :: Type; -- We also use typerep. -- Such that performSubstitution(e.typerep, e.upSubst) is the expression's real type (as of that moment) diff --git a/grammars/silver/compiler/analysis/uniqueness/AGDcl.sv b/grammars/silver/compiler/analysis/uniqueness/AGDcl.sv new file mode 100644 index 000000000..312753373 --- /dev/null +++ b/grammars/silver/compiler/analysis/uniqueness/AGDcl.sv @@ -0,0 +1,20 @@ +grammar silver:compiler:analysis:uniqueness; + +attribute uniqueRefs occurs on Grammar, Root, AGDcls, AGDcl; +propagate uniqueRefs on Grammar, Root, AGDcls, AGDcl; + +aspect production globalValueDclConcrete +top::AGDcl ::= 'global' id::Name '::' cl::ConstraintList '=>' t::TypeExpr '=' e::Expr ';' +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} +aspect production defaultConstraintClassBodyItem +top::ClassBodyItem ::= id::Name '::' cl::ConstraintList '=>' ty::TypeExpr '=' e::Expr ';' +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} +aspect production instanceBodyItem +top::InstanceBodyItem ::= id::QName '=' e::Expr ';' +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} diff --git a/grammars/silver/compiler/analysis/uniqueness/Expr.sv b/grammars/silver/compiler/analysis/uniqueness/Expr.sv new file mode 100644 index 000000000..f11274bc7 --- /dev/null +++ b/grammars/silver/compiler/analysis/uniqueness/Expr.sv @@ -0,0 +1,374 @@ +grammar silver:compiler:analysis:uniqueness; + +attribute uniqueRefs occurs on Expr, Exprs, AppExprs, AppExpr, PrimPatterns, PrimPattern; +propagate uniqueRefs on Expr, Exprs, AppExprs, AppExpr, PrimPatterns, PrimPattern + excluding + errorAccessHandler, terminalAccessHandler, + synDecoratedAccessHandler, inhDecoratedAccessHandler, + transDecoratedAccessHandler, + annoAccessHandler, synDataAccessHandler, + unknownDclAccessHandler, inhUndecoratedAccessErrorHandler, transUndecoratedAccessErrorHandler, + ifThenElse, lambdap, letp, matchPrimitiveReal, consPattern; + +-- Unique references taken when this expression is wrapped in an attribute access +synthesized attribute accessUniqueRefs::[(String, UniqueRefSite)] occurs on Expr; + +aspect default production +top::Expr ::= +{ + top.accessUniqueRefs = top.uniqueRefs; +} + +aspect production childReference +top::Expr ::= q::Decorated! QName +{ + top.uniqueRefs <- + case top.finalType, refSet of + | uniqueDecoratedType(_, _), just(inhs) + when isExportedBy(top.grammarName, [q.lookupValue.dcl.sourceGrammar], top.compiledGrammars) -> + [(top.frame.fullName ++ ":" ++ q.lookupValue.fullName, + uniqueRefSite( + sourceGrammar=top.grammarName, + sourceLocation=q.location, + refSet=inhs, + refFlowDeps=top.flowDeps + ))] + | _, _ -> [] + end; + top.accessUniqueRefs = []; + + top.errors <- + case top.finalType of + | uniqueDecoratedType(_, _) when q.lookupValue.found -> + -- Check that we are exported by the decoration site. + if !isExportedBy(top.grammarName, [q.lookupValue.dcl.sourceGrammar], top.compiledGrammars) + then [err(top.location, s"Orphaned unique reference to ${q.lookupValue.fullName} in production ${top.frame.fullName} (reference has type ${prettyType(top.finalType)}).")] + -- Check that there is at most one unique reference taken to this decoration site. + else if length(lookupUniqueRefs(top.frame.fullName, q.lookupValue.fullName, top.flowEnv)) > 1 + then [err(top.location, s"Multiple unique references taken to ${q.name} in production ${top.frame.fullName} (reference has type ${prettyType(top.finalType)}).")] + else [] + | _ -> [] + end; +} +aspect production localReference +top::Expr ::= q::Decorated! QName +{ + top.uniqueRefs <- + case top.finalType, refSet of + | uniqueDecoratedType(_, _), just(inhs) + when isExportedBy(top.grammarName, [q.lookupValue.dcl.sourceGrammar], top.compiledGrammars) -> + [(q.lookupValue.fullName, + uniqueRefSite( + sourceGrammar=top.grammarName, + sourceLocation=q.location, + refSet=inhs, + refFlowDeps=top.flowDeps + ))] + | _, _ -> [] + end; + top.accessUniqueRefs = []; + + top.errors <- + case top.finalType of + | uniqueDecoratedType(_, _) when q.lookupValue.found -> + -- Check that we are exported by the decoration site. + if !isExportedBy(top.grammarName, [q.lookupValue.dcl.sourceGrammar], top.compiledGrammars) + then [err(top.location, s"Orphaned unique reference to ${q.lookupValue.fullName} in production ${top.frame.fullName} (reference has type ${prettyType(top.finalType)}).")] + -- Check that there is at most one unique reference taken to this decoration site. + else if length(lookupLocalUniqueRefs(q.lookupValue.fullName, top.flowEnv)) > 1 + then [err(top.location, s"Multiple unique references taken to ${q.name} in production ${top.frame.fullName} (reference has type ${prettyType(top.finalType)}).")] + else [] + | _ -> [] + end; +} +aspect production lhsReference +top::Expr ::= q::Decorated! QName +{ + top.errors <- + case top.finalType of + | uniqueDecoratedType(_, _) -> + [err(top.location, s"Cannot take a unique reference of type ${prettyType(top.finalType)} to ${q.name}.")] + | _ -> [] + end; +} +aspect production forwardReference +top::Expr ::= q::Decorated! QName +{ + top.errors <- + case top.finalType of + | uniqueDecoratedType(_, _) -> + [err(top.location, s"Cannot take a unique reference of type ${prettyType(top.finalType)} to the forward tree.")] + | _ -> [] + end; +} +aspect production productionReference +top::Expr ::= q::Decorated! QName +{ + top.errors <- flatMap(\ tv::TyVar -> + let substTy::Type = performSubstitution(varType(tv), top.finalSubst) + in if substTy.isUniqueDecorated + then [err(top.location, s"Cannot specialize type variable ${prettyTypeWith(varType(tv), top.typerep.freeVariables)} of ${q.name}::${prettyType(top.typerep)} to a unique reference type ${prettyType(substTy)}")] + else [] + end, + top.typerep.freeVariables); +} +aspect production functionReference +top::Expr ::= q::Decorated! QName +{ + top.errors <- flatMap(\ tv::TyVar -> + let substTy::Type = performSubstitution(varType(tv), top.finalSubst) + in if substTy.isUniqueDecorated + then [err(top.location, s"Cannot specialize type variable ${prettyTypeWith(varType(tv), top.typerep.freeVariables)} of ${q.name}::${prettyType(top.typerep)} to a unique reference type ${prettyType(substTy)}")] + else [] + end, + top.typerep.freeVariables); +} +aspect production classMemberReference +top::Expr ::= q::Decorated! QName +{ + top.errors <- flatMap(\ tv::TyVar -> + let substTy::Type = performSubstitution(varType(tv), top.finalSubst) + in if substTy.isUniqueDecorated + then [err(top.location, s"Cannot specialize type variable ${prettyTypeWith(varType(tv), top.typerep.freeVariables)} of ${q.name}::${prettyType(top.typerep)} to a unique reference type ${prettyType(substTy)}")] + else [] + end, + top.typerep.freeVariables); +} +aspect production globalValueReference +top::Expr ::= q::Decorated! QName +{ + top.errors <- flatMap(\ tv::TyVar -> + let substTy::Type = performSubstitution(varType(tv), top.finalSubst) + in if substTy.isUniqueDecorated + then [err(top.location, s"Cannot specialize type variable ${prettyTypeWith(varType(tv), top.typerep.freeVariables)} of ${q.name}::${prettyType(top.typerep)} to a unique reference type ${prettyType(substTy)}")] + else [] + end, + top.typerep.freeVariables); +} + +-- Whether nonterminal uniqueness is preserved for this argument position, +-- i.e. this is an argument to a direct function or production application +-- that will be copied upon undecoration. +inherited attribute isNtUniquenessPreserving::Boolean occurs on AppExprs, AppExpr; +propagate isNtUniquenessPreserving on AppExprs; + +monoid attribute appExprUniquenessErrors::[Message] occurs on AppExprs, AppExpr, AnnoAppExprs, AnnoExpr; +propagate appExprUniquenessErrors on AppExprs, AppExpr, AnnoAppExprs, AnnoExpr; + +aspect production functionInvocation +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs +{ + top.errors <- es.appExprUniquenessErrors ++ anns.appExprUniquenessErrors; + es.isNtUniquenessPreserving = + case e of + | functionReference(_) -> true + | productionReference(_) -> true + | _ -> false + end; +} + +aspect production partialApplication +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs +{ + top.errors <- es.appExprUniquenessErrors ++ anns.appExprUniquenessErrors; + es.isNtUniquenessPreserving = + case e of + | functionReference(_) -> true + | productionReference(_) -> true + | _ -> false + end; +} + +aspect production annoExpr +top::AnnoExpr ::= qn::QName '=' e::AppExpr +{ + e.isNtUniquenessPreserving = false; +} + +aspect production presentAppExpr +top::AppExpr ::= e::Expr +{ + top.appExprUniquenessErrors <- + case top.appExprTyperep.baseType of + | varType(_) -> uniqueContextErrors(e.uniqueRefs) -- Would need linear types to make this work... + | nonterminalType(_, _, true, _) -> uniqueContextErrors(e.uniqueRefs) + | nonterminalType(_, _, _, _) when !top.isNtUniquenessPreserving -> uniqueContextErrors(e.uniqueRefs) + | _ -> [] + end; +} + +aspect production errorAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.uniqueRefs := e.accessUniqueRefs; +} +aspect production terminalAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.uniqueRefs := e.accessUniqueRefs; +} +aspect production synDecoratedAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.uniqueRefs := e.accessUniqueRefs; +} +aspect production inhDecoratedAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.uniqueRefs := e.accessUniqueRefs; +} +aspect production transDecoratedAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.uniqueRefs := + case top.finalType, refSet of + | uniqueDecoratedType(_, _), just(inhs) -> + [(case e.flowVertexInfo of + | just(rhsVertexType(sigName)) -> s"${top.frame.fullName}:${sigName}.${q.attrDcl.fullName}" + | just(localVertexType(fName)) -> s"${fName}.${q.attrDcl.fullName}" + | _ -> "" + end, + uniqueRefSite( + sourceGrammar=top.grammarName, + sourceLocation=q.location, + refSet=inhs, + refFlowDeps=top.flowDeps + ))] + | _, _ -> [] + end; + + top.errors <- + case top.finalType of + | uniqueDecoratedType(_, _) when q.found -> + case e.flowVertexInfo of + | just(rhsVertexType(sigName)) -> + -- Check that we are exported by the occurs-on or the production. + if !isExportedBy(top.grammarName, [q.dcl.sourceGrammar, top.frame.sourceGrammar], top.compiledGrammars) + then [err(top.location, s"Orphaned unique reference to ${top.unparse} in production ${top.frame.fullName} (reference has type ${prettyType(top.finalType)}).")] + -- Check that there is at most one unique reference taken to this decoration site. + else + (if length(lookupTransUniqueRefs(top.frame.fullName, sigName, q.attrDcl.fullName, top.flowEnv)) > 1 + then [err(top.location, s"Multiple unique references taken to ${top.unparse} in production ${top.frame.fullName} (reference has type ${prettyType(top.finalType)}).")] + -- Check that there isn't also a unique reference taken to e + else []) ++ + if !null(lookupUniqueRefs(top.frame.fullName, sigName, top.flowEnv)) + then [err(top.location, s"Cannot take a unique reference to ${top.unparse} in production ${top.frame.fullName} (reference has type ${prettyType(top.finalType)}) since there is also a unique reference taken to ${e.unparse}.")] + else [] + | just(localVertexType(fName)) -> + -- Check that we are exported by the occurs-on or the local. + if !isExportedBy(top.grammarName, [q.dcl.sourceGrammar, head(getValueDcl(fName, top.env)).sourceGrammar], top.compiledGrammars) + then [err(top.location, s"Orphaned unique reference to ${top.unparse} in production ${top.frame.fullName} (reference has type ${prettyType(top.finalType)}).")] + -- Check that there is at most one unique reference taken to this decoration site. + else + (if length(lookupLocalTransUniqueRefs(fName, q.attrDcl.fullName, top.flowEnv)) > 1 + then [err(top.location, s"Multiple unique references taken to ${top.unparse} in production ${top.frame.fullName} (reference has type ${prettyType(top.finalType)}).")] + -- Check that there isn't also a unique reference taken to e + else []) ++ + case lookupLocalUniqueRefs(fName, top.flowEnv) of + | u :: _ -> + [err(top.location, s"Cannot take a unique reference to ${top.unparse} in production ${top.frame.fullName} (reference has type ${prettyType(top.finalType)}) since there is also a unique reference taken to ${e.unparse} at ${u.sourceGrammar}:${u.sourceLocation.unparse}.")] + | [] -> [] + end + | _ -> [err(top.location, s"Cannot take a unique reference (of type ${prettyType(top.finalType)}) to ${top.unparse}")] + end + | _ -> [] + end; +} +aspect production annoAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.uniqueRefs := e.accessUniqueRefs; +} +aspect production synDataAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.uniqueRefs := e.accessUniqueRefs; +} +aspect production inhUndecoratedAccessErrorHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.uniqueRefs := e.accessUniqueRefs; +} +aspect production transUndecoratedAccessErrorHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.uniqueRefs := e.accessUniqueRefs; +} +aspect production unknownDclAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.uniqueRefs := e.accessUniqueRefs; +} + +aspect production ifThenElse +top::Expr ::= 'if' e1::Expr 'then' e2::Expr 'else' e3::Expr +{ + top.uniqueRefs := + e1.uniqueRefs ++ + unionMutuallyExclusiveRefs(e1.uniqueRefs, e2.uniqueRefs); +} + +aspect production lambdaParamReference +top::Expr ::= q::Decorated! QName +{ + top.uniqueRefs <- + if top.finalType.isUniqueDecorated + then [(q.name, uniqueRefSite( + refSet=top.finalType.inhSetMembers, + refFlowDeps=top.flowDeps, + sourceGrammar=top.grammarName, + sourceLocation=top.location + ))] + else []; + top.accessUniqueRefs = []; +} + +aspect production lambdap +top::Expr ::= params::ProductionRHS e::Expr +{ + top.uniqueRefs := filter(\ r::(String, UniqueRefSite) -> !contains(r.1, params.lambdaBoundVars), e.uniqueRefs); + top.errors <- flatMap(\ n::String -> + let rs::[UniqueRefSite] = lookupAll(n, e.uniqueRefs) + in + if length(rs) > 1 + then map(err(_, s"Multiple uses of unique reference lambda parameter ${n}"), map((.sourceLocation), rs)) + else [] + end, + params.lambdaBoundVars); +} + +aspect production lexicalLocalReference +top::Expr ::= q::Decorated! QName fi::Maybe fd::[FlowVertex] rs::[(String, UniqueRefSite)] +{ + top.errors <- + -- This check is needed due to how we handle let binding auto-undecoration in the type system: + -- unique and regular references can both undecorate and unique references can become regular ones, + -- but ensure that we don't create a unique reference out of a regular one. + case top.finalType, q.lookupValue.typeScheme.monoType of + | uniqueDecoratedType(_, _), uniqueDecoratedType(_, _) -> [] + | uniqueDecoratedType(_, _), _ -> + [err(top.location, s"${q.name} was not bound as a unique reference, but here it is used with type ${prettyType(top.finalType)}.")] + | _, _ -> [] + end; + + top.uniqueRefs <- rs; + top.accessUniqueRefs = []; +} + +aspect production letp +top::Expr ::= la::AssignExpr e::Expr +{ + -- Excluding refs from la, they flow up through the lexicalLocalReferences in e + top.uniqueRefs := e.uniqueRefs; +} +aspect production matchPrimitiveReal +top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr +{ + top.uniqueRefs := e.uniqueRefs ++ unionMutuallyExclusiveRefs(pr.uniqueRefs, f.uniqueRefs); + top.errors <- uniqueContextErrors(e.uniqueRefs); +} +aspect production consPattern +top::PrimPatterns ::= p::PrimPattern _ ps::PrimPatterns +{ + top.uniqueRefs := unionMutuallyExclusiveRefs(p.uniqueRefs, ps.uniqueRefs); +} diff --git a/grammars/silver/compiler/analysis/uniqueness/ProductionBody.sv b/grammars/silver/compiler/analysis/uniqueness/ProductionBody.sv new file mode 100644 index 000000000..59b8d5548 --- /dev/null +++ b/grammars/silver/compiler/analysis/uniqueness/ProductionBody.sv @@ -0,0 +1,113 @@ +grammar silver:compiler:analysis:uniqueness; + +attribute uniqueRefs occurs on ProductionBody, ProductionStmts, ProductionStmt; +propagate uniqueRefs on ProductionBody, ProductionStmts, ProductionStmt; + +aspect production productionDcl +top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::ProductionBody +{ + top.errors <- + if any(map((.isUniqueDecorated), namedSig.inputTypes)) && null(body.undecorateExpr) + then [err(top.location, s"Production '${id.name}' has a unique reference in its signature but no 'undecorates to'.")] + else []; +} + +aspect production attachNoteStmt +top::ProductionStmt ::= 'attachNote' note::Expr ';' +{ + top.errors <- uniqueContextErrors(note.uniqueRefs); +} +aspect production forwardInh +top::ForwardInh ::= lhs::ForwardLHSExpr '=' e::Expr ';' +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} +aspect production returnDef +top::ProductionStmt ::= 'return' e::Expr ';' +{ + top.errors <- + if any(map((.isUniqueDecorated), top.frame.signature.inputTypes)) then [] + else map(\ r::(String, UniqueRefSite) -> err(r.2.sourceLocation, + s"Unique reference to ${r.1} taken outside of a unique context. " ++ + s"The return of ${top.frame.fullName} is not a unique context as this function has no unique parameters."), + e.uniqueRefs); +} +aspect production undecoratesTo +top::ProductionStmt ::= 'undecorates' 'to' e::Expr ';' +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} +aspect production synthesizedAttributeDef +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr +{ + top.errors <- + if !attr.found || attr.attrDcl.isTranslation then [] + else uniqueContextErrors(e.uniqueRefs); +} +aspect production inheritedAttributeDef +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} + +-- Modifications +aspect production synAppendColAttributeDef +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur {- <- -} e::Expr +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} +aspect production inhAppendColAttributeDef +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur {- <- -} e::Expr +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} +aspect production synBaseColAttributeDef +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} +aspect production inhBaseColAttributeDef +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} +aspect production appendCollectionValueDef +top::ProductionStmt ::= val::Decorated! QName e::Expr +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} +aspect production pluckDef +top::ProductionStmt ::= 'pluck' e::Expr ';' +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} +aspect production printStmt +top::ProductionStmt ::= 'print' e::Expr ';' +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} +aspect production parserAttributeValueDef +top::ProductionStmt ::= val::Decorated! QName e::Expr +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} +aspect production pushTokenStmt +top::ProductionStmt ::= 'pushToken' '(' val::QName ',' lexeme::Expr ')' ';' +{ + top.errors <- uniqueContextErrors(lexeme.uniqueRefs); +} +aspect production insertSemanticTokenStmt +top::ProductionStmt ::= 'insert' 'semantic' 'token' n::QNameType 'at' loc::Expr ';' +{ + top.errors <- uniqueContextErrors(loc.uniqueRefs); +} +aspect production ifElseStmt +top::ProductionStmt ::= 'if' '(' condition::Expr ')' th::ProductionStmt 'else' el::ProductionStmt +{ + top.errors <- uniqueContextErrors(condition.uniqueRefs); +} +aspect production termAttrValueValueDef +top::ProductionStmt ::= val::Decorated! QName e::Expr +{ + top.errors <- uniqueContextErrors(e.uniqueRefs); +} diff --git a/grammars/silver/compiler/analysis/uniqueness/Project.sv b/grammars/silver/compiler/analysis/uniqueness/Project.sv new file mode 100644 index 000000000..f83ccb423 --- /dev/null +++ b/grammars/silver/compiler/analysis/uniqueness/Project.sv @@ -0,0 +1,22 @@ +grammar silver:compiler:analysis:uniqueness; + +imports silver:compiler:definition:core; +imports silver:compiler:definition:env; +imports silver:compiler:definition:type; +imports silver:compiler:definition:type:syntax; +imports silver:compiler:definition:flow:ast; +imports silver:compiler:definition:flow:env; +imports silver:compiler:definition:flow:syntax; +imports silver:compiler:definition:concrete_syntax; +imports silver:compiler:analysis:typechecking:core; +imports silver:compiler:driver:util; + +imports silver:compiler:modification:let_fix; +imports silver:compiler:modification:lambda_fn; +imports silver:compiler:modification:primitivepattern; +imports silver:compiler:modification:copper; +imports silver:compiler:modification:copper_mda; +imports silver:compiler:modification:collection; +imports silver:compiler:modification:defaultattr; +imports silver:compiler:modification:ffi; + diff --git a/grammars/silver/compiler/analysis/uniqueness/RootSpec.sv b/grammars/silver/compiler/analysis/uniqueness/RootSpec.sv new file mode 100644 index 000000000..c3e45ce3d --- /dev/null +++ b/grammars/silver/compiler/analysis/uniqueness/RootSpec.sv @@ -0,0 +1,35 @@ +grammar silver:compiler:analysis:uniqueness; + +monoid attribute hasUniqueRefs::Boolean with false, ||; + +attribute uniqueRefs, hasUniqueRefs occurs on InterfaceItems, InterfaceItem; +propagate uniqueRefs, hasUniqueRefs on InterfaceItems, InterfaceItem; + +aspect production consInterfaceItem +top::InterfaceItems ::= h::InterfaceItem t::InterfaceItems +{ + top.interfaceErrors <- if !top.hasUniqueRefs then ["Missing item uniqueRefs"] else []; +} + +aspect default production +top::InterfaceItem ::= +{ + propagate uniqueRefs, hasUniqueRefs; +} + +abstract production uniqueRefs +top::InterfaceItem ::= val::[(String, UniqueRefSite)] +{ + propagate isEqual; + top.uniqueRefs <- val; + top.hasUniqueRefs <- true; +} + +aspect function packInterfaceItems +InterfaceItems ::= r::Decorated RootSpec +{ + interfaceItems <- [uniqueRefs(r.uniqueRefs)]; +} + +attribute uniqueRefs occurs on RootSpec; +propagate uniqueRefs on RootSpec; diff --git a/grammars/silver/compiler/analysis/uniqueness/UniqueRefSite.sv b/grammars/silver/compiler/analysis/uniqueness/UniqueRefSite.sv new file mode 100644 index 000000000..d9e41f1ca --- /dev/null +++ b/grammars/silver/compiler/analysis/uniqueness/UniqueRefSite.sv @@ -0,0 +1,40 @@ +grammar silver:compiler:analysis:uniqueness; + +-- Unique references taken in this tree +monoid attribute uniqueRefs::[(String, UniqueRefSite)]; + +{-- + - Represents taking of a unique reference to a child or local/production attribute. + - Since taking a unique reference means that inherited equations + - on the decoration site for attributes not in the reference set are forbidden, + - this info tracks what decoration sites have partial references taken. + -} +nonterminal UniqueRefSite with refSet, refFlowDeps, + sourceGrammar, -- The grammar of where the reference was taken + sourceLocation; -- The location of where the reference was taken + +-- The attributes in the type of the taken reference +annotation refSet::[String]; + +-- The flow dependencies of taking this reference +annotation refFlowDeps::[FlowVertex]; + +abstract production uniqueRefSite +top::UniqueRefSite ::= +{} + +-- Append lists of references, ignoring duplicate refs to the same ref site +function unionMutuallyExclusiveRefs +[(String, UniqueRefSite)] ::= rs1::[(String, UniqueRefSite)] rs2::[(String, UniqueRefSite)] +{ + return rs1 ++ filter(\ r::(String, UniqueRefSite) -> !lookup(r.1, rs1).isJust, rs2); +} + +-- Compare unique ref sites based on ref set. +-- Source location doesn't matter, and we should never be comparing unique ref sites from different grammars. +instance Eq UniqueRefSite { + eq = \ r1::UniqueRefSite r2::UniqueRefSite -> r1.refSet == r2.refSet; +} + +global uniqueContextErrors::([Message] ::= [(String, UniqueRefSite)]) = + map(\ r::(String, UniqueRefSite) -> err(r.2.sourceLocation, s"Unique reference to ${r.1} taken outside of a unique context."), _); diff --git a/grammars/silver/compiler/analysis/warnings/exporting/Graph.sv b/grammars/silver/compiler/analysis/warnings/exporting/Graph.sv index 19cb711e5..0b19fd0e6 100644 --- a/grammars/silver/compiler/analysis/warnings/exporting/Graph.sv +++ b/grammars/silver/compiler/analysis/warnings/exporting/Graph.sv @@ -9,11 +9,13 @@ import silver:compiler:definition:env; -- This isn't exactly a warning, but it can live here for now... synthesized attribute dumpDepGraph :: Boolean occurs on CmdArgs; +synthesized attribute dumpExportGraph :: Boolean occurs on CmdArgs; aspect production endCmdArgs top::CmdArgs ::= _ { top.dumpDepGraph = false; + top.dumpExportGraph = false; } abstract production dumpDepGraphFlag top::CmdArgs ::= rest::CmdArgs @@ -21,6 +23,12 @@ top::CmdArgs ::= rest::CmdArgs top.dumpDepGraph = true; forwards to rest; } +abstract production dumpExportGraphFlag +top::CmdArgs ::= rest::CmdArgs +{ + top.dumpExportGraph = true; + forwards to rest; +} aspect function parseArgs Either ::= args::[String] { @@ -28,12 +36,17 @@ Either ::= args::[String] flagSpec(name="--dump-import-graph", paramString=nothing(), help="dump a graph of dependencies between grammars as a Graphviz file", flagParser=flag(dumpDepGraphFlag))]; + flags <- [ + flagSpec(name="--dump-export-graph", paramString=nothing(), + help="dump a graph of exports between grammars as a Graphviz file", + flagParser=flag(dumpExportGraphFlag))]; -- not omitting from descriptions deliberately! } aspect production compilation top::Compilation ::= g::Grammars _ _ benv::BuildEnv { top.postOps <- if top.config.dumpDepGraph then [dumpDepGraphAction(g.grammarList)] else []; + top.postOps <- if top.config.dumpExportGraph then [dumpExportGraphAction(g.grammarList)] else []; } abstract production dumpDepGraphAction @@ -48,6 +61,18 @@ top::DriverAction ::= specs::[Decorated RootSpec] top.order = 0; } +abstract production dumpExportGraphAction +top::DriverAction ::= specs::[Decorated RootSpec] +{ + top.run = do { + eprintln("Generating export graph"); + writeFile("exports.dot", "digraph exports {\n" ++ generateDotExportGraph(specs) ++ "}"); + return 0; + }; + + top.order = 0; +} + function generateDotGraph String ::= specs::[Decorated RootSpec] { @@ -60,6 +85,18 @@ String ::= specs::[Decorated RootSpec] end; } +function generateDotExportGraph +String ::= specs::[Decorated RootSpec] +{ + return case specs of + | [] -> "" + | h::t -> + "\"" ++ h.declaredName ++ "\"[label=\"" ++ h.declaredName ++ "\"];\n" ++ + implode("", map(makeDotArrow(h.declaredName, _), computeOptionalDeps([h.declaredName], h.compiledGrammars))) ++ + generateDotExportGraph(t) + end; +} + function makeDotArrow String ::= f::String t::String { diff --git a/grammars/silver/compiler/analysis/warnings/flow/FlowTypeCopyEquation.sv b/grammars/silver/compiler/analysis/warnings/flow/FlowTypeCopyEquation.sv index 7e60d50dc..c951fed61 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/FlowTypeCopyEquation.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/FlowTypeCopyEquation.sv @@ -3,6 +3,10 @@ grammar silver:compiler:analysis:warnings:flow; -- Flow type check: the implicitly generated copy equations for synthesized -- attributes due to forwarding may exceed their flow type. +-- This can happen when the forward equation itself exceeds the flow type, +-- or when a forward inh equation for an inh that the syn depends on exceeds +-- the syn's flow type. + -- This can only occur with *host-language attributes* as extension -- attribute are required to have ft(syn) > ft(fwd). @@ -15,9 +19,7 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr -- oh no again! local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; local myGraphs :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; - - local transitiveDeps :: [FlowVertex] = expandGraph([forwardEqVertex()], findProductionGraph(fName, myGraphs)); - local fwdFlowDeps :: set:Set = onlyLhsInh(transitiveDeps); + local myGraph :: ProductionGraph = findProductionGraph(fName, myGraphs); local lhsNt :: String = namedSig.outputElement.typerep.typeName; local hostSyns :: [String] = getHostSynsFor(lhsNt, top.flowEnv); @@ -28,15 +30,17 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr if null(body.errors ++ ns.errors) && top.config.warnMissingInh -- Must be a forwarding production - && !null(body.uniqueSignificantExpression) - then flatMap(raiseImplicitFwdEqFlowTypes(top.config, top.location, lhsNt, fName, _, top.flowEnv, fwdFlowDeps, myFlow), hostSyns) + && !null(body.forwardExpr) + then flatMap(raiseImplicitFwdEqFlowTypes(top.config, top.location, lhsNt, fName, _, top.flowEnv, myGraph, myFlow), hostSyns) else []; } function raiseImplicitFwdEqFlowTypes -[Message] ::= config::Decorated CmdArgs l::Location lhsNt::String prod::String attr::String e::FlowEnv fwdFlowDeps::set:Set myFlow::EnvTree +[Message] ::= config::Decorated CmdArgs l::Location lhsNt::String prod::String attr::String e::FlowEnv myGraph::ProductionGraph myFlow::EnvTree { + -- The actual dependencies for `forward.attr` + local fwdFlowDeps :: set:Set = onlyLhsInh(expandGraph([forwardEqVertex(), forwardSynVertex(attr)], myGraph)); -- The flow type for `attr` on `lhsNt` local depsForThisAttr :: set:Set = inhDepsForSyn(attr, lhsNt, myFlow); -- Actual forwards equation deps not in the flow type for `attr` @@ -46,7 +50,7 @@ function raiseImplicitFwdEqFlowTypes | eq :: _ -> [] | [] -> if null(diff) then [] - else [mwdaWrn(config, l, s"In production ${prod}, the implicit copy equation for ${attr} (due to forwarding) would exceed the attribute's flow type because the production forward equation depends on ${implode(", ", diff)}")] + else [mwdaWrn(config, l, s"In production ${prod}, the implicit copy equation for ${attr} (due to forwarding) would exceed the attribute's flow type with dependencies on ${implode(", ", diff)}")] end; } diff --git a/grammars/silver/compiler/analysis/warnings/flow/Inh.sv b/grammars/silver/compiler/analysis/warnings/flow/Inh.sv index 9b429910f..a1695265c 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/Inh.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/Inh.sv @@ -46,56 +46,27 @@ Either ::= args::[String] -------------------------------------------------------------------------------- - -{-- - - This is a glorified lambda function, to help look for equations. - - Literally, we're just checking for null here. - - - - @param f The lookup function for the appropriate type of equation - - e.g. `lookupInh(prod, rhs, _, env)` - - @param attr The attribute to look up. - -} -function isEquationMissing -Boolean ::= f::([FlowDef] ::= String) attr::String -{ - return null(f(attr)); -} - -{-- - - False if 'attr' is an autocopy attribute, occurs on the LHS nonterminal, - - and child 'sigName' is a nonterminal (not a type var with an occurs-on context); - - true otherwise. Used in conjunction with 'filter' to get - - remove "missing equations" that are actually implicit autocopies. - -} -function ignoreIfAutoCopyOnLhs -Boolean ::= sigName::String ns::NamedSignature env::Decorated Env attr::String -{ - return !(isAutocopy(attr, env) && !null(getOccursDcl(attr, ns.outputElement.typerep.typeName, env)) && - -- Only ignore autocopies if the sig item is a nonterminal and not a type variable with an occurs-on context - findNamedSigElemType(sigName, ns.inputElements).isNonterminal); -} - {-- - - Given a name of a child, return whether it has a fully decorated nonterminal + - Given a name of a child, return whether it has a normal decorated nonterminal - type (covered by the more specific checks on accesses from references) or a - - partially decorated nonterminal type decorated with the attr. + - unique decorated nonterminal type decorated with the attr. - True if nonsensicle. -} function sigAttrViaReference -Boolean ::= sigName::String attrName::String ns::NamedSignature e::Decorated Env +Boolean ::= sigName::String attrName::String ns::NamedSignature e::Env { local ty :: Type = findNamedSigElemType(sigName, ns.inputElements); return !isDecorable(ty, e) || contains(attrName, getMinRefSet(ty, e)); } {-- - - Given a name of a local, return whether it has a fully decorated nonterminal + - Given a name of a local, return whether it has a normal decorated nonterminal - type (covered by the more specific checks on accesses from references) or a - - partially decorated nonterminal type decorated with the attr. + - unique decorated nonterminal type decorated with the attr. - True if nonsensicle. -} function localAttrViaReference -Boolean ::= sigName::String attrName::String e::Decorated Env +Boolean ::= sigName::String attrName::String e::Env { local d :: [ValueDclInfo] = getValueDcl(sigName, e); local ty :: Type = head(d).typeScheme.typerep; @@ -109,8 +80,7 @@ Boolean ::= sigName::String attrName::String e::Decorated Env - ensure such an equation exists, accounting for: - 1. Defaults - 2. Forwards - - 3. Autocopy - - 4. Reference accesses + - 3. Reference accesses - - This gives rise to 'missing transitive dependency' errors. - The reason this exists is to handle 'taking a reference' @@ -127,7 +97,7 @@ Boolean ::= sigName::String attrName::String e::Decorated Env - @returns Errors for missing equations -} function checkEqDeps -[Message] ::= v::FlowVertex config::Decorated CmdArgs l::Location prodName::String flowEnv::FlowEnv realEnv::Decorated Env anonResolve::[Pair] +[Message] ::= v::FlowVertex config::Decorated CmdArgs l::Location prodName::String flowEnv::FlowEnv realEnv::Env anonResolve::[Pair] { -- We're concerned with missing inherited equations on RHS, LOCAL, and ANON. (Implicitly, FORWARD.) @@ -146,29 +116,36 @@ function checkEqDeps -- All productions must have all SYN equations, so those errors are raised elsewhere. | lhsSynVertex(attrName) -> [] -- A dependency on an RHS.ATTR. SYN are always present, so we only care about INH here. - -- Filter missing equations for autocopy or for RHS that are references. - | rhsVertex(sigName, attrName) -> - if isInherited(attrName, realEnv) - then if !null(lookupInh(prodName, sigName, attrName, flowEnv)) - || !ignoreIfAutoCopyOnLhs(sigName, ns, realEnv, attrName) - || sigAttrViaReference(sigName, attrName, ns, realEnv) - then [] - else [mwdaWrn(config, l, "Equation has transitive dependency on child " ++ sigName ++ "'s inherited attribute for " ++ attrName ++ " but this equation appears to be missing.")] - else [] + -- Filter missing equations for RHS that are references or supplied through another decoration site. + | rhsInhVertex(sigName, attrName) -> + if !null(lookupInh(prodName, sigName, attrName, flowEnv)) + || sigAttrViaReference(sigName, attrName, ns, realEnv) + || !null(lookupRefDecSite(prodName, sigName, flowEnv)) + || case splitTransAttrInh(attrName) of + | just((transAttr, _)) -> !null(lookupTransRefDecSite(prodName, sigName, transAttr, flowEnv)) + | nothing() -> false + end + then [] + else [mwdaWrn(config, l, "Equation has transitive dependency on child " ++ sigName ++ "'s inherited attribute for " ++ attrName ++ " but this equation appears to be missing.")] + | rhsSynVertex(sigName, attrName) -> [] -- A dependency on a LOCAL. Technically, local equations may not exist! -- But let's just assume they do, since `local name :: type = expr;` is the prefered syntax. | localEqVertex(fName) -> [] -- A dependency on a LOCAL.ATTR. SYN always exist again, so we only care about INH here. -- Ignore the FORWARD (a special case of LOCAL), which always has both SYN/INH. - -- And again ignore references. Autocopy isn't relevant to locals, though. - | localVertex(fName, attrName) -> - if isInherited(attrName, realEnv) - then if !null(lookupLocalInh(prodName, fName, attrName, flowEnv)) - || fName == "forward" - || localAttrViaReference(fName, attrName, realEnv) - then [] - else [mwdaWrn(config, l, "Equation has transitive dependency on local " ++ fName ++ "'s inherited attribute for " ++ attrName ++ " but this equation appears to be missing.")] - else [] + -- And again ignore references and additional decoration sites. + | localInhVertex(fName, attrName) -> + if !null(lookupLocalInh(prodName, fName, attrName, flowEnv)) + || fName == "forward" + || localAttrViaReference(fName, attrName, realEnv) + || !null(lookupLocalRefDecSite(fName, flowEnv)) + || case splitTransAttrInh(attrName) of + | just((transAttr, _)) -> !null(lookupLocalTransRefDecSite(fName, transAttr, flowEnv)) + | nothing() -> isForwardProdAttr(fName, realEnv) -- Inh on trans are not copied with forwarding + end + then [] + else [mwdaWrn(config, l, "Equation has transitive dependency on local " ++ fName ++ "'s inherited attribute for " ++ attrName ++ " but this equation appears to be missing.")] + | localSynVertex(fName, attrName) -> [] -- A dependency on a ANON. This do always exist (`decorate expr with..` always has expr.) | anonEqVertex(fName) -> [] -- A dependency on ANON.ATTR. Again, SYN are safe. We need to check only for INH. @@ -176,21 +153,27 @@ function checkEqDeps -- missing within THIS overall equation. -- i.e. `top.syn1 = ... missing ...; top.syn2 = top.syn1;` should only raise -- the missing in the first equation. - | anonVertex(fName, attrName) -> - if isInherited(attrName, realEnv) - then if !null(lookupLocalInh(prodName, fName, attrName, flowEnv)) - then [] - else let - anonl :: Maybe = lookup(fName, anonResolve) - in if anonl.isJust - then [mwdaWrn(config, anonl.fromJust, "Decoration requires inherited attribute for " ++ attrName ++ ".")] - else [] -- If it's not in the list, then it's a transitive dep from a DIFFERENT equation (and thus reported there) - end - else [] + | anonInhVertex(fName, attrName) -> + if !null(lookupLocalInh(prodName, fName, attrName, flowEnv)) + then [] + else let + anonl :: Maybe = lookup(fName, anonResolve) + in if anonl.isJust + then [mwdaWrn(config, anonl.fromJust, "Decoration requires inherited attribute for " ++ attrName ++ ".")] + else [] -- If it's not in the list, then it's a transitive dep from a DIFFERENT equation (and thus reported there) + end + | anonSynVertex(fName, attrName) -> [] + -- A dependency on a projected equation in another production. + -- Again, SYN are safe. We need to check only for INH. + | subtermInhVertex(parent, termProdName, sigName, attrName) -> + if !remoteProdMissingInhEq(termProdName, sigName, attrName, flowEnv) + then [] + else [mwdaWrn(config, l, s"Equation has transitive dependencies on a missing remote equation.\n\tRemote production: ${termProdName}\n\tChild: ${sigName}\n\tMissing inherited equations for: ${attrName}")] + | subtermSynVertex(parent, termProdName, sigName, attrName) -> [] end; } function checkAllEqDeps -[Message] ::= v::[FlowVertex] config::Decorated CmdArgs l::Location prodName::String flowEnv::FlowEnv realEnv::Decorated Env anonResolve::[Pair] +[Message] ::= v::[FlowVertex] config::Decorated CmdArgs l::Location prodName::String flowEnv::FlowEnv realEnv::Env anonResolve::[Pair] { return flatMap(checkEqDeps(_, config, l, prodName, flowEnv, realEnv, anonResolve), v); } @@ -206,7 +189,7 @@ function checkAllEqDeps - needed to compute this synthesized attribute on this type. -} function inhDepsForSynOnType -(Maybe>, [TyVar]) ::= syn::String t::Type flow::EnvTree ns::NamedSignature env::Decorated Env +(Maybe>, [TyVar]) ::= syn::String t::Type flow::EnvTree ns::NamedSignature env::Env { local contexts::Contexts = foldContexts(ns.contexts); contexts.env = env; @@ -257,7 +240,7 @@ top::InstanceBodyItem ::= id::QName '=' e::Expr ';' } aspect production synthesizedAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { -- oh no again! local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; @@ -277,23 +260,147 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated } aspect production inheritedAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { + -- oh no again! + local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; + local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, top.frame.flowGraph); - -- TODO: if LHS is forward, we have to check that we aren't exceeding flow type!! (BUG) - - -- check transitive deps only. Nothing to check for flow types + local lhsInhDeps :: set:Set = onlyLhsInh(transitiveDeps); + + -- problem = lhsinh deps - fwd flow type - this inh attribute + local lhsInhExceedsForwardFlowType :: [String] = + set:toList( + set:removeAll( + [dl.inhAttrName], + set:difference( + lhsInhDeps, + inhDepsForSyn("forward", top.frame.lhsNtName, myFlow)))); + + local refDecSiteInhDepsLhsInh :: Maybe> = + map(\ deps::[FlowVertex] -> onlyLhsInh(expandGraph(deps, top.frame.flowGraph)), dl.refDecSiteInhDeps); + + -- problem = lhsinh deps - inh deps on dec site + local lhsInhExceedsRefDecSiteDeps :: [String] = + case refDecSiteInhDepsLhsInh of + -- A unique reference is taken that doesn't include this attribute, + -- make sure we aren't introducing any hidden transitive dependencies. + | just(deps) -> set:toList(set:difference(lhsInhDeps, deps)) + | _ -> [] + end; + top.errors <- if top.config.warnMissingInh then checkAllEqDeps(transitiveDeps, top.config, top.location, top.frame.fullName, top.flowEnv, top.env, collectAnonOrigin(e.flowDefs)) else []; + top.errors <- + if top.config.warnMissingInh && dl.name == "forward" && !null(lhsInhExceedsForwardFlowType) + then [mwdaWrn(top.config, top.location, "Forward inherited equation exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsForwardFlowType))] + else []; + top.errors <- + case dl.lhsUniqueRefs of + | u :: _ when top.config.warnMissingInh && !null(lhsInhExceedsRefDecSiteDeps) -> + [mwdaWrn(top.config, top.location, + s"Inherited override equation may exceed a flow type with hidden transitive dependencies on ${implode(", ", lhsInhExceedsRefDecSiteDeps)}; " ++ + s"${attr.attrDcl.fullName} on the reference taken at ${u.sourceGrammar}:${u.sourceLocation.unparse} may be expected to depend only on ${implode(", ", set:toList(refDecSiteInhDepsLhsInh.fromJust))}")] + | _ -> [] + end; +} + +-- All unique references to the LHS's decoration site +synthesized attribute lhsUniqueRefs::[UniqueRefSite] occurs on DefLHS; + +-- Minimum flow deps of this inherited attribute on any unique references to this decoration site +synthesized attribute refDecSiteInhDeps::Maybe<[FlowVertex]> occurs on DefLHS; + +flowtype DefLHS = lhsUniqueRefs {grammarName, config, frame, env, flowEnv}, refDecSiteInhDeps {grammarName, config, frame, env, flowEnv, defLHSattr}; + +aspect default production +top::DefLHS ::= +{ + top.lhsUniqueRefs = []; + top.refDecSiteInhDeps = nothing(); +} +aspect production childDefLHS +top::DefLHS ::= q::Decorated! QName +{ + top.lhsUniqueRefs = lookupUniqueRefs(top.frame.fullName, q.lookupValue.fullName, top.flowEnv); + top.refDecSiteInhDeps = + case top.lhsUniqueRefs of + | u :: _ when !contains(top.inhAttrName, u.refSet) -> just( + u.refFlowDeps ++ + map( + \ v::VertexType -> v.inhVertex(top.inhAttrName), + lookupRefPossibleDecSites(top.frame.fullName, q.lookupValue.fullName, top.flowEnv))) + | _ -> nothing() + end; +} +aspect production localDefLHS +top::DefLHS ::= q::Decorated! QName +{ + top.lhsUniqueRefs = lookupLocalUniqueRefs(q.lookupValue.fullName, top.flowEnv); + top.refDecSiteInhDeps = + case top.lhsUniqueRefs of + | u :: _ when !contains(top.inhAttrName, u.refSet) -> just( + u.refFlowDeps ++ + map( + \ v::VertexType -> v.inhVertex(top.inhAttrName), + lookupLocalRefPossibleDecSites(q.lookupValue.fullName, top.flowEnv))) + | _ -> nothing() + end; +} +aspect production childTransAttrDefLHS +top::DefLHS ::= q::Decorated! QName attr::Decorated! QNameAttrOccur +{ + local childUniqueRefs::[UniqueRefSite] = + lookupUniqueRefs(top.frame.fullName, q.lookupValue.fullName, top.flowEnv); + local childTransAttrUniqueRefs::[UniqueRefSite] = + lookupTransUniqueRefs(top.frame.fullName, q.lookupValue.fullName, attr.attrDcl.fullName, top.flowEnv); + top.lhsUniqueRefs = if !null(childUniqueRefs) then childUniqueRefs else childTransAttrUniqueRefs; + top.refDecSiteInhDeps = + case childUniqueRefs, childTransAttrUniqueRefs of + | u :: _, _ when !contains(top.inhAttrName, u.refSet) -> just( + u.refFlowDeps ++ + map( + \ v::VertexType -> v.inhVertex(top.inhAttrName), + lookupRefPossibleDecSites(top.frame.fullName, q.lookupValue.fullName, top.flowEnv))) + | _, u :: _ when !contains(top.defLHSattr.attrDcl.fullName, u.refSet) -> just( + u.refFlowDeps ++ + map( + \ v::VertexType -> v.inhVertex(top.defLHSattr.attrDcl.fullName), + lookupTransRefPossibleDecSites(top.frame.fullName, q.lookupValue.fullName, attr.attrDcl.fullName, top.flowEnv))) + | _, _ -> nothing() + end; +} +aspect production localTransAttrDefLHS +top::DefLHS ::= q::Decorated! QName attr::Decorated! QNameAttrOccur +{ + local localUniqueRefs::[UniqueRefSite] = + lookupUniqueRefs(top.frame.fullName, q.lookupValue.fullName, top.flowEnv); + local localTransAttrUniqueRefs::[UniqueRefSite] = + lookupTransUniqueRefs(top.frame.fullName, q.lookupValue.fullName, attr.attrDcl.fullName, top.flowEnv); + top.lhsUniqueRefs = if !null(localUniqueRefs) then localUniqueRefs else localTransAttrUniqueRefs; + top.refDecSiteInhDeps = + case localUniqueRefs, localTransAttrUniqueRefs of + | u :: _, _ when !contains(top.inhAttrName, u.refSet) -> just( + u.refFlowDeps ++ + map( + \ v::VertexType -> v.inhVertex(top.inhAttrName), + lookupLocalRefPossibleDecSites(q.lookupValue.fullName, top.flowEnv))) + | _, u :: _ when !contains(top.defLHSattr.attrDcl.fullName, u.refSet) -> just( + u.refFlowDeps ++ + map( + \ v::VertexType -> v.inhVertex(top.defLHSattr.attrDcl.fullName), + lookupLocalTransRefPossibleDecSites(q.lookupValue.fullName, attr.attrDcl.fullName, top.flowEnv))) + | _, _ -> nothing() + end; } ----- WARNING TODO BEGIN MASSIVE COPY & PASTE SESSION aspect production synBaseColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { -- oh no again! local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; @@ -312,7 +419,7 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated else []; } aspect production synAppendColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { -- oh no again! local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; @@ -331,27 +438,55 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated else []; } aspect production inhBaseColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { - local transitiveDeps :: [FlowVertex] = + -- oh no again! + local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; + + local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, top.frame.flowGraph); - -- check transitive deps only. Nothing to be done for flow types + local lhsInhDeps :: set:Set = onlyLhsInh(transitiveDeps); + -- problem = lhsinh deps - fwd flow type - this inh attribute + local lhsInhExceedsForwardFlowType :: [String] = + set:toList( + set:removeAll( + [dl.inhAttrName], + set:difference( + lhsInhDeps, + inhDepsForSyn("forward", top.frame.lhsNtName, myFlow)))); + top.errors <- if top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, top.config, top.location, top.frame.fullName, top.flowEnv, top.env, collectAnonOrigin(e.flowDefs)) + then checkAllEqDeps(transitiveDeps, top.config, top.location, top.frame.fullName, top.flowEnv, top.env, collectAnonOrigin(e.flowDefs)) ++ + if dl.name != "forward" || null(lhsInhExceedsForwardFlowType) then [] + else [mwdaWrn(top.config, top.location, "Forward inherited equation exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsForwardFlowType))] else []; } aspect production inhAppendColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { + -- oh no again! + local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; + local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, top.frame.flowGraph); - -- check transitive deps only. Nothing to be done for flow types + local lhsInhDeps :: set:Set = onlyLhsInh(transitiveDeps); + -- problem = lhsinh deps - fwd flow type - this inh attribute + local lhsInhExceedsForwardFlowType :: [String] = + set:toList( + set:removeAll( + [dl.inhAttrName], + set:difference( + lhsInhDeps, + inhDepsForSyn("forward", top.frame.lhsNtName, myFlow)))); + top.errors <- if top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, top.config, top.location, top.frame.fullName, top.flowEnv, top.env, collectAnonOrigin(e.flowDefs)) + then checkAllEqDeps(transitiveDeps, top.config, top.location, top.frame.fullName, top.flowEnv, top.env, collectAnonOrigin(e.flowDefs)) ++ + if dl.name != "forward" || null(lhsInhExceedsForwardFlowType) then [] + else [mwdaWrn(top.config, top.location, "Forward inherited equation exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsForwardFlowType))] else []; } ------ END AWFUL COPY & PASTE SESSION @@ -392,9 +527,9 @@ top::ForwardInh ::= lhs::ForwardLHSExpr '=' e::Expr ';' [case lhs of | forwardLhsExpr(q) -> q.attrDcl.fullName end], - set:difference( - lhsInhDeps, - inhDepsForSyn("forward", top.frame.lhsNtName, myFlow)))); + set:difference( + lhsInhDeps, + inhDepsForSyn("forward", top.frame.lhsNtName, myFlow)))); top.errors <- if top.config.warnMissingInh @@ -404,8 +539,27 @@ top::ForwardInh ::= lhs::ForwardLHSExpr '=' e::Expr ';' else []; } +aspect production undecoratesTo +top::ProductionStmt ::= 'undecorates' 'to' e::Expr ';' +{ + -- oh no again! + local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; + + local transitiveDeps :: [FlowVertex] = + expandGraph(e.flowDeps, top.frame.flowGraph); + + local lhsInhDeps :: [String] = set:toList(onlyLhsInh(transitiveDeps)); + + top.errors <- + if top.config.warnMissingInh + then checkAllEqDeps(transitiveDeps, top.config, top.location, top.frame.fullName, top.flowEnv, top.env, collectAnonOrigin(e.flowDefs)) ++ + if null(lhsInhDeps) then [] + else [mwdaWrn(top.config, top.location, "Undecorates equation has dependencies on " ++ implode(", ", lhsInhDeps))] + else []; +} + aspect production localValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, top.frame.flowGraph); @@ -445,7 +599,7 @@ top::ProductionStmt ::= 'attachNote' e::Expr ';' -- Partially skipping `appendCollectionValueDef`: it likewise forwards -- But we do have a special "exceeds check" to do here: aspect production appendCollectionValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { local productionFlowGraph :: ProductionGraph = top.frame.flowGraph; local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, productionFlowGraph); @@ -482,45 +636,41 @@ Step 2: Let's go check on expressions. This has two purposes: -} aspect production childReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - top.errors <- + top.errors <- if top.config.warnMissingInh && isDecorable(q.lookupValue.typeScheme.typerep, top.env) then if refSet.isJust then [] - else [mwdaWrn(top.config, top.location, s"Cannot take a reference of type ${prettyType(finalTy)}, as the reference set is not bounded.")] + else [mwdaWrn(top.config, top.location, s"Cannot take a reference of type ${prettyType(top.finalType)}, as the reference set is not bounded.")] else []; } aspect production lhsReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - top.errors <- + top.errors <- if top.config.warnMissingInh then if refSet.isJust then [] - else [mwdaWrn(top.config, top.location, s"Cannot take a reference of type ${prettyType(finalTy)}, as the reference set is not bounded.")] + else [mwdaWrn(top.config, top.location, s"Cannot take a reference of type ${prettyType(top.finalType)}, as the reference set is not bounded.")] else []; } aspect production localReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - top.errors <- + top.errors <- if top.config.warnMissingInh && isDecorable(q.lookupValue.typeScheme.typerep, top.env) then if refSet.isJust then [] - else [mwdaWrn(top.config, top.location, s"Cannot take a reference of type ${prettyType(finalTy)}, as the reference set is not bounded.")] + else [mwdaWrn(top.config, top.location, s"Cannot take a reference of type ${prettyType(top.finalType)}, as the reference set is not bounded.")] else []; } aspect production forwardReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - top.errors <- + top.errors <- if top.config.warnMissingInh then if refSet.isJust then [] - else [mwdaWrn(top.config, top.location, s"Cannot take a reference of type ${prettyType(finalTy)}, as the reference set is not bounded.")] + else [mwdaWrn(top.config, top.location, s"Cannot take a reference of type ${prettyType(top.finalType)}, as the reference set is not bounded.")] else []; } @@ -531,20 +681,19 @@ top::Expr ::= e::Expr '.' 'forward' } aspect production synDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { -- oh no again local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; - local finalTy :: Type = performSubstitution(e.typerep, e.upSubst); local deps :: (Maybe>, [TyVar]) = - inhDepsForSynOnType(q.attrDcl.fullName, finalTy, myFlow, top.frame.signature, top.env); + inhDepsForSynOnType(q.attrDcl.fullName, e.finalType, myFlow, top.frame.signature, top.env); local inhDeps :: set:Set = fromMaybe(set:empty(), deps.1); -- Need to check that we have bounded inh deps, i.e. deps.1 == just(...) -- This aspect is in two parts. First: we *must* check that any accesses -- on a unknown decorated tree are in the ref-set. local acceptable :: ([String], [TyVar]) = - case finalTy of + case e.finalType of | decoratedType(_, i) -> getMinInhSetMembers([], i, top.env) | _ -> ([], []) end; @@ -560,60 +709,72 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur case e.flowVertexInfo of -- We don't track dependencies on inh sets transitively, so we need to check that the inh deps are bounded here; -- an access with unbounded inh deps only ever makes sense on a reference. - | hasVertex(_) -> + | just(_) -> if deps.1.isJust then [] - else [mwdaWrn(top.config, top.location, "Access of " ++ q.name ++ " from " ++ prettyType(finalTy) ++ " requires an unbounded set of inherited attributes")] + else [mwdaWrn(top.config, top.location, "Access of " ++ q.name ++ " from " ++ prettyType(e.finalType) ++ " requires an unbounded set of inherited attributes")] -- without a vertex, we're accessing from a reference, and so... - | noVertex() -> + | nothing() -> if any(map(contains(_, deps.2), acceptable.2)) then [] -- The deps are supplied as a common InhSet var -- We didn't find the deps as an InhSet var else if null(diff) then if deps.fst.isJust then [] -- We have a bound on the inh deps, and they are all present -- We don't have a bound on the inh deps, flag the unsatisfied InhSet deps else if null(acceptable.2) - then [mwdaWrn(top.config, top.location, "Access of " ++ q.name ++ " from " ++ prettyType(finalTy) ++ " requires an unbounded set of inherited attributes")] - else [mwdaWrn(top.config, top.location, "Access of " ++ q.name ++ " from reference of type " ++ prettyType(finalTy) ++ " requires one of the following sets of inherited attributes not known to be supplied to this reference: " ++ implode(", ", map(findAbbrevFor(_, top.frame.signature.freeVariables), deps.snd)))] + then [mwdaWrn(top.config, top.location, "Access of " ++ q.name ++ " from " ++ prettyType(e.finalType) ++ " requires an unbounded set of inherited attributes")] + else [mwdaWrn(top.config, top.location, "Access of " ++ q.name ++ " from reference of type " ++ prettyType(e.finalType) ++ " requires one of the following sets of inherited attributes not known to be supplied to this reference: " ++ implode(", ", map(findAbbrevFor(_, top.frame.signature.freeVariables), deps.snd)))] -- We didn't find the inh deps - else [mwdaWrn(top.config, top.location, "Access of " ++ q.name ++ " from reference of type " ++ prettyType(finalTy) ++ " requires inherited attributes not known to be supplied to this reference: " ++ implode(", ", diff))] + else [mwdaWrn(top.config, top.location, "Access of " ++ q.name ++ " from reference of type " ++ prettyType(e.finalType) ++ " requires inherited attributes not known to be supplied to this reference: " ++ implode(", ", diff))] end else []; ---------------- -- CASE 2: More specific errors for things already caught by `checkAllEqDeps`. - -- Equation has transition dep on `i`, but here we can say where this dependency - -- originated: from an syn acces. + -- Equation has transitive dep on `i`, but here we can say where this dependency + -- originated: from a syn access. top.errors <- if null(e.errors) && top.config.warnMissingInh then case e of | childReference(lq) -> - if isDecorable(lq.lookupValue.typeScheme.typerep, top.env) + if isDecorable(lq.lookupValue.typeScheme.typerep, top.env) && + null(lookupRefDecSite(top.frame.fullName, lq.lookupValue.fullName, top.flowEnv)) -- Decoration site projection, covered by checkAllEqDeps then - let inhs :: [String] = - -- N.B. we're filtering out autocopies here + let inhs :: [String] = + filter(\ attr::String -> + case splitTransAttrInh(attr) of + -- If the dep is for an inh on a trans attribute, check for a decoration site projection for the trans attribute + | just((transAttr, _)) -> null(lookupTransRefDecSite(top.frame.fullName, lq.lookupValue.fullName, transAttr, top.flowEnv)) + | _ -> true + end, filter( - ignoreIfAutoCopyOnLhs(lq.name, top.frame.signature, top.env, _), - filter( - isEquationMissing( - lookupInh(top.frame.fullName, lq.lookupValue.fullName, _, top.flowEnv), - _), - removeAll(getMinRefSet(lq.lookupValue.typeScheme.typerep, top.env), - set:toList(inhDeps)))) + isEquationMissing( + lookupInh(top.frame.fullName, lq.lookupValue.fullName, _, top.flowEnv), + _), + removeAll(getMinRefSet(lq.lookupValue.typeScheme.typerep, top.env), + set:toList(inhDeps)))) in if null(inhs) then [] else [mwdaWrn(top.config, top.location, "Access of syn attribute " ++ q.name ++ " on " ++ e.unparse ++ " requires missing inherited attributes " ++ implode(", ", inhs) ++ " to be supplied")] end else [] | localReference(lq) -> - if isDecorable(lq.lookupValue.typeScheme.typerep, top.env) + if isDecorable(lq.lookupValue.typeScheme.typerep, top.env) && + null(lookupLocalRefDecSite(lq.lookupValue.fullName, top.flowEnv)) -- Decoration site projection, covered by checkAllEqDeps then let inhs :: [String] = + filter(\ attr::String -> + case splitTransAttrInh(attr) of + -- If the dep is for an inh on a trans attribute, check for a decoration site projection for the trans attribute + | just((transAttr, _)) -> null(lookupLocalTransRefDecSite(lq.lookupValue.fullName, transAttr, top.flowEnv)) + -- If the dep is for a normal inh attribute, ignore if the local is a forward production attribute + | nothing() -> !lq.lookupValue.dcl.hasForward + end, filter( isEquationMissing( lookupLocalInh(top.frame.fullName, lq.lookupValue.fullName, _, top.flowEnv), _), removeAll(getMinRefSet(lq.lookupValue.typeScheme.typerep, top.env), - set:toList(inhDeps))) + set:toList(inhDeps)))) in if null(inhs) then [] else [mwdaWrn(top.config, top.location, "Access of syn attribute " ++ q.name ++ " on " ++ e.unparse ++ " requires missing inherited attributes " ++ implode(", ", inhs) ++ " to be supplied")] end @@ -624,26 +785,144 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur } aspect production inhDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { -- In this case, ONLY check for references. -- The transitive deps error will be less difficult to figure out when there's -- an explicit access to the attributes. - local finalTy::Type = performSubstitution(e.typerep, e.upSubst); top.errors <- if null(e.errors) && top.config.warnMissingInh then case e.flowVertexInfo of - | hasVertex(_) -> [] -- no check to make, as it was done transitively + | just(_) -> [] -- no check to make, as it was done transitively -- without a vertex, we're accessing from a reference, and so... - | noVertex() -> - if contains(q.attrDcl.fullName, getMinRefSet(finalTy, top.env)) + | nothing() -> + if contains(q.attrDcl.fullName, getMinRefSet(e.finalType, top.env)) then [] - else [mwdaWrn(top.config, top.location, "Access of inherited attribute " ++ q.name ++ " on reference of type " ++ prettyType(finalTy) ++ " is not permitted")] + else [mwdaWrn(top.config, top.location, "Access of inherited attribute " ++ q.name ++ " on reference of type " ++ prettyType(e.finalType) ++ " is not permitted")] end else []; } +aspect production transDecoratedAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + -- oh no again + local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; + + local deps :: (Maybe>, [TyVar]) = + inhDepsForSynOnType(q.attrDcl.fullName, e.finalType, myFlow, top.frame.signature, top.env); + local inhDeps :: set:Set = + -- Inh deps for computing this syn attribute + fromMaybe(set:empty(), deps.1) ++ -- Need to check that we have bounded inh deps, i.e. deps.1 == just(...) + -- When taking a reference to this translation attribute access, we depend on the ref set inhs on e. + set:fromList(map(\ inh::String -> s"${q.attrDcl.fullName}.${inh}", fromMaybe([], refSet))); + + -- Need to check that the reference set is bounded when taking a reference, as with locals/children/etc. + top.errors <- + if top.config.warnMissingInh + then if refSet.isJust then [] + else [mwdaWrn(top.config, top.location, s"Cannot take a reference of type ${prettyType(e.finalType)}, as the reference set is not bounded.")] + else []; + + -- TODO: check that reference set is only inhs? + + -- This logic exactly mirrors synDecoratedAccessHandler, except with inhDeps containing extra inh dependencies from taking a reference. + +-- This aspect is in two parts. First: we *must* check that any accesses +-- on a unknown decorated tree are in the ref-set. + local acceptable :: ([String], [TyVar]) = + case e.finalType of + | decoratedType(_, i) -> getMinInhSetMembers([], i, top.env) + | _ -> ([], []) + end; + local diff :: [String] = + set:toList(set:removeAll(acceptable.1, -- blessed inhs for a reference + inhDeps)); -- needed inhs + + -- CASE 1: References. This check is necessary and won't be caught elsewhere. + top.errors <- + if null(e.errors) + && top.config.warnMissingInh + then + case e.flowVertexInfo of + -- We don't track dependencies on inh sets transitively, so we need to check that the inh deps are bounded here; + -- an access with unbounded inh deps only ever makes sense on a reference. + | just(_) -> + if deps.1.isJust then [] + else [mwdaWrn(top.config, top.location, "Access of " ++ q.name ++ " from " ++ prettyType(e.finalType) ++ " requires an unbounded set of inherited attributes")] + -- without a vertex, we're accessing from a reference, and so... + | nothing() -> + if any(map(contains(_, deps.2), acceptable.2)) then [] -- The deps are supplied as a common InhSet var + -- We didn't find the deps as an InhSet var + else if null(diff) + then if deps.fst.isJust then [] -- We have a bound on the inh deps, and they are all present + -- We don't have a bound on the inh deps, flag the unsatisfied InhSet deps + else if null(acceptable.2) + then [mwdaWrn(top.config, top.location, "Access of " ++ q.name ++ " from " ++ prettyType(e.finalType) ++ " requires an unbounded set of inherited attributes")] + else [mwdaWrn(top.config, top.location, "Access of " ++ q.name ++ " from reference of type " ++ prettyType(e.finalType) ++ " requires one of the following sets of inherited attributes not known to be supplied to this reference: " ++ implode(", ", map(findAbbrevFor(_, top.frame.signature.freeVariables), deps.snd)))] + -- We didn't find the inh deps + else [mwdaWrn(top.config, top.location, "Access of " ++ q.name ++ " from reference of type " ++ prettyType(e.finalType) ++ " requires inherited attributes not known to be supplied to this reference: " ++ implode(", ", diff))] + end + else []; + +---------------- + + -- CASE 2: More specific errors for things already caught by `checkAllEqDeps`. + -- Equation has transitive dep on `i`, but here we can say where this dependency + -- originated: from a syn access. + top.errors <- + if null(e.errors) && top.config.warnMissingInh + then + case e of + | childReference(lq) -> + if isDecorable(lq.lookupValue.typeScheme.typerep, top.env) && + null(lookupRefDecSite(top.frame.fullName, lq.lookupValue.fullName, top.flowEnv)) -- Decoration site projection, covered by checkAllEqDeps + then + let inhs :: [String] = + filter(\ attr::String -> + case splitTransAttrInh(attr) of + -- If the dep is for an inh on a trans attribute, check for a decoration site projection for the trans attribute + | just((transAttr, _)) -> null(lookupTransRefDecSite(top.frame.fullName, lq.lookupValue.fullName, transAttr, top.flowEnv)) + | _ -> true + end, + filter( + isEquationMissing( + lookupInh(top.frame.fullName, lq.lookupValue.fullName, _, top.flowEnv), + _), + removeAll(getMinRefSet(lq.lookupValue.typeScheme.typerep, top.env), + set:toList(inhDeps)))) + in if null(inhs) then [] + else [mwdaWrn(top.config, top.location, "Access of syn attribute " ++ q.name ++ " on " ++ e.unparse ++ " requires missing inherited attributes " ++ implode(", ", inhs) ++ " to be supplied")] + end + else [] + | localReference(lq) -> + if isDecorable(lq.lookupValue.typeScheme.typerep, top.env) && + null(lookupLocalRefDecSite(lq.lookupValue.fullName, top.flowEnv)) -- Decoration site projection, covered by checkAllEqDeps + then + let inhs :: [String] = + filter(\ attr::String -> + case splitTransAttrInh(attr) of + -- If the dep is for an inh on a trans attribute, check for a decoration site projection for the trans attribute + | just((transAttr, _)) -> null(lookupLocalTransRefDecSite(lq.lookupValue.fullName, transAttr, top.flowEnv)) + -- If the dep is for a normal inh attribute, ignore if the local is a forward production attribute + | nothing() -> !lq.lookupValue.dcl.hasForward + end, + filter( + isEquationMissing( + lookupLocalInh(top.frame.fullName, lq.lookupValue.fullName, _, top.flowEnv), + _), + removeAll(getMinRefSet(lq.lookupValue.typeScheme.typerep, top.env), + set:toList(inhDeps)))) + in if null(inhs) then [] + else [mwdaWrn(top.config, top.location, "Access of syn attribute " ++ q.name ++ " on " ++ e.unparse ++ " requires missing inherited attributes " ++ implode(", ", inhs) ++ " to be supplied")] + end + else [] + | _ -> [] + end + else []; +} + aspect production decorateExprWith top::Expr ::= 'decorate' e::Expr 'with' '{' inh::ExprInhs '}' { @@ -661,7 +940,7 @@ top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr -- slightly awkward way to recover the name and whether/not it was invented local sinkVertexName :: Maybe = case e.flowVertexInfo, pr.scrutineeVertexType of - | noVertex(), anonVertexType(n) -> just(n) + | nothing(), anonVertexType(n) -> just(n) | _, _ -> nothing() end; @@ -672,8 +951,7 @@ top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr pr.receivedDeps = transitiveDeps; -- just the deps on inhs of our sink - local inhDeps :: [String] = - toAnonInhs(transitiveDeps, sinkVertexName.fromJust, top.env); + local inhDeps :: [String] = toAnonInhs(transitiveDeps, sinkVertexName.fromJust); -- Subtract the ref set from our deps local diff :: [String] = @@ -690,17 +968,13 @@ top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr } function toAnonInhs -[String] ::= v::[FlowVertex] vertex::String env::Decorated Env +[String] ::= vs::[FlowVertex] vertex::String { - return + return filterMap(\ v::FlowVertex -> case v of - | anonVertex(n, inh) :: tl -> - if vertex == n && isInherited(inh, env) - then inh :: toAnonInhs(tl, vertex, env) - else toAnonInhs(tl, vertex, env) - | _ :: tl -> toAnonInhs(tl, vertex, env) - | [] -> [] - end; + | anonInhVertex(n, inh) when n == vertex -> just(inh) + | _ -> nothing() + end, vs); } inherited attribute receivedDeps :: [FlowVertex] occurs on VarBinders, VarBinder, PrimPatterns, PrimPattern; @@ -718,15 +992,14 @@ top::VarBinder ::= n::Name else []; -- fName is our invented vertex name for the pattern variable - local requiredInhs :: [String] = - toAnonInhs(top.receivedDeps, fName, top.env); + local requiredInhs :: [String] = toAnonInhs(top.receivedDeps, fName); -- Check for equation's existence: -- Prod: top.matchingAgainst.fromJust.fullName -- Child: top.bindingName -- Inh: each of requiredInhs local missingInhs :: [String] = - filter(remoteProdMissingEq(top.matchingAgainst.fromJust, top.bindingName, _, top.env, top.flowEnv), + filter(remoteProdMissingInhEq(top.matchingAgainst.fromJust.fullName, top.bindingName, _, top.flowEnv), removeAll(getMinRefSet(top.bindingType, top.env), requiredInhs)); top.errors <- @@ -738,12 +1011,61 @@ top::VarBinder ::= n::Name else []; } -function remoteProdMissingEq -Boolean ::= prod::ValueDclInfo sigName::String attrName::String realEnv::Decorated Env flowEnv::FlowEnv +-- Is this there an equation for this inh attr on any decoration site for this child? +function remoteProdMissingInhEq +Boolean ::= prodName::String sigName::String attrName::String flowEnv::FlowEnv +{ + return !any(unzipWith( + vertexHasInhEq(_, _, attrName, flowEnv), + lookupAllDecSites(prodName, rhsVertexType(sigName), flowEnv))); +} + +-- Find all decoration sites productions/vertices for this vertex +function lookupAllDecSites +[(String, VertexType)] ::= prodName::String vt::VertexType flowEnv::FlowEnv { return - null(lookupInh(prod.fullName, sigName, attrName, flowEnv)) && -- no equation - ignoreIfAutoCopyOnLhs(sigName, prod.namedSignature, realEnv, attrName); -- not autocopy (and on lhs) + (prodName, vt) :: + case vt of + | lhsVertexType_real() -> [] + | rhsVertexType(sigName) -> + flatMap(lookupAllDecSites(prodName, _, flowEnv), lookupRefDecSite(prodName, sigName, flowEnv)) + | localVertexType(fName) -> + flatMap(lookupAllDecSites(prodName, _, flowEnv), lookupLocalRefDecSite(fName, flowEnv)) + | transAttrVertexType(rhsVertexType(sigName), transAttr) -> + flatMap(lookupAllDecSites(prodName, _, flowEnv), lookupTransRefDecSite(prodName, sigName, transAttr, flowEnv)) + | transAttrVertexType(localVertexType(fName), transAttr) -> + flatMap(lookupAllDecSites(prodName, _, flowEnv), lookupLocalTransRefDecSite(fName, transAttr, flowEnv)) + | transAttrVertexType(_, _) -> [] + | anonVertexType(fName) -> [] + | forwardVertexType_real() -> [] + | subtermVertexType(_, remoteProdName, sigName) -> + lookupAllDecSites(remoteProdName, rhsVertexType(sigName), flowEnv) + end; +} + +function vertexHasInhEq +Boolean ::= prodName::String vt::VertexType attrName::String flowEnv::FlowEnv +{ + return + case vt of + | rhsVertexType(sigName) -> !null(lookupInh(prodName, sigName, attrName, flowEnv)) + | localVertexType(fName) -> !null(lookupLocalInh(prodName, fName, attrName, flowEnv)) + | transAttrVertexType(rhsVertexType(sigName), transAttr) -> + !null(lookupInh(prodName, sigName, s"${transAttr}.${attrName}", flowEnv)) + | transAttrVertexType(localVertexType(fName), transAttr) -> + !null(lookupLocalInh(prodName, fName, s"${transAttr}.${attrName}", flowEnv)) + | transAttrVertexType(_, _) -> false + | anonVertexType(fName) -> !null(lookupLocalInh(prodName, fName, attrName, flowEnv)) + | subtermVertexType(_, remoteProdName, sigName) -> + vertexHasInhEq(remoteProdName, rhsVertexType(sigName), attrName, flowEnv) + -- This is a tricky case since we don't know what decorated this prod. + -- checkEqDeps can count on missing LHS inh eqs being caught as flow issues elsewhere, + -- but here we are remotely looking for equations that might not be the direct dependency of + -- anything in the prod flow graph. + | lhsVertexType_real() -> false -- Shouldn't ever be directly needed, since the LHS is never the dec site for another vertex. + | forwardVertexType_real() -> false -- Same as LHS, but we can check this if e.g. forwarding to a child. + end; } -- In places where we solve a synthesized attribute occurs-on context, diff --git a/grammars/silver/compiler/analysis/warnings/flow/MWDA.sv b/grammars/silver/compiler/analysis/warnings/flow/MWDA.sv index 69403195a..79be8e5b7 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/MWDA.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/MWDA.sv @@ -15,51 +15,28 @@ imports silver:compiler:definition:type; imports silver:compiler:definition:type:syntax; imports silver:compiler:definition:env; +-- type checking +imports silver:compiler:analysis:typechecking:core; + -- flow analysis imports silver:compiler:definition:flow:ast; +imports silver:compiler:definition:flow:env; imports silver:compiler:definition:flow:driver only ProductionGraph, FlowType, prod, inhDepsForSyn, findProductionGraph, expandGraph, onlyLhsInh; +-- uniqueness analysis +imports silver:compiler:analysis:uniqueness; + -- the modifications we need to be aware of -imports silver:compiler:modification:autocopyattr only isAutocopy; imports silver:compiler:modification:collection; imports silver:compiler:modification:defaultattr; imports silver:compiler:modification:primitivepattern; imports silver:compiler:modification:copper only parserAttributeDefLHS; -function isOccursSynthesized -Boolean ::= occs::OccursDclInfo e::Decorated Env -{ - return case getAttrDcl(occs.attrOccurring, e) of - | at :: _ -> at.isSynthesized - | _ -> false - end; -} - --- TODO: this should probably not be a thing I have to write here -function isAutocopy -Boolean ::= attr::String e::Decorated Env -{ - return case getAttrDclAll(attr, e) of - | at :: _ -> at.isAutocopy - | _ -> false - end; -} --- TODO: why is this a thing I have to write here. Sheesh. FIX THIS. --- The real fix is for our vertexes to remember whether they are syn/inh. -function isInherited -Boolean ::= a::String e::Decorated Env -{ - return case getAttrDclAll(a, e) of - | at :: _ -> at.isInherited - | _ -> false - end; -} - -function isLhsInh -Boolean ::= v::FlowVertex +function isForwardProdAttr +Boolean ::= a::String e::Env { - return case v of - | lhsInhVertex(_) -> true + return case getValueDclAll(a, e) of + | d :: _ -> d.hasForward | _ -> false end; } diff --git a/grammars/silver/compiler/analysis/warnings/flow/MissingSynEq.sv b/grammars/silver/compiler/analysis/warnings/flow/MissingSynEq.sv index e1780ad8c..1654d05a5 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/MissingSynEq.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/MissingSynEq.sv @@ -86,17 +86,16 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr { -- All locally known synthesized attributes. This does not need to be exhaustive, -- because this error message is a courtesy, not the basis of the analysis. - local attrs :: [OccursDclInfo] = - filter(isOccursSynthesized(_, top.env), - getAttrsOn(namedSig.outputElement.typerep.typeName, top.env)); + local attrs :: [String] = + getSynAttrsOn(namedSig.outputElement.typerep.typeName, top.env); top.errors <- if null(body.errors ++ ns.errors) && top.config.warnMissingSyn - -- Forwarding productions do no have missing synthesized equations: - && null(body.uniqueSignificantExpression) + -- Forwarding productions do not have missing synthesized equations: + && null(body.forwardExpr) -- Otherwise, examine them all: - then flatMap(raiseMissingAttrs(top.config, top.location, fName, _, top.flowEnv), attrs) + then flatMap(raiseMissingAttrs(top.config, top.location, fName, namedSig.outputElement.typerep.typeName, _, top.flowEnv), attrs) else []; } @@ -105,28 +104,28 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr - for the synthesized attribute `attr`. - - @param l Location to raise the error message (of the production) - - @param attr DclInfo of a synthesized attribute occurrence - @param prod Full name of the non-forwarding production in question + - @param nt Full name of prod's lhs nonterminal + - @param attr Full name of a synthesized attribute - @param e The local flow environment - @returns An error message from the production's perspective, if any -} function raiseMissingAttrs -[Message] ::= config::Decorated CmdArgs l::Location prod::String attr::OccursDclInfo e::FlowEnv +[Message] ::= config::Decorated CmdArgs l::Location prod::String nt::String attr::String e::FlowEnv { -- Because the location is of the production, deliberately use the production's shortname local shortName :: String = substring(lastIndexOf(":", prod) + 1, length(prod), prod); - local lacks_default_equation :: Boolean = - null(lookupDef(attr.fullName, attr.attrOccurring, e)); + local lacks_default_equation :: Boolean = null(lookupDef(nt, attr, e)); local missing_explicit_equation :: Boolean = - case lookupSyn(prod, attr.attrOccurring, e) of + case lookupSyn(prod, attr, e) of | eq :: _ -> false | [] -> true end; return if lacks_default_equation && missing_explicit_equation - then [mwdaWrn(config, l, "production " ++ shortName ++ " lacks synthesized equation for " ++ attr.attrOccurring)] + then [mwdaWrn(config, l, "production " ++ shortName ++ " lacks synthesized equation for " ++ attr)] else []; } diff --git a/grammars/silver/compiler/analysis/warnings/flow/MwdaFlag.sv b/grammars/silver/compiler/analysis/warnings/flow/MwdaFlag.sv index d52a03ead..7aa692438 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/MwdaFlag.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/MwdaFlag.sv @@ -39,10 +39,10 @@ Either ::= args::[String] flagParser=flag(mwdaFlag))]; } -abstract production mwdaWrn -top::Message ::= config::Decorated CmdArgs l::Location m::String +function mwdaWrn +Message ::= config::Decorated CmdArgs l::Location m::String { - forwards to + return if config.errorMwda then err(l, m) else wrn(l, m); diff --git a/grammars/silver/compiler/analysis/warnings/flow/OrphanedEquation.sv b/grammars/silver/compiler/analysis/warnings/flow/OrphanedEquation.sv index ad58127b2..13367aa52 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/OrphanedEquation.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/OrphanedEquation.sv @@ -1,5 +1,6 @@ grammar silver:compiler:analysis:warnings:flow; +import silver:compiler:analysis:uniqueness; import silver:compiler:modification:let_fix only lexicalLocalReference; synthesized attribute warnEqdef :: Boolean occurs on CmdArgs; @@ -25,7 +26,7 @@ Either ::= args::[String] } aspect production synthesizedAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { local exportedBy :: [String] = if top.frame.hasPartialSignature @@ -48,14 +49,21 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated } aspect production inheritedAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { local exportedBy :: [String] = case dl of -- Exported by the declaration of the thing we're giving inh to, or to the occurs | localDefLHS(q) -> [q.lookupValue.dcl.sourceGrammar, attr.dcl.sourceGrammar] -- For rhs or forwards, that's the production. - | _ -> [top.frame.sourceGrammar, attr.dcl.sourceGrammar] + | childDefLHS(_) -> [top.frame.sourceGrammar, attr.dcl.sourceGrammar] + | forwardDefLHS(_) -> [top.frame.sourceGrammar, attr.dcl.sourceGrammar] + -- Eqs on translation attributes can be with the thing we're giving inh to, or either attr occurs + | localTransAttrDefLHS(q, transAttr) -> + [q.lookupValue.dcl.sourceGrammar, transAttr.dcl.sourceGrammar, attr.dcl.sourceGrammar] + | childTransAttrDefLHS(_, transAttr) -> + [top.frame.sourceGrammar, transAttr.dcl.sourceGrammar, attr.dcl.sourceGrammar] + | _ -> [] end; top.errors <- @@ -67,32 +75,16 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated else []; top.errors <- - if length(dl.lookupEqDefLHS) > 1 || contains(dl.defLHSattr.attrDcl.fullName, getMinRefSet(dl.typerep, top.env)) + if length(dl.lookupEqDefLHS) > 1 || contains(dl.inhAttrName, getMinRefSet(dl.typerep, top.env)) then [mwdaWrn(top.config, top.location, "Duplicate equation for " ++ attr.name ++ " on " ++ dl.name ++ " in production " ++ top.frame.fullName)] else []; - - -- Check that if there is a partially decorated reference taken to this decoration site, - -- we aren't defining an equation that isn't in that reference type (Decorated Foo with only {...}). - top.errors <- - if dl.found && attr.found - && top.config.warnEqdef - then flatMap( - \ refSite::(String, Location, [String]) -> - if contains(attr.attrDcl.fullName, refSite.3) then [] - else [mwdaWrn(top.config, top.location, "Attribute " ++ attr.name ++ " with an equation on " ++ dl.name ++ " is not in the partially decorated reference taken at " ++ refSite.1 ++ ":" ++ refSite.2.unparse ++ " with only " ++ implode(", ", refSite.3))], - case dl of - | childDefLHS(q) -> getPartialRefs(top.frame.fullName, q.lookupValue.fullName, top.flowEnv) - | localDefLHS(q) -> getPartialRefs(top.frame.fullName, q.lookupValue.fullName, top.flowEnv) - | _ -> [] - end) - else []; } --- FROM COLLECTIONS aspect production synBaseColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { local exportedBy :: [String] = if top.frame.hasPartialSignature @@ -114,14 +106,21 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated else []; } aspect production inhBaseColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { local exportedBy :: [String] = case dl of -- Exported by the declaration of the thing we're giving inh to, or to the occurs | localDefLHS(q) -> [q.lookupValue.dcl.sourceGrammar, attr.dcl.sourceGrammar] -- For rhs or forwards, that's the production. - | _ -> [top.frame.sourceGrammar, attr.dcl.sourceGrammar] + | childDefLHS(_) -> [top.frame.sourceGrammar, attr.dcl.sourceGrammar] + | forwardDefLHS(_) -> [top.frame.sourceGrammar, attr.dcl.sourceGrammar] + -- Eqs on translation attributes can be with the thing we're giving inh to, or either attr occurs + | localTransAttrDefLHS(q, transAttr) -> + [q.lookupValue.dcl.sourceGrammar, transAttr.dcl.sourceGrammar, attr.dcl.sourceGrammar] + | childTransAttrDefLHS(_, transAttr) -> + [top.frame.sourceGrammar, transAttr.dcl.sourceGrammar, attr.dcl.sourceGrammar] + | _ -> [] end; top.errors <- @@ -133,25 +132,9 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated else []; top.errors <- - if length(dl.lookupEqDefLHS) > 1 || contains(dl.defLHSattr.attrDcl.fullName, getMinRefSet(dl.typerep, top.env)) + if length(dl.lookupEqDefLHS) > 1 || contains(dl.inhAttrName, getMinRefSet(dl.typerep, top.env)) then [mwdaWrn(top.config, top.location, "Duplicate equation for " ++ attr.name ++ " on " ++ dl.name ++ " in production " ++ top.frame.fullName)] else []; - - -- Check that if there is a partially decorated reference taken to this decoration site, - -- we aren't defining an equation that isn't in that reference type (Decorated Foo with only {...}). - top.errors <- - if dl.found && attr.found - && top.config.warnEqdef - then flatMap( - \ refSite::(String, Location, [String]) -> - if contains(attr.attrDcl.fullName, refSite.3) then [] - else [mwdaWrn(top.config, top.location, "Attribute " ++ attr.name ++ " with an equation for " ++ dl.name ++ " is not in the partially decorated reference taken at " ++ refSite.1 ++ ":" ++ refSite.2.unparse ++ " with only " ++ implode(", ", refSite.3))], - case dl of - | childDefLHS(q) -> getPartialRefs(top.frame.fullName, q.lookupValue.fullName, top.flowEnv) - | localDefLHS(q) -> getPartialRefs(top.frame.fullName, q.lookupValue.fullName, top.flowEnv) - | _ -> [] - end) - else []; } aspect production exprLhsExpr @@ -164,97 +147,6 @@ top::ExprLHSExpr ::= attr::QNameAttrOccur else []; } --- These checks live here for now, since they are related to duplicate equations: -aspect production childReference -top::Expr ::= q::PartiallyDecorated QName -{ - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - local partialRefs::[(String, Location, [String])] = getPartialRefs(top.frame.fullName, q.lookupValue.fullName, top.flowEnv); - top.errors <- - case finalTy, refSet of - | partiallyDecoratedType(_, _), just(inhs) when top.config.warnEqdef && q.lookupValue.found -> - case getMaxRefSet(q.lookupValue.typeScheme.typerep, top.env) of - | just(origInhs) -> - if all(map(contains(_, inhs), origInhs)) then [] - else [mwdaWrn(top.config, top.location, s"Partially decorated reference of type ${prettyType(finalTy)} does not contain all attributes in the reference set of ${q.name}'s type ${prettyType(q.lookupValue.typeScheme.monoType)}")] - | nothing() -> [mwdaWrn(top.config, top.location, s"Cannot take a partially decorated reference to ${q.name} of type ${prettyType(q.lookupValue.typeScheme.monoType)}, as the reference set is not bounded")] - end ++ - -- Check that we are exported by the decoration site. - if q.lookupValue.found && top.config.warnEqdef - && !isExportedBy(top.grammarName, [q.lookupValue.dcl.sourceGrammar], top.compiledGrammars) - then [mwdaWrn(top.config, top.location, s"Orphaned partially decorated reference to ${q.lookupValue.fullName} in production ${top.frame.fullName} (reference has type ${prettyType(finalTy)}).")] - -- Check that there is at most one partial reference taken to this decoration site. - -- TODO: This check isn't actually sufficent for well-definedness (e.g. wrapping this ref in - -- a term and decorating that more than once), need some sort of "linearity analysis". - else if length(partialRefs) > 1 - then [mwdaWrn(top.config, top.location, s"Multiple partially decorated references taken to ${q.name} in production ${top.frame.fullName} (reference has type ${prettyType(finalTy)}).")] - else [] - | _, _ -> [] - end; -} -aspect production localReference -top::Expr ::= q::PartiallyDecorated QName -{ - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - local partialRefs::[(String, Location, [String])] = getPartialRefs(top.frame.fullName, q.lookupValue.fullName, top.flowEnv); - top.errors <- - case finalTy, refSet of - | partiallyDecoratedType(_, _), just(inhs) when top.config.warnEqdef && q.lookupValue.found -> - case getMaxRefSet(q.lookupValue.typeScheme.typerep, top.env) of - | just(origInhs) -> - if all(map(contains(_, inhs), origInhs)) then [] - else [mwdaWrn(top.config, top.location, s"Partially decorated reference of type ${prettyType(finalTy)} does not contain all attributes in the reference set of ${q.name}'s type ${prettyType(q.lookupValue.typeScheme.monoType)}")] - | nothing() -> [mwdaWrn(top.config, top.location, s"Cannot take a partially decorated reference to ${q.name} of type ${prettyType(q.lookupValue.typeScheme.monoType)}, as the reference set is not bounded")] - end ++ - -- Check that we are exported by the decoration site/ - if q.lookupValue.found && top.config.warnEqdef - && !isExportedBy(top.grammarName, [q.lookupValue.dcl.sourceGrammar], top.compiledGrammars) - then [mwdaWrn(top.config, top.location, s"Orphaned partially decorated reference to ${q.lookupValue.fullName} in production ${top.frame.fullName} (reference has type ${prettyType(finalTy)}).")] - -- Check that there is at most one partial reference taken to this decoration site. - -- TODO: This check isn't actually sufficent for well-definedness (e.g. wrapping this ref in - -- a term and decorating that more than once), need some sort of "linearity analysis". - else if length(partialRefs) > 1 - then [mwdaWrn(top.config, top.location, s"Multiple partially decorated references taken to ${q.name} in production ${top.frame.fullName} (reference has type ${prettyType(finalTy)}).")] - else [] - | _, _ -> [] - end; -} -aspect production lhsReference -top::Expr ::= q::PartiallyDecorated QName -{ - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - top.errors <- - case finalTy of - | partiallyDecoratedType(_, _) when top.config.warnEqdef -> - [mwdaWrn(top.config, top.location, s"Cannot take a partially decorated reference of type ${prettyType(finalTy)} to ${q.name}.")] - | _ -> [] - end; -} -aspect production forwardReference -top::Expr ::= q::PartiallyDecorated QName -{ - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - top.errors <- - case finalTy of - | partiallyDecoratedType(_, _) when top.config.warnEqdef -> - [mwdaWrn(top.config, top.location, s"Cannot take a partially decorated reference of type ${prettyType(finalTy)} to the forward tree.")] - | _ -> [] - end; -} -aspect production lexicalLocalReference -top::Expr ::= q::PartiallyDecorated QName fi::ExprVertexInfo fd::[FlowVertex] -{ - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - top.errors <- - case finalTy, q.lookupValue.typeScheme.monoType of - | partiallyDecoratedType(_, _), partiallyDecoratedType(_, _) -> [] -- TODO: Need linearity analysis... - | partiallyDecoratedType(_, _), _ when top.config.warnEqdef -> - [mwdaWrn(top.config, top.location, s"${q.name} was not bound as a partially decorated reference, but here it is used with type ${prettyType(finalTy)}.")] - | _, _ -> [] - end; -} - - --- For our DefLHSs: {-- @@ -266,15 +158,20 @@ flowtype lookupEqDefLHS {decorate} on DefLHS; aspect lookupEqDefLHS on top::DefLHS of -- prod, child, attr | childDefLHS(q) -> lookupInh(top.frame.fullName, q.lookupValue.fullName, top.defLHSattr.attrDcl.fullName, top.flowEnv) + -- prod, child, trans attr, attr +| childTransAttrDefLHS(q, attr) -> lookupInh(top.frame.fullName, q.lookupValue.fullName, s"${attr.attrDcl.fullName}.${top.defLHSattr.attrDcl.fullName}", top.flowEnv) -- prod, attr | lhsDefLHS(q) -> lookupSyn(top.frame.fullName, top.defLHSattr.attrDcl.fullName, top.flowEnv) -- prod, local, attr | localDefLHS(q) -> lookupLocalInh(top.frame.fullName, q.lookupValue.fullName, top.defLHSattr.attrDcl.fullName, top.flowEnv) + -- prod, local, trans attr, attr +| localTransAttrDefLHS(q, attr) -> lookupLocalInh(top.frame.fullName, q.lookupValue.fullName, s"${attr.attrDcl.fullName}.${top.defLHSattr.attrDcl.fullName}", top.flowEnv) -- prod, attr | forwardDefLHS(q) -> lookupFwdInh(top.frame.fullName, top.defLHSattr.attrDcl.fullName, top.flowEnv) -- nt, attr | defaultLhsDefLHS(q) -> lookupDef(top.frame.lhsNtName, top.defLHSattr.attrDcl.fullName, top.flowEnv) | errorDefLHS(q) -> [] +| errorTransAttrDefLHS(_, _) -> [] | parserAttributeDefLHS(q) -> [] -- TODO: maybe error? end; diff --git a/grammars/silver/compiler/analysis/warnings/flow/OrphanedOccurs.sv b/grammars/silver/compiler/analysis/warnings/flow/OrphanedOccurs.sv index 9bd5d912b..e28d3523d 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/OrphanedOccurs.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/OrphanedOccurs.sv @@ -25,12 +25,6 @@ Either ::= args::[String] aspect production attributionDcl top::AGDcl ::= 'attribute' at::QName attl::BracketedOptTypeExprs 'occurs' 'on' nt::QName nttl::BracketedOptTypeExprs ';' { - local isClosedNt :: Boolean = - case nt.lookupType.dcls of - | ntDcl(_, _, closed, _) :: _ -> closed - | _ -> false -- default, if the lookup fails - end; - top.errors <- if nt.lookupType.found && at.lookupAttribute.found && top.config.warnOrphaned @@ -40,7 +34,7 @@ top::AGDcl ::= 'attribute' at::QName attl::BracketedOptTypeExprs 'occurs' 'on' n else []; top.errors <- - if !nt.lookupType.found || !at.lookupAttribute.found || !isClosedNt || !at.lookupAttribute.dcl.isSynthesized then [] + if !nt.lookupType.found || !at.lookupAttribute.found || !nt.lookupType.dcl.isClosed || !at.lookupAttribute.dcl.isSynthesized then [] -- For closed nt, either we're exported by only the nt, OR there MUST be a default! else if !isExportedBy(top.grammarName, [nt.lookupType.dcl.sourceGrammar], top.compiledGrammars) && null(lookupDef(nt.lookupType.fullName, at.lookupAttribute.fullName, top.flowEnv)) diff --git a/grammars/silver/compiler/analysis/warnings/flow/OrphanedProduction.sv b/grammars/silver/compiler/analysis/warnings/flow/OrphanedProduction.sv index f097489ff..c89ee9ae2 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/OrphanedProduction.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/OrphanedProduction.sv @@ -30,7 +30,7 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr local isClosedNt :: Boolean = case getTypeDclAll(namedSig.outputElement.typerep.typeName, top.env) of - | ntDcl(_, _, closed, _) :: _ -> closed + | ntDcl(_, _, _, closed, _) :: _ -> closed | _ -> false -- default, if the lookup fails end; @@ -38,7 +38,7 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr if null(body.errors ++ ns.errors) && top.config.warnFwd -- If this production does not forward - && null(body.uniqueSignificantExpression) + && null(body.forwardExpr) -- AND this is not a closed nonterminal && !isClosedNt -- AND this production is not exported by the nonterminal definition grammar... even including options diff --git a/grammars/silver/compiler/definition/concrete_syntax/NonTerminalDcl.sv b/grammars/silver/compiler/definition/concrete_syntax/NonTerminalDcl.sv index 1be9d45ea..c85af5cb1 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/NonTerminalDcl.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/NonTerminalDcl.sv @@ -17,7 +17,7 @@ top::AGDcl ::= quals::NTDeclQualifiers 'nonterminal' id::Name tl::BracketedOptTy top.syntaxAst := [ syntaxNonterminal( - nonterminalType(fName, map((.kindrep), tl.types), isThisTracked), + nonterminalType(fName, map((.kindrep), tl.types), quals.data, isThisTracked), nilSyntax(), exportedProds, exportedLayoutTerms, foldr(consNonterminalMod, nilNonterminalMod(), nm.nonterminalModifiers), location=top.location, sourceGrammar=top.grammarName) diff --git a/grammars/silver/compiler/definition/concrete_syntax/ParserSpec.sv b/grammars/silver/compiler/definition/concrete_syntax/ParserSpec.sv index 6f6039f7f..8e7e5088c 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ParserSpec.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ParserSpec.sv @@ -60,14 +60,14 @@ top::ParserSpec ::= production componentGrammarMarkingTerminals::[Pair] = map( \ g::String -> - pair(g, + (g, foldr(consSyntax, nilSyntax(), moduleExportedDefs(top.location, top.compiledGrammars, deps, [g], []).syntaxAst).allMarkingTerminals), grams); production markingTerminalPrefixes::[Pair] = flatMap( \ gp::Pair -> - map(pair(_, gp.snd), lookup(gp.fst, componentGrammarMarkingTerminals).fromJust), + map(pair(fst=_, snd=gp.snd), lookup(gp.fst, componentGrammarMarkingTerminals).fromJust), grammarTerminalPrefixes); top.cstAst = diff --git a/grammars/silver/compiler/definition/concrete_syntax/ProductionDcl.sv b/grammars/silver/compiler/definition/concrete_syntax/ProductionDcl.sv index 854d35249..ae4350d02 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ProductionDcl.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ProductionDcl.sv @@ -2,12 +2,13 @@ grammar silver:compiler:definition:concrete_syntax; import silver:compiler:modification:copper only actionDefs; -autocopy attribute productionSig :: NamedSignature; +inherited attribute productionSig :: NamedSignature; concrete production concreteProductionDcl top::AGDcl ::= 'concrete' 'production' id::Name ns::ProductionSignature pm::ProductionModifiers body::ProductionBody { - top.unparse = "concrete production " ++ id.unparse ++ "\n" ++ ns.unparse ++ " " ++ pm.unparse ++ "\n" ++ body.unparse; + top.unparse = "concrete production " ++ id.unparse ++ "\n" ++ ns.unparse ++ " " ++ pm.unparse ++ "\n" ++ body.unparse; + propagate config, grammarName, compiledGrammars; production fName :: String = top.grammarName ++ ":" ++ id.name; production namedSig :: NamedSignature = ns.namedSignature; @@ -39,7 +40,8 @@ closed nonterminal ProductionModifier with config, location, unparse, production monoid attribute productionModifiers :: [SyntaxProductionModifier]; propagate productionModifiers on ProductionModifiers, ProductionModifierList; -propagate errors on ProductionModifiers, ProductionModifierList, ProductionModifier; +propagate config, errors, env, productionSig + on ProductionModifiers, ProductionModifierList, ProductionModifier; concrete production productionModifiersNone top::ProductionModifiers ::= @@ -103,9 +105,9 @@ top::ProductionSignature ::= cl::ConstraintList '=>' lhs::ProductionLHS '::=' rh local lstType :: Type = last(top.namedSignature.inputElements).typerep; local checkFirst :: Boolean = - fstType.isTerminal || !null(getOccursDcl("silver:core:location", fstType.typeName, top.env)) || fstType.tracked; + fstType.isTerminal || !null(getOccursDcl("silver:core:location", fstType.typeName, top.env)) || fstType.isTracked; local checkSecond :: Boolean = - lstType.isTerminal || !null(getOccursDcl("silver:core:location", lstType.typeName, top.env)) || lstType.tracked; + lstType.isTerminal || !null(getOccursDcl("silver:core:location", lstType.typeName, top.env)) || lstType.isTracked; local errFirst :: [Message] = if checkFirst then [] else [err(top.location, "Production has location annotation or is tracked, but first element of signature does not have location and is not tracked.")]; local errSecond :: [Message] = @@ -116,7 +118,7 @@ top::ProductionSignature ::= cl::ConstraintList '=>' lhs::ProductionLHS '::=' rh | [namedSignatureElement("silver:core:location", _)] -> true | _ -> false end; - local lhsHasOrigin :: Boolean = top.namedSignature.outputElement.typerep.tracked; + local lhsHasOrigin :: Boolean = top.namedSignature.outputElement.typerep.isTracked; top.concreteSyntaxTypeErrors <- case top.namedSignature.namedInputElements of @@ -152,7 +154,7 @@ top::Type ::= } aspect production nonterminalType -top::Type ::= fn::String ks::[Kind] tracked::Boolean +top::Type ::= fn::String ks::[Kind] data::Boolean tracked::Boolean { top.permittedInConcreteSyntax = null(ks); } diff --git a/grammars/silver/compiler/definition/concrete_syntax/Project.sv b/grammars/silver/compiler/definition/concrete_syntax/Project.sv index af6d048cd..03ba818ef 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/Project.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/Project.sv @@ -7,6 +7,7 @@ imports silver:compiler:definition:type:syntax; imports silver:compiler:definition:env; imports silver:compiler:definition:type; +imports silver:compiler:definition:flow:env; imports silver:compiler:definition:concrete_syntax:ast; diff --git a/grammars/silver/compiler/definition/concrete_syntax/TerminalDcl.sv b/grammars/silver/compiler/definition/concrete_syntax/TerminalDcl.sv index 879e2bb3d..1daeab44a 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/TerminalDcl.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/TerminalDcl.sv @@ -10,6 +10,7 @@ terminal Named_kwd 'named' lexer classes {MODIFIER}; terminal Left_kwd 'left' lexer classes {MODIFIER}; terminal Association_kwd 'association' lexer classes {MODIFIER}; terminal Right_kwd 'right' lexer classes {MODIFIER}; +terminal None_kwd 'none' lexer classes {MODIFIER}; terminal RepeatProb_kwd 'repeatProb' lexer classes {MODIFIER}; -- For use by the treegen extension -- We actually need to reserved this due to its appearance in PRODUCTION modifiers. @@ -41,7 +42,7 @@ top::AGDcl ::= t::TerminalKeywordModifier id::Name r::RegExpr tm::TerminalModifi then [wrn(r.location, "Regex contains '\\n' but not '\\r'. This is your reminder about '\\r\\n' newlines.")] else []; - propagate errors; + propagate config, grammarName, compiledGrammars, env, errors; top.syntaxAst := [ syntaxTerminal(fName, r.terminalRegExprSpec, @@ -126,7 +127,8 @@ closed nonterminal TerminalModifier with config, location, unparse, terminalModi monoid attribute terminalModifiers :: [SyntaxTerminalModifier]; monoid attribute genRepeatProb :: Maybe with nothing(), orElse; -propagate terminalModifiers, genRepeatProb, errors on TerminalModifiers; +propagate config, grammarName, compiledGrammars, flowEnv, terminalModifiers, genRepeatProb, errors, env + on TerminalModifiers; aspect default production top::TerminalModifier ::= @@ -166,6 +168,14 @@ top::TerminalModifier ::= 'association' '=' 'right' top.terminalModifiers := [termAssociation("right")]; top.errors := []; } +concrete production terminalModifierNone +top::TerminalModifier ::= 'association' '=' 'none' +{ + top.unparse = "association = none"; + + top.terminalModifiers := [termAssociation("none")]; + top.errors := []; +} concrete production terminalModifierPrecedence top::TerminalModifier ::= 'precedence' '=' i::Int_t diff --git a/grammars/silver/compiler/definition/concrete_syntax/ast/CstAst.sv b/grammars/silver/compiler/definition/concrete_syntax/ast/CstAst.sv index 13862b9a0..0ee0f1973 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ast/CstAst.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ast/CstAst.sv @@ -45,7 +45,7 @@ top::SyntaxRoot ::= g:toList( g:transitiveClosure( g:add( - map(\ p::Pair -> pair(p.snd, p.fst), s.superClassContribs), + map(\ p::Pair -> (p.snd, p.fst), s.superClassContribs), g:empty())))); s.parserAttributeAspects = directBuildTree(s.parserAttributeAspectContribs); s.layoutTerms = @@ -163,12 +163,12 @@ EnvTree ::= allTerms::[String] layoutItems::[String] layoutContribs::[Pa local layoutTerms::[Pair] = map( \ item::String -> - pair(item, s:toList(s:intersect(terms, g:edgesFrom(item, transitiveLayout)))), + (item, s:toList(s:intersect(terms, g:edgesFrom(item, transitiveLayout)))), layoutItems); -- Build the layout EnvTree return directBuildTree( flatMap( - \ item::Pair -> map(pair(item.fst, _), item.snd), + \ item::Pair -> map(pair(fst=item.fst, snd=_), item.snd), layoutTerms)); } diff --git a/grammars/silver/compiler/definition/concrete_syntax/ast/LexerClassModifiers.sv b/grammars/silver/compiler/definition/concrete_syntax/ast/LexerClassModifiers.sv index 8b13273d2..37505615a 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ast/LexerClassModifiers.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ast/LexerClassModifiers.sv @@ -7,14 +7,18 @@ import silver:util:treemap as tm; -- monoid attribute submits_ :: [Decorated SyntaxDcl]; -- synthesized attribute prefixSeperator :: Maybe; -autocopy attribute className :: String; +inherited attribute className :: String; {-- - Modifiers for lexer classes. -} -nonterminal SyntaxLexerClassModifiers with compareTo, isEqual, cstEnv, cstErrors, className, classTerminals, superClasses, subClasses, superClassContribs, disambiguationClasses, prefixSeperator, containingGrammar, dominates_, submits_; +nonterminal SyntaxLexerClassModifiers with + compareTo, isEqual, cstEnv, cstErrors, className, classTerminals, superClasses, subClasses, superClassContribs, + disambiguationClasses, prefixSeperator, containingGrammar, dominates_, submits_; -propagate compareTo, isEqual, cstErrors, superClassContribs, disambiguationClasses, prefixSeperator, dominates_, submits_ +propagate + compareTo, isEqual, cstEnv, cstErrors, className, classTerminals, superClasses, subClasses, superClassContribs, + disambiguationClasses, prefixSeperator, containingGrammar, dominates_, submits_ on SyntaxLexerClassModifiers; abstract production consLexerClassMod @@ -35,9 +39,13 @@ top::SyntaxLexerClassModifiers ::= {-- - Modifiers for lexer classes. -} -closed nonterminal SyntaxLexerClassModifier with location, sourceGrammar, compareTo, isEqual, cstEnv, cstErrors, className, classTerminals, superClasses, subClasses, superClassContribs, disambiguationClasses, prefixSeperator, containingGrammar, dominates_, submits_; +closed nonterminal SyntaxLexerClassModifier with location, sourceGrammar, + compareTo, isEqual, cstEnv, cstErrors, className, classTerminals, superClasses, subClasses, superClassContribs, + disambiguationClasses, prefixSeperator, containingGrammar, dominates_, submits_; -propagate compareTo, isEqual on SyntaxLexerClassModifier; +propagate + compareTo, isEqual, cstEnv, className, classTerminals, superClasses, subClasses, containingGrammar + on SyntaxLexerClassModifier; {- We default ALL attributes, so we can focus only on those that are interesting in each case... -} aspect default production @@ -58,7 +66,7 @@ top::SyntaxLexerClassModifier ::= super::[String] -- included in the parser. See https://github.com/melt-umn/silver/issues/694 production superRefs :: [Decorated SyntaxDcl] = concat(lookupStrings(super, top.cstEnv)); - top.superClassContribs := map(pair(top.className, _), map((.fullName), superRefs)); + top.superClassContribs := map(pair(fst=top.className, snd=_), map((.fullName), superRefs)); } {-- @@ -74,7 +82,7 @@ top::SyntaxLexerClassModifier ::= sub::[String] if !null(a.snd) then [] else ["Terminal / Lexer Class " ++ a.fst ++ " was referenced but " ++ "this grammar was not included in this parser. (Referenced from submit clause for lexer class)"], --TODO: come up with a way to reference a given lexer class (line numbers would be great) - zipWith(pair, sub, subRefs)); + zip(sub, subRefs)); top.submits_ := map(head, subRefs); } @@ -91,7 +99,7 @@ top::SyntaxLexerClassModifier ::= dom::[String] if !null(a.snd) then [] else ["Terminal / Lexer Class " ++ a.fst ++ " was referenced but " ++ "this grammar was not included in this parser. (Referenced from dominates clause for lexer class)"], - zipWith(pair, dom, domRefs)); + zip(dom, domRefs)); top.dominates_ := map(head, domRefs); } diff --git a/grammars/silver/compiler/definition/concrete_syntax/ast/NonterminalModifiers.sv b/grammars/silver/compiler/definition/concrete_syntax/ast/NonterminalModifiers.sv index a68e6a60a..01b87b40d 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ast/NonterminalModifiers.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ast/NonterminalModifiers.sv @@ -8,7 +8,7 @@ imports silver:compiler:definition:core only nonterminalName; nonterminal SyntaxNonterminalModifiers with compareTo, isEqual, cstEnv, cstErrors, customLayout, nonterminalName; -propagate compareTo, isEqual, cstErrors, customLayout on SyntaxNonterminalModifiers; +propagate compareTo, isEqual, cstEnv, cstErrors, customLayout, nonterminalName on SyntaxNonterminalModifiers; abstract production consNonterminalMod top::SyntaxNonterminalModifiers ::= h::SyntaxNonterminalModifier t::SyntaxNonterminalModifiers @@ -45,7 +45,7 @@ top::SyntaxNonterminalModifier ::= terms::[String] if !null(a.snd) then [] else ["Terminal " ++ a.fst ++ " was referenced but " ++ "this grammar was not included in this parser. (Referenced from layout clause on nonterminal " ++ top.nonterminalName ++ ")"], - zipWith(pair, terms, termRefs)); + zip(terms, termRefs)); top.customLayout := just(terms); } diff --git a/grammars/silver/compiler/definition/concrete_syntax/ast/ProductionModifiers.sv b/grammars/silver/compiler/definition/concrete_syntax/ast/ProductionModifiers.sv index a8f17f5a9..3cd1aaece 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ast/ProductionModifiers.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ast/ProductionModifiers.sv @@ -10,9 +10,11 @@ monoid attribute productionOperator :: Maybe with nothing() {-- - Modifiers for productions. -} -nonterminal SyntaxProductionModifiers with compareTo, isEqual, cstEnv, cstErrors, acode, productionPrecedence, customLayout, productionOperator, productionSig; +nonterminal SyntaxProductionModifiers with + compareTo, isEqual, cstEnv, cstErrors, acode, productionPrecedence, customLayout, productionOperator, productionSig; -propagate compareTo, isEqual, cstErrors, acode, productionPrecedence, customLayout, productionOperator +propagate + compareTo, isEqual, cstEnv, cstErrors, acode, productionPrecedence, customLayout, productionOperator, productionSig on SyntaxProductionModifiers; abstract production consProductionMod @@ -27,9 +29,10 @@ top::SyntaxProductionModifiers ::= {-- - Modifiers for productions. -} -nonterminal SyntaxProductionModifier with compareTo, isEqual, cstEnv, cstErrors, acode, productionPrecedence, customLayout, productionOperator, productionSig; +nonterminal SyntaxProductionModifier with + compareTo, isEqual, cstEnv, cstErrors, acode, productionPrecedence, customLayout, productionOperator, productionSig; -propagate compareTo, isEqual on SyntaxProductionModifier; +propagate compareTo, isEqual, cstEnv, productionSig on SyntaxProductionModifier; aspect default production top::SyntaxProductionModifier ::= @@ -80,7 +83,7 @@ top::SyntaxProductionModifier ::= terms::[String] if !null(a.snd) then [] else ["Terminal " ++ a.fst ++ " was referenced but " ++ "this grammar was not included in this parser. (Referenced from layout clause on production " ++ top.productionSig.fullName ++ ")"], - zipWith(pair, terms, termRefs)); + zip(terms, termRefs)); top.customLayout := just(terms); } diff --git a/grammars/silver/compiler/definition/concrete_syntax/ast/Syntax.sv b/grammars/silver/compiler/definition/concrete_syntax/ast/Syntax.sv index bd064c163..6d16f3075 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ast/Syntax.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ast/Syntax.sv @@ -7,24 +7,24 @@ import silver:util:treeset as s; -- For looking syntax elements up by name. monoid attribute cstDcls :: [Pair]; -autocopy attribute cstEnv :: EnvTree; +inherited attribute cstEnv :: EnvTree; monoid attribute cstErrors :: [String]; -- Transformation that moves productions underneath their respective nonterminals. monoid attribute cstProds :: [Pair]; -autocopy attribute cstNTProds :: EnvTree; +inherited attribute cstNTProds :: EnvTree; monoid attribute cstNormalize :: [SyntaxDcl]; -- Compute and allow lookup of all terminals in a lexer class monoid attribute classTerminalContribs::[Pair]; -autocopy attribute classTerminals::EnvTree; +inherited attribute classTerminals::EnvTree; monoid attribute superClassContribs::[Pair]; -autocopy attribute superClasses::EnvTree; -autocopy attribute subClasses::EnvTree; +inherited attribute superClasses::EnvTree; +inherited attribute subClasses::EnvTree; -- Parser attribute action code aspects monoid attribute parserAttributeAspectContribs::[Pair]; -autocopy attribute parserAttributeAspects::EnvTree; +inherited attribute parserAttributeAspects::EnvTree; -- TODO: Attributes that lift out various sorts of SyntaxDcls all extract references -- of type Decorated SyntaxDcl. The actual set of attributes needed for translation @@ -45,21 +45,21 @@ synthesized attribute subContribs :: [Decorated SyntaxDcl]; monoid attribute memberTerminals :: [Decorated SyntaxDcl]; monoid attribute dominatingTerminalContribs :: [(String, Decorated SyntaxDcl)]; synthesized attribute terminalRegex::Regex; -autocopy attribute containingGrammar :: String; +inherited attribute containingGrammar :: String; monoid attribute lexerClassRefDcls :: String; synthesized attribute exportedProds :: [String]; synthesized attribute hasCustomLayout :: Boolean; monoid attribute layoutContribs :: [Pair]; -- prod/nt name, prod/nt/term name -autocopy attribute layoutTerms::EnvTree; +inherited attribute layoutTerms::EnvTree; -autocopy attribute prefixesForTerminals :: EnvTree; -autocopy attribute componentGrammarMarkingTerminals :: EnvTree<[String]>; +inherited attribute prefixesForTerminals :: EnvTree; +inherited attribute componentGrammarMarkingTerminals :: EnvTree<[String]>; -- Creating unambiguous s; this is a multiset used to accumulate all the -- names for terminals, and the actual name for will be modified to -- disambiguate if it would be ambiguous. monoid attribute prettyNamesAccum::[Pair]; -autocopy attribute prettyNames::tm:Map; +inherited attribute prettyNames::tm:Map; synthesized attribute copperElementReference::copper:ElementReference; synthesized attribute copperGrammarElements::[copper:GrammarElement]; @@ -67,12 +67,26 @@ synthesized attribute copperGrammarElements::[copper:GrammarElement]; {-- - An abstract syntax tree for representing concrete syntax. -} -nonterminal Syntax with compareTo, isEqual, cstDcls, cstEnv, cstErrors, cstProds, cstNTProds, cstNormalize, allTerminals, allIgnoreTerminals, allMarkingTerminals, allProductions, allProductionNames, allNonterminals, disambiguationClasses, memberTerminals, dominatingTerminalContribs, classTerminalContribs, classTerminals, superClassContribs, superClasses, subClasses, parserAttributeAspectContribs, parserAttributeAspects, lexerClassRefDcls, layoutContribs, layoutTerms, containingGrammar, prefixesForTerminals, componentGrammarMarkingTerminals, prettyNamesAccum, prettyNames, copperGrammarElements; -propagate compareTo, isEqual on Syntax; - -flowtype decorate {cstEnv, classTerminals, superClasses, subClasses, containingGrammar, layoutTerms, prefixesForTerminals, componentGrammarMarkingTerminals, parserAttributeAspects, prettyNames} on Syntax, SyntaxDcl; - -propagate cstDcls, cstErrors, cstProds, cstNormalize, allTerminals, allIgnoreTerminals, allMarkingTerminals, allProductions, allProductionNames, allNonterminals, disambiguationClasses, memberTerminals, dominatingTerminalContribs, classTerminalContribs, superClassContribs, parserAttributeAspectContribs, lexerClassRefDcls, layoutContribs, prettyNamesAccum +nonterminal Syntax with + compareTo, isEqual, cstDcls, cstEnv, cstErrors, cstProds, cstNTProds, cstNormalize, + allTerminals, allIgnoreTerminals, allMarkingTerminals, allProductions, allProductionNames, allNonterminals, + disambiguationClasses, memberTerminals, dominatingTerminalContribs, classTerminalContribs, classTerminals, + superClassContribs, superClasses, subClasses, parserAttributeAspectContribs, parserAttributeAspects, + lexerClassRefDcls, layoutContribs, layoutTerms, containingGrammar, prefixesForTerminals, componentGrammarMarkingTerminals, + prettyNamesAccum, prettyNames, copperGrammarElements; + +flowtype decorate { + cstEnv, classTerminals, superClasses, subClasses, containingGrammar, + layoutTerms, prefixesForTerminals, componentGrammarMarkingTerminals, parserAttributeAspects, prettyNames +} on Syntax, SyntaxDcl; + +propagate + compareTo, isEqual, cstDcls, cstEnv, cstErrors, cstProds, cstNTProds, cstNormalize, + allTerminals, allIgnoreTerminals, allMarkingTerminals, allProductions, allProductionNames, allNonterminals, + disambiguationClasses, memberTerminals, dominatingTerminalContribs, classTerminalContribs, classTerminals, + superClassContribs, superClasses, subClasses, parserAttributeAspectContribs, parserAttributeAspects, + lexerClassRefDcls, layoutContribs, layoutTerms, containingGrammar, prefixesForTerminals, componentGrammarMarkingTerminals, + prettyNamesAccum, prettyNames on Syntax; abstract production nilSyntax @@ -90,11 +104,21 @@ top::Syntax ::= s1::SyntaxDcl s2::Syntax {-- - An individual declaration of a concrete syntax element. -} -closed nonterminal SyntaxDcl with location, sourceGrammar, compareTo, isEqual, cstDcls, cstEnv, cstErrors, cstProds, cstNTProds, cstNormalize, fullName, sortKey, allTerminals, allIgnoreTerminals, allMarkingTerminals, allProductions, allProductionNames, allNonterminals, disambiguationClasses, memberTerminals, dominatingTerminalContribs, classTerminalContribs, classTerminals, superClassContribs, superClasses, subClasses, parserAttributeAspectContribs, parserAttributeAspects, lexerClassRefDcls, exportedProds, hasCustomLayout, layoutContribs, layoutTerms, domContribs, subContribs, terminalRegex, prefixSeperator, containingGrammar, prefixesForTerminals, componentGrammarMarkingTerminals, prettyNamesAccum, prettyNames, copperElementReference, copperGrammarElements; +closed nonterminal SyntaxDcl with location, sourceGrammar, + compareTo, isEqual, cstDcls, cstEnv, cstErrors, cstProds, cstNTProds, cstNormalize, + fullName, sortKey, allTerminals, allIgnoreTerminals, allMarkingTerminals, allProductions, allProductionNames, allNonterminals, + disambiguationClasses, memberTerminals, dominatingTerminalContribs, classTerminalContribs, classTerminals, + superClassContribs, superClasses, subClasses, parserAttributeAspectContribs, parserAttributeAspects, + lexerClassRefDcls, exportedProds, hasCustomLayout, layoutContribs, layoutTerms, + domContribs, subContribs, terminalRegex, prefixSeperator, containingGrammar, prefixesForTerminals, componentGrammarMarkingTerminals, + prettyNamesAccum, prettyNames, copperElementReference, copperGrammarElements; synthesized attribute sortKey :: String; -propagate compareTo, isEqual, cstErrors, prefixSeperator on SyntaxDcl; +propagate + compareTo, isEqual, cstEnv, cstErrors, cstNTProds, containingGrammar, layoutTerms, prettyNames, prefixSeperator, + classTerminals, parserAttributeAspects, prefixesForTerminals, componentGrammarMarkingTerminals, subClasses, superClasses + on SyntaxDcl; aspect default production top::SyntaxDcl ::= @@ -119,7 +143,7 @@ top::SyntaxDcl ::= t::Type subdcls::Syntax exportedProds::[String] exportedLayou { top.fullName = t.typeName; top.sortKey = "EEE" ++ t.typeName; - top.cstDcls := [pair(t.typeName, top)] ++ subdcls.cstDcls; + top.cstDcls := [(t.typeName, top)] ++ subdcls.cstDcls; top.allNonterminals := [top]; top.cstErrors <- if length(searchEnvTree(t.typeName, top.cstEnv)) == 1 then [] @@ -136,7 +160,7 @@ top::SyntaxDcl ::= t::Type subdcls::Syntax exportedProds::[String] exportedLayou top.exportedProds = exportedProds; top.hasCustomLayout = modifiers.customLayout.isJust; - top.layoutContribs := map(pair(t.typeName, _), fromMaybe(exportedLayoutTerms, modifiers.customLayout)); + top.layoutContribs := map(pair(fst=t.typeName, snd=_), fromMaybe(exportedLayoutTerms, modifiers.customLayout)); top.copperElementReference = copper:elementReference(top.sourceGrammar, top.location, top.containingGrammar, makeCopperName(t.typeName)); @@ -158,7 +182,7 @@ top::SyntaxDcl ::= n::String regex::Regex modifiers::SyntaxTerminalModifiers { top.fullName = n; top.sortKey = "CCC" ++ n; - top.cstDcls := [pair(n, top)]; + top.cstDcls := [(n, top)]; top.cstErrors <- if length(searchEnvTree(n, top.cstEnv)) == 1 then [] else ["Name conflict with terminal " ++ n]; @@ -171,8 +195,8 @@ top::SyntaxDcl ::= n::String regex::Regex modifiers::SyntaxTerminalModifiers top.classTerminalContribs := modifiers.classTerminalContribs; top.memberTerminals := [top]; top.dominatingTerminalContribs := - map(pair(n, _), flatMap((.memberTerminals), modifiers.submits_)) ++ - map(pair(_, top), map((.fullName), flatMap((.memberTerminals), modifiers.dominates_))); + map(pair(fst=n, snd=_), flatMap((.memberTerminals), modifiers.submits_)) ++ + map(pair(fst=_, snd=top), map((.fullName), flatMap((.memberTerminals), modifiers.dominates_))); top.terminalRegex = regex; -- left(terminal name) or right(string prefix) @@ -191,7 +215,7 @@ top::SyntaxDcl ::= n::String regex::Regex modifiers::SyntaxTerminalModifiers end; local prettyName :: String = fromMaybe(fromMaybe(n, asPrettyName(regex)), modifiers.prettyName); - top.prettyNamesAccum := [pair(prettyName, n)]; + top.prettyNamesAccum := [(prettyName, n)]; local disambiguatedPrettyName :: String = case length(tm:lookup(prettyName, top.prettyNames)) of | 1 -> prettyName @@ -221,7 +245,7 @@ top::SyntaxDcl ::= ns::NamedSignature modifiers::SyntaxProductionModifiers { top.fullName = ns.fullName; top.sortKey = "FFF" ++ ns.fullName; - top.cstDcls := [pair(ns.fullName, top)]; + top.cstDcls := [(ns.fullName, top)]; top.allProductions := [top]; top.allProductionNames := [ns.fullName]; @@ -244,14 +268,14 @@ top::SyntaxDcl ::= ns::NamedSignature modifiers::SyntaxProductionModifiers top.cstErrors <- checkRHS(ns.fullName, map((.typerep), ns.inputElements), rhsRefs); - top.cstProds := [pair(ns.outputElement.typerep.typeName, top)]; + top.cstProds := [(ns.outputElement.typerep.typeName, top)]; top.cstNormalize := []; top.hasCustomLayout = modifiers.customLayout.isJust; top.layoutContribs := - map(pair(ns.fullName, _), fromMaybe([], modifiers.customLayout)) ++ + map(pair(fst=ns.fullName, snd=_), fromMaybe([], modifiers.customLayout)) ++ -- The production inherits its LHS nonterminal's layout, unless overridden. - (if top.hasCustomLayout then [] else [pair(ns.fullName, head(lhsRef).fullName)]) ++ + (if top.hasCustomLayout then [] else [(ns.fullName, head(lhsRef).fullName)]) ++ -- All nonterminals on the RHS that export this production inherit this -- production's layout, unless overriden on the nonterminal. flatMap( @@ -260,7 +284,7 @@ top::SyntaxDcl ::= ns::NamedSignature modifiers::SyntaxProductionModifiers | syntaxNonterminal(_,_,_,_,_) when !head(rhsRef).hasCustomLayout && contains(top.fullName, head(rhsRef).exportedProds) -> - [pair(head(rhsRef).fullName, ns.fullName)] + [(head(rhsRef).fullName, ns.fullName)] | _ -> [] end, rhsRefs); @@ -272,7 +296,7 @@ top::SyntaxDcl ::= ns::NamedSignature modifiers::SyntaxProductionModifiers local isTracked :: Boolean = case head(lhsRef) of - | syntaxNonterminal(nonterminalType(_, _, tracked), _, _, _, _) -> tracked + | syntaxNonterminal(nonterminalType(_, _, _, tracked), _, _, _, _) -> tracked | _ -> error("LHS is not a nonterminal") end; local commaIfArgsOrAnnos :: String = if length(ns.inputElements) + length(ns.namedInputElements)!= 0 then "," else ""; @@ -309,7 +333,7 @@ String ::= i::Integer ns::[NamedSignatureElement] } function insertLocationAnnotation -String ::= ns::Decorated NamedSignature +String ::= ns::NamedSignature { local pfx :: String = if null(ns.inputElements) then "" else ", "; @@ -349,7 +373,7 @@ top::SyntaxDcl ::= n::String modifiers::SyntaxLexerClassModifiers { top.fullName = n; top.sortKey = "AAA" ++ n; - top.cstDcls := [pair(n, top)]; + top.cstDcls := [(n, top)]; top.cstErrors <- if length(searchEnvTree(n, top.cstEnv)) == 1 then [] else ["Name conflict with lexer class " ++ n]; @@ -390,7 +414,7 @@ top::SyntaxDcl ::= n::String ty::Type acode::String { top.fullName = n; top.sortKey = "BBB" ++ n; - top.cstDcls := [pair(n, top)]; + top.cstDcls := [(n, top)]; top.cstErrors <- if length(searchEnvTree(n, top.cstEnv)) == 1 then [] else ["Name conflict with parser attribute " ++ n]; @@ -424,7 +448,7 @@ top::SyntaxDcl ::= n::String acode::String top.cstNormalize := [top]; - top.parserAttributeAspectContribs := [pair(n, acode)]; + top.parserAttributeAspectContribs := [(n, acode)]; -- The Copper information for these gets picked up by the main syntaxParserAttribute declaration. top.copperElementReference = error("can't demand copperElementReference of an aspect"); top.copperGrammarElements = []; @@ -449,7 +473,7 @@ top::SyntaxDcl ::= n::String terms::[String] applicableToSubsets::Boolean acode: if !null(p.snd) then [] else ["Terminal " ++ p.fst ++ " was referenced but " ++ "this grammar was not included in this parser. (Referenced from disambiguation group " ++ n ++ ")"], - zipWith(pair, terms, trefs)); + zip(terms, trefs)); top.cstNormalize := [top]; diff --git a/grammars/silver/compiler/definition/concrete_syntax/ast/TerminalModifiers.sv b/grammars/silver/compiler/definition/concrete_syntax/ast/TerminalModifiers.sv index 9835a61e1..0854aef29 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ast/TerminalModifiers.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ast/TerminalModifiers.sv @@ -10,7 +10,7 @@ monoid attribute opAssociation :: Maybe with nothing(), orElse; -- TODO monoid attribute prefixSeperator :: Maybe with nothing(), orElse; monoid attribute prefixSeperatorToApply :: Maybe with nothing(), orElse; monoid attribute prettyName :: Maybe with nothing(), orElse; -autocopy attribute terminalName :: String; +inherited attribute terminalName :: String; monoid attribute dominates_ :: [Decorated SyntaxDcl]; monoid attribute submits_ :: [Decorated SyntaxDcl]; @@ -25,8 +25,10 @@ nonterminal SyntaxTerminalModifiers with compareTo, isEqual, cstEnv, cstErrors, componentGrammarMarkingTerminals, marking, terminalName, prettyName, dominates_, submits_, lexerClasses; -propagate compareTo, isEqual, cstErrors, classTerminalContribs, ignored, acode, opPrecedence, - opAssociation, prefixSeperator, prefixSeperatorToApply, marking, prettyName, +propagate compareTo, isEqual, cstEnv, cstErrors, + classTerminalContribs, superClasses, subClasses, ignored, acode, + opPrecedence, opAssociation, prefixSeperator, prefixSeperatorToApply, + componentGrammarMarkingTerminals, marking, terminalName, prettyName, dominates_, submits_, lexerClasses on SyntaxTerminalModifiers; @@ -121,7 +123,7 @@ top::SyntaxTerminalModifier ::= cls::[String] production allClsRefs :: [Decorated SyntaxDcl] = concat(lookupStrings(allCls, top.cstEnv)); top.cstErrors := []; - top.classTerminalContribs := map(pair(_, top.terminalName), allCls); + top.classTerminalContribs := map(pair(fst=_, snd=top.terminalName), allCls); -- We "translate away" lexer classes dom/sub, by moving that info to the terminals (here) top.dominates_ := flatMap((.domContribs), allClsRefs); top.submits_ := flatMap((.subContribs), allClsRefs); @@ -147,7 +149,7 @@ top::SyntaxTerminalModifier ::= sub::[String] if !null(a.snd) then [] else ["Terminal / Lexer Class " ++ a.fst ++ " was referenced but " ++ "this grammar was not included in this parser. (Referenced from submit clause on terminal " ++ top.terminalName ++ ")"], - zipWith(pair, sub, subRefs)); + zip(sub, subRefs)); top.submits_ := map(head, subRefs); } {-- @@ -163,7 +165,7 @@ top::SyntaxTerminalModifier ::= dom::[String] if !null(a.snd) then [] else ["Terminal / Lexer Class " ++ a.fst ++ " was referenced but " ++ "this grammar was not included in this parser. (Referenced from dominates clause on terminal " ++ top.terminalName ++ ")"], - zipWith(pair, dom, domRefs)); + zip(dom, domRefs)); top.dominates_ := map(head, domRefs); } {-- @@ -203,7 +205,7 @@ top::SyntaxTerminalModifier ::= terms::[String] grams::[String] if !null(a.snd) then [] else ["Terminal " ++ a.fst ++ " was referenced but " ++ "this grammar was not included in this parser. (Referenced from use prefix seperator for clause for terminal)"], - zipWith(pair, terms, termRefs)); + zip(terms, termRefs)); top.cstErrors <- flatMap( diff --git a/grammars/silver/compiler/definition/core/AGDcl.sv b/grammars/silver/compiler/definition/core/AGDcl.sv index 573cb7633..3134a55f9 100644 --- a/grammars/silver/compiler/definition/core/AGDcl.sv +++ b/grammars/silver/compiler/definition/core/AGDcl.sv @@ -7,14 +7,16 @@ nonterminal AGDcls with config, grammarName, env, location, unparse, errors, def nonterminal AGDcl with config, grammarName, env, location, unparse, errors, defs, occursDefs, moduleNames, compiledGrammars, grammarDependencies, jarName; flowtype decorate {config, grammarName, env, flowEnv, compiledGrammars, grammarDependencies} on AGDcls, AGDcl; -flowtype forward {decorate} on AGDcls, AGDcl; +flowtype forward {} on AGDcls; +flowtype forward {decorate} on AGDcl; flowtype errors {decorate} on AGDcls, AGDcl; flowtype defs {decorate} on AGDcls, AGDcl; flowtype occursDefs {decorate} on AGDcls, AGDcl; flowtype jarName {decorate} on AGDcls, AGDcl; -propagate errors, moduleNames, jarName on AGDcls, AGDcl; -propagate defs, occursDefs on AGDcls; +propagate config, grammarName, compiledGrammars, grammarDependencies, errors, moduleNames, jarName + on AGDcls, AGDcl; +propagate env, defs, occursDefs on AGDcls; concrete production nilAGDcls top::AGDcls ::= @@ -64,7 +66,7 @@ abstract production appendAGDcl top::AGDcl ::= h::AGDcl t::AGDcl { top.unparse = h.unparse ++ "\n" ++ t.unparse; - propagate defs, occursDefs; + propagate env, defs, occursDefs; top.errors <- warnIfMultJarName(h.jarName, t.jarName, top.location); } diff --git a/grammars/silver/compiler/definition/core/AspectDcl.sv b/grammars/silver/compiler/definition/core/AspectDcl.sv index 9a5739f32..18a9e8937 100644 --- a/grammars/silver/compiler/definition/core/AspectDcl.sv +++ b/grammars/silver/compiler/definition/core/AspectDcl.sv @@ -15,14 +15,16 @@ flowtype forward {deterministicCount, realSignature, grammarName, env, flowEnv} {-- - The signature elements from the fun/produciton being aspected. -} -autocopy attribute realSignature :: [NamedSignatureElement]; +inherited attribute realSignature :: [NamedSignatureElement]; -propagate errors on AspectProductionSignature, AspectProductionLHS, AspectFunctionSignature, AspectFunctionLHS, AspectRHS, AspectRHSElem; +propagate config, grammarName, env, grammarDependencies, errors + on AspectProductionSignature, AspectProductionLHS, AspectFunctionSignature, AspectFunctionLHS, AspectRHS, AspectRHSElem; concrete production aspectProductionDcl top::AGDcl ::= 'aspect' 'production' id::QName ns::AspectProductionSignature body::ProductionBody { top.unparse = "aspect production " ++ id.unparse ++ "\n" ++ ns.unparse ++ "\n" ++ body.unparse; + id.env = top.env; top.defs := if null(body.productionAttributes) then [] @@ -32,7 +34,7 @@ top::AGDcl ::= 'aspect' 'production' id::QName ns::AspectProductionSignature bod production attribute realSig :: NamedSignature; realSig = if id.lookupValue.found - then freshenNamedSignature(id.lookupValue.dcl.namedSignature) + then id.lookupValue.dcl.namedSignature.freshenNamedSignature else bogusNamedSignature(); -- Making sure we're aspecting a production is taken care of by type checking. @@ -79,6 +81,7 @@ concrete production aspectFunctionDcl top::AGDcl ::= 'aspect' 'function' id::QName ns::AspectFunctionSignature body::ProductionBody { top.unparse = "aspect function " ++ id.unparse ++ "\n" ++ ns.unparse ++ "\n" ++ body.unparse; + id.env = top.env; top.defs := if null(body.productionAttributes) then [] @@ -88,7 +91,7 @@ top::AGDcl ::= 'aspect' 'function' id::QName ns::AspectFunctionSignature body::P production attribute realSig :: NamedSignature; realSig = if id.lookupValue.found - then freshenNamedSignature(id.lookupValue.dcl.namedSignature) + then id.lookupValue.dcl.namedSignature.freshenNamedSignature else bogusNamedSignature(); -- Making sure we're aspecting a function is taken care of by type checking. @@ -175,6 +178,7 @@ concrete production aspectProductionLHSTyped top::AspectProductionLHS ::= id::Name '::' t::TypeExpr { top.unparse = id.unparse; + propagate env, grammarName, config; top.errors <- t.errors; @@ -258,6 +262,7 @@ concrete production aspectRHSElemTyped top::AspectRHSElem ::= id::Name '::' t::TypeExpr { top.unparse = id.unparse ++ "::" ++ t.unparse; + propagate env, grammarName, config; top.errors <- t.errors; diff --git a/grammars/silver/compiler/definition/core/AttributeDcl.sv b/grammars/silver/compiler/definition/core/AttributeDcl.sv index a96deddd8..36ac70eac 100644 --- a/grammars/silver/compiler/definition/core/AttributeDcl.sv +++ b/grammars/silver/compiler/definition/core/AttributeDcl.sv @@ -43,3 +43,26 @@ top::AGDcl ::= 'synthesized' 'attribute' a::Name tl::BracketedOptTypeExprs '::' top.errors <- tl.errorsTyVars; } + +concrete production attributeDclTrans +top::AGDcl ::= 'translation' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr ';' +{ + top.unparse = "translation attribute " ++ a.unparse ++ tl.unparse ++ " :: " ++ te.unparse ++ ";"; + + production attribute fName :: String; + fName = top.grammarName ++ ":" ++ a.name; + + top.defs := [transDef(top.grammarName, a.location, fName, tl.freeVariables, te.typerep)]; + + tl.initialEnv = top.env; + tl.env = tl.envBindingTyVars; + te.env = tl.envBindingTyVars; + + top.errors <- + if length(getAttrDclAll(fName, top.env)) > 1 + then [err(a.location, "Attribute '" ++ fName ++ "' is already bound.")] + else []; + + top.errors <- tl.errorsTyVars; +} + diff --git a/grammars/silver/compiler/definition/core/Attributes.sv b/grammars/silver/compiler/definition/core/Attributes.sv index 148593213..6d6e60f71 100644 --- a/grammars/silver/compiler/definition/core/Attributes.sv +++ b/grammars/silver/compiler/definition/core/Attributes.sv @@ -3,7 +3,7 @@ grammar silver:compiler:definition:core; {-- - The grammar containing this tree. -} -autocopy attribute grammarName :: String; +inherited attribute grammarName :: String; {-- - The name to use for the generated .jar if not overridden by -o command-line option. diff --git a/grammars/silver/compiler/definition/core/BlockContext.sv b/grammars/silver/compiler/definition/core/BlockContext.sv index c235532e4..4bc0dadb1 100644 --- a/grammars/silver/compiler/definition/core/BlockContext.sv +++ b/grammars/silver/compiler/definition/core/BlockContext.sv @@ -7,7 +7,7 @@ import silver:compiler:definition:flow:driver only ProductionGraph; - statements, etc. i.e. "can forward/return/pluck?" -} nonterminal BlockContext with permitReturn, permitForward, permitProductionAttributes, - permitLocalAttributes, lazyApplication, hasFullSignature, hasPartialSignature, + permitForwardProductionAttributes, permitLocalAttributes, lazyApplication, hasFullSignature, hasPartialSignature, fullName, lhsNtName, signature, sourceGrammar, flowGraph; @@ -20,6 +20,8 @@ synthesized attribute permitLocalAttributes :: Boolean; {-- Are 'production attribute' equations allowed in this context? DISTINCT from locals, due to action blocks. -} synthesized attribute permitProductionAttributes :: Boolean; +{-- Are 'forward production attribute' equations allowed in this context? -} +synthesized attribute permitForwardProductionAttributes :: Boolean; {-- - Whether the signature includes the name of a LHS. @@ -79,6 +81,7 @@ top::BlockContext ::= top.permitReturn = false; top.permitForward = false; top.permitProductionAttributes = false; + top.permitForwardProductionAttributes = false; top.permitLocalAttributes = false; top.lazyApplication = true; top.hasPartialSignature = false; @@ -109,10 +112,11 @@ top::BlockContext ::= sig::NamedSignature g::ProductionGraph top.signature = sig; top.flowGraph = g; - top.permitForward = true; + top.permitForward = !sig.outputElement.typerep.isData; top.hasPartialSignature = true; top.hasFullSignature = true; top.permitProductionAttributes = true; + top.permitForwardProductionAttributes = !sig.outputElement.typerep.isData; top.permitLocalAttributes = true; } diff --git a/grammars/silver/compiler/definition/core/ClassDcl.sv b/grammars/silver/compiler/definition/core/ClassDcl.sv index 078690eec..1ef30993f 100644 --- a/grammars/silver/compiler/definition/core/ClassDcl.sv +++ b/grammars/silver/compiler/definition/core/ClassDcl.sv @@ -5,7 +5,7 @@ import silver:compiler:definition:flow:driver only ProductionGraph, FlowType, co concrete production typeClassDcl top::AGDcl ::= 'class' cl::ConstraintList '=>' id::QNameType var::TypeExpr '{' body::ClassBody '}' { - top.unparse = s"class ${cl.unparse} => ${id.unparse} ${var.unparse}\n{\n${body.unparse}\n}"; + top.unparse = s"class ${cl.unparse} => ${id.unparse} ${var.unparse}\n{\n${body.unparse}\n}"; production fName :: String = top.grammarName ++ ":" ++ id.name; production tv :: TyVar = @@ -52,6 +52,7 @@ top::AGDcl ::= 'class' cl::ConstraintList '=>' id::QNameType var::TypeExpr '{' b cl.constraintPos = classPos(fName, var.freeVariables); cl.env = newScopeEnv(headPreDefs, top.env); + id.env = cl.env; var.env = cl.env; body.env = occursEnv(cl.occursDefs, newScopeEnv(headDefs, cl.env)); @@ -72,17 +73,19 @@ top::AGDcl ::= 'class' id::QNameType var::TypeExpr '{' body::ClassBody '}' insert semantic token IdTypeClassDcl_t at id.baseNameLoc; } -autocopy attribute classHead::Context; -autocopy attribute constraintEnv::Decorated Env; -autocopy attribute frameContexts::[Context]; -- Only used for computing frame in members +inherited attribute classHead::Context; +inherited attribute constraintEnv::Env; +inherited attribute frameContexts::[Context]; -- Only used for computing frame in members nonterminal ClassBody with - config, grammarName, env, defs, flowEnv, flowDefs, location, unparse, errors, lexicalTypeVariables, lexicalTyVarKinds, classHead, constraintEnv, frameContexts, compiledGrammars, classMembers; + config, grammarName, env, defs, location, unparse, errors, lexicalTypeVariables, lexicalTyVarKinds, classHead, constraintEnv, frameContexts, compiledGrammars, classMembers; nonterminal ClassBodyItem with - config, grammarName, env, defs, flowEnv, flowDefs, location, unparse, errors, lexicalTypeVariables, lexicalTyVarKinds, classHead, constraintEnv, frameContexts, compiledGrammars, classMembers; + config, grammarName, env, defs, location, unparse, errors, lexicalTypeVariables, lexicalTyVarKinds, classHead, constraintEnv, frameContexts, compiledGrammars, classMembers; -propagate flowDefs, errors, lexicalTypeVariables, lexicalTyVarKinds on ClassBody, ClassBodyItem; -propagate defs on ClassBody; +propagate + config, grammarName, errors, lexicalTypeVariables, lexicalTyVarKinds, classHead, constraintEnv, frameContexts, compiledGrammars + on ClassBody, ClassBodyItem; +propagate env, defs on ClassBody; concrete production consClassBody top::ClassBody ::= h::ClassBodyItem t::ClassBody @@ -113,7 +116,7 @@ top::ClassBodyItem ::= id::Name '::' cl::ConstraintList '=>' ty::TypeExpr ';' production fName :: String = top.grammarName ++ ":" ++ id.name; production boundVars :: [TyVar] = setUnionTyVarsAll(top.classHead.freeVariables :: map((.freeVariables), cl.contexts) ++ [ty.typerep.freeVariables]); - top.classMembers = [pair(fName, false)]; + top.classMembers = [(fName, false)]; cl.constraintPos = case top.classHead of @@ -121,6 +124,8 @@ top::ClassBodyItem ::= id::Name '::' cl::ConstraintList '=>' ty::TypeExpr ';' | _ -> error("Class head is not an instContext") end; cl.env = top.constraintEnv; + + ty.env = top.env; top.defs := [classMemberDef(top.grammarName, top.location, fName, boundVars, top.classHead, cl.contexts, ty.typerep)]; @@ -148,7 +153,7 @@ top::ClassBodyItem ::= id::Name '::' cl::ConstraintList '=>' ty::TypeExpr '=' e: production fName :: String = top.grammarName ++ ":" ++ id.name; production boundVars :: [TyVar] = setUnionTyVarsAll(top.classHead.freeVariables :: map((.freeVariables), cl.contexts) ++ [ty.typerep.freeVariables]); - top.classMembers = [pair(fName, true)]; + top.classMembers = [(fName, true)]; cl.constraintPos = case top.classHead of @@ -156,6 +161,8 @@ top::ClassBodyItem ::= id::Name '::' cl::ConstraintList '=>' ty::TypeExpr '=' e: | _ -> error("Class head is not an instContext") end; cl.env = top.constraintEnv; + + ty.env = top.env; e.isRoot = true; e.originRules = []; diff --git a/grammars/silver/compiler/definition/core/DclInfo.sv b/grammars/silver/compiler/definition/core/DclInfo.sv index 5bbee786a..b7153079a 100644 --- a/grammars/silver/compiler/definition/core/DclInfo.sv +++ b/grammars/silver/compiler/definition/core/DclInfo.sv @@ -5,36 +5,43 @@ import silver:compiler:modification:copper only terminalIdReference; {-- - The production a variable reference should forward to for this type of value -} -synthesized attribute refDispatcher :: (Expr ::= PartiallyDecorated QName Location) occurs on ValueDclInfo; +synthesized attribute refDispatcher :: (Expr ::= Decorated! QName Location) occurs on ValueDclInfo; {-- - The production an "assignment" should forward to for this type of value -} -synthesized attribute defDispatcher :: (ProductionStmt ::= PartiallyDecorated QName Expr Location) occurs on ValueDclInfo; +synthesized attribute defDispatcher :: (ProductionStmt ::= Decorated! QName Expr Location) occurs on ValueDclInfo; {-- - The production an "equation" left hand side should forward to for this type of value (i.e. the 'x' in 'x.a = e') -} -synthesized attribute defLHSDispatcher :: (DefLHS ::= PartiallyDecorated QName Location) occurs on ValueDclInfo; +synthesized attribute defLHSDispatcher :: (DefLHS ::= Decorated! QName Location) occurs on ValueDclInfo; +{-- + - The production a translation attribute left hand side should forward to, for this type of value (i.e. the 'x.a' in 'x.a.b = e') + -} +synthesized attribute transDefLHSDispatcher :: (DefLHS ::= Decorated! QName Decorated! QNameAttrOccur Location) occurs on ValueDclInfo; {-- - The handler for 'x.a' for 'a', given that 'x' is DECORATED. - - @see accessDispather in TypeExp.sv, for the first step in that process... - @see decoratedAccessHandler production for where this is used -} -synthesized attribute decoratedAccessHandler :: (Expr ::= PartiallyDecorated Expr PartiallyDecorated QNameAttrOccur Location) occurs on AttributeDclInfo; +synthesized attribute decoratedAccessHandler :: (Expr ::= Decorated! Expr Decorated! QNameAttrOccur Location) occurs on AttributeDclInfo; {-- - The handler for 'x.a' for 'a', given that 'x' is UNdecorated. - - @see accessDispather in TypeExp.sv, for the first step in that process... - @see undecoratedAccessHandler production for where this is used -} -synthesized attribute undecoratedAccessHandler :: (Expr ::= PartiallyDecorated Expr PartiallyDecorated QNameAttrOccur Location) occurs on AttributeDclInfo; +synthesized attribute undecoratedAccessHandler :: (Expr ::= Decorated! Expr Decorated! QNameAttrOccur Location) occurs on AttributeDclInfo; +{-- + - The handler for 'x.a' for 'a', given that 'x' is data. + - @see dataAccessHandler production for where this is used + -} +synthesized attribute dataAccessHandler :: (Expr ::= Decorated! Expr Decorated! QNameAttrOccur Location) occurs on AttributeDclInfo; {-- - The production an "equation" should forward to for this type of attribute (i.e. the 'a' in 'x.a = e') -} -synthesized attribute attrDefDispatcher :: (ProductionStmt ::= PartiallyDecorated DefLHS PartiallyDecorated QNameAttrOccur Expr Location) occurs on AttributeDclInfo; +synthesized attribute attrDefDispatcher :: (ProductionStmt ::= Decorated! DefLHS Decorated! QNameAttrOccur Expr Location) occurs on AttributeDclInfo; {-- - - The production an "occurs on" decl should forward to for this type of attribute (for extension use, defaultAttributionDcl for all syn/inh/autocopy attrs.) + - The production an "occurs on" decl should forward to for this type of attribute (for extension use, defaultAttributionDcl for all syn/inh attrs.) -} -synthesized attribute attributionDispatcher :: (AGDcl ::= PartiallyDecorated QName BracketedOptTypeExprs QName BracketedOptTypeExprs Location) occurs on AttributeDclInfo; +synthesized attribute attributionDispatcher :: (AGDcl ::= Decorated! QName BracketedOptTypeExprs QName BracketedOptTypeExprs Location) occurs on AttributeDclInfo; -- -- non-interface values aspect production childDcl @@ -43,6 +50,7 @@ top::ValueDclInfo ::= fn::String ty::Type top.refDispatcher = childReference(_, location=_); top.defDispatcher = errorValueDef(_, _, location=_); -- TODO: we should be smarted about error messages, and mention its a child top.defLHSDispatcher = childDefLHS(_, location=_); + top.transDefLHSDispatcher = childTransAttrDefLHS(_, _, location=_); } aspect production lhsDcl top::ValueDclInfo ::= fn::String ty::Type @@ -50,13 +58,15 @@ top::ValueDclInfo ::= fn::String ty::Type top.refDispatcher = lhsReference(_, location=_); top.defDispatcher = errorValueDef(_, _, location=_); -- TODO: be smarter about the error message top.defLHSDispatcher = lhsDefLHS(_, location=_); + top.transDefLHSDispatcher = errorTransAttrDefLHS(_, _, location=_); } aspect production localDcl -top::ValueDclInfo ::= fn::String ty::Type +top::ValueDclInfo ::= fn::String ty::Type _ { top.refDispatcher = localReference(_, location=_); top.defDispatcher = localValueDef(_, _, location=_); top.defLHSDispatcher = localDefLHS(_, location=_); + top.transDefLHSDispatcher = localTransAttrDefLHS(_, _, location=_); } @@ -68,6 +78,7 @@ top::ValueDclInfo ::= ns::NamedSignature hasForward::Boolean -- Note that we still need production references, even though bug #16 removes the production type. top.defDispatcher = errorValueDef(_, _, location=_); top.defLHSDispatcher = errorDefLHS(_, location=_); + top.transDefLHSDispatcher = errorTransAttrDefLHS(_, _, location=_); } aspect production funDcl top::ValueDclInfo ::= ns::NamedSignature @@ -75,6 +86,7 @@ top::ValueDclInfo ::= ns::NamedSignature top.refDispatcher = functionReference(_, location=_); top.defDispatcher = errorValueDef(_, _, location=_); top.defLHSDispatcher = errorDefLHS(_, location=_); + top.transDefLHSDispatcher = errorTransAttrDefLHS(_, _, location=_); } aspect production globalValueDcl top::ValueDclInfo ::= fn::String bound::[TyVar] contexts::[Context] ty::Type @@ -82,6 +94,7 @@ top::ValueDclInfo ::= fn::String bound::[TyVar] contexts::[Context] ty::Type top.refDispatcher = globalValueReference(_, location=_); top.defDispatcher = errorValueDef(_, _, location=_); top.defLHSDispatcher = errorDefLHS(_, location=_); + top.transDefLHSDispatcher = errorTransAttrDefLHS(_, _, location=_); } aspect production classMemberDcl top::ValueDclInfo ::= fn::String bound::[TyVar] head::Context contexts::[Context] ty::Type @@ -89,6 +102,7 @@ top::ValueDclInfo ::= fn::String bound::[TyVar] head::Context contexts::[Context top.refDispatcher = classMemberReference(_, location=_); top.defDispatcher = errorValueDef(_, _, location=_); top.defLHSDispatcher = errorDefLHS(_, location=_); + top.transDefLHSDispatcher = errorTransAttrDefLHS(_, _, location=_); } -- -- interface Production attr (values) @@ -98,6 +112,7 @@ top::ValueDclInfo ::= ty::Type top.refDispatcher = forwardReference(_, location=_); top.defDispatcher = errorValueDef(_, _, location=_); -- TODO: better error message top.defLHSDispatcher = forwardDefLHS(_, location=_); + top.transDefLHSDispatcher = errorTransAttrDefLHS(_, _, location=_); } aspect production termIdDcl @@ -106,6 +121,7 @@ top::ValueDclInfo ::= fn::String top.refDispatcher = terminalIdReference(_, location=_); top.defDispatcher = errorValueDef(_, _, location=_); top.defLHSDispatcher = errorDefLHS(_, location=_); + top.transDefLHSDispatcher = errorTransAttrDefLHS(_, _, location=_); } -- -- interface Attributes @@ -114,6 +130,7 @@ top::AttributeDclInfo ::= fn::String bound::[TyVar] ty::Type { top.decoratedAccessHandler = synDecoratedAccessHandler(_, _, location=_); top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); + top.dataAccessHandler = synDataAccessHandler(_, _, location=_); top.attrDefDispatcher = synthesizedAttributeDef(_, _, _, location=_); top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); } @@ -121,17 +138,28 @@ aspect production inhDcl top::AttributeDclInfo ::= fn::String bound::[TyVar] ty::Type { top.decoratedAccessHandler = inhDecoratedAccessHandler(_, _, location=_); - top.undecoratedAccessHandler = accessBounceDecorate(inhDecoratedAccessHandler(_, _, location=_), _, _, _); -- TODO: above should probably be an error handler! access inh from undecorated? + top.undecoratedAccessHandler = inhUndecoratedAccessErrorHandler(_, _, location=_); + top.dataAccessHandler = inhUndecoratedAccessErrorHandler(_, _, location=_); top.attrDefDispatcher = inheritedAttributeDef(_, _, _, location=_); top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); } +aspect production transDcl +top::AttributeDclInfo ::= fn::String bound::[TyVar] ty::Type +{ + top.decoratedAccessHandler = transDecoratedAccessHandler(_, _, location=_); + top.undecoratedAccessHandler = transUndecoratedAccessErrorHandler(_, _, location=_); + top.dataAccessHandler = transUndecoratedAccessErrorHandler(_, _, location=_); + top.attrDefDispatcher = synthesizedAttributeDef(_, _, _, location=_); + top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); +} aspect production annoDcl top::AttributeDclInfo ::= fn::String bound::[TyVar] ty::Type { top.decoratedAccessHandler = accessBounceUndecorate(annoAccessHandler(_, _, location=_), _, _, _); top.undecoratedAccessHandler = annoAccessHandler(_, _, location=_); + top.dataAccessHandler = annoAccessHandler(_, _, location=_); top.attrDefDispatcher = - \ dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr l::Location -> + \ dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr l::Location -> errorAttributeDef([err(l, "Annotations are not defined as equations within productions")], dl, attr, e, location=l); top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); } \ No newline at end of file diff --git a/grammars/silver/compiler/definition/core/Expr.sv b/grammars/silver/compiler/definition/core/Expr.sv index dcf6b0234..258854bd9 100644 --- a/grammars/silver/compiler/definition/core/Expr.sv +++ b/grammars/silver/compiler/definition/core/Expr.sv @@ -6,39 +6,44 @@ import silver:util:treeset as ts; nonterminal Expr with config, grammarName, env, location, unparse, errors, freeVars, frame, compiledGrammars, typerep, isRoot, originRules; nonterminal Exprs with - config, grammarName, env, location, unparse, errors, freeVars, frame, compiledGrammars, exprs, rawExprs, isRoot, originRules; + config, grammarName, env, location, unparse, errors, freeVars, frame, compiledGrammars, exprs, rawExprs, originRules; nonterminal ExprInhs with - config, grammarName, env, location, unparse, errors, freeVars, frame, compiledGrammars, decoratingnt, suppliedInhs, allSuppliedInhs, isRoot, originRules; + config, grammarName, env, location, unparse, errors, freeVars, frame, compiledGrammars, decoratingnt, suppliedInhs, allSuppliedInhs, originRules; nonterminal ExprInh with - config, grammarName, env, location, unparse, errors, freeVars, frame, compiledGrammars, decoratingnt, suppliedInhs, allSuppliedInhs, isRoot, originRules; + config, grammarName, env, location, unparse, errors, freeVars, frame, compiledGrammars, decoratingnt, suppliedInhs, allSuppliedInhs, originRules; nonterminal ExprLHSExpr with - config, grammarName, env, location, unparse, errors, freeVars, frame, name, typerep, decoratingnt, suppliedInhs, allSuppliedInhs, isRoot, originRules; + config, grammarName, env, location, unparse, errors, freeVars, frame, name, typerep, decoratingnt, suppliedInhs, allSuppliedInhs, originRules; flowtype unparse {} on Expr, Exprs, ExprInhs, ExprInh, ExprLHSExpr; flowtype freeVars {frame} on Expr, Exprs, ExprInhs, ExprInh, ExprLHSExpr; -flowtype Expr = decorate {grammarName, env, flowEnv, downSubst, finalSubst, frame, isRoot, originRules, compiledGrammars, config}, forward {decorate}; +flowtype Expr = + forward {grammarName, env, flowEnv, downSubst, finalSubst, frame, isRoot, originRules, compiledGrammars, config}, + decorate {forward, alwaysDecorated}; -flowtype decorate {grammarName, env, flowEnv, downSubst, finalSubst, frame, isRoot, originRules, compiledGrammars, config} on Exprs; -flowtype decorate {grammarName, env, flowEnv, downSubst, finalSubst, frame, isRoot, originRules, compiledGrammars, config, decoratingnt, allSuppliedInhs} on ExprInhs, ExprInh; -flowtype decorate {grammarName, env, frame, isRoot, originRules, config, decoratingnt, allSuppliedInhs} on ExprLHSExpr; +flowtype decorate {grammarName, env, flowEnv, downSubst, finalSubst, frame, originRules, compiledGrammars, config} on Exprs; +flowtype decorate {grammarName, env, flowEnv, downSubst, finalSubst, frame, originRules, compiledGrammars, config, decoratingnt, allSuppliedInhs} on ExprInhs, ExprInh; +flowtype decorate {grammarName, env, frame, originRules, config, decoratingnt, allSuppliedInhs} on ExprLHSExpr; flowtype forward {} on Exprs, ExprInhs, ExprInh, ExprLHSExpr; flowtype errors {decorate} on Exprs, ExprInhs, ExprInh, ExprLHSExpr; propagate errors on Expr, Exprs, ExprInhs, ExprInh, ExprLHSExpr excluding terminalAccessHandler; -propagate freeVars on Expr, Exprs, ExprInhs, ExprInh, ExprLHSExpr; +propagate config, grammarName, env, freeVars, frame, compiledGrammars + on Expr, Exprs, ExprInhs, ExprInh, ExprLHSExpr; +propagate originRules on Expr, Exprs, ExprInhs, ExprInh, ExprLHSExpr excluding noteAttachment; +propagate decoratingnt, allSuppliedInhs on ExprInhs, ExprInh, ExprLHSExpr; {-- - The nonterminal being decorated. (Used for 'decorate with {}') -} -autocopy attribute decoratingnt :: Type; +inherited attribute decoratingnt :: Type; {-- - The inherited attributes being supplied in a decorate expression -} synthesized attribute suppliedInhs :: [String]; -autocopy attribute allSuppliedInhs :: [String]; +inherited attribute allSuppliedInhs :: [String]; {-- - A list of decorated expressions from an Exprs. -} @@ -54,11 +59,12 @@ monoid attribute freeVars :: ts:Set; -- Is this Expr the logical "root" of the expression? That is, will it's value be the value computed -- for the attribute/return value/etc that it is part of? -autocopy attribute isRoot :: Boolean; +inherited attribute isRoot :: Boolean; -autocopy attribute originRules :: [Decorated Expr]; +inherited attribute originRules :: [Decorated Expr]; attribute grammarName, frame occurs on Contexts, Context; +propagate grammarName, frame on Contexts, Context; abstract production errorExpr top::Expr ::= e::[Message] @@ -81,6 +87,7 @@ top::Expr ::= q::QName { top.unparse = q.unparse; top.freeVars := ts:fromList([q.name]); + propagate env; forwards to (if null(q.lookupValue.dcls) then errorReference(q.lookupValue.errors, _, location=_) @@ -92,8 +99,9 @@ top::Expr ::= q::QName } abstract production errorReference -top::Expr ::= msg::[Message] q::PartiallyDecorated QName +top::Expr ::= msg::[Message] q::Decorated! QName { + undecorates to errorExpr(msg, location=top.location); -- TODO: Should this be baseExpr? top.unparse = q.unparse; top.freeVars <- ts:fromList([q.name]); @@ -103,8 +111,9 @@ top::Expr ::= msg::[Message] q::PartiallyDecorated QName -- TODO: We should separate this out, even, to be "nonterminal/decorable" and "as-is" abstract production childReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars <- ts:fromList([q.name]); @@ -114,8 +123,9 @@ top::Expr ::= q::PartiallyDecorated QName } abstract production lhsReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars <- ts:fromList([q.name]); @@ -124,8 +134,9 @@ top::Expr ::= q::PartiallyDecorated QName } abstract production localReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars <- ts:fromList([q.name]); @@ -135,8 +146,9 @@ top::Expr ::= q::PartiallyDecorated QName } abstract production forwardReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars <- ts:fromList([q.name]); @@ -148,8 +160,9 @@ top::Expr ::= q::PartiallyDecorated QName -- Later on, we do *not* distinguish for application. abstract production productionReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars <- ts:fromList([q.name]); @@ -166,8 +179,9 @@ top::Expr ::= q::PartiallyDecorated QName } abstract production functionReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars <- ts:fromList([q.name]); @@ -184,8 +198,9 @@ top::Expr ::= q::PartiallyDecorated QName } abstract production classMemberReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars <- ts:fromList([q.name]); @@ -215,8 +230,9 @@ top::Expr ::= q::PartiallyDecorated QName } abstract production globalValueReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars <- ts:fromList([q.name]); @@ -250,7 +266,8 @@ top::Expr ::= e::Expr '(' es::AppExprs ',' anns::AnnoAppExprs ')' { -- TODO: fix comma when one or the other is empty top.unparse = e.unparse ++ "(" ++ es.unparse ++ "," ++ anns.unparse ++ ")"; - propagate freeVars; + propagate config, grammarName, env, freeVars, frame, originRules, compiledGrammars; + e.isRoot = false; local correctNumTypes :: [Type] = if length(t.inputTypes) > es.appExprSize @@ -299,8 +316,9 @@ top::Expr ::= e::Expr '(' ')' } abstract production errorApplication -top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::PartiallyDecorated AnnoAppExprs +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs { + undecorates to application(e, '(', es, ',', anns, ')', location=top.location); top.unparse = e.unparse ++ "(" ++ es.unparse ++ "," ++ anns.unparse ++ ")"; top.errors <- @@ -316,16 +334,12 @@ top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::P -- We don't distinguish anymore at this point. A production reference -- becomes a function, effectively. abstract production functionApplication -top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::PartiallyDecorated AnnoAppExprs +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs { + undecorates to application(e, '(', es, ',', anns, ')', location=top.location); top.unparse = e.unparse ++ "(" ++ es.unparse ++ "," ++ anns.unparse ++ ")"; top.freeVars := e.freeVars ++ es.freeVars ++ anns.freeVars; - - -- TODO: we have an ambiguity here in the longer term. - -- How to distinguish between - -- foo(x) where there is an annotation 'a'? - -- Is this partial application, give (Foo ::= ;a::Something) or (Foo) + error. - -- Possibly this can be solved by having somehting like "foo(x,a=?)" + forwards to (if es.isPartial || anns.isPartial then partialApplication @@ -333,8 +347,9 @@ top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::P } abstract production functionInvocation -top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::PartiallyDecorated AnnoAppExprs +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs { + undecorates to application(e, '(', es, ',', anns, ')', location=top.location); top.unparse = e.unparse ++ "(" ++ es.unparse ++ "," ++ anns.unparse ++ ")"; local ety :: Type = performSubstitution(e.typerep, e.upSubst); @@ -343,8 +358,9 @@ top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::P } abstract production partialApplication -top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::PartiallyDecorated AnnoAppExprs +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs { + undecorates to application(e, '(', es, ',', anns, ')', location=top.location); top.unparse = e.unparse ++ "(" ++ es.unparse ++ "," ++ anns.unparse ++ ")"; local ety :: Type = performSubstitution(e.typerep, e.upSubst); @@ -364,6 +380,7 @@ top::Expr ::= 'attachNote' note::Expr 'on' e::Expr 'end' note.isRoot = false; e.isRoot = false; + note.originRules = top.originRules; e.originRules = top.originRules ++ [note]; } @@ -374,13 +391,16 @@ top::Expr ::= e::Expr '.' 'forward' { top.unparse = e.unparse ++ ".forward"; top.typerep = e.typerep; + + e.isRoot = false; } concrete production access top::Expr ::= e::Expr '.' q::QNameAttrOccur { top.unparse = e.unparse ++ "." ++ q.unparse; - propagate freeVars; + propagate config, grammarName, env, freeVars, frame, originRules, compiledGrammars; + e.isRoot = false; local eTy::Type = performSubstitution(e.typerep, e.upSubst); q.attrFor = if eTy.isDecorated then eTy.decoratedType else eTy; @@ -390,13 +410,15 @@ top::Expr ::= e::Expr '.' q::QNameAttrOccur -- This jumps to: -- errorAccessHandler (e.g. 1.unparse) -- undecoratedAccessHandler + -- dataAccessHandler -- decoratedAccessHandler (see that production, for how normal attribute access proceeds!) -- terminalAccessHandler } abstract production errorAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { + undecorates to access(e, '.', q, location=top.location); top.unparse = e.unparse ++ "." ++ q.unparse; top.typerep = errorType(); @@ -409,20 +431,10 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur end; } -abstract production annoAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur -{ - top.unparse = e.unparse ++ "." ++ q.unparse; - - production index :: Integer = - findNamedSigElem(q.name, annotationsForNonterminal(q.attrFor, top.env), 0); - - top.typerep = q.typerep; -} - abstract production terminalAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { + undecorates to access(e, '.', q, location=top.location); top.unparse = e.unparse ++ "." ++ q.unparse; -- NO use of q.errors, as that become nonsensical here. @@ -440,20 +452,37 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur else if q.name == "line" || q.name == "column" then intType() else if q.name == "location" - then nonterminalType("silver:core:Location", [], false) + then nonterminalType("silver:core:Location", [], true, false) else errorType(); } abstract production undecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { + undecorates to access(e, '.', q, location=top.location); top.unparse = e.unparse ++ "." ++ q.unparse; -- Note: LHS is UNdecorated, here we dispatch based on the kind of attribute. - forwards to (if !q.found then errorDecoratedAccessHandler(_, _, location=_) + forwards to (if !q.found then unknownDclAccessHandler(_, _, location=_) else q.attrDcl.undecoratedAccessHandler)(e, q, top.location); -- annoAccessHandler -- accessBouncer + -- transUndecoratedAccessErrorHandler + -- unknownDclAccessHandler -- unknown attribute error raised already. +} + +abstract production dataAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + undecorates to access(e, '.', q, location=top.location); + top.unparse = e.unparse ++ "." ++ q.unparse; + + -- Note: LHS is data, here we dispatch based on the kind of attribute. + forwards to (if !q.found then unknownDclAccessHandler(_, _, location=_) + else q.attrDcl.dataAccessHandler)(e, q, top.location); + -- annoAccessHandler + -- synDataAccessHandler + -- unknownDclAccessHandler -- unknown attribute error raised already. } {-- @@ -461,59 +490,125 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur - This production is intended to permit that. -} abstract production accessBouncer -top::Expr ::= target::(Expr ::= PartiallyDecorated Expr PartiallyDecorated QNameAttrOccur Location) e::Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= target::(Expr ::= Decorated! Expr Decorated! QNameAttrOccur Location) e::Expr q::Decorated! QNameAttrOccur { + undecorates to access(e, '.', q, location=top.location); top.unparse = e.unparse ++ "." ++ q.unparse; - propagate freeVars; + propagate config, grammarName, env, freeVars, frame, originRules, compiledGrammars; + e.isRoot = false; -- Basically the only purpose here is to decorate 'e'. forwards to target(e, q, top.location); } function accessBounceDecorate -Expr ::= target::(Expr ::= PartiallyDecorated Expr PartiallyDecorated QNameAttrOccur Location) e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur l::Location +Expr ::= target::(Expr ::= Decorated! Expr Decorated! QNameAttrOccur Location) e::Decorated! Expr q::Decorated! QNameAttrOccur loc::Location { - return accessBouncer(target, decorateExprWithEmpty('decorate', exprRef(e, location=l), 'with', '{', '}', location=l), q, location=l); + return accessBouncer(target, decorateExprWithEmpty('decorate', @e, 'with', '{', '}', location=loc), q, location=loc); } +-- Note that this performs the access on the term that was originally decorated, rather than properly undecorating. function accessBounceUndecorate -Expr ::= target::(Expr ::= PartiallyDecorated Expr PartiallyDecorated QNameAttrOccur Location) e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur l::Location +Expr ::= target::(Expr ::= Decorated! Expr Decorated! QNameAttrOccur Location) e::Decorated! Expr q::Decorated! QNameAttrOccur loc::Location { - return accessBouncer(target, mkStrFunctionInvocationDecorated(l, "silver:core:new", [e]), q, location=l); + return accessBouncer(target, + application( + baseExpr(qName(loc, "silver:core:getTermThatWasDecorated"), location=loc), '(', + oneAppExprs( + presentAppExpr(@e, location=loc), + location=loc), ',', + emptyAnnoAppExprs(location=loc), ')', + location=loc), + q, location=loc); } abstract production decoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { + undecorates to access(e, '.', q, location=top.location); top.unparse = e.unparse ++ "." ++ q.unparse; -- Note: LHS is decorated, here we dispatch based on the kind of attribute. - forwards to (if !q.found then errorDecoratedAccessHandler(_, _, location=_) + forwards to (if !q.found then unknownDclAccessHandler(_, _, location=_) else q.attrDcl.decoratedAccessHandler)(e, q, top.location); -- From here we go to: -- synDecoratedAccessHandler -- inhDecoratedAccessHandler - -- errorDecoratedAccessHandler -- unknown attribute error raised already. + -- unknownDclAccessHandler -- unknown attribute error raised already. } abstract production synDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { + undecorates to access(e, '.', q, location=top.location); top.unparse = e.unparse ++ "." ++ q.unparse; top.typerep = q.typerep; } abstract production inhDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { + undecorates to access(e, '.', q, location=top.location); top.unparse = e.unparse ++ "." ++ q.unparse; top.typerep = q.typerep; } --- TODO: change name. really "unknownDclAccessHandler" -abstract production errorDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +abstract production transDecoratedAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + undecorates to access(e, '.', q, location=top.location); + top.unparse = e.unparse ++ "." ++ q.unparse; + + top.typerep = q.typerep.asNtOrDecType; +} + +abstract production annoAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + undecorates to access(e, '.', q, location=top.location); + top.unparse = e.unparse ++ "." ++ q.unparse; + + production index :: Integer = + findNamedSigElem(q.name, annotationsForNonterminal(q.attrFor, top.env), 0); + + top.typerep = q.typerep; +} + +abstract production synDataAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + undecorates to access(e, '.', q, location=top.location); + top.unparse = e.unparse ++ "." ++ q.unparse; + + top.typerep = q.typerep; +} + +abstract production inhUndecoratedAccessErrorHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + undecorates to access(e, '.', q, location=top.location); + top.unparse = e.unparse ++ "." ++ q.unparse; + + top.typerep = q.typerep.asNtOrDecType; + + top.errors <- [err(top.location, s"Cannot access inherited attribute ${q.attrDcl.fullName} from an undecorated type")]; +} + +abstract production transUndecoratedAccessErrorHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + undecorates to access(e, '.', q, location=top.location); + top.unparse = e.unparse ++ "." ++ q.unparse; + + top.typerep = q.typerep.asNtOrDecType; + + top.errors <- [err(top.location, s"Cannot access translation attribute ${q.attrDcl.fullName} from an undecorated type")]; +} + +abstract production unknownDclAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { + undecorates to access(e, '.', q, location=top.location); top.unparse = e.unparse ++ "." ++ q.unparse; top.typerep = errorType(); @@ -525,7 +620,7 @@ top::Expr ::= 'decorate' e::Expr 'with' '{' '}' { top.unparse = "decorate " ++ e.unparse ++ " with {}"; - forwards to decorateExprWith($1, e, $3, $4, exprInhsEmpty(location=top.location), $5, location=top.location); + forwards to decorateExprWith($1, @e, $3, $4, exprInhsEmpty(location=top.location), $5, location=top.location); } concrete production decorateExprWith @@ -536,7 +631,7 @@ top::Expr ::= 'decorate' e::Expr 'with' '{' inh::ExprInhs '}' production eType::Type = performSubstitution(e.typerep, inh.downSubst); -- Specialize e.typerep production ntType::Type = if eType.isDecorated then eType.decoratedType else eType; - -- TODO: This _could_ be partiallyDecoratedType, but we use decorate in a ton of places where we expect a decoratedType + -- TODO: This _could_ be uniqueDecoratedType, but we use decorate in a ton of places where we expect a decoratedType top.typerep = decoratedType(ntType, inhSetType(sort(nub(inh.suppliedInhs ++ eType.inhSetMembers)))); e.isRoot = false; @@ -544,6 +639,15 @@ top::Expr ::= 'decorate' e::Expr 'with' '{' inh::ExprInhs '}' inh.allSuppliedInhs = inh.suppliedInhs; } +concrete production decorationSiteExpr +top::Expr ::= '@' e::Expr +{ + top.unparse = s"@${e.unparse}"; + + top.typerep = e.typerep.decoratedType; + e.isRoot = false; +} + abstract production exprInhsEmpty top::ExprInhs ::= { @@ -574,8 +678,11 @@ top::ExprInh ::= lhs::ExprLHSExpr '=' e::Expr ';' top.unparse = lhs.unparse ++ " = " ++ e.unparse ++ ";"; top.suppliedInhs = lhs.suppliedInhs; + + e.isRoot = false; } +-- TODO: permit supplying inhs on translation attributes concrete production exprLhsExpr top::ExprLHSExpr ::= q::QNameAttrOccur { @@ -739,6 +846,10 @@ precedence = 0 top.unparse = "if " ++ e1.unparse ++ " then " ++ e2.unparse ++ " else " ++ e3.unparse; top.typerep = e2.typerep; + + e1.isRoot=false; + e2.isRoot=false; + e3.isRoot=false; } concrete production intConst @@ -890,6 +1001,8 @@ top::Exprs ::= e::Expr top.exprs := [e]; top.rawExprs := [e]; + + e.isRoot = false; } concrete production exprsCons top::Exprs ::= e1::Expr ',' e2::Exprs @@ -898,6 +1011,8 @@ top::Exprs ::= e1::Expr ',' e2::Exprs top.exprs := [e1] ++ e2.exprs; top.rawExprs := [e1] ++ e2.rawExprs; + + e1.isRoot = false; } @@ -907,14 +1022,19 @@ top::Exprs ::= e1::Expr ',' e2::Exprs -} nonterminal AppExprs with config, grammarName, env, location, unparse, errors, freeVars, frame, compiledGrammars, exprs, rawExprs, - isPartial, missingTypereps, appExprIndicies, appExprSize, appExprTypereps, appExprApplied, isRoot, originRules; + isPartial, missingTypereps, appExprIndicies, appExprSize, appExprTypereps, appExprApplied, originRules; +flowtype AppExprs = + decorate { + config, grammarName, env, frame, compiledGrammars, appExprTypereps, appExprApplied, originRules, + downSubst, finalSubst, flowEnv + }; nonterminal AppExpr with config, grammarName, env, location, unparse, errors, freeVars, frame, compiledGrammars, exprs, rawExprs, - isPartial, missingTypereps, appExprIndicies, appExprIndex, appExprTyperep, appExprApplied, isRoot, originRules; + isPartial, missingTypereps, appExprIndicies, appExprIndex, appExprTyperep, appExprApplied, originRules; -propagate errors, freeVars on AppExprs, AppExpr; -propagate exprs, rawExprs on AppExprs; +propagate config, grammarName, env, freeVars, frame, compiledGrammars, errors, originRules on AppExprs, AppExpr; +propagate appExprApplied, exprs, rawExprs on AppExprs; synthesized attribute isPartial :: Boolean; synthesized attribute missingTypereps :: [Type]; @@ -923,7 +1043,7 @@ synthesized attribute appExprSize :: Integer; inherited attribute appExprIndex :: Integer; inherited attribute appExprTypereps :: [Type]; inherited attribute appExprTyperep :: Type; -autocopy attribute appExprApplied :: String; +inherited attribute appExprApplied :: String; -- These are the "new" Exprs syntax. This allows missing (_) arguments, to indicate partial application. concrete production missingAppExpr @@ -949,6 +1069,8 @@ top::AppExpr ::= e::Expr top.rawExprs := [e]; top.exprs := [e]; top.appExprIndicies = [top.appExprIndex]; + + e.isRoot = false; } concrete production snocAppExprs @@ -1007,27 +1129,32 @@ nonterminal AnnoAppExprs with config, grammarName, env, location, unparse, errors, freeVars, frame, compiledGrammars, isPartial, appExprApplied, exprs, remainingFuncAnnotations, funcAnnotations, - missingAnnotations, partialAnnoTypereps, annoIndexConverted, annoIndexSupplied, isRoot, originRules; + missingAnnotations, partialAnnoTypereps, annoIndexConverted, annoIndexSupplied, originRules; nonterminal AnnoExpr with config, grammarName, env, location, unparse, errors, freeVars, frame, compiledGrammars, isPartial, appExprApplied, exprs, remainingFuncAnnotations, funcAnnotations, - missingAnnotations, partialAnnoTypereps, annoIndexConverted, annoIndexSupplied, isRoot, originRules; - -propagate errors, freeVars, exprs on AnnoAppExprs, AnnoExpr; + missingAnnotations, partialAnnoTypereps, annoIndexConverted, annoIndexSupplied, originRules; +flowtype decorate { + grammarName, env, flowEnv, downSubst, finalSubst, frame, originRules, compiledGrammars, config, + appExprApplied, remainingFuncAnnotations, funcAnnotations + } on AnnoAppExprs, AnnoExpr; + +propagate config, grammarName, env, errors, freeVars, frame, compiledGrammars, exprs, funcAnnotations, appExprApplied, originRules + on AnnoAppExprs, AnnoExpr; {-- - Annotations that have not yet been supplied -} -inherited attribute remainingFuncAnnotations :: [Pair]; +inherited attribute remainingFuncAnnotations :: [(String, Type)]; {-- - All annotations of this function -} -autocopy attribute funcAnnotations :: [Pair]; +inherited attribute funcAnnotations :: [(String, Type)]; {-- - Annotations that have not been supplied (by subtracting from remainingFuncAnnotations) -} -synthesized attribute missingAnnotations :: [Pair]; +synthesized attribute missingAnnotations :: [(String, Type)]; {-- - Typereps of those annotations that are partial (_) -} @@ -1041,7 +1168,7 @@ top::AnnoExpr ::= qn::QName '=' e::AppExpr { top.unparse = qn.unparse ++ "=" ++ e.unparse; - local fq :: Pair> [Pair]> = + local fq :: (Maybe<(String, Type)>, [(String, Type)]) = extractNamedArg(qn.name, top.remainingFuncAnnotations); e.appExprIndex = @@ -1119,24 +1246,24 @@ function reorderedAnnoAppExprs [Decorated Expr] ::= d::Decorated AnnoAppExprs { -- This is an annoyingly poor quality implementation - return map(snd, sortBy(reorderedLte, zipWith(pair, d.annoIndexSupplied, d.exprs))); + return map(snd, sortBy(reorderedLte, zip(d.annoIndexSupplied, d.exprs))); } function reorderedLte -Boolean ::= l::Pair r::Pair { return l.fst <= r.fst; } +Boolean ::= l::(Integer, Decorated Expr) r::(Integer, Decorated Expr) { return l.fst <= r.fst; } function extractNamedArg -Pair> [Pair]> ::= n::String l::[Pair] +(Maybe<(String, Type)>, [(String, Type)]) ::= n::String l::[(String, Type)] { - local recurse :: Pair> [Pair]> = + local recurse :: (Maybe<(String, Type)>, [(String, Type)]) = extractNamedArg(n, tail(l)); - return if null(l) then pair(nothing(), []) - else if head(l).fst == n then pair(just(head(l)), tail(l)) - else pair(recurse.fst, head(l) :: recurse.snd); + return if null(l) then (nothing(), []) + else if head(l).fst == n then (just(head(l)), tail(l)) + else (recurse.fst, head(l) :: recurse.snd); } function findNamedArgType -Integer ::= s::String l::[Pair] z::Integer +Integer ::= s::String l::[(String, Type)] z::Integer { return if null(l) then -1 else if s == head(l).fst then z @@ -1177,53 +1304,16 @@ AnnoExpr ::= p::Pair } {-- - - Utility for other modules to create function invocations. - - - - Major assumption: The expressions are already decorated, and the - - typing substitution threaded through them will then be fed through - - the expr created by this function. - - - - The purpose of this vs just mkFunctionInvocationDecorated - - is to avoid exponential growth from forwarding. Type checking - - an expr, then forwarding to a function call that again type - - checks that expr well... just nest those and boom. - -} -function mkFunctionInvocationDecorated -Expr ::= l::Location e::Expr es::[PartiallyDecorated Expr] -{ - return mkFunctionInvocation(l, e, map(exprRef(_, location=l), es)); -} -function mkStrFunctionInvocationDecorated -Expr ::= l::Location e::String es::[PartiallyDecorated Expr] -{ - return mkFunctionInvocation(l, baseExpr(qName(l, e), location=l), map(exprRef(_, location=l), es)); -} - -{-- - - We allow references to existing subexpressions to appear arbitrarily in trees. + - Note on the use of the 'decorated here' (@) operator with already-decorated expressions: - - - There is one MAJOR restriction on the use of this production: - - The referenced expression (e) MUST APPEAR in the same expression tree + - There is one MAJOR restriction on the use of this operator: + - The referenced expression MUST APPEAR in the same expression tree - as it is referenced in. - - This is for type information reasons: the subtree referenced must have been - typechecked in the same 'typing context' as wherever this tree appears. - - - This is trivially satisfied for the typical use case for this production, + - This is trivially satisfied for the typical use case for this operator, - where you're typechecking your children, then forwarding to some tree with - references to those children. - -} -abstract production exprRef -top::Expr ::= e::PartiallyDecorated Expr -{ - top.unparse = e.unparse; - - -- See the major restriction. This should have been checked for error already! - top.typerep = e.typerep; - - -- TODO: one of the little things we might want is to make this transparent to - -- forwarding. e.g. e might be a 'childReference' and pattern matching would - -- need to separately account for this! - -- To accomplish this, we might want some notion of a decorated forward. -} - + -} \ No newline at end of file diff --git a/grammars/silver/compiler/definition/core/FunctionDcl.sv b/grammars/silver/compiler/definition/core/FunctionDcl.sv index 60fef7243..ae6269bf0 100644 --- a/grammars/silver/compiler/definition/core/FunctionDcl.sv +++ b/grammars/silver/compiler/definition/core/FunctionDcl.sv @@ -3,7 +3,7 @@ grammar silver:compiler:definition:core; nonterminal FunctionSignature with config, grammarName, env, location, unparse, errors, defs, constraintDefs, occursDefs, namedSignature, signatureName; nonterminal FunctionLHS with config, grammarName, env, location, unparse, errors, defs, outputElement; -propagate errors on FunctionSignature, FunctionLHS; +propagate config, grammarName, errors on FunctionSignature, FunctionLHS; concrete production functionDcl top::AGDcl ::= 'function' id::Name ns::FunctionSignature body::ProductionBody @@ -23,9 +23,9 @@ top::AGDcl ::= 'function' id::Name ns::FunctionSignature body::ProductionBody else []; top.errors <- - if null(body.uniqueSignificantExpression) + if null(body.returnExpr) then [err(top.location, "Function '" ++ id.name ++ "' does not have a return value.")] - else if length(body.uniqueSignificantExpression) > 1 + else if length(body.returnExpr) > 1 then [err(top.location, "Function '" ++ id.name ++ "' has more than one declared return value.")] else []; @@ -51,6 +51,8 @@ top::FunctionSignature ::= cl::ConstraintList '=>' lhs::FunctionLHS '::=' rhs::P top.unparse = s"${cl.unparse} => ${lhs.unparse} ::= ${rhs.unparse}"; cl.constraintPos = signaturePos(top.namedSignature); + cl.env = top.env; + lhs.env = top.env; rhs.env = occursEnv(cl.occursDefs, top.env); top.defs := lhs.defs ++ rhs.defs; @@ -83,6 +85,7 @@ concrete production functionLHS top::FunctionLHS ::= t::TypeExpr { top.unparse = t.unparse; + propagate env; production attribute fName :: String; fName = "__func__lhs"; diff --git a/grammars/silver/compiler/definition/core/GrammarParts.sv b/grammars/silver/compiler/definition/core/GrammarParts.sv index 2f335b4a0..74857097b 100644 --- a/grammars/silver/compiler/definition/core/GrammarParts.sv +++ b/grammars/silver/compiler/definition/core/GrammarParts.sv @@ -7,7 +7,7 @@ nonterminal Grammar with grammarName, env, globalImports, grammarDependencies, -- Synthesized attributes declaredName, moduleNames, exportedGrammars, optionalGrammars, condBuild, - defs, occursDefs, importedDefs, importedOccursDefs, grammarErrors, allFileErrors, jarName; + defs, occursDefs, importedDefs, importedOccursDefs, allFileErrors, jarName; flowtype Grammar = decorate {config, compiledGrammars, productionFlowGraphs, grammarFlowTypes, grammarName, env, flowEnv, globalImports, grammarDependencies}; @@ -16,13 +16,13 @@ flowtype Grammar = decorate {config, compiledGrammars, productionFlowGraphs, gra - directly or indirectly. (i.e. based on other grammar's exports) - NOT including options. -} -autocopy attribute grammarDependencies :: [String]; +inherited attribute grammarDependencies :: [String]; {-- - Grammar-wide imports definitions. Exists because we need to place - a file's individual imports between grammar definitions and grammar - wide imports. -} -autocopy attribute globalImports :: Decorated Env; +inherited attribute globalImports :: Env; {-- - The definitions resulting from grammar-wide imports definitions. - At the top of a grammar, these are echoed down as globalImports @@ -39,6 +39,8 @@ synthesized attribute grammarErrors :: [Pair]; synthesized attribute allFileErrors :: [Pair]; propagate + config, compiledGrammars, productionFlowGraphs, grammarFlowTypes, + grammarName, env, globalImports, grammarDependencies, moduleNames, exportedGrammars, optionalGrammars, condBuild, defs, occursDefs, importedDefs, importedOccursDefs, jarName on Grammar; @@ -49,7 +51,6 @@ top::Grammar ::= -- A value here is actually used. Grammars without any .sv files -- turn into this, and this "aren't found". TODO verify this is true? top.declaredName = ":null"; - top.grammarErrors = []; top.allFileErrors = []; } @@ -57,10 +58,10 @@ abstract production consGrammar top::Grammar ::= h::Root t::Grammar { top.declaredName = if h.declaredName == t.declaredName then h.declaredName else top.grammarName; - top.grammarErrors = - if null(h.errors ++ jarNameErrors) then t.grammarErrors - else pair(h.location.filename, h.errors ++ jarNameErrors) :: t.grammarErrors; - top.allFileErrors = (h.location.filename, h.errors ++ jarNameErrors) :: t.allFileErrors; - local jarNameErrors :: [Message] = warnIfMultJarName(h.jarName, t.jarName, h.location); + production attribute rootErrors::[Message] with ++; + rootErrors := h.errors; + top.allFileErrors = (h.location.filename, rootErrors) :: t.allFileErrors; + + rootErrors <- warnIfMultJarName(h.jarName, t.jarName, h.location); } diff --git a/grammars/silver/compiler/definition/core/InstanceDcl.sv b/grammars/silver/compiler/definition/core/InstanceDcl.sv index 0bea79490..7174dd16e 100644 --- a/grammars/silver/compiler/definition/core/InstanceDcl.sv +++ b/grammars/silver/compiler/definition/core/InstanceDcl.sv @@ -61,6 +61,7 @@ top::AGDcl ::= 'instance' cl::ConstraintList '=>' id::QNameType ty::TypeExpr '{' headDefs <- [currentInstDef(top.grammarName, id.location, fName, ty.typerep)]; cl.env = newScopeEnv(headPreDefs, top.env); + id.env = cl.env; ty.env = cl.env; body.env = occursEnv(cl.occursDefs, newScopeEnv(headDefs, cl.env)); @@ -82,22 +83,26 @@ top::AGDcl ::= 'instance' id::QNameType ty::TypeExpr '{' body::InstanceBody '}' insert semantic token IdTypeClass_t at id.baseNameLoc; } -autocopy attribute className::String; -autocopy attribute instanceType::Type; +inherited attribute className::String; +inherited attribute instanceType::Type; inherited attribute expectedClassMembers::[Pair]; nonterminal InstanceBody with - config, grammarName, env, defs, flowEnv, flowDefs, location, unparse, errors, compiledGrammars, className, instanceType, frameContexts, expectedClassMembers, definedMembers; + config, grammarName, env, defs, location, unparse, errors, compiledGrammars, className, instanceType, frameContexts, expectedClassMembers, definedMembers; nonterminal InstanceBodyItem with - config, grammarName, env, defs, flowEnv, flowDefs, location, unparse, errors, compiledGrammars, className, instanceType, frameContexts, expectedClassMembers, fullName; + config, grammarName, env, defs, location, unparse, errors, compiledGrammars, className, instanceType, frameContexts, expectedClassMembers, fullName; -propagate defs, flowDefs, errors on InstanceBody, InstanceBodyItem; +propagate + config, grammarName, compiledGrammars, className, instanceType, + defs, errors, frameContexts + on InstanceBody, InstanceBodyItem; concrete production consInstanceBody top::InstanceBody ::= h::InstanceBodyItem t::InstanceBody { top.unparse = h.unparse ++ "\n" ++ t.unparse; top.definedMembers = h.fullName :: t.definedMembers; + propagate env; h.expectedClassMembers = top.expectedClassMembers; t.expectedClassMembers = @@ -147,6 +152,8 @@ top::InstanceBodyItem ::= id::QName '=' e::Expr ';' top.fullName = id.lookupValue.fullName; + id.env = top.env; + local cmDefs::[Def] = flatMap( \ c::Context -> c.contextMemberDefs(boundVars, top.grammarName, top.location), diff --git a/grammars/silver/compiler/definition/core/ModuleStmts.sv b/grammars/silver/compiler/definition/core/ModuleStmts.sv index da6b18e55..e83c976e0 100644 --- a/grammars/silver/compiler/definition/core/ModuleStmts.sv +++ b/grammars/silver/compiler/definition/core/ModuleStmts.sv @@ -16,8 +16,10 @@ nonterminal NameList with config, grammarName, location, unparse, names, env; nonterminal WithElems with config, grammarName, location, unparse, envMaps; nonterminal WithElem with config, grammarName, location, unparse, envMaps; -propagate errors, moduleNames, defs, occursDefs on ModuleStmts, ModuleStmt, ImportStmt, ImportStmts; +propagate config, grammarName, errors, moduleNames, defs, occursDefs, compiledGrammars, grammarDependencies + on ModuleStmts, ModuleStmt, ImportStmt, ImportStmts; propagate exportedGrammars, optionalGrammars, condBuild on ModuleStmts; +propagate env on NameList; {-- - A list of QName strings. Used for 'only' and 'hiding'. @@ -380,7 +382,7 @@ concrete production withElement top::WithElem ::= n::QName 'as' newname::QName { top.unparse = n.unparse ++ " as " ++ newname.unparse; - top.envMaps = [pair(n.name, newname.name)]; + top.envMaps = [(n.name, newname.name)]; } ----------- diff --git a/grammars/silver/compiler/definition/core/NonTerminalDcl.sv b/grammars/silver/compiler/definition/core/NonTerminalDcl.sv index a70be8950..c22dfb8c5 100644 --- a/grammars/silver/compiler/definition/core/NonTerminalDcl.sv +++ b/grammars/silver/compiler/definition/core/NonTerminalDcl.sv @@ -1,6 +1,6 @@ grammar silver:compiler:definition:core; -autocopy attribute nonterminalName :: String; +inherited attribute nonterminalName :: String; concrete production nonterminalDcl top::AGDcl ::= quals::NTDeclQualifiers 'nonterminal' id::Name tl::BracketedOptTypeExprs nm::NonterminalModifiers ';' @@ -15,6 +15,7 @@ top::AGDcl ::= quals::NTDeclQualifiers 'nonterminal' id::Name tl::BracketedOptTy id.location, fName, map((.kindrep), tl.types), + quals.data, quals.closed, quals.tracked)]; -- TODO: It's probably reasonable to skip listing @@ -29,6 +30,8 @@ top::AGDcl ::= quals::NTDeclQualifiers 'nonterminal' id::Name tl::BracketedOptTy -- Here we bind those type variables. tl.initialEnv = top.env; tl.env = tl.envBindingTyVars; + + nm.env = top.env; -- Redefinition check of the name top.errors <- @@ -44,38 +47,36 @@ top::AGDcl ::= quals::NTDeclQualifiers 'nonterminal' id::Name tl::BracketedOptTy insert semantic token IdTypeDcl_t at id.location; } -nonterminal NTDeclQualifiers with location, errors; +nonterminal NTDeclQualifiers with location, errors, data, closed, tracked; +propagate errors, data, closed, tracked on NTDeclQualifiers; -synthesized attribute closed :: Boolean occurs on NTDeclQualifiers; -synthesized attribute tracked :: Boolean occurs on NTDeclQualifiers; +monoid attribute data :: Boolean with false, ||; +monoid attribute closed :: Boolean with false, ||; +monoid attribute tracked :: Boolean with false, ||; concrete production nilNTQualifier top::NTDeclQualifiers ::= { - -- This controls the default closed-ness and tracked-ness of nonterminals - top.closed = false; - top.tracked = false; +} - top.errors := []; +concrete production dataNTQualifier +top::NTDeclQualifiers ::= 'data' rest::NTDeclQualifiers +{ + top.data <- true; + top.errors <- if rest.data then [err(top.location, "Duplicate 'data' qualifier")] else []; } concrete production closedNTQualifier top::NTDeclQualifiers ::= 'closed' rest::NTDeclQualifiers { - top.closed = true; - top.tracked = rest.tracked; - - top.errors := rest.errors; + top.closed <- true; top.errors <- if rest.closed then [err(top.location, "Duplicate 'closed' qualifier")] else []; } concrete production trackedNTQualifier top::NTDeclQualifiers ::= 'tracked' rest::NTDeclQualifiers { - top.closed = rest.closed; - top.tracked = true; - - top.errors := rest.errors; + top.tracked <- true; top.errors <- if rest.tracked then [err(top.location, "Duplicate 'tracked' qualifier")] else []; } @@ -83,7 +84,8 @@ nonterminal NonterminalModifiers with config, location, unparse, errors, env, no nonterminal NonterminalModifierList with config, location, unparse, errors, env, nonterminalName; -- 1 or more closed nonterminal NonterminalModifier with config, location, unparse, errors, env, nonterminalName; -- 1 -propagate errors on NonterminalModifiers, NonterminalModifierList, NonterminalModifier; +propagate config, errors, env, nonterminalName + on NonterminalModifiers, NonterminalModifierList, NonterminalModifier; concrete production nonterminalModifiersNone top::NonterminalModifiers ::= diff --git a/grammars/silver/compiler/definition/core/OccursDcl.sv b/grammars/silver/compiler/definition/core/OccursDcl.sv index 18ebabafe..0787d65bb 100644 --- a/grammars/silver/compiler/definition/core/OccursDcl.sv +++ b/grammars/silver/compiler/definition/core/OccursDcl.sv @@ -1,8 +1,9 @@ grammar silver:compiler:definition:core; abstract production defaultAttributionDcl -top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs +top::AGDcl ::= at::Decorated! QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs { + undecorates to attributionDcl('attribute', at, attl, 'occurs', 'on', nt, nttl, ';', location=top.location); top.unparse = "attribute " ++ at.unparse ++ attl.unparse ++ " occurs on " ++ nt.unparse ++ nttl.unparse ++ ";"; -- TODO: this location is highly unreliable. @@ -31,6 +32,7 @@ top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QNam nttl.initialEnv = top.env; attl.env = nttl.envBindingTyVars; + nt.env = top.env; nttl.env = nttl.envBindingTyVars; local ntTypeScheme::PolyType = nt.lookupType.typeScheme; @@ -39,7 +41,7 @@ top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QNam -- Make sure we get the number and kind of type variables correct for the NT local ntParamKinds :: [Kind] = case nt.lookupType.dcls of - | ntDcl(_, ks, _, _) :: _ -> ks + | ntDcl(_, ks, _, _, _) :: _ -> ks | _ -> [] end; top.errors <- @@ -114,25 +116,37 @@ top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QNam else []; top.errors <- - if nt.lookupType.found && (!nt.lookupType.dcl.isType || !isDecorable(ntTypeScheme.typerep, top.env)) + if nt.lookupType.found && (!nt.lookupType.dcl.isType || !ntTypeScheme.typerep.isNonterminal) then [err(nt.location, nt.name ++ " is not a nonterminal. Attributes can only occur on nonterminals.")] else []; - + top.errors <- if !nt.lookupType.found || !at.lookupAttribute.found || !at.lookupAttribute.dcl.isAnnotation || isExportedBy(top.grammarName, [nt.lookupType.dcl.sourceGrammar], top.compiledGrammars) then [] else [err(top.location, "Annotations for a nonterminal must be in a module exported by the nonterminal's declaring grammar.")]; + + top.errors <- + if nt.lookupType.found && ntTypeScheme.isData && at.lookupAttribute.found + then + if at.lookupAttribute.dcl.isInherited + then [err(top.location, "Inherited attributes may not occur on data nonterminals.")] + else if at.lookupAttribute.dcl.isTranslation + then [err(top.location, "Translation attributes may not occur on data nonterminals.")] + else [] + else []; } abstract production errorAttributionDcl -top::AGDcl ::= msg::[Message] at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs +top::AGDcl ::= msg::[Message] at::Decorated! QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs { + undecorates to errorAGDcl(msg, location=top.location); top.unparse = "attribute " ++ at.unparse ++ attl.unparse ++ " occurs on " ++ nt.unparse ++ nttl.unparse ++ ";"; top.occursDefs := []; top.errors <- msg; nttl.initialEnv = top.env; attl.env = nttl.envBindingTyVars; + nt.env = top.env; nttl.env = nttl.envBindingTyVars; -- Decorate everything else to still check for errors @@ -145,11 +159,11 @@ top::AGDcl ::= msg::[Message] at::PartiallyDecorated QName attl::BracketedOptTyp -- Make sure we get the number and kinds of tyvars correct for the NT top.errors <- case nt.lookupType.dcls of - | ntDcl(_, ks, _, _) :: _ when length(ks) != length(nttl.types) -> + | ntDcl(_, ks, _, _, _) :: _ when length(ks) != length(nttl.types) -> [err(nt.location, nt.name ++ " expects " ++ toString(length(ks)) ++ " type variables, but " ++ toString(length(nttl.types)) ++ " were provided.")] - | ntDcl(_, ks, _, _) :: _ when ks != map((.kindrep), nttl.types) -> + | ntDcl(_, ks, _, _, _) :: _ when ks != map((.kindrep), nttl.types) -> [err(nt.location, nt.name ++ " had kind " ++ foldr(arrowKind, starKind(), ks).typepp ++ " but type variable(s) have kind(s) " ++ implode(", ", map(compose(prettyKind, (.kindrep)), nttl.types)) ++ ".")] @@ -161,6 +175,7 @@ concrete production attributionDcl top::AGDcl ::= 'attribute' at::QName attl::BracketedOptTypeExprs 'occurs' 'on' nt::QName nttl::BracketedOptTypeExprs ';' { top.unparse = "attribute " ++ at.unparse ++ attl.unparse ++ " occurs on " ++ nt.unparse ++ nttl.unparse ++ ";"; + propagate env; -- Workaround for circular dependency due to dispatching on env: -- Nothing used to build the env namespaces on which we dispatch can depend on diff --git a/grammars/silver/compiler/definition/core/ProductionBody.sv b/grammars/silver/compiler/definition/core/ProductionBody.sv index c1b8e21ba..e9045fb09 100644 --- a/grammars/silver/compiler/definition/core/ProductionBody.sv +++ b/grammars/silver/compiler/definition/core/ProductionBody.sv @@ -2,13 +2,13 @@ grammar silver:compiler:definition:core; nonterminal ProductionBody with config, grammarName, env, location, unparse, errors, defs, frame, compiledGrammars, - productionAttributes, uniqueSignificantExpression; + productionAttributes, forwardExpr, returnExpr, undecorateExpr; nonterminal ProductionStmts with config, grammarName, env, location, unparse, errors, defs, frame, compiledGrammars, - productionAttributes, uniqueSignificantExpression, originRules; + productionAttributes, forwardExpr, returnExpr, undecorateExpr, originRules; nonterminal ProductionStmt with config, grammarName, env, location, unparse, errors, defs, frame, compiledGrammars, - productionAttributes, uniqueSignificantExpression, originRules; + productionAttributes, forwardExpr, returnExpr, undecorateExpr, originRules; flowtype decorate {frame, grammarName, compiledGrammars, config, env, flowEnv, downSubst} on ProductionBody; @@ -35,17 +35,19 @@ nonterminal ForwardLHSExpr with - Context for ProductionStmt blocks. (Indicates function, production, aspect, etc) - Includes singature for those contexts with a signature. -} -autocopy attribute frame :: BlockContext; +inherited attribute frame :: BlockContext; {-- - Defs of attributes that should be wrapped up as production attributes. -} monoid attribute productionAttributes :: [Def]; {-- - - Either the 'forward' expression, or the 'return' expression. - - I gave it an obtuse name so it could easily be renamed in the future. + - The forward, return and undecorate expressions for production/function bodies. + - These are lists since we check for duplicates at the top level -} -monoid attribute uniqueSignificantExpression :: [Decorated Expr]; +monoid attribute forwardExpr :: [Decorated Expr]; +monoid attribute returnExpr :: [Decorated Expr]; +monoid attribute undecorateExpr :: [Decorated Expr]; {-- - The attribute we're defining on a DefLHS. @@ -56,8 +58,11 @@ inherited attribute defLHSattr :: Decorated QNameAttrOccur; -- Notes flow 'up' in this from statements and then back 'down' into the via originRules. synthesized attribute originRuleDefs :: [Decorated Expr] occurs on ProductionStmt, ProductionStmts; -propagate errors on ProductionBody, ProductionStmts, ProductionStmt, DefLHS, ForwardInhs, ForwardInh, ForwardLHSExpr; -propagate defs, productionAttributes, uniqueSignificantExpression on ProductionBody, ProductionStmts; +propagate config, grammarName, env, errors, frame, compiledGrammars on + ProductionBody, ProductionStmts, ProductionStmt, DefLHS, ForwardInhs, ForwardInh, ForwardLHSExpr; +propagate defs, productionAttributes, forwardExpr, returnExpr, undecorateExpr on ProductionBody, ProductionStmts; +propagate originRules on ProductionStmts, ProductionStmt, DefLHS, ForwardInhs, ForwardInh, ForwardLHSExpr + excluding attachNoteStmt; concrete production productionBody @@ -92,7 +97,7 @@ top::ProductionStmt ::= h::ProductionStmt t::ProductionStmt top.unparse = h.unparse ++ "\n" ++ t.unparse; top.originRuleDefs = h.originRuleDefs ++ t.originRuleDefs; - propagate defs, productionAttributes, uniqueSignificantExpression; + propagate defs, productionAttributes, forwardExpr, returnExpr, undecorateExpr; } abstract production errorProductionStmt @@ -110,7 +115,9 @@ top::ProductionStmt ::= -- as is usual for defaults ("base classes") -- can't provide unparse or location, errors should NOT be defined! top.productionAttributes := []; - top.uniqueSignificantExpression := []; + top.forwardExpr := []; + top.returnExpr := []; + top.undecorateExpr := []; top.defs := []; @@ -131,7 +138,7 @@ top::ProductionStmt ::= 'return' e::Expr ';' { top.unparse = "\treturn " ++ e.unparse ++ ";"; - top.uniqueSignificantExpression := [e]; + top.returnExpr := [e]; top.errors <- if !top.frame.permitReturn then [err(top.location, "Return is not valid in this context. (They are only permitted in function declarations.)")] @@ -148,7 +155,7 @@ top::ProductionStmt ::= 'local' 'attribute' a::Name '::' te::TypeExpr ';' production attribute fName :: String; fName = s"${top.frame.fullName}:local:${top.grammarName}:${implode("_", filter(isAlpha, explode(".", top.location.filename)))}:${toString(top.location.line)}:${toString(top.location.column)}:${a.name}"; - top.defs := [localDef(top.grammarName, a.location, fName, te.typerep)]; + top.defs := [localDef(top.grammarName, a.location, fName, te.typerep, false)]; top.errors <- if length(getValueDclInScope(a.name, top.env)) > 1 @@ -168,7 +175,7 @@ top::ProductionStmt ::= 'production' 'attribute' a::Name '::' te::TypeExpr ';' production attribute fName :: String; fName = top.frame.fullName ++ ":local:" ++ top.grammarName ++ ":" ++ a.name; - top.productionAttributes := [localDef(top.grammarName, a.location, fName, te.typerep)]; + top.productionAttributes := [localDef(top.grammarName, a.location, fName, te.typerep, false)]; top.errors <- if length(getValueDclAll(fName, top.env)) > 1 @@ -180,6 +187,26 @@ top::ProductionStmt ::= 'production' 'attribute' a::Name '::' te::TypeExpr ';' else []; } +concrete production forwardProductionAttributeDcl +top::ProductionStmt ::= 'forward' 'production' 'attribute' a::Name ';' +{ + top.unparse = "\tforward production attribute " ++ a.unparse ++ ";"; + + production attribute fName :: String; + fName = top.frame.fullName ++ ":local:" ++ top.grammarName ++ ":" ++ a.name; + + top.productionAttributes := [localDef(top.grammarName, a.location, fName, top.frame.signature.outputElement.typerep, true)]; + + top.errors <- + if length(getValueDclAll(fName, top.env)) > 1 + then [err(a.location, "Value '" ++ fName ++ "' is already bound.")] + else []; + + top.errors <- if !top.frame.permitForwardProductionAttributes + then [err(top.location, "Forward production attributes are not valid in this context.")] + else []; +} + concrete production forwardsTo top::ProductionStmt ::= 'forwards' 'to' e::Expr ';' { @@ -188,7 +215,7 @@ top::ProductionStmt ::= 'forwards' 'to' e::Expr ';' e.isRoot = true; top.productionAttributes := [forwardDef(top.grammarName, top.location, top.frame.signature.outputElement.typerep)]; - top.uniqueSignificantExpression := [e]; + top.forwardExpr := [e]; top.errors <- if !top.frame.permitForward then [err(top.location, "Forwarding is not permitted in this context. (Only permitted in non-aspect productions.)")] @@ -251,10 +278,26 @@ top::ForwardLHSExpr ::= q::QNameAttrOccur q.attrFor = top.frame.signature.outputElement.typerep; } +concrete production undecoratesTo +top::ProductionStmt ::= 'undecorates' 'to' e::Expr ';' +{ + top.unparse = "\tundecorates to " ++ e.unparse; + + e.isRoot = true; + + top.undecorateExpr := [e]; + + top.errors <- + if !top.frame.permitForward -- Permitted in the same place as forwards to + then [err(top.location, "Undecorates is not permitted in this context. (Only permitted in non-aspect productions.)")] + else []; +} + concrete production attributeDef top::ProductionStmt ::= dl::DefLHS '.' attr::QNameAttrOccur '=' e::Expr ';' { top.unparse = "\t" ++ dl.unparse ++ "." ++ attr.unparse ++ " = " ++ e.unparse ++ ";"; + propagate grammarName, config, env, frame, compiledGrammars, originRules; -- defs must stay here explicitly, because we dispatch on types in the forward here! top.productionAttributes := []; @@ -281,36 +324,66 @@ top::ProductionStmt ::= dl::DefLHS '.' attr::QNameAttrOccur '=' e::Expr ';' {- This is a helper that exist primarily to decorate 'e' and add its error messages to the list. Invariant: msg should not be null! -} abstract production errorAttributeDef -top::ProductionStmt ::= msg::[Message] dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= msg::[Message] dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { + undecorates to errorProductionStmt(msg, location=top.location); top.unparse = "\t" ++ dl.unparse ++ "." ++ attr.unparse ++ " = " ++ e.unparse ++ ";"; - + propagate grammarName, config, env, frame, compiledGrammars, originRules; e.isRoot = true; forwards to errorProductionStmt(msg ++ e.errors, location=top.location); } abstract production synthesizedAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { + undecorates to attributeDef(dl, '.', attr, '=', e, ';', location=top.location); top.unparse = "\t" ++ dl.unparse ++ "." ++ attr.unparse ++ " = " ++ e.unparse ++ ";"; e.isRoot = true; + + top.errors <- + case getValueDcl(top.frame.fullName, top.env) of + | dcl :: _ when dcl.hasForward && attr.found && attr.attrDcl.isTranslation -> + [err(top.location, s"Overriding translation attribute ${attr.attrDcl.fullName} in a forwarding production is not currently supported.")] + | _ -> [] + end; } abstract production inheritedAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { + undecorates to attributeDef(dl, '.', attr, '=', e, ';', location=top.location); top.unparse = "\t" ++ dl.unparse ++ "." ++ attr.unparse ++ " = " ++ e.unparse ++ ";"; e.isRoot = true; } +-- The grammar needs to be structured in this way to avoid a shift/reduce conflict... +concrete production transInhAttributeDef +top::ProductionStmt ::= dl::DefLHS '.' transAttr::QNameAttrOccur '.' attr::QNameAttrOccur '=' e::Expr ';' +{ + top.unparse = "\t" ++ dl.unparse ++ "." ++ transAttr.unparse ++ "." ++ attr.unparse ++ " = " ++ e.unparse ++ ";"; + dl.env = top.env; + dl.grammarName = top.grammarName; + dl.config = top.config; + forwards to + attributeDef( + transAttrDefLHS( + case dl of + | concreteDefLHS(q) -> q + | _ -> error("Unexpected concrete DefLHS") + end, transAttr, location=top.location), + $4, attr, $6, e, $8, + location=top.location); +} + concrete production concreteDefLHS top::DefLHS ::= q::QName { top.name = q.name; top.unparse = q.unparse; + propagate env; forwards to (if null(q.lookupValue.dcls) then errorDefLHS(_, location=_) @@ -322,8 +395,9 @@ top::DefLHS ::= q::QName } abstract production errorDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName { + undecorates to concreteDefLHS(q, location=top.location); top.name = q.name; top.unparse = q.unparse; top.found = false; @@ -331,7 +405,7 @@ top::DefLHS ::= q::PartiallyDecorated QName top.errors <- q.lookupValue.errors; top.errors <- if top.typerep.isError then [] else [err(q.location, "Cannot define attributes on " ++ q.name)]; - top.typerep = q.lookupValue.typeScheme.monoType; + top.typerep = q.lookupValue.typeScheme.typerep; } concrete production concreteDefLHSfwd @@ -341,8 +415,9 @@ top::DefLHS ::= q::'forward' } abstract production childDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName { + undecorates to concreteDefLHS(q, location=top.location); top.name = q.name; top.unparse = q.unparse; top.found = !existingProblems && top.defLHSattr.attrDcl.isInherited; @@ -357,8 +432,9 @@ top::DefLHS ::= q::PartiallyDecorated QName } abstract production lhsDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName { + undecorates to concreteDefLHS(q, location=top.location); top.name = q.name; top.unparse = q.unparse; top.found = !existingProblems && top.defLHSattr.attrDcl.isSynthesized; @@ -373,8 +449,9 @@ top::DefLHS ::= q::PartiallyDecorated QName } abstract production localDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName { + undecorates to concreteDefLHS(q, location=top.location); top.name = q.name; top.unparse = q.unparse; top.found = !existingProblems && top.defLHSattr.attrDcl.isInherited; @@ -389,8 +466,9 @@ top::DefLHS ::= q::PartiallyDecorated QName } abstract production forwardDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName { + undecorates to concreteDefLHS(q, location=top.location); top.name = q.name; top.unparse = q.unparse; top.found = !existingProblems && top.defLHSattr.attrDcl.isInherited; @@ -404,12 +482,93 @@ top::DefLHS ::= q::PartiallyDecorated QName top.typerep = q.lookupValue.typeScheme.monoType; } +-- See transAttributeDef above - this is abstract to avoid a shift/reduce conflict. +abstract production transAttrDefLHS +top::DefLHS ::= q::QName attr::QNameAttrOccur +{ + top.name = q.name; + top.unparse = s"${q.unparse}.${attr.unparse}"; + propagate env; + attr.grammarName = top.grammarName; + attr.config = top.config; + attr.attrFor = q.lookupValue.typeScheme.monoType; + + forwards to (if null(q.lookupValue.dcls) || !attr.found || !attr.attrDcl.isTranslation + then errorTransAttrDefLHS(_, _, location=_) + else q.lookupValue.dcl.transDefLHSDispatcher)(q, attr, top.location); +} + +abstract production errorTransAttrDefLHS +top::DefLHS ::= q::Decorated! QName attr::Decorated! QNameAttrOccur +{ + undecorates to transAttrDefLHS(q, attr, location=top.location); + top.name = q.name; + top.unparse = s"${q.unparse}.${attr.unparse}"; + top.found = false; + + top.errors <- q.lookupValue.errors; + top.errors <- + if top.typerep.isError then [] else [err(q.location, "Cannot define attributes on " ++ top.unparse)]; + top.typerep = attr.typerep; +} + +abstract production childTransAttrDefLHS +top::DefLHS ::= q::Decorated! QName attr::Decorated! QNameAttrOccur +{ + undecorates to transAttrDefLHS(q, attr, location=top.location); + top.name = q.name; + top.unparse = s"${q.unparse}.${attr.unparse}"; + top.found = !existingProblems && attr.attrDcl.isSynthesized && top.defLHSattr.attrDcl.isInherited; + + local existingProblems :: Boolean = !top.defLHSattr.found || !attr.found || top.typerep.isError; + + top.errors <- + if existingProblems then [] + else if !top.defLHSattr.attrDcl.isInherited + then [err(attr.location, s"Attribute '${attr.name}' is not inherited and cannot be defined on '${top.unparse}'")] + else []; + + local ty::Type = q.lookupValue.typeScheme.monoType; + top.errors <- + if attr.found && !ty.isNonterminal && !ty.isUniqueDecorated + then [err(q.location, s"Inherited equations on translation attributes on child ${q.name} of type ${prettyType(ty)} are not supported")] + else []; + + top.typerep = attr.typerep; +} + +abstract production localTransAttrDefLHS +top::DefLHS ::= q::Decorated! QName attr::Decorated! QNameAttrOccur +{ + undecorates to transAttrDefLHS(q, attr, location=top.location); + top.name = q.name; + top.unparse = s"${q.unparse}.${attr.unparse}"; + top.found = !existingProblems && attr.attrDcl.isSynthesized && top.defLHSattr.attrDcl.isInherited; + + local existingProblems :: Boolean = !top.defLHSattr.found || !attr.found || top.typerep.isError; + + top.errors <- + if existingProblems then [] + else if !top.defLHSattr.attrDcl.isInherited + then [err(attr.location, s"Attribute '${attr.name}' is not inherited and cannot be defined on '${top.unparse}'")] + else []; + + local ty::Type = q.lookupValue.typeScheme.monoType; + top.errors <- + if attr.found && !ty.isNonterminal && !ty.isUniqueDecorated + then [err(q.location, s"Inherited equations on translation attributes on local ${q.name} of type ${prettyType(ty)} are not supported")] + else []; + + top.typerep = attr.typerep; +} + ----- done with DefLHS concrete production valueEq top::ProductionStmt ::= val::QName '=' e::Expr ';' { top.unparse = "\t" ++ val.unparse ++ " = " ++ e.unparse ++ ";"; + propagate env; top.errors <- val.lookupValue.errors; @@ -423,8 +582,9 @@ top::ProductionStmt ::= val::QName '=' e::Expr ';' } abstract production errorValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { + undecorates to valueEq(val, '=', e, ';', location=top.location); top.unparse = "\t" ++ val.unparse ++ " = " ++ e.unparse ++ ";"; e.isRoot = true; @@ -435,8 +595,9 @@ top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr } abstract production localValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { + undecorates to valueEq(val, '=', e, ';', location=top.location); top.unparse = "\t" ++ val.unparse ++ " = " ++ e.unparse ++ ";"; -- val is already valid here diff --git a/grammars/silver/compiler/definition/core/ProductionDcl.sv b/grammars/silver/compiler/definition/core/ProductionDcl.sv index 6002b6b6b..3f2c82d6b 100644 --- a/grammars/silver/compiler/definition/core/ProductionDcl.sv +++ b/grammars/silver/compiler/definition/core/ProductionDcl.sv @@ -11,8 +11,9 @@ flowtype forward {deterministicCount, env} on ProductionRHSElem; flowtype decorate {forward, grammarName, flowEnv} on ProductionSignature, ProductionLHS, ProductionRHS, ProductionRHSElem; -propagate errors on ProductionSignature, ProductionLHS, ProductionRHS, ProductionRHSElem; -propagate defs on ProductionRHS; +propagate config, grammarName, errors on + ProductionSignature, ProductionLHS, ProductionRHS, ProductionRHSElem; +propagate env, defs on ProductionRHS; {-- - Used to help give names to children, when names are omitted. @@ -44,7 +45,7 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr production fName :: String = top.grammarName ++ ":" ++ id.name; production namedSig :: NamedSignature = ns.namedSignature; - top.defs := prodDef(top.grammarName, id.location, namedSig, length(body.uniqueSignificantExpression) > 0) :: + top.defs := prodDef(top.grammarName, id.location, namedSig, length(body.forwardExpr) > 0) :: if null(body.productionAttributes) then [] else [prodOccursDef(top.grammarName, id.location, namedSig, body.productionAttributes)]; @@ -58,9 +59,14 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr else []; top.errors <- - if length(body.uniqueSignificantExpression) > 1 + if length(body.forwardExpr) > 1 then [err(top.location, "Production '" ++ id.name ++ "' has more than one forward declaration.")] else []; + + top.errors <- + if length(body.undecorateExpr) > 1 + then [err(top.location, "Production '" ++ id.name ++ "' has more than one undecorate declaration.")] + else []; top.errors <- if isLower(substring(0,1,id.name)) then [] @@ -87,7 +93,9 @@ top::ProductionSignature ::= cl::ConstraintList '=>' lhs::ProductionLHS '::=' rh { top.unparse = s"${cl.unparse} => ${lhs.unparse} ::= ${rhs.unparse}"; + cl.env = top.env; cl.constraintPos = signaturePos(top.namedSignature); + lhs.env = top.env; rhs.env = occursEnv(cl.occursDefs, top.env); top.defs := lhs.defs ++ rhs.defs; @@ -118,10 +126,11 @@ concrete production productionLHS top::ProductionLHS ::= id::Name '::' t::TypeExpr { top.unparse = id.unparse ++ "::" ++ t.unparse; + propagate env; top.outputElement = namedSignatureElement(id.name, t.typerep); - top.defs := [lhsDef(top.grammarName, t.location, id.name, t.typerep)]; + top.defs := [lhsDef(top.grammarName, id.location, id.name, t.typerep)]; top.errors <- if length(getValueDclInScope(id.name, top.env)) > 1 @@ -154,10 +163,11 @@ concrete production productionRHSElem top::ProductionRHSElem ::= id::Name '::' t::TypeExpr { top.unparse = id.unparse ++ "::" ++ t.unparse; + propagate env; top.inputElements = [namedSignatureElement(id.name, t.typerep)]; - top.defs := [childDef(top.grammarName, t.location, id.name, t.typerep)]; + top.defs := [childDef(top.grammarName, id.location, id.name, t.typerep)]; top.errors <- if length(getValueDclInScope(id.name, top.env)) > 1 diff --git a/grammars/silver/compiler/definition/core/Project.sv b/grammars/silver/compiler/definition/core/Project.sv index 0373d9a3d..bbd13459c 100644 --- a/grammars/silver/compiler/definition/core/Project.sv +++ b/grammars/silver/compiler/definition/core/Project.sv @@ -10,9 +10,15 @@ imports silver:compiler:definition:type:syntax; -- Type Representation imports silver:compiler:definition:type; +-- Type Checking +imports silver:compiler:analysis:typechecking:core; + -- Environment Representation imports silver:compiler:definition:env; +-- Flow Information +imports silver:compiler:definition:flow:env; + -- Utilities option silver:compiler:definition:concrete_syntax; @@ -33,6 +39,7 @@ option silver:compiler:modification:copper_mda; option silver:compiler:extension:testing; -- TODO this is about that buggy experiment of Eric's... -- These are somewhat less than desirable exports, due to the modularity analysis. -exports silver:compiler:analysis:typechecking:core; -exports silver:compiler:definition:flow:env; +option silver:compiler:definition:type:syntax; +option silver:compiler:analysis:typechecking:core; +option silver:compiler:definition:flow:env; diff --git a/grammars/silver/compiler/definition/core/QName.sv b/grammars/silver/compiler/definition/core/QName.sv index daf2e7f41..c4ee8100e 100644 --- a/grammars/silver/compiler/definition/core/QName.sv +++ b/grammars/silver/compiler/definition/core/QName.sv @@ -34,9 +34,9 @@ top::QName ::= id::Name top.qNameType = qNameTypeId(terminal(IdUpper_t, id.name, id.location), location=id.location); top.baseNameLoc = id.location; - top.lookupValue = decorate customLookup("value", getValueDcl(top.name, top.env), top.name, top.location) with {}; - top.lookupType = decorate customLookup("type", getTypeDcl(top.name, top.env), top.name, top.location) with {}; - top.lookupAttribute = decorate customLookup("attribute", getAttrDcl(top.name, top.env), top.name, top.location) with {}; + top.lookupValue = customLookup("value", getValueDcl(top.name, top.env), top.name, top.location); + top.lookupType = customLookup("type", getTypeDcl(top.name, top.env), top.name, top.location); + top.lookupAttribute = customLookup("attribute", getAttrDcl(top.name, top.env), top.name, top.location); } concrete production qNameCons @@ -47,9 +47,9 @@ top::QName ::= id::Name ':' qn::QName top.qNameType = qNameTypeCons(id, ':', qn.qNameType, location=top.location); top.baseNameLoc = qn.baseNameLoc; - top.lookupValue = decorate customLookup("value", getValueDcl(top.name, top.env), top.name, top.location) with {}; - top.lookupType = decorate customLookup("type", getTypeDcl(top.name, top.env), top.name, top.location) with {}; - top.lookupAttribute = decorate customLookup("attribute", getAttrDcl(top.name, top.env), top.name, top.location) with {}; + top.lookupValue = customLookup("value", getValueDcl(top.name, top.env), top.name, top.location); + top.lookupType = customLookup("type", getTypeDcl(top.name, top.env), top.name, top.location); + top.lookupAttribute = customLookup("attribute", getAttrDcl(top.name, top.env), top.name, top.location); } action { insert semantic token IdGrammarName_t at id.location; } @@ -62,16 +62,16 @@ top::QName ::= msg::[Message] top.qNameType = qNameTypeId(terminal(IdUpper_t, "Err", top.location), location=top.location); top.baseNameLoc = top.location; - top.lookupValue = decorate errorLookup(msg) with {}; - top.lookupType = decorate errorLookup(msg) with {}; - top.lookupAttribute = decorate errorLookup(msg) with {}; + top.lookupValue = errorLookup(msg); + top.lookupType = errorLookup(msg); + top.lookupAttribute = errorLookup(msg); } -nonterminal QNameLookup with fullName, typeScheme, errors, dcls, dcl, found; +data nonterminal QNameLookup with fullName, typeScheme, errors, dcls, dcl, found; -synthesized attribute lookupValue :: Decorated QNameLookup occurs on QName; -synthesized attribute lookupType :: Decorated QNameLookup occurs on QName; -synthesized attribute lookupAttribute :: Decorated QNameLookup occurs on QName; +synthesized attribute lookupValue :: QNameLookup occurs on QName; +synthesized attribute lookupType :: QNameLookup occurs on QName; +synthesized attribute lookupAttribute :: QNameLookup occurs on QName; flowtype QName = lookupValue {env}, lookupType {env}, lookupAttribute {env}; @@ -136,7 +136,7 @@ top::QNameType ::= id::IdUpper_t top.unparse = id.lexeme; top.baseNameLoc = id.location; - top.lookupType = decorate customLookup("type", getTypeDcl(top.name, top.env), top.name, top.location) with {}; + top.lookupType = customLookup("type", getTypeDcl(top.name, top.env), top.name, top.location); } concrete production qNameTypeCons @@ -146,7 +146,7 @@ top::QNameType ::= id::Name ':' qn::QNameType top.baseNameLoc = qn.baseNameLoc; top.unparse = id.unparse ++ ":" ++ qn.unparse; - top.lookupType = decorate customLookup("type", getTypeDcl(top.name, top.env), top.name, top.location) with {}; + top.lookupType = customLookup("type", getTypeDcl(top.name, top.env), top.name, top.location); } action { insert semantic token IdGrammarName_t at id.location; } @@ -156,7 +156,7 @@ top::QNameType ::= id::Name ':' qn::QNameType -} nonterminal QNameAttrOccur with config, name, location, grammarName, env, unparse, attrFor, errors, typerep, dcl, attrDcl, found, attrFound; -flowtype QNameAttrOccur = decorate {grammarName, env, attrFor}, dcl {decorate}, attrDcl {decorate}; +flowtype QNameAttrOccur = decorate {grammarName, config, env, attrFor}, dcl {grammarName, env, attrFor}, attrDcl {grammarName, env, attrFor}; {-- - For QNameAttrOccur, the name of the LHS to look up this attribute on. @@ -185,6 +185,7 @@ top::QNameAttrOccur ::= at::QName { top.name = at.name; top.unparse = at.unparse; + propagate env; -- We start with all attributes we find with the name `at`: local attrs :: [AttributeDclInfo] = at.lookupAttribute.dcls; diff --git a/grammars/silver/compiler/definition/core/Root.sv b/grammars/silver/compiler/definition/core/Root.sv index 88a857877..0306ecdf7 100644 --- a/grammars/silver/compiler/definition/core/Root.sv +++ b/grammars/silver/compiler/definition/core/Root.sv @@ -19,16 +19,11 @@ nonterminal GrammarDcl with declaredName, grammarName, location, unparse, errors; propagate errors on Root, GrammarDcl; -propagate moduleNames on Root; +propagate config, compiledGrammars, grammarName, globalImports, grammarDependencies, moduleNames on Root; concrete production root top::Root ::= gdcl::GrammarDcl ms::ModuleStmts ims::ImportStmts ags::AGDcls { - ims.compiledGrammars = top.compiledGrammars; - ims.grammarDependencies = top.grammarDependencies; - ims.grammarName = top.grammarName; - ims.config = top.config; - top.unparse = gdcl.unparse ++ "\n\n" ++ ms.unparse ++ "\n\n" ++ ims.unparse ++ "\n\n" ++ ags.unparse; top.declaredName = gdcl.declaredName; diff --git a/grammars/silver/compiler/definition/core/Terminals.sv b/grammars/silver/compiler/definition/core/Terminals.sv index b435bec1d..111af9d14 100644 --- a/grammars/silver/compiler/definition/core/Terminals.sv +++ b/grammars/silver/compiler/definition/core/Terminals.sv @@ -34,8 +34,8 @@ terminal Aspect_kwd 'aspect' lexer classes {KEYWORD,RESERVED}; terminal Attribute_kwd 'attribute' lexer classes {KEYWORD,RESERVED}; terminal Class_kwd 'class' lexer classes {KEYWORD}; terminal Closed_kwd 'closed' lexer classes {KEYWORD}; -terminal Tracked_kwd 'tracked' lexer classes {KEYWORD}; terminal Concrete_kwd 'concrete' lexer classes {KEYWORD,RESERVED}; +terminal Data_kwd 'data' lexer classes {KEYWORD}; terminal Decorate_kwd 'decorate' lexer classes {KEYWORD,RESERVED}; terminal Else_kwd 'else' lexer classes {KEYWORD,RESERVED}, precedence = 4, association = left; -- Association needed for dangling else in action code. terminal End_kwd 'end' lexer classes {KEYWORD,RESERVED}; @@ -57,11 +57,15 @@ terminal Synthesized_kwd 'synthesized' lexer classes {KEYWORD,RESERVED}; terminal Terminal_kwd 'terminal' lexer classes {KEYWORD,RESERVED}; terminal Then_kwd 'then' lexer classes {KEYWORD,RESERVED}; terminal To_kwd 'to' lexer classes {KEYWORD,RESERVED}; +terminal Tracked_kwd 'tracked' lexer classes {KEYWORD}; +terminal Translation_kwd 'translation' lexer classes {KEYWORD}; terminal Type_t 'type' lexer classes {KEYWORD}; +terminal Undecorates_t 'undecorates' lexer classes {KEYWORD,RESERVED}; terminal With_kwd 'with' lexer classes {KEYWORD,RESERVED}, precedence = 3; -- Precedence to fix Decorated Decorated Expr with {}, which is a semantic error either way terminal AttachNote_kwd 'attachNote' lexer classes {BUILTIN,RESERVED}; +terminal DecSite_t '@' lexer classes {OP}, precedence = 2; terminal Comma_t ',' precedence = 4; terminal Or_t '||' lexer classes {OP}, precedence = 5, association = left; terminal And_t '&&' lexer classes {OP}, precedence = 6, association = left; @@ -92,9 +96,13 @@ terminal CCEQ_t '::=' lexer classes {SPECOP}; terminal Equal_t '=' lexer classes {SPECOP}; terminal CtxArrow_t '=>' lexer classes {SPECOP}; --- Unused infix operators: ~ ` @ # % ^ & | \ +-- Unused infix operators: ~ ` # % ^ & | \ -- $ is used by convenience. +disambiguate IdLower_t, Data_kwd { pluck Data_kwd; } +disambiguate IdLower_t, Closed_kwd { pluck Closed_kwd; } +disambiguate IdLower_t, Tracked_kwd { pluck Tracked_kwd; } + -- this is a very careful regex. beware: --ignore terminal BlockComments /\{\-([^\-]|\-+[^\}\-])*\-+\}/ lexer classes {COMMENT}; ignore terminal BlockComments /\{\-(\{\-([^\-]|\-+[^\}\-])*\-+\}|[^\-]|\-+[^\}\-])*\-+\}/ lexer classes {COMMENT}; -- Allows (one level of) nested comments. diff --git a/grammars/silver/compiler/definition/core/Type.sv b/grammars/silver/compiler/definition/core/Type.sv index f63b6f3e5..866903ee2 100644 --- a/grammars/silver/compiler/definition/core/Type.sv +++ b/grammars/silver/compiler/definition/core/Type.sv @@ -1,10 +1,10 @@ grammar silver:compiler:definition:core; -- LHS type gives this to 'application' for "foo(...)" calls. -synthesized attribute applicationDispatcher :: (Expr ::= PartiallyDecorated Expr PartiallyDecorated AppExprs PartiallyDecorated AnnoAppExprs Location); +synthesized attribute applicationDispatcher :: (Expr ::= Decorated! Expr Decorated! AppExprs Decorated! AnnoAppExprs Location); -- LHS type gives this to 'access' for "foo.some" accesses. -- (See DclInfo for the next step) -synthesized attribute accessHandler :: (Expr ::= PartiallyDecorated Expr PartiallyDecorated QNameAttrOccur Location); +synthesized attribute accessHandler :: (Expr ::= Decorated! Expr Decorated! QNameAttrOccur Location); -- Used for poor man's type classes -- TODO: Finish removing these and replace with real type classes @@ -54,9 +54,12 @@ top::Type ::= } aspect production nonterminalType -top::Type ::= fn::String _ _ +top::Type ::= fn::String _ data::Boolean _ { - top.accessHandler = undecoratedAccessHandler(_, _, location=_); + top.accessHandler = + if data + then dataAccessHandler(_, _, location=_) + else undecoratedAccessHandler(_, _, location=_); } aspect production terminalType @@ -71,7 +74,7 @@ top::Type ::= te::Type _ top.accessHandler = decoratedAccessHandler(_, _, location=_); } -aspect production partiallyDecoratedType +aspect production uniqueDecoratedType top::Type ::= te::Type _ { top.accessHandler = decoratedAccessHandler(_, _, location=_); diff --git a/grammars/silver/compiler/definition/env/Attributes.sv b/grammars/silver/compiler/definition/env/Attributes.sv index 5927de124..dab50e44a 100644 --- a/grammars/silver/compiler/definition/env/Attributes.sv +++ b/grammars/silver/compiler/definition/env/Attributes.sv @@ -66,7 +66,7 @@ monoid attribute defs :: [Def]; {-- - The environment. Dun dun dunnn. -} -autocopy attribute env :: Decorated Env; +inherited attribute env :: Env; -- -- Top-level, compiler-wide information passed down by the build process @@ -75,16 +75,16 @@ autocopy attribute env :: Decorated Env; {-- - All grammars Silver looked at. Despite the name, including interface files. -} -autocopy attribute compiledGrammars :: EnvTree; +inherited attribute compiledGrammars :: EnvTree; {-- - Compiler configuration information, made available everywhere. -} -autocopy attribute config :: Decorated CmdArgs; +inherited attribute config :: Decorated CmdArgs; {-- - Flow information computed for this grammar -} -autocopy attribute productionFlowGraphs :: EnvTree; -autocopy attribute grammarFlowTypes :: EnvTree; +inherited attribute productionFlowGraphs :: EnvTree; +inherited attribute grammarFlowTypes :: EnvTree; {-- - The path to the origin of this root spec diff --git a/grammars/silver/compiler/definition/env/Context.sv b/grammars/silver/compiler/definition/env/Context.sv index 3a1886525..96209db1b 100644 --- a/grammars/silver/compiler/definition/env/Context.sv +++ b/grammars/silver/compiler/definition/env/Context.sv @@ -4,11 +4,14 @@ import silver:compiler:definition:core only frame, grammarName, compiledGrammars -- Context lookup/resolution stuff lives here -attribute env occurs on Context; +attribute env, config, compiledGrammars, grammarFlowTypes occurs on Context; +propagate env, config, compiledGrammars, grammarFlowTypes on Context, Contexts; -- This mostly exists as a convenient way to perform multiple env-dependant operations -- on a list of contexts without re-decorating them and repeating context resolution. nonterminal Contexts with env, config, compiledGrammars, grammarFlowTypes, contexts, freeVariables, boundVariables; +propagate boundVariables on Contexts; + abstract production consContext top::Contexts ::= h::Context t::Contexts { @@ -38,8 +41,6 @@ synthesized attribute resolvedOccurs::[OccursDclInfo] occurs on Context; monoid attribute isTypeError::Boolean with false, || occurs on Contexts, Context; propagate isTypeError on Contexts, Context; -attribute config, compiledGrammars, grammarFlowTypes occurs on Context; - aspect default production top::Context ::= { @@ -261,7 +262,7 @@ Boolean ::= a::Type b::Type (isMoreSpecific(c1, c2) || isMoreSpecific(a1, a2)) && !(isMoreSpecific(c2, c1) || isMoreSpecific(a2, a1)) | decoratedType(t1, i1), decoratedType(t2, i2) -> (isMoreSpecific(t1, t2) || isMoreSpecific(i1, i2)) && !(isMoreSpecific(t2, t1) || isMoreSpecific(i2, i1)) - | partiallyDecoratedType(t1, i1), partiallyDecoratedType(t2, i2) -> + | uniqueDecoratedType(t1, i1), uniqueDecoratedType(t2, i2) -> (isMoreSpecific(t1, t2) || isMoreSpecific(i1, i2)) && !(isMoreSpecific(t2, t1) || isMoreSpecific(i2, i1)) | _, _ -> false end; diff --git a/grammars/silver/compiler/definition/env/DclInfo.sv b/grammars/silver/compiler/definition/env/DclInfo.sv index e65c9e002..bc219af49 100644 --- a/grammars/silver/compiler/definition/env/DclInfo.sv +++ b/grammars/silver/compiler/definition/env/DclInfo.sv @@ -18,6 +18,7 @@ synthesized attribute isType :: Boolean; synthesized attribute isTypeAlias :: Boolean; synthesized attribute isClass :: Boolean; synthesized attribute classMembers :: [Pair]; +synthesized attribute isClosed :: Boolean; -- instances inherited attribute givenInstanceType :: Type; @@ -38,6 +39,7 @@ synthesized attribute isAnnotation :: Boolean; -- also "attrs" -- attrs synthesized attribute isSynthesized :: Boolean; synthesized attribute isInherited :: Boolean; +synthesized attribute isTranslation :: Boolean; -- production attribute synthesized attribute prodDefs :: [Def]; @@ -78,13 +80,14 @@ top::ValueDclInfo ::= fn::String ty::Type -- ValueDclInfos that CAN appear in interface files, but only via "production attributes:" abstract production localDcl -top::ValueDclInfo ::= fn::String ty::Type +top::ValueDclInfo ::= fn::String ty::Type isForward::Boolean { top.fullName = fn; top.typeScheme = monoType(ty); - top.substitutedDclInfo = localDcl( fn, performRenaming(ty, top.givenSubstitution), sourceGrammar=top.sourceGrammar, sourceLocation=top.sourceLocation); + top.hasForward = isForward; + top.substitutedDclInfo = localDcl( fn, performRenaming(ty, top.givenSubstitution), isForward, sourceGrammar=top.sourceGrammar, sourceLocation=top.sourceLocation); } abstract production forwardDcl top::ValueDclInfo ::= ty::Type @@ -149,7 +152,7 @@ top::ValueDclInfo ::= fn::String closed nonterminal TypeDclInfo with sourceGrammar, sourceLocation, fullName, compareTo, isEqual, - typeScheme, kindrep, givenNonterminalType, isType, isTypeAlias, mentionedAliases, isClass, classMembers, givenInstanceType, superContexts; + typeScheme, kindrep, givenNonterminalType, isType, isTypeAlias, mentionedAliases, isClass, classMembers, givenInstanceType, superContexts, isClosed; propagate isEqual, compareTo on TypeDclInfo excluding typeAliasDcl, clsDcl; aspect default production @@ -162,16 +165,18 @@ top::TypeDclInfo ::= top.isClass = false; top.classMembers = []; top.superContexts = []; + top.isClosed = false; } abstract production ntDcl -top::TypeDclInfo ::= fn::String ks::[Kind] closed::Boolean tracked::Boolean +top::TypeDclInfo ::= fn::String ks::[Kind] data::Boolean closed::Boolean tracked::Boolean { top.fullName = fn; - top.typeScheme = monoType(nonterminalType(fn, ks, tracked)); + top.typeScheme = monoType(nonterminalType(fn, ks, data, tracked)); top.kindrep = foldr(arrowKind, starKind(), ks); top.isType = true; + top.isClosed = closed; } abstract production termDcl top::TypeDclInfo ::= fn::String regex::Regex easyName::Maybe genRepeatProb::Maybe @@ -232,7 +237,7 @@ top::TypeDclInfo ::= fn::String supers::[Context] tv::TyVar k::Kind members::[Pa closed nonterminal AttributeDclInfo with sourceGrammar, sourceLocation, fullName, compareTo, compareKey, isEqual, - typeScheme, isInherited, isSynthesized, isAnnotation; + typeScheme, isInherited, isSynthesized, isAnnotation, isTranslation; propagate compareKey on AttributeDclInfo; aspect default production @@ -246,6 +251,7 @@ top::AttributeDclInfo ::= top.isSynthesized = false; top.isInherited = false; top.isAnnotation = false; + top.isTranslation = false; } abstract production synDcl @@ -264,6 +270,15 @@ top::AttributeDclInfo ::= fn::String bound::[TyVar] ty::Type top.typeScheme = polyType(bound, ty); top.isInherited = true; } +abstract production transDcl +top::AttributeDclInfo ::= fn::String bound::[TyVar] ty::Type +{ + top.fullName = fn; + + top.typeScheme = polyType(bound, ty); + top.isSynthesized = true; + top.isTranslation = true; +} abstract production annoDcl top::AttributeDclInfo ::= fn::String bound::[TyVar] ty::Type { diff --git a/grammars/silver/compiler/definition/env/Defs.sv b/grammars/silver/compiler/definition/env/Defs.sv index 382c8a217..ea8049d26 100644 --- a/grammars/silver/compiler/definition/env/Defs.sv +++ b/grammars/silver/compiler/definition/env/Defs.sv @@ -131,9 +131,9 @@ Def ::= sg::String sl::Location fn::String ty::Type return valueDef(defaultEnvItem(lhsDcl(fn,ty,sourceGrammar=sg,sourceLocation=sl))); } function localDef -Def ::= sg::String sl::Location fn::String ty::Type +Def ::= sg::String sl::Location fn::String ty::Type isForward::Boolean { - return valueDef(defaultEnvItem(localDcl(fn,ty,sourceGrammar=sg,sourceLocation=sl))); + return valueDef(defaultEnvItem(localDcl(fn,ty,isForward,sourceGrammar=sg,sourceLocation=sl))); } function prodDef Def ::= sg::String sl::Location ns::NamedSignature hasForward::Boolean @@ -156,9 +156,9 @@ Def ::= sg::String sl::Location fn::String bound::[TyVar] head::Context conte return valueDef(defaultEnvItem(classMemberDcl(fn,bound,head,contexts,ty,sourceGrammar=sg,sourceLocation=sl))); } function ntDef -Def ::= sg::String sl::Location fn::String ks::[Kind] closed::Boolean tracked::Boolean +Def ::= sg::String sl::Location fn::String ks::[Kind] data::Boolean closed::Boolean tracked::Boolean { - return typeDef(defaultEnvItem(ntDcl(fn,ks,closed,tracked,sourceGrammar=sg,sourceLocation=sl))); + return typeDef(defaultEnvItem(ntDcl(fn,ks,data,closed,tracked,sourceGrammar=sg,sourceLocation=sl))); } function termDef Def ::= sg::String sl::Location fn::String regex::Regex easyName::Maybe genRepeatProb::Maybe @@ -193,6 +193,11 @@ Def ::= sg::String sl::Location fn::String bound::[TyVar] ty::Type { return attrDef(defaultEnvItem(inhDcl(fn,bound,ty,sourceGrammar=sg,sourceLocation=sl))); } +function transDef +Def ::= sg::String sl::Location fn::String bound::[TyVar] ty::Type +{ + return attrDef(defaultEnvItem(transDcl(fn,bound,ty,sourceGrammar=sg,sourceLocation=sl))); +} function prodOccursDef Def ::= sg::String sl::Location ns::NamedSignature dcls::[Def] { diff --git a/grammars/silver/compiler/definition/env/Env.sv b/grammars/silver/compiler/definition/env/Env.sv index 4f17899a8..9145bf9a6 100644 --- a/grammars/silver/compiler/definition/env/Env.sv +++ b/grammars/silver/compiler/definition/env/Env.sv @@ -1,19 +1,19 @@ grammar silver:compiler:definition:env; --- emptyEnv Decorated Env ::= --- toEnv Decorated Env ::= d::Defs --- appendEnv Decorated Env ::= e1::Decorated Env e2::Decorated Env --- newScopeEnv Decorated Env ::= e1::Defs e2::Decorated Env +-- emptyEnv Env ::= +-- toEnv Env ::= d::Defs +-- appendEnv Env ::= e1::Env e2::Env +-- newScopeEnv Env ::= e1::Defs e2::Env --- [DclInfo] ::= search::String e::Decorated Env +-- [DclInfo] ::= search::String e::Env -- getValueDclInScope getValueDcl getValueDclAll -- getTypeDcl -- getAttrDcl --- getProdAttrs [DclInfo] ::= prod::String e::Decorated Env +-- getProdAttrs [DclInfo] ::= prod::String e::Env -nonterminal Env with typeTree, valueTree, attrTree, instTree, prodOccursTree, occursTree, prodsForNtTree; +data nonterminal Env with typeTree, valueTree, attrTree, instTree, prodOccursTree, occursTree, prodsForNtTree; synthesized attribute typeTree :: [EnvTree]; -- Expr is type tau synthesized attribute valueTree :: [EnvTree]; -- x has type tau @@ -29,12 +29,7 @@ synthesized attribute prodsForNtTree :: [EnvTree]; -- maps nt fnam --Environment creation functions-------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -function emptyEnv -Decorated Env ::= -{ - return decorate i_emptyEnv() with {}; -} -abstract production i_emptyEnv +abstract production emptyEnv top::Env ::= { top.typeTree = [emptyEnvTree()]; @@ -49,7 +44,7 @@ top::Env ::= } function toEnv -Decorated Env ::= d::[Def] +Env ::= d::[Def] { return newScopeEnv(d, emptyEnv()); } @@ -65,13 +60,8 @@ Decorated Env ::= d::[Def] - Instead, we build these three scopes as essentially separate environments, - and append them together in the correct order. -} -function appendEnv -Decorated Env ::= e1::Decorated Env e2::Decorated Env -{ - return decorate i_appendEnv(e1, e2) with {}; -} -abstract production i_appendEnv -top::Env ::= e1::Decorated Env e2::Decorated Env +abstract production appendEnv +top::Env ::= e1::Env e2::Env { top.typeTree = e1.typeTree ++ e2.typeTree; top.valueTree = e1.valueTree ++ e2.valueTree; @@ -87,14 +77,10 @@ top::Env ::= e1::Decorated Env e2::Decorated Env {-- - The usual means of introducing new defs to an environment, by creating a new nested scope. -} -function newScopeEnv -Decorated Env ::= d::[Def] e::Decorated Env -{ - return decorate i_newScopeEnv(foldr(consDefs, nilDefs(), d), e) with {}; -} -abstract production i_newScopeEnv -top::Env ::= d::Defs e::Decorated Env +abstract production newScopeEnv +top::Env ::= ds::[Def] e::Env { + production d::Defs = foldr(consDefs, nilDefs(), ds); top.typeTree = buildTree(d.typeList) :: e.typeTree; top.valueTree = buildTree(d.valueList) :: e.valueTree; top.attrTree = buildTree(d.attrList) :: e.attrTree; @@ -112,13 +98,8 @@ top::Env ::= d::Defs e::Decorated Env - Introduces new occurs defs to an environment. - This is seperate from newScopeEnv as we must be able to build the other env trees without having the occurs tree. -} -function occursEnv -Decorated Env ::= d::[OccursDclInfo] e::Decorated Env -{ - return decorate i_occursEnv(d, e) with {}; -} -abstract production i_occursEnv -top::Env ::= d::[OccursDclInfo] e::Decorated Env +abstract production occursEnv +top::Env ::= d::[OccursDclInfo] e::Env { top.typeTree = e.typeTree; top.valueTree = e.valueTree; @@ -152,55 +133,55 @@ function searchEnv } function getValueDclInScope -[ValueDclInfo] ::= search::String e::Decorated Env +[ValueDclInfo] ::= search::String e::Env { return searchEnvTree(search, head(e.valueTree)); } function getValueDcl -[ValueDclInfo] ::= search::String e::Decorated Env +[ValueDclInfo] ::= search::String e::Env { return searchEnv(search, e.valueTree); } function getValueDclAll -[ValueDclInfo] ::= search::String e::Decorated Env +[ValueDclInfo] ::= search::String e::Env { return searchEnvAll(search, e.valueTree); } function getTypeDclInScope -[TypeDclInfo] ::= search::String e::Decorated Env +[TypeDclInfo] ::= search::String e::Env { return searchEnvTree(search, head(e.typeTree)); } function getTypeDcl -[TypeDclInfo] ::= search::String e::Decorated Env +[TypeDclInfo] ::= search::String e::Env { return searchEnv(search, e.typeTree); } function getTypeDclAll -[TypeDclInfo] ::= search::String e::Decorated Env +[TypeDclInfo] ::= search::String e::Env { return searchEnvAll(search, e.typeTree); } function getAttrDclInScope -[AttributeDclInfo] ::= search::String e::Decorated Env +[AttributeDclInfo] ::= search::String e::Env { return searchEnvTree(search, head(e.attrTree)); } function getAttrDcl -[AttributeDclInfo] ::= search::String e::Decorated Env +[AttributeDclInfo] ::= search::String e::Env { return searchEnv(search, e.attrTree); } function getAttrDclAll -[AttributeDclInfo] ::= search::String e::Decorated Env +[AttributeDclInfo] ::= search::String e::Env { return searchEnvAll(search, e.attrTree); } function getOccursDcl -[OccursDclInfo] ::= fnat::String fnnt::String e::Decorated Env +[OccursDclInfo] ::= fnat::String fnnt::String e::Env { -- retrieve all attribute Dcls on NT fnnt return occursOnHelp(searchEnvTree(fnnt, e.occursTree), fnat); @@ -219,19 +200,19 @@ function occursOnHelp -- and whether a type may be supplied with inherited attributes. -- Used by expression (id refs), decorate type checking, and translations. function isDecorable -Boolean ::= t::Type e::Decorated Env +Boolean ::= t::Type e::Env { return case t of | skolemType(_) -> !null(searchEnvTree(t.typeName, e.occursTree)) | varType(_) -> !null(searchEnvTree(t.typeName, e.occursTree)) -- Can happen when pattern matching on a prod with occurs contexts - | partiallyDecoratedType(nt, _) -> isDecorable(nt, e) - | _ -> t.isNonterminal + | uniqueDecoratedType(nt, _) -> isDecorable(nt, e) + | _ -> t.isNonterminal && !t.isData end; } function getProdAttrs -[ProductionAttrDclInfo] ::= fnprod::String e::Decorated Env +[ProductionAttrDclInfo] ::= fnprod::String e::Env { return searchEnvTree(fnprod, e.prodOccursTree); } @@ -250,7 +231,7 @@ function getProdAttrs - You should probably have a good reason for using this, and document it here if you do. -} function getKnownProds -[ValueDclInfo] ::= fnnt::String e::Decorated Env +[ValueDclInfo] ::= fnnt::String e::Env { return searchEnvAll(fnnt, e.prodsForNtTree); } @@ -264,18 +245,69 @@ function getKnownProds - Obviously we can never know all attributes, but we generally don't need to for - any reason. -} -function getAttrsOn -[OccursDclInfo] ::= fnnt::String e::Decorated Env +function getAttrOccursOn +[OccursDclInfo] ::= fnnt::String e::Env { return searchEnvTree(fnnt, e.occursTree); } +{-- + - Returns the names of all synthesized attributes known locally to occur on a nonterminal. + -} +function getSynAttrsOn +[String] ::= fnnt::String e::Env +{ + return flatMap( + \ o::OccursDclInfo -> + case getAttrDcl(o.attrOccurring, e) of + | at :: _ when at.isSynthesized -> [o.attrOccurring] + | _ -> [] + end, + getAttrOccursOn(fnnt, e)); +} + +{-- + - Returns the names of all inherited attributes known locally to occur on a nonterminal. + -} +function getInhAttrsOn +[String] ::= fnnt::String e::Env +{ + return flatMap( + \ o::OccursDclInfo -> + case getAttrDcl(o.attrOccurring, e) of + | at :: _ when at.isInherited -> [o.attrOccurring] + | _ -> [] + end, + getAttrOccursOn(fnnt, e)); +} + +{-- + - Returns the names of all inherited attributes known locally to occur on a nonterminal. + - Also includes all inherited attributes occuring on translation attributes on the + - nonterminal, when we want to treat these like inherited attributes. + -} +function getInhAndInhOnTransAttrsOn +[String] ::= fnnt::String e::Env +{ + return flatMap( + \ o::OccursDclInfo -> + case getAttrDcl(o.attrOccurring, e) of + | at :: _ when at.isInherited -> [o.attrOccurring] + | at :: _ when at.isSynthesized && at.isTranslation -> + map( + \ inh::String -> s"${o.attrOccurring}.${inh}", + getInhAttrsOn(at.typeScheme.typeName, e)) + | _ -> [] + end, + getAttrOccursOn(fnnt, e)); +} + -- This ensure the annotation list is in the properly sorted order! function annotationsForNonterminal -[NamedSignatureElement] ::= nt::Type env::Decorated Env +[NamedSignatureElement] ::= nt::Type env::Env { local annos :: [OccursDclInfo] = - filter((.isAnnotation), getAttrsOn(nt.typeName, env)); + filter((.isAnnotation), getAttrOccursOn(nt.typeName, env)); return sortBy(namedSignatureElementLte, map(annoInstanceToNamed(nt, _), annos)); } @@ -291,7 +323,7 @@ NamedSignatureElement ::= nt::Type anno::OccursDclInfo -- Looks up class instances matching a type function getInstanceDcl -[InstDclInfo] ::= fntc::String t::Type e::Decorated Env +[InstDclInfo] ::= fntc::String t::Type e::Env { local c::Context = instContext(fntc, t); c.env = e; @@ -300,7 +332,7 @@ function getInstanceDcl -- Compute a lower bound on the members of an InhSet type, including transitive ones arising from subset constraints function getMinInhSetMembers -([String], [TyVar]) ::= seen::[TyVar] t::Type e::Decorated Env +([String], [TyVar]) ::= seen::[TyVar] t::Type e::Env { local c::Context = inhSubsetContext(varType(freshTyVar(inhSetKind())), t); c.env = e; @@ -319,19 +351,19 @@ function getMinInhSetMembers } function getMinRefSet -[String] ::= t::Type e::Decorated Env +[String] ::= t::Type e::Env { return case t of | decoratedType(_, i) -> getMinInhSetMembers([], i, e).fst - | partiallyDecoratedType(_, i) -> getMinInhSetMembers([], i, e).fst + | uniqueDecoratedType(_, i) -> getMinInhSetMembers([], i, e).fst | _ -> [] end; } -- Try to compute an upper bound on the members of an InhSet type, including transitive ones arising from subset constraints function getMaxInhSetMembers -(Maybe<[String]>, [TyVar]) ::= seen::[TyVar] t::Type e::Decorated Env +(Maybe<[String]>, [TyVar]) ::= seen::[TyVar] t::Type e::Env { local c::Context = inhSubsetContext(t, varType(freshTyVar(inhSetKind()))); c.env = e; @@ -354,12 +386,12 @@ function getMaxInhSetMembers } function getMaxRefSet -Maybe<[String]> ::= t::Type e::Decorated Env +Maybe<[String]> ::= t::Type e::Env { return case t of | decoratedType(_, i) -> getMaxInhSetMembers([], i, e).fst - | partiallyDecoratedType(_, i) -> getMaxInhSetMembers([], i, e).fst + | uniqueDecoratedType(_, i) -> getMaxInhSetMembers([], i, e).fst | _ -> just([]) end; } diff --git a/grammars/silver/compiler/definition/env/EnvItem.sv b/grammars/silver/compiler/definition/env/EnvItem.sv index c8735b4c8..802164021 100644 --- a/grammars/silver/compiler/definition/env/EnvItem.sv +++ b/grammars/silver/compiler/definition/env/EnvItem.sv @@ -35,8 +35,8 @@ ei::EnvItem ::= newname::String di::a ei.dcl = di; ei.envContribs = if newname != di.fullName - then [pair(newname, di), pair(di.fullName, di)] - else [pair(newname, di)]; + then [(newname, di), (di.fullName, di)] + else [(newname, di)]; ei.filterIncludeOnly := contains(newname, ei.filterItems); ei.filterIncludeHiding := !contains(newname, ei.filterItems); @@ -62,7 +62,7 @@ ei::EnvItem ::= di::a { ei.itemName = di.fullName; ei.dcl = di; - ei.envContribs = [pair(di.fullName, di)]; + ei.envContribs = [(di.fullName, di)]; propagate filterIncludeOnly, filterIncludeHiding, renamed, prepended; -- Always imported & not renamed propagate compareTo, isEqual; @@ -79,7 +79,7 @@ ei::EnvItem ::= newname::String di::a { ei.itemName = newname; ei.dcl = di; - ei.envContribs = [pair(newname, di)]; + ei.envContribs = [(newname, di)]; propagate filterIncludeOnly, filterIncludeHiding, renamed, prepended; -- Should never be imported propagate compareTo, isEqual; diff --git a/grammars/silver/compiler/definition/env/NamedSignature.sv b/grammars/silver/compiler/definition/env/NamedSignature.sv index c0a18f9dc..2d0a24e8e 100644 --- a/grammars/silver/compiler/definition/env/NamedSignature.sv +++ b/grammars/silver/compiler/definition/env/NamedSignature.sv @@ -7,9 +7,7 @@ grammar silver:compiler:definition:env; - TODO: we might want to remove the full name of the production from this, and make it just `Signature`? - It's not clear if this information really belongs here, or not. -} -nonterminal NamedSignature with fullName, contexts, inputElements, outputElement, namedInputElements, typeScheme, freeVariables, inputNames, inputTypes, typerep; - -flowtype NamedSignature = decorate {}; +data nonterminal NamedSignature with fullName, contexts, inputElements, outputElement, namedInputElements, typeScheme, freeVariables, inputNames, inputTypes, typerep, freshenNamedSignature; synthesized attribute inputElements :: [NamedSignatureElement]; synthesized attribute outputElement :: NamedSignatureElement; @@ -17,6 +15,10 @@ synthesized attribute namedInputElements :: [NamedSignatureElement]; synthesized attribute inputNames :: [String]; -- inputTypes comes from the types grammar. +-- "Freshens" all the signature's type variables with new skolem constants, +-- to avoid type vars from interface files clashing with new ones from genInt() +synthesized attribute freshenNamedSignature::NamedSignature; + @{- - Represents the signature of a production (or function). - @param fn The full name @@ -44,6 +46,13 @@ top::NamedSignature ::= fn::String ctxs::Contexts ie::NamedSignatureElements oe: ie.boundVariables = top.freeVariables; oe.boundVariables = top.freeVariables; np.boundVariables = top.freeVariables; + + top.freshenNamedSignature = namedSignature(fn, ctxs.flatRenamed, ie.flatRenamed, oe.flatRenamed, np.flatRenamed); + local freshSubst::Substitution = zipVarsAndTypesIntoSubstitution(top.freeVariables, map(skolemType, top.typeScheme.boundVars)); + ctxs.substitution = freshSubst; + ie.substitution = freshSubst; + oe.substitution = freshSubst; + np.substitution = freshSubst; } @{- @@ -66,24 +75,27 @@ top::NamedSignature ::= fn::String ctxs::Contexts ty::Type top.freeVariables = setUnionTyVars(ctxs.freeVariables, ty.freeVariables); top.typerep = ty; - ctxs.boundVariables = top.freeVariables; - ty.boundVariables = top.freeVariables; + top.freshenNamedSignature = globalSignature(fn, ctxs.flatRenamed, ty.flatRenamed); + local freshSubst::Substitution = zipVarsAndTypesIntoSubstitution(top.freeVariables, map(skolemType, top.typeScheme.boundVars)); + ctxs.substitution = freshSubst; + ty.substitution = freshSubst; } {-- - Used when an error occurs. e.g. aspecting a non-existant production. - Or, in contexts that have no valid signature, which maybe we should do something about... -} -abstract production bogusNamedSignature -top::NamedSignature ::= +function bogusNamedSignature +NamedSignature ::= { - forwards to namedSignature("_NULL_", nilContext(), nilNamedSignatureElement(), bogusNamedSignatureElement(), nilNamedSignatureElement()); + return namedSignature("_NULL_", nilContext(), nilNamedSignatureElement(), bogusNamedSignatureElement(), nilNamedSignatureElement()); } {-- - Represents a collection of NamedSignatureElements -} nonterminal NamedSignatureElements with elements, elementNames, elementShortNames, elementTypes, freeVariables, boundVariables; +propagate boundVariables on NamedSignatureElements; synthesized attribute elements::[NamedSignatureElement]; synthesized attribute elementNames::[String]; @@ -117,6 +129,7 @@ global foldNamedSignatureElements::(NamedSignatureElements ::= [NamedSignatureEl - Represents an elements of a signature, whether input, output, or annotation. -} nonterminal NamedSignatureElement with elementName, elementShortName, typerep, freeVariables, boundVariables; +propagate boundVariables on NamedSignatureElement; synthesized attribute elementName :: String; synthesized attribute elementShortName :: String; @@ -167,22 +180,13 @@ function findNamedSigElemType Type ::= n::String l::[NamedSignatureElement] { local elems::NamedSignatureElements = foldNamedSignatureElements(l); - return fromMaybe(errorType(), lookup(n, zipWith(pair, elems.elementNames, elems.elementTypes))); + return fromMaybe(errorType(), lookup(n, zip(elems.elementNames, elems.elementTypes))); } -------------- -attribute substitution, flatRenamed occurs on NamedSignature, Contexts, NamedSignatureElements, NamedSignatureElement; -propagate flatRenamed on NamedSignature, Contexts, NamedSignatureElements, NamedSignatureElement; - --- "Freshens" all the signature's type variables with new skolem constants, --- to avoid type vars from interface files clashing with new ones from genInt() -function freshenNamedSignature -NamedSignature ::= ns::NamedSignature -{ - ns.substitution = zipVarsAndTypesIntoSubstitution(ns.freeVariables, map(skolemType, ns.typeScheme.boundVars)); - return ns.flatRenamed; -} +attribute substitution, flatRenamed occurs on Contexts, NamedSignatureElements, NamedSignatureElement; +propagate substitution, flatRenamed on Contexts, NamedSignatureElements, NamedSignatureElement; function unifyNamedSignature Substitution ::= ns1::NamedSignature ns2::NamedSignature diff --git a/grammars/silver/compiler/definition/env/Type.sv b/grammars/silver/compiler/definition/env/Type.sv index f196d9d7e..ae884881f 100644 --- a/grammars/silver/compiler/definition/env/Type.sv +++ b/grammars/silver/compiler/definition/env/Type.sv @@ -40,7 +40,7 @@ top::Type ::= c::Type a::Type } aspect production nonterminalType -top::Type ::= fn::String _ _ +top::Type ::= fn::String _ _ _ { top.typeName = fn; } @@ -57,7 +57,7 @@ top::Type ::= te::Type _ top.typeName = te.typeName; } -aspect production partiallyDecoratedType +aspect production uniqueDecoratedType top::Type ::= te::Type _ { top.typeName = te.typeName; diff --git a/grammars/silver/compiler/definition/flow/ast/ExprVertexInfo.sv b/grammars/silver/compiler/definition/flow/ast/ExprVertexInfo.sv deleted file mode 100644 index 1fc94070c..000000000 --- a/grammars/silver/compiler/definition/flow/ast/ExprVertexInfo.sv +++ /dev/null @@ -1,35 +0,0 @@ -grammar silver:compiler:definition:flow:ast; - -{-- - - Information about an expression. Specifically, whether it corresponds to a - - vertex in the graph, or not. - -} -nonterminal ExprVertexInfo; - - -{-- - - The expression DOES have a corresponding vertex in the production graph. - - - - @param vertexType How we should address its attributes - - - - Do not forget we also need to address its equation (but vertexType takes care of that too) - - - - e.g. new(decorate rhs.a with {}) needs to emit 'rhs.a' still, even while - - ignoring the decorate vertex. That happens when we refer to the anonEq. - -} -abstract production hasVertex -top::ExprVertexInfo ::= - vertexType::VertexType -{ -} - -{-- - - The expression does not have a corresponding vertex in the production graph - - and so much be treated as any value. - -} -abstract production noVertex -top::ExprVertexInfo ::= -{ -} - - diff --git a/grammars/silver/compiler/definition/flow/ast/Flow.sv b/grammars/silver/compiler/definition/flow/ast/Flow.sv index a27b60f9d..68e067296 100644 --- a/grammars/silver/compiler/definition/flow/ast/Flow.sv +++ b/grammars/silver/compiler/definition/flow/ast/Flow.sv @@ -10,8 +10,8 @@ grammar silver:compiler:definition:flow:ast; - - extraEq (handling collections '<-') - which the thesis does not address. -} -nonterminal FlowDef with synTreeContribs, inhTreeContribs, defTreeContribs, fwdTreeContribs, fwdInhTreeContribs, prodTreeContribs, prodGraphContribs, flowEdges, localInhTreeContribs, suspectFlowEdges, hostSynTreeContribs, nonSuspectContribs, localTreeContribs, partialRefContribs; -nonterminal FlowDefs with synTreeContribs, inhTreeContribs, defTreeContribs, fwdTreeContribs, fwdInhTreeContribs, prodTreeContribs, prodGraphContribs, localInhTreeContribs, hostSynTreeContribs, nonSuspectContribs, localTreeContribs, partialRefContribs; +data nonterminal FlowDef with synTreeContribs, inhTreeContribs, defTreeContribs, fwdTreeContribs, fwdInhTreeContribs, prodTreeContribs, prodGraphContribs, flowEdges, localInhTreeContribs, suspectFlowEdges, hostSynTreeContribs, nonSuspectContribs, localTreeContribs, refPossibleDecSiteContribs, refDecSiteContribs; +data nonterminal FlowDefs with synTreeContribs, inhTreeContribs, defTreeContribs, fwdTreeContribs, fwdInhTreeContribs, prodTreeContribs, prodGraphContribs, localInhTreeContribs, hostSynTreeContribs, nonSuspectContribs, localTreeContribs, refPossibleDecSiteContribs, refDecSiteContribs; {-- lookup (production, attribute) to find synthesized equations - Used to ensure a necessary lhs.syn equation exists. @@ -19,8 +19,7 @@ nonterminal FlowDefs with synTreeContribs, inhTreeContribs, defTreeContribs, fwd monoid attribute synTreeContribs :: [Pair]; {-- lookup (production, sig, attribute) to find inherited equation - - Used to ensure a necessary rhs.inh equation exists. - - Also decides whether to add a copy equation for autocopy attributes to rhs elements. -} + - Used to ensure a necessary rhs.inh equation exists. -} monoid attribute inhTreeContribs :: [Pair]; {-- lookup (nonterminal, attribute) to find default syn equations @@ -67,10 +66,14 @@ monoid attribute hostSynTreeContribs :: [Pair]; {-- A list of attributes for a production that are non-suspect -} monoid attribute nonSuspectContribs :: [Pair]; -{-- A list of decoration sites where partial references are taken, and the attributes on those partial references -} -monoid attribute partialRefContribs :: [(String, String, Location, [String])]; +{-- lookup dec site to find places that a unique reference to this ref site *might be* decorated. + - This includes e.g. unique reference sites that appear in an if/else branch. -} +monoid attribute refPossibleDecSiteContribs :: [(String, VertexType)]; -propagate synTreeContribs, inhTreeContribs, defTreeContribs, fwdTreeContribs, fwdInhTreeContribs, localInhTreeContribs, localTreeContribs, prodTreeContribs, prodGraphContribs, hostSynTreeContribs, nonSuspectContribs, partialRefContribs +{-- lookup dec site to find places that a unique reference to this ref site are *unconditionally* decorated. -} +monoid attribute refDecSiteContribs :: [(String, VertexType)]; + +propagate synTreeContribs, inhTreeContribs, defTreeContribs, fwdTreeContribs, fwdInhTreeContribs, localInhTreeContribs, localTreeContribs, prodTreeContribs, prodGraphContribs, hostSynTreeContribs, nonSuspectContribs, refPossibleDecSiteContribs, refDecSiteContribs on FlowDefs; abstract production consFlow @@ -101,7 +104,8 @@ top::FlowDef ::= top.hostSynTreeContribs := []; top.nonSuspectContribs := []; top.suspectFlowEdges = []; -- flowEdges is required, but suspect is typically not! - top.partialRefContribs := []; + top.refPossibleDecSiteContribs := []; + top.refDecSiteContribs := []; -- require prodGraphContibs, flowEdges } @@ -115,7 +119,7 @@ top::FlowDef ::= abstract production prodFlowDef top::FlowDef ::= nt::String prod::String { - top.prodTreeContribs := [pair(nt, top)]; + top.prodTreeContribs := [(nt, top)]; top.prodGraphContribs := []; top.flowEdges = error("Internal compiler error: this sort of def should not be in a context where edges are requested."); } @@ -131,7 +135,7 @@ top::FlowDef ::= nt::String prod::String abstract production hostSynFlowDef top::FlowDef ::= nt::String attr::String { - top.hostSynTreeContribs := [pair(nt, top)]; + top.hostSynTreeContribs := [(nt, top)]; top.prodGraphContribs := []; top.flowEdges = error("Internal compiler error: this sort of def should not be in a context where edges are requested."); } @@ -147,9 +151,9 @@ top::FlowDef ::= nt::String attr::String abstract production defaultSynEq top::FlowDef ::= nt::String attr::String deps::[FlowVertex] { - top.defTreeContribs := [pair(crossnames(nt, attr), top)]; + top.defTreeContribs := [(crossnames(nt, attr), top)]; top.prodGraphContribs := []; -- defaults don't show up in the prod graph!! - top.flowEdges = map(pair(lhsSynVertex(attr), _), deps); -- but their edges WILL end up added to graphs in fixup-phase!! + top.flowEdges = map(pair(fst=lhsSynVertex(attr), snd=_), deps); -- but their edges WILL end up added to graphs in fixup-phase!! } {-- @@ -163,9 +167,9 @@ top::FlowDef ::= nt::String attr::String deps::[FlowVertex] abstract production synEq top::FlowDef ::= prod::String attr::String deps::[FlowVertex] mayAffectFlowType::Boolean { - top.synTreeContribs := [pair(crossnames(prod, attr), top)]; - top.prodGraphContribs := [pair(prod, top)]; - local edges :: [Pair] = map(pair(lhsSynVertex(attr), _), deps); + top.synTreeContribs := [(crossnames(prod, attr), top)]; + top.prodGraphContribs := [(prod, top)]; + local edges :: [Pair] = map(pair(fst=lhsSynVertex(attr), snd=_), deps); top.flowEdges = if mayAffectFlowType then edges else []; top.suspectFlowEdges = if mayAffectFlowType then [] else edges; } @@ -182,9 +186,9 @@ top::FlowDef ::= prod::String attr::String deps::[FlowVertex] mayAffectFlowTy abstract production inhEq top::FlowDef ::= prod::String sigName::String attr::String deps::[FlowVertex] { - top.inhTreeContribs := [pair(crossnames(prod, crossnames(sigName, attr)), top)]; - top.prodGraphContribs := [pair(prod, top)]; - top.flowEdges = map(pair(rhsVertex(sigName, attr), _), deps); + top.inhTreeContribs := [(crossnames(prod, crossnames(sigName, attr)), top)]; + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = map(pair(fst=rhsInhVertex(sigName, attr), snd=_), deps); } {-- @@ -197,9 +201,9 @@ top::FlowDef ::= prod::String sigName::String attr::String deps::[FlowVertex] abstract production fwdEq top::FlowDef ::= prod::String deps::[FlowVertex] mayAffectFlowType::Boolean { - top.fwdTreeContribs := [pair(prod, top)]; - top.prodGraphContribs := [pair(prod, top)]; - local edges :: [Pair] = map(pair(forwardEqVertex(), _), deps); + top.fwdTreeContribs := [(prod, top)]; + top.prodGraphContribs := [(prod, top)]; + local edges :: [Pair] = map(pair(fst=forwardEqVertex(), snd=_), deps); top.flowEdges = if mayAffectFlowType then edges else []; top.suspectFlowEdges = if mayAffectFlowType then [] else edges; } @@ -214,7 +218,7 @@ top::FlowDef ::= prod::String deps::[FlowVertex] mayAffectFlowType::Boolean abstract production implicitFwdAffects top::FlowDef ::= prod::String attrs::[String] { - top.nonSuspectContribs := [pair(prod, attrs)]; + top.nonSuspectContribs := [(prod, attrs)]; top.prodGraphContribs := []; top.flowEdges = error("Internal compiler error: this sort of def should not be in a context where edges are requested."); } @@ -230,9 +234,9 @@ top::FlowDef ::= prod::String attrs::[String] abstract production fwdInhEq top::FlowDef ::= prod::String attr::String deps::[FlowVertex] { - top.fwdInhTreeContribs := [pair(crossnames(prod, attr), top)]; - top.prodGraphContribs := [pair(prod, top)]; - top.flowEdges = map(pair(forwardVertex(attr), _), deps); + top.fwdInhTreeContribs := [(crossnames(prod, attr), top)]; + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = map(pair(fst=forwardInhVertex(attr), snd=_), deps); } {-- @@ -243,15 +247,16 @@ top::FlowDef ::= prod::String attr::String deps::[FlowVertex] - @param fName the name of the local/production attribute - @param typeName the full name of the type, or empty string if not a decorable type! - @param isNT true if the type is a nonterminal + - @param isFwrd true if this is a forward production attribute - @param deps the dependencies of this equation on other flow graph elements - CONTRIBUTIONS ARE POSSIBLE -} abstract production localEq -top::FlowDef ::= prod::String fName::String typeName::String isNT::Boolean deps::[FlowVertex] +top::FlowDef ::= prod::String fName::String typeName::String isNT::Boolean isFwrd::Boolean deps::[FlowVertex] { - top.localTreeContribs := [pair(crossnames(prod, fName), top)]; - top.prodGraphContribs := [pair(prod, top)]; - top.flowEdges = map(pair(localEqVertex(fName), _), deps); + top.localTreeContribs := [(crossnames(prod, fName), top)]; + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = map(pair(fst=localEqVertex(fName), snd=_), deps); } {-- @@ -266,9 +271,45 @@ top::FlowDef ::= prod::String fName::String typeName::String isNT::Boolean d abstract production localInhEq top::FlowDef ::= prod::String fName::String attr::String deps::[FlowVertex] { - top.localInhTreeContribs := [pair(crossnames(prod, crossnames(fName, attr)), top)]; - top.prodGraphContribs := [pair(prod, top)]; - top.flowEdges = map(pair(localVertex(fName, attr), _), deps); + top.localInhTreeContribs := [(crossnames(prod, crossnames(fName, attr)), top)]; + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = map(pair(fst=localInhVertex(fName, attr), snd=_), deps); +} + +{-- + - The definition of an inherited attribute for a translation attribute + - on an rhs signature element in a production. + - + - @param prod the full name of the production + - @param sigName the name of the RHS element + - @param transAttr the full name of the translation attribute + - @param attr the full name of the attribute + - @param deps the dependencies of this equation on other flow graph elements + -} +abstract production transInhEq +top::FlowDef ::= prod::String sigName::String transAttr::String attr::String deps::[FlowVertex] +{ + top.inhTreeContribs := [(crossnames(prod, crossnames(sigName, s"${transAttr}.${attr}")), top)]; + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = map(pair(fst=rhsInhVertex(sigName, s"${transAttr}.${attr}"), snd=_), deps); +} + +{-- + - The definition of an inherited attribute for a translation attribute + - on an local attribute. + - + - @param prod the full name of the production + - @param fName the name of the local/production attribute + - @param transAttr the full name of the translation attribute + - @param attr the full name of the attribute + - @param deps the dependencies of this equation on other flow graph elements + -} +abstract production localTransInhEq +top::FlowDef ::= prod::String fName::String transAttr::String attr::String deps::[FlowVertex] +{ + top.inhTreeContribs := [(crossnames(prod, crossnames(fName, s"${transAttr}.${attr}")), top)]; + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = map(pair(fst=localSynVertex(fName, s"${transAttr}.${attr}"), snd=_), deps); } {-- @@ -282,8 +323,8 @@ top::FlowDef ::= prod::String fName::String attr::String deps::[FlowVertex] abstract production extraEq top::FlowDef ::= prod::String src::FlowVertex deps::[FlowVertex] mayAffectFlowType::Boolean { - top.prodGraphContribs := [pair(prod, top)]; - local edges :: [Pair] = map(pair(src, _), deps); + top.prodGraphContribs := [(prod, top)]; + local edges :: [Pair] = map(pair(fst=src, snd=_), deps); top.flowEdges = if mayAffectFlowType then edges else []; top.suspectFlowEdges = if mayAffectFlowType then [] else edges; } @@ -301,9 +342,9 @@ top::FlowDef ::= prod::String src::FlowVertex deps::[FlowVertex] mayAffectFlo abstract production anonEq top::FlowDef ::= prod::String fName::String typeName::String isNT::Boolean loc::Location deps::[FlowVertex] { - top.localTreeContribs := [pair(crossnames(prod, fName), top)]; - top.prodGraphContribs := [pair(prod, top)]; - top.flowEdges = map(pair(anonEqVertex(fName), _), deps); + top.localTreeContribs := [(crossnames(prod, fName), top)]; + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = map(pair(fst=anonEqVertex(fName), snd=_), deps); } {-- @@ -318,9 +359,9 @@ top::FlowDef ::= prod::String fName::String typeName::String isNT::Boolean l abstract production anonInhEq top::FlowDef ::= prod::String fName::String attr::String deps::[FlowVertex] { - top.localInhTreeContribs := [pair(crossnames(prod, crossnames(fName, attr)), top)]; - top.prodGraphContribs := [pair(prod, top)]; - top.flowEdges = map(pair(anonVertex(fName, attr), _), deps); + top.localInhTreeContribs := [(crossnames(prod, crossnames(fName, attr)), top)]; + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = map(pair(fst=anonInhVertex(fName, attr), snd=_), deps); } {-- @@ -334,8 +375,8 @@ top::FlowDef ::= prod::String fName::String attr::String deps::[FlowVertex] abstract production synOccursContextEq top::FlowDef ::= prod::String vt::VertexType attr::String deps::[String] { - top.prodGraphContribs := [pair(prod, top)]; - top.flowEdges = map(pair(vt.synVertex(attr), _), map(vt.inhVertex, deps)); + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = map(pair(fst=vt.synVertex(attr), snd=_), map(vt.inhVertex, deps)); } {-- @@ -346,36 +387,103 @@ top::FlowDef ::= prod::String vt::VertexType attr::String deps::[String] abstract production patternRuleEq top::FlowDef ::= prod::String matchProd::String scrutinee::VertexType vars::[PatternVarProjection] { - top.prodGraphContribs := [pair(prod, top)]; + top.prodGraphContribs := [(prod, top)]; top.flowEdges = []; } - nonterminal PatternVarProjection; - abstract production patternVarProjection top::PatternVarProjection ::= child::String typeName::String patternVar::String +{} + +{-- + - A sub-term with a flow vertex, that has a known decoration site. + - Like patternRuleEq, this is only used in creating stitch points. + - + - @param prod the full name of the production + - @param parent the flow vertex of the enclosing production call + - @param termProd the applied production + - @param sigName the name of the child under which this term appears + -} +abstract production subtermDecEq +top::FlowDef ::= prod::String parent::VertexType termProd::String sigName::String { + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = []; } {-- - - The taking of a partially decorated reference to a child or local/production attribute. - - Since taking a partially decorated reference means that inherited equations - - on the decoration site for attributes not in the reference set are forbidden, - - this info tracks what decoration sites have partial references taken. + - A unique reference to a child that is elsewhere decorated with additional inherited attributes. - - - @param prod the full name of the production - - @param fName the full name of the child or local - - @param gram the grammar where the reference was taken - - @param loc the location of where the reference was taken - - @param attrs the attributes in the type of the taken reference + - @param prod the full name of the production + - @param sigName the name of the child + - @param alwaysDec is this decoration uncondtional (as opposed to e.g. a unique reference appearing in an if/else branch) + - @param decSite the vertex type that is supplying the attributes + - @param attrs the inherited attributes that are being supplied -} -abstract production partialRef -top::FlowDef ::= prod::String fName::String gram::String loc::Location attrs::[String] +abstract production childRefDecSiteEq +top::FlowDef ::= prod::String sigName::String alwaysDec::Boolean decSite::VertexType attrs::[String] { - top.partialRefContribs := [(crossnames(prod, fName), gram, loc, attrs)]; - top.prodGraphContribs := []; - top.flowEdges = []; + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = map(\ attr::String -> (rhsInhVertex(sigName, attr), decSite.inhVertex(attr)), attrs); + top.refPossibleDecSiteContribs := [(s"${prod}:${sigName}", decSite)]; + top.refDecSiteContribs := if alwaysDec then top.refPossibleDecSiteContribs else []; +} + +{-- + - A unique reference to a local/production attribute that is elsewhere decorated with additional inherited attributes. + - + - @param prod the full name of the production + - @param fName the full name of the local/production attribute + - @param alwaysDec is this decoration uncondtional (as opposed to e.g. a unique reference appearing in an if/else branch) + - @param decSite the vertex type that is supplying the attributes + - @param attrs the inherited attributes that are being supplied + -} +abstract production localRefDecSiteEq +top::FlowDef ::= prod::String fName::String alwaysDec::Boolean decSite::VertexType attrs::[String] +{ + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = map(\ attr::String -> (localInhVertex(fName, attr), decSite.inhVertex(attr)), attrs); + top.refPossibleDecSiteContribs := [(fName, decSite)]; + top.refDecSiteContribs := if alwaysDec then top.refPossibleDecSiteContribs else []; +} + +{-- + - A unique reference to a translation attribute on a child that is elsewhere decorated with additional inherited attributes. + - + - @param prod the full name of the production + - @param sigName the name of the child + - @param transAttr the name of the translation attribute + - @param alwaysDec is this decoration uncondtional (as opposed to e.g. a unique reference appearing in an if/else branch) + - @param decSite the vertex type that is supplying the attributes + - @param attrs the inherited attributes that are being supplied + -} +abstract production childTransRefDecSiteEq +top::FlowDef ::= prod::String sigName::String transAttr::String alwaysDec::Boolean decSite::VertexType attrs::[String] +{ + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = map(\ attr::String -> (rhsInhVertex(sigName, s"${transAttr}.${attr}"), decSite.inhVertex(attr)), attrs); + top.refPossibleDecSiteContribs := [(s"${prod}:${sigName}.${transAttr}", decSite)]; + top.refDecSiteContribs := if alwaysDec then top.refPossibleDecSiteContribs else []; +} + +{-- + - A unique reference to a translation attribute on a local/production attribute that is elsewhere decorated with additional inherited attributes. + - + - @param prod the full name of the production + - @param fName the full name of the local/production attribute + - @param transAttr the name of the translation attribute + - @param alwaysDec is this decoration uncondtional (as opposed to e.g. a unique reference appearing in an if/else branch) + - @param decSite the vertex type that is supplying the attributes + - @param attrs the inherited attributes that are being supplied + -} +abstract production localTransRefDecSiteEq +top::FlowDef ::= prod::String fName::String transAttr::String alwaysDec::Boolean decSite::VertexType attrs::[String] +{ + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = map(\ attr::String -> (localInhVertex(fName, s"${transAttr}.${attr}"), decSite.inhVertex(attr)), attrs); + top.refPossibleDecSiteContribs := [(s"${fName}.${transAttr}", decSite)]; + top.refDecSiteContribs := if alwaysDec then top.refPossibleDecSiteContribs else []; } -- @@ -402,7 +510,7 @@ function collectAnonOriginItem -- Small hack to improve error messages. Ignore anonEq's that come from patterns if startsWith("__scrutinee", fN) then rest - else pair(fN, l) :: rest + else (fN, l) :: rest | _ -> rest end; } diff --git a/grammars/silver/compiler/definition/flow/ast/Vertex.sv b/grammars/silver/compiler/definition/flow/ast/Vertex.sv index 684c1c054..23867ae93 100644 --- a/grammars/silver/compiler/definition/flow/ast/Vertex.sv +++ b/grammars/silver/compiler/definition/flow/ast/Vertex.sv @@ -5,41 +5,39 @@ grammar silver:compiler:definition:flow:ast; - - See VertexType for some extra information organizing these vertexes somewhat. -} -nonterminal FlowVertex with compareTo, isEqual, compareKey, compare; -propagate compareTo, isEqual, compareKey, compare on FlowVertex; - +data FlowVertex = {-- - - A vertex representing a synthesized attribute on the nonterminal being constructed by this production. - - - - @param attrName the full name of a synthesized attribute on the lhs. - -} -abstract production lhsSynVertex -top::FlowVertex ::= attrName::String -{} +- A vertex representing a synthesized attribute on the nonterminal being constructed by this production. +- +- @param attrName the full name of a synthesized attribute on the lhs. +-} + lhsSynVertex attrName::String {-- - - A vertex representing an inherited attribute on the nonterminal being constructed by this production. - - - - Inherited attributes are separate for 'lhs' and not for 'rhs' because we care rather specially about lhsInh, - - as that's the bit that contributes to computing a flow type. - - - - @param attrName the full name of an inherited attribute on the lhs. - -} -abstract production lhsInhVertex -top::FlowVertex ::= attrName::String -{} +- A vertex representing an inherited attribute on the nonterminal being constructed by this production. +- +- Inherited attributes are separate for 'lhs' and not for 'rhs' because we care rather specially about lhsInh, +- as that's the bit that contributes to computing a flow type. +- +- @param attrName the full name of an inherited attribute on the lhs. +-} +| lhsInhVertex attrName::String --- TODO: we should do the above syn/inh separation for everything below too. +{-- +- A vertex representing a synthesized attribute on an element of the signature RHS. +- +- @param sigName the name given to a signature nonterminal. +- @param attrName the full name of an attribute on that signature element. +-} +| rhsSynVertex sigName::String attrName::String {-- - - A vertex representing an attribute on an element of the signature RHS. - - - - @param sigName the name given to a signature nonterminal. - - @param attrName the full name of an attribute on that signature element. - -} -abstract production rhsVertex -top::FlowVertex ::= sigName::String attrName::String -{} +- A vertex representing an inherited attribute on an element of the signature RHS. +- +- @param sigName the name given to a signature nonterminal. +- @param attrName the full name of an attribute on that signature element. +-} +| rhsInhVertex sigName::String attrName::String {-- - A vertex representing a local equation. i.e. forward, local attribute, production @@ -49,37 +47,27 @@ top::FlowVertex ::= sigName::String attrName::String - - @param fName the full name of the NTA/FWD being defined -} -abstract production localEqVertex -top::FlowVertex ::= fName::String -{} +| localEqVertex fName::String {-- - - A vertex representing an attribute on a local equation. i.e. forward, local + - A vertex representing a synthesized attribute on a local equation. i.e. forward, local - attribute, production attribute, etc. Note this this implies the equation - above IS a decorable type! - - @param fName the full name of the NTA/FWD - @param attrName the full name of the attribute on that element -} -abstract production localVertex -top::FlowVertex ::= fName::String attrName::String -{} - --- TODO: we should distinguish these! - --- The forward equation for this production. We do not care to distinguish it. -function forwardEqVertex -FlowVertex ::= -{ - return localEqVertex("forward"); -} +| localSynVertex fName::String attrName::String --- An attribute on the forward node for this production -function forwardVertex -FlowVertex ::= attrName::String -{ - return localVertex("forward", attrName); -} +{-- + - A vertex representing an inherited attribute on a local equation. i.e. forward, local + - attribute, production attribute, etc. Note this this implies the equation + - above IS a decorable type! + - + - @param fName the full name of the NTA/FWD + - @param attrName the full name of the attribute on that element + -} +| localInhVertex fName::String attrName::String {-- - A vertex representing an anonymous equation. i.e. a 'decorate e with..' @@ -87,17 +75,69 @@ FlowVertex ::= attrName::String - - @param fName an anonymous name (typically generated with genInt) -} -abstract production anonEqVertex -top::FlowVertex ::= fName::String -{} +| anonEqVertex fName::String {-- - - A vertex representing an attribute on an anonymous equation. + - A vertex representing a synthesized attribute on an anonymous equation. + - e.g. 'decorate e with { a = d } . b' this represents 'b'. + - + - @param fName the anonymous name + - @param attrName the full name of the attribute on that element + -} +| anonSynVertex fName::String attrName::String + +{-- + - A vertex representing an inherited attribute on an anonymous equation. - e.g. 'decorate e with { a = d }' this represents 'e_nt.a's deps 'd'. - - @param fName the anonymous name - @param attrName the full name of the attribute on that element -} -abstract production anonVertex -top::FlowVertex ::= fName::String attrName::String -{} +| anonInhVertex fName::String attrName::String + +{-- + - A vertex corresponding to a synthesized attribute on a sub-term of an expression with a known decoration site. + - e.g. 'local foo::Foo = bar(baz(@x));', we need a vertex for the attributes on baz(@x) + - for decoration site projections. + - + - @param parent the decoration site of the enclosing term + - @param prodName the full name of the applied production + - @param sigName the name given to the corresponding child + - @param attrName the full name of an attribute on this subterm, when decorated + -} +| subtermSynVertex parent::VertexType prodName::String sigName::String attrName::String + +{-- + - A vertex corresponding to an inherited synthesized attribute on a sub-term of an expression with a known decoration site. + - e.g. 'local foo::Foo = bar(baz(@x));', we need a vertex for the attributes on baz(@x) + - for decoration site projections. + - + - @param parent the decoration site of the enclosing term + - @param prodName the full name of the applied production + - @param sigName the name given to the corresponding child + - @param attrName the full name of an attribute on this subterm, when decorated + -} +| subtermInhVertex parent::VertexType prodName::String sigName::String attrName::String +; + +derive Eq, Ord on FlowVertex; + + +-- The forward equation for this production. We do not care to distinguish it. +function forwardEqVertex +FlowVertex ::= +{ + return localEqVertex("forward"); +} + +-- An attribute on the forward node for this production +function forwardSynVertex +FlowVertex ::= attrName::String +{ + return localSynVertex("forward", attrName); +} +function forwardInhVertex +FlowVertex ::= attrName::String +{ + return localInhVertex("forward", attrName); +} diff --git a/grammars/silver/compiler/definition/flow/ast/VertexType.sv b/grammars/silver/compiler/definition/flow/ast/VertexType.sv index 147e3a688..9407c855b 100644 --- a/grammars/silver/compiler/definition/flow/ast/VertexType.sv +++ b/grammars/silver/compiler/definition/flow/ast/VertexType.sv @@ -7,7 +7,12 @@ grammar silver:compiler:definition:flow:ast; - lhsVertexType, rhsVertexType(sigName), localVertexType(fName), - forwardVertexType, anonVertexType(x) -} -nonterminal VertexType with synVertex, inhVertex, fwdVertex, eqVertex; +data nonterminal VertexType with + vertexName, + synVertex, inhVertex, fwdVertex, eqVertex; +derive Eq, Ord on VertexType; + +synthesized attribute vertexName::String; {-- FlowVertex for a synthesized attribute for this FlowVertex -} synthesized attribute synVertex :: (FlowVertex ::= String); @@ -33,6 +38,7 @@ global forwardEqVertex_singleton :: FlowVertex = localEqVertex("forward"); abstract production lhsVertexType_real top::VertexType ::= { + top.vertexName = "top"; top.synVertex = lhsSynVertex; top.inhVertex = lhsInhVertex; top.fwdVertex = forwardEqVertex_singleton; @@ -45,9 +51,10 @@ top::VertexType ::= abstract production rhsVertexType top::VertexType ::= sigName::String { - top.synVertex = rhsVertex(sigName, _); - top.inhVertex = rhsVertex(sigName, _); - top.fwdVertex = rhsVertex(sigName, "forward"); + top.vertexName = sigName; + top.synVertex = rhsSynVertex(sigName, _); + top.inhVertex = rhsInhVertex(sigName, _); + top.fwdVertex = rhsSynVertex(sigName, "forward"); top.eqVertex = []; } @@ -57,21 +64,36 @@ top::VertexType ::= sigName::String abstract production localVertexType top::VertexType ::= fName::String { - top.synVertex = localVertex(fName, _); - top.inhVertex = localVertex(fName, _); - top.fwdVertex = localVertex(fName, "forward"); + top.vertexName = fName; + top.synVertex = localSynVertex(fName, _); + top.inhVertex = localInhVertex(fName, _); + top.fwdVertex = localSynVertex(fName, "forward"); top.eqVertex = [localEqVertex(fName)]; } +{-- + - Represents the vertexes for each translation attribute on a production lhs/rhs/local. + -} +abstract production transAttrVertexType +top::VertexType ::= v::VertexType transAttr::String +{ + top.vertexName = s"${v.vertexName}.${transAttr}"; + top.synVertex = \ attr::String -> v.synVertex(s"${transAttr}.${attr}"); + top.inhVertex = \ attr::String -> v.inhVertex(s"${transAttr}.${attr}"); + top.fwdVertex = v.synVertex(s"${transAttr}.forward"); + top.eqVertex = [v.synVertex(transAttr)]; +} + {-- - Represents the vertexes for the forward of a production. You can use forwardVertexType instead of this production directly. -} abstract production forwardVertexType_real top::VertexType ::= { - top.synVertex = localVertex("forward", _); - top.inhVertex = localVertex("forward", _); - top.fwdVertex = localVertex("forward", "forward"); + top.vertexName = "forward"; + top.synVertex = forwardSynVertex; + top.inhVertex = forwardInhVertex; + top.fwdVertex = forwardSynVertex("forward"); top.eqVertex = [forwardEqVertex_singleton]; } @@ -81,10 +103,22 @@ top::VertexType ::= abstract production anonVertexType top::VertexType ::= x::String { - top.synVertex = anonVertex(x, _); - top.inhVertex = anonVertex(x, _); - top.fwdVertex = anonVertex(x, "forward"); + top.vertexName = x; + top.synVertex = anonSynVertex(x, _); + top.inhVertex = anonInhVertex(x, _); + top.fwdVertex = anonSynVertex(x, "forward"); top.eqVertex = [anonEqVertex(x)]; } - +{-- + - Represents the vertexes corresponding to sub-terms of an expression with a known decoration site. + -} +abstract production subtermVertexType +top::VertexType ::= parent::VertexType prodName::String sigName::String +{ + top.vertexName = s"${parent.vertexName}[${prodName}:${sigName}]"; + top.synVertex = subtermSynVertex(parent, prodName, sigName, _); + top.inhVertex = subtermInhVertex(parent, prodName, sigName, _); + top.fwdVertex = subtermSynVertex(parent, prodName, sigName, "forward"); + top.eqVertex = []; +} diff --git a/grammars/silver/compiler/definition/flow/driver/DumpGraph.sv b/grammars/silver/compiler/definition/flow/driver/DumpGraph.sv index 044f15705..2ea7f3b8d 100644 --- a/grammars/silver/compiler/definition/flow/driver/DumpGraph.sv +++ b/grammars/silver/compiler/definition/flow/driver/DumpGraph.sv @@ -52,9 +52,9 @@ function unList return if null(l) then [] else if !null(recurse) && head(recurse).fst == head(l).fst then - pair(head(l).fst, head(l).snd :: head(recurse).snd) :: tail(recurse) + (head(l).fst, head(l).snd :: head(recurse).snd) :: tail(recurse) else - pair(head(l).fst, [head(l).snd]) :: recurse; + (head(l).fst, [head(l).snd]) :: recurse; } @@ -143,7 +143,12 @@ top::FlowVertex ::= attrName::String { top.dotName = attrName; } -aspect production rhsVertex +aspect production rhsSynVertex +top::FlowVertex ::= sigName::String attrName::String +{ + top.dotName = sigName ++ "/" ++ attrName; +} +aspect production rhsInhVertex top::FlowVertex ::= sigName::String attrName::String { top.dotName = sigName ++ "/" ++ attrName; @@ -153,7 +158,12 @@ top::FlowVertex ::= fName::String { top.dotName = fName; } -aspect production localVertex +aspect production localSynVertex +top::FlowVertex ::= fName::String attrName::String +{ + top.dotName = fName ++ "/" ++ attrName; +} +aspect production localInhVertex top::FlowVertex ::= fName::String attrName::String { top.dotName = fName ++ "/" ++ attrName; @@ -163,9 +173,26 @@ top::FlowVertex ::= fName::String { top.dotName = fName; } -aspect production anonVertex +aspect production anonSynVertex +top::FlowVertex ::= fName::String attrName::String +{ + top.dotName = fName ++ "/" ++ attrName; +} +aspect production anonInhVertex top::FlowVertex ::= fName::String attrName::String { top.dotName = fName ++ "/" ++ attrName; } +aspect production subtermSynVertex +top::FlowVertex ::= parent::VertexType prodName::String sigName::String attrName::String +{ + top.dotName = parent.synVertex(prodName ++ "@" ++ sigName ++ "/" ++ attrName).dotName; -- Hack! +} +aspect production subtermInhVertex +top::FlowVertex ::= parent::VertexType prodName::String sigName::String attrName::String +{ + top.dotName = parent.inhVertex(prodName ++ "@" ++ sigName ++ "/" ++ attrName).dotName; -- Hack! +} + + diff --git a/grammars/silver/compiler/definition/flow/driver/FlowGraph.sv b/grammars/silver/compiler/definition/flow/driver/FlowGraph.sv index 939ee375f..27d2435a0 100644 --- a/grammars/silver/compiler/definition/flow/driver/FlowGraph.sv +++ b/grammars/silver/compiler/definition/flow/driver/FlowGraph.sv @@ -52,7 +52,7 @@ set:Set ::= todolist::[FlowVertex] current::set:Set p: {-- - Look up flow types. - - @param syn A synthesized attribute's full name (or "forward") + - @param syn A synthesized attribute's full name (or "forward", or trans.syn) - @param nt The nonterminal to look up this attribute on - @param flow The flow type environment (NOTE: TODO: this is currently 'myFlow' or something, NOT top.flowEnv) - @return A set of inherited attributes on this nonterminal, needed to compute this synthesized attribute. diff --git a/grammars/silver/compiler/definition/flow/driver/FlowTypes.sv b/grammars/silver/compiler/definition/flow/driver/FlowTypes.sv index 8542bcd47..be74a204f 100644 --- a/grammars/silver/compiler/definition/flow/driver/FlowTypes.sv +++ b/grammars/silver/compiler/definition/flow/driver/FlowTypes.sv @@ -2,11 +2,10 @@ grammar silver:compiler:definition:flow:driver; imports silver:compiler:definition:core; imports silver:compiler:definition:env; ---import silver:compiler:definition:flow:env; +imports silver:compiler:definition:flow:env; imports silver:compiler:definition:flow:ast; -imports silver:compiler:analysis:warnings:flow only isOccursSynthesized, isAutocopy; - -imports silver:compiler:modification:autocopyattr; +imports silver:compiler:analysis:warnings:flow only isOccursSynthesized; +imports silver:compiler:analysis:uniqueness; imports silver:util:treemap as rtm; imports silver:util:graph as g; @@ -32,7 +31,7 @@ EnvTree ::= specDefs::[(String, String, [String], [String])] function initialFlowType Pair ::= x::(NtName, [(String, [String])]) { - return pair(x.fst, g:add(flatMap(toFlatEdges, x.snd), g:empty())); + return (x.fst, g:add(flatMap(toFlatEdges, x.snd), g:empty())); } function ntListLte Boolean ::= a::Pair b::Pair @@ -48,12 +47,12 @@ function ntListCoalesce [(NtName, [(String, [String])])] ::= l::[[(NtName, String, [String])]] { return if null(l) then [] - else pair(head(head(l)).fst, map(snd, head(l))) :: ntListCoalesce(tail(l)); + else (head(head(l)).fst, map(snd, head(l))) :: ntListCoalesce(tail(l)); } function toFlatEdges [Pair] ::= x::Pair { - return map(pair(x.fst, _), x.snd); + return map(pair(fst=x.fst, snd=_), x.snd); } @@ -62,7 +61,7 @@ function toFlatEdges - Iterates until convergence. -} function fullySolveFlowTypes -Pair<[ProductionGraph] EnvTree> ::= +([ProductionGraph], EnvTree) ::= graphs::[ProductionGraph] ntEnv::EnvTree { @@ -71,21 +70,19 @@ Pair<[ProductionGraph] EnvTree> ::= local prodEnv :: EnvTree = directBuildTree(map(prodGraphToEnv, graphs)); - local iter :: Pair>> = + local iter :: (Boolean, [ProductionGraph], EnvTree) = solveFlowTypes(graphs, prodEnv, ntEnv); -- Just iterate until no new edges are added - return if !iter.fst then iter.snd - else fullySolveFlowTypes(iter.snd.fst, iter.snd.snd); + return if !iter.1 then iter.snd + else fullySolveFlowTypes(iter.2, iter.3); } {-- - One iteration of solving flow type equations. Goes through each production once. -} function solveFlowTypes -Pair>> ::= +(Boolean, [ProductionGraph], EnvTree) ::= graphs::[ProductionGraph] prodEnv::EnvTree ntEnv::EnvTree @@ -110,8 +107,8 @@ Pair>> = solveFlowTypes(tail(graphs), prodEnv, rtm:update(updatedGraph.lhsNt, [newFlowType], ntEnv)); - return if null(graphs) then pair(false, pair([], ntEnv)) - else pair(!null(brandNewEdges) || recurse.fst, pair(updatedGraph :: recurse.snd.fst, recurse.snd.snd)); + return if null(graphs) then (false, ([], ntEnv)) + else (!null(brandNewEdges) || recurse.fst, updatedGraph :: recurse.snd.fst, recurse.snd.snd); } @@ -124,7 +121,7 @@ function findBrandNewEdges -- TODO: we might take '[Pair>]' insteadof [String] and gain speed? local newinhs :: [String] = removeAll(set:toList(g:edgesFrom(syn, currentFlowType)), inhs); - local newEdges :: [Pair] = map(pair(syn, _), newinhs); + local newEdges :: [Pair] = map(pair(fst=syn, snd=_), newinhs); return if null(candidates) then [] else newEdges ++ findBrandNewEdges(tail(candidates), currentFlowType); } @@ -135,7 +132,7 @@ Pair ::= ver::FlowVertex graph::ProductionGraph { -- TODO: we might return 'Pair>' instead of [String] and gain speed? -- Have set:filter, don't have "set:map" yet... (FlowVertex->String) - return pair(ver.flowTypeName, filterLhsInh(set:toList(graph.edgeMap(ver)))); + return (ver.flowTypeName, filterLhsInh(set:toList(graph.edgeMap(ver)))); } {-- @@ -179,17 +176,27 @@ top::FlowVertex ::= attrName::String { top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for inherited attributes?"); } -aspect production rhsVertex +aspect production rhsSynVertex +top::FlowVertex ::= sigName::String attrName::String +{ + top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for child synthesized attributes?"); +} +aspect production rhsInhVertex top::FlowVertex ::= sigName::String attrName::String { - top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for child attributes?"); + top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for child inherited attributes?"); } aspect production localEqVertex top::FlowVertex ::= fName::String { top.flowTypeName = fName; -- secretly only ever "forward" when we actually demand flowTypeName } -aspect production localVertex +aspect production localSynVertex +top::FlowVertex ::= fName::String attrName::String +{ + top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for local synthesized attributes?"); +} +aspect production localInhVertex top::FlowVertex ::= fName::String attrName::String { top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for local inherited attributes?"); @@ -199,8 +206,23 @@ top::FlowVertex ::= fName::String { top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for anon equations?"); } -aspect production anonVertex +aspect production anonSynVertex +top::FlowVertex ::= fName::String attrName::String +{ + top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for anon synthesized attributes?"); +} +aspect production anonInhVertex top::FlowVertex ::= fName::String attrName::String { top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for anon inherited attributes?"); } +aspect production subtermSynVertex +top::FlowVertex ::= parent::VertexType prodName::String sigName::String attrName::String +{ + top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for subterm synthesized attributes?"); +} +aspect production subtermInhVertex +top::FlowVertex ::= parent::VertexType prodName::String sigName::String attrName::String +{ + top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for subterm inherited attributes?"); +} diff --git a/grammars/silver/compiler/definition/flow/driver/ProductionGraph.sv b/grammars/silver/compiler/definition/flow/driver/ProductionGraph.sv index c52b5fb22..ca10e3095 100644 --- a/grammars/silver/compiler/definition/flow/driver/ProductionGraph.sv +++ b/grammars/silver/compiler/definition/flow/driver/ProductionGraph.sv @@ -1,18 +1,16 @@ grammar silver:compiler:definition:flow:driver; import silver:compiler:definition:type only isNonterminal, typerep; +import silver:compiler:analysis:warnings:flow only sigAttrViaReference, localAttrViaReference; -nonterminal ProductionGraph with flowTypes, stitchedGraph, prod, lhsNt, transitiveClosure, edgeMap, suspectEdgeMap, cullSuspect, flowTypeVertexes, prodGraphs; - -inherited attribute flowTypes :: EnvTree; -inherited attribute prodGraphs :: EnvTree; +data nonterminal ProductionGraph with stitchedGraph, prod, lhsNt, transitiveClosure, edgeMap, suspectEdgeMap, cullSuspect, flowTypeVertexes; -- TODO: future me note: these are good candidates to be "static attributes" maybe? {-- - Given a set of flow types, stitches those edges into the graph for - all stitch points (i.e. children, locals, forward) -} -synthesized attribute stitchedGraph :: ProductionGraph; +synthesized attribute stitchedGraph :: (ProductionGraph ::= EnvTree EnvTree); {-- - Just compute the transitive closure of the edge set -} @@ -23,7 +21,7 @@ synthesized attribute transitiveClosure :: ProductionGraph; synthesized attribute edgeMap :: (set:Set ::= FlowVertex); synthesized attribute suspectEdgeMap :: ([FlowVertex] ::= FlowVertex); -synthesized attribute cullSuspect :: ProductionGraph; +synthesized attribute cullSuspect :: (ProductionGraph ::= EnvTree); -- This is, apparently, only used to look up production by name synthesized attribute prod::String; @@ -60,10 +58,10 @@ top::ProductionGraph ::= top.lhsNt = lhsNt; top.flowTypeVertexes = flowTypeVertexes; - top.stitchedGraph = + top.stitchedGraph = \ flowTypes::EnvTree prodGraphs::EnvTree -> let newEdges :: [Pair] = filter(edgeIsNew(_, graph), - flatMap(stitchEdgesFor(_, top.flowTypes, top.prodGraphs), stitchPoints)) + flatMap(stitchEdgesFor(_, flowTypes, prodGraphs), stitchPoints)) in let repaired :: g:Graph = repairClosure(newEdges, graph) in if null(newEdges) then top else @@ -79,10 +77,10 @@ top::ProductionGraph ::= top.edgeMap = g:edgesFrom(_, graph); top.suspectEdgeMap = lookupAll(_, suspectEdges); - top.cullSuspect = + top.cullSuspect = \ flowTypes::EnvTree -> -- this potentially introduces the same edge twice, but that's a nonissue let newEdges :: [Pair] = - flatMap(findAdmissibleEdges(_, graph, findFlowType(lhsNt, top.flowTypes)), suspectEdges) + flatMap(findAdmissibleEdges(_, graph, findFlowType(lhsNt, flowTypes)), suspectEdges) in let repaired :: g:Graph = repairClosure(newEdges, graph) in if null(newEdges) then top else @@ -96,18 +94,12 @@ ProductionGraph ::= prodEnv::EnvTree ntEnv::EnvTree { - graph.flowTypes = ntEnv; - graph.prodGraphs = prodEnv; - - local stitchedGraph :: ProductionGraph = graph.stitchedGraph; - stitchedGraph.flowTypes = ntEnv; - - return stitchedGraph.cullSuspect; + return graph.stitchedGraph(ntEnv, prodEnv).cullSuspect(ntEnv); } -- construct a production graph for each production function computeAllProductionGraphs -[ProductionGraph] ::= prods::[ValueDclInfo] prodTree::EnvTree flowEnv::FlowEnv realEnv::Decorated Env +[ProductionGraph] ::= prods::[ValueDclInfo] prodTree::EnvTree flowEnv::FlowEnv realEnv::Env { return if null(prods) then [] else constructProductionGraph(head(prods), searchEnvTree(head(prods).fullName, prodTree), flowEnv, realEnv) :: @@ -143,31 +135,26 @@ function computeAllProductionGraphs - 2. All synthesized attributes missing equations have dep on their corresponding fwd. - 2b. OR use their default if not forwarding and it exists. - 3. All inherited attributes not supplied to forward have copies. - - 4. All autocopy attributes not supplied to childred have copies. - - @param dcl The DclInfo of the production - @param defs The set of defs from prodGraphContribs - @param flowEnv A full flow environment - (used to discover what explicit equations exist, find info on nonterminals) - @param realEnv A full real environment - - (used to discover attribute occurrences, whether inh/syn/auto) + - (used to discover attribute occurrences, whether inh/syn) - @return A fixed up graph. -} function constructProductionGraph -ProductionGraph ::= dcl::ValueDclInfo defs::[FlowDef] flowEnv::FlowEnv realEnv::Decorated Env +ProductionGraph ::= dcl::ValueDclInfo defs::[FlowDef] flowEnv::FlowEnv realEnv::Env { -- The name of this production local prod :: String = dcl.fullName; -- The LHS nonterminal full name local nt :: NtName = dcl.namedSignature.outputElement.typerep.typeName; - -- All attributes occurrences - local attrs :: [OccursDclInfo] = getAttrsOn(nt, realEnv); -- Just synthesized attributes. - local syns :: [String] = map((.attrOccurring), filter(isOccursSynthesized(_, realEnv), attrs)); - -- Just inherited. - local inhs :: [String] = map((.attrOccurring), filter(isOccursInherited(_, realEnv), attrs)); - -- Autocopy. - local autos :: [String] = filter(isAutocopy(_, realEnv), inhs); + local syns :: [String] = getSynAttrsOn(nt, realEnv); + -- Just inherited and inherited on translation attributes. + local inhs :: [String] = getInhAndInhOnTransAttrsOn(nt, realEnv); -- Does this production forward? local nonForwarding :: Boolean = null(lookupFwd(prod, flowEnv)); @@ -181,10 +168,10 @@ ProductionGraph ::= dcl::ValueDclInfo defs::[FlowDef] flowEnv::FlowEnv realEn (if nonForwarding then addDefEqs(prod, nt, syns, flowEnv) else -- This first pair is used sometimes as an alias: - pair(lhsSynVertex("forward"), forwardEqVertex()) :: + (lhsSynVertex("forward"), forwardEqVertex()) :: addFwdSynEqs(prod, synsBySuspicion.fst, flowEnv) ++ addFwdInhEqs(prod, inhs, flowEnv)) ++ - addAllAutoCopyEqs(prod, dcl.namedSignature.inputElements, autos, flowEnv, realEnv); + flatMap(addFwdProdAttrInhEqs(prod, _, inhs, flowEnv), allFwdProdAttrs(defs)); -- (safe, suspect) local synsBySuspicion :: Pair<[String] [String]> = @@ -198,9 +185,10 @@ ProductionGraph ::= dcl::ValueDclInfo defs::[FlowDef] flowEnv::FlowEnv realEn -- RHS and locals and forward. local stitchPoints :: [StitchPoint] = - flatMap(rhsStitchPoints, dcl.namedSignature.inputElements) ++ - localStitchPoints(nt, defs) ++ - patternStitchPoints(realEnv, defs); + flatMap(rhsStitchPoints(realEnv, _), dcl.namedSignature.inputElements) ++ + localStitchPoints(realEnv, nt, defs) ++ + patternStitchPoints(realEnv, defs) ++ + subtermDecSiteStitchPoints(flowEnv, realEnv, defs); local flowTypeVertexesOverall :: [FlowVertex] = (if nonForwarding then [] else [forwardEqVertex()]) ++ @@ -228,7 +216,7 @@ ProductionGraph ::= dcl::ValueDclInfo defs::[FlowDef] flowEnv::FlowEnv realEn - @param ntEnv The flow types we've previously computed -} function constructFunctionGraph -ProductionGraph ::= ns::NamedSignature flowEnv::FlowEnv realEnv::Decorated Env prodEnv::EnvTree ntEnv::EnvTree +ProductionGraph ::= ns::NamedSignature flowEnv::FlowEnv realEnv::Env prodEnv::EnvTree ntEnv::EnvTree { local prod :: String = ns.fullName; local nt :: NtName = "::nolhs"; -- the same hack we use elsewhere @@ -246,9 +234,10 @@ ProductionGraph ::= ns::NamedSignature flowEnv::FlowEnv realEnv::Decorated Env -- RHS and locals and forward. local stitchPoints :: [StitchPoint] = - flatMap(rhsStitchPoints, ns.inputElements) ++ - localStitchPoints(error("functions shouldn't have a forwarding equation?"), defs) ++ - patternStitchPoints(realEnv, defs); + flatMap(rhsStitchPoints(realEnv, _), ns.inputElements) ++ + localStitchPoints(realEnv, error("functions shouldn't have a forwarding equation?"), defs) ++ + patternStitchPoints(realEnv, defs) ++ + subtermDecSiteStitchPoints(flowEnv, realEnv, defs); local flowTypeVertexes :: [FlowVertex] = []; -- Not used as part of inference. @@ -266,7 +255,7 @@ ProductionGraph ::= ns::NamedSignature flowEnv::FlowEnv realEnv::Decorated Env - -} function constructAnonymousGraph -ProductionGraph ::= defs::[FlowDef] realEnv::Decorated Env prodEnv::EnvTree ntEnv::EnvTree +ProductionGraph ::= defs::[FlowDef] realEnv::Env prodEnv::EnvTree ntEnv::EnvTree { -- Actually very unclear to me right now if these dummy names matter. -- Presently duplicating what appears in BlockContext @@ -284,7 +273,7 @@ ProductionGraph ::= defs::[FlowDef] realEnv::Decorated Env prodEnv::EnvTree ntEnv::EnvTree +ProductionGraph ::= ns::NamedSignature defs::[FlowDef] realEnv::Env prodEnv::EnvTree ntEnv::EnvTree { local prod :: String = ns.fullName; local nt :: NtName = ns.outputElement.typerep.typeName; @@ -319,8 +308,8 @@ ProductionGraph ::= ns::NamedSignature defs::[FlowDef] realEnv::Decorated Env -- There can still be anonEq, but there's no RHS anymore -- However, we do behave like phantom graphs and create an LHS stitch point! local stitchPoints :: [StitchPoint] = - [nonterminalStitchPoint(nt, lhsVertexType)] ++ - localStitchPoints(error("default production shouldn't have a forwarding equation?"), defs) ++ + nonterminalStitchPoints(realEnv, nt, lhsVertexType) ++ + localStitchPoints(realEnv, error("default production shouldn't have a forwarding equation?"), defs) ++ patternStitchPoints(realEnv, defs); local flowTypeVertexes :: [FlowVertex] = []; -- Not used as part of inference. @@ -342,23 +331,21 @@ ProductionGraph ::= ns::NamedSignature defs::[FlowDef] realEnv::Decorated Env - @return A fixed up graph. -} function constructPhantomProductionGraph -ProductionGraph ::= nt::String flowEnv::FlowEnv realEnv::Decorated Env +ProductionGraph ::= nt::String flowEnv::FlowEnv realEnv::Env { - -- All attributes occurrences - local attrs :: [OccursDclInfo] = getAttrsOn(nt, realEnv); -- Just synthesized attributes. - local syns :: [String] = map((.attrOccurring), filter(isOccursSynthesized(_, realEnv), attrs)); + local syns :: [String] = getSynAttrsOn(nt, realEnv); -- Those syns that are not part of the host, and so should have edges to fwdeq local extSyns :: [String] = removeAll(getHostSynsFor(nt, flowEnv), syns); -- The phantom edges: ext syn -> fwd.eq local phantomEdges :: [Pair] = -- apparently this alias may sometimes be used. we should get rid of this by making good use of vertex types - pair(lhsSynVertex("forward"), forwardEqVertex()) :: + (lhsSynVertex("forward"), forwardEqVertex()) :: map(getPhantomEdge, extSyns); -- The stitch point: oddball. LHS stitch point. Normally, the LHS is not. - local stitchPoints :: [StitchPoint] = [nonterminalStitchPoint(nt, lhsVertexType)]; + local stitchPoints :: [StitchPoint] = nonterminalStitchPoints(realEnv, nt, lhsVertexType); local flowTypeVertexes :: [FlowVertex] = [forwardEqVertex()] ++ map(lhsSynVertex, syns); local initialGraph :: g:Graph = createFlowGraph(phantomEdges); @@ -370,7 +357,7 @@ ProductionGraph ::= nt::String flowEnv::FlowEnv realEnv::Decorated Env function getPhantomEdge Pair ::= at::String { - return pair(lhsSynVertex(at), forwardEqVertex()); + return (lhsSynVertex(at), forwardEqVertex()); } ---- Begin helpers for fixing up graphs ---------------------------------------- @@ -384,8 +371,8 @@ function addFwdSynEqs { return if null(syns) then [] else (if null(lookupSyn(prod, head(syns), flowEnv)) - then [pair(lhsSynVertex(head(syns)), forwardVertex(head(syns))), - pair(lhsSynVertex(head(syns)), forwardEqVertex())] else []) ++ + then [(lhsSynVertex(head(syns)), forwardSynVertex(head(syns))), + (lhsSynVertex(head(syns)), forwardEqVertex())] else []) ++ addFwdSynEqs(prod, tail(syns), flowEnv); } {-- @@ -396,9 +383,29 @@ function addFwdInhEqs [Pair] ::= prod::ProdName inhs::[String] flowEnv::FlowEnv { return if null(inhs) then [] - else (if null(lookupFwdInh(prod, head(inhs), flowEnv)) then [pair(forwardVertex(head(inhs)), lhsInhVertex(head(inhs)))] else []) ++ + else (if null(lookupFwdInh(prod, head(inhs), flowEnv)) then [(forwardInhVertex(head(inhs)), lhsInhVertex(head(inhs)))] else []) ++ addFwdInhEqs(prod, tail(inhs), flowEnv); } +{-- + - Introduces implicit 'fwrd.inh = lhs.inh' equations for forward production attributes. + - Inherited equations are never suspect. + -} +function addFwdProdAttrInhEqs +[Pair] ::= prod::ProdName fName::String inhs::[String] flowEnv::FlowEnv +{ + return if null(inhs) then [] + else (if null(lookupLocalInh(prod, fName, head(inhs), flowEnv)) then [(localInhVertex(fName, head(inhs)), lhsInhVertex(head(inhs)))] else []) ++ + addFwdProdAttrInhEqs(prod, fName, tail(inhs), flowEnv); +} +function allFwdProdAttrs +[String] ::= d::[FlowDef] +{ + return case d of + | [] -> [] + | localEq(_, fN, _, true, true, _) :: rest -> fN :: allFwdProdAttrs(rest) + | _ :: rest -> allFwdProdAttrs(rest) + end; +} {-- - Introduces default equations deps. Realistically, should be empty, always. -} @@ -413,58 +420,56 @@ function addDefEqs else []) ++ addDefEqs(prod, nt, tail(syns), flowEnv); } -{-- - - Introduces 'rhs.inh = lhs.inh' wherever not present. - - Inherited equations are never suspect. - -} -function addAllAutoCopyEqs -[Pair] ::= prod::ProdName sigNames::[NamedSignatureElement] inhs::[String] flowEnv::FlowEnv realEnv::Decorated Env -{ - return if null(sigNames) then [] - else addAutocopyEqs(prod, head(sigNames), inhs, flowEnv, realEnv) ++ addAllAutoCopyEqs(prod, tail(sigNames), inhs, flowEnv, realEnv); -} --- Helper for above. -function addAutocopyEqs -[Pair] ::= prod::ProdName sigName::NamedSignatureElement inhs::[String] flowEnv::FlowEnv realEnv::Decorated Env -{ - return if null(inhs) then [] - else (if null(lookupInh(prod, sigName.elementName, head(inhs), flowEnv)) -- no equation - && !null(getOccursDcl(head(inhs), sigName.typerep.typeName, realEnv)) -- and it occurs on this type - then [pair(rhsVertex(sigName.elementName, head(inhs)), lhsInhVertex(head(inhs)))] - else []) ++ - addAutocopyEqs(prod, sigName, tail(inhs), flowEnv, realEnv); -} ---- End helpers for fixing up graphs ------------------------------------------ ---- Begin helpers for figuring out stitch points ------------------------------ +{-- + - Stitch points for the flow type of 'nt', and the flow types of all translation attributes on 'nt'. + -} +function nonterminalStitchPoints +[StitchPoint] ::= realEnv::Env nt::NtName vertexType::VertexType +{ + return + nonterminalStitchPoint(nt, vertexType) :: + flatMap( + \ o::OccursDclInfo -> + case getAttrDcl(o.attrOccurring, realEnv) of + | at :: _ when at.isSynthesized && at.isTranslation -> + [nonterminalStitchPoint( + at.typeScheme.typeName, + transAttrVertexType(vertexType, o.attrOccurring))] + | _ -> [] + end, + getAttrOccursOn(nt, realEnv)); +} function localStitchPoints -[StitchPoint] ::= nt::NtName d::[FlowDef] +[StitchPoint] ::= realEnv::Env nt::NtName ds::[FlowDef] { - return case d of - | [] -> [] - -- We add the forward stitch point here, too! - | fwdEq(_, _, _) :: rest -> nonterminalStitchPoint(nt, forwardVertexType) :: localStitchPoints(nt, rest) - -- Add locals that are nonterminal types. - | localEq(_, fN, tN, true, _) :: rest -> nonterminalStitchPoint(tN, localVertexType(fN)) :: localStitchPoints(nt, rest) - -- Add anon decoration sites that are nonterminal types - | anonEq(_, fN, tN, true, _, _) :: rest -> nonterminalStitchPoint(tN, anonVertexType(fN)) :: localStitchPoints(nt, rest) - -- Ignore all other flow def info - | _ :: rest -> localStitchPoints(nt, rest) - end; + return flatMap(\ d::FlowDef -> + case d of + -- We add the forward stitch point here, too! + | fwdEq(_, _, _) -> nonterminalStitchPoints(realEnv, nt, forwardVertexType) + -- Add locals that are nonterminal types. + | localEq(_, fN, tN, true, _, _) -> nonterminalStitchPoints(realEnv, tN, localVertexType(fN)) + -- Add anon decoration sites that are nonterminal types + | anonEq(_, fN, tN, true, _, _) -> nonterminalStitchPoints(realEnv, tN, anonVertexType(fN)) + -- Ignore all other flow def info + | _ -> [] + end, ds); } function rhsStitchPoints -[StitchPoint] ::= rhs::NamedSignatureElement +[StitchPoint] ::= realEnv::Env rhs::NamedSignatureElement { return -- We want only NONTERMINAL stitch points! if rhs.typerep.isNonterminal - then [nonterminalStitchPoint(rhs.typerep.typeName, rhsVertexType(rhs.elementName))] + then nonterminalStitchPoints(realEnv, rhs.typerep.typeName, rhsVertexType(rhs.elementName)) else []; } function patternStitchPoints -[StitchPoint] ::= realEnv::Decorated Env defs::[FlowDef] +[StitchPoint] ::= realEnv::Env defs::[FlowDef] { return case defs of | [] -> [] @@ -475,22 +480,30 @@ function patternStitchPoints end; } function patVarStitchPoints -[StitchPoint] ::= matchProd::String scrutinee::VertexType realEnv::Decorated Env var::PatternVarProjection +[StitchPoint] ::= matchProd::String scrutinee::VertexType realEnv::Env var::PatternVarProjection { return case var of | patternVarProjection(child, typeName, patternVar) -> - [nonterminalStitchPoint(typeName, anonVertexType(patternVar)), - projectionStitchPoint(matchProd, anonVertexType(patternVar), scrutinee, rhsVertexType(child), getInhsForNtForPatternVars(typeName, realEnv))] + projectionStitchPoint( + matchProd, anonVertexType(patternVar), scrutinee, rhsVertexType(child), + getInhAndInhOnTransAttrsOn(typeName, realEnv)) :: + nonterminalStitchPoints(realEnv, typeName, anonVertexType(patternVar)) end; } - --- fudge :( --- This is an annoying thing to have to write here. --- I wish for a better way to discover this info. -function getInhsForNtForPatternVars -[String] ::= nt::String realEnv::Decorated Env +function subtermDecSiteStitchPoints +[StitchPoint] ::= flowEnv::FlowEnv realEnv::Env defs::[FlowDef] { - return map((.attrOccurring), filter(isOccursInherited(_, realEnv), getAttrsOn(nt, realEnv))); + return flatMap(\ d::FlowDef -> + case d of + | subtermDecEq(prodName, parent, termProdName, sigName) -> + map(\ prodDcl::ValueDclInfo -> + projectionStitchPoint( + termProdName, subtermVertexType(parent, termProdName, sigName), parent, rhsVertexType(sigName), + getInhAndInhOnTransAttrsOn(prodDcl.namedSignature.outputElement.typerep.typeName, realEnv)), + getValueDcl(termProdName, realEnv)) + | _ -> [] + end, + defs); } ---- End helpers for figuring our stitch points -------------------------------- @@ -498,15 +511,7 @@ function getInhsForNtForPatternVars function prodGraphToEnv Pair ::= p::ProductionGraph { - return pair(p.prod, p); -} -function isOccursInherited -Boolean ::= occs::OccursDclInfo e::Decorated Env -{ - return case getAttrDcl(occs.attrOccurring, e) of - | at :: _ -> at.isInherited - | _ -> false - end; + return (p.prod, p); } ---- Begin Suspect edge handling ----------------------------------------------- @@ -557,6 +562,6 @@ function findAdmissibleEdges filter(isLhsInhSet(_, currentDeps), set:toList(targetNotSource)); return if set:isEmpty(currentDeps) then [] -- just a quick optimization. - else map(pair(edge.fst, _), validDeps); + else map(pair(fst=edge.fst, snd=_), validDeps); } diff --git a/grammars/silver/compiler/definition/flow/driver/StitchPoint.sv b/grammars/silver/compiler/definition/flow/driver/StitchPoint.sv index 9cacb5f30..e2c97dcc2 100644 --- a/grammars/silver/compiler/definition/flow/driver/StitchPoint.sv +++ b/grammars/silver/compiler/definition/flow/driver/StitchPoint.sv @@ -1,8 +1,8 @@ grammar silver:compiler:definition:flow:driver; -nonterminal StitchPoint with prodGraphs, flowTypes, stitchEdges; +data nonterminal StitchPoint with stitchEdges; -synthesized attribute stitchEdges :: [Pair]; +synthesized attribute stitchEdges :: ([Pair] ::= EnvTree EnvTree); {-- - Introduces internal edges corresponding to the flow type of 'nt' @@ -11,9 +11,9 @@ synthesized attribute stitchEdges :: [Pair]; abstract production nonterminalStitchPoint top::StitchPoint ::= nt::String vertexType::VertexType { - top.stitchEdges = + top.stitchEdges = \ flowTypes::EnvTree prodGraphs::EnvTree -> map(flowTypeEdge(vertexType, _), - g:toList(findFlowType(nt, top.flowTypes))); + g:toList(findFlowType(nt, flowTypes))); } @@ -45,9 +45,9 @@ top::StitchPoint ::= prodType::VertexType -- a rhsVertex of 'prod' attrs::[String] -- all inhs on the NT type of prodType/sourceType { - top.stitchEdges = + top.stitchEdges = \ flowTypes::EnvTree prodGraphs::EnvTree -> flatMap( - projectAttribute(_, sourceType, targetType, prodType, findProductionGraph(prod, top.prodGraphs)), + projectAttribute(_, sourceType, targetType, prodType, findProductionGraph(prod, prodGraphs)), attrs); } @@ -69,7 +69,7 @@ function projectAttribute prod::ProductionGraph { -- emit edges from the src vertex of this production - return map(pair(sourceType.inhVertex(attr), _), + return map(pair(fst=sourceType.inhVertex(attr), snd=_), -- Turn into inh vertexes (in this production) on targetType map(targetType.inhVertex, -- Filter down to just LHS Inh in that production, (string names) @@ -83,9 +83,7 @@ function projectAttribute function stitchEdgesFor [Pair] ::= sp::StitchPoint ntEnv::EnvTree prodEnv::EnvTree { - sp.prodGraphs = prodEnv; - sp.flowTypes = ntEnv; - return sp.stitchEdges; + return sp.stitchEdges(ntEnv, prodEnv); } function edgeIsNew @@ -105,8 +103,8 @@ function flowTypeEdge Pair ::= vt::VertexType edge::Pair { return if edge.fst == "forward" then - pair(vt.fwdVertex, vt.inhVertex(edge.snd)) + (vt.fwdVertex, vt.inhVertex(edge.snd)) else - pair(vt.synVertex(edge.fst), vt.inhVertex(edge.snd)); + (vt.synVertex(edge.fst), vt.inhVertex(edge.snd)); } diff --git a/grammars/silver/compiler/definition/flow/env/Expr.sv b/grammars/silver/compiler/definition/flow/env/Expr.sv index b682b81ca..39f75ccd1 100644 --- a/grammars/silver/compiler/definition/flow/env/Expr.sv +++ b/grammars/silver/compiler/definition/flow/env/Expr.sv @@ -2,10 +2,12 @@ grammar silver:compiler:definition:flow:env; import silver:compiler:definition:type:syntax; import silver:compiler:definition:type; +import silver:compiler:analysis:typechecking:core; import silver:compiler:modification:copper; import silver:compiler:modification:primitivepattern; import silver:compiler:extension:patternmatching only Arrow_kwd, Vbar_kwd; -- TODO remove import silver:compiler:modification:let_fix; +import silver:compiler:modification:lambda_fn; import silver:compiler:driver:util only isExportedBy; @@ -13,11 +15,38 @@ import silver:compiler:driver:util only isExportedBy; - Direct (potential) dependencies this expression has on nodes in the production flow graph. -} monoid attribute flowDeps :: [FlowVertex]; + {-- - Determines whether this expression corresponds to a node in the flow graph, and how - to treat it specially if so. + - + - Do not forget we also need to address its equation (but vertexType takes care of that too) + - + - e.g. new(decorate rhs.a with {}) needs to emit 'rhs.a' still, even while + - ignoring the decorate vertex. That happens when we refer to the anonEq. + - + - When this is nothing(), the expression does not have a corresponding vertex in the + - production graph and so much be treated as any value. + -} +synthesized attribute flowVertexInfo :: Maybe; + +{-- + - Where this expression is known to ultimately get decorated, if at all. + - The supplied inherited attributes correspond to the inherited vertices for this vertex type. + -} +inherited attribute decSiteVertexInfo :: Maybe; + +{-- + - Is this expression unconditionally decorated. + - Can be false when decSiteVertexInfo is just(...)! For example: + - + - local foo::Expr = if cond then @e else bar; + - foo.env = top.env; + - + - we know that e's decoration site vertex is foo, and e.env can depend on top.env, + - but we can't gurantee that e.env is defined in case cond is false. -} -synthesized attribute flowVertexInfo :: ExprVertexInfo; +inherited attribute alwaysDecorated :: Boolean; -- flowDefs because expressions (decorate, patterns) can now generate stitchpoints attribute flowDeps, flowDefs, flowEnv occurs on Expr, ExprInhs, ExprInh, Exprs, AppExprs, AppExpr, AnnoAppExprs, AnnoExpr; @@ -25,9 +54,13 @@ attribute flowVertexInfo occurs on Expr; propagate flowDeps on Expr, ExprInhs, ExprInh, Exprs, AppExprs, AppExpr, AnnoAppExprs, AnnoExpr excluding - childReference, lhsReference, localReference, forwardReference, forwardAccess, synDecoratedAccessHandler, inhDecoratedAccessHandler, + childReference, lhsReference, localReference, forwardReference, forwardAccess, + synDecoratedAccessHandler, inhDecoratedAccessHandler, transDecoratedAccessHandler, decorateExprWith, letp, lexicalLocalReference, matchPrimitiveReal; -propagate flowDefs on Expr, ExprInhs, ExprInh, Exprs, AppExprs, AppExpr, AnnoAppExprs, AnnoExpr; +propagate flowDefs, flowEnv on Expr, ExprInhs, ExprInh, Exprs, AppExprs, AppExpr, AnnoAppExprs, AnnoExpr; + +attribute decSiteVertexInfo, alwaysDecorated occurs on Expr, AppExprs, AppExpr; +propagate decSiteVertexInfo, alwaysDecorated on AppExprs; aspect default production top::Expr ::= @@ -35,89 +68,203 @@ top::Expr ::= -- We go with using default here because -- (a) it's safe. vertexInfo is for being less conservative and more precise. -- (b) only a few productions actually provide it. - top.flowVertexInfo = noVertex(); + top.flowVertexInfo = nothing(); } aspect production childReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { -- Note that q should find the actual type written in the signature, and so -- isDecorable on that indeed tells us whether it's something autodecorated. - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - production refSet::Maybe<[String]> = getMaxRefSet(finalTy, top.env); + production refSet::Maybe<[String]> = getMaxRefSet(top.finalType, top.env); production origRefSet::[String] = getMinRefSet(q.lookupValue.typeScheme.monoType, top.env); top.flowDeps := - if isDecorable(q.lookupValue.typeScheme.monoType, top.env) && finalTy.isDecorated + if isDecorable(q.lookupValue.typeScheme.monoType, top.env) && top.finalType.isDecorated then map(rhsVertexType(q.lookupValue.fullName).inhVertex, removeAll(origRefSet, fromMaybe([], refSet))) else []; top.flowVertexInfo = - if isDecorable(q.lookupValue.typeScheme.monoType, top.env) && finalTy.isDecorated - then hasVertex(rhsVertexType(q.lookupValue.fullName)) - else noVertex(); - + if isDecorable(q.lookupValue.typeScheme.monoType, top.env) && top.finalType.isDecorated + then just(rhsVertexType(q.lookupValue.fullName)) + else nothing(); + + -- Inherited attributes on q's NT that aren't in the reference set and don't have an equation: + local notSuppliedInhs::[String] = + filter( + isEquationMissing(lookupInh(top.frame.fullName, q.lookupValue.fullName, _, top.flowEnv), _), + removeAll( + origRefSet, + getInhAndInhOnTransAttrsOn(top.finalType.decoratedType.typeName, top.env))); + -- Add remote equations for reference site decoration with attributes that aren't supplied here top.flowDefs <- - case finalTy, refSet of - | partiallyDecoratedType(_, _), just(inhs) - when isExportedBy(top.grammarName, [q.lookupValue.dcl.sourceGrammar], top.compiledGrammars) -> - [partialRef(top.frame.fullName, q.lookupValue.fullName, top.grammarName, q.location, inhs)] - | _, _ -> [] + case top.decSiteVertexInfo of + | just(decSite) when top.finalType.isUniqueDecorated -> + [childRefDecSiteEq(top.frame.fullName, q.lookupValue.fullName, top.alwaysDecorated, decSite, notSuppliedInhs)] + | _ -> [] end; } aspect production lhsReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { -- Always a decorable type, so just check how it's being used: - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - production refSet::Maybe<[String]> = getMaxRefSet(finalTy, top.env); + production refSet::Maybe<[String]> = getMaxRefSet(top.finalType, top.env); top.flowDeps := - if finalTy.isDecorated + if top.finalType.isDecorated then map(lhsVertexType.inhVertex, fromMaybe([], refSet)) else []; top.flowVertexInfo = - if finalTy.isDecorated - then hasVertex(lhsVertexType) - else noVertex(); + if top.finalType.isDecorated + then just(lhsVertexType) + else nothing(); } aspect production localReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { -- Again, q give the actual type written. - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - production refSet::Maybe<[String]> = getMaxRefSet(finalTy, top.env); + production refSet::Maybe<[String]> = getMaxRefSet(top.finalType, top.env); production origRefSet::[String] = getMinRefSet(q.lookupValue.typeScheme.monoType, top.env); top.flowDeps := [localEqVertex(q.lookupValue.fullName)] ++ - if isDecorable(q.lookupValue.typeScheme.monoType, top.env) && finalTy.isDecorated - then map(rhsVertexType(q.lookupValue.fullName).inhVertex, removeAll(origRefSet, fromMaybe([], refSet))) + if isDecorable(q.lookupValue.typeScheme.monoType, top.env) && top.finalType.isDecorated + then map(localVertexType(q.lookupValue.fullName).inhVertex, removeAll(origRefSet, fromMaybe([], refSet))) else []; - top.flowVertexInfo = - if isDecorable(q.lookupValue.typeScheme.monoType, top.env) && finalTy.isDecorated - then hasVertex(localVertexType(q.lookupValue.fullName)) - else noVertex(); - + if isDecorable(q.lookupValue.typeScheme.monoType, top.env) && top.finalType.isDecorated + then just(localVertexType(q.lookupValue.fullName)) + else nothing(); + + -- If this is a forward production attribute, then all inh attributes have an equation here. + local isForwardProdAttr::Boolean = q.lookupValue.found && q.lookupValue.dcl.hasForward; + + -- Inherited attributes on q's NT that aren't in the reference set and don't have an equation: + local notSuppliedInhs::[String] = + if isForwardProdAttr then [] else + filter( + isEquationMissing(lookupLocalInh(top.frame.fullName, q.lookupValue.fullName, _, top.flowEnv), _), + removeAll( + origRefSet, + getInhAndInhOnTransAttrsOn(top.finalType.decoratedType.typeName, top.env))); + -- Add remote equations for reference site decoration with attributes that aren't supplied here top.flowDefs <- - case finalTy, refSet of - | partiallyDecoratedType(_, _), just(inhs) - when isExportedBy(top.grammarName, [q.lookupValue.dcl.sourceGrammar], top.compiledGrammars) -> - [partialRef(top.frame.fullName, q.lookupValue.fullName, top.grammarName, q.location, inhs)] - | _, _ -> [] + case top.decSiteVertexInfo of + | just(decSite) when top.finalType.isUniqueDecorated && !isForwardProdAttr -> + [localRefDecSiteEq(top.frame.fullName, q.lookupValue.fullName, top.alwaysDecorated, decSite, notSuppliedInhs)] + | _ -> [] end; } aspect production forwardReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { -- Again, always a decorable type. - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - production refSet::Maybe<[String]> = getMaxRefSet(finalTy, top.env); + production refSet::Maybe<[String]> = getMaxRefSet(top.finalType, top.env); top.flowDeps := [forwardEqVertex()]++ - if finalTy.isDecorated + if top.finalType.isDecorated then map(forwardVertexType.inhVertex, fromMaybe([], refSet)) else []; - top.flowVertexInfo = - if finalTy.isDecorated - then hasVertex(forwardVertexType) - else noVertex(); + if top.finalType.isDecorated + then just(forwardVertexType) + else nothing(); +} + +-- The named signature of the applied production. +-- Note that we don't project functions at the moment, since we don't build function flow graphs during inference. +inherited attribute appProd::Maybe occurs on AppExprs, AppExpr; +propagate appProd on AppExprs; + +aspect production application +top::Expr ::= e::Expr '(' es::AppExprs ',' anns::AnnoAppExprs ')' +{ + propagate flowEnv; + e.alwaysDecorated = false; +} + +aspect production errorApplication +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs +{ + e.decSiteVertexInfo = nothing(); + es.decSiteVertexInfo = nothing(); + es.alwaysDecorated = false; + es.appProd = nothing(); +} + +aspect production functionInvocation +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs +{ + top.flowVertexInfo = top.decSiteVertexInfo; + es.appProd = + case e of + | productionReference(q) -> just(q.lookupValue.dcl.namedSignature) + | _ -> nothing() + end; + e.decSiteVertexInfo = nothing(); + es.decSiteVertexInfo = top.decSiteVertexInfo; + es.alwaysDecorated = top.alwaysDecorated; +} + +aspect production partialApplication +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs +{ + es.appProd = + case e of + | productionReference(q) -> just(q.lookupValue.dcl.namedSignature) + | _ -> nothing() + end; + e.decSiteVertexInfo = nothing(); + es.decSiteVertexInfo = nothing(); + es.alwaysDecorated = false; +} + +aspect production annoExpr +top::AnnoExpr ::= qn::QName '=' e::AppExpr +{ + e.decSiteVertexInfo = nothing(); + e.appProd = nothing(); + e.alwaysDecorated = false; +} + +aspect production presentAppExpr +top::AppExpr ::= e::Expr +{ + production sigName::String = + case top.appProd of + | just(ns) when top.appExprIndex < length(ns.inputNames) -> head(drop(top.appExprIndex, ns.inputNames)) + | _ -> "err" + end; + top.flowDefs <- + case e.decSiteVertexInfo of + | just(subtermVertexType(parent, prodName, sigName)) -> + [subtermDecEq(top.frame.fullName, parent, prodName, sigName)] + | _ -> [] + end; + e.decSiteVertexInfo = + case top.decSiteVertexInfo, top.appProd of + | just(parent), just(ns) when isDecorable(e.finalType, top.env) -> + just(subtermVertexType(parent, ns.fullName, sigName)) + | _, _ -> nothing() + end; + e.alwaysDecorated = top.alwaysDecorated && e.decSiteVertexInfo.isJust; +} + +aspect production noteAttachment +top::Expr ::= 'attachNote' note::Expr 'on' e::Expr 'end' +{ + note.decSiteVertexInfo = nothing(); + e.decSiteVertexInfo = nothing(); + note.alwaysDecorated = false; + e.alwaysDecorated = false; +} + +aspect production access +top::Expr ::= e::Expr '.' q::QNameAttrOccur +{ + propagate flowEnv; + e.alwaysDecorated = false; +} + +aspect production accessBouncer +top::Expr ::= target::(Expr ::= Decorated! Expr Decorated! QNameAttrOccur Location) e::Expr q::Decorated! QNameAttrOccur +{ + propagate flowEnv; + e.alwaysDecorated = false; } aspect production forwardAccess @@ -125,30 +272,107 @@ top::Expr ::= e::Expr '.' 'forward' { top.flowDeps := case e.flowVertexInfo of - | hasVertex(vertex) -> vertex.fwdVertex :: vertex.eqVertex - | noVertex() -> e.flowDeps + | just(vertex) -> vertex.fwdVertex :: vertex.eqVertex + | nothing() -> e.flowDeps end; + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; } + +aspect production errorAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + e.decSiteVertexInfo = nothing(); +} +aspect production terminalAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + e.decSiteVertexInfo = nothing(); +} -- Note that below we IGNORE the flow deps of the lhs if we know what it is -- this is because by default the lhs will have 'taking ref' flow deps (see above) aspect production synDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { top.flowDeps := case e.flowVertexInfo of - | hasVertex(vertex) -> vertex.synVertex(q.attrDcl.fullName) :: vertex.eqVertex - | noVertex() -> e.flowDeps + | just(vertex) -> vertex.synVertex(q.attrDcl.fullName) :: vertex.eqVertex + | nothing() -> e.flowDeps end; + e.decSiteVertexInfo = nothing(); } aspect production inhDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { top.flowDeps := case e.flowVertexInfo of - | hasVertex(vertex) -> vertex.inhVertex(q.attrDcl.fullName) :: vertex.eqVertex - | noVertex() -> e.flowDeps + | just(vertex) -> vertex.inhVertex(q.attrDcl.fullName) :: vertex.eqVertex + | nothing() -> e.flowDeps + end; + e.decSiteVertexInfo = nothing(); +} +aspect production transDecoratedAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + production refSet::Maybe<[String]> = getMaxRefSet(top.finalType, top.env); + top.flowVertexInfo = map(transAttrVertexType(_, q.attrDcl.fullName), e.flowVertexInfo); + top.flowDeps := + case e.flowVertexInfo of + | just(vertex) -> vertex.synVertex(q.attrDcl.fullName) :: vertex.eqVertex ++ + if top.finalType.isDecorated then map(vertex.inhVertex, fromMaybe([], refSet)) else [] + | nothing() -> e.flowDeps + end; + + local allInhs::[String] = getInhAndInhOnTransAttrsOn(top.finalType.decoratedType.typeName, top.env); + top.flowDefs <- + case top.decSiteVertexInfo of + | just(decSite) when top.finalType.isUniqueDecorated -> + case e of + | childReference(cqn) -> + [childTransRefDecSiteEq( + top.frame.fullName, cqn.lookupValue.fullName, q.attrDcl.fullName, top.alwaysDecorated, decSite, + filter( + isEquationMissing(lookupInh(top.frame.fullName, cqn.lookupValue.fullName, _, top.flowEnv), _), + allInhs))] + | localReference(lqn) -> + [localTransRefDecSiteEq( + top.frame.fullName, lqn.lookupValue.fullName, q.attrDcl.fullName, top.alwaysDecorated, decSite, + filter( + isEquationMissing(lookupLocalInh(top.frame.fullName, lqn.lookupValue.fullName, _, top.flowEnv), _), + allInhs))] + | _ -> [] + end + | _ -> [] end; + e.decSiteVertexInfo = nothing(); +} +aspect production annoAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + e.decSiteVertexInfo = nothing(); +} +aspect production synDataAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + -- No flow vertex, since there are never any inh deps + + e.decSiteVertexInfo = nothing(); +} +aspect production inhUndecoratedAccessErrorHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + e.decSiteVertexInfo = nothing(); +} +aspect production transUndecoratedAccessErrorHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + e.decSiteVertexInfo = nothing(); +} +aspect production unknownDclAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + e.decSiteVertexInfo = nothing(); } aspect production decorateExprWith @@ -170,26 +394,29 @@ top::Expr ::= 'decorate' e::Expr 'with' '{' inh::ExprInhs '}' -- Next, emit the "local equation" for this anonymous flow vertex. -- This means only the deps in 'e', see above conceptual transformation to see why. -- N.B. 'inh.flowDefs' will emit 'localInhEq's for this anonymous flow vertex. - local eTy::Type = performSubstitution(e.typerep, top.finalSubst); + local eTy::Type = e.finalType; top.flowDefs <- [anonEq(top.frame.fullName, inh.decorationVertex, eTy.typeName, eTy.isNonterminal, top.location, e.flowDeps)]; -- Now, we represent ourselves to anything that might use us specially -- as though we were a reference to this anonymous local - top.flowVertexInfo = hasVertex(anonVertexType(inh.decorationVertex)); + top.flowVertexInfo = just(anonVertexType(inh.decorationVertex)); + e.decSiteVertexInfo = just(anonVertexType(inh.decorationVertex)); + -- The type of decorate ... with ... is a normal reference for now, so this should always be false, but that could change. + e.alwaysDecorated = top.alwaysDecorated; -- Finally, our standard flow deps mimic those of a local: "taking a reference" -- This are of course ignored when treated specially. - local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); - production refSet::Maybe<[String]> = getMaxRefSet(finalTy, top.env); + production refSet::Maybe<[String]> = getMaxRefSet(top.finalType, top.env); top.flowDeps := [anonEqVertex(inh.decorationVertex)] ++ map(anonVertexType(inh.decorationVertex).inhVertex, fromMaybe([], refSet)); -- If we have a type var with occurs-on contexts, add the specified syn -> inh deps for the new vertex - top.flowDefs <- occursContextDeps(top.frame.signature, top.env, finalTy, anonVertexType(inh.decorationVertex)); + top.flowDefs <- occursContextDeps(top.frame.signature, top.env, top.finalType, anonVertexType(inh.decorationVertex)); } -autocopy attribute decorationVertex :: String occurs on ExprInhs, ExprInh; +inherited attribute decorationVertex :: String occurs on ExprInhs, ExprInh; +propagate decorationVertex on ExprInhs, ExprInh; aspect production exprInh top::ExprInh ::= lhs::ExprLHSExpr '=' e1::Expr ';' @@ -199,27 +426,150 @@ top::ExprInh ::= lhs::ExprLHSExpr '=' e1::Expr ';' case lhs of | exprLhsExpr(q) -> [anonInhEq(top.frame.fullName, top.decorationVertex, q.attrDcl.fullName, e1.flowDeps)] end; - + e1.decSiteVertexInfo = nothing(); + e1.alwaysDecorated = false; } -aspect production exprRef -top::Expr ::= e::PartiallyDecorated Expr +aspect production decorationSiteExpr +top::Expr ::= '@' e::Expr { top.flowVertexInfo = e.flowVertexInfo; + e.decSiteVertexInfo = top.decSiteVertexInfo; + e.alwaysDecorated = top.alwaysDecorated; +} + +aspect production and +top::Expr ::= e1::Expr '&&' e2::Expr +{ + e1.decSiteVertexInfo = nothing(); + e2.decSiteVertexInfo = nothing(); + e1.alwaysDecorated = false; + e2.alwaysDecorated = false; +} +aspect production or +top::Expr ::= e1::Expr '||' e2::Expr +{ + e1.decSiteVertexInfo = nothing(); + e2.decSiteVertexInfo = nothing(); + e1.alwaysDecorated = false; + e2.alwaysDecorated = false; +} +aspect production notOp +top::Expr ::= '!' e::Expr +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} + +aspect production ifThenElse +top::Expr ::= 'if' e1::Expr 'then' e2::Expr 'else' e3::Expr +{ + e1.decSiteVertexInfo = nothing(); + e2.decSiteVertexInfo = top.decSiteVertexInfo; + e3.decSiteVertexInfo = top.decSiteVertexInfo; + e1.alwaysDecorated = false; + e2.alwaysDecorated = false; + e3.alwaysDecorated = false; +} + +aspect production plus +top::Expr ::= e1::Expr '+' e2::Expr +{ + e1.decSiteVertexInfo = nothing(); + e2.decSiteVertexInfo = nothing(); + e1.alwaysDecorated = false; + e2.alwaysDecorated = false; +} +aspect production minus +top::Expr ::= e1::Expr '-' e2::Expr +{ + e1.decSiteVertexInfo = nothing(); + e2.decSiteVertexInfo = nothing(); + e1.alwaysDecorated = false; + e2.alwaysDecorated = false; +} +aspect production multiply +top::Expr ::= e1::Expr '*' e2::Expr +{ + e1.decSiteVertexInfo = nothing(); + e2.decSiteVertexInfo = nothing(); + e1.alwaysDecorated = false; + e2.alwaysDecorated = false; +} +aspect production divide +top::Expr ::= e1::Expr _ e2::Expr +{ + e1.decSiteVertexInfo = nothing(); + e2.decSiteVertexInfo = nothing(); + e1.alwaysDecorated = false; + e2.alwaysDecorated = false; +} +aspect production modulus +top::Expr ::= e1::Expr '%' e2::Expr +{ + e1.decSiteVertexInfo = nothing(); + e2.decSiteVertexInfo = nothing(); + e1.alwaysDecorated = false; + e2.alwaysDecorated = false; +} +aspect production neg +top::Expr ::= '-' e::Expr +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} + +aspect production terminalConstructor +top::Expr ::= 'terminal' '(' t::TypeExpr ',' es::Expr ',' el::Expr ')' +{ + es.decSiteVertexInfo = nothing(); + el.decSiteVertexInfo = nothing(); + es.alwaysDecorated = false; + el.alwaysDecorated = false; +} + +aspect production exprsSingle +top::Exprs ::= e::Expr +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} +aspect production exprsCons +top::Exprs ::= e1::Expr ',' e2::Exprs +{ + e1.decSiteVertexInfo = nothing(); + e1.alwaysDecorated = false; +} + +aspect production lambdap +top::Expr ::= params::ProductionRHS e::Expr +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; } -- FROM LET TODO attribute flowDefs, flowEnv occurs on AssignExpr; -propagate flowDefs on AssignExpr; +propagate flowDefs, flowEnv on AssignExpr; aspect production letp top::Expr ::= la::AssignExpr e::Expr { top.flowDeps := e.flowDeps; + top.flowVertexInfo = e.flowVertexInfo; + e.decSiteVertexInfo = top.decSiteVertexInfo; + e.alwaysDecorated = top.alwaysDecorated; +} + +aspect production assignExpr +top::AssignExpr ::= id::Name '::' t::TypeExpr '=' e::Expr +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; } aspect production lexicalLocalReference -top::Expr ::= q::PartiallyDecorated QName fi::ExprVertexInfo fd::[FlowVertex] +top::Expr ::= q::Decorated! QName fi::Maybe fd::[FlowVertex] _ { -- Because of the auto-undecorate behavior, we need to check for the case -- where `t` should be equivalent to `new(t)` and report accoringly. @@ -232,22 +582,22 @@ top::Expr ::= q::PartiallyDecorated QName fi::ExprVertexInfo fd::[FlowVertex] top.flowDeps := case fi of - | hasVertex(vertex) -> + | just(vertex) -> if performSubstitution(q.lookupValue.typeScheme.monoType, top.finalSubst).isDecorated && - !performSubstitution(top.typerep, top.finalSubst).isDecorated + !top.finalType.isDecorated then vertex.eqVertex -- we're a `t` emulating `new(t)` else fd -- we're passing along our vertex-ness to the outer expression - | noVertex() -> fd -- we're actually being used as a ref-set-taking decorated var + | nothing() -> fd -- we're actually being used as a ref-set-taking decorated var end; top.flowVertexInfo = fi; } -- FROM PATTERN TODO -attribute flowDeps, flowDefs, flowEnv, scrutineeVertexType occurs on PrimPatterns, PrimPattern; -propagate flowDeps, flowDefs on PrimPatterns, PrimPattern; +attribute flowDeps, flowDefs, flowEnv, decSiteVertexInfo, alwaysDecorated, scrutineeVertexType occurs on PrimPatterns, PrimPattern; +propagate flowDeps, flowDefs, flowEnv, decSiteVertexInfo, alwaysDecorated, scrutineeVertexType on PrimPatterns, PrimPattern; -autocopy attribute scrutineeVertexType :: VertexType; +inherited attribute scrutineeVertexType :: VertexType; aspect production matchPrimitiveReal top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr @@ -266,8 +616,8 @@ top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr pr.scrutineeVertexType = case e.flowVertexInfo of - | hasVertex(vertex) -> vertex - | noVertex() -> anonVertexType(anonName) + | just(vertex) -> vertex + | nothing() -> anonVertexType(anonName) end; -- Let's make sure for decorated types, we only demand what's necessary for forward @@ -275,13 +625,20 @@ top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr top.flowDeps := pr.flowDeps ++ f.flowDeps ++ (pr.scrutineeVertexType.fwdVertex :: pr.scrutineeVertexType.eqVertex); - local eTy::Type = performSubstitution(e.typerep, top.finalSubst); + local eTy::Type = e.finalType; top.flowDefs <- case e.flowVertexInfo of - | hasVertex(vertex) -> [] - | noVertex() -> [anonEq(top.frame.fullName, anonName, eTy.typeName, eTy.isNonterminal, top.location, e.flowDeps)] + | just(vertex) -> [] + | nothing() -> [anonEq(top.frame.fullName, anonName, eTy.typeName, eTy.isNonterminal, top.location, e.flowDeps)] end; -- We want to use anonEq here because that introduces the nonterminal stitch point for our vertex. + + e.decSiteVertexInfo = nothing(); + pr.decSiteVertexInfo = top.decSiteVertexInfo; + f.decSiteVertexInfo = top.decSiteVertexInfo; + e.alwaysDecorated = false; + pr.alwaysDecorated = false; + f.alwaysDecorated = false; } aspect production prodPatternNormal diff --git a/grammars/silver/compiler/definition/flow/env/FlowEnv.sv b/grammars/silver/compiler/definition/flow/env/FlowEnv.sv index 3ba298ea4..6b5fb4135 100644 --- a/grammars/silver/compiler/definition/flow/env/FlowEnv.sv +++ b/grammars/silver/compiler/definition/flow/env/FlowEnv.sv @@ -3,59 +3,59 @@ grammar silver:compiler:definition:flow:env; imports silver:compiler:definition:flow:ast; imports silver:compiler:definition:env; imports silver:compiler:definition:core; +imports silver:compiler:analysis:uniqueness; import silver:compiler:definition:type; -autocopy attribute flowEnv :: FlowEnv; +inherited attribute flowEnv :: FlowEnv; monoid attribute flowDefs :: [FlowDef]; -- These are factored out of FlowDefs to avoid a circular dependency, -- since they are needed during type checking monoid attribute specDefs :: [(String, String, [String], [String])]; -- (nt, attr, [inhs], [referenced flow specs]) monoid attribute refDefs :: [(String, [String])]; -nonterminal FlowEnv with synTree, inhTree, defTree, fwdTree, prodTree, fwdInhTree, refTree, partialRefTree, localInhTree, localTree, nonSuspectTree, hostSynTree, specTree, prodGraphTree; - -annotation synTree :: EnvTree; -annotation inhTree :: EnvTree; -annotation defTree :: EnvTree; -annotation fwdTree :: EnvTree; -annotation fwdInhTree :: EnvTree; -annotation prodTree :: EnvTree; -annotation refTree :: EnvTree<[String]>; -annotation partialRefTree :: EnvTree<(String, Location, [String])>; -annotation localInhTree ::EnvTree; -annotation localTree :: EnvTree; -annotation nonSuspectTree :: EnvTree<[String]>; -annotation hostSynTree :: EnvTree; -annotation specTree :: EnvTree<(String, [String], [String])>; -annotation prodGraphTree :: EnvTree; +data nonterminal FlowEnv with synTree, inhTree, defTree, fwdTree, prodTree, fwdInhTree, refTree, uniqueRefTree, refPossibleDecSiteTree, refDecSiteTree, localInhTree, localTree, nonSuspectTree, hostSynTree, specTree, prodGraphTree; + +synthesized attribute synTree :: EnvTree; +synthesized attribute inhTree :: EnvTree; +synthesized attribute defTree :: EnvTree; +synthesized attribute fwdTree :: EnvTree; +synthesized attribute fwdInhTree :: EnvTree; +synthesized attribute prodTree :: EnvTree; +synthesized attribute refTree :: EnvTree<[String]>; +synthesized attribute uniqueRefTree :: EnvTree; +synthesized attribute refPossibleDecSiteTree :: EnvTree; +synthesized attribute refDecSiteTree :: EnvTree; +synthesized attribute localInhTree ::EnvTree; +synthesized attribute localTree :: EnvTree; +synthesized attribute nonSuspectTree :: EnvTree<[String]>; +synthesized attribute hostSynTree :: EnvTree; +synthesized attribute specTree :: EnvTree<(String, [String], [String])>; +synthesized attribute prodGraphTree :: EnvTree; abstract production flowEnv top::FlowEnv ::= -{} - -function fromFlowDefs -FlowEnv ::= specContribs::[(String, String, [String], [String])] refContribs::[(String, [String])] + uniqueRefContribs::[(String, UniqueRefSite)] d::FlowDefs { - return flowEnv( - synTree = directBuildTree(d.synTreeContribs), - inhTree = directBuildTree(d.inhTreeContribs), - defTree = directBuildTree(d.defTreeContribs), - fwdTree = directBuildTree(d.fwdTreeContribs), - fwdInhTree = directBuildTree(d.fwdInhTreeContribs), - prodTree = directBuildTree(d.prodTreeContribs), - refTree = directBuildTree(refContribs), - partialRefTree = directBuildTree(d.partialRefContribs), - localInhTree = directBuildTree(d.localInhTreeContribs), - localTree = directBuildTree(d.localTreeContribs), - nonSuspectTree = directBuildTree(d.nonSuspectContribs), - hostSynTree = directBuildTree(d.hostSynTreeContribs), - specTree = directBuildTree(specContribs), - prodGraphTree = directBuildTree(d.prodGraphContribs) - ); + top.synTree = directBuildTree(d.synTreeContribs); + top.inhTree = directBuildTree(d.inhTreeContribs); + top.defTree = directBuildTree(d.defTreeContribs); + top.fwdTree = directBuildTree(d.fwdTreeContribs); + top.fwdInhTree = directBuildTree(d.fwdInhTreeContribs); + top.prodTree = directBuildTree(d.prodTreeContribs); + top.refTree = directBuildTree(refContribs); + top.uniqueRefTree = directBuildTree(uniqueRefContribs); + top.refPossibleDecSiteTree = directBuildTree(d.refPossibleDecSiteContribs); + top.refDecSiteTree = directBuildTree(d.refDecSiteContribs); + top.localInhTree = directBuildTree(d.localInhTreeContribs); + top.localTree = directBuildTree(d.localTreeContribs); + top.nonSuspectTree = directBuildTree(d.nonSuspectContribs); + top.hostSynTree = directBuildTree(d.hostSynTreeContribs); + top.specTree = directBuildTree(specContribs); + top.prodGraphTree = directBuildTree(d.prodGraphContribs); } @@ -107,6 +107,104 @@ function lookupLocalEq return searchEnvTree(crossnames(prod, fName), e.localTree); } +-- unique references taken for a child +function lookupUniqueRefs +[UniqueRefSite] ::= prod::String sigName::String e::FlowEnv +{ + return searchEnvTree(prod ++ ":" ++ sigName, e.uniqueRefTree); +} + +-- unique references taken for a local/production attribute +function lookupLocalUniqueRefs +[UniqueRefSite] ::= fName::String e::FlowEnv +{ + return searchEnvTree(fName, e.uniqueRefTree); +} + +-- unique references taken for a translation attribute on a child +function lookupTransUniqueRefs +[UniqueRefSite] ::= prod::String sigName::String attrName::String e::FlowEnv +{ + return searchEnvTree(prod ++ ":" ++ sigName ++ "." ++ attrName, e.uniqueRefTree); +} + +-- unique references taken for a translation attribute on a local +function lookupLocalTransUniqueRefs +[UniqueRefSite] ::= fName::String attrName::String e::FlowEnv +{ + return searchEnvTree(fName ++ "." ++ attrName, e.uniqueRefTree); +} + +-- possible decoration sites for unique references taken for a child +function lookupRefPossibleDecSites +[VertexType] ::= prod::String sigName::String e::FlowEnv +{ + return searchEnvTree(s"${prod}:${sigName}", e.refPossibleDecSiteTree); +} + +-- possible decoration sites for unique references taken for a local/production attribute +function lookupLocalRefPossibleDecSites +[VertexType] ::= fName::String e::FlowEnv +{ + return searchEnvTree(fName, e.refPossibleDecSiteTree); +} + +-- possible decoration sites for unique references taken for a translation attribute on a child +function lookupTransRefPossibleDecSites +[VertexType] ::= prod::String sigName::String attrName::String e::FlowEnv +{ + return searchEnvTree(s"${prod}:${sigName}.${attrName}", e.refPossibleDecSiteTree); +} + +-- possible decoration sites for unique references taken for a translation attribute on a local/production attribute +function lookupLocalTransRefPossibleDecSites +[VertexType] ::= fName::String attrName::String e::FlowEnv +{ + return searchEnvTree(s"${fName}.${attrName}", e.refPossibleDecSiteTree); +} + +-- unconditional decoration sites for unique references taken for a child +function lookupRefDecSite +[VertexType] ::= prod::String sigName::String e::FlowEnv +{ + return searchEnvTree(s"${prod}:${sigName}", e.refDecSiteTree); +} + +-- unconditional decoration sites for unique references taken for a local/production attribute +function lookupLocalRefDecSite +[VertexType] ::= fName::String e::FlowEnv +{ + return searchEnvTree(fName, e.refDecSiteTree); +} + +-- unconditional decoration sites for unique references taken for a translation attribute on a child +function lookupTransRefDecSite +[VertexType] ::= prod::String sigName::String attrName::String e::FlowEnv +{ + return searchEnvTree(s"${prod}:${sigName}.${attrName}", e.refDecSiteTree); +} + +-- unconditional decoration sites for unique references taken for a translation attribute on a local/production attribute +function lookupLocalTransRefDecSite +[VertexType] ::= fName::String attrName::String e::FlowEnv +{ + return searchEnvTree(s"${fName}.${attrName}", e.refDecSiteTree); +} + +{-- + - This is a glorified lambda function, to help look for equations. + - Literally, we're just checking for null here. + - + - @param f The lookup function for the appropriate type of equation + - e.g. `lookupInh(prod, rhs, _, env)` + - @param attr The attribute to look up. + -} +function isEquationMissing +Boolean ::= f::([FlowDef] ::= String) attr::String +{ + return null(f(attr)); +} + -- default set of inherited attributes required/assumed to exist for references function getInhsForNtRef [[String]] ::= nt::String e::FlowEnv @@ -114,13 +212,6 @@ function getInhsForNtRef return searchEnvTree(nt, e.refTree); } --- partially decorated references taken for a child/local/production attribute -function getPartialRefs -[(String, Location, [String])] ::= prod::String fName::String e::FlowEnv -{ - return searchEnvTree(crossnames(prod, fName), e.partialRefTree); -} - -- implicit forward syn copy equations that are allowed to affect the flow type function getNonSuspectAttrsForProd [String] ::= prod::String e::FlowEnv @@ -192,7 +283,7 @@ top::Context ::= syn::String _ _ inhs::Type ntty::Type -- Defs for the dependencies introduced by syn occurs-on contexts at a decoration site function occursContextDeps -[FlowDef] ::= ns::NamedSignature env::Decorated Env t::Type vt::VertexType +[FlowDef] ::= ns::NamedSignature env::Env t::Type vt::VertexType { local contexts::Contexts = foldContexts(ns.contexts); contexts.env = env; @@ -200,3 +291,11 @@ function occursContextDeps \ synDeps::(String, [String]) -> synOccursContextEq(ns.fullName, vt, synDeps.fst, synDeps.snd), lookupAll(t.typeName, contexts.occursContextInhDeps)); } + +function splitTransAttrInh +Maybe<(String, String)> ::= attr::String +{ + local i::Integer = indexOf(".", attr); + return if i == -1 then nothing() else + just((substring(0, i, attr), substring(i + 1, length(attr), attr))); +} diff --git a/grammars/silver/compiler/definition/flow/env/FunctionDcl.sv b/grammars/silver/compiler/definition/flow/env/FunctionDcl.sv index c66469738..7411c6c68 100644 --- a/grammars/silver/compiler/definition/flow/env/FunctionDcl.sv +++ b/grammars/silver/compiler/definition/flow/env/FunctionDcl.sv @@ -3,8 +3,10 @@ grammar silver:compiler:definition:flow:env; import silver:compiler:definition:type only typerep; import silver:compiler:definition:flow:driver only ProductionGraph, FlowType, constructFunctionGraph; import silver:compiler:driver:util only RootSpec; -- actually we just want the occurrences +import silver:compiler:definition:type:syntax; -- actually we just want the occurrences attribute flowEnv occurs on FunctionSignature, FunctionLHS; +propagate flowEnv on FunctionSignature, FunctionLHS; aspect production functionDcl top::AGDcl ::= 'function' id::Name ns::FunctionSignature body::ProductionBody diff --git a/grammars/silver/compiler/definition/flow/env/NonterminalDcl.sv b/grammars/silver/compiler/definition/flow/env/NonterminalDcl.sv index f656568f2..cb02f3c5b 100644 --- a/grammars/silver/compiler/definition/flow/env/NonterminalDcl.sv +++ b/grammars/silver/compiler/definition/flow/env/NonterminalDcl.sv @@ -1,5 +1,6 @@ grammar silver:compiler:definition:flow:env; +import silver:compiler:definition:type; import silver:compiler:definition:type:syntax only BracketedOptTypeExprs; import silver:compiler:driver:util only isStrictlyExportedBy; @@ -10,9 +11,7 @@ top::AGDcl ::= quals::NTDeclQualifiers 'nonterminal' id::Name tl::BracketedOptTy -- Here, to avoid creating a hard dependency on options, we ignore options when -- deciding the include things in the *inferred* ref set. (Thus, isStrictlyExportedBy.) local inferredInhs :: [String] = - flatMap( - filterOccursForReferences(_, top.env, isStrictlyExportedBy(_, [top.grammarName], top.compiledGrammars)), - getAttrsOn(fName, top.env)); + getInhAttrsOnForReferences(fName, top.env, isStrictlyExportedBy(_, [top.grammarName], top.compiledGrammars)); local specInhs :: Maybe<[String]> = map(fst, lookup("decorate", getFlowTypeSpecFor(fName, top.flowEnv))); @@ -24,14 +23,32 @@ top::AGDcl ::= quals::NTDeclQualifiers 'nonterminal' id::Name tl::BracketedOptTy } -- If it is inherited and exported by this grammar (according to authority) -function filterOccursForReferences -[String] ::= occ::OccursDclInfo e::Decorated Env authority::(Boolean ::= String) +-- Also includes inherited on translation attributes. +-- Note that we only include trans.inh when both trans and inh are exported by nt's grammar. +-- We might want to consider including all trans.inh where inh is in the ref set of trans's nonterminal. +function getInhAttrsOnForReferences +[String] ::= nt::String e::Env authority::(Boolean ::= String) { - return case getAttrDcl(occ.attrOccurring, e) of - | at :: _ -> - if at.isInherited && authority(occ.sourceGrammar) - then [occ.attrOccurring] - else [] - | _ -> [] - end; + local ntty::Type = + case getTypeDcl(nt, e) of + | ty :: _ -> ty.typeScheme.monoType + | [] -> errorType() + end; + return flatMap(\ occ::OccursDclInfo -> + case getAttrDcl(occ.attrOccurring, e) of + | at :: _ when authority(occ.sourceGrammar) -> + if at.isInherited + then [occ.attrOccurring] + else if at.isSynthesized && at.isTranslation + then flatMap(\ occ2::OccursDclInfo -> + case getAttrDcl(occ2.attrOccurring, e) of + | at2 :: _ when authority(occ2.sourceGrammar) && at2.isInherited -> + [s"${occ.attrOccurring}.${occ2.attrOccurring}"] + | _ -> [] + end, + getAttrOccursOn(determineAttributeType(occ, ntty).typeName, e)) + else [] + | _ -> [] + end, + getAttrOccursOn(nt, e)); } diff --git a/grammars/silver/compiler/definition/flow/env/Occurs.sv b/grammars/silver/compiler/definition/flow/env/Occurs.sv index c943321db..938784688 100644 --- a/grammars/silver/compiler/definition/flow/env/Occurs.sv +++ b/grammars/silver/compiler/definition/flow/env/Occurs.sv @@ -6,6 +6,7 @@ import silver:compiler:driver:util only isExportedBy; -- Needed for specializing inh deps in syn occurs-on contexts attribute flowEnv occurs on Contexts, Context; +propagate flowEnv on Contexts, Context; aspect production attributionDcl top::AGDcl ::= 'attribute' at::QName attl::BracketedOptTypeExprs 'occurs' 'on' nt::QName nttl::BracketedOptTypeExprs ';' diff --git a/grammars/silver/compiler/definition/flow/env/ProductionBody.sv b/grammars/silver/compiler/definition/flow/env/ProductionBody.sv index 4a5faf1d3..cf88c1628 100644 --- a/grammars/silver/compiler/definition/flow/env/ProductionBody.sv +++ b/grammars/silver/compiler/definition/flow/env/ProductionBody.sv @@ -2,6 +2,7 @@ grammar silver:compiler:definition:flow:env; import silver:compiler:definition:type only isNonterminal, typerep; import silver:compiler:definition:type:syntax; +import silver:compiler:analysis:typechecking:core; import silver:compiler:modification:defaultattr; import silver:compiler:modification:collection; import silver:compiler:modification:copper; @@ -10,7 +11,8 @@ import silver:compiler:driver:util only isExportedBy, RootSpec; attribute flowDefs, flowEnv occurs on ProductionBody, ProductionStmts, ProductionStmt, ForwardInhs, ForwardInh; attribute flowEnv occurs on DefLHS; -propagate flowDefs on ProductionBody, ProductionStmts, ProductionStmt, ForwardInhs, ForwardInh; +propagate flowDefs, flowEnv on ProductionBody, ProductionStmts, ProductionStmt, ForwardInhs, ForwardInh; +propagate flowEnv on DefLHS; {- A short note on how flowDefs are generated: @@ -28,6 +30,13 @@ Boolean ::= prodgram::String ntgram::String cg::EnvTree d return isExportedBy(prodgram, [ntgram, d.sourceGrammar], cg); } +aspect production attachNoteStmt +top::ProductionStmt ::= 'attachNote' note::Expr ';' +{ + note.decSiteVertexInfo = nothing(); + note.alwaysDecorated = false; +} + aspect production forwardsTo top::ProductionStmt ::= 'forwards' 'to' e::Expr ';' { @@ -43,9 +52,13 @@ top::ProductionStmt ::= 'forwards' 'to' e::Expr ';' -- we regard these as non-suspect. That is, we implicitly insert these copy -- equations here. -- Currently, we don't bother to filter this to just synthesized, but we should? + -- TODO: What about attrs on translation attrs? implicitFwdAffects(top.frame.fullName, map((.attrOccurring), filter(isAffectable(top.grammarName, ntDefGram, top.compiledGrammars, _), - getAttrsOn(top.frame.lhsNtName, top.env))))]; + getAttrOccursOn(top.frame.lhsNtName, top.env))))]; + + e.decSiteVertexInfo = just(forwardVertexType); + e.alwaysDecorated = true; } aspect production forwardInh top::ForwardInh ::= lhs::ForwardLHSExpr '=' e::Expr ';' @@ -56,10 +69,34 @@ top::ForwardInh ::= lhs::ForwardLHSExpr '=' e::Expr ';' case lhs of | forwardLhsExpr(q) -> [fwdInhEq(top.frame.fullName, q.attrDcl.fullName, e.flowDeps)] end; + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} +aspect production returnDef +top::ProductionStmt ::= 'return' e::Expr ';' +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} +aspect production undecoratesTo +top::ProductionStmt ::= 'undecorates' 'to' e::Expr ';' +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; } +aspect production attributeDef +top::ProductionStmt ::= dl::DefLHS '.' attr::QNameAttrOccur '=' e::Expr ';' +{ + propagate flowEnv; +} +aspect production errorAttributeDef +top::ProductionStmt ::= msg::[Message] dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr +{ + propagate flowEnv; +} aspect production synthesizedAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { local ntDefGram :: String = hackGramFromFName(top.frame.lhsNtName); @@ -73,36 +110,111 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated [synEq(top.frame.fullName, attr.attrDcl.fullName, e.flowDeps, mayAffectFlowType)] else [defaultSynEq(top.frame.lhsNtName, attr.attrDcl.fullName, e.flowDeps)]; + e.decSiteVertexInfo = + if attr.found && attr.attrDcl.isTranslation + then just(transAttrVertexType(dl.defLHSVertex, attr.attrDcl.fullName)) + else nothing(); + e.alwaysDecorated = attr.found && attr.attrDcl.isTranslation; } aspect production inheritedAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { - top.flowDefs <- - case dl of - | childDefLHS(q) -> [inhEq(top.frame.fullName, q.lookupValue.fullName, attr.attrDcl.fullName, e.flowDeps)] - | localDefLHS(q) -> [localInhEq(top.frame.fullName, q.lookupValue.fullName, attr.attrDcl.fullName, e.flowDeps)] - | forwardDefLHS(q) -> [fwdInhEq(top.frame.fullName, attr.attrDcl.fullName, e.flowDeps)] - | _ -> [] -- TODO: this isn't quite extensible... more better way eventually, plz - end; + top.flowDefs <- flap(dl.defLHSInhEq, e.flowDeps); + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} + +-- The flow vertex type corresponding to attributes on this DefLHS +synthesized attribute defLHSVertex::VertexType occurs on DefLHS; + +-- The constructor for inherited equations on this DefLHS +synthesized attribute defLHSInhEq::[(FlowDef ::= [FlowVertex])] occurs on DefLHS; + +-- The name of the inherited attribute described by this DefLHS. May be syn.inh for translation attributes. +synthesized attribute inhAttrName::String occurs on DefLHS; + +aspect default production +top::DefLHS ::= +{ + top.defLHSVertex = localVertexType("bogus:lhs:vertex"); + top.defLHSInhEq = []; + top.inhAttrName = ""; +} +aspect production childDefLHS +top::DefLHS ::= q::Decorated! QName +{ + top.defLHSVertex = rhsVertexType(q.lookupValue.fullName); + top.defLHSInhEq = [inhEq(top.frame.fullName, q.lookupValue.fullName, top.defLHSattr.attrDcl.fullName, _)]; + top.inhAttrName = top.defLHSattr.attrDcl.fullName; +} +aspect production lhsDefLHS +top::DefLHS ::= q::Decorated! QName +{ + top.defLHSVertex = lhsVertexType; + top.defLHSInhEq = []; + top.inhAttrName = ""; +} +aspect production localDefLHS +top::DefLHS ::= q::Decorated! QName +{ + top.defLHSVertex = localVertexType(q.lookupValue.fullName); + top.defLHSInhEq = [localInhEq(top.frame.fullName, q.lookupValue.fullName, top.defLHSattr.attrDcl.fullName, _)]; + top.inhAttrName = top.defLHSattr.attrDcl.fullName; +} +aspect production forwardDefLHS +top::DefLHS ::= q::Decorated! QName +{ + top.defLHSVertex = forwardVertexType; + top.defLHSInhEq = [fwdInhEq(top.frame.fullName, top.defLHSattr.attrDcl.fullName, _)]; + top.inhAttrName = top.defLHSattr.attrDcl.fullName; +} +aspect production childTransAttrDefLHS +top::DefLHS ::= q::Decorated! QName attr::Decorated! QNameAttrOccur +{ + top.defLHSVertex = transAttrVertexType(rhsVertexType(q.lookupValue.fullName), attr.attrDcl.fullName); + top.defLHSInhEq = [transInhEq(top.frame.fullName, q.lookupValue.fullName, attr.attrDcl.fullName, top.defLHSattr.attrDcl.fullName, _)]; + top.inhAttrName = s"${attr.attrDcl.fullName}.${top.defLHSattr.attrDcl.fullName}"; +} +aspect production localTransAttrDefLHS +top::DefLHS ::= q::Decorated! QName attr::Decorated! QNameAttrOccur +{ + top.defLHSVertex = transAttrVertexType(localVertexType(q.lookupValue.fullName), attr.attrDcl.fullName); + top.defLHSInhEq = [localTransInhEq(top.frame.fullName, q.lookupValue.fullName, attr.attrDcl.fullName, top.defLHSattr.attrDcl.fullName, _)]; + top.inhAttrName = s"${attr.attrDcl.fullName}.${top.defLHSattr.attrDcl.fullName}"; +} + +aspect production errorValueDef +top::ProductionStmt ::= val::Decorated! QName e::Expr +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; } aspect production localValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { -- TODO: So, I'm just going to assume for the moment that we're always allowed to define the eq for a local... -- technically, it's possible to break this if you declare it in one grammar, but define it in another, but -- I think we should forbid that syntactically, later on... top.flowDefs <- - [localEq(top.frame.fullName, val.lookupValue.fullName, val.lookupValue.typeScheme.typeName, val.lookupValue.typeScheme.typerep.isNonterminal, e.flowDeps)]; + [localEq( + top.frame.fullName, val.lookupValue.fullName, val.lookupValue.typeScheme.typeName, + val.lookupValue.typeScheme.typerep.isNonterminal, val.lookupValue.found && val.lookupValue.dcl.hasForward, e.flowDeps)]; -- If we have a type var with occurs-on contexts, add the specified syn -> inh deps for the new vertex top.flowDefs <- occursContextDeps(top.frame.signature, top.env, val.lookupValue.typeScheme.typerep, localVertexType(val.lookupValue.fullName)); + + e.decSiteVertexInfo = + if e.alwaysDecorated + then just(localVertexType(val.lookupValue.fullName)) + else nothing(); + e.alwaysDecorated = isDecorable(e.finalType, top.env); } -- FROM COLLECTIONS TODO aspect production synAppendColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur {- <- -} e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur {- <- -} e::Expr { local ntDefGram :: String = hackGramFromFName(top.frame.lhsNtName); @@ -111,23 +223,19 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated top.flowDefs <- [extraEq(top.frame.fullName, lhsSynVertex(attr.attrDcl.fullName), e.flowDeps, mayAffectFlowType)]; + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; } aspect production inhAppendColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur {- <- -} e::Expr -{ - local vertex :: FlowVertex = - case dl of - | childDefLHS(q) -> rhsVertex(q.lookupValue.fullName, attr.attrDcl.fullName) - | localDefLHS(q) -> localVertex(q.lookupValue.fullName, attr.attrDcl.fullName) - | forwardDefLHS(q) -> forwardVertex(attr.attrDcl.fullName) - | _ -> localEqVertex("bogus:value:from:inhcontrib:flow") - end; - top.flowDefs <- - [extraEq(top.frame.fullName, vertex, e.flowDeps, true)]; +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur {- <- -} e::Expr +{ + top.flowDefs <- [extraEq(top.frame.fullName, dl.defLHSVertex.inhVertex(attr.attrDcl.fullName), e.flowDeps, true)]; + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; } aspect production synBaseColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { local ntDefGram :: String = hackGramFromFName(top.frame.lhsNtName); @@ -141,25 +249,29 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated [synEq(top.frame.fullName, attr.attrDcl.fullName, e.flowDeps, mayAffectFlowType)] else [defaultSynEq(top.frame.lhsNtName, attr.attrDcl.fullName, e.flowDeps)]; + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; } aspect production inhBaseColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { - top.flowDefs <- - case dl of - | childDefLHS(q) -> [inhEq(top.frame.fullName, q.lookupValue.fullName, attr.attrDcl.fullName, e.flowDeps)] - | localDefLHS(q) -> [localInhEq(top.frame.fullName, q.lookupValue.fullName, attr.attrDcl.fullName, e.flowDeps)] - | forwardDefLHS(q) -> [fwdInhEq(top.frame.fullName, attr.attrDcl.fullName, e.flowDeps)] - | _ -> [] -- TODO: this isn't quite extensible... more better way eventually, plz - end; + top.flowDefs <- flap(dl.defLHSInhEq, e.flowDeps); + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; } - +aspect production baseCollectionValueDef +top::ProductionStmt ::= val::Decorated! QName e::Expr +{ + -- We actually don't want reference site flow projections in e, + -- since we don't actually know the entire tree in which it is decorated. + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} aspect production appendCollectionValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { local locDefGram :: String = hackGramFromQName(val.lookupValue); - -- TODO: possible bug? this would include ":local" in the gram wouldn't it? local mayAffectFlowType :: Boolean = isExportedBy(top.grammarName, [locDefGram], top.compiledGrammars); @@ -171,13 +283,58 @@ top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr -- If we do, we'll have to come back here to add 'location' info anyway, -- so if we do that, uhhh... fix this! Because you're here! Reading this! - top.flowDefs <- + -- TODO: This shouldn't be a forwarding prod! + top.flowDefs := e.flowDefs ++ if mayAffectFlowType then [extraEq(top.frame.fullName, localEqVertex(val.lookupValue.fullName), e.flowDeps, true)] else []; + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; } --- TODO: Copper ProductionStmts +-- TODO: flowDefs for Copper ProductionStmts +aspect production pluckDef +top::ProductionStmt ::= 'pluck' e::Expr ';' +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} +aspect production printStmt +top::ProductionStmt ::= 'print' e::Expr ';' +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} +aspect production parserAttributeValueDef +top::ProductionStmt ::= val::Decorated! QName e::Expr +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} +aspect production pushTokenStmt +top::ProductionStmt ::= 'pushToken' '(' val::QName ',' lexeme::Expr ')' ';' +{ + lexeme.decSiteVertexInfo = nothing(); + lexeme.alwaysDecorated = false; +} +aspect production insertSemanticTokenStmt +top::ProductionStmt ::= 'insert' 'semantic' 'token' n::QNameType 'at' loc::Expr ';' +{ + loc.decSiteVertexInfo = nothing(); + loc.alwaysDecorated = false; +} +aspect production ifElseStmt +top::ProductionStmt ::= 'if' '(' condition::Expr ')' th::ProductionStmt 'else' el::ProductionStmt +{ + condition.decSiteVertexInfo = nothing(); + condition.alwaysDecorated = false; +} +aspect production termAttrValueValueDef +top::ProductionStmt ::= val::Decorated! QName e::Expr +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} -- We're in the unfortunate position of HAVING to compute values for 'flowDefs' -- even if there are errors in the larger grammar, as remote errors in binding @@ -202,7 +359,7 @@ String ::= qn::Decorated QNameAttrOccur } -- Source grammar of a lookup of a local dcl function hackGramFromQName -String ::= qn::Decorated QNameLookup +String ::= qn::QNameLookup { return if qn.found then qn.dcl.sourceGrammar else ""; } diff --git a/grammars/silver/compiler/definition/flow/env/ProductionDcl.sv b/grammars/silver/compiler/definition/flow/env/ProductionDcl.sv index 5f1edaa81..724e4edff 100644 --- a/grammars/silver/compiler/definition/flow/env/ProductionDcl.sv +++ b/grammars/silver/compiler/definition/flow/env/ProductionDcl.sv @@ -1,7 +1,10 @@ grammar silver:compiler:definition:flow:env; import silver:compiler:definition:type; +import silver:compiler:definition:type:syntax; +import silver:compiler:definition:concrete_syntax; import silver:compiler:modification:defaultattr; +import silver:compiler:modification:copper; import silver:compiler:definition:flow:driver; import silver:compiler:driver:util; -- only for productionFlowGraphs occurrence? @@ -9,6 +12,10 @@ attribute flowEnv occurs on ProductionSignature, ProductionLHS, ProductionRHS, ProductionRHSElem, AspectProductionSignature, AspectProductionLHS, AspectFunctionSignature, AspectFunctionLHS, AspectRHS, AspectRHSElem; +propagate flowEnv on + ProductionSignature, ProductionLHS, ProductionRHS, ProductionRHSElem, + AspectProductionSignature, AspectProductionLHS, AspectFunctionSignature, AspectFunctionLHS, + AspectRHS, AspectRHSElem; aspect production productionDcl top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::ProductionBody @@ -21,7 +28,7 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr findProductionGraph(fName, myGraphs); top.flowDefs <- - if null(body.uniqueSignificantExpression) + if null(body.forwardExpr) then [prodFlowDef(namedSig.outputElement.typerep.typeName, fName)] else []; @@ -30,6 +37,12 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr namedSig.inputElements); } +aspect production concreteProductionDcl +top::AGDcl ::= 'concrete' 'production' id::Name ns::ProductionSignature pm::ProductionModifiers body::ProductionBody +{ + propagate flowEnv; +} + aspect production aspectProductionDcl top::AGDcl ::= 'aspect' 'production' id::QName ns::AspectProductionSignature body::ProductionBody { @@ -46,3 +59,15 @@ top::AGDcl ::= 'aspect' 'production' id::QName ns::AspectProductionSignature bod | [] -> constructAnonymousGraph(body.flowDefs, top.env, myGraphs, myFlow) end; } + +aspect production aspectProductionLHSTyped +top::AspectProductionLHS ::= id::Name '::' t::TypeExpr +{ + propagate flowEnv; +} + +aspect production aspectRHSElemTyped +top::AspectRHSElem ::= id::Name '::' t::TypeExpr +{ + propagate flowEnv; +} diff --git a/grammars/silver/compiler/definition/flow/env/Root.sv b/grammars/silver/compiler/definition/flow/env/Root.sv index 0fb0512f1..3219b4401 100644 --- a/grammars/silver/compiler/definition/flow/env/Root.sv +++ b/grammars/silver/compiler/definition/flow/env/Root.sv @@ -1,10 +1,16 @@ grammar silver:compiler:definition:flow:env; +import silver:compiler:definition:type:syntax; +import silver:compiler:definition:concrete_syntax; +import silver:compiler:modification:defaultattr; +import silver:compiler:modification:collection; +import silver:compiler:modification:copper; + attribute flowDefs, refDefs, specDefs, flowEnv occurs on Root, AGDcls, AGDcl, Grammar; flowtype flowDefs {decorate} on Root, AGDcls, AGDcl, Grammar; flowtype refDefs {decorate} on Root, AGDcls, AGDcl, Grammar; flowtype specDefs {decorate} on Root, AGDcls, AGDcl, Grammar; -propagate flowDefs, refDefs, specDefs on Root, AGDcls, AGDcl, Grammar; +propagate flowDefs, refDefs, specDefs, flowEnv on Root, AGDcls, AGDcl, Grammar; aspect default production top::AGDcl ::= @@ -13,3 +19,22 @@ top::AGDcl ::= top.refDefs := []; top.specDefs := []; } + +aspect production globalValueDclConcrete +top::AGDcl ::= 'global' id::Name '::' cl::ConstraintList '=>' t::TypeExpr '=' e::Expr ';' +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} +aspect production defaultConstraintClassBodyItem +top::ClassBodyItem ::= id::Name '::' cl::ConstraintList '=>' ty::TypeExpr '=' e::Expr ';' +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} +aspect production instanceBodyItem +top::InstanceBodyItem ::= id::QName '=' e::Expr ';' +{ + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; +} diff --git a/grammars/silver/compiler/definition/flow/env/TypeClasses.sv b/grammars/silver/compiler/definition/flow/env/TypeClasses.sv new file mode 100644 index 000000000..a6b850d98 --- /dev/null +++ b/grammars/silver/compiler/definition/flow/env/TypeClasses.sv @@ -0,0 +1,8 @@ +grammar silver:compiler:definition:flow:env; + +import silver:compiler:definition:type:syntax; + +attribute flowDefs, flowEnv occurs on + ClassBody, ClassBodyItem, InstanceBody, InstanceBodyItem; +propagate flowDefs, flowEnv on + ClassBody, ClassBodyItem, InstanceBody, InstanceBodyItem; diff --git a/grammars/silver/compiler/definition/flow/syntax/FlowSpec.sv b/grammars/silver/compiler/definition/flow/syntax/FlowSpec.sv index 41978f473..d5d80c18a 100644 --- a/grammars/silver/compiler/definition/flow/syntax/FlowSpec.sv +++ b/grammars/silver/compiler/definition/flow/syntax/FlowSpec.sv @@ -2,6 +2,7 @@ grammar silver:compiler:definition:flow:syntax; imports silver:compiler:definition:core; imports silver:compiler:definition:flow:ast; +imports silver:compiler:definition:flow:env; imports silver:compiler:definition:flow:driver only FlowType, inhDepsForSyn; imports silver:compiler:definition:env; imports silver:compiler:definition:type; @@ -18,6 +19,8 @@ concrete production flowtypeDcl top::AGDcl ::= 'flowtype' nt::QName '=' specs::FlowSpecs ';' { top.unparse = "flowtype " ++ nt.unparse ++ " = " ++ specs.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, env, flowEnv; + top.errors := if nt.lookupType.found then specs.errors @@ -34,6 +37,8 @@ concrete production flowtypeAttrDcl top::AGDcl ::= 'flowtype' attr::FlowSpec 'on' nts::NtList ';' { top.unparse = "flowtype " ++ attr.unparse ++ " on " ++ nts.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, env, flowEnv; + top.errors := nts.errors; top.specDefs := nts.specDefs; @@ -43,7 +48,7 @@ top::AGDcl ::= 'flowtype' attr::FlowSpec 'on' nts::NtList ';' nonterminal FlowSpecs with config, location, grammarName, errors, env, unparse, onNt, specDefs, compiledGrammars, flowEnv; -propagate errors, specDefs on FlowSpecs; +propagate config, grammarName, errors, env, onNt, specDefs, compiledGrammars, flowEnv on FlowSpecs; concrete production oneFlowSpec top::FlowSpecs ::= h::FlowSpec @@ -58,9 +63,9 @@ top::FlowSpecs ::= h::FlowSpecs ',' t::FlowSpec nonterminal FlowSpec with config, location, grammarName, errors, env, unparse, onNt, specDefs, compiledGrammars, flowEnv; -autocopy attribute onNt :: Type; +inherited attribute onNt :: Type; -propagate errors on FlowSpec; +propagate config, grammarName, errors, env, onNt, compiledGrammars, flowEnv on FlowSpec; concrete production flowSpecDcl top::FlowSpec ::= attr::FlowSpecId '{' inhs::FlowSpecInhs '}' @@ -109,7 +114,7 @@ nonterminal FlowSpecId with config, location, grammarName, errors, env, unparse, synthesized attribute synName :: String; synthesized attribute authorityGrammar :: String; -propagate errors on FlowSpecId; +propagate config, grammarName, errors, env, compiledGrammars, flowEnv on FlowSpecId; concrete production qnameSpecId top::FlowSpecId ::= syn::QNameAttrOccur @@ -153,7 +158,7 @@ nonterminal FlowSpecInhs with config, location, grammarName, errors, env, unpars monoid attribute inhList :: [String]; -- The attributes in the flow specification monoid attribute refList :: [String]; -- Flow specifications referenced in this one (currently can only contain "decorate" / "forward") -propagate errors, inhList, refList on FlowSpecInhs; +propagate config, grammarName, errors, env, onNt, inhList, refList, flowEnv on FlowSpecInhs; concrete production nilFlowSpecInhs top::FlowSpecInhs ::= @@ -173,9 +178,9 @@ top::FlowSpecInhs ::= h::FlowSpecInh ',' t::FlowSpecInhs nonterminal FlowSpecInh with config, location, grammarName, errors, env, unparse, onNt, inhList, refList, flowEnv; -flowtype FlowSpecInh = forward {grammarName, env, flowEnv, onNt}, inhList {forward}; +flowtype FlowSpecInh = forward {grammarName, env, flowEnv, onNt}, inhList {forward}, errors {forward}; -propagate errors on FlowSpecInh; +propagate config, grammarName, errors, env, flowEnv on FlowSpecInh; concrete production flowSpecInh top::FlowSpecInh ::= inh::QNameAttrOccur @@ -191,6 +196,27 @@ top::FlowSpecInh ::= inh::QNameAttrOccur else [err(inh.location, inh.name ++ " is not an inherited attribute and so cannot be within a flow type")]; } +concrete production flowSpecTrans +top::FlowSpecInh ::= transSyn::QNameAttrOccur '.' inh::QNameAttrOccur +{ + top.unparse = s"${transSyn.unparse}.${inh.unparse}"; + top.inhList := + if transSyn.attrFound && inh.attrFound + then [s"${transSyn.attrDcl.fullName}.${inh.attrDcl.fullName}"] + else []; + top.refList := []; + + transSyn.attrFor = top.onNt; + inh.attrFor = transSyn.typerep; + + top.errors <- + if !transSyn.found || transSyn.attrDcl.isSynthesized && transSyn.attrDcl.isTranslation then [] + else [err(transSyn.location, transSyn.name ++ " is not a translation attribute and so cannot be within a flow type")]; + top.errors <- + if !inh.found || inh.attrDcl.isInherited then [] + else [err(inh.location, inh.name ++ " is not an inherited attribute and so cannot be within a flow type")]; +} + {-- - Inherit a flow spec from another flow spec. - @@ -218,8 +244,8 @@ top::FlowSpecInh ::= 'decorate' -- so be sufficiently general here. top.errors <- case top.onNt, decSpec of - | nonterminalType(_, _, _), just(_) -> [] - | nonterminalType(_, _, _), nothing() -> + | nonterminalType(_, _, _, _), just(_) -> [] + | nonterminalType(_, _, _, _), nothing() -> [err(top.location, s"to use the default reference set for nonterminal ${top.onNt.typeName}, 'decorate' must also have an explicit flow type")] | errorType(), _ -> [] | _, _ -> [err(top.location, s"default reference set can only be used with nonterminal types, not ${prettyType(top.onNt)}")] @@ -251,7 +277,7 @@ top::FlowSpecInh ::= 'forward' nonterminal NtList with config, location, grammarName, errors, env, unparse, flowSpecSpec, specDefs, compiledGrammars, flowEnv; -propagate errors, specDefs on NtList; +propagate config, grammarName, errors, env, flowSpecSpec, specDefs, compiledGrammars, flowEnv on NtList; concrete production nilNtList top::NtList ::= @@ -271,7 +297,9 @@ top::NtList ::= h::NtName ',' t::NtList nonterminal NtName with config, location, grammarName, errors, env, unparse, flowSpecSpec, specDefs, compiledGrammars, flowEnv; -autocopy attribute flowSpecSpec :: FlowSpec; +propagate config, grammarName, env, compiledGrammars, flowEnv on NtName; + +inherited attribute flowSpecSpec :: FlowSpec; concrete production ntName top::NtName ::= nt::QName diff --git a/grammars/silver/compiler/definition/type/PrettyPrinting.sv b/grammars/silver/compiler/definition/type/PrettyPrinting.sv index 3bb80b1ee..f329ba256 100644 --- a/grammars/silver/compiler/definition/type/PrettyPrinting.sv +++ b/grammars/silver/compiler/definition/type/PrettyPrinting.sv @@ -3,7 +3,9 @@ grammar silver:compiler:definition:type; import silver:langutil:pp; synthesized attribute typepp :: String occurs on PolyType, Context, Type, Kind; -autocopy attribute boundVariables :: [TyVar] occurs on Context, Type; +inherited attribute boundVariables :: [TyVar] occurs on Context, Type; + +propagate boundVariables on Context, Type; function prettyType String ::= te::Type @@ -135,9 +137,10 @@ top::Type ::= c::Type a::Type else "_") ++ " ::= " ++ implode(" ", map(prettyTypeWith(_, top.boundVariables), take(params, top.argTypes))) ++ (if length(top.argTypes) < params then replicate(params - length(top.argTypes), " _") else "") ++ + (if null(namedParams) then "" else ";") ++ concat( - zipWith(\ np::String t::Type -> s"; ${np}::${prettyTypeWith(t, top.boundVariables)}", namedParams, drop(params, top.argTypes)) ++ - map(\ np::String -> s"; ${np}::_", drop(length(top.argTypes) - (params + length(namedParams)), namedParams))) ++ ")" ++ + zipWith(\ np::String t::Type -> s" ${np}::${prettyTypeWith(t, top.boundVariables)}", namedParams, drop(params, top.argTypes)) ++ + map(\ np::String -> s" ${np}::_", drop(length(top.argTypes) - params, namedParams))) ++ ")" ++ if length(top.argTypes) <= params + length(namedParams) + 1 then "" else "<" ++ implode(" ", map(prettyTypeWith(_, top.boundVariables), drop(params + length(namedParams) + 1, top.argTypes))) ++ ">" | _ -> prettyTypeWith(top.baseType, top.boundVariables) ++ @@ -184,7 +187,7 @@ top::Type ::= } aspect production nonterminalType -top::Type ::= fn::String _ _ +top::Type ::= fn::String _ _ _ { top.typepp = fn; } @@ -213,10 +216,10 @@ top::Type ::= t::Type i::Type top.typepp = s"Decorated ${t.typepp} with ${i.typepp}"; } -aspect production partiallyDecoratedType +aspect production uniqueDecoratedType top::Type ::= t::Type i::Type { - top.typepp = s"PartiallyDecorated ${t.typepp} with ${i.typepp}"; + top.typepp = s"Decorated! ${t.typepp} with ${i.typepp}"; } aspect production ntOrDecType diff --git a/grammars/silver/compiler/definition/type/Substitutions.sv b/grammars/silver/compiler/definition/type/Substitutions.sv index de63cf403..1db91d057 100644 --- a/grammars/silver/compiler/definition/type/Substitutions.sv +++ b/grammars/silver/compiler/definition/type/Substitutions.sv @@ -10,7 +10,7 @@ grammar silver:compiler:definition:type; - Consider unify returning Maybe or Pair depending. - TODO: More efficient type representations than a assoc-list, somehow. -} -nonterminal Substitution with substList, substErrors, failure; +data nonterminal Substitution with substList, substErrors, failure; synthesized attribute substList :: [Pair]; synthesized attribute substErrors :: [String]; @@ -47,7 +47,7 @@ Substitution ::= e::String function subst Substitution ::= tv::TyVar te::Type { - return goodSubst([pair(tv,te)]); + return goodSubst([(tv,te)]); } function composeSubst Substitution ::= s1::Substitution s2::Substitution @@ -80,11 +80,12 @@ Maybe ::= tv::TyVar s::Substitution -------------------------------------------------------------------------------- -- These are for ordinary tyvar substitutions. -autocopy attribute substitution :: Substitution occurs on Context, Type; +inherited attribute substitution :: Substitution occurs on Context, Type; functor attribute substituted occurs on Context, Type; -- These are for flat, non-recursive replacement of tyvars with something else directly functor attribute flatRenamed occurs on Context, Type; +propagate substitution on Context, Type; propagate substituted, flatRenamed on Context, Type excluding inhOccursContext, synOccursContext, annoOccursContext, varType, skolemType, ntOrDecType; @@ -178,7 +179,7 @@ top::Type ::= nt::Type inhs::Type hidden::Type | _ -> hidden.substituted end; -- For a renaming, we don't need to specialize. - propagate flatRenamed; + propagate substitution, flatRenamed; } -------------------------------------------------------------------------------- diff --git a/grammars/silver/compiler/definition/type/Type.sv b/grammars/silver/compiler/definition/type/Type.sv index 4b8b50580..2310286de 100644 --- a/grammars/silver/compiler/definition/type/Type.sv +++ b/grammars/silver/compiler/definition/type/Type.sv @@ -95,17 +95,10 @@ top::Context ::= msg::String {-- - Silver Type Representations. -} -nonterminal Type with kindrep, freeVariables, tracked; -synthesized attribute tracked :: Boolean; +nonterminal Type with kindrep, freeVariables; flowtype Type = decorate {}, forward {}; -aspect default production -top::Type ::= -{ - top.tracked = false; -} - {-- - This is a (universally quantified) type variable. -} @@ -139,7 +132,6 @@ top::Type ::= c::Type a::Type | _ -> starKind() end; top.freeVariables = setUnionTyVars(c.freeVariables, a.freeVariables); - top.tracked = c.tracked; } {-- @@ -209,18 +201,18 @@ top::Type ::= - An (undecorated) nonterminal type. - Note that this is the *unapplied* type constructor for a nonterminal type; - e.g. `Pair` would be represented as - - `apType(apType(nonterminalType("silver:core:Pair", [starKind(), starKind()], false), stringType()), integerType())`. + - `apType(apType(nonterminalType("silver:core:Pair", [starKind(), starKind()], true, false), stringType()), integerType())`. - - @param fn The fully qualified name of the nonterminal. - @param k The number type parameters for that nonterminal. - - @param tracked Might this NT be tracked. + - @param data Is this a data nonterminal. + - @param tracked Is this NT tracked. -} abstract production nonterminalType -top::Type ::= fn::String ks::[Kind] tracked::Boolean +top::Type ::= fn::String ks::[Kind] data::Boolean tracked::Boolean { top.kindrep = foldr(arrowKind, starKind(), ks); top.freeVariables = []; - top.tracked = tracked; } {-- @@ -261,13 +253,13 @@ top::Type ::= te::Type i::Type } {-- - - A *partially decorated* nonterminal type. + - A *unique decorated* nonterminal type. - Represents a reference with some exact set of provided inherited attributes, - may be decorated with additional attributes. - @param te MUST be a 'nonterminalType' or 'varType'/'skolemType' - @param i MUST have kind InhSet -} -abstract production partiallyDecoratedType +abstract production uniqueDecoratedType top::Type ::= te::Type i::Type { top.kindrep = starKind(); @@ -297,7 +289,7 @@ top::Type ::= te::Type i::Type - - @param nt MUST be a 'nonterminalType' - @param inhs The inh set that we're decorated with, or a free var if we don't care - MUST have kind InhSet - - @param hidden One of: (a) a type variable (b) 'nt' (c) 'decoratedType(nt, inhs)' (d) 'partiallyDecoratedType(nt, inhs)' + - @param hidden One of: (a) a type variable (b) 'nt' (c) 'decoratedType(nt, inhs)' (d) 'uniqueDecoratedType(nt, inhs)' - representing state: unspecialized, undecorated, or decorated. - @param defaultPartialDec The default for what we are if we never specialize. - @param inhs The default for what we're decorated with if we never specialize - MUST have kind InhSet @@ -327,7 +319,7 @@ top::Type ::= nt::Type inhs::Type hidden::Type {-- - Function type. (Whether production or function.) - - Note that this is the *unapplied* type constructor for a nonterminal type, + - Note that this is the *unapplied* type constructor for a function type, - and argument types are provided before the result type; - e.g. `(Integer ::= String Boolean)` would be represented as - `apType(apType(apType(functionType(3, []), stringType()), booleanType()), integerType())`. diff --git a/grammars/silver/compiler/definition/type/Unification.sv b/grammars/silver/compiler/definition/type/Unification.sv index e4bc645b4..78a058464 100644 --- a/grammars/silver/compiler/definition/type/Unification.sv +++ b/grammars/silver/compiler/definition/type/Unification.sv @@ -104,12 +104,12 @@ top::Type ::= } aspect production nonterminalType -top::Type ::= fn::String ks::[Kind] tracked::Boolean +top::Type ::= fn::String ks::[Kind] data::Boolean tracked::Boolean { top.unify = case top.unifyWith of - | nonterminalType(ofn, oks, otracked) -> - if fn == ofn && tracked == otracked -- Mismatched trackedness can happen when comparing interface files + | nonterminalType(ofn, oks, odata, otracked) -> + if fn == ofn --&& data == odata && tracked == otracked -- Mismatched data/tractness can happen when comparing interface files then if ks == oks then emptySubst() else error("kind mismatch during unification for " ++ prettyType(top) ++ " and " ++ prettyType(top.unifyWith)) -- Should be impossible @@ -153,14 +153,14 @@ top::Type ::= te::Type i::Type end; } -aspect production partiallyDecoratedType +aspect production uniqueDecoratedType top::Type ::= te::Type i::Type { top.unify = case top.unifyWith of - | partiallyDecoratedType(ote, oi) -> composeSubst(unify(te, ote), unify(i, oi)) + | uniqueDecoratedType(ote, oi) -> composeSubst(unify(te, ote), unify(i, oi)) | ntOrDecType(_,_,_) -> errorSubst("dte-nodte: try again") - | _ -> errorSubst("Tried to unify partially decorated type with " ++ prettyType(top.unifyWith)) + | _ -> errorSubst("Tried to unify unique decorated type with " ++ prettyType(top.unifyWith)) end; } @@ -180,11 +180,11 @@ top::Type ::= nt::Type inhs::Type hidden::Type -- Ensure compatibility between Decorated nonterminal types, then specialize ourselves unifyAllShortCircuit([ote, oi, top.unifyWith], [nt, inhs, hidden]) - | partiallyDecoratedType(ote, oi) -> + | uniqueDecoratedType(ote, oi) -> -- Ensure compatibility between Decorated nonterminal types, then specialize ourselves unifyAllShortCircuit([ote, oi, top.unifyWith], [nt, inhs, hidden]) - | nonterminalType(_, _, _) -> + | nonterminalType(_, _, _, _) -> -- Ensure compatibility between nonterminal types, then specialize ourselves unifyAllShortCircuit([top.unifyWith, top.unifyWith], [nt, hidden]) diff --git a/grammars/silver/compiler/definition/type/Util.sv b/grammars/silver/compiler/definition/type/Util.sv index e6af4f8d7..7c20a6b3d 100644 --- a/grammars/silver/compiler/definition/type/Util.sv +++ b/grammars/silver/compiler/definition/type/Util.sv @@ -20,14 +20,20 @@ monoid attribute freeFlexibleVars :: [TyVar] with [], setUnionTyVars; -- Also used by 'new()' synthesized attribute isDecorated :: Boolean; --- Determines whether a type is a partially decorated nonterminal type +-- Determines whether a type is a unique decorated nonterminal type -- Used in determining whether a type may be supplied with inherited attributes. -synthesized attribute isPartiallyDecorated :: Boolean; +synthesized attribute isUniqueDecorated :: Boolean; -- Determines whether a type is an (undecorated) nonterminal type -- Used in determining whether a type may be supplied with inherited attributes. synthesized attribute isNonterminal :: Boolean; +-- Determines whether a type is a data nonterminal type +synthesized attribute isData :: Boolean; + +-- Determines whether a type is tracked +synthesized attribute isTracked :: Boolean; + -- Used for type checking by 'terminal()' synthesized attribute isTerminal :: Boolean; @@ -43,9 +49,9 @@ synthesized attribute defaultSpecialization :: Type; -- Used instead of unify() when we want to just know its decorated or undecorated synthesized attribute unifyInstanceNonterminal :: Substitution; synthesized attribute unifyInstanceDecorated :: Substitution; -synthesized attribute unifyInstanceDecorable :: Substitution; -- NT or partially decorated +synthesized attribute unifyInstanceDecorable :: Substitution; -- NT or unique decorated -attribute arity, isError, isDecorated, isPartiallyDecorated, isNonterminal, isTerminal, asNtOrDecType, compareTo, isEqual occurs on PolyType; +attribute arity, isError, isDecorated, isUniqueDecorated, isNonterminal, isData, isTerminal, asNtOrDecType, compareTo, isEqual occurs on PolyType; aspect production monoType top::PolyType ::= ty::Type @@ -53,8 +59,9 @@ top::PolyType ::= ty::Type top.arity = ty.arity; top.isError = ty.isError; top.isDecorated = ty.isDecorated; - top.isPartiallyDecorated = ty.isPartiallyDecorated; + top.isUniqueDecorated = ty.isUniqueDecorated; top.isNonterminal = ty.isNonterminal; + top.isData = ty.isData; top.isTerminal = ty.isTerminal; top.asNtOrDecType = ty.asNtOrDecType; @@ -70,8 +77,9 @@ top::PolyType ::= bound::[TyVar] ty::Type top.arity = ty.arity; top.isError = ty.isError; top.isDecorated = ty.isDecorated; - top.isPartiallyDecorated = ty.isPartiallyDecorated; + top.isUniqueDecorated = ty.isUniqueDecorated; top.isNonterminal = ty.isNonterminal; + top.isData = ty.isData; top.isTerminal = ty.isTerminal; top.asNtOrDecType = error("Only mono types should be possibly-decorated"); @@ -88,8 +96,9 @@ top::PolyType ::= bound::[TyVar] contexts::[Context] ty::Type top.arity = ty.arity; top.isError = ty.isError; top.isDecorated = ty.isDecorated; - top.isPartiallyDecorated = ty.isPartiallyDecorated; + top.isUniqueDecorated = ty.isUniqueDecorated; top.isNonterminal = ty.isNonterminal; + top.isData = ty.isData; top.isTerminal = ty.isTerminal; top.asNtOrDecType = error("Only mono types should be possibly-decorated"); @@ -100,7 +109,7 @@ top::PolyType ::= bound::[TyVar] contexts::[Context] ty::Type top.compareTo.typerep == performRenaming(ty, eqSub); } -attribute isError, inputTypes, outputType, namedTypes, arity, baseType, argTypes, isDecorated, isPartiallyDecorated, isNonterminal, isTerminal, isApplicable, decoratedType, asNtOrDecType, defaultSpecialization, inhSetMembers, freeSkolemVars, freeFlexibleVars, unifyInstanceNonterminal, unifyInstanceDecorated, unifyInstanceDecorable occurs on Type; +attribute isError, inputTypes, outputType, namedTypes, arity, baseType, argTypes, isDecorated, isUniqueDecorated, isNonterminal, isData, isTracked, isTerminal, isApplicable, decoratedType, asNtOrDecType, defaultSpecialization, inhSetMembers, freeSkolemVars, freeFlexibleVars, unifyInstanceNonterminal, unifyInstanceDecorated, unifyInstanceDecorable occurs on Type; propagate freeSkolemVars, freeFlexibleVars on Type; @@ -116,8 +125,10 @@ top::Type ::= top.inhSetMembers = []; top.isDecorated = false; - top.isPartiallyDecorated = false; + top.isUniqueDecorated = false; top.isNonterminal = false; + top.isData = false; + top.isTracked = false; top.isTerminal = false; top.isError = false; top.isApplicable = false; @@ -154,6 +165,8 @@ top::Type ::= c::Type a::Type top.baseType = c.baseType; top.argTypes = c.argTypes ++ [a]; top.isNonterminal = c.isNonterminal; + top.isData = c.isData; + top.isTracked = c.isTracked; top.asNtOrDecType = ntOrDecType(top, freshInhSet(), freshType()); -- c.baseType should be a nonterminal or skolem top.unifyInstanceNonterminal = c.unifyInstanceNonterminal; top.unifyInstanceDecorable = c.unifyInstanceDecorable; @@ -168,7 +181,7 @@ top::Type ::= c::Type a::Type end; top.namedTypes = case top.baseType of - | functionType(_, nps) -> zipWith(pair, nps, drop(top.arity, top.argTypes)) + | functionType(_, nps) -> zip(nps, drop(top.arity, top.argTypes)) | _ -> [] end; } @@ -201,12 +214,14 @@ top::Type ::= } aspect production nonterminalType -top::Type ::= fn::String _ _ +top::Type ::= fn::String ks::[Kind] data::Boolean tracked::Boolean { top.isNonterminal = true; - top.asNtOrDecType = ntOrDecType(top, freshInhSet(), freshType()); + top.isData = data; + top.isTracked = tracked; + top.asNtOrDecType = if data then top else ntOrDecType(top, freshInhSet(), freshType()); top.unifyInstanceNonterminal = emptySubst(); - top.unifyInstanceDecorable = emptySubst(); + top.unifyInstanceDecorable = if data then errorSubst("data") else emptySubst(); } aspect production terminalType @@ -230,11 +245,11 @@ top::Type ::= te::Type i::Type top.unifyInstanceDecorated = emptySubst(); } -aspect production partiallyDecoratedType +aspect production uniqueDecoratedType top::Type ::= te::Type i::Type { top.isDecorated = true; - top.isPartiallyDecorated = true; + top.isUniqueDecorated = true; top.decoratedType = te; top.asNtOrDecType = ntOrDecType(te, freshInhSet(), freshType()); top.inhSetMembers = i.inhSetMembers; diff --git a/grammars/silver/compiler/definition/type/syntax/AspectDcl.sv b/grammars/silver/compiler/definition/type/syntax/AspectDcl.sv index af1285637..c1f10a5a5 100644 --- a/grammars/silver/compiler/definition/type/syntax/AspectDcl.sv +++ b/grammars/silver/compiler/definition/type/syntax/AspectDcl.sv @@ -1,6 +1,7 @@ grammar silver:compiler:definition:type:syntax; -attribute lexicalTypeVariables, lexicalTyVarKinds occurs on AspectProductionSignature, AspectProductionLHS, AspectRHS, AspectRHSElem, AspectFunctionSignature, AspectFunctionLHS; +attribute lexicalTypeVariables, lexicalTyVarKinds occurs on + AspectProductionSignature, AspectProductionLHS, AspectRHS, AspectRHSElem, AspectFunctionSignature, AspectFunctionLHS; flowtype lexicalTypeVariables {realSignature, env, flowEnv, grammarName} on AspectProductionSignature, AspectProductionLHS, AspectRHS, AspectFunctionSignature, AspectFunctionLHS; flowtype lexicalTypeVariables {realSignature, env, flowEnv, grammarName, deterministicCount} on AspectRHSElem; diff --git a/grammars/silver/compiler/definition/type/syntax/Constraint.sv b/grammars/silver/compiler/definition/type/syntax/Constraint.sv index 31b3f633c..79f23160a 100644 --- a/grammars/silver/compiler/definition/type/syntax/Constraint.sv +++ b/grammars/silver/compiler/definition/type/syntax/Constraint.sv @@ -1,6 +1,6 @@ grammar silver:compiler:definition:type:syntax; -autocopy attribute constraintPos::ConstraintPosition; +inherited attribute constraintPos::ConstraintPosition; nonterminal ConstraintList -- This grammar doesn't export silver:compiler:definition:core, so the type concrete @@ -12,7 +12,8 @@ nonterminal Constraint with config, grammarName, env, flowEnv, location, unparse flowtype Constraint = decorate {grammarName, env, flowEnv, constraintPos}; -propagate errors, defs, occursDefs, lexicalTypeVariables, lexicalTyVarKinds on ConstraintList, Constraint; +propagate config, grammarName, env, flowEnv, errors, defs, occursDefs, lexicalTypeVariables, lexicalTyVarKinds, constraintPos + on ConstraintList, Constraint; concrete production consConstraint top::ConstraintList ::= h::Constraint ',' t::ConstraintList @@ -81,7 +82,7 @@ top::Constraint ::= c::QNameType t::TypeExpr | typeVariableTypeExpr(tv) -- Avoid circular inference if someone uses a class constraint within its own definition when top.constraintPos.classDefName != just(fName) -> - [pair(tv.lexeme, c.lookupType.typeScheme.monoType.kindrep)] + [(tv.lexeme, c.lookupType.typeScheme.monoType.kindrep)] | _ -> [] end; } action { @@ -178,7 +179,7 @@ top::Constraint ::= 'attribute' at::QName attl::BracketedOptTypeExprs i::TypeExp top.lexicalTyVarKinds <- case i of - | typeVariableTypeExpr(tv) -> [pair(tv.lexeme, inhSetKind())] + | typeVariableTypeExpr(tv) -> [(tv.lexeme, inhSetKind())] | _ -> [] end; } @@ -267,12 +268,12 @@ top::Constraint ::= i1::TypeExpr 'subset' i2::TypeExpr top.lexicalTyVarKinds <- case i1 of - | typeVariableTypeExpr(tv) -> [pair(tv.lexeme, inhSetKind())] + | typeVariableTypeExpr(tv) -> [(tv.lexeme, inhSetKind())] | _ -> [] end; top.lexicalTyVarKinds <- case i2 of - | typeVariableTypeExpr(tv) -> [pair(tv.lexeme, inhSetKind())] + | typeVariableTypeExpr(tv) -> [(tv.lexeme, inhSetKind())] | _ -> [] end; } @@ -363,7 +364,7 @@ top::ConstraintPosition ::= tvs::[TyVar] } function transitiveSuperContexts -[Context] ::= env::Decorated Env ty::Type seenClasses::[String] className::String +[Context] ::= env::Env ty::Type seenClasses::[String] className::String { local dcls::[TypeDclInfo] = getTypeDcl(className, env); local dcl::TypeDclInfo = head(dcls); @@ -393,7 +394,7 @@ Boolean ::= c1::Context c2::Context } function transitiveSuperDefs -[Def] ::= env::Decorated Env ty::Type seenClasses::[String] instDcl::InstDclInfo +[Def] ::= env::Env ty::Type seenClasses::[String] instDcl::InstDclInfo { local dcls::[TypeDclInfo] = getTypeDcl(instDcl.fullName, env); local dcl::TypeDclInfo = head(dcls); @@ -414,7 +415,7 @@ function transitiveSuperDefs } function transitiveSuperOccursDefs -[OccursDclInfo] ::= env::Decorated Env ty::Type seenClasses::[String] instDcl::InstDclInfo +[OccursDclInfo] ::= env::Env ty::Type seenClasses::[String] instDcl::InstDclInfo { local dcls::[TypeDclInfo] = getTypeDcl(instDcl.fullName, env); local dcl::TypeDclInfo = head(dcls); diff --git a/grammars/silver/compiler/definition/type/syntax/Terminals.sv b/grammars/silver/compiler/definition/type/syntax/Terminals.sv index eeb32a074..d7effb56d 100644 --- a/grammars/silver/compiler/definition/type/syntax/Terminals.sv +++ b/grammars/silver/compiler/definition/type/syntax/Terminals.sv @@ -14,7 +14,7 @@ disambiguate LCurly_t, InhSetLCurly_t { pluck LCurly_t; } terminal Boolean_tkwd 'Boolean' lexer classes {TYPE,RESERVED}; terminal Decorated_tkwd 'Decorated' lexer classes {TYPE,RESERVED}, precedence=1; -terminal PartiallyDecorated_tkwd 'PartiallyDecorated' lexer classes {TYPE,RESERVED}, precedence=1; +terminal UniqueDecorated_tkwd 'Decorated!' lexer classes {TYPE,RESERVED}, precedence=1; terminal Float_tkwd 'Float' lexer classes {TYPE,RESERVED}; terminal Integer_tkwd 'Integer' lexer classes {TYPE,RESERVED}; terminal String_tkwd 'String' lexer classes {TYPE,RESERVED}; diff --git a/grammars/silver/compiler/definition/type/syntax/TypeExpr.sv b/grammars/silver/compiler/definition/type/syntax/TypeExpr.sv index 9f207998f..af2ca8681 100644 --- a/grammars/silver/compiler/definition/type/syntax/TypeExpr.sv +++ b/grammars/silver/compiler/definition/type/syntax/TypeExpr.sv @@ -4,6 +4,7 @@ imports silver:compiler:definition:core; imports silver:compiler:definition:type; imports silver:compiler:definition:env; imports silver:compiler:definition:flow:syntax; +imports silver:compiler:definition:flow:env; nonterminal TypeExpr with config, location, grammarName, errors, env, flowEnv, unparse, typerep, lexicalTypeVariables, lexicalTyVarKinds, errorsTyVars, errorsKindStar, freeVariables, mentionedAliases, onNt, errorsInhSet, typerepInhSet; nonterminal Signature with config, location, grammarName, errors, env, flowEnv, unparse, typerep, lexicalTypeVariables, lexicalTyVarKinds, mentionedAliases; @@ -11,6 +12,7 @@ nonterminal SignatureLHS with config, location, grammarName, errors, env, flowEn nonterminal TypeExprs with config, location, grammarName, errors, env, unparse, flowEnv, types, missingCount, lexicalTypeVariables, lexicalTyVarKinds, appArgKinds, appLexicalTyVarKinds, errorsTyVars, errorsKindStar, freeVariables, mentionedAliases; nonterminal BracketedTypeExprs with config, location, grammarName, errors, env, flowEnv, unparse, types, missingCount, lexicalTypeVariables, lexicalTyVarKinds, appArgKinds, appLexicalTyVarKinds, errorsTyVars, freeVariables, mentionedAliases, envBindingTyVars, initialEnv; nonterminal BracketedOptTypeExprs with config, location, grammarName, errors, env, flowEnv, unparse, types, missingCount, lexicalTypeVariables, lexicalTyVarKinds, appArgKinds, appLexicalTyVarKinds, errorsTyVars, freeVariables, mentionedAliases, envBindingTyVars, initialEnv; +nonterminal NamedTypeExprs with config, location, grammarName, errors, env, unparse, flowEnv, namedTypes, lexicalTypeVariables, lexicalTyVarKinds, errorsKindStar, freeVariables, mentionedAliases; synthesized attribute maybeType :: Maybe; synthesized attribute types :: [Type]; @@ -28,8 +30,8 @@ monoid attribute appLexicalTyVarKinds :: [Pair]; -- These attributes are used if we're using the TypeExprs as type variables-only. monoid attribute errorsTyVars :: [Message]; -- A new environment, with the type variables in this list appearing bound -inherited attribute initialEnv :: Decorated Env; -synthesized attribute envBindingTyVars :: Decorated Env; +inherited attribute initialEnv :: Env; +synthesized attribute envBindingTyVars :: Env; monoid attribute errorsKindStar::[Message]; @@ -50,19 +52,20 @@ flowtype typerepInhSet {decorate, onNt} on TypeExpr; flowtype TypeExpr = decorate {grammarName, env, flowEnv}, forward {decorate}, freeVariables {decorate}, lexicalTypeVariables {decorate}, lexicalTyVarKinds {decorate}, - errorsTyVars {decorate}, errorsKindStar {decorate}; + errors {decorate}, errorsTyVars {decorate}, errorsKindStar {decorate}; -- typerep requires flowEnv to look up default ref sets flowtype typerep {grammarName, env, flowEnv} on TypeExpr, Signature; flowtype maybeType {grammarName, env, flowEnv} on SignatureLHS; flowtype types {grammarName, env, flowEnv} on TypeExprs, BracketedTypeExprs, BracketedOptTypeExprs; -propagate errors on TypeExpr, Signature, SignatureLHS, TypeExprs, BracketedTypeExprs, BracketedOptTypeExprs excluding refTypeExpr, partialRefTypeExpr; -propagate lexicalTypeVariables, lexicalTyVarKinds on TypeExpr, Signature, SignatureLHS, TypeExprs, BracketedTypeExprs, BracketedOptTypeExprs; +propagate errors on TypeExpr, Signature, SignatureLHS, TypeExprs, BracketedTypeExprs, BracketedOptTypeExprs, NamedTypeExprs excluding refTypeExpr, uniqueRefTypeExpr; +propagate config, grammarName, env, flowEnv, lexicalTypeVariables, lexicalTyVarKinds + on TypeExpr, Signature, SignatureLHS, TypeExprs, BracketedTypeExprs, BracketedOptTypeExprs, NamedTypeExprs; propagate appLexicalTyVarKinds on TypeExprs, BracketedTypeExprs, BracketedOptTypeExprs; propagate errorsTyVars on TypeExprs, BracketedTypeExprs, BracketedOptTypeExprs; -propagate errorsKindStar on TypeExprs; -propagate mentionedAliases on TypeExpr, Signature, SignatureLHS, TypeExprs, BracketedTypeExprs, BracketedOptTypeExprs; +propagate errorsKindStar on TypeExprs, NamedTypeExprs; +propagate mentionedAliases on TypeExpr, Signature, SignatureLHS, TypeExprs, BracketedTypeExprs, BracketedOptTypeExprs, NamedTypeExprs; function addNewLexicalTyVars [Def] ::= gn::String sl::Location lk::[Pair] l::[String] @@ -102,6 +105,13 @@ top::TypeExpr ::= t::Type top.unparse = prettyType(t); top.typerep = t; + + top.errorsTyVars := + case t of + | varType(_) -> [] + | skolemType(_) -> [] + | _ -> [err(top.location, top.unparse ++ " is not permitted here, only type variables are")] + end; } concrete production integerTypeExpr @@ -217,7 +227,7 @@ top::TypeExpr ::= '(' tv::IdLower_t '::' k::KindExpr ')' top.errorsTyVars := []; top.lexicalTypeVariables <- [tv.lexeme]; - top.lexicalTyVarKinds <- [pair(tv.lexeme, k.kindrep)]; + top.lexicalTyVarKinds <- [(tv.lexeme, k.kindrep)]; } action { insert semantic token IdTypeVar_t at tv.location; } @@ -227,6 +237,7 @@ top::TypeExpr ::= ty::TypeExpr tl::BracketedTypeExprs { top.unparse = ty.unparse ++ tl.unparse; + propagate grammarName, env, flowEnv; propagate lexicalTypeVariables; -- Needed to avoid circularity forwards to @@ -265,7 +276,7 @@ top::TypeExpr ::= ty::Decorated TypeExpr tl::BracketedTypeExprs { top.unparse = ty.unparse ++ tl.unparse; - top.typerep = appTypes(ty.typerep, tl.types); + top.typerep = if null(kindErrors) then appTypes(ty.typerep, tl.types) else errorType(); top.mentionedAliases <- ty.mentionedAliases; @@ -273,12 +284,13 @@ top::TypeExpr ::= ty::Decorated TypeExpr tl::BracketedTypeExprs local tlCount::Integer = length(tl.types) + tl.missingCount; local tlKinds::[Kind] = map((.kindrep), tl.types); - top.errors <- + local kindErrors::[Message] = if tlCount != length(ty.typerep.kindrep.argKinds) then [err(top.location, ty.unparse ++ " has kind " ++ prettyKind(ty.typerep.kindrep) ++ ", but there are " ++ toString(tlCount) ++ " type arguments supplied here.")] else if take(length(tlKinds), ty.typerep.kindrep.argKinds) != tlKinds then [err(top.location, ty.unparse ++ " has kind " ++ prettyKind(ty.typerep.kindrep) ++ ", but argument(s) have kind(s) " ++ implode(", ", map(prettyKind, tlKinds)))] else []; + top.errors <- kindErrors; tl.appArgKinds = case ty of @@ -291,7 +303,7 @@ top::TypeExpr ::= ty::Decorated TypeExpr tl::BracketedTypeExprs -- This assumes that all type args have kind *. -- If that is not the case, then an explcit kind signature is needed on ty, -- which will shadow this entry in the lexicalTyVarKinds list. - [pair(tv.lexeme, constructorKind(tlCount))] + [(tv.lexeme, constructorKind(tlCount))] | nominalTypeExpr(q) when q.lookupType.found -> tl.appLexicalTyVarKinds | _ -> [] @@ -310,8 +322,10 @@ top::TypeExpr ::= 'Decorated' t::TypeExpr 'with' i::TypeExpr top.errors := i.errorsInhSet ++ t.errors; top.errors <- case t.typerep.baseType of - | nonterminalType(_,_,_) -> [] + | nonterminalType(fn,_,true,_) -> [err(t.location, s"${fn} is a data nonterminal and cannot be decorated")] + | nonterminalType(_,_,_,_) -> [] | skolemType(_) -> [] + | varType(_) -> [] | _ -> [err(t.location, t.unparse ++ " is not a nonterminal, and cannot be Decorated.")] end; top.errors <- @@ -322,7 +336,7 @@ top::TypeExpr ::= 'Decorated' t::TypeExpr 'with' i::TypeExpr top.lexicalTyVarKinds <- case i of - | typeVariableTypeExpr(tv) -> [pair(tv.lexeme, inhSetKind())] + | typeVariableTypeExpr(tv) -> [(tv.lexeme, inhSetKind())] | _ -> [] end; } @@ -338,27 +352,31 @@ top::TypeExpr ::= 'Decorated' t::TypeExpr top.errors <- case t.typerep.baseType of - | nonterminalType(_,_,_) -> [] + | nonterminalType(fn,_,true,_) -> [err(t.location, s"${fn} is a data nonterminal and cannot be decorated")] + | nonterminalType(_,_,_,_) -> [] | skolemType(_) -> [err(t.location, "polymorphic Decorated types must specify an explicit reference set")] + | varType(_) -> [err(t.location, "polymorphic Decorated types must specify an explicit reference set")] | _ -> [err(t.location, t.unparse ++ " is not a nonterminal, and cannot be Decorated.")] end; } -concrete production partialRefTypeExpr -top::TypeExpr ::= 'PartiallyDecorated' t::TypeExpr 'with' i::TypeExpr +concrete production uniqueRefTypeExpr +top::TypeExpr ::= 'Decorated!' t::TypeExpr 'with' i::TypeExpr { - top.unparse = "PartiallyDecorated " ++ t.unparse ++ " with " ++ i.unparse; + top.unparse = "Decorated! " ++ t.unparse ++ " with " ++ i.unparse; i.onNt = t.typerep; - top.typerep = partiallyDecoratedType(t.typerep, i.typerepInhSet); + top.typerep = uniqueDecoratedType(t.typerep, i.typerepInhSet); top.errors := i.errorsInhSet ++ t.errors; top.errors <- case t.typerep.baseType of - | nonterminalType(_,_,_) -> [] + | nonterminalType(fn,_,true,_) -> [err(t.location, s"${fn} is a data nonterminal and cannot be decorated")] + | nonterminalType(_,_,_,_) -> [] | skolemType(_) -> [] - | _ -> [err(t.location, t.unparse ++ " is not a nonterminal, and cannot be PartiallyDecorated.")] + | varType(_) -> [] + | _ -> [err(t.location, t.unparse ++ " is not a nonterminal, and cannot be Decorated!.")] end; top.errors <- if i.typerep.kindrep != inhSetKind() @@ -368,25 +386,27 @@ top::TypeExpr ::= 'PartiallyDecorated' t::TypeExpr 'with' i::TypeExpr top.lexicalTyVarKinds <- case i of - | typeVariableTypeExpr(tv) -> [pair(tv.lexeme, inhSetKind())] + | typeVariableTypeExpr(tv) -> [(tv.lexeme, inhSetKind())] | _ -> [] end; } -concrete production partialRefDefaultTypeExpr -top::TypeExpr ::= 'PartiallyDecorated' t::TypeExpr +concrete production uniqueRefDefaultTypeExpr +top::TypeExpr ::= 'Decorated!' t::TypeExpr { - top.unparse = "PartiallyDecorated " ++ t.unparse; + top.unparse = "Decorated! " ++ t.unparse; top.typerep = - partiallyDecoratedType(t.typerep, + uniqueDecoratedType(t.typerep, inhSetType(sort(concat(getInhsForNtRef(t.typerep.typeName, top.flowEnv))))); top.errors <- case t.typerep.baseType of - | nonterminalType(_,_,_) -> [] - | skolemType(_) -> [err(t.location, "polymorphic PartiallyDecorated types must specify an explicit reference set")] - | _ -> [err(t.location, t.unparse ++ " is not a nonterminal, and cannot be PartiallyDecorated.")] + | nonterminalType(fn,_,true,_) -> [err(t.location, s"${fn} is a data nonterminal and cannot be decorated")] + | nonterminalType(_,_,_,_) -> [] + | skolemType(_) -> [err(t.location, "polymorphic Decorated! types must specify an explicit reference set")] + | varType(_) -> [err(t.location, "polymorphic Decorated! types must specify an explicit reference set")] + | _ -> [err(t.location, t.unparse ++ " is not a nonterminal, and cannot be Decorated!.")] end; } @@ -420,6 +440,42 @@ top::Signature ::= l::SignatureLHS '::=' list::TypeExprs else []; } +concrete production signatureOnlyNamed +top::Signature ::= l::SignatureLHS '::=' ';' namedList::NamedTypeExprs +{ + top.unparse = l.unparse ++ " ::= ; " ++ namedList.unparse; + + local names::[String] = sort(map(fst, namedList.namedTypes)); + top.typerep = + appTypes( + functionType(0, names), + map((.fromJust), map(lookup(_, namedList.namedTypes), names)) ++ + case l.maybeType of just(t) -> [t] | nothing() -> [] end); + + top.errors <- namedList.errorsKindStar; +} + +concrete production signatureNamed +top::Signature ::= l::SignatureLHS '::=' list::TypeExprs ';' namedList::NamedTypeExprs +{ + top.unparse = l.unparse ++ " ::= " ++ list.unparse ++ "; " ++ namedList.unparse; + + local names::[String] = sort(map(fst, namedList.namedTypes)); + top.typerep = + appTypes( + functionType(length(list.types) + list.missingCount, names), + list.types ++ + map((.fromJust), map(lookup(_, namedList.namedTypes), names)) ++ + case l.maybeType of just(t) -> [t] | nothing() -> [] end); + + top.errors <- list.errorsKindStar; + top.errors <- namedList.errorsKindStar; + top.errors <- + if list.missingCount > 0 + then [err($1.location, "Named parameters cannot be present when argument types are missing")] + else []; +} + concrete production presentSignatureLhs top::SignatureLHS ::= t::TypeExpr { @@ -525,7 +581,7 @@ top::TypeExprs ::= t::TypeExpr list::TypeExprs end; top.appLexicalTyVarKinds <- case t, top.appArgKinds of - | typeVariableTypeExpr(tv), k :: _ -> [pair(tv.lexeme, k)] + | typeVariableTypeExpr(tv), k :: _ -> [(tv.lexeme, k)] | _, _ -> [] end; } @@ -549,3 +605,28 @@ top::TypeExprs ::= '_' list::TypeExprs then [err($1.location, "Missing type argument cannot be followed by a provided argument")] else []; } + +-- NamedTypeExprs ------------------------------------------------------------------- + +abstract production namedTypeListNone +top::NamedTypeExprs ::= +{ + top.unparse = ""; + top.namedTypes = []; + top.freeVariables = []; +} + +concrete production namedTypeListSingle +top::NamedTypeExprs ::= n::Name '::' t::TypeExpr +{ + top.unparse = t.unparse; + forwards to namedTypeListCons(n, $2, t, namedTypeListNone(location=top.location), location=top.location); +} + +concrete production namedTypeListCons +top::NamedTypeExprs ::= n::Name '::' t::TypeExpr list::NamedTypeExprs +{ + top.unparse = n.unparse ++ "::" ++ t.unparse ++ " " ++ list.unparse; + top.namedTypes = (n.name, t.typerep) :: list.namedTypes; + top.freeVariables = t.freeVariables ++ list.freeVariables; +} diff --git a/grammars/silver/compiler/driver/util/Compilation.sv b/grammars/silver/compiler/driver/util/Compilation.sv index d56baf58b..6fd3b9923 100644 --- a/grammars/silver/compiler/driver/util/Compilation.sv +++ b/grammars/silver/compiler/driver/util/Compilation.sv @@ -6,6 +6,7 @@ import silver:util:treemap as map; synthesized attribute initRecompiledGrammars::[Decorated RootSpec]; nonterminal Compilation with config, postOps, grammarList, allGrammars, initRecompiledGrammars, recompiledGrammars; +propagate config on Compilation; flowtype postOps {config} on Compilation; @@ -79,7 +80,7 @@ top::Compilation ::= g::Grammars r::Grammars buildGrammars::[String] benv::Bu nonterminal Grammars with config, compiledGrammars, productionFlowGraphs, grammarFlowTypes, dependentGrammars, grammarList, dirtyGrammars, recompiledGrammars, jarName; -propagate dirtyGrammars, recompiledGrammars, jarName, dependentGrammars on Grammars; +propagate config, productionFlowGraphs, grammarFlowTypes, dirtyGrammars, recompiledGrammars, jarName, dependentGrammars on Grammars; abstract production consGrammars top::Grammars ::= h::RootSpec t::Grammars diff --git a/grammars/silver/compiler/driver/util/FlowTypes.sv b/grammars/silver/compiler/driver/util/FlowTypes.sv index dce3b61e1..edf105a22 100644 --- a/grammars/silver/compiler/driver/util/FlowTypes.sv +++ b/grammars/silver/compiler/driver/util/FlowTypes.sv @@ -3,6 +3,7 @@ grammar silver:compiler:driver:util; import silver:compiler:definition:flow:driver; import silver:compiler:definition:flow:ast; import silver:compiler:definition:flow:env; +import silver:compiler:analysis:uniqueness; import silver:util:treemap as rtm; import silver:util:graph as g; @@ -15,7 +16,8 @@ top::Compilation ::= g::Grammars r::Grammars buildGrammars::[String] benv::Bu local allFlowDefs :: FlowDefs = foldr(consFlow, nilFlow(), flatMap((.flowDefs), allLatestGrammars)); local allSpecDefs :: [(String, String, [String], [String])] = flatMap((.specDefs), allLatestGrammars); local allRefDefs :: [(String, [String])] = flatMap((.refDefs), allLatestGrammars); - local allFlowEnv :: FlowEnv = fromFlowDefs(allSpecDefs, allRefDefs, allFlowDefs); + local allUniqueRefs :: [(String, UniqueRefSite)] = flatMap((.uniqueRefs), allLatestGrammars); + local allFlowEnv :: FlowEnv = flowEnv(allSpecDefs, allRefDefs, allUniqueRefs, allFlowDefs); -- Look up tree for production info local prodTree :: EnvTree = directBuildTree(allFlowDefs.prodGraphContribs); @@ -24,7 +26,7 @@ top::Compilation ::= g::Grammars r::Grammars buildGrammars::[String] benv::Bu -- It's possible (likely) we could do better than using the overall env here. local allRealDefs :: [Def] = flatMap((.defs), allLatestGrammars); local allRealOccursDefs :: [OccursDclInfo] = flatMap((.occursDefs), allLatestGrammars); - local allRealEnv :: Decorated Env = occursEnv(allRealOccursDefs, toEnv(allRealDefs)); + local allRealEnv :: Env = occursEnv(allRealOccursDefs, toEnv(allRealDefs)); -- List of all productions local allProds :: [ValueDclInfo] = foldr(consDefs, nilDefs(), allRealDefs).prodDclList; diff --git a/grammars/silver/compiler/driver/util/RootSpec.sv b/grammars/silver/compiler/driver/util/RootSpec.sv index 783ac5e32..2045e77db 100644 --- a/grammars/silver/compiler/driver/util/RootSpec.sv +++ b/grammars/silver/compiler/driver/util/RootSpec.sv @@ -12,6 +12,7 @@ import silver:compiler:definition:flow:ast only nilFlow, consFlow, FlowDef; import silver:compiler:definition:core only jarName; import silver:compiler:analysis:warnings:flow only warnMissingInh; +import silver:compiler:analysis:uniqueness; {-- - A representation of a grammar, from an unknown source. TODO: rename GrammarSpec @@ -28,7 +29,7 @@ nonterminal RootSpec with flowtype RootSpec = decorate {config, compiledGrammars, productionFlowGraphs, grammarFlowTypes, dependentGrammars}; -propagate exportedGrammars, optionalGrammars, condBuild, defs, occursDefs on RootSpec; +propagate productionFlowGraphs, grammarFlowTypes, exportedGrammars, optionalGrammars, condBuild, defs, occursDefs on RootSpec; {-- - Grammars (a, b) where b depends on a @@ -85,9 +86,10 @@ top::RootSpec ::= g::Grammar oldInterface::Maybe grammarName:: local rootSpecs :: [Decorated RootSpec] = flatMap(searchEnvTree(_, top.compiledGrammars), depsPlusOptions); g.grammarDependencies = actualDependencies; g.flowEnv = - fromFlowDefs( + flowEnv( flatMap((.specDefs), rootSpecs), flatMap((.refDefs), rootSpecs), + flatMap((.uniqueRefs), rootSpecs), foldr(consFlow, nilFlow(), flatMap((.flowDefs), rootSpecs))); production newInterface::InterfaceItems = packInterfaceItems(top); @@ -127,9 +129,21 @@ top::RootSpec ::= g::Grammar oldInterface::Maybe grammarName:: top.declaredName = g.declaredName; top.moduleNames := nub(g.moduleNames ++ ["silver:core"]); -- Ensure the prelude is in the deps, always top.allGrammarDependencies := actualDependencies; - top.grammarErrors = g.grammarErrors; + + top.grammarErrors = filter(\ fe::(String, [Message]) -> !null(fe.2), top.allFileErrors); top.parsingErrors = []; - top.allFileErrors = g.allFileErrors; + + production attribute extraFileErrors::[(String, [Message])] with ++; + extraFileErrors := []; + + -- Seed flow deps with {compiledGrammars, config} + extraFileErrors <- if false then error(hackUnparse((top.compiledGrammars, top.config))) else []; + + top.allFileErrors = map( + \ fe::(String, [Message]) -> case fe of (fileName, fileErrors) -> + (fileName, fileErrors ++ concat(lookupAll(fileName, extraFileErrors))) + end, + g.allFileErrors); top.jarName := g.jarName; } @@ -190,11 +204,11 @@ Pair ::= grammarSource::String e::ParseError { return case e of | syntaxError(str, locat, _, _) -> - pair(locat.filename, + (locat.filename, [err(locat, "Syntax error:\n" ++ str)]) | unknownParseError(str, file) -> - pair(file, + (file, [err(loc(grammarSource ++ file, -1, -1, -1, -1, -1, -1), "Unknown error while parsing:\n" ++ str)]) end; diff --git a/grammars/silver/compiler/extension/attrsection/AttrSection.sv.md b/grammars/silver/compiler/extension/attrsection/AttrSection.sv.md index 06ded8585..dfde8e953 100644 --- a/grammars/silver/compiler/extension/attrsection/AttrSection.sv.md +++ b/grammars/silver/compiler/extension/attrsection/AttrSection.sv.md @@ -5,6 +5,8 @@ imports silver:compiler:definition:core; imports silver:compiler:definition:type:syntax; imports silver:compiler:definition:type; imports silver:compiler:definition:env; +imports silver:compiler:definition:flow:env; +imports silver:compiler:analysis:typechecking:core; imports silver:compiler:modification:lambda_fn; import silver:util:treeset as ts; @@ -17,7 +19,7 @@ concrete production attributeSection top::Expr ::= '(' '.' q::QNameAttrOccur ')' { top.unparse = s"(.${q.unparse})"; - propagate freeVars; + propagate freeVars, env, grammarName; ``` In constructing the forward we need to know on what type the attribute will be accessed. @@ -54,6 +56,8 @@ Determine the actual final input and output types that were computed elsewhere d local finalTy::Type = performSubstitution(top.typerep, top.finalSubst); local inputTy::Type = head(finalTy.inputTypes); local outputTy::Type = finalTy.outputType; + + q.attrFor = inputTy; ``` The inferred output type must be unambiguous: otherwise it is possible that a consumer of this diff --git a/grammars/silver/compiler/extension/auto_ast/AutoAst.sv b/grammars/silver/compiler/extension/auto_ast/AutoAst.sv index bd2f07652..750c1656b 100644 --- a/grammars/silver/compiler/extension/auto_ast/AutoAst.sv +++ b/grammars/silver/compiler/extension/auto_ast/AutoAst.sv @@ -3,13 +3,14 @@ grammar silver:compiler:extension:auto_ast; import silver:compiler:definition:core; import silver:compiler:definition:env; import silver:compiler:definition:type; ---import silver:compiler:analysis:typechecking:core; +import silver:compiler:analysis:typechecking:core; concrete production autoAstDcl top::ProductionStmt ::= 'abstract' v::QName ';' { top.unparse = "abstract " ++ v.unparse ++ ";"; + propagate env; local vty :: Type = v.lookupValue.typeScheme.typerep; @@ -24,7 +25,7 @@ top::ProductionStmt ::= 'abstract' v::QName ';' functionType(length(elems), if hasLoc then ["location"] else []), map(astType(_, top.env), elems) ++ (if hasLoc - then [ nonterminalType("silver:core:Location", [], false)] + then [nonterminalType("silver:core:Location", [], true, false)] else []) ++ [astType(top.frame.signature.outputElement, top.env)]); @@ -63,7 +64,7 @@ top::ProductionStmt ::= 'abstract' v::QName ';' baseExpr(v, location=v.location), map(accessAst(_, top.location), elems), if hasLoc then - [pair("location", + [("location", access( baseExpr(lhsQName, location=top.location), '.', @@ -76,13 +77,13 @@ top::ProductionStmt ::= 'abstract' v::QName ';' function hasAst -Boolean ::= ns::NamedSignatureElement env::Decorated Env +Boolean ::= ns::NamedSignatureElement env::Env { return isDecorable(ns.typerep, env) && !null(getOccursDcl("silver:langutil:ast", ns.typerep.typeName, env)); } function astType -Type ::= ns::NamedSignatureElement env::Decorated Env +Type ::= ns::NamedSignatureElement env::Env { local occursCheck :: [OccursDclInfo] = getOccursDcl("silver:langutil:ast", ns.typerep.typeName, env); diff --git a/grammars/silver/compiler/extension/autoattr/Unification.sv b/grammars/silver/compiler/extension/autoattr/BiEquality.sv similarity index 72% rename from grammars/silver/compiler/extension/autoattr/Unification.sv rename to grammars/silver/compiler/extension/autoattr/BiEquality.sv index d32680fdc..b45a88166 100644 --- a/grammars/silver/compiler/extension/autoattr/Unification.sv +++ b/grammars/silver/compiler/extension/autoattr/BiEquality.sv @@ -1,11 +1,13 @@ grammar silver:compiler:extension:autoattr; -concrete production unificationAttributeDcl -top::AGDcl ::= 'unification' 'attribute' synPartial::Name ',' syn::Name 'with' inh::QName ';' +concrete production biequalityAttributeDcl +top::AGDcl ::= 'biequality' 'attribute' synPartial::Name ',' syn::Name 'with' inh::QName ';' { - top.unparse = s"unification attribute ${synPartial.unparse}, ${syn.unparse} with ${inh.unparse};"; + top.unparse = s"biequality attribute ${synPartial.unparse}, ${syn.unparse} with ${inh.unparse};"; top.moduleNames := []; + propagate grammarName, env, flowEnv; + production attribute inhFName :: String; inhFName = inh.lookupAttribute.fullName; production attribute synPartialFName :: String; @@ -24,16 +26,19 @@ top::AGDcl ::= 'unification' 'attribute' synPartial::Name ',' syn::Name 'with' i forwards to defsAGDcl( - [attrDef(defaultEnvItem(unificationPartialDcl(inhFName, synPartialFName, synFName, sourceGrammar=top.grammarName, sourceLocation=synPartial.location))), - attrDef(defaultEnvItem(unificationDcl(inhFName, synPartialFName, synFName, sourceGrammar=top.grammarName, sourceLocation=syn.location)))], + [attrDef(defaultEnvItem(biequalityPartialDcl(inhFName, synPartialFName, synFName, sourceGrammar=top.grammarName, sourceLocation=synPartial.location))), + attrDef(defaultEnvItem(biequalityDcl(inhFName, synPartialFName, synFName, sourceGrammar=top.grammarName, sourceLocation=syn.location)))], location=top.location); } -abstract production unificationInhAttributionDcl -top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs +abstract production biequalityInhAttributionDcl +top::AGDcl ::= at::Decorated! QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs { + undecorates to attributionDcl('attribute', at, attl, 'occurs', 'on', nt, nttl, ';', location=top.location); top.unparse = "attribute " ++ at.unparse ++ attl.unparse ++ " occurs on " ++ nt.unparse ++ nttl.unparse ++ ";"; top.moduleNames := []; + + propagate grammarName, env, flowEnv; forwards to defaultAttributionDcl( @@ -59,9 +64,10 @@ top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QNam location=top.location); } -abstract production propagateUnificationSynPartial -top::ProductionStmt ::= inh::String synPartial::PartiallyDecorated QName syn::String +abstract production propagateBiequalitySynPartial +top::ProductionStmt ::= inh::String synPartial::Decorated! QName syn::String { + undecorates to propagateOneAttr(synPartial, location=top.location); top.unparse = s"propagate ${synPartial.unparse};"; forwards to @@ -95,9 +101,10 @@ top::ProductionStmt ::= inh::String synPartial::PartiallyDecorated QName syn::St }; } -abstract production propagateUnificationSyn -top::ProductionStmt ::= inh::String synPartial::String syn::PartiallyDecorated QName +abstract production propagateBiequalitySyn +top::ProductionStmt ::= inh::String synPartial::String syn::Decorated! QName { + undecorates to propagateOneAttr(syn, location=top.location); top.unparse = s"propagate ${syn.unparse};"; forwards to diff --git a/grammars/silver/compiler/extension/autoattr/DclInfo.sv b/grammars/silver/compiler/extension/autoattr/DclInfo.sv index 26017e411..c5e64379b 100644 --- a/grammars/silver/compiler/extension/autoattr/DclInfo.sv +++ b/grammars/silver/compiler/extension/autoattr/DclInfo.sv @@ -1,6 +1,6 @@ grammar silver:compiler:extension:autoattr; -synthesized attribute propagateDispatcher :: (ProductionStmt ::= PartiallyDecorated QName Location) occurs on AttributeDclInfo; +synthesized attribute propagateDispatcher :: (ProductionStmt ::= Decorated! QName Location) occurs on AttributeDclInfo; synthesized attribute emptyVal::Expr occurs on AttributeDclInfo; @@ -29,6 +29,7 @@ top::AttributeDclInfo ::= fn::String top.decoratedAccessHandler = synDecoratedAccessHandler(_, _, location=_); top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); + top.dataAccessHandler = synDataAccessHandler(_, _, location=_); top.attrDefDispatcher = synthesizedAttributeDef(_, _, _, location=_); -- Allow normal syn equations top.attributionDispatcher = functorAttributionDcl(_, _, _, _, location=_); top.propagateDispatcher = propagateFunctor(_, location=_); @@ -53,8 +54,9 @@ top::AttributeDclInfo ::= fn::String bound::[TyVar] ty::Type empty::Expr append: top.decoratedAccessHandler = synDecoratedAccessHandler(_, _, location=_); top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); + top.dataAccessHandler = synDataAccessHandler(_, _, location=_); top.attrDefDispatcher = - \ dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr l::Location -> + \ dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr l::Location -> errorAttributeDef([err(l, attr.name ++ " is a monoid collection attribute, and you must use ':=' or '<-', not '='.")], dl, attr, e, location=l); top.attrBaseDefDispatcher = synBaseColAttributeDef(_, _, _, location=_); top.attrAppendDefDispatcher = synAppendColAttributeDef(_, _, _, location=_); @@ -74,7 +76,8 @@ top::AttributeDclInfo ::= fn::String top.isInherited = true; top.decoratedAccessHandler = inhDecoratedAccessHandler(_, _, location=_); - top.undecoratedAccessHandler = accessBounceDecorate(inhDecoratedAccessHandler(_, _, location=_), _, _, _); -- TODO: should probably be an error handler! access inh from undecorated? + top.undecoratedAccessHandler = inhUndecoratedAccessErrorHandler(_, _, location=_); + top.dataAccessHandler = inhUndecoratedAccessErrorHandler(_, _, location=_); top.attrDefDispatcher = inheritedAttributeDef(_, _, _, location=_); -- Allow normal inh equations top.attributionDispatcher = destructAttributionDcl(_, _, _, _, location=_); top.propagateDispatcher = propagateDestruct(_, location=_); @@ -91,6 +94,7 @@ top::AttributeDclInfo ::= inh::String syn::String top.decoratedAccessHandler = synDecoratedAccessHandler(_, _, location=_); top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); + top.dataAccessHandler = synDataAccessHandler(_, _, location=_); top.attrDefDispatcher = synthesizedAttributeDef(_, _, _, location=_); -- Allow normal syn equations top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); top.propagateDispatcher = propagateEquality(inh, _, location=_); @@ -107,6 +111,7 @@ top::AttributeDclInfo ::= syn::String top.decoratedAccessHandler = synDecoratedAccessHandler(_, _, location=_); top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); + top.dataAccessHandler = synDataAccessHandler(_, _, location=_); top.attrDefDispatcher = synthesizedAttributeDef(_, _, _, location=_); -- Allow normal syn equations top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); top.propagateDispatcher = propagateOrderingKey(_, location=_); @@ -123,12 +128,13 @@ top::AttributeDclInfo ::= inh::String keySyn::String syn::String top.decoratedAccessHandler = synDecoratedAccessHandler(_, _, location=_); top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); + top.dataAccessHandler = synDataAccessHandler(_, _, location=_); top.attrDefDispatcher = synthesizedAttributeDef(_, _, _, location=_); -- Allow normal syn equations top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); top.propagateDispatcher = propagateOrdering(inh, keySyn, _, location=_); } -abstract production unificationPartialDcl +abstract production biequalityPartialDcl top::AttributeDclInfo ::= inh::String synPartial::String syn::String { top.fullName = synPartial; @@ -139,12 +145,13 @@ top::AttributeDclInfo ::= inh::String synPartial::String syn::String top.decoratedAccessHandler = synDecoratedAccessHandler(_, _, location=_); top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); + top.dataAccessHandler = synDataAccessHandler(_, _, location=_); top.attrDefDispatcher = synthesizedAttributeDef(_, _, _, location=_); -- Allow normal syn equations top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); - top.propagateDispatcher = propagateUnificationSynPartial(inh, _, syn, location=_); + top.propagateDispatcher = propagateBiequalitySynPartial(inh, _, syn, location=_); } -abstract production unificationDcl +abstract production biequalityDcl top::AttributeDclInfo ::= inh::String synPartial::String syn::String { top.fullName = syn; @@ -155,51 +162,80 @@ top::AttributeDclInfo ::= inh::String synPartial::String syn::String top.decoratedAccessHandler = synDecoratedAccessHandler(_, _, location=_); top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); + top.dataAccessHandler = synDataAccessHandler(_, _, location=_); top.attrDefDispatcher = synthesizedAttributeDef(_, _, _, location=_); -- Allow normal syn equations top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); - top.propagateDispatcher = propagateUnificationSyn(inh, synPartial, _, location=_); + top.propagateDispatcher = propagateBiequalitySyn(inh, synPartial, _, location=_); } abstract production threadedInhDcl -top::AttributeDclInfo ::= inh::String syn::String bound::[TyVar] ty::Type rev::Boolean +top::AttributeDclInfo ::= inh::String syn::String bound::[TyVar] ty::Type o::Maybe rev::Boolean { top.fullName = inh; propagate compareKey; top.isEqual = case top.compareTo of - | threadedInhDcl(inh2, syn2, _, _, rev2) -> + | threadedInhDcl(inh2, syn2, _, _, _, rev2) -> inh == inh2 && syn == syn2 && top.typeScheme == top.compareTo.typeScheme && rev == rev2 | _ -> false end; top.typeScheme = polyType(bound, ty); top.isInherited = true; + top.isCollection = o.isJust; + top.operation = o.fromJust; top.decoratedAccessHandler = inhDecoratedAccessHandler(_, _, location=_); - top.undecoratedAccessHandler = accessBounceDecorate(inhDecoratedAccessHandler(_, _, location=_), _, _, _); - top.attrDefDispatcher = inheritedAttributeDef(_, _, _, location=_); -- Allow normal inh equations + top.undecoratedAccessHandler = inhUndecoratedAccessErrorHandler(_, _, location=_); + top.dataAccessHandler = inhUndecoratedAccessErrorHandler(_, _, location=_); + top.attrDefDispatcher = + if o.isJust + then collectionAttrDefError + else inheritedAttributeDef(_, _, _, location=_); -- Allow normal inh equations + top.attrBaseDefDispatcher = + if o.isJust + then inhBaseColAttributeDef(_, _, _, location=_) -- Allow normal inh base equations + else nonCollectionAttrBaseDefError; + top.attrAppendDefDispatcher = + if o.isJust + then inhAppendColAttributeDef(_, _, _, location=_) -- Allow normal inh append equations + else nonCollectionAttrAppendDefError; top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); - top.propagateDispatcher = propagateThreadedInh(rev, _, syn, location=_); + top.propagateDispatcher = propagateThreadedInh(o.isJust, rev, _, syn, location=_); } abstract production threadedSynDcl -top::AttributeDclInfo ::= inh::String syn::String bound::[TyVar] ty::Type rev::Boolean +top::AttributeDclInfo ::= inh::String syn::String bound::[TyVar] ty::Type o::Maybe rev::Boolean { top.fullName = syn; propagate compareKey; top.isEqual = case top.compareTo of - | threadedSynDcl(inh2, syn2, _, _, rev2) -> + | threadedSynDcl(inh2, syn2, _, _, _, rev2) -> inh == inh2 && syn == syn2 && top.typeScheme == top.compareTo.typeScheme && rev == rev2 | _ -> false end; top.typeScheme = polyType(bound, ty); top.isSynthesized = true; + top.isCollection = o.isJust; + top.operation = o.fromJust; top.decoratedAccessHandler = synDecoratedAccessHandler(_, _, location=_); top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); - top.attrDefDispatcher = synthesizedAttributeDef(_, _, _, location=_); -- Allow normal syn equations + top.dataAccessHandler = synDataAccessHandler(_, _, location=_); + top.attrDefDispatcher = + if o.isJust + then collectionAttrDefError + else synthesizedAttributeDef(_, _, _, location=_); -- Allow normal syn equations + top.attrBaseDefDispatcher = + if o.isJust + then synBaseColAttributeDef(_, _, _, location=_) -- Allow normal syn base equations + else nonCollectionAttrBaseDefError; + top.attrAppendDefDispatcher = + if o.isJust + then synAppendColAttributeDef(_, _, _, location=_) -- Allow normal syn append equations + else nonCollectionAttrAppendDefError; top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); - top.propagateDispatcher = propagateThreadedSyn(rev, inh, _, location=_); + top.propagateDispatcher = propagateThreadedSyn(o.isJust, rev, inh, _, location=_); } diff --git a/grammars/silver/compiler/extension/autoattr/Destruct.sv b/grammars/silver/compiler/extension/autoattr/Destruct.sv index d7b8b9bfb..47e02524f 100644 --- a/grammars/silver/compiler/extension/autoattr/Destruct.sv +++ b/grammars/silver/compiler/extension/autoattr/Destruct.sv @@ -21,10 +21,13 @@ top::AGDcl ::= 'destruct' 'attribute' inh::Name ';' } abstract production destructAttributionDcl -top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs +top::AGDcl ::= at::Decorated! QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs { + undecorates to attributionDcl('attribute', at, attl, 'occurs', 'on', nt, nttl, ';', location=top.location); top.unparse = "attribute " ++ at.unparse ++ attl.unparse ++ " occurs on " ++ nt.unparse ++ nttl.unparse ++ ";"; top.moduleNames := []; + + propagate grammarName, env, flowEnv; forwards to defaultAttributionDcl( @@ -77,8 +80,9 @@ top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QNam - @param attr The name of the attribute to propagate -} abstract production propagateDestruct -top::ProductionStmt ::= attr::PartiallyDecorated QName +top::ProductionStmt ::= attr::Decorated! QName { + undecorates to propagateOneAttr(attr, location=top.location); top.unparse = s"propagate ${attr.unparse};"; local numChildren::Integer = length(top.frame.signature.inputElements); @@ -108,12 +112,12 @@ top::ProductionStmt ::= attr::PartiallyDecorated QName "Destruct attribute " ++ $Expr{stringConst(terminal(String_t, s"\"${attr.name}\"", top.location), location=top.location)} ++ " demanded on child " ++ $Expr{stringConst(terminal(String_t, s"\"${ie.snd.elementName}\"", top.location), location=top.location)} ++ " of production " ++ $Expr{stringConst(terminal(String_t, s"\"${top.frame.signature.fullName}\"", top.location), location=top.location)} ++ - " when given value " ++ silver:core:hackUnparse(a) ++ " does not match.") + " when given value " ++ silver:core:hackUnparse(a) ++ " does not match.") -- TODO: Shouldn't really be using hackUnparse here. end; }, filter( \ ie::Pair -> !null(getOccursDcl(attr.lookupAttribute.dcl.fullName, ie.snd.typerep.typeName, top.env)), - zipWith(pair, range(0, numChildren), top.frame.signature.inputElements)))); + zip(range(0, numChildren), top.frame.signature.inputElements)))); } diff --git a/grammars/silver/compiler/extension/autoattr/Equality.sv b/grammars/silver/compiler/extension/autoattr/Equality.sv index 1561793fc..4e43bee94 100644 --- a/grammars/silver/compiler/extension/autoattr/Equality.sv +++ b/grammars/silver/compiler/extension/autoattr/Equality.sv @@ -6,6 +6,8 @@ top::AGDcl ::= 'equality' 'attribute' syn::Name 'with' inh::QName ';' top.unparse = s"equality attribute ${syn.unparse} with ${inh.unparse};"; top.moduleNames := []; + propagate env; + production attribute inhFName :: String; inhFName = inh.lookupAttribute.fullName; production attribute synFName :: String; @@ -27,8 +29,9 @@ top::AGDcl ::= 'equality' 'attribute' syn::Name 'with' inh::QName ';' - @param attr The name of the attribute to propagate -} abstract production propagateEquality -top::ProductionStmt ::= inh::String syn::PartiallyDecorated QName +top::ProductionStmt ::= inh::String syn::Decorated! QName { + undecorates to propagateOneAttr(syn, location=top.location); top.unparse = s"propagate ${syn.unparse};"; forwards to diff --git a/grammars/silver/compiler/extension/autoattr/Functor.sv b/grammars/silver/compiler/extension/autoattr/Functor.sv index 87acb52e1..9360f27ae 100644 --- a/grammars/silver/compiler/extension/autoattr/Functor.sv +++ b/grammars/silver/compiler/extension/autoattr/Functor.sv @@ -21,10 +21,13 @@ top::AGDcl ::= 'functor' 'attribute' a::Name ';' } abstract production functorAttributionDcl -top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs +top::AGDcl ::= at::Decorated! QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs { + undecorates to attributionDcl('attribute', at, attl, 'occurs', 'on', nt, nttl, ';', location=top.location); top.unparse = "attribute " ++ at.unparse ++ attl.unparse ++ " occurs on " ++ nt.unparse ++ nttl.unparse ++ ";"; top.moduleNames := []; + + propagate grammarName, env, flowEnv; forwards to defaultAttributionDcl( @@ -55,8 +58,9 @@ top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QNam - @param attr The name of the attribute to propagate -} abstract production propagateFunctor -top::ProductionStmt ::= attr::PartiallyDecorated QName +top::ProductionStmt ::= attr::Decorated! QName { + undecorates to propagateOneAttr(attr, location=top.location); top.unparse = s"propagate ${attr.unparse};"; -- No explicit errors, for now. The only conceivable issue is the attribute not @@ -95,7 +99,7 @@ top::ProductionStmt ::= attr::PartiallyDecorated QName - @return Either this the child, or accessing `attrName` on the child -} function makeArg -Expr ::= loc::Location env::Decorated Env attrName::Decorated QName input::NamedSignatureElement +Expr ::= loc::Location env::Env attrName::Decorated QName input::NamedSignatureElement { local at::QName = qName(loc, input.elementName); at.env = env; @@ -103,7 +107,8 @@ Expr ::= loc::Location env::Decorated Env attrName::Decorated QName input::Named -- Check if the attribute occurs on the first child local attrOccursOnHead :: Boolean = !null(getOccursDcl(attrName.lookupAttribute.dcl.fullName, input.typerep.typeName, env)); - local validTypeHead :: Boolean = isDecorable(input.typerep, env) && !input.typerep.isPartiallyDecorated; + local validTypeHead :: Boolean = + (isDecorable(input.typerep, env) || input.typerep.isNonterminal) && !input.typerep.isUniqueDecorated; return if validTypeHead && attrOccursOnHead @@ -129,7 +134,7 @@ Pair ::= loc::Location baseName::String input::NamedSignatureElemen local annoName :: String = last(explode(":", input.elementName)); return - pair(annoName, + (annoName, access( baseExpr(qName(loc, baseName), location=loc), '.', qNameAttrOccur(qName(loc, annoName), location=loc), diff --git a/grammars/silver/compiler/extension/autoattr/Inherited.sv b/grammars/silver/compiler/extension/autoattr/Inherited.sv index abf6d37f7..c440e4ae5 100644 --- a/grammars/silver/compiler/extension/autoattr/Inherited.sv +++ b/grammars/silver/compiler/extension/autoattr/Inherited.sv @@ -1,8 +1,9 @@ grammar silver:compiler:extension:autoattr; abstract production propagateInh -top::ProductionStmt ::= attr::PartiallyDecorated QName +top::ProductionStmt ::= attr::Decorated! QName { + undecorates to propagateOneAttr(attr, location=top.location); top.unparse = s"propagate ${attr.unparse};"; local attrFullName::String = attr.lookupAttribute.dcl.fullName; @@ -10,7 +11,11 @@ top::ProductionStmt ::= attr::PartiallyDecorated QName filter( \ input::NamedSignatureElement -> isDecorable(input.typerep, top.env) && - !input.typerep.isPartiallyDecorated && -- Don't copy on partially decorated children + -- Only propagate for unique decorated children that don't have the attribute + case getMaxRefSet(input.typerep, top.env) of + | just(inhs) -> !contains(attrFullName, inhs) + | nothing() -> false + end && !null(getOccursDcl(attrFullName, input.typerep.typeName, top.env)), top.frame.signature.inputElements); forwards to diff --git a/grammars/silver/compiler/extension/autoattr/Monoid.sv b/grammars/silver/compiler/extension/autoattr/Monoid.sv index 0d6d29d4c..a118b4a1f 100644 --- a/grammars/silver/compiler/extension/autoattr/Monoid.sv +++ b/grammars/silver/compiler/extension/autoattr/Monoid.sv @@ -7,6 +7,7 @@ concrete production monoidAttributeDcl top::AGDcl ::= 'monoid' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr 'with' e::Expr ',' q::NameOrBOperator ';' { top.unparse = "monoid attribute " ++ a.unparse ++ tl.unparse ++ " :: " ++ te.unparse ++ " with " ++ e.unparse ++ ", " ++ q.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, flowEnv; production attribute fName :: String; fName = top.grammarName ++ ":" ++ a.name; @@ -14,6 +15,8 @@ top::AGDcl ::= 'monoid' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::T tl.initialEnv = top.env; tl.env = tl.envBindingTyVars; te.env = tl.envBindingTyVars; + e.env = tl.envBindingTyVars; + q.env = tl.envBindingTyVars; q.operatorForType = te.typerep; @@ -51,6 +54,8 @@ top::AGDcl ::= 'monoid' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::T e.frame = globalExprContext(fName, nilContext(), te.typerep, myFlowGraph, sourceGrammar=top.grammarName); e.isRoot = false; e.originRules = []; + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; forwards to collectionAttributeDclSyn( @@ -113,8 +118,9 @@ top::Operation ::= - @param attr The name of the attribute to propagate -} abstract production propagateMonoid -top::ProductionStmt ::= attr::PartiallyDecorated QName +top::ProductionStmt ::= attr::Decorated! QName { + undecorates to propagateOneAttr(attr, location=top.location); top.unparse = s"propagate ${attr.unparse};"; -- No explicit errors, for now. The only conceivable issue is the attribute not @@ -124,7 +130,7 @@ top::ProductionStmt ::= attr::PartiallyDecorated QName local inputsWithAttr::[NamedSignatureElement] = filter( \ input::NamedSignatureElement -> - isDecorable(input.typerep, top.env) && + (isDecorable(input.typerep, top.env) || input.typerep.isNonterminal) && !null(getOccursDcl(attrFullName, input.typerep.typeName, top.env)), top.frame.signature.inputElements); local res :: Expr = diff --git a/grammars/silver/compiler/extension/autoattr/Ordering.sv b/grammars/silver/compiler/extension/autoattr/Ordering.sv index 5a990df61..190ed9404 100644 --- a/grammars/silver/compiler/extension/autoattr/Ordering.sv +++ b/grammars/silver/compiler/extension/autoattr/Ordering.sv @@ -6,6 +6,8 @@ top::AGDcl ::= 'ordering' 'attribute' keySyn::Name ',' syn::Name 'with' inh::QNa top.unparse = s"ordering attribute ${keySyn.unparse}, ${syn.unparse} with ${inh.unparse};"; top.moduleNames := []; + propagate env; + production attribute inhFName :: String; inhFName = inh.lookupAttribute.fullName; production attribute keySynFName :: String; @@ -34,8 +36,9 @@ top::AGDcl ::= 'ordering' 'attribute' keySyn::Name ',' syn::Name 'with' inh::QNa - Propagate a ordering key synthesized attribute on the enclosing production -} abstract production propagateOrderingKey -top::ProductionStmt ::= syn::PartiallyDecorated QName +top::ProductionStmt ::= syn::Decorated! QName { + undecorates to propagateOneAttr(syn, location=top.location); top.unparse = s"propagate ${syn.unparse};"; forwards to @@ -49,8 +52,9 @@ top::ProductionStmt ::= syn::PartiallyDecorated QName - Propagate a ordering synthesized attribute on the enclosing production -} abstract production propagateOrdering -top::ProductionStmt ::= inh::String keySyn::String syn::PartiallyDecorated QName +top::ProductionStmt ::= inh::String keySyn::String syn::Decorated! QName { + undecorates to propagateOneAttr(syn, location=top.location); top.unparse = s"propagate ${syn.unparse};"; local topName::String = top.frame.signature.outputElement.elementName; @@ -76,7 +80,7 @@ top::ProductionStmt ::= inh::String keySyn::String syn::PartiallyDecorated QName else foldr1( \ e1::Expr e2::Expr -> - Silver_Expr { if $Expr{e1} == 0 then $Expr{e2} else $Expr{e1} }, + Silver_Expr { let res::Integer = $Expr{e1} in if res == 0 then $Expr{e2} else res end }, map( \ ie::NamedSignatureElement -> if null(getOccursDcl(syn.lookupAttribute.dcl.fullName, ie.typerep.typeName, top.env)) diff --git a/grammars/silver/compiler/extension/autoattr/Project.sv b/grammars/silver/compiler/extension/autoattr/Project.sv index 4fac1e21d..8e1c08511 100644 --- a/grammars/silver/compiler/extension/autoattr/Project.sv +++ b/grammars/silver/compiler/extension/autoattr/Project.sv @@ -4,6 +4,8 @@ imports silver:compiler:definition:core; imports silver:compiler:definition:env; imports silver:compiler:definition:type; imports silver:compiler:definition:type:syntax; +imports silver:compiler:definition:flow:env; +imports silver:compiler:analysis:typechecking:core; imports silver:compiler:modification:collection; imports silver:compiler:modification:let_fix; imports silver:compiler:extension:patternmatching; diff --git a/grammars/silver/compiler/extension/autoattr/Propagate.sv b/grammars/silver/compiler/extension/autoattr/Propagate.sv index 48dc0bcec..fe38c5f2e 100644 --- a/grammars/silver/compiler/extension/autoattr/Propagate.sv +++ b/grammars/silver/compiler/extension/autoattr/Propagate.sv @@ -4,6 +4,7 @@ concrete production propagateOnNTListExcludingDcl_c top::AGDcl ::= 'propagate' attrs::NameList 'on' nts::NameList 'excluding' ps::ProdNameList ';' { top.unparse = s"propagate ${attrs.unparse} on ${nts.unparse} excluding ${ps.unparse};"; + propagate env; top.errors <- ps.errors; forwards to propagateOnNTListDcl(attrs, nts, ps, location=top.location); @@ -42,10 +43,12 @@ abstract production propagateOnOneNTDcl top::AGDcl ::= attrs::NameList nt::QName ps::ProdNameList { top.unparse = s"propagate ${attrs.unparse} on ${nt.unparse} excluding ${ps.unparse};"; + propagate env; -- Ugh, workaround for circular dependency top.defs := []; top.occursDefs := []; + top.refDefs := []; top.moduleNames := []; top.specDefs := []; @@ -125,6 +128,7 @@ abstract production propagateOneAttr top::ProductionStmt ::= attr::QName { top.unparse = s"propagate ${attr.unparse};"; + propagate env; -- We make an exception to permit propagated equations in places that would otherwise be orphaned. -- Since this is the only possible equation permitted in these contexts, having duplicates will @@ -144,8 +148,9 @@ top::ProductionStmt ::= attr::QName } abstract production propagateError -top::ProductionStmt ::= attr::PartiallyDecorated QName +top::ProductionStmt ::= attr::Decorated! QName { + undecorates to propagateOneAttr(attr, location=top.location); forwards to errorProductionStmt( [err(attr.location, s"Attribute ${attr.name} cannot be propagated")], @@ -155,7 +160,7 @@ top::ProductionStmt ::= attr::PartiallyDecorated QName -- Need a seperate nonterminal since this can be empty and needs env to check errors nonterminal ProdNameList with config, grammarName, env, location, unparse, names, errors; -propagate errors on ProdNameList; +propagate config, grammarName, env, errors on ProdNameList; abstract production prodNameListNil top::ProdNameList ::= diff --git a/grammars/silver/compiler/extension/autoattr/Terminals.sv b/grammars/silver/compiler/extension/autoattr/Terminals.sv index f31ae0287..ba422f766 100644 --- a/grammars/silver/compiler/extension/autoattr/Terminals.sv +++ b/grammars/silver/compiler/extension/autoattr/Terminals.sv @@ -10,5 +10,5 @@ terminal Monoid_kwd 'monoid' lexer classes {KEYWORD}; terminal Destruct_kwd 'destruct' lexer classes {KEYWORD}; terminal Equality_kwd 'equality' lexer classes {KEYWORD}; terminal Ordering_kwd 'ordering' lexer classes {KEYWORD}; -terminal Unification_kwd 'unification' lexer classes {KEYWORD}; +terminal Biequality_kwd 'biequality' lexer classes {KEYWORD}; terminal Threaded_kwd 'threaded' lexer classes {KEYWORD}; \ No newline at end of file diff --git a/grammars/silver/compiler/extension/autoattr/Threaded.sv b/grammars/silver/compiler/extension/autoattr/Threaded.sv index 48843cd8c..76f7df756 100644 --- a/grammars/silver/compiler/extension/autoattr/Threaded.sv +++ b/grammars/silver/compiler/extension/autoattr/Threaded.sv @@ -5,9 +5,11 @@ import silver:compiler:definition:concrete_syntax only Left_kwd, Right_kwd; concrete production threadedAttributeDcl top::AGDcl ::= 'threaded' 'attribute' inh::Name ',' syn::Name tl::BracketedOptTypeExprs '::' te::TypeExpr d::OptDirectionMod ';' { - top.unparse = s"threaded attribute ${inh.unparse}, ${syn.unparse} ${tl.unparse} :: ${te.unparse};"; + top.unparse = s"threaded attribute ${inh.unparse}, ${syn.unparse} ${tl.unparse} :: ${te.unparse}${d.unparse};"; top.moduleNames := []; + propagate grammarName, flowEnv; + production attribute inhFName :: String; inhFName = top.grammarName ++ ":" ++ inh.name; production attribute synFName :: String; @@ -28,30 +30,78 @@ top::AGDcl ::= 'threaded' 'attribute' inh::Name ',' syn::Name tl::BracketedOptTy forwards to defsAGDcl( - [attrDef(defaultEnvItem(threadedInhDcl(inhFName, synFName, tl.freeVariables, te.typerep, d.reversed, sourceGrammar=top.grammarName, sourceLocation=inh.location))), - attrDef(defaultEnvItem(threadedSynDcl(inhFName, synFName, tl.freeVariables, te.typerep, d.reversed, sourceGrammar=top.grammarName, sourceLocation=syn.location)))], + [attrDef(defaultEnvItem(threadedInhDcl(inhFName, synFName, tl.freeVariables, te.typerep, nothing(), d.reversed, sourceGrammar=top.grammarName, sourceLocation=inh.location))), + attrDef(defaultEnvItem(threadedSynDcl(inhFName, synFName, tl.freeVariables, te.typerep, nothing(), d.reversed, sourceGrammar=top.grammarName, sourceLocation=syn.location)))], + location=top.location); +} + +concrete production collectionThreadedAttributeDcl +top::AGDcl ::= 'threaded' 'attribute' inh::Name ',' syn::Name tl::BracketedOptTypeExprs '::' te::TypeExpr 'with' q::NameOrBOperator d::OptDirectionMod ';' +{ + top.unparse = s"threaded attribute ${inh.unparse}, ${syn.unparse} ${tl.unparse} :: ${te.unparse} with ${q.unparse}${d.unparse};"; + top.moduleNames := []; + + propagate grammarName, compiledGrammars, config, flowEnv; + + production attribute inhFName :: String; + inhFName = top.grammarName ++ ":" ++ inh.name; + production attribute synFName :: String; + synFName = top.grammarName ++ ":" ++ syn.name; + + tl.initialEnv = top.env; + tl.env = tl.envBindingTyVars; + te.env = tl.envBindingTyVars; + + q.env = top.env; + q.operatorForType = te.typerep; + + top.errors <- + if length(getAttrDclAll(inhFName, top.env)) > 1 + then [err(inh.location, "Attribute '" ++ inhFName ++ "' is already bound.")] + else []; + top.errors <- + if length(getAttrDclAll(synFName, top.env)) > 1 + then [err(syn.location, "Attribute '" ++ synFName ++ "' is already bound.")] + else []; + + -- TODO: We want to forward to collection attr decls for the translation, but provide our own defs. + -- The non-interfering way of doing this would be to split up the collection attr decl prodictions + -- into a prod providing the defs, and a prod providing the translation... + top.defs := + [attrDef(defaultEnvItem(threadedInhDcl(inhFName, synFName, tl.freeVariables, te.typerep, just(q.operation), d.reversed, sourceGrammar=top.grammarName, sourceLocation=inh.location))), + attrDef(defaultEnvItem(threadedSynDcl(inhFName, synFName, tl.freeVariables, te.typerep, just(q.operation), d.reversed, sourceGrammar=top.grammarName, sourceLocation=syn.location)))]; + + forwards to + appendAGDcl( + collectionAttributeDclInh('inherited', 'attribute', inh, tl, '::', te, 'with', q, ';', location=top.location), + collectionAttributeDclSyn('synthesized', 'attribute', syn, tl, '::', te, 'with', q, ';', location=top.location), location=top.location); } synthesized attribute reversed::Boolean; -nonterminal OptDirectionMod with reversed; +nonterminal OptDirectionMod with unparse, reversed; concrete productions top::OptDirectionMod | 'direction' '=' d::Direction - { top.reversed = d.reversed; } + { top.unparse = " direction=" ++ d.unparse; + top.reversed = d.reversed; } | - { top.reversed = false; } + { top.unparse = ""; + top.reversed = false; } -nonterminal Direction with reversed; +nonterminal Direction with unparse, reversed; concrete productions top::Direction | 'left' 'to' 'right' - { top.reversed = false; } + { top.unparse = "left to right"; + top.reversed = false; } | 'right' 'to' 'left' - { top.reversed = true; } + { top.unparse = "right to left"; + top.reversed = true; } abstract production propagateThreadedInh -top::ProductionStmt ::= rev::Boolean inh::PartiallyDecorated QName syn::String +top::ProductionStmt ::= isCol::Boolean rev::Boolean inh::Decorated! QName syn::String { + undecorates to propagateOneAttr(inh, location=top.location); top.unparse = s"propagate ${inh.unparse};"; local lhsName::String = top.frame.signature.outputElement.elementName; @@ -61,7 +111,11 @@ top::ProductionStmt ::= rev::Boolean inh::PartiallyDecorated QName syn::String filter( \ ie::NamedSignatureElement -> isDecorable(ie.typerep, top.env) && - !ie.typerep.isPartiallyDecorated && -- Don't thread on partially decorated children + -- Only propagate for unique decorated children that don't have the inh attribute + case getMaxRefSet(ie.typerep, top.env) of + | just(inhs) -> !contains(inh.lookupAttribute.fullName, inhs) + | nothing() -> false + end && !null(getOccursDcl(inh.lookupAttribute.fullName, ie.typerep.typeName, top.env)) && !null(getOccursDcl(syn, ie.typerep.typeName, top.env)), if null(getOccursDcl(syn, top.frame.lhsNtName, top.env)) && !null(top.frame.signature.inputElements) @@ -69,7 +123,7 @@ top::ProductionStmt ::= rev::Boolean inh::PartiallyDecorated QName syn::String else top.frame.signature.inputElements)); forwards to threadInhDcl( - inh.name, syn, + isCol, inh.name, syn, map( name(_, top.location), lhsName :: @@ -83,8 +137,9 @@ top::ProductionStmt ::= rev::Boolean inh::PartiallyDecorated QName syn::String } abstract production propagateThreadedSyn -top::ProductionStmt ::= rev::Boolean inh::String syn::PartiallyDecorated QName +top::ProductionStmt ::= isCol::Boolean rev::Boolean inh::String syn::Decorated! QName { + undecorates to propagateOneAttr(syn, location=top.location); top.unparse = s"propagate ${syn.unparse};"; local lhsName::String = top.frame.signature.outputElement.elementName; @@ -94,13 +149,17 @@ top::ProductionStmt ::= rev::Boolean inh::String syn::PartiallyDecorated QName filter( \ ie::NamedSignatureElement -> isDecorable(ie.typerep, top.env) && - !ie.typerep.isPartiallyDecorated && -- Don't thread on partially decorated children + -- Only propagate for unique decorated children that don't have the inh attribute + case getMaxRefSet(ie.typerep, top.env) of + | just(inhs) -> !contains(inh, inhs) + | nothing() -> false + end && !null(getOccursDcl(inh, ie.typerep.typeName, top.env)) && !null(getOccursDcl(syn.lookupAttribute.fullName, ie.typerep.typeName, top.env)), top.frame.signature.inputElements)); forwards to threadSynDcl( - inh, syn.name, + isCol, inh, syn.name, map( name(_, top.location), lhsName :: @@ -113,19 +172,35 @@ concrete production threadDcl_c top::ProductionStmt ::= 'thread' inh::QName ',' syn::QName 'on' children::ChildNameList ';' { top.unparse = s"thread ${inh.unparse}, ${syn.unparse} on ${children.unparse};"; + propagate env; + + -- Needed to avoid circularity due to forwarding based on env + top.productionAttributes := []; + top.defs := []; + forwards to productionStmtAppend( - threadInhDcl(inh.name, syn.name, children.ids, location=top.location), - threadSynDcl(inh.name, syn.name, children.ids, location=top.location), + threadInhDcl( + inh.lookupAttribute.found && inh.lookupAttribute.dcl.isCollection, + inh.name, syn.name, children.ids, + location=top.location), + threadSynDcl( + syn.lookupAttribute.found && syn.lookupAttribute.dcl.isCollection, + inh.name, syn.name, children.ids, + location=top.location), location=top.location); } abstract production threadInhDcl -top::ProductionStmt ::= inh::String syn::String children::[Name] +top::ProductionStmt ::= isCol::Boolean inh::String syn::String children::[Name] { top.unparse = s"thread ${inh}, ${syn} on ${implode(", ", map((.unparse), children))};"; local lhsName::String = top.frame.signature.outputElement.elementName; + local attrDefProd::(ProductionStmt ::= DefLHS QNameAttrOccur Expr) = + if isCol + then attrContainsBase(_, '.', _, ':=', _, ';', location=top.location) + else attributeDef(_, '.', _, '=', _, ';', location=top.location); forwards to foldr( productionStmtAppend(_, _, location=top.location), @@ -134,27 +209,27 @@ top::ProductionStmt ::= inh::String syn::String children::[Name] \ c1::Name c2::Name -> if c1.name != lhsName then - attributeDef( + attrDefProd( concreteDefLHS(qNameId(c1, location=top.location), location=top.location), - '.', qNameAttrOccur(qName(top.location, inh), location=top.location), - '=', access( baseExpr(qNameId(c2, location=top.location), location=top.location), '.', qNameAttrOccur(qName(top.location, if c2.name == lhsName then inh else syn), location=top.location), - location=top.location), - ';', - location=top.location) + location=top.location)) else errorProductionStmt([], location=top.location), tail(children), children)); } abstract production threadSynDcl -top::ProductionStmt ::= inh::String syn::String children::[Name] +top::ProductionStmt ::= isCol::Boolean inh::String syn::String children::[Name] { top.unparse = s"thread ${inh}, ${syn} on ${implode(", ", map((.unparse), children))};"; local lhsName::String = top.frame.signature.outputElement.elementName; + local attrDefProd::(ProductionStmt ::= DefLHS QNameAttrOccur Expr) = + if isCol + then attrContainsBase(_, '.', _, ':=', _, ';', location=top.location) + else attributeDef(_, '.', _, '=', _, ';', location=top.location); forwards to foldr( productionStmtAppend(_, _, location=top.location), @@ -163,17 +238,13 @@ top::ProductionStmt ::= inh::String syn::String children::[Name] \ c1::Name c2::Name -> if c1.name == lhsName then - attributeDef( + attrDefProd( concreteDefLHS(qNameId(c1, location=top.location), location=top.location), - '.', qNameAttrOccur(qName(top.location, syn), location=top.location), - '=', access( baseExpr(qNameId(c2, location=top.location), location=top.location), '.', qNameAttrOccur(qName(top.location, if c2.name == lhsName then inh else syn), location=top.location), - location=top.location), - ';', - location=top.location) + location=top.location)) else errorProductionStmt([], location=top.location), tail(children), children)); } diff --git a/grammars/silver/compiler/extension/autoattr/convenience/Convenience.sv b/grammars/silver/compiler/extension/autoattr/convenience/Convenience.sv index 5daea4e10..93e9fd2a6 100644 --- a/grammars/silver/compiler/extension/autoattr/convenience/Convenience.sv +++ b/grammars/silver/compiler/extension/autoattr/convenience/Convenience.sv @@ -120,13 +120,13 @@ top::AGDcl ::= 'ordering' 'attribute' inh::Name ',' keySyn::Name ',' syn::Name ' location=top.location); } -concrete production unificationAttributeDclMultiple -top::AGDcl ::= 'unification' 'attribute' synPartial::Name ',' syn::Name 'with' inh::QName 'occurs' 'on' qs::QNames ';' +concrete production biequalityAttributeDclMultiple +top::AGDcl ::= 'biequality' 'attribute' synPartial::Name ',' syn::Name 'with' inh::QName 'occurs' 'on' qs::QNames ';' { - top.unparse = "unification attribute " ++ synPartial.name ++ ", " ++ syn.name ++ " with " ++ inh.unparse ++ " occurs on " ++ qs.unparse ++ ";"; + top.unparse = "biequality attribute " ++ synPartial.name ++ ", " ++ syn.name ++ " with " ++ inh.unparse ++ " occurs on " ++ qs.unparse ++ ";"; forwards to appendAGDcl( - unificationAttributeDcl($1, $2, synPartial, ',', syn, 'with', inh, ';', location=top.location), + biequalityAttributeDcl($1, $2, synPartial, ',', syn, 'with', inh, ';', location=top.location), appendAGDcl( makeOccursDclsHelp($1.location, qNameWithTL(qNameId(synPartial, location=synPartial.location), botlNone(location=top.location)), qs.qnames), makeOccursDclsHelp($1.location, qNameWithTL(qNameId(syn, location=syn.location), botlNone(location=top.location)), qs.qnames), @@ -135,9 +135,9 @@ top::AGDcl ::= 'unification' 'attribute' synPartial::Name ',' syn::Name 'with' i } concrete production threadedAttributeDclMultiple -top::AGDcl ::= 'threaded' 'attribute' inh::Name ',' syn::Name tl::BracketedOptTypeExprs '::' te::TypeExpr 'occurs' 'on' qs::QNames d::OptDirectionMod ';' +top::AGDcl ::= 'threaded' 'attribute' inh::Name ',' syn::Name tl::BracketedOptTypeExprs '::' te::TypeExpr d::OptDirectionMod 'occurs' 'on' qs::QNames ';' { - top.unparse = "threaded attribute " ++ inh.unparse ++ ", " ++ syn.name ++ tl.unparse ++ " :: " ++ te.unparse ++ " occurs on " ++ qs.unparse ++ ";"; + top.unparse = "threaded attribute " ++ inh.unparse ++ ", " ++ syn.name ++ tl.unparse ++ " :: " ++ te.unparse ++ d.unparse ++ " occurs on " ++ qs.unparse ++ ";"; forwards to appendAGDcl( threadedAttributeDcl($1, $2, inh, $4, syn, tl, $7, te, d, ';', location=top.location), @@ -147,3 +147,17 @@ top::AGDcl ::= 'threaded' 'attribute' inh::Name ',' syn::Name tl::BracketedOptTy location=top.location), location=top.location); } + +concrete production collectionThreadedAttributeDclMultiple +top::AGDcl ::= 'threaded' 'attribute' inh::Name ',' syn::Name tl::BracketedOptTypeExprs '::' te::TypeExpr 'with' q::NameOrBOperator d::OptDirectionMod 'occurs' 'on' qs::QNames ';' +{ + top.unparse = "threaded attribute " ++ inh.unparse ++ ", " ++ syn.name ++ tl.unparse ++ " :: " ++ te.unparse ++ " with " ++ q.unparse ++ d.unparse ++ " occurs on " ++ qs.unparse ++ ";"; + forwards to + appendAGDcl( + collectionThreadedAttributeDcl($1, $2, inh, $4, syn, tl, $7, te, 'with', q, d, ';', location=top.location), + appendAGDcl( + makeOccursDclsHelp($1.location, qNameWithTL(qNameId(inh, location=inh.location), botlNone(location=top.location)), qs.qnames), + makeOccursDclsHelp($1.location, qNameWithTL(qNameId(syn, location=syn.location), botlNone(location=top.location)), qs.qnames), + location=top.location), + location=top.location); +} diff --git a/grammars/silver/compiler/extension/convenience/Convenience.sv b/grammars/silver/compiler/extension/convenience/Convenience.sv index 28bf8c10f..6ca6c91b3 100644 --- a/grammars/silver/compiler/extension/convenience/Convenience.sv +++ b/grammars/silver/compiler/extension/convenience/Convenience.sv @@ -81,6 +81,16 @@ top::AGDcl ::= 'synthesized' 'attribute' a::Name tl::BracketedOptTypeExprs '::' location=top.location); } +concrete production attributeDclTransMultiple +top::AGDcl ::= 'translation' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr 'occurs' 'on' qs::QNames ';' +{ + top.unparse = "translation attribute " ++ a.name ++ tl.unparse ++ " :: " ++ te.unparse ++ " occurs on " ++ qs.unparse ++ ";" ; + forwards to appendAGDcl( + attributeDclTrans($1, $2, a, tl, $5, te, $10, location=top.location), + makeOccursDclsHelp(top.location, qNameWithTL(qNameId(a, location=a.location), tl), qs.qnames), + location=top.location); +} + concrete production collectionAttributeDclInhMultiple top::AGDcl ::= 'inherited' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr 'with' q::NameOrBOperator 'occurs' 'on' qs::QNames ';' { diff --git a/grammars/silver/compiler/extension/convenience/Productions.sv b/grammars/silver/compiler/extension/convenience/Productions.sv index 2a7557d09..525b1e9e1 100644 --- a/grammars/silver/compiler/extension/convenience/Productions.sv +++ b/grammars/silver/compiler/extension/convenience/Productions.sv @@ -12,9 +12,10 @@ top::AGDcl ::= 'production' id::Name ns::ProductionSignature body::ProductionBod -- "concrete productions" syntax nonterminal ProductionDclStmts with unparse, location, proddcls, lhsdcl, grammarName; nonterminal ProductionDclStmt with unparse, location, proddcls, lhsdcl, grammarName; +propagate lhsdcl, grammarName on ProductionDclStmts, ProductionDclStmt; synthesized attribute proddcls :: AGDcl; -autocopy attribute lhsdcl :: ProductionLHS; +inherited attribute lhsdcl :: ProductionLHS; terminal Productions_kwd 'productions' lexer classes {KEYWORD}; terminal ProdVBar '|'; @@ -23,7 +24,7 @@ concrete production productionDclC top::AGDcl ::= 'concrete' 'productions' lhs::ProductionLHS stmts::ProductionDclStmts { top.unparse = "concrete productions " ++ lhs.unparse ++ stmts.unparse; - propagate moduleNames, jarName; -- Avoid dependency on forward + propagate grammarName, moduleNames, jarName; -- Avoid dependency on forward stmts.lhsdcl = lhs; diff --git a/grammars/silver/compiler/extension/convenience/ShortLocalProdAttrDeclDef.sv b/grammars/silver/compiler/extension/convenience/ShortLocalProdAttrDeclDef.sv index 4fba93f62..e4f52b3da 100644 --- a/grammars/silver/compiler/extension/convenience/ShortLocalProdAttrDeclDef.sv +++ b/grammars/silver/compiler/extension/convenience/ShortLocalProdAttrDeclDef.sv @@ -44,3 +44,25 @@ top::ProductionStmt ::= pk::'production' ak::'attribute' location=top.location); } +concrete production shortForwardProductionDecl +top::ProductionStmt ::= fk::'forward' a::Name + eq::'=' v::Expr sm::';' +{ + forwards to + productionStmtAppend( + forwardProductionAttributeDcl(fk, 'production', 'attribute', a, sm, location=top.location), + valueEq(qNameId(a, location=a.location), eq, v, sm, location=v.location), + location=top.location); +} + +concrete production shortForwardProductionDeclwKwds +top::ProductionStmt ::= fk::'forward' pk::'production' ak::'attribute' + a::Name eq::'=' v::Expr sm::';' +{ + forwards to + productionStmtAppend( + forwardProductionAttributeDcl(fk, pk, ak, a, sm, location=top.location), + valueEq(qNameId(a, location=a.location), eq, v, sm, location=v.location), + location=top.location); +} + diff --git a/grammars/silver/compiler/extension/convenienceaspects/AbstractSyntax.sv b/grammars/silver/compiler/extension/convenienceaspects/AbstractSyntax.sv index 34ea7e785..d7c8f1800 100644 --- a/grammars/silver/compiler/extension/convenienceaspects/AbstractSyntax.sv +++ b/grammars/silver/compiler/extension/convenienceaspects/AbstractSyntax.sv @@ -227,11 +227,11 @@ Expr ::= patList::PatternList aspectLHS::Decorated ConvAspectLHS e::Expr loc::Lo - @param aspectAttr The aspect attribute we're generating productions for - @param eqKind The operator that assigns or binds to the attribute - @param location The location where the aspect pattern is defined - - @param env A decorated environment for looking up production types. + - @param env A Environment for looking up production types. - @return A pair of a single AgDcl that defines the aspect production we're generating, and a list of warnings or errors that came from generating the AgDcl. -} function extractAspectAgDclFromRuleList -Pair ::= rules::[MatchRule] aspectLHS::Decorated ConvAspectLHS aspectAttr::QNameAttrOccur eqKind::ConvenienceAspectEquationKind location::Location env::Decorated Env +Pair ::= rules::[MatchRule] aspectLHS::Decorated ConvAspectLHS aspectAttr::QNameAttrOccur eqKind::ConvenienceAspectEquationKind location::Location env::Env { local lookupProdInputTypes::([Type] ::= String) = \prodName::String -> @@ -327,7 +327,7 @@ Pair ::= rules::[MatchRule] aspectLHS::Decorated ConvAspectLHS -- Handling for production patterns let paramNames :: [Name] = makeGeneratedNamesFromMatchRule(head(rules),location) in - pair( + ( makeAspectProduction( makeParamsCaseExpr( makeBaseExprFromQNames(makeQNamesFromNames(paramNames)), @@ -343,7 +343,7 @@ Pair ::= rules::[MatchRule] aspectLHS::Decorated ConvAspectLHS -> let paramNames :: [Name] = makeGeneratedNamesFromMatchRule(head(rules),location) in - pair( + ( makeAspectProduction( makeParamsCaseExpr( makeBaseExprFromQNames(makeQNamesFromNames(paramNames)), @@ -357,7 +357,7 @@ Pair ::= rules::[MatchRule] aspectLHS::Decorated ConvAspectLHS end -- Handling for wildcard patterns | matchRule_c(patternList_one(wildcPattern(_)),_,e) :: _ -> - pair( + ( Silver_AGDcl { aspect default production $Name{aspectLHS.aspectName}::$TypeExpr{aspectLHS.aspectType} ::= @@ -371,7 +371,7 @@ Pair ::= rules::[MatchRule] aspectLHS::Decorated ConvAspectLHS }, []) | matchRule_c(patternList_more(wildcPattern(_),_,_),_,e) :: _ -> - pair( + ( Silver_AGDcl { aspect default production $Name{aspectLHS.aspectName}::$TypeExpr{aspectLHS.aspectType} ::= @@ -386,7 +386,7 @@ Pair ::= rules::[MatchRule] aspectLHS::Decorated ConvAspectLHS []) -- Handling for varpatterns | matchRule_c(patternList_one(varPattern(name)),_,e) :: _ -> - pair( + ( Silver_AGDcl { aspect default production $Name{aspectLHS.aspectName}::$TypeExpr{aspectLHS.aspectType} ::= @@ -400,7 +400,7 @@ Pair ::= rules::[MatchRule] aspectLHS::Decorated ConvAspectLHS }, []) | matchRule_c(patternList_more(varPattern(name),_,_),_,e) :: _ -> - pair( + ( Silver_AGDcl { aspect default production $Name{aspectLHS.aspectName}::$TypeExpr{aspectLHS.aspectType} ::= @@ -414,7 +414,7 @@ Pair ::= rules::[MatchRule] aspectLHS::Decorated ConvAspectLHS }, []) | _ -> - pair( + ( emptyAGDcl(location=location), [err(location,"Patterns in aspect convenience syntax should be productions,wildcards, or varpatterns only")]) end; diff --git a/grammars/silver/compiler/extension/data/DataDcl.sv b/grammars/silver/compiler/extension/data/DataDcl.sv new file mode 100644 index 000000000..21b8ed9c1 --- /dev/null +++ b/grammars/silver/compiler/extension/data/DataDcl.sv @@ -0,0 +1,84 @@ +grammar silver:compiler:extension:data; + +concrete production dataDcl +top::AGDcl ::= 'data' id::Name tl::BracketedOptTypeExprs '=' ctors::DataConstructors ';' +{ + top.unparse = s"data ${id.unparse}${tl.unparse} = ${ctors.unparse};"; + ctors.ntName = id.name; + ctors.ntTypeArgs = tl; + forwards to appendAGDcl( + nonterminalDcl( + dataNTQualifier($1, nilNTQualifier(location=top.location), location=top.location), + 'nonterminal', id, tl, nonterminalModifiersNone(location=top.location), ';', + location=top.location), + ctors.ctorDcls, + location=top.location); +} + +concrete production dataDclWith +top::AGDcl ::= 'data' id::Name tl::BracketedOptTypeExprs '=' ctors::DataConstructors 'with' attrs::QNames ';' +{ + top.unparse = s"data ${id.unparse}${tl.unparse} = ${ctors.unparse};"; + ctors.ntName = id.name; + ctors.ntTypeArgs = tl; + forwards to appendAGDcl( + nonterminalWithDcl( + dataNTQualifier($1, nilNTQualifier(location=top.location), location=top.location), + 'nonterminal', id, tl, nonterminalModifiersNone(location=top.location), 'with', attrs, ';', + location=top.location), + ctors.ctorDcls, + location=top.location); +} + +synthesized attribute ctorDcls::AGDcl; +inherited attribute ntName::String; +inherited attribute ntTypeArgs::BracketedOptTypeExprs; + +terminal DataConstructorOr_t '|' lexer classes {SPECOP}; + +nonterminal DataConstructors with location, unparse, grammarName, config, ctorDcls, ntName, ntTypeArgs; +propagate grammarName, config, ntName, ntTypeArgs on DataConstructors; + +concrete production consDataConstructor +top::DataConstructors ::= h::DataConstructor '|' t::DataConstructors +{ + top.unparse = s"${h.unparse} | ${t.unparse}"; + top.ctorDcls = appendAGDcl(h.ctorDcls, t.ctorDcls, location=top.location); +} + +concrete production oneDataConstructor +top::DataConstructors ::= h::DataConstructor +{ + top.unparse = s"${h.unparse}"; + top.ctorDcls = h.ctorDcls; +} + +concrete production nilDataConstructor +top::DataConstructors ::= +{ + top.unparse = ""; + top.ctorDcls = emptyAGDcl(location=top.location); +} + +nonterminal DataConstructor with location, unparse, grammarName, config, ctorDcls, ntName, ntTypeArgs; +propagate grammarName, config on DataConstructor; + +concrete production dataConstructor +top::DataConstructor ::= id::Name rhs::ProductionRHS +{ + top.unparse = s"${id.unparse} ${rhs.unparse}"; + + local ntBaseType::TypeExpr = nominalTypeExpr( + qNameTypeId(terminal(IdUpper_t, top.ntName, top.location), location=top.location), + location=top.location); + local ntType::TypeExpr = + case top.ntTypeArgs of + | botlNone() -> ntBaseType + | botlSome(btl) -> appTypeExpr(ntBaseType, btl, location=top.location) + end; + top.ctorDcls = Silver_AGDcl { + abstract production $Name{id} + top::$TypeExpr{ntType} ::= $ProductionRHS{rhs} + {} + }; +} diff --git a/grammars/silver/compiler/extension/data/Project.sv b/grammars/silver/compiler/extension/data/Project.sv new file mode 100644 index 000000000..37a651004 --- /dev/null +++ b/grammars/silver/compiler/extension/data/Project.sv @@ -0,0 +1,7 @@ +grammar silver:compiler:extension:data; + +imports silver:compiler:definition:core; +imports silver:compiler:definition:env; +imports silver:compiler:definition:type; +imports silver:compiler:definition:type:syntax; +imports silver:compiler:extension:convenience; diff --git a/grammars/silver/compiler/extension/deriving/Derive.sv b/grammars/silver/compiler/extension/deriving/Derive.sv new file mode 100644 index 000000000..5075a93fe --- /dev/null +++ b/grammars/silver/compiler/extension/deriving/Derive.sv @@ -0,0 +1,307 @@ +grammar silver:compiler:extension:deriving; + +import silver:compiler:extension:patternmatching only Arrow_kwd, Vbar_kwd; + +terminal Derive_t 'derive' lexer classes {KEYWORD}; + +concrete production deriveTCsOnNTListDcl_c +top::AGDcl ::= 'derive' tcs::NameList 'on' nts::NameList ';' +{ + top.unparse = s"derive ${tcs.unparse} on ${nts.unparse};"; + + forwards to deriveTCsOnNTListDcl(tcs, nts, location=top.location); +} + +production deriveTCsOnNTListDcl +top::AGDcl ::= tcs::NameList nts::NameList +{ + top.unparse = s"derive ${tcs.unparse} on ${nts.unparse};"; + + forwards to + case nts of + | nameListOne(n) -> deriveTCsOnOneNTDcl(tcs, n, location=n.location) + | nameListCons(n, _, rest) -> + appendAGDcl( + deriveTCsOnOneNTDcl(tcs, n, location=n.location), + deriveTCsOnNTListDcl(tcs, rest, location=top.location), + location=top.location) + end; +} + +production deriveTCsOnOneNTDcl +top::AGDcl ::= tcs::NameList nt::QName +{ + top.unparse = s"derive ${tcs.unparse} on ${nt.unparse};"; + + forwards to + case tcs of + | nameListOne(tc) -> deriveDcl(tc, nt, location=top.location) + | nameListCons(tc, _, rest) -> + appendAGDcl( + deriveDcl(tc, nt, location=top.location), + deriveTCsOnOneNTDcl(rest, nt, location=top.location), + location=top.location) + end; +} + +production deriveDcl +top::AGDcl ::= tc::QName nt::QName +{ + top.unparse = s"derive ${tc.unparse} on ${nt.unparse};"; + top.moduleNames := []; + propagate env; + + local localErrors::[Message] = + tc.lookupType.errors ++ nt.lookupType.errors ++ + (if tc.lookupType.found && !tc.lookupType.dcl.isClass + then [err(tc.location, s"${tc.lookupType.fullName} is not a type class")] + else []) ++ + (if nt.lookupType.found && !(nt.lookupType.dcl.isType && nt.lookupType.typeScheme.isNonterminal) + then [err(nt.location, s"${nt.lookupType.fullName} is not a nonterminal")] + else []) ++ + (if nt.lookupType.found && nt.lookupType.dcl.isClosed + then [err(nt.location, s"Cannot derive instances for ${nt.lookupType.fullName}, since that nonterminal is closed")] + else []); + top.errors := if null(localErrors) then forward.errors else localErrors; + + forwards to + -- TODO: Yuck, can't forward based on env here since we need the defs from the forward. + case if startsWith("silver:core:", tc.name) then tc.name else "silver:core:" ++ tc.name of -- tc.lookupType.fullName + | "silver:core:Eq" -> deriveEqDcl(nt, location=top.location) + | "silver:core:Ord" -> deriveOrdDcl(nt, location=top.location) + | fn -> errorAGDcl([err(tc.location, s"Cannot derive type class ${fn}")], location=top.location) + end; +} + +production deriveEqDcl +top::AGDcl ::= nt::Decorated! QName +{ + undecorates to deriveDcl(qName(top.location, "silver:core:Eq"), nt, location=top.location); + top.unparse = s"derive silver:core:Eq on ${nt.unparse};"; + top.moduleNames := []; + + local tvs::[TyVar] = map(freshTyVar, nt.lookupType.dcl.kindrep.argKinds); + local ntty::Type = appTypes(nt.lookupType.typeScheme.monoType, map(skolemType, tvs)); + + local includedProds::[ValueDclInfo] = + filter( + \ d::ValueDclInfo -> !d.hasForward, + getKnownProds(nt.lookupType.fullName, top.env)); + forwards to Silver_AGDcl { + instance $ConstraintList{ + foldr( + consConstraint(_, ',', _, location=top.location), + nilConstraint(location=top.location), + filterMap( + \ tv::TyVar -> + if tv.kindrep == starKind() + then just( + classConstraint( + qName(top.location, "silver:core:Eq").qNameType, + typerepTypeExpr(skolemType(tv), location=top.location), + location=top.location)) + else nothing(), + tvs))} => silver:core:Eq $TypeExpr{typerepTypeExpr(ntty, location=top.location)} { + eq = \ x::$TypeExpr{typerepTypeExpr(ntty, location=top.location)} y::$TypeExpr{typerepTypeExpr(ntty, location=top.location)} -> $Expr{ + if null(includedProds) then Silver_Expr {true} else + foldr( + and(_, '&&', _, location=top.location), + matchPrimitive( + Silver_Expr {x}, + Silver_TypeExpr {Boolean}, + foldPrimPatterns( + map( + \ prod::ValueDclInfo -> + prodPattern(qName(top.location, prod.fullName), '(', + foldr( + consVarBinder(_, ',', _, location=top.location), + nilVarBinder(location=top.location), + map(\ i::Integer -> + varVarBinder(name(s"a${toString(i)}", top.location), location=top.location), + range(0, length(prod.namedSignature.inputElements)))), ')', '->', + matchPrimitive( + Silver_Expr {y}, + Silver_TypeExpr {Boolean}, + onePattern( + prodPattern(qName(top.location, prod.fullName), '(', + foldr( + consVarBinder(_, ',', _, location=top.location), + nilVarBinder(location=top.location), + map(\ i::Integer -> + varVarBinder(name(s"b${toString(i)}", top.location), location=top.location), + range(0, length(prod.namedSignature.inputElements)))), ')', '->', + foldr( + and(_, '&&', _, location=top.location), + Silver_Expr {true}, + map( + \ i::Integer -> Silver_Expr { $name{s"a${toString(i)}"} == $name{s"b${toString(i)}"} }, + range(0, length(prod.namedSignature.inputElements)))), + location=top.location), + location=top.location), + Silver_Expr {false}, + location=top.location), + location=top.location), + includedProds), + top.location), + Silver_Expr {silver:core:error("Unexpected production in derived Eq instance!")}, + location=top.location), + map( + \ anno::NamedSignatureElement -> + Silver_Expr { x.$name{anno.elementName} == y.$name{anno.elementName} }, + annotationsForNonterminal(ntty, top.env)))}; + neq = \ x::$TypeExpr{typerepTypeExpr(ntty, location=top.location)} y::$TypeExpr{typerepTypeExpr(ntty, location=top.location)} -> $Expr{ + if null(includedProds) then Silver_Expr {false} else + foldr( + or(_, '||', _, location=top.location), + matchPrimitive( + Silver_Expr {x}, + Silver_TypeExpr {Boolean}, + foldPrimPatterns( + map( + \ prod::ValueDclInfo -> + prodPattern(qName(top.location, prod.fullName), '(', + foldr( + consVarBinder(_, ',', _, location=top.location), + nilVarBinder(location=top.location), + map(\ i::Integer -> + varVarBinder(name(s"a${toString(i)}", top.location), location=top.location), + range(0, length(prod.namedSignature.inputElements)))), ')', '->', + matchPrimitive( + Silver_Expr {y}, + Silver_TypeExpr {Boolean}, + onePattern( + prodPattern(qName(top.location, prod.fullName), '(', + foldr( + consVarBinder(_, ',', _, location=top.location), + nilVarBinder(location=top.location), + map(\ i::Integer -> + varVarBinder(name(s"b${toString(i)}", top.location), location=top.location), + range(0, length(prod.namedSignature.inputElements)))), ')', '->', + foldr( + or(_, '||', _, location=top.location), + Silver_Expr {false}, + map( + \ i::Integer -> Silver_Expr { $name{s"a${toString(i)}"} != $name{s"b${toString(i)}"} }, + range(0, length(prod.namedSignature.inputElements)))), + location=top.location), + location=top.location), + Silver_Expr {true}, + location=top.location), + location=top.location), + includedProds), + top.location), + Silver_Expr {silver:core:error("Unexpected production in derived Eq instance!")}, + location=top.location), + map( + \ anno::NamedSignatureElement -> + Silver_Expr { x.$name{anno.elementName} != y.$name{anno.elementName} }, + annotationsForNonterminal(ntty, top.env)))}; + } + }; +} + +production deriveOrdDcl +top::AGDcl ::= nt::Decorated! QName +{ + undecorates to deriveDcl(qName(top.location, "silver:core:Ord"), nt, location=top.location); + top.unparse = s"derive silver:core:Ord on ${nt.unparse};"; + top.moduleNames := []; + + local tvs::[TyVar] = map(freshTyVar, nt.lookupType.dcl.kindrep.argKinds); + local ntty::Type = appTypes(nt.lookupType.typeScheme.monoType, map(skolemType, tvs)); + + local includedProds::[ValueDclInfo] = + filter( + \ d::ValueDclInfo -> !d.hasForward, + getKnownProds(nt.lookupType.fullName, top.env)); + + forwards to Silver_AGDcl { + instance $ConstraintList{ + foldr( + consConstraint(_, ',', _, location=top.location), + nilConstraint(location=top.location), + filterMap( + \ tv::TyVar -> + if tv.kindrep == starKind() + then just( + classConstraint( + qName(top.location, "silver:core:Ord").qNameType, + typerepTypeExpr(skolemType(tv), location=top.location), + location=top.location)) + else nothing(), + tvs))} => silver:core:Ord $TypeExpr{typerepTypeExpr(ntty, location=top.location)} { + compare = \ x::$TypeExpr{typerepTypeExpr(ntty, location=top.location)} y::$TypeExpr{typerepTypeExpr(ntty, location=top.location)} -> $Expr{ + if null(includedProds) then Silver_Expr { 0 } else + foldr( + \ e1::Expr e2::Expr -> + Silver_Expr { let res::Integer = $Expr{e1} in if res == 0 then $Expr{e2} else res end }, + matchPrimitive( + Silver_Expr {x}, + Silver_TypeExpr {Integer}, + foldPrimPatterns( + map( + \ prod::ValueDclInfo -> + prodPattern(qName(top.location, prod.fullName), '(', + foldr( + consVarBinder(_, ',', _, location=top.location), + nilVarBinder(location=top.location), + map(\ i::Integer -> + varVarBinder(name(s"a${toString(i)}", top.location), location=top.location), + range(0, length(prod.namedSignature.inputElements)))), ')', '->', + matchPrimitive( + Silver_Expr {y}, + Silver_TypeExpr {Integer}, + foldPrimPatterns( + map( + \ prod2::ValueDclInfo -> + prodPattern( + qName(top.location, prod2.fullName), '(', + foldr( + consVarBinder(_, ',', _, location=top.location), + nilVarBinder(location=top.location), + map( + \ i::Integer -> + if prod.fullName == prod2.fullName + then varVarBinder(name(s"b${toString(i)}", top.location), location=top.location) + else ignoreVarBinder('_', location=top.location), + range(0, length(prod2.namedSignature.inputElements)))), ')', '->', + if prod.fullName < prod2.fullName + then Silver_Expr { -1 } + else if prod.fullName > prod2.fullName + then Silver_Expr { 1 } + else if null(prod2.namedSignature.inputElements) + then Silver_Expr { 0 } + else foldr1( + \ e1::Expr e2::Expr -> + Silver_Expr { let res::Integer = $Expr{e1} in if res == 0 then $Expr{e2} else res end }, + map( + \ i::Integer -> Silver_Expr { silver:core:compare($name{s"a${toString(i)}"}, $name{s"b${toString(i)}"}) }, + range(0, length(prod2.namedSignature.inputElements)))), + location=top.location), + includedProds), + top.location), + Silver_Expr {silver:core:error("Unexpected production in derived Ord instance!")}, + location=top.location), + location=top.location), + includedProds), + top.location), + Silver_Expr {silver:core:error("Unexpected production in derived Ord instance!")}, + location=top.location), + map( + \ anno::NamedSignatureElement -> + Silver_Expr { silver:core:compare(x.$name{anno.elementName}, y.$name{anno.elementName}) }, + annotationsForNonterminal(ntty, top.env)))}; + } + }; +} + +function foldPrimPatterns +PrimPatterns ::= ps::[PrimPattern] loc::Location +{ + return + case ps of + | [h] -> onePattern(h, location=loc) + | h :: t -> consPattern(h, '|', foldPrimPatterns(t, loc), location=loc) + | [] -> error("empty patterns") + end; +} diff --git a/grammars/silver/compiler/extension/deriving/Project.sv b/grammars/silver/compiler/extension/deriving/Project.sv new file mode 100644 index 000000000..7f7b35ddb --- /dev/null +++ b/grammars/silver/compiler/extension/deriving/Project.sv @@ -0,0 +1,11 @@ +grammar silver:compiler:extension:deriving; + +imports silver:compiler:definition:core; +imports silver:compiler:definition:env; +imports silver:compiler:definition:type; +imports silver:compiler:definition:type:syntax; +imports silver:compiler:modification:collection; +imports silver:compiler:modification:lambda_fn; +imports silver:compiler:modification:let_fix; +imports silver:compiler:modification:primitivepattern; +imports silver:compiler:metatranslation; diff --git a/grammars/silver/compiler/extension/do_notation/Syntax.sv b/grammars/silver/compiler/extension/do_notation/Syntax.sv index ecf8f0449..1f9ef45c7 100644 --- a/grammars/silver/compiler/extension/do_notation/Syntax.sv +++ b/grammars/silver/compiler/extension/do_notation/Syntax.sv @@ -4,6 +4,7 @@ concrete production do_c top::Expr ::= 'do' '{' body::DoBody '}' { top.unparse = s"do {${body.unparse}}"; + propagate frame; forwards to body.transform; } @@ -40,6 +41,7 @@ concrete production mdo_c top::Expr ::= 'mdo' '{' body::DoBody '}' { top.unparse = s"mdo {${body.unparse}}"; + propagate frame; body.boundVarEnv = mempty; body.allBoundVars = body.boundVars; @@ -96,7 +98,7 @@ nonterminal DoBinding with transform, transformIn, recBindings; -propagate boundVars on DoBody, DoBinding; +propagate frame, boundVars on DoBody, DoBinding; propagate freeVars on DoBinding; concrete production consDoBody @@ -147,7 +149,7 @@ top::DoBody ::= b::DoBinding rest::DoBody then finalReturnDoBody('return', foldr1( - \ e1::Expr e2::Expr -> Silver_Expr { silver:core:pair($Expr{e1}, $Expr{e2}) }, + \ e1::Expr e2::Expr -> Silver_Expr { silver:core:pair(fst=$Expr{e1}, snd=$Expr{e2}) }, map(\ item::(String, TypeExpr) -> Silver_Expr { $name{item.1} }, top.recBindings)), ';', location=top.location) else top.recRes; @@ -172,7 +174,7 @@ top::DoBody ::= b::DoBinding rest::DoBody \ i::Integer item::(String, TypeExpr) -> letDoBinding( 'let', name(item.1, top.location), '::', item.2, '=', - select(Silver_Expr { $name{recVarName} }, 1, i + 1, length(top.recBindings)), ';', + select(Silver_Expr { $name{recVarName} }, 1, i + 1, length(top.recBindings), location=top.location), ';', location=top.location), range(0, length(top.recBindings)), top.recBindings)); diff --git a/grammars/silver/compiler/extension/doc/core/AGDcl.sv b/grammars/silver/compiler/extension/doc/core/AGDcl.sv index 31863ea4e..af9ed6a97 100644 --- a/grammars/silver/compiler/extension/doc/core/AGDcl.sv +++ b/grammars/silver/compiler/extension/doc/core/AGDcl.sv @@ -19,7 +19,7 @@ top::AGDcl ::= 'function' id::Name ns::FunctionSignature body::ProductionBody { top.docForName = id.name; top.docUnparse = "`function " ++ id.name ++ "`   (`" ++ ns.unparse ++ "`)"; - top.docDcls := [pair(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -37,7 +37,7 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr { top.docForName = id.name; top.docUnparse = "`abstract production " ++ id.name ++ "`   (`" ++ ns.unparse ++ "`)"; - top.docDcls := [pair(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -46,7 +46,7 @@ top::AGDcl ::= 'concrete' 'production' id::Name ns::ProductionSignature pm::Prod { top.docForName = id.name; top.docUnparse = "`concrete production " ++ id.name ++ "`   (`" ++ ns.unparse ++ "`)"; - top.docDcls := [pair(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -55,7 +55,7 @@ top::AGDcl ::= 'synthesized' 'attribute' a::Name tl::BracketedOptTypeExprs '::' { top.docForName = a.name; top.docUnparse = s"`synthesized attribute ${a.name}${tl.unparse} :: ${te.unparse}`"; - top.docDcls := [pair(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -64,7 +64,16 @@ top::AGDcl ::= 'inherited' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te { top.docForName = a.name; top.docUnparse = s"`inherited attribute ${a.name}${tl.unparse} :: ${te.unparse}`"; - top.docDcls := [pair(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docs := [mkUndocumentedItem(top.docForName, top)]; +} + +aspect production attributeDclTrans +top::AGDcl ::= 'translation' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr ';' +{ + top.docForName = a.name; + top.docUnparse = s"`translation attribute ${a.name}${tl.unparse} :: ${te.unparse}`"; + top.docDcls := [(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -72,8 +81,8 @@ aspect production nonterminalDcl top::AGDcl ::= quals::NTDeclQualifiers 'nonterminal' id::Name tl::BracketedOptTypeExprs nm::NonterminalModifiers ';' { top.docForName = id.name; - top.docUnparse = s"`nonterminal ${id.name}${tl.unparse}`"; - top.docDcls := [pair(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docUnparse = s"`${quals.docUnparse}nonterminal ${id.name}${tl.unparse}`"; + top.docDcls := [(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -91,7 +100,7 @@ top::AGDcl ::= t::TerminalKeywordModifier id::Name r::RegExpr tm::TerminalModifi { top.docForName = id.name; top.docUnparse = s"`terminal ${id.unparse}`"; - top.docDcls := [pair(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -100,7 +109,7 @@ top::AGDcl ::= 'lexer' 'class' id::Name modifiers::LexerClassModifiers ';' { top.docForName = id.name; top.docUnparse = s"`lexer class ${id.unparse} ${modifiers.unparse}`"; - top.docDcls := [pair(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -109,7 +118,7 @@ top::AGDcl ::= 'parser' n::Name '::' t::TypeExpr '{' m::ParserComponents '}' { top.docForName = n.name; top.docUnparse = s"`parser ${n.unparse} :: ${t.unparse}`"; - top.docDcls := [pair(n.name, docDclInfo(n.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(n.name, docDclInfo(n.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -118,7 +127,7 @@ top::AGDcl ::= 'annotation' a::QName tl::BracketedOptTypeExprs '::' te::TypeExpr { top.docForName = a.name; top.docUnparse = s"`annotation ${a.unparse}${tl.unparse} :: ${te.unparse}`"; - top.docDcls := [pair(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -127,7 +136,7 @@ top::AGDcl ::= 'equality' 'attribute' syn::Name 'with' inh::QName ';' { top.docForName = syn.name; top.docUnparse = s"`equality attribute ${syn.name} with ${inh.name}`"; - top.docDcls := [pair(syn.name, docDclInfo(syn.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(syn.name, docDclInfo(syn.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -136,8 +145,8 @@ top::AGDcl ::= 'ordering' 'attribute' keySyn::Name ',' syn::Name 'with' inh::QNa { top.docForName = keySyn.name++" and "++syn.name++" (ordering pair)"; top.docUnparse = s"`ordering attribute ${keySyn.name}, ${syn.name} with ${inh.name}`"; - top.docDcls := [pair(keySyn.name, docDclInfo(keySyn.name, sourceLocation=top.location, sourceGrammar=top.grammarName)), - pair(syn.name, docDclInfo(syn.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(keySyn.name, docDclInfo(keySyn.name, sourceLocation=top.location, sourceGrammar=top.grammarName)), + (syn.name, docDclInfo(syn.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -146,7 +155,7 @@ top::AGDcl ::= 'monoid' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::T { top.docForName = a.name; top.docUnparse = s"`monoid attribute ${a.unparse}${tl.unparse} :: ${te.unparse}`"; - top.docDcls := [pair(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -155,8 +164,8 @@ top::AGDcl ::= 'threaded' 'attribute' inh::Name ',' syn::Name tl::BracketedOptTy { top.docForName = inh.name++" and "++syn.name++" (threaded pair)"; top.docUnparse = s"`threaded attribute ${inh.name}, ${syn.name}${tl.unparse} :: ${te.unparse} direction=${if d.reversed then "right to left" else "left to right"}`"; - top.docDcls := [pair(inh.name, docDclInfo(inh.name, sourceLocation=top.location, sourceGrammar=top.grammarName)), - pair(syn.name, docDclInfo(syn.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(inh.name, docDclInfo(inh.name, sourceLocation=top.location, sourceGrammar=top.grammarName)), + (syn.name, docDclInfo(syn.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -165,7 +174,7 @@ top::AGDcl ::= 'functor' 'attribute' a::Name ';' { top.docForName = a.name; top.docUnparse = s"`monoid attribute ${a.unparse}`"; - top.docDcls := [pair(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -175,9 +184,9 @@ top::AGDcl ::= 'functor' 'attribute' a::Name ';' -- { -- top.docForName = inh.name++" and "++synPartial.name++" and "++syn.name++" (unification set)"; -- top.docUnparse = s"`unification attribute ${inh.name}, ${syn.name}, ${syn.name}`"; --- top.docDcls := [pair(inh.name, docDclInfo(inh.name, sourceLocation=top.location, sourceGrammar=top.grammarName)), --- pair(syn.name, docDclInfo(syn.name, sourceLocation=top.location, sourceGrammar=top.grammarName)), --- pair(synPartial.name, docDclInfo(synPartial.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; +-- top.docDcls := [(inh.name, docDclInfo(inh.name, sourceLocation=top.location, sourceGrammar=top.grammarName)), +-- (syn.name, docDclInfo(syn.name, sourceLocation=top.location, sourceGrammar=top.grammarName)), +-- (synPartial.name, docDclInfo(synPartial.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; -- top.docs := [mkUndocumentedItem(top.docForName, top)]; -- } @@ -195,13 +204,13 @@ top::AGDcl ::= 'type' id::Name tl::BracketedOptTypeExprs 'foreign' '=' trans::St { top.docForName = id.name; top.docUnparse = s"`ffi type ${id.unparse}`"; - top.docDcls := [pair(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } aspect production defaultAttributionDcl -top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs +top::AGDcl ::= at::Decorated! QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs { top.docForName = ""; top.docUnparse = ""; @@ -246,7 +255,7 @@ top::AGDcl ::= 'parser' 'attribute' a::Name '::' te::TypeExpr 'action' acode::Ac { top.docForName = a.name; top.docUnparse = s"`parser attribute ${a.unparse}`"; - top.docDcls := [pair(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -292,7 +301,7 @@ top::AGDcl ::= n::Name } aspect production errorAttributionDcl -top::AGDcl ::= msg::[Message] at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs +top::AGDcl ::= msg::[Message] at::Decorated! QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs { top.docForName = ""; top.docUnparse = ""; @@ -304,7 +313,7 @@ top::AGDcl ::= 'global' id::Name '::' cl::ConstraintList '=>' t::TypeExpr '=' e: { top.docForName = id.name; top.docUnparse = s"`global ${id.unparse}`"; - top.docDcls := [pair(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -313,7 +322,7 @@ top::AGDcl ::= 'type' id::Name tl::BracketedOptTypeExprs '=' te::TypeExpr ';' { top.docForName = id.name; top.docUnparse = s"`type ${id.unparse}`"; - top.docDcls := [pair(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -322,7 +331,7 @@ top::AGDcl ::= 'synthesized' 'attribute' a::Name tl::BracketedOptTypeExprs '::' { top.docForName = a.name; top.docUnparse = s"`synthesized attribute ${a.unparse} (collection)`"; - top.docDcls := [pair(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -331,7 +340,7 @@ top::AGDcl ::= 'inherited' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te { top.docForName = a.name; top.docUnparse = s"`synthesized attribute ${a.unparse} (collection)`"; - top.docDcls := [pair(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; + top.docDcls := [(a.name, docDclInfo(a.name, sourceLocation=top.location, sourceGrammar=top.grammarName))]; top.docs := [mkUndocumentedItem(top.docForName, top)]; } @@ -342,3 +351,11 @@ top::AGDcl ::= 'copper_mda' testname::Name '(' orig::QName ')' '{' m::ParserComp top.docUnparse = ""; top.docs := []; } + +attribute docUnparse occurs on NTDeclQualifiers; +aspect docUnparse on NTDeclQualifiers of +| closedNTQualifier(_, rest) -> "closed " ++ rest.docUnparse +| dataNTQualifier(_, rest) -> "data " ++ rest.docUnparse +| trackedNTQualifier(_, rest) -> rest.docUnparse +| nilNTQualifier() -> "" +end; \ No newline at end of file diff --git a/grammars/silver/compiler/extension/doc/core/DataDcl.sv b/grammars/silver/compiler/extension/doc/core/DataDcl.sv new file mode 100644 index 000000000..3d83fad3e --- /dev/null +++ b/grammars/silver/compiler/extension/doc/core/DataDcl.sv @@ -0,0 +1,86 @@ +grammar silver:compiler:extension:doc:core; + +imports silver:compiler:extension:data; + +attribute docUnparse, docForName occurs on DataConstructor; + +propagate upDocConfig, downDocConfig, docDcls, docs on DataConstructors; + +aspect production dataDcl +top::AGDcl ::= 'data' id::Name tl::BracketedOptTypeExprs '=' ctors::DataConstructors ';' +{ + propagate grammarName, config, docEnv; + top.docForName = id.name; + top.docUnparse = s"`data nonterminal ${id.unparse}`"; + top.docDcls := (id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName)) :: ctors.docDcls; + top.docs := mkUndocumentedItem(top.docForName, top) :: ctors.docs; + ctors.downDocConfig = top.downDocConfig; +} + +aspect production dataDclWith +top::AGDcl ::= 'data' id::Name tl::BracketedOptTypeExprs '=' ctors::DataConstructors 'with' attrs::QNames ';' +{ + propagate grammarName, config, docEnv; + top.docForName = id.name; + top.docUnparse = s"`data nonterminal ${id.unparse}`"; + top.docDcls := (id.name, docDclInfo(id.name, sourceLocation=top.location, sourceGrammar=top.grammarName)) :: ctors.docDcls; + top.docs := mkUndocumentedItem(top.docForName, top) :: ctors.docs; + ctors.downDocConfig = top.downDocConfig; +} + +concrete production documentedConsDataConstructor +top::DataConstructors ::= h::DataConstructor comment::DocComment_t '|' t::DataConstructors +{ + forwards to + case t of + | consDataConstructor(h1, _, t1) -> + consDataConstructor( + h, '|', + consDataConstructor(documentedConstructor(comment, h1, location=h1.location), '|', t1, location=t.location), + location=top.location) + | oneDataConstructor(h1) -> + consDataConstructor( + h, '|', + oneDataConstructor(documentedConstructor(comment, h1, location=h1.location), location=t.location), + location=top.location) + | nilDataConstructor() -> consDataConstructor(h, '|', t, location=top.location) + end; +} + +concrete production documentedConstructor +top::DataConstructor ::= comment::DocComment_t item::DataConstructor +{ + local parsed::DclComment = parseComment(top.config, comment); + + parsed.paramNames = nothing(); + parsed.isForWhat = "abstract production"; + parsed.downDocConfig = top.downDocConfig; + parsed.docEnv = top.docEnv; + parsed.offsetLocation = comment.location; + parsed.indentBy = ">"; + + top.upDocConfig <- parsed.upDocConfig; + top.docErrors <- parsed.errors; + + local realDclDocs::[CommentItem] = filter((\x::CommentItem->!x.stub), forward.docs); + local isDoubleComment::Boolean = length(realDclDocs) != 0; + top.docs := if isDoubleComment + then [standaloneDclCommentItem(parsed)] ++ realDclDocs + else [dclCommentItem(top.docForName, forward.docUnparse, forward.grammarName, item.location, parsed)]; + top.docErrors <- + if isDoubleComment + then [wrn(parsed.location, "Doc comment not immediately preceding constructor, so association is ambiguous. Treating as standalone comment. Mark with @@{- instead of @{- to silence this warning.")] + else []; + + forwards to item; +} + +aspect production dataConstructor +top::DataConstructor ::= id::Name rhs::ProductionRHS +{ + top.docForName = id.name; + top.docUnparse = "`abstract production " ++ id.name ++ "`   (`" ++ top.ntName ++ top.ntTypeArgs.unparse ++ " ::= " ++ rhs.unparse ++ "`)"; + top.docDcls := []; + top.docs := [undocumentedItem(top.docForName, top.docUnparse, top.grammarName, top.location)]; + top.upDocConfig := []; +} \ No newline at end of file diff --git a/grammars/silver/compiler/extension/doc/core/DocumentedAGDcl.sv b/grammars/silver/compiler/extension/doc/core/DocumentedAGDcl.sv index 14c555730..ddab5fb3f 100644 --- a/grammars/silver/compiler/extension/doc/core/DocumentedAGDcl.sv +++ b/grammars/silver/compiler/extension/doc/core/DocumentedAGDcl.sv @@ -53,15 +53,15 @@ top::AGDcl ::= comment::DocComment_t dcl::AGDcl { local parsed::DclComment = parseComment(top.config, comment); - local paramNamesAndForWhat::Pair String> = case getFirstAGDcl(dcl) of - | functionDcl(_, _, ns, _) -> pair(just(ns.argNames), "function") - | aspectFunctionDcl(_, _, _, ns, _) -> pair(just(ns.argNames), "function") - | productionDcl(_, _, _, ns, _) -> pair(just(ns.argNames), "production") - | aspectProductionDcl(_, _, _, ns, _) -> pair(just(ns.argNames), "production") - | nonterminalDcl(_, _, _, tl, _, _) -> pair(just(getFreeTypeNames(tl.freeVariables)), "nonterminal") - | attributeDclInh(_, _, _, tl, _, _, _) -> pair(just(getFreeTypeNames(tl.freeVariables)), "attribute") - | attributeDclSyn(_, _, _, tl, _, _, _) -> pair(just(getFreeTypeNames(tl.freeVariables)), "attribute") - | _ -> pair(just([]), if isDoubleComment then "standalone" else "other") + local paramNamesAndForWhat::Pair String> = case getFirstAGDcl(forward) of + | functionDcl(_, _, ns, _) -> (just(ns.argNames), "function") + | aspectFunctionDcl(_, _, _, ns, _) -> (just(ns.argNames), "function") + | productionDcl(_, _, _, ns, _) -> (just(ns.argNames), "production") + | aspectProductionDcl(_, _, _, ns, _) -> (just(ns.argNames), "production") + | nonterminalDcl(_, _, _, tl, _, _) -> (just(getFreeTypeNames(tl.freeVariables)), "nonterminal") + | attributeDclInh(_, _, _, tl, _, _, _) -> (just(getFreeTypeNames(tl.freeVariables)), "attribute") + | attributeDclSyn(_, _, _, tl, _, _, _) -> (just(getFreeTypeNames(tl.freeVariables)), "attribute") + | _ -> (just([]), if isDoubleComment then "standalone" else "other") end; parsed.paramNames = paramNamesAndForWhat.fst; @@ -70,17 +70,15 @@ top::AGDcl ::= comment::DocComment_t dcl::AGDcl parsed.docEnv = top.docEnv; parsed.offsetLocation = comment.location; parsed.indentBy = ""; - - dcl.downDocConfig = top.downDocConfig; - top.upDocConfig <- parsed.upDocConfig ++ dcl.upDocConfig; + top.upDocConfig <- parsed.upDocConfig; top.docErrors <- parsed.errors; - local isDoubleComment::Boolean = case dcl of documentedAGDcl(_, _) -> true | _ -> false end; + local isDoubleComment::Boolean = case forward of documentedAGDcl(_, _) -> true | _ -> false end; top.docs := if isDoubleComment - then [standaloneDclCommentItem(parsed)] ++ dcl.docs - else [dclCommentItem(dcl.docForName, dcl.docUnparse, dcl.grammarName, dcl.location, parsed)] - ++ if length(dcl.docs) > 1 then tail(dcl.docs) else []; + then [standaloneDclCommentItem(parsed)] ++ forward.docs + else [dclCommentItem(forward.docForName, forward.docUnparse, forward.grammarName, dcl.location, parsed)] + ++ if length(forward.docs) > 1 then tail(forward.docs) else []; top.errors <- if isDoubleComment then [wrn(parsed.location, "Doc comment not immediately preceding AGDcl, so association is ambiguous. Treating as standalone comment. Mark with @@{- instead of @{- to silence this warning.")] else []; diff --git a/grammars/silver/compiler/extension/doc/core/Project.sv b/grammars/silver/compiler/extension/doc/core/Project.sv index 1918ca336..4b4353414 100644 --- a/grammars/silver/compiler/extension/doc/core/Project.sv +++ b/grammars/silver/compiler/extension/doc/core/Project.sv @@ -6,6 +6,6 @@ imports silver:compiler:definition:type:syntax; imports silver:compiler:definition:env; imports silver:compiler:definition:type; -imports silver:compiler:extension:convenience; +imports silver:compiler:extension:convenience hiding ProdVBar; imports silver:util:treemap as tm; diff --git a/grammars/silver/compiler/extension/doc/core/Root.sv b/grammars/silver/compiler/extension/doc/core/Root.sv index 3328e634e..d72828293 100644 --- a/grammars/silver/compiler/extension/doc/core/Root.sv +++ b/grammars/silver/compiler/extension/doc/core/Root.sv @@ -8,8 +8,7 @@ synthesized attribute genFiles :: [Pair] with ++; - Used for getting doc comments on AGDcls to emit. - Note that not every item really should be emitted, see doEmit. -} -synthesized attribute docs :: [CommentItem] with ++; -attribute docs occurs on Grammar, Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody; +monoid attribute docs :: [CommentItem] occurs on Grammar, Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody, DataConstructors, DataConstructor; @@{- - Doc config is managed in both a per-file, and per-grammar way. Directives are either file-scope @@ -21,10 +20,10 @@ attribute docs occurs on Grammar, Root, AGDcls, AGDcl, ClassBodyItem, InstanceBo - in @link[downDocConfig] (and stored on the `Root` as @link[localDocConfig].) -} @{- Final doc config flowing back down, inside files (Roots) will include file scoped settings first. -} -inherited attribute downDocConfig :: [DocConfigSetting] occurs on Grammar, Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody; +inherited attribute downDocConfig :: [DocConfigSetting] occurs on Grammar, Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody, DataConstructors, DataConstructor; @{- Doc config information flowing up. File scoped settings are stripped at the Root level. -} -synthesized attribute upDocConfig :: [DocConfigSetting] with ++ occurs on Grammar, Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody; +monoid attribute upDocConfig :: [DocConfigSetting] occurs on Grammar, Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody, DataConstructors, DataConstructor; @{- Snapshot of @link[downDocConfig] stored on `Root`. -} synthesized attribute localDocConfig :: [DocConfigSetting] occurs on Root; @@ -36,17 +35,22 @@ synthesized attribute documentedNamed :: [String] occurs on Root, Grammar; - Declarations of documented AGDcls, flowing up. Used for linking and counting documented items. - Flows back down as @link[docEnv]. -} -synthesized attribute docDcls :: [Pair] with ++; -attribute docDcls occurs on Grammar, Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody; +monoid attribute docDcls :: [Pair] occurs on Grammar, Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody, DataConstructors, DataConstructor; @{- Environment of all documented AGDcls, flowing back down after being computed from @link[docDcls]. -} -autocopy attribute docEnv :: tm:Map; -attribute docEnv occurs on Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody; +inherited attribute docEnv :: tm:Map; +attribute docEnv occurs on Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody, DataConstructors, DataConstructor; +propagate docEnv on AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody, DataConstructors, DataConstructor; @{- Errors arising from ill-formed doc comments. -} monoid attribute docErrors :: [Message]; -attribute docErrors occurs on Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody; -propagate docErrors on Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody; +attribute docErrors occurs on Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody, DataConstructors, DataConstructor; +propagate docErrors on Root, AGDcls, AGDcl, ClassBodyItem, InstanceBodyItem, ClassBody, InstanceBody, DataConstructors, DataConstructor; + +@{- + - All file names in a grammar, paired with their documentation-related error messages. + -} +synthesized attribute allFileDocErrors::[(String, [Message])] occurs on Grammar; aspect production root top::Root ::= gdcl::GrammarDcl ms::ModuleStmts ims::ImportStmts ags::AGDcls @@ -60,7 +64,6 @@ top::Root ::= gdcl::GrammarDcl ms::ModuleStmts ims::ImportStmts ags::AGDcls ags.downDocConfig = filter((\x::DocConfigSetting -> x.fileScope), ags.upDocConfig) ++ top.downDocConfig; ags.docEnv = tm:add(flatMap((.docDcls), searchEnvTree(top.grammarName, top.compiledGrammars)), tm:empty()); - top.errors <- ags.docErrors; } aspect production nilAGDcls @@ -108,6 +111,7 @@ top::Grammar ::= top.docDcls := []; top.undocumentedNamed = []; top.documentedNamed = []; + top.allFileDocErrors = []; } aspect production consGrammar @@ -120,6 +124,7 @@ top::Grammar ::= c1::Root c2::Grammar top.docDcls := c1.docDcls ++ c2.docDcls; top.undocumentedNamed = c1.undocumentedNamed ++ c2.undocumentedNamed; top.documentedNamed = c1.documentedNamed ++ c2.documentedNamed; + top.allFileDocErrors = (c1.location.filename, c1.docErrors) :: c2.allFileDocErrors; } -- consGrammar(FILE1, consGrammar(FILE2, nilGrammar())) diff --git a/grammars/silver/compiler/extension/doc/core/RootSpec.sv b/grammars/silver/compiler/extension/doc/core/RootSpec.sv index 9090da3b4..fe28883a6 100644 --- a/grammars/silver/compiler/extension/doc/core/RootSpec.sv +++ b/grammars/silver/compiler/extension/doc/core/RootSpec.sv @@ -24,6 +24,7 @@ top::RootSpec ::= g::Grammar _ _ _ _ _ { top.genFiles := toSplitFiles(g, g.upDocConfig, [], []); top.docDcls := g.docDcls; + extraFileErrors <- g.allFileDocErrors; g.downDocConfig = g.upDocConfig; } @@ -68,7 +69,7 @@ function formatFile local realDocs::[CommentItem] = filter((.doEmit), comments); local stubDocs::[CommentItem] = filter((.stub), realDocs); local nonStubDocs::[CommentItem] = filter((\x::CommentItem->!x.stub), realDocs); - return if length(realDocs) == 0 && skipIfEmpty then [] else [pair(fileName, s"""--- + return if length(realDocs) == 0 && skipIfEmpty then [] else [(fileName, s"""--- title: "${title}" weight: ${toString(weight)} geekdocBreadcrumb: false diff --git a/grammars/silver/compiler/extension/doc/core/TypeClassDcls.sv b/grammars/silver/compiler/extension/doc/core/TypeClassDcls.sv index 34a5c8798..8ac29a559 100644 --- a/grammars/silver/compiler/extension/doc/core/TypeClassDcls.sv +++ b/grammars/silver/compiler/extension/doc/core/TypeClassDcls.sv @@ -4,14 +4,15 @@ attribute docUnparse occurs on ClassBodyItem, InstanceBodyItem; attribute docForName occurs on ClassBodyItem, InstanceBodyItem; @{- What to prefix 'child' declaration names with in docs and for hyperlinking. -} -autocopy attribute scopeName :: String occurs on ClassBody, ClassBodyItem, InstanceBody, InstanceBodyItem; +inherited attribute scopeName :: String occurs on ClassBody, ClassBodyItem, InstanceBody, InstanceBodyItem; +propagate scopeName on ClassBody, ClassBodyItem, InstanceBody, InstanceBodyItem; aspect production typeClassDcl top::AGDcl ::= 'class' cl::ConstraintList '=>' id::QNameType var::TypeExpr '{' body::ClassBody '}' { top.docForName = "class " ++ id.name; top.docUnparse = s"`class ${id.unparse}`"; - top.docDcls := [pair(id.name, docDclInfo(top.docForName, sourceLocation=top.location, sourceGrammar=top.grammarName))] ++ body.docDcls; + top.docDcls := [(id.name, docDclInfo(top.docForName, sourceLocation=top.location, sourceGrammar=top.grammarName))] ++ body.docDcls; top.docs := [mkUndocumentedItem(top.docForName, top)] ++ body.docs; body.scopeName = top.docForName; body.downDocConfig = top.downDocConfig; @@ -23,7 +24,7 @@ top::AGDcl ::= 'instance' cl::ConstraintList '=>' id::QNameType ty::TypeExpr '{' { top.docForName = "instance "++id.name++" "++ty.unparse; top.docUnparse = s"`instance ${id.unparse} ${ty.unparse}`"; - top.docDcls := [pair(id.name, docDclInfo(top.docForName, sourceLocation=top.location, sourceGrammar=top.grammarName))] ++ body.docDcls; + top.docDcls := [(id.name, docDclInfo(top.docForName, sourceLocation=top.location, sourceGrammar=top.grammarName))] ++ body.docDcls; top.docs := [mkUndocumentedItem(top.docForName, top)] ++ body.docs; body.scopeName = top.docForName; body.downDocConfig = top.downDocConfig; @@ -70,15 +71,14 @@ top::ClassBodyItem ::= comment::DocComment_t item::ClassBodyItem parsed.offsetLocation = comment.location; parsed.indentBy = ">"; - item.downDocConfig = top.downDocConfig; - top.upDocConfig <- parsed.upDocConfig ++ item.upDocConfig; + top.upDocConfig <- parsed.upDocConfig; top.docErrors <- parsed.errors; - local realDclDocs::[CommentItem] = filter((\x::CommentItem->!x.stub), item.docs); + local realDclDocs::[CommentItem] = filter((\x::CommentItem->!x.stub), forward.docs); local isDoubleComment::Boolean = length(realDclDocs) != 0; top.docs := if isDoubleComment then [standaloneDclCommentItem(parsed)] ++ realDclDocs - else [dclCommentItem(top.scopeName ++ "." ++ item.docForName, item.docUnparse, item.grammarName, item.location, parsed)]; + else [dclCommentItem(top.scopeName ++ "." ++ forward.docForName, forward.docUnparse, forward.grammarName, item.location, parsed)]; top.docErrors <- if isDoubleComment then [wrn(parsed.location, "Doc comment not immediately preceding ClassBodyItem, so association is ambiguous. Treating as standalone comment. Mark with @@{- instead of @{- to silence this warning.")] @@ -148,15 +148,14 @@ top::InstanceBodyItem ::= comment::DocComment_t item::InstanceBodyItem parsed.offsetLocation = comment.location; parsed.indentBy = ">"; - item.downDocConfig = top.downDocConfig; - top.upDocConfig <- parsed.upDocConfig ++ item.upDocConfig; + top.upDocConfig <- parsed.upDocConfig; top.docErrors <- parsed.errors; - local realDclDocs::[CommentItem] = filter((\x::CommentItem->!x.stub), item.docs); + local realDclDocs::[CommentItem] = filter((\x::CommentItem->!x.stub), forward.docs); local isDoubleComment::Boolean = length(realDclDocs) != 0; top.docs := if isDoubleComment then [standaloneDclCommentItem(parsed)] ++ realDclDocs - else [dclCommentItem(top.scopeName ++ "." ++ item.docForName, item.docUnparse, item.grammarName, item.location, parsed)]; + else [dclCommentItem(top.scopeName ++ "." ++ forward.docForName, forward.docUnparse, forward.grammarName, item.location, parsed)]; top.docErrors <- if isDoubleComment then [wrn(parsed.location, "Doc comment not immediately preceding InstanceBodyItem, so association is ambiguous. Treating as standalone comment. Mark with @@{- instead of @{- to silence this warning.")] diff --git a/grammars/silver/compiler/extension/doc/core/doclang/DclComment.sv b/grammars/silver/compiler/extension/doc/core/doclang/DclComment.sv index 95bf4013a..13b1acdeb 100644 --- a/grammars/silver/compiler/extension/doc/core/doclang/DclComment.sv +++ b/grammars/silver/compiler/extension/doc/core/doclang/DclComment.sv @@ -46,6 +46,9 @@ nonterminal DclCommentLines layout {} with body, location, docEnv, errors; nonterminal DclCommentParts layout {} with body, location, docEnv, errors; nonterminal DclCommentPart layout {} with body, location, docEnv, errors; +propagate docEnv on + DclComment, DclCommentBlocks, DclCommentStrictBlocks, DclCommentBlock, + DclCommentLines, DclCommentParts, DclCommentPart; propagate errors on DclCommentBlocks, DclCommentStrictBlocks, DclCommentBlock, DclCommentLines, DclCommentParts, DclCommentPart; @@ -141,36 +144,36 @@ Pair<[String] [DocConfigSetting]> ::= alreadyErrs::[String] args::[Pair if !v.asBool.isJust then ["@config split takes a boolean value (or just @config split)"] else [] - | pair("fileSplit", v) -> if !v.asBool.isJust then ["@config fileSplit takes a boolean value (or just @config fileSplit)"] else [] - | pair("noToc", v) -> if !v.asBool.isJust then ["@config noToc takes a boolean value (or just @config noToc)"] else [] - | pair("weight", v) -> if !v.asInteger.isJust then ["@config weight takes an integer"] else [] - | pair("grammarWeight", v) -> if !v.asInteger.isJust then ["@config grammarWeight takes an integer"] else [] - | pair("title", v) -> if !v.asString.isJust then ["@config title takes a string in quotes"] else [] - | pair("grammarTitle", v) -> if !v.asString.isJust then ["@config grammarTitle takes a string in quotes"] else [] - | pair("excludeFile", v) -> if !v.asBool.isJust then ["@config excludeFile takes a boolean value (or just @config excludeFile)"] else [] - | pair("excludeGrammar", v) -> if !v.asBool.isJust then ["@config excludeGrammar takes a boolean value (or just @config excludeGrammar)"] else [] - | pair("hide", v) -> if !v.asBool.isJust then ["@config hide takes a boolean value (or just @config hide or @hide)"] else [] - | pair(k, _) -> ["Unknown @config directive '"++k++"'"] + | ("split", v) -> if !v.asBool.isJust then ["@config split takes a boolean value (or just @config split)"] else [] + | ("fileSplit", v) -> if !v.asBool.isJust then ["@config fileSplit takes a boolean value (or just @config fileSplit)"] else [] + | ("noToc", v) -> if !v.asBool.isJust then ["@config noToc takes a boolean value (or just @config noToc)"] else [] + | ("weight", v) -> if !v.asInteger.isJust then ["@config weight takes an integer"] else [] + | ("grammarWeight", v) -> if !v.asInteger.isJust then ["@config grammarWeight takes an integer"] else [] + | ("title", v) -> if !v.asString.isJust then ["@config title takes a string in quotes"] else [] + | ("grammarTitle", v) -> if !v.asString.isJust then ["@config grammarTitle takes a string in quotes"] else [] + | ("excludeFile", v) -> if !v.asBool.isJust then ["@config excludeFile takes a boolean value (or just @config excludeFile)"] else [] + | ("excludeGrammar", v) -> if !v.asBool.isJust then ["@config excludeGrammar takes a boolean value (or just @config excludeGrammar)"] else [] + | ("hide", v) -> if !v.asBool.isJust then ["@config hide takes a boolean value (or just @config hide or @hide)"] else [] + | (k, _) -> ["Unknown @config directive '"++k++"'"] end; local boundConf::[DocConfigSetting] = case arg of - | pair("split", v) -> [splitConfig(v.asBool.fromJust)] - | pair("fileSplit", v) -> [fileSplitConfig(v.asBool.fromJust)] - | pair("noToc", v) -> [tocConfig(!v.asBool.fromJust)] - | pair("weight", v) -> [weightConfig(v.asInteger.fromJust)] - | pair("grammarWeight", v) -> [grammarWeightConfig(v.asInteger.fromJust)] - | pair("title", v) -> [titleConfig(v.asString.fromJust)] - | pair("grammarTitle", v) -> [grammarTitleConfig(v.asString.fromJust)] - | pair("excludeFile", v) -> [fileNoDocsConfig(v.asBool.fromJust)] - | pair("excludeGrammar", v) -> [grammarNoDocsConfig(v.asBool.fromJust)] - | pair("hide", _) -> [] + | ("split", v) -> [splitConfig(v.asBool.fromJust)] + | ("fileSplit", v) -> [fileSplitConfig(v.asBool.fromJust)] + | ("noToc", v) -> [tocConfig(!v.asBool.fromJust)] + | ("weight", v) -> [weightConfig(v.asInteger.fromJust)] + | ("grammarWeight", v) -> [grammarWeightConfig(v.asInteger.fromJust)] + | ("title", v) -> [titleConfig(v.asString.fromJust)] + | ("grammarTitle", v) -> [grammarTitleConfig(v.asString.fromJust)] + | ("excludeFile", v) -> [fileNoDocsConfig(v.asBool.fromJust)] + | ("excludeGrammar", v) -> [grammarNoDocsConfig(v.asBool.fromJust)] + | ("hide", _) -> [] | _ -> error("(Impossible)") end; return case args of - | [] -> pair(alreadyErrs, conf) + | [] -> (alreadyErrs, conf) | _::r when length(err)!=0 -> processConfigOptions(err++alreadyErrs, r, conf) | _::r -> processConfigOptions(alreadyErrs, r, boundConf ++ conf) end; @@ -219,7 +222,7 @@ concrete production initialCommentBlocks top::DclCommentBlocks ::= block::DclCommentLines blocks::DclCommentStrictBlocks { top.otherBlocks = - pair("normal", block.body) :: blocks.otherBlocks; + ("normal", block.body) :: blocks.otherBlocks; top.paramBlocks = blocks.paramBlocks; top.configArgs = blocks.configArgs; } @@ -257,7 +260,7 @@ concrete production commentBlock top::DclCommentBlock ::= EmptyLines_t content::DclCommentLines { top.body = content.body; - top.otherBlocks = [pair("normal", top.body)]; + top.otherBlocks = [("normal", top.body)]; top.paramBlocks = []; top.configArgs = []; } @@ -267,7 +270,7 @@ top::DclCommentBlock ::= Param_t Whitespace_t id::Id_t Whitespace_t content::Dcl { top.body = "{{< hint info >}}\n**Parameter `"++id.lexeme++"`**\\\n " ++ content.body ++ "\n{{< /hint >}}"; top.otherBlocks = []; - top.paramBlocks = [pair(id.lexeme, top.body)]; + top.paramBlocks = [(id.lexeme, top.body)]; top.configArgs = []; } @@ -275,7 +278,7 @@ concrete production prodattrBlock top::DclCommentBlock ::= Prodattr_t Whitespace_t id::Id_t Whitespace_t content::DclCommentLines { top.body = "{{< hint warning >}}\n**Production Attribute `"++id.lexeme++"`**\\\n " ++ content.body ++ "\n{{< /hint >}}"; - top.otherBlocks = [pair("prodAttr", top.body)]; + top.otherBlocks = [("prodAttr", top.body)]; top.paramBlocks = []; top.configArgs = []; } @@ -284,7 +287,7 @@ concrete production returnBlock top::DclCommentBlock ::= Return_t Whitespace_t content::DclCommentLines { top.body = "{{< hint info >}}\n**Return**\\\n " ++ content.body ++ "\n{{< /hint >}}"; - top.otherBlocks = [pair("return", top.body)]; + top.otherBlocks = [("return", top.body)]; top.paramBlocks = []; top.configArgs = []; } @@ -293,7 +296,7 @@ concrete production forwardBlock top::DclCommentBlock ::= Forward_t Whitespace_t content::DclCommentLines { top.body = "{{< hint warning >}}\n**Forward**\\\n " ++ content.body ++ "\n{{< /hint >}}"; - top.otherBlocks = [pair("forward", top.body)]; + top.otherBlocks = [("forward", top.body)]; top.paramBlocks = []; top.configArgs = []; } @@ -302,7 +305,7 @@ concrete production warningBlock top::DclCommentBlock ::= Warning_t Whitespace_t content::DclCommentLines { top.body = "{{< hint danger >}}\n**WARNING!**\\\n " ++ content.body ++ "\n{{< /hint >}}"; - top.otherBlocks = [pair("warning", top.body)]; + top.otherBlocks = [("warning", top.body)]; top.paramBlocks = []; top.configArgs = []; } @@ -321,7 +324,7 @@ top::DclCommentBlock ::= Config_t Whitespace_t param::Id_t Whitespace_t Equals_t top.body = "@config " ++ param.lexeme ++ " = " ++ hackUnparse(value); --not emitted top.otherBlocks = []; top.paramBlocks = []; - top.configArgs = [pair(param.lexeme, value)]; + top.configArgs = [(param.lexeme, value)]; } concrete production configBlockImplicitTrue diff --git a/grammars/silver/compiler/extension/easyterminal/Env.sv b/grammars/silver/compiler/extension/easyterminal/Env.sv index 2f5c8eba3..d40993fff 100644 --- a/grammars/silver/compiler/extension/easyterminal/Env.sv +++ b/grammars/silver/compiler/extension/easyterminal/Env.sv @@ -3,7 +3,7 @@ grammar silver:compiler:extension:easyterminal; import silver:compiler:definition:env; function getTerminalRegexDclAll -[TypeDclInfo] ::= search::String e::Decorated Env +[TypeDclInfo] ::= search::String e::Env { return searchEnv(search, e.terminalTree); } @@ -14,7 +14,7 @@ function filterAndConvertTermDcls [Pair] ::= ei::EnvItem sofar::[Pair] { return case ei.dcl of - | termDcl(fn, _, just(en), _) -> pair(en, ei.dcl) :: sofar + | termDcl(fn, _, just(en), _) -> (en, ei.dcl) :: sofar | _ -> sofar end; } @@ -25,26 +25,26 @@ EnvTree ::= eis::[EnvItem] return directBuildTree(foldr(filterAndConvertTermDcls,[],eis)); } -aspect production i_emptyEnv +aspect production emptyEnv top::Env ::= { top.terminalTree = [emptyEnvTree()]; } -aspect production i_appendEnv -top::Env ::= e1::Decorated Env e2::Decorated Env +aspect production appendEnv +top::Env ::= e1::Env e2::Env { top.terminalTree = e1.terminalTree ++ e2.terminalTree; } -aspect production i_newScopeEnv -top::Env ::= d::Defs e::Decorated Env +aspect production newScopeEnv +top::Env ::= _ e::Env { top.terminalTree = buildTerminalTree(d.typeList) :: e.terminalTree; } -aspect production i_occursEnv -top::Env ::= _ e::Decorated Env +aspect production occursEnv +top::Env ::= _ e::Env { top.terminalTree = e.terminalTree; } diff --git a/grammars/silver/compiler/extension/easyterminal/TerminalDcl.sv b/grammars/silver/compiler/extension/easyterminal/TerminalDcl.sv index f03d97b66..06d0da632 100644 --- a/grammars/silver/compiler/extension/easyterminal/TerminalDcl.sv +++ b/grammars/silver/compiler/extension/easyterminal/TerminalDcl.sv @@ -66,6 +66,7 @@ concrete production productionRhsElemEasyReg top::ProductionRHSElem ::= id::Name '::' reg::EasyTerminalRef { top.unparse = id.unparse ++ "::" ++ reg.unparse; + propagate env; top.errors <- reg.errors; top.lambdaBoundVars := [id.name]; -- Needed because we are forwrding based on env @@ -77,6 +78,7 @@ concrete production productionRhsElemTypeEasyReg top::ProductionRHSElem ::= reg::EasyTerminalRef { top.unparse = reg.unparse; + propagate env; top.errors <- reg.errors; top.lambdaBoundVars := []; -- Needed because we are forwrding based on env @@ -88,6 +90,7 @@ concrete production aspectRHSElemEasyReg top::AspectRHSElem ::= reg::EasyTerminalRef { top.unparse = reg.unparse; + propagate env; top.errors <- reg.errors; forwards to aspectRHSElemNone('_', location=reg.location); -- TODO This isn't checking if the type is right!! @@ -97,6 +100,7 @@ concrete production aspectRHSElemTypedEasyReg top::AspectRHSElem ::= id::Name '::' reg::EasyTerminalRef { top.unparse = id.unparse ++ " :: " ++ reg.unparse; + propagate env; top.errors <- reg.errors; forwards to aspectRHSElemTyped(id, $2, typerepTypeExpr(reg.typerep, location=reg.location), location=top.location); @@ -107,7 +111,7 @@ concrete production terminalExprReg top::Expr ::= reg::EasyTerminalRef { top.unparse = reg.unparse; - propagate freeVars; + propagate env, freeVars; top.errors <- reg.errors; local escapedName :: String = escapeString(reg.easyString); diff --git a/grammars/silver/compiler/extension/implicit_monads/AttributeDefs.sv b/grammars/silver/compiler/extension/implicit_monads/AttributeDefs.sv index 79b5d5d31..8abc398c4 100644 --- a/grammars/silver/compiler/extension/implicit_monads/AttributeDefs.sv +++ b/grammars/silver/compiler/extension/implicit_monads/AttributeDefs.sv @@ -5,6 +5,7 @@ concrete production attributeDclInh_Restricted top::AGDcl ::= 'restricted' 'inherited' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr ';' { top.unparse = "restricted inherited attribute " ++ a.unparse ++ tl.unparse ++ " :: " ++ te.unparse ++ ";"; + propagate grammarName, flowEnv; top.moduleNames := []; @@ -34,6 +35,7 @@ concrete production attributeDclSyn_Restricted top::AGDcl ::= 'restricted' 'synthesized' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr ';' { top.unparse = "restricted synthesized attribute " ++ a.unparse ++ tl.unparse ++ " :: " ++ te.unparse ++ ";"; + propagate grammarName, flowEnv; top.moduleNames := []; @@ -65,6 +67,7 @@ concrete production attributeDclInh_Implicit top::AGDcl ::= 'implicit' 'inherited' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr ';' { top.unparse = "implicit inherited attribute " ++ a.unparse ++ tl.unparse ++ " :: " ++ te.unparse ++ ";"; + propagate grammarName, flowEnv; top.moduleNames := []; @@ -96,6 +99,7 @@ concrete production attributeDclSyn_Implicit top::AGDcl ::= 'implicit' 'synthesized' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr ';' { top.unparse = "implicit synthesized attribute " ++ a.unparse ++ tl.unparse ++ " :: " ++ te.unparse ++ ";"; + propagate grammarName, flowEnv; top.moduleNames := []; diff --git a/grammars/silver/compiler/extension/implicit_monads/Case.sv b/grammars/silver/compiler/extension/implicit_monads/Case.sv index 3b0a9443a..f188a8728 100644 --- a/grammars/silver/compiler/extension/implicit_monads/Case.sv +++ b/grammars/silver/compiler/extension/implicit_monads/Case.sv @@ -78,7 +78,6 @@ top::Expr ::= 'case' es::Exprs 'of' vbar::Opt_Vbar_t ml::MRuleList 'end' redeces.config = top.config; redeces.flowEnv = top.flowEnv; redeces.expectedMonad = top.expectedMonad; - redeces.isRoot = top.isRoot; redeces.originRules = top.originRules; {- @@ -105,6 +104,7 @@ top::Expr ::= 'case' es::Exprs 'of' vbar::Opt_Vbar_t ml::MRuleList 'end' monadLocal.downSubst = ml.mUpSubst; monadLocal.finalSubst = top.finalSubst; monadLocal.expectedMonad = top.expectedMonad; + monadLocal.alwaysDecorated = false; monadLocal.originRules = top.originRules; monadLocal.isRoot = false; top.monadRewritten = monadLocal.monadRewritten; @@ -119,7 +119,7 @@ top::Expr ::= 'case' es::Exprs 'of' vbar::Opt_Vbar_t ml::MRuleList 'end' decorate x.fst with {env=top.env; mDownSubst=top.mDownSubst; frame=top.frame; grammarName=top.grammarName; downSubst=top.mDownSubst; finalSubst=top.mDownSubst; compiledGrammars=top.compiledGrammars; - config=top.config; flowEnv=top.flowEnv;expectedMonad=top.expectedMonad; + config=top.config; alwaysDecorated = false; flowEnv=top.flowEnv;expectedMonad=top.expectedMonad; isRoot=top.isRoot; originRules=top.originRules;} in if isMonad(a.mtyperep, top.env) && monadsMatch(a.mtyperep, top.expectedMonad, top.mDownSubst).fst && !isMonad(performSubstitution(x.snd, top.mDownSubst), top.env) @@ -127,15 +127,15 @@ top::Expr ::= 'case' es::Exprs 'of' vbar::Opt_Vbar_t ml::MRuleList 'end' frame=top.frame; grammarName=top.grammarName; downSubst=top.mDownSubst; finalSubst=top.mDownSubst; compiledGrammars=top.compiledGrammars; config=top.config; flowEnv=top.flowEnv; monadicallyUsed=true; - expectedMonad=top.expectedMonad; isRoot=top.isRoot; originRules=top.originRules;}.monadicNames + expectedMonad=top.expectedMonad; alwaysDecorated = false; isRoot=top.isRoot; originRules=top.originRules;}.monadicNames else [] end ++ l, - monadLocal.monadicNames, zipWith(\x::Expr y::Type -> pair(x,y), es.rawExprs, ml.patternTypeList)); + monadLocal.monadicNames, zipWith(\x::Expr y::Type -> (x,y), es.rawExprs, ml.patternTypeList)); } --find if any of the expressions are being matched as their inner type --if returns (true, ty), ty will be used to find the correct Fail() function monadicallyUsedExpr -Boolean ::= elst::[Expr] env::Decorated Env sub::Substitution f::BlockContext gn::String +Boolean ::= elst::[Expr] env::Env sub::Substitution f::BlockContext gn::String cg::EnvTree c::Decorated CmdArgs fe::FlowEnv em::Type iR::Boolean oR::[Decorated Expr] { @@ -144,7 +144,7 @@ Boolean ::= elst::[Expr] env::Decorated Env sub::Substitution f::BlockContext gn | e::etl -> let etyp::Type = decorate e with {env=env; mDownSubst=sub; frame=f; grammarName=gn; downSubst=sub; finalSubst=sub; - compiledGrammars=cg; config=c; flowEnv=fe; + compiledGrammars=cg; config=c; alwaysDecorated = false; flowEnv=fe; expectedMonad=em; isRoot=iR; originRules=oR;}.mtyperep in fst(monadsMatch(etyp, em, sub)) || monadicallyUsedExpr(etl, env, sub, f, gn, cg, c, fe, em, iR, oR) @@ -157,7 +157,7 @@ Boolean ::= elst::[Expr] env::Decorated Env sub::Substitution f::BlockContext gn function monadicMatchTypesNames ([(Type, (Expr, String))], [Expr]) ::= elst::[Decorated Expr with MonadInhs] - tylst::[Type] names::[String] env::Decorated Env sub::Substitution em::Type + tylst::[Type] names::[String] env::Env sub::Substitution em::Type loc::Location index::Integer { local attribute subcall::([(Type, Expr, String)], [Expr]); @@ -171,8 +171,8 @@ function monadicMatchTypesNames then "__sv_expression_in_case" ++ toString(index) ++ "_" ++ toString(genInt()) else head(names); return case elst, tylst of - | [], _ -> pair([], []) - | _, [] -> pair([], map(new, elst)) + | [], _ -> ([], []) + | _, [] -> ([], map(new, elst)) | decE::etl, t::ttl -> let ety::Type = decE.mtyperep in @@ -191,19 +191,7 @@ function monadicMatchTypesNames fails.-} aspect production caseExpr top::Expr ::= es::[Expr] ml::[AbstractMatchRule] complete::Boolean failExpr::Expr retType::Type { - local monadLocal::Expr = monadCompileCaseExpr(es, ml, failExpr, retType, top.location, top.env); - monadLocal.mDownSubst = top.mDownSubst; - monadLocal.frame = top.frame; - monadLocal.grammarName = top.grammarName; - monadLocal.compiledGrammars = top.compiledGrammars; - monadLocal.config = top.config; - monadLocal.env = top.env; - monadLocal.flowEnv = top.flowEnv; - monadLocal.downSubst = top.mDownSubst; - monadLocal.finalSubst = top.finalSubst; - monadLocal.expectedMonad = top.expectedMonad; - monadLocal.originRules = top.originRules; - monadLocal.isRoot = top.isRoot; + forward monadLocal = monadCompileCaseExpr(es, ml, failExpr, retType, top.location, top.env); top.monadRewritten = monadLocal.monadRewritten; @@ -230,7 +218,7 @@ top::Expr ::= es::[Expr] ml::[AbstractMatchRule] complete::Boolean failExpr::Exp copying the function format from the patternmatching extension. -} function monadCompileCaseExpr -Expr ::= es::[Expr] ml::[AbstractMatchRule] failExpr::Expr retType::Type loc::Location env::Decorated Env +Expr ::= es::[Expr] ml::[AbstractMatchRule] failExpr::Expr retType::Type loc::Location env::Env { --Split rules into segments of non-forwarding constructors, all same -- forwarding constructor, and variables based on first pattern @@ -283,7 +271,7 @@ Expr ::= es::[Expr] ml::[AbstractMatchRule] failExpr::Expr retType::Type loc::Lo -- but without using lets which would end up being problematic in our implicit use function monadCompilePatternGroups Expr ::= matchEs::[Expr] ruleGroups::[[AbstractMatchRule]] finalFail::Expr - retType::Type loc::Location env::Decorated Env + retType::Type loc::Location env::Env { local compileRest::Expr = monadCompilePatternGroups(matchEs, tail(ruleGroups), finalFail, @@ -341,7 +329,7 @@ Expr ::= matchEs::[Expr] ruleGroups::[[AbstractMatchRule]] finalFail::Expr Turn matching on all constructors into primitive matching. -} function monadAllConCaseTransform -PrimPattern ::= currExpr::Expr restExprs::[Expr] failCase::Expr retType::Type mrs::[AbstractMatchRule] env::Decorated Env +PrimPattern ::= currExpr::Expr restExprs::[Expr] failCase::Expr retType::Type mrs::[AbstractMatchRule] env::Env { local names :: [Name] = map(patternListVars, head(mrs).headPattern.patternSubPatternList); @@ -379,6 +367,7 @@ concrete production mcaseExpr_c top::Expr ::= 'case_any' es::Exprs 'of' vbar::Opt_Vbar_t ml::MRuleList 'end' { top.unparse = "case_any " ++ es.unparse ++ " of " ++ ml.unparse ++ " end"; + propagate config, frame, env; top.merrors := []; top.merrors <- if isMonadPlus_instance then [] else [err(top.location, notMonadPlus)]; @@ -399,7 +388,7 @@ top::Expr ::= 'case_any' es::Exprs 'of' vbar::Opt_Vbar_t ml::MRuleList 'end' --we need fresh names for the expressions being matched on, which we will use to only evaluate them once local newNames::[String] = map(\ x::Expr -> "__sv_mcase_var_" ++ toString(genInt()), es.rawExprs); - local params::[Pair] = zipWith(pair, newNames, ml.patternTypeList); + local params::[Pair] = zip(newNames, ml.patternTypeList); local nameExprs::[Expr] = map(\x::String -> baseExpr(qName(top.location, x), location=top.location), newNames); @@ -422,6 +411,7 @@ top::Expr ::= 'case_any' es::Exprs 'of' vbar::Opt_Vbar_t ml::MRuleList 'end' downSubst = top.mDownSubst; finalSubst = top.mDownSubst; expectedMonad = top.expectedMonad; + alwaysDecorated = false; isRoot = top.isRoot; originRules = top.originRules; }.monadRewritten, @@ -476,7 +466,7 @@ top::Expr ::= 'case_any' es::Exprs 'of' vbar::Opt_Vbar_t ml::MRuleList 'end' -} function mcaseBindsApps Expr ::= exprs::[Expr] names::[String] loc::Location base::Expr - env::Decorated Env sub::Substitution f::BlockContext + env::Env sub::Substitution f::BlockContext gn::String cg::EnvTree c::Decorated CmdArgs fe::FlowEnv em::Type iR::Boolean oR::[Decorated Expr] { @@ -491,7 +481,7 @@ Expr ::= exprs::[Expr] names::[String] loc::Location base::Expr downSubst=sub; finalSubst=sub; compiledGrammars=cg; config=c; flowEnv=fe; expectedMonad=em; originRules = oR; - isRoot = iR;}.mtyperep + isRoot = iR; alwaysDecorated = false; }.mtyperep in if isMonad(ety, env) && fst(monadsMatch(ety, em, sub)) then buildApplication( @@ -539,7 +529,7 @@ top::Exprs ::= e1::Expr ',' e2::Exprs --There are several thing we need for mtyperep on e which don't occur on match rules --Therefore we need to pass them here inherited attribute temp_flowEnv::FlowEnv; -inherited attribute temp_env::Decorated Env; +inherited attribute temp_env::Env; inherited attribute temp_config::Decorated CmdArgs; inherited attribute temp_compiledGrammars::EnvTree; inherited attribute temp_grammarName::String; @@ -581,7 +571,7 @@ top::MRuleList ::= h::MatchRule vbar::Vbar_kwd t::MRuleList -- it and not incorrectly identify something as being used non-monadically top.mUpSubst = foldl(\s::Substitution p::Pair -> decorate check(p.fst, p.snd) with {downSubst=s;}.upSubst, - t.mUpSubst, zipWith(pair, h.patternTypeList, t.patternTypeList)); + t.mUpSubst, zip(h.patternTypeList, t.patternTypeList)); } aspect production matchRule_c @@ -596,6 +586,7 @@ top::MatchRule ::= pt::PatternList arr::Arrow_kwd e::Expr ne.frame = top.frame; ne.finalSubst = top.mDownSubst; ne.downSubst = top.mDownSubst; + ne.alwaysDecorated = false; ne.originRules = []; ne.isRoot = false; @@ -616,6 +607,7 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr arr::Arrow_kwd e::Expr ncond.frame = top.frame; ncond.finalSubst = top.mDownSubst; ncond.downSubst = top.mDownSubst; + ncond.alwaysDecorated = false; ncond.originRules = []; ncond.isRoot = false; local ne::Expr = e; @@ -627,6 +619,7 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr arr::Arrow_kwd e::Expr ne.frame = top.frame; ne.finalSubst = top.mDownSubst; ne.downSubst = top.mDownSubst; + ne.alwaysDecorated = false; ne.originRules = []; ne.isRoot = false; @@ -647,6 +640,7 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr 'matches' p::Pattern arr::A ncond.frame = top.frame; ncond.finalSubst = top.mDownSubst; ncond.downSubst = top.mDownSubst; + ncond.alwaysDecorated = false; ncond.originRules = []; ncond.isRoot = false; local ne::Expr = e; @@ -658,6 +652,7 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr 'matches' p::Pattern arr::A ne.frame = top.frame; ne.finalSubst = top.mDownSubst; ne.downSubst = top.mDownSubst; + ne.alwaysDecorated = false; ne.originRules = []; ne.isRoot = false; @@ -708,6 +703,7 @@ top::AbstractMatchRule ::= pl::[Decorated Pattern] cond::Maybe<(Expr, Maybe, merrors, mtyperep, mDownSubst, mUpSubst, expectedMonad occurs on Expr; propagate expectedMonad on Expr; type MonadInhs = { - downSubst, finalSubst, frame, grammarName, isRoot, originRules, + downSubst, finalSubst, frame, grammarName, alwaysDecorated, isRoot, originRules, compiledGrammars, config, env, flowEnv, expectedMonad, mDownSubst }; @@ -43,17 +43,17 @@ top::Expr ::= e::[Message] } aspect production errorReference -top::Expr ::= msg::[Message] q::PartiallyDecorated QName +top::Expr ::= msg::[Message] q::Decorated! QName { top.merrors := msg; propagate mDownSubst, mUpSubst; top.mtyperep = errorType(); top.monadicNames = []; - top.monadRewritten = errorReference(msg, q, location=top.location); + top.monadRewritten = baseExpr(q, location=top.location); } aspect production childReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.merrors := []; propagate mDownSubst, mUpSubst; @@ -67,7 +67,7 @@ top::Expr ::= q::PartiallyDecorated QName } aspect production lhsReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.merrors := []; propagate mDownSubst, mUpSubst; @@ -79,7 +79,7 @@ top::Expr ::= q::PartiallyDecorated QName } aspect production localReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.merrors := []; propagate mDownSubst, mUpSubst; @@ -93,7 +93,7 @@ top::Expr ::= q::PartiallyDecorated QName } aspect production forwardReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.merrors := []; propagate mDownSubst, mUpSubst; @@ -106,7 +106,7 @@ top::Expr ::= q::PartiallyDecorated QName } aspect production productionReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.merrors := []; propagate mDownSubst, mUpSubst; @@ -118,7 +118,7 @@ top::Expr ::= q::PartiallyDecorated QName } aspect production functionReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.merrors := []; propagate mDownSubst, mUpSubst; @@ -130,7 +130,7 @@ top::Expr ::= q::PartiallyDecorated QName } aspect production classMemberReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.merrors := []; propagate mDownSubst, mUpSubst; @@ -142,7 +142,7 @@ top::Expr ::= q::PartiallyDecorated QName } aspect production globalValueReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.merrors := []; propagate mDownSubst, mUpSubst; @@ -172,6 +172,8 @@ top::Expr ::= e::Expr '(' es::AppExprs ',' anns::AnnoAppExprs ')' ne.frame = top.frame; ne.finalSubst = top.finalSubst; ne.downSubst = top.downSubst; + ne.alwaysDecorated = false; + ne.decSiteVertexInfo = nothing(); ne.originRules = top.originRules; ne.isRoot = false; local nes::AppExprs = new(es); @@ -184,28 +186,36 @@ top::Expr ::= e::Expr '(' es::AppExprs ',' anns::AnnoAppExprs ')' nes.frame = top.frame; nes.finalSubst = top.finalSubst; nes.downSubst = top.downSubst; + nes.alwaysDecorated = false; + nes.decSiteVertexInfo = nothing(); + nes.appProd = nothing(); nes.originRules = top.originRules; - nes.isRoot = false; nes.appExprTypereps = reverse(performSubstitution(ne.mtyperep, ne.mUpSubst).inputTypes); nes.appExprApplied = ne.unparse; nes.monadArgumentsAllowed = acceptableMonadFunction(e); + local nanns::AnnoAppExprs = new(anns); + nanns.mDownSubst = nes.mUpSubst; + nanns.flowEnv = top.flowEnv; + nanns.env = top.env; + nanns.config = top.config; + nanns.compiledGrammars = top.compiledGrammars; + nanns.grammarName = top.grammarName; + nanns.frame = top.frame; + nanns.finalSubst = top.finalSubst; + nanns.downSubst = top.downSubst; + nanns.originRules = top.originRules; + nanns.appExprApplied = ne.unparse; + nanns.remainingFuncAnnotations = anns.remainingFuncAnnotations; + nanns.funcAnnotations = anns.funcAnnotations; + nanns.monadArgumentsAllowed = acceptableMonadFunction(e); + nanns.previousArgs = nes.monadRewritten; ne.expectedMonad = top.expectedMonad; nes.expectedMonad = top.expectedMonad; + nanns.expectedMonad = top.expectedMonad; - top.merrors := ne.merrors ++ nes.merrors; - top.mUpSubst = nes.mUpSubst; - - top.merrors <- - case anns of - | emptyAnnoAppExprs() -> - [] - | _ -> - if null(nes.monadTypesLocations) - then [] - else [err(top.location, "Monad Rewriting not defined with annotated " ++ - "expressions in a function application")] - end; + top.merrors := ne.merrors ++ nes.merrors ++ nanns.merrors; + top.mUpSubst = nanns.mUpSubst; local substTy::Type = performSubstitution(ne.mtyperep, top.mUpSubst); local ety :: Type = @@ -213,26 +223,28 @@ top::Expr ::= e::Expr '(' es::AppExprs ',' anns::AnnoAppExprs ')' monadsMatch(top.expectedMonad, substTy, top.mDownSubst).fst then monadInnerType(substTy, top.location) else substTy; + local areMonadicArgs::Boolean = + !null(nes.monadTypesLocations) || any(map(\ p::(Type, QName, Boolean) -> p.3, nanns.monadAnns)); + local funIsMonadic::Boolean = + isMonad(substTy, top.env) && monadsMatch(top.expectedMonad, substTy, top.mUpSubst).fst; + local funResultIsMonad::Boolean = + isMonad(ety.outputType, top.env) && monadsMatch(ety.outputType, top.expectedMonad, top.mUpSubst).fst; --needs to add a monad to the result if there are monadic args or the function is monadic top.mtyperep = - if null(nes.monadTypesLocations) - then if isMonad(substTy, top.env) && monadsMatch(top.expectedMonad, substTy, top.mDownSubst).fst - then monadOfType(top.expectedMonad, ety.outputType) - else ety.outputType - else if isMonad(ety.outputType, top.env) && fst(monadsMatch(ety.outputType, top.expectedMonad, top.mUpSubst)) + if areMonadicArgs || funIsMonadic + then if funResultIsMonad then ety.outputType - else monadOfType(top.expectedMonad, ety.outputType); + else monadOfType(top.expectedMonad, ety.outputType) + else ety.outputType; - ne.monadicallyUsed = isMonad(ne.mtyperep, top.env) && fst(monadsMatch(ne.mtyperep, top.expectedMonad, top.mUpSubst)); + ne.monadicallyUsed = funIsMonadic; top.monadicNames = ne.monadicNames ++ nes.monadicNames; --whether we need to wrap the ultimate function call in monadRewritten in a Return local wrapReturn::Boolean = - --monadic args or monadic function - (!null(nes.monadTypesLocations) || (isMonad(substTy, top.env) && monadsMatch(substTy, top.expectedMonad, top.mUpSubst).fst)) && - --not monadic result or not the right monad - (!isMonad(ety.outputType, top.env) || !fst(monadsMatch(ety.outputType, top.expectedMonad, top.mUpSubst))); + --monadic args or monadic function and not a monad result + (areMonadicArgs || funIsMonadic) && !funResultIsMonad; {- Monad translation creates a lambda to apply to all the arguments @@ -247,46 +259,23 @@ top::Expr ::= e::Expr '(' es::AppExprs ',' anns::AnnoAppExprs ')' Reusing ai in the bind for the ith argument simplifies doing the application inside all the binds. -} - local lambda_fun::Expr = buildMonadApplicationLambda(nes.realTypes, nes.monadTypesLocations, ety, wrapReturn, top.location); - local expanded_args::AppExprs = snocAppExprs(nes.monadRewritten, ',', presentAppExpr(ne.monadRewritten, location=top.location), - location=top.location); - local bind_name::String = "__bindFun_" ++ toString(genInt()); - -- fun >>= \ bind_name -> lambda_fun(args, bind_name) - local bind_fun_in::Expr = - Silver_Expr { - bind($Expr {if ne.mtyperep.isDecorated then mkStrFunctionInvocation(top.location, "silver:core:new", [ne.monadRewritten]) else ne.monadRewritten}, - $Expr {buildLambda(bind_name, monadInnerType(ne.mtyperep, top.location), applicationExpr(lambda_fun, '(', expanded_name_args, ')', location=top.location), top.location) }) - }; - local expanded_name_args::AppExprs = - snocAppExprs(nes.monadRewritten, ',', presentAppExpr(baseExpr(qNameId(name(bind_name, top.location), location=top.location), - location=top.location), location=top.location), location=top.location); - --haven't done monadRewritten on annotated ones, so ignore them + local lambda_fun::Expr = + buildMonadApplicationLambda(nes.realTypes, nes.monadTypesLocations, + nanns.monadAnns, top.expectedMonad, ety, funIsMonadic, wrapReturn, top.location); + local expanded_args::AppExprs = + snocAppExprs(nanns.fullArgs, ',', presentAppExpr(ne.monadRewritten, location=top.location), + location=top.location); top.monadRewritten = - if isMonad(substTy, top.env) && monadsMatch(top.expectedMonad, substTy, top.mDownSubst).fst - then bind_fun_in - else if null(nes.monadTypesLocations) - then applicationExpr(ne.monadRewritten, '(', nes.monadRewritten, ')', location=top.location) - else applicationExpr(lambda_fun, '(', expanded_args, ')', location=top.location); + if areMonadicArgs || funIsMonadic + then applicationExpr(lambda_fun, '(', expanded_args, ')', location=top.location) + else application(ne.monadRewritten, '(', nes.monadRewritten, ',', nanns.monadRewritten, ')', location=top.location); } + aspect production functionInvocation -top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::PartiallyDecorated AnnoAppExprs -{ - local t::Expr = application(e, '(', es, ',', anns, ')', location=top.location); - t.mDownSubst = top.mDownSubst; - t.env = top.env; - t.flowEnv = top.flowEnv; - t.config = top.config; - t.compiledGrammars = top.compiledGrammars; - t.grammarName = top.grammarName; - t.frame = top.frame; - t.finalSubst = top.finalSubst; - t.downSubst = top.downSubst; - t.isRoot = top.isRoot; - t.originRules = top.originRules; - t.expectedMonad = top.expectedMonad; - - t.monadicallyUsed = top.monadicallyUsed; +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs +{ + forward t = application(e, '(', es, ',', anns, ')', location=top.location); top.merrors := t.merrors; top.mUpSubst = t.mUpSubst; @@ -296,13 +285,23 @@ top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::P top.monadicNames = t.monadicNames; } --build the lambda to apply to all the original arguments plus the function ---we're going to assume this is only called if monadTysLocs is non-empty function buildMonadApplicationLambda -Expr ::= realtys::[Type] monadTysLocs::[Pair] funType::Type wrapReturn::Boolean loc::Location +Expr ::= realtys::[Type] monadTysLocs::[Pair] monadAnns::[(Type, QName, Boolean)] + expectedMonad::Type funType::Type bindFun::Boolean wrapReturn::Boolean loc::Location { local funargs::AppExprs = buildFunArgs(length(realtys), loc); - local params::ProductionRHS = buildMonadApplicationParams(realtys, 1, funType, loc); - local body::Expr = buildMonadApplicationBody(monadTysLocs, funargs, head(monadTysLocs).fst, wrapReturn, loc); + local funannargs::AnnoAppExprs = buildFunAnnArgs(monadAnns, length(realtys) + 1, loc); + local params::ProductionRHS = + buildMonadApplicationParams(realtys ++ map(fst, monadAnns), 1, + if bindFun then monadOfType(expectedMonad, funType) else funType, loc); + local actualMonadAnns::[(Type, Integer)] = + foldr(\ here::(Type, QName, Boolean) rest::([(Type, Integer)], Integer) -> + if here.3 + then ((here.1, rest.2)::rest.1, rest.2 - 1) + else (rest.1, rest.2 -1), + ([], length(realtys) + length(monadAnns)), monadAnns).1; + local body::Expr = buildMonadApplicationBody(monadTysLocs ++ actualMonadAnns, funargs, funannargs, + head(monadTysLocs).fst, funType, bindFun, wrapReturn, loc); return lambdap(params, body, location=loc); } --build the parameters for the lambda applied to all the original arguments plus the function @@ -319,12 +318,12 @@ ProductionRHS ::= realtys::[Type] currentLoc::Integer funType::Type loc::Locatio else productionRHSCons(productionRHSElem(name("a"++toString(currentLoc), loc), '::', typerepTypeExpr(dropDecorated(head(realtys)), location=loc), - --typerepTypeExpr(head(realtys), location=loc), location=loc), buildMonadApplicationParams(tail(realtys), currentLoc+1, funType, loc), location=loc); } --build the arguments for the application inside all the binds +--currentIndex is the numerical index of the argument for the name (a, like a3) function buildFunArgs AppExprs ::= currentIndex::Integer loc::Location { @@ -336,11 +335,29 @@ AppExprs ::= currentIndex::Integer loc::Location location=loc), location=loc), location=loc); } +--build the annotation arguments for the application inside all the binds +--annotations are the annotations given to the original call +--currentIndex is the numerical index of the argument for the name (a, like a3) +function buildFunAnnArgs +AnnoAppExprs ::= annotations::[(Type, QName, Boolean)] currentIndex::Integer loc::Location +{ + return case annotations of + | [] -> emptyAnnoAppExprs(location=loc) + | (ty, q, _)::rest -> + snocAnnoAppExprs(buildFunAnnArgs(rest, currentIndex + 1, loc), ',', + annoExpr(q, '=', + presentAppExpr(baseExpr(qName(loc, "a" ++ toString(currentIndex)), + location=loc), location=loc), location=loc), + location=loc) + end; +} --build the body of the lambda which includes all the binds function buildMonadApplicationBody -Expr ::= monadTysLocs::[Pair] funargs::AppExprs monadType::Type wrapReturn::Boolean loc::Location +Expr ::= monadTysLocs::[Pair] funargs::AppExprs annargs::AnnoAppExprs + monadType::Type funTy::Type bindFun::Boolean wrapReturn::Boolean loc::Location { - local sub::Expr = buildMonadApplicationBody(tail(monadTysLocs), funargs, monadType, wrapReturn, loc); + local sub::Expr = buildMonadApplicationBody(tail(monadTysLocs), funargs, annargs, + monadType, funTy, bindFun, wrapReturn, loc); local argty::Type = head(monadTysLocs).fst; local bind::Expr = monadBind(loc); local binding::ProductionRHS = @@ -367,20 +384,39 @@ Expr ::= monadTysLocs::[Pair] funargs::AppExprs monadType::Type wr local step::Expr = applicationExpr(bind, '(', bindargs, ')', location=loc); --the function is always going to be bound into the name "f", so we hard code that here - local baseapp::Expr = applicationExpr(baseExpr(qName(loc, "f"), location=loc), - '(', funargs, ')', location=loc); + local baseapp::Expr = application(baseExpr(qName(loc, "f"), location=loc), + '(', funargs, ',', annargs, ')', location=loc); local funapp::Expr = if wrapReturn then Silver_Expr { $Expr {monadReturn(loc)}($Expr {baseapp}) } else baseapp; + local funbinding::ProductionRHS = + productionRHSCons(productionRHSElem(name("f", loc), '::', + typerepTypeExpr(funTy, location=loc), location=loc), + productionRHSNil(location=loc), + location=loc); + local funbindargs::AppExprs = + snocAppExprs( + oneAppExprs(presentAppExpr( + baseExpr(qName(loc,"f"), location=loc), + location=loc), + location=loc), + ',', + presentAppExpr(lambdap(funbinding, funapp, location=loc), + location=loc), + location=loc); + local fullfun::Expr = + if bindFun + then applicationExpr(bind, '(', funbindargs, ')', location=loc) + else funapp; return if null(monadTysLocs) - then funapp + then fullfun else step; } aspect production partialApplication -top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::PartiallyDecorated AnnoAppExprs +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs { top.merrors := error("merrors not defined on partial applications"); top.mUpSubst = error("mUpSubst not defined on partial applications"); @@ -392,7 +428,7 @@ top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::P } aspect production errorApplication -top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::PartiallyDecorated AnnoAppExprs +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs { top.merrors := []; @@ -434,6 +470,7 @@ top::Expr ::= e::Expr '.' 'forward' ne.config = top.config; ne.env = top.env; ne.flowEnv = top.flowEnv; + ne.alwaysDecorated = false; ne.originRules = top.originRules; ne.isRoot = false; ne.monadicallyUsed = false; --this needs to change when we decorated monadic trees @@ -448,6 +485,7 @@ top::Expr ::= e::Expr '.' 'forward' res_e.config = top.config; res_e.env = top.env; res_e.flowEnv = top.flowEnv; + res_e.alwaysDecorated = false; res_e.isRoot = false; res_e.originRules = top.originRules; top.notExplicitAttributes := res_e.notExplicitAttributes; @@ -460,10 +498,8 @@ top::Expr ::= e::Expr '.' 'forward' } aspect production errorAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { - e.mDownSubst = top.mDownSubst; - e.expectedMonad = top.expectedMonad; e.monadicallyUsed = false; --this needs to change when we decorate monadic trees top.monadicNames = if top.monadicallyUsed then [access(e, '.', q, location=top.location)] ++ e.monadicNames @@ -476,6 +512,7 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur | restrictedInhDcl(_, _, _) -> [] | implicitSynDcl(_, _, _) -> [] | implicitInhDcl(_, _, _) -> [] + | annoDcl(_, _, _) -> [] | _ -> [err(top.location, "Attributes accessed in implicit equations must " ++ "be either implicit or restricted; " ++ q.unparse ++ " is neither")] @@ -529,16 +566,75 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur then case q.attrDcl of | restrictedSynDcl(_, _, _) -> [] | restrictedInhDcl(_, _, _) -> [] - | _ -> [pair(q.unparse, top.location)] + | annoDcl(_, _, _) -> [] + | _ -> [(q.unparse, top.location)] end else []; } aspect production annoAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + e.mDownSubst = top.mDownSubst; + e.monadicallyUsed = false; --this needs to change when we decorate monadic trees + top.monadicNames = if top.monadicallyUsed + then [access(e, '.', q, location=top.location)] ++ e.monadicNames + else e.monadicNames; + + local eUnDec::Expr = + if e.mtyperep.isDecorated + then Silver_Expr{ silver:core:new($Expr {e.monadRewritten}) } + else e.monadRewritten; + local noMonad::Expr = access(e.monadRewritten, '.', q, location=top.location); + local isEMonad::Expr = + Silver_Expr { + $Expr {monadBind(top.location)} + ($Expr {eUnDec}, + (\x::$TypeExpr {typerepTypeExpr(monadInnerType(e.mtyperep, top.location), location=top.location)} -> + $Expr {monadReturn(top.location)} + (x.$QName {qName(q.location, q.name)}) + ) + ) + }; + local isBothMonad::Expr = + Silver_Expr { + $Expr {monadBind(top.location)} + ($Expr {eUnDec}, + (\x::$TypeExpr {typerepTypeExpr(monadInnerType(e.mtyperep, top.location), location=top.location)} -> + (x.$QName {qName(q.location, q.name)}) + ) + ) + }; + top.monadRewritten = if isMonad(e.mtyperep, top.env) && + fst(monadsMatch(e.mtyperep, top.expectedMonad, top.mUpSubst)) + then if isMonad(q.typerep, top.env) && + fst(monadsMatch(q.typerep, top.expectedMonad, top.mUpSubst)) + then isBothMonad + else isEMonad + else noMonad; + + top.mtyperep = if isMonad(e.mtyperep, top.env) && + fst(monadsMatch(e.mtyperep, top.expectedMonad, top.mUpSubst)) + then if isMonad(q.typerep, top.env) && + fst(monadsMatch(q.typerep, top.expectedMonad, top.mUpSubst)) + then q.typerep + else monadOfType(top.expectedMonad, q.typerep) + else q.typerep; + + top.mUpSubst = top.mDownSubst; + top.merrors := []; + {- + Note that we don't treat annotations as having a plicitness (restricted, + implicit, explicit) like attributes because they are arguments to a + constructor like any other argument, only named. Then they have a different + character than attributes and plicitness does not make sense for them. + -} +} + +aspect production synDataAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { e.mDownSubst = top.mDownSubst; - e.expectedMonad = top.expectedMonad; e.monadicallyUsed = false; --this needs to change when we decorate monadic trees top.monadicNames = if top.monadicallyUsed then [access(e, '.', q, location=top.location)] ++ e.monadicNames @@ -591,6 +687,7 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur | restrictedInhDcl(_, _, _) -> [] | implicitSynDcl(_, _, _) -> [] | implicitInhDcl(_, _, _) -> [] + | annoDcl(_, _, _) -> [] | _ -> [err(top.location, "Attributes accessed in implicit equations must " ++ "be either implicit or restricted; " ++ q.unparse ++ " is neither")] @@ -601,16 +698,16 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur then case q.attrDcl of | restrictedSynDcl(_, _, _) -> [] | restrictedInhDcl(_, _, _) -> [] - | _ -> [pair(q.unparse, top.location)] + | annoDcl(_, _, _) -> [] + | _ -> [(q.unparse, top.location)] end else []; } aspect production terminalAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { e.mDownSubst = top.mDownSubst; - e.expectedMonad = top.expectedMonad; top.merrors := e.merrors; top.mUpSubst = top.mDownSubst; @@ -651,15 +748,14 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur else if q.name == "line" || q.name == "column" then intType() else if q.name == "location" - then nonterminalType("silver:core:Location", [], false) + then nonterminalType("silver:core:Location", [], true, false) else errorType(); } aspect production synDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { e.mDownSubst = top.mDownSubst; - e.expectedMonad = top.expectedMonad; e.monadicallyUsed = false; --this needs to change when we decorate monadic trees top.monadicNames = if top.monadicallyUsed then [access(e, '.', q, location=top.location)] ++ e.monadicNames @@ -712,6 +808,7 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur | restrictedInhDcl(_, _, _) -> [] | implicitSynDcl(_, _, _) -> [] | implicitInhDcl(_, _, _) -> [] + | annoDcl(_, _, _) -> [] | _ -> [err(top.location, "Attributes accessed in implicit equations must " ++ "be either implicit or restricted; " ++ q.unparse ++ " is neither")] @@ -722,16 +819,16 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur then case q.attrDcl of | restrictedSynDcl(_, _, _) -> [] | restrictedInhDcl(_, _, _) -> [] - | _ -> [pair(q.unparse, top.location)] + | annoDcl(_, _, _) -> [] + | _ -> [(q.unparse, top.location)] end else []; } aspect production inhDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { e.mDownSubst = top.mDownSubst; - e.expectedMonad = top.expectedMonad; e.monadicallyUsed = false; --this needs to change when we decorate monadic trees top.monadicNames = if top.monadicallyUsed then [access(e, '.', q, location=top.location)] ++ e.monadicNames @@ -784,6 +881,7 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur | restrictedInhDcl(_, _, _) -> [] | implicitSynDcl(_, _, _) -> [] | implicitInhDcl(_, _, _) -> [] + | annoDcl(_, _, _) -> [] | _ -> [err(top.location, "Attributes accessed in implicit equations must " ++ "be either implicit or restricted; " ++ q.unparse ++ " is neither")] @@ -794,16 +892,72 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur then case q.attrDcl of | restrictedSynDcl(_, _, _) -> [] | restrictedInhDcl(_, _, _) -> [] - | _ -> [pair(q.unparse, top.location)] + | annoDcl(_, _, _) -> [] + | _ -> [(q.unparse, top.location)] end else []; } -aspect production errorDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +-- TODO: restricted translation attributes? +aspect production transDecoratedAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + e.monadicallyUsed = false; --this needs to change when we decorate monadic trees + top.monadicNames = if top.monadicallyUsed + then [access(e, '.', q, location=top.location)] ++ e.monadicNames + else e.monadicNames; + + propagate mDownSubst, mUpSubst; + top.merrors := []; + top.merrors <- case q.attrDcl of + -- TODO: restricted translation attributes? + -- | restrictedSynDcl(_, _, _) -> [] + -- | restrictedInhDcl(_, _, _) -> [] + | _ -> [err(top.location, "Attributes accessed in implicit equations must " ++ + "be either implicit or restricted; " ++ q.unparse ++ + " is neither")] + end; + + local eUnDec::Expr = + if e.mtyperep.isDecorated + then Silver_Expr{ silver:core:new($Expr {e.monadRewritten}) } + else e.monadRewritten; + local noMonad::Expr = access(e.monadRewritten, '.', q, location=top.location); + local isEMonad::Expr = + Silver_Expr { + $Expr {monadBind(top.location)} + ($Expr {eUnDec}, + (\x::$TypeExpr {typerepTypeExpr(monadInnerType(e.mtyperep, top.location), location=top.location)} -> + $Expr {monadReturn(top.location)} + (x.$QName {qName(q.location, q.name)}) + ) + ) + }; + top.monadRewritten = if isMonad(e.mtyperep, top.env) && + fst(monadsMatch(e.mtyperep, top.expectedMonad, top.mUpSubst)) + then isEMonad + else noMonad; + + top.mtyperep = if isMonad(e.mtyperep, top.env) && + fst(monadsMatch(e.mtyperep, top.expectedMonad, top.mUpSubst)) + then monadOfType(top.expectedMonad, q.typerep) + else q.typerep; + + top.notExplicitAttributes <- e.notExplicitAttributes ++ + if q.found + then case q.attrDcl of + -- TODO: restricted translation attributes? + -- | restrictedSynDcl(_, _, _) -> [] + -- | restrictedInhDcl(_, _, _) -> [] + | _ -> [(q.unparse, top.location)] + end + else []; +} + +aspect production unknownDclAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { e.mDownSubst = top.mDownSubst; - e.expectedMonad = top.expectedMonad; top.monadicNames = []; @@ -856,6 +1010,7 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur | restrictedInhDcl(_, _, _) -> [] | implicitSynDcl(_, _, _) -> [] | implicitInhDcl(_, _, _) -> [] + | annoDcl(_, _, _) -> [] | _ -> [err(top.location, "Attributes accessed in implicit equations must " ++ "be either implicit or restricted; " ++ q.unparse ++ " is neither")] @@ -867,11 +1022,123 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur then case q.attrDcl of | restrictedSynDcl(_, _, _) -> [] | restrictedInhDcl(_, _, _) -> [] - | _ -> [pair(q.unparse, top.location)] + | annoDcl(_, _, _) -> [] + | _ -> [(q.unparse, top.location)] end else []; } +aspect production inhUndecoratedAccessErrorHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + e.monadicallyUsed = false; --this needs to change when we decorate monadic trees + top.monadicNames = if top.monadicallyUsed + then [access(e, '.', q, location=top.location)] ++ e.monadicNames + else e.monadicNames; + + propagate mDownSubst, mUpSubst; + top.merrors := []; + top.merrors <- case q.attrDcl of + -- TODO: restricted translation attributes? + -- | restrictedSynDcl(_, _, _) -> [] + -- | restrictedInhDcl(_, _, _) -> [] + | _ -> [err(top.location, "Attributes accessed in implicit equations must " ++ + "be either implicit or restricted; " ++ q.unparse ++ + " is neither")] + end; + + --Why do we rewrite here, in an error production? We can get here from the basic access + -- production based on normal typechecking failing even though our typechecking will + -- succeed, and we then need to be able to go back. + local eUnDec::Expr = + if e.mtyperep.isDecorated + then Silver_Expr{ silver:core:new($Expr {e.monadRewritten}) } + else e.monadRewritten; + local noMonad::Expr = access(e.monadRewritten, '.', q, location=top.location); + local isEMonad::Expr = + Silver_Expr { + $Expr {monadBind(top.location)} + ($Expr {eUnDec}, + (\x::$TypeExpr {typerepTypeExpr(monadInnerType(e.mtyperep, top.location), location=top.location)} -> + $Expr {monadReturn(top.location)} + (x.$QName {qName(q.location, q.name)}) + ) + ) + }; + top.monadRewritten = if isMonad(e.mtyperep, top.env) && + fst(monadsMatch(e.mtyperep, top.expectedMonad, top.mUpSubst)) + then isEMonad + else noMonad; + + top.mtyperep = if isMonad(e.mtyperep, top.env) && + fst(monadsMatch(e.mtyperep, top.expectedMonad, top.mUpSubst)) + then monadOfType(top.expectedMonad, q.typerep) + else q.typerep; + + top.notExplicitAttributes <- e.notExplicitAttributes ++ + if q.found + then [(q.unparse, top.location)] + else []; +} + +-- TODO: restricted translation attributes? +aspect production transUndecoratedAccessErrorHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + e.monadicallyUsed = false; --this needs to change when we decorate monadic trees + top.monadicNames = if top.monadicallyUsed + then [access(e, '.', q, location=top.location)] ++ e.monadicNames + else e.monadicNames; + + propagate mDownSubst, mUpSubst; + top.merrors := []; + top.merrors <- case q.attrDcl of + -- TODO: restricted translation attributes? + -- | restrictedSynDcl(_, _, _) -> [] + -- | restrictedInhDcl(_, _, _) -> [] + | _ -> [err(top.location, "Attributes accessed in implicit equations must " ++ + "be either implicit or restricted; " ++ q.unparse ++ + " is neither")] + end; + + --Why do we rewrite here, in an error production? We can get here from the basic access + -- production based on normal typechecking failing even though our typechecking will + -- succeed, and we then need to be able to go back. + local eUnDec::Expr = + if e.mtyperep.isDecorated + then Silver_Expr{ silver:core:new($Expr {e.monadRewritten}) } + else e.monadRewritten; + local noMonad::Expr = access(e.monadRewritten, '.', q, location=top.location); + local isEMonad::Expr = + Silver_Expr { + $Expr {monadBind(top.location)} + ($Expr {eUnDec}, + (\x::$TypeExpr {typerepTypeExpr(monadInnerType(e.mtyperep, top.location), location=top.location)} -> + $Expr {monadReturn(top.location)} + (x.$QName {qName(q.location, q.name)}) + ) + ) + }; + top.monadRewritten = if isMonad(e.mtyperep, top.env) && + fst(monadsMatch(e.mtyperep, top.expectedMonad, top.mUpSubst)) + then isEMonad + else noMonad; + + top.mtyperep = if isMonad(e.mtyperep, top.env) && + fst(monadsMatch(e.mtyperep, top.expectedMonad, top.mUpSubst)) + then monadOfType(top.expectedMonad, q.typerep) + else q.typerep; + + top.notExplicitAttributes <- e.notExplicitAttributes ++ + if q.found + then case q.attrDcl of + -- TODO: restricted translation attributes? + -- | restrictedSynDcl(_, _, _) -> [] + -- | restrictedInhDcl(_, _, _) -> [] + | _ -> [(q.unparse, top.location)] + end + else []; +} aspect production decorateExprWith top::Expr ::= 'decorate' e::Expr 'with' '{' inh::ExprInhs '}' @@ -973,7 +1240,25 @@ top::ExprInh ::= lhs::ExprLHSExpr '=' e::Expr ';' } +aspect production decorationSiteExpr +top::Expr ::= '@' e::Expr +{ + top.mtyperep = e.mtyperep.decoratedType; + top.merrors := e.merrors; + top.monadicNames = e.monadicNames; + top.monadRewritten = decorationSiteExpr('@', e.monadRewritten, location=top.location); + e.monadicallyUsed = false; + local attribute errCheck1 :: TypeCheck; errCheck1.finalSubst = top.finalSubst; + e.mDownSubst = top.mDownSubst; + errCheck1.downSubst = e.mUpSubst; + top.mUpSubst = errCheck1.upSubst; + errCheck1 = check(e.typerep, uniqueDecoratedType(freshType(), inhSetType([]))); + top.merrors <- + if errCheck1.typeerror + then [err(top.location, "Operand to @ must be a unique reference with no inherited attributes. Instead it is of type " ++ errCheck1.leftpp)] + else []; +} aspect production trueConst top::Expr ::= 'true' @@ -1204,6 +1489,8 @@ concrete production ifThen top::Expr ::= 'if' e1::Expr 'then' e2::Expr 'end' --this is easier than anything else to do { top.unparse = "if " ++ e1.unparse ++ " then " ++ e2.unparse ++ " end"; + propagate config, grammarName, compiledGrammars, frame, env, flowEnv, finalSubst, originRules; + top.merrors <- if isMonad(e1.mtyperep, top.env) && monadsMatch(top.expectedMonad, e1.mtyperep, top.mDownSubst).fst then if monadsMatch(top.expectedMonad, e1.mtyperep, top.mDownSubst).fst @@ -1244,6 +1531,11 @@ top::Expr ::= 'if' e1::Expr 'then' e2::Expr 'end' --this is easier than anything e2.expectedMonad = if isMonad(e1.mtyperep, top.env) && monadsMatch(top.expectedMonad, e1.mtyperep, top.mDownSubst).fst then e1.mtyperep else top.expectedMonad; + + e1.alwaysDecorated = false; + e2.alwaysDecorated = false; + e1.isRoot = false; + e2.isRoot = false; forwards to ifThenElse('if', e1, 'then', e2, 'else', monadFail(top.location), location=top.location); } @@ -1915,16 +2207,26 @@ top::Expr ::= s::String_t --A list of the locations where arguments are monads used implicitly synthesized attribute monadTypesLocations::[Pair] occurs on AppExpr, AppExprs; +--A list of the annotation names, with the final argument being if it is monadic +synthesized attribute monadAnns::[(Type, QName, Boolean)] occurs on AnnoExpr, AnnoAppExprs; --A list of the actual types of arguments -synthesized attribute realTypes::[Type] occurs on AppExpr, AppExprs; +synthesized attribute realTypes::[Type] occurs on AppExpr, AppExprs, AnnoExpr, AnnoAppExprs; --The only monad banned from being used as an actual argument -attribute expectedMonad occurs on AppExpr, AppExprs; -propagate expectedMonad on AppExpr, AppExprs; +attribute expectedMonad occurs on AppExpr, AppExprs, AnnoExpr, AnnoAppExprs; +propagate expectedMonad on AppExpr, AppExprs, AnnoExpr, AnnoAppExprs; --Whether we're in a special case where monad arguments are allowed, despite the normal prohibition -autocopy attribute monadArgumentsAllowed::Boolean occurs on AppExpr, AppExprs; +inherited attribute monadArgumentsAllowed::Boolean occurs on AppExpr, AppExprs, AnnoExpr, AnnoAppExprs; + +--We need to put together all the args for the function giving fresh names +--Pass down the args from the regular args to add the annotated args at the end +inherited attribute previousArgs::AppExprs occurs on AnnoAppExprs; +synthesized attribute fullArgs::AppExprs occurs on AnnoAppExprs; +synthesized attribute rewrittenArg::AppExpr occurs on AnnoExpr; attribute monadRewritten, merrors, mDownSubst, mUpSubst occurs on AppExpr; attribute monadRewritten, merrors, mDownSubst, mUpSubst occurs on AppExprs; +attribute monadRewritten, merrors, mDownSubst, mUpSubst occurs on AnnoExpr; +attribute monadRewritten, merrors, mDownSubst, mUpSubst occurs on AnnoAppExprs; aspect production missingAppExpr top::AppExpr ::= '_' @@ -1943,7 +2245,7 @@ top::AppExpr ::= e::Expr top.realTypes = [e.mtyperep]; top.monadTypesLocations = if isMonadic - then [pair(e.mtyperep, top.appExprIndex+1)] + then [(e.mtyperep, top.appExprIndex+1)] else []; e.monadicallyUsed = isMonadic; top.monadicNames = e.monadicNames; @@ -1993,7 +2295,7 @@ top::AppExpr ::= e::Expr top.monadRewritten = presentAppExpr(e.monadRewritten, location=top.location); } -propagate mDownSubst, mUpSubst on AppExprs; +propagate monadArgumentsAllowed, mDownSubst, mUpSubst on AppExprs; aspect production snocAppExprs top::AppExprs ::= es::AppExprs ',' e::AppExpr @@ -2035,23 +2337,79 @@ top::AppExprs ::= top.monadRewritten = emptyAppExprs(location=top.location); } +propagate monadArgumentsAllowed, mDownSubst, mUpSubst on AnnoAppExprs; -aspect production exprRef -top::Expr ::= e::PartiallyDecorated Expr +aspect production annoExpr +top::AnnoExpr ::= qn::QName '=' e::AppExpr { + top.merrors := e.merrors; + + e.monadArgumentsAllowed = top.monadArgumentsAllowed; + + top.realTypes = e.realTypes; + --can be at most one entry + top.monadAnns = case e.monadTypesLocations of + | [(ty, _)] -> [(ty, qn, true)] + | _ -> [(e.appExprTyperep, qn, false)] + end; + top.monadicNames = e.monadicNames; + e.mDownSubst = top.mDownSubst; - e.expectedMonad = top.expectedMonad; - e.monadicallyUsed = top.monadicallyUsed; + top.mUpSubst = e.mUpSubst; + top.monadRewritten = annoExpr(qn, '=', e.monadRewritten, location=top.location); + + top.rewrittenArg = e.monadRewritten; +} + +aspect production snocAnnoAppExprs +top::AnnoAppExprs ::= es::AnnoAppExprs ',' e::AnnoExpr +{ + top.merrors := es.merrors ++ e.merrors; + + top.realTypes = es.realTypes ++ e.realTypes; + + top.monadAnns = es.monadAnns ++ e.monadAnns; + + top.monadicNames = es.monadicNames ++ e.monadicNames; + + top.monadRewritten = snocAnnoAppExprs(es.monadRewritten, ',', e.monadRewritten, location=top.location); + + es.previousArgs = top.previousArgs; + top.fullArgs = snocAppExprs(es.fullArgs, ',', e.rewrittenArg, location=top.location); +} + +aspect production oneAnnoAppExprs +top::AnnoAppExprs ::= e::AnnoExpr +{ top.merrors := e.merrors; - top.mUpSubst = e.mUpSubst; - top.mtyperep = e.mtyperep; + + top.realTypes = e.realTypes; + + top.monadAnns = e.monadAnns; + top.monadicNames = e.monadicNames; - top.monadRewritten = e.monadRewritten; + + top.monadRewritten = oneAnnoAppExprs(e.monadRewritten, location=top.location); + + top.fullArgs = snocAppExprs(top.previousArgs, ',', e.rewrittenArg, location=top.location); } +aspect production emptyAnnoAppExprs +top::AnnoAppExprs ::= +{ + top.merrors := []; + + top.realTypes = []; + top.monadAnns = []; + top.monadicNames = []; + + top.monadRewritten = emptyAnnoAppExprs(location=top.location); + + top.fullArgs = top.previousArgs; +} --Copper Expressions aspect production failureTerminalIdExpr @@ -2066,7 +2424,7 @@ top::Expr ::= 'disambiguationFailure' aspect production lexerClassReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.mUpSubst = top.mDownSubst; top.mtyperep = q.lookupValue.typeScheme.typerep; diff --git a/grammars/silver/compiler/extension/implicit_monads/Lambda.sv b/grammars/silver/compiler/extension/implicit_monads/Lambda.sv index 6fca47f21..52e5ea30f 100644 --- a/grammars/silver/compiler/extension/implicit_monads/Lambda.sv +++ b/grammars/silver/compiler/extension/implicit_monads/Lambda.sv @@ -17,7 +17,7 @@ top::Expr ::= params::ProductionRHS e::Expr aspect production lambdaParamReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.merrors := []; propagate mDownSubst, mUpSubst; diff --git a/grammars/silver/compiler/extension/implicit_monads/Let.sv b/grammars/silver/compiler/extension/implicit_monads/Let.sv index 975715858..17c408ebf 100644 --- a/grammars/silver/compiler/extension/implicit_monads/Let.sv +++ b/grammars/silver/compiler/extension/implicit_monads/Let.sv @@ -1,6 +1,6 @@ grammar silver:compiler:extension:implicit_monads; - +import silver:compiler:analysis:uniqueness; aspect production letp top::Expr ::= la::AssignExpr e::Expr @@ -19,6 +19,7 @@ top::Expr ::= la::AssignExpr e::Expr ne.finalSubst = top.mUpSubst; ne.env = newScopeEnv(la.mdefs, top.env); ne.expectedMonad = top.expectedMonad; + ne.alwaysDecorated = top.alwaysDecorated; ne.originRules = top.originRules; ne.isRoot = top.isRoot; @@ -116,10 +117,10 @@ top::AssignExpr ::= id::Name '::' t::TypeExpr '=' e::Expr top.mdefs = [lexicalLocalDef(top.grammarName, id.location, fName, performSubstitution(t.typerep, top.mUpSubst), - e.flowVertexInfo, e.flowDeps)]; + e.flowVertexInfo, e.flowDeps, e.uniqueRefs)]; top.bindInList = if isMonad(e.mtyperep, top.env) && fst(monadsMatch(e.mtyperep, top.expectedMonad, top.mUpSubst)) - then [pair(id, t)] + then [(id, t)] else []; top.fixedAssigns = if isMonad(e.mtyperep, top.env) && fst(monadsMatch(e.mtyperep, top.expectedMonad, top.mUpSubst)) @@ -134,7 +135,7 @@ top::AssignExpr ::= id::Name '::' t::TypeExpr '=' e::Expr aspect production lexicalLocalReference -top::Expr ::= q::PartiallyDecorated QName fi::ExprVertexInfo fd::[FlowVertex] +top::Expr ::= q::Decorated! QName _ _ _ { top.merrors := []; propagate mDownSubst, mUpSubst; diff --git a/grammars/silver/compiler/extension/implicit_monads/PatternTypes.sv b/grammars/silver/compiler/extension/implicit_monads/PatternTypes.sv index a8bbd0c76..f817c1888 100644 --- a/grammars/silver/compiler/extension/implicit_monads/PatternTypes.sv +++ b/grammars/silver/compiler/extension/implicit_monads/PatternTypes.sv @@ -3,6 +3,8 @@ grammar silver:compiler:extension:implicit_monads; aspect production prodAppPattern top::Pattern ::= prod::QName '(' ps::PatternList ')' { + propagate env; + -- TODO: is this right? Seems like we should unify with ps pattern types? top.patternType = prod.lookupValue.typeScheme.typerep.outputType; } diff --git a/grammars/silver/compiler/extension/implicit_monads/PrimitiveMatch.sv b/grammars/silver/compiler/extension/implicit_monads/PrimitiveMatch.sv index aa0076065..375e2f2c8 100644 --- a/grammars/silver/compiler/extension/implicit_monads/PrimitiveMatch.sv +++ b/grammars/silver/compiler/extension/implicit_monads/PrimitiveMatch.sv @@ -264,8 +264,9 @@ top::PrimPattern ::= qn::QName '(' ns::VarBinders ')' arr::Arrow_kwd e::Expr ne.grammarName = top.grammarName; ne.config = top.config; ne.flowEnv = top.flowEnv; + ne.alwaysDecorated = false; ne.originRules = top.originRules; - ne.isRoot = top.isRoot; + ne.isRoot = false; ne.finalSubst = top.finalSubst; ne.downSubst = top.mDownSubst; diff --git a/grammars/silver/compiler/extension/implicit_monads/ProductionBody.sv b/grammars/silver/compiler/extension/implicit_monads/ProductionBody.sv index 5d4a7654a..8dcfc4e60 100644 --- a/grammars/silver/compiler/extension/implicit_monads/ProductionBody.sv +++ b/grammars/silver/compiler/extension/implicit_monads/ProductionBody.sv @@ -13,10 +13,13 @@ concrete production emptyAttributeDef top::ProductionStmt ::= 'implicit' dl::DefLHS '.' attr::QNameAttrOccur '=' ';' { top.unparse = "\timplicit " ++ dl.unparse ++ "." ++ attr.unparse ++ " = ;"; + propagate grammarName, compiledGrammars, config, frame, env, flowEnv, finalSubst, originRules; top.productionAttributes := []; top.defs := []; - top.uniqueSignificantExpression := []; + top.forwardExpr := []; + top.returnExpr := []; + top.undecorateExpr := []; top.containsPluck = false; @@ -46,18 +49,21 @@ top::ProductionStmt ::= 'implicit' dl::DefLHS '.' attr::QNameAttrOccur '=' ';' } -global partialDefaultAttributeDef::(ProductionStmt ::= PartiallyDecorated DefLHS PartiallyDecorated QNameAttrOccur Expr Location) = - \ dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr loc::Location -> - attributeDef(newPartial(dl), '.', newPartial(attr), '=', e, ';', location=loc); +global partialDefaultAttributeDef::(ProductionStmt ::= Decorated! DefLHS Decorated! QNameAttrOccur Expr Location) = + \ dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr loc::Location -> + attributeDef(newUnique(dl), '.', newUnique(attr), '=', e, ';', location=loc); concrete production implicitAttributeDef top::ProductionStmt ::= 'implicit' dl::DefLHS '.' attr::QNameAttrOccur '=' e::Expr ';' { top.unparse = "\timplicit" ++ dl.unparse ++ "." ++ attr.unparse ++ " = ;"; + propagate grammarName, compiledGrammars, config, frame, env, flowEnv, finalSubst, originRules; top.productionAttributes := []; top.defs := []; - top.uniqueSignificantExpression := []; + top.forwardExpr := []; + top.returnExpr := []; + top.undecorateExpr := []; top.containsPluck = false; @@ -75,14 +81,13 @@ top::ProductionStmt ::= 'implicit' dl::DefLHS '.' attr::QNameAttrOccur '=' e::Ex dl.defLHSattr = attr; attr.attrFor = dl.typerep; - local fwd::ProductionStmt = + forwards to (if null(merrors) then if attr.found then attr.attrDcl.attrDefDispatcher --if not found, let the normal dispatcher handle it else partialDefaultAttributeDef else errorAttributeDef(merrors, _, _, _, location=_))(dl, attr, e, top.location); - forwards to fwd; } @@ -93,10 +98,13 @@ top::ProductionStmt ::= 'restricted' dl::DefLHS '.' attr::QNameAttrOccur '=' e:: { e.downSubst = top.downSubst; top.unparse = "\trestricted" ++ dl.unparse ++ "." ++ attr.unparse ++ " = ;"; + propagate grammarName, compiledGrammars, config, frame, env, flowEnv, finalSubst, originRules; top.productionAttributes := []; top.defs := []; - top.uniqueSignificantExpression := []; + top.forwardExpr := []; + top.returnExpr := []; + top.undecorateExpr := []; top.containsPluck = false; @@ -114,15 +122,13 @@ top::ProductionStmt ::= 'restricted' dl::DefLHS '.' attr::QNameAttrOccur '=' e:: dl.defLHSattr = attr; attr.attrFor = dl.typerep; - local fwd::ProductionStmt = + forwards to (if null(merrors) then if attr.found then attr.attrDcl.attrDefDispatcher --if not found, let the normal dispatcher handle it else partialDefaultAttributeDef else errorAttributeDef(merrors, _, _, _, location=_))(dl, attr, e, top.location); - - forwards to fwd; } @@ -132,10 +138,13 @@ concrete production unrestrictedAttributeDef top::ProductionStmt ::= 'unrestricted' dl::DefLHS '.' attr::QNameAttrOccur '=' e::Expr ';' { top.unparse = "\tunrestricted" ++ dl.unparse ++ "." ++ attr.unparse ++ " = ;"; + propagate grammarName, compiledGrammars, config, frame, env, flowEnv, finalSubst, originRules; top.productionAttributes := []; top.defs := []; - top.uniqueSignificantExpression := []; + top.forwardExpr := []; + top.returnExpr := []; + top.undecorateExpr := []; dl.defLHSattr = attr; attr.attrFor = dl.typerep; @@ -150,7 +159,7 @@ top::ProductionStmt ::= 'unrestricted' dl::DefLHS '.' attr::QNameAttrOccur '=' e [err(top.location, "Unrestricted equations can only be used for attributes " ++ "not declared to be restricted or implicit; " ++ attr.unparse ++ " is implicit")]; - local fwd::ProductionStmt = + forwards to (if attr.found then case attr.attrDcl of | restrictedSynDcl(_, _, _) -> errorAttributeDef(restrictedErr, _, _, _, location=_) @@ -161,7 +170,6 @@ top::ProductionStmt ::= 'unrestricted' dl::DefLHS '.' attr::QNameAttrOccur '=' e end --if not found, let the normal dispatcher handle it else partialDefaultAttributeDef)(dl, attr, e, top.location); - forwards to fwd; } @@ -175,7 +183,7 @@ function buildExplicitAttrErrors { return case l of | [] -> [] - | pair(name, loca)::t -> + | (name, loca)::t -> err(loca, "Attributes accessed in restricted equations must be restricted; " ++ name ++ " is not")::buildExplicitAttrErrors(t) end; @@ -185,50 +193,56 @@ function buildExplicitAttrErrors --productions for error checking on restricted attributes abstract production restrictedSynAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { + undecorates to attributeDef(dl, '.', attr, '=', e, ';', location=top.location); top.unparse = dl.unparse ++ "." ++ attr.unparse ++ " = " ++ e.unparse ++ ";"; + propagate grammarName, compiledGrammars, config, frame, env, flowEnv, finalSubst, originRules; e.downSubst = top.downSubst; - e.originRules = top.originRules; + e.alwaysDecorated = false; e.isRoot = true; top.containsPluck = false; - top.uniqueSignificantExpression := []; + top.forwardExpr := []; + top.returnExpr := []; + top.undecorateExpr := []; local merrors::[Message] = --gives errors for implicit/unrestricted attributes used buildExplicitAttrErrors(e.notExplicitAttributes); - local fwd::ProductionStmt = + forwards to (if null(merrors) then synthesizedAttributeDef(_, _, _, location=_) else errorAttributeDef(merrors, _, _, _, location=_))(dl, attr, e, top.location); - forwards to fwd; } abstract production restrictedInhAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { + undecorates to attributeDef(dl, '.', attr, '=', e, ';', location=top.location); top.unparse = dl.unparse ++ "." ++ attr.unparse ++ " = " ++ e.unparse ++ ";"; + propagate grammarName, compiledGrammars, config, frame, env, flowEnv, finalSubst, originRules; e.downSubst = top.downSubst; - e.originRules = top.originRules; + e.alwaysDecorated = false; e.isRoot = true; top.containsPluck = false; - top.uniqueSignificantExpression := []; + top.forwardExpr := []; + top.returnExpr := []; + top.undecorateExpr := []; local merrors::[Message] = --gives errors for implicit/unrestricted attributes used buildExplicitAttrErrors(e.notExplicitAttributes); - local fwd::ProductionStmt = + forwards to (if null(merrors) then inheritedAttributeDef(_, _, _, location=_) else errorAttributeDef(merrors, _, _, _, location=_))(dl, attr, e, top.location); - forwards to fwd; } @@ -236,23 +250,26 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated Q --productions for error checking on implicit attributes abstract production implicitSynAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { + undecorates to attributeDef(dl, '.', attr, '=', e, ';', location=top.location); top.unparse = dl.unparse ++ "." ++ attr.unparse ++ " = " ++ e.unparse ++ ";"; + propagate grammarName, compiledGrammars, config, frame, env, flowEnv, originRules; e.downSubst = top.downSubst; e.mDownSubst = top.downSubst; e.finalSubst = e.mUpSubst; - e.env = top.env; - e.originRules = top.originRules; + e.alwaysDecorated = false; e.isRoot = true; e.expectedMonad = attr.typerep; top.containsPluck = false; - top.uniqueSignificantExpression := []; + top.forwardExpr := []; + top.returnExpr := []; + top.undecorateExpr := []; - local fwd::ProductionStmt = + forwards to (if null(e.merrors) then if fst(monadsMatch(attr.typerep, e.mtyperep, e.mUpSubst)) then synthesizedAttributeDef(_, _, e.monadRewritten, location=_) @@ -261,28 +278,30 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated Q ($Expr {e.monadRewritten}) }, location=_) else errorAttributeDef(e.merrors, _, _, e.monadRewritten, location=_))(dl, attr, top.location); - forwards to fwd; } abstract production implicitInhAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { + undecorates to attributeDef(dl, '.', attr, '=', e, ';', location=top.location); top.unparse = dl.unparse ++ "." ++ attr.unparse ++ " = " ++ e.unparse ++ ";"; + propagate grammarName, compiledGrammars, config, frame, env, flowEnv, originRules; e.downSubst = top.downSubst; e.mDownSubst = top.downSubst; e.finalSubst = e.mUpSubst; - e.env = top.env; - e.originRules = top.originRules; + e.alwaysDecorated = false; e.isRoot = true; e.expectedMonad = attr.typerep; top.containsPluck = false; - top.uniqueSignificantExpression := []; + top.forwardExpr := []; + top.returnExpr := []; + top.undecorateExpr := []; - local fwd::ProductionStmt = + forwards to (if null(e.merrors) then if fst(monadsMatch(attr.typerep, e.mtyperep, e.mUpSubst)) then inheritedAttributeDef(_, _, e.monadRewritten, location=_) @@ -291,6 +310,5 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated Q ($Expr {e.monadRewritten}) }, location=_) else errorAttributeDef(e.merrors, _, _, e.monadRewritten, location=_))(dl, attr, top.location); - forwards to fwd; } diff --git a/grammars/silver/compiler/extension/implicit_monads/Project.sv b/grammars/silver/compiler/extension/implicit_monads/Project.sv index 255f02828..b4fe84c12 100644 --- a/grammars/silver/compiler/extension/implicit_monads/Project.sv +++ b/grammars/silver/compiler/extension/implicit_monads/Project.sv @@ -4,10 +4,12 @@ imports silver:compiler:definition:core; imports silver:compiler:definition:type:syntax; imports silver:compiler:definition:flow:driver; imports silver:compiler:definition:flow:ast; +imports silver:compiler:definition:flow:env; imports silver:compiler:driver:util; imports silver:compiler:definition:env; imports silver:compiler:definition:type; +imports silver:compiler:analysis:typechecking:core; imports silver:util:cmdargs; diff --git a/grammars/silver/compiler/extension/implicit_monads/Util.sv b/grammars/silver/compiler/extension/implicit_monads/Util.sv index 1542009be..b65a9b5f7 100644 --- a/grammars/silver/compiler/extension/implicit_monads/Util.sv +++ b/grammars/silver/compiler/extension/implicit_monads/Util.sv @@ -35,7 +35,7 @@ threaded attribute mDownSubst, mUpSubst::Substitution; function isMonad -Boolean ::= ty::Type env::Decorated Env +Boolean ::= ty::Type env::Env { return case dropDecorated(ty) of | appType(t, _) -> length(getInstanceDcl("silver:core:Monad", t, env)) > 0 @@ -44,7 +44,7 @@ Boolean ::= ty::Type env::Decorated Env } function isMonadPlus -Boolean ::= ty::Type env::Decorated Env +Boolean ::= ty::Type env::Env { return case dropDecorated(ty) of | appType(t, _) -> length(getInstanceDcl("silver:core:MonadPlus", t, env)) > 0 @@ -53,7 +53,7 @@ Boolean ::= ty::Type env::Decorated Env } function isMonadFail -Boolean ::= ty::Type env::Decorated Env +Boolean ::= ty::Type env::Env { return case dropDecorated(ty) of | appType(t, _) -> length(getInstanceDcl("silver:core:MonadFail", t, env)) > 0 @@ -78,7 +78,7 @@ Pair ::= ty1::Type ty2::Type subst::Substitution case dropDecorated(ty1), dropDecorated(ty2) of | appType(c1, _), appType(c2, _) -> tyMatch(c1, c2, subst) - | _, _ -> pair(false, subst) + | _, _ -> (false, subst) end; } @@ -106,7 +106,7 @@ Pair ::= t1::Type t2::Type subst::Substitution { local tycheck::TypeCheck = check(t1, t2); tycheck.downSubst = subst; - return pair(!tycheck.typeerror, tycheck.upSubst); + return (!tycheck.typeerror, tycheck.upSubst); } @@ -143,7 +143,7 @@ String ::= ty::Type | appType(c, _) -> --We use nonterminalType to get it to show just an underscore --e.g. this gives us Maybe<_>, Either - prettyType(appType(c, nonterminalType("_", [], false))) + prettyType(appType(c, nonterminalType("_", [], false, false))) | _ -> error("Tried to get monadToString for a non-monadic type (" ++ prettyType(ty) ++ ")") end; } @@ -239,7 +239,7 @@ Expr ::= names::[Pair] body::Expr loc::Location local sig::ProductionRHS = foldr(\ pr::Pair p::ProductionRHS -> case pr of - | pair(n, ty) -> + | (n, ty) -> productionRHSCons(productionRHSElem(name(n, loc), '::', typerepTypeExpr(ty, location=loc), location=loc), p, location=loc) diff --git a/grammars/silver/compiler/extension/patternmatching/Case.sv b/grammars/silver/compiler/extension/patternmatching/Case.sv index 77b7583db..171850119 100644 --- a/grammars/silver/compiler/extension/patternmatching/Case.sv +++ b/grammars/silver/compiler/extension/patternmatching/Case.sv @@ -10,8 +10,7 @@ imports silver:compiler:modification:list; --Get mwdaWrn production for completeness analysis import silver:compiler:analysis:warnings:flow; ---Get getNonforwardingProds to check all are covered -import silver:compiler:definition:flow:env only getNonforwardingProds; +import silver:compiler:definition:flow:env; import silver:compiler:definition:type:syntax only typerepTypeExpr; import silver:compiler:modification:let_fix; @@ -28,12 +27,12 @@ terminal Matches_kwd 'matches' lexer classes {KEYWORD}; -- MR | ... nonterminal MRuleList with location, config, unparse, env, frame, errors, freeVars, matchRuleList, matchRulePatternSize; -propagate errors, freeVars on MRuleList; +propagate config, frame, env, errors, freeVars, matchRulePatternSize on MRuleList; -- Turns MRuleList (of MatchRules) into [AbstractMatchRule] synthesized attribute matchRuleList :: [AbstractMatchRule]; -- Notification of the number of expressions being matched upon -autocopy attribute matchRulePatternSize :: Integer; +inherited attribute matchRulePatternSize :: Integer; -- P -> E nonterminal MatchRule with location, config, unparse, env, frame, errors, freeVars, matchRuleList, matchRulePatternSize; @@ -50,7 +49,7 @@ synthesized attribute hasCondition::Boolean; -- P , ... nonterminal PatternList with location, config, unparse, patternList, env, frame, errors, patternVars, patternVarEnv; -propagate errors on PatternList; +propagate config, frame, env, errors on PatternList; -- Turns PatternList into [Pattern] synthesized attribute patternList :: [Decorated Pattern]; @@ -73,7 +72,7 @@ concrete production caseExpr_c top::Expr ::= 'case' es::Exprs 'of' Opt_Vbar_t ml::MRuleList 'end' { top.unparse = "case " ++ es.unparse ++ " of " ++ ml.unparse ++ " end"; - propagate freeVars; + propagate config, frame, env, freeVars; ml.matchRulePatternSize = length(es.rawExprs); top.errors <- ml.errors; @@ -98,6 +97,7 @@ top::Expr ::= es::[Expr] ml::[AbstractMatchRule] complete::Boolean failExpr::Exp "(case " ++ implode(", ", map((.unparse), es)) ++ " of " ++ implode(" | ", map((.unparse), ml)) ++ " | _ -> " ++ failExpr.unparse ++ " end :: " ++ prettyType(retType) ++ ")"; + propagate frame; top.freeVars := concat(map(getFreeVars(top.frame, _), es) ++ map(getFreeVars(top.frame, _), ml) ++ [failExpr.freeVars]); {-Checking Pattern Completeness @@ -166,7 +166,7 @@ top::Expr ::= es::[Expr] ml::[AbstractMatchRule] complete::Boolean failExpr::Exp local fwdResult::Expr = foldr(\ p::(String, Expr) rest::Expr -> makeLet(top.location, p.1, freshType(), p.2, rest), - compiledCase, zipWith(pair(_, _), names, es)); + compiledCase, zip(names, es)); forwards to fwdResult; } @@ -187,15 +187,15 @@ Pair<[AbstractMatchRule] [AbstractMatchRule]> ::= lst::[AbstractMatchRule] { return case lst of --this probably shouldn't be called with an empty list, but catch it anyway - | [] -> pair([], []) - | [mr] -> pair([mr], []) + | [] -> ([], []) + | [mr] -> ([mr], []) | mr1::mr2::rest -> if mr1.isVarMatchRule == mr2.isVarMatchRule then --both have the same type of pattern let sub::Pair<[AbstractMatchRule] [AbstractMatchRule]> = initialSegmentPatternType(mr2::rest) - in pair(mr1::sub.fst, sub.snd) end + in (mr1::sub.fst, sub.snd) end else --the first has a different type of pattern than the second - pair([mr1], mr2::rest) + ([mr1], mr2::rest) end; } @@ -215,7 +215,7 @@ Pair<[AbstractMatchRule] [AbstractMatchRule]> ::= lst::[AbstractMatchRule] - primitive match). -} function splitPatternGroups -[[AbstractMatchRule]] ::= ml::[AbstractMatchRule] env::Decorated Env +[[AbstractMatchRule]] ::= ml::[AbstractMatchRule] env::Env { local firstPatt::Decorated Pattern = head(ml).headPattern; @@ -283,7 +283,7 @@ function splitPatternGroups --Compile a case expression `case es of ml` down into primitive matches function compileCaseExpr Expr ::= es::[Expr] ml::[AbstractMatchRule] failExpr::Expr retType::Type - loc::Location env::Decorated Env + loc::Location env::Env { --Split rules into segments of non-forwarding constructors, all same -- forwarding constructor, and variables based on first pattern @@ -333,7 +333,7 @@ Expr ::= es::[Expr] ml::[AbstractMatchRule] failExpr::Expr retType::Type --implement the match function compilePatternGroups Expr ::= matchEs::[Expr] ruleGroups::[[AbstractMatchRule]] finalFail::Expr - retType::Type loc::Location env::Decorated Env + retType::Type loc::Location env::Env { local compileRest::Expr = compilePatternGroups(matchEs, tail(ruleGroups), finalFail, @@ -407,7 +407,7 @@ Expr ::= matchEs::[Expr] ruleGroups::[[AbstractMatchRule]] finalFail::Expr -} function allConCaseTransform PrimPattern ::= currExpr::Expr restExprs::[Expr] failCase::Expr - retType::Type mrs::[AbstractMatchRule] env::Decorated Env + retType::Type mrs::[AbstractMatchRule] env::Env { local names :: [Name] = map(patternListVars, head(mrs).headPattern.patternSubPatternList); @@ -561,7 +561,7 @@ function allConCaseCheckOverlapping set (matching over multiple values at once). -} function checkCompleteness -Maybe<[Pattern]> ::= lst::[[Decorated Pattern]] env::Decorated Env +Maybe<[Pattern]> ::= lst::[[Decorated Pattern]] env::Env flowEnv::FlowEnv { local pattGroups::([[Decorated Pattern]], [[Decorated Pattern]]) = @@ -661,7 +661,7 @@ function groupAllPattsByHead if null(pattLists) then [] else case groupAllPattsByHeadHelp(head(pattLists), tail(pattLists)) of - | pair(thisGroup, others) -> + | (thisGroup, others) -> (head(pattLists)::thisGroup)::groupAllPattsByHead(others) end; } @@ -671,12 +671,12 @@ Pair<[[Decorated Pattern]] [[Decorated Pattern]]> ::= { return case rest of - | [] -> pair([], []) + | [] -> ([], []) | h::t -> case groupAllPattsByHeadHelp(item, t) of - | pair(grp, rst) -> + | (grp, rst) -> if head(item).patternSortKey == head(h).patternSortKey - then pair(h::grp, rst) - else pair(grp, h::rst) + then (h::grp, rst) + else (grp, h::rst) end end; } @@ -738,7 +738,7 @@ Pattern ::= lst::[String] initial::String --The first match can only be completed by a variable function checkPrimitiveCompleteness Maybe<[Pattern]> ::= conPatts::[[Decorated Pattern]] varPatts::[[Decorated Pattern]] - env::Decorated Env flowEnv::FlowEnv + env::Env flowEnv::FlowEnv { local firstPatts::[Decorated Pattern] = map(head, conPatts); local firstPattMissing::Maybe = @@ -783,7 +783,7 @@ Maybe<[Pattern]> ::= conPatts::[[Decorated Pattern]] varPatts::[[Decorated Patte --The first match can be completed by a variable or patterns for true and false function checkBooleanCompleteness Maybe<[Pattern]> ::= conPatts::[[Decorated Pattern]] varPatts::[[Decorated Pattern]] - env::Decorated Env flowEnv::FlowEnv + env::Env flowEnv::FlowEnv { --create groups for true and false local grouped::([[Decorated Pattern]], [[Decorated Pattern]]) = @@ -832,7 +832,7 @@ Maybe<[Pattern]> ::= conPatts::[[Decorated Pattern]] varPatts::[[Decorated Patte --The first match can be completed by a variable or patterns for cons and nil function checkListCompleteness Maybe<[Pattern]> ::= conPatts::[[Decorated Pattern]] varPatts::[[Decorated Pattern]] - env::Decorated Env flowEnv::FlowEnv + env::Env flowEnv::FlowEnv { --create groups for nil and cons local grouped::([[Decorated Pattern]], [[Decorated Pattern]]) = @@ -896,7 +896,7 @@ Maybe<[Pattern]> ::= conPatts::[[Decorated Pattern]] varPatts::[[Decorated Patte -- by having a pattern for each non-forwarding production function checkNonterminalCompleteness Maybe<[Pattern]> ::= conPatts::[[Decorated Pattern]] varPatts::[[Decorated Pattern]] - env::Decorated Env flowEnv::FlowEnv + env::Env flowEnv::FlowEnv { local numPatts::Integer = length(head(conPatts)); @@ -946,7 +946,7 @@ Maybe<[Pattern]> ::= conPatts::[[Decorated Pattern]] varPatts::[[Decorated Patte nt.env = env; local isClosed::Boolean = case nt.lookupType.dcls of - | ntDcl(_, _, closed, _) :: _ -> closed + | ntDcl(_, _, _, closed, _) :: _ -> closed | _ -> false -- default, if the lookup fails end; @@ -971,7 +971,7 @@ Maybe<[Pattern]> ::= conPatts::[[Decorated Pattern]] varPatts::[[Decorated Patte --Check every set of patterns in conGrps is complete, when varPatts is added to it function checkAllProdGroupsComplete Maybe<[Pattern]> ::= conGrps::[ [[Decorated Pattern]] ] varPatts::[[Decorated Pattern]] - env::Decorated Env flowEnv::FlowEnv + env::Env flowEnv::FlowEnv { local hdProdPatt::Decorated Pattern = head(head(head(conGrps))); local numChildren::Integer = length(hdProdPatt.patternSubPatternList); @@ -1003,7 +1003,7 @@ Maybe<[Pattern]> ::= conGrps::[ [[Decorated Pattern]] ] varPatts::[[Decorated Pa --check that all required productions are present function checkAllProdsRepresented -Maybe ::= givenPatts::[Decorated Pattern] requiredProds::[String] env::Decorated Env +Maybe ::= givenPatts::[Decorated Pattern] requiredProds::[String] env::Env { {- We walk down through requiredProds rather than pattGroups. We @@ -1058,6 +1058,8 @@ concrete production matchRule_c top::MatchRule ::= pt::PatternList '->' e::Expr { top.unparse = pt.unparse ++ " -> " ++ e.unparse; + propagate frame, config, env; + top.errors := pt.errors; -- e.errors is examined later, after transformation. top.freeVars := ts:removeAll(pt.patternVars, e.freeVars); @@ -1074,6 +1076,8 @@ concrete production matchRuleWhen_c top::MatchRule ::= pt::PatternList 'when' cond::Expr '->' e::Expr { top.unparse = pt.unparse ++ " when " ++ cond.unparse ++ " -> " ++ e.unparse; + propagate frame, config, env; + top.errors := pt.errors; -- e.errors is examined later, after transformation, as is cond.errors top.freeVars := ts:removeAll(pt.patternVars, cond.freeVars ++ e.freeVars); @@ -1083,13 +1087,15 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr '->' e::Expr pt.patternVarEnv = []; - top.matchRuleList = [matchRule(pt.patternList, just(pair(cond, nothing())), e, location=top.location)]; + top.matchRuleList = [matchRule(pt.patternList, just((cond, nothing())), e, location=top.location)]; } concrete production matchRuleWhenMatches_c top::MatchRule ::= pt::PatternList 'when' cond::Expr 'matches' p::Pattern '->' e::Expr { top.unparse = pt.unparse ++ " when " ++ cond.unparse ++ " matches " ++ p.unparse ++ " -> " ++ e.unparse; + propagate frame, config, env; + top.errors := pt.errors; -- e.errors is examined later, after transformation, as is cond.errors top.freeVars := ts:removeAll(pt.patternVars, cond.freeVars ++ ts:removeAll(p.patternVars, e.freeVars)); @@ -1100,7 +1106,7 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr 'matches' p::Pattern '->' e pt.patternVarEnv = []; p.patternVarEnv = pt.patternVars; - top.matchRuleList = [matchRule(pt.patternList, just(pair(cond, just(p))), e, location=top.location)]; + top.matchRuleList = [matchRule(pt.patternList, just((cond, just(p))), e, location=top.location)]; } abstract production matchRule @@ -1112,11 +1118,13 @@ top::AbstractMatchRule ::= pl::[Decorated Pattern] top.unparse = implode(", ", map((.unparse), pl)) ++ case cond of - | just(pair(c, just(p))) -> " when " ++ c.unparse ++ " matches " ++ p.unparse - | just(pair(c, nothing())) -> " when " ++ c.unparse + | just((c, just(p))) -> " when " ++ c.unparse ++ " matches " ++ p.unparse + | just((c, nothing())) -> " when " ++ c.unparse | nothing() -> "" end ++ " -> " ++ e.unparse; + propagate frame; + top.freeVars := ts:removeAll(concat(map((.patternVars), pl)), case cond of | just((e1, just(p))) -> getFreeVars(top.frame, e1) ++ ts:removeAll(p.patternVars, e.freeVars) @@ -1167,6 +1175,7 @@ top::PatternList ::= p::Pattern ',' ps1::PatternList top.unparse = p.unparse ++ (if ps1.unparse == "" then "" else ", " ++ ps1.unparse); top.patternVars = p.patternVars ++ ps1.patternVars; + p.patternVarEnv = top.patternVarEnv; ps1.patternVarEnv = p.patternVarEnv ++ p.patternVars; top.patternList = p :: ps1.patternList; @@ -1248,7 +1257,7 @@ AbstractMatchRule ::= headExpr::Expr headType::Type absRule::AbstractMatchRule matchRule( restPat, case cond of - | just(pair(c, p)) -> just(pair(makeLet(absRule.location, pvn, headType, headExpr, c), p)) + | just((c, p)) -> just((makeLet(absRule.location, pvn, headType, headExpr, c), p)) | nothing() -> nothing() end, makeLet(absRule.location, pvn, headType, headExpr, e), @@ -1281,17 +1290,6 @@ Expr ::= l::Location s::String t::Type e::Expr o::Expr o, location=l); } -function ensureDecoratedExpr -Expr ::= e::PartiallyDecorated Expr -{ - local et :: Type = performSubstitution(e.typerep, e.upSubst); - local eRef :: Expr = exprRef(e, location=e.location); - - return if isDecorable(et, e.env) - then decorateExprWithEmpty('decorate', eRef, 'with', '{', '}', location=e.location) - else eRef; -} - instance Eq AbstractMatchRule { eq = \ a::AbstractMatchRule b::AbstractMatchRule -> a.headPattern.patternSortKey == b.headPattern.patternSortKey; @@ -1322,13 +1320,13 @@ Expr ::= ml::[AbstractMatchRule] failExpr::Expr { return case ml of - | matchRule(_, just(pair(c, nothing())), e) :: tl -> + | matchRule(_, just((c, nothing())), e) :: tl -> Silver_Expr { if $Expr{c} then $Expr{e} else $Expr{buildMatchWhenConditionals(tl, failExpr)} } - | matchRule(_, just(pair(c, just(p))), e) :: tl -> + | matchRule(_, just((c, just(p))), e) :: tl -> Silver_Expr { case $Expr{c} of | $Pattern{p} -> $Expr{e} diff --git a/grammars/silver/compiler/extension/patternmatching/PatternTypes.sv b/grammars/silver/compiler/extension/patternmatching/PatternTypes.sv index 0694c431b..1f74d87f2 100644 --- a/grammars/silver/compiler/extension/patternmatching/PatternTypes.sv +++ b/grammars/silver/compiler/extension/patternmatching/PatternTypes.sv @@ -6,6 +6,7 @@ import silver:compiler:modification:list only LSqr_t, RSqr_t; - The forms of syntactic patterns that are permissible in (nested) case expresssions. -} nonterminal Pattern with location, config, unparse, env, frame, errors, patternVars, patternVarEnv, patternIsVariable, patternVariableName, patternSubPatternList, patternNamedSubPatternList, patternSortKey, isPrimitivePattern, isBoolPattern, isListPattern, patternTypeName; +propagate config, frame, env, errors on Pattern; {-- - The names of all var patterns in the pattern. @@ -14,7 +15,7 @@ synthesized attribute patternVars :: [String]; {-- - The names of all var patterns seen so far. -} -autocopy attribute patternVarEnv :: [String]; +inherited attribute patternVarEnv :: [String]; {-- - False if it actually matches anything specific, true if it's a variable/wildcard. -} @@ -70,7 +71,6 @@ concrete production prodAppPattern_named top::Pattern ::= prod::QName '(' ps::PatternList ',' nps::NamedPatternList ')' { top.unparse = prod.unparse ++ "(" ++ ps.unparse ++ ")"; - top.errors := ps.errors ++ nps.errors; local parms :: Integer = prod.lookupValue.typeScheme.arity; @@ -79,6 +79,7 @@ top::Pattern ::= prod::QName '(' ps::PatternList ',' nps::NamedPatternList ')' else [err(prod.location, prod.name ++ " has " ++ toString(parms) ++ " parameters but " ++ toString(length(ps.patternList)) ++ " patterns were provided")]; top.patternVars = ps.patternVars ++ nps.patternVars; + ps.patternVarEnv = top.patternVarEnv; nps.patternVarEnv = ps.patternVarEnv ++ ps.patternVars; top.patternIsVariable = false; @@ -112,7 +113,6 @@ concrete production wildcPattern top::Pattern ::= '_' { top.unparse = "_"; - top.errors := []; top.patternVars = []; top.patternIsVariable = true; @@ -136,7 +136,6 @@ concrete production varPattern top::Pattern ::= v::Name { top.unparse = v.name; - top.errors := []; top.errors <- if contains(v.name, top.patternVarEnv) then [err(v.location, "Duplicate pattern variable " ++ v.name)] @@ -171,7 +170,7 @@ abstract production errorPattern top::Pattern ::= msg::[Message] { top.unparse = s"{-${messagesToString(msg)}-}"; - top.errors := msg; + top.errors <- msg; top.patternVars = []; top.patternIsVariable = true; @@ -212,7 +211,6 @@ concrete production intPattern top::Pattern ::= num::Int_t { top.unparse = num.lexeme; - top.errors := []; top.patternVars = []; top.patternSubPatternList = []; @@ -227,7 +225,6 @@ concrete production fltPattern top::Pattern ::= num::Float_t { top.unparse = num.lexeme; - top.errors := []; top.patternVars = []; top.patternSubPatternList = []; @@ -242,7 +239,6 @@ concrete production strPattern top::Pattern ::= str::String_t { top.unparse = str.lexeme; - top.errors := []; top.patternVars = []; top.patternSubPatternList = []; @@ -257,7 +253,6 @@ concrete production truePattern top::Pattern ::= 'true' { top.unparse = "true"; - top.errors := []; top.patternVars = []; top.patternSubPatternList = []; @@ -272,7 +267,6 @@ concrete production falsePattern top::Pattern ::= 'false' { top.unparse = "false"; - top.errors := []; top.patternVars = []; top.patternSubPatternList = []; @@ -287,7 +281,6 @@ abstract production nilListPattern top::Pattern ::= '[' ']' { top.unparse = "[]"; - top.errors := []; top.patternVars = []; top.patternSubPatternList = []; @@ -302,7 +295,6 @@ concrete production consListPattern top::Pattern ::= hp::Pattern '::' tp::Pattern { top.unparse = hp.unparse ++ "::" ++ tp.unparse; - top.errors := hp.errors ++ tp.errors; top.patternVars = hp.patternVars ++ tp.patternVars; hp.patternVarEnv = top.patternVarEnv; @@ -346,23 +338,24 @@ top::PatternList ::= synthesized attribute namedPatternList::[Pair]; nonterminal NamedPatternList with location, config, unparse, frame, env, errors, patternVars, patternVarEnv, namedPatternList; +propagate config, frame, env, errors on NamedPatternList; concrete production namedPatternList_one top::NamedPatternList ::= p::NamedPattern { top.unparse = p.unparse; - top.errors := p.errors; top.patternVars = p.patternVars; + p.patternVarEnv = top.patternVarEnv; top.namedPatternList = p.namedPatternList; } concrete production namedPatternList_more top::NamedPatternList ::= p::NamedPattern ',' ps::NamedPatternList { top.unparse = p.unparse ++ ", " ++ ps.unparse; - top.errors := p.errors ++ ps.errors; top.patternVars = p.patternVars ++ ps.patternVars; + p.patternVarEnv = top.patternVarEnv; ps.patternVarEnv = p.patternVarEnv ++ p.patternVars; top.namedPatternList = p.namedPatternList ++ ps.namedPatternList; } @@ -372,19 +365,18 @@ abstract production namedPatternList_nil top::NamedPatternList ::= { top.unparse = ""; - top.errors := []; top.patternVars = []; top.namedPatternList = []; } nonterminal NamedPattern with location, config, unparse, frame, env, errors, patternVars, patternVarEnv, namedPatternList; +propagate config, frame, env, patternVarEnv, errors on NamedPattern; concrete production namedPattern top::NamedPattern ::= qn::QName '=' p::Pattern { top.unparse = s"${qn.unparse}=${p.unparse}"; - top.errors := p.errors; -- TODO: Error checking for annotation patterns is a bit broken. -- We can check that it is an annotation here, but any other @@ -396,7 +388,7 @@ top::NamedPattern ::= qn::QName '=' p::Pattern else []; top.patternVars = p.patternVars; - top.namedPatternList = [pair(qn.lookupAttribute.fullName, p)]; + top.namedPatternList = [(qn.lookupAttribute.fullName, p)]; } --helper function for building patternLists from lists of patterns diff --git a/grammars/silver/compiler/extension/regex/Regex.sv b/grammars/silver/compiler/extension/regex/Regex.sv index 62cfefb3a..13890e4d7 100644 --- a/grammars/silver/compiler/extension/regex/Regex.sv +++ b/grammars/silver/compiler/extension/regex/Regex.sv @@ -26,7 +26,7 @@ concrete production matches top::Expr ::= e::Expr '=~' r::Expr { top.unparse = s"(${e.unparse}) =~ (${r.unparse})"; - propagate freeVars; + propagate frame, freeVars; forwards to if null(getValueDcl("silver:regex:matches", top.env)) then errorExpr([err(top.location, "Use of regexes requires import of silver:regex")], location=top.location) diff --git a/grammars/silver/compiler/extension/rewriting/Expr.sv b/grammars/silver/compiler/extension/rewriting/Expr.sv index 48514baa7..f3bc6bd6c 100644 --- a/grammars/silver/compiler/extension/rewriting/Expr.sv +++ b/grammars/silver/compiler/extension/rewriting/Expr.sv @@ -1,6 +1,6 @@ grammar silver:compiler:extension:rewriting; --- Environment mapping variables that were defined on the rule RHS to Booleans indicating whether +-- Environment mapping variables that were defined on the rule LHS to Booleans indicating whether -- the variable was explicitly (i.e. not implicitly) decorated in the pattern. inherited attribute boundVars::[Pair] occurs on Expr, Exprs, ExprInhs, ExprInh, AppExprs, AppExpr, AnnoAppExprs, AnnoExpr, AssignExpr, PrimPatterns, PrimPattern; propagate boundVars on Expr, Exprs, ExprInhs, ExprInh, AppExprs, AppExpr, AnnoAppExprs, AnnoExpr, AssignExpr, PrimPatterns, PrimPattern @@ -8,7 +8,7 @@ propagate boundVars on Expr, Exprs, ExprInhs, ExprInh, AppExprs, AppExpr, AnnoAp attribute transform occurs on Expr; -synthesized attribute decRuleExprs::[(String, Decorated Expr with {decorate, boundVars})] occurs on Expr, AssignExpr, PrimPatterns, PrimPattern; +synthesized attribute decRuleExprs::[(String, Decorated Expr with {decorate, decSiteVertexInfo, boundVars})] occurs on Expr, AssignExpr, PrimPatterns, PrimPattern; aspect default production top::Expr ::= @@ -18,7 +18,7 @@ top::Expr ::= -- Constrain the type of the wrapped expression to the type that was inferred here, -- to allow for any type class constraints to be resolved in the translation. silver:rewrite:anyASTExpr( - let rewrite_rule_anyAST_val__::$TypeExpr{typerepTypeExpr(finalType(top), location=top.location)} = $Expr{top} + let rewrite_rule_anyAST_val__::$TypeExpr{typerepTypeExpr(top.finalType, location=top.location)} = $Expr{top} in rewrite_rule_anyAST_val__ end) }); @@ -26,7 +26,7 @@ top::Expr ::= } aspect production lexicalLocalReference -top::Expr ::= q::PartiallyDecorated QName _ _ +top::Expr ::= q::Decorated! QName _ _ _ { -- In regular pattern matching nonterminal values are always effectively decorated, but we are -- using the same typing behavior while matching on *undecorated* trees. So when a variable is @@ -37,14 +37,14 @@ top::Expr ::= q::PartiallyDecorated QName _ _ case lookup(q.name, top.boundVars) of | just(bindingIsDecorated) -> -- The variable is bound in the rule - if finalType(top).isDecorated && !bindingIsDecorated + if top.finalType.isDecorated && !bindingIsDecorated then -- We want the decorated version, but the bound value is undecorated applyASTExpr( antiquoteASTExpr( Silver_Expr { silver:rewrite:anyASTExpr( - \ e::$TypeExpr{typerepTypeExpr(finalType(top).decoratedType, location=builtin)} -> + \ e::$TypeExpr{typerepTypeExpr(top.finalType.decoratedType, location=builtin)} -> $Expr{ decorateExprWithEmpty( 'decorate', Silver_Expr { e }, 'with', '{', '}', @@ -52,7 +52,7 @@ top::Expr ::= q::PartiallyDecorated QName _ _ }), consASTExpr(varASTExpr(q.name), nilASTExpr()), nilNamedASTExpr()) - else if isDecorable(finalType(top), top.env) && bindingIsDecorated + else if isDecorable(top.finalType, top.env) && bindingIsDecorated -- We want the undecorated version, but the bound value is decorated then applyASTExpr( @@ -67,63 +67,60 @@ top::Expr ::= q::PartiallyDecorated QName _ _ | nothing() -> -- The variable is bound in an enclosing let/match -- Explicitly undecorate the variable, if appropriate for the final expected type - if isDecorable(q.lookupValue.typeScheme.typerep, top.env) && !finalType(top).isDecorated + if isDecorable(q.lookupValue.typeScheme.typerep, top.env) && !top.finalType.isDecorated then antiquoteASTExpr(Silver_Expr { silver:rewrite:anyASTExpr(silver:core:new($Expr{top})) }) else antiquoteASTExpr(Silver_Expr { silver:rewrite:anyASTExpr($Expr{top}) }) end; } aspect production childReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.transform = -- Explicitly undecorate the variable, if appropriate for the final expected type - if isDecorable(q.lookupValue.typeScheme.typerep, top.env) && !finalType(top).isDecorated + if isDecorable(q.lookupValue.typeScheme.typerep, top.env) && !top.finalType.isDecorated then antiquoteASTExpr(Silver_Expr { silver:rewrite:anyASTExpr(silver:core:new($Expr{top})) }) else antiquoteASTExpr(Silver_Expr { silver:rewrite:anyASTExpr($Expr{top}) }); } aspect production lhsReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.transform = -- Explicitly undecorate the variable, if appropriate for the final expected type - if isDecorable(q.lookupValue.typeScheme.typerep, top.env) && !finalType(top).isDecorated + if isDecorable(q.lookupValue.typeScheme.typerep, top.env) && !top.finalType.isDecorated then antiquoteASTExpr(Silver_Expr { silver:rewrite:anyASTExpr(silver:core:new($Expr{top})) }) else antiquoteASTExpr(Silver_Expr { silver:rewrite:anyASTExpr($Expr{top}) }); } aspect production localReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.transform = -- Explicitly undecorate the variable, if appropriate for the final expected type - if isDecorable(q.lookupValue.typeScheme.typerep, top.env) && !finalType(top).isDecorated + if isDecorable(q.lookupValue.typeScheme.typerep, top.env) && !top.finalType.isDecorated then antiquoteASTExpr(Silver_Expr { silver:rewrite:anyASTExpr(silver:core:new($Expr{top})) }) else antiquoteASTExpr(Silver_Expr { silver:rewrite:anyASTExpr($Expr{top}) }); } aspect production forwardReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.transform = -- Explicitly undecorate the variable, if appropriate for the final expected type - if isDecorable(q.lookupValue.typeScheme.typerep, top.env) && !finalType(top).isDecorated + if isDecorable(q.lookupValue.typeScheme.typerep, top.env) && !top.finalType.isDecorated then antiquoteASTExpr(Silver_Expr { silver:rewrite:anyASTExpr(silver:core:new($Expr{top})) }) else antiquoteASTExpr(Silver_Expr { silver:rewrite:anyASTExpr($Expr{top}) }); } aspect production errorApplication -top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::PartiallyDecorated AnnoAppExprs +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs { top.transform = applyASTExpr(e.transform, es.transform, anns.transform); - e.boundVars = top.boundVars; - es.boundVars = top.boundVars; - anns.boundVars = top.boundVars; } aspect production functionInvocation -top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::PartiallyDecorated AnnoAppExprs +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs { top.transform = case e, es of @@ -161,18 +158,12 @@ top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::P | _, _ -> applyASTExpr(e.transform, es.transform, anns.transform) end; - e.boundVars = top.boundVars; - es.boundVars = top.boundVars; - anns.boundVars = top.boundVars; } aspect production partialApplication -top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs anns::PartiallyDecorated AnnoAppExprs +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs anns::Decorated! AnnoAppExprs { top.transform = applyASTExpr(e.transform, es.transform, anns.transform); - e.boundVars = top.boundVars; - es.boundVars = top.boundVars; - anns.boundVars = top.boundVars; } aspect production forwardAccess @@ -181,7 +172,7 @@ top::Expr ::= e::Expr '.' 'forward' -- Flow analysis has no way to track what e is decorated with across reflect/reify, -- so if the inh set is unspecialized, assume that it has the reference set. local finalTy::Type = - case finalType(e) of + case e.finalType of | decoratedType(nt, varType(_)) -> decoratedType(nt, inhSetType(sort(concat(getInhsForNtRef(nt.typeName, top.flowEnv))))) | t -> t @@ -198,58 +189,69 @@ top::Expr ::= e::Expr '.' 'forward' } aspect production errorAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { top.transform = applyASTExpr( antiquoteASTExpr( Silver_Expr { silver:rewrite:anyASTExpr( - \ e::$TypeExpr{typerepTypeExpr(finalType(e), location=builtin)} -> e.$qName{q.name}) + \ e::$TypeExpr{typerepTypeExpr(e.finalType, location=builtin)} -> e.$qName{q.name}) }), consASTExpr(e.transform, nilASTExpr()), nilNamedASTExpr()); - e.boundVars = top.boundVars; } aspect production annoAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { top.transform = applyASTExpr( antiquoteASTExpr( Silver_Expr { silver:rewrite:anyASTExpr( - \ e::$TypeExpr{typerepTypeExpr(finalType(e), location=builtin)} -> e.$qName{q.name}) + \ e::$TypeExpr{typerepTypeExpr(e.finalType, location=builtin)} -> e.$qName{q.name}) + }), + consASTExpr(e.transform, nilASTExpr()), + nilNamedASTExpr()); +} + +aspect production synDataAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.transform = + applyASTExpr( + antiquoteASTExpr( + Silver_Expr { + silver:rewrite:anyASTExpr( + \ e::$TypeExpr{typerepTypeExpr(e.finalType, location=builtin)} -> e.$qName{q.name}) }), consASTExpr(e.transform, nilASTExpr()), nilNamedASTExpr()); - e.boundVars = top.boundVars; } aspect production terminalAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { top.transform = applyASTExpr( antiquoteASTExpr( Silver_Expr { silver:rewrite:anyASTExpr( - \ e::$TypeExpr{typerepTypeExpr(finalType(e), location=builtin)} -> e.$qName{q.name}) + \ e::$TypeExpr{typerepTypeExpr(e.finalType, location=builtin)} -> e.$qName{q.name}) }), consASTExpr(e.transform, nilASTExpr()), nilNamedASTExpr()); - e.boundVars = top.boundVars; } aspect production synDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { -- Flow analysis has no way to track what e is decorated with across reflect/reify, -- so if the inh set is unspecialized, assume that it has the reference set. local finalTy::Type = - case finalType(e) of + case e.finalType of | decoratedType(nt, varType(_)) -> decoratedType(nt, inhSetType(sort(concat(getInhsForNtRef(nt.typeName, top.flowEnv))))) | t -> t @@ -267,7 +269,7 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur productionRHSCons( productionRHSElem( name("_e", builtin), '::', - typerepTypeExpr(finalType(eUndec), location=builtin), + typerepTypeExpr(eUndec.finalType, location=builtin), location=builtin), inh.lambdaParams, location=builtin), @@ -282,7 +284,7 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur }), consASTExpr(eUndec.transform, inh.transform), nilNamedASTExpr()) - | lexicalLocalReference(qn, _, _) when + | lexicalLocalReference(qn, _, _, _) when case lookup(qn.name, top.boundVars) of | just(bindingIsDecorated) -> !bindingIsDecorated | nothing() -> false @@ -291,7 +293,7 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur antiquoteASTExpr( Silver_Expr { silver:rewrite:anyASTExpr( - \ e::$TypeExpr{typerepTypeExpr(finalType(e).decoratedType, location=builtin)} -> e.$qName{q.name}) + \ e::$TypeExpr{typerepTypeExpr(e.finalType.decoratedType, location=builtin)} -> e.$qName{q.name}) }), consASTExpr(varASTExpr(qn.name), nilASTExpr()), nilNamedASTExpr()) @@ -305,16 +307,59 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur consASTExpr(e.transform, nilASTExpr()), nilNamedASTExpr()) end; - e.boundVars = top.boundVars; } aspect production inhDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + -- Flow analysis has no way to track what e is decorated with across reflect/reify, + -- so if the inh set is unspecialized, assume that it has the reference set. + local finalTy::Type = + case e.finalType of + | decoratedType(nt, varType(_)) -> + decoratedType(nt, inhSetType(sort(concat(getInhsForNtRef(nt.typeName, top.flowEnv))))) + | t -> t + end; + top.transform = + applyASTExpr( + antiquoteASTExpr( + Silver_Expr { + silver:rewrite:anyASTExpr( + \ e::$TypeExpr{typerepTypeExpr(finalTy, location=builtin)} -> e.$qName{q.name}) + }), + consASTExpr(e.transform, nilASTExpr()), + nilNamedASTExpr()); +} + +aspect production inhUndecoratedAccessErrorHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + -- Flow analysis has no way to track what e is decorated with across reflect/reify, + -- so if the inh set is unspecialized, assume that it has the reference set. + local finalTy::Type = + case e.finalType of + | decoratedType(nt, varType(_)) -> + decoratedType(nt, inhSetType(sort(concat(getInhsForNtRef(nt.typeName, top.flowEnv))))) + | t -> t + end; + top.transform = + applyASTExpr( + antiquoteASTExpr( + Silver_Expr { + silver:rewrite:anyASTExpr( + \ e::$TypeExpr{typerepTypeExpr(finalTy, location=builtin)} -> e.$qName{q.name}) + }), + consASTExpr(e.transform, nilASTExpr()), + nilNamedASTExpr()); +} + +aspect production transUndecoratedAccessErrorHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { -- Flow analysis has no way to track what e is decorated with across reflect/reify, -- so if the inh set is unspecialized, assume that it has the reference set. local finalTy::Type = - case finalType(e) of + case e.finalType of | decoratedType(nt, varType(_)) -> decoratedType(nt, inhSetType(sort(concat(getInhsForNtRef(nt.typeName, top.flowEnv))))) | t -> t @@ -328,16 +373,15 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur }), consASTExpr(e.transform, nilASTExpr()), nilNamedASTExpr()); - e.boundVars = top.boundVars; } -aspect production errorDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +aspect production unknownDclAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { -- Flow analysis has no way to track what e is decorated with across reflect/reify, -- so if the inh set is unspecialized, assume that it has the reference set. local finalTy::Type = - case finalType(e) of + case e.finalType of | decoratedType(nt, varType(_)) -> decoratedType(nt, inhSetType(sort(concat(getInhsForNtRef(nt.typeName, top.flowEnv))))) | t -> t @@ -351,7 +395,6 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur }), consASTExpr(e.transform, nilASTExpr()), nilNamedASTExpr()); - e.boundVars = top.boundVars; } aspect production decorateExprWith @@ -367,7 +410,7 @@ top::Expr ::= 'decorate' e::Expr 'with' '{' inh::ExprInhs '}' productionRHSCons( productionRHSElem( name("_e", builtin), '::', - typerepTypeExpr(finalType(e), location=builtin), + typerepTypeExpr(e.finalType, location=builtin), location=builtin), inh.lambdaParams, location=builtin), @@ -420,7 +463,7 @@ top::ExprInh ::= lhs::ExprLHSExpr '=' e::Expr ';' top.lambdaParam = productionRHSElem( name(paramName, builtin), '::', - typerepTypeExpr(finalType(e), location=builtin), + typerepTypeExpr(e.finalType, location=builtin), location=builtin); top.bodyExprInhTransform = exprInh( @@ -555,7 +598,7 @@ aspect production fullList top::Expr ::= '[' es::Exprs ']' { -- TODO: Consider refactoring listtrans on Exprs to decorate the expressions here - -- before forwarding via partially decorated references. + -- before forwarding via unique references. local decEs::Exprs = es; decEs.downSubst = top.downSubst; decEs.finalSubst = top.finalSubst; @@ -566,25 +609,11 @@ top::Expr ::= '[' es::Exprs ']' decEs.env = top.env; decEs.flowEnv = top.flowEnv; decEs.boundVars = top.boundVars; - decEs.isRoot = top.isRoot; decEs.originRules = top.originRules; top.transform = listASTExpr(decEs.transform); } -aspect production listPlusPlus -top::Expr ::= e1::PartiallyDecorated Expr e2::PartiallyDecorated Expr -{ - top.transform = - -- This is a forwarding prod, so we can't decorate e1 and e2 with boundVars here. - -- TODO: need some way for the flow analysis to track that e1 and e2 will be provided with boundVars through the forward. - case forward of - | functionInvocation(_, snocAppExprs(snocAppExprs(emptyAppExprs(), _, decE1), _, decE2), _) -> - appendASTExpr(decE1.transform, decE2.transform) - | _ -> error("Unexpected forward") - end; -} - -- TODO: Awful hack to allow case to appear on rule RHS. -- This is interfering (should really be defined on primitive match) -- and only supports variables from the rule LHS appearing in the match expressions. @@ -601,7 +630,6 @@ top::Expr ::= 'case' es::Exprs 'of' o::Opt_Vbar_t ml::MRuleList 'end' decEs.env = top.env; decEs.flowEnv = top.flowEnv; decEs.boundVars = top.boundVars; - decEs.isRoot = top.isRoot; decEs.originRules = top.originRules; top.transform = @@ -654,11 +682,11 @@ top::AssignExpr ::= id::Name '::' t::TypeExpr '=' e::Expr -- primitive pattern variable was implictly decorated. local isDecorated::Boolean = case e of - | lexicalLocalReference(qn, _, _) -> - fromMaybe(finalType(e).isDecorated, lookup(qn.name, top.boundVars)) - | _ -> finalType(e).isDecorated + | lexicalLocalReference(qn, _, _, _) -> + fromMaybe(e.finalType.isDecorated, lookup(qn.name, top.boundVars)) + | _ -> e.finalType.isDecorated end; - top.varBindings = [pair(id.name, isDecorated)]; + top.varBindings = [(id.name, isDecorated)]; top.decRuleExprs = e.decRuleExprs; } @@ -692,7 +720,7 @@ top::Exprs ::= e::Expr productionRHSCons( productionRHSElem( name(lambdaParamName, builtin), '::', - typerepTypeExpr(finalType(e), location=builtin), + typerepTypeExpr(e.finalType, location=builtin), location=builtin), productionRHSNil(location=builtin), location=builtin); @@ -711,7 +739,7 @@ top::Exprs ::= e1::Expr ',' e2::Exprs productionRHSCons( productionRHSElem( name(lambdaParamName, builtin), '::', - typerepTypeExpr(finalType(e1), location=builtin), + typerepTypeExpr(e1.finalType, location=builtin), location=builtin), e2.lambdaParams, location=builtin); @@ -782,10 +810,3 @@ top::AnnoAppExprs ::= { top.transform = nilNamedASTExpr(); } - -aspect production exprRef -top::Expr ::= e::PartiallyDecorated Expr -{ - top.transform = e.transform; - e.boundVars = top.boundVars; -} diff --git a/grammars/silver/compiler/extension/rewriting/Pattern.sv b/grammars/silver/compiler/extension/rewriting/Pattern.sv index f7b9d599f..93bacee5c 100644 --- a/grammars/silver/compiler/extension/rewriting/Pattern.sv +++ b/grammars/silver/compiler/extension/rewriting/Pattern.sv @@ -33,13 +33,16 @@ attribute transform occurs on MRuleList, MatchRule; synthesized attribute isPolymorphic :: Boolean occurs on MRuleList, MatchRule, PatternList, Pattern, NamedPatternList, NamedPattern; inherited attribute typeHasUniversalVars :: Boolean occurs on Pattern; inherited attribute typesHaveUniversalVars :: [Boolean] occurs on PatternList; -autocopy attribute namedTypesHaveUniversalVars :: [(String, Boolean)] occurs on NamedPatternList, NamedPattern; +inherited attribute namedTypesHaveUniversalVars :: [(String, Boolean)] occurs on NamedPatternList, NamedPattern; synthesized attribute wrappedMatchRuleList :: [AbstractMatchRule] occurs on MRuleList, MatchRule; -autocopy attribute decRuleExprsIn::[(String, Decorated Expr with {decorate, boundVars})] occurs on MRuleList, MatchRule; +inherited attribute decRuleExprsIn::[(String, Decorated Expr with {decorate, decSiteVertexInfo, boundVars})] occurs on MRuleList, MatchRule; inherited attribute ruleIndex::Integer occurs on MRuleList, MatchRule; +propagate decRuleExprsIn on MRuleList; +propagate namedTypesHaveUniversalVars on NamedPatternList, NamedPattern; + aspect production mRuleList_one top::MRuleList ::= m::MatchRule { @@ -108,7 +111,7 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr _ e::Expr top.wrappedMatchRuleList = [matchRule( pt.patternList, - just(pair(hackWrapKey(toString(top.ruleIndex) ++ "_cond", cond, location=e.location), nothing())), + just((hackWrapKey(toString(top.ruleIndex) ++ "_cond", cond, location=e.location), nothing())), hackWrapKey(toString(top.ruleIndex), e, location=e.location), location=top.location)]; } @@ -138,7 +141,7 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr 'matches' p::Pattern _ e::E top.wrappedMatchRuleList = [matchRule( pt.patternList, - just(pair(hackWrapKey(toString(top.ruleIndex) ++ "_cond", cond, location=e.location), just(p))), + just((hackWrapKey(toString(top.ruleIndex) ++ "_cond", cond, location=e.location), just(p))), hackWrapKey(toString(top.ruleIndex), e, location=e.location), location=top.location)]; } @@ -147,7 +150,7 @@ abstract production hackWrapKey top::Expr ::= key::String e::Expr { top.unparse = s"key(${key}, ${e.unparse})"; - top.decRuleExprs = [pair(key, forward)]; + top.decRuleExprs = [(key, forward)]; forwards to e; } @@ -255,7 +258,7 @@ top::Pattern ::= prod::QName '(' ps::PatternList ',' nps::NamedPatternList ')' nps.namedTypesHaveUniversalVars = map( \ t::Pair -> - pair(t.fst, !null(intersect(outputFreeVars, t.snd.freeVariables))), + (t.fst, !null(intersect(outputFreeVars, t.snd.freeVariables))), prodType.namedTypes); } @@ -412,7 +415,7 @@ top::VarBinders ::= aspect production varVarBinder top::VarBinder ::= n::Name { - top.varBindings = [pair(n.name, performSubstitution(top.bindingType, top.finalSubst).isDecorated)]; + top.varBindings = [(n.name, performSubstitution(top.bindingType, top.finalSubst).isDecorated)]; } aspect production ignoreVarBinder top::VarBinder ::= '_' diff --git a/grammars/silver/compiler/extension/rewriting/Rewriting.sv b/grammars/silver/compiler/extension/rewriting/Rewriting.sv index 4a946451d..d4cfb7cc9 100644 --- a/grammars/silver/compiler/extension/rewriting/Rewriting.sv +++ b/grammars/silver/compiler/extension/rewriting/Rewriting.sv @@ -11,7 +11,8 @@ imports silver:compiler:definition:core; imports silver:compiler:definition:type; imports silver:compiler:definition:type:syntax; imports silver:compiler:definition:env; -imports silver:compiler:translation:java:core only finalType; +imports silver:compiler:definition:flow:env; +imports silver:compiler:analysis:typechecking:core; imports silver:compiler:extension:patternmatching; imports silver:compiler:modification:list; imports silver:compiler:modification:primitivepattern; @@ -45,14 +46,15 @@ concrete production traverseProdExprAnno top::Expr ::= 'traverse' n::QName '(' es::AppExprs ',' anns::AnnoAppExprs ')' { top.unparse = s"traverse ${n.name}(${es.unparse}, ${anns.unparse})"; + propagate config, grammarName, compiledGrammars, frame, env, flowEnv, originRules; local numChildren::Integer = n.lookupValue.typeScheme.arity; local annotations::[String] = map(fst, n.lookupValue.typeScheme.typerep.namedTypes); - es.appExprTypereps = repeat(nonterminalType("silver:rewrite:Strategy", [], false), numChildren); + es.appExprTypereps = repeat(nonterminalType("silver:rewrite:Strategy", [], false, false), numChildren); es.appExprApplied = n.unparse; anns.appExprApplied = n.unparse; anns.funcAnnotations = - map(pair(_, nonterminalType("silver:rewrite:Strategy", [], false)), annotations); + map(pair(fst=_, snd=nonterminalType("silver:rewrite:Strategy", [], false, false)), annotations); anns.remainingFuncAnnotations = anns.funcAnnotations; local localErrors::[Message] = @@ -61,7 +63,7 @@ top::Expr ::= 'traverse' n::QName '(' es::AppExprs ',' anns::AnnoAppExprs ')' then [err(top.location, "Term rewriting requires import of silver:rewrite")] else []; - propagate downSubst, upSubst, freeVars; + propagate downSubst, upSubst, finalSubst, freeVars; local transform::Strategy = traversal(n.lookupValue.fullName, es.traverseTransform, anns.traverseTransform); @@ -165,7 +167,7 @@ top::AnnoExpr ::= qn::QName '=' e::AppExpr if !extractNamedArg(qn.name, top.funcAnnotations).fst.isJust then [err(qn.location, "Named parameter '" ++ qn.name ++ "' is not appropriate for '" ++ top.appExprApplied ++ "'")] else []; - top.traverseTransform = pair(qn.lookupAttribute.fullName, e.traverseTransform); + top.traverseTransform = (qn.lookupAttribute.fullName, e.traverseTransform); } aspect production snocAnnoAppExprs @@ -193,7 +195,7 @@ concrete production ruleExpr top::Expr ::= 'rule' 'on' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'end' { top.unparse = "rule on " ++ ty.unparse ++ " of " ++ ml.unparse ++ " end"; - propagate freeVars; + propagate grammarName, config, frame, flowEnv, freeVars; -- Find the free type variables (i.e. lacking a definition) to add as skolem constants local freeTyVars::[String] = @@ -217,9 +219,12 @@ top::Expr ::= 'rule' 'on' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'end' checkExpr.config = top.config; checkExpr.compiledGrammars = top.compiledGrammars; checkExpr.boundVars = []; - checkExpr.isRoot = top.isRoot; + checkExpr.alwaysDecorated = false; + checkExpr.decSiteVertexInfo = nothing(); + checkExpr.isRoot = false; checkExpr.originRules = top.originRules; + ml.env = top.env; ml.matchRulePatternSize = 1; ml.ruleIndex = 0; ml.decRuleExprsIn = checkExpr.decRuleExprs; diff --git a/grammars/silver/compiler/extension/silverconstruction/Syntax.sv b/grammars/silver/compiler/extension/silverconstruction/Syntax.sv index d52d02729..f5d615f73 100644 --- a/grammars/silver/compiler/extension/silverconstruction/Syntax.sv +++ b/grammars/silver/compiler/extension/silverconstruction/Syntax.sv @@ -78,6 +78,14 @@ top::TypeExpr ::= '$TypeExpr' '{' e::Expr '}' location=top.location); } +concrete production antiquoteConstraintList +top::ConstraintList ::= '$ConstraintList' '{' e::Expr '}' +{ + top.unparse = s"$$ConstraintList{${e.unparse}}"; + -- [err(top.location, "$ConstraintList should not occur outside of quoted Silver Literal.")] + forwards to nilConstraint(location=top.location); +} + concrete production antiquotePattern top::Pattern ::= '$Pattern' '{' e::Expr '}' { @@ -88,6 +96,12 @@ top::Pattern ::= '$Pattern' '{' e::Expr '}' location=top.location); } +concrete production antiquoteProductionRHS +top::ProductionRHS ::= '$ProductionRHS' '{' e::Expr '}' +{ + top.unparse = s"$$ProductionRHS{${e.unparse}}"; + forwards to productionRHSNil(location=top.location); +} concrete production antiquoteAspectRHS top::AspectRHS ::= '$AspectRHS' '{' e::Expr '}' diff --git a/grammars/silver/compiler/extension/silverconstruction/Terminals.sv b/grammars/silver/compiler/extension/silverconstruction/Terminals.sv index 6a4c46217..1bc2aefd8 100644 --- a/grammars/silver/compiler/extension/silverconstruction/Terminals.sv +++ b/grammars/silver/compiler/extension/silverconstruction/Terminals.sv @@ -12,7 +12,9 @@ lexer class Antiquote extends SPECOP; terminal AntiquoteExpr_t '$Expr' lexer classes {Antiquote}; terminal AntiquoteExprInhs_t '$ExprInhs' lexer classes {Antiquote}; terminal AntiquoteTypeExpr_t '$TypeExpr' lexer classes {Antiquote}; +terminal AntiquoteConstraintList_t '$ConstraintList' lexer classes {Antiquote}; terminal AntiquotePattern_t '$Pattern' lexer classes {Antiquote}; +terminal AntiquoteProductionRHS_t '$ProductionRHS' lexer classes {Antiquote}; terminal AntiquoteAspectRHS_t '$AspectRHS' lexer classes {Antiquote}; terminal AntiquoteProductionStmt_t '$ProductionStmt' lexer classes {Antiquote}; terminal AntiquoteQName_t '$QName' lexer classes {Antiquote}; diff --git a/grammars/silver/compiler/extension/silverconstruction/Translation.sv b/grammars/silver/compiler/extension/silverconstruction/Translation.sv index 33a990a55..80e928fe3 100644 --- a/grammars/silver/compiler/extension/silverconstruction/Translation.sv +++ b/grammars/silver/compiler/extension/silverconstruction/Translation.sv @@ -10,7 +10,9 @@ top::AST ::= prodName::String children::ASTs annotations::NamedASTs ["silver:compiler:extension:silverconstruction:antiquoteExpr", "silver:compiler:extension:silverconstruction:antiquoteExprInhs", "silver:compiler:extension:silverconstruction:antiquoteTypeExpr", + "silver:compiler:extension:silverconstruction:antiquoteConstraintList", "silver:compiler:extension:silverconstruction:antiquotePattern", + "silver:compiler:extension:silverconstruction:antiquoteProductionRHS", "silver:compiler:extension:silverconstruction:antiquoteAspectRHS", "silver:compiler:extension:silverconstruction:antiquoteProductionStmt", "silver:compiler:extension:silverconstruction:antiquoteQName", diff --git a/grammars/silver/compiler/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/compiler/extension/strategyattr/ConcreteSyntax.sv index f005384e8..9aa082ec7 100644 --- a/grammars/silver/compiler/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/compiler/extension/strategyattr/ConcreteSyntax.sv @@ -209,7 +209,7 @@ concrete productions top::StrategyExpr_c s.givenGenName = top.givenGenName ++ "_outermost_arg"; } -autocopy attribute index::Integer; +inherited attribute index::Integer; nonterminal StrategyExprs_c with location, index, givenGenName, unparse, ast; concrete productions top::StrategyExprs_c diff --git a/grammars/silver/compiler/extension/strategyattr/DclInfo.sv b/grammars/silver/compiler/extension/strategyattr/DclInfo.sv index 4ecc02002..c21f1ae36 100644 --- a/grammars/silver/compiler/extension/strategyattr/DclInfo.sv +++ b/grammars/silver/compiler/extension/strategyattr/DclInfo.sv @@ -39,12 +39,13 @@ top::AttributeDclInfo ::= top.typeScheme = polyType([tyVar], if isTotal then varType(tyVar) - else appType(nonterminalType("silver:core:Maybe", [starKind()], false), varType(tyVar))); + else appType(nonterminalType("silver:core:Maybe", [starKind()], true, false), varType(tyVar))); top.isSynthesized = true; top.isStrategy = true; top.decoratedAccessHandler = synDecoratedAccessHandler(_, _, location=_); top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); + top.dataAccessHandler = synDataAccessHandler(_, _, location=_); top.attrDefDispatcher = synthesizedAttributeDef(_, _, _, location=_); -- Allow normal syn equations top.attributionDispatcher = strategyAttributionDcl(_, _, _, _, location=_); top.propagateDispatcher = propagateStrategy(_, location=_); diff --git a/grammars/silver/compiler/extension/strategyattr/Project.sv b/grammars/silver/compiler/extension/strategyattr/Project.sv index 0c0307a14..cb68f4659 100644 --- a/grammars/silver/compiler/extension/strategyattr/Project.sv +++ b/grammars/silver/compiler/extension/strategyattr/Project.sv @@ -6,6 +6,8 @@ imports silver:compiler:definition:core; imports silver:compiler:definition:env; imports silver:compiler:definition:type; imports silver:compiler:definition:type:syntax hiding Arrow_t; +imports silver:compiler:definition:flow:env; +imports silver:compiler:analysis:typechecking:core; imports silver:compiler:extension:autoattr; imports silver:compiler:extension:patternmatching; imports silver:compiler:modification:list; diff --git a/grammars/silver/compiler/extension/strategyattr/Strategy.sv b/grammars/silver/compiler/extension/strategyattr/Strategy.sv index a9759fdbc..8fa7aacc1 100644 --- a/grammars/silver/compiler/extension/strategyattr/Strategy.sv +++ b/grammars/silver/compiler/extension/strategyattr/Strategy.sv @@ -4,6 +4,8 @@ abstract production strategyAttributeDcl top::AGDcl ::= isTotal::Boolean a::Name recVarNameEnv::[Pair] recVarTotalEnv::[Pair] e::StrategyExpr { top.unparse = (if isTotal then "" else "partial ") ++ "strategy attribute " ++ a.unparse ++ "=" ++ e.unparse ++ ";"; + propagate grammarName, config, env, flowEnv; + top.occursDefs := []; top.specDefs := []; top.refDefs := []; @@ -13,7 +15,7 @@ top::AGDcl ::= isTotal::Boolean a::Name recVarNameEnv::[Pair] rec -- Define these directly to avoid circular dependencies, -- since the forward contributes to the env. - propagate errors, moduleNames; + propagate compiledGrammars, errors, moduleNames; top.errors <- if length(getAttrDclAll(fName, top.env)) > 1 @@ -56,8 +58,11 @@ top::AGDcl ::= isTotal::Boolean a::Name recVarNameEnv::[Pair] rec } abstract production strategyAttributionDcl -top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs +top::AGDcl ::= at::Decorated! QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs { + undecorates to attributionDcl('attribute', at, attl, 'occurs', 'on', nt, nttl, ';', location=top.location); + propagate grammarName, env, flowEnv; + production attribute localErrors::[Message] with ++; localErrors := attl.errors ++ attl.errorsTyVars ++ nt.lookupType.errors ++ nttl.errors ++ nttl.errorsTyVars; @@ -79,33 +84,40 @@ top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QNam top.errors := if !null(localErrors) then localErrors else forward.errors; - forwards to - foldr( - appendAGDcl(_, _, location=top.location), - defaultAttributionDcl( - at, - botlSome( - bTypeList( - '<', - typeListSingle( - case nttl of - | botlSome(tl) -> - appTypeExpr( - nominalTypeExpr(nt.qNameType, location=top.location), - tl, location=top.location) - | botlNone() -> nominalTypeExpr(nt.qNameType, location=top.location) - end, - location=top.location), - '>', location=top.location), - location=top.location), - nt, nttl, - location=top.location), - map( - \ n::String -> - attributionDcl( - 'attribute', qName(top.location, n), attl, 'occurs', 'on', nt, nttl, ';', + local atOccursDcl::AGDcl = + defaultAttributionDcl( + at, + botlSome( + bTypeList( + '<', + typeListSingle( + case nttl of + | botlSome(tl) -> + appTypeExpr( + nominalTypeExpr(nt.qNameType, location=top.location), + tl, location=top.location) + | botlNone() -> nominalTypeExpr(nt.qNameType, location=top.location) + end, location=top.location), - at.lookupAttribute.dcl.liftedStrategyNames)); + '>', location=top.location), + location=top.location), + nt, nttl, + location=top.location); + + forwards to + if null(at.lookupAttribute.dcl.liftedStrategyNames) then @atOccursDcl + else + appendAGDcl( + @atOccursDcl, + foldr1( + appendAGDcl(_, _, location=top.location), + map( + \ n::String -> + attributionDcl( + 'attribute', qName(top.location, n), attl, 'occurs', 'on', nt, nttl, ';', + location=top.location), + at.lookupAttribute.dcl.liftedStrategyNames)), + location=top.location); } {-- @@ -113,8 +125,9 @@ top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QNam - @param attr The name of the attribute to propagate -} abstract production propagateStrategy -top::ProductionStmt ::= attr::PartiallyDecorated QName +top::ProductionStmt ::= attr::Decorated! QName { + undecorates to propagateOneAttr(attr, location=top.location); top.unparse = s"propagate ${attr.unparse}"; production isTotal::Boolean = attr.lookupAttribute.dcl.isTotal; diff --git a/grammars/silver/compiler/extension/strategyattr/StrategyExpr.sv b/grammars/silver/compiler/extension/strategyattr/StrategyExpr.sv index ec6bf10d5..33114bdb8 100644 --- a/grammars/silver/compiler/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/compiler/extension/strategyattr/StrategyExpr.sv @@ -1,18 +1,20 @@ grammar silver:compiler:extension:strategyattr; import silver:compiler:metatranslation; +import silver:compiler:definition:flow:syntax; +import silver:compiler:definition:flow:ast only lhsVertexType; import silver:compiler:definition:flow:driver only ProductionGraph, FlowType, constructAnonymousGraph; import silver:compiler:driver:util; annotation genName::String; -- Used to generate the names of lifted strategy attributes -autocopy attribute recVarNameEnv::[Pair]; -- name, (isTotal, genName) -autocopy attribute recVarTotalEnv::[Pair]; -- name, (isTotal, genName) -autocopy attribute recVarTotalNoEnvEnv::[Pair]; -- same as above but doesn't depend on env +inherited attribute recVarNameEnv::[Pair]; -- name, (isTotal, genName) +inherited attribute recVarTotalEnv::[Pair]; -- name, (isTotal, genName) +inherited attribute recVarTotalNoEnvEnv::[Pair]; -- same as above but doesn't depend on env inherited attribute isOutermost::Boolean; -autocopy attribute outerAttr::String; -autocopy attribute inlinedStrategies::[String]; +inherited attribute outerAttr::String; +inherited attribute inlinedStrategies::[String]; type LiftedInhs = {recVarNameEnv, recVarTotalNoEnvEnv, outerAttr, isOutermost}; monoid attribute liftedStrategies::[(String, Decorated StrategyExpr with LiftedInhs)]; synthesized attribute attrRefName::Maybe; @@ -77,14 +79,14 @@ partial strategy attribute prodStep = | prodTraversal(p, s) when p.lookupValue.fullName != top.frame.fullName -> fail(location=top.location, genName=top.genName) | rewriteRule(_, _, ml) when !ml.matchesFrame -> fail(location=top.location, genName=top.genName) end <+ - rewriteRule( - id, id, - onceBottomUp( - rule on top::MRuleList of - | mRuleList_cons(h, _, t) when !h.matchesFrame -> t - | mRuleList_cons(h, _, mRuleList_one(t)) when !t.matchesFrame -> mRuleList_one(h, location=top.location) - end)); -attribute prodStep occurs on MRuleList; + rewriteRule(id, id, elimInfeasibleMRules); +partial strategy attribute elimInfeasibleMRules = + onceBottomUp( + rule on top::MRuleList of + | mRuleList_cons(h, _, t) when !h.matchesFrame -> t + | mRuleList_cons(h, _, mRuleList_one(t)) when !t.matchesFrame -> mRuleList_one(h, location=top.location) + end); +attribute elimInfeasibleMRules occurs on MRuleList; strategy attribute genericSimplify = innermost(genericStep); strategy attribute ntSimplify = @@ -145,13 +147,15 @@ flowtype StrategyExprs = attrRefNames {env, recVarNameEnv, givenInputElements}, containsFail {}, allId {}, freeRecVars {decorate}, partialRefs {decorate}, totalRefs {decorate}; +propagate grammarName, config, compiledGrammars, env, flowEnv, outerAttr, partialRefs, totalRefs, containsTraversal on StrategyExpr, StrategyExprs; +propagate frame on StrategyExpr excluding allTraversal, someTraversal, oneTraversal, prodTraversal; propagate errors on StrategyExpr, StrategyExprs excluding partialRef, totalRef, rewriteRule; propagate containsFail, allId on StrategyExprs; -propagate freeRecVars on StrategyExpr, StrategyExprs excluding recComb; -propagate partialRefs, totalRefs, containsTraversal on StrategyExpr, StrategyExprs; +propagate recVarNameEnv, recVarTotalEnv, recVarTotalNoEnvEnv, freeRecVars on StrategyExpr, StrategyExprs excluding recComb; +propagate inlinedStrategies on StrategyExpr, StrategyExprs excluding inlined; propagate genericSimplify on StrategyExprs; -propagate prodStep on MRuleList; propagate genericStep, ntStep, prodStep, genericSimplify, ntSimplify, optimize on StrategyExpr; +propagate elimInfeasibleMRules on MRuleList; -- Convert an expression of type a to Maybe function asPartial @@ -218,7 +222,7 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr s1.liftedStrategies ++ if s2.attrRefName.isJust then [] - else [pair(s2Name, s2)]; + else [(s2Name, s2)]; top.isTotal = s1.isTotal && s2.isTotal; top.isTotalNoEnv = s1.isTotalNoEnv && s2.isTotalNoEnv; @@ -235,15 +239,12 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr exprInhsCons(_, _, location=top.location), exprInhsEmpty(location=top.location), map( - \ a::AttributeDclInfo -> + \ attr::String -> + -- TODO: translation attributes! Silver_ExprInh { - $name{a.fullName} = $name{top.frame.signature.outputElement.elementName}.$name{a.fullName}; + $name{attr} = $name{top.frame.signature.outputElement.elementName}.$name{attr}; }, - filter( - (.isInherited), - flatMap( - getAttrDcl(_, top.env), - map((.attrOccurring), getAttrsOn(top.frame.lhsNtName, top.env)))))); + getInhAttrsOn(top.frame.lhsNtName, top.env))); top.partialTranslation = -- Optimizations when one or both of these is total, in this case a -- monadic bind may not be required. @@ -313,21 +314,20 @@ top::StrategyExpr ::= s::StrategyExpr top.liftedStrategies := if s.attrRefName.isJust then [] - else [pair(sName, s)]; + else [(sName, s)]; top.isTotal = s.isTotal; top.isTotalNoEnv = s.isTotalNoEnv; top.containsTraversal <- true; s.isOutermost = false; - s.frame = error("No frame for traversal strategies"); -- TODO: This equation shouldn't exist, but frame is an autocopy local sBaseName::String = last(explode(":", sName)); - -- pair(child name, attr occurs on child) + -- (child name, attr occurs on child) local childAccesses::[Pair] = map( \ e::NamedSignatureElement -> - pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), + (e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); top.partialTranslation = if sTotal @@ -373,7 +373,7 @@ top::StrategyExpr ::= s::StrategyExpr location=top.location)], false, Silver_Expr { silver:core:nothing() }, - appType(nonterminalType("silver:core:Maybe", [starKind()], false), top.frame.signature.outputElement.typerep), + appType(nonterminalType("silver:core:Maybe", [starKind()], true, false), top.frame.signature.outputElement.typerep), location=top.location); top.totalTranslation = if sTotal @@ -405,18 +405,17 @@ top::StrategyExpr ::= s::StrategyExpr top.liftedStrategies := if s.attrRefName.isJust then [] - else [pair(sName, s)]; + else [(sName, s)]; top.containsTraversal <- true; s.isOutermost = false; - s.frame = error("No frame for traversal strategies"); -- TODO: This equation shouldn't exist, but frame is an autocopy - -- pair(child name, attr occurs on child) + -- (child name, attr occurs on child) local childAccesses::[Pair] = map( \ e::NamedSignatureElement -> - pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), + (e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); local matchingChildren::[String] = map(fst, filter(snd, childAccesses)); top.partialTranslation = @@ -486,19 +485,18 @@ top::StrategyExpr ::= s::StrategyExpr top.liftedStrategies := if s.attrRefName.isJust then [] - else [pair(sName, s)]; + else [(sName, s)]; top.containsTraversal <- true; s.isOutermost = false; - s.frame = error("No frame for traversal strategies"); -- TODO: This equation shouldn't exist, but frame is an autocopy local sBaseName::String = last(explode(":", sName)); - -- pair(child name, attr occurs on child) + -- (child name, attr occurs on child) local childAccesses::[Pair] = map( \ e::NamedSignatureElement -> - pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), + (e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); local matchingChildren::[String] = map(fst, filter(snd, childAccesses)); top.partialTranslation = @@ -556,7 +554,7 @@ top::StrategyExpr ::= s::StrategyExpr range(0, length(matchingChildren))), false, Silver_Expr { silver:core:nothing() }, - appType(nonterminalType("silver:core:Maybe", [starKind()], false), top.frame.signature.outputElement.typerep), + appType(nonterminalType("silver:core:Maybe", [starKind()], true, false), top.frame.signature.outputElement.typerep), location=top.location); top.totalTranslation = if sTotal && !null(matchingChildren) @@ -601,9 +599,9 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs top.containsTraversal <- true; - -- pair(child name, if attr occurs on child then just(attr name) else nothing()) + -- (child name, if attr occurs on child then just(attr name) else nothing()) local childAccesses::[Pair>] = - zipWith(pair, top.frame.signature.inputNames, s.attrRefNames); + zip(top.frame.signature.inputNames, s.attrRefNames); top.partialTranslation = -- This is never total if prod.lookupValue.fullName == top.frame.fullName then @@ -613,7 +611,7 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs | just(a_s1), just(c_s3) -> just(prod(a_s1, b, c_s3, d.s4)) | _, _ -> nothing() end - Could also be implemented as chained monadic binds. Maybe more efficient this way? -} + Could also be implemented using the Applicative instance for Maybe. Maybe more efficient this way? -} caseExpr( flatMap( \ a::Pair> -> @@ -654,7 +652,7 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs location=top.location)], false, Silver_Expr { silver:core:nothing() }, - appType(nonterminalType("silver:core:Maybe", [starKind()], false), top.frame.signature.outputElement.typerep), + appType(nonterminalType("silver:core:Maybe", [starKind()], true, false), top.frame.signature.outputElement.typerep), location=top.location) else Silver_Expr { silver:core:nothing() }; } @@ -671,7 +669,7 @@ top::StrategyExprs ::= h::StrategyExpr t::StrategyExprs -- during translation - which means we will treat it as id anyway! (if h.attrRefName.isJust || h.isId then [] - else [pair(h.genName, h)]) ++ + else [(h.genName, h)]) ++ t.liftedStrategies; local hType::Type = head(top.givenInputElements).typerep; @@ -712,14 +710,14 @@ top::StrategyExpr ::= n::Name s::StrategyExpr top.liftedStrategies := if top.isOutermost then s.liftedStrategies - else [pair(sName, s)]; + else [(sName, s)]; top.freeRecVars := remove(n.name, s.freeRecVars); -- Decorate s assuming that the bound strategy is total, in order to check for totality. -- See Fig 4 of the strategy attributes paper (https://www-users.cse.umn.edu/~evw/pubs/kramer20sle/kramer20sle.pdf) local s2::StrategyExpr = s; - s2.recVarTotalEnv = pair(n.name, true) :: s.recVarTotalEnv; - s2.recVarTotalNoEnvEnv = pair(n.name, true) :: s.recVarTotalNoEnvEnv; + s2.recVarTotalEnv = (n.name, true) :: s.recVarTotalEnv; + s2.recVarTotalNoEnvEnv = (n.name, true) :: s.recVarTotalNoEnvEnv; s2.env = s.env; s2.config = s.config; s2.grammarName = s.grammarName; @@ -729,9 +727,9 @@ top::StrategyExpr ::= n::Name s::StrategyExpr top.isTotal = s2.isTotal; top.isTotalNoEnv = s2.isTotalNoEnv; - s.recVarNameEnv = pair(n.name, sName) :: top.recVarNameEnv; - s.recVarTotalEnv = pair(n.name, top.isTotal) :: top.recVarTotalEnv; - s.recVarTotalNoEnvEnv = pair(n.name, top.isTotalNoEnv) :: top.recVarTotalNoEnvEnv; + s.recVarNameEnv = (n.name, sName) :: top.recVarNameEnv; + s.recVarTotalEnv = (n.name, top.isTotal) :: top.recVarTotalEnv; + s.recVarTotalNoEnvEnv = (n.name, top.isTotalNoEnv) :: top.recVarTotalNoEnvEnv; s.isOutermost = top.isOutermost; local sTotal::Boolean = attrIsTotal(top.env, sName); @@ -759,24 +757,24 @@ top::StrategyExpr ::= id::Name ty::TypeExpr ml::MRuleList -- Pattern matching error checking (mostly) happens on what caseExpr forwards to, -- so we need to decorate one of those here. production checkExpr::Expr = - letp( - assignExpr(id, '::', ty, '=', errorExpr([], location=top.location), location=top.location), - caseExpr( - [hackExprType(ty.typerep, location=top.location)], - -- TODO: matchRuleList on MRuleList depends on frame for some reason. - -- Re-decorate ml here as a workaround to avoid checkExpr depending on top.frame - decorate ml with { - env = top.env; - config = top.config; - matchRulePatternSize = 1; - frame = error("not needed"); - }.matchRuleList, false, - errorExpr([], location=top.location), - ty.typerep, - location=top.location), + caseExpr( + [hackLHSExprType(ty.typerep.asNtOrDecType, location=top.location)], + -- TODO: matchRuleList on MRuleList depends on frame for some reason. + -- Re-decorate ml here as a workaround to avoid checkExpr depending on top.frame + decorate ml with { + env = top.env; + config = top.config; + matchRulePatternSize = 1; + frame = error("not needed"); + }.matchRuleList, false, + errorExpr([], location=top.location), + ty.typerep, location=top.location); - checkExpr.env = top.env; + checkExpr.env = + newScopeEnv([lhsDef(top.grammarName, id.location, id.name, ty.typerep)], top.env); checkExpr.flowEnv = top.flowEnv; + checkExpr.decSiteVertexInfo = nothing(); + checkExpr.alwaysDecorated = false; checkExpr.downSubst = emptySubst(); checkExpr.finalSubst = checkExpr.upSubst; checkExpr.grammarName = top.grammarName; @@ -804,7 +802,7 @@ top::StrategyExpr ::= id::Name ty::TypeExpr ml::MRuleList [Silver_Expr { $name{top.frame.signature.outputElement.elementName} }], ml.translation, false, Silver_Expr { silver:core:nothing() }, - appType(nonterminalType("silver:core:Maybe", [starKind()], false), ty.typerep), + appType(nonterminalType("silver:core:Maybe", [starKind()], true, false), ty.typerep), location=top.location); top.partialTranslation = if unify(ty.typerep, top.frame.signature.outputElement.typerep).failure @@ -819,10 +817,11 @@ top::StrategyExpr ::= id::Name ty::TypeExpr ml::MRuleList } -- Hack dummy expr with a given type -abstract production hackExprType +abstract production hackLHSExprType top::Expr ::= t::Type { top.typerep = t; + top.flowVertexInfo = just(lhsVertexType); forwards to errorExpr([], location=top.location); } @@ -860,7 +859,7 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr _ e::Expr { top.translation = matchRule( - pt.patternList, just(pair(cond, nothing())), Silver_Expr { silver:core:just($Expr{e}) }, + pt.patternList, just((cond, nothing())), Silver_Expr { silver:core:just($Expr{e}) }, location=top.location); } @@ -869,7 +868,7 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr 'matches' p::Pattern _ e::E { top.translation = matchRule( - pt.patternList, just(pair(cond, just(p))), Silver_Expr { silver:core:just($Expr{e}) }, + pt.patternList, just((cond, just(p))), Silver_Expr { silver:core:just($Expr{e}) }, location=top.location); } @@ -890,6 +889,7 @@ abstract production nameRef top::StrategyExpr ::= id::QName { top.unparse = id.unparse; + propagate env; -- Forwarding depends on env here, these must be computed without env propagate liftedStrategies; @@ -951,8 +951,9 @@ top::StrategyExpr ::= attr::QNameAttrOccur if !attrDcl.isSynthesized then [err(attr.location, s"Attribute ${attr.name} cannot be used as a partial strategy, because it is not a synthesized attribute")] else case attrTypeScheme.typerep, attrTypeScheme.boundVars of - | appType(nonterminalType("silver:core:Maybe", _, _), varType(a1)), [a2] when a1 == a2 && attrDcl.isSynthesized -> [] - | appType(nonterminalType("silver:core:Maybe", _, _), a), _ when pair(a.baseType, attrDcl.isSynthesized) matches pair(nonterminalType(nt, _, _), true) -> + | appType(nonterminalType("silver:core:Maybe", _, _, _), varType(a1)), [a2] when a1 == a2 && attrDcl.isSynthesized -> [] + | appType(nonterminalType("silver:core:Maybe", _, _, _), a), _ + when (a.baseType, attrDcl.isSynthesized) matches (nonterminalType(nt, _, _, _), true) -> if null(getOccursDcl(attrDcl.fullName, nt, top.env)) then [wrn(attr.location, s"Attribute ${attr.name} cannot be used as a partial strategy, because it doesn't occur on its own nonterminal type ${nt}")] else [] @@ -987,7 +988,7 @@ top::StrategyExpr ::= attr::QNameAttrOccur then [err(attr.location, s"Attribute ${attr.name} cannot be used as a total strategy, because it is not a synthesized attribute")] else case attrTypeScheme.typerep.baseType, attrTypeScheme.boundVars of | varType(a1), [a2] when a1 == a2 -> [] - | nonterminalType(nt, _, _), _ -> + | nonterminalType(nt, _, _, _), _ -> if null(getOccursDcl(attrDcl.fullName, nt, top.env)) then [wrn(attr.location, s"Attribute ${attr.name} cannot be used as a total strategy, because it doesn't occur on its own nonterminal type ${nt}")] else [] @@ -1032,13 +1033,13 @@ top::QNameAttrOccur ::= at::QName { top.matchesFrame := top.found && case top.typerep of - | appType(nonterminalType("silver:core:Maybe", _, _), t) -> !unify(top.attrFor, t).failure + | appType(nonterminalType("silver:core:Maybe", _, _, _), t) -> !unify(top.attrFor, t).failure | t -> !unify(top.attrFor, t).failure end; } function attrIsTotal -Boolean ::= env::Decorated Env attrName::String +Boolean ::= env::Env attrName::String { local dcls::[AttributeDclInfo] = getAttrDcl(attrName, env); return @@ -1046,14 +1047,14 @@ Boolean ::= env::Decorated Env attrName::String | [] -> false | d :: _ -> case d.typeScheme.typerep of - | appType(nonterminalType("silver:core:Maybe", _, _), _) -> false + | appType(nonterminalType("silver:core:Maybe", _, _, _), _) -> false | _ -> true end end; } function attrMatchesFrame -Boolean ::= env::Decorated Env attrName::String attrFor::Type +Boolean ::= env::Env attrName::String attrFor::Type { return decorate qNameAttrOccur(qName(loc("", -1, -1, -1, -1, -1, -1), attrName), location=loc("", -1, -1, -1, -1, -1, -1)) @@ -1061,7 +1062,7 @@ Boolean ::= env::Decorated Env attrName::String attrFor::Type } function attrMatchesChild -Boolean ::= env::Decorated Env attrName::String frame::BlockContext +Boolean ::= env::Env attrName::String frame::BlockContext { return any( diff --git a/grammars/silver/compiler/extension/templating/StringTemplating.sv b/grammars/silver/compiler/extension/templating/StringTemplating.sv index d677a7aea..6089ee127 100644 --- a/grammars/silver/compiler/extension/templating/StringTemplating.sv +++ b/grammars/silver/compiler/extension/templating/StringTemplating.sv @@ -36,21 +36,28 @@ production stringAppendCall top::Expr ::= a::Expr b::Expr { top.unparse = s"${a.unparse} ++ ${b.unparse}"; - propagate freeVars; - -- TODO: We really need eagerness analysis in Silver. + -- TODO: We really need strictness analysis in Silver. -- Otherwise the translation for a large string template block contains -- new common.Thunk(new common.Thunk.Evaluable() { public final Object eval() { return ((common.StringCatter)silver.core.PstringAppend.invoke(${a.translation}, ${b.translation}); } }) -- a ridiculous number of times, when it can just be translated as: top.translation = s"new common.StringCatter(${a.translation}, ${b.translation})"; top.lazyTranslation = wrapThunk(top.translation, top.frame.lazyApplication); - - thread downSubst, upSubst on top, a, b, forward; - - forwards to - mkStrFunctionInvocation( - top.location, "silver:core:stringAppend", - [exprRef(a, location=a.location), exprRef(b, location=b.location)]); + + forwards to application( + baseExpr( + qName(top.location, "silver:core:stringAppend"), + location=top.location), '(', + snocAppExprs( + snocAppExprs( + emptyAppExprs(location=top.location), ',', + presentAppExpr(@a, location=top.location), + location=top.location), ',', + presentAppExpr(@b, location=top.location), + location=top.location), + ',', + emptyAnnoAppExprs(location=top.location), + ')', location=top.location); } terminal PPTemplate_kwd 'pp"""' lexer classes {LITERAL, lsp:String_}; diff --git a/grammars/silver/compiler/extension/testing/EqualityTest.sv b/grammars/silver/compiler/extension/testing/EqualityTest.sv index de8cae375..0e495affa 100644 --- a/grammars/silver/compiler/extension/testing/EqualityTest.sv +++ b/grammars/silver/compiler/extension/testing/EqualityTest.sv @@ -5,6 +5,8 @@ import silver:compiler:definition:env; import silver:compiler:definition:concrete_syntax; import silver:compiler:definition:type; import silver:compiler:definition:type:syntax; +import silver:compiler:definition:flow:env; +import silver:compiler:analysis:typechecking:core; import silver:compiler:modification:collection; import silver:compiler:modification:list; @@ -23,6 +25,7 @@ ag::AGDcl ::= kwd::'equalityTest' { ag.unparse = "equalityTest (" ++ value.unparse ++ "," ++ expected.unparse ++ ",\n" ++ " " ++ valueType.unparse ++ ", " ++ testSuite.unparse ++ ");\n"; + propagate grammarName, compiledGrammars, config, env, flowEnv; local attribute errCheck1 :: TypeCheck; local attribute errCheck2 :: TypeCheck; @@ -75,6 +78,10 @@ ag::AGDcl ::= kwd::'equalityTest' expected.isRoot = true; value.originRules = []; expected.originRules = []; + value.decSiteVertexInfo = nothing(); + expected.decSiteVertexInfo = nothing(); + value.alwaysDecorated = false; + expected.alwaysDecorated = false; {- Causes some circularities with the environment. TODO forwards to if !errCheck1.typeerror && !errCheck2.typeerror && !errCheck3.typeerror diff --git a/grammars/silver/compiler/extension/testing/WrongCode.sv b/grammars/silver/compiler/extension/testing/WrongCode.sv index daab64784..69af627d3 100644 --- a/grammars/silver/compiler/extension/testing/WrongCode.sv +++ b/grammars/silver/compiler/extension/testing/WrongCode.sv @@ -2,6 +2,8 @@ grammar silver:compiler:extension:testing; import silver:compiler:definition:core; import silver:compiler:definition:env; +import silver:compiler:definition:flow:env; +import silver:compiler:analysis:uniqueness; terminal WrongCode_kwd 'wrongCode' lexer classes {KEYWORD}; terminal WarnCode_kwd 'warnCode' lexer classes {KEYWORD}; @@ -18,6 +20,7 @@ concrete production wrongDecl top::AGDcl ::= 'wrongCode' s::String_t '{' ags::AGDcls '}' { top.unparse = "wrongCode" ++ s.lexeme ++ "{" ++ ags.unparse ++ "}"; + propagate grammarName, grammarDependencies, compiledGrammars, config, flowEnv; top.errors := if !containsMessage(substring(1, length(s.lexeme) - 1, s.lexeme), 2, ags.errors) @@ -34,6 +37,7 @@ concrete production warnDecl top::AGDcl ::= 'warnCode' s::String_t '{' ags::AGDcls '}' { top.unparse = "warnCode" ++ s.lexeme ++ "{" ++ ags.unparse ++ "}"; + propagate grammarName, grammarDependencies, compiledGrammars, config, env, flowEnv; top.errors := if !containsMessage(substring(1, length(s.lexeme) - 1, s.lexeme), 1, ags.errors) @@ -56,6 +60,7 @@ concrete production noWarnDecl top::AGDcl ::= 'noWarnCode' s::String_t '{' ags::AGDcls '}' { top.unparse = "noWarnCode " ++ s.lexeme ++ " {" ++ ags.unparse ++ "}"; + propagate grammarName, grammarDependencies, compiledGrammars, config, env, flowEnv; {- I think we want the errors from ags in any case. This production @@ -77,17 +82,15 @@ concrete production wrongFlowDecl top::AGDcl ::= 'wrongFlowCode' s::String_t '{' ags::AGDcls '}' { top.unparse = "wrongFlowCode" ++ s.lexeme ++ "{" ++ ags.unparse ++ "}"; + propagate grammarName, grammarDependencies, compiledGrammars, config, flowEnv, env; top.errors := if !containsMessage(substring(1, length(s.lexeme) - 1, s.lexeme), 2, ags.errors) then [err(top.location, "Wrong code did not raise an error containing " ++ s.lexeme ++ ". Bubbling up errors from lines " ++ toString($3.line) ++ " to " ++ toString($5.line))] ++ ags.errors else []; - -- do extend its environment with its defs - ags.env = occursEnv(ags.occursDefs, newScopeEnv(ags.defs, top.env)); - - -- let's ALSO propagate up flow info, so these kinds of errors are checked/caught - top.flowDefs := ags.flowDefs; + -- These need to be passed up for the flow analysis to work: + propagate defs, flowDefs, uniqueRefs; forwards to emptyAGDcl(location=top.location); } diff --git a/grammars/silver/compiler/extension/treegen/Arbitrary.sv b/grammars/silver/compiler/extension/treegen/Arbitrary.sv index 3efddb49b..a2d531a47 100644 --- a/grammars/silver/compiler/extension/treegen/Arbitrary.sv +++ b/grammars/silver/compiler/extension/treegen/Arbitrary.sv @@ -6,6 +6,7 @@ imports silver:compiler:definition:concrete_syntax; imports silver:compiler:definition:concrete_syntax:ast; imports silver:compiler:definition:type; imports silver:compiler:definition:type:syntax; +imports silver:compiler:definition:flow:env; imports silver:compiler:extension:convenience; imports silver:compiler:modification:list; imports silver:compiler:extension:tuple; @@ -21,13 +22,14 @@ concrete production generatorDcl top::AGDcl ::= 'generator' n::Name '::' t::TypeExpr '{' grammars::GeneratorComponents '}' { top.unparse = s"generator ${n.unparse} :: ${t.unparse} { ${grammars.unparse} }"; + propagate config, grammarName, compiledGrammars, grammarDependencies, env, flowEnv; -- Compute the defs exported by the specified grammars local med::ModuleExportedDefs = moduleExportedDefs( top.location, top.compiledGrammars, top.grammarDependencies, grammars.moduleNames, []); - production specEnv::Decorated Env = newScopeEnv(med.defs, emptyEnv()); + production specEnv::Env = newScopeEnv(med.defs, emptyEnv()); -- Override defs to suppress production attributes from flowing up as a paDef, -- to avoid a circularity as what production attributes are generated depends @@ -85,7 +87,7 @@ top::AGDcl ::= 'generator' n::Name '::' t::TypeExpr '{' grammars::GeneratorCompo nonterminal GeneratorComponents with config, grammarName, location, unparse, errors, moduleNames, compiledGrammars, grammarDependencies; nonterminal GeneratorComponent with config, grammarName, location, unparse, errors, moduleNames, compiledGrammars, grammarDependencies; -propagate errors, moduleNames on GeneratorComponents, GeneratorComponent; +propagate config, grammarName, compiledGrammars, grammarDependencies, env, errors, moduleNames on GeneratorComponents, GeneratorComponent; concrete production nilGeneratorComponent top::GeneratorComponents ::= @@ -107,13 +109,13 @@ top::GeneratorComponent ::= m::ModuleName ';' -- Generate the expression for constructing a type function genForType -Expr ::= loc::Location env::Decorated Env specEnv::Decorated Env depth::Expr t::Type +Expr ::= loc::Location env::Env specEnv::Env depth::Expr t::Type { return case t of -- Monomorphic nonterminals that don't have an explicit Arbitrary instance, -- call the appropriate local generator function. - | nonterminalType(ntName, [], _) + | nonterminalType(ntName, [], _, _) when (getTypeDcl(ntName, specEnv), getInstanceDcl("silver:util:random:Arbitrary", t, env)) matches (dcl :: _, []) -> Silver_Expr { $Name{name("gen_" ++ substitute(":", "_", ntName), loc)}($Expr{depth}) } @@ -125,12 +127,10 @@ Expr ::= loc::Location env::Decorated Env specEnv::Decorated Env depth::Expr -- e.g. lists of nonterminals in a production RHS. | appType(listCtrType(), elemT) -> Silver_Expr { - silver:core:bind(random, \ len::Integer -> - silver:core:sequence( + silver:core:bind(silver:util:random:randomRange(0, $Expr{depth}), \ len::Integer -> + silver:core:traverseA( \ depth::Integer -> $Expr{genForType(loc, env, specEnv, Silver_Expr { depth - 1 }, elemT)}, - silver:core:take( - silver:core:toInteger(len * silver:core:toFloat($Expr{depth}))), - silver:core:reverse(silver:core:range(0, $Expr{depth})))) + silver:core:take(len, silver:core:reverse(silver:core:range(0, $Expr{depth}))))) } -- Primitives and polymorphic nonterminals (e.g. Pair for tuples) are @@ -141,11 +141,11 @@ Expr ::= loc::Location env::Decorated Env specEnv::Decorated Env depth::Expr -- Determine whether we can generate an arbitrary value for some type. function isTypeGeneratable -Boolean ::= env::Decorated Env specEnv::Decorated Env t::Type +Boolean ::= env::Env specEnv::Env t::Type { return case t of - | nonterminalType(ntName, [], _) when getTypeDcl(ntName, specEnv) matches _ :: _ -> true + | nonterminalType(ntName, [], _, _) when getTypeDcl(ntName, specEnv) matches _ :: _ -> true | terminalType(ntName) when getTypeDcl(ntName, specEnv) matches _ :: _ -> true | appType(listCtrType(), elemT) -> isTypeGeneratable(env, specEnv, elemT) | _ -> !null(getInstanceDcl("silver:util:random:Arbitrary", t, env)) @@ -155,7 +155,7 @@ Boolean ::= env::Decorated Env specEnv::Decorated Env t::Type -- Determine whether we can generate an arbitrary value for some production - -- i.e. that it is monomorphic and all the RHS types are generatable. function isProdGeneratable -Boolean ::= env::Decorated Env specEnv::Decorated Env p::ValueDclInfo +Boolean ::= env::Env specEnv::Env p::ValueDclInfo { local prodType::Type = p.typeScheme.typerep; return @@ -197,7 +197,7 @@ function takeWhile2 -- local genExpr::(RandomGen ::= Integer) = \ depth::Integer -> ...; function genNtLocalDecl -ProductionStmt ::= loc::Location env::Decorated Env specEnv::Decorated Env nt::String +ProductionStmt ::= loc::Location env::Env specEnv::Env nt::String { -- All productions that are generatable for nt, sorted by arity local prods :: [ValueDclInfo] = @@ -235,7 +235,7 @@ ProductionStmt ::= loc::Location env::Decorated Env specEnv::Decorated Env nt } function genTermLocalDecl -ProductionStmt ::= loc::Location env::Decorated Env specEnv::Decorated Env dominatingTerminals::EnvTree t::String +ProductionStmt ::= loc::Location env::Env specEnv::Env dominatingTerminals::EnvTree t::String { local te::TypeExpr = nominalTypeExpr(qName(loc, t).qNameType, location=loc); @@ -287,12 +287,12 @@ Note that this expects lst to be non-empty! -} function generateExprChain -Expr ::= loc::Location env::Decorated Env specEnv::Decorated Env nt::String index::Integer lst::[ValueDclInfo] +Expr ::= loc::Location env::Env specEnv::Env nt::String index::Integer lst::[ValueDclInfo] { local prod::ValueDclInfo = head(lst); local prodType::Type = prod.typeScheme.typerep; local args::[(String, Type)] = - zipWith(pair, map(\ i::Integer -> "a" ++ toString(i), range(0, length(prodType.inputTypes))), prodType.inputTypes) ++ + zip(map(\ i::Integer -> "a" ++ toString(i), range(0, length(prodType.inputTypes))), prodType.inputTypes) ++ prodType.namedTypes; local argGenExprs::[Expr] = map(genForType(loc, env, specEnv, Silver_Expr { depth + 1 }, _), map(snd, args)); diff --git a/grammars/silver/compiler/extension/treegen/TerminalGen.sv b/grammars/silver/compiler/extension/treegen/TerminalGen.sv index d75020061..1d7fa9d97 100644 --- a/grammars/silver/compiler/extension/treegen/TerminalGen.sv +++ b/grammars/silver/compiler/extension/treegen/TerminalGen.sv @@ -16,7 +16,7 @@ concrete production genArbTerminalNoLocExpr top::Expr ::= 'genArbTerminal' '(' te::TypeExpr ',' '_' ')' { top.unparse = s"genArbTerminal(${te.unparse}, _)"; - propagate freeVars; + propagate grammarName, env, flowEnv, freeVars; local regex::Regex = case getTypeDcl(te.typerep.typeName, top.env) of diff --git a/grammars/silver/compiler/extension/tuple/PatternMatching.sv b/grammars/silver/compiler/extension/tuple/PatternMatching.sv index 96f430d8b..befb5c529 100644 --- a/grammars/silver/compiler/extension/tuple/PatternMatching.sv +++ b/grammars/silver/compiler/extension/tuple/PatternMatching.sv @@ -23,12 +23,12 @@ concrete production patternTuple_two top::TuplePatternList ::= fst::Pattern ',' snd::Pattern { top.unparse = fst.unparse ++ ", " ++ snd.unparse; - top.asTuplePattern = Silver_Pattern { silver:core:pair($Pattern{fst}, $Pattern{snd}) }; + top.asTuplePattern = Silver_Pattern { silver:core:pair(fst=$Pattern{fst}, snd=$Pattern{snd}) }; } concrete production patternTuple_more top::TuplePatternList ::= fst::Pattern ',' snd::TuplePatternList { top.unparse = fst.unparse ++ ", " ++ snd.unparse; - top.asTuplePattern = Silver_Pattern { silver:core:pair($Pattern{fst}, $Pattern{snd.asTuplePattern}) }; + top.asTuplePattern = Silver_Pattern { silver:core:pair(fst=$Pattern{fst}, snd=$Pattern{snd.asTuplePattern}) }; } \ No newline at end of file diff --git a/grammars/silver/compiler/extension/tuple/Tuple.sv b/grammars/silver/compiler/extension/tuple/Tuple.sv index aa3be23e3..e2dadd54f 100644 --- a/grammars/silver/compiler/extension/tuple/Tuple.sv +++ b/grammars/silver/compiler/extension/tuple/Tuple.sv @@ -7,6 +7,8 @@ imports silver:compiler:definition:core; imports silver:compiler:definition:env; imports silver:compiler:definition:type:syntax; imports silver:compiler:definition:type; +imports silver:compiler:definition:flow:env; +imports silver:compiler:analysis:typechecking:core; imports silver:compiler:extension:patternmatching; @@ -46,36 +48,36 @@ top::Expr ::= tuple::Expr '.' a::IntConst { -- Forward gets the substitution context of the tuple - propagate downSubst, upSubst, freeVars; + propagate grammarName, config, compiledGrammars, frame, env, flowEnv, downSubst, upSubst, finalSubst, freeVars, originRules; + tuple.isRoot = false; local accessIndex::Integer = toInteger(a.lexeme); top.unparse = tuple.unparse ++ "." ++ a.lexeme; - -- Ensure that we extract the tupleElems from the underlying chain of pair types if the tuple type is decorated. local ty :: Type = performSubstitution(tuple.typerep, tuple.upSubst); - local len::Integer = length((if ty.isDecorated then ty.decoratedType else ty).tupleElems); + local len::Integer = length(ty.tupleElems); forwards to if (accessIndex > len || accessIndex < 1) then errorExpr([err(top.location, "Invalid tuple selector index.")], location=top.location) - -- exprRef prevents exponential type checking - else select(exprRef(tuple, location=top.location), 1, accessIndex, len); + -- @ prevents exponential type checking + else select(@tuple, 1, accessIndex, len, location=top.location); } -function select +abstract production select -- i is the current index, a is the desired access index -- len is the total length of the tuple -Expr ::= exp::Expr i::Integer a::Integer len::Integer - { - return +top::Expr ::= exp::Expr i::Integer a::Integer len::Integer +{ + forwards to if i == a then if a == len then -- only if the access index is the length of the -- tuple do we simply return the expression itself - Silver_Expr { $Expr{exp} } - else Silver_Expr { $Expr{exp}.fst } - else select(Silver_Expr{ $Expr{exp}.snd }, i + 1, a, len); + @exp + else Silver_Expr { $Expr{@exp}.fst } + else select(Silver_Expr{ $Expr{@exp}.snd }, i + 1, a, len, location=top.location); } -- TupleList cases: @@ -84,7 +86,7 @@ concrete production tupleList_2Elements top::TupleList ::= fst::Expr ',' snd::Expr { top.unparse = fst.unparse ++ ", " ++ snd.unparse; - top.translation = Silver_Expr { silver:core:pair($Expr{fst}, $Expr{snd}) }; + top.translation = Silver_Expr { silver:core:pair(fst=$Expr{fst}, snd=$Expr{snd}) }; } -- There are more than two elements in the tuple @@ -92,5 +94,5 @@ concrete production tupleList_nElements top::TupleList ::= fst::Expr ',' snd::TupleList { top.unparse = fst.unparse ++ ", " ++ snd.unparse; - top.translation = Silver_Expr { silver:core:pair($Expr{fst}, $Expr{snd.translation}) }; + top.translation = Silver_Expr { silver:core:pair(fst=$Expr{fst}, snd=$Expr{snd.translation}) }; } \ No newline at end of file diff --git a/grammars/silver/compiler/extension/tuple/Type.sv b/grammars/silver/compiler/extension/tuple/Type.sv index f0c7f90ef..ad4019138 100644 --- a/grammars/silver/compiler/extension/tuple/Type.sv +++ b/grammars/silver/compiler/extension/tuple/Type.sv @@ -30,7 +30,7 @@ top::Type ::= c::Type a::Type top.tupleElems = -- c.argTypes should only have a single element case c.baseType of - | nonterminalType("silver:core:Pair", [starKind(), starKind()], false) -> c.argTypes ++ a.tupleElems + | nonterminalType("silver:core:Pair", [starKind(), starKind()], true, false) -> c.argTypes ++ a.tupleElems | _ -> [top] end; @@ -71,12 +71,15 @@ top::Type ::= ts::[Type] top.flatRenamed = tupleType(map (\ t::Type -> decorate t with {substitution = top.substitution;}.flatRenamed, ts)); -- elements of ts need the boundVariables from the top because typepp attribute has a dependency on boundVariables - top.typepp = "(" ++ implode(", ", map(prettyTypeWith(_, top.boundVariables), ts)) ++ ")"; + top.typepp = + if length(ts) == 1 + then forward.typepp + else "(" ++ implode(", ", map(prettyTypeWith(_, top.boundVariables), ts)) ++ ")"; forwards to case ts of - | [] -> nonterminalType("silver:core:Unit", [], false) + | [] -> nonterminalType("silver:core:Unit", [], true, false) | [t] -> t - | t1::t1s -> appType(appType(nonterminalType("silver:core:Pair", [starKind(), starKind()], false), t1), tupleType(t1s)) + | t1::t1s -> appType(appType(nonterminalType("silver:core:Pair", [starKind(), starKind()], true, false), t1), tupleType(t1s)) end; } diff --git a/grammars/silver/compiler/host/Project.sv b/grammars/silver/compiler/host/Project.sv index a5ed604ea..e6f6d3751 100644 --- a/grammars/silver/compiler/host/Project.sv +++ b/grammars/silver/compiler/host/Project.sv @@ -19,17 +19,16 @@ exports silver:compiler:modification:let_fix; exports silver:compiler:modification:lambda_fn; exports silver:compiler:modification:collection; exports silver:compiler:modification:primitivepattern; -exports silver:compiler:modification:autocopyattr; exports silver:compiler:modification:ffi; exports silver:compiler:modification:copper; exports silver:compiler:modification:defaultattr; +exports silver:compiler:modification:list; -- slight hacks, for the moment exports silver:compiler:modification:copper_mda; -- Pure extensions to Silver exports silver:compiler:extension:doc; exports silver:compiler:extension:convenience; -exports silver:compiler:modification:list; -- Not really a pure extension, yuck. exports silver:compiler:extension:easyterminal; exports silver:compiler:extension:deprecation; exports silver:compiler:extension:testing; @@ -37,7 +36,6 @@ exports silver:compiler:extension:auto_ast; exports silver:compiler:extension:templating; exports silver:compiler:extension:patternmatching; exports silver:compiler:extension:treegen; -exports silver:compiler:extension:doc; exports silver:compiler:extension:autoattr; exports silver:compiler:extension:strategyattr; exports silver:compiler:extension:do_notation; @@ -50,6 +48,8 @@ exports silver:compiler:extension:regex; exports silver:compiler:extension:convenienceaspects; exports silver:compiler:extension:attrsection; exports silver:compiler:extension:implicit_monads; +exports silver:compiler:extension:data; +exports silver:compiler:extension:deriving; -- Other generally useful stuff: exports silver:compiler:translation:java; diff --git a/grammars/silver/compiler/host/core/Project.sv b/grammars/silver/compiler/host/core/Project.sv index 224c52bb9..ab75ed23e 100644 --- a/grammars/silver/compiler/host/core/Project.sv +++ b/grammars/silver/compiler/host/core/Project.sv @@ -16,6 +16,7 @@ exports silver:regex:concrete_syntax; -- symbols exports silver:compiler:analysis:typechecking:core; +exports silver:compiler:definition:flow:env; --We wish regex to remain a generic grammar, so we resolve the conflict here! -- Regexes end with /. Escape it if you want it. diff --git a/grammars/silver/compiler/langserver/ReferenceLocations.sv b/grammars/silver/compiler/langserver/ReferenceLocations.sv index 94d1685a6..ccc3dc8f0 100644 --- a/grammars/silver/compiler/langserver/ReferenceLocations.sv +++ b/grammars/silver/compiler/langserver/ReferenceLocations.sv @@ -6,7 +6,7 @@ monoid attribute attributeRefLocs::[(Location, AttributeDclInfo)]; attribute valueRefLocs, typeRefLocs, attributeRefLocs occurs on RootSpec, Grammar, Root, NameList, AGDcls, AGDcl, - ProductionSignature, FunctionSignature, AspectProductionSignature, AspectFunctionSignature, + ProductionSignature, FunctionSignature, AspectProductionSignature, AspectFunctionSignature, AspectDefaultProductionSignature, ConstraintList, Constraint, ProductionLHS, FunctionLHS, AspectProductionLHS, AspectFunctionLHS, ProductionRHS, AspectRHS, ProductionRHSElem, AspectRHSElem, TypeExpr, Signature, SignatureLHS, TypeExprs, BracketedTypeExprs, BracketedOptTypeExprs, @@ -17,7 +17,7 @@ attribute valueRefLocs, typeRefLocs, attributeRefLocs occurs on propagate valueRefLocs, typeRefLocs, attributeRefLocs on RootSpec, Grammar, Root, NameList, AGDcls, AGDcl, - ProductionSignature, FunctionSignature, AspectProductionSignature, AspectFunctionSignature, + ProductionSignature, FunctionSignature, AspectProductionSignature, AspectFunctionSignature, AspectDefaultProductionSignature, ConstraintList, Constraint, ProductionLHS, FunctionLHS, AspectProductionLHS, AspectFunctionLHS, ProductionRHS, AspectRHS, ProductionRHSElem, AspectRHSElem, TypeExpr, Signature, SignatureLHS, TypeExprs, BracketedTypeExprs, BracketedOptTypeExprs, @@ -82,12 +82,30 @@ aspect attributeRefLocs on AGDcl using := of | strategyAttributeDcl(_, _, _, _, e) -> e.attributeRefLocs end; +aspect production propagateOnNTListDcl +top::AGDcl ::= attrs::NameList nts::NameList ps::ProdNameList +{ + propagate grammarName, env, flowEnv; +} + +aspect production tcMonoidAttributeDcl +top::AGDcl ::= 'monoid' 'attribute' a::Name tl::BracketedOptTypeExprs _ te::TypeExpr ';' +{ + propagate grammarName, env, flowEnv; +} + aspect attributeRefLocs on Constraint using <- of | inhOccursConstraint(_, at, _, _, _, _) -> if at.lookupAttribute.found then [(at.location, at.lookupAttribute.dcl)] else [] | synOccursConstraint(_, at, _, _, _, _, _) -> if at.lookupAttribute.found then [(at.location, at.lookupAttribute.dcl)] else [] | annoOccursConstraint(_, at, _, _, _, _) -> if at.lookupAttribute.found then [(at.location, at.lookupAttribute.dcl)] else [] end; +aspect valueRefLocs on top::ProductionStmt using <- of +| localAttributeDcl(_, _, id, _, _, _) -> map(\dcl :: ValueDclInfo -> (id.location, dcl), getValueDcl(id.name, top.env)) +| productionAttributeDcl(_, _, id, _, _, _) -> map(\dcl :: ValueDclInfo -> (id.location, dcl), getValueDcl(id.name, top.env)) +| forwardProductionAttributeDcl(_, _, _, id, _) -> map(\dcl :: ValueDclInfo -> (id.location, dcl), getValueDcl(id.name, top.env)) +end; + aspect valueRefLocs on ProductionStmt using := of | propagateOneAttr(_) -> [] end; @@ -112,10 +130,19 @@ end; aspect valueRefLocs on Expr using := of | access(q, _, _) -> q.valueRefLocs +| attributeSection(_, _, _, _) -> [] +| consListOp(h, _, t) -> h.valueRefLocs ++ t.valueRefLocs +| emptyList(_, _) -> [] +| stringAppendCall(a, b) -> a.valueRefLocs ++ b.valueRefLocs end; aspect attributeRefLocs on Expr using := of | access(_, _, a) -> a.attributeRefLocs +| attributeSection(_, _, a, _) -> a.attributeRefLocs +end; + +aspect typeRefLocs on Expr using := of +| attributeSection(_, _, _, _) -> [] end; aspect attributeRefLocs on AnnoExpr using <- of @@ -158,31 +185,120 @@ aspect attributeRefLocs on StrategyExpr using := of | totalRef(a) -> if attrDclFound then [(a.location, attrDcl)] else [] end; +-- Productions +-- LHS +aspect valueRefLocs on top::ProductionLHS using <- of +| productionLHS(id, _, _) -> map(\dcl :: ValueDclInfo -> (id.location, dcl), getValueDcl(id.name, top.env)) +end; + +aspect valueRefLocs on top::AspectProductionLHS using <- of +| aspectProductionLHSFull(id, _) -> map(\dcl :: ValueDclInfo -> (id.location, dcl), getValueDcl(id.name, top.env)) +end; + +aspect typeRefLocs on ProductionLHS using <- of +| productionLHS(_, _, t) -> t.typeRefLocs +end; + +aspect typeRefLocs on AspectProductionLHS using <- of +| aspectProductionLHSTyped(_, _, t) -> t.typeRefLocs +end; + +aspect typeRefLocs on top::AspectDefaultProductionSignature using <- of +| aspectDefaultProductionSignature(_,_,t,_) -> t.typeRefLocs +end; + +--RHS +aspect valueRefLocs on top::ProductionRHSElem using <- of +| productionRHSElem(id, _, _) -> map(\dcl :: ValueDclInfo -> (id.location, dcl), getValueDcl(id.name, top.env)) +end; + +aspect valueRefLocs on top::AspectRHSElem using <- of +| aspectRHSElemFull(id, _) -> map(\dcl :: ValueDclInfo -> (id.location, dcl), getValueDcl(id.name, top.env)) +end; + +aspect typeRefLocs on ProductionRHSElem using <- of +| productionRHSElem(_, _, t) -> t.typeRefLocs +end; + +aspect typeRefLocs on AspectRHSElem using <- of +| aspectRHSElemTyped(_, _, t) -> t.typeRefLocs +end; + synthesized attribute valueFileRefLocs::map:Map; synthesized attribute typeFileRefLocs::map:Map; synthesized attribute attributeFileRefLocs::map:Map; -attribute valueFileRefLocs, typeFileRefLocs, attributeFileRefLocs occurs on Compilation; +synthesized attribute allValueRefs::map:Map; +synthesized attribute allTypeRefs::map:Map; +synthesized attribute allAttributeRefs::map:Map; + +attribute valueFileRefLocs, typeFileRefLocs, attributeFileRefLocs, allValueRefs, allTypeRefs, allAttributeRefs occurs on Compilation; aspect production compilation top::Compilation ::= g::Grammars r::Grammars _ _ { - top.valueFileRefLocs = buildFileRefs((.valueRefLocs), g.grammarList); - top.typeFileRefLocs = buildFileRefs((.typeRefLocs), g.grammarList); - top.attributeFileRefLocs = buildFileRefs((.attributeRefLocs), g.grammarList); + top.valueFileRefLocs = buildFileRefs((.valueRefLocs), (.valueList), g.grammarList); + top.typeFileRefLocs = buildFileRefs((.typeRefLocs), (.typeList), g.grammarList); + top.attributeFileRefLocs = buildFileRefs((.attributeRefLocs), (.attrList), g.grammarList); + top.allValueRefs = buildAllRefs((.valueRefLocs), g.grammarList); + top.allTypeRefs = buildAllRefs((.typeRefLocs), g.grammarList); + top.allAttributeRefs = buildAllRefs((.attributeRefLocs), g.grammarList); } function buildFileRefs +annotation sourceLocation occurs on a, annotation sourceGrammar occurs on a => -map:Map ::= accessor::([(Location, a)] ::= Decorated RootSpec) rs::[Decorated RootSpec] +map:Map ::= + accessor::([(Location, a)] ::= Decorated RootSpec) + accessList::([EnvItem] ::= Def) + rs::[Decorated RootSpec] { return directBuildTree(flatMap(\ r::Decorated RootSpec -> map(\ item::(Location, a) -> (r.grammarSource ++ item.1.filename, item.1, head(map:lookup(item.2.sourceGrammar, r.compiledGrammars)), item.2), - accessor(r)), + accessor(r)) ++ + -- We add the declaration sites of all global defs as reference locations here as a shortcut + -- instead of adding aspects for them in RefLocs + flatMap(\def::Def -> + map(\item::EnvItem -> + (r.grammarSource ++ item.dcl.sourceLocation.filename, item.dcl.sourceLocation, r, item.dcl), + accessList(def)), + r.defs), rs)); } +-- Create a map from a reference's unique id to its path & location +function buildAllRefs +annotation sourceGrammar occurs on a, +annotation sourceLocation occurs on a, +attribute fullName {} occurs on a => +map:Map ::= accessor::([(Location, a)] ::= Decorated RootSpec) rs::[Decorated RootSpec] +{ + local grammarMap :: map:Map = + directBuildTree(map(\ r::Decorated RootSpec -> (r.declaredName, r.grammarSource), rs)); + + return directBuildTree(flatMap(\ r::Decorated RootSpec -> + (flatMap(\item::(Location, a) -> + [(makeRefId(item.2), r.grammarSource ++ item.1.filename, item.1)] ++ + -- Include source location & file of reference dcl + (map(\grammarPath::String -> + (makeRefId(item.2), grammarPath ++ item.2.sourceLocation.filename, item.2.sourceLocation), + map:lookup(item.2.sourceGrammar, grammarMap))), + accessor(r))), + rs)); +} + +-- Compute a unique identifier for a decl including its sourceGrammar and sourceLocation, +-- since fullName might not be globally unique. +function makeRefId +annotation sourceGrammar occurs on a, +annotation sourceLocation occurs on a, +attribute fullName {} occurs on a => +String ::= dcl::a +{ + return s"${dcl.fullName}@${dcl.sourceGrammar}@${dcl.sourceLocation.unparse}"; +} + attribute valueRefLocs, typeRefLocs, attributeRefLocs occurs on InterfaceItems, InterfaceItem; propagate valueRefLocs, typeRefLocs, attributeRefLocs on InterfaceItems; @@ -244,3 +360,28 @@ function findDeclLocation lookupDeclLocation(fileName, line, col, c.typeFileRefLocs) ++ lookupDeclLocation(fileName, line, col, c.attributeFileRefLocs); } + +-- Looks up all references to symbol at the given location +-- Returns a list of all reference locations +-- Input is filename, line & col number, & decl map to resolve the symbol +-- Uses refs map to lookup the reference paths & locations from the symbol unique id +function lookupReferenceLocations +annotation sourceGrammar occurs on a, +annotation sourceLocation occurs on a, +attribute fullName {} occurs on a => +[Location] ::= fileName::String line::Integer col::Integer decls::map:Map refs::map:Map +{ + return flatMap(\ item::(Decorated RootSpec, a) -> + map(\ loc::(String, Location) -> updateLocPath(loc.1, loc.2), + map:lookup(makeRefId(item.2), refs)), + lookupPos(line, col, map:lookup(fileName, decls))); +} + +function findReferences +[Location] ::= fileName::String line::Integer col::Integer c::Decorated Compilation +{ + return + lookupReferenceLocations(fileName, line, col, c.valueFileRefLocs, c.allValueRefs) ++ + lookupReferenceLocations(fileName, line, col, c.typeFileRefLocs, c.allTypeRefs) ++ + lookupReferenceLocations(fileName, line, col, c.attributeFileRefLocs, c.allAttributeRefs); +} diff --git a/grammars/silver/compiler/metatranslation/Translation.sv b/grammars/silver/compiler/metatranslation/Translation.sv index fe01f6eeb..2e6a11d43 100644 --- a/grammars/silver/compiler/metatranslation/Translation.sv +++ b/grammars/silver/compiler/metatranslation/Translation.sv @@ -27,12 +27,14 @@ Pattern ::= loc::Location ast::AST synthesized attribute translation::a; synthesized attribute patternTranslation::a; synthesized attribute foundLocation::Maybe; -autocopy attribute givenLocation::Location; +inherited attribute givenLocation::Location; flowtype translation {givenLocation} on AST, ASTs, NamedASTs, NamedAST; flowtype patternTranslation {givenLocation} on AST, ASTs; flowtype foundLocation {} on ASTs, NamedASTs, NamedAST; +propagate givenLocation on AST, ASTs, NamedASTs, NamedAST excluding nonterminalAST; + attribute givenLocation, translation, patternTranslation occurs on AST; aspect production nonterminalAST @@ -74,8 +76,8 @@ top::AST ::= prodName::String children::ASTs annotations::NamedASTs -- "Collection" antiquote productions -- Key: antiquote production name - -- Value: (nonterminal short name, cons production name, append production name) - production attribute collectionAntiquoteProductions::[(String, String, String, String)] with ++; + -- Value: (nonterminal short name, cons production name, nil production name, append production name) + production attribute collectionAntiquoteProductions::[(String, String, String, String, String)] with ++; collectionAntiquoteProductions := []; antiquoteTranslation <- do { @@ -83,26 +85,34 @@ top::AST ::= prodName::String children::ASTs annotations::NamedASTs antiquote::(String, AST, Decorated AST with {givenLocation}) <- case children of | consAST( - nonterminalAST(n, consAST(a, _), _), - consAST(rest, nilAST())) -> just((n, a, let decRest :: Decorated AST with {givenLocation} = rest in decRest end)) -- let is a workaround for type inference bug with case + nonterminalAST(p, consAST(a, _), _), + consAST(rest, nilAST())) -> + just((p, a, rest)) | _ -> nothing() end; - -- (nonterminal short name, cons production name, append production name) - trans::(String, String, String) <- + -- (nonterminal short name, cons production name, nil production name, append production name) + trans::(String, String, String, String) <- lookup(antiquote.1, collectionAntiquoteProductions); - if prodName == trans.2 then just(unit()) else nothing(); -- require prodName == trans.2 - return + guard(prodName == trans.2); + let antiquoteExpr::Expr = case reify(antiquote.2) of - | right(e) -> - mkStrFunctionInvocation( - givenLocation, trans.3, [e, antiquote.3.translation]) + | right(e) -> e | left(msg) -> error(s"Error in reifying child of production ${prodName}:\n${msg}") end; + return + case antiquote.3 of + -- The next item in the list is the nil production, no need to insert an append. + | nonterminalAST(p, _, _) when p == trans.3 -> antiquoteExpr + -- There are more items that need to be appended to the antiquoted expression. + | _ -> + mkStrFunctionInvocation( + givenLocation, trans.4, [antiquoteExpr, antiquote.3.translation]) + end; }; antiquoteTranslation <- do { -- (nonterminal short name, cons production name, append production name) - trans::(String, String, String) <- + trans::(String, String, String, String) <- lookup(prodName, collectionAntiquoteProductions); return errorExpr([err(givenLocation, s"$$${trans.1} may only occur as a member of ${trans.1}")], location=givenLocation); @@ -176,7 +186,7 @@ top::AST ::= prodName::String children::ASTs annotations::NamedASTs aspect production terminalAST top::AST ::= terminalName::String lexeme::String location::Location { - local locationAST::AST = reflect(new(location)); + local locationAST::AST = reflect(location); locationAST.givenLocation = top.givenLocation; top.translation = diff --git a/grammars/silver/compiler/modification/autocopyattr/AutoCopy.sv b/grammars/silver/compiler/modification/autocopyattr/AutoCopy.sv deleted file mode 100644 index 9e264a456..000000000 --- a/grammars/silver/compiler/modification/autocopyattr/AutoCopy.sv +++ /dev/null @@ -1,35 +0,0 @@ -grammar silver:compiler:modification:autocopyattr; - -terminal AutoCopy_kwd 'autocopy' lexer classes {KEYWORD}; - -concrete production attributeDclAuto -top::AGDcl ::= 'autocopy' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr ';' -{ - top.unparse = "autocopy attribute " ++ a.unparse ++ tl.unparse ++ " :: " ++ te.unparse ++ ";"; - - production attribute fName :: String; - fName = top.grammarName ++ ":" ++ a.name; - - top.defs := [autocopyDef(top.grammarName, a.location, fName, tl.freeVariables, te.typerep)]; - - tl.initialEnv = top.env; - tl.env = tl.envBindingTyVars; - te.env = tl.envBindingTyVars; - - top.errors := tl.errors ++ te.errors ++ tl.errorsTyVars; - - top.errors <- - if length(getAttrDclAll(fName, top.env)) > 1 - then [err(a.location, "Attribute '" ++ fName ++ "' is already bound.")] - else []; - - -- AUTOCOPY IS UNSOUND OTHERWISE - -- We don't know just from the "occurs on" bit whether the types are the same and its safe to autocopy, so... - top.errors <- - if !null(tl.types) - then [err(tl.location, "Autocopy attributes cannot be parameterized by type variables!")] - else []; - - forwards to attributeDclInh('inherited', $2, a, tl, $5, te, $7, location=top.location); -} - diff --git a/grammars/silver/compiler/modification/autocopyattr/DclInfo.sv b/grammars/silver/compiler/modification/autocopyattr/DclInfo.sv deleted file mode 100644 index c78fbb8ab..000000000 --- a/grammars/silver/compiler/modification/autocopyattr/DclInfo.sv +++ /dev/null @@ -1,36 +0,0 @@ -grammar silver:compiler:modification:autocopyattr; - -synthesized attribute isAutocopy :: Boolean occurs on AttributeDclInfo; - -aspect default production -top::AttributeDclInfo ::= -{ - top.isAutocopy = false; -} - -abstract production autocopyDcl -top::AttributeDclInfo ::= fn::String bound::[TyVar] ty::Type -{ - top.fullName = fn; - propagate compareKey; - - top.typeScheme = polyType(bound, ty); - - top.isInherited = true; - top.isAutocopy = true; - - -- the core dispatchers - top.decoratedAccessHandler = inhDecoratedAccessHandler(_, _, location=_); - top.undecoratedAccessHandler = accessBounceDecorate(inhDecoratedAccessHandler(_, _, location=_), _, _, _); -- TODO: should probably be an error handler! - top.attrDefDispatcher = inheritedAttributeDef(_, _, _, location=_); - top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); -} - --- Defs: - -function autocopyDef -Def ::= sg::String sl::Location fn::String bound::[TyVar] ty::Type -{ - return attrDef(defaultEnvItem(autocopyDcl(fn,bound,ty, sourceGrammar=sg, sourceLocation=sl))); -} - diff --git a/grammars/silver/compiler/modification/autocopyattr/Project.sv b/grammars/silver/compiler/modification/autocopyattr/Project.sv deleted file mode 100644 index bda4ec708..000000000 --- a/grammars/silver/compiler/modification/autocopyattr/Project.sv +++ /dev/null @@ -1,10 +0,0 @@ -grammar silver:compiler:modification:autocopyattr; - -imports silver:compiler:definition:env; -imports silver:compiler:definition:core; -imports silver:compiler:definition:type; -imports silver:compiler:definition:type:syntax; - -exports silver:compiler:modification:autocopyattr:java with silver:compiler:translation:java:core; -exports silver:compiler:modification:autocopyattr:convenience with silver:compiler:extension:convenience; - diff --git a/grammars/silver/compiler/modification/autocopyattr/convenience/Convenience.sv b/grammars/silver/compiler/modification/autocopyattr/convenience/Convenience.sv deleted file mode 100644 index c741d09dd..000000000 --- a/grammars/silver/compiler/modification/autocopyattr/convenience/Convenience.sv +++ /dev/null @@ -1,18 +0,0 @@ -grammar silver:compiler:modification:autocopyattr:convenience; - -import silver:compiler:modification:autocopyattr; -import silver:compiler:extension:convenience; -import silver:compiler:definition:core; -import silver:compiler:definition:concrete_syntax; -import silver:compiler:definition:type:syntax; -import silver:compiler:definition:type; -import silver:compiler:definition:env; - -concrete production attributeDclAutoMultiple -top::AGDcl ::= 'autocopy' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr 'occurs' 'on' qs::QNames ';' -{ - top.unparse = "autocopy attribute " ++ a.name ++ tl.unparse ++ " :: " ++ te.unparse ++ " occurs on " ++ qs.unparse ++ ";" ; - forwards to appendAGDcl(attributeDclAuto($1, $2, a, tl, $5, te, $10, location=a.location), - makeOccursDclsHelp($1.location, qNameWithTL(qNameId(a, location=a.location), tl), qs.qnames), location=top.location); -} - diff --git a/grammars/silver/compiler/modification/autocopyattr/java/Autocopy.sv b/grammars/silver/compiler/modification/autocopyattr/java/Autocopy.sv deleted file mode 100644 index 9cf48c409..000000000 --- a/grammars/silver/compiler/modification/autocopyattr/java/Autocopy.sv +++ /dev/null @@ -1,50 +0,0 @@ -grammar silver:compiler:modification:autocopyattr:java; -import silver:compiler:modification:autocopyattr; - -import silver:compiler:definition:core; -import silver:compiler:definition:env; -import silver:compiler:definition:type:syntax; -import silver:compiler:definition:type; - -import silver:compiler:translation:java:core; -import silver:compiler:translation:java:type; - - - -aspect production attributeDclAuto -top::AGDcl ::= 'autocopy' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr ';' -{ - local attribute className :: String; - className = "D" ++ a.name; - - top.genFiles := [pair(className ++ ".java", - -"package " ++ makeName(top.grammarName) ++ ";\n\n" ++ - -"import java.util.*;\n\n" ++ - -"public class " ++ className ++ " extends common.Decorator {\n\n" ++ - -"public static final " ++ className ++ " singleton = new " ++ className ++ "();\n\n" ++ - -"\tpublic void decorate(common.RTTIManager.Prodleton production) {\n" ++ -"\t\tdecorateAutoCopy(production, \"" ++ fName ++ "\");\n" ++ -"\t}\n" ++ -"}\n")]; -} - -aspect production attributionDcl -top::AGDcl ::= 'attribute' at::QName attl::BracketedOptTypeExprs 'occurs' 'on' nt::QName nttl::BracketedOptTypeExprs ';' -{ - top.setupInh <- - if at.lookupAttribute.dcl.isAutocopy then - "\t\t" ++ makeNTName(nt.lookupType.fullName) ++ ".decorators.add(" ++ makeDecoratorClassName(at.lookupAttribute.fullName) ++ ".singleton);\n" - else ""; -} - -function makeDecoratorClassName -String ::= s::String -{ - return substituteLast(".", ".D", makeName(s)); -} - diff --git a/grammars/silver/compiler/modification/collection/Collection.sv b/grammars/silver/compiler/modification/collection/Collection.sv index 5ed3513b6..1aa0e435c 100644 --- a/grammars/silver/compiler/modification/collection/Collection.sv +++ b/grammars/silver/compiler/modification/collection/Collection.sv @@ -3,12 +3,14 @@ grammar silver:compiler:modification:collection; import silver:compiler:definition:type:syntax; import silver:compiler:modification:list; ---import silver:compiler:analysis:typechecking:core; +import silver:compiler:analysis:typechecking:core; import silver:compiler:driver:util; import silver:compiler:definition:flow:driver only ProductionGraph, FlowType, constructAnonymousGraph; import silver:compiler:translation:java:core; nonterminal NameOrBOperator with config, location, grammarName, compiledGrammars, flowEnv, productionFlowGraphs, errors, env, unparse, operation, operatorForType; +propagate config, grammarName, compiledGrammars, flowEnv, productionFlowGraphs, env on NameOrBOperator; + nonterminal Operation with compareTo, isEqual; propagate compareTo, isEqual on Operation excluding functionOperation; @@ -47,6 +49,8 @@ top::NameOrBOperator ::= e::Expr e.frame = bogusContext(myFlowGraph, sourceGrammar=top.grammarName); e.originRules = []; e.isRoot = false; + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; } concrete production plusplusOperator @@ -147,6 +151,7 @@ concrete production collectionAttributeDclSyn top::AGDcl ::= 'synthesized' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr 'with' q::NameOrBOperator ';' { top.unparse = "synthesized attribute " ++ a.name ++ tl.unparse ++ " :: " ++ te.unparse ++ " with " ++ q.unparse ++ " ;" ; + propagate config, grammarName, compiledGrammars, grammarDependencies, errors; production attribute fName :: String; fName = top.grammarName ++ ":" ++ a.name; @@ -156,11 +161,10 @@ top::AGDcl ::= 'synthesized' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te.env = tl.envBindingTyVars; q.operatorForType = te.typerep; + q.env = top.env; top.defs := [synColDef(top.grammarName, a.location, fName, tl.freeVariables, te.typerep, q.operation)]; - propagate errors, flowDefs; - top.errors <- tl.errorsTyVars; top.errors <- te.errorsKindStar; @@ -174,6 +178,7 @@ concrete production collectionAttributeDclInh top::AGDcl ::= 'inherited' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::TypeExpr 'with' q::NameOrBOperator ';' { top.unparse = "inherited attribute " ++ a.name ++ tl.unparse ++ " :: " ++ te.unparse ++ " with " ++ q.unparse ++ " ;" ; + propagate config, grammarName, compiledGrammars, grammarDependencies, errors; production attribute fName :: String; fName = top.grammarName ++ ":" ++ a.name; @@ -183,10 +188,9 @@ top::AGDcl ::= 'inherited' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te te.env = tl.envBindingTyVars; q.operatorForType = te.typerep; + q.env = top.env; top.defs := [inhColDef(top.grammarName, a.location, fName, tl.freeVariables, te.typerep, q.operation)]; - - propagate errors, flowDefs; top.errors <- tl.errorsTyVars; top.errors <- te.errorsKindStar; @@ -202,6 +206,7 @@ concrete production collectionAttributeDclProd top::ProductionStmt ::= 'production' 'attribute' a::Name '::' te::TypeExpr 'with' q::NameOrBOperator ';' { top.unparse = "production attribute " ++ a.name ++ " :: " ++ te.unparse ++ " with " ++ q.unparse ++ " ;" ; + propagate config, grammarName, compiledGrammars, env, flowEnv; top.productionAttributes := [localColDef(top.grammarName, a.location, fName, te.typerep, q.operation)]; @@ -220,61 +225,57 @@ top::ProductionStmt ::= 'production' 'attribute' a::Name '::' te::TypeExpr 'with -- ERROR ON VALUE DEFS: abstract production errorCollectionValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { + undecorates to valContainsBase(val, ':=', e, ';', location=top.location); + -- Override to just e.errors since we don't want the standard error message about val cannot be assigned to. + top.errors := e.errors; + top.errors <- [err(top.location, "The ':=' and '<-' operators can only be used for collections. " ++ val.name ++ " is not a collection.")]; - - -- TODO: this production also produces an error message, so we'll produce two errors for one flaw. - -- We don't want to use := for the errors, because we'd miss any errors in e, and we don't want to repeat - -- it because that will produce duplicate trees. - forwards to errorValueDef(val, e, location=top.location); + + forwards to errorValueDef(val, @e, location=top.location); } abstract production errorColNormalValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { + undecorates to valueEq(val, '=', e, ';', location=top.location); + -- Override to just e.errors since we don't want the standard error message about val cannot be assigned to. + top.errors := e.errors; + top.errors <- [err(top.location, val.name ++ " is a collection attribute, and you must use ':=' or '<-', not '='.")]; - - -- TODO: same problem - forwards to errorValueDef(val, e, location=top.location); + + forwards to errorValueDef(val, @e, location=top.location); } -- NON-ERRORS for PRODUCTIONS abstract production baseCollectionValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { + undecorates to valContainsBase(val, ':=', e, ';', location=top.location); top.unparse = "\t" ++ val.unparse ++ " := " ++ e.unparse ++ ";"; - e.isRoot = false; - - e.downSubst = top.downSubst; - -- the real type checking is done by the forward, but we must ensure things are tied up nicely - -- otherwise we don't specialize ntOrDecs in OUR e - forward.downSubst = unifyCheck(val.lookupValue.typeScheme.monoType, e.typerep, e.upSubst); - - forwards to localValueDef(val, e, location=top.location); + -- TODO: We override the translation, so this probably shouldn't be a forwarding production... + forwards to localValueDef(val, @e, location=top.location); } abstract production appendCollectionValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { + undecorates to valContainsAppend(val, '<-', e, ';', location=top.location); top.unparse = "\t" ++ val.unparse ++ " <- " ++ e.unparse ++ ";"; - e.isRoot = false; - - e.downSubst = top.downSubst; - -- the real type checking is done by the forward, but we must ensure things are tied up nicely - -- otherwise we don't specialize ntOrDecs in OUR e - forward.downSubst = unifyCheck(val.lookupValue.typeScheme.monoType, e.typerep, e.upSubst); - - forwards to localValueDef(val, e, location=top.location); + -- TODO: We override the translation, so this probably shouldn't be a forwarding production... + forwards to localValueDef(val, @e, location=top.location); } -- NON-ERRORS for SYN ATTRS abstract production synBaseColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { + undecorates to attrContainsBase(dl, '.', attr, ':=', e, ';', location=top.location); top.unparse = "\t" ++ dl.unparse ++ "." ++ attr.unparse ++ " := " ++ e.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, frame, env, finalSubst, originRules; top.errors := e.errors; @@ -291,9 +292,11 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated else []; } abstract production synAppendColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { + undecorates to attrContainsAppend(dl, '.', attr, '<-', e, ';', location=top.location); top.unparse = "\t" ++ dl.unparse ++ "." ++ attr.unparse ++ " <- " ++ e.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, frame, env, finalSubst, originRules; top.errors := e.errors; @@ -313,9 +316,11 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated -- NON-ERRORS for INHERITED ATTRS abstract production inhBaseColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { + undecorates to attrContainsBase(dl, '.', attr, ':=', e, ';', location=top.location); top.unparse = "\t" ++ dl.unparse ++ "." ++ attr.unparse ++ " := " ++ e.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, frame, env, finalSubst, originRules; top.errors := e.errors; @@ -332,9 +337,11 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated else []; } abstract production inhAppendColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { + undecorates to attrContainsAppend(dl, '.', attr, '<-', e, ';', location=top.location); top.unparse = "\t" ++ dl.unparse ++ "." ++ attr.unparse ++ " <- " ++ e.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, frame, env, finalSubst, originRules; top.errors := e.errors; @@ -360,6 +367,7 @@ concrete production attrContainsAppend top::ProductionStmt ::= dl::DefLHS '.' attr::QNameAttrOccur '<-' e::Expr ';' { top.unparse = "\t" ++ dl.unparse ++ "." ++ attr.unparse ++ " <- " ++ e.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, frame, env, finalSubst, originRules, flowEnv; -- defs must stay here explicitly, because we dispatch on types in the forward here! top.productionAttributes := []; @@ -378,6 +386,7 @@ concrete production attrContainsBase top::ProductionStmt ::= dl::DefLHS '.' attr::QNameAttrOccur ':=' e::Expr ';' { top.unparse = "\t" ++ dl.unparse ++ "." ++ attr.unparse ++ " := " ++ e.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, frame, env, finalSubst, originRules, flowEnv; -- defs must stay here explicitly, because we dispatch on types in the forward here! top.productionAttributes := []; @@ -396,6 +405,7 @@ concrete production valContainsAppend top::ProductionStmt ::= val::QName '<-' e::Expr ';' { top.unparse = val.unparse ++ " <- " ++ e.unparse ++ ";"; + propagate compiledGrammars, frame, env, finalSubst, originRules; top.errors <- val.lookupValue.errors; @@ -412,6 +422,7 @@ concrete production valContainsBase top::ProductionStmt ::= val::QName ':=' e::Expr ';' { top.unparse = val.unparse ++ " := " ++ e.unparse ++ ";"; + propagate compiledGrammars, frame, env, finalSubst, originRules; top.errors <- val.lookupValue.errors; diff --git a/grammars/silver/compiler/modification/collection/DclInfo.sv b/grammars/silver/compiler/modification/collection/DclInfo.sv index 150ef6faa..a1b148ec8 100644 --- a/grammars/silver/compiler/modification/collection/DclInfo.sv +++ b/grammars/silver/compiler/modification/collection/DclInfo.sv @@ -1,25 +1,24 @@ grammar silver:compiler:modification:collection; -attribute operation, attrBaseDefDispatcher, attrAppendDefDispatcher occurs on AttributeDclInfo; +attribute isCollection, operation, attrBaseDefDispatcher, attrAppendDefDispatcher occurs on AttributeDclInfo; attribute operation, baseDefDispatcher, appendDefDispatcher occurs on ValueDclInfo; -synthesized attribute attrBaseDefDispatcher :: (ProductionStmt ::= PartiallyDecorated DefLHS PartiallyDecorated QNameAttrOccur Expr Location); -synthesized attribute attrAppendDefDispatcher :: (ProductionStmt ::= PartiallyDecorated DefLHS PartiallyDecorated QNameAttrOccur Expr Location); +synthesized attribute isCollection::Boolean; -synthesized attribute baseDefDispatcher :: (ProductionStmt ::= PartiallyDecorated QName Expr Location); -synthesized attribute appendDefDispatcher :: (ProductionStmt ::= PartiallyDecorated QName Expr Location); +synthesized attribute attrBaseDefDispatcher :: (ProductionStmt ::= Decorated! DefLHS Decorated! QNameAttrOccur Expr Location); +synthesized attribute attrAppendDefDispatcher :: (ProductionStmt ::= Decorated! DefLHS Decorated! QNameAttrOccur Expr Location); + +synthesized attribute baseDefDispatcher :: (ProductionStmt ::= Decorated! QName Expr Location); +synthesized attribute appendDefDispatcher :: (ProductionStmt ::= Decorated! QName Expr Location); aspect default production top::AttributeDclInfo ::= { + top.isCollection = false; top.operation = error("Internal compiler error: must be defined for all collection attribute declarations"); - top.attrBaseDefDispatcher = - \ dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr l::Location -> - errorAttributeDef([err(l, "The ':=' operator can only be used for collections. " ++ attr.name ++ " is not a collection.")], dl, attr, e, location=l); - top.attrAppendDefDispatcher = - \ dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr l::Location -> - errorAttributeDef([err(l, "The '<-' operator can only be used for collections. " ++ attr.name ++ " is not a collection.")], dl, attr, e, location=l); + top.attrBaseDefDispatcher = nonCollectionAttrBaseDefError; + top.attrAppendDefDispatcher = nonCollectionAttrAppendDefError; } aspect default production @@ -44,13 +43,13 @@ top::AttributeDclInfo ::= fn::String bound::[TyVar] ty::Type o::Operation top.typeScheme = polyType(bound, ty); top.isSynthesized = true; + top.isCollection = true; top.operation = o; top.decoratedAccessHandler = synDecoratedAccessHandler(_, _, location=_); top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); - top.attrDefDispatcher = - \ dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr l::Location -> - errorAttributeDef([err(l, attr.name ++ " is a collection attribute, and you must use ':=' or '<-', not '='.")], dl, attr, e, location=l); + top.dataAccessHandler = synDataAccessHandler(_, _, location=_); + top.attrDefDispatcher = collectionAttrDefError; top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); top.attrBaseDefDispatcher = synBaseColAttributeDef(_, _, _, location=_); @@ -69,13 +68,13 @@ top::AttributeDclInfo ::= fn::String bound::[TyVar] ty::Type o::Operation top.typeScheme = polyType(bound, ty); top.isInherited = true; + top.isCollection = true; top.operation = o; top.decoratedAccessHandler = inhDecoratedAccessHandler(_, _, location=_); - top.undecoratedAccessHandler = accessBounceDecorate(inhDecoratedAccessHandler(_, _, location=_), _, _, _); -- TODO: above should probably be an error handler! - top.attrDefDispatcher = - \ dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr l::Location -> - errorAttributeDef([err(l, attr.name ++ " is a collection attribute, and you must use ':=' or '<-', not '='.")], dl, attr, e, location=l); + top.undecoratedAccessHandler = inhUndecoratedAccessErrorHandler(_, _, location=_); + top.dataAccessHandler = inhUndecoratedAccessErrorHandler(_, _, location=_); + top.attrDefDispatcher = collectionAttrDefError; top.attributionDispatcher = defaultAttributionDcl(_, _, _, _, location=_); top.attrBaseDefDispatcher = inhBaseColAttributeDef(_, _, _, location=_); @@ -102,9 +101,21 @@ top::ValueDclInfo ::= fn::String ty::Type o::Operation -- TODO: attrOccursIndex -- We shouldn't be forwarding here - forwards to localDcl(fn,ty,sourceGrammar=top.sourceGrammar,sourceLocation=top.sourceLocation); + forwards to localDcl(fn,ty,false,sourceGrammar=top.sourceGrammar,sourceLocation=top.sourceLocation); } +global nonCollectionAttrBaseDefError::(ProductionStmt ::= Decorated! DefLHS Decorated! QNameAttrOccur Expr Location) = + \ dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr l::Location -> + errorAttributeDef([err(l, "The ':=' operator can only be used for collections. " ++ attr.name ++ " is not a collection.")], dl, attr, e, location=l); + +global nonCollectionAttrAppendDefError::(ProductionStmt ::= Decorated! DefLHS Decorated! QNameAttrOccur Expr Location) = + \ dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr l::Location -> + errorAttributeDef([err(l, "The '<-' operator can only be used for collections. " ++ attr.name ++ " is not a collection.")], dl, attr, e, location=l); + +global collectionAttrDefError::(ProductionStmt ::= Decorated! DefLHS Decorated! QNameAttrOccur Expr Location) = + \ dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr l::Location -> + errorAttributeDef([err(l, attr.name ++ " is a collection attribute, and you must use ':=' or '<-', not '='.")], dl, attr, e, location=l); + -- Defs function synColDef diff --git a/grammars/silver/compiler/modification/collection/Project.sv b/grammars/silver/compiler/modification/collection/Project.sv index 2d43a3ae9..b848057aa 100644 --- a/grammars/silver/compiler/modification/collection/Project.sv +++ b/grammars/silver/compiler/modification/collection/Project.sv @@ -3,6 +3,7 @@ grammar silver:compiler:modification:collection; imports silver:compiler:definition:env; imports silver:compiler:definition:core; imports silver:compiler:definition:type; +imports silver:compiler:definition:flow:env; exports silver:compiler:modification:collection:java with silver:compiler:translation:java:core; diff --git a/grammars/silver/compiler/modification/collection/java/Collection.sv b/grammars/silver/compiler/modification/collection/java/Collection.sv index ba6d36906..a4c1a2e01 100644 --- a/grammars/silver/compiler/modification/collection/java/Collection.sv +++ b/grammars/silver/compiler/modification/collection/java/Collection.sv @@ -125,7 +125,7 @@ top::AGDcl ::= 'synthesized' 'attribute' a::Name tl::BracketedOptTypeExprs '::' o.leftOpTranslation = s"(${te.typerep.transType})result"; o.rightOpTranslation = s"(${te.typerep.transType})this.getPieces().get(i).eval(context)"; - top.genFiles := [pair(className ++ ".java", + top.genFiles := [(className ++ ".java", s""" package ${makeName(top.grammarName)}; @@ -159,7 +159,7 @@ top::AGDcl ::= 'inherited' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te o.leftOpTranslation = s"(${te.typerep.transType})result"; o.rightOpTranslation = s"(${te.typerep.transType})this.getPieces().get(i).eval(context)"; - top.genFiles := [pair(className ++ ".java", + top.genFiles := [(className ++ ".java", s""" package ${makeName(top.grammarName)}; @@ -187,7 +187,7 @@ public class ${className} extends common.CollectionAttribute { ---------- LOCALS --- aspect production baseCollectionValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { -- for locals, the CA object was created already top.translation = s""" @@ -196,7 +196,7 @@ top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr """; } aspect production appendCollectionValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { -- for locals, the CA object was created already top.translation = s""" @@ -207,7 +207,7 @@ top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr ---------- SYNTHESIZED ---- aspect production synBaseColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur {- := -} e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur {- := -} e::Expr { top.translation = s""" // ${dl.unparse}.${attr.unparse} := ${e.unparse} @@ -217,7 +217,7 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated """; } aspect production synAppendColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur {- <- -} e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur {- <- -} e::Expr { top.translation = s""" // ${dl.unparse}.${attr.unparse} <- ${e.unparse} @@ -229,7 +229,7 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated ---------- INHERITED ---- aspect production inhBaseColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur {- := -} e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur {- := -} e::Expr { top.translation = s""" // ${dl.unparse}.${attr.unparse} := ${e.unparse} @@ -239,7 +239,7 @@ top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated """; } aspect production inhAppendColAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur {- <- -} e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur {- <- -} e::Expr { top.translation = s""" // ${dl.unparse}.${attr.unparse} <- ${e.unparse} diff --git a/grammars/silver/compiler/modification/copper/ActionCode.sv b/grammars/silver/compiler/modification/copper/ActionCode.sv index 1dadf7462..7a0e8df29 100644 --- a/grammars/silver/compiler/modification/copper/ActionCode.sv +++ b/grammars/silver/compiler/modification/copper/ActionCode.sv @@ -6,6 +6,7 @@ concrete production concreteProductionDclAction top::AGDcl ::= 'concrete' 'production' id::Name ns::ProductionSignature pm::ProductionModifiers body::ProductionBody 'action' acode::ActionCode_c { top.unparse = forward.unparse ++ "action " ++ acode.unparse; + propagate config, grammarName, compiledGrammars, flowEnv; production fName :: String = top.grammarName ++ ":" ++ id.name; @@ -50,7 +51,7 @@ top::ActionCode_c ::= '{' stmts::ProductionStmts '}' { top.unparse = "{\n" ++ stmts.unparse ++ "}\n"; top.defs := flatMap(hackTransformLocals, stmts.defs); - propagate flowDefs; + propagate config, grammarName, compiledGrammars, env, frame, flowDefs, flowEnv; top.actionCode = -- action code translation goes in the env/syntax AST, so we might demand it @@ -113,7 +114,7 @@ function hackTransformLocals { return case d of - | valueDef(item) when item.dcl matches localDcl(fn,ty,sourceGrammar=sg,sourceLocation=sl) -> [parserLocalDef(sg,sl,fn,ty)] + | valueDef(item) when item.dcl matches localDcl(fn,ty,false,sourceGrammar=sg,sourceLocation=sl) -> [parserLocalDef(sg,sl,fn,ty)] | _ -> [] -- TODO: possibly error?? end; } diff --git a/grammars/silver/compiler/modification/copper/CustomLayout.sv b/grammars/silver/compiler/modification/copper/CustomLayout.sv index 64c55751c..39380136f 100644 --- a/grammars/silver/compiler/modification/copper/CustomLayout.sv +++ b/grammars/silver/compiler/modification/copper/CustomLayout.sv @@ -7,6 +7,7 @@ concrete production productionModifierLayout top::ProductionModifier ::= 'layout' '{' terms::TermList '}' { top.unparse = "layout {" ++ terms.unparse ++ "}"; + propagate env; top.productionModifiers := [prodLayout(terms.termList)]; top.errors := terms.errors; @@ -25,6 +26,7 @@ concrete production nonterminalModifierLayout top::NonterminalModifier ::= 'layout' '{' terms::TermList '}' { top.unparse = "layout {" ++ terms.unparse ++ "}"; + propagate env; top.nonterminalModifiers := [ntLayout(terms.termList)]; top.errors := terms.errors; diff --git a/grammars/silver/compiler/modification/copper/DclInfo.sv b/grammars/silver/compiler/modification/copper/DclInfo.sv index c1971005a..c351ac8c9 100644 --- a/grammars/silver/compiler/modification/copper/DclInfo.sv +++ b/grammars/silver/compiler/modification/copper/DclInfo.sv @@ -22,6 +22,8 @@ top::ValueDclInfo ::= fn::String ty::Type top.refDispatcher = parserAttributeReference(_, location=_); top.defDispatcher = parserAttributeValueDef(_, _, location=_); top.defLHSDispatcher = parserAttributeDefLHS(_, location=_); + top.transDefLHSDispatcher = \ q::Decorated! QName Decorated! QNameAttrOccur l::Location -> + parserAttributeDefLHS(q, location=l); } {-- @@ -40,6 +42,7 @@ top::ValueDclInfo ::= fn::String top.refDispatcher = pluckTerminalReference(_, location=_); top.defDispatcher = errorValueDef(_, _, location=_); top.defLHSDispatcher = errorDefLHS(_, location=_); + top.transDefLHSDispatcher = errorTransAttrDefLHS(_, _, location=_); } {-- @@ -59,6 +62,7 @@ top::ValueDclInfo ::= fn::String superClasses::[String] top.refDispatcher = lexerClassReference(_, location=_); top.defDispatcher = errorValueDef(_, _, location=_); top.defLHSDispatcher = errorDefLHS(_, location=_); + top.transDefLHSDispatcher = errorTransAttrDefLHS(_, _, location=_); } {-- @@ -75,6 +79,7 @@ top::ValueDclInfo ::= fn::String ty::Type top.refDispatcher = termAttrValueReference(_, location=_); top.defDispatcher = termAttrValueValueDef(_, _, location=_); top.defLHSDispatcher = errorDefLHS(_, location=_); + top.transDefLHSDispatcher = errorTransAttrDefLHS(_, _, location=_); } {-- @@ -91,6 +96,8 @@ top::ValueDclInfo ::= fn::String ty::Type top.refDispatcher = actionChildReference(_, location=_); top.defDispatcher = errorValueDef(_, _, location=_); top.defLHSDispatcher = parserAttributeDefLHS(_, location=_); -- TODO: specialize this + top.transDefLHSDispatcher = \ q::Decorated! QName Decorated! QNameAttrOccur l::Location -> + parserAttributeDefLHS(q, location=l); } {-- @@ -108,4 +115,6 @@ top::ValueDclInfo ::= fn::String ty::Type top.refDispatcher = parserAttributeReference(_, location=_); top.defDispatcher = parserAttributeValueDef(_, _, location=_); top.defLHSDispatcher = parserAttributeDefLHS(_, location=_); + top.transDefLHSDispatcher = \ q::Decorated! QName Decorated! QNameAttrOccur l::Location -> + parserAttributeDefLHS(q, location=l); } diff --git a/grammars/silver/compiler/modification/copper/DisambiguationGroup.sv b/grammars/silver/compiler/modification/copper/DisambiguationGroup.sv index f56fdc0ef..db3a11fbf 100644 --- a/grammars/silver/compiler/modification/copper/DisambiguationGroup.sv +++ b/grammars/silver/compiler/modification/copper/DisambiguationGroup.sv @@ -6,9 +6,9 @@ concrete production disambiguationGroupDcl top::AGDcl ::= 'disambiguate' terms::TermList acode::ActionCode_c { top.unparse = "disambiguate " ++ terms.unparse ++ " " ++ acode.unparse; + propagate config, grammarName, compiledGrammars, errors; - top.errors := terms.errors ++ acode.errors; - + terms.env = top.env; acode.env = newScopeEnv(disambiguationActionVars ++ acode.defs ++ terms.defs, top.env); -- Give the group a name, deterministically, based on line number diff --git a/grammars/silver/compiler/modification/copper/Env.sv b/grammars/silver/compiler/modification/copper/Env.sv index ee8756df6..8ccc49119 100644 --- a/grammars/silver/compiler/modification/copper/Env.sv +++ b/grammars/silver/compiler/modification/copper/Env.sv @@ -72,38 +72,38 @@ Def ::= sg::String sl::Location fn::String ty::Type synthesized attribute lexerClassTree :: EnvTree occurs on Env; -aspect production i_emptyEnv +aspect production emptyEnv top::Env ::= { top.lexerClassTree = emptyEnvTree(); } -aspect production i_appendEnv -top::Env ::= e1::Decorated Env e2::Decorated Env +aspect production appendEnv +top::Env ::= e1::Env e2::Env { top.lexerClassTree = appendEnvTree(e1.lexerClassTree, e2.lexerClassTree); } -aspect production i_newScopeEnv -top::Env ::= d::Defs e::Decorated Env +aspect production newScopeEnv +top::Env ::= _ e::Env { top.lexerClassTree = consEnvTree(d.lexerClassList, e.lexerClassTree); } -aspect production i_occursEnv -top::Env ::= _ e::Decorated Env +aspect production occursEnv +top::Env ::= _ e::Env { top.lexerClassTree = e.lexerClassTree; } function getLexerClassDcl -[ValueDclInfo] ::= search::String e::Decorated Env +[ValueDclInfo] ::= search::String e::Env { return searchEnvTree(search, e.lexerClassTree); } function expandTransitiveSuperClasses -[String] ::= seen::[String] toExpand::[String] e::Decorated Env +[String] ::= seen::[String] toExpand::[String] e::Env { return case toExpand of @@ -119,24 +119,24 @@ function expandTransitiveSuperClasses -------------------------------------------------------------------------------- -- QName.sv -synthesized attribute lookupLexerClass :: Decorated QNameLookup occurs on QName; +synthesized attribute lookupLexerClass :: QNameLookup occurs on QName; aspect production qNameId top::QName ::= id::Name { - top.lookupLexerClass = decorate customLookup("lexer class", getLexerClassDcl(top.name, top.env), top.name, top.location) with {}; + top.lookupLexerClass = customLookup("lexer class", getLexerClassDcl(top.name, top.env), top.name, top.location); } aspect production qNameCons top::QName ::= id::Name ':' qn::QName { - top.lookupLexerClass = decorate customLookup("lexer class", getLexerClassDcl(top.name, top.env), top.name, top.location) with {}; + top.lookupLexerClass = customLookup("lexer class", getLexerClassDcl(top.name, top.env), top.name, top.location); } aspect production qNameError top::QName ::= msg::[Message] { - top.lookupLexerClass = decorate errorLookup(msg) with {}; + top.lookupLexerClass = errorLookup(msg); } diff --git a/grammars/silver/compiler/modification/copper/Expr.sv b/grammars/silver/compiler/modification/copper/Expr.sv index 94fbf977f..482910c8e 100644 --- a/grammars/silver/compiler/modification/copper/Expr.sv +++ b/grammars/silver/compiler/modification/copper/Expr.sv @@ -19,8 +19,9 @@ top::Expr ::= 'disambiguationFailure' } abstract production actionChildReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars := ts:fromList([q.name]); @@ -35,8 +36,9 @@ top::Expr ::= q::PartiallyDecorated QName } abstract production pluckTerminalReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars := ts:fromList([q.name]); @@ -56,8 +58,9 @@ top::Expr ::= q::PartiallyDecorated QName -- thing. Also having type classes would let us use a more specific type than generic TerminalId, -- and pluckTerminalReference wouldn't need to cheat with a fresh type. abstract production terminalIdReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars := ts:fromList([q.name]); @@ -74,8 +77,9 @@ top::Expr ::= q::PartiallyDecorated QName } abstract production lexerClassReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars := ts:fromList([q.name]); @@ -93,8 +97,9 @@ top::Expr ::= q::PartiallyDecorated QName } abstract production parserAttributeReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars := ts:fromList([q.name]); @@ -112,8 +117,9 @@ top::Expr ::= q::PartiallyDecorated QName } abstract production termAttrValueReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.freeVars := ts:fromList([q.name]); diff --git a/grammars/silver/compiler/modification/copper/LexerClass.sv b/grammars/silver/compiler/modification/copper/LexerClass.sv index 7bc6609e2..87bad0c0f 100644 --- a/grammars/silver/compiler/modification/copper/LexerClass.sv +++ b/grammars/silver/compiler/modification/copper/LexerClass.sv @@ -18,6 +18,7 @@ concrete production lexerClassDecl top::AGDcl ::= 'lexer' 'class' id::Name modifiers::LexerClassModifiers ';' { top.unparse = "lexer class " ++ id.name ++ modifiers.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, env; production attribute fName :: String; fName = top.grammarName ++ ":" ++ id.name; @@ -43,8 +44,9 @@ closed nonterminal LexerClassModifier with config, location, unparse, lexerClass monoid attribute lexerClassModifiers :: [SyntaxLexerClassModifier]; -propagate errors on LexerClassModifiers, LexerClassModifier; -propagate lexerClassModifiers, superClasses on LexerClassModifiers; +propagate config, grammarName, compiledGrammars, flowEnv, errors on LexerClassModifiers, LexerClassModifier; +propagate env, lexerClassModifiers, superClasses on LexerClassModifiers; +propagate env on LexerClassModifier excluding lexerClassModifierDisambiguate; abstract production lexerClassModifiersNone top::LexerClassModifiers ::= diff --git a/grammars/silver/compiler/modification/copper/ParserAttributes.sv b/grammars/silver/compiler/modification/copper/ParserAttributes.sv index 721e37baf..998787803 100644 --- a/grammars/silver/compiler/modification/copper/ParserAttributes.sv +++ b/grammars/silver/compiler/modification/copper/ParserAttributes.sv @@ -4,13 +4,13 @@ concrete production attributeDclParser top::AGDcl ::= 'parser' 'attribute' a::Name '::' te::TypeExpr 'action' acode::ActionCode_c ';' { top.unparse = "parser attribute " ++ a.name ++ " :: " ++ te.unparse ++ " action " ++ acode.unparse ++ " ;" ; + propagate config, grammarName, compiledGrammars, errors; production attribute fName :: String; fName = top.grammarName ++ ":" ++ a.name; top.defs := [parserAttrDef(top.grammarName, a.location, fName, te.typerep)]; - propagate errors; top.errors <- if length(getValueDclAll(fName, top.env)) > 1 then [err(a.location, "Attribute '" ++ fName ++ "' is already bound.")] else []; @@ -23,6 +23,8 @@ top::AGDcl ::= 'parser' 'attribute' a::Name '::' te::TypeExpr 'action' acode::Ac local myFlowGraph :: ProductionGraph = constructAnonymousGraph(acode.flowDefs, top.env, myProds, myFlow); + te.env = top.env; + acode.frame = actionContext(myFlowGraph, sourceGrammar=top.grammarName); acode.env = newScopeEnv(acode.defs, top.env); @@ -36,13 +38,13 @@ concrete production attributeAspectParser top::AGDcl ::= 'aspect' 'parser' 'attribute' a::QName 'action' acode::ActionCode_c ';' { top.unparse = "aspect parser attribute " ++ a.name ++ " action " ++ acode.unparse ++ " ;" ; + propagate config, grammarName, compiledGrammars, errors; production attribute fName :: String; fName = a.lookupValue.dcl.fullName; top.defs := []; - propagate errors; top.errors <- if null(a.lookupValue.dcls) then [err(a.location, "Undefined attribute '" ++ a.name ++ "'.")] else []; @@ -54,6 +56,8 @@ top::AGDcl ::= 'aspect' 'parser' 'attribute' a::QName 'action' acode::ActionCode local myFlowGraph :: ProductionGraph = constructAnonymousGraph(acode.flowDefs, top.env, myProds, myFlow); + a.env = top.env; + acode.frame = actionContext(myFlowGraph, sourceGrammar=top.grammarName); acode.env = newScopeEnv(acode.defs, top.env); diff --git a/grammars/silver/compiler/modification/copper/ParserDcl.sv b/grammars/silver/compiler/modification/copper/ParserDcl.sv index 5684b016e..101606344 100644 --- a/grammars/silver/compiler/modification/copper/ParserDcl.sv +++ b/grammars/silver/compiler/modification/copper/ParserDcl.sv @@ -11,7 +11,7 @@ top::AGDcl ::= 'parser' n::Name '::' t::TypeExpr '{' m::ParserComponents '}' { top.unparse = "parser " ++ m.unparse ++ ";"; -- TODO? - propagate errors, moduleNames; + propagate config, grammarName, compiledGrammars, errors, moduleNames; -- Right now parsers masquerade as functions. This is probably fine. -- Only bug is that you can aspect it, but it's pointless to do so, you can't affect anything. @@ -24,6 +24,7 @@ top::AGDcl ::= 'parser' n::Name '::' t::TypeExpr '{' m::ParserComponents '}' production med :: ModuleExportedDefs = moduleExportedDefs(top.location, top.compiledGrammars, m.grammarDependencies, m.moduleNames, []); + t.env = top.env; m.env = appendEnv(toEnv(med.defs), top.env); production fName :: String = top.grammarName ++ ":" ++ n.name; @@ -33,7 +34,7 @@ top::AGDcl ::= 'parser' n::Name '::' t::TypeExpr '{' m::ParserComponents '}' foldNamedSignatureElements([ namedSignatureElement("stringToParse", stringType()), namedSignatureElement("filenameToReport", stringType())]), - namedSignatureElement("__func__lhs", appType(nonterminalType("silver:core:ParseResult", [starKind()], false), t.typerep)), + namedSignatureElement("__func__lhs", appType(nonterminalType("silver:core:ParseResult", [starKind()], true, false), t.typerep)), nilNamedSignatureElement()); production spec :: ParserSpec = @@ -47,7 +48,7 @@ top::AGDcl ::= 'parser' n::Name '::' t::TypeExpr '{' m::ParserComponents '}' nonterminal ParserComponents with config, env, flowEnv, grammarName, location, unparse, errors, moduleNames, compiledGrammars, grammarDependencies, terminalPrefixes, grammarTerminalPrefixes, syntaxAst, genFiles; -propagate errors, moduleNames, terminalPrefixes, grammarTerminalPrefixes, syntaxAst, genFiles on ParserComponents; +propagate config, env, flowEnv, grammarName, compiledGrammars, grammarDependencies, errors, moduleNames, terminalPrefixes, grammarTerminalPrefixes, syntaxAst, genFiles on ParserComponents; concrete production nilParserComponent top::ParserComponents ::= @@ -63,7 +64,7 @@ top::ParserComponents ::= c1::ParserComponent c2::ParserComponents closed nonterminal ParserComponent with config, env, flowEnv, grammarName, location, unparse, errors, moduleNames, compiledGrammars, grammarDependencies, terminalPrefixes, grammarTerminalPrefixes, syntaxAst, genFiles; -propagate errors, moduleNames, terminalPrefixes, grammarTerminalPrefixes, syntaxAst, genFiles on ParserComponent; +propagate config, env, flowEnv, grammarName, compiledGrammars, grammarDependencies, errors, moduleNames, terminalPrefixes, grammarTerminalPrefixes, syntaxAst, genFiles on ParserComponent; aspect default production top::ParserComponent ::= @@ -79,12 +80,12 @@ top::ParserComponent ::= m::ModuleName mods::ParserComponentModifiers ';' mods.componentGrammarName = head(m.moduleNames); } -autocopy attribute componentGrammarName::String; +inherited attribute componentGrammarName::String; {-- Have special env built from just this parser component and the global env -} nonterminal ParserComponentModifiers with config, env, flowEnv, grammarName, componentGrammarName, compiledGrammars, grammarDependencies, location, unparse, errors, terminalPrefixes, grammarTerminalPrefixes, syntaxAst, genFiles; -propagate errors, terminalPrefixes, grammarTerminalPrefixes, syntaxAst, genFiles on ParserComponentModifiers; +propagate config, env, flowEnv, grammarName, componentGrammarName, compiledGrammars, grammarDependencies, errors, terminalPrefixes, grammarTerminalPrefixes, syntaxAst, genFiles on ParserComponentModifiers; concrete production nilParserComponentModifier top::ParserComponentModifiers ::= @@ -100,7 +101,7 @@ top::ParserComponentModifiers ::= h::ParserComponentModifier t::ParserComponentM nonterminal ParserComponentModifier with config, env, flowEnv, grammarName, componentGrammarName, compiledGrammars, grammarDependencies, location, unparse, errors, terminalPrefixes, grammarTerminalPrefixes, syntaxAst, genFiles; -propagate errors, terminalPrefixes, grammarTerminalPrefixes, syntaxAst, genFiles on ParserComponentModifier; +propagate config, env, flowEnv, grammarName, componentGrammarName, compiledGrammars, grammarDependencies, errors, terminalPrefixes, grammarTerminalPrefixes, syntaxAst, genFiles on ParserComponentModifier; aspect default production top::ParserComponentModifier ::= @@ -129,8 +130,8 @@ top::AGDcl ::= 'parser' n::Name '::' t::TypeExpr '{' m::ParserComponents '}' -- TODO: As a hack, even though we don't propogates defs up to the top level, we -- do generate files for the lifted dcl. Needed to generate terminal class files. top.genFiles := m.genFiles ++ - [pair(className ++ ".java", - generateFunctionClassString(top.grammarName, n.name, namedSig, parseResult))]; + [(className ++ ".java", + generateFunctionClassString(top.env, top.flowEnv, top.grammarName, n.name, namedSig, parseResult))]; local parseResult :: String = s"""return common.Util.callCopperParser(new ${packageName}.${parserName}(), c_stringToParse, c_filenameToReport);"""; diff --git a/grammars/silver/compiler/modification/copper/Prefix.sv b/grammars/silver/compiler/modification/copper/Prefix.sv index 23e757a0d..46e11c98c 100644 --- a/grammars/silver/compiler/modification/copper/Prefix.sv +++ b/grammars/silver/compiler/modification/copper/Prefix.sv @@ -10,19 +10,19 @@ concrete production prefixParserComponentModifier top::ParserComponentModifier ::= 'prefix' ts::TerminalPrefixItems 'with' s::TerminalPrefix { top.unparse = "prefix " ++ ts.unparse ++ " with " ++ s.unparse; - top.terminalPrefixes <- map(pair(_, s.terminalPrefix), ts.prefixItemNames); + top.terminalPrefixes <- map(pair(fst=_, snd=s.terminalPrefix), ts.prefixItemNames); top.grammarTerminalPrefixes <- - if ts.isAllMarking then [pair(top.componentGrammarName, s.terminalPrefix)] else []; + if ts.isAllMarking then [(top.componentGrammarName, s.terminalPrefix)] else []; s.prefixedTerminals = ts.prefixItemNames; s.prefixedGrammars = if ts.isAllMarking then [top.componentGrammarName] else []; } -autocopy attribute prefixedTerminals::[String]; -autocopy attribute prefixedGrammars::[String]; +inherited attribute prefixedTerminals::[String]; +inherited attribute prefixedGrammars::[String]; synthesized attribute terminalPrefix::String; nonterminal TerminalPrefix with config, env, flowEnv, grammarName, componentGrammarName, compiledGrammars, prefixedTerminals, prefixedGrammars, location, unparse, errors, syntaxAst, genFiles, terminalPrefix; -propagate errors, syntaxAst, genFiles on TerminalPrefix; +propagate config, env, flowEnv, grammarName, componentGrammarName, compiledGrammars, errors, syntaxAst, genFiles on TerminalPrefix; concrete production nameTerminalPrefix top::TerminalPrefix ::= s::QName @@ -92,8 +92,7 @@ top::TerminalModifier ::= terms::[String] grams::[String] synthesized attribute prefixItemNames::[String]; synthesized attribute isAllMarking::Boolean; nonterminal TerminalPrefixItems with config, env, grammarName, componentGrammarName, compiledGrammars, grammarDependencies, location, unparse, errors, prefixItemNames, isAllMarking; - -propagate errors on TerminalPrefixItems; +propagate config, env, grammarName, componentGrammarName, compiledGrammars, errors on TerminalPrefixItems; concrete production consTerminalPrefixItem top::TerminalPrefixItems ::= t::TerminalPrefixItem ',' ts::TerminalPrefixItems @@ -129,6 +128,7 @@ top::TerminalPrefixItems ::= } nonterminal TerminalPrefixItem with config, env, grammarName, componentGrammarName, compiledGrammars, location, unparse, errors, prefixItemNames; +propagate config, env, grammarName, componentGrammarName, compiledGrammars on TerminalPrefixItem; concrete production qNameTerminalPrefixItem top::TerminalPrefixItem ::= t::QName @@ -143,6 +143,7 @@ top::TerminalPrefixItem ::= t::QName concrete production easyTerminalRefTerminalPrefixItem top::TerminalPrefixItem ::= t::EasyTerminalRef { + propagate env; forwards to qNameTerminalPrefixItem( qName(top.location, head(t.dcls).fullName), @@ -172,7 +173,7 @@ top::ParserComponent ::= 'prefer' t::QName 'over' ts::TermList ';' pluckTAction.originRules = []; local tName::String = t.lookupType.dcl.fullName; - top.syntaxAst <- + top.syntaxAst <- if !t.lookupType.found then [] else -- Generate a disambiguation function for every combination of ts. -- TODO: we can't use Copper's subset disambiguation functions here unfourtunately, -- since we currently require those to be disjoint. diff --git a/grammars/silver/compiler/modification/copper/ProductionStmt.sv b/grammars/silver/compiler/modification/copper/ProductionStmt.sv index 746a53c75..da80493cd 100644 --- a/grammars/silver/compiler/modification/copper/ProductionStmt.sv +++ b/grammars/silver/compiler/modification/copper/ProductionStmt.sv @@ -23,13 +23,13 @@ concrete production pluckDef top::ProductionStmt ::= 'pluck' e::Expr ';' { top.unparse = "pluck " ++ e.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, env, frame, errors, finalSubst; -- Cast to integer is required, because that's secretly the real type of the -- result, but our type system only calls it an Object at the moment. -- Perhaps this problem can be resolved by using a proper type in this situation. top.translation = "return (Integer)(" ++ e.translation ++ ");\n"; - propagate errors; top.errors <- if !top.frame.permitPluck then [err(top.location, "'pluck' allowed only in disambiguation-group parser actions.")] @@ -57,10 +57,10 @@ concrete production printStmt top::ProductionStmt ::= 'print' e::Expr ';' { top.unparse = "print " ++ e.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, env, frame, errors, finalSubst; top.translation = "System.err.println(" ++ e.translation ++ ");\n"; - propagate errors; top.errors <- if !top.frame.permitActions then [err(top.location, "'print' statement allowed only in parser action blocks. You may be looking for print(String,IO) :: IO.")] @@ -87,11 +87,12 @@ top::ProductionStmt ::= 'local' 'attribute' a::Name '::' te::TypeExpr ';' } abstract production parserAttributeValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { + undecorates to valueEq(val, '=', e, ';', location=top.location); top.unparse = "\t" ++ val.unparse ++ " = " ++ e.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, env, frame, errors, finalSubst; - propagate errors; top.errors <- if !top.frame.permitActions then [err(top.location, "Assignment to parser attributes only permitted in parser action blocks")] @@ -117,8 +118,8 @@ concrete production pushTokenStmt top::ProductionStmt ::= 'pushToken' '(' val::QName ',' lexeme::Expr ')' ';' { top.unparse = "\t" ++ "pushToken(" ++ val.unparse ++ ", " ++ lexeme.unparse ++ ");"; + propagate config, grammarName, compiledGrammars, env, frame, errors, finalSubst; - propagate errors; top.errors <- if !top.frame.permitActions then [err(top.location, "Tokens may only be pushed in action blocks")] @@ -144,8 +145,8 @@ concrete production insertSemanticTokenStmt top::ProductionStmt ::= 'insert' 'semantic' 'token' n::QNameType 'at' loc::Expr ';' { top.unparse = "\t" ++ "insert semantic token " ++ n.unparse ++ " at " ++ loc.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, env, frame, errors, finalSubst; - propagate errors; top.errors <- if !top.frame.permitActions then [err(top.location, "Semantic tokens may only be inserted in action blocks")] @@ -160,7 +161,7 @@ top::ProductionStmt ::= 'insert' 'semantic' 'token' n::QNameType 'at' loc::Expr thread downSubst, upSubst on top, loc, errCheck1, top; - errCheck1 = check(loc.typerep, nonterminalType("silver:core:Location", [], false)); + errCheck1 = check(loc.typerep, nonterminalType("silver:core:Location", [], true, false)); top.errors <- if errCheck1.typeerror then [err(loc.location, s"Semantic token position expected a ${errCheck1.rightpp}, but got ${errCheck1.leftpp}")] @@ -173,8 +174,8 @@ concrete production blockStmt top::ProductionStmt ::= '{' stmts::ProductionStmts '}' { top.unparse = "\t{\n" ++ stmts.unparse ++ "\n\t}"; + propagate config, grammarName, compiledGrammars, env, frame, errors, finalSubst; - propagate errors; top.errors <- if !top.frame.permitActions then [err(top.location, "Block statement is only permitted in action blocks")] @@ -183,6 +184,7 @@ top::ProductionStmt ::= '{' stmts::ProductionStmts '}' top.translation = stmts.translation; stmts.downSubst = top.downSubst; + stmts.originRules = []; top.upSubst = error("Shouldn't ever be needed anywhere. (Should only ever be fed back here as top.finalSubst)"); -- Of course, this means do not use top.finalSubst here! } @@ -191,8 +193,8 @@ concrete production ifElseStmt top::ProductionStmt ::= 'if' '(' condition::Expr ')' th::ProductionStmt 'else' el::ProductionStmt { top.unparse = "\t" ++ "if (" ++ condition.unparse ++ ") " ++ th.unparse ++ "\nelse " ++ el.unparse; + propagate config, grammarName, compiledGrammars, env, frame, errors; - propagate errors; top.errors <- if !top.frame.permitActions then [err(top.location, "If statement is only permitted in action blocks")] @@ -202,10 +204,14 @@ top::ProductionStmt ::= 'if' '(' condition::Expr ')' th::ProductionStmt 'else' e condition.originRules = []; condition.isRoot = false; + th.originRules = []; + el.originRules = []; local attribute errCheck1 :: TypeCheck; errCheck1.finalSubst = top.finalSubst; thread downSubst, upSubst on top, condition, errCheck1, top; + + condition.finalSubst = condition.upSubst; th.downSubst = top.downSubst; th.finalSubst = th.upSubst; @@ -229,8 +235,9 @@ top::ProductionStmt ::= 'if' '(' condition::Expr ')' th::ProductionStmt abstract production parserAttributeDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName { + undecorates to concreteDefLHS(q, location=top.location); top.name = q.name; top.unparse = q.unparse; top.found = false; @@ -248,13 +255,14 @@ top::DefLHS ::= q::PartiallyDecorated QName } abstract production termAttrValueValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { + undecorates to valueEq(val, '=', e, ';', location=top.location); top.unparse = "\t" ++ val.unparse ++ " = " ++ e.unparse ++ ";"; + propagate config, grammarName, compiledGrammars, env, frame, errors, finalSubst; -- these values should only ever be in scope when it's valid to use them - propagate errors; - + top.errors <- if val.name != "lexeme" then [] else [err(val.location, "lexeme is not reassignable.")]; diff --git a/grammars/silver/compiler/modification/copper/Project.sv b/grammars/silver/compiler/modification/copper/Project.sv index 2683ba890..ea53ab545 100644 --- a/grammars/silver/compiler/modification/copper/Project.sv +++ b/grammars/silver/compiler/modification/copper/Project.sv @@ -8,10 +8,12 @@ imports silver:compiler:definition:concrete_syntax; imports silver:compiler:definition:concrete_syntax:ast; imports silver:compiler:definition:type; imports silver:compiler:definition:type:syntax; +imports silver:compiler:definition:flow:env; imports silver:compiler:modification:list; ---imports silver:compiler:analysis:typechecking:core; +imports silver:compiler:analysis:typechecking:core; +imports silver:compiler:analysis:uniqueness; imports silver:compiler:translation:java:core; imports silver:compiler:translation:java:type; diff --git a/grammars/silver/compiler/modification/copper/TermList.sv b/grammars/silver/compiler/modification/copper/TermList.sv index 35b10cfcf..8220adcfa 100644 --- a/grammars/silver/compiler/modification/copper/TermList.sv +++ b/grammars/silver/compiler/modification/copper/TermList.sv @@ -9,7 +9,7 @@ nonterminal TermList with config, grammarName, unparse, location, termList, defs monoid attribute termList :: [String]; -propagate errors, termList on TermList; +propagate config, grammarName, env, errors, termList on TermList; concrete production termListOne terms::TermList ::= t::QName @@ -38,7 +38,7 @@ top::TermList ::= h::QName t::TermList production fName::String = h.lookupType.dcl.fullName; - top.termList <- [fName]; + top.termList <- if h.lookupType.found then [fName] else []; -- Itd be nice if we didnt need this guard top.defs := if null(h.lookupType.dcls) then t.defs diff --git a/grammars/silver/compiler/modification/copper/TerminalDcl.sv b/grammars/silver/compiler/modification/copper/TerminalDcl.sv index d2232aaa8..13c2e8fd7 100644 --- a/grammars/silver/compiler/modification/copper/TerminalDcl.sv +++ b/grammars/silver/compiler/modification/copper/TerminalDcl.sv @@ -12,33 +12,34 @@ concrete production terminalModifierDominates top::TerminalModifier ::= 'dominates' terms::TermPrecs { top.unparse = "dominates { " ++ terms.unparse ++ " } "; + propagate env, errors; top.terminalModifiers := [termDominates(terms.precTermList)]; - propagate errors; } concrete production terminalModifierSubmitsTo top::TerminalModifier ::= 'submits' 'to' terms::TermPrecs { top.unparse = "submits to { " ++ terms.unparse ++ " } " ; + propagate env, errors; top.terminalModifiers := [termSubmits(terms.precTermList)]; - propagate errors; } concrete production terminalModifierClassSpec top::TerminalModifier ::= 'lexer' 'classes' cl::LexerClasses { top.unparse = "lexer classes { " ++ cl.unparse ++ " } " ; + propagate env, errors; top.terminalModifiers := [termClasses(cl.lexerClasses)]; - propagate errors; } concrete production terminalModifierActionCode top::TerminalModifier ::= 'action' acode::ActionCode_c { top.unparse = "action " ++ acode.unparse; + propagate config, grammarName, compiledGrammars, flowEnv, errors; top.terminalModifiers := [termAction(acode.actionCode)]; @@ -51,14 +52,12 @@ top::TerminalModifier ::= 'action' acode::ActionCode_c acode.frame = actionContext(myFlowGraph, sourceGrammar=top.grammarName); acode.env = newScopeEnv(terminalActionVars ++ acode.defs, top.env); - - propagate errors; } monoid attribute precTermList :: [String]; nonterminal TermPrecs with config, grammarName, unparse, location, precTermList, errors, env; -propagate errors, precTermList on TermPrecs; +propagate config, grammarName, env, errors, precTermList on TermPrecs; concrete production termPrecsOne top::TermPrecs ::= t::QName @@ -81,7 +80,7 @@ top::TermPrecs ::= terms::TermPrecList } nonterminal TermPrecList with config, grammarName, unparse, location, precTermList, errors, env; -propagate errors, precTermList on TermPrecList; +propagate config, grammarName, env, errors, precTermList on TermPrecList; abstract production termPrecList top::TermPrecList ::= h::QName t::TermPrecList @@ -92,7 +91,7 @@ top::TermPrecList ::= h::QName t::TermPrecList production fName::String = if null(h.lookupType.dcls) then h.lookupLexerClass.dcl.fullName else h.lookupType.dcl.fullName; - top.precTermList <- [fName]; + top.precTermList <- if h.lookupType.found || h.lookupLexerClass.found then [fName] else []; -- Since we're looking it up in two ways, do the errors ourselves top.errors <- if null(h.lookupType.dcls) && null(h.lookupLexerClass.dcls) @@ -126,7 +125,7 @@ top::TermPrecList ::= t::QName ',' terms_tail::TermPrecList } nonterminal LexerClasses with location, config, unparse, lexerClasses, errors, env; -propagate errors, lexerClasses on LexerClasses; +propagate config, env, errors, lexerClasses on LexerClasses; concrete production lexerClassesOne top::LexerClasses ::= n::QName @@ -149,7 +148,7 @@ top::LexerClasses ::= cls::LexerClassList } nonterminal LexerClassList with location, config, unparse, lexerClasses, errors, env; -propagate errors, lexerClasses on LexerClassList; +propagate config, env, errors, lexerClasses on LexerClassList; concrete production lexerClassListOne top::LexerClassList ::= n::QName @@ -177,7 +176,7 @@ top::LexerClassList ::= n::QName t::LexerClassList top.errors <- n.lookupLexerClass.errors; - top.lexerClasses <- [n.lookupLexerClass.dcl.fullName]; + top.lexerClasses <- if n.lookupLexerClass.found then [n.lookupLexerClass.dcl.fullName] else []; } abstract production lexerClassListNull diff --git a/grammars/silver/compiler/modification/copper_mda/Analysis.sv b/grammars/silver/compiler/modification/copper_mda/Analysis.sv index d65601b57..1269e1a06 100644 --- a/grammars/silver/compiler/modification/copper_mda/Analysis.sv +++ b/grammars/silver/compiler/modification/copper_mda/Analysis.sv @@ -4,6 +4,7 @@ imports silver:compiler:definition:core; imports silver:compiler:definition:env; imports silver:compiler:definition:concrete_syntax; imports silver:compiler:definition:concrete_syntax:ast; +imports silver:compiler:definition:flow:env; imports silver:compiler:modification:copper; import silver:compiler:driver:util only computeDependencies, RootSpec; @@ -16,7 +17,7 @@ top::AGDcl ::= 'copper_mda' testname::Name '(' orig::QName ')' '{' m::ParserComp { top.unparse = ""; - propagate errors, moduleNames; + propagate config, grammarName, compiledGrammars, grammarDependencies, env, flowEnv, errors, moduleNames; top.errors <- orig.lookupValue.errors; diff --git a/grammars/silver/compiler/modification/copper_mda/BuildProcess.sv b/grammars/silver/compiler/modification/copper_mda/BuildProcess.sv index 8d2d961c2..30e975742 100644 --- a/grammars/silver/compiler/modification/copper_mda/BuildProcess.sv +++ b/grammars/silver/compiler/modification/copper_mda/BuildProcess.sv @@ -32,11 +32,12 @@ top::DriverAction ::= spec::MdaSpec compiledGrammars::EnvTree error("BUG: specCstAst was not serializable; hopefully this was caused by the most recent change to the copper_mda modification: " ++ e) - | right(dump) -> writeBinaryFile(dumpFile, dump) - end; + makeName(spec.sourceGrammar), parserName, true, "", false, parserName ++ ".html", false); + when_(ret == 0, + case nativeSerialize(new(specCstAst)) of + | left(e) -> error("BUG: specCstAst was not serializable; hopefully this was caused by the most recent change to the copper_mda modification: " ++ e) + | right(dump) -> writeBinaryFile(dumpFile, dump) + end); return ret; } else do { -- Should this be stderr? diff --git a/grammars/silver/compiler/modification/copper_mda/SyntaxMdaRoot.sv b/grammars/silver/compiler/modification/copper_mda/SyntaxMdaRoot.sv index 252cf3b58..fda4ec33b 100644 --- a/grammars/silver/compiler/modification/copper_mda/SyntaxMdaRoot.sv +++ b/grammars/silver/compiler/modification/copper_mda/SyntaxMdaRoot.sv @@ -30,7 +30,7 @@ top::SyntaxRoot ::= parsername::String startnt::String host::Syntax ext::Synt g:transitiveClosure( g:add( map( - \ p::Pair -> pair(p.snd, p.fst), + \ p::Pair -> (p.snd, p.fst), host.superClassContribs ++ ext.superClassContribs), g:empty())))); host.parserAttributeAspects = diff --git a/grammars/silver/compiler/modification/defaultattr/DefaultAttr.sv b/grammars/silver/compiler/modification/defaultattr/DefaultAttr.sv index da2fe8f62..781534923 100644 --- a/grammars/silver/compiler/modification/defaultattr/DefaultAttr.sv +++ b/grammars/silver/compiler/modification/defaultattr/DefaultAttr.sv @@ -5,9 +5,11 @@ import silver:compiler:definition:origins; import silver:compiler:definition:env; import silver:compiler:definition:type; import silver:compiler:definition:type:syntax; ---import silver:compiler:analysis:typechecking:core; +import silver:compiler:analysis:typechecking:core; import silver:compiler:translation:java; +import silver:compiler:definition:flow:env; +import silver:compiler:definition:flow:ast only lhsVertexType; import silver:compiler:definition:flow:driver only ProductionGraph, FlowType, constructDefaultProductionGraph; -- for the "oh no again!" hack below import silver:compiler:driver:util only RootSpec; -- ditto @@ -20,7 +22,7 @@ top::AGDcl ::= 'aspect' 'default' 'production' ns::AspectDefaultProductionSignat top.defs := []; - propagate errors, flowDefs; + propagate config, grammarName, compiledGrammars, errors; local sigDefs :: [Def] = addNewLexicalTyVars(top.grammarName, top.location, ns.lexicalTyVarKinds, ns.lexicalTypeVariables); @@ -58,7 +60,7 @@ top::AspectDefaultProductionSignature ::= lhs::Name '::' te::TypeExpr '::=' namedSignatureElement(lhs.name, te.typerep), foldNamedSignatureElements(annotationsForNonterminal(te.typerep, top.env))); - propagate errors, lexicalTypeVariables, lexicalTyVarKinds; + propagate config, grammarName, env, compiledGrammars, errors, lexicalTypeVariables, lexicalTyVarKinds, flowEnv; local checkNT::TypeCheck = checkNonterminal(top.env, false, te.typerep); checkNT.downSubst = emptySubst(); @@ -97,11 +99,13 @@ top::ValueDclInfo ::= fn::String ty::Type top.refDispatcher = lhsReference(_, location=_); top.defDispatcher = errorValueDef(_, _, location=_); -- TODO: be smarter about the error message top.defLHSDispatcher = defaultLhsDefLHS(_, location=_); + top.transDefLHSDispatcher = errorTransAttrDefLHS(_, _, location=_); } abstract production defaultLhsDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName { + undecorates to concreteDefLHS(q, location=top.location); top.name = q.name; top.unparse = q.unparse; top.found = !existingProblems && top.defLHSattr.attrDcl.isSynthesized; @@ -114,6 +118,10 @@ top::DefLHS ::= q::PartiallyDecorated QName top.typerep = q.lookupValue.typeScheme.monoType; + top.defLHSVertex = lhsVertexType; + top.defLHSInhEq = []; + top.inhAttrName = ""; + top.translation = makeNTName(top.frame.lhsNtName) ++ ".defaultSynthesizedAttributes"; } diff --git a/grammars/silver/compiler/modification/ffi/FunctionDcl.sv b/grammars/silver/compiler/modification/ffi/FunctionDcl.sv index 631c42b11..903459ae2 100644 --- a/grammars/silver/compiler/modification/ffi/FunctionDcl.sv +++ b/grammars/silver/compiler/modification/ffi/FunctionDcl.sv @@ -8,26 +8,17 @@ nonterminal FFIDef with config, location, grammarName, errors, env, unparse; concrete production functionDclFFI top::AGDcl ::= 'function' id::Name ns::FunctionSignature body::ProductionBody 'foreign' '{' ffidefs::FFIDefs '}' { - top.unparse = "function " ++ id.unparse ++ "\n" ++ ns.unparse ++ "\n" ++ body.unparse ++ " foreign {\n" ++ ffidefs.unparse ++ "}"; + top.unparse = "function " ++ id.unparse ++ "\n" ++ ns.unparse ++ "\n" ++ body.unparse ++ " foreign {\n" ++ ffidefs.unparse ++ "}"; + propagate grammarName; production fName :: String = top.grammarName ++ ":" ++ id.name; production namedSig :: NamedSignature = ns.namedSignature; top.errors <- ffidefs.errors; - -- Quick copy & paste to make signatures look right. Otherwise they contain errorTypes for - -- type parameters - production attribute sigDefs :: [Def] with ++; - sigDefs := ns.defs; - ns.signatureName = fName; - ns.env = newScopeEnv(sigDefs, top.env); - production attribute allLexicalTyVars :: [String]; - allLexicalTyVars = nub(ns.lexicalTypeVariables); - sigDefs <- addNewLexicalTyVars(top.grammarName, top.location, ns.lexicalTyVarKinds, allLexicalTyVars); - - -- TODO this is a BS use of forwarding and should be eliminated. body.env and .frame are all wrong locally... + -- TODO this is a BS use of forwarding and should be eliminated. - forwards to functionDcl($1, id, ns, body, location=top.location); + forwards to functionDcl($1, @id, @ns, @body, location=top.location); } action { insert semantic token IdFnProdDcl_t at id.location; sigNames = []; diff --git a/grammars/silver/compiler/modification/ffi/TypeDcl.sv b/grammars/silver/compiler/modification/ffi/TypeDcl.sv index 909c0f080..808a80325 100644 --- a/grammars/silver/compiler/modification/ffi/TypeDcl.sv +++ b/grammars/silver/compiler/modification/ffi/TypeDcl.sv @@ -4,6 +4,7 @@ imports silver:compiler:definition:core; imports silver:compiler:definition:env; imports silver:compiler:definition:type; imports silver:compiler:definition:type:syntax; +imports silver:compiler:definition:flow:env; -- Yikes, this was a weird choice of syntax. concrete production ffiTypeDclLegacy @@ -42,7 +43,7 @@ top::AGDcl ::= 'type' id::Name tl::BracketedOptTypeExprs 'foreign' '=' trans::St top.defs := [typeAliasDef(top.grammarName, id.location, fName, [], tl.freeVariables, foreignType(fName, transType, tl.types))]; - propagate errors, flowDefs; + propagate grammarName, errors, flowDefs, flowEnv; top.errors <- tl.errorsTyVars; -- Put the variables listed on the rhs in the environment FOR TL ONLY, so they're all "declared" diff --git a/grammars/silver/compiler/modification/ffi/java/FunctionDcl.sv b/grammars/silver/compiler/modification/ffi/java/FunctionDcl.sv index bda7381c7..4cced97f3 100644 --- a/grammars/silver/compiler/modification/ffi/java/FunctionDcl.sv +++ b/grammars/silver/compiler/modification/ffi/java/FunctionDcl.sv @@ -7,6 +7,7 @@ import silver:compiler:translation:java:type; import silver:compiler:definition:core; import silver:compiler:definition:env; import silver:compiler:definition:type; +import silver:compiler:definition:flow:env; synthesized attribute ffiTranslationString :: [String] occurs on FFIDef, FFIDefs; @@ -63,8 +64,8 @@ top::AGDcl ::= 'function' id::Name ns::FunctionSignature body::ProductionBody 'f top.genFiles := if null(ffidefs.ffiTranslationString) then forward.genFiles else - [pair("P" ++ id.name ++ ".java", - generateFunctionClassString(top.grammarName, id.name, namedSig, "return (" ++ namedSig.outputElement.typerep.transClassType ++ ")" ++ computeSigTranslation(head(ffidefs.ffiTranslationString), namedSig) ++ ";\n") + [("P" ++ id.name ++ ".java", + generateFunctionClassString(body.env, top.flowEnv, top.grammarName, id.name, namedSig, "return (" ++ namedSig.outputElement.typerep.transClassType ++ ")" ++ computeSigTranslation(head(ffidefs.ffiTranslationString), namedSig) ++ ";\n") )]; top.errors <- if length(ffidefs.ffiTranslationString) > 1 diff --git a/grammars/silver/compiler/modification/lambda_fn/DclInfo.sv b/grammars/silver/compiler/modification/lambda_fn/DclInfo.sv index 96b2c1fdb..5539fa6d1 100644 --- a/grammars/silver/compiler/modification/lambda_fn/DclInfo.sv +++ b/grammars/silver/compiler/modification/lambda_fn/DclInfo.sv @@ -1,5 +1,3 @@ -import silver:compiler:definition:flow:ast only ExprVertexInfo, FlowVertex; - synthesized attribute lambdaId::Integer occurs on ValueDclInfo; synthesized attribute lambdaParamIndex::Integer occurs on ValueDclInfo; @@ -25,6 +23,7 @@ top::ValueDclInfo ::= fn::String ty::Type id::Integer paramIndex::Integer top.refDispatcher = lambdaParamReference(_, location=_); top.defDispatcher = errorValueDef(_, _, location=_); -- should be impossible (never in scope at production level?) top.defLHSDispatcher = errorDefLHS(_, location=_); -- ditto + top.transDefLHSDispatcher = errorTransAttrDefLHS(_, _, location=_); } function lambdaParamDef diff --git a/grammars/silver/compiler/modification/lambda_fn/Lambda.sv b/grammars/silver/compiler/modification/lambda_fn/Lambda.sv index 4105e4f6d..afb9bfdf6 100644 --- a/grammars/silver/compiler/modification/lambda_fn/Lambda.sv +++ b/grammars/silver/compiler/modification/lambda_fn/Lambda.sv @@ -1,4 +1,3 @@ -import silver:compiler:definition:flow:ast only ExprVertexInfo, FlowVertex; import silver:compiler:definition:env; import silver:util:treeset as ts; @@ -24,7 +23,7 @@ top::Expr ::= params::ProductionRHS e::Expr top.unparse = "\\ " ++ params.unparse ++ " -> " ++ e.unparse; top.freeVars := ts:removeAll(params.lambdaBoundVars, e.freeVars); - propagate errors; + propagate config, grammarName, compiledGrammars, errors, originRules; top.typerep = appTypes(functionType(length(params.inputElements), []), map((.typerep), params.inputElements) ++ [e.typerep]); @@ -35,14 +34,14 @@ top::Expr ::= params::ProductionRHS e::Expr top.grammarName, top.location, params.lexicalTyVarKinds, filter(\ tv::String -> null(getTypeDcl(tv, top.env)), nub(params.lexicalTypeVariables))); - propagate downSubst, upSubst; - propagate flowDeps, flowDefs; + propagate downSubst, upSubst, finalSubst; params.env = newScopeEnv(sigDefs, top.env); params.givenLambdaParamIndex = 0; params.givenLambdaId = genInt(); e.env = params.env; e.frame = inLambdaContext(top.frame, sourceGrammar=top.frame.sourceGrammar); --TODO: Is this sourceGrammar correct? + e.isRoot = false; } monoid attribute lambdaDefs::[Def]; @@ -76,8 +75,9 @@ top::ProductionRHSElem ::= id::Name '::' t::TypeExpr } abstract production lambdaParamReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; propagate errors; top.freeVars := ts:fromList([q.name]); @@ -85,7 +85,4 @@ top::Expr ::= q::PartiallyDecorated QName top.typerep = q.lookupValue.typeScheme.monoType; propagate downSubst, upSubst; - - -- TODO? - propagate flowDeps, flowDefs; } diff --git a/grammars/silver/compiler/modification/lambda_fn/Project.sv b/grammars/silver/compiler/modification/lambda_fn/Project.sv index 480e0b36c..081dffb75 100644 --- a/grammars/silver/compiler/modification/lambda_fn/Project.sv +++ b/grammars/silver/compiler/modification/lambda_fn/Project.sv @@ -4,7 +4,8 @@ imports silver:compiler:definition:core; imports silver:compiler:definition:env; imports silver:compiler:definition:type; imports silver:compiler:definition:type:syntax; ---imports silver:compiler:analysis:typechecking:core; +imports silver:compiler:analysis:typechecking:core; +imports silver:compiler:analysis:uniqueness; exports silver:compiler:modification:lambda_fn:java with silver:compiler:translation:java:core; exports silver:compiler:modification:lambda_fn:java with silver:compiler:translation:java:type; diff --git a/grammars/silver/compiler/modification/lambda_fn/java/Lambda.sv b/grammars/silver/compiler/modification/lambda_fn/java/Lambda.sv index 3469f492a..c2c16c8ab 100644 --- a/grammars/silver/compiler/modification/lambda_fn/java/Lambda.sv +++ b/grammars/silver/compiler/modification/lambda_fn/java/Lambda.sv @@ -6,34 +6,31 @@ import silver:compiler:definition:core; import silver:compiler:definition:env; import silver:compiler:definition:type; import silver:compiler:definition:type:syntax; +import silver:compiler:analysis:typechecking:core only finalType; import silver:compiler:translation:java:core; import silver:compiler:translation:java:type; -import silver:compiler:definition:flow:ast only ExprVertexInfo, FlowVertex; - aspect production lambdap top::Expr ::= params::ProductionRHS e::Expr { - local finTy :: Type = finalType(top); - - -- Attempt to solve a context `runtimeTypeable ${finType}`, from which the runtime TypeRep translation is computed. + -- Attempt to solve a context `runtimeTypeable ${top.finalType)}`, from which the runtime TypeRep translation is computed. -- If the type somehow contains a skolem (e.g. through scoped type variables), -- then we will attempt to use the more specific runtime TypeRep from the context, -- but will otherwise fall back to rigid skolem constant TypeReps. - local context :: Context = typeableContext(finTy); + local context :: Context = typeableContext(top.finalType); context.env = top.env; local lambdaTrans :: (String ::= String) = \ runtimeTypeTrans::String -> -s"""(new common.NodeFactory<${finTy.outputType.transType}>() { +s"""(new common.NodeFactory<${top.finalType.outputType.transType}>() { @Override - public final ${finTy.outputType.transType} invoke(final common.OriginContext originCtx, final Object[] lambda_${toString(params.givenLambdaId)}_args, final Object[] namedArgs) { + public final ${top.finalType.outputType.transType} invoke(final common.OriginContext originCtx, final Object[] lambda_${toString(params.givenLambdaId)}_args, final Object[] namedArgs) { return ${e.translation}; } @Override public final common.TypeRep getType() { -${makeTyVarDecls(5, finTy.freeVariables)} +${makeTyVarDecls(5, top.finalType.freeVariables)} return ${runtimeTypeTrans}; } @@ -49,13 +46,15 @@ ${makeTyVarDecls(5, finTy.freeVariables)} -- Same as above, except that we know that this is a top-level generalized binding -- (e.g. global id :: (a ::= a) = \ x::a -> x;) -- so freshen all skolem type vars in the run-time type representation. - top.generalizedTranslation = lambdaTrans(transFreshTypeRep(finTy)); + top.generalizedTranslation = lambdaTrans(transFreshTypeRep(top.finalType)); + + propagate initTransDecSites; } aspect production lambdaParamReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { - top.translation = s"common.Util.<${finalType(top).transType}>demandIndex(lambda_${toString(q.lookupValue.dcl.lambdaId)}_args, ${toString(q.lookupValue.dcl.lambdaParamIndex)})"; + top.translation = s"common.Util.<${top.finalType.transType}>demandIndex(lambda_${toString(q.lookupValue.dcl.lambdaId)}_args, ${toString(q.lookupValue.dcl.lambdaParamIndex)})"; top.lazyTranslation = wrapThunk(top.translation, top.frame.lazyApplication); + top.initTransDecSites := ""; } - diff --git a/grammars/silver/compiler/modification/let_fix/DclInfo.sv b/grammars/silver/compiler/modification/let_fix/DclInfo.sv index 2330afffd..194ec8b10 100644 --- a/grammars/silver/compiler/modification/let_fix/DclInfo.sv +++ b/grammars/silver/compiler/modification/let_fix/DclInfo.sv @@ -1,28 +1,29 @@ grammar silver:compiler:modification:let_fix; -import silver:compiler:definition:flow:ast only ExprVertexInfo, FlowVertex; +import silver:compiler:definition:flow:ast only VertexType, FlowVertex; abstract production lexicalLocalDcl -top::ValueDclInfo ::= fn::String ty::Type fi::ExprVertexInfo fd::[FlowVertex] +top::ValueDclInfo ::= fn::String ty::Type fi::Maybe fd::[FlowVertex] rs::[(String, UniqueRefSite)] { top.fullName = fn; top.isEqual = -- Should never show up in an interface file anyway... case top.compareTo of - | lexicalLocalDcl(fn2, ty2, _, _) -> fn == fn2 && ty == ty2 + | lexicalLocalDcl(fn2, ty2, _, _, _) -> fn == fn2 && ty == ty2 | _ -> false end; top.typeScheme = monoType(ty); - top.refDispatcher = lexicalLocalReference(_, fi, fd, location=_); + top.refDispatcher = lexicalLocalReference(_, fi, fd, rs, location=_); top.defDispatcher = errorValueDef(_, _, location=_); -- should be impossible (never in scope at production level?) top.defLHSDispatcher = errorDefLHS(_, location=_); -- ditto + top.transDefLHSDispatcher = errorTransAttrDefLHS(_, _, location=_); } function lexicalLocalDef -Def ::= sg::String sl::Location fn::String ty::Type fi::ExprVertexInfo fd::[FlowVertex] +Def ::= sg::String sl::Location fn::String ty::Type fi::Maybe fd::[FlowVertex] rs::[(String, UniqueRefSite)] { - return valueDef(defaultEnvItem(lexicalLocalDcl(fn,ty,fi,fd,sourceGrammar=sg,sourceLocation=sl))); + return valueDef(defaultEnvItem(lexicalLocalDcl(fn,ty,fi,fd,rs,sourceGrammar=sg,sourceLocation=sl))); } diff --git a/grammars/silver/compiler/modification/let_fix/Let.sv b/grammars/silver/compiler/modification/let_fix/Let.sv index 725bfdf49..ece715488 100644 --- a/grammars/silver/compiler/modification/let_fix/Let.sv +++ b/grammars/silver/compiler/modification/let_fix/Let.sv @@ -1,6 +1,6 @@ grammar silver:compiler:modification:let_fix; -import silver:compiler:definition:flow:ast only ExprVertexInfo, FlowVertex; +import silver:compiler:definition:flow:ast only VertexType, FlowVertex; import silver:util:treeset as ts; --- Concrete Syntax for lets @@ -44,14 +44,16 @@ top::Expr ::= la::AssignExpr e::Expr top.unparse = "let " ++ la.unparse ++ " in " ++ e.unparse ++ " end"; top.freeVars := ts:removeAll(la.boundNames, e.freeVars); - propagate errors; + propagate config, grammarName, compiledGrammars, frame, errors, originRules; + e.isRoot = false; top.typerep = e.typerep; - propagate downSubst, upSubst; + propagate downSubst, upSubst, finalSubst; -- Semantics for the moment is these are not mutually recursive, -- so la does NOT get new environment, only e. Thus, la.defs can depend on downSubst... + la.env = top.env; e.env = newScopeEnv(la.defs, top.env); } @@ -59,9 +61,9 @@ monoid attribute boundNames::[String]; nonterminal AssignExpr with location, config, grammarName, env, compiledGrammars, unparse, defs, errors, boundNames, freeVars, upSubst, - downSubst, finalSubst, frame, isRoot, originRules; + downSubst, finalSubst, frame, originRules; -propagate errors, defs on AssignExpr; +propagate config, grammarName, compiledGrammars, frame, env, errors, defs, finalSubst, originRules on AssignExpr; abstract production appendAssignExpr top::AssignExpr ::= a1::AssignExpr a2::AssignExpr @@ -93,7 +95,7 @@ top::AssignExpr ::= id::Name '::' t::TypeExpr '=' e::Expr -- auto-undecorate feature, so that's why we bother substituting. -- (er, except that we're starting with t, which is a Type... must be because we fake these -- in e.g. the pattern matching code, so type variables might appear there?) - top.defs <- [lexicalLocalDef(top.grammarName, id.location, fName, semiTy, e.flowVertexInfo, e.flowDeps)]; + top.defs <- [lexicalLocalDef(top.grammarName, id.location, fName, semiTy, e.flowVertexInfo, e.flowDeps, e.uniqueRefs)]; -- TODO: At present, this isn't working properly, because the local scope is -- whatever scope encloses the real local scope... hrmm! @@ -113,11 +115,14 @@ top::AssignExpr ::= id::Name '::' t::TypeExpr '=' e::Expr if errCheck1.typeerror then [err(id.location, "Value " ++ id.name ++ " declared with type " ++ errCheck1.rightpp ++ " but the expression being assigned to it has type " ++ errCheck1.leftpp)] else []; + + e.isRoot = false; } abstract production lexicalLocalReference -top::Expr ::= q::PartiallyDecorated QName fi::ExprVertexInfo fd::[FlowVertex] +top::Expr ::= q::Decorated! QName fi::Maybe fd::[FlowVertex] rs::[(String, UniqueRefSite)] { + undecorates to baseExpr(q, location=top.location); top.unparse = q.unparse; top.errors := []; top.freeVars := ts:fromList([q.name]); @@ -141,7 +146,7 @@ top::Expr ::= q::PartiallyDecorated QName fi::ExprVertexInfo fd::[FlowVertex] case q.lookupValue.typeScheme.monoType of | ntOrDecType(t, i, _) -> ntOrDecType(t, i, freshType()) | decoratedType(t, i) -> ntOrDecType(t, i, freshType()) - | partiallyDecoratedType(t, i) -> ntOrDecType(t, i, freshType()) + | uniqueDecoratedType(t, i) -> ntOrDecType(t, i, freshType()) | t -> t end; diff --git a/grammars/silver/compiler/modification/let_fix/Project.sv b/grammars/silver/compiler/modification/let_fix/Project.sv index 6303ae671..9aa39df5e 100644 --- a/grammars/silver/compiler/modification/let_fix/Project.sv +++ b/grammars/silver/compiler/modification/let_fix/Project.sv @@ -4,7 +4,9 @@ imports silver:compiler:definition:core; imports silver:compiler:definition:env; imports silver:compiler:definition:type; imports silver:compiler:definition:type:syntax; ---imports silver:compiler:analysis:typechecking:core; +imports silver:compiler:definition:flow:env; +imports silver:compiler:analysis:typechecking:core; +imports silver:compiler:analysis:uniqueness; exports silver:compiler:modification:let_fix:java with silver:compiler:translation:java:core; exports silver:compiler:modification:let_fix:java with silver:compiler:translation:java:type; diff --git a/grammars/silver/compiler/modification/let_fix/java/Let.sv b/grammars/silver/compiler/modification/let_fix/java/Let.sv index 20a4c275d..9e05417a7 100644 --- a/grammars/silver/compiler/modification/let_fix/java/Let.sv +++ b/grammars/silver/compiler/modification/let_fix/java/Let.sv @@ -6,22 +6,19 @@ import silver:compiler:definition:core; import silver:compiler:definition:env; import silver:compiler:definition:type; import silver:compiler:definition:type:syntax; +import silver:compiler:analysis:typechecking:core; import silver:compiler:translation:java:core; import silver:compiler:translation:java:type; -import silver:compiler:definition:flow:ast only ExprVertexInfo, FlowVertex; - aspect production letp top::Expr ::= la::AssignExpr e::Expr { - local finTy :: Type = finalType(top); - -- We need to create these nested locals, so we have no choice but to create a thunk object so we can declare these things. local closureExpr :: String = - s"new common.Thunk<${finTy.transType}>(new common.Thunk.Evaluable<${finTy.transType}>() { public final ${finTy.transType} eval() { ${la.let_translation} return ${e.translation}; } })"; + s"new common.Thunk<${top.finalType.transType}>(new common.Thunk.Evaluable<${top.finalType.transType}>() { public final ${top.finalType.transType} eval() { ${la.let_translation} return ${e.translation}; } })"; --TODO: java lambdas are bugged - --s"new common.Thunk<${finTy.transType}>(() -> { ${la.let_translation} return ${e.translation};\n})"; + --s"new common.Thunk<${top.finalType.transType}>(() -> { ${la.let_translation} return ${e.translation};\n})"; top.translation = s"${closureExpr}.eval()"; @@ -29,9 +26,13 @@ top::Expr ::= la::AssignExpr e::Expr if top.frame.lazyApplication then closureExpr else top.translation; + + propagate initTransDecSites; } synthesized attribute let_translation :: String occurs on AssignExpr; +attribute initTransDecSites occurs on AssignExpr; +propagate initTransDecSites on AssignExpr; function makeLocalValueName String ::= s::String @@ -63,7 +64,7 @@ String ::= fn::String et::String ty::String } aspect production lexicalLocalReference -top::Expr ::= q::PartiallyDecorated QName fi::ExprVertexInfo fd::[FlowVertex] +top::Expr ::= q::Decorated! QName _ _ _ { -- To account for a magic case where we generate a let expression with a type -- that is, for example, a ntOrDecType or something, @@ -71,17 +72,19 @@ top::Expr ::= q::PartiallyDecorated QName fi::ExprVertexInfo fd::[FlowVertex] -- it could be isDecorated (ntOrDecType) that later gets specialized to undecorated -- and therefore we must be careful not to try to undecorate it again! local needsUndecorating :: Boolean = - performSubstitution(q.lookupValue.typeScheme.monoType, top.finalSubst).isDecorated && !finalType(top).isDecorated; + performSubstitution(q.lookupValue.typeScheme.monoType, top.finalSubst).isDecorated && !top.finalType.isDecorated; top.translation = if needsUndecorating - then "((" ++ finalType(top).transType ++ ")((common.DecoratedNode)" ++ makeLocalValueName(q.lookupValue.fullName) ++ ".eval()).undecorate())" - else "((" ++ finalType(top).transType ++ ")(" ++ makeLocalValueName(q.lookupValue.fullName) ++ ".eval()))"; + then "((" ++ top.finalType.transType ++ ")((common.DecoratedNode)" ++ makeLocalValueName(q.lookupValue.fullName) ++ ".eval()).undecorate())" + else "((" ++ top.finalType.transType ++ ")(" ++ makeLocalValueName(q.lookupValue.fullName) ++ ".eval()))"; top.lazyTranslation = if !top.frame.lazyApplication then top.translation else if needsUndecorating then "common.Thunk.transformUndecorate(" ++ makeLocalValueName(q.lookupValue.fullName) ++ ")" else makeLocalValueName(q.lookupValue.fullName); + + top.initTransDecSites := ""; } diff --git a/grammars/silver/compiler/modification/list/List.sv b/grammars/silver/compiler/modification/list/List.sv index 2988fa430..f8584cb89 100644 --- a/grammars/silver/compiler/modification/list/List.sv +++ b/grammars/silver/compiler/modification/list/List.sv @@ -10,6 +10,7 @@ concrete production listTypeExpr top::TypeExpr ::= '[' te::TypeExpr ']' { top.unparse = "[" ++ te.unparse ++ "]"; + propagate grammarName, env, flowEnv; top.typerep = listType(te.typerep); @@ -58,7 +59,26 @@ top::Expr ::= h::Expr '::' t::Expr { top.unparse = "(" ++ h.unparse ++ " :: " ++ t.unparse ++ ")" ; - forwards to mkStrFunctionInvocation(top.location, "silver:core:cons", [h, t]); + -- Needed to satisfy flow analysis, since we demand translation of h and t. + h.decSiteVertexInfo = nothing(); + t.decSiteVertexInfo = nothing(); + h.alwaysDecorated = false; + t.alwaysDecorated = false; + + forwards to application( + baseExpr( + qName(top.location, "silver:core:cons"), + location=top.location), '(', + snocAppExprs( + snocAppExprs( + emptyAppExprs(location=top.location), ',', + presentAppExpr(@h, location=top.location), + location=top.location), ',', + presentAppExpr(@t, location=top.location), + location=top.location), + ',', + emptyAnnoAppExprs(location=top.location), + ')', location=top.location); } concrete production fullList @@ -80,19 +100,11 @@ top::Exprs ::= aspect production exprsSingle top::Exprs ::= e::Expr { - top.listtrans = mkStrFunctionInvocation(e.location, "silver:core:cons", [e, emptyList('[',']', location=top.location)]); + top.listtrans = consListOp(e, '::', emptyList('[',']', location=top.location), location=top.location); } aspect production exprsCons top::Exprs ::= e1::Expr ',' e2::Exprs { - top.listtrans = mkStrFunctionInvocation(e1.location, "silver:core:cons", [e1, e2.listtrans]); -} - --- Overloaded operators -------------------------------------------------------- - -abstract production listPlusPlus -top::Expr ::= e1::PartiallyDecorated Expr e2::PartiallyDecorated Expr -{ - forwards to mkStrFunctionInvocationDecorated(e1.location, "silver:core:append", [e1,e2]); + top.listtrans = consListOp(e1, '::', e2.listtrans, location=top.location); } diff --git a/grammars/silver/compiler/modification/list/Project.sv b/grammars/silver/compiler/modification/list/Project.sv index 49d5cb826..46fd33b93 100644 --- a/grammars/silver/compiler/modification/list/Project.sv +++ b/grammars/silver/compiler/modification/list/Project.sv @@ -3,6 +3,7 @@ grammar silver:compiler:modification:list; imports silver:compiler:definition:type; imports silver:compiler:definition:env; imports silver:compiler:definition:core; +imports silver:compiler:definition:flow:env; exports silver:compiler:modification:list:java with silver:compiler:translation:java:core; -- special case for [] exports silver:compiler:modification:list:java:type with silver:compiler:translation:java:type; -- listCtrType translation diff --git a/grammars/silver/compiler/modification/list/Type.sv b/grammars/silver/compiler/modification/list/Type.sv index 980f7124c..3788ad1e3 100644 --- a/grammars/silver/compiler/modification/list/Type.sv +++ b/grammars/silver/compiler/modification/list/Type.sv @@ -6,7 +6,7 @@ grammar silver:compiler:modification:list; abstract production listType top::Type ::= el::Type { - propagate substituted, flatRenamed; + propagate substitution, substituted, flatRenamed, boundVariables; top.typepp = "[" ++ el.typepp ++ "]"; forwards to appType(listCtrType(), el); @@ -26,7 +26,8 @@ top::Type ::= top.isNonterminal = false; top.isDecorated = false; - top.tracked = false; + top.isData = false; + top.isTracked = false; top.kindrep = arrowKind(starKind(),starKind()); top.unify = diff --git a/grammars/silver/compiler/modification/list/java/List.sv b/grammars/silver/compiler/modification/list/java/List.sv index 226ff7d69..826e63e88 100644 --- a/grammars/silver/compiler/modification/list/java/List.sv +++ b/grammars/silver/compiler/modification/list/java/List.sv @@ -19,3 +19,14 @@ top::Expr ::= '[' ']' top.translation = "(common.ConsCell)common.ConsCell.nil"; top.lazyTranslation = top.translation; } + +aspect production consListOp +top::Expr ::= h::Expr '::' t::Expr +{ + -- Also avoid an extra function call for `::` (remember, this is used in list literals) + top.translation = s"new common.ConsCell(${h.lazyTranslation}, ${t.lazyTranslation})"; + + -- Avoid wrapping the ConsCell constructor in an extra thunk. + -- This is analagous to the trick with invokeLazyTranslation on productionReference. + top.lazyTranslation = top.translation; +} diff --git a/grammars/silver/compiler/modification/primitivepattern/PrimitiveMatch.sv b/grammars/silver/compiler/modification/primitivepattern/PrimitiveMatch.sv index 375914550..3f38fdd16 100644 --- a/grammars/silver/compiler/modification/primitivepattern/PrimitiveMatch.sv +++ b/grammars/silver/compiler/modification/primitivepattern/PrimitiveMatch.sv @@ -5,16 +5,19 @@ imports silver:util:treeset as ts; imports silver:compiler:definition:core; imports silver:compiler:definition:env; imports silver:compiler:definition:type; +imports silver:compiler:definition:flow:env; + +imports silver:compiler:analysis:typechecking:core; +imports silver:compiler:analysis:uniqueness; import silver:compiler:definition:type:syntax only typerepType, TypeExpr, errorsKindStar; -import silver:compiler:extension:patternmatching only Arrow_kwd, Vbar_kwd, ensureDecoratedExpr; -- TODO remove +import silver:compiler:extension:patternmatching only Arrow_kwd, Vbar_kwd; -- TODO remove import silver:compiler:translation:java:core; import silver:compiler:translation:java:type; -- Actually only used for lists, in this file... TODO import silver:compiler:modification:let_fix only makeSpecialLocalBinding, lexicalLocalDef; -import silver:compiler:definition:flow:ast only noVertex; import silver:compiler:modification:list; -- Oh no, this is a hack! TODO @@ -24,18 +27,19 @@ nonterminal PrimPatterns with config, grammarName, env, compiledGrammars, frame, location, unparse, errors, freeVars, downSubst, upSubst, finalSubst, - scrutineeType, returnType, translation, isRoot, originRules; + scrutineeType, returnType, translation, initTransDecSites, originRules; nonterminal PrimPattern with config, grammarName, env, compiledGrammars, frame, location, unparse, errors, freeVars, downSubst, upSubst, finalSubst, - scrutineeType, returnType, translation, isRoot, originRules; + scrutineeType, returnType, translation, initTransDecSites, originRules; -autocopy attribute scrutineeType :: Type; -autocopy attribute returnType :: Type; +inherited attribute scrutineeType :: Type; +inherited attribute returnType :: Type; -propagate errors on PrimPatterns, PrimPattern; -propagate freeVars on PrimPatterns, PrimPattern excluding prodPatternNormal, prodPatternGadt, conslstPattern; +propagate config, grammarName, compiledGrammars, frame, errors, scrutineeType, returnType, initTransDecSites, originRules + on PrimPatterns, PrimPattern; +propagate env, finalSubst, freeVars on PrimPatterns, PrimPattern excluding prodPatternNormal, prodPatternGadt, conslstPattern; concrete production matchPrimitiveConcrete top::Expr ::= 'match' e::Expr 'return' t::TypeExpr 'with' pr::PrimPatterns 'else' '->' f::Expr 'end' @@ -49,13 +53,20 @@ top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr { top.unparse = "match " ++ e.unparse ++ " return " ++ t.unparse ++ " with " ++ pr.unparse ++ " else -> " ++ f.unparse ++ "end"; - propagate freeVars; + propagate config, grammarName, env, freeVars, frame, compiledGrammars, finalSubst, originRules, flowEnv; + e.isRoot = false; e.downSubst = top.downSubst; forward.downSubst = e.upSubst; - forwards to matchPrimitiveReal(ensureDecoratedExpr(e), t, pr, f, location=top.location); + forwards to + matchPrimitiveReal( + if isDecorable(performSubstitution(e.typerep, e.upSubst), e.env) + then decorateExprWithEmpty('decorate', @e, 'with', '{', '}', location=e.location) + else @e, + t, pr, f, location=top.location); } + {-- - @param e The value to match against (should be DECORATED if it's nonterminal type at all) - @param t The RETURN TYPE, explicitly. @@ -67,7 +78,7 @@ top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr { top.unparse = "match " ++ e.unparse ++ " return " ++ t.unparse ++ " with " ++ pr.unparse ++ " else -> " ++ f.unparse ++ "end"; - propagate errors, freeVars; + propagate config, grammarName, env, freeVars, frame, errors, compiledGrammars, finalSubst, originRules; top.typerep = t.typerep; top.errors <- t.errorsKindStar; @@ -95,10 +106,13 @@ top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr pr.scrutineeType = scrutineeType; pr.returnType = t.typerep; + + e.isRoot = false; + f.isRoot = false; local resultTransType :: String = performSubstitution(t.typerep, top.finalSubst).transType; -- It is necessary to subst on scrutineeType here for the horrible reason that the type we're matching on - -- may not be determined until we get to the constructor list. e.g. 'case error("lol") of pair(x,_) -> x end' + -- may not be determined until we get to the constructor list. e.g. 'case error("lol") of (x,_) -> x end' -- which is legal, but if we don't do this will result in java translation errors (as the scrutinee will be -- type 'a' which is Object, which doesn't have .childAsIs for 'x'.) local scrutineeFinalType :: Type = performSubstitution(scrutineeType, top.finalSubst); @@ -111,19 +125,22 @@ top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr then "while(true) {" ++ "final " ++ scrutineeTransType ++ " scrutinee = scrutineeIter; " ++ -- our Lazy needs a final variable - "final common.Node scrutineeNode = scrutinee.undecorate(); " ++ + "final common.Node scrutineeNode = scrutinee.getNode(); " ++ pr.translation ++ - "if(!scrutineeIter.undecorate().hasForward()) break;" ++ + "if(!scrutineeIter.getNode().hasForward()) break;" ++ "scrutineeIter = scrutineeIter.forward();" ++ "}" else - "final " ++ scrutineeTransType ++ " scrutinee = scrutineeIter; " ++ -- ditto - pr.translation) ++ + s"final ${scrutineeTransType} ${ -- ditto + if scrutineeFinalType.isData then "scrutineeNode" else "scrutinee"} = scrutineeIter; " ++ + pr.translation) ++ "return " ++ f.translation ++ ";" ++ "}}.eval(context, (" ++ scrutineeTransType ++")" ++ e.translation ++ ")"; top.lazyTranslation = wrapThunk(top.translation, top.frame.lazyApplication); -- TODO there seems to be an opportunity here to avoid an anon class somehow... + + propagate initTransDecSites; } concrete production onePattern @@ -133,8 +150,7 @@ top::PrimPatterns ::= p::PrimPattern top.translation = p.translation; - p.downSubst = top.downSubst; - top.upSubst = p.upSubst; + propagate downSubst, upSubst; } concrete production consPattern top::PrimPatterns ::= p::PrimPattern '|' ps::PrimPatterns @@ -143,9 +159,7 @@ top::PrimPatterns ::= p::PrimPattern '|' ps::PrimPatterns top.translation = p.translation ++ "\nelse " ++ ps.translation; - p.downSubst = top.downSubst; - ps.downSubst = p.upSubst; - top.upSubst = ps.upSubst; + propagate downSubst, upSubst; } -- TODO: Long term, I'd like to switch to having a PrimRule and rename PrimPatterns PrimRules. @@ -157,6 +171,7 @@ concrete production prodPattern top::PrimPattern ::= qn::QName '(' ns::VarBinders ')' '->' e::Expr { top.unparse = qn.unparse ++ "(" ++ ns.unparse ++ ") -> " ++ e.unparse; + propagate frame, env, compiledGrammars, grammarName; top.freeVars := ts:removeAll(ns.boundNames, e.freeVars); @@ -168,7 +183,7 @@ top::PrimPattern ::= qn::QName '(' ns::VarBinders ')' '->' e::Expr -- 1. has a non-type-variable parameter (e.g. Expr) -- 2. has fewer free variables than parameters (e.g. Eq) -- THEN it's a gadt. - | nonterminalType(_, _, _) -> !isOnlyTyVars(t.argTypes) || length(t.argTypes) != length(setUnionTyVarsAll(map((.freeVariables), t.argTypes))) + | nonterminalType(_, _, _, _) -> !isOnlyTyVars(t.argTypes) || length(t.argTypes) != length(setUnionTyVarsAll(map((.freeVariables), t.argTypes))) | _ -> false end; @@ -222,10 +237,15 @@ top::PrimPattern ::= qn::Decorated QName ns::VarBinders e::Expr prod_contexts, if null(qn.lookupValue.dcls) then [] else qn.lookupValue.dcl.namedSignature.contexts)); ns.env = occursEnv(contextOccursDefs, top.env); + production expectedScrutineeType :: Type = + if prod_type.outputType.isData + then prod_type.outputType + else decoratedType(prod_type.outputType, freshInhSet()); + local attribute errCheck1 :: TypeCheck; errCheck1.finalSubst = top.finalSubst; local attribute errCheck2 :: TypeCheck; errCheck2.finalSubst = top.finalSubst; - - errCheck1 = check(decoratedType(prod_type.outputType, freshInhSet()), top.scrutineeType); + + errCheck1 = check(expectedScrutineeType, top.scrutineeType); top.errors <- if errCheck1.typeerror then [err(top.location, qn.name ++ " has type " ++ errCheck1.leftpp ++ " but we're trying to match against " ++ errCheck1.rightpp)] else []; @@ -237,6 +257,7 @@ top::PrimPattern ::= qn::Decorated QName ns::VarBinders e::Expr -- Thread NORMALLY! YAY! thread downSubst, upSubst on top, errCheck1, e, errCheck2, top; + propagate finalSubst; -- If there are contexts on the production, then we need to make the scrutinee available -- in the RHS to access their implementations. @@ -250,6 +271,7 @@ top::PrimPattern ::= qn::Decorated QName ns::VarBinders e::Expr scrutineeName, top.location, top.grammarName), prod_contexts, if null(qn.lookupValue.dcls) then [] else qn.lookupValue.dcl.namedSignature.contexts)); e.env = newScopeEnv(contextDefs ++ ns.defs, ns.env); + e.isRoot = false; top.translation = "if(scrutineeNode instanceof " ++ makeProdName(qn.lookupValue.fullName) ++ ") { " ++ (if null(prod_contexts) then "" else s"final ${makeProdName(qn.lookupValue.fullName)} ${scrutineeName} = (${makeProdName(qn.lookupValue.fullName)})scrutineeNode; ") ++ @@ -295,10 +317,15 @@ top::PrimPattern ::= qn::Decorated QName ns::VarBinders e::Expr prod_contexts, if null(qn.lookupValue.dcls) then [] else qn.lookupValue.dcl.namedSignature.contexts)); ns.env = occursEnv(contextOccursDefs, top.env); + production expectedScrutineeType :: Type = + if prod_type.outputType.isData + then prod_type.outputType + else decoratedType(prod_type.outputType, freshInhSet()); + local attribute errCheck1 :: TypeCheck; errCheck1.finalSubst = composeSubst(errCheck2.upSubst, top.finalSubst); -- part of the local attribute errCheck2 :: TypeCheck; errCheck2.finalSubst = composeSubst(errCheck2.upSubst, top.finalSubst); -- threading hack - errCheck1 = check(decoratedType(prod_type.outputType, freshInhSet()), top.scrutineeType); + errCheck1 = check(expectedScrutineeType, top.scrutineeType); top.errors <- if errCheck1.typeerror then [err(top.location, qn.name ++ " has type " ++ errCheck1.leftpp ++ " but we're trying to match against " ++ errCheck1.rightpp)] else []; @@ -313,9 +340,10 @@ top::PrimPattern ::= qn::Decorated QName ns::VarBinders e::Expr -- but for now for simplicity, we avoid that. -- So for now, we're just skipping over this case entirely: top.upSubst = top.downSubst; + ns.finalSubst = top.finalSubst; -- AFTER everything is done elsewhere, we come back with finalSubst, and we produce the refinement, and thread THAT through everything. - errCheck1.downSubst = composeSubst(top.finalSubst, produceRefinement(top.scrutineeType, decoratedType(prod_type.outputType, freshInhSet()))); + errCheck1.downSubst = composeSubst(top.finalSubst, produceRefinement(top.scrutineeType, expectedScrutineeType)); e.downSubst = errCheck1.upSubst; errCheck2.downSubst = e.upSubst; -- Okay, now update the finalSubst.... @@ -334,6 +362,8 @@ top::PrimPattern ::= qn::Decorated QName ns::VarBinders e::Expr scrutineeName, top.location, top.grammarName), prod_contexts, if null(qn.lookupValue.dcls) then [] else qn.lookupValue.dcl.namedSignature.contexts)); e.env = newScopeEnv(contextDefs ++ ns.defs, ns.env); + + e.isRoot = false; top.translation = "if(scrutineeNode instanceof " ++ makeProdName(qn.lookupValue.fullName) ++ ") { " ++ (if null(prod_contexts) then "" else s"final ${makeProdName(qn.lookupValue.fullName)} ${scrutineeName} = (${makeProdName(qn.lookupValue.fullName)})scrutineeNode; ") ++ @@ -363,6 +393,8 @@ top::PrimPattern ::= i::Int_t '->' e::Expr thread downSubst, upSubst on top, errCheck1, e, errCheck2, top; + e.isRoot = false; + top.translation = "if(scrutinee == " ++ i.lexeme ++ ") { return (" ++ performSubstitution(top.returnType, top.finalSubst).transType ++ ")" ++ e.translation ++ "; }"; } @@ -386,6 +418,8 @@ top::PrimPattern ::= f::Float_t '->' e::Expr thread downSubst, upSubst on top, errCheck1, e, errCheck2, top; + e.isRoot = false; + top.translation = "if(scrutinee == " ++ f.lexeme ++ ") { return (" ++ performSubstitution(top.returnType, top.finalSubst).transType ++ ")" ++ e.translation ++ "; }"; } @@ -409,6 +443,8 @@ top::PrimPattern ::= i::String_t '->' e::Expr thread downSubst, upSubst on top, errCheck1, e, errCheck2, top; + e.isRoot = false; + top.translation = "if(scrutinee.equals(" ++ i.lexeme ++ ")) { return (" ++ performSubstitution(top.returnType, top.finalSubst).transType ++ ")" ++ e.translation ++ "; }"; } @@ -432,6 +468,8 @@ top::PrimPattern ::= i::String '->' e::Expr thread downSubst, upSubst on top, errCheck1, e, errCheck2, top; + e.isRoot = false; + top.translation = "if(scrutinee == " ++ i ++ ") { return (" ++ performSubstitution(top.returnType, top.finalSubst).transType ++ ")" ++ e.translation ++ "; }"; } @@ -455,6 +493,8 @@ top::PrimPattern ::= e::Expr thread downSubst, upSubst on top, errCheck1, e, errCheck2, top; + e.isRoot = false; + top.translation = "if(scrutinee.nil()) { return (" ++ performSubstitution(top.returnType, top.finalSubst).transType ++ ")" ++ e.translation ++ "; }"; } @@ -482,12 +522,15 @@ top::PrimPattern ::= h::Name t::Name e::Expr else []; thread downSubst, upSubst on top, errCheck1, e, errCheck2, top; + + propagate finalSubst; local consdefs :: [Def] = - [lexicalLocalDef(top.grammarName, top.location, h_fName, elemType, noVertex(), []), - lexicalLocalDef(top.grammarName, top.location, t_fName, top.scrutineeType, noVertex(), [])]; + [lexicalLocalDef(top.grammarName, top.location, h_fName, elemType, nothing(), [], []), + lexicalLocalDef(top.grammarName, top.location, t_fName, top.scrutineeType, nothing(), [], [])]; e.env = newScopeEnv(consdefs, top.env); + e.isRoot = false; top.translation = let diff --git a/grammars/silver/compiler/modification/primitivepattern/Types.sv b/grammars/silver/compiler/modification/primitivepattern/Types.sv index bda06396e..7173d3976 100644 --- a/grammars/silver/compiler/modification/primitivepattern/Types.sv +++ b/grammars/silver/compiler/modification/primitivepattern/Types.sv @@ -22,7 +22,7 @@ Pair<[Context] Type> ::= te::PolyType zipVarsIntoSkolemizedSubstitution(existentialVars, freshTyVars(existentialVars)), zipVarsIntoSubstitution(te.typerep.outputType.freeVariables, freshTyVars(te.typerep.outputType.freeVariables))); - return pair(map(performContextRenaming(_, skolemize), te.contexts), performRenaming(te.typerep, skolemize)); + return (map(performContextRenaming(_, skolemize), te.contexts), performRenaming(te.typerep, skolemize)); } {-- @@ -59,7 +59,7 @@ Pair<[Context] Type> ::= te::PolyType { local skolemize :: Substitution = zipVarsIntoSkolemizedSubstitution(te.boundVars, freshTyVars(te.boundVars)); - return pair(map(performContextRenaming(_, skolemize), te.contexts), performRenaming(te.typerep, skolemize)); + return (map(performContextRenaming(_, skolemize), te.contexts), performRenaming(te.typerep, skolemize)); } @@ -185,11 +185,11 @@ top::Type ::= inhs::[String] } aspect production nonterminalType -top::Type ::= fn::String ks::[Kind] _ +top::Type ::= fn::String ks::[Kind] _ _ { top.refine = case top.refineWith of - | nonterminalType(ofn, oks, _) -> + | nonterminalType(ofn, oks, _, _) -> if fn == ofn && ks == oks then emptySubst() else errorSubst("Tried to refine conflicting nonterminal types " ++ fn ++ " and " ++ ofn) @@ -220,13 +220,13 @@ top::Type ::= te::Type i::Type end; } -aspect production partiallyDecoratedType +aspect production uniqueDecoratedType top::Type ::= te::Type i::Type { top.refine = case top.refineWith of - | partiallyDecoratedType(oi, ote) -> composeSubst(refine(te, ote), refine(i, oi)) - | _ -> errorSubst("Tried to refine partially decorated type with " ++ prettyType(top.refineWith)) + | uniqueDecoratedType(oi, ote) -> composeSubst(refine(te, ote), refine(i, oi)) + | _ -> errorSubst("Tried to refine unique decorated type with " ++ prettyType(top.refineWith)) end; } @@ -279,7 +279,7 @@ Substitution ::= scrutineeType::Type constructorType::Type return case scrutineeType, constructorType of | decoratedType(t1, i1), decoratedType(t2, i2) -> case t1.baseType, t2.baseType of - | nonterminalType(n1, _, _), nonterminalType(n2, _, _) when n1 == n2 -> + | nonterminalType(n1, _, _, _), nonterminalType(n2, _, _, _) when n1 == n2 -> refineAll(i1 :: t1.argTypes, i2 :: t2.argTypes) | _, _ -> emptySubst() end diff --git a/grammars/silver/compiler/modification/primitivepattern/VarBinders.sv b/grammars/silver/compiler/modification/primitivepattern/VarBinders.sv index 606c64dd5..c1873d4bf 100644 --- a/grammars/silver/compiler/modification/primitivepattern/VarBinders.sv +++ b/grammars/silver/compiler/modification/primitivepattern/VarBinders.sv @@ -7,7 +7,7 @@ import silver:compiler:translation:java:type; import silver:compiler:modification:let_fix only makeSpecialLocalBinding, lexicalLocalDef; -import silver:compiler:definition:flow:ast only hasVertex, noVertex, PatternVarProjection, patternVarProjection, anonVertexType, ExprVertexInfo, FlowVertex, inhVertex; +import silver:compiler:definition:flow:ast only just, PatternVarProjection, patternVarProjection, anonVertexType, VertexType, FlowVertex, inhVertex; -- also unfortunately placed references to flowEnv import silver:compiler:analysis:warnings:flow only receivedDeps; -- Used in computing flow errors @@ -31,7 +31,8 @@ flowtype errors {decorate, receivedDeps} on VarBinders, VarBinder; flowtype defs {decorate} on VarBinders, VarBinder; flowtype boundNames {} on VarBinders, VarBinder; -propagate errors, defs, boundNames on VarBinders, VarBinder; +propagate config, grammarName, env, compiledGrammars, frame, errors, defs, boundNames, finalSubst, flowEnv, matchingAgainst + on VarBinders, VarBinder; --- Types of each child inherited attribute bindingTypes :: [Type]; @@ -45,7 +46,7 @@ inherited attribute bindingName :: String; synthesized attribute flowProjections :: [PatternVarProjection]; -- The DclInfo of the production we're matching against -autocopy attribute matchingAgainst :: Maybe; +inherited attribute matchingAgainst :: Maybe; synthesized attribute varBinderCount :: Integer; @@ -120,12 +121,19 @@ top::VarBinder ::= n::Name -- (We *DO NOT* want to substitute first... because that will turn the type -- variables into concrete types! and type variables in a production are -- NOT automatically decorated!) - -- Also, don't attempt to decorate already-partially-decorated types. + -- Also, don't attempt to decorate already-decorated types. local ty :: Type = if isDecorable(top.bindingType, top.env) && !top.bindingType.isDecorated then decoratedType(top.bindingType, freshInhSet()) else top.bindingType; - production finalTy::Type = performSubstitution(ty, top.finalSubst); + + -- finalSubst is not necessary, downSubst would work fine, but is not threaded through here. + -- the point is that 'ty' for Pair would currently show Pair + -- since top.bindingType comes straight from the production's type in the environment. + -- we need to do some substitution to connect it with the real types. + -- (in the env above its okay, since that must always be consulted with the current substitution, + -- but here we're rendering the translation. it's the end of the line.) + production finalTy :: Type = performSubstitution(ty, top.finalSubst); production refSet::Maybe<[String]> = getMaxRefSet(finalTy, top.env); production fName :: String = "__pv" ++ toString(genInt()) ++ ":" ++ n.name; @@ -141,34 +149,34 @@ top::VarBinder ::= n::Name -- Recall that we emit (vertex, [reference set]) for expressions with a vertex. -- and the correct value is computed based on how this gets used. -- (e.g. if 'new' - local vt :: ExprVertexInfo = + local vt :: Maybe = if isDecorable(top.bindingType, top.env) - then hasVertex(anonVertexType(fName)) - else noVertex(); + then just(anonVertexType(fName)) + else nothing(); local deps :: [FlowVertex] = if isDecorable(top.bindingType, top.env) then map(anonVertexType(fName).inhVertex, fromMaybe([], refSet)) else []; - top.defs <- [lexicalLocalDef(top.grammarName, n.location, fName, ty, vt, deps)]; + -- Unique refs are forbidden in the scrutinee. + top.defs <- [lexicalLocalDef(top.grammarName, n.location, fName, ty, vt, deps, [])]; top.boundNames <- [n.name]; - -- finalSubst is not necessary, downSubst would work fine, but is not threaded through here. - -- the point is that 'ty' for Pair would currently show Pair - -- since top.bindingType comes straight from the production's type in the environment. - -- we need to do some substitution to connect it with the real types. - -- (in the env above its okay, since that must always be consulted with the current substitution, - -- but here we're rendering the translation. it's the end of the line.) - local actualTy :: Type = performSubstitution(ty, top.finalSubst); - top.translation = - makeSpecialLocalBinding(fName, - "scrutinee." ++ + makeSpecialLocalBinding(fName, + if top.matchingAgainst.fromJust.namedSignature.outputElement.typerep.isData + then + if isDecorable(top.bindingType, top.env) + then s"scrutineeNode.childDecorated(${toString(top.bindingIndex)})" + else if top.bindingType.transType == finalTy.transType + then s"((${makeProdName(top.matchingAgainst.fromJust.fullName)})scrutineeNode).getChild_${top.bindingName}()" + else s"common.Util.<${finalTy.transType}>uncheckedCast(((${makeProdName(top.matchingAgainst.fromJust.fullName)})scrutineeNode).getChild_${top.bindingName}())" + else "scrutinee." ++ (if isDecorable(top.bindingType, top.env) then "childDecorated(" - else s"<${actualTy.transType}>childAsIs(") ++ + else s"<${finalTy.transType}>childAsIs(") ++ toString(top.bindingIndex) ++ ")", - actualTy.transType); + finalTy.transType); -- We prevent this to prevent newbies from thinking patterns are "typecase" -- (Types have to be upper case) diff --git a/grammars/silver/compiler/translation/java/core/Annotation.sv b/grammars/silver/compiler/translation/java/core/Annotation.sv index 231bde2fd..c3190b38f 100644 --- a/grammars/silver/compiler/translation/java/core/Annotation.sv +++ b/grammars/silver/compiler/translation/java/core/Annotation.sv @@ -9,7 +9,7 @@ top::AGDcl ::= 'annotation' a::QName tl::BracketedOptTypeExprs '::' te::TypeExpr -- It should be fine, though. If we're a tv, then it's 'Object' and anything -- else will be a subtype... - top.genFiles := [pair(className ++ ".java", s""" + top.genFiles := [(className ++ ".java", s""" package ${makeName(top.grammarName)}; diff --git a/grammars/silver/compiler/translation/java/core/ClassDcl.sv b/grammars/silver/compiler/translation/java/core/ClassDcl.sv index 043f5316d..e8110ea0e 100644 --- a/grammars/silver/compiler/translation/java/core/ClassDcl.sv +++ b/grammars/silver/compiler/translation/java/core/ClassDcl.sv @@ -5,7 +5,7 @@ top::AGDcl ::= 'class' cl::ConstraintList '=>' id::QNameType var::TypeExpr '{' b { local className :: String = "C" ++ last(explode(":", fName)); - top.genFiles := [pair(className ++ ".java", s""" + top.genFiles := [(className ++ ".java", s""" package ${makeName(top.grammarName)}; diff --git a/grammars/silver/compiler/translation/java/core/DclInfo.sv b/grammars/silver/compiler/translation/java/core/DclInfo.sv index 9cca5a52f..3c90edeef 100644 --- a/grammars/silver/compiler/translation/java/core/DclInfo.sv +++ b/grammars/silver/compiler/translation/java/core/DclInfo.sv @@ -52,7 +52,7 @@ top::OccursDclInfo ::= fnat::String ntty::Type atty::Type ns::NamedSignature { top.attrOccursIndexName = makeIdName(fnat ++ "__ON__" ++ ntty.transTypeName); top.attrOccursInitIndex = makeProdName(ns.fullName) ++ "." ++ top.attrOccursIndexName; - top.attrOccursIndex = s"((${makeProdName(ns.fullName)})(context.undecorate())).${makeConstraintDictName(fnat, ntty, ns.freeVariables)}"; + top.attrOccursIndex = s"((${makeProdName(ns.fullName)})(context.getNode())).${makeConstraintDictName(fnat, ntty, ns.freeVariables)}"; } aspect production occursSuperDcl top::OccursDclInfo ::= fnat::String atty::Type baseDcl::InstDclInfo @@ -102,7 +102,7 @@ top::ValueDclInfo ::= } aspect production localDcl -top::ValueDclInfo ::= fn::String ty::Type +top::ValueDclInfo ::= fn::String ty::Type _ { local attribute li :: Integer; li = lastIndexOf(":local:", fn); diff --git a/grammars/silver/compiler/translation/java/core/Expr.sv b/grammars/silver/compiler/translation/java/core/Expr.sv index 95feeebd7..1d256f4fd 100644 --- a/grammars/silver/compiler/translation/java/core/Expr.sv +++ b/grammars/silver/compiler/translation/java/core/Expr.sv @@ -1,15 +1,8 @@ grammar silver:compiler:translation:java:core; -import silver:compiler:analysis:typechecking:core only finalSubst; - import silver:compiler:driver only noOrigins; - -function finalType -Type ::= e::Decorated Expr -{ - return performSubstitution(e.typerep, e.finalSubst); -} +import silver:compiler:definition:flow:ast; {-- - A translation string that will be a thunk instead of the raw value. @@ -20,6 +13,12 @@ synthesized attribute lazyTranslation :: String; attribute lazyTranslation, translation occurs on Expr; attribute lazyTranslation occurs on Exprs; +-- Record decoration sites for translation attributes. +monoid attribute initTransDecSites::String occurs on + Expr, Exprs, AppExprs, AppExpr, ExprInhs, ExprInh; +propagate initTransDecSites on + Expr, Exprs, AppExprs, AppExpr, ExprInhs, ExprInh; + -- `translation` should yield an expression of the appropriate Java type. -- e.g. `NodeFactory` for a (String ::= ...) -- At the moment, this requires a lot of casts. Oh well. @@ -28,7 +27,9 @@ attribute lazyTranslation occurs on Exprs; -- to put values in a `new Object[]{...}` synthesized attribute invokeTranslation :: String occurs on Expr; -inherited attribute invokeArgs :: Decorated AppExprs occurs on Expr; +synthesized attribute invokeLazyTranslation :: String occurs on Expr; +inherited attribute invokeIsUnique :: Boolean occurs on Expr; +inherited attribute invokeArgs :: Decorated AppExprs with {decorate, decSiteVertexInfo, alwaysDecorated, appProd} occurs on Expr; inherited attribute invokeNamedArgs :: Decorated AnnoAppExprs occurs on Expr; inherited attribute sameProdAsProductionDefinedOn :: Boolean occurs on Expr; @@ -45,6 +46,7 @@ top::Expr ::= top.invokeTranslation = -- dynamic method invocation s"${top.translation}.invoke(${makeOriginContextRef(top)}, new Object[]{${argsTranslation(top.invokeArgs)}}, ${namedargsTranslation(top.invokeNamedArgs)})"; + top.invokeLazyTranslation = wrapThunk(top.invokeTranslation, top.frame.lazyApplication); top.generalizedTranslation = top.translation; } @@ -56,81 +58,100 @@ top::Expr ::= msg::[Message] } aspect production errorReference -top::Expr ::= msg::[Message] q::PartiallyDecorated QName +top::Expr ::= msg::[Message] q::Decorated! QName { top.translation = error("Internal compiler error: translation not defined in the presence of errors"); top.lazyTranslation = top.translation; } aspect production childReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { local childIDref :: String = top.frame.className ++ ".i_" ++ q.lookupValue.fullName; top.translation = - if isDecorable(q.lookupValue.typeScheme.typerep, top.env) - then if finalType(top).isDecorated - then s"((${finalType(top).transType})context.childDecorated(${childIDref}))" - else s"((${finalType(top).transType})context.childDecorated(${childIDref}).undecorate())" - else s"context.<${finalType(top).transType}>childAsIs(${childIDref})"; - -- the reason we do .childDecorated().undecorate() is that it's not safe to mix as-is/decorated accesses to the same child. - -- this is a potential source of minor inefficiency for functions that do not decorate. - + if !isDecorable(q.lookupValue.typeScheme.typerep, top.env) then + -- Reference to a primitive (not decorated or undecorated): + s"context.<${top.finalType.transType}>childAsIs(${childIDref})" + else if !top.finalType.isDecorated then + -- Undecorated reference to a nonterminal: + -- the reason we do .childDecorated().undecorate() is that it's not safe to mix as-is/decorated accesses to the same child. + -- this is a potential source of minor inefficiency for functions that do not decorate. + s"((${top.finalType.transType})context.childDecorated(${childIDref}).undecorate())" + else if top.finalType.isUniqueDecorated && top.alwaysDecorated then + -- Unique reference to a child that is a remote decoration site: + -- Note that this is not cached; uniqueness guarantees that it should only be demanded once. + s"context.createDecoratedChild(${childIDref})" + else + -- Normal decorated reference: + -- This may create the child, or demand it via the remote decoration site if the child has one. + s"context.childDecorated(${childIDref})"; + + -- Mirrors the above, but with lazyness: top.lazyTranslation = if !top.frame.lazyApplication then top.translation else - if isDecorable(q.lookupValue.typeScheme.typerep, top.env) - then if finalType(top).isDecorated - then s"context.childDecoratedLazy(${childIDref})" - else s"common.Thunk.transformUndecorate(context.childDecoratedLazy(${childIDref}))" - else s"context.childAsIsLazy(${childIDref})"; + if !isDecorable(q.lookupValue.typeScheme.typerep, top.env) + then s"context.childAsIsLazy(${childIDref})" + else if !top.finalType.isDecorated + then s"common.Thunk.transformUndecorate(context.childDecoratedLazy(${childIDref}))" + else if top.finalType.isUniqueDecorated && top.alwaysDecorated then + wrapThunk(top.translation, true) + else + s"context.childDecoratedLazy(${childIDref})"; } aspect production localReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.translation = - if isDecorable(q.lookupValue.typeScheme.typerep, top.env) - then if finalType(top).isDecorated - then s"((${finalType(top).transType})context.localDecorated(${q.lookupValue.dcl.attrOccursIndex}))" - else s"((${finalType(top).transType})context.localDecorated(${q.lookupValue.dcl.attrOccursIndex}).undecorate())" - else s"context.<${finalType(top).transType}>localAsIs(${q.lookupValue.dcl.attrOccursIndex})"; + if !isDecorable(q.lookupValue.typeScheme.typerep, top.env) + then s"context.<${top.finalType.transType}>localAsIs(${q.lookupValue.dcl.attrOccursIndex})" + else if !top.finalType.isDecorated + then s"((${top.finalType.transType})context.localDecorated(${q.lookupValue.dcl.attrOccursIndex}).undecorate())" + else if top.finalType.isUniqueDecorated && top.alwaysDecorated then + s"context.evalLocalDecorated(${q.lookupValue.dcl.attrOccursIndex})" + else + s"context.localDecorated(${q.lookupValue.dcl.attrOccursIndex})"; -- reminder: look at comments for childReference top.lazyTranslation = if !top.frame.lazyApplication then top.translation else - if isDecorable(q.lookupValue.typeScheme.typerep, top.env) - then if finalType(top).isDecorated - then s"context.localDecoratedLazy(${q.lookupValue.dcl.attrOccursIndex})" - else s"common.Thunk.transformUndecorate(context.localDecoratedLazy(${q.lookupValue.dcl.attrOccursIndex}))" - else s"context.localAsIsLazy(${q.lookupValue.dcl.attrOccursIndex})"; + if !isDecorable(q.lookupValue.typeScheme.typerep, top.env) + then s"context.localAsIsLazy(${q.lookupValue.dcl.attrOccursIndex})" + else if !top.finalType.isDecorated + then s"common.Thunk.transformUndecorate(context.localDecoratedLazy(${q.lookupValue.dcl.attrOccursIndex}))" + else if top.finalType.isUniqueDecorated && top.alwaysDecorated then + wrapThunk(top.translation, true) + else + s"context.localDecoratedLazy(${q.lookupValue.dcl.attrOccursIndex})"; } aspect production lhsReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.translation = - if finalType(top).isDecorated + if top.finalType.isDecorated then "context" - else s"((${finalType(top).transType})context.undecorate())"; + else s"((${top.finalType.transType})context.undecorate())"; top.lazyTranslation = top.translation; } aspect production forwardReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.translation = - if finalType(top).isDecorated + if top.finalType.isDecorated then "context.forward()" - else s"((${finalType(top).transType})context.forward().undecorate())"; + else s"((${top.finalType.transType})context.forward().undecorate())"; -- this might evaluate the forward equation, so suspend it as a thunk top.lazyTranslation = wrapThunk(top.translation, top.frame.lazyApplication); } aspect production productionReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { top.translation = if null(typeScheme.contexts) @@ -139,17 +160,27 @@ top::Expr ::= q::PartiallyDecorated QName top.lazyTranslation = top.translation; top.invokeTranslation = -- static constructor invocation - s"new ${makeProdName(q.lookupValue.fullName)}(${implode(", ", makeNewConstructionOrigin(top, !top.sameProdAsProductionDefinedOn) ++ contexts.transContexts ++ map((.lazyTranslation), top.invokeArgs.exprs ++ reorderedAnnoAppExprs(top.invokeNamedArgs)))})"; + s"new ${makeProdName(q.lookupValue.fullName)}(${implode(", ", + makeNewConstructionOrigin(top, !top.sameProdAsProductionDefinedOn) ++ + toString(top.invokeIsUnique) :: + contexts.transContexts ++ + map((.lazyTranslation), top.invokeArgs.exprs ++ reorderedAnnoAppExprs(top.invokeNamedArgs)))})"; + -- Safe to be eager here, since the only work being done is constructing a term. + -- This means that large nested terms will be built eagerly, but we rarely define a term without + -- demanding it, so overall this is a performance win. + -- Note that this shouldn't create any cycles, since we still use lazyTranslation from the children; + -- any function calls/references inside some complex nested term will still be done lazily. + top.invokeLazyTranslation = top.invokeTranslation; } aspect production functionReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { -- functions, unlike productions, can return a type variable. -- as such, we have to cast it to the real inferred final type. top.translation = - if top.typerep.transType != finalType(top).transType - then s"common.Util.<${finalType(top).transType}>uncheckedCast(${top.lazyTranslation})" + if top.typerep.transType != top.finalType.transType + then s"common.Util.<${top.finalType.transType}>uncheckedCast(${top.lazyTranslation})" else top.lazyTranslation; top.lazyTranslation = if null(typeScheme.contexts) @@ -158,15 +189,18 @@ top::Expr ::= q::PartiallyDecorated QName local invokeTrans::String = -- static method invocation - s"${makeProdName(q.lookupValue.fullName)}.invoke(${implode(", ", [makeOriginContextRef(top)] ++ contexts.transContexts ++ map((.lazyTranslation), top.invokeArgs.exprs))})"; + s"${makeProdName(q.lookupValue.fullName)}.invoke(${implode(", ", + [makeOriginContextRef(top)] ++ + contexts.transContexts ++ + map((.lazyTranslation), top.invokeArgs.exprs))})"; top.invokeTranslation = - if top.typerep.outputType.transType != finalType(top).outputType.transType - then s"common.Util.<${finalType(top).outputType.transType}>uncheckedCast(${invokeTrans})" + if top.typerep.outputType.transType != top.finalType.outputType.transType + then s"common.Util.<${top.finalType.outputType.transType}>uncheckedCast(${invokeTrans})" else invokeTrans; } aspect production classMemberReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { local transContextMember::String = s"${instHead.transContext}.${makeInstanceMemberAccessorName(q.lookupValue.fullName)}(${implode(", ", contexts.transContexts)})"; @@ -176,38 +210,39 @@ top::Expr ::= q::PartiallyDecorated QName -- The resolved instance has a polymorphic implementation for the member, -- or relies on a default implementation, which may have a more general type. -- This means that we must insert a cast to the more specific inferred result type. - then s"common.Util.<${finalType(top).transType}>uncheckedCast(${transContextMember})" + then s"common.Util.<${top.finalType.transType}>uncheckedCast(${transContextMember})" else transContextMember; top.lazyTranslation = wrapThunk(top.translation, top.frame.lazyApplication); } aspect production globalValueReference -top::Expr ::= q::PartiallyDecorated QName +top::Expr ::= q::Decorated! QName { local directThunk :: String = s"${makeName(q.lookupValue.dcl.sourceGrammar)}.Init.global_${fullNameToShort(q.lookupValue.fullName)}" ++ if null(typeScheme.contexts) then "" else s"(${implode(", ", contexts.transContexts)})"; - top.translation = s"common.Util.<${finalType(top).transType}>uncheckedCast(${directThunk}.eval())"; + top.translation = s"common.Util.<${top.finalType.transType}>uncheckedCast(${directThunk}.eval())"; top.lazyTranslation = if top.frame.lazyApplication then directThunk else s"${directThunk}.eval()"; } aspect production errorApplication -top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs annos::PartiallyDecorated AnnoAppExprs +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs annos::Decorated! AnnoAppExprs { top.translation = error("Internal compiler error: translation not defined in the presence of errors"); top.lazyTranslation = top.translation; } aspect production functionInvocation -top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs annos::PartiallyDecorated AnnoAppExprs +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs annos::Decorated! AnnoAppExprs { top.translation = e.invokeTranslation; - top.lazyTranslation = wrapThunk(top.translation, top.frame.lazyApplication); + top.lazyTranslation = e.invokeLazyTranslation; + e.invokeIsUnique = !null(top.uniqueRefs); e.invokeArgs = es; e.invokeNamedArgs = annos; e.sameProdAsProductionDefinedOn = @@ -218,7 +253,7 @@ top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs annos:: } function argsTranslation -String ::= e::Decorated AppExprs +String ::= e::Decorated AppExprs with {decorate, decSiteVertexInfo, alwaysDecorated, appProd} { -- TODO: This is the ONLY use of .exprs We could eliminate that, if we fix this. return implode(", ", map((.lazyTranslation), e.exprs)); @@ -238,10 +273,8 @@ String ::= e::Decorated AnnoAppExprs else s"new Object[]{${implode(", ", map((.lazyTranslation), e.exprs))}}"; } -function int2str String ::= i::Integer { return toString(i); } - aspect production partialApplication -top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs annos::PartiallyDecorated AnnoAppExprs +top::Expr ::= e::Decorated! Expr es::Decorated! AppExprs annos::Decorated! AnnoAppExprs { local step1 :: String = e.translation; -- Note: we check for nullity of the index lists instead of use @@ -250,16 +283,16 @@ top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs annos:: local step2 :: String = if !null(es.appExprIndicies) then step1 ++ ".invokePartial(" ++ - s"new int[]{${implode(", ", map(int2str, es.appExprIndicies))}}, " ++ + s"new int[]{${implode(", ", map(toString, es.appExprIndicies))}}, " ++ s"new Object[]{${argsTranslation(es)}})" else step1; local step3 :: String = if !null(annos.annoIndexConverted) || !null(annos.annoIndexSupplied) then step2 ++ ".invokeNamedPartial(" ++ (if null(annos.annoIndexConverted) then "null" - else s"new int[]{${implode(", ", map(int2str, annos.annoIndexConverted))}}") ++ ", " ++ + else s"new int[]{${implode(", ", map(toString, annos.annoIndexConverted))}}") ++ ", " ++ (if null(annos.annoIndexSupplied) then "null" - else s"new int[]{${implode(", ", map(int2str, annos.annoIndexSupplied))}}") ++ ", " ++ + else s"new int[]{${implode(", ", map(toString, annos.annoIndexSupplied))}}") ++ ", " ++ namedargsTranslationNOReorder(annos) ++ ")" else step2; @@ -270,14 +303,28 @@ top::Expr ::= e::PartiallyDecorated Expr es::PartiallyDecorated AppExprs annos:: } aspect production errorAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { top.translation = error("Internal compiler error: translation not defined in the presence of errors"); top.lazyTranslation = top.translation; } -aspect production errorDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +aspect production inhUndecoratedAccessErrorHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.translation = error("Internal compiler error: translation not defined in the presence of errors"); + top.lazyTranslation = top.translation; +} + +aspect production transUndecoratedAccessErrorHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.translation = error("Internal compiler error: translation not defined in the presence of errors"); + top.lazyTranslation = top.translation; +} + +aspect production unknownDclAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { top.translation = error("Internal compiler error: translation not defined in the presence of errors"); top.lazyTranslation = top.translation; @@ -286,14 +333,14 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur aspect production forwardAccess top::Expr ::= e::Expr '.' 'forward' { - top.translation = s"((${finalType(top).transType})${e.translation}.forwardOrThis())"; + top.translation = s"((${top.finalType.transType})${e.translation}.forwardOrThis())"; top.lazyTranslation = wrapThunk(top.translation, top.frame.lazyApplication); } aspect production synDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { - top.translation = wrapAccessWithOT(top, s"${e.translation}.<${finalType(top).transType}>synthesized(${q.attrOccursIndex})"); + top.translation = wrapAccessWithOT(top, s"${e.translation}.<${top.finalType.transType}>synthesized(${q.attrOccursIndex})"); top.lazyTranslation = case e, top.frame.lazyApplication of @@ -310,9 +357,9 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur } aspect production inhDecoratedAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { - top.translation = wrapAccessWithOT(top, s"${e.translation}.<${finalType(top).transType}>inherited(${q.attrOccursIndex})"); + top.translation = wrapAccessWithOT(top, s"${e.translation}.<${top.finalType.transType}>inherited(${q.attrOccursIndex})"); top.lazyTranslation = case e, top.frame.lazyApplication of @@ -321,8 +368,50 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur end; } +aspect production transDecoratedAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + -- TODO: Origin tracking? + top.translation = + if !top.finalType.isDecorated then + s"((${top.finalType.transType})${e.translation}.translation(${q.attrOccursIndex}, ${q.attrOccursIndex}_inhs, ${q.attrOccursIndex}_dec_site).undecorate())" + else if top.finalType.isUniqueDecorated && top.alwaysDecorated && + case e of + | childReference(cqn) -> true + | localReference(lqn) -> true + | _ -> false + end then + -- Unique reference to a translation attribute on a child or local that is a remote decoration site: + -- Note that this is not cached; uniqueness guarantees that it should only be demanded once. + s"${e.translation}.evalTrans(${q.attrOccursIndex}, ${q.attrOccursIndex}_inhs)" + else + -- Normal decorated reference: + -- This may create the child, or demand it via the remote decoration site if the child has one. + s"${e.translation}.translation(${q.attrOccursIndex}, ${q.attrOccursIndex}_inhs, ${q.attrOccursIndex}_dec_site)"; + + -- TODO: Specialized thunks for accesses on child/local, for efficency + top.lazyTranslation = wrapThunk(top.translation, top.frame.lazyApplication); + + top.initTransDecSites <- + case top.decSiteVertexInfo of + | just(decSite) when top.finalType.isUniqueDecorated && top.alwaysDecorated -> + case e of + | childReference(cqn) -> + s"\t\t// Decoration site for ${q.unparse}: ${decSite.vertexName}\n" ++ + s"\t\t${top.frame.className}.childInheritedAttributes[${top.frame.className}.i_${cqn.lookupValue.fullName}][${q.attrOccursInitIndex}_dec_site] = " ++ + s"(context) -> ${refAccessTranslation(top.env, top.flowEnv, top.frame.lhsNtName, decSite)};\n" + | localReference(lqn) -> + s"\t\t// Decoration site for ${q.unparse}: ${decSite.vertexName}\n" ++ + s"\t\t${top.frame.className}.localInheritedAttributes[${lqn.lookupValue.dcl.attrOccursIndex}][${q.attrOccursInitIndex}_dec_site] = " ++ + s"(context) -> ${refAccessTranslation(top.env, top.flowEnv, top.frame.lhsNtName, decSite)};\n" + | _ -> "" + end + | _ -> "" + end; +} + aspect production terminalAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { local accessor :: String = if q.name == "lexeme" || q.name == "location" @@ -335,16 +424,28 @@ top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur then "getFilename()" else error("Not possible -- an error should have been raised about " ++ q.unparse); - top.translation = s"((${finalType(top).transType})${e.translation}.${accessor})"; + top.translation = s"((${top.finalType.transType})${e.translation}.${accessor})"; top.lazyTranslation = top.translation; } aspect production annoAccessHandler -top::Expr ::= e::PartiallyDecorated Expr q::PartiallyDecorated QNameAttrOccur +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur { + local accessTrans::String = s"((${makeAnnoName(q.attrDcl.fullName)})${e.translation}).getAnno_${makeIdName(q.attrDcl.fullName)}()"; -- Note that the transType is specific to the nonterminal we're accessing from. - top.translation = s"((${finalType(top).transType})((${makeAnnoName(q.attrDcl.fullName)})${e.translation}).getAnno_${makeIdName(q.attrDcl.fullName)}())"; + top.translation = + if q.attrDcl.typeScheme.typerep.transType != top.finalType.transType + then s"common.Util.<${top.finalType.transType}>uncheckedCast(${accessTrans})" + else accessTrans; + + top.lazyTranslation = wrapThunk(top.translation, top.frame.lazyApplication); +} + +aspect production synDataAccessHandler +top::Expr ::= e::Decorated! Expr q::Decorated! QNameAttrOccur +{ + top.translation = wrapAccessWithOT(top, s"${e.translation}.<${top.finalType.transType}>synthesized(${q.attrOccursIndex})"); top.lazyTranslation = wrapThunk(top.translation, top.frame.lazyApplication); } @@ -361,7 +462,7 @@ top::Expr ::= 'decorate' e::Expr 'with' '{' inh::ExprInhs '}' -- (especially important because we're implicitly inserted when accessing attributes -- from undecorated nodes, and this is a common error for new silverers.) | _ -> ".decorate(context, common.Util.populateInh(" ++ - case finalType(e) of + case e.finalType of -- Don't know the actual number of attributes for skolems with occurs-on contexts, -- fall back to using the max index. | skolemType(_) -> foldr1(\ i1::String i2::String -> s"Math.max(${i1}, ${i2})", inh.nameTrans) ++ " + 1" @@ -416,6 +517,16 @@ top::ExprLHSExpr ::= q::QNameAttrOccur } + +aspect production decorationSiteExpr +top::Expr ::= '@' e::Expr +{ + top.translation = + s"new ${top.finalType.transType}.DecorationSiteWrapper(${ + if top.finalType.isTracked then makeOriginContextRef(top) ++ ".makeNewConstructionOrigin(true), " else ""}${e.translation})"; + top.lazyTranslation = wrapThunk(top.translation, top.frame.lazyApplication); +} + aspect production trueConst top::Expr ::='true' { @@ -459,7 +570,7 @@ top::Expr ::= 'if' e1::Expr 'then' e2::Expr 'else' e3::Expr Java tries to cast it to the type of the then branch, which doesn't always work. -} - top.translation = s"(${e1.translation} ? ${e2.translation} : (${finalType(top).transType})${e3.translation})"; + top.translation = s"(${e1.translation} ? ${e2.translation} : (${top.finalType.transType})${e3.translation})"; top.lazyTranslation = wrapThunk(top.translation, top.frame.lazyApplication); } @@ -553,14 +664,6 @@ top::Exprs ::= e1::Expr ',' e2::Exprs top.lazyTranslation = e1.lazyTranslation ++ ", " ++ e2.lazyTranslation; } -aspect production exprRef -top::Expr ::= e::PartiallyDecorated Expr -{ - top.translation = e.translation; - top.lazyTranslation = e.lazyTranslation; -} - - function wrapThunk String ::= exp::String beLazy::Boolean { diff --git a/grammars/silver/compiler/translation/java/core/FunctionDcl.sv b/grammars/silver/compiler/translation/java/core/FunctionDcl.sv index be617479e..d31d4f8be 100644 --- a/grammars/silver/compiler/translation/java/core/FunctionDcl.sv +++ b/grammars/silver/compiler/translation/java/core/FunctionDcl.sv @@ -19,14 +19,14 @@ top::AGDcl ::= 'function' id::Name ns::FunctionSignature body::ProductionBody local funBody :: String = s""" final common.DecoratedNode context = new P${id.name}(${argsAccess}).decorate(originCtx); - //${head(body.uniqueSignificantExpression).unparse} - return (${namedSig.outputElement.typerep.transType})(${head(body.uniqueSignificantExpression).translation}); + //${head(body.returnExpr).unparse} + return (${namedSig.outputElement.typerep.transType})(${head(body.returnExpr).translation}); """; top.genFiles := - [pair(s"P${id.name}.java", generateFunctionClassString(top.grammarName, id.name, namedSig, funBody))] ++ + [(s"P${id.name}.java", generateFunctionClassString(body.env, top.flowEnv, top.grammarName, id.name, namedSig, funBody))] ++ if id.name == "main" - then [pair("Main.java", generateMainClassString(top.grammarName, !typeIOValFailed))] -- !typeIOValFailed true if main type used was IOVal + then [("Main.java", generateMainClassString(top.grammarName, !typeIOValFailed))] -- !typeIOValFailed true if main type used was IOVal else []; -- For main functions which return IOVal @@ -35,14 +35,14 @@ s""" final common.DecoratedNode context = new P${id.name}(${argsAccess}).decor functionType(2, []), [appType(listCtrType(), stringType()), ioForeignType, - appType(nonterminalType("silver:core:IOVal", [starKind()], false), intType())])).failure; + appType(nonterminalType("silver:core:IOVal", [starKind()], true, false), intType())])).failure; -- For main functions which return IO local attribute typeIOMonadFailed::Boolean = unify(namedSig.typerep, appTypes( functionType(1, []), [appType(listCtrType(), stringType()), - appType(nonterminalType("silver:core:IO", [starKind()], false), intType())])).failure; + appType(nonterminalType("silver:core:IO", [starKind()], false, false), intType())])).failure; -- main function signature check TODO: this should probably be elsewhere! top.errors <- @@ -53,7 +53,7 @@ s""" final common.DecoratedNode context = new P${id.name}(${argsAccess}).decor } function generateFunctionClassString -String ::= whatGrammar::String whatName::String whatSig::NamedSignature whatResult::String +String ::= env::Env flowEnv::FlowEnv whatGrammar::String whatName::String whatSig::NamedSignature whatResult::String { local className :: String = "P" ++ whatName; @@ -80,6 +80,7 @@ ${makeIndexDcls(0, whatSig.inputElements)} public static final common.Lazy[][] childInheritedAttributes = new common.Lazy[${toString(length(whatSig.inputElements))}][]; public static final common.Lazy[] localAttributes = new common.Lazy[num_local_attrs]; + public static final common.Lazy[] localDecSites = new common.Lazy[num_local_attrs]; public static final common.Lazy[][] localInheritedAttributes = new common.Lazy[num_local_attrs][]; ${whatSig.inhOccursIndexDecls} @@ -116,6 +117,14 @@ ${implode("", map(makeChildAccessCaseLazy, whatSig.inputElements))} } } + @Override + public common.Lazy getChildDecSite(final int index) { + switch(index) { +${implode("", map(makeChildDecSiteAccessCase(env, flowEnv, whatSig.outputElement.typerep.typeName, whatSig.fullName, _), whatSig.inputElements))} + default: return null; + } + } + @Override public final int getNumberOfChildren() { return ${toString(length(whatSig.inputElements))}; @@ -138,6 +147,11 @@ ${flatMap(makeInhOccursContextAccess(whatSig.freeVariables, whatSig.contextInhOc return localAttributes[key]; } + @Override + public common.Lazy getLocalDecSite(final int key) { + return localDecSites[key]; + } + @Override public final int getNumberOfLocalAttrs() { return num_local_attrs; @@ -179,7 +193,10 @@ ${contexts.contextInitTrans} @Override public final ${whatSig.outputElement.typerep.transType} invoke(final common.OriginContext originCtx, final Object[] children, final Object[] namedNotApplicable) { - return ${className}.invoke(${implode(", ", ["originCtx"] ++ map(\ c::Context -> decorate c with {boundVariables = whatSig.freeVariables;}.contextRefElem, whatSig.contexts) ++ unpackChildren(0, whatSig.inputElements))}); + return ${className}.invoke(${implode(", ", + ["originCtx"] ++ + map(\ c::Context -> decorate c with {boundVariables = whatSig.freeVariables;}.contextRefElem, whatSig.contexts) ++ + unpackChildren(0, whatSig.inputElements))}); } @Override @@ -225,7 +242,7 @@ public class Main { try { common.Node rv = (common.Node) ${if isIOValReturn then invocationIOVal else invokationEvalIO}; - common.DecoratedNode drv = rv.decorate(common.TopNode.singleton, (common.Lazy[])null); + common.DecoratedNode drv = rv.decorate(); drv.synthesized(silver.core.Init.silver_core_io__ON__silver_core_IOVal); // demand the io token System.exit( (Integer)drv.synthesized(silver.core.Init.silver_core_iovalue__ON__silver_core_IOVal) ); } catch(Throwable t) { diff --git a/grammars/silver/compiler/translation/java/core/InstanceDcl.sv b/grammars/silver/compiler/translation/java/core/InstanceDcl.sv index 72fd8517c..b346dcf3f 100644 --- a/grammars/silver/compiler/translation/java/core/InstanceDcl.sv +++ b/grammars/silver/compiler/translation/java/core/InstanceDcl.sv @@ -8,7 +8,7 @@ top::AGDcl ::= 'instance' cl::ConstraintList '=>' id::QNameType ty::TypeExpr '{' local contexts::Contexts = foldContexts(cl.contexts); contexts.boundVariables = boundVars; - top.genFiles := if contexts.isTypeError then [] else [pair(className ++ ".java", s""" + top.genFiles := if contexts.isTypeError then [] else [(className ++ ".java", s""" package ${makeName(top.grammarName)}; @@ -75,7 +75,7 @@ top::InstanceBodyItem ::= id::QName '=' e::Expr ';' contexts.boundVariables = boundVars; top.translation = s""" - public ${finalType(e).transType} ${makeInstanceMemberAccessorName(top.fullName)}(${contexts.contextParamTrans}) { + public ${e.finalType.transType} ${makeInstanceMemberAccessorName(top.fullName)}(${contexts.contextParamTrans}) { //${e.unparse} return ${e.generalizedTranslation}; } diff --git a/grammars/silver/compiler/translation/java/core/NamedSignature.sv b/grammars/silver/compiler/translation/java/core/NamedSignature.sv index 70371d285..ad099dfd9 100644 --- a/grammars/silver/compiler/translation/java/core/NamedSignature.sv +++ b/grammars/silver/compiler/translation/java/core/NamedSignature.sv @@ -1,5 +1,7 @@ grammar silver:compiler:translation:java:core; +import silver:compiler:definition:flow:ast; + {-- - The java translation of the *input parameters* signature. -} @@ -10,7 +12,7 @@ synthesized attribute contextSigElems :: [String] occurs on Contexts; synthesized attribute contextSigElem :: String occurs on Context; -- Track what children with inh occurs-on contexts need to have indices generated monoid attribute contextInhOccurs :: [(Type, String)] occurs on NamedSignature, Contexts, Context; -autocopy attribute sigInhOccurs :: [(Type, String)] occurs on NamedSignatureElements, NamedSignatureElement; +inherited attribute sigInhOccurs :: [(Type, String)] occurs on NamedSignatureElements, NamedSignatureElement; synthesized attribute inhOccursContextTypes :: [Type] occurs on NamedSignature; monoid attribute inhOccursIndexDecls :: String occurs on NamedSignature, Contexts, Context; -- Track what children can be used to resolve contexts at runtime @@ -24,7 +26,7 @@ synthesized attribute annoSigElems :: [String] occurs on NamedSignatureElements; synthesized attribute childSigElem :: String occurs on NamedSignatureElement; synthesized attribute annoSigElem :: String occurs on NamedSignatureElement; -- "d_contextname" -synthesized attribute contextRefElems :: [String] occurs on Contexts; +synthesized attribute contextRefElems :: [String] occurs on NamedSignature, Contexts; synthesized attribute contextRefElem :: String occurs on Context; -- "c_signame" synthesized attribute childRefElems :: [String] occurs on NamedSignatureElements; @@ -41,16 +43,21 @@ synthesized attribute childStatic :: String occurs on NamedSignature, NamedSigna synthesized attribute childDeclElem :: String occurs on NamedSignatureElement; synthesized attribute annoDeclElem :: String occurs on NamedSignatureElement; synthesized attribute childDecls :: String occurs on NamedSignature, NamedSignatureElements; --- "signame" +-- \"sig:name\" synthesized attribute annoNameElem :: String occurs on NamedSignatureElement; +-- getAnno_signame() +synthesized attribute annoAccessorElem :: String occurs on NamedSignatureElement; -- "if (name.equals("signame")) { return getAnno_signame(); }" synthesized attribute annoLookupElem :: String occurs on NamedSignatureElement; +propagate sigInhOccurs on NamedSignatureElements, NamedSignatureElement; + aspect production namedSignature top::NamedSignature ::= fn::String ctxs::Contexts ie::NamedSignatureElements oe::NamedSignatureElement np::NamedSignatureElements { top.javaSignature = implode(", ", ctxs.contextSigElems ++ ie.childSigElems ++ np.annoSigElems); top.refInvokeTrans = implode(", ", ctxs.contextRefElems ++ ie.childRefElems ++ np.annoRefElems); + top.contextRefElems = ctxs.contextRefElems; top.childTypeVarElems = ie.childTypeVarElems; top.childStatic = ie.childStatic; top.childDecls = ie.childDecls; @@ -77,6 +84,7 @@ top::NamedSignature ::= fn::String ctxs::Contexts ty::Type top.javaSignature = error("Translation shouldn't be demanded from global signature"); top.refInvokeTrans = error("Translation shouldn't be demanded from global signature"); top.contextRuntimeResolve := error("Translation shouldn't be demanded from global signature"); + top.contextRefElems = error("Translation shouldn't be demanded from global signature"); top.childTypeVarElems = error("Translation shouldn't be demanded from global signature"); top.childStatic = error("Translation shouldn't be demanded from global signature"); top.childDecls = error("Translation shouldn't be demanded from global signature"); @@ -256,7 +264,7 @@ s"""private Object child_${n}; top.childStaticElem = if lookupBy(typeNameEq, ty, top.sigInhOccurs).isJust then s"\t\tchildInheritedAttributes[i_${n}] = new common.Lazy[count_inh__ON__${ntType.transTypeName}];\n" - else if ty.isNonterminal || ty.isPartiallyDecorated && ntType.isNonterminal + else if ty.isNonterminal && !ty.isData || ty.isUniqueDecorated && ntType.isNonterminal then s"\t\tchildInheritedAttributes[i_${n}] = new common.Lazy[${makeNTName(ntType.typeName)}.num_inh_attrs];\n" else ""; @@ -278,6 +286,7 @@ s""" protected Object anno_${fn}; } """; + top.annoAccessorElem = s"getAnno_${fn}()"; top.annoNameElem = s"\"${n}\""; top.annoLookupElem = @@ -316,6 +325,38 @@ String ::= n::NamedSignatureElement { return s"\t\t\tcase i_${n.elementName}: return child_${n.elementName};\n"; } +function makeChildDecSiteAccessCase +String ::= env::Env flowEnv::FlowEnv lhsNtName::String prodName::String n::NamedSignatureElement +{ + return + case lookupUniqueRefs(prodName, n.elementName, flowEnv), lookupRefDecSite(prodName, n.elementName, flowEnv) of + | [u], [v] -> s"\t\t\tcase i_${n.elementName}: return (context) -> ${refAccessTranslation(env, flowEnv, lhsNtName, v)};\n" + | _, _ -> "" + end; +} +function refAccessTranslation +String ::= env::Env flowEnv::FlowEnv lhsNtName::String v::VertexType +{ + return + case v of + | lhsVertexType_real() -> error("lhs can't be a ref decoration site") + | rhsVertexType(sigName) -> error("child can't be a ref decoration site") + | localVertexType(fName) -> + case getValueDcl(fName, env) of + | dcl :: _ -> s"context.localDecorated(${dcl.attrOccursIndex})" + | [] -> error("Couldn't find decl for local " ++ fName) + end + | transAttrVertexType(lhsVertexType_real(), transAttr) -> + let transIndexName::String = head(getOccursDcl(transAttr, lhsNtName, env)).attrGlobalOccursInitIndex + in s"context.translation(${transIndexName}, ${transIndexName}_inhs, ${transIndexName}_dec_site)" + end + | transAttrVertexType(_, transAttr) -> error("trans attr on non-lhs can't be a ref decoration site") + | forwardVertexType_real() -> s"context.forward()" + | anonVertexType(_) -> error("dec site projection shouldn't happen with anon decorate") + | subtermVertexType(parent, prodName, sigName) -> + s"${refAccessTranslation(env, flowEnv, lhsNtName, parent)}.childDecorated(${makeProdName(prodName)}.i_${sigName})" + end; +} function makeAnnoAssign String ::= n::NamedSignatureElement @@ -335,9 +376,10 @@ String ::= bv::[TyVar] sigInhOccurs::[(Type, String)] typeVarArray::String inhAr t.boundVariables = bv; local inhs::[String] = lookupAllBy(typeNameEq, t, sigInhOccurs); return s""" if (${typeVarArray}[key] == type_${t.transTypeName}) { - common.Lazy[] res = new common.Lazy[${foldr1(\ i1::String i2::String -> s"Math.max(${i1}, ${i2})", map(makeConstraintDictName(_, t, bv), inhs))} + 1]; + ${if null(inhs) then "return null;" else +s"""common.Lazy[] res = new common.Lazy[${foldr1(\ i1::String i2::String -> s"Math.max(${i1}, ${i2})", map(makeConstraintDictName(_, t, bv), inhs))} + 1]; ${flatMap(\ inh::String -> s"\t\t\tres[${makeConstraintDictName(inh, t, bv)}] = ${inhArray}[key][${makeIdName(inh)}__ON__${t.transTypeName}];\n", inhs)} - return res; + return res;"""} } """; } @@ -363,7 +405,7 @@ String ::= i::Integer s::[NamedSignatureElement] function makeChildUnify String ::= fn::String n::NamedSignatureElement { - return + return if null(n.typerep.freeVariables) then "" else s"""try { if (!common.TypeRep.unify(${transFreshTypeRep(n.typerep)}, common.Reflection.getType(getChild_${n.elementName}()))) { throw new common.exceptions.SilverInternalError("Unification failed."); diff --git a/grammars/silver/compiler/translation/java/core/NonTerminalDcl.sv b/grammars/silver/compiler/translation/java/core/NonTerminalDcl.sv index 307b334cb..0f06fe522 100644 --- a/grammars/silver/compiler/translation/java/core/NonTerminalDcl.sv +++ b/grammars/silver/compiler/translation/java/core/NonTerminalDcl.sv @@ -8,26 +8,29 @@ top::AGDcl ::= quals::NTDeclQualifiers 'nonterminal' id::Name tl::BracketedOptTy local inhVar :: String = "count_inh__ON__" ++ id.name; local synVar :: String = "count_syn__ON__" ++ id.name; + local ntty::Type = nonterminalType(fName, map((.kindrep), tl.types), quals.data, quals.tracked); local myAnnos :: [NamedSignatureElement] = - annotationsForNonterminal(nonterminalType(fName, map((.kindrep), tl.types), quals.tracked), top.env); + annotationsForNonterminal(ntty, top.env); local commaIfAnnos :: String = if length(myAnnos)!=0 then "," else ""; - local wantsTracking :: Boolean = typeWantsTracking(nonterminalType(fName, map((.kindrep), tl.types), quals.tracked), top.config, top.env); + local wantsTracking :: Boolean = typeWantsTracking(ntty, top.config, top.env); top.initProd := s"\t\tcommon.RTTIManager.registerNonterminal(${className}.nonterminalton);\n\n"; top.initWeaving := s""" public static int ${inhVar} = 0; public static int ${synVar} = 0;"""; - local interfaces::[String] = map(makeAnnoName, map((.elementName), myAnnos)) ++ if wantsTracking then ["common.Tracked"] else []; + local interfaces::[String] = + map(makeAnnoName, map((.elementName), myAnnos)) ++ + if wantsTracking then ["common.Tracked"] else []; - top.genFiles := [pair(className ++ ".java", s""" + top.genFiles := [(className ++ ".java", s""" package ${makeName(top.grammarName)}; import java.util.*; import silver.core.*; -public abstract class ${className} extends common.Node ${ +public abstract class ${className} extends ${if quals.data then "common.DataNode" else "common.Node"} ${ (if null(interfaces) then "" else " implements " ++ implode(", ", interfaces) )} { @@ -37,11 +40,14 @@ public abstract class ${className} extends common.Node ${ public static final String[] occurs_inh = new String[num_inh_attrs]; public static final String[] occurs_syn = new String[num_syn_attrs]; - public static final LinkedList decorators = new LinkedList(); public static final common.Lazy[] defaultSynthesizedAttributes = new common.Lazy[num_syn_attrs]; - protected ${className}(${if wantsTracking then "final NOriginInfo origin"++commaIfAnnos else ""} ${implode(", ", map((.annoSigElem), myAnnos))}) { + protected ${className}(${implode(", ", + (if wantsTracking then ["final NOriginInfo origin"] else []) ++ + (if quals.data then [] else ["final boolean isUnique"]) ++ + map((.annoSigElem), myAnnos))}) { +${if quals.data then "" else " super(isUnique);"} ${if wantsTracking then "this.origin = origin;" else ""} ${implode("", map(makeAnnoAssign, myAnnos))} } @@ -49,8 +55,15 @@ ${implode("", map(makeAnnoAssign, myAnnos))} ${implode("", map((.annoDeclElem), myAnnos))} @Override - public final int getNumberOfInhAttrs() { - return num_inh_attrs; + public final String[] getAnnoNames() { + return new String[]{${implode(", ", map((.annoNameElem), myAnnos))}}; + } + + @Override + public final Object getAnno(final String name) { + ${concat(map((.annoLookupElem), myAnnos))}{ + throw new common.exceptions.SilverInternalError("Invalid annotation " + name); + } } @Override @@ -62,29 +75,158 @@ ${implode("", map((.annoDeclElem), myAnnos))} public final common.Lazy getDefaultSynthesized(final int index) { return defaultSynthesizedAttributes[index]; } - - @Override - public final String getNameOfInhAttr(final int index) { - return occurs_inh[index]; - } @Override public final String getNameOfSynAttr(final int index) { return occurs_syn[index]; } - +${if quals.data then "" else s""" @Override - public final String[] getAnnoNames() { - return new String[]{${implode(", ", map((.annoNameElem), myAnnos))}}; + public final int getNumberOfInhAttrs() { + return num_inh_attrs; } - + @Override - public final Object getAnno(final String name) { - ${concat(map((.annoLookupElem), myAnnos))}{ - throw new common.exceptions.SilverInternalError("Invalid annotation " + name); - } + public final String getNameOfInhAttr(final int index) { + return occurs_inh[index]; } + public static final class DecorationSiteWrapper extends ${className} { + private common.DecoratedNode ref; + + public DecorationSiteWrapper(${implode(", ", + (if wantsTracking then ["final NOriginInfo origin"] else []) ++ + ["final common.DecoratedNode ref"])}) { + super(${implode(", ", + (if wantsTracking then ["origin"] else []) ++ + "true" :: + map(\ anno::NamedSignatureElement -> s"((${className})ref.getNode()).${anno.annoAccessorElem}", myAnnos) + )}); + this.ref = ref; + } + + @Override + public common.DecoratedNode decorate(final common.DecoratedNode parent, final common.Lazy[] inhs) { + return ref.decorate(parent, inhs); + } + + @Override + public common.DecoratedNode decorate(final common.DecoratedNode parent, final common.Lazy[] inhs, final common.DecoratedNode fwdParent, final boolean prodFwrd) { + return ref.decorate(parent, inhs, fwdParent, prodFwrd); + } + + // Accessors used in reflection and debugging. + // These need to dispatch to the ref Node. + @Override + public common.TypeRep getType() { + return ref.getNode().getType(); + } + + @Override + public String getName() { + return ref.getNode().getName(); + } + + @Override + public int getNumberOfChildren() { + return ref.getNode().getNumberOfChildren(); + } + + @Override + public Object getChild(final int child) { + return ref.getNode().getChild(child); + } + + @Override + public Object getChildLazy(final int child) { + return ref.getNode().getChildLazy(child); + } + + @Override + public common.RTTIManager.Prodleton getProdleton() { + return ref.getNode().getProdleton(); + } + + // Accessors used only by DecoratedNode. + // This should never happen. + @Override + public common.Lazy getChildDecSite(final int child) { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should never be directly decorated!"); + } + + @Override + public common.Lazy[] getChildInheritedAttributes(final int index) { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should never be directly decorated!"); + } + + @Override + public int getNumberOfLocalAttrs() { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should never be directly decorated!"); + } + + @Override + public String getNameOfLocalAttr(final int index) { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should never be directly decorated!"); + } + + @Override + public common.Lazy getLocal(final int index) { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should never be directly decorated!"); + } + + @Override + public common.Lazy getLocalDecSite(final int index) { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should never be directly decorated!"); + } + + @Override + public boolean getLocalIsForward(final int index) { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should never be directly decorated!"); + } + + @Override + public common.Lazy[] getLocalInheritedAttributes(final int index) { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should never be directly decorated!"); + } + + @Override + public boolean hasForward() { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should never be directly decorated!"); + } + + @Override + public common.Node evalForward(final common.DecoratedNode context) { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should never be directly decorated!"); + } + + @Override + public common.Node evalUndecorate(final common.DecoratedNode context) { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should never be directly decorated!"); + } + + @Override + public common.Lazy[] getForwardInheritedAttributes() { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should never be directly decorated!"); + } + + @Override + public common.Lazy getSynthesized(final int index) { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should never be directly decorated!"); + } + + ${if wantsTracking then s""" + @Override + public ${className} duplicate(common.Node redex, common.ConsCell notes) { + throw new common.exceptions.SilverInternalError("Decoration site wrapper node should not exist in tree after undecoration!\n"); + } + + @Override + public ${className} updateOriginInfo(silver.core.NOriginInfo oi) { + return new DecorationSiteWrapper(oi, ref); + } +""" else ""} + }"""} + public static final common.RTTIManager.Nonterminalton<${className}> nonterminalton = new Nonterminalton(); public static final class Nonterminalton extends common.RTTIManager.Nonterminalton<${className}> { @@ -99,6 +241,7 @@ ${implode("", map((.annoDeclElem), myAnnos))} local otImpl::String = if wantsTracking then s""" protected final silver.core.NOriginInfo origin; + @Override public final silver.core.NOriginInfo getOrigin() { return this.origin; } diff --git a/grammars/silver/compiler/translation/java/core/OccursDcl.sv b/grammars/silver/compiler/translation/java/core/OccursDcl.sv index 2fc0454d7..2d93977ad 100644 --- a/grammars/silver/compiler/translation/java/core/OccursDcl.sv +++ b/grammars/silver/compiler/translation/java/core/OccursDcl.sv @@ -1,7 +1,7 @@ grammar silver:compiler:translation:java:core; aspect production defaultAttributionDcl -top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs +top::AGDcl ::= at::Decorated! QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs { local ntfn :: String = nt.lookupType.fullName; local occursType :: String = if at.lookupAttribute.dcl.isSynthesized then "syn" else "inh"; @@ -27,10 +27,16 @@ top::AGDcl ::= at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QNam else s"public static final int ${head(occursCheck).attrOccursIndexName} = " ++ s"${makeName(ntgrammar)}.Init.count_${occursType}__ON__${ntname}++;\n"; + + top.valueWeaving <- + if at.lookupAttribute.dcl.isTranslation then + s"public static final int ${head(occursCheck).attrOccursIndexName}_dec_site = ${makeName(ntgrammar)}.Init.count_inh__ON__${ntname}++;\n" ++ + s"public static final int ${head(occursCheck).attrOccursIndexName}_inhs = ${makeName(ntgrammar)}.Init.count_inh__ON__${ntname}++;\n" + else ""; } aspect production errorAttributionDcl -top::AGDcl ::= msg::[Message] at::PartiallyDecorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs +top::AGDcl ::= msg::[Message] at::Decorated! QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs { top.setupInh := error("Internal compiler error: translation not defined in the presence of errors"); top.valueWeaving := error("Internal compiler error: translation not defined in the presence of errors"); diff --git a/grammars/silver/compiler/translation/java/core/Origins.sv b/grammars/silver/compiler/translation/java/core/Origins.sv index 3ab986862..0abb054b5 100644 --- a/grammars/silver/compiler/translation/java/core/Origins.sv +++ b/grammars/silver/compiler/translation/java/core/Origins.sv @@ -18,8 +18,8 @@ synthesized attribute alwaysConsideredInteresting :: Boolean occurs on ContextOr aspect production useContextLhsAndRules top::ContextOriginInfoSource ::= { - top.contextRef = "new common.OriginContext(context.undecorate(), null)"; - top.contextRefAddingRules = (\x::String -> s"new common.OriginContext(context.undecorate(), ${x})"); + top.contextRef = "new common.OriginContext(context.getNode(), null)"; + top.contextRefAddingRules = (\x::String -> s"new common.OriginContext(context.getNode(), ${x})"); top.alwaysConsideredInteresting = false; } @@ -43,7 +43,7 @@ function makeOriginContextRef String ::= top::Decorated Expr --need .frame anno { local rulesTrans :: [String] = (if top.config.tracingOrigins then [locRule] else []) ++ map((.translation), top.originRules); - local locRule :: String = s"new silver.core.PtraceNote(new common.StringCatter(\"${substitute("\"", "\\\"", top.location.unparse)}\"))"; + local locRule :: String = s"new silver.core.PtraceNote(new common.StringCatter(\"${escapeString(top.location.unparse)}\"))"; return if top.config.noOrigins then "null" else if length(rulesTrans)==0 @@ -57,7 +57,7 @@ global newConstructionOriginUsingCtxRef :: String = function makeNewConstructionOrigin [String] ::= top::Decorated Expr inInteresting::Boolean --need .frame anno { - local ty :: Type = finalType(top).outputType; + local ty :: Type = top.finalType.outputType; local interesting :: Boolean = top.frame.originsContextSource.alwaysConsideredInteresting || !top.isRoot || inInteresting; return if typeWantsTracking(ty, top.config, top.env) @@ -74,20 +74,18 @@ function getSpecialCaseNoOrigins -- These are forced to be untracked to prevent circularity "silver:core:OriginInfo", "silver:core:OriginInfoType", - "silver:core:OriginNote", - -- List is special(TM) because of it's special(TM) quasi-extension translation specialization - "silver:core:List" + "silver:core:OriginNote" ]; return names; } function typeWantsTracking -Boolean ::= ty::Type conf::Decorated CmdArgs env::Decorated Env +Boolean ::= ty::Type conf::Decorated CmdArgs env::Env { return if conf.noOrigins || containsBy((\a::String b::String -> a==b), ty.typeName, getSpecialCaseNoOrigins()) then false else case ty of - | nonterminalType(fn, _, tracked) -> conf.forceOrigins || tracked + | nonterminalType(fn, _, _, tracked) -> conf.forceOrigins || tracked | appType(c, _) -> typeWantsTracking(c, conf, env) | _ -> false end; @@ -96,7 +94,7 @@ Boolean ::= ty::Type conf::Decorated CmdArgs env::Decorated Env function wrapAccessWithOT String ::= top::Decorated Expr expr::String { - local ty :: Type = finalType(top); + local ty :: Type = top.finalType; -- The complexity here is needed because of silver generics. A nonterminal like Maybe is monomorphized in such a way -- that the parameter type is Object. As a result we can't tell, when it's possible that we are doing something on a type diff --git a/grammars/silver/compiler/translation/java/core/ProductionBody.sv b/grammars/silver/compiler/translation/java/core/ProductionBody.sv index cb657b4e1..539f69dcc 100644 --- a/grammars/silver/compiler/translation/java/core/ProductionBody.sv +++ b/grammars/silver/compiler/translation/java/core/ProductionBody.sv @@ -10,6 +10,8 @@ attribute translation occurs on DefLHS, ForwardInhs, For propagate setupInh, valueWeaving on ProductionBody, ProductionStmts; +synthesized attribute initTransInh :: String occurs on DefLHS; + aspect production productionBody top::ProductionBody ::= '{' stmts::ProductionStmts '}' { @@ -55,7 +57,7 @@ top::ProductionStmt ::= aspect production forwardsTo top::ProductionStmt ::= 'forwards' 'to' e::Expr ';' { - top.translation = ""; + top.translation = e.initTransDecSites; } aspect production forwardingWith @@ -90,6 +92,12 @@ top::ForwardLHSExpr ::= q::QNameAttrOccur top.attrName = q.attrOccursInitIndex; } +aspect production undecoratesTo +top::ProductionStmt ::= 'undecorates' 'to' e::Expr ';' +{ + top.translation = ""; +} + aspect production localAttributeDcl top::ProductionStmt ::= 'local' 'attribute' a::Name '::' te::TypeExpr ';' { @@ -102,15 +110,22 @@ top::ProductionStmt ::= 'local' 'attribute' a::Name '::' te::TypeExpr ';' if isDecorable(te.typerep, top.env) then s"\t\t//${top.unparse}\n" ++ - s"\t\t${top.frame.className}.localInheritedAttributes[${ugh_dcl_hack.attrOccursInitIndex}] = " ++ - if te.typerep.isNonterminal || te.typerep.isPartiallyDecorated - then s"new common.Lazy[${makeNTName(te.typerep.typeName)}.num_inh_attrs];\n" - else s"new common.Lazy[${top.frame.className}.count_inh__ON__${makeIdName(transTypeNameWith(te.typerep, top.frame.signature.freeVariables))}];\n" + if te.typerep.isNonterminal || te.typerep.isUniqueDecorated + then + s"\t\t${top.frame.className}.localInheritedAttributes[${ugh_dcl_hack.attrOccursInitIndex}] = new common.Lazy[${makeNTName(te.typerep.typeName)}.num_inh_attrs];\n" + else s"\t\t${top.frame.className}.localInheritedAttributes[${ugh_dcl_hack.attrOccursInitIndex}] = new common.Lazy[${top.frame.className}.count_inh__ON__${makeIdName(transTypeNameWith(te.typerep, top.frame.signature.freeVariables))}];\n" else ""; top.setupInh <- s"\t\t${top.frame.className}.occurs_local[${ugh_dcl_hack.attrOccursInitIndex}] = \"${fName}\";\n"; - top.translation = ""; + top.translation = + case lookupLocalUniqueRefs(fName, top.flowEnv), lookupLocalRefDecSite(fName, top.flowEnv) of + | [u], [v] -> + s"\t\t//${top.unparse}\n" ++ + s"\t\t${top.frame.className}.localDecSites[${ugh_dcl_hack.attrOccursInitIndex}] = " ++ + s"(context) -> ${refAccessTranslation(top.env, top.flowEnv, top.frame.lhsNtName, v)};\n" + | _, _ -> "" + end; } aspect production productionAttributeDcl @@ -125,81 +140,144 @@ top::ProductionStmt ::= 'production' 'attribute' a::Name '::' te::TypeExpr ';' if isDecorable(te.typerep, top.env) then s"\t\t//${top.unparse}\n" ++ - s"\t\t${top.frame.className}.localInheritedAttributes[${ugh_dcl_hack.attrOccursInitIndex}] = " ++ - if te.typerep.isNonterminal || te.typerep.isPartiallyDecorated - then s"new common.Lazy[${makeNTName(te.typerep.typeName)}.num_inh_attrs];\n" - else s"new common.Lazy[${top.frame.className}.count_inh__ON__${makeIdName(transTypeNameWith(te.typerep, top.frame.signature.freeVariables))}];\n" + if te.typerep.isNonterminal || te.typerep.isUniqueDecorated + then + s"\t\t${top.frame.className}.localInheritedAttributes[${ugh_dcl_hack.attrOccursInitIndex}] = new common.Lazy[${makeNTName(te.typerep.typeName)}.num_inh_attrs];\n" + else s"\t\t${top.frame.className}.localInheritedAttributes[${ugh_dcl_hack.attrOccursInitIndex}] = new common.Lazy[${top.frame.className}.count_inh__ON__${makeIdName(transTypeNameWith(te.typerep, top.frame.signature.freeVariables))}];\n" else ""; top.setupInh <- s"\t\t${top.frame.className}.occurs_local[${ugh_dcl_hack.attrOccursInitIndex}] = \"${fName}\";\n"; + top.translation = + case lookupLocalUniqueRefs(fName, top.flowEnv), lookupLocalRefDecSite(fName, top.flowEnv) of + | [u], [v] -> + s"\t\t//${top.unparse}\n" ++ + s"\t\t${top.frame.className}.localDecSites[${ugh_dcl_hack.attrOccursInitIndex}] = " ++ + s"(context) -> ${refAccessTranslation(top.env, top.flowEnv, top.frame.lhsNtName, v)};\n" + | _, _ -> "" + end; +} + +aspect production forwardProductionAttributeDcl +top::ProductionStmt ::= 'forward' 'production' 'attribute' a::Name ';' +{ + local attribute ugh_dcl_hack :: ValueDclInfo; + ugh_dcl_hack = head(getValueDclAll(fName, top.env)); -- TODO really, we should have a DclInfo for ourselves no problem. but out current approach of constructing it via localDef makes this annoyingly difficult. this suggests a probably environment refactoring... + + top.valueWeaving := s"public static final int ${ugh_dcl_hack.attrOccursIndexName} = ${top.frame.prodLocalCountName}++;\n"; + + top.setupInh := + s"\t\t//${top.unparse}\n" ++ + s"\t\t${top.frame.className}.localIsForward[${ugh_dcl_hack.attrOccursInitIndex}] = true;\n" ++ + s"\t\t${top.frame.className}.localInheritedAttributes[${ugh_dcl_hack.attrOccursInitIndex}] = new common.Lazy[${makeNTName(top.frame.lhsNtName)}.num_inh_attrs];\n"; + + top.setupInh <- s"\t\t${top.frame.className}.occurs_local[${ugh_dcl_hack.attrOccursInitIndex}] = \"${fName}\";\n"; + + -- Decoration through a remote reference has no effect, since all inhs are supplied here via a forward parent top.translation = ""; } +aspect default production +top::DefLHS ::= +{ + top.initTransInh = ""; +} + aspect production childDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName { top.translation = s"${top.frame.className}.childInheritedAttributes[${top.frame.className}.i_${q.lookupValue.fullName}]"; } aspect production lhsDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName { top.translation = s"${top.frame.className}.synthesizedAttributes"; } aspect production localDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName { top.translation = s"${top.frame.className}.localInheritedAttributes[${q.lookupValue.dcl.attrOccursIndex}]"; } aspect production forwardDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName { top.translation = s"${top.frame.className}.forwardInheritedAttributes"; } aspect production errorDefLHS -top::DefLHS ::= q::PartiallyDecorated QName +top::DefLHS ::= q::Decorated! QName +{ + top.translation = error("Internal compiler error: translation not defined in the presence of errors"); +} + +aspect production childTransAttrDefLHS +top::DefLHS ::= q::Decorated! QName attr::Decorated! QNameAttrOccur +{ + local inhsIndex::String = s"${top.frame.className}.childInheritedAttributes[${top.frame.className}.i_${q.lookupValue.fullName}][${attr.attrOccursIndex}_inhs]"; + top.translation = s"((common.TransInhs)${inhsIndex}).inhs"; + top.initTransInh = + s"\t\tif (${inhsIndex} == null) {\n" ++ + s"\t\t\t${inhsIndex} = new common.TransInhs(${makeNTName(attr.typerep.typeName)}.num_inh_attrs);\n" ++ + "\t\t}\n"; +} + +aspect production localTransAttrDefLHS +top::DefLHS ::= q::Decorated! QName attr::Decorated! QNameAttrOccur +{ + local inhsIndex::String = s"${top.frame.className}.localInheritedAttributes[${q.lookupValue.dcl.attrOccursIndex}][${attr.attrOccursIndex}_inhs]"; + top.translation = s"((common.TransInhs)${inhsIndex}).inhs"; + top.initTransInh = + s"\t\tif (${inhsIndex} == null) {\n" ++ + s"\t\t\t${inhsIndex} = new common.TransInhs(${makeNTName(attr.typerep.typeName)}.num_inh_attrs);\n" ++ + "\t\t}\n"; +} + +aspect production errorTransAttrDefLHS +top::DefLHS ::= q::Decorated! QName attr::Decorated! QNameAttrOccur { top.translation = error("Internal compiler error: translation not defined in the presence of errors"); } aspect production errorAttributeDef -top::ProductionStmt ::= msg::[Message] dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= msg::[Message] dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { top.translation = error("Internal compiler error: translation not defined in the presence of errors"); } aspect production synthesizedAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { top.translation = s"\t\t// ${dl.unparse}.${attr.unparse} = ${e.unparse}\n" ++ + dl.initTransInh ++ e.initTransDecSites ++ s"\t\t${dl.translation}[${attr.attrOccursInitIndex}] = ${wrapLazy(e)};\n"; } aspect production inheritedAttributeDef -top::ProductionStmt ::= dl::PartiallyDecorated DefLHS attr::PartiallyDecorated QNameAttrOccur e::Expr +top::ProductionStmt ::= dl::Decorated! DefLHS attr::Decorated! QNameAttrOccur e::Expr { top.translation = s"\t\t// ${dl.unparse}.${attr.unparse} = ${e.unparse}\n" ++ + dl.initTransInh ++ s"\t\t${dl.translation}[${attr.attrOccursInitIndex}] = ${wrapLazy(e)};\n"; } aspect production errorValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { top.translation = error("Internal compiler error: translation not defined in the presence of errors"); } aspect production localValueDef -top::ProductionStmt ::= val::PartiallyDecorated QName e::Expr +top::ProductionStmt ::= val::Decorated! QName e::Expr { top.translation = s"\t\t// ${val.unparse} = ${e.unparse}\n" ++ + e.initTransDecSites ++ s"\t\t${top.frame.className}.localAttributes[${val.lookupValue.dcl.attrOccursInitIndex}] = ${wrapLazy(e)};\n"; } diff --git a/grammars/silver/compiler/translation/java/core/ProductionDcl.sv b/grammars/silver/compiler/translation/java/core/ProductionDcl.sv index 5a0c22ea3..075a79ba8 100644 --- a/grammars/silver/compiler/translation/java/core/ProductionDcl.sv +++ b/grammars/silver/compiler/translation/java/core/ProductionDcl.sv @@ -10,7 +10,7 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr top.setupInh := body.setupInh; top.initProd := s"\t\t${className}.initProductionAttributeDefinitions();\n" ++ s"\t\tcommon.RTTIManager.registerProduction(${className}.prodleton);\n\n"; - top.postInit := s"\t\tcommon.Decorator.applyDecorators(${fnnt}.decorators, ${className}.prodleton);\n"; + top.postInit := s""; top.initWeaving := s"\tpublic static int ${localVar} = 0;\n"; top.valueWeaving := body.valueWeaving; @@ -19,22 +19,32 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr local ntName :: String = namedSig.outputElement.typerep.typeName; local fnnt :: String = makeNTName(ntName); + local isData :: Boolean = namedSig.outputElement.typerep.isData; local wantsTracking :: Boolean = typeWantsTracking(namedSig.outputElement.typerep, top.config, top.env); local ntDeclPackage :: String = implode(".", init(explode(".", fnnt))); local typeNameSnipped :: String = last(explode(":", namedSig.outputElement.typerep.typeName)); - local dupX :: (String ::= NamedSignatureElement String) = - (\x::NamedSignatureElement gc::String -> - (if x.typerep.transType == "Object" then s"(${gc} instanceof common.Tracked?((common.Tracked)${gc}).duplicate(null, notes):${gc})" - else if !x.typerep.tracked then gc - else gc++".duplicate(null, notes)")); + local decorableChildren :: [NamedSignatureElement] = + filter(\ x::NamedSignatureElement -> isDecorable(x.typerep, body.env), namedSig.inputElements); - local dupChild :: (String ::= NamedSignatureElement) = - (\x::NamedSignatureElement -> dupX(x, s"getChild_${x.elementName}()")); + local undecChild :: (String ::= NamedSignatureElement) = + \ x::NamedSignatureElement -> + if x.typerep.isDecorated + then if isDecorable(x.typerep, body.env) + then error("Production " ++ fName ++ " has a decorable decorated child but no 'undecorates to'.") -- TODO: Remove this when this becomes a uniqueness analysis warning + else s"context.childDecoratedLazy(i_${x.elementName})" + else if isDecorable(x.typerep, body.env) + then s"context.childUndecoratedLazy(i_${x.elementName})" + else s"child_${x.elementName}"; - local dupAnno :: (String ::= NamedSignatureElement) = - (\x::NamedSignatureElement -> dupX(x, s"getAnno_${makeIdName(x.elementName)}()")); + local dupChild :: (String ::= NamedSignatureElement) = + \ x::NamedSignatureElement -> + if x.typerep.transType == "Object" + then s"(getChild_${x.elementName}() instanceof common.Tracked?((common.Tracked)child_${x.elementName}).duplicate(null, notes):child_${x.elementName})" + else if x.typerep.isTracked + then s"getChild_${x.elementName}().duplicate(null, notes)" + else s"child_${x.elementName}"; local copyChild :: (String ::= NamedSignatureElement) = (\x::NamedSignatureElement -> s"child_${x.elementName}"); @@ -44,19 +54,16 @@ top::AGDcl ::= 'abstract' 'production' id::Name ns::ProductionSignature body::Pr local getChildTypes :: (String ::= NamedSignatureElement) = (\x::NamedSignatureElement -> case x.typerep of - | nonterminalType(fn, _, _) -> s"\"${fn}\"" + | nonterminalType(fn, _, _, _) -> s"\"${fn}\"" | _ -> "null" end); - local commaIfKids :: String = if length(namedSig.inputElements)!=0 then "," else ""; - local commaIfAnnos :: String = if length(namedSig.namedInputElements)!=0 then "," else ""; - local commaIfContexts :: String = if length(namedSig.contexts)!=0 then "," else ""; local commaIfAny :: String = if length(namedSig.inputElements)!=0 || length(namedSig.namedInputElements)!=0 || length(namedSig.contexts)!=0 then "," else ""; local contexts::Contexts = foldContexts(namedSig.contexts); contexts.boundVariables = namedSig.freeVariables; - top.genFiles := [pair(className ++ ".java", s""" + top.genFiles := [(className ++ ".java", s""" package ${makeName(top.grammarName)}; import silver.core.*; @@ -72,14 +79,17 @@ ${makeIndexDcls(0, namedSig.inputElements)} public static final int num_local_attrs = Init.${localVar}; public static final String[] occurs_local = new String[num_local_attrs]; - public static final common.Lazy[] forwardInheritedAttributes = new common.Lazy[${fnnt}.num_inh_attrs]; - public static final common.Lazy[] synthesizedAttributes = new common.Lazy[${fnnt}.num_syn_attrs]; public static final common.Lazy[][] childInheritedAttributes = new common.Lazy[${toString(length(namedSig.inputElements))}][]; public static final common.Lazy[] localAttributes = new common.Lazy[num_local_attrs]; + public static final common.Lazy[] localDecSites = new common.Lazy[num_local_attrs]; public static final common.Lazy[][] localInheritedAttributes = new common.Lazy[num_local_attrs][]; +${if isData then "" else s""" + public static final common.Lazy[] forwardInheritedAttributes = new common.Lazy[${fnnt}.num_inh_attrs]; + public static final boolean[] localIsForward = new boolean[num_local_attrs];"""} + ${namedSig.inhOccursIndexDecls} public static final int[] childInhContextTypeVars = {${implode(",", namedSig.childTypeVarElems)}}; @@ -89,15 +99,28 @@ ${namedSig.inhOccursIndexDecls} ${namedSig.childStatic} } - public ${className}(final NOriginInfo origin ${commaIfAny} ${namedSig.javaSignature}) { - super(${if wantsTracking then "origin"++commaIfAnnos else ""}${implode(", ", map((.annoRefElem), namedSig.namedInputElements))}); + public ${className}(final NOriginInfo origin, final boolean isUniqueInvocation${commaIfAny} ${namedSig.javaSignature}) { + super(${implode(", ", + (if wantsTracking then ["origin"] else []) ++ + (if isData then [] + else if any(map(\ x::NamedSignatureElement -> x.typerep.isUniqueDecorated, namedSig.inputElements)) + then ["true"] + else ["isUniqueInvocation"]) ++ + map((.annoRefElem), namedSig.namedInputElements))}); ${implode("", map(makeChildAssign, namedSig.inputElements))} ${contexts.contextInitTrans} } + public ${className}(final NOriginInfo origin${commaIfAny} ${namedSig.javaSignature}) { + this(origin, false${if length(namedSig.refInvokeTrans)!=0 then ", " ++ namedSig.refInvokeTrans else ""}); + } + + public ${className}(final boolean isUniqueInvocation${commaIfAny} ${namedSig.javaSignature}) { + this(null, isUniqueInvocation${if length(namedSig.refInvokeTrans)!=0 then ", " ++ namedSig.refInvokeTrans else ""}); + } public ${className}(${namedSig.javaSignature}) { - this(null ${if length(namedSig.refInvokeTrans)!=0 then ", " ++ namedSig.refInvokeTrans else ""}); + this(null${if length(namedSig.refInvokeTrans)!=0 then ", " ++ namedSig.refInvokeTrans else ""}); } ${namedSig.childDecls} @@ -120,6 +143,14 @@ ${implode("", map(makeChildAccessCaseLazy, namedSig.inputElements))} } } + @Override + public common.Lazy getChildDecSite(final int index) { + switch(index) { +${implode("", map(makeChildDecSiteAccessCase(body.env, top.flowEnv, body.frame.lhsNtName, fName, _), namedSig.inputElements))} + default: return null; + } + } + @Override public final int getNumberOfChildren() { return ${toString(length(namedSig.inputElements))}; @@ -142,28 +173,60 @@ ${flatMap(makeInhOccursContextAccess(namedSig.freeVariables, namedSig.contextInh return childInheritedAttributes[key]; } +${if isData then "" else s""" + @Override + public common.Node evalUndecorate(final common.DecoratedNode context) { + ${if !null(body.undecorateExpr) + then s"return (common.Node)${head(body.undecorateExpr).translation};" + else if !null(decorableChildren) + then s"return new ${className}(${implode(", ", + -- A production node with no special undecoration behavior has the same origin as the + -- original node when implicitly undecorated. + -- This will be overidden by duplicate when calling new(). + (if wantsTracking then ["this.origin"] else []) ++ + namedSig.contextRefElems ++ + map(undecChild, namedSig.inputElements) ++ + map(copyAnno, namedSig.namedInputElements))});" + -- TODO: Consider if all decorable children are directly undecorable. + -- This must avoid forcing children that are thunks, and probably also should be cached. + else "return this;"} + } + @Override public boolean hasForward() { - return ${(if null(body.uniqueSignificantExpression) then "false" else "true")}; + return ${(if null(body.forwardExpr) then "false" else "true")}; } @Override public common.Node evalForward(final common.DecoratedNode context) { - ${if null(body.uniqueSignificantExpression) + ${if null(body.forwardExpr) then s"throw new common.exceptions.SilverInternalError(\"Production ${fName} erroneously claimed to forward\")" - else s"return ((common.Node)${head(body.uniqueSignificantExpression).translation}${if wantsTracking && !top.config.noRedex then s".duplicateForForwarding(context.undecorate(), \"${substitute("\"", "\\\"", hackUnparse(head(body.uniqueSignificantExpression).location))}\")" else ""})"}; + else s"return ((common.Node)${head(body.forwardExpr).translation}${ + if wantsTracking && !top.config.noRedex + then s".duplicateForForwarding(context.getNode(), \"${escapeString(hackUnparse(head(body.forwardExpr).location))}\")" + else ""})"}; } @Override - public common.Lazy getForwardInheritedAttributes(final int index) { - return forwardInheritedAttributes[index]; + public common.Lazy[] getForwardInheritedAttributes() { + return forwardInheritedAttributes; } + @Override + public boolean getLocalIsForward(final int key) { + return localIsForward[key]; + }"""} + @Override public common.Lazy getLocal(final int key) { return localAttributes[key]; } + @Override + public common.Lazy getLocalDecSite(final int key) { + return localDecSites[key]; + } + @Override public final int getNumberOfLocalAttrs() { return num_local_attrs; @@ -248,7 +311,7 @@ ${body.translation} public String getName(){ return "${fName}"; } public common.RTTIManager.Nonterminalton<${fnnt}> getNonterminalton(){ return ${fnnt}.nonterminalton; } - public String getTypeUnparse() { return "${substitute("\"", "\\\"", substitute("\\", "\\\\", ns.unparse))}"; } + public String getTypeUnparse() { return "${escapeString(ns.unparse)}"; } public int getChildCount() { return ${toString(length(namedSig.inputElements))}; } public int getAnnoCount() { return ${toString(length(namedSig.namedInputElements))}; } @@ -271,7 +334,10 @@ ${contexts.contextInitTrans} @Override public final ${fnnt} invoke(final common.OriginContext originCtx, final Object[] children, final Object[] annotations) { - return new ${className}(${implode(", ", (if wantsTracking then [newConstructionOriginUsingCtxRef] else []) ++ map(\ c::Context -> decorate c with {boundVariables = namedSig.freeVariables;}.contextRefElem, namedSig.contexts) ++ unpackChildren(0, namedSig.inputElements) ++ unpackAnnotations(0, namedSig.namedInputElements))}); + return new ${className}( + ${implode(", ", (if wantsTracking then [newConstructionOriginUsingCtxRef] else []) ++ + map(\ c::Context -> decorate c with {boundVariables = namedSig.freeVariables;}.contextRefElem, namedSig.contexts) ++ + unpackChildren(0, namedSig.inputElements) ++ unpackAnnotations(0, namedSig.namedInputElements))}); } @Override @@ -290,50 +356,31 @@ ${makeTyVarDecls(3, namedSig.typerep.freeVariables)} """)]; local otImpl :: String = if wantsTracking then s""" - public ${fnnt} duplicate(Object redex, Object notes) { + @Override + public ${fnnt} duplicate(common.Node redex, common.ConsCell notes) { + silver.core.NOriginInfo oi; if (redex == null || ${if top.config.noRedex then "true" else "false"}) { - return new ${className}(new PoriginOriginInfo(common.OriginsUtil.SET_AT_NEW_OIT, this, notes, true) ${commaIfKids} - ${implode(", ", map(dupChild, namedSig.inputElements))} ${commaIfAnnos} ${implode(", ", map(dupAnno, namedSig.namedInputElements))}); + oi = new PoriginOriginInfo(common.OriginsUtil.SET_AT_NEW_OIT, this, notes, true); } else { - return new ${className}(new PoriginAndRedexOriginInfo(common.OriginsUtil.SET_AT_NEW_OIT, this, notes, redex, notes, true) ${commaIfKids} - ${implode(", ", map(dupChild, namedSig.inputElements))} ${commaIfAnnos} ${implode(", ", map(dupAnno, namedSig.namedInputElements))}); + oi = new PoriginAndRedexOriginInfo(common.OriginsUtil.SET_AT_NEW_OIT, this, notes, redex, notes, true); } + return new ${className}( + ${implode(", ", + "oi" :: + namedSig.contextRefElems ++ + map(dupChild, namedSig.inputElements) ++ + map(copyAnno, namedSig.namedInputElements))}); } - public ${fnnt} duplicate(common.OriginContext oc) { - return this.duplicate(oc.lhs, oc.rulesAsSilverList()); - } - - public ${fnnt} copy(Object newRedex, Object newRule) { - Object origin, originNotes, newlyConstructed; - Object roi = this.origin; - if (roi instanceof PoriginOriginInfo) { - PoriginOriginInfo oi = (PoriginOriginInfo)roi; - origin = oi.getChild_origin(); - originNotes = oi.getChild_originNotes(); - newlyConstructed = oi.getChild_newlyConstructed(); - } else if (roi instanceof PoriginAndRedexOriginInfo) { - PoriginAndRedexOriginInfo oi = (PoriginAndRedexOriginInfo)roi; - origin = oi.getChild_origin(); - originNotes = oi.getChild_originNotes(); - newlyConstructed = oi.getChild_newlyConstructed(); - } else { - return this; - } - - if (newRedex instanceof common.DecoratedNode) newRedex = ((common.DecoratedNode)newRedex).undecorate(); - - Object redex = ((common.Node)newRedex); - Object redexNotes = newRule; - return new ${className}(new PoriginAndRedexOriginInfo(common.OriginsUtil.SET_AT_ACCESS_OIT, origin, originNotes, redex, redexNotes, newlyConstructed) ${commaIfKids} - ${implode(", ", map(copyChild, namedSig.inputElements))} ${commaIfAnnos} ${implode(", ", map(copyAnno, namedSig.namedInputElements))}); - } - - public ${fnnt} duplicateForForwarding(Object redex, String note) { - return new ${className}(new PoriginOriginInfo(common.OriginsUtil.SET_AT_FORWARDING_OIT, this, new common.ConsCell(new silver.core.PoriginDbgNote(new common.StringCatter(note)), common.ConsCell.nil), true) ${commaIfKids} - ${implode(", ", map(copyChild, namedSig.inputElements))} ${commaIfAnnos} ${implode(", ", map(copyAnno, namedSig.namedInputElements))}); + @Override + public ${fnnt} updateOriginInfo(silver.core.NOriginInfo oi) { + return new ${className}( + ${implode(", ", + "oi" :: + namedSig.contextRefElems ++ + map(copyChild, namedSig.inputElements) ++ + map(copyAnno, namedSig.namedInputElements))}); } - """ else ""; -- main function signature check TODO: this should probably be elsewhere! diff --git a/grammars/silver/compiler/translation/java/core/Project.sv b/grammars/silver/compiler/translation/java/core/Project.sv index 19d40c475..61c1cea73 100644 --- a/grammars/silver/compiler/translation/java/core/Project.sv +++ b/grammars/silver/compiler/translation/java/core/Project.sv @@ -7,6 +7,10 @@ imports silver:compiler:definition:type:syntax; imports silver:compiler:definition:env; imports silver:compiler:definition:type; +imports silver:compiler:definition:flow:env; + +imports silver:compiler:analysis:uniqueness; +imports silver:compiler:analysis:typechecking:core only finalType; function makeName String ::= str::String diff --git a/grammars/silver/compiler/translation/java/core/Root.sv b/grammars/silver/compiler/translation/java/core/Root.sv index be74b9a32..c3f30cda5 100644 --- a/grammars/silver/compiler/translation/java/core/Root.sv +++ b/grammars/silver/compiler/translation/java/core/Root.sv @@ -9,7 +9,7 @@ monoid attribute genFiles :: [Pair]; -} monoid attribute genBinaryFiles :: [Pair]; {-- - - Early initializers: occurs.add, local's inh attr map creation, decorators.add, collection object creation + - Early initializers: occurs.add, local's inh attr map creation, collection object creation -} monoid attribute setupInh :: String; {-- @@ -22,7 +22,7 @@ monoid attribute initProd :: String; -} monoid attribute initValues :: String; {-- - - Late initializers. Decorator application (late because we want all attribute equations to be posted first!!) + - Late initializers. -} monoid attribute postInit :: String; diff --git a/grammars/silver/compiler/translation/java/core/RootSpec.sv b/grammars/silver/compiler/translation/java/core/RootSpec.sv index 93f357fbf..6824a5f52 100644 --- a/grammars/silver/compiler/translation/java/core/RootSpec.sv +++ b/grammars/silver/compiler/translation/java/core/RootSpec.sv @@ -23,11 +23,11 @@ aspect production grammarRootSpec top::RootSpec ::= g::Grammar _ _ _ _ _ { top.genBinaryFiles := [ - pair("Silver.svi", top.serInterface) + ("Silver.svi", top.serInterface) ]; top.genFiles := g.genFiles ++ - [pair("Init.java", s""" + [("Init.java", s""" package ${makeName(g.declaredName)}; public class Init{ diff --git a/grammars/silver/compiler/translation/java/core/TerminalDcl.sv b/grammars/silver/compiler/translation/java/core/TerminalDcl.sv index f186734f5..33379860c 100644 --- a/grammars/silver/compiler/translation/java/core/TerminalDcl.sv +++ b/grammars/silver/compiler/translation/java/core/TerminalDcl.sv @@ -17,7 +17,7 @@ function terminalTranslation local fName :: String = grammarName ++ ":" ++ name; local lexerClassesStr :: String = implode(", ", map(\ s::String -> s"\"${s}\"", lexerClasses)); - return [pair(className ++ ".java", s""" + return [(className ++ ".java", s""" package ${makeName(grammarName)}; import edu.umn.cs.melt.copper.runtime.engines.semantics.VirtualLocation; diff --git a/grammars/silver/compiler/translation/java/driver/BuildProcess.sv b/grammars/silver/compiler/translation/java/driver/BuildProcess.sv index 38d679125..84d18af73 100644 --- a/grammars/silver/compiler/translation/java/driver/BuildProcess.sv +++ b/grammars/silver/compiler/translation/java/driver/BuildProcess.sv @@ -96,6 +96,9 @@ top::Compilation ::= g::Grammars _ buildGrammars::[String] benv::BuildEnv production attribute keepFiles :: [String] with ++; keepFiles := []; + -- Seed flow deps with {config} + keepFiles <- if false then error(hackUnparse(top.config)) else []; + top.postOps <- [genBuild(buildXmlLocation, buildXml)] ++ (if top.config.noJavaGeneration then [] @@ -246,7 +249,8 @@ IO<()> ::= silverGen::String keepFiles::[String] r::Decorated RootSpec exit(-5); }); }); - oldSrcFiles::[String] <- listContents(srcPath); + srcDirContents::[String] <- listContents(srcPath); + oldSrcFiles::[String] <- filterM(isFile, map(append(srcPath, _), srcDirContents)); deleteFiles(removeAll(keepFiles, oldSrcFiles)); deleteDirFiles(binPath); writeFiles(srcPath, r.genFiles); diff --git a/grammars/silver/compiler/translation/java/type/Context.sv b/grammars/silver/compiler/translation/java/type/Context.sv index 656728095..66ac2dc5f 100644 --- a/grammars/silver/compiler/translation/java/type/Context.sv +++ b/grammars/silver/compiler/translation/java/type/Context.sv @@ -112,7 +112,7 @@ top::Context ::= t::Type { top.transType = "common.TypeRep"; - t.skolemTypeReps = zipWith(pair, t.freeVariables, requiredContexts.transTypeableContexts); + t.skolemTypeReps = zip(t.freeVariables, requiredContexts.transTypeableContexts); resolvedDcl.transContextDeps = requiredContexts.transTypeableContexts; top.transTypeableContext = case top.resolved, t of @@ -184,7 +184,7 @@ top::InstDclInfo ::= fntc::String ty::Type tvs::[TyVar] aspect production sigConstraintDcl top::InstDclInfo ::= fntc::String ty::Type ns::NamedSignature { - top.transContext = s"((${makeProdName(ns.fullName)})(context.undecorate())).${makeConstraintDictName(fntc, ty, ns.freeVariables)}"; + top.transContext = s"((${makeProdName(ns.fullName)})(context.getNode())).${makeConstraintDictName(fntc, ty, ns.freeVariables)}"; } aspect production currentInstDcl top::InstDclInfo ::= fntc::String ty::Type @@ -205,7 +205,7 @@ top::InstDclInfo ::= ty::Type tvs::[TyVar] aspect production typeableSigConstraintDcl top::InstDclInfo ::= ty::Type ns::NamedSignature { - top.transContext = s"((${makeProdName(ns.fullName)})(context.undecorate())).${makeTypeableName(ty, ns.freeVariables)}"; + top.transContext = s"((${makeProdName(ns.fullName)})(context.getNode())).${makeTypeableName(ty, ns.freeVariables)}"; } aspect production typeableSuperDcl top::InstDclInfo ::= baseDcl::InstDclInfo diff --git a/grammars/silver/compiler/translation/java/type/Type.sv b/grammars/silver/compiler/translation/java/type/Type.sv index 3b33601b0..4ec134ad5 100644 --- a/grammars/silver/compiler/translation/java/type/Type.sv +++ b/grammars/silver/compiler/translation/java/type/Type.sv @@ -13,7 +13,7 @@ synthesized attribute transCovariantType :: String; -- the <> part of the type!! e.g. "Foo.class" is illegal, should be "Foo.class" synthesized attribute transClassType :: String; -- An environment mapping skolem constants to their runtime representation translations -autocopy attribute skolemTypeReps :: [(TyVar, String)]; +inherited attribute skolemTypeReps :: [(TyVar, String)]; -- The runtime representation of a type, where all skolems are replaced with their provided representations, used for reification synthesized attribute transTypeRep :: String; -- A valid Java identifier, unique to the type @@ -48,6 +48,7 @@ String ::= te::Type tvs::[TyVar] } attribute transType, transCovariantType, transClassType, transTypeRep, skolemTypeReps, transTypeName occurs on Type; +propagate skolemTypeReps on Type; aspect default production top::Type ::= @@ -142,7 +143,7 @@ top::Type ::= } aspect production nonterminalType -top::Type ::= fn::String _ _ +top::Type ::= fn::String _ _ _ { -- untightened version would be "common.Node", but we prefer the generated -- class, e.g. silver.definition.core.NExpr @@ -177,7 +178,7 @@ top::Type ::= te::Type i::Type top.transTypeName = "Decorated_" ++ te.transTypeName; } -aspect production partiallyDecoratedType +aspect production uniqueDecoratedType top::Type ::= te::Type i::Type { -- TODO: this should probably be a generic. e.g. "DecoratedNode" diff --git a/grammars/silver/core/Alternative.sv b/grammars/silver/core/Alternative.sv index ebabda7dc..2e78ed001 100644 --- a/grammars/silver/core/Alternative.sv +++ b/grammars/silver/core/Alternative.sv @@ -46,3 +46,12 @@ Annihilation ap(empty, x) = empty -} class Applicative f, Plus f => Alternative f {} + +@{- +Conditional failure of Alternative computations. +-} +function guard +Alternative f => f<()> ::= b::Boolean +{ + return if b then pure(()) else empty; +} diff --git a/grammars/silver/core/Either.sv b/grammars/silver/core/Either.sv index 6f5155054..3e9ad35ac 100644 --- a/grammars/silver/core/Either.sv +++ b/grammars/silver/core/Either.sv @@ -16,7 +16,8 @@ synthesized attribute isRight :: Boolean; - Inspect it's state with isLeft::Boolean and isRight::Boolean, and - access it's state with fromLeft::a, fromRight::b (which panic if incorrect) -} -nonterminal Either with fromLeft, fromRight, isLeft, isRight; +data nonterminal Either with fromLeft, fromRight, isLeft, isRight; +derive Eq, Ord on Either; @{- - Left case for Either. @@ -107,7 +108,7 @@ instance Alt Either { - @param m The monad type to be transformed - @param a The "success" result type, corresponding to the right constructor -} -nonterminal EitherT *) a> with run>>; +data nonterminal EitherT *) a> with run>>; abstract production eitherT top::EitherT ::= x::m> { @@ -196,9 +197,9 @@ Pair<[a] [b]> ::= l::[Either] local recurse :: Pair<[a] [b]> = partitionEithers(tail(l)); return case l of - | [] -> pair([], []) - | left(a) :: _ -> pair(a :: recurse.fst, recurse.snd) - | right(b) :: _ -> pair(recurse.fst, b :: recurse.snd) + | [] -> ([], []) + | left(a) :: _ -> (a :: recurse.fst, recurse.snd) + | right(b) :: _ -> (recurse.fst, b :: recurse.snd) end; } diff --git a/grammars/silver/core/Eq.sv b/grammars/silver/core/Eq.sv index 8cd98e836..07ae56817 100644 --- a/grammars/silver/core/Eq.sv +++ b/grammars/silver/core/Eq.sv @@ -154,47 +154,6 @@ Boolean ::= x::ByteArray y::ByteArray "java" : return "java.util.Arrays.equals(%x%, %y%)"; } -instance Eq a => Eq [a] { - eq = \ x::[a] y::[a] -> length(x) == length(y) && all(zipWith(eq, x, y)); - neq = \ x::[a] y::[a] -> length(x) != length(y) || any(zipWith(neq, x, y)); -} - -instance Eq a => Eq Maybe { - eq = \ x::Maybe y::Maybe -> - case x, y of - | just(w), just(z) -> w == z - | nothing(), nothing() -> true - | _, _ -> false - end; -} - -instance Eq a, Eq b => Eq Pair { - eq = \ x::Pair y::Pair -> x.fst == y.fst && x.snd == y.snd; - neq = \ x::Pair y::Pair -> x.fst != y.fst || x.snd != y.snd; -} - -instance Eq a, Eq b => Eq Either { - eq = \ x::Either y::Either -> - case x, y of - | left(w), left(z) -> w == z - | right(w), right(z) -> w == z - | _, _ -> false - end; -} - -instance Eq Unit { - eq = \ Unit Unit -> true; -} - -instance Eq Location { - eq = \ l1::Location l2::Location -> - -- TODO: We could probably just compare based on filename and index - -- For the moment, though, use line & column instead. - l1.filename == l2.filename && - l1.line == l2.line && - l1.column == l2.column; -} - @{- - Compute the fixed point of a function by repeatedly applying it - until its result remains constant. diff --git a/grammars/silver/core/IO.sv b/grammars/silver/core/IO.sv index 39b803001..f93bc092b 100644 --- a/grammars/silver/core/IO.sv +++ b/grammars/silver/core/IO.sv @@ -65,6 +65,13 @@ instance Bind IO { instance Monad IO {} +instance MonadFail IO { + fail = \ msg::String -> do { + eprintln(msg); + exit(1); + }; +} + instance MonadFix IO { mfix = fixIO; } diff --git a/grammars/silver/core/IOMisc.sv b/grammars/silver/core/IOMisc.sv index 0070c58b9..92bc2da96 100644 --- a/grammars/silver/core/IOMisc.sv +++ b/grammars/silver/core/IOMisc.sv @@ -107,8 +107,8 @@ String ::= filePath::String function splitFileNameAndExtension Pair ::= filePath::String { - return if indexOfLastDot == -1 then pair(filePath, "") - else pair(substring(0, indexOfLastDot, filePath) , + return if indexOfLastDot == -1 then (filePath, "") + else (substring(0, indexOfLastDot, filePath) , substring(indexOfLastDot+1, length(filePath), filePath)); local attribute indexOfLastDot :: Integer; diff --git a/grammars/silver/core/IOToken.sv b/grammars/silver/core/IOToken.sv index 2c0d87227..af65a9b54 100644 --- a/grammars/silver/core/IOToken.sv +++ b/grammars/silver/core/IOToken.sv @@ -21,7 +21,7 @@ synthesized attribute iovalue :: a; - - @param a The type of value returned by the IO action. -} -nonterminal IOVal with io, iovalue; +data nonterminal IOVal with io, iovalue; type ByteArray foreign = "byte[]"; diff --git a/grammars/silver/core/List.sv b/grammars/silver/core/List.sv index 746e448a6..f5fa65296 100644 --- a/grammars/silver/core/List.sv +++ b/grammars/silver/core/List.sv @@ -1,5 +1,29 @@ grammar silver:core; +instance Eq a => Eq [a] { + eq = \ x::[a] y::[a] -> + case x, y of + | h1::t1, h2::t2 -> h1 == h2 && t1 == t2 + | [], [] -> true + | _, _ -> false + end; + neq = \ x::[a] y::[a] -> + case x, y of + | h1::t1, h2::t2 -> h1 != h2 || t1 != t2 + | [], [] -> false + | _, _ -> true + end; +} + +instance Ord a => Ord [a] { + lte = \ x::[a] y::[a] -> + case x, y of + | h1::t1, h2::t2 -> if h1 == h2 then t1 <= t2 else h1 < h2 + | [], _ -> true + | _, _ -> false + end; +} + instance Functor [] { map = \ f::(b ::= a) l::[a] -> if null(l) then [] @@ -172,6 +196,29 @@ function filter else filter(f, tail(lst)); } +@{-- + - Monadic (actually Applicative) version of filter + - + - @param f The filter function + - @param lst The input list to filter + - @return Only those elements of 'lst' that 'f' returns true for, in the + - same order as they appeared in 'lst' + -} +function filterM +Applicative m => +m<[a]> ::= f::(m ::= a) lst::[a] +{ + return + case lst of + | [] -> pure([]) + | h :: t -> do { + cond::Boolean <- f(h); + rest::[a] <- filterM(f, t); + return if cond then h :: rest else rest; + } + end; +} + @{-- - Partition a list in two - @@ -185,10 +232,10 @@ Pair<[a] [a]> ::= f::(Boolean ::= a) lst::[a] local attribute recurse :: Pair<[a] [a]>; recurse = partition(f, tail(lst)); - return if null(lst) then pair([],[]) + return if null(lst) then ([],[]) else if f(head(lst)) - then pair(head(lst) :: recurse.fst, recurse.snd) - else pair(recurse.fst, head(lst) :: recurse.snd); + then (head(lst) :: recurse.fst, recurse.snd) + else (recurse.fst, head(lst) :: recurse.snd); } @{-- @@ -400,6 +447,43 @@ function zipWith else f(head(l1), head(l2)) :: zipWith(f, tail(l1), tail(l2)); } +function unzipWith +[c] ::= f::(c ::= a b) l::[(a, b)] +{ + return if null(l) then [] + else f(head(l).1, head(l).2) :: unzipWith(f, tail(l)); +} + +function zip +[(a, b)] ::= l1::[a] l2::[b] +{ + return if null(l1) || null(l2) then [] + else (head(l1), head(l2)) :: zip(tail(l1), tail(l2)); +} + +function unzip +([a], [b]) ::= l::[(a, b)] +{ + local rest::([a], [b]) = unzip(tail(l)); + return if null(l) then ([], []) + else (head(l).1 :: rest.1, head(l).2 :: rest.2); +} + +function zip3 +[(a, b, c)] ::= l1::[a] l2::[b] l3::[c] +{ + return if null(l1) || null(l2) || null(l3) then [] + else (head(l1), head(l2), head(l3)) :: zip3(tail(l1), tail(l2), tail(l3)); +} + +function unzip3 +([a], [b], [c]) ::= l::[(a, b, c)] +{ + local rest::([a], [b], [c]) = unzip3(tail(l)); + return if null(l) then ([], [], []) + else (head(l).1 :: rest.1, head(l).2 :: rest.2, head(l).3 :: rest.3); +} + function reverse [a] ::= lst::[a] { @@ -476,8 +560,8 @@ Pair<[a] [a]> ::= eq::(Boolean ::= a a) f::a l::[a] recurse = groupByHelp(eq, f, tail(l)); return if null(l) || !eq(f, head(l)) - then pair([], l) - else pair(head(l) :: recurse.fst, recurse.snd); + then ([], l) + else (head(l) :: recurse.fst, recurse.snd); } function group diff --git a/grammars/silver/core/Location.sv b/grammars/silver/core/Location.sv index 4de4d6483..ec57d6888 100644 --- a/grammars/silver/core/Location.sv +++ b/grammars/silver/core/Location.sv @@ -5,8 +5,7 @@ annotation location :: Location; @{-- - Data structure storing location information on tree nodes from a parse. -} -nonterminal Location with filename, line, column, endLine, endColumn, index, endIndex, compareTo, isEqual; -propagate compareTo, isEqual on Location; +data nonterminal Location with filename, line, column, endLine, endColumn, index, endIndex; synthesized attribute filename :: String; synthesized attribute line :: Integer; @@ -16,6 +15,24 @@ synthesized attribute endColumn :: Integer; synthesized attribute index :: Integer; synthesized attribute endIndex :: Integer; +instance Eq Location { + eq = \ l1::Location l2::Location -> + -- TODO: We could probably just compare based on filename and index + -- For the moment, though, use line & column instead. + l1.filename == l2.filename && + l1.line == l2.line && + l1.column == l2.column; +} + +instance Ord Location { + lte = \ l1::Location l2::Location -> + -- TODO: We could probably just compare based on filename and index + -- For the moment, though, use line & column instead. + l1.filename < l2.filename || (l1.filename == l2.filename && + (l1.line < l2.line || (l1.line == l2.line && + (l1.column < l2.column)))); +} + @{-- - The main constructor for location information. - diff --git a/grammars/silver/core/Maybe.sv b/grammars/silver/core/Maybe.sv index 084e3d6d1..1bec6ed10 100644 --- a/grammars/silver/core/Maybe.sv +++ b/grammars/silver/core/Maybe.sv @@ -3,21 +3,21 @@ grammar silver:core; synthesized attribute fromJust :: a; synthesized attribute isJust :: Boolean; -nonterminal Maybe with fromJust, isJust; - -abstract production just -top::Maybe ::= v::a -{ - top.fromJust = v; - top.isJust = true; -} - -abstract production nothing -top::Maybe ::= -{ - top.fromJust = error("fromJust accessed on a Maybe that was actually nothing!"); - top.isJust = false; -} +data Maybe + = just a + | nothing + with fromJust, isJust; +derive Eq, Ord on Maybe; + +aspect fromJust on Maybe of +| just(v) -> v +| nothing() -> error("fromJust accessed on a Maybe that was actually nothing!") +end; + +aspect isJust on Maybe of +| just(_) -> true +| nothing() -> false +end; instance Functor Maybe { map = \ f::(b ::= a) m::Maybe -> @@ -83,7 +83,7 @@ instance MonadFix Maybe { - @param m The monad type to be transformed - @param a The optional result type -} -nonterminal MaybeT<(m :: * -> *) a> with run>>; +data nonterminal MaybeT<(m :: * -> *) a> with run>>; abstract production maybeT top::MaybeT ::= x::m> { diff --git a/grammars/silver/core/Ord.sv b/grammars/silver/core/Ord.sv index bdc9fa107..3cf99623f 100644 --- a/grammars/silver/core/Ord.sv +++ b/grammars/silver/core/Ord.sv @@ -238,49 +238,3 @@ Boolean ::= x::TerminalId y::TerminalId } foreign { "java" : return "(%x% >= (int)%y%)"; } - -instance Ord a => Ord [a] { - lte = \ x::[a] y::[a] -> - case x, y of - | h1::t1, h2::t2 -> if h1 == h2 then t1 <= t2 else h1 < h2 - | [], _ -> true - | _, _ -> false - end; -} - -instance Ord a => Ord Maybe { - lte = \ x::Maybe y::Maybe -> - case x, y of - | just(w), just(z) -> w <= z - | nothing(), _ -> true - | _, _ -> false - end; -} - -instance Ord a, Ord b => Ord Pair { - lte = \ x::Pair y::Pair -> x.fst <= y.fst && x.snd <= y.snd; -} - -instance Ord a, Ord b => Ord Either { - compare = \ x::Either y::Either -> - case x, y of - | left(w), left(z) -> compare(w, z) - | left(_), right(_) -> -1 - | right(_), left(_) -> 1 - | right(w), right(z) -> compare(w, z) - end; -} - -instance Ord Unit { - compare = \ Unit Unit -> 0; -} - -instance Ord Location { - lte = \ l1::Location l2::Location -> - -- TODO: We could probably just compare based on filename and index - -- For the moment, though, use line & column instead. - l1.filename < l2.filename || (l1.filename == l2.filename && - (l1.line < l2.line || (l1.line == l2.line && - (l1.column < l2.column)))); -} - diff --git a/grammars/silver/core/Origins.sv b/grammars/silver/core/Origins.sv index dc7455fd4..7e9d08c9a 100644 --- a/grammars/silver/core/Origins.sv +++ b/grammars/silver/core/Origins.sv @@ -4,9 +4,9 @@ grammar silver:core; -- Don't change their names, grammar locations, or parameters unless you know what your doing -- (and have made the appropriate runtime and compiler changes!) -nonterminal OriginInfo; -nonterminal OriginInfoType; -nonterminal OriginNote; +data nonterminal OriginInfo; +data nonterminal OriginInfoType; +data nonterminal OriginNote; synthesized attribute notepp :: String occurs on OriginNote; @@ -340,7 +340,7 @@ Maybe ::= arg::OriginInfo "java" : return "common.OriginsUtil.getOriginLink(%arg%)"; } -closed tracked nonterminal AmbientOriginNT; +closed tracked data nonterminal AmbientOriginNT; @{- Useful for accessing the "ambient" origin, i.e., what origin does a created node get? Create one and find out! -} abstract production ambientOrigin diff --git a/grammars/silver/core/Pair.sv b/grammars/silver/core/Pair.sv index 5b472f618..b0e6ce0bb 100644 --- a/grammars/silver/core/Pair.sv +++ b/grammars/silver/core/Pair.sv @@ -1,19 +1,14 @@ grammar silver:core; -synthesized attribute fst :: a; -synthesized attribute snd :: a; +annotation fst :: a; +annotation snd :: a; @{-- - The basic product type, counterpart to Either. -} -nonterminal Pair with fst, snd; - -abstract production pair -top::Pair ::= f::a s::b -{ - top.fst = f; - top.snd = s; -} +data Pair = pair + with fst, snd; +derive Eq, Ord on Pair; function fst a ::= p::Pair @@ -76,7 +71,7 @@ Eq a => [b] ::= elem::a lst::[Pair] @{-- - Decomposes a list of pairs into a pair of lists. - - - unzipPairs(zipWith(pair, lst)) == lst + - unzipPairs(zip(lst)) == lst - - @param lst A list to decompose into two lists. -} @@ -85,8 +80,8 @@ Pair<[a] [b]> ::= lst::[Pair] { local recurse :: Pair<[a] [b]> = unzipPairs(tail(lst)); - return if null(lst) then pair([], []) - else pair(head(lst).fst :: recurse.fst, head(lst).snd :: recurse.snd); + return if null(lst) then ([], []) + else (head(lst).fst :: recurse.fst, head(lst).snd :: recurse.snd); } diff --git a/grammars/silver/core/ParseResult.sv b/grammars/silver/core/ParseResult.sv index a2b3096e2..fcf445c79 100644 --- a/grammars/silver/core/ParseResult.sv +++ b/grammars/silver/core/ParseResult.sv @@ -30,7 +30,7 @@ synthesized attribute parseTerminals :: [TerminalDescriptor]; - - @param a The start nonterminal type. -} -nonterminal ParseResult with parseSuccess, parseError, parseErrors, parseTree, parseTerminals; +data nonterminal ParseResult with parseSuccess, parseError, parseErrors, parseTree, parseTerminals; @{-- - Parse failure constructor. @@ -84,7 +84,7 @@ a ::= pr::ParseResult @{-- - Representation of a parser error. -} -nonterminal ParseError with parseErrors; +data nonterminal ParseError with parseErrors; @{-- - This production as currently designed matches up exactly with what copper raises in its syntax error exception. diff --git a/grammars/silver/core/Random.sv b/grammars/silver/core/Random.sv index 959e0e168..fbada8a68 100644 --- a/grammars/silver/core/Random.sv +++ b/grammars/silver/core/Random.sv @@ -3,28 +3,11 @@ grammar silver:core; -- Monad for computations involving random number generation. -- This must live in silver:core because the runtime depends on these productions. -- Associated utilities are defined in silver:util:random. -nonterminal RandomGen; - --- Pure random "token" for use with threaded attributes, represented as just a seed value. --- Unlike IOToken, this is essentially safe to reuse, besides the possibility of --- repeating random values. -type RandomToken foreign = "Long"; - -production mapRandomGen -top::RandomGen ::= (b ::= a) RandomGen -{} - -production apRandomGen -top::RandomGen ::= RandomGen<(b ::= a)> RandomGen -{} - -production pureRandomGen -top::RandomGen ::= a -{} - -production bindRandomGen -top::RandomGen ::= RandomGen (RandomGen ::= a) -{} +data RandomGen + = mapRandomGen (a ::= b) RandomGen + | apRandomGen RandomGen<(a ::= b)> RandomGen + | pureRandomGen a + | bindRandomGen RandomGen (RandomGen ::= b); production randomInteger top::RandomGen ::= @@ -46,6 +29,11 @@ production randomToken_ top::RandomGen ::= {} +-- Pure random "token" for use with threaded attributes, represented as just a seed value. +-- Unlike IOToken, this is essentially safe to reuse, besides the possibility of +-- repeating random values. +type RandomToken foreign = "Long"; + instance Functor RandomGen { map = mapRandomGen; } diff --git a/grammars/silver/core/Semiring.sv b/grammars/silver/core/Semiring.sv index 0c5bab98a..0e938c637 100644 --- a/grammars/silver/core/Semiring.sv +++ b/grammars/silver/core/Semiring.sv @@ -50,3 +50,9 @@ Semiring a => a ::= n::Integer else add(add(fromN2, one), fromN2); } + +@{- Compute the sum of a list. -} +global sum :: Semiring a => (a ::= [a]) = foldr(add, zero, _); + +@{- Compute the product of a list. -} +global product :: Semiring a => (a ::= [a]) = foldr(mul, one, _); diff --git a/grammars/silver/core/State.sv b/grammars/silver/core/State.sv index 103a56e4c..6fad828e6 100644 --- a/grammars/silver/core/State.sv +++ b/grammars/silver/core/State.sv @@ -80,7 +80,7 @@ function runState Pair ::= st::State initialState::s { st.stateIn = initialState; - return pair(st.stateOut, st.stateVal); + return (st.stateOut, st.stateVal); } function evalState diff --git a/grammars/silver/core/TerminalDescriptor.sv b/grammars/silver/core/TerminalDescriptor.sv index 925789b64..f3fa61f72 100644 --- a/grammars/silver/core/TerminalDescriptor.sv +++ b/grammars/silver/core/TerminalDescriptor.sv @@ -1,18 +1,10 @@ grammar silver:core; -synthesized attribute lexeme :: String; -synthesized attribute lexerClasses :: [String]; -synthesized attribute terminalLocation :: Location; -synthesized attribute terminalName :: String; +annotation lexeme :: String; +annotation lexerClasses :: [String]; +annotation terminalLocation :: Location; +annotation terminalName :: String; -nonterminal TerminalDescriptor with lexeme, lexerClasses, terminalLocation, terminalName, compareTo, isEqual; -propagate compareTo, isEqual on TerminalDescriptor; - -abstract production terminalDescriptor -top::TerminalDescriptor ::= lexeme::String lexerClasses::[String] terminalName::String terminalLocation::Location -{ - top.lexeme = lexeme; - top.lexerClasses = lexerClasses; - top.terminalLocation = terminalLocation; - top.terminalName = terminalName; -} +data TerminalDescriptor = terminalDescriptor + with lexeme, lexerClasses, terminalLocation, terminalName; +derive Eq on TerminalDescriptor; diff --git a/grammars/silver/core/Undecorate.sv b/grammars/silver/core/Undecorate.sv index 76ea32594..bdc346fa4 100644 --- a/grammars/silver/core/Undecorate.sv +++ b/grammars/silver/core/Undecorate.sv @@ -1,5 +1,11 @@ grammar silver:core; +@{- + - Undecorate a reference. + - + - @param x The reference to undecorate. + - @return A new, undecorated term coresponding to x. + -} function new a ::= x::Decorated a with i { return error("foreign function"); } @@ -7,16 +13,45 @@ foreign { "java": return "common.OriginsUtil.duplicatePoly(%x%.undecorate(), originCtx)"; } -function newPartial -a ::= x::PartiallyDecorated a with i +@{- + - Undecorate a unique reference. + - + - @param x The reference to undecorate. + - @return A new, undecorated term coresponding to x. + -} +function newUnique +a ::= x::Decorated! a with i { return error("foreign function"); } foreign { "java": return "common.OriginsUtil.duplicatePoly(%x%.undecorate(), originCtx)"; } +@{- + - Type-safe cast of one decorated type into one with a smaller reference set. + - + - @param x The reference to cast. + - @return x, with a type that has a different reference set. + -} function castRef i1 subset i2 => Decorated a with i1 ::= x::Decorated a with i2 { return error("foreign function"); } foreign { "java": return "%x%"; } + +@{- + - Given a decorated tree, return the underlying term that was decorated to create it, + - without copying or applying any transformations. + - This is unsafe as it constitutes a hole in the uniqueness analysis, and should not + - be used outside of debugging and internally within Silver in the implementation of + - annotation accesses; use new if you want to undecorate a term. + - + - @param x The reference to undecorate. + - @return The term that was decorated to produce x. + -} +function getTermThatWasDecorated +a ::= x::Decorated a with i +{ return error("foreign function"); } +foreign { + "java": return "%x%.getNode()"; +} diff --git a/grammars/silver/core/Unit.sv b/grammars/silver/core/Unit.sv index dc59f1e92..3938f11ca 100644 --- a/grammars/silver/core/Unit.sv +++ b/grammars/silver/core/Unit.sv @@ -1,7 +1,4 @@ grammar silver:core; -nonterminal Unit; - -abstract production unit -top::Unit ::= -{} \ No newline at end of file +data Unit = unit; +derive Eq, Ord on Unit; diff --git a/grammars/silver/langutil/Message.sv b/grammars/silver/langutil/Message.sv index 7d380edc7..012fc3d10 100644 --- a/grammars/silver/langutil/Message.sv +++ b/grammars/silver/langutil/Message.sv @@ -9,7 +9,7 @@ grammar silver:langutil; @{-- - A Message represents a compiler output message (error/warning) -} -tracked nonterminal Message with message, where, noLocOutput, output, severity; +closed tracked data nonterminal Message with message, where, noLocOutput, output, severity; @{-- - The location of an error message. @@ -34,12 +34,19 @@ synthesized attribute noLocOutput :: String; @{-- - A convention for determining message severity. - err=2, wrn=1, info=0 + - TODO: Consider making this a custom datatype. -} synthesized attribute severity :: Integer; aspect default production top::Message ::= { + top.noLocOutput = + case top.severity of + | 0 -> "info" + | 1 -> "warning" + | _ -> "error" + end ++ ": " ++ top.message; top.output = s"${top.where.unparse}: ${top.noLocOutput}"; } @@ -52,7 +59,6 @@ top::Message ::= l::Location m::String { top.where = l; top.message = m; - top.noLocOutput = s"error: ${m}"; top.severity = 2; } @@ -71,7 +77,6 @@ top::Message ::= l::Location m::String { top.where = l; top.message = m; - top.noLocOutput = s"warning: ${m}"; top.severity = 1; } @@ -90,7 +95,6 @@ top::Message ::= l::Location m::String { top.where = l; top.message = m; - top.noLocOutput = s"info: ${m}"; top.severity = 0; } @@ -117,20 +121,12 @@ top::Message ::= l::Location m::String others::[Message] @{-- - Determines if a list has any errors (or, optionally, warnings, too) - - Note: user extended messages that forward to err or wrn will have - - the same effect, and unknown completely messages will be skipped as - - though they do not exist. -} function containsErrors Boolean ::= l::[Message] wError::Boolean { - return case l of - | [] -> false - | err(_,_) :: _ -> true - | wrn(_,_) :: t -> if wError then true else containsErrors(t, false) - | nested(_, _, e) :: t -> containsErrors(e, wError) || containsErrors(t, wError) - | _ :: t -> containsErrors(t, wError) - end; + local errSeverity::Integer = if wError then 1 else 2; + return any(map(\ m::Message -> m.severity >= errSeverity, l)); } @{-- diff --git a/grammars/silver/langutil/pp/Document.sv b/grammars/silver/langutil/pp/Document.sv index a79c669f4..267f1ce52 100644 --- a/grammars/silver/langutil/pp/Document.sv +++ b/grammars/silver/langutil/pp/Document.sv @@ -150,8 +150,10 @@ nonterminal Document with indent, width, result, horizontals, compareTo, isEqual; -autocopy attribute indent :: Integer; -autocopy attribute width :: Integer; +inherited attribute indent :: Integer; +inherited attribute width :: Integer; +propagate indent on Document excluding box; +propagate width on Document; -- The scanning process inherited attribute inPosition :: Integer; @@ -301,9 +303,19 @@ top::Document ::= abstract production box top::Document ::= d::Document { - forwards to d; -- top.inPosition doesn't represent our horizontal position in actual printing - forward.indent = top.width - top.inRemaining; + d.inPosition = top.inPosition; + d.inDq = top.inDq; + d.inCHorizontals = top.inCHorizontals; + d.inRemaining = top.inRemaining; + d.indent = top.width - top.inRemaining; + + top.outPosition = d.outPosition; + top.outDq = d.outDq; + top.outCHorizontals = d.outCHorizontals; + top.outRemaining = d.outRemaining; + top.result = d.result; + top.horizontals = d.horizontals; } abstract production realLine @@ -324,11 +336,11 @@ top::Document ::= function prune Pair> [Boolean]> ::= p::Integer q::dq:Deque> { - return if dq:isEmpty(q) then pair(q, []) + return if dq:isEmpty(q) then (q, []) else let h::Pair = dq:head(q) - in if p <= h.fst then pair(q, []) + in if p <= h.fst then (q, []) else let recur::Pair> [Boolean]> = prune(p, dq:tail(q)) - in pair(recur.fst, false :: (h.snd ++ recur.snd)) + in (recur.fst, false :: (h.snd ++ recur.snd)) end end; } @@ -336,19 +348,19 @@ Pair> [Boolean]> ::= p::Integer q::dq:Deque> ::= p::Integer q::dq:Deque> { - return dq:snoc(q, pair(p, [])); + return dq:snoc(q, (p, [])); } function leave Pair> [Boolean]> ::= p::Integer q::dq:Deque> { - return if dq:isEmpty(q) then pair(q, []) + return if dq:isEmpty(q) then (q, []) else let h1::Pair = dq:last(q), t1::dq:Deque> = dq:init(q) - in if dq:isEmpty(t1) then pair(t1, true :: h1.snd) + in if dq:isEmpty(t1) then (t1, true :: h1.snd) else let h2::Pair = dq:last(t1), t2::dq:Deque> = dq:init(t1) - in pair(dq:snoc(t2, pair(h2.fst, h2.snd ++ [p <= h1.fst] ++ h1.snd)), []) + in (dq:snoc(t2, (h2.fst, h2.snd ++ [p <= h1.fst] ++ h1.snd)), []) end end; } diff --git a/grammars/silver/reflect/AST.sv b/grammars/silver/reflect/AST.sv index 47e40c6a5..883166668 100644 --- a/grammars/silver/reflect/AST.sv +++ b/grammars/silver/reflect/AST.sv @@ -21,7 +21,7 @@ top::AST ::= terminalName::String lexeme::String location::Location { top.serialize = do { - locationSerialize::String <- serialize(new(location)); + locationSerialize::String <- serialize(location); return s"terminal(${terminalName}, \"${escapeString(lexeme)}\", ${locationSerialize})"; }; } diff --git a/grammars/silver/rewrite/AST.sv b/grammars/silver/rewrite/AST.sv index 7a29220fe..294cfb9be 100644 --- a/grammars/silver/rewrite/AST.sv +++ b/grammars/silver/rewrite/AST.sv @@ -2,14 +2,14 @@ grammar silver:rewrite; exports silver:reflect; -- Needed by the extension, so just export it here. -autocopy attribute givenStrategy::Strategy occurs on AST, ASTs, NamedASTs, NamedAST; +inherited attribute givenStrategy::Strategy occurs on AST, ASTs, NamedASTs, NamedAST; synthesized attribute allResult::Maybe; synthesized attribute someResult::Maybe; synthesized attribute oneResult::Maybe; inherited attribute productionName::String occurs on AST; -autocopy attribute childStrategies::[Strategy] occurs on AST, ASTs; -autocopy attribute annotationStrategies::[Pair] occurs on AST, NamedASTs, NamedAST; +inherited attribute childStrategies::[Strategy] occurs on AST, ASTs; +inherited attribute annotationStrategies::[Pair] occurs on AST, NamedASTs, NamedAST; synthesized attribute traversalResult::Maybe; inherited attribute headStrategy::Strategy occurs on AST; inherited attribute tailStrategy::Strategy occurs on AST; @@ -21,6 +21,8 @@ attribute someResult occurs on AST; attribute oneResult occurs on AST; attribute traversalResult occurs on AST; +propagate givenStrategy on AST, ASTs, NamedASTs, NamedAST; + aspect default production top::AST ::= { @@ -59,6 +61,8 @@ top::AST ::= prodName::String children::ASTs annotations::NamedASTs just(nonterminalAST(prodName, children, annotationsResult)) | nothing(), nothing() -> nothing() end; + children.childStrategies = top.childStrategies; + annotations.annotationStrategies = top.annotationStrategies; top.traversalResult = do { if prodName != top.productionName then nothing() else just(unit()); @@ -216,6 +220,7 @@ top::NamedASTs ::= h::NamedAST t::NamedASTs | nothing(), just(tResult) -> just(consNamedAST(h, tResult)) | nothing(), nothing() -> nothing() end; + propagate annotationStrategies; top.traversalResult = do { hResult::NamedAST <- h.traversalResult; @@ -244,7 +249,7 @@ attribute traversalResult occurs on NamedAST; aspect production namedAST top::NamedAST ::= n::String v::AST { - top.binding = pair(n, v); + top.binding = (n, v); top.allResult = do { vResult::AST <- decorate top.givenStrategy with { term = v; }.result; diff --git a/grammars/silver/rewrite/ASTExpr.sv b/grammars/silver/rewrite/ASTExpr.sv index 6f65a9a70..48ccbcae9 100644 --- a/grammars/silver/rewrite/ASTExpr.sv +++ b/grammars/silver/rewrite/ASTExpr.sv @@ -3,10 +3,11 @@ grammar silver:rewrite; imports silver:langutil; imports silver:langutil:pp; -autocopy attribute substitutionEnv::[Pair]; +inherited attribute substitutionEnv::[Pair]; synthesized attribute value::AST; nonterminal ASTExpr with pp, substitutionEnv, value; +propagate substitutionEnv on ASTExpr excluding letASTExpr, matchASTExpr; -- AST constructors abstract production prodCallASTExpr @@ -348,8 +349,9 @@ top::ASTExpr ::= a::NamedASTExprs body::ASTExpr { top.pp = pp"let ${ppImplode(pp", ", a.pps)} in ${body.pp} end"; top.value = body.value; + a.substitutionEnv = top.substitutionEnv; body.substitutionEnv = - map(\ n::NamedAST -> case n of namedAST(n, a) -> pair(n, a) end, a.namedValues) ++ top.substitutionEnv; + map(\ n::NamedAST -> case n of namedAST(n, a) -> (n, a) end, a.namedValues) ++ top.substitutionEnv; } abstract production lengthASTExpr @@ -426,8 +428,10 @@ top::ASTExpr ::= e::ASTExpr pattern::ASTPattern res::ASTExpr fail::ASTExpr { top.pp = pp"case ${e.pp} of ${pattern.pp} -> ${res.pp} | _ -> ${fail.pp} end"; + e.substitutionEnv = top.substitutionEnv; pattern.matchWith = e.value; res.substitutionEnv = pattern.substitution.fromJust ++ top.substitutionEnv; + fail.substitutionEnv = top.substitutionEnv; top.value = if pattern.substitution.isJust then res.value else fail.value; } @@ -451,6 +455,7 @@ synthesized attribute values::[AST]; synthesized attribute appValues::[Maybe]; nonterminal ASTExprs with pps, astExprs, substitutionEnv, values, appValues; +propagate substitutionEnv on ASTExprs; abstract production consASTExpr top::ASTExprs ::= h::ASTExpr t::ASTExprs @@ -488,6 +493,7 @@ synthesized attribute namedValues::[NamedAST]; synthesized attribute namedAppValues::[Pair>]; nonterminal NamedASTExprs with pps, substitutionEnv, namedValues, namedAppValues; +propagate substitutionEnv on NamedASTExprs; abstract production consNamedASTExpr top::NamedASTExprs ::= h::NamedASTExpr t::NamedASTExprs @@ -519,6 +525,7 @@ synthesized attribute namedValue::NamedAST; synthesized attribute namedAppValue::Pair>; nonterminal NamedASTExpr with pp, substitutionEnv, namedValue, namedAppValue; +propagate substitutionEnv on NamedASTExpr; abstract production namedASTExpr top::NamedASTExpr ::= n::String v::ASTExpr @@ -526,7 +533,7 @@ top::NamedASTExpr ::= n::String v::ASTExpr top.pp = pp"${text(n)}=${v.pp}"; top.namedValue = namedAST(n, v.value); top.namedAppValue = - pair( + ( last(explode(":", n)), case v of | missingArgASTExpr() -> nothing() diff --git a/grammars/silver/rewrite/ASTPattern.sv b/grammars/silver/rewrite/ASTPattern.sv index 63ceb607d..789122c3b 100644 --- a/grammars/silver/rewrite/ASTPattern.sv +++ b/grammars/silver/rewrite/ASTPattern.sv @@ -112,7 +112,7 @@ abstract production varASTPattern top::ASTPattern ::= n::String { top.pp = text(n); - top.substitution = just([pair(n, top.matchWith)]); + top.substitution = just([(n, top.matchWith)]); } abstract production wildASTPattern diff --git a/grammars/silver/util/random/Arbitrary.sv b/grammars/silver/util/random/Arbitrary.sv index 3cdd27ce3..0559f7b6d 100644 --- a/grammars/silver/util/random/Arbitrary.sv +++ b/grammars/silver/util/random/Arbitrary.sv @@ -37,7 +37,7 @@ instance Arbitrary Location { } instance Arbitrary a, Arbitrary b => Arbitrary Pair { - genArb = \ depth::Integer -> lift2(pair, genArb(depth), genArb(depth)); + genArb = \ depth::Integer -> lift2(pair(fst=_, snd=_), genArb(depth), genArb(depth)); } instance Arbitrary a, Arbitrary b => Arbitrary Either { diff --git a/language-server/build.sh b/language-server/build.sh index e5b7fd198..00efbca01 100755 --- a/language-server/build.sh +++ b/language-server/build.sh @@ -12,3 +12,4 @@ mvn install:install-file -Dfile=../jars/silver.compiler.composed.Default.jar -Dg mvn package +cp launcher/target/launcher.jar ../jars/silver-langserver-launcher.jar diff --git a/language-server/langserver/src/main/java/edu/umn/cs/melt/silver/langserver/SilverCompiler.java b/language-server/langserver/src/main/java/edu/umn/cs/melt/silver/langserver/SilverCompiler.java new file mode 100644 index 000000000..2ed6a4325 --- /dev/null +++ b/language-server/langserver/src/main/java/edu/umn/cs/melt/silver/langserver/SilverCompiler.java @@ -0,0 +1,168 @@ +package edu.umn.cs.melt.silver.langserver; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; + +import org.eclipse.lsp4j.Diagnostic; + +import common.ConsCell; +import common.DecoratedNode; +import common.OriginContext; +import common.StringCatter; +import common.javainterop.ConsCellCollection; +import edu.umn.cs.melt.lsp4jutil.CopperParserNodeFactory; +import edu.umn.cs.melt.lsp4jutil.Util; +import silver.compiler.driver.PbuildRun; +import silver.compiler.driver.PparseArgsOrError; +import silver.compiler.driver.util.NBuildEnv; +import silver.compiler.driver.util.PbuildEnv; +import silver.compiler.driver.util.PwriteInterface; +import silver.compiler.langserver.PfindDeclLocation; +import silver.compiler.langserver.PfindReferences; +import silver.core.NLocation; +import silver.core.NPair; +import silver.core.PunsafeEvalIO; + +/** + * Abstraction over the Silver compiler, to perform builds and query information from the most recent build. + * + * @author krame505 + */ +public class SilverCompiler { + private DecoratedNode comp = null; + private String silverGen; + private String stdLibGrammarsDir; + + private SilverCompiler() { + try { + silverGen = Files.createTempDirectory("silver_generated").toString() + "/"; + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static SilverCompiler instance; + public static SilverCompiler getInstance() { + if (instance == null) { + instance = new SilverCompiler(); + } + return instance; + } + + public void setStdLibGrammarsDir(Path stdLibGrammars) { + this.stdLibGrammarsDir = stdLibGrammars.toString() + "/"; + } + + public void build( + CopperParserNodeFactory parserFn, Collection grammarDirs, Collection buildGrammars, + boolean cleanBuild, boolean enableMWDA, BiConsumer> reportDiagnostics) { + System.err.println("Building"); + String silverHome = ""; // Not needed since we aren't doing translation + List args = new ArrayList<>(); + List grammarPath = new ArrayList<>(grammarDirs); + List silverHostGen = List.of(silverGen); + + if (stdLibGrammarsDir == null) { + throw new IllegalStateException("Silver host grammars path not set"); + } + + if (enableMWDA) { + System.err.println("MWDA enabled"); + args.add("--warn-all"); + } + + // Clean build if requested + if (cleanBuild) { + System.err.println("Clean build"); + args.add("--clean"); + } + + // Add the silver resource grammars to the end of the grammar path, + // so if silver is in the workspace we will find it there first. + grammarPath.add(stdLibGrammarsDir); + + // Set up the build environment + NBuildEnv benv = new PbuildEnv( + new StringCatter(silverHome), + new StringCatter(silverGen), + ConsCellCollection.fromStringList(grammarPath), + ConsCellCollection.fromStringList(silverHostGen) + ); + DecoratedNode a = PparseArgsOrError.invoke(OriginContext.FFI_CONTEXT, ConsCellCollection.fromStringList(args)); + + // Build! + DecoratedNode comp = (DecoratedNode)PunsafeEvalIO.invoke(OriginContext.FFI_CONTEXT, + PbuildRun.invoke(OriginContext.FFI_CONTEXT, + parserFn, a, benv, + ConsCellCollection.fromIterator(buildGrammars.stream().map(StringCatter::new).iterator()))); + + // Note that we must demand allGrammars from comp before demanding + // recompiledGrammars to ensure that IO happens properly, + // due to the circularity in the driver involving unsafeInterleaveIO. + Collection allGrammars = new ConsCellCollection<>( + comp.synthesized(silver.compiler.driver.util.Init.silver_compiler_driver_util_allGrammars__ON__silver_compiler_driver_util_Compilation)); + Collection recompiledGrammars = new ConsCellCollection<>( + comp.synthesized(silver.compiler.driver.util.Init.silver_compiler_driver_util_recompiledGrammars__ON__silver_compiler_driver_util_Compilation)); + + // Check that we built all triggered grammars. + Set builtGrammars = allGrammars.stream() + .map(r -> r.synthesized(silver.compiler.driver.util.Init.silver_compiler_definition_env_declaredName__ON__silver_compiler_driver_util_RootSpec).toString()) + .collect(Collectors.toSet()); + for (String grammar : buildGrammars) { + if (!builtGrammars.contains(grammar)) { + System.err.println("Failed to find triggered grammar " + grammar); + } + } + + // Report diagnostics + System.err.println("Reporting diagnostics"); + for (DecoratedNode r : allGrammars) { + String grammarSource = + r.synthesized(silver.compiler.driver.util.Init.silver_compiler_definition_env_grammarSource__ON__silver_compiler_driver_util_RootSpec).toString(); + + Collection allFileErrors = new ConsCellCollection<>( + r.synthesized(silver.compiler.driver.util.Init.silver_compiler_definition_core_allFileErrors__ON__silver_compiler_driver_util_RootSpec)); + for (NPair fileErrors : allFileErrors) { + String fileName = fileErrors.getAnno_silver_core_fst().toString(); + ConsCell messages = (ConsCell)fileErrors.getAnno_silver_core_snd(); + String uri = "file://" + grammarSource + fileName; + + // System.err.println("Reporting diagnostics for " + grammarSource + fileName); + reportDiagnostics.accept(uri, Util.messagesToDiagnostics(messages, uri)); + } + } + + // Write updated interface files + System.err.println("Writing interface files"); + for (DecoratedNode r : recompiledGrammars) { + PunsafeEvalIO.invoke(OriginContext.FFI_CONTEXT, + PwriteInterface.invoke(OriginContext.FFI_CONTEXT, new StringCatter(silverGen), r)); + } + + // Only update the compilation result once we are done reporting errors, to avoid race conditions from other attributes being demanded + this.comp = comp; + } + + public Collection getDeclaration(String fileName, int line, int col) { + if (comp == null) { + return List.of(); + } + return new ConsCellCollection( + PfindDeclLocation.invoke(OriginContext.FFI_CONTEXT, new StringCatter(fileName), line, col, comp)); + } + + public Collection getReferences(String fileName, int line, int col) { + if (comp == null) { + return List.of(); + } + return new ConsCellCollection( + PfindReferences.invoke(OriginContext.FFI_CONTEXT, new StringCatter(fileName), line, col, comp)); + } +} diff --git a/language-server/langserver/src/main/java/edu/umn/cs/melt/silver/langserver/SilverLanguageServer.java b/language-server/langserver/src/main/java/edu/umn/cs/melt/silver/langserver/SilverLanguageServer.java index 03bb03d93..ccd516c63 100644 --- a/language-server/langserver/src/main/java/edu/umn/cs/melt/silver/langserver/SilverLanguageServer.java +++ b/language-server/langserver/src/main/java/edu/umn/cs/melt/silver/langserver/SilverLanguageServer.java @@ -14,6 +14,8 @@ import org.eclipse.lsp4j.FileOperationsServerCapabilities; import org.eclipse.lsp4j.InitializeParams; import org.eclipse.lsp4j.InitializeResult; +import org.eclipse.lsp4j.MessageParams; +import org.eclipse.lsp4j.MessageType; import org.eclipse.lsp4j.SemanticTokensLegend; import org.eclipse.lsp4j.SemanticTokensServerFull; import org.eclipse.lsp4j.SemanticTokensWithRegistrationOptions; @@ -26,10 +28,14 @@ import org.eclipse.lsp4j.services.TextDocumentService; import org.eclipse.lsp4j.services.WorkspaceService; +import com.google.gson.JsonObject; + import edu.umn.cs.melt.lsp4jutil.Util; +import silver.compiler.definition.core.NRoot; public class SilverLanguageServer implements LanguageServer, LanguageClientAware { private SilverLanguageService service; + private LanguageClient client; private int errorCode = 1; public SilverLanguageServer() { @@ -38,13 +44,47 @@ public SilverLanguageServer() { @Override public CompletableFuture initialize(InitializeParams initializeParams) { + System.err.println("Initializing Silver language server"); + + // Initialize the Silver runtime common.Util.init(); - silver.compiler.composed.Default.Init.initAllStatics(); - silver.compiler.composed.Default.Init.init(); - silver.compiler.composed.Default.Init.postInit(); - System.err.println("Initializing Silver language server"); + // Get the initialization options + String parserName = ""; + try { + JsonObject initOptions = (JsonObject)initializeParams.getInitializationOptions(); + if (initOptions != null) { + if (initOptions.has("parserName")) { + parserName = initOptions.get("parserName").getAsString(); + } + } + } catch(ClassCastException e) { + System.err.println("Got unexpected init options: " + initializeParams.getInitializationOptions()); + } + if (parserName.isEmpty()) { + parserName = "silver:compiler:composed:Default:svParse"; + } + // Initialize the compiler grammars + ClassLoader loader = ClassLoader.getSystemClassLoader(); + try { + // The grammar silver:compiler:langserver contains language server-specific + // compiler utilities, and imports silver:compiler:host. + Util.initGrammar("silver:compiler:langserver", loader); + } catch (SecurityException | ReflectiveOperationException e) { + client.showMessage(new MessageParams(MessageType.Error, "Error loading compiler jar: " + e.toString())); + } + + // Load the specified parser + boolean loadedParser = false; + try { + service.setParserFactory(Util.loadCopperParserFactory(loader, parserName, NRoot.class)); + loadedParser = true; + } catch (SecurityException | ReflectiveOperationException e) { + client.showMessage(new MessageParams(MessageType.Error, "Error loading parser " + parserName + " from jar: " + e.toString())); + } + + // Set up the Silver standard library grammars folder Path silverGrammars; try { silverGrammars = Files.createTempDirectory("silver_grammars"); @@ -52,22 +92,28 @@ public CompletableFuture initialize(InitializeParams initializ } catch (IOException | URISyntaxException e) { throw new RuntimeException(e); } - service.setSilverGrammarsPath(silverGrammars); + SilverCompiler.getInstance().setStdLibGrammarsDir(silverGrammars); - service.setWorkspaceFolders(initializeParams.getWorkspaceFolders()); + // Initialize the project grammars folder(s) + if (initializeParams.getWorkspaceFolders() != null) { + service.setWorkspaceFolders(initializeParams.getWorkspaceFolders()); + } // Set the capabilities of the LS to inform the client. ServerCapabilities capabilities = new ServerCapabilities(); capabilities.setTextDocumentSync(TextDocumentSyncKind.Full); - capabilities.setSemanticTokensProvider( - new SemanticTokensWithRegistrationOptions( - new SemanticTokensLegend( - SilverLanguageService.tokenTypes, SilverLanguageService.tokenModifiers), - new SemanticTokensServerFull(false), false)); + if (loadedParser) { + capabilities.setSemanticTokensProvider( + new SemanticTokensWithRegistrationOptions( + new SemanticTokensLegend( + SilverLanguageService.tokenTypes, SilverLanguageService.tokenModifiers), + new SemanticTokensServerFull(false), false)); + } capabilities.setExecuteCommandProvider(new ExecuteCommandOptions(List.of( "silver.clean" ))); capabilities.setDeclarationProvider(true); + capabilities.setReferencesProvider(true); FileOperationOptions fileOperationOptions = new FileOperationOptions( List.of(new FileOperationFilter(new FileOperationPattern("**/*.{sv,ag,sv.md,ag.md}"))) @@ -111,6 +157,7 @@ public WorkspaceService getWorkspaceService() { @Override public void connect(LanguageClient languageClient) { + this.client = languageClient; service.setClient(languageClient); } } diff --git a/language-server/langserver/src/main/java/edu/umn/cs/melt/silver/langserver/SilverLanguageService.java b/language-server/langserver/src/main/java/edu/umn/cs/melt/silver/langserver/SilverLanguageService.java index b3e51d37b..48d2a6c1f 100644 --- a/language-server/langserver/src/main/java/edu/umn/cs/melt/silver/langserver/SilverLanguageService.java +++ b/language-server/langserver/src/main/java/edu/umn/cs/melt/silver/langserver/SilverLanguageService.java @@ -1,17 +1,10 @@ package edu.umn.cs.melt.silver.langserver; import java.io.File; -import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.FileTime; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -29,6 +22,7 @@ import org.eclipse.lsp4j.CreateFilesParams; import org.eclipse.lsp4j.DeclarationParams; import org.eclipse.lsp4j.DeleteFilesParams; +import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.DidChangeConfigurationParams; import org.eclipse.lsp4j.DidChangeTextDocumentParams; import org.eclipse.lsp4j.DidChangeWatchedFilesParams; @@ -39,11 +33,10 @@ import org.eclipse.lsp4j.FileCreate; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.LocationLink; -import org.eclipse.lsp4j.MessageParams; -import org.eclipse.lsp4j.MessageType; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.ReferenceParams; import org.eclipse.lsp4j.RenameFilesParams; import org.eclipse.lsp4j.SemanticTokens; import org.eclipse.lsp4j.SemanticTokensParams; @@ -57,28 +50,14 @@ import org.eclipse.lsp4j.services.TextDocumentService; import org.eclipse.lsp4j.services.WorkspaceService; +import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; -import common.ConsCell; -import common.DecoratedNode; -import common.OriginContext; import common.SilverCopperParser; -import common.StringCatter; -import common.javainterop.ConsCellCollection; import edu.umn.cs.melt.lsp4jutil.CopperParserNodeFactory; import edu.umn.cs.melt.lsp4jutil.CopperSemanticTokenEncoder; import edu.umn.cs.melt.lsp4jutil.Util; -import silver.compiler.composed.Default.Parser_silver_compiler_composed_Default_svParse; import silver.compiler.definition.core.NRoot; -import silver.compiler.driver.PbuildRun; -import silver.compiler.driver.PparseArgsOrError; -import silver.compiler.driver.util.NBuildEnv; -import silver.compiler.driver.util.PbuildEnv; -import silver.compiler.driver.util.PwriteInterface; -import silver.compiler.langserver.PfindDeclLocation; -import silver.core.NLocation; -import silver.core.NPair; -import silver.core.PunsafeEvalIO; /** * Implementation of LSP text document and workspace services for Silver. @@ -91,35 +70,14 @@ public class SilverLanguageService implements TextDocumentService, WorkspaceServ private Map fileContents = new HashMap<>(); private Map fileVersions = new HashMap<>(); private Map savedVersions = new HashMap<>(); - private boolean buildInProgress = false, buildTriggered = false; - private boolean cleanBuild = false; - private boolean enableMWDA = false; - private String compilerJar = ""; - private String parserName = ""; - private FileTime compilerJarTime; - private String silverGen; - private String silverStdlibGrammars = null; - private DecoratedNode comp = null; + private boolean buildInProgress = false, buildTriggered = false, cleanRequested = false, mwdaEnabled = false; private Set grammarDirs = new HashSet<>(); private Set buildGrammars = new HashSet<>(); - public SilverLanguageService() { - try { - silverGen = Files.createTempDirectory("silver_generated").toString() + "/"; - } catch (IOException e) { - e.printStackTrace(); - } - setParserFactory(Parser_silver_compiler_composed_Default_svParse::new); - } - public void setClient(LanguageClient client) { this.client = client; } - public void setSilverGrammarsPath(Path path) { - this.silverStdlibGrammars = path.toString() + "/"; - } - public void setWorkspaceFolders(List folders) { this.folders = folders; refreshWorkspace(); @@ -132,7 +90,7 @@ public void didOpen(DidOpenTextDocumentParams params) { fileContents.put(uri, params.getTextDocument().getText()); fileVersions.put(uri, params.getTextDocument().getVersion()); savedVersions.put(uri, params.getTextDocument().getVersion()); - triggerBuild(false); + triggerBuild(); } @Override @@ -162,14 +120,15 @@ public void didSave(DidSaveTextDocumentParams params) { throw new IllegalStateException("File saved before it was changed"); } savedVersions.put(uri, fileVersions.get(uri)); - triggerBuild(false); + triggerBuild(); } @Override public CompletableFuture executeCommand(ExecuteCommandParams params) { switch (params.getCommand()) { case "silver.clean": - triggerBuild(true); + cleanRequested = true; + triggerBuild(); return null; } throw new UnsupportedOperationException("Unsupported command " + params.getCommand()); @@ -214,22 +173,34 @@ public void didRenameFiles(RenameFilesParams params) { @Override public CompletableFuture, List>> declaration(DeclarationParams params) { return CompletableFutures.computeAsync((cancelChecker) -> { - if (comp == null) { - return Either.forLeft(List.of()); + String fileName = ""; + try { + fileName = new URI(params.getTextDocument().getUri()).getPath(); + } catch (URISyntaxException e) { + e.printStackTrace(); } + return Either.forLeft(SilverCompiler.getInstance() + .getDeclaration(fileName, params.getPosition().getLine() + 1, params.getPosition().getCharacter()) + .stream() + .map((loc) -> new Location("file://" + Util.locationToFile(loc), Util.locationToRange(loc))) + .collect(Collectors.toList())); + }); + } + @Override + public CompletableFuture> references(ReferenceParams params) { + return CompletableFutures.computeAsync((cancelChecker) -> { String fileName = ""; try { fileName = new URI(params.getTextDocument().getUri()).getPath(); } catch (URISyntaxException e) { e.printStackTrace(); } - return Either.forLeft(new ConsCellCollection( - PfindDeclLocation.invoke(OriginContext.FFI_CONTEXT, - new StringCatter(fileName), params.getPosition().getLine() + 1, params.getPosition().getCharacter(), comp)) + return SilverCompiler.getInstance() + .getReferences(fileName, params.getPosition().getLine() + 1, params.getPosition().getCharacter()) .stream() .map((loc) -> new Location("file://" + Util.locationToFile(loc), Util.locationToRange(loc))) - .collect(Collectors.toList())); + .collect(Collectors.toList()); }); } @@ -241,49 +212,21 @@ public CompletableFuture, List> parserFactory) { + private CopperSemanticTokenEncoder semanticTokenEncoder = null; + private CopperParserNodeFactory parserFn = null; + public void setParserFactory(Supplier> parserFactory) { semanticTokenEncoder = new CopperSemanticTokenEncoder(parserFactory, tokenTypes, tokenModifiers); parserFn = new CopperParserNodeFactory(parserFactory); } - private CompletableFuture reloadParser() { - ConfigurationItem compilerJarConfigItem = new ConfigurationItem(); - compilerJarConfigItem.setSection("silver.compilerJar"); - ConfigurationItem parserNameConfigItem = new ConfigurationItem(); - parserNameConfigItem.setSection("silver.parserName"); - ConfigurationParams configParams = new ConfigurationParams( - List.of(compilerJarConfigItem, parserNameConfigItem)); - return client.configuration(configParams).thenAccept((configs) -> { - String oldParserJar = compilerJar; - String oldParserName = parserName; - compilerJar = ((JsonPrimitive)configs.get(0)).getAsString(); - parserName = ((JsonPrimitive)configs.get(1)).getAsString(); - if (compilerJar.isEmpty() || parserName.isEmpty()) { - if (!compilerJar.equals(oldParserJar) || !parserName.equals(oldParserName)) { - setParserFactory(Parser_silver_compiler_composed_Default_svParse::new); - } - } else { - try { - Path compilerJarPath = Paths.get(compilerJar); - FileTime newParserJarTime = Files.readAttributes(compilerJarPath, BasicFileAttributes.class).lastModifiedTime(); - if (!compilerJar.equals(oldParserJar) || !parserName.equals(oldParserName) || !newParserJarTime.equals(compilerJarTime)) { - compilerJarTime = newParserJarTime; - System.err.println("Loading parser " + compilerJar + " " + parserName); - setParserFactory(Util.loadCopperParserFactory(compilerJarPath, parserName, NRoot.class)); - } - } catch (SecurityException | ReflectiveOperationException | IOException e) { - client.showMessage(new MessageParams(MessageType.Error, "Error loading parser from jar: " + e.toString())); - } - } - }); - } - @Override public CompletableFuture semanticTokensFull(SemanticTokensParams params) { + if (semanticTokenEncoder == null) { + throw new IllegalStateException("Semantic tokens requested when parser has not been initialized"); + } + String uri = params.getTextDocument().getUri(); - return reloadParser().thenApply((arg) -> { + return CompletableFutures.computeAsync((cancelChecker) -> { List tokens; int requestVersion; // Recompute tokens if the file is changed while tokens are being computed @@ -313,13 +256,13 @@ private void refreshWorkspace() { findGrammars(new File(uri)); } - triggerBuild(false); + triggerBuild(); } private void findGrammars(File root) { // Workaround to avoid copied resource grammars in the maven build // directory in this LSP plugin under the Silver repo. - // We might want to add a more intelegent way of specifying grammars to + // We might want to add a more intelligent way of specifying grammars to // exclude in case duplicates are found. if (root.getPath().contains("/target/classes/")) return; @@ -336,138 +279,57 @@ private void findGrammars(File root) { } } - public synchronized void triggerBuild(boolean cleanBuild) { - this.cleanBuild = cleanBuild; - + public synchronized void triggerBuild() { buildTriggered = true; - if (!buildInProgress) { + if (!buildInProgress && parserFn != null) { buildInProgress = true; - new Thread(() -> { - while(true) { - Map buildVersions; - synchronized (this) { - buildTriggered = false; - buildVersions = new HashMap<>(savedVersions); - } - doBuild(buildVersions); - synchronized (this) { - if (!buildTriggered) { - buildInProgress = false; - break; - } - } - }; - }).start(); + new Thread(this::doBuild).start(); } } - private void doBuild(Map buildVersions) { - System.err.println("Building"); - - String silverHome = ""; // Not needed since we aren't doing translation - List args = new ArrayList<>(); - List grammarPath = new ArrayList<>(grammarDirs); - List silverHostGen = List.of(silverGen); - - // Check the config for whether the MWDA is enabled - ConfigurationItem enableMWDAConfigItem = new ConfigurationItem(); - enableMWDAConfigItem.setSection("silver.enableMWDA"); - ConfigurationParams configParams = new ConfigurationParams(List.of(enableMWDAConfigItem)); - boolean newEnableMWDA = enableMWDA; - try { - newEnableMWDA = ((JsonPrimitive)client.configuration(configParams).get().get(0)).getAsBoolean(); - } catch (InterruptedException | ExecutionException e) { - // Ignore, getting the settings sometimes fails when a build is triggered during initialization - } - - if (newEnableMWDA && !enableMWDA) { - // Do a clean build when the MWDA is initially enabled - cleanBuild = true; - } - enableMWDA = newEnableMWDA; - - if (enableMWDA) { - System.err.println("MWDA enabled"); - args.add("--warn-all"); - } - - // Clean build if requested - if (cleanBuild) { - System.err.println("Clean build"); - args.add("--clean"); - } - - if (silverStdlibGrammars == null) { - throw new IllegalStateException("Silver host grammars path not set"); - } else { - // Add the silver resource grammars to the end of the grammar path, - // so if silver is in the workspace we will find it there first. - grammarPath.add(silverStdlibGrammars); - } - - // Set up the build environment - NBuildEnv benv = new PbuildEnv( - new StringCatter(silverHome), - new StringCatter(silverGen), - ConsCellCollection.fromStringList(grammarPath), - ConsCellCollection.fromStringList(silverHostGen) - ); - DecoratedNode a = PparseArgsOrError.invoke(OriginContext.FFI_CONTEXT, ConsCellCollection.fromStringList(args)); - - // Build! - DecoratedNode comp = (DecoratedNode)PunsafeEvalIO.invoke(OriginContext.FFI_CONTEXT, - PbuildRun.invoke(OriginContext.FFI_CONTEXT, - parserFn, a, benv, - ConsCellCollection.fromIterator(buildGrammars.stream().map(StringCatter::new).iterator()))); - - // Note that we must demand allGrammars from comp before demanding - // recompiledGrammars to ensure that IO happens properly, - // due to the circularity in the driver involving unsafeInterleaveIO. - Collection allGrammars = new ConsCellCollection<>( - comp.synthesized(silver.compiler.driver.util.Init.silver_compiler_driver_util_allGrammars__ON__silver_compiler_driver_util_Compilation)); - Collection recompiledGrammars = new ConsCellCollection<>( - comp.synthesized(silver.compiler.driver.util.Init.silver_compiler_driver_util_recompiledGrammars__ON__silver_compiler_driver_util_Compilation)); - - // Check that we built all triggered grammars. - Set builtGrammars = allGrammars.stream() - .map(r -> r.synthesized(silver.compiler.driver.util.Init.silver_compiler_definition_env_declaredName__ON__silver_compiler_driver_util_RootSpec).toString()) - .collect(Collectors.toSet()); - for (String grammar : buildGrammars) { - if (!builtGrammars.contains(grammar)) { - System.err.println("Failed to find triggered grammar " + grammar); + private void doBuild() { + while(true) { + Map buildVersions; + synchronized (this) { + buildTriggered = false; + buildVersions = new HashMap<>(savedVersions); + } + if (parserFn == null) { + throw new IllegalStateException("Build requested when parser has not been loaded"); } - } - // Report diagnostics - System.err.println("Reporting diagnostics"); - for (DecoratedNode r : allGrammars) { - String grammarSource = - r.synthesized(silver.compiler.driver.util.Init.silver_compiler_definition_env_grammarSource__ON__silver_compiler_driver_util_RootSpec).toString(); - - Collection allFileErrors = new ConsCellCollection<>( - r.synthesized(silver.compiler.driver.util.Init.silver_compiler_definition_core_allFileErrors__ON__silver_compiler_driver_util_RootSpec)); - for (NPair fileErrors : allFileErrors) { - DecoratedNode decFileErrors = fileErrors.decorate(); - String fileName = decFileErrors.synthesized(silver.core.Init.silver_core_fst__ON__silver_core_Pair).toString(); - ConsCell messages = decFileErrors.synthesized(silver.core.Init.silver_core_snd__ON__silver_core_Pair); - String uri = "file://" + grammarSource + fileName; - - // System.err.println("Reporting diagnostics for " + grammarSource + fileName); - client.publishDiagnostics(new PublishDiagnosticsParams(uri, Util.messagesToDiagnostics(messages, uri), buildVersions.get(uri))); + // Check the config for whether the MWDA is enabled + ConfigurationItem enableMWDAConfigItem = new ConfigurationItem(); + enableMWDAConfigItem.setSection("silver.enableMWDA"); + ConfigurationParams configParams = new ConfigurationParams(List.of(enableMWDAConfigItem)); + boolean enableMWDA = mwdaEnabled; + try { + Object configMWDAGet = client.configuration(configParams).get().get(0); + if (configMWDAGet != null && !((JsonElement)configMWDAGet).isJsonNull()) { + enableMWDA = ((JsonPrimitive)configMWDAGet).getAsBoolean(); + } + } catch (InterruptedException | ExecutionException e) { + // Ignore, getting the settings sometimes fails when a build is triggered during initialization } - } - // Write updated interface files - System.err.println("Writing interface files"); - for (DecoratedNode r : recompiledGrammars) { - PunsafeEvalIO.invoke(OriginContext.FFI_CONTEXT, - PwriteInterface.invoke(OriginContext.FFI_CONTEXT, new StringCatter(silverGen), r)); + boolean cleanBuild = cleanRequested; + if (enableMWDA && !mwdaEnabled) { + // Do a clean build when the MWDA is initially enabled + cleanBuild = true; + } + mwdaEnabled = enableMWDA; + cleanRequested = false; + + SilverCompiler.getInstance().build( + parserFn, grammarDirs, buildGrammars, cleanBuild, enableMWDA, + (String uri, List diagnostics) -> + client.publishDiagnostics(new PublishDiagnosticsParams(uri, diagnostics, buildVersions.get(uri)))); + synchronized (this) { + if (!buildTriggered) { + buildInProgress = false; + break; + } + } } - - // Only update the compilation result once we are done reporting errors, to avoid race conditions from other attributes being demanded - this.comp = comp; - - // Reset option flags - this.cleanBuild = false; } } diff --git a/language-server/launcher/.classpath b/language-server/launcher/.classpath index 9ba41a249..b3a434205 100644 --- a/language-server/launcher/.classpath +++ b/language-server/launcher/.classpath @@ -31,6 +31,19 @@ + + + + + + + + + + + + + diff --git a/language-server/launcher/.settings/org.eclipse.jdt.apt.core.prefs b/language-server/launcher/.settings/org.eclipse.jdt.apt.core.prefs new file mode 100644 index 000000000..d4313d4b2 --- /dev/null +++ b/language-server/launcher/.settings/org.eclipse.jdt.apt.core.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.apt.aptEnabled=false diff --git a/language-server/launcher/.settings/org.eclipse.jdt.core.prefs b/language-server/launcher/.settings/org.eclipse.jdt.core.prefs index 1679c57c7..cbcd33000 100644 --- a/language-server/launcher/.settings/org.eclipse.jdt.core.prefs +++ b/language-server/launcher/.settings/org.eclipse.jdt.core.prefs @@ -131,7 +131,7 @@ org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info -org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=enabled org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore org.eclipse.jdt.core.compiler.problem.tasks=warning org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning diff --git a/make-dist b/make-dist index c1d95f79a..3b9bee9bb 100755 --- a/make-dist +++ b/make-dist @@ -32,6 +32,7 @@ tar -zcvf $SV.tar.gz \ $SV/support/vim \ $SV/support/gedit \ $SV/support/nailgun \ + $SV/support/vs-code/silverlsp/*.vsix \ $SV/tutorials/ \ $SV/grammars/silver/core/ \ $SV/grammars/silver/xml/ \ diff --git a/make-ide b/make-ide deleted file mode 100755 index 4bc99691e..000000000 --- a/make-ide +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash - -set -eu - -# Make sure any compiler changes make it before we build -./self-compile -cp build/silver.compiler.composed.Default.jar jars/ - -# Rebuild the IDE-specific runtime jars -cd runtime/imp -./build.sh -cd ../.. - -# Create plug-in sources and .class files. -# this creates a silver.compiler.composed.idetest.jar that is not used, but -# this does create stuff in the generated directory that is used in -# the next step -SV_BUILD_TARGET="silver:compiler:composed:idetest" ./self-compile --clean - -# Create the Eclipse repository. -# The repository is in the generated/ide/silver.compiler.composed.idetest -# directory. To make it public run the make-ide-dist script. -cd generated/ide/silver.compiler.composed.idetest -mvn package - -TARGET=$(pwd)/updatesite/target/repository - -echo "..." -echo "..." -echo "..." -echo "Be sure to increment IDE version number in silver:compiler:composed:idetest:Main.sv" -echo "..." -echo "..." -echo "Reminder: add $TARGET as path to find update site in eclipse, if using directly" -echo "..." - diff --git a/make-ide-dist b/make-ide-dist deleted file mode 100755 index a037c9a11..000000000 --- a/make-ide-dist +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -set -e - -IDEDIR="/web/research/melt.cs.umn.edu/downloads/silver-eclipse-beta" -ZIPFILE="generated/ide/silver.compiler.composed.idetest/updatesite/target/SILVER_UPDATESITE.zip" - -if [ ! -d $IDEDIR ]; then - echo "Must be running on a umn machine in the melt group." - exit 1 -fi - -if [ ! -a $ZIPFILE ]; then - echo "Should be run from root of silver tree with IDE generated." - exit 2 -fi - -echo "..." -echo "Be sure to increment IDE version number in silver:compiler:composed:idetest:Main.sv" -echo "..." - -rm -Rf ${IDEDIR}/* -cp $ZIPFILE ${IDEDIR}/ - -cd ${IDEDIR} -unzip SILVER_UPDATESITE.zip -chmod -R go=u * - diff --git a/make-vscode-extension b/make-vscode-extension new file mode 100755 index 000000000..f810bcf93 --- /dev/null +++ b/make-vscode-extension @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# Utility to clean-rebuild and package the Silver language server +# and VS Code extension. + +set -eu + +SILVERLSP_VSIX="silverlsp-latest.vsix" + +# Make sure we are in the root of the silver repo +cd "$(dirname "${BASH_SOURCE[0]}")" + +echo "Cleaning..." +cd runtime/lsp4j/ +mvn clean +cd ../.. + +cd language-server/ +mvn clean + +echo +echo "Building language server..." +./build.sh +cd .. + +echo "Packaging $SILVERLSP_VSIX..." +cd support/vs-code/silverlsp/ +npm install --dev +node_modules/@vscode/vsce/vsce package -o "$SILVERLSP_VSIX" + +echo "Packaged Silver LSP extension: $(realpath "$SILVERLSP_VSIX")" diff --git a/runtime/java/src/common/CollectionAttribute.java b/runtime/java/src/common/CollectionAttribute.java index 7d463b6f4..13f800bad 100644 --- a/runtime/java/src/common/CollectionAttribute.java +++ b/runtime/java/src/common/CollectionAttribute.java @@ -55,7 +55,7 @@ private static class BaseDefault implements Lazy { } @Override public Object eval(final DecoratedNode context) { - final Node un = context.undecorate(); + final Node un = context.getNode(); if(un.hasForward()) { try { return context.forward().synthesized(index); diff --git a/runtime/java/src/common/CopperUtil.java b/runtime/java/src/common/CopperUtil.java index 661e412a6..7377f4e85 100644 --- a/runtime/java/src/common/CopperUtil.java +++ b/runtime/java/src/common/CopperUtil.java @@ -30,17 +30,14 @@ public final class CopperUtil { private static Location svToCuLocation(String sourceGrammar, - NLocation locTerm) { - // datatypes when... - DecoratedNode locTree = locTerm.decorate(); - + NLocation loc) { String fileName = String.format("%s/%s", sourceGrammar, - locTree.synthesized( + loc.synthesized( Init.silver_core_filename__ON__silver_core_Location)); - Integer line = (Integer)locTree.synthesized( + Integer line = loc.synthesized( Init.silver_core_line__ON__silver_core_Location); - Integer column = (Integer)locTree.synthesized( + Integer column = loc.synthesized( Init.silver_core_column__ON__silver_core_Location); return new VirtualLocation(fileName, line, column); @@ -354,7 +351,7 @@ public static ParserAttribute makeParserAttribute(String sourceGrammar, case "right": terminal.setOperatorAssociativity(OperatorAssociativity.RIGHT); break; - default: + case "none": terminal.setOperatorAssociativity(OperatorAssociativity.NONASSOC); break; } diff --git a/runtime/java/src/common/DataNode.java b/runtime/java/src/common/DataNode.java new file mode 100644 index 000000000..3d95f1121 --- /dev/null +++ b/runtime/java/src/common/DataNode.java @@ -0,0 +1,119 @@ +package common; + +import common.exceptions.SilverInternalError; + +/** + * A specialized version of Nodes that do not have any inherited attributes. + * + *

Data nonterminals subclass this class instead of Node. + * Since data nonterminals do not forward or get decorated with inherited attributes, + * the relevant methods do not have implementations supplied by the nonterminal subclass. + * Since data nonterminals are not decorated, DataNode has methods to directly demand + * synthesized attributes or decorated children. + * + * @author lkramer + * @see Node + */ +public abstract class DataNode extends Node { + // The DecoratedNode used as context for evaluating syn/production attributes, if ever demanded. + // Since we have no inh attributes, syn attribute values are always the same and are cached here. + private DecoratedNode context; + + public DataNode() { + super(false); + } + + /** + * Obtain a synthesized attribute from this DataNode, creating the local context if needed. + * + * @param attribute The index of the attribute. + * @return The value of the attribute. + */ + public T synthesized(final int attribute) { + if (context == null) { + context = createContext(); + } + return context.synthesized(attribute); + } + + /** + * Obtain a decorated child with any supplied inherited attributes, from the local context created here. + * + * @param child The number of the child to obtain. + * @return The decorated value of the child. + */ + public DecoratedNode childDecorated(final int child) { + if (context == null) { + context = createContext(); + } + return context.childDecorated(child); + } + + /** + * We might still need to produce a DecoratedNode in polymorphic contexts with synthesized occurs-on constraints. + * + * @param inhs The inherited attributes supplied, should always be null. + * @param transInhs The inherited attributes supplied on translation attributes, should always be null. + * @return The "decorated" form of this DataNode. + */ + @Override + public final DecoratedNode decorate(final DecoratedNode parent, final Lazy[] inhs) { + if (inhs != null) { + throw new SilverInternalError("Data nonterminals cannot be decorated with inherited attributes!"); + } + if (context == null) { + context = createContext(); + } + return context; + } + + private DecoratedNode createContext() { + return new DecoratedNode( + getNumberOfChildren(), 0, getNumberOfSynAttrs(), getNumberOfLocalAttrs(), + this, TopNode.singleton, null, null, false); + } + + // These methods have implementations here since we never forward or supply inherited attributes: + @Override + public final boolean getLocalIsForward(final int index) { + return false; + } + + @Override + public final boolean hasForward() { + return false; + } + + @Override + public final int getNumberOfInhAttrs() { + return 0; + } + + // Overrides for methods that should never be consulted on data nonterminals: + @Override + public final DecoratedNode decorate( + final DecoratedNode parent, final Lazy[] inhs, + final DecoratedNode fwdParent, final boolean isProdForward) { + throw new SilverInternalError("Data nonterminals should never be decorated with a forward parent!"); + } + + @Override + public final Node evalUndecorate(final DecoratedNode context) { + throw new SilverInternalError("Data nonterminals do not undecorate!"); + } + + @Override + public final Node evalForward(final DecoratedNode context) { + throw new SilverInternalError("Data nonterminals do not forward!"); + } + + @Override + public final Lazy[] getForwardInheritedAttributes() { + throw new SilverInternalError("Data nonterminals do not forward!"); + } + + @Override + public final String getNameOfInhAttr(final int index) { + throw new SilverInternalError("Data nonterminals do not possess inherited attributes! (Requested name of index " + index + ")"); + } +} diff --git a/runtime/java/src/common/Decorable.java b/runtime/java/src/common/Decorable.java index 1c5d6e197..9ce5599fe 100644 --- a/runtime/java/src/common/Decorable.java +++ b/runtime/java/src/common/Decorable.java @@ -12,8 +12,26 @@ public interface Decorable { * Decorate this node with additional inherited attributes. * * @param parent The DecoratedNode creating this one. (Whether this is a child or a local (or other) of that node.) - * @param inhs A map from attribute names to Lazys that define them. These Lazys will be supplied with 'parent' as their context for evaluation. + * @param inhs A map from inh attribute indexes to Lazys that define them. + * These Lazys will be supplied with 'parent' as their context for evaluation. * @return A DecoratedNode with the attributes supplied. */ public DecoratedNode decorate(final DecoratedNode parent, final Lazy[] inhs); + + /** + * Decorate this node with a forward parent. + * + * @param parent The "true parent" of this node (same as the fwdParent's parent) + * @param inhs Overrides for inherited attributes that should not be computed via forwarding. + * These Lazys will be supplied with 'parent' as their context for evaluation. + * @param fwdParent The DecoratedNode that forwards to the one we are about to create. + * We will pass inherited attribute access requests to this node. + * @param prodFwrd Is this the forward for fwdParent's prod? False for forward prod attributes. + * @return A DecoratedNode with the attributes supplied. + */ + public DecoratedNode decorate( + final DecoratedNode parent, + final Lazy[] inhs, + final DecoratedNode fwdParent, + final boolean prodFwrd); } diff --git a/runtime/java/src/common/DecoratedNode.java b/runtime/java/src/common/DecoratedNode.java index 8e56bfebe..3ef3706fd 100644 --- a/runtime/java/src/common/DecoratedNode.java +++ b/runtime/java/src/common/DecoratedNode.java @@ -1,7 +1,10 @@ package common; +import java.util.Arrays; + import common.exceptions.MissingDefinitionException; import common.exceptions.SilverException; +import common.exceptions.SilverInternalError; import common.exceptions.TraceException; /** @@ -9,7 +12,7 @@ * *

Here be dragons, unfortunately. Don't modify at all without running it past me. * - * @author tedinski + * @author tedinski, krame505 * @see Node */ public class DecoratedNode implements Decorable, Typed { @@ -21,7 +24,7 @@ public class DecoratedNode implements Decorable, Typed { // Please note: the methods in this file have been refined to be quite small // because the JVM makes inlining decisions on a per-method basis (of course!) // So we try to keep the "slow paths" in a separate method, so the hot paths - // can be inlined. (Things are designed around 37 bytes of bytecode as the limit.) + // can be inlined. (Things are designed around 35 bytes of bytecode as the limit.) // Error reporting note: we don't attempt to identify and report errors for // mis-generated code. e.g. asking for synthesized attributes that @@ -39,12 +42,12 @@ public class DecoratedNode implements Decorable, Typed { protected final Node self; /** * The node that forwards to this one. (May be null) - * - * @see #inheritedForwarded(String) + * Not final, because we may set this when forwarding to a decorated tree via a unique reference. */ - protected final DecoratedNode forwardParent; + protected DecoratedNode forwardParent; /** - * The DecoratedNode to use as a context for evaluating inherited attributes. (Never null except for TopNode) + * The DecoratedNode creating this one. (Never null except for TopNode) + * This is only used for debugging and origins. * *

May be actual parent. Or production this is a local in. Or just a production that * called 'decorate' to create this one. @@ -52,7 +55,14 @@ public class DecoratedNode implements Decorable, Typed { * @see TopNode */ protected final DecoratedNode parent; - + /** + * Is this the forward for the production of forwardParent? + * This is true for normal forwarding, where there will be syn copy equations, + * but false for forward production attributes, which only forward inhs. + * Thus this determines whether translation attributes on this node + * default to having the same decoration sites as forwardParent. + */ + protected boolean isProdForward; /** * The cache of children (e.g. the DecoratedNodes) * @@ -68,14 +78,14 @@ public class DecoratedNode implements Decorable, Typed { /** * The cache of the inherited attribute supplied to this node. * - * @see #inherited(String) + * @see #inherited(int) * @see #inheritedAttributes */ protected final Object[] inheritedValues; /** * The cache of the synthesized attributes on this node. * - * @see #synthesized(String) + * @see #synthesized(int) * @see #local(String) */ protected final Object[] synthesizedValues; @@ -84,7 +94,7 @@ public class DecoratedNode implements Decorable, Typed { * The inherited attributes supplied to this DecoratedNode, to be evaluated with context 'parent'. * Not final, because we make a copy of the array if this DecoratedNode is extra-decorated. * - * @see #inherited(String) + * @see #inherited(int) * @see #inheritedValues */ protected Lazy[] inheritedAttributes; @@ -94,14 +104,28 @@ public class DecoratedNode implements Decorable, Typed { */ protected final Object[] localValues; + /** + * Track whether a decorated child has already been created, for sanity checking. + * This may be true when childrenValues[i] == null, because of how unique references are translated. + */ + protected final boolean[] childCreated; + /** + * Track whether a decorated local has already been created, for sanity checking. + * This may be true when localValues[i] == null, because of how unique references are translated. + */ + protected final boolean[] localCreated; + /** + * Track whether a decorated translation attribute has already been created, for sanity checking. + * This may be true when synthesizedValues[i] == null, because of how unique references are translated. + */ + protected final boolean[] transCreated; + /** * Construct a decorated form of a Node. Called only via Node. * *

'self' and 'parent' are not null (except for TopNode) * - *

Only one or none of 'inhs' and 'forwardParent' should be supplied. - * * @param cc Child count * @param ic Inherited attribute count * @param sc Synthesized attribute count @@ -109,26 +133,40 @@ public class DecoratedNode implements Decorable, Typed { * @param self The Node to decorate. * @param parent The DecoratedNode creating this one, to evaluate inhs in. * @param inhs The inherited attributes to decorate this node with. - * @param forwardParent The node to request inherited attributes from instead of using 'inhs'. + * @param forwardParent The node to request inherited attributes from if not supplied in 'inhs'. + * @param isProdForward Is this the forward for forwardParent's prod? False for forward prod attributes. * - * @see Node#decorate(DecoratedNode, DecoratedNode) * @see Node#decorate(DecoratedNode, Lazy[]) + * @see Node#decorate(DecoratedNode, Lazy[], DecoratedNode, boolean) */ DecoratedNode( final int cc, final int ic, final int sc, final int lc, final Node self, final DecoratedNode parent, - final Lazy[] inhs, final DecoratedNode forwardParent) { + final Lazy[] inhs, + final DecoratedNode forwardParent, final boolean isProdForward) { this.self = self; this.parent = parent; this.originCtx = parent!=null?parent.originCtx:null; - this.inheritedAttributes = inhs; this.forwardParent = forwardParent; + this.isProdForward = isProdForward; + + if(inhs != null && inhs.length < ic) { + // TODO: Due to the implementation of inherited occurs-on constraints, we might + // get passed a shorter array when decorating a polymorphic type. + // This seems like it should be avoidable? + this.inheritedAttributes = Arrays.copyOf(inhs, ic); + } else { + this.inheritedAttributes = inhs; + } // create caches this.childrenValues = (cc > 0) ? new Object[cc] : null; this.inheritedValues = (ic > 0) ? new Object[ic] : null; this.synthesizedValues = (sc > 0) ? new Object[sc] : null; this.localValues = (lc > 0) ? new Object[lc] : null; + this.childCreated = (cc > 0) ? new boolean[cc] : null; + this.localCreated = (lc > 0) ? new boolean[lc] : null; + this.transCreated = (sc > 0) ? new boolean[sc] : null; // STATS: Uncomment to enable statistics //Statistics.dnSpawn(self!=null?self.getClass():TopNode.class); @@ -144,17 +182,21 @@ public class DecoratedNode implements Decorable, Typed { */ DecoratedNode(final int cc, final int lc, final FunctionNode self) { // TODO: I added this constructor largely because I wanted to - // see if I could make all this fit under the 37 byte inline limit. + // see if I could make all this fit under the 35 byte inline limit. // This doesn't. :( Leaving it, because it certainly doesn't hurt. this.self = self; this.parent = TopNode.singleton; this.inheritedAttributes = null; this.forwardParent = null; + this.isProdForward = false; this.childrenValues = new Object[cc]; this.inheritedValues = null; this.synthesizedValues = null; this.localValues = (lc > 0) ? new Object[lc] : null; + this.childCreated = new boolean[cc]; + this.localCreated = (lc > 0) ? new boolean[lc] : null; + this.transCreated = null; } // STATS: Uncomment to enable statistics @@ -164,31 +206,42 @@ public class DecoratedNode implements Decorable, Typed { //} /** - * @return The {@link Node} this decorates. + * @return Turn this DecoratedNode back into an undecorated {@link Node}. */ public final Node undecorate() { - return self; + if (self.isUnique) { + // System.err.println("TRACE: undecorating " + getDebugID()); + return self.undecorate(this); + } else { + return self; + } } /** - * Decorate this (partially decorated) node with additional inherited attributes. + * Decorate this (unique decorated) node with additional inherited attributes. + * This has no effect if the node already has a forward parent. * * @param parent The DecoratedNode extra-decorating this one. (Whether this is a child or a local (or other) of that node.) - * @param inhs A map from attribute names to Lazys that define them. These Lazys will be supplied with 'parent' as their context for evaluation. + * @param inhs Overrides for inherited attributes that should not be computed via forwarding. + * These Lazys will be supplied with 'parent' as their context for evaluation. + * @param transInhs Overrides for inherited attributes on translation attributes that should not be computed via forwarding. + * These Lazys will be supplied with 'parent' as their context for evaluation. * @return A DecoratedNode with the additional attributes supplied, referencing this DecoratedNode as 'base'. */ @Override public DecoratedNode decorate(final DecoratedNode parent, final Lazy[] inhs) { // System.err.println("TRACE: " + parent.getDebugID() + " extra-decorating " + getDebugID()); - if (inhs != null) { - inheritedAttributes = inheritedAttributes.clone(); // Avoid modifying the static inh array from the original parent Node - for(int i = 0; i < inhs.length; i++) { - final int attribute = i; - if(inhs[attribute] != null) { - if(inheritedAttributes[attribute] == null) { - inheritedAttributes[attribute] = (context) -> inhs[attribute].eval(parent); - } else { - throw new SilverException(parent.getDebugID() + " cannot decorate " + getDebugID() + " with inh '" + self.getNameOfInhAttr(attribute) + "' as this attribute has already been provided by " + this.parent.getDebugID() + "."); + if (forwardParent == null) { + if (inhs != null) { + if (inheritedAttributes == null) { + inheritedAttributes = new Lazy[self.getNumberOfInhAttrs()]; + } else { + inheritedAttributes = inheritedAttributes.clone(); // Avoid modifying the static inh array from the original parent Node + } + for(int i = 0; i < inhs.length; i++) { + final int attribute = i; + if(inhs[attribute] != null && inheritedAttributes[attribute] == null) { + inheritedAttributes[attribute] = inhs[attribute].withContext(parent); } } } @@ -196,11 +249,44 @@ public DecoratedNode decorate(final DecoratedNode parent, final Lazy[] inhs) { return this; } + /** + * Decorate this node with a forward parent. + * This has no effect if the node already has a forward parent. + * + * @param parent The "true parent" of this node (same as the fwdParent's parent) + * @param inhs A map from attribute indexes to Lazys that define them. These Lazys will be supplied with 'parent' as their context for evaluation. + * @param transInhs Overrides for inherited attributes on translation attributes that should not be computed via forwarding. + * These Lazys will be supplied with 'parent' as their context for evaluation. + * @param fwdParent The DecoratedNode that forwards to the one we are about to create. We will pass inherited attribute access requests to this node. + * @param prodFwrd Is this the forward for fwdParent's prod? False for forward prod attributes. + * @return A DecoratedNode with the attributes supplied. + */ + @Override + public DecoratedNode decorate(final DecoratedNode parent, final Lazy[] inhs, final DecoratedNode fwdParent, final boolean prodFwrd) { + if (forwardParent == null) { + decorate(parent, inhs); + forwardParent = fwdParent; + isProdForward = prodFwrd; + } + return this; + } + + /** + * Accessor function to access the originally-decorated Node. + * The Node returned by this function must never be decorated - + * e.g. for use by origin tracking or for debugging purposes. + * One should typically use {@link undecorate} instead to avoid duplicating any unique children. + * + * @return The {@link Node} this decorates. + */ + public final Node getNode() { + return self; + } + /** * Returns the child of this DecoratedNode, without potentially decorating it. * - *

Warning: While it is technically safe to mix calls to {@link #childAsIs} and {@link #childDecorated} - * this behavior should not be relied upon, as it may change later. + *

Warning: do not mix {@link #childAsIs} and {@link #childDecorated} on the same child! * * @param child The number of the child to obtain. * @return The unmodified value of the child. @@ -214,8 +300,7 @@ public T childAsIs(final int child) { * Returns the child of this DecoratedNode, decorating it with whatever inherited attributes * this production has for it. * - *

Warning: While it is technically safe to mix calls to {@link #childAsIs} and {@link #childDecorated} - * this behavior should not be relied upon, as it may change later. + *

Warning: do not mix {@link #childAsIs} and {@link #childDecorated} on the same child! * * @param child The number of the child to obtain. * @return The decorated value of the child. @@ -223,7 +308,7 @@ public T childAsIs(final int child) { public DecoratedNode childDecorated(final int child) { Object o = this.childrenValues[child]; if(o == null) { - o = createDecoratedChild(child); + o = obtainDecoratedChild(child); assert(o != null); @@ -234,12 +319,34 @@ public DecoratedNode childDecorated(final int child) { } /** - * Create the DecoratedNode for a child. + * Create or retrieve the DecoratedNode for a child. * Separate function to keep {@link #childDecorated} small and inlineable. * This is, after all, the "slow path." */ - private final DecoratedNode createDecoratedChild(final int child) { - return ((Decorable)self.getChild(child)).decorate(this, self.getChildInheritedAttributes(child)); + private final DecoratedNode obtainDecoratedChild(final int child) { + Lazy decSite = self.getChildDecSite(child); + if(decSite == null) { + return createDecoratedChild(child); + } else { + return (DecoratedNode)decSite.eval(this); + } + } + + /** + * Create the DecoratedNode for a child. + * This can also be called directly in the translation of taking a unique reference. + * Invariant: should never be called more than once for a child! + * + * @param child The number of the child to create. + * @return The decorated value of the child. + */ + public final DecoratedNode createDecoratedChild(final int child) { + if(childCreated[child]) { + throw new SilverInternalError("Decorated child " + child + " created more than once in " + getDebugID()); + } + DecoratedNode result = ((Decorable)self.getChild(child)).decorate(this, self.getChildInheritedAttributes(child)); + childCreated[child] = true; + return result; } /** @@ -247,7 +354,7 @@ private final DecoratedNode createDecoratedChild(final int child) { * *

Warning: do not mix {@link #localAsIs} and {@link #localDecorated} on the same local attribute! * - * @param attribute The full name of the local to obtain. + * @param attribute The index of the local to obtain. * @return The value of the local. */ @SuppressWarnings("unchecked") @@ -293,13 +400,13 @@ private final SilverException handleLocalError(final int attribute, final Throwa * *

Warning: do not mix {@link #localAsIs} and {@link #localDecorated} on the same local attribute! * - * @param attribute The full name of the local to obtain. + * @param attribute The index of the local to obtain. * @return The value of the local. */ public DecoratedNode localDecorated(final int attribute) { Object o = this.localValues[attribute]; if(o == null) { - o = evalLocalDecorated(attribute); + o = obtainDecoratedLocal(attribute); assert(o != null); @@ -309,19 +416,48 @@ public DecoratedNode localDecorated(final int attribute) { } return (DecoratedNode)o; } - + /** * Another case of keeping the slow paths out of here, so it can be inlined. */ - private final DecoratedNode evalLocalDecorated(final int attribute) { - return ((Decorable)evalLocalAsIs(attribute)).decorate(this, self.getLocalInheritedAttributes(attribute)); + private final DecoratedNode obtainDecoratedLocal(final int attribute) { + Lazy decSite = self.getLocalDecSite(attribute); + if(decSite == null) { + return evalLocalDecorated(attribute); + } else { + return (DecoratedNode)decSite.eval(this); + } + } + + /** + * Evaluate a local and decorate it. + * This can also be called directly in the translation of taking a unique reference. + * Invariant: should never be called more than once for a local! + * + * @param attribute The index of the local to obtain. + * @return The decorated value of the local. + */ + public final DecoratedNode evalLocalDecorated(final int attribute) { + if(localCreated[attribute]) { + throw new SilverInternalError("Decorated local '" + self.getNameOfLocalAttr(attribute) + "' created more than once in " + getDebugID()); + } + Decorable localAsIs = (Decorable)evalLocalAsIs(attribute); + Lazy[] inhs = self.getLocalInheritedAttributes(attribute); + DecoratedNode result; + if(self.getLocalIsForward(attribute)) { + result = localAsIs.decorate(this, inhs, this, false); + } else { + result = localAsIs.decorate(this, inhs); + } + localCreated[attribute] = true; + return result; } /** * Obtain a synthesized attribute from this DecoratedNode. First, look for definitions on this node, * and if that fails, request it from whatever we forward to, if anything. * - * @param attribute The full name of the attribute. + * @param attribute The index of the attribute. * @return The value of the attribute. */ @SuppressWarnings("unchecked") @@ -342,7 +478,7 @@ public T synthesized(final int attribute) { } private final Object evalSyn(final int attribute) { - // TODO: Try to break this up into < 37 byte methods? + // TODO: Try to break this up into < 35 byte methods? Lazy l = self.getSynthesized(attribute); if(l != null) { try { @@ -375,14 +511,100 @@ private final Object evalSyn(final int attribute) { try { return l.eval(this); } catch(Throwable t) { - throw new TraceException("While evaling default for '" + self.getNameOfSynAttr(attribute) + "' in " + getDebugID(), t); + throw new TraceException("While evaling default for syn '" + self.getNameOfSynAttr(attribute) + "' in " + getDebugID(), t); } } else { throw new MissingDefinitionException("Synthesized attribute '" + self.getNameOfSynAttr(attribute) + "' not defined in " + getDebugID()); } } } - + + /** + * Obtain a translation attribute from this DecoratedNode. + * Evaluate it as a synthesized attribute, then decorate it. + * + * @param attribute The index of the attribute. + * @param decSiteAttribute The index of the attribute's decoration site attribute + * @return The value of the attribute. + */ + public DecoratedNode translation(final int attribute, final int inhsAttribute, final int decSiteAttribute) { + // common.Util.stackProbe(); + // System.err.println("TRACE: " + getDebugID() + " demanding trans attribute: " + self.getNameOfSynAttr(attribute)); + + DecoratedNode o = (DecoratedNode)this.synthesizedValues[attribute]; + if(o == null) { + o = obtainDecoratedTrans(attribute, inhsAttribute, decSiteAttribute); + + assert(o != null); + + // CACHE : comment out to disable caching for translation attributes + this.synthesizedValues[attribute] = o; + } + return o; + } + + private final DecoratedNode obtainDecoratedTrans(final int attribute, final int inhsAttribute, final int decSiteAttribute) { + Lazy decSite = inheritedAttributes == null? null : inheritedAttributes[decSiteAttribute]; + if(decSite != null) { + return (DecoratedNode)decSite.eval(parent); + } else if(forwardParent != null && isProdForward) { + return forwardParent.translation(attribute, inhsAttribute, decSiteAttribute); + } else { + return evalTrans(attribute, inhsAttribute); + } + } + + /** + * Evaluate a translation attribute and decorate it. + * This can also be called directly in the translation of taking a unique reference. + * Invariant: should never be called more than once for an attribute! + * + * @param attribute The index of the translation attribute to obtain. + * @return The decorated value of the translation attribute. + */ + public final DecoratedNode evalTrans(final int attribute, final int inhsAttribute) { + if(transCreated[attribute]) { + throw new SilverInternalError("Decorated translation attribute " + self.getNameOfSynAttr(attribute) + " created more than once!"); + } + Lazy l = self.getSynthesized(attribute); + Decorable d; + if(l != null) { + try { + d = (Decorable)l.eval(this); + } catch(Throwable t) { + throw new TraceException("While evaling trans '" + self.getNameOfSynAttr(attribute) + "' in " + getDebugID(), t); + } + } else if(self.hasForward()) { + try { + d = forward().evalTrans(attribute, inhsAttribute); + } catch(Throwable t) { + throw new TraceException("While evaling trans '" + self.getNameOfSynAttr(attribute) + "' via forward in " + getDebugID(), t); + } + } else { + l = self.getDefaultSynthesized(attribute); + if(l != null) { + try { + d = (Decorable)l.eval(this); + } catch(Throwable t) { + throw new TraceException("While evaling default for trans '" + self.getNameOfSynAttr(attribute) + "' in " + getDebugID(), t); + } + } else { + throw new MissingDefinitionException("Translation attribute '" + self.getNameOfSynAttr(attribute) + "' not defined in " + getDebugID()); + } + } + Lazy[] inhs = null; + if (inheritedAttributes != null && inheritedAttributes[inhsAttribute] != null) { + if (inheritedAttributes[inhsAttribute] instanceof TransInhs) { + inhs = ((TransInhs)inheritedAttributes[inhsAttribute]).inhs; + } else { + throw new SilverInternalError("Supplied trans inhs attribute not TransInhs!"); + } + } + DecoratedNode result = d.decorate(parent, inhs); + transCreated[attribute] = true; + return result; + } + /** * Get the forwarded-to DecoratedNode. Cached. There is no need for an "AsIs" vs "Decorated" * variant of this function, since we always know it's a Node. @@ -411,11 +633,27 @@ public DecoratedNode forwardOrThis() { */ private final DecoratedNode evalForward() { try { - return self.evalForward(this).decorate(parent, this); + return self.evalForward(this).decorate( + parent, getForwardInheritedAttributes(), this, true); } catch(Throwable t) { throw handleFwdError(t); } } + + private final Lazy[] getForwardInheritedAttributes() { + Lazy[] forwardInhs = self.getForwardInheritedAttributes(); + if(forwardInhs == null) return null; + Lazy[] result = new Lazy[self.getNumberOfInhAttrs()]; + for(int i = 0; i < result.length; i++) { + Lazy l = forwardInhs[i]; + if (l != null) { + // The Lazys in self.getForwardInheritedAttributes expect this (forwarding) DecoratedNode as context, + // but will be passed the parent of this node instead. + result[i] = l.withContext(this); + } + } + return result; + } private final RuntimeException handleFwdError(Throwable t) { return new TraceException("While evaling forward equation in " + getDebugID(), t); @@ -425,10 +663,8 @@ private final RuntimeException handleFwdError(Throwable t) { * Get the value of an inherited attribute on this DN. First, try the inherited attributes we were given. * If that fails, ask our {@link #forwardParent}, if any, for whatever they may give us. * - * @param attribute The full name of the attribute. + * @param attribute The index of the attribute. * @return The value of the attribute. - * - * @see #inheritedForwarded(String) */ @SuppressWarnings("unchecked") public T inherited(final int attribute) { @@ -451,23 +687,28 @@ public T inherited(final int attribute) { } private final Object evalInhSomehow(final int attribute) { - if(forwardParent == null) + // We specifically have to check here for inheritedAttributes == null, because + // that's what happens when we don't supply any inherited attributes... + // That is, unlike the unconditional access earlier for inheritedValues[attribute] + // (which could be null if *no inherited attributes occur at all* on this + // node), this could be the result of correctly compiled, but wrongly written user + // code. + if(inheritedAttributes != null && inheritedAttributes[attribute] != null) return evalInhHere(attribute); else return evalInhViaFwdP(attribute); } private final Object evalInhViaFwdP(final int attribute) { try { - return forwardParent.inheritedForwarded(attribute); + return forwardParent.inherited(attribute); } catch(Throwable t) { throw handleInhFwdPError(attribute, t); } } private final SilverException handleInhFwdPError(final int attribute, Throwable t) { - //This seems impossible since we're checking if forwardParent==null earlier up there! - //if(forwardParent == null) { - // return new MissingDefinitionException("Inherited attribute '" + self.getNameOfInhAttr(attribute) + "' not provided to " + getDebugID() + " by " + parent.getDebugID()); - //} + if(forwardParent == null) { + return new MissingDefinitionException("Inherited attribute '" + self.getNameOfInhAttr(attribute) + "' not provided to " + getDebugID() + " by " + parent.getDebugID()); + } return new TraceException("While evaling inh '" + self.getNameOfInhAttr(attribute) + "' via forward in " + getDebugID(), t); } private final Object evalInhHere(final int attribute) { @@ -478,52 +719,12 @@ private final Object evalInhHere(final int attribute) { } } private final SilverException handleInhHereError(final int attribute, Throwable t) { - // We specifically have to check here for inheritedAttributes == null, because - // that's what happens when we don't supply any inherited attributes... - // That is, unlike the unconditional access earlier for inheritedValues[attribute] - // (which could be null if *no inherited attributes occur at all* on this - // node), this could be the result of correctly compiled, but wrongly written user - // code. - // Also, we need to check for attribute >= inheritedAttributes.length, because - // with inherited occurs-on constraints don't know how big to make the array, - // only the largest supplied attribute index, - // so the user omitting some inherited equations for attributes with higher indices - // could mean the resulting array that we are passed is too short. Sigh. - if(inheritedAttributes == null || attribute >= inheritedAttributes.length || inheritedAttributes[attribute] == null) { - return new MissingDefinitionException("Inherited attribute '" + self.getNameOfInhAttr(attribute) + "' not provided to " + getDebugID() + " by " + parent.getDebugID()); - } + // This seems impossible since we're checking if it has an equation earlier up there! + // if(inheritedAttributes == null || inheritedAttributes[attribute] == null) { + // return new MissingDefinitionException("Inherited attribute '" + self.getNameOfInhAttr(attribute) + "' not provided to " + getDebugID() + " by " + parent.getDebugID()); + // } return new TraceException("While evaling inh '" + self.getNameOfInhAttr(attribute) + "' in " + getDebugID(), t); } - - /** - * Only called by {@link #inherited(String)}, when it doesn't have an inherited attribute, - * and it wants to request that value from this DecorateNode (its {@link #forwardParent}). - * - * @param attribute The full name of the attribute. - * @return The value of the attribute. - */ - protected Object inheritedForwarded(final int attribute) { - // common.Util.stackProbe(); - // System.err.println("TRACE: " + getDebugID() + " demanding FORWARDED inh attribute: " + self.getNameOfInhAttr(attribute)); - - // No cache look up here. There is only one forward production. It will call this method - // a maximum of once for each attribute, since it will cache the result. - - Lazy l = self.getForwardInheritedAttributes(attribute); - if(l == null) { - return inherited(attribute); - } - try { - // No need for caching here, it'll be cached by the inherited() that called us - return l.eval(this); - } catch(Throwable t) { - throw handleInhFwdError(attribute, t); - } - } - - private final SilverException handleInhFwdError(final int attribute, Throwable t) { - return new TraceException("While evaling inh '" + self.getNameOfInhAttr(attribute) + "' for forward in " + getDebugID(), t); - } // The following are very common types of thunks. // We put them here in the runtime to reduce generated jar sizes, @@ -536,6 +737,9 @@ public final Object childDecoratedLazy(final int child) { return new Thunk(() -> this.childDecorated(child)); } + public final Object childUndecoratedLazy(final int child) { + return new Thunk(() -> this.childDecorated(child).undecorate()); + } public final Object childAsIsLazy(final int child) { // childAsIs does not store in the childrenValues array, so... // Straight up use whatever thunk (or not!) is in the node. @@ -599,7 +803,7 @@ public final String getDebugID() { if(self == null) { return ""; } else if(self instanceof silver.core.Alocation) { - DecoratedNode loc = ((silver.core.Alocation)self).getAnno_silver_core_location().decorate(TopNode.singleton, (Lazy[])null); + DecoratedNode loc = ((silver.core.Alocation)self).getAnno_silver_core_location().decorate(); String file = loc.synthesized(silver.core.Init.silver_core_filename__ON__silver_core_Location).toString(); int line = (Integer)loc.synthesized(silver.core.Init.silver_core_line__ON__silver_core_Location); int col = (Integer)loc.synthesized(silver.core.Init.silver_core_column__ON__silver_core_Location); diff --git a/runtime/java/src/common/Decorator.java b/runtime/java/src/common/Decorator.java deleted file mode 100644 index ebc7b292d..000000000 --- a/runtime/java/src/common/Decorator.java +++ /dev/null @@ -1,79 +0,0 @@ -package common; - -import java.util.*; - -import common.exceptions.SilverInternalError; - -/** - * Right now this is an ugly hack for getting autocopy to work properly. - * - *

In the future, this may be extended to support more general kinds of "decorators". - * - * See "Decorated attribute grammars: Attribute evaluation meets strategic programming" - * by Kats, Sloane, Visser to get an idea of what this might look like. - * - * @author tedinski - */ -abstract public class Decorator { - abstract public void decorate(RTTIManager.Prodleton production); - - public static void applyDecorators(List nonterminal, RTTIManager.Prodleton production) { - for( Decorator decorator : nonterminal ) { - decorator.decorate(production); - } - - // STATS: Uncomment to enable statistics - // TODO: OH GOD THIS IS A HACK - //Statistics.hook(); - } - - // Default actions for autocopy - static protected void decorateAutoCopy(final RTTIManager.Prodleton production, final String attribute) { - - // Find the index of the inh attribute on this production's NT - int attrindex; - String[] oi = production.getNonterminalton().getOccursInh(); - attrindex = Arrays.asList(oi).indexOf(attribute); - if(attrindex == -1) - throw new SilverInternalError("Attribute doesn't occur on NT it is supposed to?"); - - // Create the lazy that we'll be putting on children. - Lazy eq = new acLazy(attrindex); - - // Get information about the children - String childTypes[]; - Lazy[][] inheritedAttributes; - childTypes = production.getChildTypes(); - inheritedAttributes = production.getChildInheritedAttributes(); - - for(int i = 0; i < childTypes.length; i++) { - if (childTypes[i] == null) continue; // Not a nonterminal - - String[] occurs; - RTTIManager.Nonterminalton nt = RTTIManager.getNonterminalton(childTypes[i]); - if (nt == null) throw new SilverInternalError("Cannot find nonterminal " + childTypes[i]); - occurs = nt.getOccursInh(); - - int loc = Arrays.asList(occurs).indexOf(attribute); - if(loc != -1) { - // The nonterminal of this child contains the attribute in question - if(inheritedAttributes[i][loc] == null) { - // ... and this production does not define that attribute for this child! - //System.out.println("Applying decorator to child # " + i + " in production " + production.getName() + " which is of type" + childTypes[i].getName()); - inheritedAttributes[i][loc] = eq; - } - } - } - } - - private static class acLazy implements Lazy { - private final int attr; - acLazy(final int s) { - attr = s; - } - public Object eval(common.DecoratedNode context) { - return context.inherited(attr); - } - } - -} diff --git a/runtime/java/src/common/FunctionNode.java b/runtime/java/src/common/FunctionNode.java index f2cb34042..328e43b31 100644 --- a/runtime/java/src/common/FunctionNode.java +++ b/runtime/java/src/common/FunctionNode.java @@ -1,7 +1,6 @@ package common; import common.exceptions.SilverInternalError; -import silver.core.*; /** * FunctionNode is a Node, but with a few methods "removed". @@ -17,6 +16,9 @@ * @see Node */ public abstract class FunctionNode extends Node { + public FunctionNode() { + super(false); + } // Used only when needing origins info on lazily evaluated locals in functions :/ public DecoratedNode decorate(OriginContext originCtx) { @@ -25,6 +27,17 @@ public DecoratedNode decorate(OriginContext originCtx) { return tmp; } + @Override + public final Node evalUndecorate(final DecoratedNode context) { + // Functions should never even have this consulted. Ever. + throw new SilverInternalError("Functions do not undecorate!"); + } + + @Override + public final boolean getLocalIsForward(final int index) { + return false; + } + @Override public final boolean hasForward() { // Functions should never even have this consulted. Ever. @@ -37,7 +50,7 @@ public final Node evalForward(final DecoratedNode context) { } @Override - public final Lazy getForwardInheritedAttributes(final int index) { + public final Lazy[] getForwardInheritedAttributes() { throw new SilverInternalError("Functions do not forward!"); } @@ -47,7 +60,7 @@ public final Lazy getSynthesized(final int index) { } @Override - public Lazy getDefaultSynthesized(int index) { + public final Lazy getDefaultSynthesized(int index) { throw new SilverInternalError("Functions do not possess synthesized attributes! (Requested default for index " + index + ")"); } diff --git a/runtime/java/src/common/IOToken.java b/runtime/java/src/common/IOToken.java index 58ae606d4..ad15230a3 100644 --- a/runtime/java/src/common/IOToken.java +++ b/runtime/java/src/common/IOToken.java @@ -151,9 +151,10 @@ public NIOVal readByteFile(StringCatter filename) { public IOToken writeByteFile(StringCatter filename, byte[] content) { try { File outputFile = new File(filename.toString()); - FileOutputStream outputStream = new FileOutputStream(outputFile); - outputStream.write(content); - outputStream.flush(); + try (FileOutputStream outputStream = new FileOutputStream(outputFile)) { + outputStream.write(content); + outputStream.flush(); + } return this; } catch (Exception e) { throw new RuntimeException(e); diff --git a/runtime/java/src/common/Lazy.java b/runtime/java/src/common/Lazy.java index 2eaf53d4d..f15419d55 100644 --- a/runtime/java/src/common/Lazy.java +++ b/runtime/java/src/common/Lazy.java @@ -13,6 +13,16 @@ public interface Lazy { // TODO: probably make this Lazy... public Object eval(DecoratedNode context); + /** + * Create a Lazy that evaluates in some context and ignores the supplied one. + * + * @param context The context to evaluate in. + * @return A Lazy that evaluates in the supplied context. + */ + public default Lazy withContext(final DecoratedNode context) { + return (ignoredNewContext) -> eval(context); + } + public static class Trap implements Lazy { String m; diff --git a/runtime/java/src/common/Node.java b/runtime/java/src/common/Node.java index a47067576..8caccd42d 100644 --- a/runtime/java/src/common/Node.java +++ b/runtime/java/src/common/Node.java @@ -1,5 +1,8 @@ package common; +import common.exceptions.SilverException; +import common.exceptions.TraceException; + /** * Node represents undecorated nodes. That is, we have children, but no inherited attributes, yet. * @@ -11,6 +14,12 @@ * @see DecoratedNode */ public abstract class Node implements Decorable, Typed { + public final boolean isUnique; + + protected Node(final boolean isUnique) { + this.isUnique = isUnique; + } + // Common manipulators of Node objects. /** @@ -18,16 +27,19 @@ public abstract class Node implements Decorable, Typed { * (child and local) * * @param parent The DecoratedNode creating this one. (Whether this is a child or a local (or other) of that node.) - * @param inhs A map from attribute names to Lazys that define them. These Lazys will be supplied with 'parent' as their context for evaluation. + * @param inhs A map from attribute indexes to Lazys that define them. These Lazys will be supplied with 'parent' as their context for evaluation. + * @param transInhs A map from trans (syn) attribute indexes, to maps from inh attribute indexes to Lazys that define them. + * These Lazys will be supplied with 'parent' as their context for evaluation. * @return A "decorated" form of this Node */ @Override - public final DecoratedNode decorate(final DecoratedNode parent, final Lazy[] inhs) { + public DecoratedNode decorate( + final DecoratedNode parent, final Lazy[] inhs) { return new DecoratedNode(getNumberOfChildren(), getNumberOfInhAttrs(), getNumberOfSynAttrs(), getNumberOfLocalAttrs(), - this, parent, inhs, null); + this, parent, inhs, null, false); } /** @@ -35,17 +47,26 @@ public final DecoratedNode decorate(final DecoratedNode parent, final Lazy[] inh * (fwd only) * * @param parent The "true parent" of this node (same as the fwdParent's parent) - * @param fwdParent The DecoratedNode that forwards to the one we are about to create. We will pass inherited attribute access requests to this node. + * @param inhs Overrides for inherited attributes that should not be computed via forwarding. + * These Lazys will be supplied with 'parent' as their context for evaluation. + * @param transInhs Overrides for inherited attributes on translation attributes that should not be computed via forwarding. + * These Lazys will be supplied with 'parent' as their context for evaluation. + * @param fwdParent The DecoratedNode that forwards to the one we are about to create. + * We will pass inherited attribute access requests to this node. + * @param prodFwrd Is this the forward for fwdParent's prod? False for forward prod attributes. * @return A "decorated" form of this Node */ - public final DecoratedNode decorate(final DecoratedNode parent, final DecoratedNode fwdParent) { + @Override + public DecoratedNode decorate( + final DecoratedNode parent, final Lazy[] inhs, + final DecoratedNode fwdParent, final boolean isProdForward) { return new DecoratedNode(getNumberOfChildren(), getNumberOfInhAttrs(), getNumberOfSynAttrs(), getNumberOfLocalAttrs(), - this, parent, null, fwdParent); + this, parent, inhs, fwdParent, isProdForward); } - + /** * A convenience method unused by generate Silver code, but useful when working with * the Silver runtime from Java. @@ -53,7 +74,26 @@ public final DecoratedNode decorate(final DecoratedNode parent, final DecoratedN * @return A node decorated with no inherited attributes, without a parent. */ public DecoratedNode decorate() { - return decorate(TopNode.singleton, (Lazy[])null); + return decorate(TopNode.singleton, null); + } + + private Node undecoratedValue = null; + public final Node undecorate(final DecoratedNode context) { + if (undecoratedValue == null) { + try { + undecoratedValue = evalUndecorate(context); + } catch(Throwable t) { + throw handleUndecorateError(context, t); + } + } + return undecoratedValue; + } + + /** + * Attempt at factoring out the slow path. + */ + private final SilverException handleUndecorateError(final DecoratedNode context, final Throwable t) { + return new TraceException("While undecorating " + context.getDebugID(), t); } // These methods are to be provided by the *nonterminal* @@ -144,9 +184,18 @@ public DecoratedNode decorate() { * @return The child object, WITHOUT forcing the Thunk, if any. */ public abstract Object getChildLazy(final int child); + + /** + * Access the decorated form of this child through its reference decoration site, if it has one. + * + * @param child A number in the range 0 - getNumberofChildren() + * @return A Lazy to evaluate on a decorated form of this Node, to get the decorated child, + * or null if it has no reference decoration site + */ + public abstract Lazy getChildDecSite(final int child); /** - * @param key The child index to look up the inherited attributes. + * @param index The child index to look up the inherited attributes. * @return An array containing the inherited attributes supplied to that child */ public abstract Lazy[] getChildInheritedAttributes(final int index); @@ -172,6 +221,21 @@ public DecoratedNode decorate() { */ public abstract Lazy getLocal(final int index); + /** + * Access the decorated form of this local through its reference decoration site, if it has one. + * + * @param index The index of a local or production attribute on this Node + * @return A Lazy to evaluate on a decorated form of this Node, to get the decorated local, + * or null if it has no reference decoration site + */ + public abstract Lazy getLocalDecSite(final int index); + + /** + * @param index The index of a local or production attribute on this Node + * @return true if this is a forward production attribute. + */ + public abstract boolean getLocalIsForward(final int index); + /** * @param key The index for a local, to retrieve inherited attributes for. * @return An array containing the inherited attributes supplied to that local @@ -181,7 +245,7 @@ public DecoratedNode decorate() { /** * Reports whether or not this production forwards. * - * @return true is {@link #evalForward} can be called, false if that immediately throws. + * @return true if {@link #evalForward} can be called, false if that immediately throws. */ public abstract boolean hasForward(); @@ -193,14 +257,21 @@ public DecoratedNode decorate() { * @return The Node that context forwards to. */ public abstract Node evalForward(final DecoratedNode context); + + /** + * Compute the term that this Node undecorates to. + * + * @param context The DN of this node, to use to evaluate the undecorate equation. + * @return The Node that context undecorates to. + */ + public abstract Node evalUndecorate(final DecoratedNode context); /** * Get any overridden attributes for this node's forward. (e.g. forwarding with { inh = foo; }) * - * @param index The inherited attribute requested by a forwarded-to Node. * @return A Lazy to evaluate on a decorated form of this Node, to get the value of this attribute provided to the forward. */ - public abstract Lazy getForwardInheritedAttributes(final int index); + public abstract Lazy[] getForwardInheritedAttributes(); /** * @param index Any synthesized attribute on this Node diff --git a/runtime/java/src/common/NodeFactory.java b/runtime/java/src/common/NodeFactory.java index 578e63155..8c0cea73c 100644 --- a/runtime/java/src/common/NodeFactory.java +++ b/runtime/java/src/common/NodeFactory.java @@ -1,8 +1,5 @@ package common; -import silver.core.NOriginInfo; - - /** * NodeFactories are used when we take references to Silver functions. * @@ -17,7 +14,7 @@ public abstract class NodeFactory implements Typed { * @return The return value (or node constructed.) */ public abstract T invoke(final common.OriginContext originCtx, final Object[] args, final Object[] namedArgs); - + // Below are just utilities /** diff --git a/runtime/java/src/common/OriginContext.java b/runtime/java/src/common/OriginContext.java index af8ec76c1..80e14c786 100644 --- a/runtime/java/src/common/OriginContext.java +++ b/runtime/java/src/common/OriginContext.java @@ -2,10 +2,6 @@ import silver.core.*; -import java.util.*; - -import common.exceptions.*; - /** * Implementation of "the stuff on the left of the turnstile" that needs to be @@ -115,4 +111,4 @@ public Object attrAccessCopyPolyThunk(final Object t) { else return attrAccessCopyPoly(t); } -} \ No newline at end of file +} diff --git a/runtime/java/src/common/OriginsUtil.java b/runtime/java/src/common/OriginsUtil.java index 990ca3c66..524ff195a 100644 --- a/runtime/java/src/common/OriginsUtil.java +++ b/runtime/java/src/common/OriginsUtil.java @@ -36,7 +36,7 @@ private static String pySanitize(String arg) { private static String sexprifyObj(List seen, Object arg) { - if (arg instanceof DecoratedNode) arg = ((DecoratedNode)arg).undecorate(); + if (arg instanceof DecoratedNode) arg = ((DecoratedNode)arg).getNode(); String id = ids(arg); if (seen.contains(id)) return "[" + id + "]"; @@ -83,7 +83,7 @@ else if (arg instanceof Terminal){ r += sexprifyObj(seen, cc.head()); r += ","; next = cc.tail(); - if (next instanceof DecoratedNode) next = ((DecoratedNode)next).undecorate(); + if (next instanceof DecoratedNode) next = ((DecoratedNode)next).getNode(); if (!(next instanceof ConsCell)) { throw new SilverInternalError("ConsCell.tail() evaluated to not a ConsCell"); } @@ -115,7 +115,7 @@ public static NOriginInfo getOriginOrNull(final Object arg) { // Implementation of the stdlib origins helpers public static silver.core.NMaybe polyGetOrigin(Object o) { - if (o instanceof DecoratedNode) o = ((DecoratedNode)o).undecorate(); + if (o instanceof DecoratedNode) o = ((DecoratedNode)o).getNode(); NOriginInfo r = getOriginOrNull(o); if (r == null) return new silver.core.Pnothing(); return new silver.core.Pjust(r); diff --git a/runtime/java/src/common/RTTIManager.java b/runtime/java/src/common/RTTIManager.java index 57240efb1..debddc6a4 100644 --- a/runtime/java/src/common/RTTIManager.java +++ b/runtime/java/src/common/RTTIManager.java @@ -16,7 +16,6 @@ * * This is used for the following: * - silver reflection (and transitively, reflective de/serialization, rewriting stuff, etc) - * - decorators (read: implementing autocopy) * - native de/serialization (see Reflection.java:nativeSerialize) * * @author louisg @@ -90,7 +89,7 @@ public abstract T constructDirect( public abstract int getAnnoCount(); public abstract String[] getChildTypes(); - public abstract Lazy[][] getChildInheritedAttributes(); + public abstract Lazy[][] getChildInheritedAttributes(); // Originally for autocopy, not currently used } // Represents a terminal (not an instance of the terminal, but the terminal itself.) diff --git a/runtime/java/src/common/Reflection.java b/runtime/java/src/common/Reflection.java index 3b4fbdcd6..c0fd882fa 100644 --- a/runtime/java/src/common/Reflection.java +++ b/runtime/java/src/common/Reflection.java @@ -281,7 +281,7 @@ public static NEither applyAST(final OriginContext ctx, final NAST fn, final Con FunctionTypeRep fnType = (FunctionTypeRep)a; List params = typeArgs.subList(0, fnType.params); List namedParamTypes = typeArgs.subList(fnType.params, fnType.params + fnType.namedParams.length); - TypeRep resultType = typeArgs.get(fnType.params + fnType.namedParams.length); + //TypeRep resultType = typeArgs.get(fnType.params + fnType.namedParams.length); final ConsCell rules = ctx.rulesAsSilverList(); @@ -320,12 +320,12 @@ public static NEither applyAST(final OriginContext ctx, final NAST fn, final Con final Object[] reorderedNamedArgs = new Object[fnType.namedParams.length]; for (ConsCell current = namedArgs; !current.nil(); current = current.tail()) { final NPair entry = (NPair)current.head(); - final String name = entry.getChild(0).toString(); + final String name = entry.getAnno_silver_core_fst().toString(); int index = Arrays.asList(fnType.namedParams).indexOf(name); if (index == -1) { return new Pleft(new StringCatter("Unexpected named argument " + name)); } - final NMaybe item = (NMaybe)entry.getChild(1); + final NMaybe item = (NMaybe)entry.getAnno_silver_core_snd(); if (item instanceof Pjust) { Object o; try { @@ -450,7 +450,7 @@ public static NEither nativeSerialize(Object x) { if (prodset.size() > 1<<15) throw new NativeSerializationException("Too many productions for native serialize"); o.writeShort(prodset.size()); // Write lookup table size - for (RTTIManager.Prodleton p : prodset) { // Write lookup table. For each prod: + for (RTTIManager.Prodleton p : prodset) { // Write lookup table. For each prod: o.writeUTF(p.getName()); // fully qualified silver prod name o.writeUTF(p.getTypeUnparse()); // opaque typerep } diff --git a/runtime/java/src/common/Statistics.java b/runtime/java/src/common/Statistics.java index 54b7fe46e..8ba1dbef6 100644 --- a/runtime/java/src/common/Statistics.java +++ b/runtime/java/src/common/Statistics.java @@ -6,7 +6,6 @@ public class Statistics extends Thread { // Enabling: // Uncomment the two things in both DecoratedNode and Node and Thunk. - // Also, as an ugly hack to make this all-runtime, uncomment the thing in Decorator. :( protected static boolean hooked = false; diff --git a/runtime/java/src/common/Terminal.java b/runtime/java/src/common/Terminal.java index 369491ec2..b20d0205f 100644 --- a/runtime/java/src/common/Terminal.java +++ b/runtime/java/src/common/Terminal.java @@ -42,8 +42,7 @@ public Terminal(final StringCatter lexeme, final NLocation location) { // It'd be nice to just directly access its children, but we don't actually know // that our NLocation is Ploc. :( private Object getFromLoc(int syn) { - DecoratedNode d = location.decorate(TopNode.singleton, (Lazy[])null); - return d.synthesized(syn); + return location.synthesized(syn); } public Integer getLine() { return (Integer)getFromLoc(silver.core.Init.silver_core_line__ON__silver_core_Location); @@ -68,10 +67,7 @@ public Integer getEndOffset() { } // This is a utility that I put here because why not. Perhaps it should be moved? - public static NLocation span(final NLocation a, final NLocation b) { - final DecoratedNode x = a.decorate(TopNode.singleton, (Lazy[])null); - final DecoratedNode y = b.decorate(TopNode.singleton, (Lazy[])null); - + public static NLocation span(final NLocation x, final NLocation y) { return new Ploc(x.synthesized(silver.core.Init.silver_core_filename__ON__silver_core_Location), x.synthesized(silver.core.Init.silver_core_line__ON__silver_core_Location), x.synthesized(silver.core.Init.silver_core_column__ON__silver_core_Location), diff --git a/runtime/java/src/common/Thunk.java b/runtime/java/src/common/Thunk.java index ffcc6402a..6faf6d3a1 100644 --- a/runtime/java/src/common/Thunk.java +++ b/runtime/java/src/common/Thunk.java @@ -1,5 +1,8 @@ package common; +import common.exceptions.CycleException; +import common.exceptions.CycleTraceException; + /** * A thunk that ensures an expression is evaluated once, and memoizes the result. * @@ -17,6 +20,9 @@ public static interface Evaluable { // Either T or Evaluable private Object o; + // Used to check if we are about to demand a thunk that we are currently evaluating + private int demanded = 0; + public Thunk(final Evaluable e) { assert(e != null); o = e; @@ -25,11 +31,37 @@ public Thunk(final Evaluable e) { @SuppressWarnings("unchecked") public T eval() { if(o instanceof Evaluable) { - o = ((Evaluable)o).eval(); - assert(o != null); + doEval(); } return (T)o; } + @SuppressWarnings("unchecked") + private void doEval() { + demanded++; + if(demanded > 1) { + handleCycleError(); + } + try { + o = ((Evaluable)o).eval(); + } catch(Throwable t) { + traceCycleError(t); + } + assert(o != null); + } + private void handleCycleError() { + throw new CycleException("Cycle detected in execution"); + } + private void traceCycleError(Throwable t) { + // If we caught a cycle, report the start of it here. + // Otherwise just re-throw the exception. + if (demanded > 1) { + throw new CycleTraceException("Cycle begins here", t); + } else if (t instanceof RuntimeException) { + throw (RuntimeException)t; + } else { + throw new RuntimeException(t); + } + } public static Thunk fromLazy(Lazy l, DecoratedNode ctx) { return new Thunk(() -> l.eval(ctx)); diff --git a/runtime/java/src/common/TopNode.java b/runtime/java/src/common/TopNode.java index 453c12633..8e028360f 100644 --- a/runtime/java/src/common/TopNode.java +++ b/runtime/java/src/common/TopNode.java @@ -17,7 +17,7 @@ public class TopNode extends DecoratedNode{ // TODO: this should become a Node! public static final TopNode singleton = new TopNode(); private TopNode() { - super(0,0,0,0,null,null,null,null); + super(0,0,0,0,null,null,null,null,false); this.originCtx = OriginContext.GLOBAL_CONTEXT; } @@ -27,13 +27,13 @@ public final DecoratedNode decorate(final DecoratedNode parent, final Lazy[] inh } @Override - public T inherited(final int attribute) { - throw new SilverInternalError("No inherited attributes given to TopNode."); + public final DecoratedNode decorate(final DecoratedNode parent, final Lazy[] inhs, final DecoratedNode fwdParent, final boolean prodFwrd) { + throw new SilverInternalError("TopNode cannot be decorated."); } @Override - protected Object inheritedForwarded(final int attribute) { - throw new SilverInternalError("TopNode does not provided inherited attributes."); + public T inherited(final int attribute) { + throw new SilverInternalError("No inherited attributes given to TopNode."); } @Override diff --git a/runtime/java/src/common/Tracked.java b/runtime/java/src/common/Tracked.java index 5803142ee..2779a65f3 100644 --- a/runtime/java/src/common/Tracked.java +++ b/runtime/java/src/common/Tracked.java @@ -1,15 +1,56 @@ package common; import silver.core.NOriginInfo; +import silver.core.PoriginOriginInfo; +import silver.core.PoriginAndRedexOriginInfo; +import silver.core.PoriginDbgNote; public interface Tracked { public abstract NOriginInfo getOrigin(); - public abstract Object duplicate(Object redex, Object rule); + /** + * Deep copy, setting the redex at the root and the notes everywhere + */ + public abstract Tracked duplicate(Node redex, ConsCell notes); - public abstract Object duplicate(OriginContext oc); + public default Tracked duplicate(OriginContext oc) { + return this.duplicate(oc.lhs, oc.rulesAsSilverList()); + } - public abstract Object duplicateForForwarding(Object redex, String note); + /** + * Shallow copy, updating the origin info. + */ + public abstract Tracked updateOriginInfo(NOriginInfo oi); - public abstract Object copy(Object redex, Object rule); + public default Tracked copy(Node redex, ConsCell redexNotes) { + Object origin; + ConsCell originNotes; + Boolean newlyConstructed; + NOriginInfo roi = getOrigin(); + if (roi instanceof PoriginOriginInfo) { + PoriginOriginInfo oi = (PoriginOriginInfo)roi; + origin = oi.getChild_origin(); + originNotes = oi.getChild_originNotes(); + newlyConstructed = oi.getChild_newlyConstructed(); + } else if (roi instanceof PoriginAndRedexOriginInfo) { + PoriginAndRedexOriginInfo oi = (PoriginAndRedexOriginInfo)roi; + origin = oi.getChild_origin(); + originNotes = oi.getChild_originNotes(); + newlyConstructed = oi.getChild_newlyConstructed(); + } else { + return this; + } + + return updateOriginInfo( + new PoriginAndRedexOriginInfo( + OriginsUtil.SET_AT_ACCESS_OIT, + origin, originNotes, redex, redexNotes, newlyConstructed)); + } + + public default Tracked duplicateForForwarding(Node redex, String note) { + return updateOriginInfo( + new PoriginOriginInfo( + OriginsUtil.SET_AT_FORWARDING_OIT, + this, new ConsCell(new PoriginDbgNote(new StringCatter(note)), ConsCell.nil), true)); + } } \ No newline at end of file diff --git a/runtime/java/src/common/TransInhs.java b/runtime/java/src/common/TransInhs.java new file mode 100644 index 000000000..84aab3550 --- /dev/null +++ b/runtime/java/src/common/TransInhs.java @@ -0,0 +1,33 @@ +package common; + +import common.exceptions.SilverInternalError; + +/** + * Represents the inherited attributes supplied to a translation attribute. + * + *

This class pretends to be a Lazy, so that it can hide in the inherited + * attribute array passed for decoration. But it should never be evaluated! + * + * @author krame505 + */ +public class TransInhs implements Lazy { + public final Lazy[] inhs; + + public TransInhs(final int ni) { + inhs = new Lazy[ni]; + } + + @Override + public Object eval(DecoratedNode context) { + throw new SilverInternalError("TransInhs should never be evaluated!"); + } + + @Override + public TransInhs withContext(final DecoratedNode context) { + TransInhs result = new TransInhs(inhs.length); + for(int i = 0; i < inhs.length; i++) { + result.inhs[i] = inhs[i].withContext(context); + } + return result; + } +} diff --git a/runtime/java/src/common/Util.java b/runtime/java/src/common/Util.java index 1381c119a..5590af164 100644 --- a/runtime/java/src/common/Util.java +++ b/runtime/java/src/common/Util.java @@ -190,7 +190,7 @@ public static int genInt() { public static void printStackCauses(Throwable e) { freeThisToPrintErrors = null; - System.err.println("\nAn error occured. Silver stack trace follows. (To see full traces including java elements, SILVERTRACE=1)\n"); + System.err.println("\nAn error occurred. Silver stack trace follows. (To see full traces including java elements, SILVERTRACE=1)\n"); if(! "1".equals(System.getenv("SILVERTRACE"))) { Throwable t = e; @@ -201,7 +201,9 @@ public static void printStackCauses(Throwable e) { if(msg == null) // Some exceptions have no message... apparently. msg = t.toString(); - if(st.length == 0) { + if(t instanceof CycleTraceException) { + System.err.println("\tCycle begins here:"); + } else if(st.length == 0) { // Some exceptions don't seem to occur anywhere... somehow. System.err.println("(??): " + msg); } else if(st[0].getClassName().startsWith("common.")) { @@ -337,8 +339,8 @@ private static void hackyhackyUnparseObject(Object o, StringBuilder sb) { if(o instanceof Node) { hackyhackyUnparseNode((Node)o, sb); } else if(o instanceof DecoratedNode) { - // For the time being, just undecorate it - hackyhackyUnparseNode(((DecoratedNode)o).undecorate(), sb); + // For the time being, just grab the underlying Node (don't copy-undecorate!) + hackyhackyUnparseNode(((DecoratedNode)o).getNode(), sb); } else if(o instanceof Terminal) { Terminal t = (Terminal) o; sb.append("'" + t.lexeme + "'"); @@ -356,13 +358,25 @@ private static void hackyhackyUnparseObject(Object o, StringBuilder sb) { } private static void hackyhackyUnparseNode(Node n, StringBuilder sb) { sb.append(n.getName() + "("); - for(int i = 0; i < n.getNumberOfChildren(); i++) { + int nc = n.getNumberOfChildren(); + for(int i = 0; i < nc; i++) { if(i != 0) { sb.append(", "); } hackyhackyUnparseObject(n.getChild(i), sb); //System.out.println(sb.toString()); } + String[] annos = n.getAnnoNames(); + for(int i = 0; i < annos.length; i++) { + if(!annos[i].equals("silver:core:location")) { + if(nc != 0 || i != 0) { + sb.append(", "); + } + sb.append(annos[i] + "="); + hackyhackyUnparseObject(n.getAnno(annos[i]), sb); + //System.out.println(sb.toString()); + } + } sb.append(")"); } private static void hackyhackyUnparseList(ConsCell c, StringBuilder sb) { @@ -413,7 +427,7 @@ public static NParseResult callCopperParser(SilverCopperParser pars NParseError err = new PunknownParseError(new StringCatter(e.getMessage()), file); return new PparseFailed(err, null); } catch(Throwable t) { - throw new TraceException("An error occured while parsing", t); + throw new TraceException("An error occurred while parsing", t); } } @@ -437,8 +451,8 @@ private static Object getTerminals(SilverCopperParser parser) { private static NTerminalDescriptor terminalToTerminalDescriptor(Terminal t) { return new PterminalDescriptor(t.lexeme, convertStrings(Arrays.stream(t.getLexerClasses()).iterator()), - new StringCatter(t.getName()), - Terminal.extractLocation(t)); + Terminal.extractLocation(t), + new StringCatter(t.getName())); } /** diff --git a/runtime/java/src/common/exceptions/CycleException.java b/runtime/java/src/common/exceptions/CycleException.java new file mode 100644 index 000000000..67de0f99d --- /dev/null +++ b/runtime/java/src/common/exceptions/CycleException.java @@ -0,0 +1,14 @@ +package common.exceptions; + +/** + * CycleException occurs when we detect a cycle in attribute evaluation. + * + * @author krame505 + */ +@SuppressWarnings("serial") +public class CycleException extends SilverError { + + public CycleException(String s) { + super(s); + } +} diff --git a/runtime/java/src/common/exceptions/CycleTraceException.java b/runtime/java/src/common/exceptions/CycleTraceException.java new file mode 100644 index 000000000..21a9405b9 --- /dev/null +++ b/runtime/java/src/common/exceptions/CycleTraceException.java @@ -0,0 +1,14 @@ +package common.exceptions; + +/** + * Cycle trace exceptions introduce a note on where the cycle begins in the stack trace when a cycle is detected. + * + * @author krame505 + */@SuppressWarnings("serial") +public class CycleTraceException extends ThunkTraceException { + + public CycleTraceException(String s, Throwable t) { + super(s, t); + } + +} diff --git a/runtime/java/src/common/exceptions/SilverException.java b/runtime/java/src/common/exceptions/SilverException.java index 2c2904e00..81e197a69 100644 --- a/runtime/java/src/common/exceptions/SilverException.java +++ b/runtime/java/src/common/exceptions/SilverException.java @@ -11,6 +11,7 @@ *

    *
  • MissingDefinitionException - demanded something the user didn't define *
  • PatternMatchFailure - pattern matching failure (NOT YET IMPLEMENTED) + *
  • CycleException - detected a cycle in attribute evaluation *
*
  • TraceException - documentation about what triggered the error. *