vis

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

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

snobol4.lua

(2589B)


      1 -- Copyright 2013-2025 Michael T. Richter. See LICENSE.
      2 -- SNOBOL4 lexer.
      3 -- This lexer works with classic SNOBOL4 as well as the CSNOBOL4 extensions.
      4 
      5 local lexer = require('lexer')
      6 local token, word_match = lexer.token, lexer.word_match
      7 local B, P, S = lpeg.B, lpeg.P, lpeg.S
      8 
      9 local lex = lexer.new('snobol4')
     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 	'ABORT', 'ARRAY', 'CONTINUE', 'DEFINE', 'END', 'FRETURN', 'INPUT', 'NRETURN', 'OUTPUT', 'PUNCH',
     17 	'RETURN', 'SCONTINUE', 'TABLE'
     18 }, true) + '&' * lexer.word))
     19 
     20 -- Helper patterns.
     21 local dotted_id = lexer.word * ('.' * lexer.word)^0
     22 
     23 -- Labels.
     24 lex:add_rule('label', token(lexer.LABEL, lexer.starts_line(dotted_id)))
     25 
     26 -- Targets.
     27 local branch = B(lexer.space * ':(') * dotted_id * #P(')')
     28 local sbranch = B(lexer.space * ':' * S('SsFf') * '(') * dotted_id * #P(')')
     29 local sbranchx = B(')' * S('SsFf') * '(') * dotted_id * #P(')')
     30 lex:add_rule('target', token(lexer.LABEL, branch + sbranch + sbranchx))
     31 
     32 -- Patterns.
     33 lex:add_rule('pattern', lexer.token(lexer.CLASS, word_match({
     34 	-- Keep distinct.
     35 	'ABORT', 'ANY', 'ARB', 'ARBNO', 'BAL', 'BREAK', 'BREAKX', 'FAIL', 'FENCE', 'LEN', 'NOTANY', 'POS',
     36 	'REM', 'RPOS', 'RTAB', 'SPAN', 'SUCCEED', 'TAB'
     37 }, true) * #P('(')))
     38 
     39 -- Token definitions.
     40 lex:add_rule('built-in', token(lexer.FUNCTION, word_match({
     41 	'APPLY', 'ARRAY', 'CHAR', 'CONVERT', 'COPY', 'DATA', 'DATE', 'DIFFER', 'DUPL', 'EQ', 'EVAL',
     42 	'FILE_ABSPATH', 'FILE_ISDIR', 'FREEZE', 'FUNCTION', 'GE', 'GT', 'HOST', 'IDENT', 'INTEGER',
     43 	'IO_FINDUNIT', 'ITEM', 'LABEL', 'LOAD', 'LPAD', 'LE', 'LGT', 'LT', 'NE', 'OPSYN', 'ORD',
     44 	'PROTOTYPE', 'REMDR', 'REPLACE', 'REVERSE', 'RPAD', 'RSORT', 'SERV_LISTEN', 'SET', 'SETEXIT',
     45 	'SIZE', 'SORT', 'SQRT', 'SSET', 'SUBSTR', 'TABLE', 'THAW', 'TIME', 'TRACE', 'TRIM', 'UNLOAD',
     46 	'VALUE', 'VDIFFER'
     47 }, true) * #P('(')))
     48 
     49 -- Identifiers.
     50 lex:add_rule('identifier', token(lexer.DEFAULT, dotted_id))
     51 
     52 -- Strings.
     53 local dq_str = lexer.range('"', true, false)
     54 local sq_str = lexer.range("'", true, false)
     55 lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
     56 
     57 -- Comments.
     58 lex:add_rule('comment', token(lexer.COMMENT, lexer.starts_line(lexer.to_eol(S('*#|;!')))))
     59 
     60 -- Numbers.
     61 lex:add_rule('number', token(lexer.NUMBER, lexer.number))
     62 
     63 -- Control.
     64 lex:add_rule('control', token(lexer.PREPROCESSOR, lexer.starts_line('-' * lexer.word)))
     65 
     66 -- Operators.
     67 lex:add_rule('operator', token(lexer.OPERATOR, S'¬?$.!%*/#+-@⊥&^~\\='))
     68 
     69 lexer.property['scintillua.comment'] = '#'
     70 
     71 return lex