1
+ module CodeRay module Scanners
2
+
3
+ #A simple scanner for a simple language: Io
4
+
5
+ class Io < Scanner
6
+
7
+ register_for :io
8
+
9
+ RESERVED_WORDS = [ 'clone' , 'init' , 'method' , 'list' , 'vector' , 'block' , 'if' , 'ifTrue' , 'ifFalse' , 'ifTrueIfFalse' , 'then' , 'for' , 'loop' ,
10
+ 'reverseForeach' , 'foreach' , 'map' , 'continue' , 'break' , 'while' , 'do' , 'return' ,
11
+ 'self' , 'sender' , 'target' , 'proto' , 'parent' , 'protos' ]
12
+
13
+ PREDEFINED_TYPES = [ ]
14
+
15
+ PREDEFINED_CONSTANTS = [ 'Object' , 'Lobby' ,
16
+ 'TRUE' , 'true' , 'FALSE' , 'false' , 'NULL' , 'null' , 'Null' , 'Nil' , 'nil' , 'YES' , 'NO' ]
17
+
18
+ IDENT_KIND = WordList . new ( :ident ) .
19
+ add ( RESERVED_WORDS , :reserved ) .
20
+ add ( PREDEFINED_TYPES , :pre_type ) .
21
+ add ( PREDEFINED_CONSTANTS , :pre_constant )
22
+
23
+ ESCAPE = / [rbfnrtv\n \\ '"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x
24
+ UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x
25
+
26
+ def scan_tokens tokens , options
27
+
28
+ state = :initial
29
+
30
+ until eos?
31
+
32
+ kind = :error
33
+ match = nil
34
+
35
+ if state == :initial
36
+
37
+ if scan ( / \s + | \\ \n /x )
38
+ kind = :space
39
+
40
+ elsif scan ( %r! // [^\n \\ ]* (?: \\ . [^\n \\ ]* )* | /\* (?: .*? \* / | .* ) !mx )
41
+ kind = :comment
42
+
43
+
44
+ elsif scan ( / [-+*\/ \$ \@ =<>?:;,!&^|()\[ \] {}~%]+ | \. (?!\d ) /x )
45
+ kind = :operator
46
+
47
+ elsif match = scan ( / [A-Za-z_][A-Za-z_0-9]* /x )
48
+ kind = IDENT_KIND [ match ]
49
+ if kind == :ident and check ( /:(?!:)/ )
50
+ match << scan ( /:/ )
51
+ kind = :label
52
+ end
53
+
54
+ elsif match = scan ( /L?"/ )
55
+ tokens << [ :open , :string ]
56
+ if match [ 0 ] == ?L
57
+ tokens << [ 'L' , :modifier ]
58
+ match = '"'
59
+ end
60
+ state = :string
61
+ kind = :delimiter
62
+
63
+ elsif scan ( /#\s *(\w *)/ )
64
+ kind = :preprocessor # FIXME multiline preprocs
65
+ state = :include_expected if self [ 1 ] == 'include'
66
+
67
+ elsif scan ( / L?' (?: [^\' \n \\ ] | \\ #{ ESCAPE } )? '? /ox )
68
+ kind = :char
69
+
70
+ elsif scan ( /0[xX][0-9A-Fa-f]+/ )
71
+ kind = :hex
72
+
73
+ elsif scan ( /(?:0[0-7]+)(?![89.eEfF])/ )
74
+ kind = :oct
75
+
76
+ elsif scan ( /(?:\d +)(?![.eEfF])/ )
77
+ kind = :integer
78
+
79
+ elsif scan ( /\d [fF]?|\d *\. \d +(?:[eE][+-]?\d +)?[fF]?|\d +[eE][+-]?\d +[fF]?/ )
80
+ kind = :float
81
+
82
+ else
83
+ getch
84
+ end
85
+
86
+ elsif state == :string
87
+ if scan ( /[^\\ "]+/ )
88
+ kind = :content
89
+ elsif scan ( /"/ )
90
+ tokens << [ '"' , :delimiter ]
91
+ tokens << [ :close , :string ]
92
+ state = :initial
93
+ next
94
+ elsif scan ( / \\ (?: #{ ESCAPE } | #{ UNICODE_ESCAPE } ) /mox )
95
+ kind = :char
96
+ elsif scan ( / \\ | $ /x )
97
+ kind = :error
98
+ state = :initial
99
+ else
100
+ raise "else case \" reached; %p not handled." % peek ( 1 ) , tokens
101
+ end
102
+
103
+ elsif state == :include_expected
104
+ if scan ( /<[^>\n ]+>?|"[^"\n \\ ]*(?:\\ .[^"\n \\ ]*)*"?/ )
105
+ kind = :include
106
+ state = :initial
107
+
108
+ elsif match = scan ( /\s +/ )
109
+ kind = :space
110
+ state = :initial if match . index ?\n
111
+
112
+ else
113
+ getch
114
+
115
+ end
116
+
117
+ else
118
+ raise 'else-case reached' , tokens
119
+
120
+ end
121
+
122
+ match ||= matched
123
+ raise [ match , kind ] , tokens if kind == :error
124
+
125
+ tokens << [ match , kind ]
126
+
127
+ end
128
+
129
+ tokens
130
+ end
131
+
132
+ end
133
+
134
+ end end
0 commit comments