diff options
author | Nathan Youngman <git@nathany.com> | 2012-10-27 13:46:49 -0600 |
---|---|---|
committer | Nathan Youngman <git@nathany.com> | 2012-10-27 13:46:49 -0600 |
commit | 3f69ed0e2454b6389526ef1e41ed579f64158b54 (patch) | |
tree | 335bf36c166b49fa2477cfa6b54f2671c0224d7a /lib/coderay/scanners/lisp.rb | |
parent | 3effca8291ed4941f7b3a1c2088b50274f28aa6f (diff) | |
download | coderay-3f69ed0e2454b6389526ef1e41ed579f64158b54.tar.gz |
Nathan Weizenbaum's Lisp scanner
Diffstat (limited to 'lib/coderay/scanners/lisp.rb')
-rw-r--r-- | lib/coderay/scanners/lisp.rb | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/lib/coderay/scanners/lisp.rb b/lib/coderay/scanners/lisp.rb new file mode 100644 index 0000000..73ce0da --- /dev/null +++ b/lib/coderay/scanners/lisp.rb @@ -0,0 +1,102 @@ +# By Nathan Weizenbaum (http://nex3.leeweiz.net) +# MIT License (http://www.opensource.org/licenses/mit-license.php) +# +# CodeRay scanner for Lisp. +# The keywords are mostly geared towards Emacs Lisp, +# but it should work fine for Common Lisp +# and reasonably well for Scheme. + +require 'rubygems' +require 'coderay' + +module CodeRay::Scanners + class Lisp < Scanner + register_for :lisp + + NON_SYMBOL_CHARS = '();\s\[\]' + SYMBOL_RE = /[^#{NON_SYMBOL_CHARS}]+/ + EXPONENT_RE = /(e[\-+]?[0-9]+)?/ + + GEN_DEFINES = %w{ + defun defun* defsubst defmacro defadvice define-skeleton define-minor-mode + define-global-minor-mode define-globalized-minor-mode define-derived-mode + define-generic-mode define-compiler-macro define-modify-macro defsetf + define-setf-expander define-method-combination defgeneric defmethod + } + TYPE_DEFINES = %w{ + defgroup deftheme deftype defstruct defclass define-condition + define-widget defface defpackage + } + VAR_DEFINES = %w{ + defvar defconst defconstant defcustom defparameter define-symbol-macro + } + KEYWORDS = (GEN_DEFINES + TYPE_DEFINES + VAR_DEFINES + %w{ + lambda autoload progn prog1 prog2 save-excursion save-window-excursion + save-selected-window save-restriction save-match-data save-current-buffer + with-current-buffer combine-after-change-calls with-output-to-string + with-temp-file with-temp-buffer with-temp-message with-syntax-table let + let* while if read-if catch condition-case unwind-protect + with-output-to-temp-buffer eval-after-load dolist dotimes when unless + }).inject({}) { |memo, str| memo[str] = nil; memo } + + DEFINES = WordList.new. + add(GEN_DEFINES, :function). + add(TYPE_DEFINES, :class). + add(VAR_DEFINES, :variable) + + def scan_tokens(tokens, options) + defined = false + until eos? + kind = nil + match = nil + + if scan(/\s+/m) + kind = :space + else + if scan(/[\(\)\[\]]/) + kind = :delimiter + elsif scan(/'+#{SYMBOL_RE}/) + kind = :symbol + elsif scan(/\&#{SYMBOL_RE}/) + kind = :reserved + elsif scan(/:#{SYMBOL_RE}/) + kind = :constant + elsif scan(/\?#{SYMBOL_RE}/) + kind = :char + elsif match = scan(/"(\\"|[^"])+"/m) + tokens << [:open, :string] << ['"', :delimiter] << + [match[1...-1], :content] << ['"', :delimiter] << [:close, :string] + next + elsif scan(/[\-+]?[0-9]*\.[0-9]+#{EXPONENT_RE}/) + kind = :float + elsif scan(/[\-+]?[0-9]+#{EXPONENT_RE}/) + kind = :integer + elsif scan(/;.*$/) + kind = :comment + elsif scan(SYMBOL_RE) + kind = :plain + + if defined + kind = defined + else + sym = matched + if KEYWORDS.include? sym + kind = :reserved + defined = DEFINES[sym] + end + end + end + end + + match ||= matched + raise_inspect 'Empty token', tokens unless match + + defined = [:reserved, :comment, :space].include?(kind) && defined + + tokens << [match, kind] + end + + tokens + end + end +end
\ No newline at end of file |