Skip to content

Commit

Permalink
?map works on hts. improved operator envs. rename *map to ?map
Browse files Browse the repository at this point in the history
  • Loading branch information
inconvergent committed Feb 28, 2024
1 parent 8d64016 commit 19972a1
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 149 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ See [bin/ex.lisp](bin/ex.lisp) for more examples.
## Object Representation
Internally JSON arrays are represented as `vector`. and JSON objects are
Internally JSON arrays are represented as `vector`. and JSON objects are
represented as `hash-table`; `kv` (key/value) is used in the docs for short.
In `tqn` lines of text are `vectors` of `strings`. In `lqn` Lisp files are
In `tqn` lines of text are `vectors` of `strings`. In `lqn` Lisp files are
read as a `vector` of lisp data.
## Operators
Expand All @@ -148,7 +148,7 @@ The following operators have special behaviour. You can also write generic CL
code, anywhere you can use an operator. Including the functions further down.
Note that you can use `_` to refer to the current value.
In the following sections `[d]` represents an optional default value. E.g. if
In the following sections `[d]` represents an optional default value. E.g. if
key/index is missing, or if a functon returns `nil`. `k` is an initial counter
value. Whereas `..` menans that there can be arbitrary arguments, `Selectors`
or `exprs`; depending on the context. `expr` denotes any expression or
Expand All @@ -166,16 +166,16 @@ surrounds all terminal queries by default.
For convenience, particularly in the terminal, pipe has the following default
translations:
- `fx`: to `(*map (fx _))`: map `fx` across all items.
- `fx`: to `(?map (fx _))`: map `fx` across all items.
- `:word`: to `[(isub? _ "word")]` to filter by `"word"`.
- `"Word"`: to `[(sub? _ "Word")]` to filter all items by this `string` with
case.
- `(..)`: to itself. That is, expressions are not translated.
### Map Operator - `#()`/`*map`
### Map Operator - `#()`/`?map`
Map operations over `vector`:
- `#(fx)` or `(*map fx)`: map `(fx _)` across all items.
- `#(expr ..)` or `(*map expr ..)`: evaluate these expressions
- `#(fx)` or `(?map fx)`: map `(fx _)` across all items.
- `#(expr ..)` or `(?map expr ..)`: evaluate these expressions
sequentially on all items in `sequence`.
### Fold Operator - `*fld`
Expand Down
114 changes: 65 additions & 49 deletions bin/ex.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -5,59 +5,75 @@
(ql:quickload :lqn :silent t)
(in-package :lqn)

(print (qry "1 x 1 x 7 x 100" (splt _ :x) int!? (*fld 0 (+ _)))) ;; 109
(print (qry "1 x 1 x 7 x 100" (splt _ :x) int!? (*fld 0 +))) ;; 109
(print (qry "1 x 1 x 7 x 100" (splt _ :x) int!? (*fld 0 acc (- _ acc)))) ;; 93

