Skip to content

Commit 5ac5752

Browse files
committed
fix: several improvements to funcrefs
1 parent e1b39c3 commit 5ac5752

21 files changed

+166
-50
lines changed

crates/vim9-gen/src/call_expr.rs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -263,26 +263,18 @@ pub fn generate(call: &CallExpression, state: &mut State) -> String {
263263
}
264264
FunctionData::VimFuncRef { name, arglist, .. } => match arglist {
265265
Some(arglist) => {
266+
let arglist = arglist.gen(state);
267+
let name = name.gen(state);
268+
269+
// TODO: How does vim9script handle mutability for funcrefs
270+
// and their args? If you pass a list, does it let you mutate
271+
// that list and the next call it changes? probably yes...
266272
format!(
267273
r#"
268-
function(...)
269-
local copied = vim.deepcopy({})
270-
for _, val in ipairs({{...}}) do
271-
table.insert(copied, val)
272-
end
273-
274-
local funcref = {}
275-
if type(funcref) == "function" then
276-
return funcref(unpack(copied))
277-
elseif type(funcref) == "string" then
278-
return vim.fn[funcref](unpack(copied))
279-
else
280-
error(string.format("unable to call funcref: %s", funcref))
281-
end
282-
end
283-
"#,
284-
arglist.gen(state),
285-
name.gen(state)
274+
function(...)
275+
return vim9.fn_ref(M, {name}, vim.deepcopy({arglist}), ...)
276+
end
277+
"#,
286278
)
287279
}
288280
None => {

crates/vim9-gen/src/lib.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,7 +1684,7 @@ fn toplevel_ident(s: &mut State, command: &ExCommand) -> Option<String> {
16841684
mod generate_program {
16851685
use super::*;
16861686

1687-
pub fn preamble(state: &State, output: &mut Output) {
1687+
pub fn preamble(_: &State, output: &mut Output) {
16881688
output.write_lua(
16891689
r#"
16901690
----------------------------------------
@@ -1697,12 +1697,9 @@ mod generate_program {
16971697
-- luacheck: ignore 311
16981698
16991699
local vim9 = require('_vim9script')
1700+
local M = {}
17001701
"#,
17011702
);
1702-
1703-
if state.opts.mode != ParserMode::Test {
1704-
output.write_lua("local M = {}\n");
1705-
}
17061703
}
17071704

17081705
// "hoist" top-level declaractions to top of program, to ensure proper names
@@ -1752,6 +1749,7 @@ let s:nvim_module = luaeval('require("_vim9script").autoload(_A)', s:lua_path)
17521749
}
17531750

17541751
output.write_lua("end)");
1752+
output.write_lua("return M");
17551753
}
17561754
}
17571755

crates/vim9-gen/src/lua/init.lua

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,29 @@ M.ternary = function(cond, if_true, if_false)
1616
end
1717
end
1818

19+
M.fn_ref = function(module, name, copied, ...)
20+
for _, val in ipairs({ ... }) do
21+
table.insert(copied, val)
22+
end
23+
24+
local funcref = name
25+
if type(funcref) == 'function' then
26+
return funcref(unpack(copied))
27+
elseif type(funcref) == 'string' then
28+
if vim.fn.exists('*' .. funcref) == 1 then
29+
return vim.fn[funcref](unpack(copied))
30+
end
31+
32+
if module[funcref] then
33+
module[funcref](unpack(copied))
34+
end
35+
36+
error('unknown function: ' .. funcref)
37+
else
38+
error(string.format('unable to call funcref: %s', funcref))
39+
end
40+
end
41+
1942
M.fn_mut = function(name, args, info)
2043
local result = vim.fn._Vim9ScriptFn(name, args)
2144
for idx, val in pairs(result[2]) do

crates/vim9-gen/testdata/busted/function.vim

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,30 @@ def Test_insert_inplace()
3838
reverse(sort(foo))
3939
assert_equal([3, 2, 1], foo)
4040
enddef
41+
42+
def Test_can_do_funcref()
43+
def MyDoubler(x: number): number
44+
return x * 2
45+
enddef
46+
47+
var Doubler = function(MyDoubler, [1])
48+
assert_equal(Doubler(), 2)
49+
enddef
50+
51+
def Test_can_do_str_for_vimfuncs()
52+
var Lengther = function('len', ['foo'])
53+
assert_equal(Lengther(), 3)
54+
enddef
55+
56+
57+
# Can't do this yet
58+
# def Test_can_do_forward_funcref()
59+
# var something = 'MyDoubler'
60+
# var StrDoubler = function(something, [1])
61+
#
62+
# def MyDoubler(x: number): number
63+
# return x *2
64+
# enddef
65+
#
66+
# assert_equal(StrDoubler(), 2)
67+
# enddef

crates/vim9-gen/testdata/output/busted_assign.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
-- luacheck: ignore 311
99

1010
local vim9 = require('_vim9script')
11+
local M = {}
1112
describe('filename', function()
1213
-- vim9script
1314

@@ -129,3 +130,4 @@ describe('filename', function()
129130
assert.are.same({}, vim.v.errors)
130131
end)
131132
end)
133+
return M

crates/vim9-gen/testdata/output/busted_defer.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
-- luacheck: ignore 311
99

1010
local vim9 = require('_vim9script')
11+
local M = {}
1112
local MyDefer = nil
1213
local RangeDefer = nil
1314
describe('filename', function()
@@ -105,3 +106,4 @@ describe('filename', function()
105106
assert.are.same({}, vim.v.errors)
106107
end)
107108
end)
109+
return M

crates/vim9-gen/testdata/output/busted_function.lua

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
-- luacheck: ignore 311
99

1010
local vim9 = require('_vim9script')
11+
local M = {}
1112
describe('filename', function()
1213
-- vim9script
1314

@@ -79,4 +80,52 @@ describe('filename', function()
7980
-- Assert that errors is still empty
8081
assert.are.same({}, vim.v.errors)
8182
end)
83+
84+
it('Test_can_do_funcref', function()
85+
-- Set errors to empty
86+
vim.v.errors = {}
87+
88+
-- Actual test
89+
90+
local MyDoubler = function(x)
91+
return vim9.ops.Multiply(x, 2)
92+
end
93+
94+
local Doubler = function(...)
95+
return vim9.fn_ref(M, MyDoubler, vim.deepcopy({ 1 }), ...)
96+
end
97+
98+
vim9.fn.assert_equal(Doubler(), 2)
99+
100+
-- Assert that errors is still empty
101+
assert.are.same({}, vim.v.errors)
102+
end)
103+
104+
it('Test_can_do_str_for_vimfuncs', function()
105+
-- Set errors to empty
106+
vim.v.errors = {}
107+
108+
-- Actual test
109+
local Lengther = function(...)
110+
return vim9.fn_ref(M, 'len', vim.deepcopy({ 'foo' }), ...)
111+
end
112+
113+
vim9.fn.assert_equal(Lengther(), 3)
114+
115+
-- Assert that errors is still empty
116+
assert.are.same({}, vim.v.errors)
117+
end)
118+
119+
-- # Can't do this yet
120+
-- # def Test_can_do_forward_funcref()
121+
-- # var something = 'MyDoubler'
122+
-- # var StrDoubler = function(something, [1])
123+
-- #
124+
-- # def MyDoubler(x: number): number
125+
-- # return x *2
126+
-- # enddef
127+
-- #
128+
-- # assert_equal(StrDoubler(), 2)
129+
-- # enddef
82130
end)
131+
return M

crates/vim9-gen/testdata/output/busted_heredoc.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
-- luacheck: ignore 311
99

1010
local vim9 = require('_vim9script')
11+
local M = {}
1112
describe('filename', function()
1213
-- vim9script
1314

@@ -72,3 +73,4 @@ describe('filename', function()
7273
-- # assert_equal([" "hello"", " world"], x)
7374
-- # enddef
7475
end)
76+
return M

crates/vim9-gen/testdata/output/busted_indexing.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
-- luacheck: ignore 311
99

1010
local vim9 = require('_vim9script')
11+
local M = {}
1112
local l = nil
1213
describe('filename', function()
1314
-- vim9script
@@ -104,3 +105,4 @@ describe('filename', function()
104105
assert.are.same({}, vim.v.errors)
105106
end)
106107
end)
108+
return M

crates/vim9-gen/testdata/output/busted_loops.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
-- luacheck: ignore 311
99

1010
local vim9 = require('_vim9script')
11+
local M = {}
1112
describe('filename', function()
1213
-- vim9script
1314

@@ -158,3 +159,4 @@ describe('filename', function()
158159
assert.are.same({}, vim.v.errors)
159160
end)
160161
end)
162+
return M

0 commit comments

Comments
 (0)