1-- Copyright 2006-2021 Mitchell. See LICENSE.
2-- D LPeg lexer.
3-- Heavily modified by Brian Schott (@Hackerpilot on Github).
4
5local lexer = require('lexer')
6local token, word_match = lexer.token, lexer.word_match
7local P, S = lpeg.P, lpeg.S
8
9local lex = lexer.new('dmd')
10
11-- Whitespace.
12local ws = token(lexer.WHITESPACE, lexer.space^1)
13lex:add_rule('whitespace', ws)
14
15-- Class names.
16lex:add_rule('class', token(lexer.TYPE, P('class') + 'struct') * ws^-1 *
17  token(lexer.CLASS, lexer.word))
18
19-- Versions.
20local version = word_match[[
21  AArch64 AIX all Alpha Alpha_HardFloat Alpha_SoftFloat Android ARM
22  ARM_HardFloat ARM_SoftFloat ARM_SoftFP ARM_Thumb assert BigEndian BSD Cygwin
23  D_Coverage D_Ddoc D_HardFloat DigitalMars D_InlineAsm_X86 D_InlineAsm_X86_64
24  D_LP64 D_NoBoundsChecks D_PIC DragonFlyBSD D_SIMD D_SoftFloat D_Version2 D_X32
25  FreeBSD GNU Haiku HPPA HPPA64 Hurd IA64 LDC linux LittleEndian MIPS32 MIPS64
26  MIPS_EABI MIPS_HardFloat MIPS_N32 MIPS_N64 MIPS_O32 MIPS_O64 MIPS_SoftFloat
27  NetBSD none OpenBSD OSX Posix PPC PPC64 PPC_HardFloat PPC_SoftFloat S390 S390X
28  SDC SH SH64 SkyOS Solaris SPARC SPARC64 SPARC_HardFloat SPARC_SoftFloat
29  SPARC_V8Plus SysV3 SysV4 unittest Win32 Win64 Windows X86 X86_64
30]]
31lex:add_rule('version', token(lexer.KEYWORD, 'version') * ws^-1 *
32  token(lexer.OPERATOR, '(') * ws^-1 * token('versions', version))
33lex:add_style('versions', lexer.styles.constant)
34
35-- Scopes.
36local scope = word_match('exit success failure')
37lex:add_rule('scope', token(lexer.KEYWORD, 'scope') * ws^-1 *
38  token(lexer.OPERATOR, '(') * ws^-1 * token('scopes', scope))
39lex:add_style('scopes', lexer.styles.constant)
40
41-- Traits.
42local trait = word_match[[
43  allMembers classInstanceSize compiles derivedMembers getAttributes getMember
44  getOverloads getProtection getUnitTests getVirtualFunctions getVirtualIndex
45  getVirtualMethods hasMember identifier isAbstractClass isAbstractFunction
46  isArithmetic isAssociativeArray isFinalClass isFinalFunction isFloating
47  isIntegral isLazy isNested isOut isOverrideFunction isPOD isRef isSame
48  isScalar isStaticArray isStaticFunction isUnsigned isVirtualFunction
49  isVirtualMethod parent
50]]
51lex:add_rule('trait', token(lexer.KEYWORD, '__traits') * ws^-1 *
52  token(lexer.OPERATOR, '(') * ws^-1 * token('traits', trait))
53lex:add_style('traits', {fore = lexer.colors.yellow})
54
55-- Function names.
56lex:add_rule('function', token(lexer.FUNCTION, lexer.word) *
57  #(ws^-1 * ('!' * lexer.word^-1 * ws^-1)^-1 * '('))
58
59-- Keywords.
60lex:add_rule('keyword', token(lexer.KEYWORD, word_match[[
61  abstract align asm assert auto body break case cast catch const continue debug
62  default delete deprecated do else extern export false final finally for
63  foreach foreach_reverse goto if import immutable in inout invariant is lazy
64  macro mixin new nothrow null out override pragma private protected public pure
65  ref return scope shared static super switch synchronized this throwtrue try
66  typeid typeof unittest version virtual volatile while with __gshared __thread
67  __traits __vector __parameters
68]]))
69
70-- Types.
71local type = token(lexer.TYPE, word_match[[
72  alias bool byte cdouble cent cfloat char class creal dchar delegate double
73  enum float function idouble ifloat int interface ireal long module package
74  ptrdiff_t real short size_t struct template typedef ubyte ucent uint ulong
75  union ushort void wchar string wstring dstring hash_t equals_t
76]])
77lex:add_rule('type', type)
78
79-- Constants.
80lex:add_rule('constant', token(lexer.CONSTANT, word_match[[
81  __FILE__ __LINE__ __DATE__ __EOF__ __TIME__ __TIMESTAMP__ __VENDOR__
82  __VERSION__ __FUNCTION__ __PRETTY_FUNCTION__ __MODULE__
83]]))
84
85-- Properties.
86lex:add_rule('property', lpeg.B(lexer.alnum + ')') *
87  token(lexer.OPERATOR, '.') * token(lexer.VARIABLE, word_match[[
88    alignof dig dup epsilon idup im init infinity keys length mangleof mant_dig
89    max max_10_exp max_exp min min_normal min_10_exp min_exp nan offsetof ptr
90    re rehash reverse sizeof sort stringof tupleof values
91  ]]))
92
93-- Strings.
94local sq_str = lexer.range("'", true) * S('cwd')^-1
95local dq_str = lexer.range('"') * S('cwd')^-1
96local lit_str = 'r' * lexer.range('"', false, false) * S('cwd')^-1
97local bt_str = lexer.range('`', false, false) * S('cwd')^-1
98local hex_str = 'x' * lexer.range('"') * S('cwd')^-1
99local other_hex_str = '\\x' * (lexer.xdigit * lexer.xdigit)^1
100local str = sq_str + dq_str + lit_str + bt_str + hex_str + other_hex_str
101for left, right in pairs{['['] = ']', ['('] = ')', ['{'] = '}', ['<'] = '>'} do
102  str = str + lexer.range('q"' .. left, right .. '"', false, false, true) *
103    S('cwd')^-1
104end
105lex:add_rule('string', token(lexer.STRING, str))
106
107-- Identifiers.
108lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
109
110-- Comments.
111local line_comment = lexer.to_eol('//', true)
112local block_comment = lexer.range('/*', '*/')
113local nested_comment = lexer.range('/+', '+/', false, false, true)
114lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment +
115  nested_comment))
116
117-- Numbers.
118local dec = lexer.digit^1 * ('_' * lexer.digit^1)^0
119local hex_num = lexer.hex_num * ('_' * lexer.xdigit^1)^0
120local bin_num = '0' * S('bB') * S('01_')^1
121local oct_num = '0' * S('01234567_')^1
122local integer = S('+-')^-1 * (hex_num + oct_num + bin_num + dec)
123lex:add_rule('number', token(lexer.NUMBER, (lexer.float + integer) *
124  S('uULdDfFi')^-1))
125
126-- Preprocessor.
127lex:add_rule('annotation', token('annotation', '@' * lexer.word^1))
128lex:add_style('annotation', lexer.styles.preprocessor)
129lex:add_rule('preprocessor', token(lexer.PREPROCESSOR, lexer.to_eol('#')))
130
131-- Operators.
132lex:add_rule('operator', token(lexer.OPERATOR, S('?=!<>+-*$/%&|^~.,;:()[]{}')))
133
134-- Fold points.
135lex:add_fold_point(lexer.OPERATOR, '{', '}')
136lex:add_fold_point(lexer.COMMENT, '/*', '*/')
137lex:add_fold_point(lexer.COMMENT, '/+', '+/')
138lex:add_fold_point(lexer.COMMENT, lexer.fold_consecutive_lines('//'))
139
140return lex
141