Skip to content

Commit

Permalink
Merge pull request #3585 from RZhang05/identifier-string-template
Browse files Browse the repository at this point in the history
Limited string templates: \(identifier)
  • Loading branch information
SupunS authored Oct 18, 2024
2 parents 0fe614a + 6983288 commit 3208a5d
Show file tree
Hide file tree
Showing 21 changed files with 1,606 additions and 87 deletions.
1 change: 1 addition & 0 deletions runtime/ast/elementtype.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,5 @@ const (
ElementTypeForceExpression
ElementTypePathExpression
ElementTypeAttachExpression
ElementTypeStringTemplateExpression
)
5 changes: 3 additions & 2 deletions runtime/ast/elementtype_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 75 additions & 0 deletions runtime/ast/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,81 @@ func (*StringExpression) precedence() precedence {
return precedenceLiteral
}

// StringTemplateExpression

type StringTemplateExpression struct {
// Values and Expressions are assumed to be interleaved, V[0] + E[0] + V[1] + ... + E[n-1] + V[n]
// this is enforced in the parser e.g. "a\(b)c" will be parsed as follows
// Values: []string{"a","c"}
// Expressions: []Expression{b}
Values []string
Expressions []Expression
Range
}

var _ Expression = &StringTemplateExpression{}

func NewStringTemplateExpression(
gauge common.MemoryGauge,
values []string,
exprs []Expression,
exprRange Range,
) *StringTemplateExpression {
common.UseMemory(gauge, common.NewStringTemplateExpressionMemoryUsage(len(values)+len(exprs)))
if len(values) != len(exprs)+1 {
// assert string template alternating structure
panic(errors.NewUnreachableError())
}
return &StringTemplateExpression{
Values: values,
Expressions: exprs,
Range: exprRange,
}
}

var _ Element = &StringExpression{}
var _ Expression = &StringExpression{}

func (*StringTemplateExpression) ElementType() ElementType {
return ElementTypeStringTemplateExpression
}

func (*StringTemplateExpression) isExpression() {}

func (*StringTemplateExpression) isIfStatementTest() {}

func (e *StringTemplateExpression) Walk(walkChild func(Element)) {
walkExpressions(walkChild, e.Expressions)
}

func (e *StringTemplateExpression) String() string {
return Prettier(e)
}

func (e *StringTemplateExpression) Doc() prettier.Doc {
if len(e.Expressions) == 0 {
return prettier.Text(QuoteString(e.Values[0]))
}

// TODO: must reproduce expressions as literals
panic("not implemented")
}

func (e *StringTemplateExpression) MarshalJSON() ([]byte, error) {
type Alias StringTemplateExpression
return json.Marshal(&struct {
*Alias
Type string
}{
Type: "StringTemplateExpression",
Alias: (*Alias)(e),
})
}

func (*StringTemplateExpression) precedence() precedence {
return precedenceLiteral
}

// IntegerExpression

