Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom placeholders #107

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
28 changes: 17 additions & 11 deletions lwb/metalang/cfg/cfg.spoofax2/syntax/part/language.sdf3
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,27 @@ imports
context-free sorts

Sdf3Option Sdf3Source Sdf3FilesOption Sdf3PrebuiltOption
Sdf3ParseTableGeneratorOption
Sdf3ParseTableGeneratorOption Sdf3PlaceholderOption

context-free syntax

Part.Sdf3Section = <sdf3 {
<{Sdf3Option "\n"}*>
}>
Sdf3Option.Sdf3Source = <source = <Sdf3Source>>

Sdf3Source.Sdf3Files = <files {
<{Sdf3FilesOption "\n"}*>
}>
Sdf3FilesOption.Sdf3FilesMainSourceDirectory = <main-source-directory = <Expr>>
Sdf3FilesOption.Sdf3FilesMainFile = <main-file = <Expr>>

Sdf3Source.Sdf3Prebuilt = <prebuilt {
<{Sdf3PrebuiltOption "\n"}*>
}>
Sdf3PrebuiltOption.Sdf3PrebuiltParseTableAtermFile = <parse-table-aterm-file = <Expr>>
Sdf3PrebuiltOption.Sdf3PrebuiltParseTablePersistedFile = <parse-table-persisted-file = <Expr>>

// TODO: move into source after CC lab.
Sdf3Option.Sdf3ParseTableGeneratorSection = <parse-table-generator {
<{Sdf3ParseTableGeneratorOption "\n"}*>
Expand All @@ -40,6 +40,12 @@ context-free syntax
Sdf3ParseTableGeneratorOption.Sdf3ParseTableGeneratorCheckOverlap = <check-overlap = <Expr>>
Sdf3ParseTableGeneratorOption.Sdf3ParseTableGeneratorCheckPriorities = <check-priorities = <Expr>>

Sdf3Option.Sdf3PlaceholderSection = <placeholder {
<{Sdf3PlaceholderOption "\n"}*>
}>
Sdf3PlaceholderOption.Sdf3PlaceholderPrefix = <prefix = <Expr>>
Sdf3PlaceholderOption.Sdf3PlaceholderSuffix = <suffix = <Expr>>

context-free sorts

EsvOption EsvSource EsvFilesOption EsvPrebuiltOption
Expand All @@ -50,15 +56,15 @@ context-free syntax
<{EsvOption "\n"}*>
}>
EsvOption.EsvSource = <source = <EsvSource>>

EsvSource.EsvFiles = <files {
<{EsvFilesOption "\n"}*>
}>
EsvFilesOption.EsvFilesMainSourceDirectory = <main-source-directory = <Expr>>
EsvFilesOption.EsvFilesMainFile = <main-file = <Expr>>
EsvFilesOption.EsvFilesIncludeDirectory = <include-directory = <Expr>>
EsvFilesOption.EsvFilesIncludeLibspoofax2Exports = <include-libspoofax2-exports = <Expr>>

EsvSource.EsvPrebuilt = <prebuilt {
<{EsvPrebuiltOption "\n"}*>
}>
Expand All @@ -74,14 +80,14 @@ context-free syntax
<{StatixOption "\n"}*>
}>
StatixOption.StatixSource = <source = <StatixSource>>

StatixSource.StatixFiles = <files {
<{StatixFilesOption "\n"}*>
}>
StatixFilesOption.StatixFilesMainSourceDirectory = <main-source-directory = <Expr>>
StatixFilesOption.StatixFilesMainFile = <main-file = <Expr>>
StatixFilesOption.StatixFilesIncludeDirectory = <include-directory = <Expr>>

StatixSource.StatixPrebuilt = <prebuilt {
<{StatixPrebuiltOption "\n"}*>
}>
Expand All @@ -100,16 +106,16 @@ context-free syntax
<{StrategoOption "\n"}*>
}>
StrategoOption.StrategoSource = <source = <StrategoSource>>

StrategoSource.StrategoFiles = <files {
<{StrategoFilesOption "\n"}*>
}>
StrategoFilesOption.StrategoFilesMainSourceDirectory = <main-source-directory = <Expr>>
StrategoFilesOption.StrategoFilesMainFile = <main-file = <Expr>>
StrategoFilesOption.StrategoFilesIncludeDirectory = <include-directory = <Expr>>

// TODO: move into source after CC lab.
StrategoOption.StrategoSdf3StatixExplicationGen = <sdf3-statix-explication-generation = <Expr>>

StrategoOption.StrategoLanguageStrategyAffix = <language-strategy-affix = <Expr>>
StrategoOption.StrategoOutputJavaPackageId = <output-java-package = <Expr>>
61 changes: 36 additions & 25 deletions lwb/metalang/cfg/cfg.spoofax2/trans/statsem/part/language.stx
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ imports

