python.el 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. ;;; wisent-python.el --- Semantic support for Python
  2. ;; Copyright (C) 2002, 2004, 2006-2012 Free Software Foundation, Inc.
  3. ;; Author: Richard Kim <emacs18@gmail.com>
  4. ;; Maintainer: Richard Kim <emacs18@gmail.com>
  5. ;; Created: June 2002
  6. ;; Keywords: syntax
  7. ;; This file is part of GNU Emacs.
  8. ;; GNU Emacs is free software: you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; GNU Emacs is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;;
  20. ;; Parser support for Python.
  21. ;;; Code:
  22. (require 'semantic/wisent)
  23. (require 'semantic/wisent/python-wy)
  24. (require 'semantic/dep)
  25. (require 'semantic/ctxt)
  26. ;;; Lexical analysis
  27. ;;
  28. ;; Python strings are delimited by either single quotes or double
  29. ;; quotes, e.g., "I'm a string" and 'I too am s string'.
  30. ;; In addition a string can have either a 'r' and/or 'u' prefix.
  31. ;; The 'r' prefix means raw, i.e., normal backslash substitutions are
  32. ;; to be suppressed. For example, r"01\n34" is a string with six
  33. ;; characters 0, 1, \, n, 3 and 4. The 'u' prefix means the following
  34. ;; string is Unicode.
  35. (defconst wisent-python-string-re
  36. (concat (regexp-opt '("r" "u" "ur" "R" "U" "UR" "Ur" "uR") t)
  37. "?['\"]")
  38. "Regexp matching beginning of a Python string.")
  39. (defvar wisent-python-EXPANDING-block nil
  40. "Non-nil when expanding a paren block for Python lexical analyzer.")
  41. (defun wisent-python-implicit-line-joining-p ()
  42. "Return non-nil if implicit line joining is active.
  43. That is, if inside an expression in parentheses, square brackets or
  44. curly braces."
  45. wisent-python-EXPANDING-block)
  46. (defsubst wisent-python-forward-string ()
  47. "Move point at the end of the Python string at point."
  48. (when (looking-at wisent-python-string-re)
  49. ;; skip the prefix
  50. (and (match-end 1) (goto-char (match-end 1)))
  51. ;; skip the quoted part
  52. (cond
  53. ((looking-at "\"\"\"[^\"]")
  54. (search-forward "\"\"\"" nil nil 2))
  55. ((looking-at "'''[^']")
  56. (search-forward "'''" nil nil 2))
  57. ((forward-sexp 1)))))
  58. (defun wisent-python-forward-line ()
  59. "Move point to the beginning of the next logical line.
  60. Usually this is simply the next physical line unless strings,
  61. implicit/explicit line continuation, blank lines, or comment lines are
  62. encountered. This function skips over such items so that the point is
  63. at the beginning of the next logical line. If the current logical
  64. line ends at the end of the buffer, leave the point there."
  65. (while (not (eolp))
  66. (when (= (point)
  67. (progn
  68. (cond
  69. ;; Skip over python strings.
  70. ((looking-at wisent-python-string-re)
  71. (wisent-python-forward-string))
  72. ;; At a comment start just goto end of line.
  73. ((looking-at "\\s<")
  74. (end-of-line))
  75. ;; Skip over generic lists and strings.
  76. ((looking-at "\\(\\s(\\|\\s\"\\)")
  77. (forward-sexp 1))
  78. ;; At the explicit line continuation character
  79. ;; (backslash) move to next line.
  80. ((looking-at "\\s\\")
  81. (forward-line 1))
  82. ;; Skip over white space, word, symbol, punctuation,
  83. ;; and paired delimiter (backquote) characters.
  84. ((skip-syntax-forward "-w_.$)")))
  85. (point)))
  86. (error "python-forward-line endless loop detected")))
  87. ;; The point is at eol, skip blank and comment lines.
  88. (forward-comment (point-max))
  89. ;; Goto the beginning of the next line.
  90. (or (eobp) (beginning-of-line)))
  91. (defun wisent-python-forward-line-skip-indented ()
  92. "Move point to the next logical line, skipping indented lines.
  93. That is the next line whose indentation is less than or equal to the
  94. indentation of the current line."
  95. (let ((indent (current-indentation)))
  96. (while (progn (wisent-python-forward-line)
  97. (and (not (eobp))
  98. (> (current-indentation) indent))))))
  99. (defun wisent-python-end-of-block ()
  100. "Move point to the end of the current block."
  101. (let ((indent (current-indentation)))
  102. (while (and (not (eobp)) (>= (current-indentation) indent))
  103. (wisent-python-forward-line-skip-indented))
  104. ;; Don't include final comments in current block bounds
  105. (forward-comment (- (point-max)))
  106. (or (bolp) (forward-line 1))
  107. ))
  108. ;; Indentation stack, what the Python (2.3) language spec. says:
  109. ;;
  110. ;; The indentation levels of consecutive lines are used to generate
  111. ;; INDENT and DEDENT tokens, using a stack, as follows.
  112. ;;
  113. ;; Before the first line of the file is read, a single zero is pushed
  114. ;; on the stack; this will never be popped off again. The numbers
  115. ;; pushed on the stack will always be strictly increasing from bottom
  116. ;; to top. At the beginning of each logical line, the line's
  117. ;; indentation level is compared to the top of the stack. If it is
  118. ;; equal, nothing happens. If it is larger, it is pushed on the stack,
  119. ;; and one INDENT token is generated. If it is smaller, it must be one
  120. ;; of the numbers occurring on the stack; all numbers on the stack
  121. ;; that are larger are popped off, and for each number popped off a
  122. ;; DEDENT token is generated. At the end of the file, a DEDENT token
  123. ;; is generated for each number remaining on the stack that is larger
  124. ;; than zero.
  125. (defvar wisent-python-indent-stack)
  126. (define-lex-analyzer wisent-python-lex-beginning-of-line
  127. "Detect and create Python indentation tokens at beginning of line."
  128. (and
  129. (bolp) (not (wisent-python-implicit-line-joining-p))
  130. (let ((last-indent (car wisent-python-indent-stack))
  131. (last-pos (point))
  132. (curr-indent (current-indentation)))
  133. (skip-syntax-forward "-")
  134. (cond
  135. ;; Skip comments and blank lines. No change in indentation.
  136. ((or (eolp) (looking-at semantic-lex-comment-regex))
  137. (forward-comment (point-max))
  138. (or (eobp) (beginning-of-line))
  139. (setq semantic-lex-end-point (point))
  140. ;; Loop lexer to handle the next line.
  141. t)
  142. ;; No change in indentation.
  143. ((= curr-indent last-indent)
  144. (setq semantic-lex-end-point (point))
  145. ;; Try next analyzers.
  146. nil)
  147. ;; Indentation increased
  148. ((> curr-indent last-indent)
  149. (if (or (not semantic-lex-maximum-depth)
  150. (< semantic-lex-current-depth semantic-lex-maximum-depth))
  151. (progn
  152. ;; Return an INDENT lexical token
  153. (setq semantic-lex-current-depth (1+ semantic-lex-current-depth))
  154. (push curr-indent wisent-python-indent-stack)
  155. (semantic-lex-push-token
  156. (semantic-lex-token 'INDENT last-pos (point))))
  157. ;; Add an INDENT_BLOCK token
  158. (semantic-lex-push-token
  159. (semantic-lex-token
  160. 'INDENT_BLOCK
  161. (progn (beginning-of-line) (point))
  162. (semantic-lex-unterminated-syntax-protection 'INDENT_BLOCK
  163. (wisent-python-end-of-block)
  164. (point)))))
  165. ;; Loop lexer to handle tokens in current line.
  166. t)
  167. ;; Indentation decreased
  168. (t
  169. ;; Pop items from indentation stack
  170. (while (< curr-indent last-indent)
  171. (pop wisent-python-indent-stack)
  172. (setq semantic-lex-current-depth (1- semantic-lex-current-depth)
  173. last-indent (car wisent-python-indent-stack))
  174. (semantic-lex-push-token
  175. (semantic-lex-token 'DEDENT last-pos (point))))
  176. ;; If pos did not change, then we must return nil so that
  177. ;; other lexical analyzers can be run.
  178. (/= last-pos (point))))))
  179. ;; All the work was done in the above analyzer matching condition.
  180. )
  181. (define-lex-regex-analyzer wisent-python-lex-end-of-line
  182. "Detect and create Python newline tokens.
  183. Just skip the newline character if the following line is an implicit
  184. continuation of current line."
  185. "\\(\n\\|\\s>\\)"
  186. (if (wisent-python-implicit-line-joining-p)
  187. (setq semantic-lex-end-point (match-end 0))
  188. (semantic-lex-push-token
  189. (semantic-lex-token 'NEWLINE (point) (match-end 0)))))
  190. (define-lex-regex-analyzer wisent-python-lex-string
  191. "Detect and create python string tokens."
  192. wisent-python-string-re
  193. (semantic-lex-push-token
  194. (semantic-lex-token
  195. 'STRING_LITERAL
  196. (point)
  197. (semantic-lex-unterminated-syntax-protection 'STRING_LITERAL
  198. (wisent-python-forward-string)
  199. (point)))))
  200. (define-lex-regex-analyzer wisent-python-lex-ignore-backslash
  201. "Detect and skip over backslash (explicit line joining) tokens.
  202. A backslash must be the last token of a physical line, it is illegal
  203. elsewhere on a line outside a string literal."
  204. "\\s\\\\s-*$"
  205. ;; Skip over the detected backslash and go to the first
  206. ;; non-whitespace character in the next physical line.
  207. (forward-line)
  208. (skip-syntax-forward "-")
  209. (setq semantic-lex-end-point (point)))
  210. (define-lex wisent-python-lexer
  211. "Lexical Analyzer for Python code."
  212. ;; Must analyze beginning of line first to handle indentation.
  213. wisent-python-lex-beginning-of-line
  214. wisent-python-lex-end-of-line
  215. ;; Must analyze string before symbol to handle string prefix.
  216. wisent-python-lex-string
  217. ;; Analyzers auto-generated from grammar.
  218. wisent-python-wy--<number>-regexp-analyzer
  219. wisent-python-wy--<keyword>-keyword-analyzer
  220. wisent-python-wy--<symbol>-regexp-analyzer
  221. wisent-python-wy--<block>-block-analyzer
  222. wisent-python-wy--<punctuation>-string-analyzer
  223. ;; Ignored things.
  224. wisent-python-lex-ignore-backslash
  225. semantic-lex-ignore-whitespace
  226. semantic-lex-ignore-comments
  227. ;; Signal error on unhandled syntax.
  228. semantic-lex-default-action)
  229. ;;; Overridden Semantic API.
  230. ;;
  231. (define-mode-local-override semantic-lex python-mode
  232. (start end &optional depth length)
  233. "Lexically analyze Python code in current buffer.
  234. See the function `semantic-lex' for the meaning of the START, END,
  235. DEPTH and LENGTH arguments.
  236. This function calls `wisent-python-lexer' to actually perform the
  237. lexical analysis, then emits the necessary Python DEDENT tokens from
  238. what remains in the `wisent-python-indent-stack'."
  239. (let* ((wisent-python-indent-stack (list 0))
  240. (stream (wisent-python-lexer start end depth length))
  241. (semantic-lex-token-stream nil))
  242. ;; Emit DEDENT tokens if something remains in the INDENT stack.
  243. (while (> (pop wisent-python-indent-stack) 0)
  244. (semantic-lex-push-token (semantic-lex-token 'DEDENT end end)))
  245. (nconc stream (nreverse semantic-lex-token-stream))))
  246. (define-mode-local-override semantic-get-local-variables python-mode ()
  247. "Get the local variables based on point's context.
  248. To be implemented for Python! For now just return nil."
  249. nil)
  250. (defcustom-mode-local-semantic-dependency-system-include-path
  251. python-mode semantic-python-dependency-system-include-path
  252. nil
  253. "The system include path used by Python language.")
  254. ;;; Enable Semantic in `python-mode'.
  255. ;;
  256. ;;;###autoload
  257. (defun wisent-python-default-setup ()
  258. "Setup buffer for parse."
  259. (wisent-python-wy--install-parser)
  260. (set (make-local-variable 'parse-sexp-ignore-comments) t)
  261. (setq
  262. ;; Character used to separation a parent/child relationship
  263. semantic-type-relation-separator-character '(".")
  264. semantic-command-separation-character ";"
  265. ;; The following is no more necessary as semantic-lex is overridden
  266. ;; in python-mode.
  267. ;; semantic-lex-analyzer 'wisent-python-lexer
  268. ;; Semantic to take over from the one provided by python.
  269. ;; The python one, if it uses the senator advice, will hang
  270. ;; Emacs unrecoverably.
  271. imenu-create-index-function 'semantic-create-imenu-index
  272. ;; I need a python guru to update this list:
  273. semantic-symbol->name-assoc-list-for-type-parts '((variable . "Variables")
  274. (function . "Methods"))
  275. semantic-symbol->name-assoc-list '((type . "Classes")
  276. (variable . "Variables")
  277. (function . "Functions")
  278. (include . "Imports")
  279. (package . "Package")
  280. (code . "Code")))
  281. )
  282. ;;;###autoload
  283. (add-hook 'python-mode-hook 'wisent-python-default-setup)
  284. ;; Make sure the newer python modes pull in the same python
  285. ;; mode overrides.
  286. (define-child-mode python-2-mode python-mode "Python 2 mode")
  287. (define-child-mode python-3-mode python-mode "Python 3 mode")
  288. ;;; Test
  289. ;;
  290. (defun wisent-python-lex-buffer ()
  291. "Run `wisent-python-lexer' on current buffer."
  292. (interactive)
  293. (semantic-lex-init)
  294. (let ((token-stream (semantic-lex (point-min) (point-max) 0)))
  295. (with-current-buffer (get-buffer-create "*wisent-python-lexer*")
  296. (erase-buffer)
  297. (pp token-stream (current-buffer))
  298. (goto-char (point-min))
  299. (pop-to-buffer (current-buffer)))))
  300. (provide 'semantic/wisent/python)
  301. ;; Local variables:
  302. ;; generated-autoload-file: "../loaddefs.el"
  303. ;; generated-autoload-load-name: "semantic/wisent/python"
  304. ;; End:
  305. ;;; semantic/wisent/python.el ends here