Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
12 changes: 12 additions & 0 deletions demo/dql-yaml/yq.xgo
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
config := yaml`server: localhost
port: 8080
features:
- auth
- logging
`!

echo config.port

for feature in config.features.* {
echo feature._value
}
17 changes: 17 additions & 0 deletions dql/html/html.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,23 @@ func (p NodeSet) Collect() ([]*Node, error) {
return dql.Collect(p.Data), nil
}

// Name returns the name of the first node in the NodeSet.
// empty string is returned if the NodeSet is empty or error occurs.
func (p NodeSet) Name__0() string {
val, _ := p.Name__1()
return val
}

// Name returns the name of the first node in the NodeSet.
// If the NodeSet is empty, it returns ErrNotFound.
func (p NodeSet) Name__1() (ret string, err error) {
node, err := p.XGo_first()
if err == nil {
ret = node.DataAtom.String()
}
return
}

// Value returns the data content of the first node in the NodeSet.
func (p NodeSet) Value__0() string {
val, _ := p.Value__1()
Expand Down
69 changes: 47 additions & 22 deletions dql/maps/maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ const (

// -----------------------------------------------------------------------------

// Node represents a map[string]any or []any node.
// Node represents a node.
type Node struct {
Name string
Children any // map[string]any or []any
Name string
Value any
}

// NodeSet represents a set of nodes.
Expand Down Expand Up @@ -78,7 +78,7 @@ func New(doc any) NodeSet {
}
return NodeSet{
Data: func(yield func(Node) bool) {
yield(Node{Name: "", Children: doc})
yield(Node{Name: "", Value: doc})
},
}
}
Expand Down Expand Up @@ -156,23 +156,14 @@ func (p NodeSet) XGo_Elem(name string) NodeSet {

// yieldElem yields the child node with the specified name if it exists.
func yieldElem(node Node, name string, yield func(Node) bool) bool {
if children, ok := node.Children.(map[string]any); ok {
if children, ok := node.Value.(map[string]any); ok {
if v, ok := children[name]; ok {
return yieldNode(name, v, yield)
return yield(Node{Name: name, Value: v})
}
}
return true
}

// yieldNode yields a node if the value is a map[string]any or []any.
func yieldNode(name string, v any, yield func(Node) bool) bool {
switch v.(type) {
case map[string]any, []any:
return yield(Node{Name: name, Children: v})
}
return true
}

// XGo_Child returns a NodeSet containing all child nodes of the nodes in the NodeSet.
func (p NodeSet) XGo_Child() NodeSet {
if p.Err != nil {
Expand All @@ -189,16 +180,16 @@ func (p NodeSet) XGo_Child() NodeSet {

// yieldChildNodes yields all child nodes of the given node.
func yieldChildNodes(node Node, yield func(Node) bool) bool {
switch children := node.Children.(type) {
switch children := node.Value.(type) {
case map[string]any:
for k, v := range children {
if !yieldNode(k, v, yield) {
if !yield(Node{Name: k, Value: v}) {
return false
}
}
case []any:
for _, v := range children {
if !yieldNode("", v, yield) {
if !yield(Node{Name: "", Value: v}) {
return false
}
}
Expand Down Expand Up @@ -233,7 +224,7 @@ func yieldAnyNodes(name string, node Node, yield func(Node) bool) bool {
return false
}
}
switch children := node.Children.(type) {
switch children := node.Value.(type) {
case map[string]any:
for k, v := range children {
if !yieldAnyNode(name, k, v, yield) {
Expand All @@ -255,7 +246,7 @@ func yieldAnyNodes(name string, node Node, yield func(Node) bool) bool {
func yieldAnyNode(name, k string, v any, yield func(Node) bool) bool {
switch v.(type) {
case map[string]any, []any:
return yieldAnyNodes(name, Node{Name: k, Children: v}, yield)
return yieldAnyNodes(name, Node{Name: k, Value: v}, yield)
}
return true
}
Expand Down Expand Up @@ -315,12 +306,46 @@ func (p NodeSet) XGo_first() (Node, error) {
return dql.First(p.Data)
}

// _name returns the name of the first node in the NodeSet.
// empty string is returned if the NodeSet is empty or error occurs.
func (p NodeSet) XGo_name__0() string {
val, _ := p.XGo_name__1()
return val
}

// _name returns the name of the first node in the NodeSet.
// If the NodeSet is empty, it returns ErrNotFound.
func (p NodeSet) XGo_name__1() (ret string, err error) {
node, err := p.XGo_first()
if err == nil {
ret = node.Name
}
return
}

// _value returns the value of the first node in the NodeSet.
// nil is returned if the NodeSet is empty or error occurs.
func (p NodeSet) XGo_value__0() any {
val, _ := p.XGo_value__1()
return val
}

// _value returns the value of the first node in the NodeSet.
// If the NodeSet is empty, it returns ErrNotFound.
func (p NodeSet) XGo_value__1() (ret any, err error) {
node, err := p.XGo_first()
if err == nil {
ret = node.Value
}
return
}

// _hasAttr returns true if the first node in the NodeSet has the specified attribute.
// It returns false otherwise.
func (p NodeSet) XGo_hasAttr(name string) bool {
node, err := p.XGo_first()
if err == nil {
switch children := node.Children.(type) {
switch children := node.Value.(type) {
case map[string]any:
_, ok := children[name]
return ok
Expand All @@ -345,7 +370,7 @@ func (p NodeSet) XGo_Attr__0(name string) any {
func (p NodeSet) XGo_Attr__1(name string) (val any, err error) {
node, err := p.XGo_first()
if err == nil {
switch children := node.Children.(type) {
switch children := node.Value.(type) {
case map[string]any:
if v, ok := children[name]; ok {
return v, nil
Expand Down
126 changes: 63 additions & 63 deletions dql/reflects/reflects.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ func uncapitalize(name string) string {

// -----------------------------------------------------------------------------

// Node represents a reflect.Value node.
// Node represents a node.
type Node struct {
Name string
Children reflect.Value
Name string
Value reflect.Value
}

// NodeSet represents a set of reflect.Value nodes.
// NodeSet represents a set of nodes.
type NodeSet struct {
Data iter.Seq[Node]
Err error
Expand Down Expand Up @@ -92,7 +92,7 @@ func Nodes(nodes ...Node) NodeSet {
func New(doc reflect.Value) NodeSet {
return NodeSet{
Data: func(yield func(Node) bool) {
yield(Node{Name: "", Children: doc})
yield(Node{Name: "", Value: doc})
},
}
}
Expand Down Expand Up @@ -167,8 +167,8 @@ func (p NodeSet) XGo_Elem(name string) NodeSet {

// yieldElem yields the child node with the specified name if it exists.
func yieldElem(node Node, name string, yield func(Node) bool) bool {
if v := lookup(node.Children, name); isNode(v) {
return yield(Node{Name: name, Children: v})
if v := lookup(node.Value, name); v.IsValid() {
return yield(Node{Name: name, Value: v})
}
return true
}
Expand Down Expand Up @@ -197,65 +197,31 @@ func deref(v reflect.Value) (reflect.Kind, reflect.Value) {
return kind, v
}

func isNodeType(v reflect.Type) bool {
kind := v.Kind()
if kind == reflect.Pointer {
v = v.Elem()
kind = v.Kind()
}
switch kind {
case reflect.Struct, reflect.Map, reflect.Interface:
return true
case reflect.Slice:
ekind := v.Elem().Kind()
return ekind > reflect.Complex128 && ekind != reflect.String
}
return false
}

func isNode(v reflect.Value) bool {
kind, v := deref(v)
switch kind {
case reflect.Struct, reflect.Map:
return true
case reflect.Slice:
ekind := v.Type().Elem().Kind()
return ekind > reflect.Complex128 && ekind != reflect.String
}
return false
}

func yieldChildNodes(node reflect.Value, yield func(Node) bool) bool {
kind, node := deref(node)
switch kind {
case reflect.Struct:
typ := node.Type()
for i, n := 0, typ.NumField(); i < n; i++ {
v := node.Field(i)
if isNode(v) {
if !yield(Node{Name: uncapitalize(typ.Field(i).Name), Children: v}) {
return false
}
if !yield(Node{Name: uncapitalize(typ.Field(i).Name), Value: v}) {
return false
}
}
case reflect.Map:
typ := node.Type()
if typ.Key().Kind() != reflect.String || !isNodeType(typ.Elem()) {
if typ.Key().Kind() != reflect.String { // Only support map[string]T
break
}
it := node.MapRange()
for it.Next() {
if !yield(Node{Name: it.Key().String(), Children: it.Value()}) {
if !yield(Node{Name: it.Key().String(), Value: it.Value()}) {
return false
}
}
case reflect.Slice:
elemType := node.Type().Elem()
if !isNodeType(elemType) {
break
}
for i := 0; i < node.Len(); i++ {
if !yield(Node{Name: "", Children: node.Index(i)}) {
if !yield(Node{Name: "", Value: node.Index(i)}) {
return false
}
}
Expand All @@ -271,7 +237,7 @@ func yieldAnyNodes(name string, node Node, yield func(Node) bool) bool {
return false
}
}
return yieldChildNodes(node.Children, func(n Node) bool {
return yieldChildNodes(node.Value, func(n Node) bool {
return yieldAnyNodes(name, n, yield)
})
}
Expand All @@ -284,7 +250,7 @@ func (p NodeSet) XGo_Child() NodeSet {
return NodeSet{
Data: func(yield func(Node) bool) {
p.Data(func(node Node) bool {
return yieldChildNodes(node.Children, yield)
return yieldChildNodes(node.Value, yield)
})
},
}
Expand Down Expand Up @@ -364,12 +330,59 @@ func (p NodeSet) XGo_first() (Node, error) {
return dql.First(p.Data)
}

// _name returns the name of the first node in the NodeSet.
// empty string is returned if the NodeSet is empty or error occurs.
func (p NodeSet) XGo_name__0() string {
val, _ := p.XGo_name__1()
return val
}

// _name returns the name of the first node in the NodeSet.
// If the NodeSet is empty, it returns ErrNotFound.
func (p NodeSet) XGo_name__1() (ret string, err error) {
node, err := p.XGo_first()
if err == nil {
ret = node.Name
}
return
}

// _value returns the value of the first node in the NodeSet.
// nil is returned if the NodeSet is empty or error occurs.
func (p NodeSet) XGo_value__0() any {
val, _ := p.XGo_value__1()
return val
}

// _value returns the value of the first node in the NodeSet.
// If the NodeSet is empty, it returns ErrNotFound.
func (p NodeSet) XGo_value__1() (ret any, err error) {
node, err := p.XGo_first()
if err == nil {
ret = node.Value.Interface()
}
return
}

// XGo_class returns the class name of the first node in the NodeSet.
func (p NodeSet) XGo_class() (class string) {
node, err := p.XGo_first()
if err != nil {
return
}
_, v := deref(node.Value)
if v.IsValid() {
return v.Type().Name()
}
return ""
}

// _hasAttr returns true if the first node in the NodeSet has the specified attribute.
// It returns false otherwise.
func (p NodeSet) XGo_hasAttr(name string) bool {
node, err := p.XGo_first()
if err == nil {
return lookup(node.Children, name).IsValid()
return lookup(node.Value, name).IsValid()
}
return false
}
Expand All @@ -390,25 +403,12 @@ func (p NodeSet) XGo_Attr__0(name string) any {
func (p NodeSet) XGo_Attr__1(name string) (val any, err error) {
node, err := p.XGo_first()
if err == nil {
if v := lookup(node.Children, name); v.IsValid() {
if v := lookup(node.Value, name); v.IsValid() {
return v.Interface(), nil
}
err = dql.ErrNotFound
}
return
}

// XGo_class returns the class name of the first node in the NodeSet.
func (p NodeSet) XGo_class() (class string) {
node, err := p.XGo_first()
if err != nil {
return
}
_, v := deref(node.Children)
if v.IsValid() {
return v.Type().Name()
}
return ""
}

// -----------------------------------------------------------------------------