lexer_spec.lua 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. local t = require('test.unit.testutil')
  2. local itp = t.gen_itp(it)
  3. local t_viml = require('test.unit.viml.testutil')
  4. local child_call_once = t.child_call_once
  5. local conv_enum = t.conv_enum
  6. local cimport = t.cimport
  7. local ffi = t.ffi
  8. local eq = t.eq
  9. local shallowcopy = t.shallowcopy
  10. local intchar2lua = t.intchar2lua
  11. local conv_ccs = t_viml.conv_ccs
  12. local new_pstate = t_viml.new_pstate
  13. local conv_cmp_type = t_viml.conv_cmp_type
  14. local pstate_set_str = t_viml.pstate_set_str
  15. local conv_expr_asgn_type = t_viml.conv_expr_asgn_type
  16. local lib = cimport('./src/nvim/viml/parser/expressions.h')
  17. local eltkn_type_tab, eltkn_mul_type_tab, eltkn_opt_scope_tab
  18. child_call_once(function()
  19. eltkn_type_tab = {
  20. [tonumber(lib.kExprLexInvalid)] = 'Invalid',
  21. [tonumber(lib.kExprLexMissing)] = 'Missing',
  22. [tonumber(lib.kExprLexSpacing)] = 'Spacing',
  23. [tonumber(lib.kExprLexEOC)] = 'EOC',
  24. [tonumber(lib.kExprLexQuestion)] = 'Question',
  25. [tonumber(lib.kExprLexColon)] = 'Colon',
  26. [tonumber(lib.kExprLexOr)] = 'Or',
  27. [tonumber(lib.kExprLexAnd)] = 'And',
  28. [tonumber(lib.kExprLexComparison)] = 'Comparison',
  29. [tonumber(lib.kExprLexPlus)] = 'Plus',
  30. [tonumber(lib.kExprLexMinus)] = 'Minus',
  31. [tonumber(lib.kExprLexDot)] = 'Dot',
  32. [tonumber(lib.kExprLexMultiplication)] = 'Multiplication',
  33. [tonumber(lib.kExprLexNot)] = 'Not',
  34. [tonumber(lib.kExprLexNumber)] = 'Number',
  35. [tonumber(lib.kExprLexSingleQuotedString)] = 'SingleQuotedString',
  36. [tonumber(lib.kExprLexDoubleQuotedString)] = 'DoubleQuotedString',
  37. [tonumber(lib.kExprLexOption)] = 'Option',
  38. [tonumber(lib.kExprLexRegister)] = 'Register',
  39. [tonumber(lib.kExprLexEnv)] = 'Env',
  40. [tonumber(lib.kExprLexPlainIdentifier)] = 'PlainIdentifier',
  41. [tonumber(lib.kExprLexBracket)] = 'Bracket',
  42. [tonumber(lib.kExprLexFigureBrace)] = 'FigureBrace',
  43. [tonumber(lib.kExprLexParenthesis)] = 'Parenthesis',
  44. [tonumber(lib.kExprLexComma)] = 'Comma',
  45. [tonumber(lib.kExprLexArrow)] = 'Arrow',
  46. [tonumber(lib.kExprLexAssignment)] = 'Assignment',
  47. }
  48. eltkn_mul_type_tab = {
  49. [tonumber(lib.kExprLexMulMul)] = 'Mul',
  50. [tonumber(lib.kExprLexMulDiv)] = 'Div',
  51. [tonumber(lib.kExprLexMulMod)] = 'Mod',
  52. }
  53. eltkn_opt_scope_tab = {
  54. [tonumber(lib.kExprOptScopeUnspecified)] = 'Unspecified',
  55. [tonumber(lib.kExprOptScopeGlobal)] = 'Global',
  56. [tonumber(lib.kExprOptScopeLocal)] = 'Local',
  57. }
  58. end)
  59. local function conv_eltkn_type(typ)
  60. return conv_enum(eltkn_type_tab, typ)
  61. end
  62. local bracket_types = {
  63. Bracket = true,
  64. FigureBrace = true,
  65. Parenthesis = true,
  66. }
  67. local function eltkn2lua(pstate, tkn)
  68. local ret = {
  69. type = conv_eltkn_type(tkn.type),
  70. }
  71. pstate_set_str(pstate, tkn.start, tkn.len, ret)
  72. if not ret.error and (#ret.str ~= ret.len) then
  73. ret.error = '#str /= len'
  74. end
  75. if ret.type == 'Comparison' then
  76. ret.data = {
  77. type = conv_cmp_type(tkn.data.cmp.type),
  78. ccs = conv_ccs(tkn.data.cmp.ccs),
  79. inv = not not tkn.data.cmp.inv,
  80. }
  81. elseif ret.type == 'Multiplication' then
  82. ret.data = { type = conv_enum(eltkn_mul_type_tab, tkn.data.mul.type) }
  83. elseif bracket_types[ret.type] then
  84. ret.data = { closing = not not tkn.data.brc.closing }
  85. elseif ret.type == 'Register' then
  86. ret.data = { name = intchar2lua(tkn.data.reg.name) }
  87. elseif ret.type == 'SingleQuotedString' or ret.type == 'DoubleQuotedString' then
  88. ret.data = { closed = not not tkn.data.str.closed }
  89. elseif ret.type == 'Option' then
  90. ret.data = {
  91. scope = conv_enum(eltkn_opt_scope_tab, tkn.data.opt.scope),
  92. name = ffi.string(tkn.data.opt.name, tkn.data.opt.len),
  93. }
  94. elseif ret.type == 'PlainIdentifier' then
  95. ret.data = {
  96. scope = intchar2lua(tkn.data.var.scope),
  97. autoload = not not tkn.data.var.autoload,
  98. }
  99. elseif ret.type == 'Number' then
  100. ret.data = {
  101. is_float = not not tkn.data.num.is_float,
  102. base = tonumber(tkn.data.num.base),
  103. }
  104. ret.data.val =
  105. tonumber(tkn.data.num.is_float and tkn.data.num.val.floating or tkn.data.num.val.integer)
  106. elseif ret.type == 'Assignment' then
  107. ret.data = { type = conv_expr_asgn_type(tkn.data.ass.type) }
  108. elseif ret.type == 'Invalid' then
  109. ret.data = { error = ffi.string(tkn.data.err.msg) }
  110. end
  111. return ret, tkn
  112. end
  113. local function next_eltkn(pstate, flags)
  114. return eltkn2lua(pstate, lib.viml_pexpr_next_token(pstate, flags))
  115. end
  116. describe('Expressions lexer', function()
  117. local flags = 0
  118. local should_advance = true
  119. local function check_advance(pstate, bytes_to_advance, initial_col)
  120. local tgt = initial_col + bytes_to_advance
  121. if should_advance then
  122. if pstate.reader.lines.items[0].size == tgt then
  123. eq(1, pstate.pos.line)
  124. eq(0, pstate.pos.col)
  125. else
  126. eq(0, pstate.pos.line)
  127. eq(tgt, pstate.pos.col)
  128. end
  129. else
  130. eq(0, pstate.pos.line)
  131. eq(initial_col, pstate.pos.col)
  132. end
  133. end
  134. local function singl_eltkn_test(typ, str, data)
  135. local pstate = new_pstate({ str })
  136. eq(
  137. { data = data, len = #str, start = { col = 0, line = 0 }, str = str, type = typ },
  138. next_eltkn(pstate, flags)
  139. )
  140. check_advance(pstate, #str, 0)
  141. if
  142. not (
  143. typ == 'Spacing'
  144. or (typ == 'Register' and str == '@')
  145. or ((typ == 'SingleQuotedString' or typ == 'DoubleQuotedString') and not data.closed)
  146. )
  147. then
  148. pstate = new_pstate({ str .. ' ' })
  149. eq(
  150. { data = data, len = #str, start = { col = 0, line = 0 }, str = str, type = typ },
  151. next_eltkn(pstate, flags)
  152. )
  153. check_advance(pstate, #str, 0)
  154. end
  155. pstate = new_pstate({ 'x' .. str })
  156. pstate.pos.col = 1
  157. eq(
  158. { data = data, len = #str, start = { col = 1, line = 0 }, str = str, type = typ },
  159. next_eltkn(pstate, flags)
  160. )
  161. check_advance(pstate, #str, 1)
  162. end
  163. local function scope_test(scope)
  164. singl_eltkn_test('PlainIdentifier', scope .. ':test#var', { autoload = true, scope = scope })
  165. singl_eltkn_test('PlainIdentifier', scope .. ':', { autoload = false, scope = scope })
  166. end
  167. local function comparison_test(op, inv_op, cmp_type)
  168. singl_eltkn_test('Comparison', op, { type = cmp_type, inv = false, ccs = 'UseOption' })
  169. singl_eltkn_test('Comparison', inv_op, { type = cmp_type, inv = true, ccs = 'UseOption' })
  170. singl_eltkn_test('Comparison', op .. '#', { type = cmp_type, inv = false, ccs = 'MatchCase' })
  171. singl_eltkn_test(
  172. 'Comparison',
  173. inv_op .. '#',
  174. { type = cmp_type, inv = true, ccs = 'MatchCase' }
  175. )
  176. singl_eltkn_test('Comparison', op .. '?', { type = cmp_type, inv = false, ccs = 'IgnoreCase' })
  177. singl_eltkn_test(
  178. 'Comparison',
  179. inv_op .. '?',
  180. { type = cmp_type, inv = true, ccs = 'IgnoreCase' }
  181. )
  182. end
  183. local function simple_test(pstate_arg, exp_type, exp_len, exp)
  184. local pstate = new_pstate(pstate_arg)
  185. exp = shallowcopy(exp)
  186. exp.type = exp_type
  187. exp.len = exp_len or #pstate_arg[0]
  188. exp.start = { col = 0, line = 0 }
  189. eq(exp, next_eltkn(pstate, flags))
  190. end
  191. local function stable_tests()
  192. singl_eltkn_test('Parenthesis', '(', { closing = false })
  193. singl_eltkn_test('Parenthesis', ')', { closing = true })
  194. singl_eltkn_test('Bracket', '[', { closing = false })
  195. singl_eltkn_test('Bracket', ']', { closing = true })
  196. singl_eltkn_test('FigureBrace', '{', { closing = false })
  197. singl_eltkn_test('FigureBrace', '}', { closing = true })
  198. singl_eltkn_test('Question', '?')
  199. singl_eltkn_test('Colon', ':')
  200. singl_eltkn_test('Dot', '.')
  201. singl_eltkn_test('Assignment', '.=', { type = 'Concat' })
  202. singl_eltkn_test('Plus', '+')
  203. singl_eltkn_test('Assignment', '+=', { type = 'Add' })
  204. singl_eltkn_test('Comma', ',')
  205. singl_eltkn_test('Multiplication', '*', { type = 'Mul' })
  206. singl_eltkn_test('Multiplication', '/', { type = 'Div' })
  207. singl_eltkn_test('Multiplication', '%', { type = 'Mod' })
  208. singl_eltkn_test('Spacing', ' \t\t \t\t')
  209. singl_eltkn_test('Spacing', ' ')
  210. singl_eltkn_test('Spacing', '\t')
  211. singl_eltkn_test(
  212. 'Invalid',
  213. '\x01\x02\x03',
  214. { error = 'E15: Invalid control character present in input: %.*s' }
  215. )
  216. singl_eltkn_test('Number', '0123', { is_float = false, base = 8, val = 83 })
  217. singl_eltkn_test('Number', '01234567', { is_float = false, base = 8, val = 342391 })
  218. singl_eltkn_test('Number', '012345678', { is_float = false, base = 10, val = 12345678 })
  219. singl_eltkn_test('Number', '0x123', { is_float = false, base = 16, val = 291 })
  220. singl_eltkn_test('Number', '0x56FF', { is_float = false, base = 16, val = 22271 })
  221. singl_eltkn_test('Number', '0xabcdef', { is_float = false, base = 16, val = 11259375 })
  222. singl_eltkn_test('Number', '0xABCDEF', { is_float = false, base = 16, val = 11259375 })
  223. singl_eltkn_test('Number', '0x0', { is_float = false, base = 16, val = 0 })
  224. singl_eltkn_test('Number', '00', { is_float = false, base = 8, val = 0 })
  225. singl_eltkn_test('Number', '0b0', { is_float = false, base = 2, val = 0 })
  226. singl_eltkn_test('Number', '0b010111', { is_float = false, base = 2, val = 23 })
  227. singl_eltkn_test('Number', '0b100111', { is_float = false, base = 2, val = 39 })
  228. singl_eltkn_test('Number', '0', { is_float = false, base = 10, val = 0 })
  229. singl_eltkn_test('Number', '9', { is_float = false, base = 10, val = 9 })
  230. singl_eltkn_test('Env', '$abc')
  231. singl_eltkn_test('Env', '$')
  232. singl_eltkn_test('PlainIdentifier', 'test', { autoload = false, scope = 0 })
  233. singl_eltkn_test('PlainIdentifier', '_test', { autoload = false, scope = 0 })
  234. singl_eltkn_test('PlainIdentifier', '_test_foo', { autoload = false, scope = 0 })
  235. singl_eltkn_test('PlainIdentifier', 't', { autoload = false, scope = 0 })
  236. singl_eltkn_test('PlainIdentifier', 'test5', { autoload = false, scope = 0 })
  237. singl_eltkn_test('PlainIdentifier', 't0', { autoload = false, scope = 0 })
  238. singl_eltkn_test('PlainIdentifier', 'test#var', { autoload = true, scope = 0 })
  239. singl_eltkn_test('PlainIdentifier', 'test#var#val###', { autoload = true, scope = 0 })
  240. singl_eltkn_test('PlainIdentifier', 't#####', { autoload = true, scope = 0 })
  241. singl_eltkn_test('And', '&&')
  242. singl_eltkn_test('Or', '||')
  243. singl_eltkn_test('Invalid', '&', { error = 'E112: Option name missing: %.*s' })
  244. singl_eltkn_test('Option', '&opt', { scope = 'Unspecified', name = 'opt' })
  245. singl_eltkn_test('Option', '&t_xx', { scope = 'Unspecified', name = 't_xx' })
  246. singl_eltkn_test('Option', '&t_\r\r', { scope = 'Unspecified', name = 't_\r\r' })
  247. singl_eltkn_test('Option', '&t_\t\t', { scope = 'Unspecified', name = 't_\t\t' })
  248. singl_eltkn_test('Option', '&t_ ', { scope = 'Unspecified', name = 't_ ' })
  249. singl_eltkn_test('Option', '&g:opt', { scope = 'Global', name = 'opt' })
  250. singl_eltkn_test('Option', '&l:opt', { scope = 'Local', name = 'opt' })
  251. singl_eltkn_test('Invalid', '&l:', { error = 'E112: Option name missing: %.*s' })
  252. singl_eltkn_test('Invalid', '&g:', { error = 'E112: Option name missing: %.*s' })
  253. singl_eltkn_test('Register', '@', { name = -1 })
  254. singl_eltkn_test('Register', '@a', { name = 'a' })
  255. singl_eltkn_test('Register', '@\r', { name = 13 })
  256. singl_eltkn_test('Register', '@ ', { name = ' ' })
  257. singl_eltkn_test('Register', '@\t', { name = 9 })
  258. singl_eltkn_test('SingleQuotedString', "'test", { closed = false })
  259. singl_eltkn_test('SingleQuotedString', "'test'", { closed = true })
  260. singl_eltkn_test('SingleQuotedString', "''''", { closed = true })
  261. singl_eltkn_test('SingleQuotedString', "'x'''", { closed = true })
  262. singl_eltkn_test('SingleQuotedString', "'''x'", { closed = true })
  263. singl_eltkn_test('SingleQuotedString', "'''", { closed = false })
  264. singl_eltkn_test('SingleQuotedString', "'x''", { closed = false })
  265. singl_eltkn_test('SingleQuotedString', "'''x", { closed = false })
  266. singl_eltkn_test('DoubleQuotedString', '"test', { closed = false })
  267. singl_eltkn_test('DoubleQuotedString', '"test"', { closed = true })
  268. singl_eltkn_test('DoubleQuotedString', '"\\""', { closed = true })
  269. singl_eltkn_test('DoubleQuotedString', '"x\\""', { closed = true })
  270. singl_eltkn_test('DoubleQuotedString', '"\\"x"', { closed = true })
  271. singl_eltkn_test('DoubleQuotedString', '"\\"', { closed = false })
  272. singl_eltkn_test('DoubleQuotedString', '"x\\"', { closed = false })
  273. singl_eltkn_test('DoubleQuotedString', '"\\"x', { closed = false })
  274. singl_eltkn_test('Not', '!')
  275. singl_eltkn_test('Assignment', '=', { type = 'Plain' })
  276. comparison_test('==', '!=', 'Equal')
  277. comparison_test('=~', '!~', 'Matches')
  278. comparison_test('>', '<=', 'Greater')
  279. comparison_test('>=', '<', 'GreaterOrEqual')
  280. singl_eltkn_test('Minus', '-')
  281. singl_eltkn_test('Assignment', '-=', { type = 'Subtract' })
  282. singl_eltkn_test('Arrow', '->')
  283. singl_eltkn_test('Invalid', '~', { error = 'E15: Unidentified character: %.*s' })
  284. simple_test({ { data = nil, size = 0 } }, 'EOC', 0, { error = 'start.col >= #pstr' })
  285. simple_test({ '' }, 'EOC', 0, { error = 'start.col >= #pstr' })
  286. simple_test(
  287. { '2.' },
  288. 'Number',
  289. 1,
  290. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  291. )
  292. simple_test(
  293. { '2e5' },
  294. 'Number',
  295. 1,
  296. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  297. )
  298. simple_test(
  299. { '2.x' },
  300. 'Number',
  301. 1,
  302. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  303. )
  304. simple_test(
  305. { '2.2.' },
  306. 'Number',
  307. 1,
  308. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  309. )
  310. simple_test(
  311. { '2.0x' },
  312. 'Number',
  313. 1,
  314. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  315. )
  316. simple_test(
  317. { '2.0e' },
  318. 'Number',
  319. 1,
  320. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  321. )
  322. simple_test(
  323. { '2.0e+' },
  324. 'Number',
  325. 1,
  326. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  327. )
  328. simple_test(
  329. { '2.0e-' },
  330. 'Number',
  331. 1,
  332. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  333. )
  334. simple_test(
  335. { '2.0e+x' },
  336. 'Number',
  337. 1,
  338. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  339. )
  340. simple_test(
  341. { '2.0e-x' },
  342. 'Number',
  343. 1,
  344. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  345. )
  346. simple_test(
  347. { '2.0e+1a' },
  348. 'Number',
  349. 1,
  350. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  351. )
  352. simple_test(
  353. { '2.0e-1a' },
  354. 'Number',
  355. 1,
  356. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  357. )
  358. simple_test(
  359. { '0b102' },
  360. 'Number',
  361. 4,
  362. { data = { is_float = false, base = 2, val = 2 }, str = '0b10' }
  363. )
  364. simple_test(
  365. { '10F' },
  366. 'Number',
  367. 2,
  368. { data = { is_float = false, base = 10, val = 10 }, str = '10' }
  369. )
  370. simple_test({ '0x0123456789ABCDEFG' }, 'Number', 18, {
  371. data = { is_float = false, base = 16, val = 81985529216486895 },
  372. str = '0x0123456789ABCDEF',
  373. })
  374. simple_test(
  375. { { data = '00', size = 2 } },
  376. 'Number',
  377. 2,
  378. { data = { is_float = false, base = 8, val = 0 }, str = '00' }
  379. )
  380. simple_test(
  381. { { data = '009', size = 2 } },
  382. 'Number',
  383. 2,
  384. { data = { is_float = false, base = 8, val = 0 }, str = '00' }
  385. )
  386. simple_test(
  387. { { data = '01', size = 1 } },
  388. 'Number',
  389. 1,
  390. { data = { is_float = false, base = 10, val = 0 }, str = '0' }
  391. )
  392. end
  393. local function regular_scope_tests()
  394. scope_test('s')
  395. scope_test('g')
  396. scope_test('v')
  397. scope_test('b')
  398. scope_test('w')
  399. scope_test('t')
  400. scope_test('l')
  401. scope_test('a')
  402. simple_test(
  403. { 'g:' },
  404. 'PlainIdentifier',
  405. 2,
  406. { data = { scope = 'g', autoload = false }, str = 'g:' }
  407. )
  408. simple_test(
  409. { 'g:is#foo' },
  410. 'PlainIdentifier',
  411. 8,
  412. { data = { scope = 'g', autoload = true }, str = 'g:is#foo' }
  413. )
  414. simple_test(
  415. { 'g:isnot#foo' },
  416. 'PlainIdentifier',
  417. 11,
  418. { data = { scope = 'g', autoload = true }, str = 'g:isnot#foo' }
  419. )
  420. end
  421. local function regular_is_tests()
  422. comparison_test('is', 'isnot', 'Identical')
  423. simple_test(
  424. { 'is' },
  425. 'Comparison',
  426. 2,
  427. { data = { type = 'Identical', inv = false, ccs = 'UseOption' }, str = 'is' }
  428. )
  429. simple_test(
  430. { 'isnot' },
  431. 'Comparison',
  432. 5,
  433. { data = { type = 'Identical', inv = true, ccs = 'UseOption' }, str = 'isnot' }
  434. )
  435. simple_test(
  436. { 'is?' },
  437. 'Comparison',
  438. 3,
  439. { data = { type = 'Identical', inv = false, ccs = 'IgnoreCase' }, str = 'is?' }
  440. )
  441. simple_test(
  442. { 'isnot?' },
  443. 'Comparison',
  444. 6,
  445. { data = { type = 'Identical', inv = true, ccs = 'IgnoreCase' }, str = 'isnot?' }
  446. )
  447. simple_test(
  448. { 'is#' },
  449. 'Comparison',
  450. 3,
  451. { data = { type = 'Identical', inv = false, ccs = 'MatchCase' }, str = 'is#' }
  452. )
  453. simple_test(
  454. { 'isnot#' },
  455. 'Comparison',
  456. 6,
  457. { data = { type = 'Identical', inv = true, ccs = 'MatchCase' }, str = 'isnot#' }
  458. )
  459. simple_test(
  460. { 'is#foo' },
  461. 'Comparison',
  462. 3,
  463. { data = { type = 'Identical', inv = false, ccs = 'MatchCase' }, str = 'is#' }
  464. )
  465. simple_test(
  466. { 'isnot#foo' },
  467. 'Comparison',
  468. 6,
  469. { data = { type = 'Identical', inv = true, ccs = 'MatchCase' }, str = 'isnot#' }
  470. )
  471. end
  472. local function regular_number_tests()
  473. simple_test(
  474. { '2.0' },
  475. 'Number',
  476. 1,
  477. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  478. )
  479. simple_test(
  480. { '2.0e5' },
  481. 'Number',
  482. 1,
  483. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  484. )
  485. simple_test(
  486. { '2.0e+5' },
  487. 'Number',
  488. 1,
  489. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  490. )
  491. simple_test(
  492. { '2.0e-5' },
  493. 'Number',
  494. 1,
  495. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  496. )
  497. end
  498. local function regular_eoc_tests()
  499. singl_eltkn_test('EOC', '|')
  500. singl_eltkn_test('EOC', '\0')
  501. singl_eltkn_test('EOC', '\n')
  502. end
  503. itp('works (single tokens, zero flags)', function()
  504. stable_tests()
  505. regular_eoc_tests()
  506. regular_scope_tests()
  507. regular_is_tests()
  508. regular_number_tests()
  509. end)
  510. itp('peeks', function()
  511. flags = tonumber(lib.kELFlagPeek)
  512. should_advance = false
  513. stable_tests()
  514. regular_eoc_tests()
  515. regular_scope_tests()
  516. regular_is_tests()
  517. regular_number_tests()
  518. end)
  519. itp('forbids scope', function()
  520. flags = tonumber(lib.kELFlagForbidScope)
  521. stable_tests()
  522. regular_eoc_tests()
  523. regular_is_tests()
  524. regular_number_tests()
  525. simple_test(
  526. { 'g:' },
  527. 'PlainIdentifier',
  528. 1,
  529. { data = { scope = 0, autoload = false }, str = 'g' }
  530. )
  531. end)
  532. itp('allows floats', function()
  533. flags = tonumber(lib.kELFlagAllowFloat)
  534. stable_tests()
  535. regular_eoc_tests()
  536. regular_scope_tests()
  537. regular_is_tests()
  538. simple_test(
  539. { '2.2' },
  540. 'Number',
  541. 3,
  542. { data = { is_float = true, base = 10, val = 2.2 }, str = '2.2' }
  543. )
  544. simple_test(
  545. { '2.0e5' },
  546. 'Number',
  547. 5,
  548. { data = { is_float = true, base = 10, val = 2e5 }, str = '2.0e5' }
  549. )
  550. simple_test(
  551. { '2.0e+5' },
  552. 'Number',
  553. 6,
  554. { data = { is_float = true, base = 10, val = 2e5 }, str = '2.0e+5' }
  555. )
  556. simple_test(
  557. { '2.0e-5' },
  558. 'Number',
  559. 6,
  560. { data = { is_float = true, base = 10, val = 2e-5 }, str = '2.0e-5' }
  561. )
  562. simple_test(
  563. { '2.500000e-5' },
  564. 'Number',
  565. 11,
  566. { data = { is_float = true, base = 10, val = 2.5e-5 }, str = '2.500000e-5' }
  567. )
  568. simple_test(
  569. { '2.5555e2' },
  570. 'Number',
  571. 8,
  572. { data = { is_float = true, base = 10, val = 2.5555e2 }, str = '2.5555e2' }
  573. )
  574. simple_test(
  575. { '2.5555e+2' },
  576. 'Number',
  577. 9,
  578. { data = { is_float = true, base = 10, val = 2.5555e2 }, str = '2.5555e+2' }
  579. )
  580. simple_test(
  581. { '2.5555e-2' },
  582. 'Number',
  583. 9,
  584. { data = { is_float = true, base = 10, val = 2.5555e-2 }, str = '2.5555e-2' }
  585. )
  586. simple_test(
  587. { { data = '2.5e-5', size = 3 } },
  588. 'Number',
  589. 3,
  590. { data = { is_float = true, base = 10, val = 2.5 }, str = '2.5' }
  591. )
  592. simple_test(
  593. { { data = '2.5e5', size = 4 } },
  594. 'Number',
  595. 1,
  596. { data = { is_float = false, base = 10, val = 2 }, str = '2' }
  597. )
  598. simple_test(
  599. { { data = '2.5e-50', size = 6 } },
  600. 'Number',
  601. 6,
  602. { data = { is_float = true, base = 10, val = 2.5e-5 }, str = '2.5e-5' }
  603. )
  604. end)
  605. itp('treats `is` as an identifier', function()
  606. flags = tonumber(lib.kELFlagIsNotCmp)
  607. stable_tests()
  608. regular_eoc_tests()
  609. regular_scope_tests()
  610. regular_number_tests()
  611. simple_test(
  612. { 'is' },
  613. 'PlainIdentifier',
  614. 2,
  615. { data = { scope = 0, autoload = false }, str = 'is' }
  616. )
  617. simple_test(
  618. { 'isnot' },
  619. 'PlainIdentifier',
  620. 5,
  621. { data = { scope = 0, autoload = false }, str = 'isnot' }
  622. )
  623. simple_test(
  624. { 'is?' },
  625. 'PlainIdentifier',
  626. 2,
  627. { data = { scope = 0, autoload = false }, str = 'is' }
  628. )
  629. simple_test(
  630. { 'isnot?' },
  631. 'PlainIdentifier',
  632. 5,
  633. { data = { scope = 0, autoload = false }, str = 'isnot' }
  634. )
  635. simple_test(
  636. { 'is#' },
  637. 'PlainIdentifier',
  638. 3,
  639. { data = { scope = 0, autoload = true }, str = 'is#' }
  640. )
  641. simple_test(
  642. { 'isnot#' },
  643. 'PlainIdentifier',
  644. 6,
  645. { data = { scope = 0, autoload = true }, str = 'isnot#' }
  646. )
  647. simple_test(
  648. { 'is#foo' },
  649. 'PlainIdentifier',
  650. 6,
  651. { data = { scope = 0, autoload = true }, str = 'is#foo' }
  652. )
  653. simple_test(
  654. { 'isnot#foo' },
  655. 'PlainIdentifier',
  656. 9,
  657. { data = { scope = 0, autoload = true }, str = 'isnot#foo' }
  658. )
  659. end)
  660. itp('forbids EOC', function()
  661. flags = tonumber(lib.kELFlagForbidEOC)
  662. stable_tests()
  663. regular_scope_tests()
  664. regular_is_tests()
  665. regular_number_tests()
  666. singl_eltkn_test('Invalid', '|', { error = 'E15: Unexpected EOC character: %.*s' })
  667. singl_eltkn_test('Invalid', '\0', { error = 'E15: Unexpected EOC character: %.*s' })
  668. singl_eltkn_test('Invalid', '\n', { error = 'E15: Unexpected EOC character: %.*s' })
  669. end)
  670. end)