vis

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

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

scheme.lua

(8120B)


      1 -- Copyright 2006-2025 Mitchell. See LICENSE.
      2 -- Scheme LPeg lexer.
      3 -- Contributions by Murray Calavera.
      4 
      5 local lexer = require('lexer')
      6 local token, word_match = lexer.token, lexer.word_match
      7 local P, S = lpeg.P, lpeg.S
      8 
      9 local lex = lexer.new('scheme')
     10 
     11 -- Whitespace.
     12 lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
     13 
     14 -- Keywords.
     15 lex:add_rule('keyword', token(lexer.KEYWORD, word_match{
     16 	'and', 'or', 'not', 'else',
     17 	--
     18 	'library', 'define-library', 'export', 'include-library-declarations', 'cond-expand', 'import',
     19 	'rename', 'only', 'except', 'prefix', 'include', 'include-ci',
     20 	--
     21 	'begin', 'case', 'case-lambda', 'cond', 'define', 'define-record-type', 'define-syntax',
     22 	'define-values', 'delay', 'delay-force', 'do', 'if', 'guard', 'lambda', 'let', 'let*',
     23 	'let*-values', 'let-syntax', 'let-values', 'letrec', 'letrec*', 'letrec-syntax', 'parameterize',
     24 	'quasiquote', 'quote', 'set!', 'unless', 'unquote', 'unquote-splicing', 'when',
     25 	--
     26 	'define-macro', 'fluid-let'
     27 }))
     28 
     29 -- Functions.
     30 lex:add_rule('function', token(lexer.FUNCTION, word_match{
     31 	'*', '+', '-', '/', '<', '<=', '=', '=>', '>', '>=', 'abs', 'append', 'apply', 'assoc', 'assq',
     32 	'assv', 'binary-port?', 'boolean=?', 'boolean?', 'bytevector', 'bytevector-append',
     33 	'bytevector-copy', 'bytevector-copy!', 'bytevector-length', 'bytevector-u8-ref',
     34 	'bytevector-u8-set!', 'bytevector?', 'caar', 'cadr', 'call-with-current-continuation',
     35 	'call-with-port', 'call-with-values', 'call/cc', 'car', 'cdar', 'cddr', 'cdr', 'ceiling',
     36 	'char->integer', 'char-ready?', 'char<=?', 'char<?', 'char=?', 'char>=?', 'char>?', 'char?',
     37 	'close-input-port', 'close-output-port', 'close-port', 'complex?', 'cons', 'current-error-port',
     38 	'current-input-port', 'current-output-port', 'denominator', 'dynamic-wind', 'eof-object',
     39 	'eof-object?', 'eq?', 'equal?', 'eqv?', 'error', 'error-object-irritants', 'error-object-message',
     40 	'error-object?', 'even?', 'exact', 'exact-integer-sqrt', 'exact-integer?', 'exact?', 'expt',
     41 	'features', 'file-error?', 'floor', 'floor-quotient', 'floor-remainder', 'floor/',
     42 	'flush-output-port', 'for-each', 'gcd', 'get-output-bytevector', 'get-output-string', 'inexact',
     43 	'inexact?', 'input-port-open?', 'input-port?', 'integer->char', 'integer?', 'lcm', 'length',
     44 	'list', 'list->string', 'list->vector', 'list-copy', 'list-ref', 'list-set!', 'list-tail',
     45 	'list?', 'make-bytevector', 'make-list', 'make-parameter', 'make-string', 'make-vector', 'map',
     46 	'max', 'member', 'memq', 'memv', 'min', 'modulo', 'negative?', 'newline', 'null?',
     47 	'number->string', 'number?', 'numerator', 'odd?', 'open-input-bytevector', 'open-input-string',
     48 	'open-output-bytevector', 'open-output-string', 'output-port-open?', 'output-port?', 'pair?',
     49 	'peek-char', 'peek-u8', 'port?', 'positive?', 'procedure?', 'quotient', 'raise',
     50 	'raise-continuable', 'rational?', 'rationalize', 'read-bytevector', 'read-bytevector!',
     51 	'read-char', 'read-error?', 'read-line', 'read-string', 'read-u8', 'real?', 'remainder',
     52 	'reverse', 'round', 'set-car!', 'set-cdr!', 'square', 'string', 'string->list', 'string->number',
     53 	'string->symbol', 'string->utf8', 'string->vector', 'string-append', 'string-copy',
     54 	'string-copy!', 'string-fill!', 'string-for-each', 'string-length', 'string-map', 'string-ref',
     55 	'string-set!', 'string<=?', 'string<?', 'string=?', 'string>=?', 'string>?', 'string?',
     56 	'substring', 'symbol->string', 'symbol=?', 'symbol?', 'syntax-error', 'syntax-rules',
     57 	'textual-port?', 'truncate', 'truncate-quotient', 'truncate-remainder', 'truncate/', 'u8-ready?',
     58 	'utf8->string', 'values', 'vector', 'vector->list', 'vector->string', 'vector-append',
     59 	'vector-copy', 'vector-copy!', 'vector-fill!', 'vector-for-each', 'vector-length', 'vector-map',
     60 	'vector-ref', 'vector-set!', 'vector?', 'with-exception-handler', 'write-bytevector',
     61 	'write-char', 'write-string', 'write-u8', 'zero?',
     62 	--
     63 	'char-alphabetic?', 'char-ci<=?', 'char-ci<?', 'char-ci=?', 'char-ci>=?', 'char-ci>?',
     64 	'char-downcase', 'char-foldcase', 'char-lower-case?', 'char-numeric?', 'char-upcase',
     65 	'char-upper-case?', 'char-whitespace?', 'digit-value', 'string-ci<=?', 'string-ci<?',
     66 	'string-ci=?', 'string-ci>=?', 'string-ci>?', 'string-downcase', 'string-foldcase',
     67 	'string-upcase',
     68 	--
     69 	'angle', 'imag-part', 'magnitude', 'make-polar', 'make-rectangular', 'real-part',
     70 	--
     71 	'caaaar', 'caaadr', 'caaar', 'caadar', 'caaddr', 'caadr', 'cadaar', 'cadadr', 'cadar', 'caddar',
     72 	'cadddr', 'caddr', 'cdaaar', 'cdaadr', 'cdaar', 'cdadar', 'cdaddr', 'cdadr', 'cddaar', 'cddadr',
     73 	'cddar', 'cdddar', 'cddddr', 'cdddr',
     74 	--
     75 	'environment', 'eval',
     76 	--
     77 	'call-with-input-file', 'call-with-output-file', 'delete-file', 'file-exists?',
     78 	'open-binary-input-file', 'open-binary-output-file', 'open-input-file', 'open-output-file',
     79 	'with-input-from-file', 'with-output-to-file',
     80 	--
     81 	'acos', 'asin', 'atan', 'cos', 'exp', 'finite?', 'infinite?', 'log', 'nan?', 'sin', 'sqrt', 'tan',
     82 	--
     83 	'force', 'make-promise', 'promise?',
     84 	--
     85 	'load',
     86 	--
     87 	'command-line', 'emergency-exit', 'exit', 'get-environment-variable', 'get-environment-variables',
     88 	--
     89 	'read',
     90 	--
     91 	'interaction-environment',
     92 	--
     93 	'current-jiffy', 'current-second', 'jiffies-per-second',
     94 	--
     95 	'display', 'write', 'write-shared', 'write-simple',
     96 	--
     97 	'syntax-case', 'er-macro-transformer', 'sc-macro-transformer', 'rsc-macro-transformer'
     98 }))
     99 
    100 -- Identifiers and symbols.
    101 local explicit_sign = S('+-')
    102 local initial = lexer.alpha + S('!$%&*/:<=>?@^_~')
    103 local subsequent = initial + lexer.digit + explicit_sign + '.'
    104 local sign_subsequent = initial + explicit_sign
    105 local dot_subsequent = sign_subsequent + '.'
    106 -- LuaFormatter off
    107 local peculiar_identifier =
    108   explicit_sign * '.' * dot_subsequent * subsequent^0 +
    109   explicit_sign * sign_subsequent * subsequent^0 +
    110   '.' * dot_subsequent * subsequent^0 +
    111   explicit_sign
    112 -- LuaFormatter on
    113 local ident = lexer.range('|') + initial * subsequent^0 + peculiar_identifier
    114 lex:add_rule('identifier', token(lexer.IDENTIFIER, ident))
    115 lex:add_rule('symbol', token(lexer.CLASS, "'" * ident))
    116 
    117 -- Strings.
    118 local character = '#\\' *
    119 	(word_match('alarm backspace delete escape newline null return space tab') + 'x' * lexer.xdigit^1 +
    120 		lexer.any)
    121 local dq_str = lexer.range('"')
    122 lex:add_rule('string', token(lexer.STRING, character + dq_str))
    123 
    124 -- Constants.
    125 lex:add_rule('constant', token(lexer.CONSTANT, word_match('#t #f #true #false')))
    126 
    127 -- Directives.
    128 lex:add_rule('directive', token(lexer.PREPROCESSOR, P('#!fold-case') + '#!no-fold-case'))
    129 
    130 -- Comments.
    131 local line_comment = lexer.to_eol(';')
    132 local block_comment = lexer.range('#|', '|#', false, false, true)
    133 local datum_comment = '#;' * lexer.space^0 * lexer.range('(', ')', false, true, true) *
    134 	(lexer.any - lexer.space)^0
    135 lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment + datum_comment))
    136 
    137 -- Numbers.
    138 local radixes = {[2] = P('#b'), [8] = P('#o'), [10] = P('#d')^-1, [16] = P('#x')}
    139 local digits = {[2] = S('01'), [8] = lpeg.R('07'), [10] = lexer.digit, [16] = lexer.xdigit}
    140 local function num(r)
    141 	local exactness = (P('#i') + '#e')^-1
    142 	local radix, digit = radixes[r], digits[r]
    143 	local prefix = radix * exactness + exactness * radix
    144 	local suffix = ('e' * S('+-')^-1 * lexer.digit^1)^-1
    145 	local infnan = S('+-') * word_match[[inf nan]] * '.0'
    146 	-- LuaFormatter off
    147   local decimal = lexer.digit^1 * suffix +
    148     '.' * lexer.digit^1 * suffix +
    149     lexer.digit^1 * '.' * lexer.digit^0 * suffix
    150   local ureal = digit^1 * '/' * digit^1 +
    151     (r == 10 and decimal or P(false)) +
    152     digit^1
    153   local real = S('+-')^-1 * ureal + infnan
    154   local i = P('i')
    155   local complex = real * '@' * real +
    156     real * S('+-') * ureal^-1 * i +
    157     real * infnan * i +
    158     infnan * i +
    159     real +
    160     S('+-') * ureal^-1 * i
    161   -- LuaFormatter on
    162 	return prefix * complex
    163 end
    164 lex:add_rule('number', token(lexer.NUMBER, num(2) + num(8) + num(10) + num(16)))
    165 
    166 -- Operators.
    167 lex:add_rule('operator', token(lexer.OPERATOR, P('#u8') + ',@' + S(".`'#(),")))
    168 
    169 -- Fold points.
    170 lex:add_fold_point(lexer.OPERATOR, '(', ')')
    171 lex:add_fold_point(lexer.COMMENT, '#|', '|#')
    172 
    173 lexer.property['scintillua.comment'] = ';'
    174 
    175 return lex