forked from highlightjs/highlightjs-solidity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
solidity.js
412 lines (381 loc) · 15.8 KB
/
solidity.js
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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
/**
* highlight.js Solidity syntax highlighting definition
*
* @see https://github.com/isagalaev/highlight.js
*
* @package: highlightjs-solidity
* @author: Sam Pospischil <[email protected]>
* @since: 2016-07-01
*/
var module = module ? module : {}; // shim for browser use
function hljsDefineSolidity(hljs) {
//first: let's set up all parameterized types (bytes, int, uint, fixed, ufixed)
//NOTE: unparameterized versions are *not* included here, those are included
//manually
var byteSizes = [];
for(var i = 0; i < 32; i++) {
byteSizes[i] = i+1;
}
var numSizes = byteSizes.map(function(bytes) { return bytes * 8 } );
var precisions = [];
for(i = 0; i <= 80; i++) {
precisions[i] = i;
}
var bytesTypes = byteSizes.map(function(size) { return 'bytes' + size });
var bytesTypesString = bytesTypes.join(' ') + ' ';
var uintTypes = numSizes.map(function(size) { return 'uint' + size });
var uintTypesString = uintTypes.join(' ') + ' ';
var intTypes = numSizes.map(function(size) { return 'int' + size });
var intTypesString = intTypes.join(' ') + ' ';
var sizePrecisionPairs = [].concat.apply([],
numSizes.map(function(size) {
return precisions.map(function(precision) {
return size + 'x' + precision;
})
})
);
var fixedTypes = sizePrecisionPairs.map(function(pair) { return 'fixed' + pair });
var fixedTypesString = fixedTypes.join(' ') + ' ';
var ufixedTypes = sizePrecisionPairs.map(function(pair) { return 'ufixed' + pair });
var ufixedTypesString = ufixedTypes.join(' ') + ' ';
var SOL_KEYWORDS = {
keyword:
'var bool string ' +
'int uint ' + intTypesString + uintTypesString +
'byte bytes ' + bytesTypesString +
'fixed ufixed ' + fixedTypesString + ufixedTypesString +
'enum struct mapping address ' +
'new delete ' +
'if else for while continue break return throw emit try catch revert ' +
'unchecked ' +
//NOTE: doesn't always act as a keyword, but seems fine to include
'_ ' +
'function modifier event constructor fallback receive error ' +
'virtual override ' +
'constant immutable anonymous indexed ' +
'storage memory calldata ' +
'external public internal payable pure view private returns ' +
'import from as using pragma ' +
'contract interface library is abstract ' +
'assembly',
literal:
'true false ' +
'wei gwei szabo finney ether ' +
'seconds minutes hours days weeks years',
built_in:
'self ' + // :NOTE: not a real keyword, but a convention used in storage manipulation libraries
'this super selfdestruct suicide ' +
'now ' +
'msg block tx abi ' +
'type ' +
'blockhash gasleft ' +
'assert require ' +
'Error Panic ' +
'sha3 sha256 keccak256 ripemd160 ecrecover addmod mulmod ' +
'log0 log1 log2 log3 log4' +
// :NOTE: not really toplevel, but advantageous to have highlighted as if reserved to
// avoid newcomers making mistakes due to accidental name collisions.
'send transfer call callcode delegatecall staticcall '
};
var SOL_ASSEMBLY_KEYWORDS = {
keyword:
'assembly ' +
'let function ' +
'if switch case default for leave ' +
'break continue ' +
'u256 ' + //not in old-style assembly, but in Yul
//NOTE: We're counting most opcodes as builtins, but the following ones we're
//treating as keywords because they alter control flow or halt execution
'jump jumpi ' +
'stop return revert selfdestruct invalid',
built_in:
//NOTE that push1 through push32, as well as jumpdest, are not included
'add sub mul div sdiv mod smod exp not lt gt slt sgt eq iszero ' +
'and or xor byte shl shr sar ' +
'addmod mulmod signextend keccak256 ' +
'pc pop ' +
'dup1 dup2 dup3 dup4 dup5 dup6 dup7 dup8 dup9 dup10 dup11 dup12 dup13 dup14 dup15 dup16 ' +
'swap1 swap2 swap3 swap4 swap5 swap6 swap7 swap8 swap9 swap10 swap11 swap12 swap13 swap14 swap15 swap16 ' +
'mload mstore mstore8 sload sstore msize ' +
'gas address balance selfbalance caller callvalue ' +
'calldataload calldatasize calldatacopy codesize codecopy extcodesize extcodecopy returndatasize returndatacopy extcodehash ' +
'create create2 call callcode delegatecall staticcall ' +
'log0 log1 log2 log3 log4 ' +
'chainid origin gasprice blockhash coinbase timestamp number difficulty gaslimit',
literal:
'true false'
};
//covers the special slot/offset notation in assembly
//(old-style, with an underscore)
var SOL_ASSEMBLY_MEMBERS_OLD = {
begin: /_/,
end: /[^A-Za-z0-9$.]/,
excludeBegin: true,
excludeEnd: true,
keywords: {
built_in: 'slot offset'
},
relevance: 2,
};
//covers the special slot/offset notation in assembly
//(new-style, with a dot; keeping this separate as it
//may be expanded in the future)
var SOL_ASSEMBLY_MEMBERS = {
begin: /\./,
end: /[^A-Za-z0-9$.]/,
excludeBegin: true,
excludeEnd: true,
keywords: {
built_in: 'slot offset length'
},
relevance: 2,
};
function isNegativeLookbehindAvailable() {
try {
new RegExp('(?<!.)');
return true;
} catch (_) {
return false;
}
}
//like a C number, except:
//1. no octal literals (leading zeroes disallowed)
//2. underscores (1 apiece) are allowed between consecutive digits
//(including hex digits)
//also, all instances of \b (word boundary) have been replaced with (?<!\$)\b
//NOTE: we use string rather than regexp in the case where negative lookbehind
//is allowed to avoid Firefox parse errors; sorry about the resulting double backslashes!
if (isNegativeLookbehindAvailable()) {
var SOL_NUMBER_RE = '-?((?<!\\$)\\b0[xX]([a-fA-F0-9]_?)*[a-fA-F0-9]|((?<!\\$)\\b[1-9](_?\\d)*(\\.((\\d_?)*\\d)?)?|\\.\\d(_?\\d)*)([eE][-+]?\\d(_?\\d)*)?|(?<!\\$)\\b0)';
} else {
var SOL_NUMBER_RE = /-?(\b0[xX]([a-fA-F0-9]_?)*[a-fA-F0-9]|(\b[1-9](_?\d)*(\.((\d_?)*\d)?)?|\.\d(_?\d)*)([eE][-+]?\d(_?\d)*)?|\b0)/;
}
var SOL_NUMBER = {
className: 'number',
begin: SOL_NUMBER_RE,
relevance: 0,
};
var HEX_APOS_STRING_MODE = {
className: 'string',
begin: /\bhex'(([0-9a-fA-F]{2}_?)*[0-9a-fA-F]{2})?'/, //please also update HEX_QUOTE_STRING_MODE
};
var HEX_QUOTE_STRING_MODE = {
className: 'string',
begin: /\bhex"(([0-9a-fA-F]{2}_?)*[0-9a-fA-F]{2})?"/, //please also update HEX_APOS_STRING_MODE
};
//I've set these up exactly like hljs's builtin STRING_MODEs,
//except with the optional initial "unicode" text
var SOL_APOS_STRING_MODE = hljs.inherit(hljs.APOS_STRING_MODE, //please also update SOL_QUOTE_STRING_MODE
{ begin: /\b(unicode)?'/ }
);
var SOL_QUOTE_STRING_MODE = hljs.inherit(hljs.QUOTE_STRING_MODE, //please also update SOL_APOS_STRING_MODE
{ begin: /\b(unicode)?"/ }
);
var SOL_FUNC_PARAMS = {
className: 'params',
begin: /\(/, end: /\)/,
excludeBegin: true,
excludeEnd: true,
keywords: SOL_KEYWORDS,
contains: [
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
SOL_APOS_STRING_MODE,
SOL_QUOTE_STRING_MODE,
SOL_NUMBER,
'self' //to account for mappings and fn variables
]
};
//NOTE: including "*" as a "lexeme" because we use it as a "keyword" below
var SOL_LEXEMES_RE = /[A-Za-z_$][A-Za-z_$0-9]*|\*/;
//in assembly, identifiers can contain periods (but may not start with them)
var SOL_ASSEMBLY_LEXEMES_RE = /[A-Za-z_$][A-Za-z_$0-9.]*/;
var SOL_RESERVED_MEMBERS = {
begin: /\.\s*/, // match any property access up to start of prop
end: /[^A-Za-z0-9$_\.]/,
excludeBegin: true,
excludeEnd: true,
keywords: {
built_in: 'gas value selector address length push pop ' +
'send transfer call callcode delegatecall staticcall ' +
'balance code codehash ' +
'name creationCode runtimeCode interfaceId min max'
},
relevance: 2,
};
var SOL_TITLE_MODE =
hljs.inherit(hljs.TITLE_MODE, {
begin: /[A-Za-z$_][0-9A-Za-z$_]*/,
lexemes: SOL_LEXEMES_RE,
keywords: SOL_KEYWORDS,
});
//special parameters (note: these aren't really handled properly, but this seems like the best compromise for now)
var SOL_SPECIAL_PARAMETERS_LIST = ['gas', 'value', 'salt'];
var SOL_SPECIAL_PARAMETERS_PARTIAL_RE = '(' + SOL_SPECIAL_PARAMETERS_LIST.join('|') + '):';
var SOL_SPECIAL_PARAMETERS = {
className: 'built_in',
begin: (isNegativeLookbehindAvailable() ? '(?<!\\$)\\b' : '\\b') + SOL_SPECIAL_PARAMETERS_PARTIAL_RE
};
function makeBuiltinProps(obj, props) {
return {
begin: (isNegativeLookbehindAvailable() ? '(?<!\\$)\\b' : '\\b') + obj + '\\.\\s*',
end: /[^A-Za-z0-9$_\.]/,
excludeBegin: false,
excludeEnd: true,
lexemes: SOL_LEXEMES_RE,
keywords: {
built_in: obj + ' ' + props,
},
contains: [
SOL_RESERVED_MEMBERS
],
relevance: 10,
};
}
return {
aliases: ['sol'],
keywords: SOL_KEYWORDS,
lexemes: SOL_LEXEMES_RE,
contains: [
// basic literal definitions
SOL_APOS_STRING_MODE,
SOL_QUOTE_STRING_MODE,
HEX_APOS_STRING_MODE,
HEX_QUOTE_STRING_MODE,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
SOL_NUMBER,
SOL_SPECIAL_PARAMETERS,
{ // functions
className: 'function',
lexemes: SOL_LEXEMES_RE,
beginKeywords: 'function modifier event constructor fallback receive error', end: /[{;]/, excludeEnd: true,
contains: [
SOL_TITLE_MODE,
SOL_FUNC_PARAMS,
SOL_SPECIAL_PARAMETERS,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
],
illegal: /%/,
},
// built-in members
makeBuiltinProps('msg', 'gas value data sender sig'),
makeBuiltinProps('block', 'blockhash coinbase difficulty gaslimit number timestamp chainid'),
makeBuiltinProps('tx', 'gasprice origin'),
makeBuiltinProps('abi', 'decode encode encodePacked encodeWithSelector encodeWithSignature'),
makeBuiltinProps('bytes', 'concat'),
SOL_RESERVED_MEMBERS,
{ // contracts & libraries & interfaces
className: 'class',
lexemes: SOL_LEXEMES_RE,
beginKeywords: 'contract interface library', end: '{', excludeEnd: true,
illegal: /[:"\[\]]/,
contains: [
{ beginKeywords: 'is', lexemes: SOL_LEXEMES_RE },
SOL_TITLE_MODE,
SOL_FUNC_PARAMS,
SOL_SPECIAL_PARAMETERS,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
},
{ // structs & enums
lexemes: SOL_LEXEMES_RE,
beginKeywords: 'struct enum', end: '{', excludeEnd: true,
illegal: /[:"\[\]]/,
contains: [
SOL_TITLE_MODE,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
},
{ // imports
beginKeywords: 'import', end: ';',
lexemes: SOL_LEXEMES_RE,
keywords: 'import * from as',
contains: [
SOL_TITLE_MODE,
SOL_APOS_STRING_MODE,
SOL_QUOTE_STRING_MODE,
HEX_APOS_STRING_MODE,
HEX_QUOTE_STRING_MODE,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
},
{ // using
beginKeywords: 'using', end: ';',
lexemes: SOL_LEXEMES_RE,
keywords: 'using * for',
contains: [
SOL_TITLE_MODE,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE
]
},
{ // pragmas
className: 'meta',
beginKeywords: 'pragma', end: ';',
lexemes: SOL_LEXEMES_RE,
keywords: {
keyword: 'pragma solidity experimental abicoder',
built_in: 'ABIEncoderV2 SMTChecker v1 v2'
},
contains: [
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
hljs.inherit(SOL_APOS_STRING_MODE, { className: 'meta-string' }),
hljs.inherit(SOL_QUOTE_STRING_MODE, { className: 'meta-string' })
]
},
{ //assembly section
beginKeywords: 'assembly',
end: /\b\B/, //unsatisfiable regex; ended by endsParent instead
contains: [
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
{ //the actual *block* in the assembly section
begin: '{', end: '}',
endsParent: true,
keywords: SOL_ASSEMBLY_KEYWORDS,
lexemes: SOL_ASSEMBLY_LEXEMES_RE,
contains: [
SOL_APOS_STRING_MODE,
SOL_QUOTE_STRING_MODE,
HEX_APOS_STRING_MODE,
HEX_QUOTE_STRING_MODE,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
SOL_NUMBER,
SOL_ASSEMBLY_MEMBERS,
SOL_ASSEMBLY_MEMBERS_OLD,
{ //block within assembly; note the lack of endsParent
begin: '{', end: '}',
keywords: SOL_ASSEMBLY_KEYWORDS,
lexemes: SOL_ASSEMBLY_LEXEMES_RE,
contains: [
SOL_APOS_STRING_MODE,
SOL_QUOTE_STRING_MODE,
HEX_APOS_STRING_MODE,
HEX_QUOTE_STRING_MODE,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
SOL_NUMBER,
SOL_ASSEMBLY_MEMBERS,
SOL_ASSEMBLY_MEMBERS_OLD,
'self'
]
}
]
}
]
}
],
illegal: /#/
};
}
module.exports = function(hljs) {
hljs.registerLanguage('solidity', hljsDefineSolidity);
};
module.exports.definer = hljsDefineSolidity;