statsem/part
statsem/expr

signatures/part/language-sig

rules // Sdf3 section and options

partOk(s, Sdf3Section(options)) :- sdf3OptionsOk(s, options).

sdf3OptionOk : scope * Sdf3Option
sdf3OptionsOk maps sdf3OptionOk(*, list(*))

sdf3OptionOk(s, Sdf3Source(source)) :-
sdf3SourceOk(s, source).

sdf3SourceOk : scope * Sdf3Source
sdf3SourceOk(s, Sdf3Files(options)) :- sdf3FilesOptionsOk(s, options).
sdf3SourceOk(s, Sdf3Prebuilt(options)) :- sdf3PrebuiltOptionsOk(s, options).

sdf3FilesOptionOk : scope * Sdf3FilesOption
sdf3FilesOptionsOk maps sdf3FilesOptionOk(*, list(*))
sdf3FilesOptionOk(s, Sdf3FilesMainSourceDirectory(e)) :-
Expand All @@ -37,37 +37,48 @@ rules // Sdf3 section and options

sdf3OptionOk(s, Sdf3ParseTableGeneratorSection(options)) :-
sdf3ParseTableGeneratorOptionsOk(s, options).

sdf3ParseTableGeneratorOptionOk : scope * Sdf3ParseTableGeneratorOption
sdf3ParseTableGeneratorOptionsOk maps sdf3ParseTableGeneratorOptionOk(*, list(*))
sdf3ParseTableGeneratorOptionOk(s, Sdf3ParseTableGeneratorDynamic(e)) :-

sdf3ParseTableGeneratorOptionOk(s, Sdf3ParseTableGeneratorDynamic(e)) :-
typeOfExpr(s, e) == BOOL() | error $[Expected boolean]@e.
sdf3ParseTableGeneratorOptionOk(s, Sdf3ParseTableGeneratorDataDependent(e)) :-
sdf3ParseTableGeneratorOptionOk(s, Sdf3ParseTableGeneratorDataDependent(e)) :-
typeOfExpr(s, e) == BOOL() | error $[Expected boolean]@e.
sdf3ParseTableGeneratorOptionOk(s, Sdf3ParseTableGeneratorLayoutSensitive(e)) :-
sdf3ParseTableGeneratorOptionOk(s, Sdf3ParseTableGeneratorLayoutSensitive(e)) :-
typeOfExpr(s, e) == BOOL() | error $[Expected boolean]@e.
sdf3ParseTableGeneratorOptionOk(s, Sdf3ParseTableGeneratorSolveDeepConflicts(e)) :-
sdf3ParseTableGeneratorOptionOk(s, Sdf3ParseTableGeneratorSolveDeepConflicts(e)) :-
typeOfExpr(s, e) == BOOL() | error $[Expected boolean]@e.
sdf3ParseTableGeneratorOptionOk(s, Sdf3ParseTableGeneratorCheckOverlap(e)) :-
sdf3ParseTableGeneratorOptionOk(s, Sdf3ParseTableGeneratorCheckOverlap(e)) :-
typeOfExpr(s, e) == BOOL() | error $[Expected boolean]@e.
sdf3ParseTableGeneratorOptionOk(s, Sdf3ParseTableGeneratorCheckPriorities(e)) :-
sdf3ParseTableGeneratorOptionOk(s, Sdf3ParseTableGeneratorCheckPriorities(e)) :-
typeOfExpr(s, e) == BOOL() | error $[Expected boolean]@e.

sdf3OptionOk(s, Sdf3PlaceholderSection(options)) :-
sdf3PlaceholderOptionsOk(s, options).

sdf3PlaceholderOptionOk : scope * Sdf3PlaceholderOption
sdf3PlaceholderOptionsOk maps sdf3PlaceholderOptionOk(*, list(*))

sdf3PlaceholderOptionOk(s, Sdf3PlaceholderPrefix(e)) :-
typeOfExpr(s, e) == STRING() | error $[Expected string]@e.
sdf3PlaceholderOptionOk(s, Sdf3PlaceholderSuffix(e)) :-
typeOfExpr(s, e) == STRING() | error $[Expected string]@e.

rules // Esv section and options

partOk(s, EsvSection(options)) :- esvOptionsOk(s, options).

esvOptionOk : scope * EsvOption
esvOptionsOk maps esvOptionOk(*, list(*))

esvOptionOk(s, EsvSource(source)) :-
esvSourceOk(s, source).

esvSourceOk : scope * EsvSource
esvSourceOk(s, EsvFiles(options)) :- esvFilesOptionsOk(s, options).
esvSourceOk(s, EsvPrebuilt(options)) :- esvPrebuiltOptionsOk(s, options).

