git.fiddlerwoaroof.com
tree-sitter-parser.lisp
74ec9fd3
 ;; Uses death's bindings to tree-sitter: https://github.com/death/cl-tree-sitter
 (defpackage :fwoar.lisp-sandbox.tree-sitter-parser
   (:use :cl )
   (:export ))
 (in-package :fwoar.lisp-sandbox.tree-sitter-parser)
 
 (named-readtables:in-readtable :fare-quasiquote)
 
 (defun tag-p (it)
   (typecase it
     (keyword t)
     (list (= 2 (length it)))))
 
 (defun d-string (pos src)
   (let ((lines (fwoar.string-utils:get-part-modifier #\newline src)))
     lines
     (trivia:ematch pos
       (`((,s-c ,s-l) (,e-c ,e-l))
         (multiple-value-bind (_ s-l-c) (array-displacement (elt lines s-l))
           (declare (ignore _))
           (let ((start-pos (+ s-l-c s-c)))
             (multiple-value-bind (_ e-l-c) (array-displacement (elt lines e-l))
               (declare (ignore _))
               (let ((end-pos (+ e-l-c e-c)))
                 (make-array (- end-pos start-pos)
                             :element-type (array-element-type src)
                             :displaced-to src
                             :displaced-index-offset start-pos)))))))))
 
 (defun parse-thing (it)
   (trivia:ematch it
     (`((,tag ,op) ,pos ,childs)
       `(,tag ,op ,pos ,childs))
     (`(,op ,pos ,childs)
       `(nil ,op ,pos ,childs))))
 
 (defun displace-tree (tree src)
   (serapeum:map-tree
    (lambda (node)
      (typecase node
        (cons (if (and (tag-p (car node)) (= 3 (length node)))
                  (locally (declare (optimize (debug 3)))
                    (destructuring-bind (tag op pos childs) (parse-thing node)
                      (list (if tag
                                (list tag op)
                                op)
                            (d-string pos src)
                            childs)))
                  node))
        (t node)))
    tree
    :traversal :postorder))
 
f504fb4b
 (defvar *current-language* :tsx)
74ec9fd3
 (defun parse (src &optional (language *current-language*))
   (typecase src
f504fb4b
     (pathname (parse (alexandria:read-file-into-string src) language))
74ec9fd3
     (string (displace-tree (cl-tree-sitter:parse-string language src)
                            src))))
 
 (defun collect-nodes-of-type (tree type)
   (serapeum:with-collector (save)
     (serapeum:map-tree
      (lambda (node)
        (typecase node
          (cons (if (and (tag-p (car node)) (= 3 (length node)))
                    (destructuring-bind (_ op . __) (parse-thing node)
                      (declare (ignore _ __))
f504fb4b
                      (if (fwoar.cl-multis.interface:isa? op type)
                          (save node)
                          node))
74ec9fd3
                    node))
          (t node)))
      tree
      :traversal :postorder)))
f504fb4b
 
 (defun child-tagged (tag)
   (lambda (node)
     (values-list
      (remove-if-not (serapeum:op (eql tag _1))
                     (fourth (parse-thing node))
                     :key (data-lens:• 'car
                                       'parse-thing)))))
 
 
 #+(or)
 (defvar *empty-package* (make-package (gensym) :use ()))
 
 #+(or)
 (defvar *ht-pprint-dispatch* (copy-pprint-dispatch *print-pprint-dispatch*))
 
 #+(or)
 (set-pprint-dispatch 'hash-table
                      (lambda (s o)
                        (let ((*package* (make-package *empty-package*)))
                          (prin1 `(alexandria:alist-hash-table
                                   (list
                                    ,@(mapcar (lambda (it)
                                                `(cons ,(car it)
                                                       ,(cdr it)))
                                              (alexandria:hash-table-alist o))))
                                 s)))
                      0 *ht-pprint-dispatch*)
 
 #+(or)
 (set-pprint-dispatch 'vector
                      nil
                      #+(or)
                      (lambda (s o)
                        (let ((*package* *empty-package*))
                          (typecase o
                            (string (let ((*print-pretty* nil))
                                      (prin1 o s)))
                            (t (prin1 `(vector
                                        ,@(map 'list 'identity o))
                                      s)))))
                      0 *ht-pprint-dispatch*)
 
 (defun collect-edits (tree collector)
   (destructuring-bind (tag type source children) (parse-thing tree)
     (multiple-value-bind (_ offs) (array-displacement source)
       (declare (ignore _))
       (let ((end (+ offs (length source))))
         (flet ((tag (start-p)
                  (format nil "<~:[~;/~]span~:*~:[ class=\"~a ~{~a~^ ~}\"~;~]>"
                          start-p
                          (if tag (string-downcase tag) "")
                          (mapcar 'string-downcase
                                  (fwoar.cl-multis.interface:ancestors
                                   type)))))
           (funcall collector (fwoar.lisp-sandbox.ot-edit:insert offs (tag nil)))
           (funcall collector (fwoar.lisp-sandbox.ot-edit:insert end (tag t)))
           (mapcar (lambda (it)
                     (collect-edits it collector))
                   children))))))
 
a8c901ce
 (defun setup-app (app)
   (setf (ningle:route app "/2/(?<url>.*)" :regexp t)
         (lambda (_)
           (let ((*standard-output* *trace-output*))
             (fresh-line)(princ "notice: ")(prin1 _)(terpri))
           (let ((src (drakma:http-request (cadr (assoc :captures _)))))
             (flet ((outp ()
                      (spinneret:with-html
                        (:div #+(or)selector-ui
                              ;; :node-types ("expression" "identifier" "operator" "subscript-expression"
                              ;;                           "member-expression" "jsx" "pair")
                              (:input :type "checkbox" :name "import-statement")
                              (:label :for "import-statement" "import-statement")
                              (:input :type "checkbox" :name "expression")
                              (:label :for "expression" "expression")
                              (:input :type "checkbox" :name "identifier")
                              (:label :for "identifier" "identifier")
                              (:input :type "checkbox" :name "operator")
                              (:label :for "operator" "operator")
                              (:input :type "checkbox" :name "subscript-expression")
                              (:label :for "subscript-expression" "subscript-expression")
                              (:input :type "checkbox" :name "member-expression")
                              (:label :for "member-expression" "member-expression")
                              (:input :type "checkbox" :name "jsx")
                              (:label :for "jsx" "jsx")
                              (:input :type "checkbox" :name "pai")
                              (:label :for "pair" "pair")
                              (:pre
                               (:code :class "language-ts"
                                      (:raw
                                       (fwoar.lisp-sandbox.ot-edit:apply-edits
                                        src
                                        (serapeum:with-collector (s)
                                          (loop for next = (position #\< src)
                                                  then (position #\< src :start (1+ next))
                                                while next
                                                do (s (fwoar.lisp-sandbox.ot-edit::replace-char next "&lt;")))
                                          (loop for next = (position #\> src)
                                                  then (position #\> src :start (1+ next))
                                                while next
                                                do (s (fwoar.lisp-sandbox.ot-edit::replace-char next "&gt;")))
                                          (collect-edits (parse src)
                                                         #'s))))))
                              (:ul#w)
                              (:script
                               (:raw "const ul = document.querySelector(\"#w\");"
                                     "const dps = new Set([]);"
                                     "[].map.call(document.querySelectorAll(\".syntax-element\"),"
                                     " v=> {Array.from(v.classList).forEach(it=>dps.add(it.toLowerCase()))});"
                                     "function it(v) {const it=document.createElement(\"li\"); "
                                     "it.textContent = v; return it}"
                                     " const dpA = Array.from(dps);dpA.sort();"
                                     " dpA.forEach(cls => { if(/^[a-zA-Z-]{2,}$/.test(cls)) {ul.appendChild(it(cls))}})"))))))
               (spinneret:with-html-string
                 (:style
                  "input[name=expression]:checked ~ pre .expression {color: var(--zenburn-red);background-color: hsla(180,0%,0%,0.1)}"
                  "input[name=jsx]:checked ~ pre .jsx {color: var(--zenburn-red);background-color: hsla(180,0%,0%,0.1)}"
                  "input[name=subscript-expression]:checked ~ pre .subscript-expression {color: var(--zenburn-red);background-color: hsla(180,0%,0%,0.1)}"
                  "input[name=member-expression]:checked ~ pre .member-expression {color: var(--zenburn-red);background-color: hsla(180,0%,0%,0.1)}"
                  "input[name=identifier]:checked ~ pre .identifier {color: var(--zenburn-red)}"
                  "input[name=operator]:checked ~ pre .operator {color: var(--zenburn-red)}"
                  "input[name=import-statement]:checked ~ pre .import-statement {color: var(--zenburn-red)}"
                  "input[name=pair]:checked ~ pre .pair .tag-key {color: var(--zenburn-blue)}"
                  "input[name=pair]:checked ~ pre .pair .tag-value {color: var(--zenburn-green)}"
                  "input[name=pair]:checked ~ pre .pair {background: var(--zenburn-fg+1)}"
                  (coerce '(#\newline) 'string)
                  (alexandria:read-file-into-string (truename "~/styles.css"))
                  )
                 (outp)))))))
f504fb4b
 
 
 #+(or)
 (mapcan (data-lens:•
          (lambda (it)
            (destructuring-bind (a c) it
              (mapcar (serapeum:op (list a _)) c)))
          (data-lens:juxt
           (data-lens:• (lambda (it)
                          (substitute #\- #\_ it))
                        (lambda (it)
                          (string-left-trim "_" it)))
           (data-lens:• (data-lens:over (data-lens:• (data-lens:applicable-when
                                                      (data-lens:• (lambda (it)
                                                                     (substitute #\- #\_ it))
                                                                   (lambda (it)
                                                                     (string-left-trim "_" it)))
                                                      'identity)
                                                     (data-lens:key "name")))
                        (lambda (it) (fw.lu:dive (list "rules" it "members") tsx-grammar:+data+)))))
         (gethash "supertypes" tsx))