type IntegerExpression struct {
Expand Down
84 changes: 59 additions & 25 deletions runtime/ast/expression_extractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ type StringExtractor interface {
ExtractString(extractor *ExpressionExtractor, expression *StringExpression) ExpressionExtraction
}

type StringTemplateExtractor interface {
ExtractStringTemplate(extractor *ExpressionExtractor, expression *StringTemplateExpression) ExpressionExtraction
}

type ArrayExtractor interface {
ExtractArray(extractor *ExpressionExtractor, expression *ArrayExpression) ExpressionExtraction
}
Expand Down Expand Up @@ -117,31 +121,32 @@ type AttachExtractor interface {
}

type ExpressionExtractor struct {
IndexExtractor IndexExtractor
ForceExtractor ForceExtractor
BoolExtractor BoolExtractor
NilExtractor NilExtractor
IntExtractor IntExtractor
FixedPointExtractor FixedPointExtractor
StringExtractor StringExtractor
ArrayExtractor ArrayExtractor
DictionaryExtractor DictionaryExtractor
IdentifierExtractor IdentifierExtractor
AttachExtractor AttachExtractor
MemoryGauge common.MemoryGauge
VoidExtractor VoidExtractor
UnaryExtractor UnaryExtractor
ConditionalExtractor ConditionalExtractor
InvocationExtractor InvocationExtractor
BinaryExtractor BinaryExtractor
FunctionExtractor FunctionExtractor
CastingExtractor CastingExtractor
CreateExtractor CreateExtractor
DestroyExtractor DestroyExtractor
ReferenceExtractor ReferenceExtractor
MemberExtractor MemberExtractor
PathExtractor PathExtractor
nextIdentifier int
IndexExtractor IndexExtractor
ForceExtractor ForceExtractor
BoolExtractor BoolExtractor
NilExtractor NilExtractor
IntExtractor IntExtractor
FixedPointExtractor FixedPointExtractor
StringExtractor StringExtractor
StringTemplateExtractor StringTemplateExtractor
ArrayExtractor ArrayExtractor
DictionaryExtractor DictionaryExtractor
IdentifierExtractor IdentifierExtractor
AttachExtractor AttachExtractor
MemoryGauge common.MemoryGauge
VoidExtractor VoidExtractor
UnaryExtractor UnaryExtractor
ConditionalExtractor ConditionalExtractor
InvocationExtractor InvocationExtractor
BinaryExtractor BinaryExtractor
FunctionExtractor FunctionExtractor
CastingExtractor CastingExtractor
CreateExtractor CreateExtractor
DestroyExtractor DestroyExtractor
ReferenceExtractor ReferenceExtractor
MemberExtractor MemberExtractor
PathExtractor PathExtractor
nextIdentifier int
}

var _ ExpressionVisitor[ExpressionExtraction] = &ExpressionExtractor{}
Expand Down Expand Up @@ -271,6 +276,35 @@ func (extractor *ExpressionExtractor) ExtractString(expression *StringExpression
return rewriteExpressionAsIs(expression)
}

func (extractor *ExpressionExtractor) VisitStringTemplateExpression(expression *StringTemplateExpression) ExpressionExtraction {

// delegate to child extractor, if any,
// or call default implementation

if extractor.StringTemplateExtractor != nil {
return extractor.StringTemplateExtractor.ExtractStringTemplate(extractor, expression)
}
return extractor.ExtractStringTemplate(expression)
}

func (extractor *ExpressionExtractor) ExtractStringTemplate(expression *StringTemplateExpression) ExpressionExtraction {

// copy the expression
newExpression := *expression

// rewrite all value expressions

rewrittenExpressions, extractedExpressions :=
extractor.VisitExpressions(expression.Expressions)

newExpression.Expressions = rewrittenExpressions

return ExpressionExtraction{
RewrittenExpression: &newExpression,
ExtractedExpressions: extractedExpressions,
}
}

func (extractor *ExpressionExtractor) VisitArrayExpression(expression *ArrayExpression) ExpressionExtraction {

// delegate to child extractor, if any,
Expand Down
1 change: 1 addition & 0 deletions runtime/ast/precedence.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ const (
// - BoolExpression
// - NilExpression
// - StringExpression
// - StringTemplateExpression
// - IntegerExpression
// - FixedPointExpression
// - ArrayExpression
Expand Down
47 changes: 47 additions & 0 deletions runtime/ast/string_template_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Cadence - The resource-oriented smart contract programming language
*
* Copyright Flow Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package ast

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/turbolent/prettier"
)

func TestStringTemplate_Doc(t *testing.T) {

t.Parallel()

stmt := &StringTemplateExpression{
Values: []string{
"abc",
},
Expressions: []Expression{},
Range: Range{
StartPos: Position{Offset: 4, Line: 2, Column: 3},
EndPos: Position{Offset: 11, Line: 2, Column: 10},
},
}

assert.Equal(t,
prettier.Text("\"abc\""),
stmt.Doc(),
)
}
4 changes: 4 additions & 0 deletions runtime/ast/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ type ExpressionVisitor[T any] interface {
VisitNilExpression(*NilExpression) T
VisitBoolExpression(*BoolExpression) T
VisitStringExpression(*StringExpression) T
VisitStringTemplateExpression(*StringTemplateExpression) T
VisitIntegerExpression(*IntegerExpression) T
VisitFixedPointExpression(*FixedPointExpression) T
VisitDictionaryExpression(*DictionaryExpression) T
Expand Down Expand Up @@ -219,6 +220,9 @@ func AcceptExpression[T any](expression Expression, visitor ExpressionVisitor[T]
case ElementTypeStringExpression:
return visitor.VisitStringExpression(expression.(*StringExpression))

case ElementTypeStringTemplateExpression:
return visitor.VisitStringTemplateExpression(expression.(*StringTemplateExpression))

case ElementTypeIntegerExpression:
return visitor.VisitIntegerExpression(expression.(*IntegerExpression))

Expand Down
1 change: 1 addition & 0 deletions runtime/common/memorykind.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ const (
MemoryKindIntegerExpression
MemoryKindFixedPointExpression
MemoryKindArrayExpression
MemoryKindStringTemplateExpression
MemoryKindDictionaryExpression
MemoryKindIdentifierExpression
MemoryKindInvocationExpression
Expand Down
Loading

0 comments on commit 3208a5d

Please sign in to comment.