-- KDL LPeg lexer for vis. -- Covers: // and /* */ comments, slashdash /-, quoted and raw strings, -- type annotations (type), keywords, numbers, node/property identifiers. local lexer = lexer local P, S = lpeg.P, lpeg.S local lex = lexer.new(..., {fold_by_indentation = true}) -- Comments. local line_comment = lexer.to_eol('//') local block_comment = lexer.range('/*', '*/', false, false, true) lex:add_rule('comment', lex:tag(lexer.COMMENT, line_comment + block_comment)) -- Slashdash node suppression. lex:add_rule('slashdash', lex:tag(lexer.OPERATOR, P('/-'))) -- Keywords. lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lexer.word_match({'true', 'false', 'null'}))) -- Strings: raw #"..."# first so the hash prefixes are not split off, -- then regular "..." strings. local raw_str = lexer.range(P('#')^1 * '"', '"' * P('#')^1) local dq_str = lexer.range('"') lex:add_rule('string', lex:tag(lexer.STRING, raw_str + dq_str)) -- Type annotations like (path)file or (const). local type_ann = P('(') * lexer.word * P(')') lex:add_rule('type', lex:tag(lexer.TYPE, type_ann)) -- Numbers (int/float/hex/oct/bin; underscores are tolerated inside). local num_pattern = (lexer.number * (S('_')^0 * lexer.number)^0) + '0x' * (lpeg.R('09') + lpeg.R('af') + lpeg.R('AF') + '_')^1 + '0o' * lpeg.R('07')^1 + '0b' * lpeg.R('01')^1 lex:add_rule('number', lex:tag(lexer.NUMBER, num_pattern)) -- Identifiers (node names, property keys). lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word)) -- Operators / punctuation. lex:add_rule('operator', lex:tag(lexer.OPERATOR, S('{}()=;,/+\\'))) lexer.property['scintillua.comment'] = '//' return lex