From ca4633bfe4d0f58bd5fb7343d282fafb71f3a3ee Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 2 Jul 2017 00:30:00 +0200 Subject: ci/quickbuild: XXX: disable server_requests test (#6851) Temporarily disable this test which hangs quickbuild. From #6905: The hang occurs when calling nvim_set_current_line. References #6594 5a151555c8dce70bbf235e7f6d5bd1ced5e7c46c --- test/functional/api/server_requests_spec.lua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index cf15062325..6a32f979ea 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -282,8 +282,13 @@ describe('server -> client', function() end) end) - describe('when connecting to its own pipe adress', function() - it('it does not deadlock', function() + describe('connecting to its own pipe address', function() + it('does not deadlock', function() + if not os.getenv("TRAVIS") and helpers.os_name() == "osx" then + -- It does, in fact, deadlock on QuickBuild. #6851 + pending("deadlocks on QuickBuild", function() end) + return + end local address = funcs.serverlist()[1] local first = string.sub(address,1,1) ok(first == '/' or first == '\\') -- cgit From 4b8bdd953e2b7928af80e8b97118d52f99f0d95a Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 2 Jul 2017 19:21:21 +0300 Subject: functests: Remove local_copy function --- test/functional/api/keymap_spec.lua | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index 833e0d2f3c..7d6445f49c 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -1,5 +1,6 @@ - local helpers = require('test.functional.helpers')(after_each) +local global_helpers = require('test.helpers') + local clear = helpers.clear local command = helpers.command local curbufmeths = helpers.curbufmeths @@ -8,13 +9,7 @@ local funcs = helpers.funcs local meths = helpers.meths local source = helpers.source -local function local_copy(t) - local copy = {} - for k,v in pairs(t) do - copy[k] = v - end - return copy -end +local shallowcopy = global_helpers.shallowcopy describe('get_keymap', function() before_each(clear) @@ -50,7 +45,7 @@ describe('get_keymap', function() -- Add another mapping command('nnoremap foo_longer bar_longer') - local foolong_bar_map_table = local_copy(foo_bar_map_table) + local foolong_bar_map_table = shallowcopy(foo_bar_map_table) foolong_bar_map_table['lhs'] = 'foo_longer' foolong_bar_map_table['rhs'] = 'bar_longer' @@ -72,7 +67,7 @@ describe('get_keymap', function() command('inoremap foo bar') -- The table will be the same except for the mode - local insert_table = local_copy(foo_bar_map_table) + local insert_table = shallowcopy(foo_bar_map_table) insert_table['mode'] = 'i' eq({insert_table}, meths.get_keymap('i')) @@ -81,11 +76,11 @@ describe('get_keymap', function() it('considers scope', function() -- change the map slightly command('nnoremap foo_longer bar_longer') - local foolong_bar_map_table = local_copy(foo_bar_map_table) + local foolong_bar_map_table = shallowcopy(foo_bar_map_table) foolong_bar_map_table['lhs'] = 'foo_longer' foolong_bar_map_table['rhs'] = 'bar_longer' - local buffer_table = local_copy(foo_bar_map_table) + local buffer_table = shallowcopy(foo_bar_map_table) buffer_table['buffer'] = 1 command('nnoremap foo bar') @@ -98,7 +93,7 @@ describe('get_keymap', function() it('considers scope for overlapping maps', function() command('nnoremap foo bar') - local buffer_table = local_copy(foo_bar_map_table) + local buffer_table = shallowcopy(foo_bar_map_table) buffer_table['buffer'] = 1 command('nnoremap foo bar') @@ -121,7 +116,7 @@ describe('get_keymap', function() command('nnoremap foo bar') -- Final buffer will have buffer mappings - local buffer_table = local_copy(foo_bar_map_table) + local buffer_table = shallowcopy(foo_bar_map_table) buffer_table['buffer'] = final_buffer eq({buffer_table}, meths.buf_get_keymap(final_buffer, 'n')) eq({buffer_table}, meths.buf_get_keymap(0, 'n')) -- cgit From a1fee487ba5199ff672a87c5830732c224fa59eb Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 2 Jul 2017 19:28:44 +0300 Subject: functests: Add tests for new behaviour Apparently it is not working yet. --- test/functional/api/keymap_spec.lua | 72 +++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 10 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index 7d6445f49c..b7858888c4 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -17,16 +17,16 @@ describe('get_keymap', function() -- Basic mapping and table to be used to describe results local foo_bar_string = 'nnoremap foo bar' local foo_bar_map_table = { - lhs='foo', - silent=0, - rhs='bar', - expr=0, - sid=0, - buffer=0, - nowait=0, - mode='n', - noremap=1, - } + lhs='foo', + silent=0, + rhs='bar', + expr=0, + sid=0, + buffer=0, + nowait=0, + mode='n', + noremap=1, + } it('returns empty list when no map', function() eq({}, meths.get_keymap('n')) @@ -238,4 +238,56 @@ describe('get_keymap', function() eq('', meths.get_keymap('n')[1]['lhs']) eq(':let g:maparg_test_var = 1', meths.get_keymap('n')[1]['rhs']) end) + + it('works correctly despite various &cpo settings', function() + local cpo_table = { + silent=0, + expr=0, + sid=0, + buffer=0, + nowait=0, + noremap=1, + } + local function cpomap(lhs, rhs, mode) + local ret = shallowcopy(cpo_table) + ret.lhs = lhs + ret.rhs = rhs + ret.mode = mode + return ret + end + + command('set cpo-=< cpo+=B') + command('nnoremap \\ \\') + command('nnoremap \\ \\') + + command('set cpo+=B<') + command('xnoremap \\ \\') + command('xnoremap \\ \\') + + command('set cpo-=B<') + command('snoremap \\ \\') + command('snoremap \\ \\') + + command('set cpo-=B cpo+=<') + command('onoremap \\ \\') + command('onoremap \\ \\') + + for _, cmd in ipairs({ + 'set cpo-=B cpo+=<', + 'set cpo-=B<', + 'set cpo+=B<', + 'set cpo-=< cpo+=B', + }) do + command(cmd) + eq({cpomap('\\', '\\', 'n'), cpomap('\\', '\\', 'n')}, + meths.get_keymap('n')) + -- FIXME + -- eq({cpomap('\\', '\\', 'x'), cpomap('\\C-A>', '\\C-B>', 'x')}, + -- meths.get_keymap('x')) + -- eq({cpomap('C-C>', 'C-D>', 's'), cpomap('C-A>', 'C-B>', 's')}, + -- meths.get_keymap('x')) + -- eq({cpomap('C-C>', 'C-D>', 'o'), cpomap('C-A>', 'C-B>', 'o')}, + -- meths.get_keymap('x')) + end + end) end) -- cgit From 24f0056ca5cb392f1e1bf38d648a6037acf1f1ef Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 2 Jul 2017 19:37:21 +0300 Subject: message: Add support for replacing `<` to str2special --- test/functional/api/keymap_spec.lua | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index b7858888c4..fc3ab2d179 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -281,13 +281,12 @@ describe('get_keymap', function() command(cmd) eq({cpomap('\\', '\\', 'n'), cpomap('\\', '\\', 'n')}, meths.get_keymap('n')) - -- FIXME - -- eq({cpomap('\\', '\\', 'x'), cpomap('\\C-A>', '\\C-B>', 'x')}, - -- meths.get_keymap('x')) - -- eq({cpomap('C-C>', 'C-D>', 's'), cpomap('C-A>', 'C-B>', 's')}, - -- meths.get_keymap('x')) - -- eq({cpomap('C-C>', 'C-D>', 'o'), cpomap('C-A>', 'C-B>', 'o')}, - -- meths.get_keymap('x')) + eq({cpomap('\\', '\\', 'x'), cpomap('\\C-a>', '\\C-b>', 'x')}, + meths.get_keymap('x')) + eq({cpomap('C-c>', 'C-d>', 's'), cpomap('C-a>', 'C-b>', 's')}, + meths.get_keymap('s')) + eq({cpomap('C-c>', 'C-d>', 'o'), cpomap('C-a>', 'C-b>', 'o')}, + meths.get_keymap('o')) end end) end) -- cgit From 5fe5d712aae512c62083754bc364030848d67987 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 2 Jul 2017 19:49:40 +0300 Subject: functests: Use more extensive testing Fixes #6937 --- test/functional/api/keymap_spec.lua | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index fc3ab2d179..f1c4d7bdf3 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -257,20 +257,20 @@ describe('get_keymap', function() end command('set cpo-=< cpo+=B') - command('nnoremap \\ \\') - command('nnoremap \\ \\') + command('nnoremap \\C-a>\\ \\C-b>\\') + command('nnoremap \\C-c>\\ \\C-d>\\') command('set cpo+=B<') - command('xnoremap \\ \\') - command('xnoremap \\ \\') + command('xnoremap \\C-a>\\ \\C-b>\\') + command('xnoremap \\C-c>\\ \\C-d>\\') command('set cpo-=B<') - command('snoremap \\ \\') - command('snoremap \\ \\') + command('snoremap \\C-a>\\ \\C-b>\\') + command('snoremap \\C-c>\\ \\C-d>\\') command('set cpo-=B cpo+=<') - command('onoremap \\ \\') - command('onoremap \\ \\') + command('onoremap \\C-a>\\ \\C-b>\\') + command('onoremap \\C-c>\\ \\C-d>\\') for _, cmd in ipairs({ 'set cpo-=B cpo+=<', @@ -279,13 +279,17 @@ describe('get_keymap', function() 'set cpo-=< cpo+=B', }) do command(cmd) - eq({cpomap('\\', '\\', 'n'), cpomap('\\', '\\', 'n')}, + eq({cpomap('\\C-c>\\', '\\C-d>\\', 'n'), + cpomap('\\C-a>\\', '\\C-b>\\', 'n')}, meths.get_keymap('n')) - eq({cpomap('\\', '\\', 'x'), cpomap('\\C-a>', '\\C-b>', 'x')}, + eq({cpomap('\\C-c>\\', '\\C-d>\\', 'x'), + cpomap('\\C-a>C-a>LT>C-a>\\', '\\C-b>C-b>LT>C-b>\\', 'x')}, meths.get_keymap('x')) - eq({cpomap('C-c>', 'C-d>', 's'), cpomap('C-a>', 'C-b>', 's')}, + eq({cpomap('C-c>C-c> ', 'C-d>C-d>', 's'), + cpomap('C-a>C-a> ', 'C-b>C-b>', 's')}, meths.get_keymap('s')) - eq({cpomap('C-c>', 'C-d>', 'o'), cpomap('C-a>', 'C-b>', 'o')}, + eq({cpomap('C-c>C-c> ', 'C-d>C-d>', 'o'), + cpomap('C-a>C-a>LT>C-a> ', 'C-b>C-b>LT>C-b>', 'o')}, meths.get_keymap('o')) end end) -- cgit From d5916a823a37a1c0fb1d3d2f52db7cad4107b924 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 2 Jul 2017 20:08:00 +0300 Subject: functests: Test how spaces appear in get_keymap output --- test/functional/api/keymap_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index f1c4d7bdf3..aa556b563d 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -293,4 +293,20 @@ describe('get_keymap', function() meths.get_keymap('o')) end end) + + it('always uses space for space and bar for bar', function() + local space_table = { + lhs='| |', + rhs='| |', + mode='n', + silent=0, + expr=0, + sid=0, + buffer=0, + nowait=0, + noremap=1, + } + command('nnoremap \\| \\| ') + eq({space_table}, meths.get_keymap('n')) + end) end) -- cgit From 0ea7e45bc1d1881f505da2b77e0b3e4eb56f12fe Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 2 Jul 2017 13:21:38 +0200 Subject: 'cpoptions': remove "<" flag; ignore Closes #6937 "nvim_get_keymap output is unreliable" --- test/functional/api/keymap_spec.lua | 18 ++++++++---------- test/functional/api/vim_spec.lua | 13 +++++++++---- 2 files changed, 17 insertions(+), 14 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index aa556b563d..3a10f9c60f 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -256,40 +256,38 @@ describe('get_keymap', function() return ret end - command('set cpo-=< cpo+=B') + command('set cpo+=B') command('nnoremap \\C-a>\\ \\C-b>\\') command('nnoremap \\C-c>\\ \\C-d>\\') - command('set cpo+=B<') + command('set cpo+=B') command('xnoremap \\C-a>\\ \\C-b>\\') command('xnoremap \\C-c>\\ \\C-d>\\') - command('set cpo-=B<') + command('set cpo-=B') command('snoremap \\C-a>\\ \\C-b>\\') command('snoremap \\C-c>\\ \\C-d>\\') - command('set cpo-=B cpo+=<') + command('set cpo-=B') command('onoremap \\C-a>\\ \\C-b>\\') command('onoremap \\C-c>\\ \\C-d>\\') for _, cmd in ipairs({ - 'set cpo-=B cpo+=<', - 'set cpo-=B<', - 'set cpo+=B<', - 'set cpo-=< cpo+=B', + 'set cpo-=B', + 'set cpo+=B', }) do command(cmd) eq({cpomap('\\C-c>\\', '\\C-d>\\', 'n'), cpomap('\\C-a>\\', '\\C-b>\\', 'n')}, meths.get_keymap('n')) eq({cpomap('\\C-c>\\', '\\C-d>\\', 'x'), - cpomap('\\C-a>C-a>LT>C-a>\\', '\\C-b>C-b>LT>C-b>\\', 'x')}, + cpomap('\\C-a>\\', '\\C-b>\\', 'x')}, meths.get_keymap('x')) eq({cpomap('C-c>C-c> ', 'C-d>C-d>', 's'), cpomap('C-a>C-a> ', 'C-b>C-b>', 's')}, meths.get_keymap('s')) eq({cpomap('C-c>C-c> ', 'C-d>C-d>', 'o'), - cpomap('C-a>C-a>LT>C-a> ', 'C-b>C-b>LT>C-b>', 'o')}, + cpomap('C-a>C-a> ', 'C-b>C-b>', 'o')}, meths.get_keymap('o')) end end) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index c531d4af46..e59b5d712d 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -373,6 +373,11 @@ describe('api', function() 'xxxx', true, true, true)) end) + it('does not convert keycodes if special=false', function() + eq('xxxx', helpers.nvim('replace_termcodes', + 'xxxx', true, true, false)) + end) + it('does not crash when transforming an empty string', function() -- Actually does not test anything, because current code will use NULL for -- an empty string. @@ -391,13 +396,13 @@ describe('api', function() -- notice the special char(…) \xe2\80\xa6 nvim('feedkeys', ':let x1="…"\n', '', true) - -- Both replace_termcodes and feedkeys escape \x80 + -- Both nvim_replace_termcodes and nvim_feedkeys escape \x80 local inp = helpers.nvim('replace_termcodes', ':let x2="…"', true, true, true) - nvim('feedkeys', inp, '', true) + nvim('feedkeys', inp, '', true) -- escape_csi=true - -- Disabling CSI escaping in feedkeys + -- nvim_feedkeys with CSI escaping disabled inp = helpers.nvim('replace_termcodes', ':let x3="…"', true, true, true) - nvim('feedkeys', inp, '', false) + nvim('feedkeys', inp, '', false) -- escape_csi=false helpers.stop() end -- cgit From af993da4351d579aa24de08d806c8c1b90813106 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 27 Jul 2017 01:08:50 +0200 Subject: rpc: close channel if stream was closed f_jobstop()/f_rpcstop() .. process_stop() .. process_close_in(proc) closes the write-stream of a RPC channel. But there might be a pending RPC notification on the queue, which may get processed just before the channel is closed. To handle that case, check the Stream.closed in channel.c:receive_msgpack(). Before this change, the above scenario could trigger this assert(!stream->closed) in wstream_write(): 0x00007f96e1cd3428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54 0x00007f96e1cd502a in __GI_abort () at abort.c:89 0x00007f96e1ccbbd7 in __assert_fail_base (fmt=, assertion=assertion@entry=0x768f9b "!stream->closed", file=file@entry=0x768f70 "../src/nvim/event/wstream.c", line=line@entry=77, function=function@entry=0x768fb0 <__PRETTY_FUNCTION__.13735> "wstream_write") at assert.c:92 0x00007f96e1ccbc82 in __GI___assert_fail (assertion=0x768f9b "!stream->closed", file=0x768f70 "../src/nvim/event/wstream.c", line=77, function=0x768fb0 <__PRETTY_FUNCTION__.13735> "wstream_write") at assert.c:101 0x00000000004d2c1f in wstream_write (stream=0x7f96e0a35078, buffer=0x7f96e09f9b40) at ../src/nvim/event/wstream.c:77 0x00000000005857b2 in channel_write (channel=0x7f96e0ae5800, buffer=0x7f96e09f9b40) at ../src/nvim/msgpack_rpc/channel.c:551 0x000000000058567d in on_request_event (argv=0x7ffed792efa0) at ../src/nvim/msgpack_rpc/channel.c:523 0x00000000005854c8 in handle_request (channel=0x7f96e0ae5800, request=0x7ffed792f1b8) at ../src/nvim/msgpack_rpc/channel.c:503 0x00000000005850cb in parse_msgpack (channel=0x7f96e0ae5800) at ../src/nvim/msgpack_rpc/channel.c:423 0x0000000000584f90 in receive_msgpack (stream=0x7f96e0a35218, rbuf=0x7f96e0d1d4c0, c=22, data=0x7f96e0ae5800, eof=false) at ../src/nvim/msgpack_rpc/channel.c:389 0x00000000004d0b20 in read_event (argv=0x7ffed792f4a8) at ../src/nvim/event/rstream.c:190 0x00000000004ce462 in multiqueue_process_events (this=0x7f96e18172d0) at ../src/nvim/event/multiqueue.c:150 0x000000000059b630 in nv_event (cap=0x7ffed792f620) at ../src/nvim/normal.c:7908 0x000000000058be69 in normal_execute (state=0x7ffed792f580, key=-25341) at ../src/nvim/normal.c:1137 0x0000000000652463 in state_enter (s=0x7ffed792f580) at ../src/nvim/state.c:61 0x000000000058a1fe in normal_enter (cmdwin=false, noexmode=false) at ../src/nvim/normal.c:467 0x00000000005500c2 in main (argc=2, argv=0x7ffed792f8d8) at ../src/nvim/main.c:554 Alternative approach suggested by bfredl is to use close_cb of the process. My unsuccessful attempt is below. (It seems close_cb is queued too late, which is the similar problem addressed by this commit): commit 75fc12c6ab15711bdb7b18c6d42ec9d157f5145e Author: Justin M. Keyes Date: Fri Aug 18 01:30:41 2017 +0200 rpc: use Stream's close_cb instead of explicit check in receive_msgpack() diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 8371d3cd482e..e52da23cdc40 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -416,6 +416,10 @@ static void on_process_exit(Process *proc) static void on_process_stream_close(Stream *stream, void *data) { Process *proc = data; + ILOG("on_process_stream_close"); + if (proc->stream_close_cb != NULL) { + proc->stream_close_cb(stream, proc->stream_close_data); + } decref(proc); } diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h index 5c00e8e7ecd5..34a8d54f6f8c 100644 --- a/src/nvim/event/process.h +++ b/src/nvim/event/process.h @@ -26,6 +26,11 @@ struct process { Stream *in, *out, *err; process_exit_cb cb; internal_process_cb internal_exit_cb, internal_close_cb; + + // Called when any of the process streams (in/out/err) closes. + stream_close_cb stream_close_cb; + void *stream_close_data; + bool closed, detach; MultiQueue *events; }; @@ -50,6 +55,8 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data) .closed = false, .internal_close_cb = NULL, .internal_exit_cb = NULL, + .stream_close_cb = NULL, + .stream_close_data = NULL, .detach = false }; } diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c index 7c865bfe1e8c..c8720d1e45d9 100644 --- a/src/nvim/event/stream.c +++ b/src/nvim/event/stream.c @@ -95,7 +95,11 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data) void stream_close_handle(Stream *stream) FUNC_ATTR_NONNULL_ALL { + ILOG("stream=%d", stream); + // LOG_CALLSTACK(); if (stream->uvstream) { + // problem: this schedules on the queue, but channel.c:receive_msgpack may + // be processed before close_cb is called by libuv. uv_close((uv_handle_t *)stream->uvstream, close_cb); } else { uv_close((uv_handle_t *)&stream->uv.idle, close_cb); @@ -105,6 +109,7 @@ void stream_close_handle(Stream *stream) static void close_cb(uv_handle_t *handle) { Stream *stream = handle->data; + ILOG(">>>>>>>>>>>>>>>>>>>>>>> stream=%p stream->internal_close_cb=%p", stream, stream->internal_close_cb); if (stream->buffer) { rbuffer_free(stream->buffer); } diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 782eabe04e4a..dc2b794e366a 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -128,6 +128,8 @@ uint64_t channel_from_process(Process *proc, uint64_t id, char *source) source); incref(channel); // process channels are only closed by the exit_cb channel->data.proc = proc; + channel->data.proc->stream_close_cb = close_cb2; + channel->data.proc->stream_close_data = channel; wstream_init(proc->in, 0); rstream_init(proc->out, 0); @@ -387,17 +389,6 @@ static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c, goto end; } - if ((chan_wstream(channel) != NULL && chan_wstream(channel)->closed) - || (chan_rstream(channel) != NULL && chan_rstream(channel)->closed)) { - char buf[256]; - snprintf(buf, sizeof(buf), - "ch %" PRIu64 ": stream closed unexpectedly. " - "closing channel", - channel->id); - call_set_error(channel, buf, WARN_LOG_LEVEL); - goto end; - } - size_t count = rbuffer_size(rbuf); DLOG("ch %" PRIu64 ": parsing %u bytes from msgpack Stream: %p", channel->id, count, stream); @@ -571,23 +562,6 @@ static Stream *chan_wstream(Channel *chan) abort(); } -/// Returns the Stream that a Channel reads from. -static Stream *chan_rstream(Channel *chan) -{ - switch (chan->type) { - case kChannelTypeSocket: - return &chan->data.stream; - case kChannelTypeProc: - return chan->data.proc->out; - case kChannelTypeStdio: - return &chan->data.std.in; - case kChannelTypeInternal: - return NULL; - } - abort(); -} - - static bool channel_write(Channel *channel, WBuffer *buffer) { bool success = false; @@ -799,6 +773,12 @@ static void close_cb(Stream *stream, void *data) decref(data); } +static void close_cb2(Stream *stream, void *data) +{ + ILOG("close_cb2"); + close_channel(data); +} + /// @param source description of source function, rplugin name, TCP addr, etc static Channel *register_channel(ChannelType type, uint64_t id, MultiQueue *events, char *source) --- test/functional/api/server_requests_spec.lua | 30 +++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 6a32f979ea..9f245d913b 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -20,6 +20,22 @@ describe('server -> client', function() cid = nvim('get_api_info')[1] end) + it('handles unexpected closed stream while preparing RPC response', function() + source([[ + let g:_nvim_args = [v:progpath, '--embed', '-n', '-u', 'NONE', '-i', 'NONE', ] + let ch1 = jobstart(g:_nvim_args, {'rpc': v:true}) + let child1_ch = rpcrequest(ch1, "nvim_get_api_info")[0] + call rpcnotify(ch1, 'nvim_eval', 'rpcrequest('.child1_ch.', "nvim_get_api_info")') + + let ch2 = jobstart(g:_nvim_args, {'rpc': v:true}) + let child2_ch = rpcrequest(ch2, "nvim_get_api_info")[0] + call rpcnotify(ch2, 'nvim_eval', 'rpcrequest('.child2_ch.', "nvim_get_api_info")') + + call jobstop(ch1) + ]]) + eq(2, eval("1+1")) -- Still alive? + end) + describe('simple call', function() it('works', function() local function on_setup() @@ -141,7 +157,7 @@ describe('server -> client', function() end) end) - describe('when the client is a recursive vim instance', function() + describe('recursive (child) nvim client', function() if os.getenv("TRAVIS") and helpers.os_name() == "osx" then -- XXX: Hangs Travis macOS since e9061117a5b8f195c3f26a5cb94e18ddd7752d86. pending("[Hangs on Travis macOS. #5002]", function() end) @@ -155,7 +171,7 @@ describe('server -> client', function() after_each(function() command('call rpcstop(vim)') end) - it('can send/recieve notifications and make requests', function() + it('can send/receive notifications and make requests', function() nvim('command', "call rpcnotify(vim, 'vim_set_current_line', 'SOME TEXT')") -- Wait for the notification to complete. @@ -188,7 +204,7 @@ describe('server -> client', function() end) end) - describe('when using jobstart', function() + describe('jobstart()', function() local jobid before_each(function() local channel = nvim('get_api_info')[1] @@ -227,7 +243,7 @@ describe('server -> client', function() end) end) - describe('when connecting to another nvim instance', function() + describe('connecting to another (peer) nvim', function() local function connect_test(server, mode, address) local serverpid = funcs.getpid() local client = spawn(nvim_argv) @@ -256,7 +272,7 @@ describe('server -> client', function() client:close() end - it('over a named pipe', function() + it('via named pipe', function() local server = spawn(nvim_argv) set_session(server) local address = funcs.serverlist()[1] @@ -265,7 +281,7 @@ describe('server -> client', function() connect_test(server, 'pipe', address) end) - it('to an ip adress', function() + it('via ip address', function() local server = spawn(nvim_argv) set_session(server) local address = funcs.serverstart("127.0.0.1:") @@ -273,7 +289,7 @@ describe('server -> client', function() connect_test(server, 'tcp', address) end) - it('to a hostname', function() + it('via hostname', function() local server = spawn(nvim_argv) set_session(server) local address = funcs.serverstart("localhost:") -- cgit From 541dde36e3302314e2646415dbfd2b79a6c2a1fc Mon Sep 17 00:00:00 2001 From: Matthew Malcomson Date: Sat, 2 Sep 2017 14:12:32 +0100 Subject: eventloop: K_EVENT should not finish operator normal_finish_command() and normal_prepare() assume that any pending operator needs to be finished after any subsequent key. Set `finish_op = false` in nv_event() to indicate that the pending operator shouldn't be finished in normal_execute(). This is how nv_visual() indicates that 'v' or 'V' in operator-pending mode should not finish the current pending operator. fixes #5398 fixes #6166 (partially; mappings are still interrupted) --- test/functional/api/vim_spec.lua | 62 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index e59b5d712d..5566c6d8e4 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -329,24 +329,80 @@ describe('api', function() } eq({ { {mode='n', blocking=false}, 13, - {mode='n', blocking=false}, -- TODO: should be blocked=true + {mode='n', blocking=false}, -- TODO: should be blocked=true ? 1 }, NIL}, meths.call_atomic(req)) eq({mode='r', blocking=true}, nvim("get_mode")) end) - -- TODO: bug #6166 it("during insert-mode map-pending, returns blocking=true #6166", function() command("inoremap xx foo") nvim("input", "ix") eq({mode='i', blocking=true}, nvim("get_mode")) end) - -- TODO: bug #6166 it("during normal-mode gU, returns blocking=false #6166", function() nvim("input", "gu") eq({mode='no', blocking=false}, nvim("get_mode")) end) end) + describe('RPC (K_EVENT) #6166', function() + it('does not complete/interrupt normal-mode operator', function() + helpers.insert([[ + FIRST LINE + SECOND LINE]]) + nvim('input', 'gg') + nvim('input', 'gu') + -- Make any non-async RPC request. + nvim('get_current_buf') + -- Buffer should not change. + helpers.expect([[ + FIRST LINE + SECOND LINE]]) + -- Now send input to complete the operator. + nvim("input", "j") + helpers.expect([[ + first line + second line]]) + end) + -- TODO: bug #6166 + pending('does not complete/interrupt normal-mode mapping', function() + command("nnoremap dd :let g:foo='it worked...'") + helpers.insert([[ + FIRST LINE + SECOND LINE]]) + nvim('input', 'gg') + nvim('input', 'd') + helpers.expect([[ + FIRST LINE + SECOND LINE]]) + -- Make any non-async RPC request. (expect() does RPC, but be explicit) + nvim('get_current_buf') + -- Send input to complete the mapping. + nvim('input', 'd') + helpers.expect([[ + FIRST LINE + SECOND LINE]]) + eq('it worked...', eval('g:foo')) + end) + it('does not complete/interrupt insert-mode mapping', function() + command("inoremap xx foo") + helpers.insert([[ + FIRST LINE + SECOND LINE]]) + nvim('input', 'ix') + helpers.expect([[ + FIRST LINE + SECOND LINxE]]) + -- Make any non-async RPC request. (expect() does RPC, but be explicit) + nvim('get_current_buf') + -- Send input to complete the mapping. + nvim('input', 'x') + helpers.expect([[ + FIRST LINE + SECOND LINxxE]]) -- TODO: should be "SECOND LINfooE" #6166 + end) + end) + describe('nvim_replace_termcodes', function() it('escapes K_SPECIAL as K_SPECIAL KS_SPECIAL KE_FILLER', function() eq('\128\254X', helpers.nvim('replace_termcodes', '\128', true, true, true)) -- cgit From 3922237b1442deed48d1be32a7967e9eb6a19151 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 4 Sep 2017 08:46:10 +0200 Subject: test: lint --- test/functional/api/vim_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 5566c6d8e4..252a380378 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -382,7 +382,7 @@ describe('api', function() helpers.expect([[ FIRST LINE SECOND LINE]]) - eq('it worked...', eval('g:foo')) + eq('it worked...', helpers.eval('g:foo')) end) it('does not complete/interrupt insert-mode mapping', function() command("inoremap xx foo") -- cgit From ce852bab04c63262ce8545c01a4ff4fc827148a1 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 4 Sep 2017 22:45:14 +0200 Subject: eventloop: K_EVENT does not finish mapping The "mapping" tests added in 541dde36e330 were flawed: - Unlike op-pending mode, RPCs are _blocked_ during map-pending. So a synchronous RPC like nvim_get_current_buf() waits until 'timeoutlen', then the mapping is canceled. - helpers.expect() also performs a blocking RPC, so again that must not intervene the two nvim_input() calls. closes #6166 --- test/functional/api/vim_spec.lua | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 252a380378..a4b643589a 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -346,37 +346,33 @@ describe('api', function() end) describe('RPC (K_EVENT) #6166', function() - it('does not complete/interrupt normal-mode operator', function() + it('does not complete ("interrupt") normal-mode operator-pending', function() helpers.insert([[ FIRST LINE SECOND LINE]]) nvim('input', 'gg') nvim('input', 'gu') - -- Make any non-async RPC request. + -- Make any RPC request (can be non-async: op-pending does not block). nvim('get_current_buf') -- Buffer should not change. helpers.expect([[ FIRST LINE SECOND LINE]]) -- Now send input to complete the operator. - nvim("input", "j") + nvim('input', 'j') helpers.expect([[ - first line - second line]]) + first line + second line]]) end) - -- TODO: bug #6166 - pending('does not complete/interrupt normal-mode mapping', function() + it('does not complete ("interrupt") normal-mode map-pending', function() command("nnoremap dd :let g:foo='it worked...'") helpers.insert([[ FIRST LINE SECOND LINE]]) nvim('input', 'gg') nvim('input', 'd') - helpers.expect([[ - FIRST LINE - SECOND LINE]]) - -- Make any non-async RPC request. (expect() does RPC, but be explicit) - nvim('get_current_buf') + -- Make any RPC request (must be async, because map-pending blocks). + nvim('get_api_info') -- Send input to complete the mapping. nvim('input', 'd') helpers.expect([[ @@ -384,22 +380,20 @@ describe('api', function() SECOND LINE]]) eq('it worked...', helpers.eval('g:foo')) end) - it('does not complete/interrupt insert-mode mapping', function() - command("inoremap xx foo") + it('does not complete ("interrupt") insert-mode map-pending', function() + command('inoremap xx foo') + command('set timeoutlen=9999') helpers.insert([[ FIRST LINE SECOND LINE]]) nvim('input', 'ix') - helpers.expect([[ - FIRST LINE - SECOND LINxE]]) - -- Make any non-async RPC request. (expect() does RPC, but be explicit) - nvim('get_current_buf') + -- Make any RPC request (must be async, because map-pending blocks). + nvim('get_api_info') -- Send input to complete the mapping. nvim('input', 'x') helpers.expect([[ FIRST LINE - SECOND LINxxE]]) -- TODO: should be "SECOND LINfooE" #6166 + SECOND LINfooE]]) end) end) -- cgit From 9d6bac3219a0cc1647b560b0d28b0a3fce9dc96a Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 16 Sep 2017 12:17:59 +0200 Subject: test: more coverage for RPC + op-pending #3732 --- test/functional/api/vim_spec.lua | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index a4b643589a..b849304d45 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -364,6 +364,24 @@ describe('api', function() first line second line]]) end) + + it('does not complete ("interrupt") `d` #3732', function() + local screen = Screen.new(20, 4) + screen:attach() + command('set listchars=eol:$') + command('set list') + feed('iabckkk') + feed('d') + -- Make any RPC request (can be non-async: op-pending does not block). + nvim('get_current_buf') + screen:expect([[ + ^a$ | + b$ | + c$ | + | + ]]) + end) + it('does not complete ("interrupt") normal-mode map-pending', function() command("nnoremap dd :let g:foo='it worked...'") helpers.insert([[ -- cgit From ba7277cfb4e2556f246446d06b53f3427f28130f Mon Sep 17 00:00:00 2001 From: Matthieu Coudron Date: Wed, 26 Jul 2017 23:28:26 +0200 Subject: Adds nvim_get_hl_by_name/by_id ...in order to retrieve highlights. Added test/functional/api/highlight_spec.lua HL_NORMAL is not really a good name, since it's more like an empty attribute than the normal's one. If one pays attention, syn_cterm_attr2entry is never called with attr=0 because it's always special cased before. I suggest in subsequent PRs we remove the ATTR_OFF and just insert an EMPTY ATTR/RESET_ATTR/UNINITIALIZED for id 0. --- test/functional/api/highlight_spec.lua | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 test/functional/api/highlight_spec.lua (limited to 'test/functional/api') diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua new file mode 100644 index 0000000000..1aacfaed03 --- /dev/null +++ b/test/functional/api/highlight_spec.lua @@ -0,0 +1,54 @@ + +local helpers = require('test.functional.helpers')(after_each) +local clear, nvim = helpers.clear, helpers.nvim +local Screen = require('test.functional.ui.screen') +local eq, eval = helpers.eq, helpers.eval +local command = helpers.command +local ok = helpers.ok +local meths = helpers.meths + + +describe('highlight api', function() + + before_each(function() + clear('--cmd', 'set termguicolors') + end) + + it("nvim_get_hl_by_id", function() + local expected_hl = { background = Screen.colors.Yellow, + foreground = Screen.colors.Red, + special = Screen.colors.Blue + } + + command('hi NewHighlight guifg=red guibg=yellow guisp=blue') + + local hl_id = eval("hlID('NewHighlight')") + eq(expected_hl, nvim("get_hl_by_id", hl_id)) + + -- assume there is no hl with 30000 + local err, emsg = pcall(meths.get_hl_by_id, 30000) + eq(false, err) + ok(string.find(emsg, 'Invalid highlight id') ~= nil) + end) + + it("nvim_get_hl_by_name", function() + local expected_hl = { background = Screen.colors.Yellow, + foreground = Screen.colors.Red } + + -- test "Normal" hl defaults + eq({}, nvim("get_hl_by_name", 'Normal')) + + command('hi NewHighlight guifg=red guibg=yellow') + eq(expected_hl, nvim("get_hl_by_name", 'NewHighlight')) + + command('hi Normal guifg=red guibg=yellow') + eq(expected_hl, nvim("get_hl_by_name", 'Normal')) + local err, emsg = pcall(meths.get_hl_by_name , 'unknown_highlight') + eq(false, err) + ok(string.find(emsg, 'Invalid highlight name') ~= nil) + end) + + + +end) + -- cgit From e3a2cca3878f44252eccdc1918cc8854145de860 Mon Sep 17 00:00:00 2001 From: Matthieu Coudron Date: Sun, 27 Aug 2017 00:33:36 +0200 Subject: Increased test coverage for RGB and cterm --- test/functional/api/highlight_spec.lua | 42 +++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index 1aacfaed03..a5d3871d13 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -8,47 +8,53 @@ local ok = helpers.ok local meths = helpers.meths -describe('highlight api', function() +describe('highlight api',function() + local expected_rgb = { background = Screen.colors.Yellow, + foreground = Screen.colors.Red, + special = Screen.colors.Blue, + bold = true, + } + + local expected_cterm = { background = 10, + underline = true, + } before_each(function() - clear('--cmd', 'set termguicolors') + clear() + command("hi NewHighlight cterm=underline ctermbg=green guifg=red guibg=yellow guisp=blue gui=bold") end) it("nvim_get_hl_by_id", function() - local expected_hl = { background = Screen.colors.Yellow, - foreground = Screen.colors.Red, - special = Screen.colors.Blue - } + local hl_id = eval("hlID('NewHighlight')") - command('hi NewHighlight guifg=red guibg=yellow guisp=blue') + eq(expected_cterm, nvim("get_hl_by_id", hl_id)) - local hl_id = eval("hlID('NewHighlight')") - eq(expected_hl, nvim("get_hl_by_id", hl_id)) + command('set termguicolors') + hl_id = eval("hlID('NewHighlight')") + eq(expected_rgb, nvim("get_hl_by_id", hl_id)) - -- assume there is no hl with 30000 + -- assume there is no hl with id 30000 local err, emsg = pcall(meths.get_hl_by_id, 30000) eq(false, err) ok(string.find(emsg, 'Invalid highlight id') ~= nil) end) it("nvim_get_hl_by_name", function() - local expected_hl = { background = Screen.colors.Yellow, + local expected_normal = { background = Screen.colors.Yellow, foreground = Screen.colors.Red } -- test "Normal" hl defaults eq({}, nvim("get_hl_by_name", 'Normal')) - command('hi NewHighlight guifg=red guibg=yellow') - eq(expected_hl, nvim("get_hl_by_name", 'NewHighlight')) + eq(expected_cterm, nvim("get_hl_by_name", 'NewHighlight')) + command('set termguicolors') + eq(expected_rgb, nvim("get_hl_by_name", 'NewHighlight')) command('hi Normal guifg=red guibg=yellow') - eq(expected_hl, nvim("get_hl_by_name", 'Normal')) + eq(expected_normal, nvim("get_hl_by_name", 'Normal')) + local err, emsg = pcall(meths.get_hl_by_name , 'unknown_highlight') eq(false, err) ok(string.find(emsg, 'Invalid highlight name') ~= nil) end) - - - end) - -- cgit From 3a006486397d611234abd9b429bce0b44d6b7747 Mon Sep 17 00:00:00 2001 From: Matthieu Coudron Date: Sun, 3 Sep 2017 05:25:57 +0200 Subject: Changed prototypes to accept a boolean "rgb" --- test/functional/api/highlight_spec.lua | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index a5d3871d13..4082b0daf9 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -27,14 +27,13 @@ describe('highlight api',function() it("nvim_get_hl_by_id", function() local hl_id = eval("hlID('NewHighlight')") - eq(expected_cterm, nvim("get_hl_by_id", hl_id)) + eq(expected_cterm, nvim("get_hl_by_id", hl_id, false)) - command('set termguicolors') hl_id = eval("hlID('NewHighlight')") - eq(expected_rgb, nvim("get_hl_by_id", hl_id)) + eq(expected_rgb, nvim("get_hl_by_id", hl_id, true)) - -- assume there is no hl with id 30000 - local err, emsg = pcall(meths.get_hl_by_id, 30000) + -- assume there is no hl with id = 30000 + local err, emsg = pcall(meths.get_hl_by_id, 30000, false) eq(false, err) ok(string.find(emsg, 'Invalid highlight id') ~= nil) end) @@ -44,16 +43,15 @@ describe('highlight api',function() foreground = Screen.colors.Red } -- test "Normal" hl defaults - eq({}, nvim("get_hl_by_name", 'Normal')) + eq({}, nvim("get_hl_by_name", 'Normal', true)) - eq(expected_cterm, nvim("get_hl_by_name", 'NewHighlight')) - command('set termguicolors') - eq(expected_rgb, nvim("get_hl_by_name", 'NewHighlight')) + eq(expected_cterm, nvim("get_hl_by_name", 'NewHighlight', false)) + eq(expected_rgb, nvim("get_hl_by_name", 'NewHighlight', true)) command('hi Normal guifg=red guibg=yellow') - eq(expected_normal, nvim("get_hl_by_name", 'Normal')) + eq(expected_normal, nvim("get_hl_by_name", 'Normal', true)) - local err, emsg = pcall(meths.get_hl_by_name , 'unknown_highlight') + local err, emsg = pcall(meths.get_hl_by_name , 'unknown_highlight', false) eq(false, err) ok(string.find(emsg, 'Invalid highlight name') ~= nil) end) -- cgit From 52517321d1859c31fef14aa75d784615693fcecb Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 8 Oct 2017 20:23:11 +0200 Subject: test: nvim_get_hl_by_name/by_id #7082 - test all properties - test failure modes --- test/functional/api/highlight_spec.lua | 77 +++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 15 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index c482128a31..2297a0760f 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -6,15 +6,26 @@ local command = helpers.command local meths = helpers.meths describe('highlight api',function() - local expected_rgb = { background = Screen.colors.Yellow, - foreground = Screen.colors.Red, - special = Screen.colors.Blue, - bold = true, - } - - local expected_cterm = { background = 10, - underline = true, - } + local expected_rgb = { + background = Screen.colors.Yellow, + foreground = Screen.colors.Red, + special = Screen.colors.Blue, + bold = true, + } + local expected_cterm = { + background = 10, + underline = true, + } + local expected_rgb2 = { + background = Screen.colors.Yellow, + foreground = Screen.colors.Red, + special = Screen.colors.Blue, + bold = true, + italic = true, + reverse = true, + undercurl = true, + underline = true, + } before_each(function() clear() @@ -26,31 +37,67 @@ describe('highlight api',function() eq(expected_cterm, nvim("get_hl_by_id", hl_id, false)) hl_id = eval("hlID('NewHighlight')") + -- Test valid id. eq(expected_rgb, nvim("get_hl_by_id", hl_id, true)) - local expected_error = 'Invalid highlight id' - -- Assume there is no hl id 30000. + -- Test invalid id. local err, emsg = pcall(meths.get_hl_by_id, 30000, false) eq(false, err) - eq(expected_error, string.match(emsg, expected_error)) + eq('Invalid highlight id: 30000', string.match(emsg, 'Invalid.*')) + + -- Test all highlight properties. + command('hi NewHighlight gui=underline,bold,undercurl,italic,reverse') + eq(expected_rgb2, nvim("get_hl_by_id", hl_id, true)) + + -- Test nil argument. + err, emsg = pcall(meths.get_hl_by_id, { nil }, false) + eq(false, err) + eq('Wrong type for argument 1, expecting Integer', + string.match(emsg, 'Wrong.*')) + + -- Test 0 argument. + err, emsg = pcall(meths.get_hl_by_id, 0, false) + eq(false, err) + eq('Invalid highlight id: 0', + string.match(emsg, 'Invalid.*')) + + -- Test -1 argument. + err, emsg = pcall(meths.get_hl_by_id, -1, false) + eq(false, err) + eq('Invalid highlight id: -1', + string.match(emsg, 'Invalid.*')) end) it("nvim_get_hl_by_name", function() local expected_normal = { background = Screen.colors.Yellow, foreground = Screen.colors.Red } - -- Test "Normal" hl defaults. + -- Test `Normal` default values. eq({}, nvim("get_hl_by_name", 'Normal', true)) eq(expected_cterm, nvim("get_hl_by_name", 'NewHighlight', false)) eq(expected_rgb, nvim("get_hl_by_name", 'NewHighlight', true)) + -- Test `Normal` modified values. command('hi Normal guifg=red guibg=yellow') eq(expected_normal, nvim("get_hl_by_name", 'Normal', true)) - local expected_error = 'Invalid highlight name' + -- Test invalid name. local err, emsg = pcall(meths.get_hl_by_name , 'unknown_highlight', false) eq(false, err) - eq(expected_error, string.match(emsg, expected_error)) + eq('Invalid highlight name: unknown_highlight', + string.match(emsg, 'Invalid.*')) + + -- Test nil argument. + err, emsg = pcall(meths.get_hl_by_name , { nil }, false) + eq(false, err) + eq('Wrong type for argument 1, expecting String', + string.match(emsg, 'Wrong.*')) + + -- Test empty string argument. + err, emsg = pcall(meths.get_hl_by_name , '', false) + eq(false, err) + eq('Invalid highlight name: ', + string.match(emsg, 'Invalid.*')) end) end) -- cgit From 2a3bcd1ff883429a3dd17e7ae5ddc1396abbad17 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 29 Oct 2017 03:06:53 +0100 Subject: rpc: Don't delay notifications when request is pending (#6544) With the old behavior, if a GUI makes a blocking request that requires user interaction (like nvim_input()), it would not get any screen updates. The client, not nvim, should decide how to handle notifications during a pending request. If an rplugin wants to avoid async calls while a sync call is busy, it likely wants to avoid processing async calls while another async call also is handled as well. This may break the expectation of some existing rplugins. For compatibility, remote/define.vim reimplements the old behavior. Clients can opt-out by specifying `sync=urgent`. - Legacy hosts should be updated to use `sync=urgent`. They could add a flag indicating which async methods are always safe to call and which must wait until the main loop returns. - New hosts can expose the full asyncness, they don't need to offer both behaviors. ref #6532 ref #1398 d83868fe9071af1b4866594eac12f7aa0fa71b53 --- test/functional/api/server_requests_spec.lua | 61 +++++++++++++++++++--------- 1 file changed, 42 insertions(+), 19 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 9f245d913b..4380e52b8b 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -109,7 +109,28 @@ describe('server -> client', function() end) describe('requests and notifications interleaved', function() - -- This tests that the following scenario won't happen: + it('does not delay notifications during pending request', function() + local received = false + local function on_setup() + eq("retval", funcs.rpcrequest(cid, "doit")) + stop() + end + local function on_request(method) + if method == "doit" then + funcs.rpcnotify(cid, "headsup") + eq(true,received) + return "retval" + end + end + local function on_notification(method) + if method == "headsup" then + received = true + end + end + run(on_request, on_notification, on_setup) + end) + + -- This tests the following scenario: -- -- server->client [request ] (1) -- client->server [request ] (2) triggered by (1) @@ -124,36 +145,38 @@ describe('server -> client', function() -- only deals with one server->client request at a time. (In other words, -- the client cannot send a response to a request that is not at the top -- of nvim's request stack). - -- - -- But above scenario shoudn't happen by the way notifications are dealt in - -- Nvim: they are only sent after there are no pending server->client - -- request(the request stack fully unwinds). So (3) is only sent after the - -- client returns (6). - it('works', function() - local expected = 300 - local notified = 0 + pending('will close connection if not properly synchronized', function() local function on_setup() eq('notified!', eval('rpcrequest('..cid..', "notify")')) end local function on_request(method) - eq('notify', method) - eq(1, eval('rpcnotify('..cid..', "notification")')) - return 'notified!' + if method == "notify" then + eq(1, eval('rpcnotify('..cid..', "notification")')) + return 'notified!' + elseif method == "nested" then + -- do some busywork, so the first request will return + -- before this one + for _ = 1, 5 do + eq(2, eval("1+1")) + end + eq(1, eval('rpcnotify('..cid..', "nested_done")')) + return 'done!' + end end local function on_notification(method) - eq('notification', method) - if notified == expected then - stop() - return + if method == "notification" then + eq('done!', eval('rpcrequest('..cid..', "nested")')) + elseif method == "nested_done" then + -- this should never have been sent + ok(false) end - notified = notified + 1 - eq('notified!', eval('rpcrequest('..cid..', "notify")')) end run(on_request, on_notification, on_setup) - eq(expected, notified) + -- ignore disconnect failure, otherwise detected by after_each + clear() end) end) -- cgit From a39c8b7ce30ddeed4329c28c42b1b699103dccab Mon Sep 17 00:00:00 2001 From: James McCoy Date: Thu, 2 Nov 2017 05:45:38 -0400 Subject: test: server_spec: Tolerate missing protocol (#7478) Travis disabled IPv6: [ RUN ] serverstart(), serverstop() parses endpoints correctly: FAIL ...build/neovim/neovim/test/functional/eval/server_spec.lua:83: Expected objects to be the same. Passed in: (table) { [1] = '127.0.0.1:12345' } Expected: (table) { [1] = '127.0.0.1:12345' *[2] = '::1:12345' } Change all tests to ensure a server was actually started before expecting it to be returned from serverlist(). --- test/functional/api/server_requests_spec.lua | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'test/functional/api') diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 4380e52b8b..a2a198ca83 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -304,14 +304,30 @@ describe('server -> client', function() connect_test(server, 'pipe', address) end) - it('via ip address', function() + it('via ipv4 address', function() local server = spawn(nvim_argv) set_session(server) local address = funcs.serverstart("127.0.0.1:") + if #address == 0 then + pending('no ipv4 stack', function() end) + return + end eq('127.0.0.1:', string.sub(address,1,10)) connect_test(server, 'tcp', address) end) + it('via ipv6 address', function() + local server = spawn(nvim_argv) + set_session(server) + local address = funcs.serverstart('::1:') + if #address == 0 then + pending('no ipv6 stack', function() end) + return + end + eq('::1:', string.sub(address,1,4)) + connect_test(server, 'tcp', address) + end) + it('via hostname', function() local server = spawn(nvim_argv) set_session(server) -- cgit From b9d5aea073521f3278bea257be306b7ac2b8d83c Mon Sep 17 00:00:00 2001 From: ZyX Date: Fri, 3 Nov 2017 11:38:59 +0300 Subject: api/vim: Create part of nvim_parse_expression function --- test/functional/api/vim_spec.lua | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index b849304d45..6b44698638 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -710,4 +710,9 @@ describe('api', function() ok(err:match(': Wrong type for argument 1, expecting String') ~= nil) end) + describe('nvim_parse_expression', function() + -- FIXME + -- FIXME Test error + end) + end) -- cgit From 7bc6de75263f58c6c4f999bc86a6454ae9f28b80 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 5 Nov 2017 02:41:44 +0300 Subject: api/vim,functests: Add tests for nvim_parse_expression, fix found bugs --- test/functional/api/vim_spec.lua | 6868 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 6868 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 6b44698638..bb7785657d 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1,5 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') +local global_helpers = require('test.helpers') + local NIL = helpers.NIL local clear, nvim, eq, neq = helpers.clear, helpers.nvim, helpers.eq, helpers.neq local ok, nvim_async, feed = helpers.ok, helpers.nvim_async, helpers.feed @@ -10,6 +12,9 @@ local request = helpers.request local meth_pcall = helpers.meth_pcall local command = helpers.command +local intchar2lua = global_helpers.intchar2lua +local format_string = global_helpers.format_string + describe('api', function() before_each(clear) @@ -711,8 +716,6871 @@ describe('api', function() end) describe('nvim_parse_expression', function() + local function simplify_east_api_node(line, east_api_node) + if east_api_node.children then + for k, v in pairs(east_api_node.children) do + east_api_node.children[k] = simplify_east_api_node(line, v) + end + end + local typ = east_api_node.type + if typ == 'Register' then + typ = typ .. ('(name=%s)'):format( + tostring(intchar2lua(east_api_node.name))) + east_api_node.name = nil + elseif typ == 'PlainIdentifier' then + typ = typ .. ('(scope=%s,ident=%s)'):format( + tostring(intchar2lua(east_api_node.scope)), east_api_node.ident) + east_api_node.scope = nil + east_api_node.ident = nil + elseif typ == 'PlainKey' then + typ = typ .. ('(key=%s)'):format(east_api_node.ident) + east_api_node.ident = nil + elseif typ == 'Comparison' then + typ = typ .. ('(type=%s,inv=%u,ccs=%s)'):format( + east_api_node.cmp_type, east_api_node.invert and 1 or 0, + east_api_node.ccs_strategy) + east_api_node.ccs_strategy = nil + east_api_node.cmp_type = nil + east_api_node.invert = nil + elseif typ == 'Integer' then + typ = typ .. ('(val=%u)'):format(east_api_node.ivalue) + east_api_node.ivalue = nil + elseif typ == 'Float' then + typ = typ .. ('(val=%e)'):format(east_api_node.fvalue) + east_api_node.fvalue = nil + elseif typ == 'SingleQuotedString' or typ == 'DoubleQuotedString' then + typ = format_string('%s(val=%q)', typ, east_api_node.svalue) + east_api_node.svalue = nil + elseif typ == 'Option' then + typ = ('%s(scope=%s,ident=%s)'):format( + typ, + tostring(intchar2lua(east_api_node.scope)), + east_api_node.ident) + east_api_node.ident = nil + east_api_node.scope = nil + elseif typ == 'Environment' then + typ = ('%s(ident=%s)'):format(typ, east_api_node.ident) + east_api_node.ident = nil + end + typ = ('%s:%u:%u:%s'):format( + typ, east_api_node.start[1], east_api_node.start[2], + line:sub(east_api_node.start[2] + 1, + east_api_node.start[2] + 1 + east_api_node.len - 1)) + assert(east_api_node.start[2] + east_api_node.len - 1 <= #line) + for k, _ in pairs(east_api_node.start) do + assert(({true, true})[k]) + end + east_api_node.start = nil + east_api_node.type = nil + east_api_node.len = nil + local can_simplify = true + for _, _ in pairs(east_api_node) do + if can_simplify then can_simplify = false end + end + if can_simplify then + return typ + else + east_api_node[1] = typ + return east_api_node + end + end + local function simplify_east_api(line, east_api) + if east_api.error then + east_api.err = east_api.error + east_api.error = nil + east_api.err.msg = east_api.err.message + east_api.err.message = nil + end + if east_api.ast then + east_api.ast = {simplify_east_api_node(line, east_api.ast)} + end + return east_api + end + local function simplify_east_hl(line, east_hl) + for i, v in ipairs(east_hl) do + east_hl[i] = ('%s:%u:%u:%s'):format( + v[4], + v[1], + v[2], + line:sub(v[2] + 1, v[3])) + end + return east_hl + end + local function check_parsing(str, flags, exp_ast, exp_highlighting_fs) + if flags == 0 then + flags = "" + end + + local err, msg = pcall(function() + local east_api = meths.parse_expression(str, flags, true) + local east_hl = east_api.highlight + east_api.highlight = nil + local ast = simplify_east_api(str, east_api) + local hls = simplify_east_hl(str, east_hl) + eq(exp_ast, ast) + if exp_highlighting_fs then + local exp_highlighting = {} + local next_col = 0 + for i, h in ipairs(exp_highlighting_fs) do + exp_highlighting[i], next_col = h(next_col) + end + eq(exp_highlighting, hls) + end + end) + if not err then + msg = format_string('Error while processing test (%r, %s):\n%s', + str, flags, msg) + error(msg) + end + end + local function hl(group, str, shift) + return function(next_col) + local col = next_col + (shift or 0) + return (('%s:%u:%u:%s'):format( + 'NVim' .. group, + 0, + col, + str)), (col + #str) + end + end + it('works with + and @a', function() + check_parsing('@a', 0, { + ast = { + 'Register(name=a):0:0:@a', + }, + }, { + hl('Register', '@a'), + }) + check_parsing('+@a', 0, { + ast = { + { + 'UnaryPlus:0:0:+', + children = { + 'Register(name=a):0:1:@a', + }, + }, + }, + }, { + hl('UnaryPlus', '+'), + hl('Register', '@a'), + }) + check_parsing('@a+@b', 0, { + ast = { + { + 'BinaryPlus:0:2:+', + children = { + 'Register(name=a):0:0:@a', + 'Register(name=b):0:3:@b', + }, + }, + }, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+'), + hl('Register', '@b'), + }) + check_parsing('@a+@b+@c', 0, { + ast = { + { + 'BinaryPlus:0:5:+', + children = { + { + 'BinaryPlus:0:2:+', + children = { + 'Register(name=a):0:0:@a', + 'Register(name=b):0:3:@b', + }, + }, + 'Register(name=c):0:6:@c', + }, + }, + }, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+'), + hl('Register', '@b'), + hl('BinaryPlus', '+'), + hl('Register', '@c'), + }) + check_parsing('+@a+@b', 0, { + ast = { + { + 'BinaryPlus:0:3:+', + children = { + { + 'UnaryPlus:0:0:+', + children = { + 'Register(name=a):0:1:@a', + }, + }, + 'Register(name=b):0:4:@b', + }, + }, + }, + }, { + hl('UnaryPlus', '+'), + hl('Register', '@a'), + hl('BinaryPlus', '+'), + hl('Register', '@b'), + }) + check_parsing('+@a++@b', 0, { + ast = { + { + 'BinaryPlus:0:3:+', + children = { + { + 'UnaryPlus:0:0:+', + children = { + 'Register(name=a):0:1:@a', + }, + }, + { + 'UnaryPlus:0:4:+', + children = { + 'Register(name=b):0:5:@b', + }, + }, + }, + }, + }, + }, { + hl('UnaryPlus', '+'), + hl('Register', '@a'), + hl('BinaryPlus', '+'), + hl('UnaryPlus', '+'), + hl('Register', '@b'), + }) + check_parsing('@a@b', 0, { + ast = { + { + 'OpMissing:0:2:', + children = { + 'Register(name=a):0:0:@a', + 'Register(name=b):0:2:@b', + }, + }, + }, + err = { + arg = '@b', + msg = 'E15: Missing operator: %.*s', + }, + }, { + hl('Register', '@a'), + hl('InvalidRegister', '@b'), + }) + check_parsing(' @a \t @b', 0, { + ast = { + { + 'OpMissing:0:3:', + children = { + 'Register(name=a):0:0: @a', + 'Register(name=b):0:3: \t @b', + }, + }, + }, + err = { + arg = '@b', + msg = 'E15: Missing operator: %.*s', + }, + }, { + hl('Register', '@a', 1), + hl('InvalidSpacing', ' \t '), + hl('Register', '@b'), + }) + check_parsing('+', 0, { + ast = { + 'UnaryPlus:0:0:+', + }, + err = { + arg = '', + msg = 'E15: Expected value, got EOC: %.*s', + }, + }, { + hl('UnaryPlus', '+'), + }) + check_parsing(' +', 0, { + ast = { + 'UnaryPlus:0:0: +', + }, + err = { + arg = '', + msg = 'E15: Expected value, got EOC: %.*s', + }, + }, { + hl('UnaryPlus', '+', 1), + }) + check_parsing('@a+ ', 0, { + ast = { + { + 'BinaryPlus:0:2:+', + children = { + 'Register(name=a):0:0:@a', + }, + }, + }, + err = { + arg = '', + msg = 'E15: Expected value, got EOC: %.*s', + }, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+'), + }) + end) + it('works with @a, + and parenthesis', function() + check_parsing('(@a)', 0, { + ast = { + { + 'Nested:0:0:(', + children = { + 'Register(name=a):0:1:@a', + }, + }, + }, + }, { + hl('NestingParenthesis', '('), + hl('Register', '@a'), + hl('NestingParenthesis', ')'), + }) + check_parsing('()', 0, { + ast = { + { + 'Nested:0:0:(', + children = { + 'Missing:0:1:', + }, + }, + }, + err = { + arg = ')', + msg = 'E15: Expected value, got parenthesis: %.*s', + }, + }, { + hl('NestingParenthesis', '('), + hl('InvalidNestingParenthesis', ')'), + }) + check_parsing(')', 0, { + ast = { + { + 'Nested:0:0:', + children = { + 'Missing:0:0:', + }, + }, + }, + err = { + arg = ')', + msg = 'E15: Expected value, got parenthesis: %.*s', + }, + }, { + hl('InvalidNestingParenthesis', ')'), + }) + check_parsing('+)', 0, { + ast = { + { + 'Nested:0:1:', + children = { + { + 'UnaryPlus:0:0:+', + children = { + 'Missing:0:1:', + }, + }, + }, + }, + }, + err = { + arg = ')', + msg = 'E15: Expected value, got parenthesis: %.*s', + }, + }, { + hl('UnaryPlus', '+'), + hl('InvalidNestingParenthesis', ')'), + }) + check_parsing('+@a(@b)', 0, { + ast = { + { + 'UnaryPlus:0:0:+', + children = { + { + 'Call:0:3:(', + children = { + 'Register(name=a):0:1:@a', + 'Register(name=b):0:4:@b', + }, + }, + }, + }, + }, + }, { + hl('UnaryPlus', '+'), + hl('Register', '@a'), + hl('CallingParenthesis', '('), + hl('Register', '@b'), + hl('CallingParenthesis', ')'), + }) + check_parsing('@a+@b(@c)', 0, { + ast = { + { + 'BinaryPlus:0:2:+', + children = { + 'Register(name=a):0:0:@a', + { + 'Call:0:5:(', + children = { + 'Register(name=b):0:3:@b', + 'Register(name=c):0:6:@c', + }, + }, + }, + }, + }, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+'), + hl('Register', '@b'), + hl('CallingParenthesis', '('), + hl('Register', '@c'), + hl('CallingParenthesis', ')'), + }) + check_parsing('@a()', 0, { + ast = { + { + 'Call:0:2:(', + children = { + 'Register(name=a):0:0:@a', + }, + }, + }, + }, { + hl('Register', '@a'), + hl('CallingParenthesis', '('), + hl('CallingParenthesis', ')'), + }) + check_parsing('@a ()', 0, { + ast = { + { + 'OpMissing:0:2:', + children = { + 'Register(name=a):0:0:@a', + { + 'Nested:0:2: (', + children = { + 'Missing:0:4:', + }, + }, + }, + }, + }, + err = { + arg = '()', + msg = 'E15: Missing operator: %.*s', + }, + }, { + hl('Register', '@a'), + hl('InvalidSpacing', ' '), + hl('NestingParenthesis', '('), + hl('InvalidNestingParenthesis', ')'), + }) + check_parsing( + '@a + (@b)', 0, { + ast = { + { + 'BinaryPlus:0:2: +', + children = { + 'Register(name=a):0:0:@a', + { + 'Nested:0:4: (', + children = { + 'Register(name=b):0:6:@b', + }, + }, + }, + }, + }, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+', 1), + hl('NestingParenthesis', '(', 1), + hl('Register', '@b'), + hl('NestingParenthesis', ')'), + }) + check_parsing( + '@a + (+@b)', 0, { + ast = { + { + 'BinaryPlus:0:2: +', + children = { + 'Register(name=a):0:0:@a', + { + 'Nested:0:4: (', + children = { + { + 'UnaryPlus:0:6:+', + children = { + 'Register(name=b):0:7:@b', + }, + }, + }, + }, + }, + }, + }, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+', 1), + hl('NestingParenthesis', '(', 1), + hl('UnaryPlus', '+'), + hl('Register', '@b'), + hl('NestingParenthesis', ')'), + }) + check_parsing( + '@a + (@b + @c)', 0, { + ast = { + { + 'BinaryPlus:0:2: +', + children = { + 'Register(name=a):0:0:@a', + { + 'Nested:0:4: (', + children = { + { + 'BinaryPlus:0:8: +', + children = { + 'Register(name=b):0:6:@b', + 'Register(name=c):0:10: @c', + }, + }, + }, + }, + }, + }, + }, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+', 1), + hl('NestingParenthesis', '(', 1), + hl('Register', '@b'), + hl('BinaryPlus', '+', 1), + hl('Register', '@c', 1), + hl('NestingParenthesis', ')'), + }) + check_parsing('(@a)+@b', 0, { + ast = { + { + 'BinaryPlus:0:4:+', + children = { + { + 'Nested:0:0:(', + children = { + 'Register(name=a):0:1:@a', + }, + }, + 'Register(name=b):0:5:@b', + }, + }, + }, + }, { + hl('NestingParenthesis', '('), + hl('Register', '@a'), + hl('NestingParenthesis', ')'), + hl('BinaryPlus', '+'), + hl('Register', '@b'), + }) + check_parsing('@a+(@b)(@c)', 0, { + -- 01234567890 + ast = { + { + 'BinaryPlus:0:2:+', + children = { + 'Register(name=a):0:0:@a', + { + 'Call:0:7:(', + children = { + { + 'Nested:0:3:(', + children = { 'Register(name=b):0:4:@b' }, + }, + 'Register(name=c):0:8:@c', + }, + }, + }, + }, + }, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+'), + hl('NestingParenthesis', '('), + hl('Register', '@b'), + hl('NestingParenthesis', ')'), + hl('CallingParenthesis', '('), + hl('Register', '@c'), + hl('CallingParenthesis', ')'), + }) + check_parsing('@a+((@b))(@c)', 0, { + -- 01234567890123456890123456789 + -- 0 1 2 + ast = { + { + 'BinaryPlus:0:2:+', + children = { + 'Register(name=a):0:0:@a', + { + 'Call:0:9:(', + children = { + { + 'Nested:0:3:(', + children = { + { + 'Nested:0:4:(', + children = { 'Register(name=b):0:5:@b' } + }, + }, + }, + 'Register(name=c):0:10:@c', + }, + }, + }, + }, + }, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+'), + hl('NestingParenthesis', '('), + hl('NestingParenthesis', '('), + hl('Register', '@b'), + hl('NestingParenthesis', ')'), + hl('NestingParenthesis', ')'), + hl('CallingParenthesis', '('), + hl('Register', '@c'), + hl('CallingParenthesis', ')'), + }) + check_parsing('@a+((@b))+@c', 0, { + -- 01234567890123456890123456789 + -- 0 1 2 + ast = { + { + 'BinaryPlus:0:9:+', + children = { + { + 'BinaryPlus:0:2:+', + children = { + 'Register(name=a):0:0:@a', + { + 'Nested:0:3:(', + children = { + { + 'Nested:0:4:(', + children = { 'Register(name=b):0:5:@b' } + }, + }, + }, + }, + }, + 'Register(name=c):0:10:@c', + }, + }, + }, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+'), + hl('NestingParenthesis', '('), + hl('NestingParenthesis', '('), + hl('Register', '@b'), + hl('NestingParenthesis', ')'), + hl('NestingParenthesis', ')'), + hl('BinaryPlus', '+'), + hl('Register', '@c'), + }) + check_parsing( + '@a + (@b + @c) + @d(@e) + (+@f) + ((+@g(@h))(@j)(@k))(@l)', 0, {--[[ + | | | | | | | | || | | || | | ||| || || || || + 000000000011111111112222222222333333333344444444445555555 + 012345678901234567890123456789012345678901234567890123456 + ]] + ast = {{ + 'BinaryPlus:0:31: +', + children = { + { + 'BinaryPlus:0:23: +', + children = { + { + 'BinaryPlus:0:14: +', + children = { + { + 'BinaryPlus:0:2: +', + children = { + 'Register(name=a):0:0:@a', + { + 'Nested:0:4: (', + children = { + { + 'BinaryPlus:0:8: +', + children = { + 'Register(name=b):0:6:@b', + 'Register(name=c):0:10: @c', + }, + }, + }, + }, + }, + }, + { + 'Call:0:19:(', + children = { + 'Register(name=d):0:16: @d', + 'Register(name=e):0:20:@e', + }, + }, + }, + }, + { + 'Nested:0:25: (', + children = { + { + 'UnaryPlus:0:27:+', + children = { + 'Register(name=f):0:28:@f', + }, + }, + }, + }, + }, + }, + { + 'Call:0:53:(', + children = { + { + 'Nested:0:33: (', + children = { + { + 'Call:0:48:(', + children = { + { + 'Call:0:44:(', + children = { + { + 'Nested:0:35:(', + children = { + { + 'UnaryPlus:0:36:+', + children = { + { + 'Call:0:39:(', + children = { + 'Register(name=g):0:37:@g', + 'Register(name=h):0:40:@h', + }, + }, + }, + }, + }, + }, + 'Register(name=j):0:45:@j', + }, + }, + 'Register(name=k):0:49:@k', + }, + }, + }, + }, + 'Register(name=l):0:54:@l', + }, + }, + }, + }}, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+', 1), + hl('NestingParenthesis', '(', 1), + hl('Register', '@b'), + hl('BinaryPlus', '+', 1), + hl('Register', '@c', 1), + hl('NestingParenthesis', ')'), + hl('BinaryPlus', '+', 1), + hl('Register', '@d', 1), + hl('CallingParenthesis', '('), + hl('Register', '@e'), + hl('CallingParenthesis', ')'), + hl('BinaryPlus', '+', 1), + hl('NestingParenthesis', '(', 1), + hl('UnaryPlus', '+'), + hl('Register', '@f'), + hl('NestingParenthesis', ')'), + hl('BinaryPlus', '+', 1), + hl('NestingParenthesis', '(', 1), + hl('NestingParenthesis', '('), + hl('UnaryPlus', '+'), + hl('Register', '@g'), + hl('CallingParenthesis', '('), + hl('Register', '@h'), + hl('CallingParenthesis', ')'), + hl('NestingParenthesis', ')'), + hl('CallingParenthesis', '('), + hl('Register', '@j'), + hl('CallingParenthesis', ')'), + hl('CallingParenthesis', '('), + hl('Register', '@k'), + hl('CallingParenthesis', ')'), + hl('NestingParenthesis', ')'), + hl('CallingParenthesis', '('), + hl('Register', '@l'), + hl('CallingParenthesis', ')'), + }) + check_parsing('@a)', 0, { + -- 012 + ast = { + { + 'Nested:0:2:', + children = { + 'Register(name=a):0:0:@a', + }, + }, + }, + err = { + arg = ')', + msg = 'E15: Unexpected closing parenthesis: %.*s', + }, + }, { + hl('Register', '@a'), + hl('InvalidNestingParenthesis', ')'), + }) + check_parsing('(@a', 0, { + -- 012 + ast = { + { + 'Nested:0:0:(', + children = { + 'Register(name=a):0:1:@a', + }, + }, + }, + err = { + arg = '(@a', + msg = 'E110: Missing closing parenthesis for nested expression: %.*s', + }, + }, { + hl('NestingParenthesis', '('), + hl('Register', '@a'), + }) + check_parsing('@a(@b', 0, { + -- 01234 + ast = { + { + 'Call:0:2:(', + children = { + 'Register(name=a):0:0:@a', + 'Register(name=b):0:3:@b', + }, + }, + }, + err = { + arg = '(@b', + msg = 'E116: Missing closing parenthesis for function call: %.*s', + }, + }, { + hl('Register', '@a'), + hl('CallingParenthesis', '('), + hl('Register', '@b'), + }) + check_parsing('@a(@b, @c, @d, @e)', 0, { + -- 012345678901234567 + -- 0 1 + ast = { + { + 'Call:0:2:(', + children = { + 'Register(name=a):0:0:@a', + { + 'Comma:0:5:,', + children = { + 'Register(name=b):0:3:@b', + { + 'Comma:0:9:,', + children = { + 'Register(name=c):0:6: @c', + { + 'Comma:0:13:,', + children = { + 'Register(name=d):0:10: @d', + 'Register(name=e):0:14: @e', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, { + hl('Register', '@a'), + hl('CallingParenthesis', '('), + hl('Register', '@b'), + hl('Comma', ','), + hl('Register', '@c', 1), + hl('Comma', ','), + hl('Register', '@d', 1), + hl('Comma', ','), + hl('Register', '@e', 1), + hl('CallingParenthesis', ')'), + }) + check_parsing('@a(@b(@c))', 0, { + -- 01234567890123456789012345678901234567 + -- 0 1 2 3 + ast = { + { + 'Call:0:2:(', + children = { + 'Register(name=a):0:0:@a', + { + 'Call:0:5:(', + children = { + 'Register(name=b):0:3:@b', + 'Register(name=c):0:6:@c', + }, + }, + }, + }, + }, + }, { + hl('Register', '@a'), + hl('CallingParenthesis', '('), + hl('Register', '@b'), + hl('CallingParenthesis', '('), + hl('Register', '@c'), + hl('CallingParenthesis', ')'), + hl('CallingParenthesis', ')'), + }) + check_parsing('@a(@b(@c(@d(@e), @f(@g(@h), @i(@j)))))', 0, { + -- 01234567890123456789012345678901234567 + -- 0 1 2 3 + ast = { + { + 'Call:0:2:(', + children = { + 'Register(name=a):0:0:@a', + { + 'Call:0:5:(', + children = { + 'Register(name=b):0:3:@b', + { + 'Call:0:8:(', + children = { + 'Register(name=c):0:6:@c', + { + 'Comma:0:15:,', + children = { + { + 'Call:0:11:(', + children = { + 'Register(name=d):0:9:@d', + 'Register(name=e):0:12:@e', + }, + }, + { + 'Call:0:19:(', + children = { + 'Register(name=f):0:16: @f', + { + 'Comma:0:26:,', + children = { + { + 'Call:0:22:(', + children = { + 'Register(name=g):0:20:@g', + 'Register(name=h):0:23:@h', + }, + }, + { + 'Call:0:30:(', + children = { + 'Register(name=i):0:27: @i', + 'Register(name=j):0:31:@j', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, { + hl('Register', '@a'), + hl('CallingParenthesis', '('), + hl('Register', '@b'), + hl('CallingParenthesis', '('), + hl('Register', '@c'), + hl('CallingParenthesis', '('), + hl('Register', '@d'), + hl('CallingParenthesis', '('), + hl('Register', '@e'), + hl('CallingParenthesis', ')'), + hl('Comma', ','), + hl('Register', '@f', 1), + hl('CallingParenthesis', '('), + hl('Register', '@g'), + hl('CallingParenthesis', '('), + hl('Register', '@h'), + hl('CallingParenthesis', ')'), + hl('Comma', ','), + hl('Register', '@i', 1), + hl('CallingParenthesis', '('), + hl('Register', '@j'), + hl('CallingParenthesis', ')'), + hl('CallingParenthesis', ')'), + hl('CallingParenthesis', ')'), + hl('CallingParenthesis', ')'), + hl('CallingParenthesis', ')'), + }) + end) + it('works with variable names, including curly braces ones', function() + check_parsing('var', 0, { + ast = { + 'PlainIdentifier(scope=0,ident=var):0:0:var', + }, + }, { + hl('IdentifierName', 'var'), + }) + check_parsing('g:var', 0, { + ast = { + 'PlainIdentifier(scope=g,ident=var):0:0:g:var', + }, + }, { + hl('IdentifierScope', 'g'), + hl('IdentifierScopeDelimiter', ':'), + hl('IdentifierName', 'var'), + }) + check_parsing('g:', 0, { + ast = { + 'PlainIdentifier(scope=g,ident=):0:0:g:', + }, + }, { + hl('IdentifierScope', 'g'), + hl('IdentifierScopeDelimiter', ':'), + }) + check_parsing('{a}', 0, { + -- 012 + ast = { + { + 'CurlyBracesIdentifier:0:0:{', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + }, + }, + }, + }, { + hl('Curly', '{'), + hl('IdentifierName', 'a'), + hl('Curly', '}'), + }) + check_parsing('{a:b}', 0, { + -- 012 + ast = { + { + 'CurlyBracesIdentifier:0:0:{', + children = { + 'PlainIdentifier(scope=a,ident=b):0:1:a:b', + }, + }, + }, + }, { + hl('Curly', '{'), + hl('IdentifierScope', 'a'), + hl('IdentifierScopeDelimiter', ':'), + hl('IdentifierName', 'b'), + hl('Curly', '}'), + }) + check_parsing('{a:@b}', 0, { + -- 012345 + ast = { + { + 'CurlyBracesIdentifier:0:0:{', + children = { + { + 'OpMissing:0:3:', + children={ + 'PlainIdentifier(scope=a,ident=):0:1:a:', + 'Register(name=b):0:3:@b', + }, + }, + }, + }, + }, + err = { + arg = '@b}', + msg = 'E15: Missing operator: %.*s', + }, + }, { + hl('Curly', '{'), + hl('IdentifierScope', 'a'), + hl('IdentifierScopeDelimiter', ':'), + hl('InvalidRegister', '@b'), + hl('Curly', '}'), + }) + check_parsing('{@a}', 0, { + ast = { + { + 'CurlyBracesIdentifier:0:0:{', + children = { + 'Register(name=a):0:1:@a', + }, + }, + }, + }, { + hl('Curly', '{'), + hl('Register', '@a'), + hl('Curly', '}'), + }) + check_parsing('{@a}{@b}', 0, { + -- 01234567 + ast = { + { + 'ComplexIdentifier:0:4:', + children = { + { + 'CurlyBracesIdentifier:0:0:{', + children = { + 'Register(name=a):0:1:@a', + }, + }, + { + 'CurlyBracesIdentifier:0:4:{', + children = { + 'Register(name=b):0:5:@b', + }, + }, + }, + }, + }, + }, { + hl('Curly', '{'), + hl('Register', '@a'), + hl('Curly', '}'), + hl('Curly', '{'), + hl('Register', '@b'), + hl('Curly', '}'), + }) + check_parsing('g:{@a}', 0, { + -- 01234567 + ast = { + { + 'ComplexIdentifier:0:2:', + children = { + 'PlainIdentifier(scope=g,ident=):0:0:g:', + { + 'CurlyBracesIdentifier:0:2:{', + children = { + 'Register(name=a):0:3:@a', + }, + }, + }, + }, + }, + }, { + hl('IdentifierScope', 'g'), + hl('IdentifierScopeDelimiter', ':'), + hl('Curly', '{'), + hl('Register', '@a'), + hl('Curly', '}'), + }) + check_parsing('{@a}_test', 0, { + -- 012345678 + ast = { + { + 'ComplexIdentifier:0:4:', + children = { + { + 'CurlyBracesIdentifier:0:0:{', + children = { + 'Register(name=a):0:1:@a', + }, + }, + 'PlainIdentifier(scope=0,ident=_test):0:4:_test', + }, + }, + }, + }, { + hl('Curly', '{'), + hl('Register', '@a'), + hl('Curly', '}'), + hl('IdentifierName', '_test'), + }) + check_parsing('g:{@a}_test', 0, { + -- 01234567890 + ast = { + { + 'ComplexIdentifier:0:2:', + children = { + 'PlainIdentifier(scope=g,ident=):0:0:g:', + { + 'ComplexIdentifier:0:6:', + children = { + { + 'CurlyBracesIdentifier:0:2:{', + children = { + 'Register(name=a):0:3:@a', + }, + }, + 'PlainIdentifier(scope=0,ident=_test):0:6:_test', + }, + }, + }, + }, + }, + }, { + hl('IdentifierScope', 'g'), + hl('IdentifierScopeDelimiter', ':'), + hl('Curly', '{'), + hl('Register', '@a'), + hl('Curly', '}'), + hl('IdentifierName', '_test'), + }) + check_parsing('g:{@a}_test()', 0, { + -- 0123456789012 + ast = { + { + 'Call:0:11:(', + children = { + { + 'ComplexIdentifier:0:2:', + children = { + 'PlainIdentifier(scope=g,ident=):0:0:g:', + { + 'ComplexIdentifier:0:6:', + children = { + { + 'CurlyBracesIdentifier:0:2:{', + children = { + 'Register(name=a):0:3:@a', + }, + }, + 'PlainIdentifier(scope=0,ident=_test):0:6:_test', + }, + }, + }, + }, + }, + }, + }, + }, { + hl('IdentifierScope', 'g'), + hl('IdentifierScopeDelimiter', ':'), + hl('Curly', '{'), + hl('Register', '@a'), + hl('Curly', '}'), + hl('IdentifierName', '_test'), + hl('CallingParenthesis', '('), + hl('CallingParenthesis', ')'), + }) + check_parsing('{@a} ()', 0, { + -- 0123456789012 + ast = { + { + 'Call:0:4: (', + children = { + { + 'CurlyBracesIdentifier:0:0:{', + children = { + 'Register(name=a):0:1:@a', + }, + }, + }, + }, + }, + }, { + hl('Curly', '{'), + hl('Register', '@a'), + hl('Curly', '}'), + hl('CallingParenthesis', '(', 1), + hl('CallingParenthesis', ')'), + }) + check_parsing('g:{@a} ()', 0, { + -- 0123456789012 + ast = { + { + 'Call:0:6: (', + children = { + { + 'ComplexIdentifier:0:2:', + children = { + 'PlainIdentifier(scope=g,ident=):0:0:g:', + { + 'CurlyBracesIdentifier:0:2:{', + children = { + 'Register(name=a):0:3:@a', + }, + }, + }, + }, + }, + }, + }, + }, { + hl('IdentifierScope', 'g'), + hl('IdentifierScopeDelimiter', ':'), + hl('Curly', '{'), + hl('Register', '@a'), + hl('Curly', '}'), + hl('CallingParenthesis', '(', 1), + hl('CallingParenthesis', ')'), + }) + check_parsing('{@a', 0, { + -- 012 + ast = { + { + 'UnknownFigure:0:0:{', + children = { + 'Register(name=a):0:1:@a', + }, + }, + }, + err = { + arg = '{@a', + msg = 'E15: Missing closing figure brace: %.*s', + }, + }, { + hl('FigureBrace', '{'), + hl('Register', '@a'), + }) + end) + it('works with lambdas and dictionaries', function() + check_parsing('{}', 0, { + ast = { + 'DictLiteral:0:0:{', + }, + }, { + hl('Dict', '{'), + hl('Dict', '}'), + }) + check_parsing('{->@a}', 0, { + ast = { + { + 'Lambda:0:0:{', + children = { + { + 'Arrow:0:1:->', + children = { + 'Register(name=a):0:3:@a', + }, + }, + }, + }, + }, + }, { + hl('Lambda', '{'), + hl('Arrow', '->'), + hl('Register', '@a'), + hl('Lambda', '}'), + }) + check_parsing('{->@a+@b}', 0, { + -- 012345678 + ast = { + { + 'Lambda:0:0:{', + children = { + { + 'Arrow:0:1:->', + children = { + { + 'BinaryPlus:0:5:+', + children = { + 'Register(name=a):0:3:@a', + 'Register(name=b):0:6:@b', + }, + }, + }, + }, + }, + }, + }, + }, { + hl('Lambda', '{'), + hl('Arrow', '->'), + hl('Register', '@a'), + hl('BinaryPlus', '+'), + hl('Register', '@b'), + hl('Lambda', '}'), + }) + check_parsing('{a->@a}', 0, { + -- 012345678 + ast = { + { + 'Lambda:0:0:{', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + { + 'Arrow:0:2:->', + children = { + 'Register(name=a):0:4:@a', + }, + }, + }, + }, + }, + }, { + hl('Lambda', '{'), + hl('IdentifierName', 'a'), + hl('Arrow', '->'), + hl('Register', '@a'), + hl('Lambda', '}'), + }) + check_parsing('{a,b->@a}', 0, { + -- 012345678 + ast = { + { + 'Lambda:0:0:{', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + 'PlainIdentifier(scope=0,ident=b):0:3:b', + }, + }, + { + 'Arrow:0:4:->', + children = { + 'Register(name=a):0:6:@a', + }, + }, + }, + }, + }, + }, { + hl('Lambda', '{'), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('IdentifierName', 'b'), + hl('Arrow', '->'), + hl('Register', '@a'), + hl('Lambda', '}'), + }) + check_parsing('{a,b,c->@a}', 0, { + -- 01234567890 + ast = { + { + 'Lambda:0:0:{', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + { + 'Comma:0:4:,', + children = { + 'PlainIdentifier(scope=0,ident=b):0:3:b', + 'PlainIdentifier(scope=0,ident=c):0:5:c', + }, + }, + }, + }, + { + 'Arrow:0:6:->', + children = { + 'Register(name=a):0:8:@a', + }, + }, + }, + }, + }, + }, { + hl('Lambda', '{'), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('IdentifierName', 'b'), + hl('Comma', ','), + hl('IdentifierName', 'c'), + hl('Arrow', '->'), + hl('Register', '@a'), + hl('Lambda', '}'), + }) + check_parsing('{a,b,c,d->@a}', 0, { + -- 0123456789012 + ast = { + { + 'Lambda:0:0:{', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + { + 'Comma:0:4:,', + children = { + 'PlainIdentifier(scope=0,ident=b):0:3:b', + { + 'Comma:0:6:,', + children = { + 'PlainIdentifier(scope=0,ident=c):0:5:c', + 'PlainIdentifier(scope=0,ident=d):0:7:d', + }, + }, + }, + }, + }, + }, + { + 'Arrow:0:8:->', + children = { + 'Register(name=a):0:10:@a', + }, + }, + }, + }, + }, + }, { + hl('Lambda', '{'), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('IdentifierName', 'b'), + hl('Comma', ','), + hl('IdentifierName', 'c'), + hl('Comma', ','), + hl('IdentifierName', 'd'), + hl('Arrow', '->'), + hl('Register', '@a'), + hl('Lambda', '}'), + }) + check_parsing('{a,b,c,d,->@a}', 0, { + -- 01234567890123 + ast = { + { + 'Lambda:0:0:{', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + { + 'Comma:0:4:,', + children = { + 'PlainIdentifier(scope=0,ident=b):0:3:b', + { + 'Comma:0:6:,', + children = { + 'PlainIdentifier(scope=0,ident=c):0:5:c', + { + 'Comma:0:8:,', + children = { + 'PlainIdentifier(scope=0,ident=d):0:7:d', + }, + }, + }, + }, + }, + }, + }, + }, + { + 'Arrow:0:9:->', + children = { + 'Register(name=a):0:11:@a', + }, + }, + }, + }, + }, + }, { + hl('Lambda', '{'), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('IdentifierName', 'b'), + hl('Comma', ','), + hl('IdentifierName', 'c'), + hl('Comma', ','), + hl('IdentifierName', 'd'), + hl('Comma', ','), + hl('Arrow', '->'), + hl('Register', '@a'), + hl('Lambda', '}'), + }) + check_parsing('{a,b->{c,d->{e,f->@a}}}', 0, { + -- 01234567890123456789012 + -- 0 1 2 + ast = { + { + 'Lambda:0:0:{', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + 'PlainIdentifier(scope=0,ident=b):0:3:b', + }, + }, + { + 'Arrow:0:4:->', + children = { + { + 'Lambda:0:6:{', + children = { + { + 'Comma:0:8:,', + children = { + 'PlainIdentifier(scope=0,ident=c):0:7:c', + 'PlainIdentifier(scope=0,ident=d):0:9:d', + }, + }, + { + 'Arrow:0:10:->', + children = { + { + 'Lambda:0:12:{', + children = { + { + 'Comma:0:14:,', + children = { + 'PlainIdentifier(scope=0,ident=e):0:13:e', + 'PlainIdentifier(scope=0,ident=f):0:15:f', + }, + }, + { + 'Arrow:0:16:->', + children = { + 'Register(name=a):0:18:@a', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, { + hl('Lambda', '{'), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('IdentifierName', 'b'), + hl('Arrow', '->'), + hl('Lambda', '{'), + hl('IdentifierName', 'c'), + hl('Comma', ','), + hl('IdentifierName', 'd'), + hl('Arrow', '->'), + hl('Lambda', '{'), + hl('IdentifierName', 'e'), + hl('Comma', ','), + hl('IdentifierName', 'f'), + hl('Arrow', '->'), + hl('Register', '@a'), + hl('Lambda', '}'), + hl('Lambda', '}'), + hl('Lambda', '}'), + }) + check_parsing('{a,b->c,d}', 0, { + -- 0123456789 + ast = { + { + 'Lambda:0:0:{', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + 'PlainIdentifier(scope=0,ident=b):0:3:b', + }, + }, + { + 'Arrow:0:4:->', + children = { + { + 'Comma:0:7:,', + children = { + 'PlainIdentifier(scope=0,ident=c):0:6:c', + 'PlainIdentifier(scope=0,ident=d):0:8:d', + }, + }, + }, + }, + }, + }, + }, + err = { + arg = ',d}', + msg = 'E15: Comma outside of call, lambda or literal: %.*s', + }, + }, { + hl('Lambda', '{'), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('IdentifierName', 'b'), + hl('Arrow', '->'), + hl('IdentifierName', 'c'), + hl('InvalidComma', ','), + hl('IdentifierName', 'd'), + hl('Lambda', '}'), + }) + check_parsing('a,b,c,d', 0, { + -- 0123456789 + ast = { + { + 'Comma:0:1:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'Comma:0:3:,', + children = { + 'PlainIdentifier(scope=0,ident=b):0:2:b', + { + 'Comma:0:5:,', + children = { + 'PlainIdentifier(scope=0,ident=c):0:4:c', + 'PlainIdentifier(scope=0,ident=d):0:6:d', + }, + }, + }, + }, + }, + }, + }, + err = { + arg = ',b,c,d', + msg = 'E15: Comma outside of call, lambda or literal: %.*s', + }, + }, { + hl('IdentifierName', 'a'), + hl('InvalidComma', ','), + hl('IdentifierName', 'b'), + hl('InvalidComma', ','), + hl('IdentifierName', 'c'), + hl('InvalidComma', ','), + hl('IdentifierName', 'd'), + }) + check_parsing('a,b,c,d,', 0, { + -- 0123456789 + ast = { + { + 'Comma:0:1:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'Comma:0:3:,', + children = { + 'PlainIdentifier(scope=0,ident=b):0:2:b', + { + 'Comma:0:5:,', + children = { + 'PlainIdentifier(scope=0,ident=c):0:4:c', + { + 'Comma:0:7:,', + children = { + 'PlainIdentifier(scope=0,ident=d):0:6:d', + }, + }, + }, + }, + }, + }, + }, + }, + }, + err = { + arg = ',b,c,d,', + msg = 'E15: Comma outside of call, lambda or literal: %.*s', + }, + }, { + hl('IdentifierName', 'a'), + hl('InvalidComma', ','), + hl('IdentifierName', 'b'), + hl('InvalidComma', ','), + hl('IdentifierName', 'c'), + hl('InvalidComma', ','), + hl('IdentifierName', 'd'), + hl('InvalidComma', ','), + }) + check_parsing(',', 0, { + -- 0123456789 + ast = { + { + 'Comma:0:0:,', + children = { + 'Missing:0:0:', + }, + }, + }, + err = { + arg = ',', + msg = 'E15: Expected value, got comma: %.*s', + }, + }, { + hl('InvalidComma', ','), + }) + check_parsing('{,a->@a}', 0, { + -- 0123456789 + ast = { + { + 'CurlyBracesIdentifier:0:0:{', + children = { + { + 'Arrow:0:3:->', + children = { + { + 'Comma:0:1:,', + children = { + 'Missing:0:1:', + 'PlainIdentifier(scope=0,ident=a):0:2:a', + }, + }, + 'Register(name=a):0:5:@a', + }, + }, + }, + }, + }, + err = { + arg = ',a->@a}', + msg = 'E15: Expected value, got comma: %.*s', + }, + }, { + hl('Curly', '{'), + hl('InvalidComma', ','), + hl('IdentifierName', 'a'), + hl('InvalidArrow', '->'), + hl('Register', '@a'), + hl('Curly', '}'), + }) + check_parsing('}', 0, { + -- 0123456789 + ast = { + 'UnknownFigure:0:0:', + }, + err = { + arg = '}', + msg = 'E15: Unexpected closing figure brace: %.*s', + }, + }, { + hl('InvalidFigureBrace', '}'), + }) + check_parsing('{->}', 0, { + -- 0123456789 + ast = { + { + 'Lambda:0:0:{', + children = { + 'Arrow:0:1:->', + }, + }, + }, + err = { + arg = '}', + msg = 'E15: Expected value, got closing figure brace: %.*s', + }, + }, { + hl('Lambda', '{'), + hl('Arrow', '->'), + hl('InvalidLambda', '}'), + }) + check_parsing('{a,b}', 0, { + -- 0123456789 + ast = { + { + 'Lambda:0:0:{', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + 'PlainIdentifier(scope=0,ident=b):0:3:b', + }, + }, + }, + }, + }, + err = { + arg = '}', + msg = 'E15: Expected lambda arguments list or arrow: %.*s', + }, + }, { + hl('Lambda', '{'), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('IdentifierName', 'b'), + hl('InvalidLambda', '}'), + }) + check_parsing('{a,}', 0, { + -- 0123456789 + ast = { + { + 'Lambda:0:0:{', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + }, + }, + }, + }, + }, + err = { + arg = '}', + msg = 'E15: Expected lambda arguments list or arrow: %.*s', + }, + }, { + hl('Lambda', '{'), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('InvalidLambda', '}'), + }) + check_parsing('{@a:@b}', 0, { + -- 0123456789 + ast = { + { + 'DictLiteral:0:0:{', + children = { + { + 'Colon:0:3::', + children = { + 'Register(name=a):0:1:@a', + 'Register(name=b):0:4:@b', + }, + }, + }, + }, + }, + }, { + hl('Dict', '{'), + hl('Register', '@a'), + hl('Colon', ':'), + hl('Register', '@b'), + hl('Dict', '}'), + }) + check_parsing('{@a:@b,@c:@d}', 0, { + -- 0123456789012 + -- 0 1 + ast = { + { + 'DictLiteral:0:0:{', + children = { + { + 'Comma:0:6:,', + children = { + { + 'Colon:0:3::', + children = { + 'Register(name=a):0:1:@a', + 'Register(name=b):0:4:@b', + }, + }, + { + 'Colon:0:9::', + children = { + 'Register(name=c):0:7:@c', + 'Register(name=d):0:10:@d', + }, + }, + }, + }, + }, + }, + }, + }, { + hl('Dict', '{'), + hl('Register', '@a'), + hl('Colon', ':'), + hl('Register', '@b'), + hl('Comma', ','), + hl('Register', '@c'), + hl('Colon', ':'), + hl('Register', '@d'), + hl('Dict', '}'), + }) + check_parsing('{@a:@b,@c:@d,@e:@f,}', 0, { + -- 01234567890123456789 + -- 0 1 + ast = { + { + 'DictLiteral:0:0:{', + children = { + { + 'Comma:0:6:,', + children = { + { + 'Colon:0:3::', + children = { + 'Register(name=a):0:1:@a', + 'Register(name=b):0:4:@b', + }, + }, + { + 'Comma:0:12:,', + children = { + { + 'Colon:0:9::', + children = { + 'Register(name=c):0:7:@c', + 'Register(name=d):0:10:@d', + }, + }, + { + 'Comma:0:18:,', + children = { + { + 'Colon:0:15::', + children = { + 'Register(name=e):0:13:@e', + 'Register(name=f):0:16:@f', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, { + hl('Dict', '{'), + hl('Register', '@a'), + hl('Colon', ':'), + hl('Register', '@b'), + hl('Comma', ','), + hl('Register', '@c'), + hl('Colon', ':'), + hl('Register', '@d'), + hl('Comma', ','), + hl('Register', '@e'), + hl('Colon', ':'), + hl('Register', '@f'), + hl('Comma', ','), + hl('Dict', '}'), + }) + check_parsing('{@a:@b,@c:@d,@e:@f,@g:}', 0, { + -- 01234567890123456789012 + -- 0 1 2 + ast = { + { + 'DictLiteral:0:0:{', + children = { + { + 'Comma:0:6:,', + children = { + { + 'Colon:0:3::', + children = { + 'Register(name=a):0:1:@a', + 'Register(name=b):0:4:@b', + }, + }, + { + 'Comma:0:12:,', + children = { + { + 'Colon:0:9::', + children = { + 'Register(name=c):0:7:@c', + 'Register(name=d):0:10:@d', + }, + }, + { + 'Comma:0:18:,', + children = { + { + 'Colon:0:15::', + children = { + 'Register(name=e):0:13:@e', + 'Register(name=f):0:16:@f', + }, + }, + { + 'Colon:0:21::', + children = { + 'Register(name=g):0:19:@g', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + err = { + arg = '}', + msg = 'E15: Expected value, got closing figure brace: %.*s', + }, + }, { + hl('Dict', '{'), + hl('Register', '@a'), + hl('Colon', ':'), + hl('Register', '@b'), + hl('Comma', ','), + hl('Register', '@c'), + hl('Colon', ':'), + hl('Register', '@d'), + hl('Comma', ','), + hl('Register', '@e'), + hl('Colon', ':'), + hl('Register', '@f'), + hl('Comma', ','), + hl('Register', '@g'), + hl('Colon', ':'), + hl('InvalidDict', '}'), + }) + check_parsing('{@a:@b,}', 0, { + -- 01234567890123 + -- 0 1 + ast = { + { + 'DictLiteral:0:0:{', + children = { + { + 'Comma:0:6:,', + children = { + { + 'Colon:0:3::', + children = { + 'Register(name=a):0:1:@a', + 'Register(name=b):0:4:@b', + }, + }, + }, + }, + }, + }, + }, + }, { + hl('Dict', '{'), + hl('Register', '@a'), + hl('Colon', ':'), + hl('Register', '@b'), + hl('Comma', ','), + hl('Dict', '}'), + }) + check_parsing('{({f -> g})(@h)(@i)}', 0, { + -- 01234567890123456789 + -- 0 1 + ast = { + { + 'CurlyBracesIdentifier:0:0:{', + children = { + { + 'Call:0:15:(', + children = { + { + 'Call:0:11:(', + children = { + { + 'Nested:0:1:(', + children = { + { + 'Lambda:0:2:{', + children = { + 'PlainIdentifier(scope=0,ident=f):0:3:f', + { + 'Arrow:0:4: ->', + children = { + 'PlainIdentifier(scope=0,ident=g):0:7: g', + }, + }, + }, + }, + }, + }, + 'Register(name=h):0:12:@h', + }, + }, + 'Register(name=i):0:16:@i', + }, + }, + }, + }, + }, + }, { + hl('Curly', '{'), + hl('NestingParenthesis', '('), + hl('Lambda', '{'), + hl('IdentifierName', 'f'), + hl('Arrow', '->', 1), + hl('IdentifierName', 'g', 1), + hl('Lambda', '}'), + hl('NestingParenthesis', ')'), + hl('CallingParenthesis', '('), + hl('Register', '@h'), + hl('CallingParenthesis', ')'), + hl('CallingParenthesis', '('), + hl('Register', '@i'), + hl('CallingParenthesis', ')'), + hl('Curly', '}'), + }) + check_parsing('a:{b()}c', 0, { + -- 01234567 + ast = { + { + 'ComplexIdentifier:0:2:', + children = { + 'PlainIdentifier(scope=a,ident=):0:0:a:', + { + 'ComplexIdentifier:0:7:', + children = { + { + 'CurlyBracesIdentifier:0:2:{', + children = { + { + 'Call:0:4:(', + children = { + 'PlainIdentifier(scope=0,ident=b):0:3:b', + }, + }, + }, + }, + 'PlainIdentifier(scope=0,ident=c):0:7:c', + }, + }, + }, + }, + }, + }, { + hl('IdentifierScope', 'a'), + hl('IdentifierScopeDelimiter', ':'), + hl('Curly', '{'), + hl('IdentifierName', 'b'), + hl('CallingParenthesis', '('), + hl('CallingParenthesis', ')'), + hl('Curly', '}'), + hl('IdentifierName', 'c'), + }) + check_parsing('a:{{b, c -> @d + @e + ({f -> g})(@h)}(@i)}j', 0, { + -- 01234567890123456789012345678901234567890123456 + -- 0 1 2 3 4 + ast = { + { + 'ComplexIdentifier:0:2:', + children = { + 'PlainIdentifier(scope=a,ident=):0:0:a:', + { + 'ComplexIdentifier:0:42:', + children = { + { + 'CurlyBracesIdentifier:0:2:{', + children = { + { + 'Call:0:37:(', + children = { + { + 'Lambda:0:3:{', + children = { + { + 'Comma:0:5:,', + children = { + 'PlainIdentifier(scope=0,ident=b):0:4:b', + 'PlainIdentifier(scope=0,ident=c):0:6: c', + }, + }, + { + 'Arrow:0:8: ->', + children = { + { + 'BinaryPlus:0:19: +', + children = { + { + 'BinaryPlus:0:14: +', + children = { + 'Register(name=d):0:11: @d', + 'Register(name=e):0:16: @e', + }, + }, + { + 'Call:0:32:(', + children = { + { + 'Nested:0:21: (', + children = { + { + 'Lambda:0:23:{', + children = { + 'PlainIdentifier(scope=0,ident=f):0:24:f', + { + 'Arrow:0:25: ->', + children = { + 'PlainIdentifier(scope=0,ident=g):0:28: g', + }, + }, + }, + }, + }, + }, + 'Register(name=h):0:33:@h', + }, + }, + }, + }, + }, + }, + }, + }, + 'Register(name=i):0:38:@i', + }, + }, + }, + }, + 'PlainIdentifier(scope=0,ident=j):0:42:j', + }, + }, + }, + }, + }, + }, { + hl('IdentifierScope', 'a'), + hl('IdentifierScopeDelimiter', ':'), + hl('Curly', '{'), + hl('Lambda', '{'), + hl('IdentifierName', 'b'), + hl('Comma', ','), + hl('IdentifierName', 'c', 1), + hl('Arrow', '->', 1), + hl('Register', '@d', 1), + hl('BinaryPlus', '+', 1), + hl('Register', '@e', 1), + hl('BinaryPlus', '+', 1), + hl('NestingParenthesis', '(', 1), + hl('Lambda', '{'), + hl('IdentifierName', 'f'), + hl('Arrow', '->', 1), + hl('IdentifierName', 'g', 1), + hl('Lambda', '}'), + hl('NestingParenthesis', ')'), + hl('CallingParenthesis', '('), + hl('Register', '@h'), + hl('CallingParenthesis', ')'), + hl('Lambda', '}'), + hl('CallingParenthesis', '('), + hl('Register', '@i'), + hl('CallingParenthesis', ')'), + hl('Curly', '}'), + hl('IdentifierName', 'j'), + }) + check_parsing('{@a + @b : @c + @d, @e + @f : @g + @i}', 0, { + -- 01234567890123456789012345678901234567 + -- 0 1 2 3 + ast = { + { + 'DictLiteral:0:0:{', + children = { + { + 'Comma:0:18:,', + children = { + { + 'Colon:0:8: :', + children = { + { + 'BinaryPlus:0:3: +', + children = { + 'Register(name=a):0:1:@a', + 'Register(name=b):0:5: @b', + }, + }, + { + 'BinaryPlus:0:13: +', + children = { + 'Register(name=c):0:10: @c', + 'Register(name=d):0:15: @d', + }, + }, + }, + }, + { + 'Colon:0:27: :', + children = { + { + 'BinaryPlus:0:22: +', + children = { + 'Register(name=e):0:19: @e', + 'Register(name=f):0:24: @f', + }, + }, + { + 'BinaryPlus:0:32: +', + children = { + 'Register(name=g):0:29: @g', + 'Register(name=i):0:34: @i', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, { + hl('Dict', '{'), + hl('Register', '@a'), + hl('BinaryPlus', '+', 1), + hl('Register', '@b', 1), + hl('Colon', ':', 1), + hl('Register', '@c', 1), + hl('BinaryPlus', '+', 1), + hl('Register', '@d', 1), + hl('Comma', ','), + hl('Register', '@e', 1), + hl('BinaryPlus', '+', 1), + hl('Register', '@f', 1), + hl('Colon', ':', 1), + hl('Register', '@g', 1), + hl('BinaryPlus', '+', 1), + hl('Register', '@i', 1), + hl('Dict', '}'), + }) + check_parsing('-> -> ->', 0, { + -- 01234567 + ast = { + { + 'Arrow:0:0:->', + children = { + 'Missing:0:0:', + { + 'Arrow:0:2: ->', + children = { + 'Missing:0:2:', + { + 'Arrow:0:5: ->', + children = { + 'Missing:0:5:', + }, + }, + }, + }, + }, + }, + }, + err = { + arg = '-> -> ->', + msg = 'E15: Unexpected arrow: %.*s', + }, + }, { + hl('InvalidArrow', '->'), + hl('InvalidArrow', '->', 1), + hl('InvalidArrow', '->', 1), + }) + check_parsing('a -> b -> c -> d', 0, { + -- 0123456789012345 + -- 0 1 + ast = { + { + 'Arrow:0:1: ->', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'Arrow:0:6: ->', + children = { + 'PlainIdentifier(scope=0,ident=b):0:4: b', + { + 'Arrow:0:11: ->', + children = { + 'PlainIdentifier(scope=0,ident=c):0:9: c', + 'PlainIdentifier(scope=0,ident=d):0:14: d', + }, + }, + }, + }, + }, + }, + }, + err = { + arg = '-> b -> c -> d', + msg = 'E15: Arrow outside of lambda: %.*s', + }, + }, { + hl('IdentifierName', 'a'), + hl('InvalidArrow', '->', 1), + hl('IdentifierName', 'b', 1), + hl('InvalidArrow', '->', 1), + hl('IdentifierName', 'c', 1), + hl('InvalidArrow', '->', 1), + hl('IdentifierName', 'd', 1), + }) + check_parsing('{a -> b -> c}', 0, { + -- 0123456789012 + -- 0 1 + ast = { + { + 'Lambda:0:0:{', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + { + 'Arrow:0:2: ->', + children = { + { + 'Arrow:0:7: ->', + children = { + 'PlainIdentifier(scope=0,ident=b):0:5: b', + 'PlainIdentifier(scope=0,ident=c):0:10: c', + }, + }, + }, + }, + }, + }, + }, + err = { + arg = '-> c}', + msg = 'E15: Arrow outside of lambda: %.*s', + }, + }, { + hl('Lambda', '{'), + hl('IdentifierName', 'a'), + hl('Arrow', '->', 1), + hl('IdentifierName', 'b', 1), + hl('InvalidArrow', '->', 1), + hl('IdentifierName', 'c', 1), + hl('Lambda', '}'), + }) + check_parsing('{a: -> b}', 0, { + -- 012345678 + ast = { + { + 'CurlyBracesIdentifier:0:0:{', + children = { + { + 'Arrow:0:3: ->', + children = { + 'PlainIdentifier(scope=a,ident=):0:1:a:', + 'PlainIdentifier(scope=0,ident=b):0:6: b', + }, + }, + }, + }, + }, + err = { + arg = '-> b}', + msg = 'E15: Arrow outside of lambda: %.*s', + }, + }, { + hl('Curly', '{'), + hl('IdentifierScope', 'a'), + hl('IdentifierScopeDelimiter', ':'), + hl('InvalidArrow', '->', 1), + hl('IdentifierName', 'b', 1), + hl('Curly', '}'), + }) + + check_parsing('{a:b -> b}', 0, { + -- 0123456789 + ast = { + { + 'CurlyBracesIdentifier:0:0:{', + children = { + { + 'Arrow:0:4: ->', + children = { + 'PlainIdentifier(scope=a,ident=b):0:1:a:b', + 'PlainIdentifier(scope=0,ident=b):0:7: b', + }, + }, + }, + }, + }, + err = { + arg = '-> b}', + msg = 'E15: Arrow outside of lambda: %.*s', + }, + }, { + hl('Curly', '{'), + hl('IdentifierScope', 'a'), + hl('IdentifierScopeDelimiter', ':'), + hl('IdentifierName', 'b'), + hl('InvalidArrow', '->', 1), + hl('IdentifierName', 'b', 1), + hl('Curly', '}'), + }) + + check_parsing('{a#b -> b}', 0, { + -- 0123456789 + ast = { + { + 'CurlyBracesIdentifier:0:0:{', + children = { + { + 'Arrow:0:4: ->', + children = { + 'PlainIdentifier(scope=0,ident=a#b):0:1:a#b', + 'PlainIdentifier(scope=0,ident=b):0:7: b', + }, + }, + }, + }, + }, + err = { + arg = '-> b}', + msg = 'E15: Arrow outside of lambda: %.*s', + }, + }, { + hl('Curly', '{'), + hl('IdentifierName', 'a#b'), + hl('InvalidArrow', '->', 1), + hl('IdentifierName', 'b', 1), + hl('Curly', '}'), + }) + check_parsing('{a : b : c}', 0, { + -- 01234567890 + -- 0 1 + ast = { + { + 'DictLiteral:0:0:{', + children = { + { + 'Colon:0:2: :', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + { + 'Colon:0:6: :', + children = { + 'PlainIdentifier(scope=0,ident=b):0:4: b', + 'PlainIdentifier(scope=0,ident=c):0:8: c', + }, + }, + }, + }, + }, + }, + }, + err = { + arg = ': c}', + msg = 'E15: Colon outside of dictionary or ternary operator: %.*s', + }, + }, { + hl('Dict', '{'), + hl('IdentifierName', 'a'), + hl('Colon', ':', 1), + hl('IdentifierName', 'b', 1), + hl('InvalidColon', ':', 1), + hl('IdentifierName', 'c', 1), + hl('Dict', '}'), + }) + check_parsing('{', 0, { + -- 0 + ast = { + 'UnknownFigure:0:0:{', + }, + err = { + arg = '{', + msg = 'E15: Missing closing figure brace: %.*s', + }, + }, { + hl('FigureBrace', '{'), + }) + check_parsing('{a', 0, { + -- 01 + ast = { + { + 'UnknownFigure:0:0:{', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + }, + }, + }, + err = { + arg = '{a', + msg = 'E15: Missing closing figure brace: %.*s', + }, + }, { + hl('FigureBrace', '{'), + hl('IdentifierName', 'a'), + }) + check_parsing('{a,b', 0, { + -- 0123 + ast = { + { + 'Lambda:0:0:{', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + 'PlainIdentifier(scope=0,ident=b):0:3:b', + }, + }, + }, + }, + }, + err = { + arg = '{a,b', + msg = 'E15: Missing closing figure brace for lambda: %.*s', + }, + }, { + hl('Lambda', '{'), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('IdentifierName', 'b'), + }) + check_parsing('{a,b->', 0, { + -- 012345 + ast = { + { + 'Lambda:0:0:{', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + 'PlainIdentifier(scope=0,ident=b):0:3:b', + }, + }, + 'Arrow:0:4:->', + }, + }, + }, + err = { + arg = '', + msg = 'E15: Expected value, got EOC: %.*s', + }, + }, { + hl('Lambda', '{'), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('IdentifierName', 'b'), + hl('Arrow', '->'), + }) + check_parsing('{a,b->c', 0, { + -- 0123456 + ast = { + { + 'Lambda:0:0:{', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + 'PlainIdentifier(scope=0,ident=b):0:3:b', + }, + }, + { + 'Arrow:0:4:->', + children = { + 'PlainIdentifier(scope=0,ident=c):0:6:c', + }, + }, + }, + }, + }, + err = { + arg = '{a,b->c', + msg = 'E15: Missing closing figure brace for lambda: %.*s', + }, + }, { + hl('Lambda', '{'), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('IdentifierName', 'b'), + hl('Arrow', '->'), + hl('IdentifierName', 'c'), + }) + check_parsing('{a : b', 0, { + -- 012345 + ast = { + { + 'DictLiteral:0:0:{', + children = { + { + 'Colon:0:2: :', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + 'PlainIdentifier(scope=0,ident=b):0:4: b', + }, + }, + }, + }, + }, + err = { + arg = '{a : b', + msg = 'E723: Missing end of Dictionary \'}\': %.*s', + }, + }, { + hl('Dict', '{'), + hl('IdentifierName', 'a'), + hl('Colon', ':', 1), + hl('IdentifierName', 'b', 1), + }) + check_parsing('{a : b,', 0, { + -- 0123456 + ast = { + { + 'DictLiteral:0:0:{', + children = { + { + 'Comma:0:6:,', + children = { + { + 'Colon:0:2: :', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + 'PlainIdentifier(scope=0,ident=b):0:4: b', + }, + }, + }, + }, + }, + }, + }, + err = { + arg = '', + msg = 'E15: Expected value, got EOC: %.*s', + }, + }, { + hl('Dict', '{'), + hl('IdentifierName', 'a'), + hl('Colon', ':', 1), + hl('IdentifierName', 'b', 1), + hl('Comma', ','), + }) + end) + it('works with ternary operator', function() + check_parsing('a ? b : c', 0, { + -- 012345678 + ast = { + { + 'Ternary:0:1: ?', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'TernaryValue:0:5: :', + children = { + 'PlainIdentifier(scope=0,ident=b):0:3: b', + 'PlainIdentifier(scope=0,ident=c):0:7: c', + }, + }, + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Ternary', '?', 1), + hl('IdentifierName', 'b', 1), + hl('TernaryColon', ':', 1), + hl('IdentifierName', 'c', 1), + }) + check_parsing('@a?@b?@c:@d:@e', 0, { + -- 01234567890123 + -- 0 1 + ast = { + { + 'Ternary:0:2:?', + children = { + 'Register(name=a):0:0:@a', + { + 'TernaryValue:0:11::', + children = { + { + 'Ternary:0:5:?', + children = { + 'Register(name=b):0:3:@b', + { + 'TernaryValue:0:8::', + children = { + 'Register(name=c):0:6:@c', + 'Register(name=d):0:9:@d', + }, + }, + }, + }, + 'Register(name=e):0:12:@e', + }, + }, + }, + }, + }, + }, { + hl('Register', '@a'), + hl('Ternary', '?'), + hl('Register', '@b'), + hl('Ternary', '?'), + hl('Register', '@c'), + hl('TernaryColon', ':'), + hl('Register', '@d'), + hl('TernaryColon', ':'), + hl('Register', '@e'), + }) + check_parsing('@a?@b:@c?@d:@e', 0, { + -- 01234567890123 + -- 0 1 + ast = { + { + 'Ternary:0:2:?', + children = { + 'Register(name=a):0:0:@a', + { + 'TernaryValue:0:5::', + children = { + 'Register(name=b):0:3:@b', + { + 'Ternary:0:8:?', + children = { + 'Register(name=c):0:6:@c', + { + 'TernaryValue:0:11::', + children = { + 'Register(name=d):0:9:@d', + 'Register(name=e):0:12:@e', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, { + hl('Register', '@a'), + hl('Ternary', '?'), + hl('Register', '@b'), + hl('TernaryColon', ':'), + hl('Register', '@c'), + hl('Ternary', '?'), + hl('Register', '@d'), + hl('TernaryColon', ':'), + hl('Register', '@e'), + }) + check_parsing('@a?@b?@c?@d:@e?@f:@g:@h?@i:@j:@k', 0, { + -- 01234567890123456789012345678901 + -- 0 1 2 3 + ast = { + { + 'Ternary:0:2:?', + children = { + 'Register(name=a):0:0:@a', + { + 'TernaryValue:0:29::', + children = { + { + 'Ternary:0:5:?', + children = { + 'Register(name=b):0:3:@b', + { + 'TernaryValue:0:20::', + children = { + { + 'Ternary:0:8:?', + children = { + 'Register(name=c):0:6:@c', + { + 'TernaryValue:0:11::', + children = { + 'Register(name=d):0:9:@d', + { + 'Ternary:0:14:?', + children = { + 'Register(name=e):0:12:@e', + { + 'TernaryValue:0:17::', + children = { + 'Register(name=f):0:15:@f', + 'Register(name=g):0:18:@g', + }, + }, + }, + }, + }, + }, + }, + }, + { + 'Ternary:0:23:?', + children = { + 'Register(name=h):0:21:@h', + { + 'TernaryValue:0:26::', + children = { + 'Register(name=i):0:24:@i', + 'Register(name=j):0:27:@j', + }, + }, + }, + }, + }, + }, + }, + }, + 'Register(name=k):0:30:@k', + }, + }, + }, + }, + }, + }, { + hl('Register', '@a'), + hl('Ternary', '?'), + hl('Register', '@b'), + hl('Ternary', '?'), + hl('Register', '@c'), + hl('Ternary', '?'), + hl('Register', '@d'), + hl('TernaryColon', ':'), + hl('Register', '@e'), + hl('Ternary', '?'), + hl('Register', '@f'), + hl('TernaryColon', ':'), + hl('Register', '@g'), + hl('TernaryColon', ':'), + hl('Register', '@h'), + hl('Ternary', '?'), + hl('Register', '@i'), + hl('TernaryColon', ':'), + hl('Register', '@j'), + hl('TernaryColon', ':'), + hl('Register', '@k'), + }) + check_parsing('?', 0, { + -- 0 + ast = { + { + 'Ternary:0:0:?', + children = { + 'Missing:0:0:', + 'TernaryValue:0:0:?', + }, + }, + }, + err = { + arg = '?', + msg = 'E15: Expected value, got question mark: %.*s', + }, + }, { + hl('InvalidTernary', '?'), + }) + + check_parsing('?:', 0, { + -- 01 + ast = { + { + 'Ternary:0:0:?', + children = { + 'Missing:0:0:', + { + 'TernaryValue:0:1::', + children = { + 'Missing:0:1:', + }, + }, + }, + }, + }, + err = { + arg = '?:', + msg = 'E15: Expected value, got question mark: %.*s', + }, + }, { + hl('InvalidTernary', '?'), + hl('InvalidTernaryColon', ':'), + }) + + check_parsing('?::', 0, { + -- 012 + ast = { + { + 'Colon:0:2::', + children = { + { + 'Ternary:0:0:?', + children = { + 'Missing:0:0:', + { + 'TernaryValue:0:1::', + children = { + 'Missing:0:1:', + 'Missing:0:2:', + }, + }, + }, + }, + }, + }, + }, + err = { + arg = '?::', + msg = 'E15: Expected value, got question mark: %.*s', + }, + }, { + hl('InvalidTernary', '?'), + hl('InvalidTernaryColon', ':'), + hl('InvalidColon', ':'), + }) + + check_parsing('a?b', 0, { + -- 012 + ast = { + { + 'Ternary:0:1:?', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'TernaryValue:0:1:?', + children = { + 'PlainIdentifier(scope=0,ident=b):0:2:b', + }, + }, + }, + }, + }, + err = { + arg = '?b', + msg = 'E109: Missing \':\' after \'?\': %.*s', + }, + }, { + hl('IdentifierName', 'a'), + hl('Ternary', '?'), + hl('IdentifierName', 'b'), + }) + check_parsing('a?b:', 0, { + -- 0123 + ast = { + { + 'Ternary:0:1:?', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'TernaryValue:0:1:?', + children = { + 'PlainIdentifier(scope=b,ident=):0:2:b:', + }, + }, + }, + }, + }, + err = { + arg = '?b:', + msg = 'E109: Missing \':\' after \'?\': %.*s', + }, + }, { + hl('IdentifierName', 'a'), + hl('Ternary', '?'), + hl('IdentifierScope', 'b'), + hl('IdentifierScopeDelimiter', ':'), + }) + + check_parsing('a?b::c', 0, { + -- 012345 + ast = { + { + 'Ternary:0:1:?', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'TernaryValue:0:4::', + children = { + 'PlainIdentifier(scope=b,ident=):0:2:b:', + 'PlainIdentifier(scope=0,ident=c):0:5:c', + }, + }, + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Ternary', '?'), + hl('IdentifierScope', 'b'), + hl('IdentifierScopeDelimiter', ':'), + hl('TernaryColon', ':'), + hl('IdentifierName', 'c'), + }) + + check_parsing('a?b :', 0, { + -- 01234 + ast = { + { + 'Ternary:0:1:?', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'TernaryValue:0:3: :', + children = { + 'PlainIdentifier(scope=0,ident=b):0:2:b', + }, + }, + }, + }, + }, + err = { + arg = '', + msg = 'E15: Expected value, got EOC: %.*s', + }, + }, { + hl('IdentifierName', 'a'), + hl('Ternary', '?'), + hl('IdentifierName', 'b'), + hl('TernaryColon', ':', 1), + }) + + check_parsing('(@a?@b:@c)?@d:@e', 0, { + -- 0123456789012345 + -- 0 1 + ast = { + { + 'Ternary:0:10:?', + children = { + { + 'Nested:0:0:(', + children = { + { + 'Ternary:0:3:?', + children = { + 'Register(name=a):0:1:@a', + { + 'TernaryValue:0:6::', + children = { + 'Register(name=b):0:4:@b', + 'Register(name=c):0:7:@c', + }, + }, + }, + }, + }, + }, + { + 'TernaryValue:0:13::', + children = { + 'Register(name=d):0:11:@d', + 'Register(name=e):0:14:@e', + }, + }, + }, + }, + }, + }, { + hl('NestingParenthesis', '('), + hl('Register', '@a'), + hl('Ternary', '?'), + hl('Register', '@b'), + hl('TernaryColon', ':'), + hl('Register', '@c'), + hl('NestingParenthesis', ')'), + hl('Ternary', '?'), + hl('Register', '@d'), + hl('TernaryColon', ':'), + hl('Register', '@e'), + }) + + check_parsing('(@a?@b:@c)?(@d?@e:@f):(@g?@h:@i)', 0, { + -- 01234567890123456789012345678901 + -- 0 1 2 3 + ast = { + { + 'Ternary:0:10:?', + children = { + { + 'Nested:0:0:(', + children = { + { + 'Ternary:0:3:?', + children = { + 'Register(name=a):0:1:@a', + { + 'TernaryValue:0:6::', + children = { + 'Register(name=b):0:4:@b', + 'Register(name=c):0:7:@c', + }, + }, + }, + }, + }, + }, + { + 'TernaryValue:0:21::', + children = { + { + 'Nested:0:11:(', + children = { + { + 'Ternary:0:14:?', + children = { + 'Register(name=d):0:12:@d', + { + 'TernaryValue:0:17::', + children = { + 'Register(name=e):0:15:@e', + 'Register(name=f):0:18:@f', + }, + }, + }, + }, + }, + }, + { + 'Nested:0:22:(', + children = { + { + 'Ternary:0:25:?', + children = { + 'Register(name=g):0:23:@g', + { + 'TernaryValue:0:28::', + children = { + 'Register(name=h):0:26:@h', + 'Register(name=i):0:29:@i', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, { + hl('NestingParenthesis', '('), + hl('Register', '@a'), + hl('Ternary', '?'), + hl('Register', '@b'), + hl('TernaryColon', ':'), + hl('Register', '@c'), + hl('NestingParenthesis', ')'), + hl('Ternary', '?'), + hl('NestingParenthesis', '('), + hl('Register', '@d'), + hl('Ternary', '?'), + hl('Register', '@e'), + hl('TernaryColon', ':'), + hl('Register', '@f'), + hl('NestingParenthesis', ')'), + hl('TernaryColon', ':'), + hl('NestingParenthesis', '('), + hl('Register', '@g'), + hl('Ternary', '?'), + hl('Register', '@h'), + hl('TernaryColon', ':'), + hl('Register', '@i'), + hl('NestingParenthesis', ')'), + }) + + check_parsing('(@a?@b:@c)?@d?@e:@f:@g?@h:@i', 0, { + -- 0123456789012345678901234567 + -- 0 1 2 + ast = { + { + 'Ternary:0:10:?', + children = { + { + 'Nested:0:0:(', + children = { + { + 'Ternary:0:3:?', + children = { + 'Register(name=a):0:1:@a', + { + 'TernaryValue:0:6::', + children = { + 'Register(name=b):0:4:@b', + 'Register(name=c):0:7:@c', + }, + }, + }, + }, + }, + }, + { + 'TernaryValue:0:19::', + children = { + { + 'Ternary:0:13:?', + children = { + 'Register(name=d):0:11:@d', + { + 'TernaryValue:0:16::', + children = { + 'Register(name=e):0:14:@e', + 'Register(name=f):0:17:@f', + }, + }, + }, + }, + { + 'Ternary:0:22:?', + children = { + 'Register(name=g):0:20:@g', + { + 'TernaryValue:0:25::', + children = { + 'Register(name=h):0:23:@h', + 'Register(name=i):0:26:@i', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, { + hl('NestingParenthesis', '('), + hl('Register', '@a'), + hl('Ternary', '?'), + hl('Register', '@b'), + hl('TernaryColon', ':'), + hl('Register', '@c'), + hl('NestingParenthesis', ')'), + hl('Ternary', '?'), + hl('Register', '@d'), + hl('Ternary', '?'), + hl('Register', '@e'), + hl('TernaryColon', ':'), + hl('Register', '@f'), + hl('TernaryColon', ':'), + hl('Register', '@g'), + hl('Ternary', '?'), + hl('Register', '@h'), + hl('TernaryColon', ':'), + hl('Register', '@i'), + }) + check_parsing('a?b{cdef}g:h', 0, { + -- 012345678901 + -- 0 1 + ast = { + { + 'Ternary:0:1:?', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'TernaryValue:0:10::', + children = { + { + 'ComplexIdentifier:0:3:', + children = { + 'PlainIdentifier(scope=0,ident=b):0:2:b', + { + 'ComplexIdentifier:0:9:', + children = { + { + 'CurlyBracesIdentifier:0:3:{', + children = { + 'PlainIdentifier(scope=0,ident=cdef):0:4:cdef', + }, + }, + 'PlainIdentifier(scope=0,ident=g):0:9:g', + }, + }, + }, + }, + 'PlainIdentifier(scope=0,ident=h):0:11:h', + }, + }, + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Ternary', '?'), + hl('IdentifierName', 'b'), + hl('Curly', '{'), + hl('IdentifierName', 'cdef'), + hl('Curly', '}'), + hl('IdentifierName', 'g'), + hl('TernaryColon', ':'), + hl('IdentifierName', 'h'), + }) + check_parsing('a ? b : c : d', 0, { + -- 0123456789012 + -- 0 1 + ast = { + { + 'Colon:0:9: :', + children = { + { + 'Ternary:0:1: ?', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'TernaryValue:0:5: :', + children = { + 'PlainIdentifier(scope=0,ident=b):0:3: b', + 'PlainIdentifier(scope=0,ident=c):0:7: c', + }, + }, + }, + }, + 'PlainIdentifier(scope=0,ident=d):0:11: d', + }, + }, + }, + err = { + arg = ': d', + msg = 'E15: Colon outside of dictionary or ternary operator: %.*s', + }, + }, { + hl('IdentifierName', 'a'), + hl('Ternary', '?', 1), + hl('IdentifierName', 'b', 1), + hl('TernaryColon', ':', 1), + hl('IdentifierName', 'c', 1), + hl('InvalidColon', ':', 1), + hl('IdentifierName', 'd', 1), + }) + end) + it('works with comparison operators', function() + check_parsing('a == b', 0, { + -- 012345 + ast = { + { + 'Comparison(type=Equal,inv=0,ccs=UseOption):0:1: ==', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:4: b', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Comparison', '==', 1), + hl('IdentifierName', 'b', 1), + }) + + check_parsing('a ==? b', 0, { + -- 0123456 + ast = { + { + 'Comparison(type=Equal,inv=0,ccs=IgnoreCase):0:1: ==?', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:5: b', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Comparison', '==', 1), + hl('ComparisonModifier', '?'), + hl('IdentifierName', 'b', 1), + }) + + check_parsing('a ==# b', 0, { + -- 0123456 + ast = { + { + 'Comparison(type=Equal,inv=0,ccs=MatchCase):0:1: ==#', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:5: b', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Comparison', '==', 1), + hl('ComparisonModifier', '#'), + hl('IdentifierName', 'b', 1), + }) + + check_parsing('a !=# b', 0, { + -- 0123456 + ast = { + { + 'Comparison(type=Equal,inv=1,ccs=MatchCase):0:1: !=#', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:5: b', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Comparison', '!=', 1), + hl('ComparisonModifier', '#'), + hl('IdentifierName', 'b', 1), + }) + + check_parsing('a <=# b', 0, { + -- 0123456 + ast = { + { + 'Comparison(type=Greater,inv=1,ccs=MatchCase):0:1: <=#', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:5: b', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Comparison', '<=', 1), + hl('ComparisonModifier', '#'), + hl('IdentifierName', 'b', 1), + }) + + check_parsing('a >=# b', 0, { + -- 0123456 + ast = { + { + 'Comparison(type=GreaterOrEqual,inv=0,ccs=MatchCase):0:1: >=#', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:5: b', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Comparison', '>=', 1), + hl('ComparisonModifier', '#'), + hl('IdentifierName', 'b', 1), + }) + + check_parsing('a ># b', 0, { + -- 012345 + ast = { + { + 'Comparison(type=Greater,inv=0,ccs=MatchCase):0:1: >#', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:4: b', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Comparison', '>', 1), + hl('ComparisonModifier', '#'), + hl('IdentifierName', 'b', 1), + }) + + check_parsing('a <# b', 0, { + -- 012345 + ast = { + { + 'Comparison(type=GreaterOrEqual,inv=1,ccs=MatchCase):0:1: <#', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:4: b', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Comparison', '<', 1), + hl('ComparisonModifier', '#'), + hl('IdentifierName', 'b', 1), + }) + + check_parsing('a is#b', 0, { + -- 012345 + ast = { + { + 'Comparison(type=Identical,inv=0,ccs=MatchCase):0:1: is#', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:5:b', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Comparison', 'is', 1), + hl('ComparisonModifier', '#'), + hl('IdentifierName', 'b'), + }) + + check_parsing('a is?b', 0, { + -- 012345 + ast = { + { + 'Comparison(type=Identical,inv=0,ccs=IgnoreCase):0:1: is?', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:5:b', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Comparison', 'is', 1), + hl('ComparisonModifier', '?'), + hl('IdentifierName', 'b'), + }) + + check_parsing('a isnot b', 0, { + -- 012345678 + ast = { + { + 'Comparison(type=Identical,inv=1,ccs=UseOption):0:1: isnot', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:7: b', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Comparison', 'isnot', 1), + hl('IdentifierName', 'b', 1), + }) + + check_parsing('a < b < c', 0, { + -- 012345678 + ast = { + { + 'Comparison(type=GreaterOrEqual,inv=1,ccs=UseOption):0:1: <', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'Comparison(type=GreaterOrEqual,inv=1,ccs=UseOption):0:5: <', + children = { + 'PlainIdentifier(scope=0,ident=b):0:3: b', + 'PlainIdentifier(scope=0,ident=c):0:7: c', + }, + }, + }, + }, + }, + err = { + arg = ' < c', + msg = 'E15: Operator is not associative: %.*s', + }, + }, { + hl('IdentifierName', 'a'), + hl('Comparison', '<', 1), + hl('IdentifierName', 'b', 1), + hl('InvalidComparison', '<', 1), + hl('IdentifierName', 'c', 1), + }) + + check_parsing('a < b <# c', 0, { + -- 012345678 + ast = { + { + 'Comparison(type=GreaterOrEqual,inv=1,ccs=UseOption):0:1: <', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'Comparison(type=GreaterOrEqual,inv=1,ccs=MatchCase):0:5: <#', + children = { + 'PlainIdentifier(scope=0,ident=b):0:3: b', + 'PlainIdentifier(scope=0,ident=c):0:8: c', + }, + }, + }, + }, + }, + err = { + arg = ' <# c', + msg = 'E15: Operator is not associative: %.*s', + }, + }, { + hl('IdentifierName', 'a'), + hl('Comparison', '<', 1), + hl('IdentifierName', 'b', 1), + hl('InvalidComparison', '<', 1), + hl('InvalidComparisonModifier', '#'), + hl('IdentifierName', 'c', 1), + }) + + check_parsing('a += b', 0, { + -- 012345 + ast = { + { + 'Comparison(type=Equal,inv=0,ccs=UseOption):0:3:=', + children = { + { + 'BinaryPlus:0:1: +', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'Missing:0:3:', + }, + }, + 'PlainIdentifier(scope=0,ident=b):0:4: b', + }, + }, + }, + err = { + arg = '= b', + msg = 'E15: Expected == or =~: %.*s', + }, + }, { + hl('IdentifierName', 'a'), + hl('BinaryPlus', '+', 1), + hl('InvalidComparison', '='), + hl('IdentifierName', 'b', 1), + }) + check_parsing('a + b == c + d', 0, { + -- 01234567890123 + -- 0 1 + ast = { + { + 'Comparison(type=Equal,inv=0,ccs=UseOption):0:5: ==', + children = { + { + 'BinaryPlus:0:1: +', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:3: b', + }, + }, + { + 'BinaryPlus:0:10: +', + children = { + 'PlainIdentifier(scope=0,ident=c):0:8: c', + 'PlainIdentifier(scope=0,ident=d):0:12: d', + }, + }, + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('BinaryPlus', '+', 1), + hl('IdentifierName', 'b', 1), + hl('Comparison', '==', 1), + hl('IdentifierName', 'c', 1), + hl('BinaryPlus', '+', 1), + hl('IdentifierName', 'd', 1), + }) + check_parsing('+ a == + b', 0, { + -- 0123456789 + ast = { + { + 'Comparison(type=Equal,inv=0,ccs=UseOption):0:3: ==', + children = { + { + 'UnaryPlus:0:0:+', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1: a', + }, + }, + { + 'UnaryPlus:0:6: +', + children = { + 'PlainIdentifier(scope=0,ident=b):0:8: b', + }, + }, + }, + }, + }, + }, { + hl('UnaryPlus', '+'), + hl('IdentifierName', 'a', 1), + hl('Comparison', '==', 1), + hl('UnaryPlus', '+', 1), + hl('IdentifierName', 'b', 1), + }) + end) + it('works with concat/subscript', function() + check_parsing('.', 0, { + -- 0 + ast = { + { + 'ConcatOrSubscript:0:0:.', + children = { + 'Missing:0:0:', + }, + }, + }, + err = { + arg = '.', + msg = 'E15: Unexpected dot: %.*s', + }, + }, { + hl('InvalidConcatOrSubscript', '.'), + }) + + check_parsing('a.', 0, { + -- 01 + ast = { + { + 'ConcatOrSubscript:0:1:.', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + }, + }, + }, + err = { + arg = '', + msg = 'E15: Expected value, got EOC: %.*s', + }, + }, { + hl('IdentifierName', 'a'), + hl('ConcatOrSubscript', '.'), + }) + + check_parsing('a.b', 0, { + -- 012 + ast = { + { + 'ConcatOrSubscript:0:1:.', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainKey(key=b):0:2:b', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('ConcatOrSubscript', '.'), + hl('IdentifierKey', 'b'), + }) + + check_parsing('1.2', 0, { + -- 012 + ast = { + 'Float(val=1.200000e+00):0:0:1.2', + }, + }, { + hl('Float', '1.2'), + }) + + check_parsing('1.2 + 1.3e-5', 0, { + -- 012345678901 + -- 0 1 + ast = { + { + 'BinaryPlus:0:3: +', + children = { + 'Float(val=1.200000e+00):0:0:1.2', + 'Float(val=1.300000e-05):0:5: 1.3e-5', + }, + }, + }, + }, { + hl('Float', '1.2'), + hl('BinaryPlus', '+', 1), + hl('Float', '1.3e-5', 1), + }) + + check_parsing('a . 1.2 + 1.3e-5', 0, { + -- 0123456789012345 + -- 0 1 + ast = { + { + 'BinaryPlus:0:7: +', + children = { + { + 'Concat:0:1: .', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'ConcatOrSubscript:0:5:.', + children = { + 'Integer(val=1):0:3: 1', + 'PlainKey(key=2):0:6:2', + }, + }, + }, + }, + 'Float(val=1.300000e-05):0:9: 1.3e-5', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Concat', '.', 1), + hl('Number', '1', 1), + hl('ConcatOrSubscript', '.'), + hl('IdentifierKey', '2'), + hl('BinaryPlus', '+', 1), + hl('Float', '1.3e-5', 1), + }) + + check_parsing('1.3e-5 + 1.2 . a', 0, { + -- 0123456789012345 + -- 0 1 + ast = { + { + 'Concat:0:12: .', + children = { + { + 'BinaryPlus:0:6: +', + children = { + 'Float(val=1.300000e-05):0:0:1.3e-5', + 'Float(val=1.200000e+00):0:8: 1.2', + }, + }, + 'PlainIdentifier(scope=0,ident=a):0:14: a', + }, + }, + }, + }, { + hl('Float', '1.3e-5'), + hl('BinaryPlus', '+', 1), + hl('Float', '1.2', 1), + hl('Concat', '.', 1), + hl('IdentifierName', 'a', 1), + }) + + check_parsing('1.3e-5 + a . 1.2', 0, { + -- 0123456789012345 + -- 0 1 + ast = { + { + 'Concat:0:10: .', + children = { + { + 'BinaryPlus:0:6: +', + children = { + 'Float(val=1.300000e-05):0:0:1.3e-5', + 'PlainIdentifier(scope=0,ident=a):0:8: a', + }, + }, + { + 'ConcatOrSubscript:0:14:.', + children = { + 'Integer(val=1):0:12: 1', + 'PlainKey(key=2):0:15:2', + }, + }, + }, + }, + }, + }, { + hl('Float', '1.3e-5'), + hl('BinaryPlus', '+', 1), + hl('IdentifierName', 'a', 1), + hl('Concat', '.', 1), + hl('Number', '1', 1), + hl('ConcatOrSubscript', '.'), + hl('IdentifierKey', '2'), + }) + + check_parsing('1.2.3', 0, { + -- 01234 + ast = { + { + 'ConcatOrSubscript:0:3:.', + children = { + { + 'ConcatOrSubscript:0:1:.', + children = { + 'Integer(val=1):0:0:1', + 'PlainKey(key=2):0:2:2', + }, + }, + 'PlainKey(key=3):0:4:3', + }, + }, + }, + }, { + hl('Number', '1'), + hl('ConcatOrSubscript', '.'), + hl('IdentifierKey', '2'), + hl('ConcatOrSubscript', '.'), + hl('IdentifierKey', '3'), + }) + + check_parsing('a.1.2', 0, { + -- 01234 + ast = { + { + 'ConcatOrSubscript:0:3:.', + children = { + { + 'ConcatOrSubscript:0:1:.', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainKey(key=1):0:2:1', + }, + }, + 'PlainKey(key=2):0:4:2', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('ConcatOrSubscript', '.'), + hl('IdentifierKey', '1'), + hl('ConcatOrSubscript', '.'), + hl('IdentifierKey', '2'), + }) + + check_parsing('a . 1.2', 0, { + -- 0123456 + ast = { + { + 'Concat:0:1: .', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'ConcatOrSubscript:0:5:.', + children = { + 'Integer(val=1):0:3: 1', + 'PlainKey(key=2):0:6:2', + }, + }, + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('Concat', '.', 1), + hl('Number', '1', 1), + hl('ConcatOrSubscript', '.'), + hl('IdentifierKey', '2'), + }) + + check_parsing('+a . +b', 0, { + -- 0123456 + ast = { + { + 'Concat:0:2: .', + children = { + { + 'UnaryPlus:0:0:+', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + }, + }, + { + 'UnaryPlus:0:4: +', + children = { + 'PlainIdentifier(scope=0,ident=b):0:6:b', + }, + }, + }, + }, + }, + }, { + hl('UnaryPlus', '+'), + hl('IdentifierName', 'a'), + hl('Concat', '.', 1), + hl('UnaryPlus', '+', 1), + hl('IdentifierName', 'b'), + }) + + check_parsing('a. b', 0, { + -- 0123 + ast = { + { + 'Concat:0:1:.', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:2: b', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('ConcatOrSubscript', '.'), + hl('IdentifierName', 'b', 1), + }) + + check_parsing('a. 1', 0, { + -- 0123 + ast = { + { + 'Concat:0:1:.', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'Integer(val=1):0:2: 1', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('ConcatOrSubscript', '.'), + hl('Number', '1', 1), + }) + end) + it('works with bracket subscripts', function() + check_parsing(':', 0, { + -- 0 + ast = { + { + 'Colon:0:0::', + children = { + 'Missing:0:0:', + }, + }, + }, + err = { + arg = ':', + msg = 'E15: Colon outside of dictionary or ternary operator: %.*s', + }, + }, { + hl('InvalidColon', ':'), + }) + check_parsing('a[]', 0, { + -- 012 + ast = { + { + 'Subscript:0:1:[', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + }, + }, + }, + err = { + arg = ']', + msg = 'E15: Expected value, got closing bracket: %.*s', + }, + }, { + hl('IdentifierName', 'a'), + hl('SubscriptBracket', '['), + hl('InvalidSubscriptBracket', ']'), + }) + check_parsing('a[b:]', 0, { + -- 01234 + ast = { + { + 'Subscript:0:1:[', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=b,ident=):0:2:b:', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('SubscriptBracket', '['), + hl('IdentifierScope', 'b'), + hl('IdentifierScopeDelimiter', ':'), + hl('SubscriptBracket', ']'), + }) + + check_parsing('a[b:c]', 0, { + -- 012345 + ast = { + { + 'Subscript:0:1:[', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=b,ident=c):0:2:b:c', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('SubscriptBracket', '['), + hl('IdentifierScope', 'b'), + hl('IdentifierScopeDelimiter', ':'), + hl('IdentifierName', 'c'), + hl('SubscriptBracket', ']'), + }) + check_parsing('a[b : c]', 0, { + -- 01234567 + ast = { + { + 'Subscript:0:1:[', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'Colon:0:3: :', + children = { + 'PlainIdentifier(scope=0,ident=b):0:2:b', + 'PlainIdentifier(scope=0,ident=c):0:5: c', + }, + }, + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('SubscriptBracket', '['), + hl('IdentifierName', 'b'), + hl('SubscriptColon', ':', 1), + hl('IdentifierName', 'c', 1), + hl('SubscriptBracket', ']'), + }) + + check_parsing('a[: b]', 0, { + -- 012345 + ast = { + { + 'Subscript:0:1:[', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'Colon:0:2::', + children = { + 'Missing:0:2:', + 'PlainIdentifier(scope=0,ident=b):0:3: b', + }, + }, + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('SubscriptBracket', '['), + hl('SubscriptColon', ':'), + hl('IdentifierName', 'b', 1), + hl('SubscriptBracket', ']'), + }) + + check_parsing('a[b :]', 0, { + -- 012345 + ast = { + { + 'Subscript:0:1:[', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + { + 'Colon:0:3: :', + children = { + 'PlainIdentifier(scope=0,ident=b):0:2:b', + }, + }, + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('SubscriptBracket', '['), + hl('IdentifierName', 'b'), + hl('SubscriptColon', ':', 1), + hl('SubscriptBracket', ']'), + }) + check_parsing('a[b][c][d](e)(f)(g)', 0, { + -- 0123456789012345678 + -- 0 1 + ast = { + { + 'Call:0:16:(', + children = { + { + 'Call:0:13:(', + children = { + { + 'Call:0:10:(', + children = { + { + 'Subscript:0:7:[', + children = { + { + 'Subscript:0:4:[', + children = { + { + 'Subscript:0:1:[', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + 'PlainIdentifier(scope=0,ident=b):0:2:b', + }, + }, + 'PlainIdentifier(scope=0,ident=c):0:5:c', + }, + }, + 'PlainIdentifier(scope=0,ident=d):0:8:d', + }, + }, + 'PlainIdentifier(scope=0,ident=e):0:11:e', + }, + }, + 'PlainIdentifier(scope=0,ident=f):0:14:f', + }, + }, + 'PlainIdentifier(scope=0,ident=g):0:17:g', + }, + }, + }, + }, { + hl('IdentifierName', 'a'), + hl('SubscriptBracket', '['), + hl('IdentifierName', 'b'), + hl('SubscriptBracket', ']'), + hl('SubscriptBracket', '['), + hl('IdentifierName', 'c'), + hl('SubscriptBracket', ']'), + hl('SubscriptBracket', '['), + hl('IdentifierName', 'd'), + hl('SubscriptBracket', ']'), + hl('CallingParenthesis', '('), + hl('IdentifierName', 'e'), + hl('CallingParenthesis', ')'), + hl('CallingParenthesis', '('), + hl('IdentifierName', 'f'), + hl('CallingParenthesis', ')'), + hl('CallingParenthesis', '('), + hl('IdentifierName', 'g'), + hl('CallingParenthesis', ')'), + }) + check_parsing('{a}{b}{c}[d][e][f]', 0, { + -- 012345678901234567 + -- 0 1 + ast = { + { + 'Subscript:0:15:[', + children = { + { + 'Subscript:0:12:[', + children = { + { + 'Subscript:0:9:[', + children = { + { + 'ComplexIdentifier:0:3:', + children = { + { + 'CurlyBracesIdentifier:0:0:{', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + }, + }, + { + 'ComplexIdentifier:0:6:', + children = { + { + 'CurlyBracesIdentifier:0:3:{', + children = { + 'PlainIdentifier(scope=0,ident=b):0:4:b', + }, + }, + { + 'CurlyBracesIdentifier:0:6:{', + children = { + 'PlainIdentifier(scope=0,ident=c):0:7:c', + }, + }, + }, + }, + }, + }, + 'PlainIdentifier(scope=0,ident=d):0:10:d', + }, + }, + 'PlainIdentifier(scope=0,ident=e):0:13:e', + }, + }, + 'PlainIdentifier(scope=0,ident=f):0:16:f', + }, + }, + }, + }, { + hl('Curly', '{'), + hl('IdentifierName', 'a'), + hl('Curly', '}'), + hl('Curly', '{'), + hl('IdentifierName', 'b'), + hl('Curly', '}'), + hl('Curly', '{'), + hl('IdentifierName', 'c'), + hl('Curly', '}'), + hl('SubscriptBracket', '['), + hl('IdentifierName', 'd'), + hl('SubscriptBracket', ']'), + hl('SubscriptBracket', '['), + hl('IdentifierName', 'e'), + hl('SubscriptBracket', ']'), + hl('SubscriptBracket', '['), + hl('IdentifierName', 'f'), + hl('SubscriptBracket', ']'), + }) + end) + it('supports list literals', function() + check_parsing('[]', 0, { + -- 01 + ast = { + 'ListLiteral:0:0:[', + }, + }, { + hl('List', '['), + hl('List', ']'), + }) + + check_parsing('[a]', 0, { + -- 012 + ast = { + { + 'ListLiteral:0:0:[', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + }, + }, + }, + }, { + hl('List', '['), + hl('IdentifierName', 'a'), + hl('List', ']'), + }) + + check_parsing('[a, b]', 0, { + -- 012345 + ast = { + { + 'ListLiteral:0:0:[', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + 'PlainIdentifier(scope=0,ident=b):0:3: b', + }, + }, + }, + }, + }, + }, { + hl('List', '['), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('IdentifierName', 'b', 1), + hl('List', ']'), + }) + + check_parsing('[a, b, c]', 0, { + -- 012345678 + ast = { + { + 'ListLiteral:0:0:[', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + { + 'Comma:0:5:,', + children = { + 'PlainIdentifier(scope=0,ident=b):0:3: b', + 'PlainIdentifier(scope=0,ident=c):0:6: c', + }, + }, + }, + }, + }, + }, + }, + }, { + hl('List', '['), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('IdentifierName', 'b', 1), + hl('Comma', ','), + hl('IdentifierName', 'c', 1), + hl('List', ']'), + }) + + check_parsing('[a, b, c, ]', 0, { + -- 01234567890 + -- 0 1 + ast = { + { + 'ListLiteral:0:0:[', + children = { + { + 'Comma:0:2:,', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + { + 'Comma:0:5:,', + children = { + 'PlainIdentifier(scope=0,ident=b):0:3: b', + { + 'Comma:0:8:,', + children = { + 'PlainIdentifier(scope=0,ident=c):0:6: c', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, { + hl('List', '['), + hl('IdentifierName', 'a'), + hl('Comma', ','), + hl('IdentifierName', 'b', 1), + hl('Comma', ','), + hl('IdentifierName', 'c', 1), + hl('Comma', ','), + hl('List', ']', 1), + }) + + check_parsing('[a : b, c : d]', 0, { + -- 01234567890123 + -- 0 1 + ast = { + { + 'ListLiteral:0:0:[', + children = { + { + 'Comma:0:6:,', + children = { + { + 'Colon:0:2: :', + children = { + 'PlainIdentifier(scope=0,ident=a):0:1:a', + 'PlainIdentifier(scope=0,ident=b):0:4: b', + }, + }, + { + 'Colon:0:9: :', + children = { + 'PlainIdentifier(scope=0,ident=c):0:7: c', + 'PlainIdentifier(scope=0,ident=d):0:11: d', + }, + }, + }, + }, + }, + }, + }, + err = { + arg = ': b, c : d]', + msg = 'E15: Colon outside of dictionary or ternary operator: %.*s', + }, + }, { + hl('List', '['), + hl('IdentifierName', 'a'), + hl('InvalidColon', ':', 1), + hl('IdentifierName', 'b', 1), + hl('Comma', ','), + hl('IdentifierName', 'c', 1), + hl('InvalidColon', ':', 1), + hl('IdentifierName', 'd', 1), + hl('List', ']'), + }) + + check_parsing(']', 0, { + -- 0 + ast = { + 'ListLiteral:0:0:', + }, + err = { + arg = ']', + msg = 'E15: Unexpected closing figure brace: %.*s', + }, + }, { + hl('InvalidList', ']'), + }) + + check_parsing('a]', 0, { + -- 01 + ast = { + { + 'ListLiteral:0:1:', + children = { + 'PlainIdentifier(scope=0,ident=a):0:0:a', + }, + }, + }, + err = { + arg = ']', + msg = 'E15: Unexpected closing figure brace: %.*s', + }, + }, { + hl('IdentifierName', 'a'), + hl('InvalidList', ']'), + }) + + check_parsing('[] []', 0, { + -- 01234 + ast = { + { + 'OpMissing:0:2:', + children = { + 'ListLiteral:0:0:[', + 'ListLiteral:0:2: [', + }, + }, + }, + err = { + arg = '[]', + msg = 'E15: Missing operator: %.*s', + }, + }, { + hl('List', '['), + hl('List', ']'), + hl('InvalidSpacing', ' '), + hl('List', '['), + hl('List', ']'), + }) + + check_parsing('[][]', 0, { + -- 0123 + ast = { + { + 'Subscript:0:2:[', + children = { + 'ListLiteral:0:0:[', + }, + }, + }, + err = { + arg = ']', + msg = 'E15: Expected value, got closing bracket: %.*s', + }, + }, { + hl('List', '['), + hl('List', ']'), + hl('SubscriptBracket', '['), + hl('InvalidSubscriptBracket', ']'), + }) + + check_parsing('[', 0, { + -- 0 + ast = { + 'ListLiteral:0:0:[', + }, + err = { + arg = '', + msg = 'E15: Expected value, got EOC: %.*s', + }, + }, { + hl('List', '['), + }) + + check_parsing('[1', 0, { + -- 01 + ast = { + { + 'ListLiteral:0:0:[', + children = { + 'Integer(val=1):0:1:1', + }, + }, + }, + err = { + arg = '[1', + msg = 'E697: Missing end of List \']\': %.*s', + }, + }, { + hl('List', '['), + hl('Number', '1'), + }) + end) + it('works with strings', function() + check_parsing('\'abc\'', 0, { + -- 01234 + ast = { + 'SingleQuotedString(val="abc"):0:0:\'abc\'', + }, + }, { + hl('SingleQuote', '\''), + hl('SingleQuotedBody', 'abc'), + hl('SingleQuote', '\''), + }) + check_parsing('"abc"', 0, { + -- 01234 + ast = { + 'DoubleQuotedString(val="abc"):0:0:"abc"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedBody', 'abc'), + hl('DoubleQuote', '"'), + }) + check_parsing('\'\'', 0, { + -- 01 + ast = { + 'SingleQuotedString(val=""):0:0:\'\'', + }, + }, { + hl('SingleQuote', '\''), + hl('SingleQuote', '\''), + }) + check_parsing('""', 0, { + -- 01 + ast = { + 'DoubleQuotedString(val=""):0:0:""', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuote', '"'), + }) + check_parsing('"', 0, { + -- 0 + ast = { + 'DoubleQuotedString(val=""):0:0:"', + }, + err = { + arg = '"', + msg = 'E114: Missing double quote: %.*s', + }, + }, { + hl('InvalidDoubleQuote', '"'), + }) + check_parsing('\'', 0, { + -- 0 + ast = { + 'SingleQuotedString(val=""):0:0:\'', + }, + err = { + arg = '\'', + msg = 'E115: Missing single quote: %.*s', + }, + }, { + hl('InvalidSingleQuote', '\''), + }) + check_parsing('"a', 0, { + -- 01 + ast = { + 'DoubleQuotedString(val="a"):0:0:"a', + }, + err = { + arg = '"a', + msg = 'E114: Missing double quote: %.*s', + }, + }, { + hl('InvalidDoubleQuote', '"'), + hl('InvalidDoubleQuotedBody', 'a'), + }) + check_parsing('\'a', 0, { + -- 01 + ast = { + 'SingleQuotedString(val="a"):0:0:\'a', + }, + err = { + arg = '\'a', + msg = 'E115: Missing single quote: %.*s', + }, + }, { + hl('InvalidSingleQuote', '\''), + hl('InvalidSingleQuotedBody', 'a'), + }) + check_parsing('\'abc\'\'def\'', 0, { + -- 0123456789 + ast = { + 'SingleQuotedString(val="abc\'def"):0:0:\'abc\'\'def\'', + }, + }, { + hl('SingleQuote', '\''), + hl('SingleQuotedBody', 'abc'), + hl('SingleQuotedQuote', '\'\''), + hl('SingleQuotedBody', 'def'), + hl('SingleQuote', '\''), + }) + check_parsing('\'abc\'\'', 0, { + -- 012345 + ast = { + 'SingleQuotedString(val="abc\'"):0:0:\'abc\'\'', + }, + err = { + arg = '\'abc\'\'', + msg = 'E115: Missing single quote: %.*s', + }, + }, { + hl('InvalidSingleQuote', '\''), + hl('InvalidSingleQuotedBody', 'abc'), + hl('InvalidSingleQuotedQuote', '\'\''), + }) + check_parsing('\'\'\'\'\'\'\'\'', 0, { + -- 01234567 + ast = { + 'SingleQuotedString(val="\'\'\'"):0:0:\'\'\'\'\'\'\'\'', + }, + }, { + hl('SingleQuote', '\''), + hl('SingleQuotedQuote', '\'\''), + hl('SingleQuotedQuote', '\'\''), + hl('SingleQuotedQuote', '\'\''), + hl('SingleQuote', '\''), + }) + check_parsing('\'\'\'a\'\'\'\'bc\'', 0, { + -- 01234567890 + -- 0 1 + ast = { + 'SingleQuotedString(val="\'a\'\'bc"):0:0:\'\'\'a\'\'\'\'bc\'', + }, + }, { + hl('SingleQuote', '\''), + hl('SingleQuotedQuote', '\'\''), + hl('SingleQuotedBody', 'a'), + hl('SingleQuotedQuote', '\'\''), + hl('SingleQuotedQuote', '\'\''), + hl('SingleQuotedBody', 'bc'), + hl('SingleQuote', '\''), + }) + check_parsing('"\\"\\"\\"\\""', 0, { + -- 0123456789 + ast = { + 'DoubleQuotedString(val="\\"\\"\\"\\""):0:0:"\\"\\"\\"\\""', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\"'), + hl('DoubleQuotedEscape', '\\"'), + hl('DoubleQuotedEscape', '\\"'), + hl('DoubleQuotedEscape', '\\"'), + hl('DoubleQuote', '"'), + }) + check_parsing('"abc\\"def\\"ghi\\"jkl\\"mno"', 0, { + -- 0123456789012345678901234 + -- 0 1 2 + ast = { + 'DoubleQuotedString(val="abc\\"def\\"ghi\\"jkl\\"mno"):0:0:"abc\\"def\\"ghi\\"jkl\\"mno"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedBody', 'abc'), + hl('DoubleQuotedEscape', '\\"'), + hl('DoubleQuotedBody', 'def'), + hl('DoubleQuotedEscape', '\\"'), + hl('DoubleQuotedBody', 'ghi'), + hl('DoubleQuotedEscape', '\\"'), + hl('DoubleQuotedBody', 'jkl'), + hl('DoubleQuotedEscape', '\\"'), + hl('DoubleQuotedBody', 'mno'), + hl('DoubleQuote', '"'), + }) + check_parsing('"\\b\\e\\f\\r\\t\\\\"', 0, { + -- 0123456789012345 + -- 0 1 + ast = { + [[DoubleQuotedString(val="\8\27\12\13\9\\"):0:0:"\b\e\f\r\t\\"]], + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\b'), + hl('DoubleQuotedEscape', '\\e'), + hl('DoubleQuotedEscape', '\\f'), + hl('DoubleQuotedEscape', '\\r'), + hl('DoubleQuotedEscape', '\\t'), + hl('DoubleQuotedEscape', '\\\\'), + hl('DoubleQuote', '"'), + }) + check_parsing('"\\n\n"', 0, { + -- 01234 + ast = { + 'DoubleQuotedString(val="\\\n\\\n"):0:0:"\\n\n"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\n'), + hl('DoubleQuotedBody', '\n'), + hl('DoubleQuote', '"'), + }) + check_parsing('"\\x00"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\\0"):0:0:"\\x00"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\x00'), + hl('DoubleQuote', '"'), + }) + check_parsing('"\\xFF"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\255"):0:0:"\\xFF"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\xFF'), + hl('DoubleQuote', '"'), + }) + check_parsing('"\\xF"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\\15"):0:0:"\\xF"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\xF'), + hl('DoubleQuote', '"'), + }) + check_parsing('"\\u00AB"', 0, { + -- 01234567 + ast = { + 'DoubleQuotedString(val="«"):0:0:"\\u00AB"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\u00AB'), + hl('DoubleQuote', '"'), + }) + check_parsing('"\\U000000AB"', 0, { + -- 01234567 + ast = { + 'DoubleQuotedString(val="«"):0:0:"\\U000000AB"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\U000000AB'), + hl('DoubleQuote', '"'), + }) + check_parsing('"\\x"', 0, { + -- 0123 + ast = { + 'DoubleQuotedString(val="x"):0:0:"\\x"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedUnknownEscape', '\\x'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\x', 0, { + -- 012 + ast = { + 'DoubleQuotedString(val="x"):0:0:"\\x', + }, + err = { + arg = '"\\x', + msg = 'E114: Missing double quote: %.*s', + }, + }, { + hl('InvalidDoubleQuote', '"'), + hl('InvalidDoubleQuotedUnknownEscape', '\\x'), + }) + + check_parsing('"\\xF', 0, { + -- 0123 + ast = { + 'DoubleQuotedString(val="\\15"):0:0:"\\xF', + }, + err = { + arg = '"\\xF', + msg = 'E114: Missing double quote: %.*s', + }, + }, { + hl('InvalidDoubleQuote', '"'), + hl('InvalidDoubleQuotedEscape', '\\xF'), + }) + + check_parsing('"\\u"', 0, { + -- 0123 + ast = { + 'DoubleQuotedString(val="u"):0:0:"\\u"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedUnknownEscape', '\\u'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\u', 0, { + -- 012 + ast = { + 'DoubleQuotedString(val="u"):0:0:"\\u', + }, + err = { + arg = '"\\u', + msg = 'E114: Missing double quote: %.*s', + }, + }, { + hl('InvalidDoubleQuote', '"'), + hl('InvalidDoubleQuotedUnknownEscape', '\\u'), + }) + + check_parsing('"\\U', 0, { + -- 012 + ast = { + 'DoubleQuotedString(val="U"):0:0:"\\U', + }, + err = { + arg = '"\\U', + msg = 'E114: Missing double quote: %.*s', + }, + }, { + hl('InvalidDoubleQuote', '"'), + hl('InvalidDoubleQuotedUnknownEscape', '\\U'), + }) + + check_parsing('"\\U"', 0, { + -- 0123 + ast = { + 'DoubleQuotedString(val="U"):0:0:"\\U"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedUnknownEscape', '\\U'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\xFX"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\\15X"):0:0:"\\xFX"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\xF'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\XFX"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\\15X"):0:0:"\\XFX"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\XF'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\xX"', 0, { + -- 01234 + ast = { + 'DoubleQuotedString(val="xX"):0:0:"\\xX"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedUnknownEscape', '\\x'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\XX"', 0, { + -- 01234 + ast = { + 'DoubleQuotedString(val="XX"):0:0:"\\XX"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedUnknownEscape', '\\X'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\uX"', 0, { + -- 01234 + ast = { + 'DoubleQuotedString(val="uX"):0:0:"\\uX"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedUnknownEscape', '\\u'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\UX"', 0, { + -- 01234 + ast = { + 'DoubleQuotedString(val="UX"):0:0:"\\UX"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedUnknownEscape', '\\U'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\x0X"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\x0X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\x0'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\X0X"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\X0X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\X0'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\u0X"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\u0X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\u0'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\U0X"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\U0X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\U0'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\x00X"', 0, { + -- 0123456 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\x00X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\x00'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\X00X"', 0, { + -- 0123456 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\X00X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\X00'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\u00X"', 0, { + -- 0123456 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\u00X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\u00'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\U00X"', 0, { + -- 0123456 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\U00X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\U00'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\u000X"', 0, { + -- 01234567 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\u000X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\u000'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\U000X"', 0, { + -- 01234567 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\U000X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\U000'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\u0000X"', 0, { + -- 012345678 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\u0000X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\u0000'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\U0000X"', 0, { + -- 012345678 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\U0000X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\U0000'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\U00000X"', 0, { + -- 0123456789 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\U00000X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\U00000'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\U000000X"', 0, { + -- 01234567890 + -- 0 1 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\U000000X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\U000000'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\U0000000X"', 0, { + -- 012345678901 + -- 0 1 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\U0000000X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\U0000000'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\U00000000X"', 0, { + -- 0123456789012 + -- 0 1 + ast = { + 'DoubleQuotedString(val="\\0X"):0:0:"\\U00000000X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\U00000000'), + hl('DoubleQuotedBody', 'X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\x000X"', 0, { + -- 01234567 + ast = { + 'DoubleQuotedString(val="\\0000X"):0:0:"\\x000X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\x00'), + hl('DoubleQuotedBody', '0X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\X000X"', 0, { + -- 01234567 + ast = { + 'DoubleQuotedString(val="\\0000X"):0:0:"\\X000X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\X00'), + hl('DoubleQuotedBody', '0X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\u00000X"', 0, { + -- 0123456789 + ast = { + 'DoubleQuotedString(val="\\0000X"):0:0:"\\u00000X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\u0000'), + hl('DoubleQuotedBody', '0X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\U000000000X"', 0, { + -- 01234567890123 + -- 0 1 + ast = { + 'DoubleQuotedString(val="\\0000X"):0:0:"\\U000000000X"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\U00000000'), + hl('DoubleQuotedBody', '0X'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\0"', 0, { + -- 0123 + ast = { + 'DoubleQuotedString(val="\\0"):0:0:"\\0"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\0'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\00"', 0, { + -- 01234 + ast = { + 'DoubleQuotedString(val="\\0"):0:0:"\\00"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\00'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\000"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\\0"):0:0:"\\000"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\000'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\0000"', 0, { + -- 0123456 + ast = { + 'DoubleQuotedString(val="\\0000"):0:0:"\\0000"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\000'), + hl('DoubleQuotedBody', '0'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\8"', 0, { + -- 0123 + ast = { + 'DoubleQuotedString(val="8"):0:0:"\\8"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedUnknownEscape', '\\8'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\08"', 0, { + -- 01234 + ast = { + 'DoubleQuotedString(val="\\0008"):0:0:"\\08"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\0'), + hl('DoubleQuotedBody', '8'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\008"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\\0008"):0:0:"\\008"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\00'), + hl('DoubleQuotedBody', '8'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\0008"', 0, { + -- 0123456 + ast = { + 'DoubleQuotedString(val="\\0008"):0:0:"\\0008"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\000'), + hl('DoubleQuotedBody', '8'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\777"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\255"):0:0:"\\777"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\777'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\050"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\40"):0:0:"\\050"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\050'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\"', 0, { + -- 012345 + ast = { + 'DoubleQuotedString(val="\\21"):0:0:"\\"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedEscape', '\\'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\<', 0, { + -- 012 + ast = { + 'DoubleQuotedString(val="<"):0:0:"\\<', + }, + err = { + arg = '"\\<', + msg = 'E114: Missing double quote: %.*s', + }, + }, { + hl('InvalidDoubleQuote', '"'), + hl('InvalidDoubleQuotedUnknownEscape', '\\<'), + }) + + check_parsing('"\\<"', 0, { + -- 0123 + ast = { + 'DoubleQuotedString(val="<"):0:0:"\\<"', + }, + }, { + hl('DoubleQuote', '"'), + hl('DoubleQuotedUnknownEscape', '\\<'), + hl('DoubleQuote', '"'), + }) + + check_parsing('"\\ Date: Sun, 5 Nov 2017 21:06:12 +0300 Subject: tests: Add missing test cases --- test/functional/api/vim_spec.lua | 1197 +++++++++++++++++++++++++------------- 1 file changed, 777 insertions(+), 420 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index bb7785657d..b904bd2a8f 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -12,8 +12,10 @@ local request = helpers.request local meth_pcall = helpers.meth_pcall local command = helpers.command +local REMOVE_THIS = global_helpers.REMOVE_THIS local intchar2lua = global_helpers.intchar2lua local format_string = global_helpers.format_string +local mergedicts_copy = global_helpers.mergedicts_copy describe('api', function() before_each(clear) @@ -717,6 +719,9 @@ describe('api', function() describe('nvim_parse_expression', function() local function simplify_east_api_node(line, east_api_node) + if east_api_node == NIL then + return nil + end if east_api_node.children then for k, v in pairs(east_api_node.children) do east_api_node.children[k] = simplify_east_api_node(line, v) @@ -806,31 +811,53 @@ describe('api', function() end return east_hl end - local function check_parsing(str, flags, exp_ast, exp_highlighting_fs) - if flags == 0 then - flags = "" - end - - local err, msg = pcall(function() - local east_api = meths.parse_expression(str, flags, true) - local east_hl = east_api.highlight - east_api.highlight = nil - local ast = simplify_east_api(str, east_api) - local hls = simplify_east_hl(str, east_hl) - eq(exp_ast, ast) - if exp_highlighting_fs then - local exp_highlighting = {} - local next_col = 0 - for i, h in ipairs(exp_highlighting_fs) do - exp_highlighting[i], next_col = h(next_col) + local FLAGS_TO_STR = { + [0] = "", + [1] = "m", + [2] = "E", + [3] = "mE", + } + local function check_parsing(str, exp_ast, exp_highlighting_fs, + nz_flags_exps) + nz_flags_exps = nz_flags_exps or {} + for _, flags in ipairs({0, 1, 2, 3}) do + local err, msg = pcall(function() + local east_api = meths.parse_expression(str, FLAGS_TO_STR[flags], true) + local east_hl = east_api.highlight + east_api.highlight = nil + local ast = simplify_east_api(str, east_api) + local hls = simplify_east_hl(str, east_hl) + local exps = { + ast = exp_ast, + hl_fs = exp_highlighting_fs, + } + local add_exps = nz_flags_exps[flags] + if not add_exps and flags == 3 then + add_exps = nz_flags_exps[1] or nz_flags_exps[2] end - eq(exp_highlighting, hls) + if add_exps then + if add_exps.ast then + exps.ast = mergedicts_copy(exps.ast, add_exps.ast) + end + if add_exps.hl_fs then + exps.hl_fs = mergedicts_copy(exps.hl_fs, add_exps.hl_fs) + end + end + eq(exps.ast, ast) + if exp_highlighting_fs then + local exp_highlighting = {} + local next_col = 0 + for i, h in ipairs(exps.hl_fs) do + exp_highlighting[i], next_col = h(next_col) + end + eq(exp_highlighting, hls) + end + end) + if not err then + msg = format_string('Error while processing test (%r, %s):\n%s', + str, FLAGS_TO_STR[flags], msg) + error(msg) end - end) - if not err then - msg = format_string('Error while processing test (%r, %s):\n%s', - str, flags, msg) - error(msg) end end local function hl(group, str, shift) @@ -844,14 +871,14 @@ describe('api', function() end end it('works with + and @a', function() - check_parsing('@a', 0, { + check_parsing('@a', { ast = { 'Register(name=a):0:0:@a', }, }, { hl('Register', '@a'), }) - check_parsing('+@a', 0, { + check_parsing('+@a', { ast = { { 'UnaryPlus:0:0:+', @@ -864,7 +891,7 @@ describe('api', function() hl('UnaryPlus', '+'), hl('Register', '@a'), }) - check_parsing('@a+@b', 0, { + check_parsing('@a+@b', { ast = { { 'BinaryPlus:0:2:+', @@ -879,7 +906,7 @@ describe('api', function() hl('BinaryPlus', '+'), hl('Register', '@b'), }) - check_parsing('@a+@b+@c', 0, { + check_parsing('@a+@b+@c', { ast = { { 'BinaryPlus:0:5:+', @@ -902,7 +929,7 @@ describe('api', function() hl('BinaryPlus', '+'), hl('Register', '@c'), }) - check_parsing('+@a+@b', 0, { + check_parsing('+@a+@b', { ast = { { 'BinaryPlus:0:3:+', @@ -923,7 +950,7 @@ describe('api', function() hl('BinaryPlus', '+'), hl('Register', '@b'), }) - check_parsing('+@a++@b', 0, { + check_parsing('+@a++@b', { ast = { { 'BinaryPlus:0:3:+', @@ -950,7 +977,7 @@ describe('api', function() hl('UnaryPlus', '+'), hl('Register', '@b'), }) - check_parsing('@a@b', 0, { + check_parsing('@a@b', { ast = { { 'OpMissing:0:2:', @@ -967,8 +994,20 @@ describe('api', function() }, { hl('Register', '@a'), hl('InvalidRegister', '@b'), + }, { + [1] = { + ast = { + err = REMOVE_THIS, + ast = { + 'Register(name=a):0:0:@a' + }, + }, + hl_fs = { + [2] = REMOVE_THIS, + }, + }, }) - check_parsing(' @a \t @b', 0, { + check_parsing(' @a \t @b', { ast = { { 'OpMissing:0:3:', @@ -986,8 +1025,21 @@ describe('api', function() hl('Register', '@a', 1), hl('InvalidSpacing', ' \t '), hl('Register', '@b'), + }, { + [1] = { + ast = { + err = REMOVE_THIS, + ast = { + 'Register(name=a):0:0: @a' + }, + }, + hl_fs = { + [2] = REMOVE_THIS, + [3] = REMOVE_THIS, + }, + }, }) - check_parsing('+', 0, { + check_parsing('+', { ast = { 'UnaryPlus:0:0:+', }, @@ -998,7 +1050,7 @@ describe('api', function() }, { hl('UnaryPlus', '+'), }) - check_parsing(' +', 0, { + check_parsing(' +', { ast = { 'UnaryPlus:0:0: +', }, @@ -1009,7 +1061,7 @@ describe('api', function() }, { hl('UnaryPlus', '+', 1), }) - check_parsing('@a+ ', 0, { + check_parsing('@a+ ', { ast = { { 'BinaryPlus:0:2:+', @@ -1028,7 +1080,7 @@ describe('api', function() }) end) it('works with @a, + and parenthesis', function() - check_parsing('(@a)', 0, { + check_parsing('(@a)', { ast = { { 'Nested:0:0:(', @@ -1042,7 +1094,7 @@ describe('api', function() hl('Register', '@a'), hl('NestingParenthesis', ')'), }) - check_parsing('()', 0, { + check_parsing('()', { ast = { { 'Nested:0:0:(', @@ -1059,7 +1111,7 @@ describe('api', function() hl('NestingParenthesis', '('), hl('InvalidNestingParenthesis', ')'), }) - check_parsing(')', 0, { + check_parsing(')', { ast = { { 'Nested:0:0:', @@ -1075,7 +1127,7 @@ describe('api', function() }, { hl('InvalidNestingParenthesis', ')'), }) - check_parsing('+)', 0, { + check_parsing('+)', { ast = { { 'Nested:0:1:', @@ -1097,7 +1149,7 @@ describe('api', function() hl('UnaryPlus', '+'), hl('InvalidNestingParenthesis', ')'), }) - check_parsing('+@a(@b)', 0, { + check_parsing('+@a(@b)', { ast = { { 'UnaryPlus:0:0:+', @@ -1119,7 +1171,7 @@ describe('api', function() hl('Register', '@b'), hl('CallingParenthesis', ')'), }) - check_parsing('@a+@b(@c)', 0, { + check_parsing('@a+@b(@c)', { ast = { { 'BinaryPlus:0:2:+', @@ -1143,7 +1195,7 @@ describe('api', function() hl('Register', '@c'), hl('CallingParenthesis', ')'), }) - check_parsing('@a()', 0, { + check_parsing('@a()', { ast = { { 'Call:0:2:(', @@ -1157,7 +1209,7 @@ describe('api', function() hl('CallingParenthesis', '('), hl('CallingParenthesis', ')'), }) - check_parsing('@a ()', 0, { + check_parsing('@a ()', { ast = { { 'OpMissing:0:2:', @@ -1181,91 +1233,102 @@ describe('api', function() hl('InvalidSpacing', ' '), hl('NestingParenthesis', '('), hl('InvalidNestingParenthesis', ')'), - }) - check_parsing( - '@a + (@b)', 0, { + }, { + [1] = { ast = { - { - 'BinaryPlus:0:2: +', - children = { - 'Register(name=a):0:0:@a', - { - 'Nested:0:4: (', - children = { - 'Register(name=b):0:6:@b', - }, + err = REMOVE_THIS, + ast = { + 'Register(name=a):0:0:@a', + }, + }, + hl_fs = { + [2] = REMOVE_THIS, + [3] = REMOVE_THIS, + [4] = REMOVE_THIS, + }, + }, + }) + check_parsing('@a + (@b)', { + ast = { + { + 'BinaryPlus:0:2: +', + children = { + 'Register(name=a):0:0:@a', + { + 'Nested:0:4: (', + children = { + 'Register(name=b):0:6:@b', }, }, }, }, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+', 1), - hl('NestingParenthesis', '(', 1), - hl('Register', '@b'), - hl('NestingParenthesis', ')'), - }) - check_parsing( - '@a + (+@b)', 0, { - ast = { - { - 'BinaryPlus:0:2: +', - children = { - 'Register(name=a):0:0:@a', - { - 'Nested:0:4: (', - children = { - { - 'UnaryPlus:0:6:+', - children = { - 'Register(name=b):0:7:@b', - }, + }, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+', 1), + hl('NestingParenthesis', '(', 1), + hl('Register', '@b'), + hl('NestingParenthesis', ')'), + }) + check_parsing('@a + (+@b)', { + ast = { + { + 'BinaryPlus:0:2: +', + children = { + 'Register(name=a):0:0:@a', + { + 'Nested:0:4: (', + children = { + { + 'UnaryPlus:0:6:+', + children = { + 'Register(name=b):0:7:@b', }, }, }, }, }, }, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+', 1), - hl('NestingParenthesis', '(', 1), - hl('UnaryPlus', '+'), - hl('Register', '@b'), - hl('NestingParenthesis', ')'), - }) - check_parsing( - '@a + (@b + @c)', 0, { - ast = { - { - 'BinaryPlus:0:2: +', - children = { - 'Register(name=a):0:0:@a', - { - 'Nested:0:4: (', - children = { - { - 'BinaryPlus:0:8: +', - children = { - 'Register(name=b):0:6:@b', - 'Register(name=c):0:10: @c', - }, + }, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+', 1), + hl('NestingParenthesis', '(', 1), + hl('UnaryPlus', '+'), + hl('Register', '@b'), + hl('NestingParenthesis', ')'), + }) + check_parsing('@a + (@b + @c)', { + ast = { + { + 'BinaryPlus:0:2: +', + children = { + 'Register(name=a):0:0:@a', + { + 'Nested:0:4: (', + children = { + { + 'BinaryPlus:0:8: +', + children = { + 'Register(name=b):0:6:@b', + 'Register(name=c):0:10: @c', }, }, }, }, }, }, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+', 1), - hl('NestingParenthesis', '(', 1), - hl('Register', '@b'), - hl('BinaryPlus', '+', 1), - hl('Register', '@c', 1), - hl('NestingParenthesis', ')'), - }) - check_parsing('(@a)+@b', 0, { + }, + }, { + hl('Register', '@a'), + hl('BinaryPlus', '+', 1), + hl('NestingParenthesis', '(', 1), + hl('Register', '@b'), + hl('BinaryPlus', '+', 1), + hl('Register', '@c', 1), + hl('NestingParenthesis', ')'), + }) + check_parsing('(@a)+@b', { ast = { { 'BinaryPlus:0:4:+', @@ -1287,7 +1350,7 @@ describe('api', function() hl('BinaryPlus', '+'), hl('Register', '@b'), }) - check_parsing('@a+(@b)(@c)', 0, { + check_parsing('@a+(@b)(@c)', { -- 01234567890 ast = { { @@ -1317,7 +1380,7 @@ describe('api', function() hl('Register', '@c'), hl('CallingParenthesis', ')'), }) - check_parsing('@a+((@b))(@c)', 0, { + check_parsing('@a+((@b))(@c)', { -- 01234567890123456890123456789 -- 0 1 2 ast = { @@ -1355,7 +1418,7 @@ describe('api', function() hl('Register', '@c'), hl('CallingParenthesis', ')'), }) - check_parsing('@a+((@b))+@c', 0, { + check_parsing('@a+((@b))+@c', { -- 01234567890123456890123456789 -- 0 1 2 ast = { @@ -1393,7 +1456,7 @@ describe('api', function() hl('Register', '@c'), }) check_parsing( - '@a + (@b + @c) + @d(@e) + (+@f) + ((+@g(@h))(@j)(@k))(@l)', 0, {--[[ + '@a + (@b + @c) + @d(@e) + (+@f) + ((+@g(@h))(@j)(@k))(@l)', {--[[ | | | | | | | | || | | || | | ||| || || || || 000000000011111111112222222222333333333344444444445555555 012345678901234567890123456789012345678901234567890123456 @@ -1527,7 +1590,7 @@ describe('api', function() hl('Register', '@l'), hl('CallingParenthesis', ')'), }) - check_parsing('@a)', 0, { + check_parsing('@a)', { -- 012 ast = { { @@ -1545,7 +1608,7 @@ describe('api', function() hl('Register', '@a'), hl('InvalidNestingParenthesis', ')'), }) - check_parsing('(@a', 0, { + check_parsing('(@a', { -- 012 ast = { { @@ -1563,7 +1626,7 @@ describe('api', function() hl('NestingParenthesis', '('), hl('Register', '@a'), }) - check_parsing('@a(@b', 0, { + check_parsing('@a(@b', { -- 01234 ast = { { @@ -1583,7 +1646,7 @@ describe('api', function() hl('CallingParenthesis', '('), hl('Register', '@b'), }) - check_parsing('@a(@b, @c, @d, @e)', 0, { + check_parsing('@a(@b, @c, @d, @e)', { -- 012345678901234567 -- 0 1 ast = { @@ -1625,7 +1688,7 @@ describe('api', function() hl('Register', '@e', 1), hl('CallingParenthesis', ')'), }) - check_parsing('@a(@b(@c))', 0, { + check_parsing('@a(@b(@c))', { -- 01234567890123456789012345678901234567 -- 0 1 2 3 ast = { @@ -1652,7 +1715,7 @@ describe('api', function() hl('CallingParenthesis', ')'), hl('CallingParenthesis', ')'), }) - check_parsing('@a(@b(@c(@d(@e), @f(@g(@h), @i(@j)))))', 0, { + check_parsing('@a(@b(@c(@d(@e), @f(@g(@h), @i(@j)))))', { -- 01234567890123456789012345678901234567 -- 0 1 2 3 ast = { @@ -1742,14 +1805,14 @@ describe('api', function() }) end) it('works with variable names, including curly braces ones', function() - check_parsing('var', 0, { + check_parsing('var', { ast = { 'PlainIdentifier(scope=0,ident=var):0:0:var', }, }, { hl('IdentifierName', 'var'), }) - check_parsing('g:var', 0, { + check_parsing('g:var', { ast = { 'PlainIdentifier(scope=g,ident=var):0:0:g:var', }, @@ -1758,7 +1821,7 @@ describe('api', function() hl('IdentifierScopeDelimiter', ':'), hl('IdentifierName', 'var'), }) - check_parsing('g:', 0, { + check_parsing('g:', { ast = { 'PlainIdentifier(scope=g,ident=):0:0:g:', }, @@ -1766,7 +1829,7 @@ describe('api', function() hl('IdentifierScope', 'g'), hl('IdentifierScopeDelimiter', ':'), }) - check_parsing('{a}', 0, { + check_parsing('{a}', { -- 012 ast = { { @@ -1781,7 +1844,7 @@ describe('api', function() hl('IdentifierName', 'a'), hl('Curly', '}'), }) - check_parsing('{a:b}', 0, { + check_parsing('{a:b}', { -- 012 ast = { { @@ -1798,7 +1861,7 @@ describe('api', function() hl('IdentifierName', 'b'), hl('Curly', '}'), }) - check_parsing('{a:@b}', 0, { + check_parsing('{a:@b}', { -- 012345 ast = { { @@ -1825,7 +1888,7 @@ describe('api', function() hl('InvalidRegister', '@b'), hl('Curly', '}'), }) - check_parsing('{@a}', 0, { + check_parsing('{@a}', { ast = { { 'CurlyBracesIdentifier:0:0:{', @@ -1839,7 +1902,7 @@ describe('api', function() hl('Register', '@a'), hl('Curly', '}'), }) - check_parsing('{@a}{@b}', 0, { + check_parsing('{@a}{@b}', { -- 01234567 ast = { { @@ -1868,7 +1931,7 @@ describe('api', function() hl('Register', '@b'), hl('Curly', '}'), }) - check_parsing('g:{@a}', 0, { + check_parsing('g:{@a}', { -- 01234567 ast = { { @@ -1891,7 +1954,7 @@ describe('api', function() hl('Register', '@a'), hl('Curly', '}'), }) - check_parsing('{@a}_test', 0, { + check_parsing('{@a}_test', { -- 012345678 ast = { { @@ -1913,7 +1976,7 @@ describe('api', function() hl('Curly', '}'), hl('IdentifierName', '_test'), }) - check_parsing('g:{@a}_test', 0, { + check_parsing('g:{@a}_test', { -- 01234567890 ast = { { @@ -1943,7 +2006,7 @@ describe('api', function() hl('Curly', '}'), hl('IdentifierName', '_test'), }) - check_parsing('g:{@a}_test()', 0, { + check_parsing('g:{@a}_test()', { -- 0123456789012 ast = { { @@ -1980,7 +2043,7 @@ describe('api', function() hl('CallingParenthesis', '('), hl('CallingParenthesis', ')'), }) - check_parsing('{@a} ()', 0, { + check_parsing('{@a} ()', { -- 0123456789012 ast = { { @@ -2002,7 +2065,7 @@ describe('api', function() hl('CallingParenthesis', '(', 1), hl('CallingParenthesis', ')'), }) - check_parsing('g:{@a} ()', 0, { + check_parsing('g:{@a} ()', { -- 0123456789012 ast = { { @@ -2032,7 +2095,7 @@ describe('api', function() hl('CallingParenthesis', '(', 1), hl('CallingParenthesis', ')'), }) - check_parsing('{@a', 0, { + check_parsing('{@a', { -- 012 ast = { { @@ -2052,7 +2115,7 @@ describe('api', function() }) end) it('works with lambdas and dictionaries', function() - check_parsing('{}', 0, { + check_parsing('{}', { ast = { 'DictLiteral:0:0:{', }, @@ -2060,7 +2123,7 @@ describe('api', function() hl('Dict', '{'), hl('Dict', '}'), }) - check_parsing('{->@a}', 0, { + check_parsing('{->@a}', { ast = { { 'Lambda:0:0:{', @@ -2080,7 +2143,7 @@ describe('api', function() hl('Register', '@a'), hl('Lambda', '}'), }) - check_parsing('{->@a+@b}', 0, { + check_parsing('{->@a+@b}', { -- 012345678 ast = { { @@ -2109,7 +2172,7 @@ describe('api', function() hl('Register', '@b'), hl('Lambda', '}'), }) - check_parsing('{a->@a}', 0, { + check_parsing('{a->@a}', { -- 012345678 ast = { { @@ -2132,7 +2195,7 @@ describe('api', function() hl('Register', '@a'), hl('Lambda', '}'), }) - check_parsing('{a,b->@a}', 0, { + check_parsing('{a,b->@a}', { -- 012345678 ast = { { @@ -2163,7 +2226,7 @@ describe('api', function() hl('Register', '@a'), hl('Lambda', '}'), }) - check_parsing('{a,b,c->@a}', 0, { + check_parsing('{a,b,c->@a}', { -- 01234567890 ast = { { @@ -2202,7 +2265,7 @@ describe('api', function() hl('Register', '@a'), hl('Lambda', '}'), }) - check_parsing('{a,b,c,d->@a}', 0, { + check_parsing('{a,b,c,d->@a}', { -- 0123456789012 ast = { { @@ -2249,7 +2312,7 @@ describe('api', function() hl('Register', '@a'), hl('Lambda', '}'), }) - check_parsing('{a,b,c,d,->@a}', 0, { + check_parsing('{a,b,c,d,->@a}', { -- 01234567890123 ast = { { @@ -2302,7 +2365,7 @@ describe('api', function() hl('Register', '@a'), hl('Lambda', '}'), }) - check_parsing('{a,b->{c,d->{e,f->@a}}}', 0, { + check_parsing('{a,b->{c,d->{e,f->@a}}}', { -- 01234567890123456789012 -- 0 1 2 ast = { @@ -2380,7 +2443,7 @@ describe('api', function() hl('Lambda', '}'), hl('Lambda', '}'), }) - check_parsing('{a,b->c,d}', 0, { + check_parsing('{a,b->c,d}', { -- 0123456789 ast = { { @@ -2423,7 +2486,7 @@ describe('api', function() hl('IdentifierName', 'd'), hl('Lambda', '}'), }) - check_parsing('a,b,c,d', 0, { + check_parsing('a,b,c,d', { -- 0123456789 ast = { { @@ -2459,7 +2522,7 @@ describe('api', function() hl('InvalidComma', ','), hl('IdentifierName', 'd'), }) - check_parsing('a,b,c,d,', 0, { + check_parsing('a,b,c,d,', { -- 0123456789 ast = { { @@ -2501,7 +2564,7 @@ describe('api', function() hl('IdentifierName', 'd'), hl('InvalidComma', ','), }) - check_parsing(',', 0, { + check_parsing(',', { -- 0123456789 ast = { { @@ -2518,7 +2581,7 @@ describe('api', function() }, { hl('InvalidComma', ','), }) - check_parsing('{,a->@a}', 0, { + check_parsing('{,a->@a}', { -- 0123456789 ast = { { @@ -2552,7 +2615,7 @@ describe('api', function() hl('Register', '@a'), hl('Curly', '}'), }) - check_parsing('}', 0, { + check_parsing('}', { -- 0123456789 ast = { 'UnknownFigure:0:0:', @@ -2564,7 +2627,7 @@ describe('api', function() }, { hl('InvalidFigureBrace', '}'), }) - check_parsing('{->}', 0, { + check_parsing('{->}', { -- 0123456789 ast = { { @@ -2583,7 +2646,7 @@ describe('api', function() hl('Arrow', '->'), hl('InvalidLambda', '}'), }) - check_parsing('{a,b}', 0, { + check_parsing('{a,b}', { -- 0123456789 ast = { { @@ -2610,7 +2673,7 @@ describe('api', function() hl('IdentifierName', 'b'), hl('InvalidLambda', '}'), }) - check_parsing('{a,}', 0, { + check_parsing('{a,}', { -- 0123456789 ast = { { @@ -2635,7 +2698,7 @@ describe('api', function() hl('Comma', ','), hl('InvalidLambda', '}'), }) - check_parsing('{@a:@b}', 0, { + check_parsing('{@a:@b}', { -- 0123456789 ast = { { @@ -2658,7 +2721,7 @@ describe('api', function() hl('Register', '@b'), hl('Dict', '}'), }) - check_parsing('{@a:@b,@c:@d}', 0, { + check_parsing('{@a:@b,@c:@d}', { -- 0123456789012 -- 0 1 ast = { @@ -2698,7 +2761,7 @@ describe('api', function() hl('Register', '@d'), hl('Dict', '}'), }) - check_parsing('{@a:@b,@c:@d,@e:@f,}', 0, { + check_parsing('{@a:@b,@c:@d,@e:@f,}', { -- 01234567890123456789 -- 0 1 ast = { @@ -2760,7 +2823,7 @@ describe('api', function() hl('Comma', ','), hl('Dict', '}'), }) - check_parsing('{@a:@b,@c:@d,@e:@f,@g:}', 0, { + check_parsing('{@a:@b,@c:@d,@e:@f,@g:}', { -- 01234567890123456789012 -- 0 1 2 ast = { @@ -2834,7 +2897,7 @@ describe('api', function() hl('Colon', ':'), hl('InvalidDict', '}'), }) - check_parsing('{@a:@b,}', 0, { + check_parsing('{@a:@b,}', { -- 01234567890123 -- 0 1 ast = { @@ -2864,7 +2927,7 @@ describe('api', function() hl('Comma', ','), hl('Dict', '}'), }) - check_parsing('{({f -> g})(@h)(@i)}', 0, { + check_parsing('{({f -> g})(@h)(@i)}', { -- 01234567890123456789 -- 0 1 ast = { @@ -2920,7 +2983,7 @@ describe('api', function() hl('CallingParenthesis', ')'), hl('Curly', '}'), }) - check_parsing('a:{b()}c', 0, { + check_parsing('a:{b()}c', { -- 01234567 ast = { { @@ -2957,7 +3020,7 @@ describe('api', function() hl('Curly', '}'), hl('IdentifierName', 'c'), }) - check_parsing('a:{{b, c -> @d + @e + ({f -> g})(@h)}(@i)}j', 0, { + check_parsing('a:{{b, c -> @d + @e + ({f -> g})(@h)}(@i)}j', { -- 01234567890123456789012345678901234567890123456 -- 0 1 2 3 4 ast = { @@ -3067,7 +3130,7 @@ describe('api', function() hl('Curly', '}'), hl('IdentifierName', 'j'), }) - check_parsing('{@a + @b : @c + @d, @e + @f : @g + @i}', 0, { + check_parsing('{@a + @b : @c + @d, @e + @f : @g + @i}', { -- 01234567890123456789012345678901234567 -- 0 1 2 3 ast = { @@ -3139,7 +3202,7 @@ describe('api', function() hl('Register', '@i', 1), hl('Dict', '}'), }) - check_parsing('-> -> ->', 0, { + check_parsing('-> -> ->', { -- 01234567 ast = { { @@ -3170,7 +3233,7 @@ describe('api', function() hl('InvalidArrow', '->', 1), hl('InvalidArrow', '->', 1), }) - check_parsing('a -> b -> c -> d', 0, { + check_parsing('a -> b -> c -> d', { -- 0123456789012345 -- 0 1 ast = { @@ -3207,7 +3270,7 @@ describe('api', function() hl('InvalidArrow', '->', 1), hl('IdentifierName', 'd', 1), }) - check_parsing('{a -> b -> c}', 0, { + check_parsing('{a -> b -> c}', { -- 0123456789012 -- 0 1 ast = { @@ -3243,7 +3306,7 @@ describe('api', function() hl('IdentifierName', 'c', 1), hl('Lambda', '}'), }) - check_parsing('{a: -> b}', 0, { + check_parsing('{a: -> b}', { -- 012345678 ast = { { @@ -3272,7 +3335,7 @@ describe('api', function() hl('Curly', '}'), }) - check_parsing('{a:b -> b}', 0, { + check_parsing('{a:b -> b}', { -- 0123456789 ast = { { @@ -3302,7 +3365,7 @@ describe('api', function() hl('Curly', '}'), }) - check_parsing('{a#b -> b}', 0, { + check_parsing('{a#b -> b}', { -- 0123456789 ast = { { @@ -3329,7 +3392,7 @@ describe('api', function() hl('IdentifierName', 'b', 1), hl('Curly', '}'), }) - check_parsing('{a : b : c}', 0, { + check_parsing('{a : b : c}', { -- 01234567890 -- 0 1 ast = { @@ -3365,7 +3428,7 @@ describe('api', function() hl('IdentifierName', 'c', 1), hl('Dict', '}'), }) - check_parsing('{', 0, { + check_parsing('{', { -- 0 ast = { 'UnknownFigure:0:0:{', @@ -3377,7 +3440,7 @@ describe('api', function() }, { hl('FigureBrace', '{'), }) - check_parsing('{a', 0, { + check_parsing('{a', { -- 01 ast = { { @@ -3395,7 +3458,7 @@ describe('api', function() hl('FigureBrace', '{'), hl('IdentifierName', 'a'), }) - check_parsing('{a,b', 0, { + check_parsing('{a,b', { -- 0123 ast = { { @@ -3421,7 +3484,7 @@ describe('api', function() hl('Comma', ','), hl('IdentifierName', 'b'), }) - check_parsing('{a,b->', 0, { + check_parsing('{a,b->', { -- 012345 ast = { { @@ -3449,7 +3512,7 @@ describe('api', function() hl('IdentifierName', 'b'), hl('Arrow', '->'), }) - check_parsing('{a,b->c', 0, { + check_parsing('{a,b->c', { -- 0123456 ast = { { @@ -3483,7 +3546,7 @@ describe('api', function() hl('Arrow', '->'), hl('IdentifierName', 'c'), }) - check_parsing('{a : b', 0, { + check_parsing('{a : b', { -- 012345 ast = { { @@ -3509,7 +3572,7 @@ describe('api', function() hl('Colon', ':', 1), hl('IdentifierName', 'b', 1), }) - check_parsing('{a : b,', 0, { + check_parsing('{a : b,', { -- 0123456 ast = { { @@ -3543,7 +3606,7 @@ describe('api', function() }) end) it('works with ternary operator', function() - check_parsing('a ? b : c', 0, { + check_parsing('a ? b : c', { -- 012345678 ast = { { @@ -3567,7 +3630,7 @@ describe('api', function() hl('TernaryColon', ':', 1), hl('IdentifierName', 'c', 1), }) - check_parsing('@a?@b?@c:@d:@e', 0, { + check_parsing('@a?@b?@c:@d:@e', { -- 01234567890123 -- 0 1 ast = { @@ -3608,7 +3671,7 @@ describe('api', function() hl('TernaryColon', ':'), hl('Register', '@e'), }) - check_parsing('@a?@b:@c?@d:@e', 0, { + check_parsing('@a?@b:@c?@d:@e', { -- 01234567890123 -- 0 1 ast = { @@ -3649,7 +3712,7 @@ describe('api', function() hl('TernaryColon', ':'), hl('Register', '@e'), }) - check_parsing('@a?@b?@c?@d:@e?@f:@g:@h?@i:@j:@k', 0, { + check_parsing('@a?@b?@c?@d:@e?@f:@g:@h?@i:@j:@k', { -- 01234567890123456789012345678901 -- 0 1 2 3 ast = { @@ -3738,7 +3801,7 @@ describe('api', function() hl('TernaryColon', ':'), hl('Register', '@k'), }) - check_parsing('?', 0, { + check_parsing('?', { -- 0 ast = { { @@ -3757,7 +3820,7 @@ describe('api', function() hl('InvalidTernary', '?'), }) - check_parsing('?:', 0, { + check_parsing('?:', { -- 01 ast = { { @@ -3782,7 +3845,7 @@ describe('api', function() hl('InvalidTernaryColon', ':'), }) - check_parsing('?::', 0, { + check_parsing('?::', { -- 012 ast = { { @@ -3814,7 +3877,7 @@ describe('api', function() hl('InvalidColon', ':'), }) - check_parsing('a?b', 0, { + check_parsing('a?b', { -- 012 ast = { { @@ -3839,7 +3902,7 @@ describe('api', function() hl('Ternary', '?'), hl('IdentifierName', 'b'), }) - check_parsing('a?b:', 0, { + check_parsing('a?b:', { -- 0123 ast = { { @@ -3866,7 +3929,7 @@ describe('api', function() hl('IdentifierScopeDelimiter', ':'), }) - check_parsing('a?b::c', 0, { + check_parsing('a?b::c', { -- 012345 ast = { { @@ -3892,7 +3955,7 @@ describe('api', function() hl('IdentifierName', 'c'), }) - check_parsing('a?b :', 0, { + check_parsing('a?b :', { -- 01234 ast = { { @@ -3919,7 +3982,7 @@ describe('api', function() hl('TernaryColon', ':', 1), }) - check_parsing('(@a?@b:@c)?@d:@e', 0, { + check_parsing('(@a?@b:@c)?@d:@e', { -- 0123456789012345 -- 0 1 ast = { @@ -3968,7 +4031,7 @@ describe('api', function() hl('Register', '@e'), }) - check_parsing('(@a?@b:@c)?(@d?@e:@f):(@g?@h:@i)', 0, { + check_parsing('(@a?@b:@c)?(@d?@e:@f):(@g?@h:@i)', { -- 01234567890123456789012345678901 -- 0 1 2 3 ast = { @@ -4063,7 +4126,7 @@ describe('api', function() hl('NestingParenthesis', ')'), }) - check_parsing('(@a?@b:@c)?@d?@e:@f:@g?@h:@i', 0, { + check_parsing('(@a?@b:@c)?@d?@e:@f:@g?@h:@i', { -- 0123456789012345678901234567 -- 0 1 2 ast = { @@ -4143,7 +4206,7 @@ describe('api', function() hl('TernaryColon', ':'), hl('Register', '@i'), }) - check_parsing('a?b{cdef}g:h', 0, { + check_parsing('a?b{cdef}g:h', { -- 012345678901 -- 0 1 ast = { @@ -4189,7 +4252,7 @@ describe('api', function() hl('TernaryColon', ':'), hl('IdentifierName', 'h'), }) - check_parsing('a ? b : c : d', 0, { + check_parsing('a ? b : c : d', { -- 0123456789012 -- 0 1 ast = { @@ -4228,7 +4291,7 @@ describe('api', function() }) end) it('works with comparison operators', function() - check_parsing('a == b', 0, { + check_parsing('a == b', { -- 012345 ast = { { @@ -4245,7 +4308,7 @@ describe('api', function() hl('IdentifierName', 'b', 1), }) - check_parsing('a ==? b', 0, { + check_parsing('a ==? b', { -- 0123456 ast = { { @@ -4263,7 +4326,7 @@ describe('api', function() hl('IdentifierName', 'b', 1), }) - check_parsing('a ==# b', 0, { + check_parsing('a ==# b', { -- 0123456 ast = { { @@ -4281,7 +4344,7 @@ describe('api', function() hl('IdentifierName', 'b', 1), }) - check_parsing('a !=# b', 0, { + check_parsing('a !=# b', { -- 0123456 ast = { { @@ -4299,7 +4362,7 @@ describe('api', function() hl('IdentifierName', 'b', 1), }) - check_parsing('a <=# b', 0, { + check_parsing('a <=# b', { -- 0123456 ast = { { @@ -4317,7 +4380,7 @@ describe('api', function() hl('IdentifierName', 'b', 1), }) - check_parsing('a >=# b', 0, { + check_parsing('a >=# b', { -- 0123456 ast = { { @@ -4335,7 +4398,7 @@ describe('api', function() hl('IdentifierName', 'b', 1), }) - check_parsing('a ># b', 0, { + check_parsing('a ># b', { -- 012345 ast = { { @@ -4353,7 +4416,7 @@ describe('api', function() hl('IdentifierName', 'b', 1), }) - check_parsing('a <# b', 0, { + check_parsing('a <# b', { -- 012345 ast = { { @@ -4371,7 +4434,7 @@ describe('api', function() hl('IdentifierName', 'b', 1), }) - check_parsing('a is#b', 0, { + check_parsing('a is#b', { -- 012345 ast = { { @@ -4389,7 +4452,7 @@ describe('api', function() hl('IdentifierName', 'b'), }) - check_parsing('a is?b', 0, { + check_parsing('a is?b', { -- 012345 ast = { { @@ -4407,7 +4470,7 @@ describe('api', function() hl('IdentifierName', 'b'), }) - check_parsing('a isnot b', 0, { + check_parsing('a isnot b', { -- 012345678 ast = { { @@ -4424,7 +4487,7 @@ describe('api', function() hl('IdentifierName', 'b', 1), }) - check_parsing('a < b < c', 0, { + check_parsing('a < b < c', { -- 012345678 ast = { { @@ -4453,7 +4516,7 @@ describe('api', function() hl('IdentifierName', 'c', 1), }) - check_parsing('a < b <# c', 0, { + check_parsing('a < b <# c', { -- 012345678 ast = { { @@ -4483,7 +4546,7 @@ describe('api', function() hl('IdentifierName', 'c', 1), }) - check_parsing('a += b', 0, { + check_parsing('a += b', { -- 012345 ast = { { @@ -4510,7 +4573,7 @@ describe('api', function() hl('InvalidComparison', '='), hl('IdentifierName', 'b', 1), }) - check_parsing('a + b == c + d', 0, { + check_parsing('a + b == c + d', { -- 01234567890123 -- 0 1 ast = { @@ -4543,7 +4606,7 @@ describe('api', function() hl('BinaryPlus', '+', 1), hl('IdentifierName', 'd', 1), }) - check_parsing('+ a == + b', 0, { + check_parsing('+ a == + b', { -- 0123456789 ast = { { @@ -4573,7 +4636,7 @@ describe('api', function() }) end) it('works with concat/subscript', function() - check_parsing('.', 0, { + check_parsing('.', { -- 0 ast = { { @@ -4591,7 +4654,7 @@ describe('api', function() hl('InvalidConcatOrSubscript', '.'), }) - check_parsing('a.', 0, { + check_parsing('a.', { -- 01 ast = { { @@ -4610,7 +4673,7 @@ describe('api', function() hl('ConcatOrSubscript', '.'), }) - check_parsing('a.b', 0, { + check_parsing('a.b', { -- 012 ast = { { @@ -4627,7 +4690,7 @@ describe('api', function() hl('IdentifierKey', 'b'), }) - check_parsing('1.2', 0, { + check_parsing('1.2', { -- 012 ast = { 'Float(val=1.200000e+00):0:0:1.2', @@ -4636,7 +4699,7 @@ describe('api', function() hl('Float', '1.2'), }) - check_parsing('1.2 + 1.3e-5', 0, { + check_parsing('1.2 + 1.3e-5', { -- 012345678901 -- 0 1 ast = { @@ -4654,7 +4717,7 @@ describe('api', function() hl('Float', '1.3e-5', 1), }) - check_parsing('a . 1.2 + 1.3e-5', 0, { + check_parsing('a . 1.2 + 1.3e-5', { -- 0123456789012345 -- 0 1 ast = { @@ -4688,7 +4751,7 @@ describe('api', function() hl('Float', '1.3e-5', 1), }) - check_parsing('1.3e-5 + 1.2 . a', 0, { + check_parsing('1.3e-5 + 1.2 . a', { -- 0123456789012345 -- 0 1 ast = { @@ -4714,7 +4777,7 @@ describe('api', function() hl('IdentifierName', 'a', 1), }) - check_parsing('1.3e-5 + a . 1.2', 0, { + check_parsing('1.3e-5 + a . 1.2', { -- 0123456789012345 -- 0 1 ast = { @@ -4748,7 +4811,7 @@ describe('api', function() hl('IdentifierKey', '2'), }) - check_parsing('1.2.3', 0, { + check_parsing('1.2.3', { -- 01234 ast = { { @@ -4773,7 +4836,7 @@ describe('api', function() hl('IdentifierKey', '3'), }) - check_parsing('a.1.2', 0, { + check_parsing('a.1.2', { -- 01234 ast = { { @@ -4798,7 +4861,7 @@ describe('api', function() hl('IdentifierKey', '2'), }) - check_parsing('a . 1.2', 0, { + check_parsing('a . 1.2', { -- 0123456 ast = { { @@ -4823,7 +4886,7 @@ describe('api', function() hl('IdentifierKey', '2'), }) - check_parsing('+a . +b', 0, { + check_parsing('+a . +b', { -- 0123456 ast = { { @@ -4852,7 +4915,7 @@ describe('api', function() hl('IdentifierName', 'b'), }) - check_parsing('a. b', 0, { + check_parsing('a. b', { -- 0123 ast = { { @@ -4869,7 +4932,7 @@ describe('api', function() hl('IdentifierName', 'b', 1), }) - check_parsing('a. 1', 0, { + check_parsing('a. 1', { -- 0123 ast = { { @@ -4887,7 +4950,7 @@ describe('api', function() }) end) it('works with bracket subscripts', function() - check_parsing(':', 0, { + check_parsing(':', { -- 0 ast = { { @@ -4904,7 +4967,7 @@ describe('api', function() }, { hl('InvalidColon', ':'), }) - check_parsing('a[]', 0, { + check_parsing('a[]', { -- 012 ast = { { @@ -4923,7 +4986,7 @@ describe('api', function() hl('SubscriptBracket', '['), hl('InvalidSubscriptBracket', ']'), }) - check_parsing('a[b:]', 0, { + check_parsing('a[b:]', { -- 01234 ast = { { @@ -4942,7 +5005,7 @@ describe('api', function() hl('SubscriptBracket', ']'), }) - check_parsing('a[b:c]', 0, { + check_parsing('a[b:c]', { -- 012345 ast = { { @@ -4961,7 +5024,7 @@ describe('api', function() hl('IdentifierName', 'c'), hl('SubscriptBracket', ']'), }) - check_parsing('a[b : c]', 0, { + check_parsing('a[b : c]', { -- 01234567 ast = { { @@ -4987,7 +5050,7 @@ describe('api', function() hl('SubscriptBracket', ']'), }) - check_parsing('a[: b]', 0, { + check_parsing('a[: b]', { -- 012345 ast = { { @@ -5012,7 +5075,7 @@ describe('api', function() hl('SubscriptBracket', ']'), }) - check_parsing('a[b :]', 0, { + check_parsing('a[b :]', { -- 012345 ast = { { @@ -5035,7 +5098,7 @@ describe('api', function() hl('SubscriptColon', ':', 1), hl('SubscriptBracket', ']'), }) - check_parsing('a[b][c][d](e)(f)(g)', 0, { + check_parsing('a[b][c][d](e)(f)(g)', { -- 0123456789012345678 -- 0 1 ast = { @@ -5098,7 +5161,7 @@ describe('api', function() hl('IdentifierName', 'g'), hl('CallingParenthesis', ')'), }) - check_parsing('{a}{b}{c}[d][e][f]', 0, { + check_parsing('{a}{b}{c}[d][e][f]', { -- 012345678901234567 -- 0 1 ast = { @@ -5171,7 +5234,7 @@ describe('api', function() }) end) it('supports list literals', function() - check_parsing('[]', 0, { + check_parsing('[]', { -- 01 ast = { 'ListLiteral:0:0:[', @@ -5181,7 +5244,7 @@ describe('api', function() hl('List', ']'), }) - check_parsing('[a]', 0, { + check_parsing('[a]', { -- 012 ast = { { @@ -5197,7 +5260,7 @@ describe('api', function() hl('List', ']'), }) - check_parsing('[a, b]', 0, { + check_parsing('[a, b]', { -- 012345 ast = { { @@ -5221,7 +5284,7 @@ describe('api', function() hl('List', ']'), }) - check_parsing('[a, b, c]', 0, { + check_parsing('[a, b, c]', { -- 012345678 ast = { { @@ -5253,7 +5316,7 @@ describe('api', function() hl('List', ']'), }) - check_parsing('[a, b, c, ]', 0, { + check_parsing('[a, b, c, ]', { -- 01234567890 -- 0 1 ast = { @@ -5292,7 +5355,7 @@ describe('api', function() hl('List', ']', 1), }) - check_parsing('[a : b, c : d]', 0, { + check_parsing('[a : b, c : d]', { -- 01234567890123 -- 0 1 ast = { @@ -5337,7 +5400,7 @@ describe('api', function() hl('List', ']'), }) - check_parsing(']', 0, { + check_parsing(']', { -- 0 ast = { 'ListLiteral:0:0:', @@ -5350,7 +5413,7 @@ describe('api', function() hl('InvalidList', ']'), }) - check_parsing('a]', 0, { + check_parsing('a]', { -- 01 ast = { { @@ -5369,7 +5432,7 @@ describe('api', function() hl('InvalidList', ']'), }) - check_parsing('[] []', 0, { + check_parsing('[] []', { -- 01234 ast = { { @@ -5390,9 +5453,23 @@ describe('api', function() hl('InvalidSpacing', ' '), hl('List', '['), hl('List', ']'), + }, { + [1] = { + ast = { + err = REMOVE_THIS, + ast = { + 'ListLiteral:0:0:[', + }, + }, + hl_fs = { + [3] = REMOVE_THIS, + [4] = REMOVE_THIS, + [5] = REMOVE_THIS, + }, + }, }) - check_parsing('[][]', 0, { + check_parsing('[][]', { -- 0123 ast = { { @@ -5413,7 +5490,7 @@ describe('api', function() hl('InvalidSubscriptBracket', ']'), }) - check_parsing('[', 0, { + check_parsing('[', { -- 0 ast = { 'ListLiteral:0:0:[', @@ -5426,7 +5503,7 @@ describe('api', function() hl('List', '['), }) - check_parsing('[1', 0, { + check_parsing('[1', { -- 01 ast = { { @@ -5446,7 +5523,7 @@ describe('api', function() }) end) it('works with strings', function() - check_parsing('\'abc\'', 0, { + check_parsing('\'abc\'', { -- 01234 ast = { 'SingleQuotedString(val="abc"):0:0:\'abc\'', @@ -5456,7 +5533,7 @@ describe('api', function() hl('SingleQuotedBody', 'abc'), hl('SingleQuote', '\''), }) - check_parsing('"abc"', 0, { + check_parsing('"abc"', { -- 01234 ast = { 'DoubleQuotedString(val="abc"):0:0:"abc"', @@ -5466,7 +5543,7 @@ describe('api', function() hl('DoubleQuotedBody', 'abc'), hl('DoubleQuote', '"'), }) - check_parsing('\'\'', 0, { + check_parsing('\'\'', { -- 01 ast = { 'SingleQuotedString(val=""):0:0:\'\'', @@ -5475,7 +5552,7 @@ describe('api', function() hl('SingleQuote', '\''), hl('SingleQuote', '\''), }) - check_parsing('""', 0, { + check_parsing('""', { -- 01 ast = { 'DoubleQuotedString(val=""):0:0:""', @@ -5484,7 +5561,7 @@ describe('api', function() hl('DoubleQuote', '"'), hl('DoubleQuote', '"'), }) - check_parsing('"', 0, { + check_parsing('"', { -- 0 ast = { 'DoubleQuotedString(val=""):0:0:"', @@ -5496,7 +5573,7 @@ describe('api', function() }, { hl('InvalidDoubleQuote', '"'), }) - check_parsing('\'', 0, { + check_parsing('\'', { -- 0 ast = { 'SingleQuotedString(val=""):0:0:\'', @@ -5508,7 +5585,7 @@ describe('api', function() }, { hl('InvalidSingleQuote', '\''), }) - check_parsing('"a', 0, { + check_parsing('"a', { -- 01 ast = { 'DoubleQuotedString(val="a"):0:0:"a', @@ -5521,7 +5598,7 @@ describe('api', function() hl('InvalidDoubleQuote', '"'), hl('InvalidDoubleQuotedBody', 'a'), }) - check_parsing('\'a', 0, { + check_parsing('\'a', { -- 01 ast = { 'SingleQuotedString(val="a"):0:0:\'a', @@ -5534,7 +5611,7 @@ describe('api', function() hl('InvalidSingleQuote', '\''), hl('InvalidSingleQuotedBody', 'a'), }) - check_parsing('\'abc\'\'def\'', 0, { + check_parsing('\'abc\'\'def\'', { -- 0123456789 ast = { 'SingleQuotedString(val="abc\'def"):0:0:\'abc\'\'def\'', @@ -5546,7 +5623,7 @@ describe('api', function() hl('SingleQuotedBody', 'def'), hl('SingleQuote', '\''), }) - check_parsing('\'abc\'\'', 0, { + check_parsing('\'abc\'\'', { -- 012345 ast = { 'SingleQuotedString(val="abc\'"):0:0:\'abc\'\'', @@ -5560,7 +5637,7 @@ describe('api', function() hl('InvalidSingleQuotedBody', 'abc'), hl('InvalidSingleQuotedQuote', '\'\''), }) - check_parsing('\'\'\'\'\'\'\'\'', 0, { + check_parsing('\'\'\'\'\'\'\'\'', { -- 01234567 ast = { 'SingleQuotedString(val="\'\'\'"):0:0:\'\'\'\'\'\'\'\'', @@ -5572,7 +5649,7 @@ describe('api', function() hl('SingleQuotedQuote', '\'\''), hl('SingleQuote', '\''), }) - check_parsing('\'\'\'a\'\'\'\'bc\'', 0, { + check_parsing('\'\'\'a\'\'\'\'bc\'', { -- 01234567890 -- 0 1 ast = { @@ -5587,7 +5664,7 @@ describe('api', function() hl('SingleQuotedBody', 'bc'), hl('SingleQuote', '\''), }) - check_parsing('"\\"\\"\\"\\""', 0, { + check_parsing('"\\"\\"\\"\\""', { -- 0123456789 ast = { 'DoubleQuotedString(val="\\"\\"\\"\\""):0:0:"\\"\\"\\"\\""', @@ -5600,7 +5677,7 @@ describe('api', function() hl('DoubleQuotedEscape', '\\"'), hl('DoubleQuote', '"'), }) - check_parsing('"abc\\"def\\"ghi\\"jkl\\"mno"', 0, { + check_parsing('"abc\\"def\\"ghi\\"jkl\\"mno"', { -- 0123456789012345678901234 -- 0 1 2 ast = { @@ -5619,7 +5696,7 @@ describe('api', function() hl('DoubleQuotedBody', 'mno'), hl('DoubleQuote', '"'), }) - check_parsing('"\\b\\e\\f\\r\\t\\\\"', 0, { + check_parsing('"\\b\\e\\f\\r\\t\\\\"', { -- 0123456789012345 -- 0 1 ast = { @@ -5635,7 +5712,7 @@ describe('api', function() hl('DoubleQuotedEscape', '\\\\'), hl('DoubleQuote', '"'), }) - check_parsing('"\\n\n"', 0, { + check_parsing('"\\n\n"', { -- 01234 ast = { 'DoubleQuotedString(val="\\\n\\\n"):0:0:"\\n\n"', @@ -5646,7 +5723,7 @@ describe('api', function() hl('DoubleQuotedBody', '\n'), hl('DoubleQuote', '"'), }) - check_parsing('"\\x00"', 0, { + check_parsing('"\\x00"', { -- 012345 ast = { 'DoubleQuotedString(val="\\0"):0:0:"\\x00"', @@ -5656,7 +5733,7 @@ describe('api', function() hl('DoubleQuotedEscape', '\\x00'), hl('DoubleQuote', '"'), }) - check_parsing('"\\xFF"', 0, { + check_parsing('"\\xFF"', { -- 012345 ast = { 'DoubleQuotedString(val="\255"):0:0:"\\xFF"', @@ -5666,7 +5743,7 @@ describe('api', function() hl('DoubleQuotedEscape', '\\xFF'), hl('DoubleQuote', '"'), }) - check_parsing('"\\xF"', 0, { + check_parsing('"\\xF"', { -- 012345 ast = { 'DoubleQuotedString(val="\\15"):0:0:"\\xF"', @@ -5676,7 +5753,7 @@ describe('api', function() hl('DoubleQuotedEscape', '\\xF'), hl('DoubleQuote', '"'), }) - check_parsing('"\\u00AB"', 0, { + check_parsing('"\\u00AB"', { -- 01234567 ast = { 'DoubleQuotedString(val="«"):0:0:"\\u00AB"', @@ -5686,7 +5763,7 @@ describe('api', function() hl('DoubleQuotedEscape', '\\u00AB'), hl('DoubleQuote', '"'), }) - check_parsing('"\\U000000AB"', 0, { + check_parsing('"\\U000000AB"', { -- 01234567 ast = { 'DoubleQuotedString(val="«"):0:0:"\\U000000AB"', @@ -5696,7 +5773,7 @@ describe('api', function() hl('DoubleQuotedEscape', '\\U000000AB'), hl('DoubleQuote', '"'), }) - check_parsing('"\\x"', 0, { + check_parsing('"\\x"', { -- 0123 ast = { 'DoubleQuotedString(val="x"):0:0:"\\x"', @@ -5707,7 +5784,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\x', 0, { + check_parsing('"\\x', { -- 012 ast = { 'DoubleQuotedString(val="x"):0:0:"\\x', @@ -5721,7 +5798,7 @@ describe('api', function() hl('InvalidDoubleQuotedUnknownEscape', '\\x'), }) - check_parsing('"\\xF', 0, { + check_parsing('"\\xF', { -- 0123 ast = { 'DoubleQuotedString(val="\\15"):0:0:"\\xF', @@ -5735,7 +5812,7 @@ describe('api', function() hl('InvalidDoubleQuotedEscape', '\\xF'), }) - check_parsing('"\\u"', 0, { + check_parsing('"\\u"', { -- 0123 ast = { 'DoubleQuotedString(val="u"):0:0:"\\u"', @@ -5746,7 +5823,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\u', 0, { + check_parsing('"\\u', { -- 012 ast = { 'DoubleQuotedString(val="u"):0:0:"\\u', @@ -5760,7 +5837,7 @@ describe('api', function() hl('InvalidDoubleQuotedUnknownEscape', '\\u'), }) - check_parsing('"\\U', 0, { + check_parsing('"\\U', { -- 012 ast = { 'DoubleQuotedString(val="U"):0:0:"\\U', @@ -5774,7 +5851,7 @@ describe('api', function() hl('InvalidDoubleQuotedUnknownEscape', '\\U'), }) - check_parsing('"\\U"', 0, { + check_parsing('"\\U"', { -- 0123 ast = { 'DoubleQuotedString(val="U"):0:0:"\\U"', @@ -5785,7 +5862,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\xFX"', 0, { + check_parsing('"\\xFX"', { -- 012345 ast = { 'DoubleQuotedString(val="\\15X"):0:0:"\\xFX"', @@ -5797,7 +5874,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\XFX"', 0, { + check_parsing('"\\XFX"', { -- 012345 ast = { 'DoubleQuotedString(val="\\15X"):0:0:"\\XFX"', @@ -5809,7 +5886,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\xX"', 0, { + check_parsing('"\\xX"', { -- 01234 ast = { 'DoubleQuotedString(val="xX"):0:0:"\\xX"', @@ -5821,7 +5898,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\XX"', 0, { + check_parsing('"\\XX"', { -- 01234 ast = { 'DoubleQuotedString(val="XX"):0:0:"\\XX"', @@ -5833,7 +5910,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\uX"', 0, { + check_parsing('"\\uX"', { -- 01234 ast = { 'DoubleQuotedString(val="uX"):0:0:"\\uX"', @@ -5845,7 +5922,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\UX"', 0, { + check_parsing('"\\UX"', { -- 01234 ast = { 'DoubleQuotedString(val="UX"):0:0:"\\UX"', @@ -5857,7 +5934,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\x0X"', 0, { + check_parsing('"\\x0X"', { -- 012345 ast = { 'DoubleQuotedString(val="\\0X"):0:0:"\\x0X"', @@ -5869,7 +5946,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\X0X"', 0, { + check_parsing('"\\X0X"', { -- 012345 ast = { 'DoubleQuotedString(val="\\0X"):0:0:"\\X0X"', @@ -5881,7 +5958,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\u0X"', 0, { + check_parsing('"\\u0X"', { -- 012345 ast = { 'DoubleQuotedString(val="\\0X"):0:0:"\\u0X"', @@ -5893,7 +5970,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\U0X"', 0, { + check_parsing('"\\U0X"', { -- 012345 ast = { 'DoubleQuotedString(val="\\0X"):0:0:"\\U0X"', @@ -5905,7 +5982,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\x00X"', 0, { + check_parsing('"\\x00X"', { -- 0123456 ast = { 'DoubleQuotedString(val="\\0X"):0:0:"\\x00X"', @@ -5917,7 +5994,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\X00X"', 0, { + check_parsing('"\\X00X"', { -- 0123456 ast = { 'DoubleQuotedString(val="\\0X"):0:0:"\\X00X"', @@ -5929,7 +6006,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\u00X"', 0, { + check_parsing('"\\u00X"', { -- 0123456 ast = { 'DoubleQuotedString(val="\\0X"):0:0:"\\u00X"', @@ -5941,7 +6018,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\U00X"', 0, { + check_parsing('"\\U00X"', { -- 0123456 ast = { 'DoubleQuotedString(val="\\0X"):0:0:"\\U00X"', @@ -5953,7 +6030,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\u000X"', 0, { + check_parsing('"\\u000X"', { -- 01234567 ast = { 'DoubleQuotedString(val="\\0X"):0:0:"\\u000X"', @@ -5965,7 +6042,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\U000X"', 0, { + check_parsing('"\\U000X"', { -- 01234567 ast = { 'DoubleQuotedString(val="\\0X"):0:0:"\\U000X"', @@ -5977,7 +6054,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\u0000X"', 0, { + check_parsing('"\\u0000X"', { -- 012345678 ast = { 'DoubleQuotedString(val="\\0X"):0:0:"\\u0000X"', @@ -5989,7 +6066,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\U0000X"', 0, { + check_parsing('"\\U0000X"', { -- 012345678 ast = { 'DoubleQuotedString(val="\\0X"):0:0:"\\U0000X"', @@ -6001,7 +6078,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\U00000X"', 0, { + check_parsing('"\\U00000X"', { -- 0123456789 ast = { 'DoubleQuotedString(val="\\0X"):0:0:"\\U00000X"', @@ -6013,7 +6090,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\U000000X"', 0, { + check_parsing('"\\U000000X"', { -- 01234567890 -- 0 1 ast = { @@ -6026,7 +6103,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\U0000000X"', 0, { + check_parsing('"\\U0000000X"', { -- 012345678901 -- 0 1 ast = { @@ -6039,7 +6116,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\U00000000X"', 0, { + check_parsing('"\\U00000000X"', { -- 0123456789012 -- 0 1 ast = { @@ -6052,7 +6129,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\x000X"', 0, { + check_parsing('"\\x000X"', { -- 01234567 ast = { 'DoubleQuotedString(val="\\0000X"):0:0:"\\x000X"', @@ -6064,7 +6141,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\X000X"', 0, { + check_parsing('"\\X000X"', { -- 01234567 ast = { 'DoubleQuotedString(val="\\0000X"):0:0:"\\X000X"', @@ -6076,7 +6153,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\u00000X"', 0, { + check_parsing('"\\u00000X"', { -- 0123456789 ast = { 'DoubleQuotedString(val="\\0000X"):0:0:"\\u00000X"', @@ -6088,7 +6165,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\U000000000X"', 0, { + check_parsing('"\\U000000000X"', { -- 01234567890123 -- 0 1 ast = { @@ -6101,7 +6178,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\0"', 0, { + check_parsing('"\\0"', { -- 0123 ast = { 'DoubleQuotedString(val="\\0"):0:0:"\\0"', @@ -6112,7 +6189,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\00"', 0, { + check_parsing('"\\00"', { -- 01234 ast = { 'DoubleQuotedString(val="\\0"):0:0:"\\00"', @@ -6123,7 +6200,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\000"', 0, { + check_parsing('"\\000"', { -- 012345 ast = { 'DoubleQuotedString(val="\\0"):0:0:"\\000"', @@ -6134,7 +6211,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\0000"', 0, { + check_parsing('"\\0000"', { -- 0123456 ast = { 'DoubleQuotedString(val="\\0000"):0:0:"\\0000"', @@ -6146,7 +6223,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\8"', 0, { + check_parsing('"\\8"', { -- 0123 ast = { 'DoubleQuotedString(val="8"):0:0:"\\8"', @@ -6157,7 +6234,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\08"', 0, { + check_parsing('"\\08"', { -- 01234 ast = { 'DoubleQuotedString(val="\\0008"):0:0:"\\08"', @@ -6169,7 +6246,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\008"', 0, { + check_parsing('"\\008"', { -- 012345 ast = { 'DoubleQuotedString(val="\\0008"):0:0:"\\008"', @@ -6181,7 +6258,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\0008"', 0, { + check_parsing('"\\0008"', { -- 0123456 ast = { 'DoubleQuotedString(val="\\0008"):0:0:"\\0008"', @@ -6193,7 +6270,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\777"', 0, { + check_parsing('"\\777"', { -- 012345 ast = { 'DoubleQuotedString(val="\255"):0:0:"\\777"', @@ -6204,7 +6281,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\050"', 0, { + check_parsing('"\\050"', { -- 012345 ast = { 'DoubleQuotedString(val="\40"):0:0:"\\050"', @@ -6215,7 +6292,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\"', 0, { + check_parsing('"\\"', { -- 012345 ast = { 'DoubleQuotedString(val="\\21"):0:0:"\\"', @@ -6226,7 +6303,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\<', 0, { + check_parsing('"\\<', { -- 012 ast = { 'DoubleQuotedString(val="<"):0:0:"\\<', @@ -6240,7 +6317,7 @@ describe('api', function() hl('InvalidDoubleQuotedUnknownEscape', '\\<'), }) - check_parsing('"\\<"', 0, { + check_parsing('"\\<"', { -- 0123 ast = { 'DoubleQuotedString(val="<"):0:0:"\\<"', @@ -6251,7 +6328,7 @@ describe('api', function() hl('DoubleQuote', '"'), }) - check_parsing('"\\ Date: Mon, 6 Nov 2017 01:15:18 +0300 Subject: api/vim: Add “len” dictionary key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows determining where parsing ended which may be needed for e.g. parsing `:echo` with that API function. --- test/functional/api/vim_spec.lua | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index b904bd2a8f..714b1988fb 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -799,6 +799,9 @@ describe('api', function() if east_api.ast then east_api.ast = {simplify_east_api_node(line, east_api.ast)} end + if east_api.len == #line then + east_api.len = nil + end return east_api end local function simplify_east_hl(line, east_hl) @@ -997,6 +1000,7 @@ describe('api', function() }, { [1] = { ast = { + len = 2, err = REMOVE_THIS, ast = { 'Register(name=a):0:0:@a' @@ -1028,6 +1032,7 @@ describe('api', function() }, { [1] = { ast = { + len = 6, err = REMOVE_THIS, ast = { 'Register(name=a):0:0: @a' @@ -1236,6 +1241,7 @@ describe('api', function() }, { [1] = { ast = { + len = 3, err = REMOVE_THIS, ast = { 'Register(name=a):0:0:@a', @@ -5456,6 +5462,7 @@ describe('api', function() }, { [1] = { ast = { + len = 3, err = REMOVE_THIS, ast = { 'ListLiteral:0:0:[', @@ -7135,6 +7142,7 @@ describe('api', function() }, { [1] = { ast = { + len = 4, err = REMOVE_THIS, ast = { 'Option(scope=0,ident=xxx):0:0:&xxx', @@ -7520,6 +7528,7 @@ describe('api', function() }, { [1] = { ast = { + len = 1, err = REMOVE_THIS, ast = { 'Integer(val=1):0:0:1', @@ -7652,6 +7661,7 @@ describe('api', function() end) it('respects highlight argument', function() eq({ + len = 1, ast = { ivalue = 1, len = 1, @@ -7660,6 +7670,7 @@ describe('api', function() }, }, meths.parse_expression('1', '', false)) eq({ + len = 1, ast = { ivalue = 1, len = 1, @@ -7674,6 +7685,7 @@ describe('api', function() it('works (KLEE tests)', function() check_parsing('\0002&A:\000', { ast = {}, + len = 0, err = { arg = '\0002&A:\0', msg = 'E15: Expected value, got EOC: %.*s', @@ -7682,6 +7694,7 @@ describe('api', function() }, { [2] = { ast = { + len = REMOVE_THIS, ast = { { 'Colon:0:4::', @@ -7711,6 +7724,7 @@ describe('api', function() }, [3] = { ast = { + len = 2, ast = { 'Integer(val=2):0:1:2', }, @@ -7754,6 +7768,7 @@ describe('api', function() check_parsing('|"\\U\\', { -- 01234 ast = {}, + len = 0, err = { arg = '|"\\U\\', msg = 'E15: Expected value, got EOC: %.*s', @@ -7762,6 +7777,7 @@ describe('api', function() }, { [2] = { ast = { + len = REMOVE_THIS, ast = { { 'Or:0:0:|', @@ -7786,6 +7802,7 @@ describe('api', function() check_parsing('|"\\e"', { -- 01234 ast = {}, + len = 0, err = { arg = '|"\\e"', msg = 'E15: Expected value, got EOC: %.*s', @@ -7794,6 +7811,7 @@ describe('api', function() }, { [2] = { ast = { + len = REMOVE_THIS, ast = { { 'Or:0:0:|', @@ -7818,6 +7836,7 @@ describe('api', function() check_parsing('|\029', { -- 01 ast = {}, + len = 0, err = { arg = '|\029', msg = 'E15: Expected value, got EOC: %.*s', @@ -7826,6 +7845,7 @@ describe('api', function() }, { [2] = { ast = { + len = REMOVE_THIS, ast = { { 'Or:0:0:|', @@ -7892,6 +7912,7 @@ describe('api', function() }, { [1] = { ast = { + len = 1, ast = { 'UnknownFigure:0:0:', }, @@ -7917,6 +7938,7 @@ describe('api', function() }, }, }, + len = 2, err = { arg = ':?\000\000\000\000\000\000\000', msg = 'E15: Colon outside of dictionary or ternary operator: %.*s', @@ -7926,6 +7948,9 @@ describe('api', function() hl('InvalidTernary', '?'), }, { [2] = { + ast = { + len = REMOVE_THIS, + }, hl_fs = { [3] = hl('InvalidSpacing', '\0'), [4] = hl('InvalidSpacing', '\0'), -- cgit From a94255a7ac22649311f858e39b217543d0d7e5e8 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 19 Nov 2017 20:20:06 +0300 Subject: tests: Use single test file for unit and functional parser tests --- test/functional/api/vim_spec.lua | 7132 +------------------------------------- 1 file changed, 37 insertions(+), 7095 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 714b1988fb..3939bc9b52 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -766,6 +766,11 @@ describe('api', function() elseif typ == 'Environment' then typ = ('%s(ident=%s)'):format(typ, east_api_node.ident) east_api_node.ident = nil + elseif typ == 'Assignment' then + local aug = east_api_node.augmentation + if aug == '' then aug = 'Plain' end + typ = ('%s(%s)'):format(typ, aug) + east_api_node.augmentation = nil end typ = ('%s:%u:%u:%s'):format( typ, east_api_node.start[1], east_api_node.start[2], @@ -798,6 +803,9 @@ describe('api', function() end if east_api.ast then east_api.ast = {simplify_east_api_node(line, east_api.ast)} + if #east_api.ast == 0 then + east_api.ast = nil + end end if east_api.len == #line then east_api.len = nil @@ -819,11 +827,19 @@ describe('api', function() [1] = "m", [2] = "E", [3] = "mE", + [4] = "l", + [5] = "lm", + [6] = "lE", + [7] = "lmE", } - local function check_parsing(str, exp_ast, exp_highlighting_fs, - nz_flags_exps) + local function _check_parsing(opts, str, exp_ast, exp_highlighting_fs, + nz_flags_exps) + if type(str) ~= 'string' then + return + end + local zflags = opts.flags[1] nz_flags_exps = nz_flags_exps or {} - for _, flags in ipairs({0, 1, 2, 3}) do + for _, flags in ipairs(opts.flags) do local err, msg = pcall(function() local east_api = meths.parse_expression(str, FLAGS_TO_STR[flags], true) local east_hl = east_api.highlight @@ -835,8 +851,8 @@ describe('api', function() hl_fs = exp_highlighting_fs, } local add_exps = nz_flags_exps[flags] - if not add_exps and flags == 3 then - add_exps = nz_flags_exps[1] or nz_flags_exps[2] + if not add_exps and flags == 3 + zflags then + add_exps = nz_flags_exps[1 + zflags] or nz_flags_exps[2 + zflags] end if add_exps then if add_exps.ast then @@ -873,7096 +889,22 @@ describe('api', function() str)), (col + #str) end end - it('works with + and @a', function() - check_parsing('@a', { - ast = { - 'Register(name=a):0:0:@a', - }, - }, { - hl('Register', '@a'), - }) - check_parsing('+@a', { - ast = { - { - 'UnaryPlus:0:0:+', - children = { - 'Register(name=a):0:1:@a', - }, - }, - }, - }, { - hl('UnaryPlus', '+'), - hl('Register', '@a'), - }) - check_parsing('@a+@b', { - ast = { - { - 'BinaryPlus:0:2:+', - children = { - 'Register(name=a):0:0:@a', - 'Register(name=b):0:3:@b', - }, - }, - }, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+'), - hl('Register', '@b'), - }) - check_parsing('@a+@b+@c', { - ast = { - { - 'BinaryPlus:0:5:+', - children = { - { - 'BinaryPlus:0:2:+', - children = { - 'Register(name=a):0:0:@a', - 'Register(name=b):0:3:@b', - }, - }, - 'Register(name=c):0:6:@c', - }, - }, - }, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+'), - hl('Register', '@b'), - hl('BinaryPlus', '+'), - hl('Register', '@c'), - }) - check_parsing('+@a+@b', { - ast = { - { - 'BinaryPlus:0:3:+', - children = { - { - 'UnaryPlus:0:0:+', - children = { - 'Register(name=a):0:1:@a', - }, - }, - 'Register(name=b):0:4:@b', - }, - }, - }, - }, { - hl('UnaryPlus', '+'), - hl('Register', '@a'), - hl('BinaryPlus', '+'), - hl('Register', '@b'), - }) - check_parsing('+@a++@b', { - ast = { - { - 'BinaryPlus:0:3:+', - children = { - { - 'UnaryPlus:0:0:+', - children = { - 'Register(name=a):0:1:@a', - }, - }, - { - 'UnaryPlus:0:4:+', - children = { - 'Register(name=b):0:5:@b', - }, - }, - }, - }, - }, - }, { - hl('UnaryPlus', '+'), - hl('Register', '@a'), - hl('BinaryPlus', '+'), - hl('UnaryPlus', '+'), - hl('Register', '@b'), - }) - check_parsing('@a@b', { - ast = { - { - 'OpMissing:0:2:', - children = { - 'Register(name=a):0:0:@a', - 'Register(name=b):0:2:@b', - }, - }, - }, - err = { - arg = '@b', - msg = 'E15: Missing operator: %.*s', - }, - }, { - hl('Register', '@a'), - hl('InvalidRegister', '@b'), - }, { - [1] = { - ast = { - len = 2, - err = REMOVE_THIS, - ast = { - 'Register(name=a):0:0:@a' - }, - }, - hl_fs = { - [2] = REMOVE_THIS, - }, - }, - }) - check_parsing(' @a \t @b', { - ast = { - { - 'OpMissing:0:3:', - children = { - 'Register(name=a):0:0: @a', - 'Register(name=b):0:3: \t @b', - }, - }, - }, - err = { - arg = '@b', - msg = 'E15: Missing operator: %.*s', - }, - }, { - hl('Register', '@a', 1), - hl('InvalidSpacing', ' \t '), - hl('Register', '@b'), - }, { - [1] = { - ast = { - len = 6, - err = REMOVE_THIS, - ast = { - 'Register(name=a):0:0: @a' - }, - }, - hl_fs = { - [2] = REMOVE_THIS, - [3] = REMOVE_THIS, - }, - }, - }) - check_parsing('+', { - ast = { - 'UnaryPlus:0:0:+', - }, - err = { - arg = '', - msg = 'E15: Expected value, got EOC: %.*s', - }, - }, { - hl('UnaryPlus', '+'), - }) - check_parsing(' +', { - ast = { - 'UnaryPlus:0:0: +', - }, - err = { - arg = '', - msg = 'E15: Expected value, got EOC: %.*s', - }, - }, { - hl('UnaryPlus', '+', 1), - }) - check_parsing('@a+ ', { - ast = { - { - 'BinaryPlus:0:2:+', - children = { - 'Register(name=a):0:0:@a', - }, - }, - }, - err = { - arg = '', - msg = 'E15: Expected value, got EOC: %.*s', - }, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+'), - }) - end) - it('works with @a, + and parenthesis', function() - check_parsing('(@a)', { - ast = { - { - 'Nested:0:0:(', - children = { - 'Register(name=a):0:1:@a', - }, - }, - }, - }, { - hl('NestingParenthesis', '('), - hl('Register', '@a'), - hl('NestingParenthesis', ')'), - }) - check_parsing('()', { - ast = { - { - 'Nested:0:0:(', - children = { - 'Missing:0:1:', - }, - }, - }, - err = { - arg = ')', - msg = 'E15: Expected value, got parenthesis: %.*s', - }, - }, { - hl('NestingParenthesis', '('), - hl('InvalidNestingParenthesis', ')'), - }) - check_parsing(')', { - ast = { - { - 'Nested:0:0:', - children = { - 'Missing:0:0:', - }, - }, - }, - err = { - arg = ')', - msg = 'E15: Expected value, got parenthesis: %.*s', - }, - }, { - hl('InvalidNestingParenthesis', ')'), - }) - check_parsing('+)', { - ast = { - { - 'Nested:0:1:', - children = { - { - 'UnaryPlus:0:0:+', - children = { - 'Missing:0:1:', - }, - }, - }, - }, - }, - err = { - arg = ')', - msg = 'E15: Expected value, got parenthesis: %.*s', - }, - }, { - hl('UnaryPlus', '+'), - hl('InvalidNestingParenthesis', ')'), - }) - check_parsing('+@a(@b)', { - ast = { - { - 'UnaryPlus:0:0:+', - children = { - { - 'Call:0:3:(', - children = { - 'Register(name=a):0:1:@a', - 'Register(name=b):0:4:@b', - }, - }, - }, - }, - }, - }, { - hl('UnaryPlus', '+'), - hl('Register', '@a'), - hl('CallingParenthesis', '('), - hl('Register', '@b'), - hl('CallingParenthesis', ')'), - }) - check_parsing('@a+@b(@c)', { - ast = { - { - 'BinaryPlus:0:2:+', - children = { - 'Register(name=a):0:0:@a', - { - 'Call:0:5:(', - children = { - 'Register(name=b):0:3:@b', - 'Register(name=c):0:6:@c', - }, - }, - }, - }, - }, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+'), - hl('Register', '@b'), - hl('CallingParenthesis', '('), - hl('Register', '@c'), - hl('CallingParenthesis', ')'), - }) - check_parsing('@a()', { - ast = { - { - 'Call:0:2:(', - children = { - 'Register(name=a):0:0:@a', - }, - }, - }, - }, { - hl('Register', '@a'), - hl('CallingParenthesis', '('), - hl('CallingParenthesis', ')'), - }) - check_parsing('@a ()', { - ast = { - { - 'OpMissing:0:2:', - children = { - 'Register(name=a):0:0:@a', - { - 'Nested:0:2: (', - children = { - 'Missing:0:4:', - }, - }, - }, - }, - }, - err = { - arg = '()', - msg = 'E15: Missing operator: %.*s', - }, - }, { - hl('Register', '@a'), - hl('InvalidSpacing', ' '), - hl('NestingParenthesis', '('), - hl('InvalidNestingParenthesis', ')'), - }, { - [1] = { - ast = { - len = 3, - err = REMOVE_THIS, - ast = { - 'Register(name=a):0:0:@a', - }, - }, - hl_fs = { - [2] = REMOVE_THIS, - [3] = REMOVE_THIS, - [4] = REMOVE_THIS, - }, - }, - }) - check_parsing('@a + (@b)', { - ast = { - { - 'BinaryPlus:0:2: +', - children = { - 'Register(name=a):0:0:@a', - { - 'Nested:0:4: (', - children = { - 'Register(name=b):0:6:@b', - }, - }, - }, - }, - }, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+', 1), - hl('NestingParenthesis', '(', 1), - hl('Register', '@b'), - hl('NestingParenthesis', ')'), - }) - check_parsing('@a + (+@b)', { - ast = { - { - 'BinaryPlus:0:2: +', - children = { - 'Register(name=a):0:0:@a', - { - 'Nested:0:4: (', - children = { - { - 'UnaryPlus:0:6:+', - children = { - 'Register(name=b):0:7:@b', - }, - }, - }, - }, - }, - }, - }, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+', 1), - hl('NestingParenthesis', '(', 1), - hl('UnaryPlus', '+'), - hl('Register', '@b'), - hl('NestingParenthesis', ')'), - }) - check_parsing('@a + (@b + @c)', { - ast = { - { - 'BinaryPlus:0:2: +', - children = { - 'Register(name=a):0:0:@a', - { - 'Nested:0:4: (', - children = { - { - 'BinaryPlus:0:8: +', - children = { - 'Register(name=b):0:6:@b', - 'Register(name=c):0:10: @c', - }, - }, - }, - }, - }, - }, - }, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+', 1), - hl('NestingParenthesis', '(', 1), - hl('Register', '@b'), - hl('BinaryPlus', '+', 1), - hl('Register', '@c', 1), - hl('NestingParenthesis', ')'), - }) - check_parsing('(@a)+@b', { - ast = { - { - 'BinaryPlus:0:4:+', - children = { - { - 'Nested:0:0:(', - children = { - 'Register(name=a):0:1:@a', - }, - }, - 'Register(name=b):0:5:@b', - }, - }, - }, - }, { - hl('NestingParenthesis', '('), - hl('Register', '@a'), - hl('NestingParenthesis', ')'), - hl('BinaryPlus', '+'), - hl('Register', '@b'), - }) - check_parsing('@a+(@b)(@c)', { - -- 01234567890 - ast = { - { - 'BinaryPlus:0:2:+', - children = { - 'Register(name=a):0:0:@a', - { - 'Call:0:7:(', - children = { - { - 'Nested:0:3:(', - children = { 'Register(name=b):0:4:@b' }, - }, - 'Register(name=c):0:8:@c', - }, - }, - }, - }, - }, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+'), - hl('NestingParenthesis', '('), - hl('Register', '@b'), - hl('NestingParenthesis', ')'), - hl('CallingParenthesis', '('), - hl('Register', '@c'), - hl('CallingParenthesis', ')'), - }) - check_parsing('@a+((@b))(@c)', { - -- 01234567890123456890123456789 - -- 0 1 2 - ast = { - { - 'BinaryPlus:0:2:+', - children = { - 'Register(name=a):0:0:@a', - { - 'Call:0:9:(', - children = { - { - 'Nested:0:3:(', - children = { - { - 'Nested:0:4:(', - children = { 'Register(name=b):0:5:@b' } - }, - }, - }, - 'Register(name=c):0:10:@c', - }, - }, - }, - }, - }, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+'), - hl('NestingParenthesis', '('), - hl('NestingParenthesis', '('), - hl('Register', '@b'), - hl('NestingParenthesis', ')'), - hl('NestingParenthesis', ')'), - hl('CallingParenthesis', '('), - hl('Register', '@c'), - hl('CallingParenthesis', ')'), - }) - check_parsing('@a+((@b))+@c', { - -- 01234567890123456890123456789 - -- 0 1 2 - ast = { - { - 'BinaryPlus:0:9:+', - children = { - { - 'BinaryPlus:0:2:+', - children = { - 'Register(name=a):0:0:@a', - { - 'Nested:0:3:(', - children = { - { - 'Nested:0:4:(', - children = { 'Register(name=b):0:5:@b' } - }, - }, - }, - }, - }, - 'Register(name=c):0:10:@c', - }, - }, - }, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+'), - hl('NestingParenthesis', '('), - hl('NestingParenthesis', '('), - hl('Register', '@b'), - hl('NestingParenthesis', ')'), - hl('NestingParenthesis', ')'), - hl('BinaryPlus', '+'), - hl('Register', '@c'), - }) - check_parsing( - '@a + (@b + @c) + @d(@e) + (+@f) + ((+@g(@h))(@j)(@k))(@l)', {--[[ - | | | | | | | | || | | || | | ||| || || || || - 000000000011111111112222222222333333333344444444445555555 - 012345678901234567890123456789012345678901234567890123456 - ]] - ast = {{ - 'BinaryPlus:0:31: +', - children = { - { - 'BinaryPlus:0:23: +', - children = { - { - 'BinaryPlus:0:14: +', - children = { - { - 'BinaryPlus:0:2: +', - children = { - 'Register(name=a):0:0:@a', - { - 'Nested:0:4: (', - children = { - { - 'BinaryPlus:0:8: +', - children = { - 'Register(name=b):0:6:@b', - 'Register(name=c):0:10: @c', - }, - }, - }, - }, - }, - }, - { - 'Call:0:19:(', - children = { - 'Register(name=d):0:16: @d', - 'Register(name=e):0:20:@e', - }, - }, - }, - }, - { - 'Nested:0:25: (', - children = { - { - 'UnaryPlus:0:27:+', - children = { - 'Register(name=f):0:28:@f', - }, - }, - }, - }, - }, - }, - { - 'Call:0:53:(', - children = { - { - 'Nested:0:33: (', - children = { - { - 'Call:0:48:(', - children = { - { - 'Call:0:44:(', - children = { - { - 'Nested:0:35:(', - children = { - { - 'UnaryPlus:0:36:+', - children = { - { - 'Call:0:39:(', - children = { - 'Register(name=g):0:37:@g', - 'Register(name=h):0:40:@h', - }, - }, - }, - }, - }, - }, - 'Register(name=j):0:45:@j', - }, - }, - 'Register(name=k):0:49:@k', - }, - }, - }, - }, - 'Register(name=l):0:54:@l', - }, - }, - }, - }}, - }, { - hl('Register', '@a'), - hl('BinaryPlus', '+', 1), - hl('NestingParenthesis', '(', 1), - hl('Register', '@b'), - hl('BinaryPlus', '+', 1), - hl('Register', '@c', 1), - hl('NestingParenthesis', ')'), - hl('BinaryPlus', '+', 1), - hl('Register', '@d', 1), - hl('CallingParenthesis', '('), - hl('Register', '@e'), - hl('CallingParenthesis', ')'), - hl('BinaryPlus', '+', 1), - hl('NestingParenthesis', '(', 1), - hl('UnaryPlus', '+'), - hl('Register', '@f'), - hl('NestingParenthesis', ')'), - hl('BinaryPlus', '+', 1), - hl('NestingParenthesis', '(', 1), - hl('NestingParenthesis', '('), - hl('UnaryPlus', '+'), - hl('Register', '@g'), - hl('CallingParenthesis', '('), - hl('Register', '@h'), - hl('CallingParenthesis', ')'), - hl('NestingParenthesis', ')'), - hl('CallingParenthesis', '('), - hl('Register', '@j'), - hl('CallingParenthesis', ')'), - hl('CallingParenthesis', '('), - hl('Register', '@k'), - hl('CallingParenthesis', ')'), - hl('NestingParenthesis', ')'), - hl('CallingParenthesis', '('), - hl('Register', '@l'), - hl('CallingParenthesis', ')'), - }) - check_parsing('@a)', { - -- 012 - ast = { - { - 'Nested:0:2:', - children = { - 'Register(name=a):0:0:@a', - }, - }, - }, - err = { - arg = ')', - msg = 'E15: Unexpected closing parenthesis: %.*s', - }, - }, { - hl('Register', '@a'), - hl('InvalidNestingParenthesis', ')'), - }) - check_parsing('(@a', { - -- 012 - ast = { - { - 'Nested:0:0:(', - children = { - 'Register(name=a):0:1:@a', - }, - }, - }, - err = { - arg = '(@a', - msg = 'E110: Missing closing parenthesis for nested expression: %.*s', - }, - }, { - hl('NestingParenthesis', '('), - hl('Register', '@a'), - }) - check_parsing('@a(@b', { - -- 01234 - ast = { - { - 'Call:0:2:(', - children = { - 'Register(name=a):0:0:@a', - 'Register(name=b):0:3:@b', - }, - }, - }, - err = { - arg = '(@b', - msg = 'E116: Missing closing parenthesis for function call: %.*s', - }, - }, { - hl('Register', '@a'), - hl('CallingParenthesis', '('), - hl('Register', '@b'), - }) - check_parsing('@a(@b, @c, @d, @e)', { - -- 012345678901234567 - -- 0 1 - ast = { - { - 'Call:0:2:(', - children = { - 'Register(name=a):0:0:@a', - { - 'Comma:0:5:,', - children = { - 'Register(name=b):0:3:@b', - { - 'Comma:0:9:,', - children = { - 'Register(name=c):0:6: @c', - { - 'Comma:0:13:,', - children = { - 'Register(name=d):0:10: @d', - 'Register(name=e):0:14: @e', - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, { - hl('Register', '@a'), - hl('CallingParenthesis', '('), - hl('Register', '@b'), - hl('Comma', ','), - hl('Register', '@c', 1), - hl('Comma', ','), - hl('Register', '@d', 1), - hl('Comma', ','), - hl('Register', '@e', 1), - hl('CallingParenthesis', ')'), - }) - check_parsing('@a(@b(@c))', { - -- 01234567890123456789012345678901234567 - -- 0 1 2 3 - ast = { - { - 'Call:0:2:(', - children = { - 'Register(name=a):0:0:@a', - { - 'Call:0:5:(', - children = { - 'Register(name=b):0:3:@b', - 'Register(name=c):0:6:@c', - }, - }, - }, - }, - }, - }, { - hl('Register', '@a'), - hl('CallingParenthesis', '('), - hl('Register', '@b'), - hl('CallingParenthesis', '('), - hl('Register', '@c'), - hl('CallingParenthesis', ')'), - hl('CallingParenthesis', ')'), - }) - check_parsing('@a(@b(@c(@d(@e), @f(@g(@h), @i(@j)))))', { - -- 01234567890123456789012345678901234567 - -- 0 1 2 3 - ast = { - { - 'Call:0:2:(', - children = { - 'Register(name=a):0:0:@a', - { - 'Call:0:5:(', - children = { - 'Register(name=b):0:3:@b', - { - 'Call:0:8:(', - children = { - 'Register(name=c):0:6:@c', - { - 'Comma:0:15:,', - children = { - { - 'Call:0:11:(', - children = { - 'Register(name=d):0:9:@d', - 'Register(name=e):0:12:@e', - }, - }, - { - 'Call:0:19:(', - children = { - 'Register(name=f):0:16: @f', - { - 'Comma:0:26:,', - children = { - { - 'Call:0:22:(', - children = { - 'Register(name=g):0:20:@g', - 'Register(name=h):0:23:@h', - }, - }, - { - 'Call:0:30:(', - children = { - 'Register(name=i):0:27: @i', - 'Register(name=j):0:31:@j', - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, { - hl('Register', '@a'), - hl('CallingParenthesis', '('), - hl('Register', '@b'), - hl('CallingParenthesis', '('), - hl('Register', '@c'), - hl('CallingParenthesis', '('), - hl('Register', '@d'), - hl('CallingParenthesis', '('), - hl('Register', '@e'), - hl('CallingParenthesis', ')'), - hl('Comma', ','), - hl('Register', '@f', 1), - hl('CallingParenthesis', '('), - hl('Register', '@g'), - hl('CallingParenthesis', '('), - hl('Register', '@h'), - hl('CallingParenthesis', ')'), - hl('Comma', ','), - hl('Register', '@i', 1), - hl('CallingParenthesis', '('), - hl('Register', '@j'), - hl('CallingParenthesis', ')'), - hl('CallingParenthesis', ')'), - hl('CallingParenthesis', ')'), - hl('CallingParenthesis', ')'), - hl('CallingParenthesis', ')'), - }) - end) - it('works with variable names, including curly braces ones', function() - check_parsing('var', { - ast = { - 'PlainIdentifier(scope=0,ident=var):0:0:var', - }, - }, { - hl('IdentifierName', 'var'), - }) - check_parsing('g:var', { - ast = { - 'PlainIdentifier(scope=g,ident=var):0:0:g:var', - }, - }, { - hl('IdentifierScope', 'g'), - hl('IdentifierScopeDelimiter', ':'), - hl('IdentifierName', 'var'), - }) - check_parsing('g:', { - ast = { - 'PlainIdentifier(scope=g,ident=):0:0:g:', - }, - }, { - hl('IdentifierScope', 'g'), - hl('IdentifierScopeDelimiter', ':'), - }) - check_parsing('{a}', { - -- 012 - ast = { - { - 'CurlyBracesIdentifier:0:0:{', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - }, - }, - }, - }, { - hl('Curly', '{'), - hl('IdentifierName', 'a'), - hl('Curly', '}'), - }) - check_parsing('{a:b}', { - -- 012 - ast = { - { - 'CurlyBracesIdentifier:0:0:{', - children = { - 'PlainIdentifier(scope=a,ident=b):0:1:a:b', - }, - }, - }, - }, { - hl('Curly', '{'), - hl('IdentifierScope', 'a'), - hl('IdentifierScopeDelimiter', ':'), - hl('IdentifierName', 'b'), - hl('Curly', '}'), - }) - check_parsing('{a:@b}', { - -- 012345 - ast = { - { - 'CurlyBracesIdentifier:0:0:{', - children = { - { - 'OpMissing:0:3:', - children={ - 'PlainIdentifier(scope=a,ident=):0:1:a:', - 'Register(name=b):0:3:@b', - }, - }, - }, - }, - }, - err = { - arg = '@b}', - msg = 'E15: Missing operator: %.*s', - }, - }, { - hl('Curly', '{'), - hl('IdentifierScope', 'a'), - hl('IdentifierScopeDelimiter', ':'), - hl('InvalidRegister', '@b'), - hl('Curly', '}'), - }) - check_parsing('{@a}', { - ast = { - { - 'CurlyBracesIdentifier:0:0:{', - children = { - 'Register(name=a):0:1:@a', - }, - }, - }, - }, { - hl('Curly', '{'), - hl('Register', '@a'), - hl('Curly', '}'), - }) - check_parsing('{@a}{@b}', { - -- 01234567 - ast = { - { - 'ComplexIdentifier:0:4:', - children = { - { - 'CurlyBracesIdentifier:0:0:{', - children = { - 'Register(name=a):0:1:@a', - }, - }, - { - 'CurlyBracesIdentifier:0:4:{', - children = { - 'Register(name=b):0:5:@b', - }, - }, - }, - }, - }, - }, { - hl('Curly', '{'), - hl('Register', '@a'), - hl('Curly', '}'), - hl('Curly', '{'), - hl('Register', '@b'), - hl('Curly', '}'), - }) - check_parsing('g:{@a}', { - -- 01234567 - ast = { - { - 'ComplexIdentifier:0:2:', - children = { - 'PlainIdentifier(scope=g,ident=):0:0:g:', - { - 'CurlyBracesIdentifier:0:2:{', - children = { - 'Register(name=a):0:3:@a', - }, - }, - }, - }, - }, - }, { - hl('IdentifierScope', 'g'), - hl('IdentifierScopeDelimiter', ':'), - hl('Curly', '{'), - hl('Register', '@a'), - hl('Curly', '}'), - }) - check_parsing('{@a}_test', { - -- 012345678 - ast = { - { - 'ComplexIdentifier:0:4:', - children = { - { - 'CurlyBracesIdentifier:0:0:{', - children = { - 'Register(name=a):0:1:@a', - }, - }, - 'PlainIdentifier(scope=0,ident=_test):0:4:_test', - }, - }, - }, - }, { - hl('Curly', '{'), - hl('Register', '@a'), - hl('Curly', '}'), - hl('IdentifierName', '_test'), - }) - check_parsing('g:{@a}_test', { - -- 01234567890 - ast = { - { - 'ComplexIdentifier:0:2:', - children = { - 'PlainIdentifier(scope=g,ident=):0:0:g:', - { - 'ComplexIdentifier:0:6:', - children = { - { - 'CurlyBracesIdentifier:0:2:{', - children = { - 'Register(name=a):0:3:@a', - }, - }, - 'PlainIdentifier(scope=0,ident=_test):0:6:_test', - }, - }, - }, - }, - }, - }, { - hl('IdentifierScope', 'g'), - hl('IdentifierScopeDelimiter', ':'), - hl('Curly', '{'), - hl('Register', '@a'), - hl('Curly', '}'), - hl('IdentifierName', '_test'), - }) - check_parsing('g:{@a}_test()', { - -- 0123456789012 - ast = { - { - 'Call:0:11:(', - children = { - { - 'ComplexIdentifier:0:2:', - children = { - 'PlainIdentifier(scope=g,ident=):0:0:g:', - { - 'ComplexIdentifier:0:6:', - children = { - { - 'CurlyBracesIdentifier:0:2:{', - children = { - 'Register(name=a):0:3:@a', - }, - }, - 'PlainIdentifier(scope=0,ident=_test):0:6:_test', - }, - }, - }, - }, - }, - }, - }, - }, { - hl('IdentifierScope', 'g'), - hl('IdentifierScopeDelimiter', ':'), - hl('Curly', '{'), - hl('Register', '@a'), - hl('Curly', '}'), - hl('IdentifierName', '_test'), - hl('CallingParenthesis', '('), - hl('CallingParenthesis', ')'), - }) - check_parsing('{@a} ()', { - -- 0123456789012 - ast = { - { - 'Call:0:4: (', - children = { - { - 'CurlyBracesIdentifier:0:0:{', - children = { - 'Register(name=a):0:1:@a', - }, - }, - }, - }, - }, - }, { - hl('Curly', '{'), - hl('Register', '@a'), - hl('Curly', '}'), - hl('CallingParenthesis', '(', 1), - hl('CallingParenthesis', ')'), - }) - check_parsing('g:{@a} ()', { - -- 0123456789012 - ast = { - { - 'Call:0:6: (', - children = { - { - 'ComplexIdentifier:0:2:', - children = { - 'PlainIdentifier(scope=g,ident=):0:0:g:', - { - 'CurlyBracesIdentifier:0:2:{', - children = { - 'Register(name=a):0:3:@a', - }, - }, - }, - }, - }, - }, - }, - }, { - hl('IdentifierScope', 'g'), - hl('IdentifierScopeDelimiter', ':'), - hl('Curly', '{'), - hl('Register', '@a'), - hl('Curly', '}'), - hl('CallingParenthesis', '(', 1), - hl('CallingParenthesis', ')'), - }) - check_parsing('{@a', { - -- 012 - ast = { - { - 'UnknownFigure:0:0:{', - children = { - 'Register(name=a):0:1:@a', - }, - }, - }, - err = { - arg = '{@a', - msg = 'E15: Missing closing figure brace: %.*s', - }, - }, { - hl('FigureBrace', '{'), - hl('Register', '@a'), - }) - end) - it('works with lambdas and dictionaries', function() - check_parsing('{}', { - ast = { - 'DictLiteral:0:0:{', - }, - }, { - hl('Dict', '{'), - hl('Dict', '}'), - }) - check_parsing('{->@a}', { - ast = { - { - 'Lambda:0:0:{', - children = { - { - 'Arrow:0:1:->', - children = { - 'Register(name=a):0:3:@a', - }, - }, - }, - }, - }, - }, { - hl('Lambda', '{'), - hl('Arrow', '->'), - hl('Register', '@a'), - hl('Lambda', '}'), - }) - check_parsing('{->@a+@b}', { - -- 012345678 - ast = { - { - 'Lambda:0:0:{', - children = { - { - 'Arrow:0:1:->', - children = { - { - 'BinaryPlus:0:5:+', - children = { - 'Register(name=a):0:3:@a', - 'Register(name=b):0:6:@b', - }, - }, - }, - }, - }, - }, - }, - }, { - hl('Lambda', '{'), - hl('Arrow', '->'), - hl('Register', '@a'), - hl('BinaryPlus', '+'), - hl('Register', '@b'), - hl('Lambda', '}'), - }) - check_parsing('{a->@a}', { - -- 012345678 - ast = { - { - 'Lambda:0:0:{', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - { - 'Arrow:0:2:->', - children = { - 'Register(name=a):0:4:@a', - }, - }, - }, - }, - }, - }, { - hl('Lambda', '{'), - hl('IdentifierName', 'a'), - hl('Arrow', '->'), - hl('Register', '@a'), - hl('Lambda', '}'), - }) - check_parsing('{a,b->@a}', { - -- 012345678 - ast = { - { - 'Lambda:0:0:{', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - 'PlainIdentifier(scope=0,ident=b):0:3:b', - }, - }, - { - 'Arrow:0:4:->', - children = { - 'Register(name=a):0:6:@a', - }, - }, - }, - }, - }, - }, { - hl('Lambda', '{'), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('IdentifierName', 'b'), - hl('Arrow', '->'), - hl('Register', '@a'), - hl('Lambda', '}'), - }) - check_parsing('{a,b,c->@a}', { - -- 01234567890 - ast = { - { - 'Lambda:0:0:{', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - { - 'Comma:0:4:,', - children = { - 'PlainIdentifier(scope=0,ident=b):0:3:b', - 'PlainIdentifier(scope=0,ident=c):0:5:c', - }, - }, - }, - }, - { - 'Arrow:0:6:->', - children = { - 'Register(name=a):0:8:@a', - }, - }, - }, - }, - }, - }, { - hl('Lambda', '{'), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('IdentifierName', 'b'), - hl('Comma', ','), - hl('IdentifierName', 'c'), - hl('Arrow', '->'), - hl('Register', '@a'), - hl('Lambda', '}'), - }) - check_parsing('{a,b,c,d->@a}', { - -- 0123456789012 - ast = { - { - 'Lambda:0:0:{', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - { - 'Comma:0:4:,', - children = { - 'PlainIdentifier(scope=0,ident=b):0:3:b', - { - 'Comma:0:6:,', - children = { - 'PlainIdentifier(scope=0,ident=c):0:5:c', - 'PlainIdentifier(scope=0,ident=d):0:7:d', - }, - }, - }, - }, - }, - }, - { - 'Arrow:0:8:->', - children = { - 'Register(name=a):0:10:@a', - }, - }, - }, - }, - }, - }, { - hl('Lambda', '{'), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('IdentifierName', 'b'), - hl('Comma', ','), - hl('IdentifierName', 'c'), - hl('Comma', ','), - hl('IdentifierName', 'd'), - hl('Arrow', '->'), - hl('Register', '@a'), - hl('Lambda', '}'), - }) - check_parsing('{a,b,c,d,->@a}', { - -- 01234567890123 - ast = { - { - 'Lambda:0:0:{', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - { - 'Comma:0:4:,', - children = { - 'PlainIdentifier(scope=0,ident=b):0:3:b', - { - 'Comma:0:6:,', - children = { - 'PlainIdentifier(scope=0,ident=c):0:5:c', - { - 'Comma:0:8:,', - children = { - 'PlainIdentifier(scope=0,ident=d):0:7:d', - }, - }, - }, - }, - }, - }, - }, - }, - { - 'Arrow:0:9:->', - children = { - 'Register(name=a):0:11:@a', - }, - }, - }, - }, - }, - }, { - hl('Lambda', '{'), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('IdentifierName', 'b'), - hl('Comma', ','), - hl('IdentifierName', 'c'), - hl('Comma', ','), - hl('IdentifierName', 'd'), - hl('Comma', ','), - hl('Arrow', '->'), - hl('Register', '@a'), - hl('Lambda', '}'), - }) - check_parsing('{a,b->{c,d->{e,f->@a}}}', { - -- 01234567890123456789012 - -- 0 1 2 - ast = { - { - 'Lambda:0:0:{', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - 'PlainIdentifier(scope=0,ident=b):0:3:b', - }, - }, - { - 'Arrow:0:4:->', - children = { - { - 'Lambda:0:6:{', - children = { - { - 'Comma:0:8:,', - children = { - 'PlainIdentifier(scope=0,ident=c):0:7:c', - 'PlainIdentifier(scope=0,ident=d):0:9:d', - }, - }, - { - 'Arrow:0:10:->', - children = { - { - 'Lambda:0:12:{', - children = { - { - 'Comma:0:14:,', - children = { - 'PlainIdentifier(scope=0,ident=e):0:13:e', - 'PlainIdentifier(scope=0,ident=f):0:15:f', - }, - }, - { - 'Arrow:0:16:->', - children = { - 'Register(name=a):0:18:@a', - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, { - hl('Lambda', '{'), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('IdentifierName', 'b'), - hl('Arrow', '->'), - hl('Lambda', '{'), - hl('IdentifierName', 'c'), - hl('Comma', ','), - hl('IdentifierName', 'd'), - hl('Arrow', '->'), - hl('Lambda', '{'), - hl('IdentifierName', 'e'), - hl('Comma', ','), - hl('IdentifierName', 'f'), - hl('Arrow', '->'), - hl('Register', '@a'), - hl('Lambda', '}'), - hl('Lambda', '}'), - hl('Lambda', '}'), - }) - check_parsing('{a,b->c,d}', { - -- 0123456789 - ast = { - { - 'Lambda:0:0:{', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - 'PlainIdentifier(scope=0,ident=b):0:3:b', - }, - }, - { - 'Arrow:0:4:->', - children = { - { - 'Comma:0:7:,', - children = { - 'PlainIdentifier(scope=0,ident=c):0:6:c', - 'PlainIdentifier(scope=0,ident=d):0:8:d', - }, - }, - }, - }, - }, - }, - }, - err = { - arg = ',d}', - msg = 'E15: Comma outside of call, lambda or literal: %.*s', - }, - }, { - hl('Lambda', '{'), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('IdentifierName', 'b'), - hl('Arrow', '->'), - hl('IdentifierName', 'c'), - hl('InvalidComma', ','), - hl('IdentifierName', 'd'), - hl('Lambda', '}'), - }) - check_parsing('a,b,c,d', { - -- 0123456789 - ast = { - { - 'Comma:0:1:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'Comma:0:3:,', - children = { - 'PlainIdentifier(scope=0,ident=b):0:2:b', - { - 'Comma:0:5:,', - children = { - 'PlainIdentifier(scope=0,ident=c):0:4:c', - 'PlainIdentifier(scope=0,ident=d):0:6:d', - }, - }, - }, - }, - }, - }, - }, - err = { - arg = ',b,c,d', - msg = 'E15: Comma outside of call, lambda or literal: %.*s', - }, - }, { - hl('IdentifierName', 'a'), - hl('InvalidComma', ','), - hl('IdentifierName', 'b'), - hl('InvalidComma', ','), - hl('IdentifierName', 'c'), - hl('InvalidComma', ','), - hl('IdentifierName', 'd'), - }) - check_parsing('a,b,c,d,', { - -- 0123456789 - ast = { - { - 'Comma:0:1:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'Comma:0:3:,', - children = { - 'PlainIdentifier(scope=0,ident=b):0:2:b', - { - 'Comma:0:5:,', - children = { - 'PlainIdentifier(scope=0,ident=c):0:4:c', - { - 'Comma:0:7:,', - children = { - 'PlainIdentifier(scope=0,ident=d):0:6:d', - }, - }, - }, - }, - }, - }, - }, - }, - }, - err = { - arg = ',b,c,d,', - msg = 'E15: Comma outside of call, lambda or literal: %.*s', - }, - }, { - hl('IdentifierName', 'a'), - hl('InvalidComma', ','), - hl('IdentifierName', 'b'), - hl('InvalidComma', ','), - hl('IdentifierName', 'c'), - hl('InvalidComma', ','), - hl('IdentifierName', 'd'), - hl('InvalidComma', ','), - }) - check_parsing(',', { - -- 0123456789 - ast = { - { - 'Comma:0:0:,', - children = { - 'Missing:0:0:', - }, - }, - }, - err = { - arg = ',', - msg = 'E15: Expected value, got comma: %.*s', - }, - }, { - hl('InvalidComma', ','), - }) - check_parsing('{,a->@a}', { - -- 0123456789 - ast = { - { - 'CurlyBracesIdentifier:0:0:{', - children = { - { - 'Arrow:0:3:->', - children = { - { - 'Comma:0:1:,', - children = { - 'Missing:0:1:', - 'PlainIdentifier(scope=0,ident=a):0:2:a', - }, - }, - 'Register(name=a):0:5:@a', - }, - }, - }, - }, - }, - err = { - arg = ',a->@a}', - msg = 'E15: Expected value, got comma: %.*s', - }, - }, { - hl('Curly', '{'), - hl('InvalidComma', ','), - hl('IdentifierName', 'a'), - hl('InvalidArrow', '->'), - hl('Register', '@a'), - hl('Curly', '}'), - }) - check_parsing('}', { - -- 0123456789 - ast = { - 'UnknownFigure:0:0:', - }, - err = { - arg = '}', - msg = 'E15: Unexpected closing figure brace: %.*s', - }, - }, { - hl('InvalidFigureBrace', '}'), - }) - check_parsing('{->}', { - -- 0123456789 - ast = { - { - 'Lambda:0:0:{', - children = { - 'Arrow:0:1:->', - }, - }, - }, - err = { - arg = '}', - msg = 'E15: Expected value, got closing figure brace: %.*s', - }, - }, { - hl('Lambda', '{'), - hl('Arrow', '->'), - hl('InvalidLambda', '}'), - }) - check_parsing('{a,b}', { - -- 0123456789 - ast = { - { - 'Lambda:0:0:{', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - 'PlainIdentifier(scope=0,ident=b):0:3:b', - }, - }, - }, - }, - }, - err = { - arg = '}', - msg = 'E15: Expected lambda arguments list or arrow: %.*s', - }, - }, { - hl('Lambda', '{'), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('IdentifierName', 'b'), - hl('InvalidLambda', '}'), - }) - check_parsing('{a,}', { - -- 0123456789 - ast = { - { - 'Lambda:0:0:{', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - }, - }, - }, - }, - }, - err = { - arg = '}', - msg = 'E15: Expected lambda arguments list or arrow: %.*s', - }, - }, { - hl('Lambda', '{'), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('InvalidLambda', '}'), - }) - check_parsing('{@a:@b}', { - -- 0123456789 - ast = { - { - 'DictLiteral:0:0:{', - children = { - { - 'Colon:0:3::', - children = { - 'Register(name=a):0:1:@a', - 'Register(name=b):0:4:@b', - }, - }, - }, - }, - }, - }, { - hl('Dict', '{'), - hl('Register', '@a'), - hl('Colon', ':'), - hl('Register', '@b'), - hl('Dict', '}'), - }) - check_parsing('{@a:@b,@c:@d}', { - -- 0123456789012 - -- 0 1 - ast = { - { - 'DictLiteral:0:0:{', - children = { - { - 'Comma:0:6:,', - children = { - { - 'Colon:0:3::', - children = { - 'Register(name=a):0:1:@a', - 'Register(name=b):0:4:@b', - }, - }, - { - 'Colon:0:9::', - children = { - 'Register(name=c):0:7:@c', - 'Register(name=d):0:10:@d', - }, - }, - }, - }, - }, - }, - }, - }, { - hl('Dict', '{'), - hl('Register', '@a'), - hl('Colon', ':'), - hl('Register', '@b'), - hl('Comma', ','), - hl('Register', '@c'), - hl('Colon', ':'), - hl('Register', '@d'), - hl('Dict', '}'), - }) - check_parsing('{@a:@b,@c:@d,@e:@f,}', { - -- 01234567890123456789 - -- 0 1 - ast = { - { - 'DictLiteral:0:0:{', - children = { - { - 'Comma:0:6:,', - children = { - { - 'Colon:0:3::', - children = { - 'Register(name=a):0:1:@a', - 'Register(name=b):0:4:@b', - }, - }, - { - 'Comma:0:12:,', - children = { - { - 'Colon:0:9::', - children = { - 'Register(name=c):0:7:@c', - 'Register(name=d):0:10:@d', - }, - }, - { - 'Comma:0:18:,', - children = { - { - 'Colon:0:15::', - children = { - 'Register(name=e):0:13:@e', - 'Register(name=f):0:16:@f', - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, { - hl('Dict', '{'), - hl('Register', '@a'), - hl('Colon', ':'), - hl('Register', '@b'), - hl('Comma', ','), - hl('Register', '@c'), - hl('Colon', ':'), - hl('Register', '@d'), - hl('Comma', ','), - hl('Register', '@e'), - hl('Colon', ':'), - hl('Register', '@f'), - hl('Comma', ','), - hl('Dict', '}'), - }) - check_parsing('{@a:@b,@c:@d,@e:@f,@g:}', { - -- 01234567890123456789012 - -- 0 1 2 - ast = { - { - 'DictLiteral:0:0:{', - children = { - { - 'Comma:0:6:,', - children = { - { - 'Colon:0:3::', - children = { - 'Register(name=a):0:1:@a', - 'Register(name=b):0:4:@b', - }, - }, - { - 'Comma:0:12:,', - children = { - { - 'Colon:0:9::', - children = { - 'Register(name=c):0:7:@c', - 'Register(name=d):0:10:@d', - }, - }, - { - 'Comma:0:18:,', - children = { - { - 'Colon:0:15::', - children = { - 'Register(name=e):0:13:@e', - 'Register(name=f):0:16:@f', - }, - }, - { - 'Colon:0:21::', - children = { - 'Register(name=g):0:19:@g', - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - err = { - arg = '}', - msg = 'E15: Expected value, got closing figure brace: %.*s', - }, - }, { - hl('Dict', '{'), - hl('Register', '@a'), - hl('Colon', ':'), - hl('Register', '@b'), - hl('Comma', ','), - hl('Register', '@c'), - hl('Colon', ':'), - hl('Register', '@d'), - hl('Comma', ','), - hl('Register', '@e'), - hl('Colon', ':'), - hl('Register', '@f'), - hl('Comma', ','), - hl('Register', '@g'), - hl('Colon', ':'), - hl('InvalidDict', '}'), - }) - check_parsing('{@a:@b,}', { - -- 01234567890123 - -- 0 1 - ast = { - { - 'DictLiteral:0:0:{', - children = { - { - 'Comma:0:6:,', - children = { - { - 'Colon:0:3::', - children = { - 'Register(name=a):0:1:@a', - 'Register(name=b):0:4:@b', - }, - }, - }, - }, - }, - }, - }, - }, { - hl('Dict', '{'), - hl('Register', '@a'), - hl('Colon', ':'), - hl('Register', '@b'), - hl('Comma', ','), - hl('Dict', '}'), - }) - check_parsing('{({f -> g})(@h)(@i)}', { - -- 01234567890123456789 - -- 0 1 - ast = { - { - 'CurlyBracesIdentifier:0:0:{', - children = { - { - 'Call:0:15:(', - children = { - { - 'Call:0:11:(', - children = { - { - 'Nested:0:1:(', - children = { - { - 'Lambda:0:2:{', - children = { - 'PlainIdentifier(scope=0,ident=f):0:3:f', - { - 'Arrow:0:4: ->', - children = { - 'PlainIdentifier(scope=0,ident=g):0:7: g', - }, - }, - }, - }, - }, - }, - 'Register(name=h):0:12:@h', - }, - }, - 'Register(name=i):0:16:@i', - }, - }, - }, - }, - }, - }, { - hl('Curly', '{'), - hl('NestingParenthesis', '('), - hl('Lambda', '{'), - hl('IdentifierName', 'f'), - hl('Arrow', '->', 1), - hl('IdentifierName', 'g', 1), - hl('Lambda', '}'), - hl('NestingParenthesis', ')'), - hl('CallingParenthesis', '('), - hl('Register', '@h'), - hl('CallingParenthesis', ')'), - hl('CallingParenthesis', '('), - hl('Register', '@i'), - hl('CallingParenthesis', ')'), - hl('Curly', '}'), - }) - check_parsing('a:{b()}c', { - -- 01234567 - ast = { - { - 'ComplexIdentifier:0:2:', - children = { - 'PlainIdentifier(scope=a,ident=):0:0:a:', - { - 'ComplexIdentifier:0:7:', - children = { - { - 'CurlyBracesIdentifier:0:2:{', - children = { - { - 'Call:0:4:(', - children = { - 'PlainIdentifier(scope=0,ident=b):0:3:b', - }, - }, - }, - }, - 'PlainIdentifier(scope=0,ident=c):0:7:c', - }, - }, - }, - }, - }, - }, { - hl('IdentifierScope', 'a'), - hl('IdentifierScopeDelimiter', ':'), - hl('Curly', '{'), - hl('IdentifierName', 'b'), - hl('CallingParenthesis', '('), - hl('CallingParenthesis', ')'), - hl('Curly', '}'), - hl('IdentifierName', 'c'), - }) - check_parsing('a:{{b, c -> @d + @e + ({f -> g})(@h)}(@i)}j', { - -- 01234567890123456789012345678901234567890123456 - -- 0 1 2 3 4 - ast = { - { - 'ComplexIdentifier:0:2:', - children = { - 'PlainIdentifier(scope=a,ident=):0:0:a:', - { - 'ComplexIdentifier:0:42:', - children = { - { - 'CurlyBracesIdentifier:0:2:{', - children = { - { - 'Call:0:37:(', - children = { - { - 'Lambda:0:3:{', - children = { - { - 'Comma:0:5:,', - children = { - 'PlainIdentifier(scope=0,ident=b):0:4:b', - 'PlainIdentifier(scope=0,ident=c):0:6: c', - }, - }, - { - 'Arrow:0:8: ->', - children = { - { - 'BinaryPlus:0:19: +', - children = { - { - 'BinaryPlus:0:14: +', - children = { - 'Register(name=d):0:11: @d', - 'Register(name=e):0:16: @e', - }, - }, - { - 'Call:0:32:(', - children = { - { - 'Nested:0:21: (', - children = { - { - 'Lambda:0:23:{', - children = { - 'PlainIdentifier(scope=0,ident=f):0:24:f', - { - 'Arrow:0:25: ->', - children = { - 'PlainIdentifier(scope=0,ident=g):0:28: g', - }, - }, - }, - }, - }, - }, - 'Register(name=h):0:33:@h', - }, - }, - }, - }, - }, - }, - }, - }, - 'Register(name=i):0:38:@i', - }, - }, - }, - }, - 'PlainIdentifier(scope=0,ident=j):0:42:j', - }, - }, - }, - }, - }, - }, { - hl('IdentifierScope', 'a'), - hl('IdentifierScopeDelimiter', ':'), - hl('Curly', '{'), - hl('Lambda', '{'), - hl('IdentifierName', 'b'), - hl('Comma', ','), - hl('IdentifierName', 'c', 1), - hl('Arrow', '->', 1), - hl('Register', '@d', 1), - hl('BinaryPlus', '+', 1), - hl('Register', '@e', 1), - hl('BinaryPlus', '+', 1), - hl('NestingParenthesis', '(', 1), - hl('Lambda', '{'), - hl('IdentifierName', 'f'), - hl('Arrow', '->', 1), - hl('IdentifierName', 'g', 1), - hl('Lambda', '}'), - hl('NestingParenthesis', ')'), - hl('CallingParenthesis', '('), - hl('Register', '@h'), - hl('CallingParenthesis', ')'), - hl('Lambda', '}'), - hl('CallingParenthesis', '('), - hl('Register', '@i'), - hl('CallingParenthesis', ')'), - hl('Curly', '}'), - hl('IdentifierName', 'j'), - }) - check_parsing('{@a + @b : @c + @d, @e + @f : @g + @i}', { - -- 01234567890123456789012345678901234567 - -- 0 1 2 3 - ast = { - { - 'DictLiteral:0:0:{', - children = { - { - 'Comma:0:18:,', - children = { - { - 'Colon:0:8: :', - children = { - { - 'BinaryPlus:0:3: +', - children = { - 'Register(name=a):0:1:@a', - 'Register(name=b):0:5: @b', - }, - }, - { - 'BinaryPlus:0:13: +', - children = { - 'Register(name=c):0:10: @c', - 'Register(name=d):0:15: @d', - }, - }, - }, - }, - { - 'Colon:0:27: :', - children = { - { - 'BinaryPlus:0:22: +', - children = { - 'Register(name=e):0:19: @e', - 'Register(name=f):0:24: @f', - }, - }, - { - 'BinaryPlus:0:32: +', - children = { - 'Register(name=g):0:29: @g', - 'Register(name=i):0:34: @i', - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, { - hl('Dict', '{'), - hl('Register', '@a'), - hl('BinaryPlus', '+', 1), - hl('Register', '@b', 1), - hl('Colon', ':', 1), - hl('Register', '@c', 1), - hl('BinaryPlus', '+', 1), - hl('Register', '@d', 1), - hl('Comma', ','), - hl('Register', '@e', 1), - hl('BinaryPlus', '+', 1), - hl('Register', '@f', 1), - hl('Colon', ':', 1), - hl('Register', '@g', 1), - hl('BinaryPlus', '+', 1), - hl('Register', '@i', 1), - hl('Dict', '}'), - }) - check_parsing('-> -> ->', { - -- 01234567 - ast = { - { - 'Arrow:0:0:->', - children = { - 'Missing:0:0:', - { - 'Arrow:0:2: ->', - children = { - 'Missing:0:2:', - { - 'Arrow:0:5: ->', - children = { - 'Missing:0:5:', - }, - }, - }, - }, - }, - }, - }, - err = { - arg = '-> -> ->', - msg = 'E15: Unexpected arrow: %.*s', - }, - }, { - hl('InvalidArrow', '->'), - hl('InvalidArrow', '->', 1), - hl('InvalidArrow', '->', 1), - }) - check_parsing('a -> b -> c -> d', { - -- 0123456789012345 - -- 0 1 - ast = { - { - 'Arrow:0:1: ->', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'Arrow:0:6: ->', - children = { - 'PlainIdentifier(scope=0,ident=b):0:4: b', - { - 'Arrow:0:11: ->', - children = { - 'PlainIdentifier(scope=0,ident=c):0:9: c', - 'PlainIdentifier(scope=0,ident=d):0:14: d', - }, - }, - }, - }, - }, - }, - }, - err = { - arg = '-> b -> c -> d', - msg = 'E15: Arrow outside of lambda: %.*s', - }, - }, { - hl('IdentifierName', 'a'), - hl('InvalidArrow', '->', 1), - hl('IdentifierName', 'b', 1), - hl('InvalidArrow', '->', 1), - hl('IdentifierName', 'c', 1), - hl('InvalidArrow', '->', 1), - hl('IdentifierName', 'd', 1), - }) - check_parsing('{a -> b -> c}', { - -- 0123456789012 - -- 0 1 - ast = { - { - 'Lambda:0:0:{', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - { - 'Arrow:0:2: ->', - children = { - { - 'Arrow:0:7: ->', - children = { - 'PlainIdentifier(scope=0,ident=b):0:5: b', - 'PlainIdentifier(scope=0,ident=c):0:10: c', - }, - }, - }, - }, - }, - }, - }, - err = { - arg = '-> c}', - msg = 'E15: Arrow outside of lambda: %.*s', - }, - }, { - hl('Lambda', '{'), - hl('IdentifierName', 'a'), - hl('Arrow', '->', 1), - hl('IdentifierName', 'b', 1), - hl('InvalidArrow', '->', 1), - hl('IdentifierName', 'c', 1), - hl('Lambda', '}'), - }) - check_parsing('{a: -> b}', { - -- 012345678 - ast = { - { - 'CurlyBracesIdentifier:0:0:{', - children = { - { - 'Arrow:0:3: ->', - children = { - 'PlainIdentifier(scope=a,ident=):0:1:a:', - 'PlainIdentifier(scope=0,ident=b):0:6: b', - }, - }, - }, - }, - }, - err = { - arg = '-> b}', - msg = 'E15: Arrow outside of lambda: %.*s', - }, - }, { - hl('Curly', '{'), - hl('IdentifierScope', 'a'), - hl('IdentifierScopeDelimiter', ':'), - hl('InvalidArrow', '->', 1), - hl('IdentifierName', 'b', 1), - hl('Curly', '}'), - }) - - check_parsing('{a:b -> b}', { - -- 0123456789 - ast = { - { - 'CurlyBracesIdentifier:0:0:{', - children = { - { - 'Arrow:0:4: ->', - children = { - 'PlainIdentifier(scope=a,ident=b):0:1:a:b', - 'PlainIdentifier(scope=0,ident=b):0:7: b', - }, - }, - }, - }, - }, - err = { - arg = '-> b}', - msg = 'E15: Arrow outside of lambda: %.*s', - }, - }, { - hl('Curly', '{'), - hl('IdentifierScope', 'a'), - hl('IdentifierScopeDelimiter', ':'), - hl('IdentifierName', 'b'), - hl('InvalidArrow', '->', 1), - hl('IdentifierName', 'b', 1), - hl('Curly', '}'), - }) - - check_parsing('{a#b -> b}', { - -- 0123456789 - ast = { - { - 'CurlyBracesIdentifier:0:0:{', - children = { - { - 'Arrow:0:4: ->', - children = { - 'PlainIdentifier(scope=0,ident=a#b):0:1:a#b', - 'PlainIdentifier(scope=0,ident=b):0:7: b', - }, - }, - }, - }, - }, - err = { - arg = '-> b}', - msg = 'E15: Arrow outside of lambda: %.*s', - }, - }, { - hl('Curly', '{'), - hl('IdentifierName', 'a#b'), - hl('InvalidArrow', '->', 1), - hl('IdentifierName', 'b', 1), - hl('Curly', '}'), - }) - check_parsing('{a : b : c}', { - -- 01234567890 - -- 0 1 - ast = { - { - 'DictLiteral:0:0:{', - children = { - { - 'Colon:0:2: :', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - { - 'Colon:0:6: :', - children = { - 'PlainIdentifier(scope=0,ident=b):0:4: b', - 'PlainIdentifier(scope=0,ident=c):0:8: c', - }, - }, - }, - }, - }, - }, - }, - err = { - arg = ': c}', - msg = 'E15: Colon outside of dictionary or ternary operator: %.*s', - }, - }, { - hl('Dict', '{'), - hl('IdentifierName', 'a'), - hl('Colon', ':', 1), - hl('IdentifierName', 'b', 1), - hl('InvalidColon', ':', 1), - hl('IdentifierName', 'c', 1), - hl('Dict', '}'), - }) - check_parsing('{', { - -- 0 - ast = { - 'UnknownFigure:0:0:{', - }, - err = { - arg = '{', - msg = 'E15: Missing closing figure brace: %.*s', - }, - }, { - hl('FigureBrace', '{'), - }) - check_parsing('{a', { - -- 01 - ast = { - { - 'UnknownFigure:0:0:{', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - }, - }, - }, - err = { - arg = '{a', - msg = 'E15: Missing closing figure brace: %.*s', - }, - }, { - hl('FigureBrace', '{'), - hl('IdentifierName', 'a'), - }) - check_parsing('{a,b', { - -- 0123 - ast = { - { - 'Lambda:0:0:{', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - 'PlainIdentifier(scope=0,ident=b):0:3:b', - }, - }, - }, - }, - }, - err = { - arg = '{a,b', - msg = 'E15: Missing closing figure brace for lambda: %.*s', - }, - }, { - hl('Lambda', '{'), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('IdentifierName', 'b'), - }) - check_parsing('{a,b->', { - -- 012345 - ast = { - { - 'Lambda:0:0:{', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - 'PlainIdentifier(scope=0,ident=b):0:3:b', - }, - }, - 'Arrow:0:4:->', - }, - }, - }, - err = { - arg = '', - msg = 'E15: Expected value, got EOC: %.*s', - }, - }, { - hl('Lambda', '{'), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('IdentifierName', 'b'), - hl('Arrow', '->'), - }) - check_parsing('{a,b->c', { - -- 0123456 - ast = { - { - 'Lambda:0:0:{', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - 'PlainIdentifier(scope=0,ident=b):0:3:b', - }, - }, - { - 'Arrow:0:4:->', - children = { - 'PlainIdentifier(scope=0,ident=c):0:6:c', - }, - }, - }, - }, - }, - err = { - arg = '{a,b->c', - msg = 'E15: Missing closing figure brace for lambda: %.*s', - }, - }, { - hl('Lambda', '{'), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('IdentifierName', 'b'), - hl('Arrow', '->'), - hl('IdentifierName', 'c'), - }) - check_parsing('{a : b', { - -- 012345 - ast = { - { - 'DictLiteral:0:0:{', - children = { - { - 'Colon:0:2: :', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - 'PlainIdentifier(scope=0,ident=b):0:4: b', - }, - }, - }, - }, - }, - err = { - arg = '{a : b', - msg = 'E723: Missing end of Dictionary \'}\': %.*s', - }, - }, { - hl('Dict', '{'), - hl('IdentifierName', 'a'), - hl('Colon', ':', 1), - hl('IdentifierName', 'b', 1), - }) - check_parsing('{a : b,', { - -- 0123456 - ast = { - { - 'DictLiteral:0:0:{', - children = { - { - 'Comma:0:6:,', - children = { - { - 'Colon:0:2: :', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - 'PlainIdentifier(scope=0,ident=b):0:4: b', - }, - }, - }, - }, - }, - }, - }, - err = { - arg = '', - msg = 'E15: Expected value, got EOC: %.*s', - }, - }, { - hl('Dict', '{'), - hl('IdentifierName', 'a'), - hl('Colon', ':', 1), - hl('IdentifierName', 'b', 1), - hl('Comma', ','), - }) - end) - it('works with ternary operator', function() - check_parsing('a ? b : c', { - -- 012345678 - ast = { - { - 'Ternary:0:1: ?', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'TernaryValue:0:5: :', - children = { - 'PlainIdentifier(scope=0,ident=b):0:3: b', - 'PlainIdentifier(scope=0,ident=c):0:7: c', - }, - }, - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Ternary', '?', 1), - hl('IdentifierName', 'b', 1), - hl('TernaryColon', ':', 1), - hl('IdentifierName', 'c', 1), - }) - check_parsing('@a?@b?@c:@d:@e', { - -- 01234567890123 - -- 0 1 - ast = { - { - 'Ternary:0:2:?', - children = { - 'Register(name=a):0:0:@a', - { - 'TernaryValue:0:11::', - children = { - { - 'Ternary:0:5:?', - children = { - 'Register(name=b):0:3:@b', - { - 'TernaryValue:0:8::', - children = { - 'Register(name=c):0:6:@c', - 'Register(name=d):0:9:@d', - }, - }, - }, - }, - 'Register(name=e):0:12:@e', - }, - }, - }, - }, - }, - }, { - hl('Register', '@a'), - hl('Ternary', '?'), - hl('Register', '@b'), - hl('Ternary', '?'), - hl('Register', '@c'), - hl('TernaryColon', ':'), - hl('Register', '@d'), - hl('TernaryColon', ':'), - hl('Register', '@e'), - }) - check_parsing('@a?@b:@c?@d:@e', { - -- 01234567890123 - -- 0 1 - ast = { - { - 'Ternary:0:2:?', - children = { - 'Register(name=a):0:0:@a', - { - 'TernaryValue:0:5::', - children = { - 'Register(name=b):0:3:@b', - { - 'Ternary:0:8:?', - children = { - 'Register(name=c):0:6:@c', - { - 'TernaryValue:0:11::', - children = { - 'Register(name=d):0:9:@d', - 'Register(name=e):0:12:@e', - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, { - hl('Register', '@a'), - hl('Ternary', '?'), - hl('Register', '@b'), - hl('TernaryColon', ':'), - hl('Register', '@c'), - hl('Ternary', '?'), - hl('Register', '@d'), - hl('TernaryColon', ':'), - hl('Register', '@e'), - }) - check_parsing('@a?@b?@c?@d:@e?@f:@g:@h?@i:@j:@k', { - -- 01234567890123456789012345678901 - -- 0 1 2 3 - ast = { - { - 'Ternary:0:2:?', - children = { - 'Register(name=a):0:0:@a', - { - 'TernaryValue:0:29::', - children = { - { - 'Ternary:0:5:?', - children = { - 'Register(name=b):0:3:@b', - { - 'TernaryValue:0:20::', - children = { - { - 'Ternary:0:8:?', - children = { - 'Register(name=c):0:6:@c', - { - 'TernaryValue:0:11::', - children = { - 'Register(name=d):0:9:@d', - { - 'Ternary:0:14:?', - children = { - 'Register(name=e):0:12:@e', - { - 'TernaryValue:0:17::', - children = { - 'Register(name=f):0:15:@f', - 'Register(name=g):0:18:@g', - }, - }, - }, - }, - }, - }, - }, - }, - { - 'Ternary:0:23:?', - children = { - 'Register(name=h):0:21:@h', - { - 'TernaryValue:0:26::', - children = { - 'Register(name=i):0:24:@i', - 'Register(name=j):0:27:@j', - }, - }, - }, - }, - }, - }, - }, - }, - 'Register(name=k):0:30:@k', - }, - }, - }, - }, - }, - }, { - hl('Register', '@a'), - hl('Ternary', '?'), - hl('Register', '@b'), - hl('Ternary', '?'), - hl('Register', '@c'), - hl('Ternary', '?'), - hl('Register', '@d'), - hl('TernaryColon', ':'), - hl('Register', '@e'), - hl('Ternary', '?'), - hl('Register', '@f'), - hl('TernaryColon', ':'), - hl('Register', '@g'), - hl('TernaryColon', ':'), - hl('Register', '@h'), - hl('Ternary', '?'), - hl('Register', '@i'), - hl('TernaryColon', ':'), - hl('Register', '@j'), - hl('TernaryColon', ':'), - hl('Register', '@k'), - }) - check_parsing('?', { - -- 0 - ast = { - { - 'Ternary:0:0:?', - children = { - 'Missing:0:0:', - 'TernaryValue:0:0:?', - }, - }, - }, - err = { - arg = '?', - msg = 'E15: Expected value, got question mark: %.*s', - }, - }, { - hl('InvalidTernary', '?'), - }) - - check_parsing('?:', { - -- 01 - ast = { - { - 'Ternary:0:0:?', - children = { - 'Missing:0:0:', - { - 'TernaryValue:0:1::', - children = { - 'Missing:0:1:', - }, - }, - }, - }, - }, - err = { - arg = '?:', - msg = 'E15: Expected value, got question mark: %.*s', - }, - }, { - hl('InvalidTernary', '?'), - hl('InvalidTernaryColon', ':'), - }) - - check_parsing('?::', { - -- 012 - ast = { - { - 'Colon:0:2::', - children = { - { - 'Ternary:0:0:?', - children = { - 'Missing:0:0:', - { - 'TernaryValue:0:1::', - children = { - 'Missing:0:1:', - 'Missing:0:2:', - }, - }, - }, - }, - }, - }, - }, - err = { - arg = '?::', - msg = 'E15: Expected value, got question mark: %.*s', - }, - }, { - hl('InvalidTernary', '?'), - hl('InvalidTernaryColon', ':'), - hl('InvalidColon', ':'), - }) - - check_parsing('a?b', { - -- 012 - ast = { - { - 'Ternary:0:1:?', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'TernaryValue:0:1:?', - children = { - 'PlainIdentifier(scope=0,ident=b):0:2:b', - }, - }, - }, - }, - }, - err = { - arg = '?b', - msg = 'E109: Missing \':\' after \'?\': %.*s', - }, - }, { - hl('IdentifierName', 'a'), - hl('Ternary', '?'), - hl('IdentifierName', 'b'), - }) - check_parsing('a?b:', { - -- 0123 - ast = { - { - 'Ternary:0:1:?', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'TernaryValue:0:1:?', - children = { - 'PlainIdentifier(scope=b,ident=):0:2:b:', - }, - }, - }, - }, - }, - err = { - arg = '?b:', - msg = 'E109: Missing \':\' after \'?\': %.*s', - }, - }, { - hl('IdentifierName', 'a'), - hl('Ternary', '?'), - hl('IdentifierScope', 'b'), - hl('IdentifierScopeDelimiter', ':'), - }) - - check_parsing('a?b::c', { - -- 012345 - ast = { - { - 'Ternary:0:1:?', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'TernaryValue:0:4::', - children = { - 'PlainIdentifier(scope=b,ident=):0:2:b:', - 'PlainIdentifier(scope=0,ident=c):0:5:c', - }, - }, - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Ternary', '?'), - hl('IdentifierScope', 'b'), - hl('IdentifierScopeDelimiter', ':'), - hl('TernaryColon', ':'), - hl('IdentifierName', 'c'), - }) - - check_parsing('a?b :', { - -- 01234 - ast = { - { - 'Ternary:0:1:?', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'TernaryValue:0:3: :', - children = { - 'PlainIdentifier(scope=0,ident=b):0:2:b', - }, - }, - }, - }, - }, - err = { - arg = '', - msg = 'E15: Expected value, got EOC: %.*s', - }, - }, { - hl('IdentifierName', 'a'), - hl('Ternary', '?'), - hl('IdentifierName', 'b'), - hl('TernaryColon', ':', 1), - }) - - check_parsing('(@a?@b:@c)?@d:@e', { - -- 0123456789012345 - -- 0 1 - ast = { - { - 'Ternary:0:10:?', - children = { - { - 'Nested:0:0:(', - children = { - { - 'Ternary:0:3:?', - children = { - 'Register(name=a):0:1:@a', - { - 'TernaryValue:0:6::', - children = { - 'Register(name=b):0:4:@b', - 'Register(name=c):0:7:@c', - }, - }, - }, - }, - }, - }, - { - 'TernaryValue:0:13::', - children = { - 'Register(name=d):0:11:@d', - 'Register(name=e):0:14:@e', - }, - }, - }, - }, - }, - }, { - hl('NestingParenthesis', '('), - hl('Register', '@a'), - hl('Ternary', '?'), - hl('Register', '@b'), - hl('TernaryColon', ':'), - hl('Register', '@c'), - hl('NestingParenthesis', ')'), - hl('Ternary', '?'), - hl('Register', '@d'), - hl('TernaryColon', ':'), - hl('Register', '@e'), - }) - - check_parsing('(@a?@b:@c)?(@d?@e:@f):(@g?@h:@i)', { - -- 01234567890123456789012345678901 - -- 0 1 2 3 - ast = { - { - 'Ternary:0:10:?', - children = { - { - 'Nested:0:0:(', - children = { - { - 'Ternary:0:3:?', - children = { - 'Register(name=a):0:1:@a', - { - 'TernaryValue:0:6::', - children = { - 'Register(name=b):0:4:@b', - 'Register(name=c):0:7:@c', - }, - }, - }, - }, - }, - }, - { - 'TernaryValue:0:21::', - children = { - { - 'Nested:0:11:(', - children = { - { - 'Ternary:0:14:?', - children = { - 'Register(name=d):0:12:@d', - { - 'TernaryValue:0:17::', - children = { - 'Register(name=e):0:15:@e', - 'Register(name=f):0:18:@f', - }, - }, - }, - }, - }, - }, - { - 'Nested:0:22:(', - children = { - { - 'Ternary:0:25:?', - children = { - 'Register(name=g):0:23:@g', - { - 'TernaryValue:0:28::', - children = { - 'Register(name=h):0:26:@h', - 'Register(name=i):0:29:@i', - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, { - hl('NestingParenthesis', '('), - hl('Register', '@a'), - hl('Ternary', '?'), - hl('Register', '@b'), - hl('TernaryColon', ':'), - hl('Register', '@c'), - hl('NestingParenthesis', ')'), - hl('Ternary', '?'), - hl('NestingParenthesis', '('), - hl('Register', '@d'), - hl('Ternary', '?'), - hl('Register', '@e'), - hl('TernaryColon', ':'), - hl('Register', '@f'), - hl('NestingParenthesis', ')'), - hl('TernaryColon', ':'), - hl('NestingParenthesis', '('), - hl('Register', '@g'), - hl('Ternary', '?'), - hl('Register', '@h'), - hl('TernaryColon', ':'), - hl('Register', '@i'), - hl('NestingParenthesis', ')'), - }) - - check_parsing('(@a?@b:@c)?@d?@e:@f:@g?@h:@i', { - -- 0123456789012345678901234567 - -- 0 1 2 - ast = { - { - 'Ternary:0:10:?', - children = { - { - 'Nested:0:0:(', - children = { - { - 'Ternary:0:3:?', - children = { - 'Register(name=a):0:1:@a', - { - 'TernaryValue:0:6::', - children = { - 'Register(name=b):0:4:@b', - 'Register(name=c):0:7:@c', - }, - }, - }, - }, - }, - }, - { - 'TernaryValue:0:19::', - children = { - { - 'Ternary:0:13:?', - children = { - 'Register(name=d):0:11:@d', - { - 'TernaryValue:0:16::', - children = { - 'Register(name=e):0:14:@e', - 'Register(name=f):0:17:@f', - }, - }, - }, - }, - { - 'Ternary:0:22:?', - children = { - 'Register(name=g):0:20:@g', - { - 'TernaryValue:0:25::', - children = { - 'Register(name=h):0:23:@h', - 'Register(name=i):0:26:@i', - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, { - hl('NestingParenthesis', '('), - hl('Register', '@a'), - hl('Ternary', '?'), - hl('Register', '@b'), - hl('TernaryColon', ':'), - hl('Register', '@c'), - hl('NestingParenthesis', ')'), - hl('Ternary', '?'), - hl('Register', '@d'), - hl('Ternary', '?'), - hl('Register', '@e'), - hl('TernaryColon', ':'), - hl('Register', '@f'), - hl('TernaryColon', ':'), - hl('Register', '@g'), - hl('Ternary', '?'), - hl('Register', '@h'), - hl('TernaryColon', ':'), - hl('Register', '@i'), - }) - check_parsing('a?b{cdef}g:h', { - -- 012345678901 - -- 0 1 - ast = { - { - 'Ternary:0:1:?', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'TernaryValue:0:10::', - children = { - { - 'ComplexIdentifier:0:3:', - children = { - 'PlainIdentifier(scope=0,ident=b):0:2:b', - { - 'ComplexIdentifier:0:9:', - children = { - { - 'CurlyBracesIdentifier:0:3:{', - children = { - 'PlainIdentifier(scope=0,ident=cdef):0:4:cdef', - }, - }, - 'PlainIdentifier(scope=0,ident=g):0:9:g', - }, - }, - }, - }, - 'PlainIdentifier(scope=0,ident=h):0:11:h', - }, - }, - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Ternary', '?'), - hl('IdentifierName', 'b'), - hl('Curly', '{'), - hl('IdentifierName', 'cdef'), - hl('Curly', '}'), - hl('IdentifierName', 'g'), - hl('TernaryColon', ':'), - hl('IdentifierName', 'h'), - }) - check_parsing('a ? b : c : d', { - -- 0123456789012 - -- 0 1 - ast = { - { - 'Colon:0:9: :', - children = { - { - 'Ternary:0:1: ?', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'TernaryValue:0:5: :', - children = { - 'PlainIdentifier(scope=0,ident=b):0:3: b', - 'PlainIdentifier(scope=0,ident=c):0:7: c', - }, - }, - }, - }, - 'PlainIdentifier(scope=0,ident=d):0:11: d', - }, - }, - }, - err = { - arg = ': d', - msg = 'E15: Colon outside of dictionary or ternary operator: %.*s', - }, - }, { - hl('IdentifierName', 'a'), - hl('Ternary', '?', 1), - hl('IdentifierName', 'b', 1), - hl('TernaryColon', ':', 1), - hl('IdentifierName', 'c', 1), - hl('InvalidColon', ':', 1), - hl('IdentifierName', 'd', 1), - }) - end) - it('works with comparison operators', function() - check_parsing('a == b', { - -- 012345 - ast = { - { - 'Comparison(type=Equal,inv=0,ccs=UseOption):0:1: ==', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:4: b', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Comparison', '==', 1), - hl('IdentifierName', 'b', 1), - }) - - check_parsing('a ==? b', { - -- 0123456 - ast = { - { - 'Comparison(type=Equal,inv=0,ccs=IgnoreCase):0:1: ==?', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:5: b', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Comparison', '==', 1), - hl('ComparisonModifier', '?'), - hl('IdentifierName', 'b', 1), - }) - - check_parsing('a ==# b', { - -- 0123456 - ast = { - { - 'Comparison(type=Equal,inv=0,ccs=MatchCase):0:1: ==#', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:5: b', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Comparison', '==', 1), - hl('ComparisonModifier', '#'), - hl('IdentifierName', 'b', 1), - }) - - check_parsing('a !=# b', { - -- 0123456 - ast = { - { - 'Comparison(type=Equal,inv=1,ccs=MatchCase):0:1: !=#', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:5: b', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Comparison', '!=', 1), - hl('ComparisonModifier', '#'), - hl('IdentifierName', 'b', 1), - }) - - check_parsing('a <=# b', { - -- 0123456 - ast = { - { - 'Comparison(type=Greater,inv=1,ccs=MatchCase):0:1: <=#', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:5: b', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Comparison', '<=', 1), - hl('ComparisonModifier', '#'), - hl('IdentifierName', 'b', 1), - }) - - check_parsing('a >=# b', { - -- 0123456 - ast = { - { - 'Comparison(type=GreaterOrEqual,inv=0,ccs=MatchCase):0:1: >=#', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:5: b', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Comparison', '>=', 1), - hl('ComparisonModifier', '#'), - hl('IdentifierName', 'b', 1), - }) - - check_parsing('a ># b', { - -- 012345 - ast = { - { - 'Comparison(type=Greater,inv=0,ccs=MatchCase):0:1: >#', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:4: b', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Comparison', '>', 1), - hl('ComparisonModifier', '#'), - hl('IdentifierName', 'b', 1), - }) - - check_parsing('a <# b', { - -- 012345 - ast = { - { - 'Comparison(type=GreaterOrEqual,inv=1,ccs=MatchCase):0:1: <#', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:4: b', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Comparison', '<', 1), - hl('ComparisonModifier', '#'), - hl('IdentifierName', 'b', 1), - }) - - check_parsing('a is#b', { - -- 012345 - ast = { - { - 'Comparison(type=Identical,inv=0,ccs=MatchCase):0:1: is#', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:5:b', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Comparison', 'is', 1), - hl('ComparisonModifier', '#'), - hl('IdentifierName', 'b'), - }) - - check_parsing('a is?b', { - -- 012345 - ast = { - { - 'Comparison(type=Identical,inv=0,ccs=IgnoreCase):0:1: is?', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:5:b', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Comparison', 'is', 1), - hl('ComparisonModifier', '?'), - hl('IdentifierName', 'b'), - }) - - check_parsing('a isnot b', { - -- 012345678 - ast = { - { - 'Comparison(type=Identical,inv=1,ccs=UseOption):0:1: isnot', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:7: b', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Comparison', 'isnot', 1), - hl('IdentifierName', 'b', 1), - }) - - check_parsing('a < b < c', { - -- 012345678 - ast = { - { - 'Comparison(type=GreaterOrEqual,inv=1,ccs=UseOption):0:1: <', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'Comparison(type=GreaterOrEqual,inv=1,ccs=UseOption):0:5: <', - children = { - 'PlainIdentifier(scope=0,ident=b):0:3: b', - 'PlainIdentifier(scope=0,ident=c):0:7: c', - }, - }, - }, - }, - }, - err = { - arg = ' < c', - msg = 'E15: Operator is not associative: %.*s', - }, - }, { - hl('IdentifierName', 'a'), - hl('Comparison', '<', 1), - hl('IdentifierName', 'b', 1), - hl('InvalidComparison', '<', 1), - hl('IdentifierName', 'c', 1), - }) - - check_parsing('a < b <# c', { - -- 012345678 - ast = { - { - 'Comparison(type=GreaterOrEqual,inv=1,ccs=UseOption):0:1: <', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'Comparison(type=GreaterOrEqual,inv=1,ccs=MatchCase):0:5: <#', - children = { - 'PlainIdentifier(scope=0,ident=b):0:3: b', - 'PlainIdentifier(scope=0,ident=c):0:8: c', - }, - }, - }, - }, - }, - err = { - arg = ' <# c', - msg = 'E15: Operator is not associative: %.*s', - }, - }, { - hl('IdentifierName', 'a'), - hl('Comparison', '<', 1), - hl('IdentifierName', 'b', 1), - hl('InvalidComparison', '<', 1), - hl('InvalidComparisonModifier', '#'), - hl('IdentifierName', 'c', 1), - }) - - check_parsing('a += b', { - -- 012345 - ast = { - { - 'Comparison(type=Equal,inv=0,ccs=UseOption):0:3:=', - children = { - { - 'BinaryPlus:0:1: +', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'Missing:0:3:', - }, - }, - 'PlainIdentifier(scope=0,ident=b):0:4: b', - }, - }, - }, - err = { - arg = '= b', - msg = 'E15: Expected == or =~: %.*s', - }, - }, { - hl('IdentifierName', 'a'), - hl('BinaryPlus', '+', 1), - hl('InvalidComparison', '='), - hl('IdentifierName', 'b', 1), - }) - check_parsing('a + b == c + d', { - -- 01234567890123 - -- 0 1 - ast = { - { - 'Comparison(type=Equal,inv=0,ccs=UseOption):0:5: ==', - children = { - { - 'BinaryPlus:0:1: +', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:3: b', - }, - }, - { - 'BinaryPlus:0:10: +', - children = { - 'PlainIdentifier(scope=0,ident=c):0:8: c', - 'PlainIdentifier(scope=0,ident=d):0:12: d', - }, - }, - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('BinaryPlus', '+', 1), - hl('IdentifierName', 'b', 1), - hl('Comparison', '==', 1), - hl('IdentifierName', 'c', 1), - hl('BinaryPlus', '+', 1), - hl('IdentifierName', 'd', 1), - }) - check_parsing('+ a == + b', { - -- 0123456789 - ast = { - { - 'Comparison(type=Equal,inv=0,ccs=UseOption):0:3: ==', - children = { - { - 'UnaryPlus:0:0:+', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1: a', - }, - }, - { - 'UnaryPlus:0:6: +', - children = { - 'PlainIdentifier(scope=0,ident=b):0:8: b', - }, - }, - }, - }, - }, - }, { - hl('UnaryPlus', '+'), - hl('IdentifierName', 'a', 1), - hl('Comparison', '==', 1), - hl('UnaryPlus', '+', 1), - hl('IdentifierName', 'b', 1), - }) - end) - it('works with concat/subscript', function() - check_parsing('.', { - -- 0 - ast = { - { - 'ConcatOrSubscript:0:0:.', - children = { - 'Missing:0:0:', - }, - }, - }, - err = { - arg = '.', - msg = 'E15: Unexpected dot: %.*s', - }, - }, { - hl('InvalidConcatOrSubscript', '.'), - }) - - check_parsing('a.', { - -- 01 - ast = { - { - 'ConcatOrSubscript:0:1:.', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - }, - }, - }, - err = { - arg = '', - msg = 'E15: Expected value, got EOC: %.*s', - }, - }, { - hl('IdentifierName', 'a'), - hl('ConcatOrSubscript', '.'), - }) - - check_parsing('a.b', { - -- 012 - ast = { - { - 'ConcatOrSubscript:0:1:.', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainKey(key=b):0:2:b', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('ConcatOrSubscript', '.'), - hl('IdentifierKey', 'b'), - }) - - check_parsing('1.2', { - -- 012 - ast = { - 'Float(val=1.200000e+00):0:0:1.2', - }, - }, { - hl('Float', '1.2'), - }) - - check_parsing('1.2 + 1.3e-5', { - -- 012345678901 - -- 0 1 - ast = { - { - 'BinaryPlus:0:3: +', - children = { - 'Float(val=1.200000e+00):0:0:1.2', - 'Float(val=1.300000e-05):0:5: 1.3e-5', - }, - }, - }, - }, { - hl('Float', '1.2'), - hl('BinaryPlus', '+', 1), - hl('Float', '1.3e-5', 1), - }) - - check_parsing('a . 1.2 + 1.3e-5', { - -- 0123456789012345 - -- 0 1 - ast = { - { - 'BinaryPlus:0:7: +', - children = { - { - 'Concat:0:1: .', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'ConcatOrSubscript:0:5:.', - children = { - 'Integer(val=1):0:3: 1', - 'PlainKey(key=2):0:6:2', - }, - }, - }, - }, - 'Float(val=1.300000e-05):0:9: 1.3e-5', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Concat', '.', 1), - hl('Number', '1', 1), - hl('ConcatOrSubscript', '.'), - hl('IdentifierKey', '2'), - hl('BinaryPlus', '+', 1), - hl('Float', '1.3e-5', 1), - }) - - check_parsing('1.3e-5 + 1.2 . a', { - -- 0123456789012345 - -- 0 1 - ast = { - { - 'Concat:0:12: .', - children = { - { - 'BinaryPlus:0:6: +', - children = { - 'Float(val=1.300000e-05):0:0:1.3e-5', - 'Float(val=1.200000e+00):0:8: 1.2', - }, - }, - 'PlainIdentifier(scope=0,ident=a):0:14: a', - }, - }, - }, - }, { - hl('Float', '1.3e-5'), - hl('BinaryPlus', '+', 1), - hl('Float', '1.2', 1), - hl('Concat', '.', 1), - hl('IdentifierName', 'a', 1), - }) - - check_parsing('1.3e-5 + a . 1.2', { - -- 0123456789012345 - -- 0 1 - ast = { - { - 'Concat:0:10: .', - children = { - { - 'BinaryPlus:0:6: +', - children = { - 'Float(val=1.300000e-05):0:0:1.3e-5', - 'PlainIdentifier(scope=0,ident=a):0:8: a', - }, - }, - { - 'ConcatOrSubscript:0:14:.', - children = { - 'Integer(val=1):0:12: 1', - 'PlainKey(key=2):0:15:2', - }, - }, - }, - }, - }, - }, { - hl('Float', '1.3e-5'), - hl('BinaryPlus', '+', 1), - hl('IdentifierName', 'a', 1), - hl('Concat', '.', 1), - hl('Number', '1', 1), - hl('ConcatOrSubscript', '.'), - hl('IdentifierKey', '2'), - }) - - check_parsing('1.2.3', { - -- 01234 - ast = { - { - 'ConcatOrSubscript:0:3:.', - children = { - { - 'ConcatOrSubscript:0:1:.', - children = { - 'Integer(val=1):0:0:1', - 'PlainKey(key=2):0:2:2', - }, - }, - 'PlainKey(key=3):0:4:3', - }, - }, - }, - }, { - hl('Number', '1'), - hl('ConcatOrSubscript', '.'), - hl('IdentifierKey', '2'), - hl('ConcatOrSubscript', '.'), - hl('IdentifierKey', '3'), - }) - - check_parsing('a.1.2', { - -- 01234 - ast = { - { - 'ConcatOrSubscript:0:3:.', - children = { - { - 'ConcatOrSubscript:0:1:.', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainKey(key=1):0:2:1', - }, - }, - 'PlainKey(key=2):0:4:2', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('ConcatOrSubscript', '.'), - hl('IdentifierKey', '1'), - hl('ConcatOrSubscript', '.'), - hl('IdentifierKey', '2'), - }) - - check_parsing('a . 1.2', { - -- 0123456 - ast = { - { - 'Concat:0:1: .', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'ConcatOrSubscript:0:5:.', - children = { - 'Integer(val=1):0:3: 1', - 'PlainKey(key=2):0:6:2', - }, - }, - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('Concat', '.', 1), - hl('Number', '1', 1), - hl('ConcatOrSubscript', '.'), - hl('IdentifierKey', '2'), - }) - - check_parsing('+a . +b', { - -- 0123456 - ast = { - { - 'Concat:0:2: .', - children = { - { - 'UnaryPlus:0:0:+', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - }, - }, - { - 'UnaryPlus:0:4: +', - children = { - 'PlainIdentifier(scope=0,ident=b):0:6:b', - }, - }, - }, - }, - }, - }, { - hl('UnaryPlus', '+'), - hl('IdentifierName', 'a'), - hl('Concat', '.', 1), - hl('UnaryPlus', '+', 1), - hl('IdentifierName', 'b'), - }) - - check_parsing('a. b', { - -- 0123 - ast = { - { - 'Concat:0:1:.', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:2: b', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('ConcatOrSubscript', '.'), - hl('IdentifierName', 'b', 1), - }) - - check_parsing('a. 1', { - -- 0123 - ast = { - { - 'Concat:0:1:.', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'Integer(val=1):0:2: 1', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('ConcatOrSubscript', '.'), - hl('Number', '1', 1), - }) - end) - it('works with bracket subscripts', function() - check_parsing(':', { - -- 0 - ast = { - { - 'Colon:0:0::', - children = { - 'Missing:0:0:', - }, - }, - }, - err = { - arg = ':', - msg = 'E15: Colon outside of dictionary or ternary operator: %.*s', - }, - }, { - hl('InvalidColon', ':'), - }) - check_parsing('a[]', { - -- 012 - ast = { - { - 'Subscript:0:1:[', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - }, - }, - }, - err = { - arg = ']', - msg = 'E15: Expected value, got closing bracket: %.*s', - }, - }, { - hl('IdentifierName', 'a'), - hl('SubscriptBracket', '['), - hl('InvalidSubscriptBracket', ']'), - }) - check_parsing('a[b:]', { - -- 01234 - ast = { - { - 'Subscript:0:1:[', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=b,ident=):0:2:b:', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('SubscriptBracket', '['), - hl('IdentifierScope', 'b'), - hl('IdentifierScopeDelimiter', ':'), - hl('SubscriptBracket', ']'), - }) - - check_parsing('a[b:c]', { - -- 012345 - ast = { - { - 'Subscript:0:1:[', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=b,ident=c):0:2:b:c', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('SubscriptBracket', '['), - hl('IdentifierScope', 'b'), - hl('IdentifierScopeDelimiter', ':'), - hl('IdentifierName', 'c'), - hl('SubscriptBracket', ']'), - }) - check_parsing('a[b : c]', { - -- 01234567 - ast = { - { - 'Subscript:0:1:[', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'Colon:0:3: :', - children = { - 'PlainIdentifier(scope=0,ident=b):0:2:b', - 'PlainIdentifier(scope=0,ident=c):0:5: c', - }, - }, - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('SubscriptBracket', '['), - hl('IdentifierName', 'b'), - hl('SubscriptColon', ':', 1), - hl('IdentifierName', 'c', 1), - hl('SubscriptBracket', ']'), - }) - - check_parsing('a[: b]', { - -- 012345 - ast = { - { - 'Subscript:0:1:[', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'Colon:0:2::', - children = { - 'Missing:0:2:', - 'PlainIdentifier(scope=0,ident=b):0:3: b', - }, - }, - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('SubscriptBracket', '['), - hl('SubscriptColon', ':'), - hl('IdentifierName', 'b', 1), - hl('SubscriptBracket', ']'), - }) - - check_parsing('a[b :]', { - -- 012345 - ast = { - { - 'Subscript:0:1:[', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - { - 'Colon:0:3: :', - children = { - 'PlainIdentifier(scope=0,ident=b):0:2:b', - }, - }, - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('SubscriptBracket', '['), - hl('IdentifierName', 'b'), - hl('SubscriptColon', ':', 1), - hl('SubscriptBracket', ']'), - }) - check_parsing('a[b][c][d](e)(f)(g)', { - -- 0123456789012345678 - -- 0 1 - ast = { - { - 'Call:0:16:(', - children = { - { - 'Call:0:13:(', - children = { - { - 'Call:0:10:(', - children = { - { - 'Subscript:0:7:[', - children = { - { - 'Subscript:0:4:[', - children = { - { - 'Subscript:0:1:[', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - 'PlainIdentifier(scope=0,ident=b):0:2:b', - }, - }, - 'PlainIdentifier(scope=0,ident=c):0:5:c', - }, - }, - 'PlainIdentifier(scope=0,ident=d):0:8:d', - }, - }, - 'PlainIdentifier(scope=0,ident=e):0:11:e', - }, - }, - 'PlainIdentifier(scope=0,ident=f):0:14:f', - }, - }, - 'PlainIdentifier(scope=0,ident=g):0:17:g', - }, - }, - }, - }, { - hl('IdentifierName', 'a'), - hl('SubscriptBracket', '['), - hl('IdentifierName', 'b'), - hl('SubscriptBracket', ']'), - hl('SubscriptBracket', '['), - hl('IdentifierName', 'c'), - hl('SubscriptBracket', ']'), - hl('SubscriptBracket', '['), - hl('IdentifierName', 'd'), - hl('SubscriptBracket', ']'), - hl('CallingParenthesis', '('), - hl('IdentifierName', 'e'), - hl('CallingParenthesis', ')'), - hl('CallingParenthesis', '('), - hl('IdentifierName', 'f'), - hl('CallingParenthesis', ')'), - hl('CallingParenthesis', '('), - hl('IdentifierName', 'g'), - hl('CallingParenthesis', ')'), - }) - check_parsing('{a}{b}{c}[d][e][f]', { - -- 012345678901234567 - -- 0 1 - ast = { - { - 'Subscript:0:15:[', - children = { - { - 'Subscript:0:12:[', - children = { - { - 'Subscript:0:9:[', - children = { - { - 'ComplexIdentifier:0:3:', - children = { - { - 'CurlyBracesIdentifier:0:0:{', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - }, - }, - { - 'ComplexIdentifier:0:6:', - children = { - { - 'CurlyBracesIdentifier:0:3:{', - children = { - 'PlainIdentifier(scope=0,ident=b):0:4:b', - }, - }, - { - 'CurlyBracesIdentifier:0:6:{', - children = { - 'PlainIdentifier(scope=0,ident=c):0:7:c', - }, - }, - }, - }, - }, - }, - 'PlainIdentifier(scope=0,ident=d):0:10:d', - }, - }, - 'PlainIdentifier(scope=0,ident=e):0:13:e', - }, - }, - 'PlainIdentifier(scope=0,ident=f):0:16:f', - }, - }, - }, - }, { - hl('Curly', '{'), - hl('IdentifierName', 'a'), - hl('Curly', '}'), - hl('Curly', '{'), - hl('IdentifierName', 'b'), - hl('Curly', '}'), - hl('Curly', '{'), - hl('IdentifierName', 'c'), - hl('Curly', '}'), - hl('SubscriptBracket', '['), - hl('IdentifierName', 'd'), - hl('SubscriptBracket', ']'), - hl('SubscriptBracket', '['), - hl('IdentifierName', 'e'), - hl('SubscriptBracket', ']'), - hl('SubscriptBracket', '['), - hl('IdentifierName', 'f'), - hl('SubscriptBracket', ']'), - }) - end) - it('supports list literals', function() - check_parsing('[]', { - -- 01 - ast = { - 'ListLiteral:0:0:[', - }, - }, { - hl('List', '['), - hl('List', ']'), - }) - - check_parsing('[a]', { - -- 012 - ast = { - { - 'ListLiteral:0:0:[', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - }, - }, - }, - }, { - hl('List', '['), - hl('IdentifierName', 'a'), - hl('List', ']'), - }) - - check_parsing('[a, b]', { - -- 012345 - ast = { - { - 'ListLiteral:0:0:[', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - 'PlainIdentifier(scope=0,ident=b):0:3: b', - }, - }, - }, - }, - }, - }, { - hl('List', '['), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('IdentifierName', 'b', 1), - hl('List', ']'), - }) - - check_parsing('[a, b, c]', { - -- 012345678 - ast = { - { - 'ListLiteral:0:0:[', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - { - 'Comma:0:5:,', - children = { - 'PlainIdentifier(scope=0,ident=b):0:3: b', - 'PlainIdentifier(scope=0,ident=c):0:6: c', - }, - }, - }, - }, - }, - }, - }, - }, { - hl('List', '['), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('IdentifierName', 'b', 1), - hl('Comma', ','), - hl('IdentifierName', 'c', 1), - hl('List', ']'), - }) - - check_parsing('[a, b, c, ]', { - -- 01234567890 - -- 0 1 - ast = { - { - 'ListLiteral:0:0:[', - children = { - { - 'Comma:0:2:,', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - { - 'Comma:0:5:,', - children = { - 'PlainIdentifier(scope=0,ident=b):0:3: b', - { - 'Comma:0:8:,', - children = { - 'PlainIdentifier(scope=0,ident=c):0:6: c', - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, { - hl('List', '['), - hl('IdentifierName', 'a'), - hl('Comma', ','), - hl('IdentifierName', 'b', 1), - hl('Comma', ','), - hl('IdentifierName', 'c', 1), - hl('Comma', ','), - hl('List', ']', 1), - }) - - check_parsing('[a : b, c : d]', { - -- 01234567890123 - -- 0 1 - ast = { - { - 'ListLiteral:0:0:[', - children = { - { - 'Comma:0:6:,', - children = { - { - 'Colon:0:2: :', - children = { - 'PlainIdentifier(scope=0,ident=a):0:1:a', - 'PlainIdentifier(scope=0,ident=b):0:4: b', - }, - }, - { - 'Colon:0:9: :', - children = { - 'PlainIdentifier(scope=0,ident=c):0:7: c', - 'PlainIdentifier(scope=0,ident=d):0:11: d', - }, - }, - }, - }, - }, - }, - }, - err = { - arg = ': b, c : d]', - msg = 'E15: Colon outside of dictionary or ternary operator: %.*s', - }, - }, { - hl('List', '['), - hl('IdentifierName', 'a'), - hl('InvalidColon', ':', 1), - hl('IdentifierName', 'b', 1), - hl('Comma', ','), - hl('IdentifierName', 'c', 1), - hl('InvalidColon', ':', 1), - hl('IdentifierName', 'd', 1), - hl('List', ']'), - }) - - check_parsing(']', { - -- 0 - ast = { - 'ListLiteral:0:0:', - }, - err = { - arg = ']', - msg = 'E15: Unexpected closing figure brace: %.*s', - }, - }, { - hl('InvalidList', ']'), - }) - - check_parsing('a]', { - -- 01 - ast = { - { - 'ListLiteral:0:1:', - children = { - 'PlainIdentifier(scope=0,ident=a):0:0:a', - }, - }, - }, - err = { - arg = ']', - msg = 'E15: Unexpected closing figure brace: %.*s', - }, - }, { - hl('IdentifierName', 'a'), - hl('InvalidList', ']'), - }) - - check_parsing('[] []', { - -- 01234 - ast = { - { - 'OpMissing:0:2:', - children = { - 'ListLiteral:0:0:[', - 'ListLiteral:0:2: [', - }, - }, - }, - err = { - arg = '[]', - msg = 'E15: Missing operator: %.*s', - }, - }, { - hl('List', '['), - hl('List', ']'), - hl('InvalidSpacing', ' '), - hl('List', '['), - hl('List', ']'), - }, { - [1] = { - ast = { - len = 3, - err = REMOVE_THIS, - ast = { - 'ListLiteral:0:0:[', - }, - }, - hl_fs = { - [3] = REMOVE_THIS, - [4] = REMOVE_THIS, - [5] = REMOVE_THIS, - }, - }, - }) - - check_parsing('[][]', { - -- 0123 - ast = { - { - 'Subscript:0:2:[', - children = { - 'ListLiteral:0:0:[', - }, - }, - }, - err = { - arg = ']', - msg = 'E15: Expected value, got closing bracket: %.*s', - }, - }, { - hl('List', '['), - hl('List', ']'), - hl('SubscriptBracket', '['), - hl('InvalidSubscriptBracket', ']'), - }) - - check_parsing('[', { - -- 0 - ast = { - 'ListLiteral:0:0:[', - }, - err = { - arg = '', - msg = 'E15: Expected value, got EOC: %.*s', - }, - }, { - hl('List', '['), - }) - - check_parsing('[1', { - -- 01 - ast = { - { - 'ListLiteral:0:0:[', - children = { - 'Integer(val=1):0:1:1', - }, - }, - }, - err = { - arg = '[1', - msg = 'E697: Missing end of List \']\': %.*s', - }, - }, { - hl('List', '['), - hl('Number', '1'), - }) - end) - it('works with strings', function() - check_parsing('\'abc\'', { - -- 01234 - ast = { - 'SingleQuotedString(val="abc"):0:0:\'abc\'', - }, - }, { - hl('SingleQuote', '\''), - hl('SingleQuotedBody', 'abc'), - hl('SingleQuote', '\''), - }) - check_parsing('"abc"', { - -- 01234 - ast = { - 'DoubleQuotedString(val="abc"):0:0:"abc"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedBody', 'abc'), - hl('DoubleQuote', '"'), - }) - check_parsing('\'\'', { - -- 01 - ast = { - 'SingleQuotedString(val=""):0:0:\'\'', - }, - }, { - hl('SingleQuote', '\''), - hl('SingleQuote', '\''), - }) - check_parsing('""', { - -- 01 - ast = { - 'DoubleQuotedString(val=""):0:0:""', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuote', '"'), - }) - check_parsing('"', { - -- 0 - ast = { - 'DoubleQuotedString(val=""):0:0:"', - }, - err = { - arg = '"', - msg = 'E114: Missing double quote: %.*s', - }, - }, { - hl('InvalidDoubleQuote', '"'), - }) - check_parsing('\'', { - -- 0 - ast = { - 'SingleQuotedString(val=""):0:0:\'', - }, - err = { - arg = '\'', - msg = 'E115: Missing single quote: %.*s', - }, - }, { - hl('InvalidSingleQuote', '\''), - }) - check_parsing('"a', { - -- 01 - ast = { - 'DoubleQuotedString(val="a"):0:0:"a', - }, - err = { - arg = '"a', - msg = 'E114: Missing double quote: %.*s', - }, - }, { - hl('InvalidDoubleQuote', '"'), - hl('InvalidDoubleQuotedBody', 'a'), - }) - check_parsing('\'a', { - -- 01 - ast = { - 'SingleQuotedString(val="a"):0:0:\'a', - }, - err = { - arg = '\'a', - msg = 'E115: Missing single quote: %.*s', - }, - }, { - hl('InvalidSingleQuote', '\''), - hl('InvalidSingleQuotedBody', 'a'), - }) - check_parsing('\'abc\'\'def\'', { - -- 0123456789 - ast = { - 'SingleQuotedString(val="abc\'def"):0:0:\'abc\'\'def\'', - }, - }, { - hl('SingleQuote', '\''), - hl('SingleQuotedBody', 'abc'), - hl('SingleQuotedQuote', '\'\''), - hl('SingleQuotedBody', 'def'), - hl('SingleQuote', '\''), - }) - check_parsing('\'abc\'\'', { - -- 012345 - ast = { - 'SingleQuotedString(val="abc\'"):0:0:\'abc\'\'', - }, - err = { - arg = '\'abc\'\'', - msg = 'E115: Missing single quote: %.*s', - }, - }, { - hl('InvalidSingleQuote', '\''), - hl('InvalidSingleQuotedBody', 'abc'), - hl('InvalidSingleQuotedQuote', '\'\''), - }) - check_parsing('\'\'\'\'\'\'\'\'', { - -- 01234567 - ast = { - 'SingleQuotedString(val="\'\'\'"):0:0:\'\'\'\'\'\'\'\'', - }, - }, { - hl('SingleQuote', '\''), - hl('SingleQuotedQuote', '\'\''), - hl('SingleQuotedQuote', '\'\''), - hl('SingleQuotedQuote', '\'\''), - hl('SingleQuote', '\''), - }) - check_parsing('\'\'\'a\'\'\'\'bc\'', { - -- 01234567890 - -- 0 1 - ast = { - 'SingleQuotedString(val="\'a\'\'bc"):0:0:\'\'\'a\'\'\'\'bc\'', - }, - }, { - hl('SingleQuote', '\''), - hl('SingleQuotedQuote', '\'\''), - hl('SingleQuotedBody', 'a'), - hl('SingleQuotedQuote', '\'\''), - hl('SingleQuotedQuote', '\'\''), - hl('SingleQuotedBody', 'bc'), - hl('SingleQuote', '\''), - }) - check_parsing('"\\"\\"\\"\\""', { - -- 0123456789 - ast = { - 'DoubleQuotedString(val="\\"\\"\\"\\""):0:0:"\\"\\"\\"\\""', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\"'), - hl('DoubleQuotedEscape', '\\"'), - hl('DoubleQuotedEscape', '\\"'), - hl('DoubleQuotedEscape', '\\"'), - hl('DoubleQuote', '"'), - }) - check_parsing('"abc\\"def\\"ghi\\"jkl\\"mno"', { - -- 0123456789012345678901234 - -- 0 1 2 - ast = { - 'DoubleQuotedString(val="abc\\"def\\"ghi\\"jkl\\"mno"):0:0:"abc\\"def\\"ghi\\"jkl\\"mno"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedBody', 'abc'), - hl('DoubleQuotedEscape', '\\"'), - hl('DoubleQuotedBody', 'def'), - hl('DoubleQuotedEscape', '\\"'), - hl('DoubleQuotedBody', 'ghi'), - hl('DoubleQuotedEscape', '\\"'), - hl('DoubleQuotedBody', 'jkl'), - hl('DoubleQuotedEscape', '\\"'), - hl('DoubleQuotedBody', 'mno'), - hl('DoubleQuote', '"'), - }) - check_parsing('"\\b\\e\\f\\r\\t\\\\"', { - -- 0123456789012345 - -- 0 1 - ast = { - [[DoubleQuotedString(val="\8\27\12\13\9\\"):0:0:"\b\e\f\r\t\\"]], - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\b'), - hl('DoubleQuotedEscape', '\\e'), - hl('DoubleQuotedEscape', '\\f'), - hl('DoubleQuotedEscape', '\\r'), - hl('DoubleQuotedEscape', '\\t'), - hl('DoubleQuotedEscape', '\\\\'), - hl('DoubleQuote', '"'), - }) - check_parsing('"\\n\n"', { - -- 01234 - ast = { - 'DoubleQuotedString(val="\\\n\\\n"):0:0:"\\n\n"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\n'), - hl('DoubleQuotedBody', '\n'), - hl('DoubleQuote', '"'), - }) - check_parsing('"\\x00"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\\0"):0:0:"\\x00"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\x00'), - hl('DoubleQuote', '"'), - }) - check_parsing('"\\xFF"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\255"):0:0:"\\xFF"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\xFF'), - hl('DoubleQuote', '"'), - }) - check_parsing('"\\xF"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\\15"):0:0:"\\xF"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\xF'), - hl('DoubleQuote', '"'), - }) - check_parsing('"\\u00AB"', { - -- 01234567 - ast = { - 'DoubleQuotedString(val="«"):0:0:"\\u00AB"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\u00AB'), - hl('DoubleQuote', '"'), - }) - check_parsing('"\\U000000AB"', { - -- 01234567 - ast = { - 'DoubleQuotedString(val="«"):0:0:"\\U000000AB"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\U000000AB'), - hl('DoubleQuote', '"'), - }) - check_parsing('"\\x"', { - -- 0123 - ast = { - 'DoubleQuotedString(val="x"):0:0:"\\x"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedUnknownEscape', '\\x'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\x', { - -- 012 - ast = { - 'DoubleQuotedString(val="x"):0:0:"\\x', - }, - err = { - arg = '"\\x', - msg = 'E114: Missing double quote: %.*s', - }, - }, { - hl('InvalidDoubleQuote', '"'), - hl('InvalidDoubleQuotedUnknownEscape', '\\x'), - }) - - check_parsing('"\\xF', { - -- 0123 - ast = { - 'DoubleQuotedString(val="\\15"):0:0:"\\xF', - }, - err = { - arg = '"\\xF', - msg = 'E114: Missing double quote: %.*s', - }, - }, { - hl('InvalidDoubleQuote', '"'), - hl('InvalidDoubleQuotedEscape', '\\xF'), - }) - - check_parsing('"\\u"', { - -- 0123 - ast = { - 'DoubleQuotedString(val="u"):0:0:"\\u"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedUnknownEscape', '\\u'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\u', { - -- 012 - ast = { - 'DoubleQuotedString(val="u"):0:0:"\\u', - }, - err = { - arg = '"\\u', - msg = 'E114: Missing double quote: %.*s', - }, - }, { - hl('InvalidDoubleQuote', '"'), - hl('InvalidDoubleQuotedUnknownEscape', '\\u'), - }) - - check_parsing('"\\U', { - -- 012 - ast = { - 'DoubleQuotedString(val="U"):0:0:"\\U', - }, - err = { - arg = '"\\U', - msg = 'E114: Missing double quote: %.*s', - }, - }, { - hl('InvalidDoubleQuote', '"'), - hl('InvalidDoubleQuotedUnknownEscape', '\\U'), - }) - - check_parsing('"\\U"', { - -- 0123 - ast = { - 'DoubleQuotedString(val="U"):0:0:"\\U"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedUnknownEscape', '\\U'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\xFX"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\\15X"):0:0:"\\xFX"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\xF'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\XFX"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\\15X"):0:0:"\\XFX"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\XF'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\xX"', { - -- 01234 - ast = { - 'DoubleQuotedString(val="xX"):0:0:"\\xX"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedUnknownEscape', '\\x'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\XX"', { - -- 01234 - ast = { - 'DoubleQuotedString(val="XX"):0:0:"\\XX"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedUnknownEscape', '\\X'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\uX"', { - -- 01234 - ast = { - 'DoubleQuotedString(val="uX"):0:0:"\\uX"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedUnknownEscape', '\\u'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\UX"', { - -- 01234 - ast = { - 'DoubleQuotedString(val="UX"):0:0:"\\UX"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedUnknownEscape', '\\U'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\x0X"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\x0X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\x0'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\X0X"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\X0X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\X0'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\u0X"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\u0X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\u0'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\U0X"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\U0X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\U0'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\x00X"', { - -- 0123456 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\x00X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\x00'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\X00X"', { - -- 0123456 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\X00X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\X00'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\u00X"', { - -- 0123456 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\u00X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\u00'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\U00X"', { - -- 0123456 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\U00X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\U00'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\u000X"', { - -- 01234567 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\u000X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\u000'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\U000X"', { - -- 01234567 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\U000X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\U000'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\u0000X"', { - -- 012345678 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\u0000X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\u0000'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\U0000X"', { - -- 012345678 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\U0000X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\U0000'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\U00000X"', { - -- 0123456789 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\U00000X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\U00000'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\U000000X"', { - -- 01234567890 - -- 0 1 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\U000000X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\U000000'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\U0000000X"', { - -- 012345678901 - -- 0 1 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\U0000000X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\U0000000'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\U00000000X"', { - -- 0123456789012 - -- 0 1 - ast = { - 'DoubleQuotedString(val="\\0X"):0:0:"\\U00000000X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\U00000000'), - hl('DoubleQuotedBody', 'X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\x000X"', { - -- 01234567 - ast = { - 'DoubleQuotedString(val="\\0000X"):0:0:"\\x000X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\x00'), - hl('DoubleQuotedBody', '0X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\X000X"', { - -- 01234567 - ast = { - 'DoubleQuotedString(val="\\0000X"):0:0:"\\X000X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\X00'), - hl('DoubleQuotedBody', '0X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\u00000X"', { - -- 0123456789 - ast = { - 'DoubleQuotedString(val="\\0000X"):0:0:"\\u00000X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\u0000'), - hl('DoubleQuotedBody', '0X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\U000000000X"', { - -- 01234567890123 - -- 0 1 - ast = { - 'DoubleQuotedString(val="\\0000X"):0:0:"\\U000000000X"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\U00000000'), - hl('DoubleQuotedBody', '0X'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\0"', { - -- 0123 - ast = { - 'DoubleQuotedString(val="\\0"):0:0:"\\0"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\0'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\00"', { - -- 01234 - ast = { - 'DoubleQuotedString(val="\\0"):0:0:"\\00"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\00'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\000"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\\0"):0:0:"\\000"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\000'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\0000"', { - -- 0123456 - ast = { - 'DoubleQuotedString(val="\\0000"):0:0:"\\0000"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\000'), - hl('DoubleQuotedBody', '0'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\8"', { - -- 0123 - ast = { - 'DoubleQuotedString(val="8"):0:0:"\\8"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedUnknownEscape', '\\8'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\08"', { - -- 01234 - ast = { - 'DoubleQuotedString(val="\\0008"):0:0:"\\08"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\0'), - hl('DoubleQuotedBody', '8'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\008"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\\0008"):0:0:"\\008"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\00'), - hl('DoubleQuotedBody', '8'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\0008"', { - -- 0123456 - ast = { - 'DoubleQuotedString(val="\\0008"):0:0:"\\0008"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\000'), - hl('DoubleQuotedBody', '8'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\777"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\255"):0:0:"\\777"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\777'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\050"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\40"):0:0:"\\050"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\050'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\"', { - -- 012345 - ast = { - 'DoubleQuotedString(val="\\21"):0:0:"\\"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedEscape', '\\'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\<', { - -- 012 - ast = { - 'DoubleQuotedString(val="<"):0:0:"\\<', - }, - err = { - arg = '"\\<', - msg = 'E114: Missing double quote: %.*s', - }, - }, { - hl('InvalidDoubleQuote', '"'), - hl('InvalidDoubleQuotedUnknownEscape', '\\<'), - }) - - check_parsing('"\\<"', { - -- 0123 - ast = { - 'DoubleQuotedString(val="<"):0:0:"\\<"', - }, - }, { - hl('DoubleQuote', '"'), - hl('DoubleQuotedUnknownEscape', '\\<'), - hl('DoubleQuote', '"'), - }) - - check_parsing('"\\ Date: Sun, 19 Nov 2017 21:13:27 +0300 Subject: *: Fix linter errors --- test/functional/api/vim_spec.lua | 1 - 1 file changed, 1 deletion(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 3939bc9b52..2572675a58 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -12,7 +12,6 @@ local request = helpers.request local meth_pcall = helpers.meth_pcall local command = helpers.command -local REMOVE_THIS = global_helpers.REMOVE_THIS local intchar2lua = global_helpers.intchar2lua local format_string = global_helpers.format_string local mergedicts_copy = global_helpers.mergedicts_copy -- cgit From ebb33eddd9ad0e9cec5013be2e37c8f9b0546c77 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 19 Nov 2017 21:40:34 +0300 Subject: tests: Stabilize float format and %e in format_luav and format_string --- test/functional/api/vim_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 2572675a58..5b5340d9e2 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -750,7 +750,7 @@ describe('api', function() typ = typ .. ('(val=%u)'):format(east_api_node.ivalue) east_api_node.ivalue = nil elseif typ == 'Float' then - typ = typ .. ('(val=%e)'):format(east_api_node.fvalue) + typ = typ .. format_string('(val=%e)', east_api_node.fvalue) east_api_node.fvalue = nil elseif typ == 'SingleQuotedString' or typ == 'DoubleQuotedString' then typ = format_string('%s(val=%q)', typ, east_api_node.svalue) -- cgit From 91b856cccec89d5a29c280441f4a6aa7c8393268 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 10 Jun 2017 15:25:23 +0200 Subject: channels: tests --- test/functional/api/server_requests_spec.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'test/functional/api') diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index a2a198ca83..37ac532d18 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -262,6 +262,7 @@ describe('server -> client', function() eq("done!",funcs.rpcrequest(jobid, "write_stderr", "fluff\n")) eq({'notification', 'stderr', {0, {'fluff', ''}}}, next_message()) funcs.rpcrequest(jobid, "exit") + eq({'notification', 'stderr', {0, {''}}}, next_message()) eq({'notification', 'exit', {0, 0}}, next_message()) end) end) -- cgit From 17077b68133a62d0dc1b84cb48779464c117e028 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 26 Nov 2017 16:08:53 +0300 Subject: viml/parser/expressions: Make $ENV not depend on &isident --- test/functional/api/vim_spec.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 5b5340d9e2..841b7a584a 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -717,6 +717,9 @@ describe('api', function() end) describe('nvim_parse_expression', function() + before_each(function() + meths.set_option('isident', '') + end) local function simplify_east_api_node(line, east_api_node) if east_api_node == NIL then return nil -- cgit From 5ab0f988caffad5e8c87a075cbd3f91f0f7e002c Mon Sep 17 00:00:00 2001 From: ZyX Date: Thu, 30 Nov 2017 11:53:25 +0300 Subject: *: Replace all occurrences of NVim with Nvim --- test/functional/api/vim_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 841b7a584a..ff28e3d133 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -885,7 +885,7 @@ describe('api', function() return function(next_col) local col = next_col + (shift or 0) return (('%s:%u:%u:%s'):format( - 'NVim' .. group, + 'Nvim' .. group, 0, col, str)), (col + #str) -- cgit From c095f83116eb8ef87983ca5fea61053755fbc4e5 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 5 Jan 2018 11:17:21 +0100 Subject: api: change nvim_command_output behavior Implement nvim_command_output with `execute({cmd},"silent")`. Behavior changes: - does not provoke any hit-enter prompt - no longer prepends a newline char - does not capture some noise (like the "[New File]" message, see the change to tabnewentered_spec.lua) Technically ("bug-for-bug") this a breaking change. But the previous behavior of nvim_command_output meant that it probably wasn't used for anything outside of tests. Also remove the undocumented `v:command_output` variable which was a hack introduced only for the purposes of nvim_command_output. closes #7726 --- test/functional/api/vim_spec.lua | 53 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index ff28e3d133..d213c3c34e 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -37,7 +37,7 @@ describe('api', function() os.remove(fname) end) - it("VimL error: fails (VimL error), does NOT update v:errmsg", function() + it("parse error: fails (specific error), does NOT update v:errmsg", function() -- Most API methods return generic errors (or no error) if a VimL -- expression fails; nvim_command returns the VimL error details. local status, rv = pcall(nvim, "command", "bogus_command") @@ -45,6 +45,57 @@ describe('api', function() eq("E492:", string.match(rv, "E%d*:")) -- VimL error was returned. eq("", nvim("eval", "v:errmsg")) -- v:errmsg was not updated. end) + + it("runtime error: fails (specific error)", function() + local status, rv = pcall(nvim, "command_output", "buffer 23487") + eq(false, status) -- nvim_command() failed. + eq("E86: Buffer 23487 does not exist", string.match(rv, "E%d*:.*")) + eq("", nvim("eval", "v:errmsg")) -- v:errmsg was not updated. + end) + end) + + describe('nvim_command_output', function() + it('does not induce hit-enter prompt', function() + -- Induce a hit-enter prompt use nvim_input (non-blocking). + nvim('command', 'set cmdheight=1') + nvim('input', [[:echo "hi\nhi2"]]) + + -- Verify hit-enter prompt. + eq({mode='r', blocking=true}, nvim("get_mode")) + nvim('input', [[]]) + + -- Verify NO hit-enter prompt. + nvim('command_output', [[echo "hi\nhi2"]]) + eq({mode='n', blocking=false}, nvim("get_mode")) + end) + + it('returns command output', function() + eq('this is\nspinal tap', + nvim('command_output', [[echo "this is\nspinal tap"]])) + end) + + it('does not return shell |:!| output', function() + eq(':!echo "foo"\r\n', nvim('command_output', [[!echo "foo"]])) + end) + + it("parse error: fails (specific error), does NOT update v:errmsg", function() + local status, rv = pcall(nvim, "command_output", "bogus commannnd") + eq(false, status) -- nvim_command_output() failed. + eq("E492: Not an editor command: bogus commannnd", + string.match(rv, "E%d*:.*")) + eq("", nvim("eval", "v:errmsg")) -- v:errmsg was not updated. + -- Verify NO hit-enter prompt. + eq({mode='n', blocking=false}, nvim("get_mode")) + end) + + it("runtime error: fails (specific error)", function() + local status, rv = pcall(nvim, "command_output", "buffer 42") + eq(false, status) -- nvim_command_output() failed. + eq("E86: Buffer 42 does not exist", string.match(rv, "E%d*:.*")) + eq("", nvim("eval", "v:errmsg")) -- v:errmsg was not updated. + -- Verify NO hit-enter prompt. + eq({mode='n', blocking=false}, nvim("get_mode")) + end) end) describe('nvim_eval', function() -- cgit From 5055d4a755d3c100cddf51bded77abca04beb971 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 9 Jan 2018 10:36:25 +0100 Subject: api: nvim_command_output: direct impl --- test/functional/api/vim_spec.lua | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index d213c3c34e..39db831fe3 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -69,11 +69,36 @@ describe('api', function() eq({mode='n', blocking=false}, nvim("get_mode")) end) - it('returns command output', function() + it('captures command output', function() eq('this is\nspinal tap', nvim('command_output', [[echo "this is\nspinal tap"]])) end) + it('captures empty command output', function() + eq('', nvim('command_output', 'echo')) + end) + + it('captures single-char command output', function() + eq('x', nvim('command_output', 'echo "x"')) + end) + + it('captures multiple commands', function() + eq('foo\n 1 %a "[No Name]" line 1', + nvim('command_output', 'echo "foo" | ls')) + end) + + it('captures nested execute()', function() + eq('\nnested1\nnested2\n 1 %a "[No Name]" line 1', + nvim('command_output', + [[echo execute('echo "nested1\nnested2"') | ls]])) + end) + + it('captures nested nvim_command_output()', function() + eq('nested1\nnested2\n 1 %a "[No Name]" line 1', + nvim('command_output', + [[echo nvim_command_output('echo "nested1\nnested2"') | ls]])) + end) + it('does not return shell |:!| output', function() eq(':!echo "foo"\r\n', nvim('command_output', [[!echo "foo"]])) end) -- cgit From a2dfeb8a16117b51744ef3c37392a61396aa3ae5 Mon Sep 17 00:00:00 2001 From: ZyX Date: Fri, 2 Feb 2018 00:55:22 +0300 Subject: functests: Improve error reporting in _check_parsing function May be needed for unit tests as well though. --- test/functional/api/vim_spec.lua | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 39db831fe3..a92acd36b1 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -951,9 +951,20 @@ describe('api', function() end end) if not err then - msg = format_string('Error while processing test (%r, %s):\n%s', - str, FLAGS_TO_STR[flags], msg) - error(msg) + if type(msg) == 'table' then + local merr, new_msg = pcall( + format_string, 'table error:\n%s\n\n(%r)', msg.message, msg) + if merr then + msg = new_msg + else + msg = format_string('table error without .message:\n(%r)', + msg) + end + elseif type(msg) ~= 'string' then + msg = format_string('non-string non-table error:\n%r', msg) + end + error(format_string('Error while processing test (%r, %s):\n%s', + str, FLAGS_TO_STR[flags], msg)) end end end -- cgit From 4e7d85e6356d88944a60c447a9754b8b37407c12 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 21 Jan 2018 19:58:19 +0100 Subject: shell: update `execute('!cmd')` test to new behavior And similarly nvim_command_output test --- test/functional/api/vim_spec.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index a92acd36b1..0a0cb2e91c 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -15,6 +15,7 @@ local command = helpers.command local intchar2lua = global_helpers.intchar2lua local format_string = global_helpers.format_string local mergedicts_copy = global_helpers.mergedicts_copy +local uname = global_helpers.uname describe('api', function() before_each(clear) @@ -99,8 +100,9 @@ describe('api', function() [[echo nvim_command_output('echo "nested1\nnested2"') | ls]])) end) - it('does not return shell |:!| output', function() - eq(':!echo "foo"\r\n', nvim('command_output', [[!echo "foo"]])) + it('returns shell |:!| output', function() + local win_lf = (uname() == 'Windows' and '\r') or '' + eq(':!echo foo\r\n\nfoo'..win_lf..'\n', nvim('command_output', [[!echo foo]])) end) it("parse error: fails (specific error), does NOT update v:errmsg", function() -- cgit From 352a51e8313d05c4701f468a79540a2410c77b23 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 10 May 2017 15:04:49 +0200 Subject: test: :! print binary data, control chars closes #5442 closes #4142 ref #6618 ref #4376 ref #7844 ref #2958 ref #4338 --- test/functional/api/vim_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 0a0cb2e91c..1faed4e9b1 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -11,11 +11,11 @@ local funcs = helpers.funcs local request = helpers.request local meth_pcall = helpers.meth_pcall local command = helpers.command +local iswin = helpers.iswin local intchar2lua = global_helpers.intchar2lua local format_string = global_helpers.format_string local mergedicts_copy = global_helpers.mergedicts_copy -local uname = global_helpers.uname describe('api', function() before_each(clear) @@ -101,7 +101,7 @@ describe('api', function() end) it('returns shell |:!| output', function() - local win_lf = (uname() == 'Windows' and '\r') or '' + local win_lf = iswin() and '\r' or '' eq(':!echo foo\r\n\nfoo'..win_lf..'\n', nvim('command_output', [[!echo foo]])) end) -- cgit From 6e5cb0debd23693175bd05409d3f1af4015567df Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Tue, 13 Feb 2018 13:45:49 +0100 Subject: ui: refactor ui options --- test/functional/api/version_spec.lua | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/version_spec.lua b/test/functional/api/version_spec.lua index d23f058f69..7bf54c0d1e 100644 --- a/test/functional/api/version_spec.lua +++ b/test/functional/api/version_spec.lua @@ -1,6 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) local mpack = require('mpack') local clear, funcs, eq = helpers.clear, helpers.funcs, helpers.eq +local call = helpers.call local function read_mpack_file(fname) local fd = io.open(fname, 'rb') @@ -18,7 +19,7 @@ describe("api_info()['version']", function() before_each(clear) it("returns API level", function() - local version = helpers.call('api_info')['version'] + local version = call('api_info')['version'] local current = version['api_level'] local compat = version['api_compatible'] eq("number", type(current)) @@ -27,7 +28,7 @@ describe("api_info()['version']", function() end) it("returns Nvim version", function() - local version = helpers.call('api_info')['version'] + local version = call('api_info')['version'] local major = version['major'] local minor = version['minor'] local patch = version['patch'] @@ -147,3 +148,14 @@ describe("api functions", function() end) end) + +describe("ui_options in metadata", function() + it('are correct', function() + -- TODO(bfredl) once a release freezes this into metadata, + -- instead check that all old options are present + local api = helpers.call('api_info') + local options = api.ui_options + eq({'rgb', 'ext_cmdline', 'ext_popupmenu', + 'ext_tabline', 'ext_wildmenu'}, options) + end) +end) -- cgit From 9f994bb69925ed943b17d03f2cad7d5e2c21e992 Mon Sep 17 00:00:00 2001 From: geekodour Date: Fri, 16 Feb 2018 14:10:40 +0530 Subject: api: nvim_list_uis #8004 ref #7438 closes #4842 --- test/functional/api/vim_spec.lua | 41 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 1faed4e9b1..bd56161a54 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -745,7 +745,7 @@ describe('api', function() end) end) - describe('list_runtime_paths', function() + describe('nvim_list_runtime_paths', function() it('returns nothing with empty &runtimepath', function() meths.set_option('runtimepath', '') eq({}, meths.list_runtime_paths()) @@ -998,4 +998,43 @@ describe('api', function() it, _check_parsing, hl, fmtn) end) + describe('nvim_list_uis', function() + it('returns empty if --headless', function() + -- --embed implies --headless. + eq({}, nvim("list_uis")) + end) + it('returns attached UIs', function() + local screen = Screen.new(20, 4) + screen:attach() + local expected = { + { + ext_cmdline = false, + ext_popupmenu = false, + ext_tabline = false, + ext_wildmenu = false, + height = 4, + rgb = true, + width = 20, + } + } + eq(expected, nvim("list_uis")) + + screen:detach() + screen = Screen.new(44, 99) + screen:attach({ rgb = false }) + expected = { + { + ext_cmdline = false, + ext_popupmenu = false, + ext_tabline = false, + ext_wildmenu = false, + height = 99, + rgb = false, + width = 44, + } + } + eq(expected, nvim("list_uis")) + end) + end) + end) -- cgit From fd4021387e696c7a2da4ad776789cfbb938d5332 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 9 Mar 2018 00:24:38 +0100 Subject: test: rename next_message() to next_msg() --- test/functional/api/server_notifications_spec.lua | 16 ++++++++-------- test/functional/api/server_requests_spec.lua | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua index 9d7cfb9b78..1d64ae7103 100644 --- a/test/functional/api/server_notifications_spec.lua +++ b/test/functional/api/server_notifications_spec.lua @@ -1,7 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) -local eq, clear, eval, command, nvim, next_message = +local eq, clear, eval, command, nvim, next_msg = helpers.eq, helpers.clear, helpers.eval, helpers.command, helpers.nvim, - helpers.next_message + helpers.next_msg local meths = helpers.meths describe('notify', function() @@ -15,10 +15,10 @@ describe('notify', function() describe('passing a valid channel id', function() it('sends the notification/args to the corresponding channel', function() eval('rpcnotify('..channel..', "test-event", 1, 2, 3)') - eq({'notification', 'test-event', {1, 2, 3}}, next_message()) + eq({'notification', 'test-event', {1, 2, 3}}, next_msg()) command('au FileType lua call rpcnotify('..channel..', "lua!")') command('set filetype=lua') - eq({'notification', 'lua!', {}}, next_message()) + eq({'notification', 'lua!', {}}, next_msg()) end) end) @@ -28,13 +28,13 @@ describe('notify', function() eval('rpcnotify(0, "event1", 1, 2, 3)') eval('rpcnotify(0, "event2", 4, 5, 6)') eval('rpcnotify(0, "event2", 7, 8, 9)') - eq({'notification', 'event2', {4, 5, 6}}, next_message()) - eq({'notification', 'event2', {7, 8, 9}}, next_message()) + eq({'notification', 'event2', {4, 5, 6}}, next_msg()) + eq({'notification', 'event2', {7, 8, 9}}, next_msg()) nvim('unsubscribe', 'event2') nvim('subscribe', 'event1') eval('rpcnotify(0, "event2", 10, 11, 12)') eval('rpcnotify(0, "event1", 13, 14, 15)') - eq({'notification', 'event1', {13, 14, 15}}, next_message()) + eq({'notification', 'event1', {13, 14, 15}}, next_msg()) end) it('does not crash for deeply nested variable', function() @@ -42,7 +42,7 @@ describe('notify', function() local nest_level = 1000 meths.command(('call map(range(%u), "extend(g:, {\'l\': [g:l]})")'):format(nest_level - 1)) eval('rpcnotify('..channel..', "event", g:l)') - local msg = next_message() + local msg = next_msg() eq('notification', msg[1]) eq('event', msg[2]) local act_ret = msg[3] diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 37ac532d18..18229b54ff 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -6,7 +6,7 @@ local Paths = require('test.config.paths') local clear, nvim, eval = helpers.clear, helpers.nvim, helpers.eval local eq, neq, run, stop = helpers.eq, helpers.neq, helpers.run, helpers.stop local nvim_prog, command, funcs = helpers.nvim_prog, helpers.command, helpers.funcs -local source, next_message = helpers.source, helpers.next_message +local source, next_msg = helpers.source, helpers.next_msg local ok = helpers.ok local meths = helpers.meths local spawn, nvim_argv = helpers.spawn, helpers.nvim_argv @@ -258,12 +258,12 @@ describe('server -> client', function() it('rpc and text stderr can be combined', function() eq("ok",funcs.rpcrequest(jobid, "poll")) funcs.rpcnotify(jobid, "ping") - eq({'notification', 'pong', {}}, next_message()) + eq({'notification', 'pong', {}}, next_msg()) eq("done!",funcs.rpcrequest(jobid, "write_stderr", "fluff\n")) - eq({'notification', 'stderr', {0, {'fluff', ''}}}, next_message()) + eq({'notification', 'stderr', {0, {'fluff', ''}}}, next_msg()) funcs.rpcrequest(jobid, "exit") - eq({'notification', 'stderr', {0, {''}}}, next_message()) - eq({'notification', 'exit', {0, 0}}, next_message()) + eq({'notification', 'stderr', {0, {''}}}, next_msg()) + eq({'notification', 'exit', {0, 0}}, next_msg()) end) end) -- cgit From dbad797edd4636f830abd7ade1138a1a27ac30d2 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 11 Mar 2018 21:47:12 +0100 Subject: API: nvim_get_proc_children() ref https://github.com/libuv/libuv/pull/836 --- test/functional/api/proc_spec.lua | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 test/functional/api/proc_spec.lua (limited to 'test/functional/api') diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua new file mode 100644 index 0000000000..eee54f9465 --- /dev/null +++ b/test/functional/api/proc_spec.lua @@ -0,0 +1,53 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear, eq = helpers.clear, helpers.eq +local funcs = helpers.funcs +local nvim_argv = helpers.nvim_argv +local request = helpers.request +local retry = helpers.retry + +describe('api', function() + before_each(clear) + + describe('nvim_get_proc_children', function() + it('returns child process ids', function() + local this_pid = funcs.getpid() + + local job1 = funcs.jobstart(nvim_argv) + retry(nil, nil, function() + eq(1, #request('nvim_get_proc_children', this_pid)) + end) + + local job2 = funcs.jobstart(nvim_argv) + retry(nil, nil, function() + eq(2, #request('nvim_get_proc_children', this_pid)) + end) + + funcs.jobstop(job1) + retry(nil, nil, function() + eq(1, #request('nvim_get_proc_children', this_pid)) + end) + + funcs.jobstop(job2) + retry(nil, nil, function() + eq(0, #request('nvim_get_proc_children', this_pid)) + end) + end) + + it('validates input', function() + local status, rv = pcall(request, "nvim_get_proc_children", -1) + eq(false, status) + eq("Invalid pid: -1", string.match(rv, "Invalid.*")) + + status, rv = pcall(request, "nvim_get_proc_children", 0) + eq(false, status) + eq("Invalid pid: 0", string.match(rv, "Invalid.*")) + + -- Assume PID 99999999 does not exist. + status, rv = pcall(request, "nvim_get_proc_children", 99999999) + eq(true, status) + eq({}, rv) + end) + end) + +end) -- cgit From a034d4b69d6032b3431c10b8a11c998551700fc2 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 16 Mar 2018 05:13:38 +0100 Subject: API: nvim_get_proc() TODO: "exepath" field (win32: QueryFullProcessImageName()) On unix-likes `ps` is used because the platform-specific APIs are a nightmare. For reference, below is a (incomplete) attempt: diff --git a/src/nvim/os/process.c b/src/nvim/os/process.c index 09769925aca5..99afbbf290c1 100644 --- a/src/nvim/os/process.c +++ b/src/nvim/os/process.c @@ -208,3 +210,60 @@ int os_proc_children(int ppid, int **proc_list, size_t *proc_count) return 0; } +/// Gets various properties of the process identified by `pid`. +/// +/// @param pid Process to inspect. +/// @return Map of process properties, empty on error. +Dictionary os_proc_info(int pid) +{ + Dictionary pinfo = ARRAY_DICT_INIT; +#ifdef WIN32 + +#elif defined(__APPLE__) + char buf[PROC_PIDPATHINFO_MAXSIZE]; + if (proc_pidpath(pid, buf, sizeof(buf))) { + name = getName(buf); + PUT(pinfo, "exepath", STRING_OBJ(cstr_to_string(buf))); + return name; + } else { + ILOG("proc_pidpath() failed for pid: %d", pid); + } +#elif defined(BSD) +# if defined(__FreeBSD__) +# define KP_COMM(o) o.ki_comm +# else +# define KP_COMM(o) o.p_comm +# endif + struct kinfo_proc *proc = kinfo_getproc(pid); + if (proc) { + PUT(pinfo, "name", cstr_to_string(KP_COMM(proc))); + xfree(proc); + } else { + ILOG("kinfo_getproc() failed for pid: %d", pid); + } + +#elif defined(__linux__) + char fname[256] = { 0 }; + char buf[MAXPATHL]; + snprintf(fname, sizeof(fname), "/proc/%d/comm", pid); + FILE *fp = fopen(fname, "r"); + // FileDescriptor *f = file_open_new(&error, fname, kFileReadOnly, 0); + // ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, + // const size_t size) + if (fp == NULL) { + ILOG("fopen() of /proc/%d/comm failed", pid); + } else { + size_t n = fread(buf, sizeof(char), sizeof(buf) - 1, fp); + if (n == 0) { + WLOG("fread() of /proc/%d/comm failed", pid); + } else { + size_t end = MIN(sizeof(buf) - 1, n); + end = (end > 0 && buf[end - 1] == '\n') ? end - 1 : end; + buf[end] = '\0'; + PUT(pinfo, "name", STRING_OBJ(cstr_to_string(buf))); + } + } + fclose(fp); +#endif + return pinfo; +} --- test/functional/api/proc_spec.lua | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua index eee54f9465..d99c26b6c2 100644 --- a/test/functional/api/proc_spec.lua +++ b/test/functional/api/proc_spec.lua @@ -1,10 +1,14 @@ local helpers = require('test.functional.helpers')(after_each) -local clear, eq = helpers.clear, helpers.eq +local clear = helpers.clear +local eq = helpers.eq local funcs = helpers.funcs +local iswin = helpers.iswin local nvim_argv = helpers.nvim_argv +local ok = helpers.ok local request = helpers.request local retry = helpers.retry +local NIL = helpers.NIL describe('api', function() before_each(clear) @@ -43,11 +47,35 @@ describe('api', function() eq(false, status) eq("Invalid pid: 0", string.match(rv, "Invalid.*")) - -- Assume PID 99999999 does not exist. - status, rv = pcall(request, "nvim_get_proc_children", 99999999) + -- Assume PID 99999 does not exist. + status, rv = pcall(request, "nvim_get_proc_children", 99999) eq(true, status) eq({}, rv) end) end) + describe('nvim_get_proc', function() + it('returns process info', function() + local pid = funcs.getpid() + local pinfo = request('nvim_get_proc', pid) + eq((iswin() and 'nvim.exe' or 'nvim'), pinfo.name) + ok(pinfo.pid == pid) + ok(type(pinfo.ppid) == 'number' and pinfo.ppid ~= pid) + end) + + it('validates input', function() + local status, rv = pcall(request, "nvim_get_proc", -1) + eq(false, status) + eq("Invalid pid: -1", string.match(rv, "Invalid.*")) + + status, rv = pcall(request, "nvim_get_proc", 0) + eq(false, status) + eq("Invalid pid: 0", string.match(rv, "Invalid.*")) + + -- Assume PID 99999 does not exist. + status, rv = pcall(request, "nvim_get_proc", 99999) + eq(true, status) + eq(NIL, rv) + end) + end) end) -- cgit From 8d5a46e77b1e0c77296f1d0d192e7906dd37c0d7 Mon Sep 17 00:00:00 2001 From: Nimit Bhardwaj Date: Wed, 28 Feb 2018 22:11:37 +0530 Subject: TUI: implement "standout" attribute #8081 closes #8054 --- test/functional/api/highlight_spec.lua | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index 2297a0760f..fed53a3dfd 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -99,5 +99,14 @@ describe('highlight api',function() eq(false, err) eq('Invalid highlight name: ', string.match(emsg, 'Invalid.*')) + + -- Test "standout" attribute. #8054 + eq({ underline = true, }, + meths.get_hl_by_name('cursorline', 0)); + command('hi CursorLine cterm=standout,underline term=standout,underline gui=standout,underline') + command('set cursorline') + eq({ underline = true, standout = true, }, + meths.get_hl_by_name('cursorline', 0)); + end) end) -- cgit