Skip to content

Commit 3f69ed0

Browse files
committed
Nathan Weizenbaum's Lisp scanner
1 parent 3effca8 commit 3f69ed0

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

lib/coderay/scanners/lisp.rb

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# By Nathan Weizenbaum (http://nex3.leeweiz.net)
2+
# MIT License (http://www.opensource.org/licenses/mit-license.php)
3+
#
4+
# CodeRay scanner for Lisp.
5+
# The keywords are mostly geared towards Emacs Lisp,
6+
# but it should work fine for Common Lisp
7+
# and reasonably well for Scheme.
8+
9+
require 'rubygems'
10+
require 'coderay'
11+
12+
module CodeRay::Scanners
13+
class Lisp < Scanner
14+
register_for :lisp
15+
16+
NON_SYMBOL_CHARS = '();\s\[\]'
17+
SYMBOL_RE = /[^#{NON_SYMBOL_CHARS}]+/
18+
EXPONENT_RE = /(e[\-+]?[0-9]+)?/
19+
20+
GEN_DEFINES = %w{
21+
defun defun* defsubst defmacro defadvice define-skeleton define-minor-mode
22+
define-global-minor-mode define-globalized-minor-mode define-derived-mode
23+
define-generic-mode define-compiler-macro define-modify-macro defsetf
24+
define-setf-expander define-method-combination defgeneric defmethod
25+
}
26+
TYPE_DEFINES = %w{
27+
defgroup deftheme deftype defstruct defclass define-condition
28+
define-widget defface defpackage
29+
}
30+
VAR_DEFINES = %w{
31+
defvar defconst defconstant defcustom defparameter define-symbol-macro
32+
}
33+
KEYWORDS = (GEN_DEFINES + TYPE_DEFINES + VAR_DEFINES + %w{
34+
lambda autoload progn prog1 prog2 save-excursion save-window-excursion
35+
save-selected-window save-restriction save-match-data save-current-buffer
36+
with-current-buffer combine-after-change-calls with-output-to-string
37+
with-temp-file with-temp-buffer with-temp-message with-syntax-table let
38+
let* while if read-if catch condition-case unwind-protect
39+
with-output-to-temp-buffer eval-after-load dolist dotimes when unless
40+
}).inject({}) { |memo, str| memo[str] = nil; memo }
41+
42+
DEFINES = WordList.new.
43+
add(GEN_DEFINES, :function).
44+
add(TYPE_DEFINES, :class).
45+
add(VAR_DEFINES, :variable)
46+
47+
def scan_tokens(tokens, options)
48+
defined = false
49+
until eos?
50+
kind = nil
51+
match = nil
52+
53+
if scan(/\s+/m)
54+
kind = :space
55+
else
56+
if scan(/[\(\)\[\]]/)
57+
kind = :delimiter
58+
elsif scan(/'+#{SYMBOL_RE}/)
59+
kind = :symbol
60+
elsif scan(/\&#{SYMBOL_RE}/)
61+
kind = :reserved
62+
elsif scan(/:#{SYMBOL_RE}/)
63+
kind = :constant
64+
elsif scan(/\?#{SYMBOL_RE}/)
65+
kind = :char
66+
elsif match = scan(/"(\\"|[^"])+"/m)
67+
tokens << [:open, :string] << ['"', :delimiter] <<
68+
[match[1...-1], :content] << ['"', :delimiter] << [:close, :string]
69+
next
70+
elsif scan(/[\-+]?[0-9]*\.[0-9]+#{EXPONENT_RE}/)
71+
kind = :float
72+
elsif scan(/[\-+]?[0-9]+#{EXPONENT_RE}/)
73+
kind = :integer
74+
elsif scan(/;.*$/)
75+
kind = :comment
76+
elsif scan(SYMBOL_RE)
77+
kind = :plain
78+
79+
if defined
80+
kind = defined
81+
else
82+
sym = matched
83+
if KEYWORDS.include? sym
84+
kind = :reserved
85+
defined = DEFINES[sym]
86+
end
87+
end
88+
end
89+
end
90+
91+
match ||= matched
92+
raise_inspect 'Empty token', tokens unless match
93+
94+
defined = [:reserved, :comment, :space].include?(kind) && defined
95+
96+
tokens << [match, kind]
97+
end
98+
99+
tokens
100+
end
101+
end
102+
end

0 commit comments

Comments
 (0)