Skip to content

Commit

Permalink
Introduce TypelessStructLiteralArg and NewConstructorArg interfac…
Browse files Browse the repository at this point in the history
…es (#183)

* Implement BracedNewConstructor

* Clean up NEW operator implementation

* Add testdata for NEW operators

* Fix receiver of isExpr

* Fix to use NamedType

* Update to use p.parseNamedType()

* Refactor SQL() using helper functions

* Add NEW constructor section in ast

* Fix comments

* Update parser implementation of NEW constructors

* Do go test --update

* Fix code placement

* Do go test --update

* Separate StructLiteral to TupleStructLiteral, TypelessStructLiteral, TypedStructLiteral

* Update testdata

* Fix comment

* Introduce AsExpr instead of TypelessStructValue and NewConstructorValue

* Rename AsExpr to ExprAsName, and use `AsAlias`

Also, this fixes a `AsAlias.As` position bug.

* Update parser.go

Co-authored-by: apstndb <[email protected]>

* Introduce `TypelessStructLiteralArg` and `NewConstructorArg`

* Remove requiredAs comments

* Add constants for the tryParseAsAlias argument

---------

Co-authored-by: apstndb <[email protected]>
  • Loading branch information
makenowjust and apstndb authored Oct 29, 2024
1 parent e50eded commit db40951
Show file tree
Hide file tree
Showing 100 changed files with 2,176 additions and 703 deletions.
216 changes: 170 additions & 46 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,38 +150,43 @@ type Expr interface {
isExpr()
}

func (BinaryExpr) isExpr() {}
func (UnaryExpr) isExpr() {}
func (InExpr) isExpr() {}
func (IsNullExpr) isExpr() {}
func (IsBoolExpr) isExpr() {}
func (BetweenExpr) isExpr() {}
func (SelectorExpr) isExpr() {}
func (IndexExpr) isExpr() {}
func (CallExpr) isExpr() {}
func (CountStarExpr) isExpr() {}
func (CastExpr) isExpr() {}
func (ExtractExpr) isExpr() {}
func (CaseExpr) isExpr() {}
func (ParenExpr) isExpr() {}
func (ScalarSubQuery) isExpr() {}
func (ArraySubQuery) isExpr() {}
func (ExistsSubQuery) isExpr() {}
func (Param) isExpr() {}
func (Ident) isExpr() {}
func (Path) isExpr() {}
func (ArrayLiteral) isExpr() {}
func (StructLiteral) isExpr() {}
func (NullLiteral) isExpr() {}
func (BoolLiteral) isExpr() {}
func (IntLiteral) isExpr() {}
func (FloatLiteral) isExpr() {}
func (StringLiteral) isExpr() {}
func (BytesLiteral) isExpr() {}
func (DateLiteral) isExpr() {}
func (TimestampLiteral) isExpr() {}
func (NumericLiteral) isExpr() {}
func (JSONLiteral) isExpr() {}
func (BinaryExpr) isExpr() {}
func (UnaryExpr) isExpr() {}
func (InExpr) isExpr() {}
func (IsNullExpr) isExpr() {}
func (IsBoolExpr) isExpr() {}
func (BetweenExpr) isExpr() {}
func (SelectorExpr) isExpr() {}
func (IndexExpr) isExpr() {}
func (CallExpr) isExpr() {}
func (CountStarExpr) isExpr() {}
func (CastExpr) isExpr() {}
func (ExtractExpr) isExpr() {}
func (CaseExpr) isExpr() {}
func (ParenExpr) isExpr() {}
func (ScalarSubQuery) isExpr() {}
func (ArraySubQuery) isExpr() {}
func (ExistsSubQuery) isExpr() {}
func (Param) isExpr() {}
func (Ident) isExpr() {}
func (Path) isExpr() {}
func (ArrayLiteral) isExpr() {}
func (TupleStructLiteral) isExpr() {}
func (TypelessStructLiteral) isExpr() {}
func (TypedStructLiteral) isExpr() {}
func (NullLiteral) isExpr() {}
func (BoolLiteral) isExpr() {}
func (IntLiteral) isExpr() {}
func (FloatLiteral) isExpr() {}
func (StringLiteral) isExpr() {}
func (BytesLiteral) isExpr() {}
func (DateLiteral) isExpr() {}
func (TimestampLiteral) isExpr() {}
func (NumericLiteral) isExpr() {}
func (JSONLiteral) isExpr() {}
func (NewConstructor) isExpr() {}
func (BracedNewConstructor) isExpr() {}
func (BracedConstructor) isExpr() {}

// Arg represents argument of function call.
type Arg interface {
Expand Down Expand Up @@ -221,6 +226,24 @@ func (UnnestInCondition) isInCondition() {}
func (SubQueryInCondition) isInCondition() {}
func (ValuesInCondition) isInCondition() {}

// TypelessStructLiteralArg represents an argument of typeless STRUCT literals.
type TypelessStructLiteralArg interface {
Node
isTypelessStructLiteralArg()
}

func (ExprArg) isTypelessStructLiteralArg() {}
func (Alias) isTypelessStructLiteralArg() {}

// NewConstructorArg represents an argument of NEW constructors.
type NewConstructorArg interface {
Node
isNewConstructorArg()
}

func (ExprArg) isNewConstructorArg() {}
func (Alias) isNewConstructorArg() {}

// Type represents type node.
type Type interface {
Node
Expand Down Expand Up @@ -607,7 +630,10 @@ type DotStar struct {
Expr Expr
}

// Alias is aliased expression by AS clause in SELECT result columns list.
// Alias is aliased expression by AS clause.
//
// Typically, this appears in SELECT result columns list, but this can appear in typeless STRUCT literals
// and NEW constructors.
//
// {{.Expr | sql}} {{.As | sql}}
type Alias struct {
Expand All @@ -622,16 +648,12 @@ type Alias struct {
//
// It is used in Alias node and some JoinExpr nodes.
//
// NOTE: Sometime keyword AS can be omited.
//
// In this case, it.token.Pos() == it.Alias.token.Pos(), so we can detect this.
//
// AS {{.Alias | sql}}
// {{if not .As.Invalid}}AS {{end}}{{.Alias | sql}}
type AsAlias struct {
// pos = As || Alias.pos
// end = Alias.end

As token.Pos // position of "AS" keyword
As token.Pos // position of "AS" keyword, optional

Alias *Ident
}
Expand Down Expand Up @@ -1376,22 +1398,45 @@ type ArrayLiteral struct {
Values []Expr
}

// StructLiteral is struct literal node.
// TupleStructLiteral is tuple syntax struct literal node.
//
// STRUCT{{if not (isnil .Fields)}}<{{.Fields | sqlJoin ","}}>{{end}}({{.Values | sqlJoin ","}})
type StructLiteral struct {
// pos = Struct || Lparen
// ({{.Values | sqlJoin ","}})
type TupleStructLiteral struct {
// pos = Lparen
// end = Rparen + 1

Struct token.Pos // position of "STRUCT"
Lparen, Rparen token.Pos // position of "(" and ")"

// NOTE: Distinguish nil from len(Fields) == 0 case.
// nil means type is not specified, or empty slice means this struct has 0 fields.
Values []Expr // len(Values) > 1
}

// TypedStructLiteral is typed struct literal node.
//
// STRUCT<{{.Fields | sqlJoin ","}}>({{.Values | sqlJoin ","}})
type TypedStructLiteral struct {
// pos = Struct
// end = Rparen + 1

Struct token.Pos // position of "STRUCT"
Rparen token.Pos // position of ")"

Fields []*StructField
Values []Expr
}

// TypelessStructLiteral is typeless struct literal node.
//
// STRUCT({{.Values | sqlJoin ","}})
type TypelessStructLiteral struct {
// pos = Struct
// end = Rparen + 1

Struct token.Pos // position of "STRUCT"
Rparen token.Pos // position of ")"

Values []TypelessStructLiteralArg
}

// NullLiteral is just NULL literal.
//
// NULL
Expand Down Expand Up @@ -1511,6 +1556,85 @@ type JSONLiteral struct {
Value *StringLiteral
}

// ================================================================================
//
// NEW constructors
//
// ================================================================================

// BracedConstructorFieldValue represents value part of fields in BracedNewConstructor.
type BracedConstructorFieldValue interface {
Node
isBracedConstructorFieldValue()
}

func (*BracedConstructor) isBracedConstructorFieldValue() {}
func (*BracedConstructorFieldValueExpr) isBracedConstructorFieldValue() {}

// NewConstructor represents NEW operator which creates a protocol buffer using a parenthesized list of arguments.
//
// NEW {{.Type | sql}} ({{.Args | sqlJoin ", "}})
type NewConstructor struct {
// pos = New
// end = Rparen + 1

New token.Pos
Type *NamedType

Args []NewConstructorArg

Rparen token.Pos
}

// BracedNewConstructor represents NEW operator which creates a protocol buffer using a map constructor.
//
// NEW {{.Type | sql}} {{"{"}}{{"}"}}
type BracedNewConstructor struct {
// pos = New
// end = Body.end

New token.Pos

Type *NamedType
Body *BracedConstructor
}

// BracedConstructor represents a single map constructor which is used in BracedNewConstructor.
// Actually, it is a top level Expr in syntax, but it is not permitted semantically in other place.
//
// {{"{"}}{{.Fields | sqlJoin ", "}}{{"}"}}
type BracedConstructor struct {
// pos = Lbrace
// end = Rbrace + 1

Lbrace, Rbrace token.Pos

Fields []*BracedConstructorField
}

// BracedConstructorField represents a single field in BracedConstructor.
//
// {{.Name | sql}} {{.Value | sql}}
type BracedConstructorField struct {
// pos = Name.pos
// end = Value.end

Name *Ident
Value BracedConstructorFieldValue
}

// BracedConstructorFieldValueExpr represents a field value node.
//
// : {{.Expr | sql}}
type BracedConstructorFieldValueExpr struct {
// pos = Colon
// end = Expr.end

Colon token.Pos

Expr Expr
}

// ================================================================================
//
// Type
Expand Down
2 changes: 1 addition & 1 deletion ast/ast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func TestExpr(t *testing.T) {
Expr(&Ident{}).isExpr()
Expr(&Path{}).isExpr()
Expr(&ArrayLiteral{}).isExpr()
Expr(&StructLiteral{}).isExpr()
Expr(&TypedStructLiteral{}).isExpr()
Expr(&NullLiteral{}).isExpr()
Expr(&BoolLiteral{}).isExpr()
Expr(&IntLiteral{}).isExpr()
Expand Down
64 changes: 60 additions & 4 deletions ast/pos.go

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

Loading

0 comments on commit db40951

Please sign in to comment.