aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/query/parser.go
diff options
context:
space:
mode:
authorJP Appel <jeanpierre.appel01@gmail.com>2025-06-10 16:33:03 -0400
committerJP Appel <jeanpierre.appel01@gmail.com>2025-06-10 16:33:03 -0400
commiteef03d11d91afe3f722830b966ad5494d8d85e19 (patch)
treef487c4cd0b99070e5a67c821a1aabc90e806d9b6 /pkg/query/parser.go
parentc3d812262761c140316f5501783f8302191e5053 (diff)
Add method to merge subtrees in a clause tree
Add `Flatten` method to `query.Clause` which merges a parent clause with its children. The merge occurs if clauses have the same operator. The merge transforms the tree similar to the examples below: (+ (+ (+ (+ a b) c) d) e) -> (+ a b c d e) (+ (+ a b) c (* d e)) -> (+ a b c (* d e))
Diffstat (limited to 'pkg/query/parser.go')
-rw-r--r--pkg/query/parser.go46
1 files changed, 42 insertions, 4 deletions
diff --git a/pkg/query/parser.go b/pkg/query/parser.go
index 2a70819..e8fccfe 100644
--- a/pkg/query/parser.go
+++ b/pkg/query/parser.go
@@ -3,6 +3,7 @@ package query
import (
"fmt"
"os"
+ "slices"
"strings"
"time"
@@ -76,7 +77,7 @@ var _ Valuer = StringValue{}
var _ Valuer = DatetimeValue{}
type StringValue struct {
- s string
+ S string
}
func (v StringValue) Type() valuerType {
@@ -89,9 +90,9 @@ func (v StringValue) Compare(other Valuer) int {
return 0
}
- if v.s < o.s {
+ if v.S < o.S {
return -1
- } else if v.s > o.s {
+ } else if v.S > o.S {
return 1
} else {
return 0
@@ -218,6 +219,43 @@ func (c Clause) String() string {
return b.String()
}
+// Merge child clauses with their parents when applicable
+func (root *Clause) Flatten() {
+ stack := make([]*Clause, 0, len(root.Clauses))
+ stack = append(stack, root)
+ for len(stack) != 0 {
+ top := len(stack) - 1
+ node := stack[top]
+ stack = stack[:top]
+
+ hasMerged := false
+ // cannot be "modernized", node.Clauses is modified in loop
+ for i := 0; i < len(node.Clauses); i++ {
+ child := node.Clauses[i]
+
+ // merge because of commutativity
+ if node.Operator == child.Operator {
+ hasMerged = true
+ node.Statements = append(node.Statements, child.Statements...)
+ node.Clauses = append(node.Clauses, child.Clauses...)
+ } else {
+ stack = append(stack, child)
+ }
+ }
+
+ if hasMerged {
+ numChildren := len(stack) - top
+ if numChildren > 0 {
+ node.Clauses = slices.Grow(node.Clauses, numChildren)
+ node.Clauses = node.Clauses[:numChildren]
+ copy(node.Clauses, stack[top:top+numChildren])
+ } else {
+ node.Clauses = nil
+ }
+ }
+ }
+}
+
func (c Clause) buildString(b *strings.Builder, level int) {
writeIndent(b, level)
b.WriteByte('(')
@@ -349,7 +387,7 @@ func Parse(tokens []Token) (*Clause, error) {
default:
fmt.Fprintln(os.Stderr, token)
return nil, &TokenError{
- got: token,
+ got: token,
gotPrev: prevToken,
}
}