vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

pony.lua

(3887B)


      1 -- Copyright 2017-2025 Murray Calavera. See LICENSE.
      2 -- Pony LPeg lexer.
      3 
      4 local lexer = require('lexer')
      5 local token, word_match = lexer.token, lexer.word_match
      6 local P, S = lpeg.P, lpeg.S
      7 
      8 local lex = lexer.new('pony')
      9 
     10 -- Whitespace.
     11 local ws = token(lexer.WHITESPACE, lexer.space^1)
     12 lex:add_rule('whitespace', ws)
     13 
     14 -- Capabilities.
     15 local capability = token(lexer.LABEL, word_match('box iso ref tag trn val'))
     16 lex:add_rule('capability', capability)
     17 
     18 -- Annotations.
     19 local annotation = token(lexer.PREPROCESSOR, lexer.range('\\', false, false))
     20 lex:add_rule('annotation', annotation)
     21 
     22 -- Functions.
     23 -- Highlight functions with syntax sugar at declaration.
     24 lex:add_rule('function',
     25 	token(lexer.KEYWORD, word_match('fun new be')) * ws^-1 * annotation^-1 * ws^-1 * capability^-1 *
     26 		ws^-1 * token(lexer.FUNCTION, word_match{
     27 		'create', 'dispose', '_final', 'apply', 'update', 'add', 'sub', 'mul', 'div', 'mod',
     28 		'add_unsafe', 'sub_unsafe', 'mul_unsafe', 'div_unsafe', 'mod_unsafe', 'shl', 'shr',
     29 		'shl_unsafe', 'shr_unsafe', 'op_and', 'op_or', 'op_xor', 'eq', 'ne', 'lt', 'le', 'ge', 'gt',
     30 		'eq_unsafe', 'ne_unsafe', 'lt_unsafe', 'le_unsafe', 'ge_unsafe', 'gt_unsafe', 'neg',
     31 		'neg_unsafe', 'op_not', --
     32 		'has_next', 'next', --
     33 		'_serialise_space', '_serialise', '_deserialise'
     34 	}))
     35 
     36 -- Keywords.
     37 lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
     38 	'actor', 'as', 'be', 'break', 'class', 'compile_error', 'compile_intrinsic', 'continue',
     39 	'consume', 'do', 'else', 'elseif', 'embed', 'end', 'error', 'for', 'fun', 'if', 'ifdef', 'iftype',
     40 	'in', 'interface', 'is', 'isnt', 'lambda', 'let', 'match', 'new', 'object', 'primitive',
     41 	'recover', 'repeat', 'return', 'struct', 'then', 'this', 'trait', 'try', 'type', 'until', 'use',
     42 	'var', 'where', 'while', 'with'
     43 }))
     44 
     45 -- Constants.
     46 lex:add_rule('constant', token(lexer.CONSTANT, word_match('true false')))
     47 
     48 -- Operators.
     49 local ops = {
     50 	['+'] = true, ['-'] = true, ['*'] = true, ['/'] = true, ['%'] = true, ['+~'] = true,
     51 	['-~'] = true, ['*~'] = true, ['/~'] = true, ['%~'] = true, ['<<'] = true, ['>>'] = true,
     52 	['<<~'] = true, ['>>~'] = true, ['=='] = true, ['!='] = true, ['<'] = true, ['<='] = true,
     53 	['>='] = true, ['>'] = true, ['==~'] = true, ['!=~'] = true, ['<~'] = true, ['<=~'] = true,
     54 	['>=~'] = true, ['>~'] = true
     55 }
     56 lex:add_rule('operator', token(lexer.OPERATOR, word_match('and or xor not addressof digestof') +
     57 	lpeg.Cmt(S('+-*/%<>=!~')^1, function(input, index, op) return ops[op] and index or nil end)))
     58 
     59 -- Identifiers.
     60 local id_suffix = (lexer.alnum + "'" + '_')^0
     61 lex:add_rule('type', token(lexer.TYPE, P('_')^-1 * lexer.upper * id_suffix))
     62 lex:add_rule('identifier', token(lexer.IDENTIFIER, P('_')^-1 * lexer.lower * id_suffix))
     63 lex:add_rule('lookup', token(lexer.IDENTIFIER, '_' * lexer.digit^1))
     64 
     65 -- Strings.
     66 local sq_str = lexer.range("'")
     67 local dq_str = lexer.range('"')
     68 local tq_str = lexer.range('"""')
     69 lex:add_rule('string', token(lexer.STRING, sq_str + tq_str + dq_str))
     70 
     71 -- Numbers.
     72 local function num(digit) return digit * (digit^0 * '_')^0 * digit^1 + digit end
     73 local int = num(lexer.digit)
     74 local frac = '.' * int
     75 local exp = S('eE') * (P('-') + '+')^-1 * int
     76 local hex = '0x' * num(lexer.xdigit)
     77 local bin = '0b' * num(S('01'))
     78 local float = int * frac^-1 * exp^-1
     79 lex:add_rule('number', token(lexer.NUMBER, hex + bin + float))
     80 
     81 -- Comments.
     82 local line_comment = lexer.to_eol('//')
     83 local block_comment = lexer.range('/*', '*/', false, false, true)
     84 lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment))
     85 
     86 -- Punctuation.
     87 -- There is no suitable token name for this, change this if ever one is added.
     88 lex:add_rule('punctuation',
     89 	token(lexer.OPERATOR, P('=>') + '.>' + '<:' + '->' + S('=.,:;()[]{}!?~^&|_@')))
     90 
     91 -- Qualifiers.
     92 lex:add_rule('qualifier', token(lexer.LABEL, '#' * word_match('read send share any alias')))
     93 
     94 lexer.property['scintillua.comment'] = '//'
     95 
     96 return lex