esvFilesOptionOk : scope * EsvFilesOption
esvFilesOptionsOk maps esvFilesOptionOk(*, list(*))
esvFilesOptionOk(s, EsvFilesMainSourceDirectory(e)) :-
Expand All @@ -87,17 +98,17 @@ rules // Esv section and options
rules // Statix section and options

partOk(s, StatixSection(options)) :- statixOptionsOk(s, options).

statixOptionOk : scope * StatixOption
statixOptionsOk maps statixOptionOk(*, list(*))

statixOptionOk(s, StatixSource(source)) :-
statixSourceOk(s, source).

statixSourceOk : scope * StatixSource
statixSourceOk(s, StatixFiles(options)) :- statixFilesOptionsOk(s, options).
statixSourceOk(s, StatixPrebuilt(options)) :- statixPrebuiltOptionsOk(s, options).

statixFilesOptionOk : scope * StatixFilesOption
statixFilesOptionsOk maps statixFilesOptionOk(*, list(*))
statixFilesOptionOk(s, StatixFilesMainSourceDirectory(e)) :-
Expand All @@ -113,21 +124,21 @@ rules // Statix section and options
typeOfExpr(s, e) == PATH() | error $[Expected path]@e.

statixOptionOk(s, StatixSdf3SignatureGen(e)) :-
typeOfExpr(s, e) == BOOL() | error $[Expected boolean]@e.
typeOfExpr(s, e) == BOOL() | error $[Expected boolean]@e.

rules // Stratego section and options

partOk(s, StrategoSection(options)) :- strategoOptionsOk(s, options).

strategoOptionOk : scope * StrategoOption
strategoOptionsOk maps strategoOptionOk(*, list(*))

strategoOptionOk(s, StrategoSource(source)) :-
strategoSourceOk(s, source).

strategoSourceOk : scope * StrategoSource
strategoSourceOk(s, StrategoFiles(options)) :- strategoFilesOptionsOk(s, options).

strategoFilesOptionOk : scope * StrategoFilesOption
strategoFilesOptionsOk maps strategoFilesOptionOk(*, list(*))
strategoFilesOptionOk(s, StrategoFilesMainSourceDirectory(e)) :-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ public static Output convert(
ptgParts.forOneSubtermAsBool("Sdf3ParseTableGeneratorCheckOverlap", builder::checkOverlapInParseTable);
ptgParts.forOneSubtermAsBool("Sdf3ParseTableGeneratorCheckPriorities", builder::checkPrioritiesInParseTable);
});

