Skip to content

Commit

Permalink
Use serde elision index (#4712)
Browse files Browse the repository at this point in the history
* chore(codegen): add UnaryFunctionCall

* chore(codegen): use SerdeElision knowledge index
  • Loading branch information
srchase authored May 9, 2023
1 parent a2d8cd8 commit 5d01f58
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ final class JsonMemberDeserVisitor extends DocumentMemberDeserVisitor {
super(context, dataSource, defaultTimestampFormat);
this.memberShape = memberShape;
context.getWriter().addImport("_json", null, "@aws-sdk/smithy-client");
serdeElision.setEnabledForModel(!context.getSettings().generateServerSdk());
this.serdeElisionEnabled = !context.getSettings().generateServerSdk();
}

JsonMemberDeserVisitor(GenerationContext context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ final class JsonMemberSerVisitor extends DocumentMemberSerVisitor {
JsonMemberSerVisitor(GenerationContext context, String dataSource, Format defaultTimestampFormat) {
super(context, dataSource, defaultTimestampFormat);
context.getWriter().addImport("_json", null, "@aws-sdk/smithy-client");
serdeElision.setEnabledForModel(!context.getSettings().generateServerSdk());
this.serdeElisionEnabled = !context.getSettings().generateServerSdk();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ protected Format getDocumentTimestampFormat() {
protected void generateDocumentBodyShapeSerializers(GenerationContext context, Set<Shape> shapes) {
AwsProtocolUtils.generateDocumentBodyShapeSerde(context, shapes,
// AWS JSON does not support jsonName
new JsonShapeSerVisitor(context, (shape, name) -> name));
new JsonShapeSerVisitor(context, (shape, name) -> name, enableSerdeElision()));
}

@Override
protected void generateDocumentBodyShapeDeserializers(GenerationContext context, Set<Shape> shapes) {
AwsProtocolUtils.generateDocumentBodyShapeSerde(context, shapes,
// AWS JSON does not support jsonName
new JsonShapeDeserVisitor(context, (shape, name) -> name));
new JsonShapeDeserVisitor(context, (shape, name) -> name, enableSerdeElision()));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Map;
import java.util.TreeMap;
import java.util.function.BiFunction;
import software.amazon.smithy.aws.typescript.codegen.validation.UnaryFunctionCall;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.shapes.CollectionShape;
Expand All @@ -41,7 +42,6 @@
import software.amazon.smithy.typescript.codegen.integration.DocumentMemberDeserVisitor;
import software.amazon.smithy.typescript.codegen.integration.DocumentShapeDeserVisitor;
import software.amazon.smithy.typescript.codegen.integration.ProtocolGenerator.GenerationContext;
import software.amazon.smithy.typescript.codegen.validation.UnaryFunctionCall;
import software.amazon.smithy.utils.SmithyInternalApi;

/**
Expand All @@ -58,16 +58,19 @@ final class JsonShapeDeserVisitor extends DocumentShapeDeserVisitor {

private final BiFunction<MemberShape, String, String> memberNameStrategy;

JsonShapeDeserVisitor(GenerationContext context) {
JsonShapeDeserVisitor(GenerationContext context, boolean serdeElisionEnabled) {
this(context,
// Use the jsonName trait value if present, otherwise use the member name.
(memberShape, memberName) -> memberShape.getTrait(JsonNameTrait.class)
.map(JsonNameTrait::getValue)
.orElse(memberName));
.orElse(memberName),
serdeElisionEnabled);
}

JsonShapeDeserVisitor(GenerationContext context, BiFunction<MemberShape, String, String> memberNameStrategy) {
JsonShapeDeserVisitor(GenerationContext context, BiFunction<MemberShape, String, String> memberNameStrategy,
boolean serdeElisionEnabled) {
super(context);
this.serdeElisionEnabled = serdeElisionEnabled;
this.memberNameStrategy = memberNameStrategy;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Map;
import java.util.TreeMap;
import java.util.function.BiFunction;
import software.amazon.smithy.aws.typescript.codegen.validation.UnaryFunctionCall;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.shapes.CollectionShape;
Expand All @@ -37,7 +38,6 @@
import software.amazon.smithy.typescript.codegen.integration.DocumentMemberSerVisitor;
import software.amazon.smithy.typescript.codegen.integration.DocumentShapeSerVisitor;
import software.amazon.smithy.typescript.codegen.integration.ProtocolGenerator.GenerationContext;
import software.amazon.smithy.typescript.codegen.validation.UnaryFunctionCall;
import software.amazon.smithy.utils.SmithyInternalApi;

/**
Expand All @@ -55,16 +55,19 @@ final class JsonShapeSerVisitor extends DocumentShapeSerVisitor {

private final BiFunction<MemberShape, String, String> memberNameStrategy;

JsonShapeSerVisitor(GenerationContext context) {
JsonShapeSerVisitor(GenerationContext context, boolean serdeElisionEnabled) {
this(context,
// Use the jsonName trait value if present, otherwise use the member name.
(memberShape, memberName) -> memberShape.getTrait(JsonNameTrait.class)
.map(JsonNameTrait::getValue)
.orElse(memberName));
.orElse(memberName),
serdeElisionEnabled);
}

JsonShapeSerVisitor(GenerationContext context, BiFunction<MemberShape, String, String> memberNameStrategy) {
JsonShapeSerVisitor(GenerationContext context, BiFunction<MemberShape, String, String> memberNameStrategy,
boolean serdeElisionEnabled) {
super(context);
this.serdeElisionEnabled = serdeElisionEnabled;
this.memberNameStrategy = memberNameStrategy;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.util.List;
import java.util.Set;
import software.amazon.smithy.aws.typescript.codegen.validation.UnaryFunctionCall;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.model.knowledge.HttpBinding;
import software.amazon.smithy.model.shapes.DocumentShape;
Expand All @@ -33,7 +34,6 @@
import software.amazon.smithy.typescript.codegen.integration.DocumentMemberDeserVisitor;
import software.amazon.smithy.typescript.codegen.integration.DocumentMemberSerVisitor;
import software.amazon.smithy.typescript.codegen.integration.HttpBindingProtocolGenerator;
import software.amazon.smithy.typescript.codegen.validation.UnaryFunctionCall;
import software.amazon.smithy.utils.IoUtils;
import software.amazon.smithy.utils.SmithyInternalApi;

Expand Down Expand Up @@ -68,12 +68,14 @@ protected TimestampFormatTrait.Format getDocumentTimestampFormat() {

@Override
protected void generateDocumentBodyShapeSerializers(GenerationContext context, Set<Shape> shapes) {
AwsProtocolUtils.generateDocumentBodyShapeSerde(context, shapes, new JsonShapeSerVisitor(context));
AwsProtocolUtils.generateDocumentBodyShapeSerde(context, shapes, new JsonShapeSerVisitor(context,
(!context.getSettings().generateServerSdk() && enableSerdeElision())));
}

@Override
protected void generateDocumentBodyShapeDeserializers(GenerationContext context, Set<Shape> shapes) {
AwsProtocolUtils.generateDocumentBodyShapeSerde(context, shapes, new JsonShapeDeserVisitor(context));
AwsProtocolUtils.generateDocumentBodyShapeSerde(context, shapes, new JsonShapeDeserVisitor(context,
(!context.getSettings().generateServerSdk() && enableSerdeElision())));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.aws.typescript.codegen.validation;

import java.util.regex.Pattern;

/**
* For handling expressions that may be unary function calls.
*/
class UnaryFunctionCall {
private static final Pattern CHECK_PATTERN = Pattern.compile("^(?!new ).+\\(((?!,).)*\\)$");
private static final Pattern TO_REF_PATTERN = Pattern.compile("(.*)\\(.*\\)$");

/**
* @param expression - to be examined.
* @return whether the expression is a single-depth function call with a single parameter.
*/
public static boolean check(String expression) {
if (expression.equals("_")) {
// not a call per se, but this indicates a pass-through function.
return true;
}
return maxCallDepth(expression) == 1 && CHECK_PATTERN.matcher(expression).matches();
}

/**
* @param callExpression the call expression to be converted. Check that
* the expression is a unary call first.
* @return the unary function call converted to a function reference.
*/
public static String toRef(String callExpression) {
return TO_REF_PATTERN.matcher(callExpression).replaceAll("$1");
}

/**
* Estimates the call depth of a function call expression.
*
* @param expression A function call expression (e.g., "call() == 1", "call(call()) == 2", etc).
*/
private static int maxCallDepth(String expression) {
int depth = 0;
int maxDepth = 0;
for (int i = 0; i < expression.length(); ++i) {
char c = expression.charAt(i);
if (c == '(') {
depth += 1;
if (depth > maxDepth) {
maxDepth = depth;
}
continue;
}
if (c == ')') {
depth -= 1;
}
}
return maxDepth;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package software.amazon.smithy.aws.typescript.codegen.validation;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

class UnaryFunctionCallTest {
@Test
void check() {
assertEquals(false, UnaryFunctionCall.check(""));
assertEquals(false, UnaryFunctionCall.check("5"));
assertEquals(false, UnaryFunctionCall.check("(param)"));
assertEquals(false, UnaryFunctionCall.check("x[5]"));
assertEquals(false, UnaryFunctionCall.check("new Date(timestamp)"));
assertEquals(false, UnaryFunctionCall.check("x(y(_))"));
assertEquals(false, UnaryFunctionCall.check("call(param).prop"));
assertEquals(false, UnaryFunctionCall.check("call(param, param2)"));

assertEquals(true, UnaryFunctionCall.check("_"));
assertEquals(true, UnaryFunctionCall.check("x()"));
assertEquals(true, UnaryFunctionCall.check("x(_)"));
assertEquals(true, UnaryFunctionCall.check("long_function_name(long_parameter_name)"));
assertEquals(true, UnaryFunctionCall.check("container.function(param)"));
assertEquals(true, UnaryFunctionCall.check("factory(param)(param2)"));
}

@Test
void toRef() {
assertEquals("_", UnaryFunctionCall.toRef("_"));
assertEquals("x", UnaryFunctionCall.toRef("x()"));
assertEquals("x", UnaryFunctionCall.toRef("x(_)"));
assertEquals("long_function_name", UnaryFunctionCall.toRef("long_function_name(long_parameter_name)"));
assertEquals("container.function", UnaryFunctionCall.toRef("container.function(param)"));
assertEquals("factory(param)", UnaryFunctionCall.toRef("factory(param)(param2)"));
}
}

0 comments on commit 5d01f58

Please sign in to comment.