Skip to content

Commit

Permalink
Add cfg configuration option for SDF3 placeholder pre/postfix
Browse files Browse the repository at this point in the history
  • Loading branch information
Apanatshka committed Jun 14, 2024
1 parent 203839e commit 567a944
Show file tree
Hide file tree
Showing 20 changed files with 394 additions and 35 deletions.
8 changes: 7 additions & 1 deletion lwb/metalang/cfg/cfg.spoofax2/syntax/part/language.sdf3
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ imports
context-free sorts

Sdf3Option Sdf3Source Sdf3FilesOption Sdf3PrebuiltOption
Sdf3ParseTableGeneratorOption
Sdf3ParseTableGeneratorOption Sdf3PlaceholderOption

context-free syntax

Expand All @@ -26,6 +26,9 @@ context-free syntax
Sdf3FilesOption.Sdf3FilesExportDirectory = <export-directory = <Expr>>
Sdf3FilesOption.Sdf3ParseTableGeneratorSection = <parse-table-generator {
<{Sdf3ParseTableGeneratorOption "\n"}*>
}>
Sdf3FilesOption.Sdf3PlaceholderSection = <placeholders {
<{Sdf3PlaceholderOption "\n"}*>
}>
Sdf3FilesOption.Sdf3StrategoConcreteSyntaxExtensionMainFile = <stratego-concrete-syntax-extension-main-file = <Expr>>

Expand All @@ -36,6 +39,9 @@ context-free syntax
Sdf3ParseTableGeneratorOption.Sdf3ParseTableGeneratorCheckOverlap = <check-overlap = <Expr>>
Sdf3ParseTableGeneratorOption.Sdf3ParseTableGeneratorCheckPriorities = <check-priorities = <Expr>>

Sdf3PlaceholderOption.Sdf3PlaceholderPrefix = <prefix = <Expr>>
Sdf3PlaceholderOption.Sdf3PlaceholderPostfix = <postfix = <Expr>>

Sdf3Source.Sdf3Prebuilt = <prebuilt {
<{Sdf3PrebuiltOption "\n"}*>
}>
Expand Down
10 changes: 10 additions & 0 deletions lwb/metalang/cfg/cfg.spoofax2/trans/statsem/part/language.stx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ rules // Sdf3 section and options
typeOfExpr(s, e) == PATH() | error $[Expected path]@e.
sdf3FilesOptionOk(s, Sdf3ParseTableGeneratorSection(options)) :-
sdf3ParseTableGeneratorOptionsOk(s, options).
sdf3FilesOptionOk(s, Sdf3PlaceholderSection(e)) :-
sdf3PlaceholderOptionsOk(s, e).
sdf3FilesOptionOk(s, Sdf3StrategoConcreteSyntaxExtensionMainFile(e)) :-
typeOfExpr(s, e) == PATH() | error $[Expected path]@e.

Expand All @@ -53,6 +55,14 @@ rules // Sdf3 section and options
sdf3ParseTableGeneratorOptionOk(s, Sdf3ParseTableGeneratorCheckPriorities(e)) :-
typeOfExpr(s, e) == BOOL() | error $[Expected boolean]@e.

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

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

