├── tests ├── breaking.clj ├── test.clj └── mini.clj ├── devnotes ├── debug.org ├── todo.org ├── java.el └── java.wy ├── README.md ├── clojure-ast.el ├── clojure.el ├── clojure.wy └── clojure-wy.el /tests/breaking.clj: -------------------------------------------------------------------------------- 1 | 2 | (defn inc' [x]) 3 | '(hello) 4 | \a 5 | ~@ 6 | @ 7 | ~() 8 | `(stuff) -------------------------------------------------------------------------------- /tests/test.clj: -------------------------------------------------------------------------------- 1 | (defn t3 2 | ([x y z]) 3 | ([x1 y1 z1]) 4 | ) 5 | 6 | (defn t2 [a b c]) -------------------------------------------------------------------------------- /devnotes/debug.org: -------------------------------------------------------------------------------- 1 | M-x semantic-lex-debug 2 | M-x wisent-debug-on-entry 3 | 4 | (setq wisent-debug-flag t) 5 | 6 | Parsing a region with a rule ? 7 | (semantic-parse-region (car $region1) (cdr $region1) (quote fn_content_simple_arity) 1) 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | clojure-semantic 2 | ================ 3 | 4 | Experiments with Emacs semantic.el, CEDET and Clojure. 5 | 6 | If you want to give it a try: 7 | 8 | * Open clojure.wy 9 | * M-x semantic-mode 10 | * C-c C-c 11 | * Open clojure.el 12 | * M-x eval-buffer 13 | 14 | ## What does work (more or less)? 15 | ### Basic variables and functions completion 16 | 17 | Open a clojure file and try: 18 | 19 | * M-x semantic-complete-jump 20 | 21 | ### Speedbar 22 | 23 | Add the following line to your ~/.emacs.d/init.el file: 24 | 25 | (eval-after-load "speedbar" 26 | (lambda () 27 | (speedbar-add-supported-extension ".clj") 28 | (speedbar-add-supported-extension ".cljs"))) 29 | 30 | Open a clojure file and try: 31 | 32 | * M-x speedbar 33 | -------------------------------------------------------------------------------- /clojure-ast.el: -------------------------------------------------------------------------------- 1 | (require 'cl) 2 | 3 | (defun wisent-clojure-find-project-tag 4 | () 5 | "Returns the tag describing the Clojure project. Must be called 6 | within the project.clj buffer." 7 | (do* ((tags (semantic-fetch-tags) (cdr tags)) 8 | (tag (car tags) (car tags))) 9 | ((string= (car tag) "project") 10 | tag))) 11 | 12 | (defun wisent-clojure-find-project-deps 13 | (ptag) 14 | "Returns the list of tags describing the project dependencies vector." 15 | (let ((properties (car (cdaddr ptag)))) 16 | (do* ((tags properties (cdr tags)) 17 | (tag (car tags) (car tags))) 18 | ((and (listp tag) (string= (car tag) ":dependencies")) 19 | (cadr tags))))) 20 | 21 | (defun wisent-clojure-ast-parse 22 | (ast) 23 | "Parse the semantic AST and returns the content of 24 | the Clojure data as an ELisp object." 25 | (let ((type (cadr ast))) 26 | (cond ((eq type 'vector) 27 | (mapcar 'wisent-clojure-ast-parse (cadr (caddr ast)))) 28 | ((eq type 'symbol) 29 | (car ast)) 30 | ((eq type 'string) 31 | (car ast))))) 32 | 33 | (defun wisent-clojure-project-dependencies 34 | () 35 | "Returns a list of lists representing the project dependencies." 36 | (when (string-match "project.clj$" (buffer-file-name)) 37 | (let* ((ptag (wisent-clojure-find-project-tag)) 38 | (depsdef (wisent-clojure-find-project-deps ptag)) 39 | (deps (wisent-clojure-ast-parse depsdef))) 40 | deps))) 41 | -------------------------------------------------------------------------------- /devnotes/todo.org: -------------------------------------------------------------------------------- 1 | allow the user configuration of the keywords for method and variable 2 | definition. This would be usefull if the user defines its own macros 3 | and need to generate tags for them. 4 | 5 | (semantic-get-all-local-variables) ? 6 | 7 | semantic-fetch-tags 8 | 9 | add Lang: 10 | 11 | http://cedet.sourceforge.net/addlang.shtml 12 | 13 | * TODO 14 | 15 | ** extend parse-ast and grammar for list/number 16 | ** improve code: search for filter and assoc/list equivalent 17 | ** replacing expandfull by expand in the first rule 18 | ** collect import for ns 19 | 20 | * context parsing 21 | The Semantic analyzer is a complex engine which has been broken down across several modules. When the Semantic analyzer fails, start with semantic-analyze-debug-assist, then dive into some of these files. 22 | 23 | semantic-ctxt.el 24 | Local context parser. Contains overloadable functions used to move around through different scopes, get 25 | local variables, and collect the current prefix used when doing completion 26 | 27 | semantic-scope.el 28 | Calculate scope for a location in a buffer. The scope includes local variables, and tag lists in scope for various reasons, such as C++ using statements. 29 | 30 | semantic-ia.el 31 | Interactive Analyzer functions. Simple routines that do completion or lookups based on the results from the Analyzer. These routines are meant as examples for application writers, but are quite useful as they are. 32 | 33 | * smart completion 34 | * defrecord and deftype definitions has CLASSES tags 35 | * include tags are missing 36 | 37 | * How to 38 | ** override semantic-ia-insert-tag-default 39 | ** get semantic-analyze-current-context working 40 | ** check semantic-ia-fast-jump working? 41 | ** (define-mode-local-override semantic-get-local-variables python-mode () 42 | "Get the local variables based on point's context. 43 | To be implemented for Python! For now just return nil." 44 | nil) 45 | ** define-mode-local-override semantic-tag-include-filename python-mode (tag) 46 | ** override semantic-sb-tag-children-to-expand ? 47 | -------------------------------------------------------------------------------- /devnotes/java.el: -------------------------------------------------------------------------------- 1 | (require 'semantic/wisent) 2 | (require ;; semantic/wisent/ 3 | 'java-wy) 4 | 5 | (defun wisent-java-default-setup2 () 6 | "Hook run to setup Semantic in `java-mode'." 7 | ;; Use the Wisent LALR(1) parser to analyze Java sources. 8 | (wisent-java-wy--install-parser) 9 | (setq semantic-lex-analyzer 'wisent-clojure2-lexer) 10 | ;; (semantic-make-local-hook 'wisent-pre-parse-hook) 11 | ;; (setq 12 | ;; ;; Lexical analysis 13 | ;; semantic-lex-number-expression semantic-java-number-regexp 14 | ;; semantic-lex-depth nil 15 | ;; semantic-lex-analyzer 'wisent-java-lexer 16 | ;; ;; Parsing 17 | ;; semantic-tag-expand-function 'semantic-java-expand-tag 18 | ;; ;; Environment 19 | ;; semantic-imenu-summary-function 'semantic-format-tag-prototype 20 | ;; semantic-imenu-expandable-tag-classes '(type variable) 21 | ;; imenu-create-index-function 'semantic-create-imenu-index 22 | ;; semantic-type-relation-separator-character '(".") 23 | ;; semantic-command-separation-character ";" 24 | ;; ;; speedbar and imenu buckets name 25 | ;; semantic-symbol->name-assoc-list-for-type-parts 26 | ;; ;; in type parts 27 | ;; '((type . "Classes") 28 | ;; (variable . "Variables") 29 | ;; (function . "Methods")) 30 | ;; semantic-symbol->name-assoc-list 31 | ;; ;; everywhere 32 | ;; (append semantic-symbol->name-assoc-list-for-type-parts 33 | ;; '((include . "Imports") 34 | ;; (package . "Package"))) 35 | ;; ;; navigation inside 'type children 36 | ;; senator-step-at-tag-classes '(function variable) 37 | ;; ;; Remove 'recursive from the default semanticdb find throttle 38 | ;; ;; since java imports never recurse. 39 | ;; semanticdb-find-default-throttle 40 | ;; (remq 'recursive (default-value 'semanticdb-find-default-throttle)) 41 | ;; ) 42 | ;; Setup javadoc stuff 43 | ;; (semantic-java-doc-setup) 44 | ) 45 | 46 | (add-hook 'java-mode-hook 'wisent-java-default-setup2) 47 | ;; (add-hook 'java-mode-hook 'wisent-java-default-setup-exp) 48 | 49 | 50 | ;; Execute that to activate the parser for the clojure-mode 51 | ;; (setq semantic-new-buffer-setup-functions (cons '(clojure-mode . wisent-java-default-setup) semantic-new-buffer-setup-functions)) 52 | -------------------------------------------------------------------------------- /tests/mini.clj: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:doc "The core Clojure language." 10 | :author "Rich Hickey"} 11 | kklojure.core) 12 | 13 | (def unquote2 12) 14 | (def ^{:a o} unquote-splicing2) 15 | 16 | (defn aa [b c] ()) 17 | 18 | (defn ^:private ^:static 19 | kreduce 20 | ([f coll] 21 | (let [s (seq coll)] 22 | (if s 23 | (reduce1 f (first s) (next s)) 24 | (f)))) 25 | ([f val coll] 26 | (let [s (seq coll)] 27 | (if s 28 | (if (chunked-seq? s) 29 | (recur f 30 | (.reduce (chunk-first s) f val) 31 | (chunk-next s)) 32 | (recur f (f val (first s)) (next s))) 33 | val)))) 34 | 35 | (defn ^:string kcheck4 36 | "Detects and rejects non-trivial cyclic load dependencies. The 37 | exception message shows the dependency chain with the cycle 38 | highlighted. Ignores the trivial case of a file attempting to load 39 | itself because that can occur when a gen-class'd class loads its 40 | implementation." 41 | [path] 42 | (when (some #{path} (rest *pending-paths*)) 43 | (let [pending (map #(if (= % path) (str "[ " % " ]") %) 44 | (cons path *pending-paths*)) 45 | chain (apply str (interpose "->" pending))] 46 | (throw (Exception. (str "Cyclic load dependency: " chain)))))) 47 | 48 | (defn- ^:string check2 49 | "Detects and rejects non-trivial cyclic load dependencies. The 50 | exception message shows the dependency chain with the cycle 51 | highlighted. Ignores the trivial case of a file attempting to load 52 | itself because that can occur when a gen-class'd class loads its 53 | implementation." 54 | [path] 55 | (when (some #{path} (rest *pending-paths*)) 56 | (let [pending (map #(if (= % path) (str "[ " % " ]") %) 57 | (cons path *pending-paths*)) 58 | chain (apply str (interpose "->" pending))] 59 | (throw (Exception. (str "Cyclic load dependency: " chain)))))) 60 | 61 | (def ^:dynamic 62 | ^{:doc "bound in a repl thread to the second most recent value printed" 63 | :added "1.0"} 64 | *2) 65 | 66 | 67 | (defn ^:static ^clojure.lang.ChunkBuffer kchunk-buffer ^clojure.lang.ChunkBuffer [capacity] 68 | (clojure.lang.ChunkBuffer. capacity)) 69 | 70 | (defn ^:static kchunk-append [^clojure.lang.ChunkBuffer b x] 71 | (.add b x)) 72 | -------------------------------------------------------------------------------- /clojure.el: -------------------------------------------------------------------------------- 1 | (require 'semantic/wisent) 2 | (require ';; semantic/wisent/ 3 | clojure-wy) 4 | 5 | (defcustom wisent-clojure-user-def-macros nil 6 | "A list of names for the user's own Clojure macros that defines variables." 7 | :type '(repeat string) 8 | :group 'wisent-clojure) 9 | 10 | (defvar wisent-clojure-def-regexp (regexp-opt (append 11 | '("def" "def-" "defonce" "defonce-" 12 | "defstruct-" "defunbound" 13 | "defunbound-" 14 | "defvar" "defvar-" 15 | "defrecord" 16 | "defstruct" "deftype" "defprotocol" 17 | "defalias" "defhinted") 18 | wisent-clojure-user-def-macros))) 19 | 20 | (defcustom wisent-clojure-user-defn-macros nil 21 | "A list of names for the user's own Clojure macros that defines functions." 22 | :type '(repeat string) 23 | :group 'wisent-clojure) 24 | 25 | (defvar wisent-clojure-defn-regexp (regexp-opt (append 26 | '("defn" "defn-" 27 | "defmulti" "defmethod" "defmacro" 28 | "deftest" 29 | "defmacro-" 30 | "defn-memo" "defnk") 31 | wisent-clojure-user-defn-macros))) 32 | 33 | (define-lex-simple-regex-analyzer wisent-clojure-lex-deffunc 34 | "Detect functions and macros." 35 | wisent-clojure-defn-regexp 'DEFN) 36 | 37 | (define-lex-simple-regex-analyzer wisent-clojure-lex-defvar 38 | "Detect variables." 39 | wisent-clojure-def-regexp 'DEF) 40 | 41 | (define-lex-simple-regex-analyzer wisent-clojure-lex-defproject 42 | "Detect projects definition." 43 | "defproject" 'DEFPROJECT) 44 | 45 | (define-lex-regex-analyzer wisent-clojure-lex-reader 46 | "Detect reader macros or metadata symbol." 47 | "\\(#[^ ]\\|\\^\\|`\\|'\\|~@\\|~\\|\\\\.\\|@\\)" 48 | (let* ((matched (match-string-no-properties 0)) 49 | (token-type (cond ((string= matched "^") 'METADATA) 50 | ((string= matched "`") 'BACKQUOTE) 51 | ((string= matched "'") 'QUOTE) 52 | ((string= (substring matched 0 1) "\\") 'CHARACTER) 53 | ((string= matched "~") 'UNQUOTE) 54 | ((string= matched "~@") 'UNQUOTE_SPLICING) 55 | ((string= matched "@") 'DEREF) 56 | ((string= matched "#^") 'META_READER) 57 | ((string= matched "#'") 'VAR_READER) 58 | ((string= matched "#{") 'SET_READER) 59 | ((string= matched "#(") 'FN_READER) 60 | ((string= matched "#=") 'EVAL_READER) 61 | ((string= matched "#!") 'COMMENT_READER) 62 | ((string= matched "#<") 'UNREADABLE_READER) 63 | ((string= matched "#_") 'DISCARD_READER) 64 | (t 'UNKNOWN_READER)))) 65 | (semantic-lex-push-token 66 | (semantic-lex-token 67 | token-type 68 | (match-beginning 0) (match-end 0))))) 69 | 70 | (define-lex-regex-analyzer wisent-clojure-lex-clj-symbol 71 | "Detect Clojure symbols." 72 | "\\([^][(){}\"\n\t ]+\\)" 73 | (let* ((matched (match-string-no-properties 0)) 74 | (token-type (cond ((string= matched "ns") 'NS) 75 | (t 'SYMBOL)))) 76 | (semantic-lex-push-token 77 | (semantic-lex-token 78 | token-type 79 | (match-beginning 0) (match-end 0))))) 80 | 81 | ;; Define the lexer for this grammar 82 | (define-lex wisent-clojure-lexer 83 | "Lexical analyzer that handles Clojure buffers. 84 | It ignores whitespaces, newlines and comments." 85 | semantic-lex-ignore-whitespace 86 | semantic-lex-ignore-newline 87 | semantic-lex-ignore-comments 88 | ;;; our own lexers: 89 | wisent-clojure-lex-reader 90 | wisent-clojure-lex-defproject 91 | wisent-clojure-lex-deffunc 92 | wisent-clojure-lex-defvar 93 | wisent-clojure-lex-clj-symbol 94 | ;;;; Auto-generated analyzers. 95 | wisent-clojure-wy---regexp-analyzer 96 | wisent-clojure-wy---sexp-analyzer 97 | wisent-clojure-wy---block-analyzer 98 | semantic-lex-default-action) 99 | 100 | (defun wisent-clojure-default-setup () 101 | "Hook run to setup Semantic in `clojure-mode'." 102 | (wisent-clojure-wy--install-parser) 103 | (setq 104 | ;; Lexical analysis 105 | ;; semantic-lex-depth nil 106 | semantic-lex-analyzer 'wisent-clojure-lexer)) 107 | 108 | (add-to-list 'semantic-new-buffer-setup-functions 109 | (cons 'clojure-mode 'wisent-clojure-default-setup)) 110 | 111 | -------------------------------------------------------------------------------- /clojure.wy: -------------------------------------------------------------------------------- 1 | ;;; semantic/wisent/clojure.wy -- LALR grammar for Clojure 2 | ;; 3 | ;; Copyright (C) 4 | ;; 5 | ;; Author: K 6 | ;; Maintainer: 7 | ;; Created: 8 | ;; Keywords: syntax 9 | ;; 10 | ;; This file is not part of GNU Emacs. 11 | ;; 12 | ;; This program is free software; you can redistribute it and/or 13 | ;; modify it under the terms of the GNU General Public License as 14 | ;; published by the Free Software Foundation; either version 2, or (at 15 | ;; your option) any later version. 16 | ;; 17 | ;; This software is distributed in the hope that it will be useful, 18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | ;; General Public License for more details. 21 | ;; 22 | ;; You should have received a copy of the GNU General Public License 23 | ;; along with GNU Emacs; see the file COPYING. If not, write to the 24 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 25 | ;; Boston, MA 02110-1301, USA. 26 | 27 | %package wisent-clojure-wy 28 | %provide clojure-wy 29 | 30 | %languagemode clojure-mode 31 | 32 | ;; The default goal. 33 | %start sexpr 34 | %start list_content_opt 35 | %start argument 36 | %start fn_content_simple_arity 37 | %start sexpr_full 38 | 39 | ;; ----------------------------- 40 | ;; Block & Parenthesis terminals 41 | ;; ----------------------------- 42 | %type ;;syntax "\\s(\\|\\s)" matchdatatype block 43 | 44 | %token PAREN_BLOCK "(LPAREN RPAREN)" 45 | %token BRACE_BLOCK "(LBRACE RBRACE)" 46 | %token BRACK_BLOCK "(LBRACK RBRACK)" 47 | 48 | %token LPAREN "(" 49 | %token RPAREN ")" 50 | %token LBRACE "{" 51 | %token RBRACE "}" 52 | %token LBRACK "[" 53 | %token RBRACK "]" 54 | 55 | %type ;;syntax "\\s\"" matchdatatype sexp 56 | %token STRING_LITERAL 57 | 58 | %type ;;syntax semantic-lex-number-expression 59 | %token NUMBER_LITERAL 60 | 61 | ;; Token generated by external lexers 62 | %token DEFN 63 | %token DEF 64 | %token DEFPROJECT 65 | %token SYMBOL 66 | %token NS 67 | 68 | %token METADATA 69 | 70 | ;; reader macros 71 | %token META_READER 72 | %token VAR_READER 73 | %token SET_READER 74 | %token FN_READER 75 | %token EVAL_READER 76 | %token COMMENT_READER 77 | %token UNREADABLE_READER 78 | %token DISCARD_READER 79 | %token UNREADABLE_READER 80 | 81 | %% 82 | 83 | sexpr: PAREN_BLOCK 84 | (EXPANDFULL $1 list_content_opt) 85 | | SYMBOL 86 | ;; | NUMBER_LITERAL 87 | ;; | STRING_LITERAL 88 | ; 89 | 90 | list_content_opt: ;; empty 91 | | list_content 92 | ; 93 | 94 | list_content: DEF metadata_defs_opt SYMBOL list_content_opt 95 | (VARIABLE-TAG $3 nil nil) 96 | | DEFN metadata_defs_opt SYMBOL doc_string_opt metadata_defs_opt fn_content_def 97 | (FUNCTION-TAG $3 nil (car $6) :arity (cadr $6)) 98 | | NS metadata_defs_opt SYMBOL 99 | (PACKAGE-TAG $3 nil) 100 | | DEFPROJECT SYMBOL STRING_LITERAL collection_content_full 101 | (TAG "project" 'project :name $2 :version $3 :properties $4) 102 | ; 103 | 104 | sexpr_full: SYMBOL 105 | (TAG $1 'symbol) 106 | | NUMBER_LITERAL 107 | (list 'number $1) 108 | | STRING_LITERAL 109 | (TAG (car (read-from-string $1)) 'string) 110 | | PAREN_BLOCK 111 | (TAG (symbol-name (gensym "list")) 'list :content (EXPANDFULL $1 sexpr_full)) 112 | | BRACE_BLOCK 113 | (TAG (symbol-name (gensym "set")) 'set :content (EXPANDFULL $1 sexpr_full)) 114 | | BRACK_BLOCK 115 | (TAG (symbol-name (gensym "vector")) 'vector :content (EXPANDFULL $1 sexpr_full)) 116 | ; 117 | 118 | collection_content_full: sexpr_full 119 | (list $1) 120 | | sexpr_full collection_content_full 121 | (cons $1 $2) 122 | ; 123 | 124 | doc_string_opt: ;; empty 125 | | STRING_LITERAL 126 | ; 127 | 128 | metadata_defs_opt: ;; empty 129 | | metadata_defs 130 | ; 131 | 132 | metadata_defs: metadata_def 133 | | metadata_defs metadata_def 134 | ; 135 | 136 | metadata_def: BRACE_BLOCK 137 | | METADATA BRACE_BLOCK 138 | | METADATA SYMBOL 139 | (list $2) 140 | ; 141 | 142 | fn_content_simple_arity: BRACK_BLOCK 143 | (EXPANDFULL $1 argument) 144 | ; 145 | 146 | fn_content_multi_arity: PAREN_BLOCK 147 | ;; for some reasons we get the arguments in the wrong order here 148 | (list (EXPANDFULL $1 fn_content_simple_arity)) 149 | | PAREN_BLOCK fn_content_multi_arity 150 | (append 151 | (list (EXPANDFULL $1 fn_content_simple_arity) 152 | (list $2))) 153 | ; 154 | 155 | fn_content_def: fn_content_simple_arity 156 | (list $1 nil) 157 | | fn_content_multi_arity 158 | (list (car $1) $1) 159 | ; 160 | 161 | argument: SYMBOL 162 | (VARIABLE-TAG $1 nil nil) 163 | | metadata_def SYMBOL 164 | (VARIABLE-TAG $2 (car $1) nil) 165 | ; 166 | 167 | %% 168 | 169 | 170 | ;;; semantic/wisent/clojure.wy ends here 171 | -------------------------------------------------------------------------------- /clojure-wy.el: -------------------------------------------------------------------------------- 1 | ;;; clojure-wy.el --- Generated parser support file 2 | 3 | ;; Copyright (C) 4 | 5 | ;; Author: Pierre Allix 6 | ;; Created: 2013-03-22 13:33:00+0100 7 | ;; Keywords: syntax 8 | ;; X-RCS: $Id$ 9 | 10 | ;; This file is not part of GNU Emacs. 11 | 12 | ;; This program is free software; you can redistribute it and/or 13 | ;; modify it under the terms of the GNU General Public License as 14 | ;; published by the Free Software Foundation, either version 3 of 15 | ;; the License, or (at your option) any later version. 16 | 17 | ;; This software is distributed in the hope that it will be useful, 18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | ;; General Public License for more details. 21 | ;; 22 | ;; You should have received a copy of the GNU General Public License 23 | ;; along with this program. If not, see . 24 | 25 | ;;; Commentary: 26 | ;; 27 | ;; PLEASE DO NOT MANUALLY EDIT THIS FILE! It is automatically 28 | ;; generated from the grammar file clojure.wy. 29 | 30 | ;;; History: 31 | ;; 32 | 33 | ;;; Code: 34 | 35 | (eval-when-compile (require 'semantic/bovine)) 36 | 37 | ;;; Prologue 38 | ;; 39 | 40 | ;;; Declarations 41 | ;; 42 | (defconst wisent-clojure-wy--keyword-table 43 | (semantic-lex-make-keyword-table 'nil 'nil) 44 | "Table of language keywords.") 45 | 46 | (defconst wisent-clojure-wy--token-table 47 | (semantic-lex-make-type-table 48 | '(("" 49 | (UNREADABLE_READER) 50 | (DISCARD_READER) 51 | (UNREADABLE_READER) 52 | (COMMENT_READER) 53 | (EVAL_READER) 54 | (FN_READER) 55 | (SET_READER) 56 | (VAR_READER) 57 | (META_READER) 58 | (METADATA) 59 | (NS) 60 | (SYMBOL) 61 | (DEFPROJECT) 62 | (DEF) 63 | (DEFN)) 64 | ("number" 65 | (NUMBER_LITERAL)) 66 | ("string" 67 | (STRING_LITERAL)) 68 | ("close-paren" 69 | (RBRACK . "]") 70 | (RBRACE . "}") 71 | (RPAREN . ")")) 72 | ("open-paren" 73 | (LBRACK . "[") 74 | (LBRACE . "{") 75 | (LPAREN . "(")) 76 | ("block" 77 | (BRACK_BLOCK . "(LBRACK RBRACK)") 78 | (BRACE_BLOCK . "(LBRACE RBRACE)") 79 | (PAREN_BLOCK . "(LPAREN RPAREN)"))) 80 | '(("number" :declared t) 81 | ("string" :declared t) 82 | ("block" :declared t))) 83 | "Table of lexical tokens.") 84 | 85 | (defconst wisent-clojure-wy--parse-table 86 | (progn 87 | (eval-when-compile 88 | (require 'semantic/wisent/comp)) 89 | (wisent-compile-grammar 90 | '((PAREN_BLOCK BRACE_BLOCK BRACK_BLOCK LPAREN RPAREN LBRACE RBRACE LBRACK RBRACK STRING_LITERAL NUMBER_LITERAL DEFN DEF DEFPROJECT SYMBOL NS METADATA META_READER VAR_READER SET_READER FN_READER EVAL_READER COMMENT_READER UNREADABLE_READER DISCARD_READER) 91 | nil 92 | (sexpr 93 | ((PAREN_BLOCK) 94 | (semantic-parse-region 95 | (car $region1) 96 | (cdr $region1) 97 | 'list_content_opt 1)) 98 | ((SYMBOL))) 99 | (list_content_opt 100 | (nil) 101 | ((list_content))) 102 | (list_content 103 | ((DEF metadata_defs_opt SYMBOL list_content_opt) 104 | (wisent-raw-tag 105 | (semantic-tag-new-variable $3 nil nil))) 106 | ((DEFN metadata_defs_opt SYMBOL doc_string_opt metadata_defs_opt fn_content_def) 107 | (wisent-raw-tag 108 | (semantic-tag-new-function $3 nil 109 | (car $6) 110 | :arity 111 | (cadr $6)))) 112 | ((NS metadata_defs_opt SYMBOL) 113 | (wisent-raw-tag 114 | (semantic-tag-new-package $3 nil))) 115 | ((DEFPROJECT SYMBOL STRING_LITERAL collection_content_full) 116 | (wisent-raw-tag 117 | (semantic-tag "project" 'project :name $2 :version $3 :properties $4)))) 118 | (sexpr_full 119 | ((SYMBOL) 120 | (wisent-raw-tag 121 | (semantic-tag $1 'symbol))) 122 | ((NUMBER_LITERAL) 123 | (list 'number $1)) 124 | ((STRING_LITERAL) 125 | (wisent-raw-tag 126 | (semantic-tag 127 | (car 128 | (read-from-string $1)) 129 | 'string))) 130 | ((PAREN_BLOCK) 131 | (wisent-raw-tag 132 | (semantic-tag 133 | (symbol-name 134 | (gensym "list")) 135 | 'list :content 136 | (semantic-parse-region 137 | (car $region1) 138 | (cdr $region1) 139 | 'sexpr_full 1)))) 140 | ((BRACE_BLOCK) 141 | (wisent-raw-tag 142 | (semantic-tag 143 | (symbol-name 144 | (gensym "set")) 145 | 'set :content 146 | (semantic-parse-region 147 | (car $region1) 148 | (cdr $region1) 149 | 'sexpr_full 1)))) 150 | ((BRACK_BLOCK) 151 | (wisent-raw-tag 152 | (semantic-tag 153 | (symbol-name 154 | (gensym "vector")) 155 | 'vector :content 156 | (semantic-parse-region 157 | (car $region1) 158 | (cdr $region1) 159 | 'sexpr_full 1))))) 160 | (collection_content_full 161 | ((sexpr_full) 162 | (list $1)) 163 | ((sexpr_full collection_content_full) 164 | (cons $1 $2))) 165 | (doc_string_opt 166 | (nil) 167 | ((STRING_LITERAL))) 168 | (metadata_defs_opt 169 | (nil) 170 | ((metadata_defs))) 171 | (metadata_defs 172 | ((metadata_def)) 173 | ((metadata_defs metadata_def))) 174 | (metadata_def 175 | ((BRACE_BLOCK)) 176 | ((METADATA BRACE_BLOCK)) 177 | ((METADATA SYMBOL) 178 | (list $2))) 179 | (fn_content_simple_arity 180 | ((BRACK_BLOCK) 181 | (semantic-parse-region 182 | (car $region1) 183 | (cdr $region1) 184 | 'argument 1))) 185 | (fn_content_multi_arity 186 | ((PAREN_BLOCK) 187 | (list 188 | (semantic-parse-region 189 | (car $region1) 190 | (cdr $region1) 191 | 'fn_content_simple_arity 1))) 192 | ((PAREN_BLOCK fn_content_multi_arity) 193 | (append 194 | (list 195 | (semantic-parse-region 196 | (car $region1) 197 | (cdr $region1) 198 | 'fn_content_simple_arity 1) 199 | (list $2))))) 200 | (fn_content_def 201 | ((fn_content_simple_arity) 202 | (list $1 nil)) 203 | ((fn_content_multi_arity) 204 | (list 205 | (car $1) 206 | $1))) 207 | (argument 208 | ((SYMBOL) 209 | (wisent-raw-tag 210 | (semantic-tag-new-variable $1 nil nil))) 211 | ((metadata_def SYMBOL) 212 | (wisent-raw-tag 213 | (semantic-tag-new-variable $2 214 | (car $1) 215 | nil))))) 216 | '(sexpr list_content_opt argument fn_content_simple_arity sexpr_full))) 217 | "Parser table.") 218 | 219 | (defun wisent-clojure-wy--install-parser () 220 | "Setup the Semantic Parser." 221 | (semantic-install-function-overrides 222 | '((parse-stream . wisent-parse-stream))) 223 | (setq semantic-parser-name "LALR" 224 | semantic--parse-table wisent-clojure-wy--parse-table 225 | semantic-debug-parser-source "clojure.wy" 226 | semantic-flex-keywords-obarray wisent-clojure-wy--keyword-table 227 | semantic-lex-types-obarray wisent-clojure-wy--token-table) 228 | ;; Collect unmatched syntax lexical tokens 229 | (semantic-make-local-hook 'wisent-discarding-token-functions) 230 | (add-hook 'wisent-discarding-token-functions 231 | 'wisent-collect-unmatched-syntax nil t)) 232 | 233 | 234 | ;;; Analyzers 235 | ;; 236 | (require 'semantic/lex) 237 | 238 | (define-lex-block-type-analyzer wisent-clojure-wy---block-analyzer 239 | "block analyzer for tokens." 240 | "\\s(\\|\\s)" 241 | '((("(" LPAREN PAREN_BLOCK) 242 | ("{" LBRACE BRACE_BLOCK) 243 | ("[" LBRACK BRACK_BLOCK)) 244 | (")" RPAREN) 245 | ("}" RBRACE) 246 | ("]" RBRACK)) 247 | ) 248 | 249 | (define-lex-regex-type-analyzer wisent-clojure-wy---regexp-analyzer 250 | "regexp analyzer for tokens." 251 | semantic-lex-number-expression 252 | nil 253 | 'NUMBER_LITERAL) 254 | 255 | (define-lex-sexp-type-analyzer wisent-clojure-wy---sexp-analyzer 256 | "sexp analyzer for tokens." 257 | "\\s\"" 258 | 'STRING_LITERAL) 259 | 260 | 261 | ;;; Epilogue 262 | ;; 263 | 264 | 265 | 266 | 267 | 268 | (provide 'clojure-wy) 269 | 270 | ;; We cannot require the corresponding Lisp implementation, since 271 | ;; this would lead to a recursion. Thus we blindly assume that 272 | ;; everything's available there. 273 | 274 | ;; Local variables: 275 | ;; byte-compile-warnings: (not unresolved) 276 | ;; End: 277 | 278 | ;;; clojure-wy.el ends here 279 | -------------------------------------------------------------------------------- /devnotes/java.wy: -------------------------------------------------------------------------------- 1 | ;;; semantic/wisent/java.wy -- LALR grammar for Java 2 | ;; 3 | ;; Copyright (C) 2002, 2003, 2004, 2005, 2006 David Ponce 4 | ;; 5 | ;; Author: David Ponce 6 | ;; Maintainer: David Ponce 7 | ;; Created: 19 Feb 2002 8 | ;; Keywords: syntax 9 | ;; 10 | ;; This file is not part of GNU Emacs. 11 | ;; 12 | ;; This program is free software; you can redistribute it and/or 13 | ;; modify it under the terms of the GNU General Public License as 14 | ;; published by the Free Software Foundation; either version 2, or (at 15 | ;; your option) any later version. 16 | ;; 17 | ;; This software is distributed in the hope that it will be useful, 18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | ;; General Public License for more details. 21 | ;; 22 | ;; You should have received a copy of the GNU General Public License 23 | ;; along with GNU Emacs; see the file COPYING. If not, write to the 24 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 25 | ;; Boston, MA 02110-1301, USA. 26 | ;; 27 | ;;; Commentary: 28 | ;; 29 | ;; This grammar fully parses correct Java 1.5 syntax. 30 | ;; 31 | ;; It is based on the GPLed CUP Grammar for Java version 1.5, plus: 32 | ;; 33 | ;; - JSR-175 "Program Annotation Facility" productions. 34 | ;; - Additional rules to extract tags needed by Semantic. 35 | ;; - Error recovery rules to work as safely as possible in an 36 | ;; interactive environment. 37 | ;; 38 | ;; The CUP parser home page is at 39 | ;; . 40 | ;; 41 | ;; TODO: 42 | ;; - Finalize production of tags from inside `block_statements'. 43 | ;; - Finalize production of `:template-specifier' attribute according 44 | ;; to what is done in the C grammar. 45 | ;; - Finalize production of tags from annotations? 46 | ;; - Review error recovery rules. 47 | ;; 48 | 49 | %{ 50 | ;; Stack of enum names in scope. 51 | (defvar wisent-java-wy--enums nil) 52 | ;; Stack of anonymous class declarations found in an expression. 53 | (defvar wisent-java-wy--anons nil) 54 | } 55 | 56 | %package wisent-java-wy 57 | %provide java-wy 58 | 59 | %languagemode java-mode 60 | 61 | ;; The default goal. 62 | %start goal 63 | ;; Alternate goals needed for re-parse. 64 | %start package_declaration 65 | %start import_declaration 66 | %start class_declaration 67 | %start enum_declaration 68 | %start enum_constant 69 | %start field_declaration 70 | %start method_declaration 71 | %start formal_parameter 72 | %start constructor_declaration 73 | %start interface_declaration 74 | %start abstract_method_declaration 75 | ;; Re-parse inside blocks (not yet finished). 76 | %start block_statements 77 | %start local_variable_declaration 78 | ;; Goal used for `semantic-get-local-variables'. 79 | %start block_statement 80 | 81 | ;; ----------------------------- 82 | ;; Block & Parenthesis terminals 83 | ;; ----------------------------- 84 | %type ;;syntax "\\s(\\|\\s)" matchdatatype block 85 | 86 | %token PAREN_BLOCK "(LPAREN RPAREN)" 87 | %token BRACE_BLOCK "(LBRACE RBRACE)" 88 | %token BRACK_BLOCK "(LBRACK RBRACK)" 89 | 90 | %token LPAREN "(" 91 | %token RPAREN ")" 92 | %token LBRACE "{" 93 | %token RBRACE "}" 94 | %token LBRACK "[" 95 | %token RBRACK "]" 96 | 97 | ;; ------------------ 98 | ;; Operator terminals 99 | ;; ------------------ 100 | %type ;;syntax "\\(\\s.\\|\\s$\\|\\s'\\)+" matchdatatype string 101 | 102 | %token NOT "!" 103 | %token NOTEQ "!=" 104 | %token MOD "%" 105 | %token MODEQ "%=" 106 | %token AND "&" 107 | %token ANDAND "&&" 108 | %token ANDEQ "&=" 109 | %token MULT "*" 110 | %token MULTEQ "*=" 111 | %token PLUS "+" 112 | %token PLUSPLUS "++" 113 | %token PLUSEQ "+=" 114 | %token COMMA "," 115 | %token MINUS "-" 116 | %token MINUSMINUS "--" 117 | %token MINUSEQ "-=" 118 | %token DOT "." 119 | %token DIV "/" 120 | %token DIVEQ "/=" 121 | %token COLON ":" 122 | %token SEMICOLON ";" 123 | %token LT "<" 124 | %token LSHIFT "<<" 125 | %token LSHIFTEQ "<<=" 126 | %token LTEQ "<=" 127 | %token EQ "=" 128 | %token EQEQ "==" 129 | %token GT ">" 130 | %token GTEQ ">=" 131 | %token RSHIFT ">>" 132 | %token RSHIFTEQ ">>=" 133 | %token URSHIFT ">>>" 134 | %token URSHIFTEQ ">>>=" 135 | %token QUESTION "?" 136 | %token XOR "^" 137 | %token XOREQ "^=" 138 | %token OR "|" 139 | %token OREQ "|=" 140 | %token OROR "||" 141 | %token COMP "~" 142 | %token ELLIPSIS "..." 143 | %token AT "@" 144 | 145 | ;; ----------------- 146 | ;; Literal terminals 147 | ;; ----------------- 148 | %type ;;syntax "\\(\\sw\\|\\s_\\)+" 149 | %token NULL_LITERAL "\\`null\\'" 150 | %token BOOLEAN_LITERAL "\\`false\\'" 151 | %token BOOLEAN_LITERAL "\\`true\\'" 152 | %token IDENTIFIER 153 | 154 | %type ;;syntax "\\s\"" matchdatatype sexp 155 | %token STRING_LITERAL 156 | 157 | %type ;;syntax semantic-lex-number-expression 158 | %token NUMBER_LITERAL 159 | 160 | ;; ----------------- 161 | ;; Keyword terminals 162 | ;; ----------------- 163 | ;; Generate a keyword analyzer 164 | %type ;;syntax "\\(\\sw\\|\\s_\\)+" matchdatatype keyword 165 | 166 | %keyword ABSTRACT "abstract" 167 | %put ABSTRACT summary 168 | "Class|Method declaration modifier: abstract {class|} ..." 169 | 170 | %keyword ASSERT "assert" 171 | %put ASSERT summary 172 | "Assertion statement: assert [, ...];" 173 | 174 | %keyword BOOLEAN "boolean" 175 | %put BOOLEAN summary 176 | "Primitive logical quantity type (true or false)" 177 | 178 | %keyword BREAK "break" 179 | %put BREAK summary 180 | "break [