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

Limited string templates: \(identifier) #3585

Merged
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.

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

// StringTemplateExpression

type StringTemplateExpression struct {
Values []string
Expressions []Expression
turbolent marked this conversation as resolved.
Show resolved Hide resolved
Range
}

var _ Expression = &StringTemplateExpression{}

func NewStringTemplateExpression(gauge common.MemoryGauge, values []string, exprs []Expression, exprRange Range) *StringTemplateExpression {
SupunS marked this conversation as resolved.
Show resolved Hide resolved
// STRINGTODO: change to be similar to array memory usage?
common.UseMemory(gauge, common.StringExpressionMemoryUsage)
SupunS marked this conversation as resolved.
Show resolved Hide resolved
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 (*StringTemplateExpression) Walk(_ func(Element)) {
// NO-OP
turbolent marked this conversation as resolved.
Show resolved Hide resolved
}

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

func (e *StringTemplateExpression) Doc() prettier.Doc {
return prettier.Text(QuoteString("String template"))
turbolent marked this conversation as resolved.
Show resolved Hide resolved
}

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
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
5 changes: 5 additions & 0 deletions runtime/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ func (compiler *Compiler) VisitFunctionExpression(_ *ast.FunctionExpression) ir.
panic(errors.NewUnreachableError())
}

func (compiler *Compiler) VisitStringTemplateExpression(e *ast.StringTemplateExpression) ir.Expr {
// TODO
panic(errors.NewUnreachableError())
}

func (compiler *Compiler) VisitStringExpression(e *ast.StringExpression) ir.Expr {
return &ir.Const{
Constant: ir.String{
Expand Down
28 changes: 28 additions & 0 deletions runtime/interpreter/interpreter_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package interpreter

import (
"math/big"
"strings"
"time"

"github.com/onflow/atree"
Expand Down Expand Up @@ -957,6 +958,33 @@ func (interpreter *Interpreter) VisitStringExpression(expression *ast.StringExpr
return NewUnmeteredStringValue(expression.Value)
}

func (interpreter *Interpreter) VisitStringTemplateExpression(expression *ast.StringTemplateExpression) Value {
values := interpreter.visitExpressionsNonCopying(expression.Expressions)

templatesType := interpreter.Program.Elaboration.StringTemplateExpressionTypes(expression)
argumentTypes := templatesType.ArgumentTypes

var builder strings.Builder
for i, str := range expression.Values {
builder.WriteString(str)
if i < len(values) {
// STRINGTODO: is this how the conversion should happen?
s := values[i].String()
switch argumentTypes[i] {
SupunS marked this conversation as resolved.
Show resolved Hide resolved
case sema.StringType:
// remove quotations
s = s[1 : len(s)-1]
builder.WriteString(s)
default:
builder.WriteString(s)
}
}
}

// STRINGTODO: already metered as a string constant in parser?
return NewUnmeteredStringValue(builder.String())
}

func (interpreter *Interpreter) VisitArrayExpression(expression *ast.ArrayExpression) Value {
values := interpreter.visitExpressionsNonCopying(expression.Values)

Expand Down
Loading
Loading