(pretty-json
(qry "abc x def x gehiil x iiii"
(splt _ :x) str!? trim ; split and trim
(new$ :in (par) ; new kv with input
:len (pnum) ; input length
:items #((new$ :s _ :len (inum)))))) ; and substr lengths
;; { "in": "abc x def x gehiil x iiii",
;; "len": 25,
;; "items": [ { "s": "abc", "len": 3 }, { "s": "def", "len": 3 },
;; { "s": "gehiil", "len": 6 }, { "s": "iiii", "len": 4 } ] }

(print (ldnout (qry #("1 x 1 x 7 x 100" "3 x 8 x 30")
#((splt _ :x) int!? ; for each row, split and parse as int
(*fld 0 +))))) ; sum each row
;; #(109 41)

(print (qry "aaayyy x abc x def x auiuu x aaaaa"
(splt _ :x) trim ; split
#((?xpr :a :-@b sup (str! _ :-miss))))) ; search & replace
;; #("AAAYYY" "abc-miss" "def-miss" "AUIUU" "AAAAA")

(print (qry #((a b xxx) (a b c) (a b (c xxx)))
#((?txpr (msym? _ xxx) ; recursive search & replace
(symb _ :-HIT---))))) ; with new symbol
;; #((A B XXX-HIT---) (A B C) (A B (C XXX-HIT---)))

(print (qry #((a bbbxxx xxx) (a b c) (a b (c xxx)))
; symbols with "xxx", but not "bbb"
(?txpr (-@msym? _ "bbb") (+@msym? _ "xxx")
(sym! _ :-HIT---))))
;; #((A BBBXXX XXX-HIT---) (A B C) (A B (C XXX-HIT---)))

(pretty-json (jsnqryf (internal-path-string "data/sample.json")
(|| #{:_id (:things #[:name])})))
;; [ { "_id": "65679d23d38d711eaf999e89",
;; "things": [ "Chris" ] },
;; { "_id": "65679d23fe33bc4c240675c0",
;; "things": [ "Winters", "Haii", "Klein" ] },
;; { "_id": "65679d235b4143d2932ea17a",
;; "things": [ "Star", "Ball" ] } ]

(print (lqn:qry #(0 1) (?rec (< (@ -1) 10000)
(cat* _ (apply* + (tail _ 2))))
#((str! "- " (cnt) ": " _))
(join _ #\Newline)))
; (print (qry "1 x 1 x 7 x 100" (splt _ :x) int!? (*fld 0 (+ _)))) ;; 109
; (print (qry "1 x 1 x 7 x 100" (splt _ :x) int!? (*fld 0 +))) ;; 109
; (print (qry "1 x 1 x 7 x 100" (splt _ :x) int!? (*fld 0 acc (- _ acc)))) ;; 93

; (pretty-json
; (qry "abc x def x gehiil x iiii"
; (splt _ :x) str!? trim ; split and trim
; (new$ :in (par) ; new kv with input
; :len (pnum) ; input length
; :items #((new$ :s _ :len (inum)))))) ; and substr lengths
; ;; { "in": "abc x def x gehiil x iiii",
; ;; "len": 25,
; ;; "items": [ { "s": "abc", "len": 3 }, { "s": "def", "len": 3 },
; ;; { "s": "gehiil", "len": 6 }, { "s": "iiii", "len": 4 } ] }

; (print (ldnout (qry #("1 x 1 x 7 x 100" "3 x 8 x 30")
; #((splt _ :x) int!? ; for each row, split and parse as int
; (*fld 0 +))))) ; sum each row
; ;; #(109 41)

; (print (qry "aaayyy x abc x def x auiuu x aaaaa"
; (splt _ :x) trim ; split
; #((?xpr :a :-@b sup (str! _ :-miss))))) ; search & replace
; ;; #("AAAYYY" "abc-miss" "def-miss" "AUIUU" "AAAAA")

; (print (qry #((a b xxx) (a b c) (a b (c xxx)))
; #((?txpr (msym? _ xxx) ; recursive search & replace
; (symb _ :-HIT---))))) ; with new symbol
; ;; #((A B XXX-HIT---) (A B C) (A B (C XXX-HIT---)))

; (print (qry #((a bbbxxx xxx) (a b c) (a b (c xxx)))
; ; symbols with "xxx", but not "bbb"
; (?txpr (-@msym? _ "bbb") (+@msym? _ "xxx")
; (sym! _ :-HIT---))))
; ;; #((A BBBXXX XXX-HIT---) (A B C) (A B (C XXX-HIT---)))

; (pretty-json (jsnqryf (internal-path-string "data/sample.json")
; (|| #{:_id (:things #[:name])})))
; ;; [ { "_id": "65679d23d38d711eaf999e89",
; ;; "things": [ "Chris" ] },
; ;; { "_id": "65679d23fe33bc4c240675c0",
; ;; "things": [ "Winters", "Haii", "Klein" ] },
; ;; { "_id": "65679d235b4143d2932ea17a",
; ;; "things": [ "Star", "Ball" ] } ]

; (print (lqn:qry #(0 1) (?rec (< (@ -1) 10000)
; (cat* _ (apply* + (tail _ 2))))
; #((str! "- " (cnt) ": " _))
; (join _ #\Newline)))
;; - 0: 0
;; - 1: 1
;; - 2: 1
;; - 3: 2
;; - 4: 3
;; - 5: 5
;; ...
(print :--------------------)

; (print (lqn:ldnout (lqn::qrydb
; (lqn:jsnloads "[1, 2, 3]")
; (*fld 0 (+ _ (progn (print (key)) (val)) )))))

; (print (lqn:ldnout (lqn::qrydb
; (lqn:jsnloads "[1, 2, 3]")
; (*fld 0 (list (print _))))))

(print (lqn:ldnout
(lqn::qrydb (lqn:jsnloads "[{\"a\": 1, \"b\": 23},
{\"a\": 11, \"b\": 123},
{\"a\": 11, \"b\": 123}
]")
(*fld 0 (+ (@ :a)) ))))
4 changes: 2 additions & 2 deletions lqn.asd
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(asdf:defsystem #:lqn
:description "Lisp Query Notation"
:version "1.16.0"
:version "1.17.0"
:author "anders hoff / @inconvergent / [email protected]"
:in-order-to ((asdf:test-op (asdf:test-op #:lqn/tests)))
:licence "MIT" :pathname "src/" :serial nil
Expand All @@ -19,7 +19,7 @@

(asdf:defsystem #:lqn/tests
:depends-on (#:lqn #:prove #:uiop #:asdf)
:version "1.16.0"
:version "1.17.0"
:perform (asdf:test-op (o s) (uiop:symbol-call ':lqn-tests '#:run-tests))
:pathname "test/" :serial t
:components ((:file "run")))
4 changes: 2 additions & 2 deletions src/init.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

(defvar *qmodes* '(:+ :? :- :%))
(defvar *operators*
`(:*map :@ :|| ?rec :*$ :$$ :$* :** :*fld :?* :?xpr :?txpr :?mxpr :?srch :?grp))
`(:?map :@ :|| ?rec :*$ :$$ :$* :** :*fld :?* :?xpr :?txpr :?mxpr :?srch :?grp))
(defvar *opt* '(optimize (speed 3) (safety 1)))
(defvar *fxns* '(:err :wrn :nope :noop :lst :lit :qt :hld :ghv :pnum :inum :cnt
:fmt :out :jsnstr
:fn :fi :ctx :par :itr :compct :?? :@@ :@*
:fn :fi :ctx :par :itr :key :val :compct :?? :@@ :@*
:read? :some? :all? :none? :smth? :size?
:new* :new$ :cat* :cat$
:ind* :sel :seq :apply* :grp :uniq
Expand Down
28 changes: 15 additions & 13 deletions src/pre-qry.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
(defun dat/new (conf dat) `((:dat . ,dat) ,@conf))
(defun strip-all (d) (declare (list d)) (if (car- dat? d) (cdr d) d))

; CONTEXTS
; CONTEXTS ; envs

(defmacro //fxs/qry ((dat fn fi) &body body)
(defmacro q∈ ((dat fn fi) &body body)
(declare (symbol dat fn fi))
(awg (nope meta)
`(let ((,meta (make-hash-table :test #'eq)))
Expand All @@ -41,18 +41,19 @@
(wrn (&optional a) (warn "qry wrn: ~a." a))
(par () ,dat)
(pnum (&optional d) (size? (par) d))
(itr () (wrn "no (itr) in qry scope."))
(inum () (wrn "no (inum) in qry scope.")))
(itr () (wrn "no (itr) in this scope."))
(key () (wrn "no (key) in this scope."))
(inum () (wrn "no (inum) in this scope.")))
,@body)))))

(defmacro ∈ ((par &optional i itr) &body body)
(declare (symbol par itr))
(defmacro ∈ ((&key par cnt itr key) &body body)
(declare (symbol par cnt itr))
`(labels (,@(when par `((par () ,par) (pnum () (size? ,par))))
,@(when itr `((itr () ,itr) (inum () (size? ,itr))))
,@(when i `((cnt (&optional (k 0)) (+ ,i k)))))
,@(when cnt `((cnt (&optional (k 0)) (+ ,cnt k))))
,@(when key `((key () ,key))))
,@body))


; PRE PROCESSORS

(defun when-equal (a b) (when (equal a b) a))
Expand Down Expand Up @@ -90,16 +91,17 @@
(defun pre/|| (qq) (unless qq (warn "||: missing args.")) ; pipe
(loop for q in (pre/scan-clauses qq '#:pipe) collect
(if (dat? q) (kw q)
(typecase q (cons q) (keyword `(** ,q)) (symbol `(*map ,q))
(string `(** ,q)) (vector `(*map ,@(coerce q 'list)))
(typecase q (cons q) (boolean q)
(keyword `(** ,q)) (string `(** ,q))
(symbol `(?map ,q)) (vector `(?map ,@(coerce q 'list)))
(otherwise q)))))

(defun pre/*map (q &optional (mm :+)) (unless q (warn "*map: missing args."))
(defun pre/?map (q &optional (mm :+)) (unless q (warn "?map: missing args."))
(labels ((unpack- (o) ; NOTE: can we use modes here?
(dsb (m sk) (unpack-mode o mm)
(unless (eq m :+) (error "*map: expected mode :+, got: ~a." m))
(unless (eq m :+) (error "?map: expected mode :+, got: ~a." m))
(etypecase sk (sequence sk) (keyword sk) (symbol `(,sk :_))))))
(let* ((q* (remove-if #'dat? (pre/scan-clauses q '#:*map)))
(let* ((q* (remove-if #'dat? (pre/scan-clauses q '#:?map)))
(res (mapcar #'unpack- q*))
(allres (if (= (length q) (length q*)) res (cons `(lit :_) res))))
(if (< (length allres) 2) allres `((|| ,@allres))))))
Expand Down
10 changes: 7 additions & 3 deletions src/qry-utils.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ match. If b is an expression, a is compared to the evaluated value of b."

(defun @@ (a path &optional d) (declare #.*opt*)
"get nested key (e.g. aa/2/bb) from nested structure of kv/vec"
(labels ((gkv (a* k) (typecase a* (hash-table (gethash k a*)) (otherwise nil)))
(labels ((err (p) (error "@@: unexpected path: ~a" p))
(wrn (p) (warn "@@: unexpected path: ~a" p))
(gkv (a* k) (typecase a* (hash-table (gethash k a*)) (otherwise nil)))
(ind (a* k) (if (< k 0) (+ (length a*) k) k))
(gv (a* k) (when (vec? a*)
(let ((kk (ind a* k)))
Expand All @@ -130,8 +132,10 @@ match. If b is an expression, a is compared to the evaluated value of b."
(t (gkv a* k)))))
(if (is? v) (rec v kk) (return-from rec d)))))
(compct
(rec a (etypecase path (fixnum (list path)) (character (list path)) (list path)
(string (pre path)) (keyword (pre (str! path))))))))
(rec a (typecase path (boolean (wrn path))
(fixnum (list path)) (character (list path)) (list path)
(string (pre path)) (keyword (pre (str! path)))
(otherwise (err path)))))))
(defun compct (o) (declare #.*opt*)
"remove none/nil, emtpy arrays, empty objects, empty keys and empty lists from `a`."
(labels
Expand Down
Loading

0 comments on commit 19972a1

Please sign in to comment.