Mercurial > core / lisp/ffi/tree-sitter/api.lisp
changeset 698: |
96958d3eb5b0 |
parent: |
48e671eac752
|
author: |
Richard Westhaver <ellis@rwest.io> |
date: |
Fri, 04 Oct 2024 22:04:59 -0400 |
permissions: |
-rw-r--r-- |
description: |
fixes |
1 ;;; ffi/tree-sitter/api.lisp --- High-level API for Tree-sitter library 3 ;; High-level Tree-sitter API 6 (in-package :tree-sitter) 8 (defstruct (node (:type list)) 11 (defun make-lisp-name (string) 12 (intern (string-upcase (substitute #\- #\_ string)) 13 (load-time-value (find-package "KEYWORD")))) 15 (define-condition tree-sitter-error (error) 18 (define-condition create-parser-error (tree-sitter-error) 21 (define-condition set-language-error (tree-sitter-error) 22 ((language :initarg :language :reader tree-sitter-error-language))) 24 (define-condition parse-string-error (tree-sitter-error) 25 ((string :initarg :string :reader tree-sitter-error-string) 26 (string-start :initarg :string-start :reader tree-sitter-error-string-start) 27 (string-end :initarg :string-end :reader tree-sitter-error-string-end) 28 (language :initarg :language :reader tree-sitter-error-language))) 30 (define-condition null-node-pointer (tree-sitter-error) 33 (define-condition null-tree-cursor-pointer (tree-sitter-error) 37 (defmacro with-ts-node ((var node) &body forms) 39 (when (sb-alien:null-alien ,var) 40 (error 'null-node-pointer)) 43 (sb-alien:free-alien ,var)))) 45 (defmacro with-tree-cursor ((var tree) &body forms &aux (node (gensym))) 46 `(with-ts-node (,node (ts-tree-root-node-pointer ,tree)) 47 (let ((,var (ts-tree-cursor-new-pointer ,node))) 48 (when (sb-alien:null-alien ,var) 49 (error 'null-tree-cursor-pointer)) 52 (ts-tree-cursor-delete ,var))))) 54 (defun parse-string (language string &key (start 0) end produce-cst (name-generator #'make-lisp-name)) 55 "Parse a STRING that represents LANGUAGE code using tree-sitter. START is 56 where to start parsing STRING. END is where to stop parsing STRING. 57 When PRODUCE-CST is set, the full concrete syntax tree will be produced as 58 opposed to the abstract syntax tree. See 'Named vs Anonymous Nodes': 59 http://tree-sitter.github.io/tree-sitter/using-parsers#named-vs-anonymous-nodes 60 NAME-GENERATOR is a function which converts a string from tree-sitter into a 61 desired name for use in lisp." 62 (let ((parser (ts-parser-new))) 63 (when (sb-alien:null-alien parser) 64 (error 'cant-create-parser)) 65 (unwind-protect (parse-string-with-language language string parser 68 :produce-cst produce-cst 69 :name-generator name-generator) 70 (ts-parser-delete parser)))) 72 (defun parse-string-with-language (language string parser 73 &key (start 0) end produce-cst name-generator) 74 (unless (ts-parser-set-language parser (language-module language)) 75 (error 'cant-set-language :language language)) 76 (let* ((string-start start) 77 (string-end (or end (length string))) 78 ;; TODO: this might need to be +1 if it's actually a c-string for null 79 (string-length (- string-end string-start)) 80 (string-to-pass (if (plusp string-start) 81 (subseq string string-start string-end) 83 (tree (ts-parser-parse-string parser string string-to-pass string-length))) 84 (when (sb-alien:null-alien tree) 85 (error 'cant-parse-string 90 (unwind-protect (convert-foreign-tree-to-list tree :produce-cst produce-cst 91 :name-generator name-generator) 92 (ts-tree-delete tree)))) 94 (defun convert-foreign-tree-to-list (tree &key produce-cst name-generator 95 &aux did-visit-children parse-stack) 96 (with-tree-cursor (cursor tree) 97 ;; Closely follows tree-sitter-cli parse 98 ;; implementation with a modification to 99 ;; allow for production of the full CST. 101 (with-ts-node (node (ts-tree-cursor-current-node-pointer cursor)) 102 (let ((is-named (or produce-cst (ts-node-is-named-pointer node)))) 103 (cond (did-visit-children 104 (when (and is-named (second parse-stack)) 105 (let ((item (pop parse-stack))) 106 (setf (node-children item) 107 (nreverse (node-children item))) 108 (push item (node-children (first parse-stack))))) 109 (cond ((ts-tree-cursor-goto-next-sibling cursor) 110 (setf did-visit-children nil)) 111 ((ts-tree-cursor-goto-parent cursor) 112 (setf did-visit-children t)) 114 (let ((root (first parse-stack))) 115 (setf (node-children root) 116 (nreverse (node-children root))) 120 (let ((start-point (ts-node-start-point-pointer node)) 121 (end-point (ts-node-end-point-pointer node)) 122 (type (funcall name-generator (ts-node-type-pointer node))) 123 (field-name-ptr (ts-tree-cursor-current-field-name cursor))) 124 (unless (sb-alien:null-alien field-name-ptr) 126 (let ((field-name (deref field-name-ptr))) 127 (setf type (list (funcall name-generator field-name) type)))) 128 (push (make-node :type type :range (list start-point end-point)) 130 (setf did-visit-children 131 (not (ts-tree-cursor-goto-first-child cursor))))))))))