Skip to content

Commit b8f16a3

Browse files
committed
Ensure that & doesn't get parsed as :amp outside of collections
Fixes GH-199
1 parent d92bd05 commit b8f16a3

File tree

2 files changed

+116
-77
lines changed

2 files changed

+116
-77
lines changed

src/meander/syntax/epsilon.cljc

+102-76
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,21 @@
1515

1616
#?(:clj (set! *warn-on-reflection* true))
1717

18+
(defn with-collection-context
19+
{:private true}
20+
[env]
21+
(assoc env ::context :collection))
22+
23+
(defn with-scalar-context
24+
{:private true}
25+
[env]
26+
(assoc env ::context :scalar))
27+
28+
(defn scalar-context?
29+
{:private true}
30+
[{:keys [::context]}]
31+
(= context :scalar))
32+
1833
(defn node?
1934
"true if x is an AST node."
2035
[x]
@@ -644,81 +659,92 @@
644659
(assoc (parse xs* env) ::original-form xs))))
645660
(parse-seq-not-special xs env))))
646661

647-
(defn parse-symbol
662+
(defn parse-maybe-special-symbol
648663
{:private true}
649664
[sym]
665+
(let [s (name sym)]
666+
(cond
667+
(r.util/re-matches? #"^_.*" s)
668+
{:tag :any
669+
:symbol sym}
670+
671+
(r.util/re-matches? #"^\?.+" s)
672+
{:tag :lvr
673+
:symbol sym}
674+
675+
(r.util/re-matches? #"^!.+" s)
676+
{:tag :mvr
677+
:symbol sym}
678+
679+
(r.util/re-matches? #"^%.+" s)
680+
{:tag :ref
681+
:symbol sym}
682+
683+
(r.util/re-matches? #"^\*.+" s)
684+
{:tag :mut
685+
:symbol sym}
686+
687+
:else
688+
{:tag :lit
689+
:value sym})))
690+
691+
(defn parse-symbol
692+
{:private true}
693+
[sym env]
650694
(if (namespace sym)
651695
{:tag :lit
652696
:value sym}
653-
(let [s (name sym)
654-
[$0 $N $L $M] (re-matches #"\.(?:\.(?:\.|(\d+)|(\?.+)|(!.+))?)?" s)]
655-
(cond
656-
;; `..<nat-int>`
657-
(some? $N)
658-
(if (= $N "0")
659-
;; `..0` is the same as `...`.
660-
{:tag :dt*}
661-
;; Inteneral tag for postfix n or more operator.
662-
{:tag :dt+
663-
:n (r.util/parse-int $N)})
664-
665-
;; `..?<name>`
666-
(some? $L)
667-
;; Internal tag for postfix ?n or more operator.
668-
{:tag :dtl
669-
:lvr {:tag :lvr
670-
:symbol (symbol $L)}}
671-
672-
(some? $M)
673-
;; Internal tag for postfix !n or more operator.
674-
{:tag :dtm
675-
:mvr {:tag :mvr
676-
:symbol (symbol $M)}}
677-
678-
:else
679-
(case $0
680-
;; Internal tag for postfix partition.
681-
"."
682-
{:tag :dot}
683-
684-
;; Internal tag for postfix n or more operator.
685-
".."
686-
{:tag :dt+
687-
:n $N}
688-
689-
;; Internal tag for postfix 0 or more operator.
690-
"..."
691-
{:tag :dt*}
692-
693-
nil
694-
(cond
695-
(r.util/re-matches? #"^_.*" s)
696-
{:tag :any
697-
:symbol sym}
698-
699-
(r.util/re-matches? #"^\?.+" s)
700-
{:tag :lvr
701-
:symbol sym}
702-
703-
(r.util/re-matches? #"^!.+" s)
704-
{:tag :mvr
705-
:symbol sym}
706-
707-
(r.util/re-matches? #"^%.+" s)
708-
{:tag :ref
709-
:symbol sym}
710-
711-
(r.util/re-matches? #"^\*.+" s)
712-
{:tag :mut
713-
:symbol sym}
714-
715-
(r.util/re-matches? #"^&.*" s)
716-
{:tag :amp
717-
:symbol sym}
718-
719-
:else
720-
{:tag :lit
721-
:value sym}))))))
697+
(if (scalar-context? env)
698+
(parse-maybe-special-symbol sym)
699+
(let [s (name sym)
700+
[$0 $N $L $M] (re-matches #"\.(?:\.(?:\.|(\d+)|(\?.+)|(!.+))?)?" s)]
701+
(cond
702+
;; `..<nat-int>`
703+
(some? $N)
704+
(if (= $N "0")
705+
;; `..0` is the same as `...`.
706+
{:tag :dt*}
707+
;; Inteneral tag for postfix n or more operator.
708+
{:tag :dt+
709+
:n (r.util/parse-int $N)})
710+
711+
;; `..?<name>`
712+
(some? $L)
713+
;; Internal tag for postfix ?n or more operator.
714+
{:tag :dtl
715+
:lvr {:tag :lvr
716+
:symbol (symbol $L)}}
717+
718+
(some? $M)
719+
;; Internal tag for postfix !n or more operator.
720+
{:tag :dtm
721+
:mvr {:tag :mvr
722+
:symbol (symbol $M)}}
723+
724+
:else
725+
(case $0
726+
;; Internal tag for postfix partition.
727+
"."
728+
{:tag :dot}
729+
730+
;; Internal tag for postfix n or more operator.
731+
".."
732+
{:tag :dt+
733+
:n $N}
734+
735+
;; Internal tag for postfix 0 or more operator.
736+
"..."
737+
{:tag :dt*}
738+
739+
nil
740+
(cond
741+
;; Internal tag for rest patterns.
742+
(r.util/re-matches? #"^&.*" s)
743+
{:tag :amp
744+
:symbol sym}
745+
746+
:else
747+
(parse-maybe-special-symbol sym))))))))
722748

723749
(defn parse-js-value
724750
{:arglists '([val-of-js-value env])
@@ -777,7 +803,7 @@
777803
(parse pattern env))
778804
:map (into {} (map
779805
(fn [e]
780-
[(parse (key e) env) (parse (val e) env)]))
806+
[(parse (key e) env) (parse (val e) (with-scalar-context env))]))
781807
(get classified :assoc))
782808
:rest-map (if-some [es (get classified :merge)]
783809
{:tag :merge
@@ -836,20 +862,20 @@
836862
([form env]
837863
(let [node (cond
838864
(seq? form)
839-
(parse-seq form env)
865+
(parse-seq form (with-collection-context env))
840866

841867
(vector? form)
842-
(parse-vector form env)
868+
(parse-vector form (with-collection-context env))
843869

844870
(and (map? form)
845871
(not (record? form)))
846-
(parse-map form env)
872+
(parse-map form (with-collection-context env))
847873

848874
(set? form)
849-
(parse-set form env)
875+
(parse-set form (with-collection-context env))
850876

851877
(symbol? form)
852-
(parse-symbol form)
878+
(parse-symbol form env)
853879

854880
#?@(:clj [(r.util/js-value? form)
855881
(parse-js-value (r.util/val-of-js-value form) env)])

test/meander/epsilon_test.cljc

+14-1
Original file line numberDiff line numberDiff line change
@@ -2752,6 +2752,19 @@
27522752
:group-by (r/scan {:alias ?alias :as ?group-by})}
27532753
{:group-by [{:default {:from-expression ?expression} & ?group-by}]}
27542754

2755-
{:group-by (r/scan {(r/some :alias) ?a :as ?group-by})
2755+
{:group-by (r/scan {:alias ?a :as ?group-by})
27562756
:group-defaults (r/scan {:attribute {:alias (r/not ?a)}})}
27572757
{:group-by [?group-by]})))))
2758+
2759+
(t/deftest gh-199-test
2760+
;; Reported as a compilation error.
2761+
(let [query {}]
2762+
(t/is (r/rewrite query
2763+
{:as ?query :aggregates [(r/cata !agg) ...]}
2764+
{& ?query :aggregates [!agg ...]}
2765+
2766+
{:op "AVG", :args [{:computed ["deal_count_by_user"]}], :alias ?alias :as ?agg}
2767+
{?agg & :op "AVG", :args [{:computed ["user_count_by_deal"]}], :alias ?alias}
2768+
;; ^
2769+
2770+
?? ??))))

0 commit comments

Comments
 (0)