102 lines
3.7 KiB
Lua
Executable File
102 lines
3.7 KiB
Lua
Executable File
-- Copyright (c) 2015-2019 Piotr Orzechowski [drzewo.org]. See License.txt.
|
|
-- vCard 2.1, 3.0 and 4.0 LPeg lexer.
|
|
|
|
local lexer = require('lexer')
|
|
local token, word_match = lexer.token, lexer.word_match
|
|
local P, R, S = lpeg.P, lpeg.R, lpeg.S
|
|
|
|
local M = {_NAME = 'vcard'}
|
|
|
|
-- Whitespace.
|
|
local ws = token(lexer.WHITESPACE, lexer.space^1)
|
|
|
|
-- Required properties.
|
|
local required_property = token(lexer.KEYWORD, word_match({
|
|
'BEGIN', 'END', 'FN', 'N' --[[ Not required in v4.0. ]], 'VERSION'
|
|
}, nil, true)) * #P(':')
|
|
|
|
-- Supported properties.
|
|
local supported_property = token(lexer.TYPE, word_match({
|
|
'ADR', 'AGENT' --[[ Not supported in v4.0. ]],
|
|
'ANNIVERSARY' --[[ Supported in v4.0 only. ]], 'BDAY',
|
|
'CALADRURI' --[[ Supported in v4.0 only. ]],
|
|
'CALURI' --[[ Supported in v4.0 only. ]], 'CATEGORIES',
|
|
'CLASS' --[[ Supported in v3.0 only. ]],
|
|
'CLIENTPIDMAP' --[[ Supported in v4.0 only. ]], 'EMAIL', 'END',
|
|
'FBURL' --[[ Supported in v4.0 only. ]],
|
|
'GENDER' --[[ Supported in v4.0 only. ]], 'GEO',
|
|
'IMPP' --[[ Not supported in v2.1. ]], 'KEY',
|
|
'KIND' --[[ Supported in v4.0 only. ]],
|
|
'LABEL' --[[ Not supported in v4.0. ]],
|
|
'LANG' --[[ Supported in v4.0 only. ]], 'LOGO',
|
|
'MAILER' --[[ Not supported in v4.0. ]],
|
|
'MEMBER' --[[ Supported in v4.0 only. ]],
|
|
'NAME' --[[ Supported in v3.0 only. ]],
|
|
'NICKNAME' --[[ Not supported in v2.1. ]], 'NOTE', 'ORG', 'PHOTO',
|
|
'PRODID' --[[ Not supported in v2.1. ]],
|
|
'PROFILE' --[[ Not supported in v4.0. ]],
|
|
'RELATED' --[[ Supported in v4.0 only. ]], 'REV', 'ROLE',
|
|
'SORT-STRING' --[[ Not supported in v4.0. ]], 'SOUND', 'SOURCE', 'TEL',
|
|
'TITLE', 'TZ', 'UID', 'URL', 'XML' --[[ Supported in v4.0 only. ]]
|
|
}, nil, true)) * #S(':;')
|
|
|
|
local identifier = lexer.alpha^1 * lexer.digit^0 * (P('-') * lexer.alnum^1)^0
|
|
|
|
-- Extension.
|
|
local extension = token(lexer.TYPE, lexer.starts_line(S('xX') * P('-') *
|
|
identifier * #S(':;')))
|
|
|
|
-- Parameter.
|
|
local parameter = token(lexer.IDENTIFIER,
|
|
lexer.starts_line(identifier * #S(':='))) +
|
|
token(lexer.STRING, identifier) * #S(':=')
|
|
|
|
-- Operators.
|
|
local operator = token(lexer.OPERATOR, S('.:;='))
|
|
|
|
-- Group and property.
|
|
local group_sequence = token(lexer.CONSTANT, lexer.starts_line(identifier)) *
|
|
token(lexer.OPERATOR, P('.')) *
|
|
(required_property + supported_property +
|
|
lexer.token(lexer.TYPE, S('xX') * P('-') * identifier) *
|
|
#S(':;'))
|
|
-- Begin vCard, end vCard.
|
|
local begin_sequence = token(lexer.KEYWORD, P('BEGIN')) *
|
|
token(lexer.OPERATOR, P(':')) *
|
|
token(lexer.COMMENT, P('VCARD'))
|
|
local end_sequence = token(lexer.KEYWORD, P('END')) *
|
|
token(lexer.OPERATOR, P(':')) *
|
|
token(lexer.COMMENT, P('VCARD'))
|
|
|
|
-- vCard version (in v3.0 and v4.0 must appear immediately after BEGIN:VCARD).
|
|
local version_sequence = token(lexer.KEYWORD, P('VERSION')) *
|
|
token(lexer.OPERATOR, P(':')) *
|
|
token(lexer.CONSTANT, lexer.digit^1 *
|
|
(P('.') * lexer.digit^1)^-1)
|
|
|
|
-- Data.
|
|
local data = token(lexer.IDENTIFIER, lexer.any)
|
|
|
|
-- Rules.
|
|
M._rules = {
|
|
{'whitespace', ws},
|
|
{'begin_sequence', begin_sequence},
|
|
{'end_sequence', end_sequence},
|
|
{'version_sequence', version_sequence},
|
|
{'group_sequence', group_sequence},
|
|
{'required_property', required_property},
|
|
{'supported_property', supported_property},
|
|
{'extension', extension},
|
|
{'parameter', parameter},
|
|
{'operator', operator},
|
|
{'data', data},
|
|
}
|
|
|
|
-- Folding.
|
|
M._foldsymbols = {
|
|
_patterns = {'BEGIN', 'END'},
|
|
[lexer.KEYWORD] = {['BEGIN'] = 1, ['END'] = -1}
|
|
}
|
|
|
|
return M
|