Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 5 additions & 1 deletion ast/ast_xgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,14 @@ func (*AnySelectorExpr) exprNode() {}
// -----------------------------------------------------------------------------

// A CondExpr node represents a conditional expression: `expr @ cond`.
// - ns@(condExpr)
// - ns@fn(args)
// - ns@"elem-name" (Cond will be a *Ident with name "elem-name", not a *BasicLit)
// - ns@name
type CondExpr struct {
X Expr // expression
OpPos token.Pos // position of "@"
Cond Expr // condition expression
Cond Expr // condition expression (can be *CallExpr, *ParensExpr or *Ident)
}

// Pos - position of first character belonging to the node.
Expand Down
4 changes: 4 additions & 0 deletions cl/_testgop/dql3/in.xgo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import "github.com/goplus/xgo/cl/internal/dql"

doc := dql.new
echo doc.*@users@"users".$name
11 changes: 11 additions & 0 deletions cl/_testgop/dql3/out.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

import (
"fmt"
"github.com/goplus/xgo/cl/internal/dql"
)

func main() {
doc := dql.New()
fmt.Println(doc.XGo_Child().XGo_Select("users").XGo_Select("users").XGo_Attr__0("name"))
}
11 changes: 11 additions & 0 deletions cl/error_msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,17 @@ b := *a
`)
}

func TestErrCondExpr(t *testing.T) {
codeErrorTest(t,
`bar.xgo:5:6: assignment mismatch: 2 variables but self.XGo_first returns 1 values
don't call End(), please use EndInit() instead`, `
import "github.com/goplus/xgo/cl/internal/dql"

doc := dql.new2
echo doc.users@($age < 18).$name
`)
}

func TestErrMember(t *testing.T) {
codeErrorTest(t,
`bar.xgo:3:6: a.$x undefined (type string has no field or method XGo_Attr)`,
Expand Down
15 changes: 12 additions & 3 deletions cl/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,8 +508,18 @@ func compileCondExpr(ctx *blockCtx, v *ast.CondExpr) {
nameErr = "_xgo_err"
)
xExpr := v.X
condExpr := v.Cond
cb := ctx.cb
compileExpr(ctx, 1, xExpr)
cb, pkg := ctx.cb, ctx.pkg
if id, ok := condExpr.(*ast.Ident); ok {
name := id.Name
if strings.HasPrefix(name, `"`) { // @"elem-name"
name = unquote(name)
}
cb.MemberVal("XGo_Select", 0, v).Val(name, id).CallWith(1, 1, 0, v)
return
}
pkg := ctx.pkg
x := cb.Get(-1) // x.Type is NodeSet
nsType := x.Type
pkgTypes := pkg.Types
Expand All @@ -518,13 +528,12 @@ func compileCondExpr(ctx *blockCtx, v *ast.CondExpr) {
yieldParams := types.NewTuple(varSelf)
yieldRets := types.NewTuple(types.NewParam(0, nil, "", types.Typ[types.Bool]))
sigYield := types.NewSignatureType(nil, nil, nil, yieldParams, yieldRets, false)
condExpr := v.Cond
cb.NewClosureWith(sigYield).BodyStart(pkg, condExpr).
If(condExpr)
compileExpr(ctx, 1, condExpr)
cb.Then(condExpr).
If().DefineVarStart(0, nameVal, nameErr).
Val(varSelf).MemberVal("XGo_first", 0).CallWith(0, 2, 0)
Val(varSelf).MemberVal("XGo_first", 0, v).CallWith(0, 2, 0, v)
firstRet := cb.Get(-1)
nodeType := firstRet.Type.(*types.Tuple).At(0).Type()
varYield := newNodeSeqParam(pkgTypes, nodeType)
Expand Down
31 changes: 31 additions & 0 deletions cl/internal/dql/dql.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func (p NodeSet) XGo_Any(name string) NodeSet {
return NodeSet{}
}

func (p NodeSet) XGo_Select(name string) NodeSet {
return NodeSet{}
}

// XGo_Child returns a NodeSet containing all child nodes of the nodes in the NodeSet.
func (p NodeSet) XGo_Child() NodeSet {
return NodeSet{}
Expand All @@ -53,3 +57,30 @@ func (p NodeSet) XGo_Attr__0(name string) int {
func (p NodeSet) XGo_Attr__1(name string) (int, error) {
return 0, nil
}

type NodeSet2 struct {
}

func New2() NodeSet2 {
return NodeSet2{}
}

func NodeSet2_Cast(func(yield func(*Node) bool)) NodeSet2 {
return NodeSet2{}
}

func (p NodeSet2) XGo_first() *Node {
return nil
}

func (p NodeSet2) XGo_Enum() iter.Seq[NodeSet2] {
return nil
}

func (p NodeSet2) XGo_Elem(name string) NodeSet2 {
return NodeSet2{}
}

func (p NodeSet2) XGo_Attr(name string) int {
return 0
}
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions parser/_testdata/dql2/dql.xgo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
echo doc.*@users@"users".$name
44 changes: 44 additions & 0 deletions parser/_testdata/dql2/parser.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package main

file dql.xgo
noEntrypoint
ast.FuncDecl:
Name:
ast.Ident:
Name: main
Type:
ast.FuncType:
Params:
ast.FieldList:
Body:
ast.BlockStmt:
List:
ast.ExprStmt:
X:
ast.CallExpr:
Fun:
ast.Ident:
Name: echo
Args:
ast.SelectorExpr:
X:
ast.CondExpr:
X:
ast.CondExpr:
X:
ast.SelectorExpr:
X:
ast.Ident:
Name: doc
Sel:
ast.Ident:
Name: *
Cond:
ast.Ident:
Name: users
Cond:
ast.Ident:
Name: "users"
Sel:
ast.Ident:
Name: $name
13 changes: 10 additions & 3 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2634,15 +2634,22 @@ L:
ce := &ast.CondExpr{X: x, OpPos: p.pos}
p.next()
switch p.tok {
case token.IDENT:
fun := p.parseIdent()
ce.Cond = p.parseCallOrConversion(fun, false) // @fun(...)
case token.LPAREN:
cond, kind := p.parseOperand(0) // @(cond)
if kind != exprNormal {
p.error(cond.Pos(), "invalid condition expression")
}
ce.Cond = p.checkExpr(cond)
case token.IDENT:
fun := p.parseIdent()
if p.tok == token.LPAREN {
ce.Cond = p.parseCallOrConversion(fun, false) // @fun(...)
} else {
ce.Cond = fun // @name
}
case token.STRING: // @"elem-name"
ce.Cond = &ast.Ident{NamePos: p.pos, Name: p.lit}
p.next()
default:
pos := p.pos
p.errorExpected(pos, "condition expression", 2)
Expand Down