sdf3PrebuiltOptionOk : scope * Sdf3PrebuiltOption
sdf3PrebuiltOptionsOk maps sdf3PrebuiltOptionOk(*, list(*))
sdf3PrebuiltOptionOk(s, Sdf3PrebuiltParseTableAtermFile(e)) :-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ public static Output convert(
ptgParts.forOneSubtermAsBool("Sdf3ParseTableGeneratorCheckOverlap", filesSourceBuilder::checkOverlapInParseTable);
ptgParts.forOneSubtermAsBool("Sdf3ParseTableGeneratorCheckPriorities", filesSourceBuilder::checkPrioritiesInParseTable);
});
filesParts.getAllSubTermsInListAsParts("Sdf3PlaceholderSection").ifSome(ptgParts -> {
ptgParts.forOneSubtermAsString("Sdf3PlaceholderPrefix", filesSourceBuilder::sdf3PlaceholderPrefix);
ptgParts.forOneSubtermAsString("Sdf3PlaceholderPostfix", filesSourceBuilder::sdf3PlaceholderPostfix);
});
filesParts.forAllSubtermsAsExistingFiles("Sdf3StrategoConcreteSyntaxExtensionMainFile", mainSourceDirectory, "SDF3 Stratego concrete syntax extension main file", filesSourceBuilder::addStrategoConcreteSyntaxExtensionMainFiles);
builder.source(CfgSdf3Source.files(filesSourceBuilder.build()));
} else if(TermUtils.isAppl(source, "Sdf3Prebuilt", 1)) {
Expand Down Expand Up @@ -280,6 +284,10 @@ public static Output convert(
final CfgStrategoSource.Files.Builder filesSourceBuilder = compileMetaLanguageSourcesInputBuilder.withStrategoFilesSource();
final ResourcePath mainSourceDirectory = filesParts.getOneSubtermAsExistingDirectory("StrategoFilesMainSourceDirectory", rootDirectory, "Stratego main source directory")
.unwrapOrElse(() -> CfgStrategoSource.Files.Builder.getDefaultMainSourceDirectory(languageShared));
compileMetaLanguageSourcesInputBuilder.sdf3.compileMetaLanguageSourcesShared(languageShared).build().source().getFiles().ifPresent(f -> {
filesSourceBuilder.sdf3PlaceholderPrefix(f.sdf3PlaceholderPrefix());
filesSourceBuilder.sdf3PlaceholderPostfix(f.sdf3PlaceholderPostfix());
});
filesSourceBuilder.mainSourceDirectory(mainSourceDirectory);
filesParts.forOneSubtermAsExistingFile("StrategoFilesMainFile", mainSourceDirectory, "Stratego main file", filesSourceBuilder::mainFile);
filesParts.forAllSubtermsAsExistingDirectories("StrategoFilesIncludeDirectory", rootDirectory, "Stratego include directory", filesSourceBuilder::addIncludeDirectories);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package mb.cfg.metalang;

import mb.cfg.CompileMetaLanguageSourcesShared;
import mb.common.option.Option;
import mb.common.util.ADT;
import mb.resource.hierarchical.ResourcePath;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.immutables.value.Value;
import org.metaborg.util.tuple.Tuple2;

import java.io.Serializable;
import java.util.List;
Expand Down Expand Up @@ -69,6 +71,20 @@ default ResourcePath unarchiveDirectory() {
return false;
}

@Value.Default default @Nullable String sdf3PlaceholderPrefix() { return null; }

@Value.Default default @Nullable String sdf3PlaceholderPostfix() { return null; }

@Value.Derived default Option<Tuple2<String, String>> sdf3Placeholders() {
final @Nullable String prefix = sdf3PlaceholderPrefix();
final @Nullable String suffix = sdf3PlaceholderPostfix();
if(prefix != null || suffix != null) {
return Option.ofSome(Tuple2.of(prefix != null ? prefix : "", suffix != null ? suffix : ""));
} else {
return Option.ofNone();
}
}


/// Automatically provided sub-inputs

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package mb.cfg.metalang;

import mb.cfg.CompileMetaLanguageSourcesShared;
import mb.common.option.Option;
import mb.common.util.ADT;
import mb.resource.hierarchical.ResourcePath;
import mb.spoofax.compiler.adapter.ExportsCompiler;
import mb.spoofax.compiler.language.StrategoRuntimeLanguageCompiler;
import mb.spoofax.compiler.util.BuilderBase;
import mb.spoofax.compiler.util.Conversion;
import mb.spoofax.compiler.util.Shared;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.immutables.value.Value;
import org.metaborg.util.tuple.Tuple2;

import java.io.Serializable;
import java.util.ArrayList;
Expand Down Expand Up @@ -79,6 +80,20 @@ public static ResourcePath getDefaultMainSourceDirectory(CompileMetaLanguageSour
return false;
}

@Value.Default default @Nullable String sdf3PlaceholderPrefix() { return null; }

@Value.Default default @Nullable String sdf3PlaceholderPostfix() { return null; }

@Value.Derived default Option<Tuple2<String, String>> sdf3Placeholders() {
final @Nullable String prefix = sdf3PlaceholderPrefix();
final @Nullable String suffix = sdf3PlaceholderPostfix();
if(prefix != null || suffix != null) {
return Option.ofSome(Tuple2.of(prefix != null ? prefix : "", suffix != null ? suffix : ""));
} else {
return Option.ofNone();
}
}

@Value.Default default String languageStrategyAffix() {
// TODO: convert to Stratego ID instead of Java ID.
return Conversion.nameToJavaId(shared().name().toLowerCase());
Expand Down
26 changes: 25 additions & 1 deletion lwb/metalang/sdf3/sdf3/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,31 @@ fun AdapterProjectCompiler.Input.Builder.configureCompilerInput() {

val showDesugarCommand = showCommand(showDesugar, "desugared")
val showPermissiveCommand = showCommand(showPermissive, "permissive grammar")
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 the normal-form of the file")
.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
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package mb.sdf3.stratego;

import org.metaborg.util.tuple.Tuple2;

import mb.common.option.Option;

public class Sdf3Context {
public final String strategoQualifier;
public final Option<String> strategoQualifier;
public final Option<Tuple2<String, String>> placeholders;

public Sdf3Context(String strategoQualifier) {
public Sdf3Context(Option<String> strategoQualifier, Option<Tuple2<String, String>> placeholders) {
this.strategoQualifier = strategoQualifier;
this.placeholders = placeholders;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package mb.sdf3.stratego;

import java.util.Objects;

import org.metaborg.util.tuple.Tuple2;
import org.spoofax.interpreter.core.IContext;
import org.spoofax.interpreter.core.InterpreterException;
import org.spoofax.interpreter.library.AbstractPrimitive;
import org.spoofax.interpreter.stratego.Strategy;
import org.spoofax.interpreter.terms.IStrategoTerm;
import org.spoofax.interpreter.terms.ITermFactory;

import mb.common.option.Option;
import mb.stratego.common.AdaptException;
import mb.stratego.common.AdaptableContext;

public class Sdf3PlaceholderCharsPrimitive extends AbstractPrimitive {
public Sdf3PlaceholderCharsPrimitive() {
super("SSL_EXT_placeholder_chars", 0, 0);
}

@Override public boolean call(IContext env, Strategy[] svars, IStrategoTerm[] tvars) throws InterpreterException {
try {
final Sdf3Context context = AdaptableContext.adaptContextObject(env.contextObject(), Sdf3Context.class);
final Option<Tuple2<String, String>> placeholders = context.placeholders;
if(placeholders.isNone()) {
return false;
}
final Tuple2<String, String> placeholderChars = Objects.requireNonNull(placeholders.get());
final ITermFactory f = env.getFactory();
env.setCurrent(f.makeTuple(f.makeString(placeholderChars._1()), f.makeString(placeholderChars._2())));
return true;
} catch(AdaptException e) {
return false; // Context not available; fail
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ public Sdf3PpLanguageSpecNamePrimitive() {
@Override public boolean call(IContext env, Strategy[] svars, IStrategoTerm[] tvars) throws InterpreterException {
try {
final Sdf3Context context = AdaptableContext.adaptContextObject(env.contextObject(), Sdf3Context.class);
env.setCurrent(env.getFactory().makeString(context.strategoQualifier));
if(context.strategoQualifier.isNone()) {
return false;
}
env.setCurrent(env.getFactory().makeString(context.strategoQualifier.get()));
return true;
} catch(RuntimeException e) {
return false; // Context not available; fail
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
public class Sdf3PrimitiveLibrary extends AbstractStrategoOperatorRegistry {
public Sdf3PrimitiveLibrary() {
add(new Sdf3PpLanguageSpecNamePrimitive());
add(new FailingPrimitive("SSL_EXT_placeholder_chars"));
add(new Sdf3PlaceholderCharsPrimitive());
add(new Sdf3SpoofaxVersionPrimitive());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
import mb.pie.api.Interactivity;
import mb.pie.api.Supplier;
import mb.sdf3.Sdf3Scope;
import mb.sdf3.task.util.Sdf3StrategoTransformTaskDef;
import mb.stratego.pie.AstStrategoTransformTaskDef;
import org.spoofax.interpreter.terms.IStrategoTerm;

import javax.inject.Inject;
import java.util.Set;

@Sdf3Scope
public class Sdf3ToNormalForm extends AstStrategoTransformTaskDef {
public class Sdf3ToNormalForm extends Sdf3StrategoTransformTaskDef {
@Inject public Sdf3ToNormalForm(Sdf3GetStrategoRuntimeProvider getStrategoRuntimeProvider) {
super(getStrategoRuntimeProvider, "module-to-normal-form");
}
Expand All @@ -20,7 +21,7 @@ public class Sdf3ToNormalForm extends AstStrategoTransformTaskDef {
return getClass().getName();
}

@Override public boolean shouldExecWhenAffected(Supplier<? extends Result<IStrategoTerm, ?>> input, Set<?> tags) {
@Override public boolean shouldExecWhenAffected(Set<?> tags) {
return tags.isEmpty() || tags.contains(Interactivity.NonInteractive);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package mb.sdf3.task;

import mb.common.option.Option;
import mb.common.result.Result;
import mb.pie.api.ExecContext;
import mb.pie.api.Interactivity;
Expand All @@ -10,6 +11,7 @@
import mb.stratego.common.StrategoException;
import mb.stratego.common.StrategoRuntime;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.metaborg.util.tuple.Tuple2;
import org.spoofax.interpreter.terms.IStrategoTerm;

import javax.inject.Inject;
Expand All @@ -23,27 +25,35 @@ public class Sdf3ToPrettyPrinter implements TaskDef<Sdf3ToPrettyPrinter.Input, R
public static class Input implements Serializable {
public final Supplier<? extends Result<IStrategoTerm, ?>> astSupplier;
public final String strategoQualifier;
public final Option<Tuple2<String, String>> placeholders;

public Input(Supplier<? extends Result<IStrategoTerm, ?>> astSupplier, String strategoQualifier) {
public Input(Supplier<? extends Result<IStrategoTerm, ?>> astSupplier, String strategoQualifier,
Option<Tuple2<String, String>> placeholders) {
this.astSupplier = astSupplier;
this.strategoQualifier = strategoQualifier;
this.placeholders = placeholders;
}

public Input(Supplier<? extends Result<IStrategoTerm, ?>> astSupplier, String strategoQualifier) {
this(astSupplier, strategoQualifier, Option.ofNone());
}

@Override public boolean equals(@Nullable Object o) {
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
final Input input = (Input)o;
return astSupplier.equals(input.astSupplier) && strategoQualifier.equals(input.strategoQualifier);
return astSupplier.equals(input.astSupplier) && strategoQualifier.equals(input.strategoQualifier) && placeholders.equals(input.placeholders);
}

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

@Override public String toString() {
return "Input{" +
"astSupplier=" + astSupplier +
", strategoQualifier='" + strategoQualifier + '\'' +
", placeholders='" + placeholders + '\'' +
'}';
}
}
Expand All @@ -60,8 +70,8 @@ public Input(Supplier<? extends Result<IStrategoTerm, ?>> astSupplier, String st
}

@Override public Result<IStrategoTerm, ?> exec(ExecContext context, Input input) throws Exception {
final StrategoRuntime strategoRuntime = strategoRuntimeProvider.get().addContextObject(new Sdf3Context(input.strategoQualifier));
return context.require(input.astSupplier).flatMapOrElse((ast) -> {
final StrategoRuntime strategoRuntime = strategoRuntimeProvider.get().addContextObject(new Sdf3Context(Option.ofSome(input.strategoQualifier), input.placeholders));
try {
ast = strategoRuntime.invoke("module-to-pp", ast, strategoRuntime.getTermFactory().makeString("2"));
return Result.ofOk(ast);
Expand Down
Loading

0 comments on commit 567a944

Please sign in to comment.