Skip to content

Commit

Permalink
Feature/#291 param dot notation (#378)
Browse files Browse the repository at this point in the history
* Added param to member expression

* Improved path lookup

* Added support for params as segments in member expression path
  • Loading branch information
ziflex authored Sep 7, 2019
2 parents fcd0a21 + 7af241b commit 926cc30
Show file tree
Hide file tree
Showing 11 changed files with 1,167 additions and 849 deletions.
82 changes: 77 additions & 5 deletions pkg/compiler/compiler_member_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,66 @@ func TestMember(t *testing.T) {
So(string(out), ShouldEqual, `"wsx"`)
})

Convey("Deep path", func() {
c := compiler.New()

p, err := c.Compile(`
LET obj = {
first: {
second: {
third: {
fourth: {
fifth: {
bottom: true
}
}
}
}
}
}
RETURN obj.first.second.third.fourth.fifth.bottom
`)

So(err, ShouldBeNil)

out, err := p.Run(context.Background())

So(err, ShouldBeNil)

So(string(out), ShouldEqual, `true`)
})

Convey("Deep computed path", func() {
c := compiler.New()

p, err := c.Compile(`
LET obj = {
first: {
second: {
third: {
fourth: {
fifth: {
bottom: true
}
}
}
}
}
}
RETURN obj["first"]["second"]["third"]["fourth"]["fifth"].bottom
`)

So(err, ShouldBeNil)

out, err := p.Run(context.Background())

So(err, ShouldBeNil)

So(string(out), ShouldEqual, `true`)
})

