forked from twinbasic/documentation
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtwinbasic.rb
More file actions
248 lines (217 loc) · 7.31 KB
/
twinbasic.rb
File metadata and controls
248 lines (217 loc) · 7.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# -*- coding: utf-8 -*- #
# frozen_string_literal: true
require "rouge"
# Register tB-specific token types so the highlighter can distinguish symbols
# the way the twinBASIC IDE's theme system does -- e.g. Boolean / Empty /
# Nothing / Null are each their own slot in tB's Symbol* palette, and the
# line-continuation '_' has its own SymbolContinuationCharacter colour.
module Rouge::Token::Tokens
[
[Literal, :Boolean, 'lb'],
[Literal, :Empty, 'le'],
[Literal, :Nothing, 'ln'],
[Literal, :Null, 'lu'],
[Punctuation, :LineContinuation, 'lc'],
].each do |parent, name, shortname|
parent.token(name, shortname) unless parent.const_defined?(name, false)
end
end
module Rouge
module Lexers
class TwinBasic < RegexLexer
title "twinBASIC"
desc "twinBASIC programming language (VB6/VBA compatible)"
tag 'tb'
aliases 'twinbasic', 'vba', 'vb'
filenames '*.twin', '*.bas', '*.cls', '*.frm'
mimetypes 'text/x-twinbasic', 'application/x-twinbasic'
def self.keywords
@keywords ||= Set.new %w(
alias byref byval call case class close coclass const
continue declare default delegate dim do each else elseif
end endif enum erase error event exit extends
finally for friend function get global gosub
goto handles if implements imports inherits input interface
let lib line lock loop me mid module
namespace new next of on open option optional
overloads paramarray preserve print private property public
put raiseevent redim resume return select set
shared static step stop structure sub
then throw to try type unlock until
using wend when while width
with withevents write
)
end
def self.keyword_constants
@keyword_constants ||= {
'true' => Literal::Boolean,
'false' => Literal::Boolean,
'empty' => Literal::Empty,
'nothing' => Literal::Nothing,
'null' => Literal::Null,
}
end
def self.keywords_type
@keywords_type ||= Set.new %w(
any boolean byte currency date decimal double integer long
longlong longptr object single string variant
)
end
def self.operator_words
@operator_words ||= Set.new %w(
addressof and andalso as eqv imp is isnot like
mod not or orelse typeof xor
)
end
def self.builtins
@builtins ||= Set.new %w(
debug err
)
end
id = /[a-z_]\w*/i
state :whitespace do
rule %r/_[ \t]*\n/, Punctuation::LineContinuation
rule %r/\n/, Text, :bol
rule %r/[^\S\n]+/, Text
rule %r/rem\b.*?$/i, Comment::Single
rule %r(/\*.*?\*/)m, Comment::Multiline
rule %r/'.*$/, Comment::Single
end
state :bol do
rule %r/[^\S\n]+/, Text
rule(//) { pop! }
end
state :root do
mixin :whitespace
rule %r(
[#]If\b .*? \bThen
| [#]ElseIf\b .*? \bThen
| [#]Else\b
| [#]End \s+ If
| [#]Const
| [#]Region .*? \n
| [#]End \s+ Region
)xi, Comment::Preproc
rule %r/#\d[^#\n]*#/, Literal::Date
rule %r/\[/, Punctuation, :attribute
rule %r/(\d+\.\d*|\d*\.\d+)(e[+-]?\d+)?[!#@]?/i, Num::Float
rule %r/\d+e[+-]?\d+[!#@]?/i, Num::Float
rule %r/&H[0-9a-f]+(_[0-9a-f]+)*[%&!#@]?/i, Num::Integer
rule %r/&O[0-7]+(_[0-7]+)*[%&!#@]?/i, Num::Integer
rule %r/&B[01]+(_[01]+)*[%&!#@]?/i, Num::Integer
rule %r/\d+[%&!#@]?/, Num::Integer
rule %r/[.]/, Punctuation, :dotted
rule %r/[(){}!#,;:]/, Punctuation
rule %r/Option\s+(Strict|Explicit|Compare|Base)\s+(On|Off|Binary|Text|0|1)/i,
Keyword::Declaration
rule %r/Exit[ \t]+(Function|Sub|Property|For|Do|While)\b/i, Keyword
rule %r/End\b/i, Keyword, :end
rule %r/(Dim|Const|ReDim)\b/i, Keyword, :dim
rule %r/(Function|Sub|Property)\b/i, Keyword, :funcname
rule %r/(Alias|Class|CoClass|Structure|Enum|Type|Interface)\b/i, Keyword, :typename
rule %r/(Module|Namespace|Imports)\b/i, Keyword, :namespace
rule %r/#{id}[%&@!#$]/, Name
rule id do |m|
key = m[0].downcase
if (kc = self.class.keyword_constants[key])
token kc
elsif self.class.keywords.include? key
token Keyword
elsif self.class.keywords_type.include? key
token Keyword::Type
elsif self.class.operator_words.include? key
token Operator::Word
elsif self.class.builtins.include? key
token Name::Builtin
else
token Name
end
end
rule(
%r(&=|[*]=|/=|\\=|\^=|\+=|-=|<<=|>>=|<<|>>|:=|<=|>=|<>|[-&*/\\^+=<>]),
Operator
)
rule %r/"/, Str, :string
end
state :dotted do
mixin :whitespace
rule %r/#{id}[%&@!#$]?/, Name, :pop!
rule(//) { pop! }
end
state :string do
rule %r/""/, Str::Escape
rule %r/"/, Str, :pop!
rule %r/[^"]+/, Str
end
state :attribute do
rule %r/[^\S\n]+/, Text
rule %r/\]/, Punctuation, :pop!
rule %r/,/, Punctuation
rule %r/\(/, Punctuation, :attrargs
rule id, Name::Attribute
rule(//) { pop! }
end
state :attrargs do
rule %r/[^\S\n]+/, Text
rule %r/\)/, Punctuation, :pop!
rule %r/,/, Punctuation
rule %r/"/, Str, :string
rule %r/(\d+\.\d*|\d*\.\d+)(e[+-]?\d+)?[!#@]?/i, Num::Float
rule %r/&H[0-9a-f]+(_[0-9a-f]+)*[%&!#@]?/i, Num::Integer
rule %r/&O[0-7]+(_[0-7]+)*[%&!#@]?/i, Num::Integer
rule %r/&B[01]+(_[01]+)*[%&!#@]?/i, Num::Integer
rule %r/\d+[%&!#@]?/, Num::Integer
rule id do |m|
key = m[0].downcase
if (kc = self.class.keyword_constants[key])
token kc
elsif self.class.keywords.include? key
token Keyword
elsif self.class.keywords_type.include? key
token Keyword::Type
else
token Name
end
end
rule(//) { pop! }
end
state :dim do
mixin :whitespace
rule %r/#{id}[%&@!#$]?/, Name::Variable, :pop!
rule(//) { pop! }
end
state :funcname do
mixin :whitespace
rule %r/#{id}[%&@!#$]?/, Name::Function, :pop!
rule(//) { pop! }
end
state :typename do
mixin :whitespace
rule id do |m|
token Name::Class
goto :typename_ext
end
rule(//) { pop! }
end
state :typename_ext do
mixin :whitespace
rule %r/(Extends|As)\b/i do |m|
token Keyword
goto :typename
end
rule(//) { pop! }
end
state :namespace do
mixin :whitespace
rule %r/#{id}([.]#{id})*/, Name::Namespace, :pop!
rule(//) { pop! }
end
state :end do
mixin :whitespace
rule %r/(Function|Sub|Property|Class|CoClass|Structure|Enum|Module|Namespace|Type|Interface|Select|If|With)\b/i,
Keyword, :pop!
rule(//) { pop! }
end
end
end
end