Compare commits

...

23 Commits

Author SHA1 Message Date
f2460a3aec patch 8.2.0229: compare instructions not tested
Problem:    Compare instructions not tested.
Solution:   Add test cases.  Fix disassemble with line continuation.
2020-02-07 22:09:54 +01:00
348808f7c0 patch 8.2.0228: configure does not recognize gcc version on BSD
Problem:    Configure does not recognize gcc version on BSD.
Solution:   Do not use "\+" in the pattern matching the version number. (Ozaki
            Kiichi, closes #5590)
2020-02-07 20:50:07 +01:00
c2a4b35b86 patch 8.2.0227: compiling a few instructions not tested
Problem:    Compiling a few instructions not tested.
Solution:   Add more test cases.
2020-02-06 22:41:16 +01:00
04d0522046 patch 8.2.0226: compiling for loop not tested
Problem:    Compiling for loop not tested.
Solution:   Add a test.  Make variable initialization work for more types.
2020-02-06 22:06:54 +01:00
777770fbb0 patch 8.2.0225: compiling lambda not tested yet
Problem:    compiling lambda not tested yet.
Solution:   Add test for lambda and funcref. Drop unused instruction arg.
2020-02-06 21:27:08 +01:00
158906cffc patch 8.2.0224: compiling :elseif not tested yet
Problem:    compiling :elseif not tested yet.
Solution:   Add test for :elseif.  Fix generating jumps.
2020-02-06 20:39:45 +01:00
5cab73f8cc patch 8.2.0223: some instructions not yet tested
Problem:    Some instructions not yet tested.
Solution:   Disassemble more instructions.  Move tests to a new file.  Compile
            call to s:function().
2020-02-06 19:25:19 +01:00
170fcfcf25 patch 8.2.0222: Vim9: optional function arguments don't work yet
Problem:    Vim9: optional function arguments don't work yet.
Solution:   Implement optional function arguments.
2020-02-06 17:51:35 +01:00
6e587dcbf3 patch 8.2.0221: no test for Vim9 += and ..=
Problem:    No test for Vim9 += and ..=.
Solution:   Add tests.
2020-02-06 13:15:52 +01:00
1af5ce01c3 patch 8.2.0220: terminal test did pass on Mac
Problem:    Terminal test did pass on Mac.
Solution:   Remove the skip again.
2020-02-06 11:54:35 +01:00
4af11174f7 patch 8.2.0219: terminal test still fails on Mac
Problem:    Terminal test still fails on Mac.
Solution:   Skip part of the test on Mac.
2020-02-05 23:01:34 +01:00
0de50864a7 patch 8.2.0218: several Vim9 instructions are not tested
Problem:    Several Vim9 instructions are not tested.
Solution:   Add more tests.
2020-02-05 22:55:48 +01:00
adbc11c2ee patch 8.2.0217: terminal test fails on Mac
Problem:    Terminal test fails on Mac.
Solution:   Add a short wait.
2020-02-05 22:21:08 +01:00
ff80cb6807 patch 8.2.0216: several Vim9 instructions are not tested
Problem:    Several Vim9 instructions are not tested.
Solution:   Add more tests. Fix :disassamble output. Make catch with pattern
            work.
2020-02-05 22:10:05 +01:00
a78e9c61a0 patch 8.2.0215: wrong file name shortening
Problem:    Wrong file name shortening. (Ingo Karkat)
Solution:   Better check for path separator. (Yasuhiro Matsumoto,
            closes #5583, closes #5584)
2020-02-05 21:14:00 +01:00
2e6638d5f0 patch 8.2.0214: a popup window with a terminal can be made hidden
Problem:    A popup window with a terminal can be made hidden.
Solution:   Disallow hiding a terminal popup.
2020-02-05 21:07:18 +01:00
7077892a79 patch 8.2.0213: configure does not recognize gcc 10.0 and later
Problem:    Configure does not recognize gcc 10.0 and later.
Solution:   Adjust the pattern matching the version number. (Sergei
            Trofimovich, closes #5580)
2020-02-05 20:44:24 +01:00
07ada5ff2f patch 8.2.0212: missing search/substitute pattern hardly tested
Problem:    Missing search/substitute pattern hardly tested.
Solution:   Add test_clear_search_pat() and tests. (Yegappan Lakshmanan,
            closes #5579)
2020-02-05 20:38:22 +01:00
94255df057 patch 8.2.0211: test for ANSI colors fails without an "ls" command
Problem:    Test for ANSI colors fails without an "ls" command.
Solution:   Use "dir". (Ken Takata, closes #5582)
2020-02-05 20:10:33 +01:00
eed3571fe0 patch 8.2.0210: Coverity complains about uninitialized field
Problem:    Coverity complains about uninitialized field.
Solution:   Initialize the field.
2020-02-04 23:08:14 +01:00
560979ed4f Update runtime files. 2020-02-04 22:53:05 +01:00
80147dda4f patch 8.2.0209: function a bit far away from where it's used
Problem:    Function a bit far away from where it's used.
Solution:   Move function close to where it's used. (Ken Takata, closes #5569)
2020-02-04 22:32:59 +01:00
d816cd94d8 patch 8.2.0208: fnamemodify() does not apply ":~" when followed by ":."
Problem:    Fnamemodify() does not apply ":~" when followed by ":.".
Solution:   Don't let a failing ":." cause the ":~" to be skipped. (Yasuhiro
            Matsumoto, closes #5577)
2020-02-04 22:23:09 +01:00
50 changed files with 1282 additions and 313 deletions

View File

@ -1,4 +1,4 @@
*autocmd.txt* For Vim version 8.2. Last change: 2020 Jan 17
*autocmd.txt* For Vim version 8.2. Last change: 2020 Jan 26
VIM REFERENCE MANUAL by Bram Moolenaar

View File

@ -933,8 +933,7 @@ These modifiers can be given, in this order:
directory.
:. Reduce file name to be relative to current directory, if
possible. File name is unmodified if it is not below the
current directory, but on MS-Windows the drive is removed if
it is the current drive.
current directory.
For maximum shortness, use ":~:.".
:h Head of the file name (the last component and any separators
removed). Cannot be used with :e, :r or :t.

View File

@ -1,4 +1,4 @@
*eval.txt* For Vim version 8.2. Last change: 2020 Jan 19
*eval.txt* For Vim version 8.2. Last change: 2020 Feb 03
VIM REFERENCE MANUAL by Bram Moolenaar
@ -1808,7 +1808,9 @@ v:errors Errors found by assert functions, such as |assert_true()|.
*v:event* *event-variable*
v:event Dictionary containing information about the current
|autocommand|. The dictionary is emptied when the |autocommand|
|autocommand|. See the specific event for what it puts in
this dictionary.
The dictionary is emptied when the |autocommand|
finishes, please refer to |dict-identity| for how to get an
independent copy of it.
@ -2846,6 +2848,7 @@ term_wait({buf} [, {time}]) Number wait for screen to be updated
test_alloc_fail({id}, {countdown}, {repeat})
none make memory allocation fail
test_autochdir() none enable 'autochdir' during startup
test_clear_search_pat() none clears the last used search pattern
test_feedinput({string}) none add key sequence to input buffer
test_garbagecollect_now() none free memory right now for testing
test_garbagecollect_soon() none free memory soon for testing
@ -3455,6 +3458,7 @@ chdir({dir}) *chdir()*
directory (|:tcd|) then changes the tabpage local
directory.
- Otherwise, changes the global directory.
{dir} must be a String.
If successful, returns the previous working directory. Pass
this to another chdir() to restore the directory.
On failure, returns an empty string.
@ -5664,7 +5668,7 @@ getwininfo([{winid}]) *getwininfo()*
GetWinnr()->getwininfo()
getwinpos([{timeout}]) *getwinpos()*
The result is a list with two numbers, the result of
The result is a List with two numbers, the result of
|getwinposx()| and |getwinposy()| combined:
[x-pos, y-pos]
{timeout} can be used to specify how long to wait in msec for
@ -10461,6 +10465,7 @@ winline() The result is a Number, which is the screen line of the cursor
*winnr()*
winnr([{arg}]) The result is a Number, which is the number of the current
window. The top window has number 1.
Returns zero for a popup window.
The optional argument {arg} supports the following values:
$ the number of the last window (the window

View File

@ -1,4 +1,4 @@
*insert.txt* For Vim version 8.2. Last change: 2020 Jan 04
*insert.txt* For Vim version 8.2. Last change: 2020 Jan 26
VIM REFERENCE MANUAL by Bram Moolenaar
@ -1079,7 +1079,8 @@ If you want to suppress the warning message for an empty result, return
Other items are ignored.
For acting upon end of completion, see the |CompleteDone| autocommand event.
For acting upon end of completion, see the |CompleteDonePre| and
|CompleteDone| autocommand event.
For example, the function can contain this: >
let matches = ... list of words ...

View File

@ -1,4 +1,4 @@
*popup.txt* For Vim version 8.2. Last change: 2019 Nov 30
*popup.txt* For Vim version 8.2. Last change: 2020 Feb 03
VIM REFERENCE MANUAL by Bram Moolenaar
@ -11,6 +11,7 @@ Displaying text in a floating window. *popup* *popup-window* *popupwin*
Window position and size |popup-position|
Closing the popup window |popup-close|
Popup buffer and window |popup-buffer|
Terminal in popup window |popup-terminal|
2. Functions |popup-functions|
Details |popup-function-details|
3. Usage |popup-usage|
@ -140,6 +141,22 @@ And options can be set on the buffer with `setbufvar()`, e.g.: >
You can also use `win_execute()` with a ":setlocal" command.
TERMINAL IN POPUP WINDOW *popup-terminal*
A special case is running a terminal in a popup window. Many rules are then
different: *E863*
- The popup window always has focus, it is not possible to switch to another
window.
- When the job ends, the popup window closes.
- The default Pmenu color is only used for the border and padding. To change
the color of the terminal itself set 'wincolor'.
To run a terminal in a popup window, first create the terminal hidden. Then
pass the buffer number to popup_create(). Example: >
let buf = term_start(['picker', 'Something'], #{hidden: 1, term_finish: 'close'})
let winid = popup_create(buf, #{minwidth: 50, minheight: 20})
set wincolor=Search
==============================================================================
2. Functions *popup-functions*

View File

@ -2313,6 +2313,7 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX*
:debug-name repeat.txt /*:debug-name*
:debugg repeat.txt /*:debugg*
:debuggreedy repeat.txt /*:debuggreedy*
:def vim9.txt /*:def*
:del change.txt /*:del*
:delc map.txt /*:delc*
:delcommand map.txt /*:delcommand*
@ -2384,6 +2385,7 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX*
:emenu gui.txt /*:emenu*
:en eval.txt /*:en*
:end eval.txt /*:end*
:enddef vim9.txt /*:enddef*
:endf eval.txt /*:endf*
:endfo eval.txt /*:endfo*
:endfor eval.txt /*:endfor*
@ -2404,6 +2406,8 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX*
:execute eval.txt /*:execute*
:exi editing.txt /*:exi*
:exit editing.txt /*:exit*
:exp vim9.txt /*:exp*
:export vim9.txt /*:export*
:exu helphelp.txt /*:exu*
:exusage helphelp.txt /*:exusage*
:f editing.txt /*:f*
@ -2506,6 +2510,9 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX*
:imapclear map.txt /*:imapclear*
:ime gui.txt /*:ime*
:imenu gui.txt /*:imenu*
:imp vim9.txt /*:imp*
:import vim9.txt /*:import*
:import-cycle vim9.txt /*:import-cycle*
:in insert.txt /*:in*
:index index.txt /*:index*
:ino map.txt /*:ino*
@ -3354,6 +3361,8 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX*
:vie editing.txt /*:vie*
:view editing.txt /*:view*
:vim quickfix.txt /*:vim*
:vim9 vim9.txt /*:vim9*
:vim9script vim9.txt /*:vim9script*
:vimgrep quickfix.txt /*:vimgrep*
:vimgrepa quickfix.txt /*:vimgrepa*
:vimgrepadd quickfix.txt /*:vimgrepadd*
@ -3834,6 +3843,7 @@ Command-line cmdline.txt /*Command-line*
Command-line-mode cmdline.txt /*Command-line-mode*
CompleteChanged autocmd.txt /*CompleteChanged*
CompleteDone autocmd.txt /*CompleteDone*
CompleteDonePre autocmd.txt /*CompleteDonePre*
ConPTY terminal.txt /*ConPTY*
Contents quickref.txt /*Contents*
Cscope if_cscop.txt /*Cscope*
@ -4661,6 +4671,7 @@ E858 eval.txt /*E858*
E859 eval.txt /*E859*
E86 windows.txt /*E86*
E862 eval.txt /*E862*
E863 popup.txt /*E863*
E864 pattern.txt /*E864*
E865 pattern.txt /*E865*
E866 pattern.txt /*E866*
@ -6276,6 +6287,7 @@ faq intro.txt /*faq*
farsi farsi.txt /*farsi*
farsi.txt farsi.txt /*farsi.txt*
fasm.vim syntax.txt /*fasm.vim*
fast-functions vim9.txt /*fast-functions*
fcs_choice-variable eval.txt /*fcs_choice-variable*
fcs_reason-variable eval.txt /*fcs_reason-variable*
feature-list eval.txt /*feature-list*
@ -8315,6 +8327,7 @@ popup-menu-added version5.txt /*popup-menu-added*
popup-position popup.txt /*popup-position*
popup-props popup.txt /*popup-props*
popup-scrollbar popup.txt /*popup-scrollbar*
popup-terminal popup.txt /*popup-terminal*
popup-textprop-pos popup.txt /*popup-textprop-pos*
popup-usage popup.txt /*popup-usage*
popup-window popup.txt /*popup-window*
@ -9544,6 +9557,7 @@ tutor usr_01.txt /*tutor*
twice if_cscop.txt /*twice*
two-engines pattern.txt /*two-engines*
type() eval.txt /*type()*
type-inference vim9.txt /*type-inference*
type-mistakes tips.txt /*type-mistakes*
typecorr-settings usr_41.txt /*typecorr-settings*
typecorr.txt usr_41.txt /*typecorr.txt*
@ -9907,6 +9921,14 @@ vim-variable eval.txt /*vim-variable*
vim.vim syntax.txt /*vim.vim*
vim7 version7.txt /*vim7*
vim8 version8.txt /*vim8*
vim9-differences vim9.txt /*vim9-differences*
vim9-export vim9.txt /*vim9-export*
vim9-import vim9.txt /*vim9-import*
vim9-rationale vim9.txt /*vim9-rationale*
vim9-script vim9.txt /*vim9-script*
vim9-types vim9.txt /*vim9-types*
vim9.txt vim9.txt /*vim9.txt*
vim9script vim9.txt /*vim9script*
vim: options.txt /*vim:*
vim_announce intro.txt /*vim_announce*
vim_dev intro.txt /*vim_dev*

View File

@ -1,4 +1,4 @@
*tagsrch.txt* For Vim version 8.2. Last change: 2019 Dec 27
*tagsrch.txt* For Vim version 8.2. Last change: 2020 Jan 30
VIM REFERENCE MANUAL by Bram Moolenaar
@ -903,8 +903,8 @@ The following is a hypothetical example of a function used for 'tagfunc'. It
uses the output of |taglist()| to generate the result: a list of tags in the
inverse order of file names.
>
function! TagFunc(pattern, flags, info)
function! CompareFilenames(item1, item2)
function TagFunc(pattern, flags, info)
function CompareFilenames(item1, item2)
let f1 = a:item1['filename']
let f2 = a:item2['filename']
return f1 >=# f2 ?

View File

@ -1,4 +1,4 @@
*terminal.txt* For Vim version 8.2. Last change: 2020 Jan 04
*terminal.txt* For Vim version 8.2. Last change: 2020 Jan 30
VIM REFERENCE MANUAL by Bram Moolenaar
@ -1025,7 +1025,7 @@ Writing a screen dump test for Vim ~
For an example see the Test_syntax_c() function in
src/testdir/test_syntax.vim. The main parts are:
- Write a file you want to test with. This is useful for testing syntax
highlighting. You can also start Vim with en empty buffer.
highlighting. You can also start Vim with an empty buffer.
- Run Vim in a terminal with a specific size. The default is 20 lines of 75
characters. This makes sure the dump is always this size. The function
RunVimInTerminal() takes care of this. Pass it the arguments for the Vim

View File

@ -52,6 +52,11 @@ test_autochdir() *test_autochdir()*
startup has finished.
test_clear_search_pat() *test_clear_search_pat()*
Clears the last used search pattern (|/|) and the substitute
pattern (|:s|). This is useful for testing conditions where
these patterns are not set previously.
test_feedinput({string}) *test_feedinput()*
Characters in {string} are queued for processing as if they
were typed by the user. This uses a low level input buffer.

View File

@ -1,4 +1,4 @@
*todo.txt* For Vim version 8.2. Last change: 2020 Jan 23
*todo.txt* For Vim version 8.2. Last change: 2020 Feb 04
VIM REFERENCE MANUAL by Bram Moolenaar
@ -40,10 +40,44 @@ browser use: https://github.com/vim/vim/issues/1234
Include ipv6 syntax changes? (DJ Lucas, #5360)
Add win_type(), which "popup" and "cmdline" as values?
Vim9 script:
- test s:var += 'some'
test exported += 'some'
- implement default values for optional arguments
Generate instructions at start of function, skip over if argument provided?
- Disallow unlet for local/script/imported vars
- :func inside vim9script must still use a:arg
- Check that import in legacy script works and puts item in s:
- Error in any command in "vim9script" aborts sourcing.
- Find a way to test expressions in legacy and Vim9 script without duplication
- Test each level of expressions properly, with type checking
- Test the
- Test try/catch and throw better, also nested.
Test return inside try/finally jumps to finally and then returns.
- call autoload function.
- Type checking arguments when calling :def function
- can use func as reference:
def SomeFunc() ...
map(list, SomeFunc)
- define function and create funcref in one step:
let ref = def(arg: type): rettype
Also extends lambda
- Test: Function declared inside a :def function is local, disappears at the
end of the function. Unless g: is used, just like with variables.
- Can we omit \ for line continuation inside (), {}, ?
Requires parsing while reading a function. Like fgetline in do_one_cmd()?
- implement :type
- implement class
- implement interface
- predefined class: Promise<T>
- import statement for type declaration?
- Make accessing varargs faster: arg[expr]
EVAL expr
LOADVARARG (varags idx)
Popup windows:
- Make it possible to put a terminal window in a popup. Would always grab key
input? Sort-of possible by creating a hidden terminal and opening a popup
with that buffer: #4063.
- Use popup (or popup menu) for command line completion
- When using a popup for the info of a completion menu, and there is not
enough space, let the popup overlap with the menu. (#4544)
@ -55,6 +89,8 @@ Popup windows:
- Figure out the size and position better if wrapping inserts indent
Text properties:
- Combining text property with 'cursorline' does not always work (Billie
Cleek, #5533)
- Text properties spanning more than one line
- See remarks at top of src/textprop.c
@ -121,9 +157,8 @@ Terminal emulator window:
conversions.
Error numbers available:
E450, E451, E452,
E453, E454, E460, E489, E491, E565, E578, E610, E611, E653,
E654, E856, E857, E860, E861, E863, E889, E900
E451, E452, E453, E454, E460, E489, E491, E565, E578, E610, E611, E653,
E654, E856, E857, E860, E861, E900
Patch to move duplicated code to a function. (Yegappan Lakshmanan, #5330)
@ -142,16 +177,20 @@ Needs better docs. Is there a better name?
undo result wrong: Masato Nishihata, #4798
When 'lazyredraw' is set sometimes the title is not updated.
(Jason Franklin, 2020 Feb 3) Looks like a race condition.
Patch to add function to return the text used in the quickfix window.
(Yegappan, #5465)
Patch for Template string: #4491. New pull: #4634
Implementation is too inefficient, avoid using lambda.
Undo puts cursor in wrong line after "cG<Esc>" undo.
:unmap <c-n> gives error but does remove the mapping. (Antony Scriven, 2019
Dec 19)
Sound: support on Mac? Or does libcanberra work there?
Patch to fix session file when using multiple tab pages. (Jason Franklin, 2019
May 20)
Also put :argadd commands at the start for all buffers, so that their order
@ -194,6 +233,8 @@ Enable 'termbidi' if $VTE_VERSION >= 5703 ?
Universal solution to detect if t_RS is working, using cursor position.
Koichi Iwamoto, #2126
Sound: support on Mac? Or does libcanberra work there?
Python 3.8 doesn't work. (Antonios Hadjigeorgalis, #5509)
The :syntax cchar value can only be a single character. It would be useful to
@ -204,6 +245,8 @@ It can replace the BeOS code, which is likely not used anymore.
Now on github: #1856. Updated Oct 2017
Got permission to include this under the Vim license.
"--cleanFOO" does not result in an error. (#5537)
Add "t" action to settagstack(): truncate and add new entries. (#5405)
Result of synID() sometimes wrong in help files. (#5252)
@ -269,9 +312,6 @@ Patch by Alex Dobrynin, 2007 Jun 3. Also fixes other scroll wheel problems.
Add a WindowScrolled event. Trigger around the same time as CursorMoved.
Can be used to update highlighting. #3127 #5181
Patch for Template string: #4491. New pull: #4634
Implementation is too inefficient, avoid using lambda.
Incorrect formatting with autoindent. (Sebastian Gniazdowski, #4909)
Patch to add the :bvimgrep command. (Christian Brabandt, 2014 Nov 12)
@ -812,9 +852,6 @@ option_save({list}) *option_save()*
directory (Paulo Marcel Coelho Arabic, 2017 Oct 30, #2266)
Also see #1689.
crash when removing an element while inside map(). (Nikolai Pavlov, 2018 Feb
17, #2652)
When 'virtualedit' is "all" and 'cursorcolumn' is set, the wrong column may be
highlighted. (van-de-bugger, 2018 Jan 23, #2576)

View File

@ -963,6 +963,7 @@ Testing: *test-functions*
assert_report() report a test failure
test_alloc_fail() make memory allocation fail
test_autochdir() enable 'autochdir' during startup
test_clear_search_pat() clears the last used search pattern
test_override() test with Vim internal overrides
test_garbagecollect_now() free memory right now
test_getvalue() get value of an internal variable

View File

@ -1,4 +1,4 @@
*version8.txt* For Vim version 8.2. Last change: 2019 Dec 29
*version8.txt* For Vim version 8.2. Last change: 2020 Feb 04
VIM REFERENCE MANUAL by Bram Moolenaar
@ -306,7 +306,6 @@ New and extended functions: ~
|systemlist()| get the result of a shell command as a list
|test_alloc_fail()| make memory allocation fail
|test_autochdir()| test 'autochdir' functionality
test_disable_char_avail() test without typeahead (removed later)
|test_garbagecollect_now()| free memory right now
|test_null_channel()| return a null Channel
|test_null_dict()| return a null Dict

View File

@ -1,4 +1,4 @@
*vim9.txt* For Vim version 8.2. Last change: 2019 Dec 06
*vim9.txt* For Vim version 8.2. Last change: 2020 Jan 30
VIM REFERENCE MANUAL by Bram Moolenaar
@ -113,7 +113,7 @@ used: >
}
echo temp " Error!
An existing variable cannot be assigend to with `:let`, since that implies a
An existing variable cannot be assigned to with `:let`, since that implies a
declaration. An exception is global variables: these can be both used with
and without `:let`, because there is no rule about where they are declared.
@ -128,7 +128,7 @@ Omitting :call and :eval ~
Functions can be called without `:call`: >
writefile(lines, 'file')
Using `:call` is still posible, but this is discouraged.
Using `:call` is still possible, but this is discouraged.
A method call without `eval` is possible, so long as the start is an
identifier or can't be an Ex command. It does not work for string constants: >
@ -146,9 +146,14 @@ No curly braces expansion ~
|curly-braces-names| cannot be used.
Comperators ~
No :append, :change or :insert ~
The 'ignorecase' option is not used for comperators that use strings.
These commands are too quickly confused with local variable names.
Comparators ~
The 'ignorecase' option is not used for comparators that use strings.
White space ~
@ -242,6 +247,10 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
The second and third form are optional arguments.
When the caller omits an argument the {value} is used.
NOTE: It is possible to nest `:def` inside another
`:def`, but it is not possible to nest `:def` inside
`:function`, for backwards compatibility.
[!] is used as with `:function`.
*:enddef*
@ -325,7 +334,7 @@ items, can then be imported in another script.
Namespace ~
*:vim9script* *:vim9*
To recognize an file that can be imported the `vim9script` statement must
To recognize a file that can be imported the `vim9script` statement must
appear as the first statement in the file. It tells Vim to interpret the
script in its own namespace, instead of the global namespace. If a file
starts with: >
@ -371,7 +380,7 @@ The exported items can be imported individually in another Vim9 script: >
To import multiple items at the same time: >
import {someValue, MyClass} from "thatscript.vim"
In case the name is ambigiuous, another name can be specified: >
In case the name is ambiguous, another name can be specified: >
import MyClass as ThatClass from "myclass.vim"
import {someValue, MyClass as ThatClass} from "myclass.vim"
@ -404,7 +413,7 @@ result in undefined items.
Import in an autoload script ~
For optimal startup speed, loading scripts should be postponed until they are
actually needed. A recommended mechamism:
actually needed. A recommended mechanism:
1. In the plugin define user commands, functions and/or mappings that refer to
an autoload script. >
@ -445,7 +454,7 @@ script-local "s:" namespace will be used, even when "s:" is not specified.
The :def command ~
Plugin writers have asked for a much faster Vim script. Investigation have
shown that keeping the existing semantics of funtion calls make this close to
shown that keeping the existing semantics of function calls make this close to
impossible, because of the overhead involved with calling a function, setting
up the local function scope and executing lines. There are many details that
need to be handled, such as error messages and exceptions. The need to create
@ -483,7 +492,7 @@ JavaScript/TypeScript syntax and semantics ~
Script writers have complained that the Vim script syntax is unexpectedly
different from what they are used to. To reduce this complaint popular
languages will be used as an example. At the same time, we do not want to
abondon the well-known parts of legacy Vim script.
abandon the well-known parts of legacy Vim script.
Since Vim already uses `:let` and `:const` and optional type checking is
desirable, the JavaScript/TypeScript syntax fits best for variable

View File

@ -1,7 +1,7 @@
" Vim filetype plugin file
" Language: C
" Maintainer: Bram Moolenaar <Bram@vim.org>
" Last Change: 2017 Sep 28
" Last Change: 2020 Feb 01
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
@ -15,12 +15,16 @@ let b:did_ftplugin = 1
let s:cpo_save = &cpo
set cpo-=C
let b:undo_ftplugin = "setl fo< com< ofu< | if has('vms') | setl isk< | endif"
let b:undo_ftplugin = "setl fo< com< ofu< cms< def< inc< | if has('vms') | setl isk< | endif"
" Set 'formatoptions' to break comment lines but not other lines,
" and insert the comment leader when hitting <CR> or using "o".
setlocal fo-=t fo+=croql
" These options have the right value as default, but the user may have
" overruled that.
setlocal commentstring& define& include&
" Set completion with CTRL-X CTRL-O to autoloaded function.
if exists('&ofu')
setlocal ofu=ccomplete#Complete

View File

@ -3,7 +3,7 @@
" Maintainer: Nick Jensen <nickspoon@gmail.com>
" Former Maintainers: Anduin Withers <awithers@anduin.com>
" Johannes Zellner <johannes@zellner.org>
" Last Change: 2019-08-01
" Last Change: 2020-01-27
" Filenames: *.cs
" License: Vim (see :h license)
" Repository: https://github.com/nickspoons/vim-cs
@ -97,6 +97,8 @@ syn match csXmlComment "///.*$" contains=csXmlCommentLeader,@csXml,@Spell keepen
syn include @csXml syntax/xml.vim
hi def link xmlRegion Comment
" Since syntax/xml.vim contains `syn spell toplevel`, we need to set it back to `default` here.
syn spell default
" [1] 9.5 Pre-processing directives
syn region csPreCondit start="^\s*#\s*\(define\|undef\|if\|elif\|else\|endif\|line\|error\|warning\)" skip="\\$" end="$" contains=csComment keepend

View File

@ -3,7 +3,7 @@
" Maintainer: Debian Vim Maintainers
" Former Maintainers: Gerfried Fuchs <alfie@ist.org>
" Wichert Akkerman <wakkerma@debian.org>
" Last Change: 2019 Oct 20
" Last Change: 2020 Feb 02
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debchangelog.vim
" Standard syntax initialization
@ -24,7 +24,7 @@ let s:supported = [
\ 'wheezy', 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm',
\ 'sid', 'rc-buggy',
\
\ 'trusty', 'xenial', 'bionic', 'disco', 'eoan', 'focal', 'devel'
\ 'trusty', 'xenial', 'bionic', 'eoan', 'focal', 'devel'
\ ]
let s:unsupported = [
\ 'frozen', 'buzz', 'rex', 'bo', 'hamm', 'slink', 'potato',
@ -33,7 +33,8 @@ let s:unsupported = [
\ 'warty', 'hoary', 'breezy', 'dapper', 'edgy', 'feisty',
\ 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid',
\ 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy',
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic'
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic',
\ 'disco'
\ ]
let &cpo=s:cpo
@ -43,7 +44,7 @@ exe 'syn match debchangelogFirstKV contained "; \('.s:urgency.'\|'.s:binNMU.'\)"
exe 'syn match debchangelogOtherKV contained ", \('.s:urgency.'\|'.s:binNMU.'\)"'
exe 'syn match debchangelogTarget contained "\%( \%('.join(s:supported, '\|').'\)\>[-[:alnum:]]*\)\+"'
exe 'syn match debchangelogUnsupportedTarget contained "\%( \%('.join(s:unsupported, '\|').'\)\>[-[:alnum:]]*\)\+"'
syn keyword debchangelogUnreleased contained UNRELEASED
syn match debchangelogUnreleased contained / UNRELEASED/
syn match debchangelogVersion contained "(.\{-})"
syn match debchangelogCloses contained "closes:\_s*\(bug\)\=#\=\_s\=\d\+\(,\_s*\(bug\)\=#\=\_s\=\d\+\)*"
syn match debchangelogLP contained "\clp:\s\+#\d\+\(,\s*#\d\+\)*"

View File

@ -2,7 +2,7 @@
" Language: Debian sources.list
" Maintainer: Debian Vim Maintainers
" Former Maintainer: Matthijs Mohlmann <matthijs@cacholong.nl>
" Last Change: 2019 Oct 18
" Last Change: 2020 Feb 02
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debsources.vim
" Standard syntax initialization
@ -26,7 +26,7 @@ let s:supported = [
\ 'wheezy', 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm',
\ 'sid', 'rc-buggy',
\
\ 'trusty', 'xenial', 'bionic', 'disco', 'eoan', 'focal', 'devel'
\ 'trusty', 'xenial', 'bionic', 'eoan', 'focal', 'devel'
\ ]
let s:unsupported = [
\ 'buzz', 'rex', 'bo', 'hamm', 'slink', 'potato',
@ -35,7 +35,8 @@ let s:unsupported = [
\ 'warty', 'hoary', 'breezy', 'dapper', 'edgy', 'feisty',
\ 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid',
\ 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy',
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic'
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic',
\ 'disco'
\ ]
let &cpo=s:cpo

View File

@ -1,26 +1,45 @@
" dockerfile.vim - Syntax highlighting for Dockerfiles
" Maintainer: Honza Pokorny <https://honza.ca>
" Version: 0.6
" Last Change: 2019 Aug 16
" Last Change: 2020 Jan 27
" License: BSD
" https://docs.docker.com/engine/reference/builder/
if exists("b:current_syntax")
finish
endif
let b:current_syntax = "dockerfile"
syntax include @JSON syntax/json.vim
unlet b:current_syntax
syntax include @Shell syntax/sh.vim
unlet b:current_syntax
syntax case ignore
syntax match dockerfileLinePrefix /\v^\s*(ONBUILD\s+)?\ze\S/ contains=dockerfileKeyword nextgroup=dockerfileInstruction skipwhite
syntax region dockerfileFrom matchgroup=dockerfileKeyword start=/\v^\s*(FROM)\ze(\s|$)/ skip=/\v\\\_./ end=/\v((^|\s)AS(\s|$)|$)/ contains=dockerfileOption
syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|ARG|CMD|COPY|ENTRYPOINT|ENV|EXPOSE|FROM|HEALTHCHECK|LABEL|MAINTAINER|RUN|SHELL|STOPSIGNAL|USER|VOLUME|WORKDIR)\s/
syntax keyword dockerfileKeyword contained ADD ARG CMD COPY ENTRYPOINT ENV EXPOSE HEALTHCHECK LABEL MAINTAINER ONBUILD RUN SHELL STOPSIGNAL USER VOLUME WORKDIR
syntax match dockerfileOption contained /\v(^|\s)\zs--\S+/
syntax match dockerfileKeyword /\v(AS)/
syntax match dockerfileInstruction contained /\v(\S+)(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileValue
syntax match dockerfileInstruction contained /\v(ADD|COPY)(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileJSON
syntax match dockerfileInstruction contained /\v(HEALTHCHECK)(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileInstruction
syntax match dockerfileInstruction contained /\v(CMD|ENTRYPOINT|RUN)/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileShell
syntax match dockerfileInstruction contained /\v(CMD|ENTRYPOINT|RUN)\ze\s+\[/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileJSON
syntax match dockerfileInstruction contained /\v(SHELL|VOLUME)/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileJSON
syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/
syntax region dockerfileString contained start=/\v"/ skip=/\v\\./ end=/\v"/
syntax region dockerfileJSON contained keepend start=/\v\[/ skip=/\v\\\_./ end=/\v$/ contains=@JSON
syntax region dockerfileShell contained keepend start=/\v/ skip=/\v\\\_./ end=/\v$/ contains=@Shell
syntax region dockerfileValue contained keepend start=/\v/ skip=/\v\\\_./ end=/\v$/ contains=dockerfileString
syntax match dockerfileComment "\v^\s*#.*$"
syntax region dockerfileComment start=/\v^\s*#/ end=/\v$/
set commentstring=#\ %s
hi def link dockerfileString String
hi def link dockerfileKeyword Keyword
hi def link dockerfileComment Comment
hi def link dockerfileOption Special
let b:current_syntax = "dockerfile"

View File

@ -1,7 +1,7 @@
" Vim syntax file
" Language: Fortran 2008 (and older: Fortran 2003, 95, 90, and 77)
" Version: 101
" Last Change: 2019 Nov. 26
" Version: 102
" Last Change: 2019 Dec. 14
" Maintainer: Ajit J. Thakkar <ajit@unb.ca>; <http://www2.unb.ca/~ajit/>
" Usage: For instructions, do :help fortran-syntax from Vim
" Credits:
@ -185,8 +185,8 @@ syn match fortranLabelNumber display "^ \d\s"ms=s+4,me=e-1
if exists("fortran_more_precise")
" Numbers as targets
syn match fortranTarget display "\(\<if\s*(.\+)\s*\)\@<=\(\d\+\s*,\s*\)\{2}\d\+\>"
syn match fortranTarget display "\(\<do\s\+\)\@<11=\d\+\>"
syn match fortranTarget display "\(\<go\s*to\s*(\=\)\@<11=\(\d\+\s*,\s*\)*\d\+\>"
syn match fortranTarget display "\(\<do\s\+\)\@11<=\d\+\>"
syn match fortranTarget display "\(\<go\s*to\s*(\=\)\@11<=\(\d\+\s*,\s*\)*\d\+\>"
endif
syn keyword fortranTypeR external
@ -274,7 +274,7 @@ syn match fortranType "\<elemental\>"
syn match fortranType "\<pure\>"
syn match fortranType "\<impure\>"
if exists("fortran_more_precise")
syn match fortranConstructName "\(\<end\s*forall\s\+\)\@<15=\a\w*\>"
syn match fortranConstructName "\(\<end\s*forall\s\+\)\@15<=\a\w*\>"
endif
if b:fortran_dialect == "f08"

2
src/auto/configure vendored
View File

@ -14762,7 +14762,7 @@ DEPEND_CFLAGS_FILTER=
if test "$GCC" = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GCC 3 or later" >&5
$as_echo_n "checking for GCC 3 or later... " >&6; }
gccmajor=`echo "$gccversion" | sed -e 's/^\([1-9]\)\..*$/\1/g'`
gccmajor=`echo "$gccversion" | sed -e 's/^\([1-9][0-9]*\)\..*$/\1/g'`
if test "$gccmajor" -gt "2"; then
DEPEND_CFLAGS_FILTER="| sed 's+-I */+-isystem /+g'"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5

View File

@ -2195,7 +2195,7 @@ else
fi
dnl On my HPUX system the X include dir is found, but the lib dir not.
dnl This is a desparate try to fix this.
dnl This is a desperate try to fix this.
if test -d "$x_includes" && test ! -d "$x_libraries"; then
x_libraries=`echo "$x_includes" | sed s/include/lib/`
@ -4447,7 +4447,7 @@ dnl the number before the version number.
DEPEND_CFLAGS_FILTER=
if test "$GCC" = yes; then
AC_MSG_CHECKING(for GCC 3 or later)
gccmajor=`echo "$gccversion" | sed -e 's/^\([[1-9]]\)\..*$/\1/g'`
gccmajor=`echo "$gccversion" | sed -e 's/^\([[1-9]][[0-9]]*\)\..*$/\1/g'`
if test "$gccmajor" -gt "2"; then
DEPEND_CFLAGS_FILTER="| sed 's+-I */+-isystem /+g'"
AC_MSG_RESULT(yes)

View File

@ -810,6 +810,7 @@ static funcentry_T global_functions[] =
#endif
{"test_alloc_fail", 3, 3, FEARG_1, &t_void, f_test_alloc_fail},
{"test_autochdir", 0, 0, 0, &t_void, f_test_autochdir},
{"test_clear_search_pat", 0, 0, 0, &t_void, f_test_clear_search_pat},
{"test_feedinput", 1, 1, FEARG_1, &t_void, f_test_feedinput},
{"test_garbagecollect_now", 0, 0, 0, &t_void, f_test_garbagecollect_now},
{"test_garbagecollect_soon", 0, 0, 0, &t_void, f_test_garbagecollect_soon},

View File

@ -4423,17 +4423,17 @@ readdir_core(
int (*checkitem)(void *context, char_u *name))
{
int failed = FALSE;
#ifdef MSWIN
# ifdef MSWIN
char_u *buf, *p;
int ok;
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATAW wfb;
WCHAR *wn = NULL; // UTF-16 name, NULL when not used.
#endif
# endif
ga_init2(gap, (int)sizeof(char *), 20);
#ifdef MSWIN
# ifdef MSWIN
buf = alloc(MAXPATHL);
if (buf == NULL)
return FAIL;
@ -4498,7 +4498,7 @@ readdir_core(
vim_free(buf);
vim_free(wn);
#else
# else
DIR *dirp;
struct dirent *dp;
char_u *p;
@ -4547,7 +4547,7 @@ readdir_core(
closedir(dirp);
}
#endif
# endif
if (!failed && gap->ga_len > 0)
sort_strings((char_u **)gap->ga_data, gap->ga_len);

View File

@ -301,6 +301,7 @@ modify_fname(
char_u dirname[MAXPATHL];
int c;
int has_fullname = 0;
int has_homerelative = 0;
#ifdef MSWIN
char_u *fname_start = *fnamep;
int has_shortname = 0;
@ -412,7 +413,7 @@ repeat:
}
pbuf = NULL;
// Need full path first (use expand_env() to remove a "~/")
if (!has_fullname)
if (!has_fullname && !has_homerelative)
{
if (c == '.' && **fnamep == '~')
p = pbuf = expand_env_save(*fnamep);
@ -428,16 +429,37 @@ repeat:
{
if (c == '.')
{
size_t namelen;
mch_dirname(dirname, MAXPATHL);
s = shorten_fname(p, dirname);
if (s != NULL)
if (has_homerelative)
{
*fnamep = s;
if (pbuf != NULL)
s = vim_strsave(dirname);
if (s != NULL)
{
vim_free(*bufp); // free any allocated file name
*bufp = pbuf;
pbuf = NULL;
home_replace(NULL, s, dirname, MAXPATHL, TRUE);
vim_free(s);
}
}
namelen = STRLEN(dirname);
// Do not call shorten_fname() here since it removes the prefix
// even though the path does not have a prefix.
if (fnamencmp(p, dirname, namelen) == 0)
{
p += namelen;
if (vim_ispathsep(*p))
{
while (*p && vim_ispathsep(*p))
++p;
*fnamep = p;
if (pbuf != NULL)
{
// free any allocated file name
vim_free(*bufp);
*bufp = pbuf;
pbuf = NULL;
}
}
}
}
@ -453,6 +475,7 @@ repeat:
*fnamep = s;
vim_free(*bufp);
*bufp = s;
has_homerelative = TRUE;
}
}
}
@ -701,6 +724,7 @@ f_chdir(typval_T *argvars, typval_T *rettv)
rettv->vval.v_string = NULL;
if (argvars[0].v_type != VAR_STRING)
// Returning an empty string means it failed.
return;
// Return the current directory
@ -1235,41 +1259,6 @@ f_isdirectory(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
}
/*
* Evaluate "expr" (= "context") for readdir().
*/
static int
readdir_checkitem(void *context, char_u *name)
{
typval_T *expr = (typval_T *)context;
typval_T save_val;
typval_T rettv;
typval_T argv[2];
int retval = 0;
int error = FALSE;
if (expr->v_type == VAR_UNKNOWN)
return 1;
prepare_vimvar(VV_VAL, &save_val);
set_vim_var_string(VV_VAL, name, -1);
argv[0].v_type = VAR_STRING;
argv[0].vval.v_string = name;
if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
goto theend;
retval = tv_get_number_chk(&rettv, &error);
if (error)
retval = -1;
clear_tv(&rettv);
theend:
set_vim_var_string(VV_VAL, NULL, 0);
restore_vimvar(VV_VAL, &save_val);
return retval;
}
/*
* Create the directory in which "dir" is located, and higher levels when
* needed.
@ -1365,6 +1354,41 @@ f_pathshorten(typval_T *argvars, typval_T *rettv)
}
}
/*
* Evaluate "expr" (= "context") for readdir().
*/
static int
readdir_checkitem(void *context, char_u *name)
{
typval_T *expr = (typval_T *)context;
typval_T save_val;
typval_T rettv;
typval_T argv[2];
int retval = 0;
int error = FALSE;
if (expr->v_type == VAR_UNKNOWN)
return 1;
prepare_vimvar(VV_VAL, &save_val);
set_vim_var_string(VV_VAL, name, -1);
argv[0].v_type = VAR_STRING;
argv[0].vval.v_string = name;
if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
goto theend;
retval = tv_get_number_chk(&rettv, &error);
if (error)
retval = -1;
clear_tv(&rettv);
theend:
set_vim_var_string(VV_VAL, NULL, 0);
restore_vimvar(VV_VAL, &save_val);
return retval;
}
/*
* "readdir()" function
*/

View File

@ -2371,6 +2371,10 @@ f_popup_close(typval_T *argvars, typval_T *rettv UNUSED)
void
popup_hide(win_T *wp)
{
#ifdef FEAT_TERMINAL
if (error_if_term_popup_window())
return;
#endif
if ((wp->w_popup_flags & POPF_HIDDEN) == 0)
{
wp->w_popup_flags |= POPF_HIDDEN;

View File

@ -12,6 +12,7 @@ int vim_regcomp_had_eol(void);
regprog_T *vim_regcomp(char_u *expr_arg, int re_flags);
void vim_regfree(regprog_T *prog);
void free_regexp_stuff(void);
void free_regexp_prev_sub(void);
int regprog_in_use(regprog_T *prog);
int vim_regexec_prog(regprog_T **prog, int ignore_case, char_u *line, colnr_T col);
int vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col);

View File

@ -9,6 +9,7 @@ void free_search_patterns(void);
void save_last_search_pattern(void);
void restore_last_search_pattern(void);
char_u *last_search_pattern(void);
void free_last_pat(int idx);
int ignorecase(char_u *pat);
int ignorecase_opt(char_u *pat, int ic_in, int scs);
int pat_has_uppercase(char_u *pat);

View File

@ -13,6 +13,7 @@ void f_assert_report(typval_T *argvars, typval_T *rettv);
void f_assert_true(typval_T *argvars, typval_T *rettv);
void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
void f_test_autochdir(typval_T *argvars, typval_T *rettv);
void f_test_clear_search_pat(typval_T *argvars, typval_T *rettv);
void f_test_feedinput(typval_T *argvars, typval_T *rettv);
void f_test_getvalue(typval_T *argvars, typval_T *rettv);
void f_test_option_not_set(typval_T *argvars, typval_T *rettv);

View File

@ -6,6 +6,7 @@ int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate);
char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
void emsg_funcname(char *ermsg, char_u *name);
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe);
char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error);
ufunc_T *find_func(char_u *name, cctx_T *cctx);
int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);
void save_funccal(funccal_entry_T *entry);
@ -26,7 +27,6 @@ int has_varargs(ufunc_T *ufunc);
int function_exists(char_u *name, int no_deref);
char_u *get_expanded_name(char_u *name, int check);
char_u *get_user_func_name(expand_T *xp, int idx);
void clean_script_functions(int sid);
void ex_delfunction(exarg_T *eap);
void func_unref(char_u *name);
void func_ptr_unref(ufunc_T *fp);

View File

@ -2663,6 +2663,15 @@ free_regexp_stuff(void)
}
#endif
/*
* Free the previously used substitute search pattern.
*/
void
free_regexp_prev_sub(void)
{
VIM_CLEAR(reg_prev_sub);
}
#ifdef FEAT_EVAL
static void
report_re_switch(char_u *pat)

View File

@ -380,6 +380,12 @@ last_search_pattern(void)
}
#endif
void
free_last_pat(int idx)
{
VIM_CLEAR(spats[idx].pat);
}
/*
* Return TRUE when case should be ignored for search pattern "pat".
* Uses the 'ignorecase' and 'smartcase' options.

View File

@ -1515,6 +1515,8 @@ typedef struct
type_T **uf_arg_types; // argument types (count == uf_args.ga_len)
type_T *uf_ret_type; // return type
garray_T uf_type_list; // types used in arg and return types
int *uf_def_arg_idx; // instruction indexes for evaluating
// uf_def_args; length: uf_def_args.ga_len + 1
char_u *uf_va_name; // name from "...name" or NULL
type_T *uf_va_type; // type from "...name: type" or NULL

View File

@ -268,6 +268,7 @@ NEW_TESTS = \
test_utf8 \
test_utf8_comparisons \
test_vartabs \
test_vim9_disassemble \
test_vim9_expr \
test_vim9_script \
test_viminfo \
@ -470,6 +471,7 @@ NEW_TESTS_RES = \
test_user_func.res \
test_usercommands.res \
test_vartabs.res \
test_vim9_disassemble.res \
test_vim9_expr.res \
test_vim9_script.res \
test_viminfo.res \

View File

@ -0,0 +1,15 @@
|3+0&#ffffff0| @12|╔+0&#a8a8a8255|═@44|╗| +0&#ffffff0@13
|4| @12|║+0&#a8a8a8255|s|o|m|e| |t|e|x|t| @35|║| +0&#ffffff0@13
|5| @12|║+0&#a8a8a8255|t|o| |e+0&#ffff4012|d|i|t| +0&#a8a8a8255@37|║| +0&#ffffff0@13
|6| @12|║+0&#a8a8a8255|i|n| |a| |p|o|p|u|p| |w|i|n|d|o|w| @27|║| +0&#ffffff0@13
|7| @12|║+0&#a8a8a8255|~+0#4040ff13&| @43|║+0#0000000&| +0&#ffffff0@13
|8| @12|║+0&#a8a8a8255|~+0#4040ff13&| @43|║+0#0000000&| +0&#ffffff0@13
|9| @12|║+0&#a8a8a8255|~+0#4040ff13&| @43|║+0#0000000&| +0&#ffffff0@13
|1|0| @11|║+0&#a8a8a8255|/|e|d|i|t| @21|2|,|4| @10|A|l@1| |║| +0&#ffffff0@13
|1@1| @11|╚+0&#a8a8a8255|═@44|⇲| +0&#ffffff0@13
|1|2| @72
|1|3| @72
|E+0#ffffff16#e000002|r@1|o|r| |d|e|t|e|c|t|e|d| |w|h|i|l|e| |p|r|o|c|e|s@1|i|n|g| |f|u|n|c|t|i|o|n| |H|i|d|e|P|o|p|u|p|:| +0#0000000#ffffff0@23
|l+0#af5f00255&|i|n|e| @3|1|:| +0#0000000&@64
|E+0#ffffff16#e000002|8|6|3|:| |N|o|t| |a|l@1|o|w|e|d| |f|o|r| |a| |t|e|r|m|i|n|a|l| |i|n| |a| |p|o|p|u|p| |w|i|n|d|o|w| +0#0000000#ffffff0@24
|P+0#00e0003&|r|e|s@1| |E|N|T|E|R| |o|r| |t|y|p|e| |c|o|m@1|a|n|d| |t|o| |c|o|n|t|i|n|u|e> +0#0000000&@35

View File

@ -3,8 +3,10 @@
func Test_fnamemodify()
let save_home = $HOME
let save_shell = &shell
let save_shellslash = &shellslash
let $HOME = fnamemodify('.', ':p:h:h')
set shell=sh
set shellslash
call assert_equal('/', fnamemodify('.', ':p')[-1:])
call assert_equal('r', fnamemodify('.', ':p:h')[-1:])
@ -28,6 +30,17 @@ func Test_fnamemodify()
call assert_equal('fb2.tar.gz', fnamemodify('abc.fb2.tar.gz', ':e:e:e:e'))
call assert_equal('tar', fnamemodify('abc.fb2.tar.gz', ':e:e:r'))
let cwd = getcwd()
call mkdir($HOME . '/XXXXXXXX/a', 'p')
call mkdir($HOME . '/XXXXXXXX/b', 'p')
call chdir($HOME . '/XXXXXXXX/a/')
call assert_equal('foo', fnamemodify($HOME . '/XXXXXXXX/a/foo', ':p:~:.'))
call assert_equal('~/XXXXXXXX/b/foo', fnamemodify($HOME . '/XXXXXXXX/b/foo', ':p:~:.'))
call mkdir($HOME . '/XXXXXXXX/a.ext', 'p')
call assert_equal('~/XXXXXXXX/a.ext/foo', fnamemodify($HOME . '/XXXXXXXX/a.ext/foo', ':p:~:.'))
call chdir(cwd)
call delete($HOME . '/XXXXXXXX', 'rf')
call assert_equal('''abc def''', fnamemodify('abc def', ':S'))
call assert_equal('''abc" "def''', fnamemodify('abc" "def', ':S'))
call assert_equal('''abc"%"def''', fnamemodify('abc"%"def', ':S'))
@ -44,6 +57,7 @@ func Test_fnamemodify()
let $HOME = save_home
let &shell = save_shell
let &shellslash = save_shellslash
endfunc
func Test_fnamemodify_er()

View File

@ -1965,7 +1965,7 @@ func Test_range()
" settagstack()
call settagstack(1, #{items : range(4)})
" sign_define()
call assert_fails("call sign_define(range(5))", "E715:")
call assert_fails("call sign_placelist(range(5))", "E715:")
@ -1997,12 +1997,17 @@ func Test_range()
set tagfunc=TagFunc
call assert_fails("call taglist('asdf')", 'E987:')
set tagfunc=
" term_start()
if has('terminal') && has('termguicolors')
call assert_fails('call term_start(range(3, 4))', 'E474:')
let g:terminal_ansi_colors = range(16)
call assert_fails('call term_start("ls", #{term_finish: "close"})', 'E475:')
if has('win32')
let cmd = "cmd /c dir"
else
let cmd = "ls"
endif
call assert_fails('call term_start("' .. cmd .. '", #{term_finish: "close"})', 'E475:')
unlet g:terminal_ansi_colors
endif

View File

@ -2718,6 +2718,10 @@ func XvimgrepTests(cchar)
call assert_equal(0, getbufinfo('Xtestfile1')[0].loaded)
call assert_equal([], getbufinfo('Xtestfile2'))
" Test with the last search pattern not set
call test_clear_search_pat()
call assert_fails('Xvimgrep // *', 'E35:')
call delete('Xtestfile1')
call delete('Xtestfile2')
endfunc

View File

@ -1455,3 +1455,44 @@ func Test_search_special()
set t_PE=
exe "norm /\x80PS"
endfunc
" Test for command failures when the last search pattern is not set.
func Test_search_with_no_last_pat()
call test_clear_search_pat()
call assert_fails("normal i\<C-R>/\e", 'E35:')
call assert_fails("exe '/'", 'E35:')
call assert_fails("exe '?'", 'E35:')
call assert_fails("/", 'E35:')
call assert_fails("?", 'E35:')
call assert_fails("normal n", 'E35:')
call assert_fails("normal N", 'E35:')
call assert_fails("normal gn", 'E35:')
call assert_fails("normal gN", 'E35:')
call assert_fails("normal cgn", 'E35:')
call assert_fails("normal cgN", 'E35:')
let p = []
let p = @/
call assert_equal('', p)
call assert_fails("normal :\<C-R>/", 'E35:')
call assert_fails("//p", 'E35:')
call assert_fails(";//p", 'E35:')
call assert_fails("??p", 'E35:')
call assert_fails(";??p", 'E35:')
call assert_fails('g//p', 'E476:')
call assert_fails('v//p', 'E476:')
endfunc
" Test for using tilde (~) atom in search. This should use the last used
" substitute pattern
func Test_search_tilde_pat()
call test_clear_search_pat()
set regexpengine=1
call assert_fails('exe "normal /~\<CR>"', 'E33:')
call assert_fails('exe "normal ?~\<CR>"', 'E33:')
set regexpengine=2
call assert_fails('exe "normal /~\<CR>"', 'E383:')
call assert_fails('exe "normal ?~\<CR>"', 'E383:')
set regexpengine&
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -1383,6 +1383,8 @@ func Test_sort_last_search_pat()
call setline(1, ['3b', '1c', '2a'])
sort //
call assert_equal(['2a', '3b', '1c'], getline(1, '$'))
call test_clear_search_pat()
call assert_fails('sort //', 'E35:')
close!
endfunc

View File

@ -803,4 +803,19 @@ func Test_sub_expand_text()
close!
endfunc
" Test for command failures when the last substitute pattern is not set.
func Test_sub_with_no_last_pat()
call test_clear_search_pat()
call assert_fails('~', 'E33:')
call assert_fails('s//abc/g', 'E476:')
call assert_fails('s\/bar', 'E476:')
call assert_fails('s\&bar&', 'E476:')
call test_clear_search_pat()
let save_cpo = &cpo
set cpo+=/
call assert_fails('s/abc/%/', 'E33:')
let &cpo = save_cpo
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -2337,12 +2337,15 @@ func Test_terminal_in_popup()
\ 'hi PopTerm ctermbg=grey',
\ 'func OpenTerm(setColor)',
\ " let buf = term_start('" .. cmd .. " Xtext', #{hidden: 1, term_finish: 'close'})",
\ ' let winid = popup_create(buf, #{minwidth: 45, minheight: 7, border: [], drag: 1, resize: 1})',
\ ' let s:winid = popup_create(buf, #{minwidth: 45, minheight: 7, border: [], drag: 1, resize: 1})',
\ ' if a:setColor',
\ ' call win_execute(winid, "set wincolor=PopTerm")',
\ ' call win_execute(s:winid, "set wincolor=PopTerm")',
\ ' endif',
\ 'endfunc',
\ 'call OpenTerm(0)',
\ 'func HidePopup()',
\ ' call popup_hide(s:winid)',
\ 'endfunc',
\ ]
call writefile(lines, 'XtermPopup')
let buf = RunVimInTerminal('-S XtermPopup', #{rows: 15})
@ -2356,6 +2359,11 @@ func Test_terminal_in_popup()
call term_sendkeys(buf, "/edit\<CR>")
call VerifyScreenDump(buf, 'Test_terminal_popup_3', {})
call term_sendkeys(buf, "\<C-W>:call HidePopup()\<CR>")
call VerifyScreenDump(buf, 'Test_terminal_popup_4', {})
call term_sendkeys(buf, "\<CR>")
call term_wait(buf, 50)
call term_sendkeys(buf, ":q\<CR>")
call term_wait(buf, 100) " wait for terminal to vanish

View File

@ -0,0 +1,533 @@
" Test the :disassemble command, and compilation as a side effect
func NotCompiled()
echo "not"
endfunc
let s:scriptvar = 4
let g:globalvar = 'g'
def s:ScriptFuncLoad(arg: string)
let local = 1
buffers
echo arg
echo local
echo v:version
echo s:scriptvar
echo g:globalvar
echo &tabstop
echo $ENVVAR
echo @z
enddef
def Test_disassemble_load()
assert_fails('disass NoFunc', 'E1061:')
assert_fails('disass NotCompiled', 'E1062:')
let res = execute('disass s:ScriptFuncLoad')
assert_match('<SNR>\d*_ScriptFuncLoad.*'
\ .. 'buffers.*'
\ .. ' EXEC \+buffers.*'
\ .. ' LOAD arg\[-1\].*'
\ .. ' LOAD $0.*'
\ .. ' LOADV v:version.*'
\ .. ' LOADS s:scriptvar from .*test_vim9_disassemble.vim.*'
\ .. ' LOADG g:globalvar.*'
\ .. ' LOADENV $ENVVAR.*'
\ .. ' LOADREG @z.*'
\, res)
enddef
def s:ScriptFuncPush()
let localbool = true
let localspec = v:none
let localblob = 0z1234
if has('float')
let localfloat = 1.234
endif
enddef
def Test_disassemble_push()
let res = execute('disass s:ScriptFuncPush')
assert_match('<SNR>\d*_ScriptFuncPush.*'
\ .. 'localbool = true.*'
\ .. ' PUSH v:true.*'
\ .. 'localspec = v:none.*'
\ .. ' PUSH v:none.*'
\ .. 'localblob = 0z1234.*'
\ .. ' PUSHBLOB 0z1234.*'
\, res)
if has('float')
assert_match('<SNR>\d*_ScriptFuncPush.*'
\ .. 'localfloat = 1.234.*'
\ .. ' PUSHF 1.234.*'
\, res)
endif
enddef
def s:ScriptFuncStore()
let localnr = 1
localnr = 2
let localstr = 'abc'
localstr = 'xyz'
v:char = 'abc'
s:scriptvar = 'sv'
g:globalvar = 'gv'
&tabstop = 8
$ENVVAR = 'ev'
@z = 'rv'
enddef
def Test_disassemble_store()
let res = execute('disass s:ScriptFuncStore')
assert_match('<SNR>\d*_ScriptFuncStore.*'
\ .. 'localnr = 2.*'
\ .. ' STORE 2 in $0.*'
\ .. 'localstr = ''xyz''.*'
\ .. ' STORE $1.*'
\ .. 'v:char = ''abc''.*'
\ .. 'STOREV v:char.*'
\ .. 's:scriptvar = ''sv''.*'
\ .. ' STORES s:scriptvar in .*test_vim9_disassemble.vim.*'
\ .. 'g:globalvar = ''gv''.*'
\ .. ' STOREG g:globalvar.*'
\ .. '&tabstop = 8.*'
\ .. ' STOREOPT &tabstop.*'
\ .. '$ENVVAR = ''ev''.*'
\ .. ' STOREENV $ENVVAR.*'
\ .. '@z = ''rv''.*'
\ .. ' STOREREG @z.*'
\, res)
enddef
def s:ScriptFuncTry()
try
echo 'yes'
catch /fail/
echo 'no'
finally
throw 'end'
endtry
enddef
def Test_disassemble_try()
let res = execute('disass s:ScriptFuncTry')
assert_match('<SNR>\d*_ScriptFuncTry.*'
\ .. 'try.*'
\ .. 'TRY catch -> \d\+, finally -> \d\+.*'
\ .. 'catch /fail/.*'
\ .. ' JUMP -> \d\+.*'
\ .. ' PUSH v:exception.*'
\ .. ' PUSHS "fail".*'
\ .. ' COMPARESTRING =\~.*'
\ .. ' JUMP_IF_FALSE -> \d\+.*'
\ .. ' CATCH.*'
\ .. 'finally.*'
\ .. ' PUSHS "end".*'
\ .. ' THROW.*'
\ .. 'endtry.*'
\ .. ' ENDTRY.*'
\, res)
enddef
def s:ScriptFuncNew()
let ll = [1, "two", 333]
let dd = #{one: 1, two: "val"}
enddef
def Test_disassemble_new()
let res = execute('disass s:ScriptFuncNew')
assert_match('<SNR>\d*_ScriptFuncNew.*'
\ .. 'let ll = \[1, "two", 333].*'
\ .. 'PUSHNR 1.*'
\ .. 'PUSHS "two".*'
\ .. 'PUSHNR 333.*'
\ .. 'NEWLIST size 3.*'
\ .. 'let dd = #{one: 1, two: "val"}.*'
\ .. 'PUSHS "one".*'
\ .. 'PUSHNR 1.*'
\ .. 'PUSHS "two".*'
\ .. 'PUSHS "val".*'
\ .. 'NEWDICT size 2.*'
\, res)
enddef
def FuncWithArg(arg)
echo arg
enddef
func UserFunc()
echo 'nothing'
endfunc
func UserFuncWithArg(arg)
echo a:arg
endfunc
def s:ScriptFuncCall(): string
changenr()
char2nr("abc")
Test_disassemble_new()
FuncWithArg(343)
ScriptFuncNew()
s:ScriptFuncNew()
UserFunc()
UserFuncWithArg("foo")
let FuncRef = function("UserFunc")
FuncRef()
let FuncRefWithArg = function("UserFuncWithArg")
FuncRefWithArg("bar")
return "yes"
enddef
def Test_disassemble_call()
let res = execute('disass s:ScriptFuncCall')
assert_match('<SNR>\d\+_ScriptFuncCall.*'
\ .. 'changenr().*'
\ .. ' BCALL changenr(argc 0).*'
\ .. 'char2nr("abc").*'
\ .. ' PUSHS "abc".*'
\ .. ' BCALL char2nr(argc 1).*'
\ .. 'Test_disassemble_new().*'
\ .. ' DCALL Test_disassemble_new(argc 0).*'
\ .. 'FuncWithArg(343).*'
\ .. ' PUSHNR 343.*'
\ .. ' DCALL FuncWithArg(argc 1).*'
\ .. 'ScriptFuncNew().*'
\ .. ' DCALL <SNR>\d\+_ScriptFuncNew(argc 0).*'
\ .. 's:ScriptFuncNew().*'
\ .. ' DCALL <SNR>\d\+_ScriptFuncNew(argc 0).*'
\ .. 'UserFunc().*'
\ .. ' UCALL UserFunc(argc 0).*'
\ .. 'UserFuncWithArg("foo").*'
\ .. ' PUSHS "foo".*'
\ .. ' UCALL UserFuncWithArg(argc 1).*'
\ .. 'let FuncRef = function("UserFunc").*'
\ .. 'FuncRef().*'
\ .. ' LOAD $\d.*'
\ .. ' PCALL (argc 0).*'
\ .. 'let FuncRefWithArg = function("UserFuncWithArg").*'
\ .. 'FuncRefWithArg("bar").*'
\ .. ' PUSHS "bar".*'
\ .. ' LOAD $\d.*'
\ .. ' PCALL (argc 1).*'
\ .. 'return "yes".*'
\ .. ' PUSHS "yes".*'
\ .. ' RETURN.*'
\, res)
enddef
def HasEval()
if has("eval")
echo "yes"
else
echo "no"
endif
enddef
def HasNothing()
if has("nothing")
echo "yes"
else
echo "no"
endif
enddef
def HasSomething()
if has("nothing")
echo "nothing"
elseif has("something")
echo "something"
elseif has("eval")
echo "eval"
elseif has("less")
echo "less"
endif
enddef
def Test_disassemble_const_expr()
assert_equal("\nyes", execute('call HasEval()'))
let instr = execute('disassemble HasEval')
assert_match('HasEval.*'
\ .. 'if has("eval").*'
\ .. ' PUSHS "yes".*'
\, instr)
assert_notmatch('JUMP', instr)
assert_equal("\nno", execute('call HasNothing()'))
instr = execute('disassemble HasNothing')
assert_match('HasNothing.*'
\ .. 'if has("nothing").*'
\ .. 'else.*'
\ .. ' PUSHS "no".*'
\, instr)
assert_notmatch('PUSHS "yes"', instr)
assert_notmatch('JUMP', instr)
assert_equal("\neval", execute('call HasSomething()'))
instr = execute('disassemble HasSomething')
assert_match('HasSomething.*'
\ .. 'if has("nothing").*'
\ .. 'elseif has("something").*'
\ .. 'elseif has("eval").*'
\ .. ' PUSHS "eval".*'
\ .. 'elseif has("less").*'
\, instr)
assert_notmatch('PUSHS "nothing"', instr)
assert_notmatch('PUSHS "something"', instr)
assert_notmatch('PUSHS "less"', instr)
assert_notmatch('JUMP', instr)
enddef
def WithLambda(): string
let F = {a -> "X" .. a .. "X"}
return F("x")
enddef
def Test_disassemble_lambda()
assert_equal("XxX", WithLambda())
let instr = execute('disassemble WithLambda')
assert_match('WithLambda.*'
\ .. 'let F = {a -> "X" .. a .. "X"}.*'
\ .. ' FUNCREF <lambda>\d\+.*'
\ .. 'PUSHS "x".*'
\ .. ' LOAD $0.*'
\ .. ' PCALL (argc 1).*'
\ .. ' CHECKTYPE string stack\[-1].*'
\, instr)
enddef
def AndOr(arg): string
if arg == 1 && arg != 2 || arg == 4
return 'yes'
endif
return 'no'
enddef
def Test_disassemble_and_or()
assert_equal("yes", AndOr(1))
assert_equal("no", AndOr(2))
assert_equal("yes", AndOr(4))
let instr = execute('disassemble AndOr')
assert_match('AndOr.*'
\ .. 'if arg == 1 && arg != 2 || arg == 4.*'
\ .. '\d LOAD arg\[-1].*'
\ .. '\d PUSHNR 1.*'
\ .. '\d COMPAREANY ==.*'
\ .. '\d JUMP_AND_KEEP_IF_FALSE -> \d\+.*'
\ .. '\d LOAD arg\[-1].*'
\ .. '\d PUSHNR 2.*'
\ .. '\d COMPAREANY !=.*'
\ .. '\d JUMP_AND_KEEP_IF_TRUE -> \d\+.*'
\ .. '\d LOAD arg\[-1].*'
\ .. '\d PUSHNR 4.*'
\ .. '\d COMPAREANY ==.*'
\ .. '\d JUMP_IF_FALSE -> \d\+.*'
\, instr)
enddef
def ForLoop(): list<number>
let res: list<number>
for i in range(3)
res->add(i)
endfor
return res
enddef
def Test_disassemble_for_loop()
assert_equal([0, 1, 2], ForLoop())
let instr = execute('disassemble ForLoop')
assert_match('ForLoop.*'
\ .. 'let res: list<number>.*'
\ .. ' NEWLIST size 0.*'
\ .. '\d STORE $0.*'
\ .. 'for i in range(3).*'
\ .. '\d STORE -1 in $1.*'
\ .. '\d PUSHNR 3.*'
\ .. '\d BCALL range(argc 1).*'
\ .. '\d FOR $1 -> \d\+.*'
\ .. '\d STORE $2.*'
\ .. 'res->add(i).*'
\ .. '\d LOAD $0.*'
\ .. '\d LOAD $2.*'
\ .. '\d BCALL add(argc 2).*'
\ .. '\d DROP.*'
\ .. 'endfor.*'
\ .. '\d JUMP -> \d\+.*'
\ .. '\d DROP.*'
\, instr)
enddef
let g:number = 42
def Computing()
let nr = 3
let nrres = nr + 7
nrres = nr - 7
nrres = nr * 7
nrres = nr / 7
nrres = nr % 7
let anyres = g:number + 7
anyres = g:number - 7
anyres = g:number * 7
anyres = g:number / 7
anyres = g:number % 7
if has('float')
let fl = 3.0
let flres = fl + 7.0
flres = fl - 7.0
flres = fl * 7.0
flres = fl / 7.0
endif
enddef
def Test_disassemble_computing()
let instr = execute('disassemble Computing')
assert_match('Computing.*'
\ .. 'let nr = 3.*'
\ .. '\d STORE 3 in $0.*'
\ .. 'let nrres = nr + 7.*'
\ .. '\d LOAD $0.*'
\ .. '\d PUSHNR 7.*'
\ .. '\d OPNR +.*'
\ .. '\d STORE $1.*'
\ .. 'nrres = nr - 7.*'
\ .. '\d OPNR -.*'
\ .. 'nrres = nr \* 7.*'
\ .. '\d OPNR \*.*'
\ .. 'nrres = nr / 7.*'
\ .. '\d OPNR /.*'
\ .. 'nrres = nr % 7.*'
\ .. '\d OPNR %.*'
\ .. 'let anyres = g:number + 7.*'
\ .. '\d LOADG g:number.*'
\ .. '\d PUSHNR 7.*'
\ .. '\d OPANY +.*'
\ .. '\d STORE $2.*'
\ .. 'anyres = g:number - 7.*'
\ .. '\d OPANY -.*'
\ .. 'anyres = g:number \* 7.*'
\ .. '\d OPANY \*.*'
\ .. 'anyres = g:number / 7.*'
\ .. '\d OPANY /.*'
\ .. 'anyres = g:number % 7.*'
\ .. '\d OPANY %.*'
\, instr)
if has('float')
assert_match('Computing.*'
\ .. 'let fl = 3.0.*'
\ .. '\d PUSHF 3.0.*'
\ .. '\d STORE $3.*'
\ .. 'let flres = fl + 7.0.*'
\ .. '\d LOAD $3.*'
\ .. '\d PUSHF 7.0.*'
\ .. '\d OPFLOAT +.*'
\ .. '\d STORE $4.*'
\ .. 'flres = fl - 7.0.*'
\ .. '\d OPFLOAT -.*'
\ .. 'flres = fl \* 7.0.*'
\ .. '\d OPFLOAT \*.*'
\ .. 'flres = fl / 7.0.*'
\ .. '\d OPFLOAT /.*'
\, instr)
endif
enddef
def Test_disassemble_compare()
" TODO: COMPAREFUNC
let cases = [
\ ['true == false', 'COMPAREBOOL =='],
\ ['true != false', 'COMPAREBOOL !='],
\ ['v:none == v:null', 'COMPARESPECIAL =='],
\ ['v:none != v:null', 'COMPARESPECIAL !='],
\
\ ['111 == 222', 'COMPARENR =='],
\ ['111 != 222', 'COMPARENR !='],
\ ['111 > 222', 'COMPARENR >'],
\ ['111 < 222', 'COMPARENR <'],
\ ['111 >= 222', 'COMPARENR >='],
\ ['111 <= 222', 'COMPARENR <='],
\ ['111 =~ 222', 'COMPARENR =\~'],
\ ['111 !~ 222', 'COMPARENR !\~'],
\
\ ['"xx" == "yy"', 'COMPARESTRING =='],
\ ['"xx" != "yy"', 'COMPARESTRING !='],
\ ['"xx" > "yy"', 'COMPARESTRING >'],
\ ['"xx" < "yy"', 'COMPARESTRING <'],
\ ['"xx" >= "yy"', 'COMPARESTRING >='],
\ ['"xx" <= "yy"', 'COMPARESTRING <='],
\ ['"xx" =~ "yy"', 'COMPARESTRING =\~'],
\ ['"xx" !~ "yy"', 'COMPARESTRING !\~'],
\ ['"xx" is "yy"', 'COMPARESTRING is'],
\ ['"xx" isnot "yy"', 'COMPARESTRING isnot'],
\
\ ['0z11 == 0z22', 'COMPAREBLOB =='],
\ ['0z11 != 0z22', 'COMPAREBLOB !='],
\ ['0z11 is 0z22', 'COMPAREBLOB is'],
\ ['0z11 isnot 0z22', 'COMPAREBLOB isnot'],
\
\ ['[1,2] == [3,4]', 'COMPARELIST =='],
\ ['[1,2] != [3,4]', 'COMPARELIST !='],
\ ['[1,2] is [3,4]', 'COMPARELIST is'],
\ ['[1,2] isnot [3,4]', 'COMPARELIST isnot'],
\
\ ['#{a:1} == #{x:2}', 'COMPAREDICT =='],
\ ['#{a:1} != #{x:2}', 'COMPAREDICT !='],
\ ['#{a:1} is #{x:2}', 'COMPAREDICT is'],
\ ['#{a:1} isnot #{x:2}', 'COMPAREDICT isnot'],
\
\ ['{->33} == {->44}', 'COMPAREPARTIAL =='],
\ ['{->33} != {->44}', 'COMPAREPARTIAL !='],
\ ['{->33} is {->44}', 'COMPAREPARTIAL is'],
\ ['{->33} isnot {->44}', 'COMPAREPARTIAL isnot'],
\
\ ['77 == g:xx', 'COMPAREANY =='],
\ ['77 != g:xx', 'COMPAREANY !='],
\ ['77 > g:xx', 'COMPAREANY >'],
\ ['77 < g:xx', 'COMPAREANY <'],
\ ['77 >= g:xx', 'COMPAREANY >='],
\ ['77 <= g:xx', 'COMPAREANY <='],
\ ['77 =~ g:xx', 'COMPAREANY =\~'],
\ ['77 !~ g:xx', 'COMPAREANY !\~'],
\ ['77 is g:xx', 'COMPAREANY is'],
\ ['77 isnot g:xx', 'COMPAREANY isnot'],
\ ]
if has('float')
cases->extend([
\ ['1.1 == 2.2', 'COMPAREFLOAT =='],
\ ['1.1 != 2.2', 'COMPAREFLOAT !='],
\ ['1.1 > 2.2', 'COMPAREFLOAT >'],
\ ['1.1 < 2.2', 'COMPAREFLOAT <'],
\ ['1.1 >= 2.2', 'COMPAREFLOAT >='],
\ ['1.1 <= 2.2', 'COMPAREFLOAT <='],
\ ['1.1 =~ 2.2', 'COMPAREFLOAT =\~'],
\ ['1.1 !~ 2.2', 'COMPAREFLOAT !\~'],
\ ])
endif
let nr = 1
for case in cases
writefile(['def TestCase' .. nr .. '()',
\ ' if ' .. case[0],
\ ' echo 42'
\ ' endif',
\ 'enddef'], 'Xdisassemble')
source Xdisassemble
let instr = execute('disassemble TestCase' .. nr)
assert_match('TestCase' .. nr .. '.*'
\ .. 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*'
\ .. '\d \(PUSH\|FUNCREF\).*'
\ .. '\d \(PUSH\|FUNCREF\|LOADG\).*'
\ .. '\d ' .. case[1] .. '.*'
\ .. '\d JUMP_IF_FALSE -> \d\+.*'
\, instr)
nr += 1
endfor
" delete('Xdisassemble')
enddef
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

View File

@ -27,6 +27,9 @@ func Test_def_basic()
call assert_equal('yes', SomeFunc())
endfunc
let s:appendToMe = 'xxx'
let s:addToMe = 111
def Test_assignment()
let bool1: bool = true
assert_equal(v:true, bool1)
@ -44,11 +47,16 @@ def Test_assignment()
let dict2: dict<number> = #{one: 1, two: 2}
v:char = 'abc'
call assert_equal('abc', v:char)
assert_equal('abc', v:char)
$ENVVAR = 'foobar'
call assert_equal('foobar', $ENVVAR)
assert_equal('foobar', $ENVVAR)
$ENVVAR = ''
appendToMe ..= 'yyy'
assert_equal('xxxyyy', appendToMe)
addToMe += 222
assert_equal(333, addToMe)
enddef
func Test_assignment_failure()
@ -131,6 +139,39 @@ def Test_call_varargs()
assert_equal('one,two,three', MyVarargs('one', 'two', 'three'))
enddef
def MyDefaultArgs(name = 'string'): string
return name
enddef
def Test_call_default_args()
assert_equal('string', MyDefaultArgs())
assert_equal('one', MyDefaultArgs('one'))
assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
enddef
func Test_call_default_args_from_func()
call assert_equal('string', MyDefaultArgs())
call assert_equal('one', MyDefaultArgs('one'))
call assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
endfunc
" Default arg and varargs
def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
let res = one .. ',' .. two
for s in rest
res ..= ',' .. s
endfor
return res
enddef
def Test_call_def_varargs()
call assert_fails('call MyDefVarargs()', 'E119:')
assert_equal('one,foo', MyDefVarargs('one'))
assert_equal('one,two', MyDefVarargs('one', 'two'))
assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three'))
enddef
"def Test_call_func_defined_later()
" call assert_equal('one', DefineLater('one'))
" call assert_fails('call NotDefined("one")', 'E99:')
@ -140,25 +181,6 @@ func DefineLater(arg)
return a:arg
endfunc
def MyDefaultArgs(name = 'string'): string
return name
enddef
func Test_call_default_args_from_func()
" TODO: implement using default value for optional argument
"call assert_equal('string', MyDefaultArgs())
call assert_fails('call MyDefaultArgs()', 'optional arguments not implemented yet')
call assert_equal('one', MyDefaultArgs('one'))
call assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
endfunc
def Test_call_default_args()
" TODO: implement using default value for optional argument
"assert_equal('string', MyDefaultArgs())
assert_equal('one', MyDefaultArgs('one'))
assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
enddef
def Test_return_type_wrong()
CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string')
CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number')
@ -195,6 +217,7 @@ let s:export_script_lines =<< trim END
export const CONST = 1234
export let exported = 9876
export let exp_name = 'John'
export def Exported(): string
return 'Exported'
enddef
@ -205,7 +228,14 @@ def Test_vim9script()
vim9script
import {exported, Exported} from './Xexport.vim'
g:imported = exported
exported += 3
g:imported_added = exported
g:imported_func = Exported()
import {exp_name} from './Xexport.vim'
g:imported_name = exp_name
exp_name ..= ' Doe'
g:imported_name_appended = exp_name
END
writefile(import_script_lines, 'Ximport.vim')
@ -216,13 +246,18 @@ def Test_vim9script()
assert_equal('bobbie', g:result)
assert_equal('bob', g:localname)
assert_equal(9876, g:imported)
assert_equal(9879, g:imported_added)
assert_equal('Exported', g:imported_func)
assert_equal('John', g:imported_name)
assert_equal('John Doe', g:imported_name_appended)
assert_false(exists('g:name'))
unlet g:result
unlet g:localname
unlet g:imported
unlet g:imported_added
unlet g:imported_func
unlet g:imported_name g:imported_name_appended
delete('Ximport.vim')
delete('Xexport.vim')
@ -424,108 +459,22 @@ def do_something():
EOF
endfunc
def HasEval()
if has('eval')
echo 'yes'
def IfElse(what: number): string
let res = ''
if what == 1
res = "one"
elseif what == 2
res = "two"
else
echo 'no'
res = "three"
endif
return res
enddef
def HasNothing()
if has('nothing')
echo 'yes'
else
echo 'no'
endif
enddef
def Test_compile_const_expr()
assert_equal("\nyes", execute('call HasEval()'))
let instr = execute('disassemble HasEval')
assert_match('PUSHS "yes"', instr)
assert_notmatch('PUSHS "no"', instr)
assert_notmatch('JUMP', instr)
assert_equal("\nno", execute('call HasNothing()'))
instr = execute('disassemble HasNothing')
assert_notmatch('PUSHS "yes"', instr)
assert_match('PUSHS "no"', instr)
assert_notmatch('JUMP', instr)
enddef
func NotCompiled()
echo "not"
endfunc
let s:scriptvar = 4
let g:globalvar = 'g'
def s:ScriptFuncLoad(arg: string)
let local = 1
buffers
echo arg
echo local
echo v:version
echo s:scriptvar
echo g:globalvar
echo &tabstop
echo $ENVVAR
echo @z
enddef
def s:ScriptFuncStore()
let localnr = 1
localnr = 2
let localstr = 'abc'
localstr = 'xyz'
v:char = 'abc'
s:scriptvar = 'sv'
g:globalvar = 'gv'
&tabstop = 8
$ENVVAR = 'ev'
@z = 'rv'
enddef
def Test_disassemble()
assert_fails('disass NoFunc', 'E1061:')
assert_fails('disass NotCompiled', 'E1062:')
let res = execute('disass s:ScriptFuncLoad')
assert_match('<SNR>\d*_ScriptFuncLoad.*'
\ .. 'buffers.*'
\ .. ' EXEC \+buffers.*'
\ .. ' LOAD arg\[-1\].*'
\ .. ' LOAD $0.*'
\ .. ' LOADV v:version.*'
\ .. ' LOADS s:scriptvar from .*test_vim9_script.vim.*'
\ .. ' LOADG g:globalvar.*'
\ .. ' LOADENV $ENVVAR.*'
\ .. ' LOADREG @z.*'
\, res)
" TODO:
" v:char =
" s:scriptvar =
res = execute('disass s:ScriptFuncStore')
assert_match('<SNR>\d*_ScriptFuncStore.*'
\ .. 'localnr = 2.*'
\ .. ' STORE 2 in $0.*'
\ .. 'localstr = ''xyz''.*'
\ .. ' STORE $1.*'
\ .. 'v:char = ''abc''.*'
\ .. 'STOREV v:char.*'
\ .. 's:scriptvar = ''sv''.*'
\ .. ' STORES s:scriptvar in .*test_vim9_script.vim.*'
\ .. 'g:globalvar = ''gv''.*'
\ .. ' STOREG g:globalvar.*'
\ .. '&tabstop = 8.*'
\ .. ' STOREOPT &tabstop.*'
\ .. '$ENVVAR = ''ev''.*'
\ .. ' STOREENV $ENVVAR.*'
\ .. '@z = ''rv''.*'
\ .. ' STOREREG @z.*'
\, res)
def Test_if_elseif_else()
assert_equal('one', IfElse(1))
assert_equal('two', IfElse(2))
assert_equal('three', IfElse(3))
enddef

View File

@ -631,6 +631,19 @@ f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
#endif
}
/*
* "test_clear_search_pat()"
* Free the last search and substitute patterns
*/
void
f_test_clear_search_pat(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{
free_last_pat(RE_SUBST);
free_last_pat(RE_SEARCH);
set_old_sub(NULL);
free_regexp_prev_sub();
}
/*
* "test_feedinput()"
*/

View File

@ -200,6 +200,7 @@ get_function_args(
{
typval_T rettv;
// find the end of the expression (doesn't evaluate it)
any_default = TRUE;
p = skipwhite(p) + 1;
p = skipwhite(p);
@ -572,8 +573,6 @@ get_func_tv(
return ret;
}
#define FLEN_FIXED 40
/*
* Return TRUE if "p" starts with "<SID>" or "s:".
* Only works if eval_fname_script() returned non-zero for "p"!
@ -590,7 +589,7 @@ eval_fname_sid(char_u *p)
* Use "fname_buf[FLEN_FIXED + 1]" when it fits, otherwise allocate memory
* (slow).
*/
static char_u *
char_u *
fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error)
{
int llen;

View File

@ -742,6 +742,50 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
229,
/**/
228,
/**/
227,
/**/
226,
/**/
225,
/**/
224,
/**/
223,
/**/
222,
/**/
221,
/**/
220,
/**/
219,
/**/
218,
/**/
217,
/**/
216,
/**/
215,
/**/
214,
/**/
213,
/**/
212,
/**/
211,
/**/
210,
/**/
209,
/**/
208,
/**/
207,
/**/

View File

@ -2574,6 +2574,9 @@ typedef enum {
#define FCERR_DELETED 7
#define FCERR_NOTMETHOD 8 // function cannot be used as a method
// fixed buffer length for fname_trans_sid()
#define FLEN_FIXED 40
// flags for find_name_end()
#define FNE_INCL_BR 1 // include [] in name
#define FNE_CHECK_START 2 // check name starts with valid character

View File

@ -130,7 +130,6 @@ typedef struct {
typedef enum {
JUMP_ALWAYS,
JUMP_IF_TRUE, // pop and jump if true
JUMP_IF_FALSE, // pop and jump if false
JUMP_AND_KEEP_IF_TRUE, // jump if top of stack is true, drop if not
JUMP_AND_KEEP_IF_FALSE, // jump if top of stack is false, drop if not

View File

@ -956,11 +956,12 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount)
* Return FAIL if the number of arguments is wrong.
*/
static int
generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int argcount)
generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
int regular_args = ufunc->uf_args.ga_len;
int argcount = pushed_argcount;
if (argcount > regular_args && !has_varargs(ufunc))
{
@ -978,9 +979,13 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int argcount)
{
int count = argcount - regular_args;
// TODO: add default values for optional arguments?
generate_NEWLIST(cctx, count < 0 ? 0 : count);
argcount = regular_args + 1;
// If count is negative an empty list will be added after evaluating
// default values for missing optional arguments.
if (count >= 0)
{
generate_NEWLIST(cctx, count);
argcount = regular_args + 1;
}
}
if ((isn = generate_instr(cctx,
@ -1681,49 +1686,60 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init)
char_u *p;
int argcount = argcount_init;
char_u namebuf[100];
char_u fname_buf[FLEN_FIXED + 1];
char_u *tofree = NULL;
int error = FCERR_NONE;
ufunc_T *ufunc;
int res = FAIL;
if (varlen >= sizeof(namebuf))
{
semsg(_("E1011: name too long: %s"), name);
return FAIL;
}
vim_strncpy(namebuf, name, varlen);
vim_strncpy(namebuf, *arg, varlen);
name = fname_trans_sid(namebuf, fname_buf, &tofree, &error);
*arg = skipwhite(*arg + varlen + 1);
if (compile_arguments(arg, cctx, &argcount) == FAIL)
return FAIL;
goto theend;
if (ASCII_ISLOWER(*name))
if (ASCII_ISLOWER(*name) && name[1] != ':')
{
int idx;
// builtin function
idx = find_internal_func(namebuf);
idx = find_internal_func(name);
if (idx >= 0)
return generate_BCALL(cctx, idx, argcount);
{
res = generate_BCALL(cctx, idx, argcount);
goto theend;
}
semsg(_(e_unknownfunc), namebuf);
}
// User defined function or variable must start with upper case.
if (!ASCII_ISUPPER(*name))
{
semsg(_("E1012: Invalid function name: %s"), namebuf);
return FAIL;
}
// If we can find the function by name generate the right call.
ufunc = find_func(namebuf, cctx);
ufunc = find_func(name, cctx);
if (ufunc != NULL)
return generate_CALL(cctx, ufunc, argcount);
{
res = generate_CALL(cctx, ufunc, argcount);
goto theend;
}
// If the name is a variable, load it and use PCALL.
p = namebuf;
if (compile_load(&p, namebuf + varlen, cctx, FALSE) == OK)
return generate_PCALL(cctx, argcount, FALSE);
{
res = generate_PCALL(cctx, argcount, FALSE);
goto theend;
}
// The function may be defined only later. Need to figure out at runtime.
return generate_UCALL(cctx, namebuf, argcount);
res = generate_UCALL(cctx, name, argcount);
theend:
vim_free(tofree);
return res;
}
// like NAMESPACE_CHAR but with 'a' and 'l'.
@ -2326,7 +2342,7 @@ compile_subscript(
emsg(_(e_missbrac));
return FAIL;
}
*arg = skipwhite(*arg + 1);
*arg = *arg + 1;
if (generate_instr_drop(cctx, ISN_INDEX, 1) == FAIL)
return FAIL;
@ -3411,13 +3427,51 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
else
{
// variables are always initialized
// TODO: support more types
if (ga_grow(instr, 1) == FAIL)
goto theend;
if (type->tt_type == VAR_STRING)
generate_PUSHS(cctx, vim_strsave((char_u *)""));
else
generate_PUSHNR(cctx, 0);
switch (type->tt_type)
{
case VAR_BOOL:
generate_PUSHBOOL(cctx, VVAL_FALSE);
break;
case VAR_SPECIAL:
generate_PUSHSPEC(cctx, VVAL_NONE);
break;
case VAR_FLOAT:
#ifdef FEAT_FLOAT
generate_PUSHF(cctx, 0.0);
#endif
break;
case VAR_STRING:
generate_PUSHS(cctx, NULL);
break;
case VAR_BLOB:
generate_PUSHBLOB(cctx, NULL);
break;
case VAR_FUNC:
// generate_PUSHS(cctx, NULL); TODO
break;
case VAR_PARTIAL:
// generate_PUSHS(cctx, NULL); TODO
break;
case VAR_LIST:
generate_NEWLIST(cctx, 0);
break;
case VAR_DICT:
generate_NEWDICT(cctx, 0);
break;
case VAR_JOB:
// generate_PUSHS(cctx, NULL); TODO
break;
case VAR_CHANNEL:
// generate_PUSHS(cctx, NULL); TODO
break;
case VAR_NUMBER:
case VAR_UNKNOWN:
case VAR_VOID:
generate_PUSHNR(cctx, 0);
break;
}
}
if (oplen > 0 && *op != '=')
@ -3678,6 +3732,7 @@ evaluate_const_and_or(char_u **arg, cctx_T *cctx, char *op, typval_T *tv)
// eval the next expression
*arg = skipwhite(p + 2);
tv2.v_type = VAR_UNKNOWN;
tv2.v_lock = 0;
if ((opchar == '|' ? evaluate_const_expr3(arg, cctx, &tv2)
: evaluate_const_expr7(arg, cctx, &tv2)) == FAIL)
{
@ -3874,7 +3929,7 @@ compile_elseif(char_u *arg, cctx_T *cctx)
}
cctx->ctx_locals.ga_len = scope->se_local_count;
if (cctx->ctx_skip != TRUE)
if (cctx->ctx_skip == MAYBE)
{
if (compile_jump_to_end(&scope->se_u.se_if.is_end_label,
JUMP_ALWAYS, cctx) == FAIL)
@ -3930,13 +3985,14 @@ compile_else(char_u *arg, cctx_T *cctx)
return NULL;
}
if (cctx->ctx_skip != TRUE)
if (cctx->ctx_skip == MAYBE)
{
if (scope->se_u.se_if.is_if_label >= 0)
{
// previous "if" or "elseif" jumps here
isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label;
isn->isn_arg.jump.jump_where = instr->ga_len;
scope->se_u.se_if.is_if_label = -1;
}
}
@ -4368,13 +4424,33 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED)
}
else
{
char_u *end;
char_u *pat;
char_u *tofree = NULL;
size_t len;
// Push v:exception, push {expr} and MATCH
generate_instr_type(cctx, ISN_PUSHEXC, &t_string);
if (compile_expr1(&p, cctx) == FAIL)
return NULL;
end = skip_regexp(p + 1, *p, TRUE, &tofree);
if (*end != *p)
{
semsg(_("E1067: Separator mismatch: %s"), p);
vim_free(tofree);
return FAIL;
}
if (tofree == NULL)
len = end - (p + 1);
else
len = end - (tofree + 1);
pat = vim_strnsave(p + 1, len);
vim_free(tofree);
p += len + 2;
if (pat == NULL)
return FAIL;
if (generate_PUSHS(cctx, pat) == FAIL)
return FAIL;
// TODO: check for strings?
if (generate_COMPARE(cctx, EXPR_MATCH, FALSE) == FAIL)
return NULL;
@ -4579,6 +4655,44 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
// Most modern script version.
current_sctx.sc_version = SCRIPT_VERSION_VIM9;
if (ufunc->uf_def_args.ga_len > 0)
{
int count = ufunc->uf_def_args.ga_len;
int i;
char_u *arg;
int off = STACK_FRAME_SIZE + (ufunc->uf_va_name != NULL ? 1 : 0);
// Produce instructions for the default values of optional arguments.
// Store the instruction index in uf_def_arg_idx[] so that we know
// where to start when the function is called, depending on the number
// of arguments.
ufunc->uf_def_arg_idx = ALLOC_CLEAR_MULT(int, count + 1);
if (ufunc->uf_def_arg_idx == NULL)
goto erret;
for (i = 0; i < count; ++i)
{
ufunc->uf_def_arg_idx[i] = instr->ga_len;
arg = ((char_u **)(ufunc->uf_def_args.ga_data))[i];
if (compile_expr1(&arg, &cctx) == FAIL
|| generate_STORE(&cctx, ISN_STORE,
i - count - off, NULL) == FAIL)
goto erret;
}
// If a varargs is following, push an empty list.
if (ufunc->uf_va_name != NULL)
{
if (generate_NEWLIST(&cctx, 0) == FAIL
|| generate_STORE(&cctx, ISN_STORE, -off, NULL) == FAIL)
goto erret;
}
ufunc->uf_def_arg_idx[count] = instr->ga_len;
}
/*
* Loop over all the lines of the function and generate instructions.
*/
for (;;)
{
if (line != NULL && *line == '|')

View File

@ -70,7 +70,7 @@ typedef struct {
#define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + idx)
/*
* Return the number of arguments, including any vararg.
* Return the number of arguments, including optional arguments and any vararg.
*/
static int
ufunc_argcount(ufunc_T *ufunc)
@ -78,6 +78,35 @@ ufunc_argcount(ufunc_T *ufunc)
return ufunc->uf_args.ga_len + (ufunc->uf_va_name != NULL ? 1 : 0);
}
/*
* Set the instruction index, depending on omitted arguments, where the default
* values are to be computed. If all optional arguments are present, start
* with the function body.
* The expression evaluation is at the start of the instructions:
* 0 -> EVAL default1
* STORE arg[-2]
* 1 -> EVAL default2
* STORE arg[-1]
* 2 -> function body
*/
static void
init_instr_idx(ufunc_T *ufunc, int argcount, ectx_T *ectx)
{
if (ufunc->uf_def_args.ga_len == 0)
ectx->ec_iidx = 0;
else
{
int defcount = ufunc->uf_args.ga_len - argcount;
// If there is a varargs argument defcount can be negative, no defaults
// to evaluate then.
if (defcount < 0)
defcount = 0;
ectx->ec_iidx = ufunc->uf_def_arg_idx[
ufunc->uf_def_args.ga_len - defcount];
}
}
/*
* Call compiled function "cdf_idx" from compiled code.
*
@ -107,23 +136,15 @@ call_dfunc(int cdf_idx, int argcount, ectx_T *ectx)
if (ga_grow(&ectx->ec_stack, optcount + 3 + dfunc->df_varcount) == FAIL)
return FAIL;
// TODO: Put omitted argument default values on the stack.
if (optcount > 0)
{
emsg("optional arguments not implemented yet");
return FAIL;
}
if (optcount < 0)
{
emsg("argument count wrong?");
return FAIL;
}
// for (idx = argcount - dfunc->df_minarg;
// idx < dfunc->df_maxarg; ++idx)
// {
// copy_tv(&dfunc->df_defarg[idx], STACK_TV_BOT(0));
// ++ectx->ec_stack.ga_len;
// }
// Reserve space for omitted optional arguments, filled in soon.
// Also any empty varargs argument.
ectx->ec_stack.ga_len += optcount;
// Store current execution state in stack frame for ISN_RETURN.
// TODO: If the actual number of arguments doesn't match what the called
@ -142,7 +163,9 @@ call_dfunc(int cdf_idx, int argcount, ectx_T *ectx)
ectx->ec_dfunc_idx = cdf_idx;
ectx->ec_instr = dfunc->df_instr;
estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1);
ectx->ec_iidx = 0;
// Decide where to start execution, handles optional arguments.
init_instr_idx(ufunc, argcount, ectx);
return OK;
}
@ -156,9 +179,9 @@ call_dfunc(int cdf_idx, int argcount, ectx_T *ectx)
static void
func_return(ectx_T *ectx)
{
int ret_idx = ectx->ec_stack.ga_len - 1;
int idx;
dfunc_T *dfunc;
int top;
// execution context goes one level up
estack_pop();
@ -166,17 +189,27 @@ func_return(ectx_T *ectx)
// Clear the local variables and temporary values, but not
// the return value.
for (idx = ectx->ec_frame + STACK_FRAME_SIZE;
idx < ectx->ec_stack.ga_len - 1; ++idx)
idx < ectx->ec_stack.ga_len - 1; ++idx)
clear_tv(STACK_TV(idx));
// Clear the arguments.
dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
ectx->ec_stack.ga_len = ectx->ec_frame
- ufunc_argcount(dfunc->df_ufunc) + 1;
top = ectx->ec_frame - ufunc_argcount(dfunc->df_ufunc);
for (idx = top; idx < ectx->ec_frame; ++idx)
clear_tv(STACK_TV(idx));
// Restore the previous frame.
ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame)->vval.v_number;
ectx->ec_iidx = STACK_TV(ectx->ec_frame + 1)->vval.v_number;
ectx->ec_frame = STACK_TV(ectx->ec_frame + 2)->vval.v_number;
*STACK_TV_BOT(-1) = *STACK_TV(ret_idx);
dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
ectx->ec_instr = dfunc->df_instr;
// Reset the stack to the position before the call, move the return value
// to the top of the stack.
idx = ectx->ec_stack.ga_len - 1;
ectx->ec_stack.ga_len = top + 1;
*STACK_TV_BOT(-1) = *STACK_TV(idx);
}
#undef STACK_TV
@ -362,7 +395,7 @@ call_def_function(
int idx;
int ret = FAIL;
dfunc_T *dfunc;
int optcount = ufunc_argcount(ufunc) - argc;
int defcount = ufunc->uf_args.ga_len - argc;
// Get pointer to item in the stack.
#define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
@ -388,17 +421,18 @@ call_def_function(
copy_tv(&argv[idx], STACK_TV_BOT(0));
++ectx.ec_stack.ga_len;
}
// Make space for omitted arguments, will store default value below.
if (defcount > 0)
for (idx = 0; idx < defcount; ++idx)
{
STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
++ectx.ec_stack.ga_len;
}
// Frame pointer points to just after arguments.
ectx.ec_frame = ectx.ec_stack.ga_len;
initial_frame_ptr = ectx.ec_frame;
// TODO: Put omitted argument default values on the stack.
if (optcount > 0)
{
emsg("optional arguments not implemented yet");
return FAIL;
}
// dummy frame entries
for (idx = 0; idx < STACK_FRAME_SIZE; ++idx)
{
@ -413,7 +447,10 @@ call_def_function(
ectx.ec_stack.ga_len += dfunc->df_varcount;
ectx.ec_instr = dfunc->df_instr;
ectx.ec_iidx = 0;
// Decide where to start execution, handles optional arguments.
init_instr_idx(ufunc, argc, &ectx);
for (;;)
{
isn_T *iptr;
@ -964,8 +1001,7 @@ call_def_function(
if (when == JUMP_IF_FALSE
|| when == JUMP_AND_KEEP_IF_FALSE)
jump = !jump;
if (when == JUMP_IF_FALSE || when == JUMP_IF_TRUE
|| !jump)
if (when == JUMP_IF_FALSE || !jump)
{
// drop the value from the stack
clear_tv(tv);
@ -1546,15 +1582,14 @@ failed:
return ret;
}
#define DISASSEMBLE 1
/*
* ":dissassemble".
* We don't really need this at runtime, but we do have tests that require it,
* so always include this.
*/
void
ex_disassemble(exarg_T *eap)
{
#ifdef DISASSEMBLE
char_u *fname;
ufunc_T *ufunc;
dfunc_T *dfunc;
@ -1587,6 +1622,7 @@ ex_disassemble(exarg_T *eap)
for (current = 0; current < dfunc->df_instr_count; ++current)
{
isn_T *iptr = &instr[current];
char *line;
while (line_idx < iptr->isn_lnum && line_idx < ufunc->uf_lines.ga_len)
{
@ -1595,7 +1631,9 @@ ex_disassemble(exarg_T *eap)
msg_puts("\n\n");
prev_current = current;
}
msg(((char **)ufunc->uf_lines.ga_data)[line_idx++]);
line = ((char **)ufunc->uf_lines.ga_data)[line_idx++];
if (line != NULL)
msg(line);
}
switch (iptr->isn_type)
@ -1657,7 +1695,11 @@ ex_disassemble(exarg_T *eap)
break;
case ISN_STORE:
smsg("%4d STORE $%lld", current, iptr->isn_arg.number);
if (iptr->isn_arg.number < 0)
smsg("%4d STORE arg[%lld]", current,
iptr->isn_arg.number + STACK_FRAME_SIZE);
else
smsg("%4d STORE $%lld", current, iptr->isn_arg.number);
break;
case ISN_STOREV:
smsg("%4d STOREV v:%s", current,
@ -1726,7 +1768,7 @@ ex_disassemble(exarg_T *eap)
char_u *tofree;
r = blob2string(iptr->isn_arg.blob, &tofree, numbuf);
smsg("%4d PUSHBLOB \"%s\"", current, r);
smsg("%4d PUSHBLOB %s", current, r);
vim_free(tofree);
}
break;
@ -1799,9 +1841,6 @@ ex_disassemble(exarg_T *eap)
case JUMP_ALWAYS:
when = "JUMP";
break;
case JUMP_IF_TRUE:
when = "JUMP_IF_TRUE";
break;
case JUMP_AND_KEEP_IF_TRUE:
when = "JUMP_AND_KEEP_IF_TRUE";
break;
@ -1956,7 +1995,6 @@ ex_disassemble(exarg_T *eap)
case ISN_DROP: smsg("%4d DROP", current); break;
}
}
#endif
}
/*