-- Copyright 2006-2015 Mitchell mitchell.att.foicica.com. See LICENSE.
-- WSF LPeg lexer (based on XML).
-- Contributed by Jeff Stone.
local l = require('lexer')
local token, word_match = l.token, l.word_match
local P, R, S, V = lpeg.P, lpeg.R, lpeg.S, lpeg.V
local M = {_NAME = 'wsf'}
-- Whitespace.
local ws = token(l.WHITESPACE, l.space^1)
-- Comments.
local comment = token(l.COMMENT, '')^0 * P('-->')^-1)
-- Strings.
local sq_str = l.delimited_range("'", false, true)
local dq_str = l.delimited_range('"', false, true)
local string = #S('\'"') * l.last_char_includes('=') *
token(l.STRING, sq_str + dq_str)
local in_tag = P(function(input, index)
local before = input:sub(1, index - 1)
local s, e = before:find('<[^>]-$'), before:find('>[^<]-$')
if s and e then return s > e and index or nil end
if s then return index end
return input:find('^[^<]->', index) and index or nil
end)
-- Numbers.
local number = #l.digit * l.last_char_includes('=') *
token(l.NUMBER, l.digit^1 * P('%')^-1) * in_tag
local alpha = R('az', 'AZ', '\127\255')
local word_char = l.alnum + S('_-:.??')
local identifier = (l.alpha + S('_-:.??')) * word_char^0
-- Elements.
local element = token('element', '<' * P('/')^-1 * identifier)
-- Attributes.
local attribute = token('attribute', identifier) * #(l.space^0 * '=')
-- Closing tags.
local tag_close = token('element', P('/')^-1 * '>')
-- Equals.
local equals = token(l.OPERATOR, '=') * in_tag
-- Entities.
local entity = token('entity', '&' * word_match{
'lt', 'gt', 'amp', 'apos', 'quot'
} * ';')
M._rules = {
{'whitespace', ws},
{'comment', comment},
{'element', element},
{'tag_close', tag_close},
{'attribute', attribute},
{'equals', equals},
{'string', string},
{'number', number},
{'entity', entity}
}
M._tokenstyles = {
element = l.STYLE_KEYWORD,
attribute = l.STYLE_TYPE,
entity = l.STYLE_OPERATOR
}
M._foldsymbols = {
_patterns = {'?', '/>', ''},
element = {['<'] = 1, ['/>'] = -1, [''] = -1},
[l.COMMENT] = {[''] = -1},
}
-- Finally, add JavaScript and VBScript as embedded languages
-- Tags that start embedded languages.
M.embed_start_tag = element *
(ws^1 * attribute * ws^0 * equals * ws^0 * string)^0 *
ws^0 * tag_close
M.embed_end_tag = element * tag_close
-- Embedded JavaScript.
local js = l.load('javascript')
local js_start_rule = #(P('') * M.embed_end_tag --
l.embed_lexer(M, js, js_start_rule, js_end_rule)
-- Embedded VBScript.
local vbs = l.load('vbscript')
local vbs_start_rule = #(P('') * M.embed_end_tag --
l.embed_lexer(M, vbs, vbs_start_rule, vbs_end_rule)
return M