Skip to content

Commit

Permalink
Add an Id class to the JS DSL. Move Kythe byteSpan there.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 709073337
  • Loading branch information
Jesse-Good authored and copybara-github committed Dec 23, 2024
1 parent 1621ef3 commit 347626c
Show file tree
Hide file tree
Showing 23 changed files with 344 additions and 187 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.google.template.soy.jssrc.dsl.DoWhile;
import com.google.template.soy.jssrc.dsl.Expression;
import com.google.template.soy.jssrc.dsl.Expressions;
import com.google.template.soy.jssrc.dsl.Id;
import com.google.template.soy.jssrc.dsl.Statement;
import com.google.template.soy.jssrc.dsl.Statements;
import com.google.template.soy.jssrc.dsl.SwitchBuilder;
Expand Down Expand Up @@ -208,7 +209,7 @@ Statement generateMsgGroupCode(MsgFallbackGroupNode node) {

Statement loop =
forOf(
itemId,
Id.create(itemId),
Expressions.id(staticDecl).bracketAccess(translationVar),
Statements.of(body.build()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import com.google.template.soy.jssrc.dsl.Expression;
import com.google.template.soy.jssrc.dsl.Expressions;
import com.google.template.soy.jssrc.dsl.GoogRequire;
import com.google.template.soy.jssrc.dsl.Id;
import com.google.template.soy.jssrc.dsl.JsCodeBuilder;
import com.google.template.soy.jssrc.dsl.JsDoc;
import com.google.template.soy.jssrc.dsl.Statement;
Expand Down Expand Up @@ -603,7 +604,7 @@ private CodeChunk generateClassForSoyElement(
ClassExpression.Builder classBuilder =
ClassExpression.builder()
.setBaseClass(SOY_IDOM.dotAccess("$SoyElement"))
.setName(soyElementClassName);
.setName(Id.create(soyElementClassName));
try (var unused = templateTranslationContext.enterSoyAndJsScope()) {
ImmutableList.Builder<Statement> stateVarInitializations = ImmutableList.builder();
stateVarInitializations.add(generateInitInternal(node));
Expand All @@ -618,7 +619,8 @@ private CodeChunk generateClassForSoyElement(
Statements.of(
id("super").call().asStatement(), Statements.of(stateVarInitializations.build()));
MethodDeclaration constructorMethod =
MethodDeclaration.builder("constructor", ctorBody).setByteSpan(byteSpan).build();
MethodDeclaration.builder(Id.builder("constructor").setSpan(byteSpan).build(), ctorBody)
.build();
classBuilder.addMethod(constructorMethod);
}
for (TemplateStateVar stateVar : node.getStateVars()) {
Expand Down Expand Up @@ -704,12 +706,12 @@ private ImmutableList<MethodDeclaration> generateStateMethodsForSoyElementClass(
id("this").dotAccess(STATE_PREFIX + stateVar.name()), typeForState, typeForGetters);
methods.add(
MethodDeclaration.builder(
"get" + stateAccessorSuffix, Statements.returnValue(getterStateValue))
Id.builder("get" + stateAccessorSuffix).setSpan(byteSpan).build(),
Statements.returnValue(getterStateValue))
.setJsDoc(
JsDoc.builder()
.addParameterizedAnnotation("return", typeForGetters.typeExpr())
.build())
.setByteSpan(byteSpan)
.build());
}

Expand All @@ -736,13 +738,13 @@ private ImmutableList<MethodDeclaration> generateStateMethodsForSoyElementClass(
setterStateValue.assign(setterParam).asStatement(), Statements.returnValue(id("this")));
methods.add(
MethodDeclaration.builder(
"set" + stateAccessorSuffix, Statements.of(setStateMethodStatements.build()))
Id.builder("set" + stateAccessorSuffix).setSpan(byteSpan).build(),
Statements.of(setStateMethodStatements.build()))
.setJsDoc(
JsDoc.builder()
.addParam(stateVar.name(), typeForSetters.typeExpr())
.addParameterizedAnnotation("return", "!" + soyElementClassName)
.build())
.setByteSpan(byteSpan)
.build());
}

Expand All @@ -758,14 +760,15 @@ private MethodDeclaration generateGetParamMethodForSoyElementClass(
Ascii.toUpperCase(param.name().substring(0, 1)) + param.name().substring(1);
ByteSpan byteSpan = SoyTreeUtils.getByteSpan(currentTemplateNode, param.nameLocation());
if (isAbstract) {
return MethodDeclaration.builder("get" + accessorSuffix, Statements.of(ImmutableList.of()))
return MethodDeclaration.builder(
Id.builder("get" + accessorSuffix).setSpan(byteSpan).build(),
Statements.of(ImmutableList.of()))
.setJsDoc(
JsDoc.builder()
.addAnnotation("abstract")
// Injected params are marked as optional, see:
.addParameterizedAnnotation("return", jsType.typeExpr())
.build())
.setByteSpan(byteSpan)
.build();
}
try (var unused = templateTranslationContext.enterSoyAndJsScope()) {
Expand Down Expand Up @@ -799,9 +802,9 @@ private MethodDeclaration generateGetParamMethodForSoyElementClass(
templateTranslationContext.codeGenerator())
: Optional.empty();
return MethodDeclaration.builder(
"get" + accessorSuffix, Statements.returnValue(typeAssertion.orElse(value)))
Id.builder("get" + accessorSuffix).setSpan(byteSpan).build(),
Statements.returnValue(typeAssertion.orElse(value)))
.setJsDoc(JsDoc.builder().addAnnotation("override").addAnnotation("public").build())
.setByteSpan(byteSpan)
.build();
}
}
Expand Down
31 changes: 12 additions & 19 deletions java/src/com/google/template/soy/jssrc/dsl/ClassExpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.template.soy.base.SourceLocation.ByteSpan;
import java.util.Objects;
import java.util.stream.Stream;
import javax.annotation.Nullable;

Expand All @@ -38,7 +38,7 @@ public abstract class ClassExpression extends Expression
implements Expression.InitialStatementsScope {

@Nullable
abstract String name();
abstract Id name();

@Nullable
abstract Expression baseClass();
Expand All @@ -47,18 +47,16 @@ public abstract class ClassExpression extends Expression

@Override
Stream<? extends CodeChunk> childrenStream() {
Stream<? extends CodeChunk> children = methods().stream();
if (baseClass() != null) {
children = Stream.concat(Stream.of(baseClass()), children);
}
return children;
return Stream.concat(
Stream.of(name(), baseClass()).filter(Objects::nonNull), methods().stream());
}

@Override
void doFormatOutputExpr(FormattingContext ctx) {
ctx.append("class");
if (name() != null) {
ctx.append(" " + name());
ctx.append(" ");
ctx.appendOutputExpression(name());
}
if (baseClass() != null) {
ctx.append(" extends ");
Expand All @@ -83,7 +81,7 @@ public static Builder builder() {
@AutoValue.Builder
public abstract static class Builder {

public abstract Builder setName(String value);
public abstract Builder setName(Id value);

public abstract Builder setBaseClass(Expression value);

Expand All @@ -110,25 +108,22 @@ public final Builder addMethod(MethodDeclaration value) {
@AutoValue
public abstract static class MethodDeclaration extends Expression
implements Expression.InitialStatementsScope {
abstract String name();

@Nullable
abstract ByteSpan byteSpan();
abstract Id name();

abstract JsDoc jsDoc();

abstract Statement body();

@Override
Stream<? extends CodeChunk> childrenStream() {
return Stream.of(jsDoc(), body());
return Stream.of(jsDoc(), name(), body());
}

@Override
void doFormatOutputExpr(FormattingContext ctx) {
ctx.appendAll(jsDoc());
ctx.endLine();
ctx.appendImputee(name(), byteSpan());
ctx.appendOutputExpression(name());
ctx.append("(");
ctx.append(
FunctionDeclaration.generateParamList(jsDoc(), /* addInlineTypeAnnotations= */ false));
Expand All @@ -138,7 +133,7 @@ void doFormatOutputExpr(FormattingContext ctx) {
}
}

public static Builder builder(String name, Statement body) {
public static Builder builder(Id name, Statement body) {
return new AutoValue_ClassExpression_MethodDeclaration.Builder()
.setName(name)
.setBody(body)
Expand All @@ -149,9 +144,7 @@ public static Builder builder(String name, Statement body) {
@AutoValue.Builder
public abstract static class Builder {

public abstract Builder setName(String value);

public abstract Builder setByteSpan(ByteSpan value);
public abstract Builder setName(Id value);

public abstract Builder setJsDoc(JsDoc value);

Expand Down
5 changes: 4 additions & 1 deletion java/src/com/google/template/soy/jssrc/dsl/Expression.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,12 @@ public Expression prepend(List<SpecialToken> tokens) {
}

public Expression withByteSpan(@Nullable ByteSpan byteSpan) {
if (byteSpan == null) {
if (byteSpan == null || !byteSpan.isKnown()) {
return this;
}
if (this instanceof Id) {
return ((Id) this).toBuilder().setSpan(byteSpan).build();
}
return ExpressionWithSpan.create(this, byteSpan);
}

Expand Down
46 changes: 24 additions & 22 deletions java/src/com/google/template/soy/jssrc/dsl/Expressions.java
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,7 @@ public static Expression recordType(List<ParamDecl> params) {
* @throws IllegalArgumentException if {@code id} is not a valid JavaScript identifier.
*/
public static Expression id(String id) {
CodeChunks.checkId(id);
return Leaf.create(id, /* isCheap= */ true);
return Id.create(id);
}

/**
Expand All @@ -177,13 +176,11 @@ public static Expression id(String id) {
* @throws IllegalArgumentException if {@code id} is not a valid JavaScript identifier.
*/
public static Expression id(String id, Iterable<GoogRequire> requires) {
CodeChunks.checkId(id);
return Leaf.create(id, /* isCheap= */ true, requires);
return Id.builder(id).setGoogRequires(ImmutableSet.copyOf(requires)).build();
}

public static Expression id(String id, GoogRequire... requires) {
CodeChunks.checkId(id);
return Leaf.create(id, /* isCheap= */ true, ImmutableList.copyOf(requires));
return Id.builder(id).setGoogRequires(ImmutableSet.copyOf(requires)).build();
}

public static Expression importedId(String id, String path) {
Expand Down Expand Up @@ -228,7 +225,10 @@ private static Expression dottedIdWithRequires(
// be instead associated with the last dot. Or perhaps with the 'whole' expression somehow.
// This is a minor philosophical concern but it should be fine in practice because nothing would
// ever split apart a code chunk into sub-chunks. So the requires could really go anywhere.
Expression tail = id(Iterables.getLast(ids), requires).withByteSpan(byteSpan);
Id tail = (Id) id(Iterables.getLast(ids), requires);
if (byteSpan != null) {
tail = tail.toBuilder().setSpan(byteSpan).build();
}

if (ids.size() == 1) {
return tail;
Expand Down Expand Up @@ -449,7 +449,13 @@ && isStringLiteral(chunks.get(1))) {

@Nullable
static String getLeafText(Expression expr) {
return expr instanceof Leaf ? ((Leaf) expr).value().getText() : null;
if (expr instanceof Id) {
return ((Id) expr).id();
}
if (expr instanceof Leaf) {
return ((Leaf) expr).value().getText();
}
return null;
}

/**
Expand All @@ -460,35 +466,31 @@ public static Expression baseForMethodCall(Expression expr, String name) {
if (expr instanceof Call) {
Expression receiver = ((Call) expr).receiver();
if (receiver instanceof Dot) {
Expression dotKeyExpression = ((Dot) receiver).key();
if (dotKeyExpression instanceof Leaf
&& ((Leaf) dotKeyExpression).value().getText().equals(name)) {
String leafText = getLeafText(((Dot) receiver).key());
if (name.equals(leafText)) {
return ((Dot) receiver).receiver();
}
}
}
return null;
}

@AutoValue
abstract static class ExpressionWithSpan extends Expression {
static final class ExpressionWithSpan extends DelegatingExpression {

public static Expression create(Expression expr, ByteSpan byteSpan) {
return new AutoValue_Expressions_ExpressionWithSpan(expr, byteSpan);
return new ExpressionWithSpan(expr, byteSpan);
}

abstract Expression expr();

abstract ByteSpan byteSpan();
private final ByteSpan byteSpan;

@Override
void doFormatOutputExpr(FormattingContext ctx) {
ctx.appendImputee(expr(), byteSpan());
private ExpressionWithSpan(Expression delegate, ByteSpan byteSpan) {
super(delegate);
this.byteSpan = byteSpan;
}

@Override
Stream<? extends CodeChunk> childrenStream() {
return expr().childrenStream();
void doFormatOutputExpr(FormattingContext ctx) {
ctx.appendImputee(delegate, byteSpan);
}
}

Expand Down
16 changes: 10 additions & 6 deletions java/src/com/google/template/soy/jssrc/dsl/For.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
@Immutable
abstract class For extends Statement {

abstract String localVar();
abstract Id localVar();

abstract Expression initial();

Expand All @@ -37,7 +37,7 @@ abstract class For extends Statement {
abstract Statement body();

static For create(
String localVar, Expression initial, Expression limit, Expression increment, Statement body) {
Id localVar, Expression initial, Expression limit, Expression increment, Statement body) {
return new AutoValue_For(localVar, initial, limit, increment, body);
}

Expand All @@ -52,16 +52,20 @@ void doFormatStatement(FormattingContext ctx) {
.appendInitialStatements(limit())
.appendInitialStatements(increment());

ctx.append("for (let " + localVar() + " = ")
ctx.append("for (let ")
.appendOutputExpression(localVar())
.append(" = ")
.appendOutputExpression(initial())
.append("; " + localVar() + " < ")
.append("; ")
.appendOutputExpression(localVar())
.append(" < ")
.appendOutputExpression(limit())
.append("; ");

if (Objects.equals(Expressions.getLeafText(increment()), "1")) {
ctx.append(localVar() + "++");
ctx.appendOutputExpression(localVar()).append("++");
} else {
ctx.append(localVar() + " += ").appendOutputExpression(increment());
ctx.appendOutputExpression(localVar()).append(" += ").appendOutputExpression(increment());
}

ctx.append(") ");
Expand Down
7 changes: 4 additions & 3 deletions java/src/com/google/template/soy/jssrc/dsl/ForOf.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
@Immutable
abstract class ForOf extends Statement {

abstract String localVar();
abstract Id localVar();

abstract Expression collection();

abstract Statement body();

static ForOf create(String localVar, Expression collection, Statement body) {
static ForOf create(Id localVar, Expression collection, Statement body) {
return new AutoValue_ForOf(localVar, collection, body);
}

Expand All @@ -44,7 +44,8 @@ Stream<? extends CodeChunk> childrenStream() {
void doFormatStatement(FormattingContext ctx) {
ctx.appendInitialStatements(collection());

ctx.append("for (const " + localVar())
ctx.append("for (const ")
.appendOutputExpression(localVar())
.append(" of ")
.appendOutputExpression(collection())
.append(") ");
Expand Down
Loading

0 comments on commit 347626c

Please sign in to comment.