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