Convey("Prop after a func call", func() {
c := compiler.New()

Expand Down Expand Up @@ -160,9 +220,9 @@ func TestMember(t *testing.T) {

func BenchmarkMemberArray(b *testing.B) {
p := compiler.New().MustCompile(`
LET arr = [1]
LET arr = [[[[1]]]]
RETURN arr[0]
RETURN arr[0][0][0][0]
`)

for n := 0; n < b.N; n++ {
Expand All @@ -172,9 +232,21 @@ func BenchmarkMemberArray(b *testing.B) {

func BenchmarkMemberObject(b *testing.B) {
p := compiler.New().MustCompile(`
LET obj = { "foo": "bar"}
RETURN obj.foo
LET obj = {
first: {
second: {
third: {
fourth: {
fifth: {
bottom: true
}
}
}
}
}
}
RETURN obj.first.second.third.fourth.fifth.bottom
`)

for n := 0; n < b.N; n++ {
Expand Down
50 changes: 50 additions & 0 deletions pkg/compiler/compiler_param_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,54 @@ func TestParam(t *testing.T) {
So(string(out), ShouldEqual, `[1,2,3,4]`)

})

Convey("Should be possible to use in member expression", t, func() {
prog := compiler.New().
MustCompile(`
RETURN @param.value
`)

out := prog.MustRun(
context.Background(),
runtime.WithParam("param", map[string]interface{}{
"value": "foobar",
}),
)

So(string(out), ShouldEqual, `"foobar"`)

})

Convey("Should be possible to use in member expression as a computed property", t, func() {
prog := compiler.New().
MustCompile(`
LET obj = { foo: "bar" }
RETURN obj[@param]
`)

out := prog.MustRun(
context.Background(),
runtime.WithParam("param", "foo"),
)

So(string(out), ShouldEqual, `"bar"`)
})

Convey("Should be possible to use in member expression as segments", t, func() {
prog := compiler.New().
MustCompile(`
LET doc = { foo: { bar: "baz" } }
RETURN doc.@attr.@subattr
`)

out := prog.MustRun(
context.Background(),
runtime.WithParam("attr", "foo"),
runtime.WithParam("subattr", "bar"),
)

So(string(out), ShouldEqual, `"baz"`)

})
}
94 changes: 60 additions & 34 deletions pkg/compiler/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -736,39 +736,13 @@ func (v *visitor) doVisitForExpressionStatement(ctx *fql.ForExpressionStatementC
}

func (v *visitor) doVisitMemberExpression(ctx *fql.MemberExpressionContext, scope *scope) (core.Expression, error) {
var source core.Expression
var children []antlr.Tree
member, err := v.doVisitMember(ctx.Member().(*fql.MemberContext), scope)

identifier := ctx.Identifier()

if identifier != nil {
varName := ctx.Identifier().GetText()

_, err := scope.GetVariable(varName)

if err != nil {
return nil, err
}

varExp, err := expressions.NewVariableExpression(v.getSourceMap(ctx), varName)

if err != nil {
return nil, err
}

source = varExp
children = ctx.GetChildren()
} else {
fcall, err := v.doVisitFunctionCallExpression(ctx.FunctionCallExpression().(*fql.FunctionCallExpressionContext), scope)

if err != nil {
return nil, err
}

source = fcall
children = ctx.GetChildren()[1:]
if err != nil {
return nil, err
}

children := ctx.MemberPath().GetChildren()
path := make([]core.Expression, 0, len(children))

for _, child := range children {
Expand Down Expand Up @@ -808,17 +782,61 @@ func (v *visitor) doVisitMemberExpression(ctx *fql.MemberExpressionContext, scop
path = append(path, exp)
}

member, err := expressions.NewMemberExpression(
exp, err := expressions.NewMemberExpression(
v.getSourceMap(ctx),
source,
member,
path,
)

if err != nil {
return nil, err
}

return member, nil
return exp, nil
}

func (v *visitor) doVisitMember(ctx *fql.MemberContext, scope *scope) (core.Expression, error) {
identifier := ctx.Identifier()

if identifier != nil {
varName := ctx.Identifier().GetText()

_, err := scope.GetVariable(varName)

if err != nil {
return nil, err
}

exp, err := expressions.NewVariableExpression(v.getSourceMap(ctx), varName)

if err != nil {
return nil, err
}

return exp, nil
}

fnCall := ctx.FunctionCallExpression()

if fnCall != nil {
exp, err := v.doVisitFunctionCallExpression(fnCall.(*fql.FunctionCallExpressionContext), scope)

if err != nil {
return nil, err
}

return exp, nil
}

param := ctx.Param()

exp, err := v.doVisitParamContext(param.(*fql.ParamContext), scope)

if err != nil {
return nil, err
}

return exp, nil
}

func (v *visitor) doVisitObjectLiteral(ctx *fql.ObjectLiteralContext, scope *scope) (core.Expression, error) {
Expand Down Expand Up @@ -871,7 +889,7 @@ func (v *visitor) doVisitObjectLiteral(ctx *fql.ObjectLiteralContext, scope *sco
return literals.NewObjectLiteralWith(props...), nil
}

func (v *visitor) doVisitPropertyNameContext(ctx *fql.PropertyNameContext, _ *scope) (core.Expression, error) {
func (v *visitor) doVisitPropertyNameContext(ctx *fql.PropertyNameContext, scope *scope) (core.Expression, error) {
var name string

identifier := ctx.Identifier()
Expand All @@ -884,6 +902,14 @@ func (v *visitor) doVisitPropertyNameContext(ctx *fql.PropertyNameContext, _ *sc
if stringLiteral != nil {
runes := []rune(stringLiteral.GetText())
name = string(runes[1 : len(runes)-1])
} else {
param, err := v.doVisitParamContext(ctx.Param().(*fql.ParamContext), scope)

if err != nil {
return nil, err
}

return param, nil
}
}

Expand Down
17 changes: 13 additions & 4 deletions pkg/parser/antlr/FqlParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ computedPropertyName
propertyName
: Identifier
| stringLiteral
| param
;

expressionGroup
Expand All @@ -209,11 +210,19 @@ functionCallExpression
: namespace Identifier arguments
;

member
: Identifier
| functionCallExpression
| param
;

memberPath
: (Dot propertyName (computedPropertyName)*)+
| computedPropertyName (Dot propertyName (computedPropertyName)*)* (computedPropertyName (Dot propertyName)*)*
;

memberExpression
: Identifier (Dot propertyName (computedPropertyName)*)+
| Identifier computedPropertyName (Dot propertyName (computedPropertyName)*)* (computedPropertyName (Dot propertyName)*)*
| functionCallExpression (Dot propertyName (computedPropertyName)*)+
| functionCallExpression computedPropertyName (Dot propertyName (computedPropertyName)*)* (computedPropertyName (Dot propertyName)*)*
: member memberPath
;

arguments
Expand Down
4 changes: 3 additions & 1 deletion pkg/parser/fql/FqlParser.interp

Large diffs are not rendered by default.

Loading

0 comments on commit 926cc30

Please sign in to comment.