subParts.getAllSubTermsInListAsParts("Sdf3PlaceholderSection").ifSome(plhdrParts -> {
plhdrParts.forOneSubtermAsString("Sdf3PlaceholderPrefix", builder::sdf3PlaceholderPrefix);
plhdrParts.forOneSubtermAsString("Sdf3PlaceholderSuffix", builder::sdf3PlaceholderSuffix);
});
});
parts.getAllSubTermsInListAsParts("EsvSection").ifSome(subParts -> {
final CfgEsvConfig.Builder builder = languageCompilerInputBuilder.withEsv();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ default ResourcePath parseTablePersistedOutputFile() {
;
}

@Value.Default default String sdf3PlaceholderPrefix() {
return "$";
}

@Value.Default default String sdf3PlaceholderSuffix() {
return "";
}

/// Automatically provided sub-inputs

Expand Down
18 changes: 16 additions & 2 deletions lwb/metalang/sdf3/sdf3/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,20 @@ fun AdapterProjectCompiler.Input.Builder.configureCompilerInput() {

val showDesugarCommand = showCommand(showDesugar, "desugared")
val showPermissiveCommand = showCommand(showPermissive, "permissive grammar")
val showNormalFormCommand = showCommand(showNormalForm, "normal-form")
//val showNormalFormCommand = showCommand(showNormalForm, "normal-form")
val showNormalFormCommand = CommandDefRepr.builder()
.type(commandPackageId, showNormalForm.id() + "Command")
.taskDefType(showNormalForm)
.argType(showNormalForm.appendToId(".Args"))
.displayName("Show normal form")
.description("Shows normal form")
.addSupportedExecutionTypes(CommandExecutionType.ManualOnce, CommandExecutionType.ManualContinuous)
.addAllParams(listOf(
ParamRepr.of("root", TypeInfo.of("mb.resource.hierarchical", "ResourcePath"), true, ArgProviderRepr.enclosingContext(EnclosingCommandContextType.Project)),
ParamRepr.of("file", TypeInfo.of("mb.resource", "ResourceKey"), true, ArgProviderRepr.context(CommandContextType.File)),
ParamRepr.of("concrete", TypeInfo.ofBoolean(), true)
))
.build()
val showSignatureCommand = showAnalyzedCommand(showSignature, "Stratego signatures")
val showDynsemSignatureCommand = showAnalyzedCommand(showDynsemSignature, "DynSem signatures")

Expand Down Expand Up @@ -243,7 +256,8 @@ fun AdapterProjectCompiler.Input.Builder.configureCompilerInput() {
.description("Shows the parse table built from given main file")
.addSupportedExecutionTypes(CommandExecutionType.ManualOnce, CommandExecutionType.ManualContinuous)
.addAllParams(listOf(
ParamRepr.of("root", TypeInfo.of("mb.resource.hierarchical", "ResourcePath"), true, ArgProviderRepr.enclosingContext(EnclosingCommandContextType.Project))
ParamRepr.of("root", TypeInfo.of("mb.resource.hierarchical", "ResourcePath"), true, ArgProviderRepr.enclosingContext(EnclosingCommandContextType.Project)),
ParamRepr.of("strategyAffix", TypeInfo.ofString(), true)
))
.build()
addCommandDefs(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,53 @@
package mb.sdf3.stratego;

public class Sdf3Context {
import java.io.Serializable;
import java.util.Objects;

/**
* SDF3 context.
*
* Add this context to a Stratego context using {@link mb.stratego.common.StrategoRuntime#addContextObject}.
*/
public final class Sdf3Context implements Serializable {
/** The language specification name as a Stratego qualifier. */
public final String strategoQualifier;
/** The prefix for placeholders; or {@code null} to use the default. */
public final String placeholderPrefix;
/** The suffix for placeholders; or {@code null} to use the default. */
public final String placeholderSuffix;

public Sdf3Context(String strategoQualifier) {
public Sdf3Context(
String strategoQualifier,
String placeholderPrefix,
String placeholderSuffix
) {
this.strategoQualifier = strategoQualifier;
this.placeholderPrefix = placeholderPrefix;
this.placeholderSuffix = placeholderSuffix;
}

@Override public boolean equals(Object o) {
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
Sdf3Context that = (Sdf3Context)o;
return strategoQualifier.equals(that.strategoQualifier)
&& placeholderPrefix.equals(that.placeholderPrefix)
&& placeholderSuffix.equals(that.placeholderSuffix);
}

@Override public int hashCode() {
return Objects.hash(
strategoQualifier,
placeholderPrefix,
placeholderSuffix
);
}

@Override public String toString() {
return "Sdf3Context{" +
"strategoQualifier='" + strategoQualifier + '\'' +
", placeholderPrefix='" + placeholderPrefix + '\'' +
", placeholderSuffix='" + placeholderSuffix + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
public class Sdf3PrimitiveLibrary extends AbstractStrategoOperatorRegistry {
public Sdf3PrimitiveLibrary() {
add(new Sdf3PpLanguageSpecNamePrimitive());
add(new FailingPrimitive("SSL_EXT_placeholder_chars"));
add(new Sdf3SslExtPlaceholderCharsPrimitive());
}

@Override public String getOperatorRegistryName() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package mb.sdf3.stratego;

import org.spoofax.interpreter.library.AbstractPrimitive;
import mb.stratego.common.AdaptableContext;
import org.spoofax.interpreter.core.IContext;
import org.spoofax.interpreter.core.InterpreterException;
import org.spoofax.interpreter.stratego.Strategy;
import org.spoofax.interpreter.terms.IStrategoTerm;
import org.spoofax.interpreter.terms.ITermFactory;

/**
* Returns a tuple with the prefix and suffix, respectively, to use to parse/pretty-print placeholders.
*/
public final class Sdf3SslExtPlaceholderCharsPrimitive extends AbstractPrimitive {

public Sdf3SslExtPlaceholderCharsPrimitive() {
super("SSL_EXT_placeholder_chars", 0, 0);
}

@Override public boolean call(IContext env, Strategy[] svars, IStrategoTerm[] tvars) throws InterpreterException {
final ITermFactory factory = env.getFactory();
try {
final Sdf3Context context = AdaptableContext.adaptContextObject(env.contextObject(), Sdf3Context.class);
env.setCurrent(factory.makeTuple(
factory.makeString(context.placeholderPrefix),
factory.makeString(context.placeholderSuffix)
));
return true;
} catch(RuntimeException e) {
return false; // Context not available; fail
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching all RuntimeExceptions is bad practice, as it catches all kinds of exceptions indicating bugs such as NullPointerException. This will silently hide them, which is very bad.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was based on your own code for Sdf3PpLanguageSpecNamePrimitive.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then that code should be changed as well. I think it should catch AdaptException instead.

}
}
}