1 -- Copyright (c) 2015 Piotr Orzechowski [drzewo.org]. See LICENSE.
2 -- vCard 2.1, 3.0 and 4.0 LPeg lexer.
4 local l
= require('lexer')
5 local token
, word_match
= l
.token
, l
.word_match
6 local P
, R
, S
= lpeg
.P
, lpeg
.R
, lpeg
.S
8 local M
= {_NAME
= 'vcard'}
11 local ws
= token(l
.WHITESPACE
, l
.space^
1)
13 -- Required properties.
14 local required_property
= token(l
.KEYWORD
, word_match({
15 'BEGIN', 'END', 'FN', 'N' --[[ Not required in v4.0. ]], 'VERSION'
16 }, nil, true)) * #P(':')
18 -- Supported properties.
19 local supported_property
= token(l
.TYPE
, word_match({
20 'ADR', 'AGENT' --[[ Not supported in v4.0. ]],
21 'ANNIVERSARY' --[[ Supported in v4.0 only. ]], 'BDAY',
22 'CALADRURI' --[[ Supported in v4.0 only. ]],
23 'CALURI' --[[ Supported in v4.0 only. ]], 'CATEGORIES',
24 'CLASS' --[[ Supported in v3.0 only. ]],
25 'CLIENTPIDMAP' --[[ Supported in v4.0 only. ]], 'EMAIL', 'END',
26 'FBURL' --[[ Supported in v4.0 only. ]],
27 'GENDER' --[[ Supported in v4.0 only. ]], 'GEO',
28 'IMPP' --[[ Not supported in v2.1. ]], 'KEY',
29 'KIND' --[[ Supported in v4.0 only. ]],
30 'LABEL' --[[ Not supported in v4.0. ]],
31 'LANG' --[[ Supported in v4.0 only. ]], 'LOGO',
32 'MAILER' --[[ Not supported in v4.0. ]],
33 'MEMBER' --[[ Supported in v4.0 only. ]],
34 'NAME' --[[ Supported in v3.0 only. ]],
35 'NICKNAME' --[[ Not supported in v2.1. ]], 'NOTE', 'ORG', 'PHOTO',
36 'PRODID' --[[ Not supported in v2.1. ]],
37 'PROFILE' --[[ Not supported in v4.0. ]],
38 'RELATED' --[[ Supported in v4.0 only. ]], 'REV', 'ROLE',
39 'SORT-STRING' --[[ Not supported in v4.0. ]], 'SOUND', 'SOURCE', 'TEL',
40 'TITLE', 'TZ', 'UID', 'URL', 'XML' --[[ Supported in v4.0 only. ]]
41 }, nil, true)) * #S(':;')
43 local identifier
= l
.alpha^
1 * l
.digit^
0 * (P('-') * l
.alnum^
1)^
0
46 local extension
= token(l
.TYPE
,
47 l
.starts_line(S('xX') * P('-') * identifier
* #S(':;')))
50 local parameter
= token(l
.IDENTIFIER
, l
.starts_line(identifier
* #S(':='))) +
51 token(l
.STRING
, identifier
) * #S(':=')
54 local operator
= token(l
.OPERATOR
, S('.:;='))
56 -- Group and property.
57 local group_sequence
= token(l
.CONSTANT
, l
.starts_line(identifier
)) *
58 token(l
.OPERATOR
, P('.')) *
59 (required_property
+ supported_property
+
60 l
.token(l
.TYPE
, S('xX') * P('-') * identifier
) *
62 -- Begin vCard, end vCard.
63 local begin_sequence
= token(l
.KEYWORD
, P('BEGIN')) *
64 token(l
.OPERATOR
, P(':')) * token(l
.COMMENT
, P('VCARD'))
65 local end_sequence
= token(l
.KEYWORD
, P('END')) * token(l
.OPERATOR
, P(':')) *
66 token(l
.COMMENT
, P('VCARD'))
68 -- vCard version (in v3.0 and v4.0 must appear immediately after BEGIN:VCARD).
69 local version_sequence
= token(l
.KEYWORD
, P('VERSION')) *
70 token(l
.OPERATOR
, P(':')) *
71 token(l
.CONSTANT
, l
.digit^
1 * (P('.') * l
.digit^
1)^
-1)
74 local data
= token(l
.IDENTIFIER
, l
.any
)
79 {'begin_sequence', begin_sequence
},
80 {'end_sequence', end_sequence
},
81 {'version_sequence', version_sequence
},
82 {'group_sequence', group_sequence
},
83 {'required_property', required_property
},
84 {'supported_property', supported_property
},
85 {'extension', extension
},
86 {'parameter', parameter
},
87 {'operator', operator
},
93 _patterns
= {'BEGIN', 'END'},
94 [l
.KEYWORD
] = {['BEGIN'] = 1, ['END'] = -1}