scheme.rb
141 lines
| 4.7 KiB
| text/x-ruby
|
RubyLexer
|
r638 | module CodeRay | |
module Scanners | |||
# Scheme scanner for CodeRay (by closure). | |||
# Thanks to murphy for putting CodeRay into public. | |||
class Scheme < Scanner | |||
register_for :scheme | |||
|
r2965 | file_extension :scm | |
|
r638 | ||
CORE_FORMS = %w[ | |||
lambda let let* letrec syntax-case define-syntax let-syntax | |||
letrec-syntax begin define quote if or and cond case do delay | |||
quasiquote set! cons force call-with-current-continuation call/cc | |||
] | |||
IDENT_KIND = CaseIgnoringWordList.new(:ident). | |||
add(CORE_FORMS, :reserved) | |||
#IDENTIFIER_INITIAL = /[a-z!@\$%&\*\/\:<=>\?~_\^]/i | |||
#IDENTIFIER_SUBSEQUENT = /#{IDENTIFIER_INITIAL}|\d|\.|\+|-/ | |||
#IDENTIFIER = /#{IDENTIFIER_INITIAL}#{IDENTIFIER_SUBSEQUENT}*|\+|-|\.{3}/ | |||
IDENTIFIER = /[a-zA-Z!@$%&*\/:<=>?~_^][\w!@$%&*\/:<=>?~^.+\-]*|[+-]|\.\.\./ | |||
DIGIT = /\d/ | |||
DIGIT10 = DIGIT | |||
DIGIT16 = /[0-9a-f]/i | |||
DIGIT8 = /[0-7]/ | |||
DIGIT2 = /[01]/ | |||
RADIX16 = /\#x/i | |||
RADIX8 = /\#o/i | |||
RADIX2 = /\#b/i | |||
RADIX10 = /\#d/i | |||
EXACTNESS = /#i|#e/i | |||
SIGN = /[\+-]?/ | |||
EXP_MARK = /[esfdl]/i | |||
EXP = /#{EXP_MARK}#{SIGN}#{DIGIT}+/ | |||
SUFFIX = /#{EXP}?/ | |||
PREFIX10 = /#{RADIX10}?#{EXACTNESS}?|#{EXACTNESS}?#{RADIX10}?/ | |||
PREFIX16 = /#{RADIX16}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX16}/ | |||
PREFIX8 = /#{RADIX8}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX8}/ | |||
PREFIX2 = /#{RADIX2}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX2}/ | |||
UINT10 = /#{DIGIT10}+#*/ | |||
UINT16 = /#{DIGIT16}+#*/ | |||
UINT8 = /#{DIGIT8}+#*/ | |||
UINT2 = /#{DIGIT2}+#*/ | |||
DECIMAL = /#{DIGIT10}+#+\.#*#{SUFFIX}|#{DIGIT10}+\.#{DIGIT10}*#*#{SUFFIX}|\.#{DIGIT10}+#*#{SUFFIX}|#{UINT10}#{EXP}/ | |||
UREAL10 = /#{UINT10}\/#{UINT10}|#{DECIMAL}|#{UINT10}/ | |||
UREAL16 = /#{UINT16}\/#{UINT16}|#{UINT16}/ | |||
UREAL8 = /#{UINT8}\/#{UINT8}|#{UINT8}/ | |||
UREAL2 = /#{UINT2}\/#{UINT2}|#{UINT2}/ | |||
REAL10 = /#{SIGN}#{UREAL10}/ | |||
REAL16 = /#{SIGN}#{UREAL16}/ | |||
REAL8 = /#{SIGN}#{UREAL8}/ | |||
REAL2 = /#{SIGN}#{UREAL2}/ | |||
IMAG10 = /i|#{UREAL10}i/ | |||
IMAG16 = /i|#{UREAL16}i/ | |||
IMAG8 = /i|#{UREAL8}i/ | |||
IMAG2 = /i|#{UREAL2}i/ | |||
COMPLEX10 = /#{REAL10}@#{REAL10}|#{REAL10}\+#{IMAG10}|#{REAL10}-#{IMAG10}|\+#{IMAG10}|-#{IMAG10}|#{REAL10}/ | |||
COMPLEX16 = /#{REAL16}@#{REAL16}|#{REAL16}\+#{IMAG16}|#{REAL16}-#{IMAG16}|\+#{IMAG16}|-#{IMAG16}|#{REAL16}/ | |||
COMPLEX8 = /#{REAL8}@#{REAL8}|#{REAL8}\+#{IMAG8}|#{REAL8}-#{IMAG8}|\+#{IMAG8}|-#{IMAG8}|#{REAL8}/ | |||
COMPLEX2 = /#{REAL2}@#{REAL2}|#{REAL2}\+#{IMAG2}|#{REAL2}-#{IMAG2}|\+#{IMAG2}|-#{IMAG2}|#{REAL2}/ | |||
NUM10 = /#{PREFIX10}?#{COMPLEX10}/ | |||
NUM16 = /#{PREFIX16}#{COMPLEX16}/ | |||
NUM8 = /#{PREFIX8}#{COMPLEX8}/ | |||
NUM2 = /#{PREFIX2}#{COMPLEX2}/ | |||
NUM = /#{NUM10}|#{NUM16}|#{NUM8}|#{NUM2}/ | |||
private | |||
def scan_tokens tokens,options | |||
state = :initial | |||
ident_kind = IDENT_KIND | |||
until eos? | |||
kind = match = nil | |||
case state | |||
when :initial | |||
if scan(/ \s+ | \\\n /x) | |||
kind = :space | |||
elsif scan(/['\(\[\)\]]|#\(/) | |||
kind = :operator_fat | |||
elsif scan(/;.*/) | |||
kind = :comment | |||
elsif scan(/#\\(?:newline|space|.?)/) | |||
kind = :char | |||
elsif scan(/#[ft]/) | |||
kind = :pre_constant | |||
elsif scan(/#{IDENTIFIER}/o) | |||
kind = ident_kind[matched] | |||
elsif scan(/\./) | |||
kind = :operator | |||
elsif scan(/"/) | |||
tokens << [:open, :string] | |||
state = :string | |||
tokens << ['"', :delimiter] | |||
next | |||
elsif scan(/#{NUM}/o) and not matched.empty? | |||
kind = :integer | |||
elsif getch | |||
kind = :error | |||
end | |||
when :string | |||
if scan(/[^"\\]+/) or scan(/\\.?/) | |||
kind = :content | |||
elsif scan(/"/) | |||
tokens << ['"', :delimiter] | |||
tokens << [:close, :string] | |||
state = :initial | |||
next | |||
else | |||
raise_inspect "else case \" reached; %p not handled." % peek(1), | |||
tokens, state | |||
end | |||
else | |||
raise "else case reached" | |||
end | |||
match ||= matched | |||
if $DEBUG and not kind | |||
raise_inspect 'Error token %p in line %d' % | |||
[[match, kind], line], tokens | |||
end | |||
raise_inspect 'Empty token', tokens, state unless match | |||
tokens << [match, kind] | |||
end # until eos | |||
if state == :string | |||
tokens << [:close, :string] | |||
end | |||
tokens | |||
end #scan_tokens | |||
end #class | |||
end #module scanners | |||
end #module coderay |