| Class | CodeRay::Scanners::Java |
| In: |
lib/coderay/scanners/java.rb
|
| Parent: | Scanner |
| KEYWORDS | = | %w[ break case catch continue default do else false finally for if instanceof new null return switch throw true try typeof while debugger export import package ] | TODO: Check this! | |
| MAGIC_VARIABLES | = | %w[ this super ] | ||
| TYPES | = | %w[ boolean byte char class interface double enum float String int long short void ] << '[]' | ||
| DIRECTIVES | = | %w[ abstract extends final implements native private protected public static strictfp synchronized threadsafe throws transient volatile ] | ||
| IDENT_KIND | = | WordList.new(:ident). add(KEYWORDS, :keyword). add(MAGIC_VARIABLES, :local_variable). add(TYPES, :type). add(BuiltinTypes::List, :pre_type). add(DIRECTIVES, :directive) | Reserved for future use. | |
| ESCAPE | = | / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x | ||
| UNICODE_ESCAPE | = | / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x | ||
| STRING_CONTENT_PATTERN | = | { "'" => /[^\\']+/, '"' => /[^\\"]+/, '/' => /[^\\\/]+/, } | ||
| IDENT | = | /[a-zA-Z_][A-Za-z_0-9]*/ |
# File lib/coderay/scanners/java.rb, line 45
45: def scan_tokens tokens, options
46:
47: state = :initial
48: string_delimiter = nil
49: import_clause = class_name_follows = last_token_dot = false
50:
51: until eos?
52:
53: kind = nil
54: match = nil
55:
56: case state
57:
58: when :initial
59:
60: if match = scan(/ \s+ | \\\n /x)
61: tokens << [match, :space]
62: next
63:
64: elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
65: kind = :comment
66:
67: elsif import_clause && scan(/ #{IDENT} (?: \. #{IDENT} )* /ox)
68: kind = :include
69:
70: elsif match = scan(/ #{IDENT} | \[\] /ox)
71: kind = IDENT_KIND[match]
72: if last_token_dot
73: kind = :ident
74: elsif class_name_follows
75: kind = :class
76: class_name_follows = false
77: else
78: import_clause = true if match == 'import'
79: class_name_follows = true if match == 'class' || match == 'interface'
80: end
81:
82: elsif scan(/ \.(?!\d) | [,?:(\[)\]}] | -- | \+\+ | && | \|\| | \*\*=? | [-+*\/%^~&|<>=!]=? | <<<?=? | >>>?=? /x)
83: kind = :operator
84:
85: elsif scan(/;/)
86: import_clause = false
87: kind = :operator
88:
89: elsif scan(/\{/)
90: class_name_follows = false
91: kind = :operator
92:
93: elsif check(/[\d.]/)
94: if scan(/0[xX][0-9A-Fa-f]+/)
95: kind = :hex
96: elsif scan(/(?>0[0-7]+)(?![89.eEfF])/)
97: kind = :oct
98: elsif scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/)
99: kind = :float
100: elsif scan(/\d+[lL]?/)
101: kind = :integer
102: end
103:
104: elsif match = scan(/["']/)
105: tokens << [:open, :string]
106: state = :string
107: string_delimiter = match
108: kind = :delimiter
109:
110: elsif scan(/ @ #{IDENT} /ox)
111: kind = :annotation
112:
113: else
114: getch
115: kind = :error
116:
117: end
118:
119: when :string
120: if scan(STRING_CONTENT_PATTERN[string_delimiter])
121: kind = :content
122: elsif match = scan(/["'\/]/)
123: tokens << [match, :delimiter]
124: tokens << [:close, state]
125: string_delimiter = nil
126: state = :initial
127: next
128: elsif state == :string && (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox))
129: if string_delimiter == "'" && !(match == "\\\\" || match == "\\'")
130: kind = :content
131: else
132: kind = :char
133: end
134: elsif scan(/\\./m)
135: kind = :content
136: elsif scan(/ \\ | $ /x)
137: tokens << [:close, :delimiter]
138: kind = :error
139: state = :initial
140: else
141: raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
142: end
143:
144: else
145: raise_inspect 'Unknown state', tokens
146:
147: end
148:
149: match ||= matched
150: if $DEBUG and not kind
151: raise_inspect 'Error token %p in line %d' %
152: [[match, kind], line], tokens
153: end
154: raise_inspect 'Empty token', tokens unless match
155:
156: last_token_dot = match == '.'
157:
158: tokens << [match, kind]
159:
160: end
161:
162: if state == :string
163: tokens << [:close, state]
164: end
165:
166: tokens
167: end