-- Copyright 2006-2011 Mitchell mitchell<att>caladbolg.net. See LICENSE.
-- Tcl LPeg lexer.

local l = lexer
local token, style, color, word_match = l.token, l.style, l.color, l.word_match
local P, R, S = l.lpeg.P, l.lpeg.R, l.lpeg.S

module(...)

-- Whitespace.
local ws = token(l.WHITESPACE, l.space^1)

-- Comments.
local comment = token(l.COMMENT, '#' * P(function(input, index)
  local i = index - 2
  while i > 0 and input:find('^[ \t]', i) do i = i - 1 end
  if i < 1 or input:find('^[\r\n;]', i) then return index end
end) * l.nonnewline^0)

-- Strings.
local sq_str = l.delimited_range("'", '\\', true, false, '\n')
local dq_str = l.delimited_range('"', '\\', true, false, '\n')
local regex = l.delimited_range('/', '\\', false, false, '\n')
local string = token(l.STRING, sq_str + dq_str + regex)

-- Numbers.
local number = token(l.NUMBER, l.float + l.integer)

-- Keywords.
local keyword = token(l.KEYWORD, word_match {
  'string', 'subst', 'regexp', 'regsub', 'scan', 'format', 'binary', 'list',
  'split', 'join', 'concat', 'llength', 'lrange', 'lsearch', 'lreplace',
  'lindex', 'lsort', 'linsert', 'lrepeat', 'dict', 'if', 'else', 'elseif',
  'then', 'for', 'foreach', 'switch', 'case', 'while', 'continue', 'return',
  'break', 'catch', 'error', 'eval', 'uplevel', 'after', 'update', 'vwait',
  'proc', 'rename', 'set', 'lset', 'lassign', 'unset', 'namespace', 'variable',
  'upvar', 'global', 'trace', 'array', 'incr', 'append', 'lappend', 'expr',
  'file', 'open', 'close', 'socket', 'fconfigure', 'puts', 'gets', 'read',
  'seek', 'tell', 'eof', 'flush', 'fblocked', 'fcopy', 'fileevent', 'source',
  'load', 'unload', 'package', 'info', 'interp', 'history', 'bgerror',
  'unknown', 'memory', 'cd', 'pwd', 'clock', 'time', 'exec', 'glob', 'pid',
  'exit'
})

-- Identifiers.
local identifier = token(l.IDENTIFIER, l.word)

-- Variables.
local variable = token(l.VARIABLE, S('$@') * P('$')^-1 * l.word)

-- Operators.
local operator = token(l.OPERATOR, S('<>=+-*/!@|&.,:;?()[]{}'))

_rules = {
  { 'whitespace', ws },
  { 'keyword', keyword },
  { 'identifier', identifier },
  { 'string', string },
  { 'comment', comment },
  { 'number', number },
  { 'variable', variable },
  { 'operator', operator },
  { 'any_char', l.any_char },
}

_foldsymbols = {
  _patterns = { '[{}]', '#' },
  [l.OPERATOR] = { ['{'] = 1, ['}'] = -1 },
  [l.COMMENT] = { ['#'] = l.fold_line_comments('#') }
}
