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