Compare commits

...

14 Commits

Author SHA1 Message Date
3a53ec8bdd patch 8.2.1330: Github workflow takes longer than needed
Problem:    Github workflow takes longer than needed.
Solution:   Do two test runs in parallel instead of sequentially. (Ken Takata,
            closes #6579)
2020-07-31 22:17:32 +02:00
38ddf333f6 patch 8.2.1329: Vim9: cannot define global function inside :def function
Problem:    Vim9: cannot define global function inside :def function.
Solution:   Assign to global variable instead of local. (closes #6584)
2020-07-31 22:05:04 +02:00
4d4d1cd5c8 patch 8.2.1328: no space allowed before comma in list
Problem:    No space allowed before comma in list.
Solution:   Legacy Vim script allows it. (closes #6577)
2020-07-30 22:14:33 +02:00
f4ee528086 patch 8.2.1327: Mac: configure can't find Tcl libraries
Problem:    Mac: configure can't find Tcl libraries.
Solution:   Adjust configure check. (closes #6575)
2020-07-30 20:18:08 +02:00
9d48956681 patch 8.2.1326: Vim9: skipping over white space after list
Problem:    Vim9: skipping over white space after list.
Solution:   Do not skip white space, a following [] would be misinterpreted.
            (closes #6552)  Fix a few side effects.
2020-07-30 20:08:50 +02:00
ea2d8d2571 patch 8.2.1325: Vim9: using Vim9 script for autaload not tested
Problem:    Vim9: using Vim9 script for autaload not tested.
Solution:   Add a test.  Update help.
2020-07-29 22:11:05 +02:00
c7e44a7e4c patch 8.2.1324: Vim9: line break after "=" does not work
Problem:    Vim9: line break after "=" does not work.
Solution:   Also allow for NUL after "=". (closes #6549)
2020-07-29 21:37:43 +02:00
696ba23149 patch 8.2.1323: Vim9: invalid operators only rejected in :def function
Problem:    Vim9: invalid operators only rejected in :def function.
Solution:   Also reject them at script level. (closes #6564)
2020-07-29 21:20:41 +02:00
1040956292 patch 8.2.1322: Vim9: method on double quoted string doesn't work
Problem:    Vim9: method on double quoted string doesn't work.
Solution:   Recognize double quoted string. (closes #6562)
2020-07-29 20:00:38 +02:00
7b7f78f51d patch 8.2.1321: GitHub CI also runs on tag push
Problem:    GitHub CI also runs on tag push.
Solution:   Skip CI on push. (Ken Takata, closes #6571)
2020-07-29 19:29:23 +02:00
33afa2447b patch 8.2.1320: Vim9: cannot declare some single letter variables
Problem:    Vim9: cannot declare some single letter variables.
Solution:   Do not recognize a colon for a namespace for single letter
            variables. (closes #6547)
2020-07-29 19:18:00 +02:00
ac7bf8c4bf patch 8.2.1319: status badge for Github CI has wrong link
Problem:    Status badge for Github CI has wrong link.
Solution:   Rename and use the right link
2020-07-29 17:43:55 +02:00
ed3c7e6339 patch 8.2.1318: no status badge for Github CI
Problem:    No status badge for Github CI.
Solution:   Add a badge.
2020-07-29 17:34:33 +02:00
f9a343f8bd patch 8.2.1317: MS-Windows tests on AppVeyor are slow
Problem:    MS-Windows tests on AppVeyor are slow.
Solution:   Use GitHub Actions. (Ken Takata, closes #6569)
2020-07-29 16:32:21 +02:00
36 changed files with 721 additions and 144 deletions

223
.github/workflows/ci-windows.yaml vendored Normal file
View File

@ -0,0 +1,223 @@
name: GitHub CI
on:
push:
branches:
- '*'
pull_request:
env:
VCVARSALL: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat
# Interfaces
# Lua
LUA_VER: 54
LUA_VER_DOT: '5.4'
LUA_RELEASE: 5.4.0
LUA32_URL: https://downloads.sourceforge.net/luabinaries/lua-%LUA_RELEASE%_Win32_dllw6_lib.zip
LUA64_URL: https://downloads.sourceforge.net/luabinaries/lua-%LUA_RELEASE%_Win64_dllw6_lib.zip
LUA_DIR: D:\Lua
# Python 2
PYTHON_VER: 27
PYTHON_VER_DOT: '2.7'
# Python 3
PYTHON3_VER: 38
PYTHON3_VER_DOT: '3.8'
# Other dependencies
# winpty
WINPTY_URL: https://github.com/rprichard/winpty/releases/download/0.4.3/winpty-0.4.3-msvc2015.zip
# Escape sequences
COL_RED: "\x1b[31m"
COL_GREEN: "\x1b[32m"
COL_YELLOW: "\x1b[33m"
COL_RESET: "\x1b[m"
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
toolchain: [msvc, mingw]
arch: [x64, x86]
features: [HUGE, NORMAL]
include:
- arch: x64
vcarch: amd64
warch: x64
bits: 64
msystem: MINGW64
cygreg: registry
pyreg: ""
- arch: x86
vcarch: x86
warch: ia32
bits: 32
msystem: MINGW32
cygreg: registry32
pyreg: "-32"
exclude:
- toolchain: msvc
arch: x64
features: NORMAL
- toolchain: mingw
arch: x86
features: NORMAL
steps:
- name: Initalize
id: init
shell: bash
run: |
git config --global core.autocrlf input
python_dir=$(cat "/proc/${{ matrix.cygreg }}/HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${PYTHON_VER_DOT}/InstallPath/@")
python3_dir=$(cat "/proc/${{ matrix.cygreg }}/HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${PYTHON3_VER_DOT}${{ matrix.pyreg }}/InstallPath/@")
echo "::set-env name=PYTHON_DIR::$python_dir"
echo "::set-env name=PYTHON3_DIR::$python3_dir"
- uses: msys2/setup-msys2@v2
if: matrix.toolchain == 'mingw'
with:
msystem: ${{ matrix.msystem }}
release: false
- uses: actions/checkout@v2
- name: Create a list of download URLs
shell: cmd
run: |
type NUL > urls.txt
echo %LUA_RELEASE%>> urls.txt
echo %WINPTY_URL%>> urls.txt
- name: Cache downloaded files
uses: actions/cache@v2
with:
path: downloads
key: ${{ runner.os }}-${{ matrix.bits }}-${{ hashFiles('urls.txt') }}
- name: Download dependencies
shell: cmd
run: |
path C:\Program Files\7-Zip;%path%
if not exist downloads mkdir downloads
echo %COL_GREEN%Download Lua%COL_RESET%
call :downloadfile %LUA${{ matrix.bits }}_URL% downloads\lua.zip
7z x downloads\lua.zip -o%LUA_DIR% > nul || exit 1
echo %COL_GREEN%Download winpty%COL_RESET%
call :downloadfile %WINPTY_URL% downloads\winpty.zip
7z x -y downloads\winpty.zip -oD:\winpty > nul || exit 1
copy /Y D:\winpty\${{ matrix.warch }}\bin\winpty.dll src\winpty${{ matrix.bits }}.dll
copy /Y D:\winpty\${{ matrix.warch }}\bin\winpty-agent.exe src\
goto :eof
:downloadfile
:: call :downloadfile <URL> <localfile>
if not exist %2 (
curl -f -L %1 -o %2
)
if ERRORLEVEL 1 (
rem Retry once.
curl -f -L %1 -o %2 || exit 1
)
goto :eof
- name: Build (MSVC)
if: matrix.toolchain == 'msvc'
shell: cmd
run: |
call "%VCVARSALL%" ${{ matrix.vcarch }}
cd src
:: Filter out the progress bar from the build log
sed -e "s/@<<$/@<< | sed -e 's#.*\\\\r.*##'/" Make_mvc.mak > Make_mvc2.mak
if "${{ matrix.features }}"=="HUGE" (
nmake -nologo -f Make_mvc2.mak ^
FEATURES=${{ matrix.features }} ^
GUI=yes IME=yes ICONV=yes VIMDLL=yes ^
DYNAMIC_LUA=yes LUA=%LUA_DIR% ^
DYNAMIC_PYTHON=yes PYTHON=%PYTHON_DIR% ^
DYNAMIC_PYTHON3=yes PYTHON3=%PYTHON3_DIR%
) else (
nmake -nologo -f Make_mvc2.mak ^
FEATURES=${{ matrix.features }} ^
GUI=yes IME=yes ICONV=yes VIMDLL=yes
)
if not exist vim${{ matrix.bits }}.dll (
echo %COL_RED%Build failure.%COL_RESET%
exit 1
)
- name: Build (MinGW)
if: matrix.toolchain == 'mingw'
shell: msys2 {0}
run: |
cd src
if [ "${{ matrix.features }}" = "HUGE" ]; then
mingw32-make -f Make_ming.mak -j2 \
FEATURES=${{ matrix.features }} \
GUI=yes IME=yes ICONV=yes VIMDLL=yes \
DYNAMIC_LUA=yes LUA=${LUA_DIR} \
DYNAMIC_PYTHON=yes PYTHON=${PYTHON_DIR} \
DYNAMIC_PYTHON3=yes PYTHON3=${PYTHON3_DIR} \
STATIC_STDCPLUS=yes
else
mingw32-make -f Make_ming.mak -j2 \
FEATURES=${{ matrix.features }} \
GUI=yes IME=yes ICONV=yes VIMDLL=yes \
STATIC_STDCPLUS=yes
fi
# - name: Prepare Artifact
# shell: cmd
# run: |
# mkdir artifacts
# copy src\*vim.exe artifacts
# copy src\vim*.dll artifacts
#
# - name: Upload Artifact
# uses: actions/upload-artifact@v1
# with:
# name: vim${{ matrix.bits }}-${{ matrix.toolchain }}
# path: ./artifacts
- name: Test
shell: cmd
timeout-minutes: 20
run: |
PATH %LUA_DIR%;C:\msys64\${{ matrix.msystem }}\bin;%PATH%;%PYTHON3_DIR%
call "%VCVARSALL%" ${{ matrix.vcarch }}
cd src
echo.
echo %COL_GREEN%vim version:%COL_RESET%
.\vim --version || exit 1
mkdir ..\src2
xcopy testdir ..\src2\testdir\ /E > nul || exit 1
copy evalfunc.c ..\src2 > nul
echo %COL_GREEN%Start testing vim in background.%COL_RESET%
start cmd /c "cd ..\src2\testdir & nmake -nologo -f Make_dos.mak VIMPROG=..\..\src\vim > nul & echo done>done.txt"
echo %COL_GREEN%Test gvim:%COL_RESET%
cd testdir
nmake -nologo -f Make_dos.mak VIMPROG=..\gvim || exit 1
cd ..
echo %COL_GREEN%Wait for vim tests to finish.%COL_RESET%
cd ..\src2\testdir
:: Wait about 5 minutes.
for /L %%i in (1,1,300) do (
if exist done.txt goto exitloop
ping -n 2 localhost > nul
)
echo %COL_RED%Timed out.%COL_RESET%
:exitloop
echo %COL_GREEN%Test results of vim:%COL_RESET%
if exist messages type messages
nmake -nologo -f Make_dos.mak report VIMPROG=..\..\src\vim || exit 1

View File

@ -9,6 +9,7 @@ SRC_ALL = \
.lgtm.yml \
.travis.yml \
.cirrus.yml \
.github/workflows/ci-windows.yaml \
appveyor.yml \
ci/appveyor.bat \
ci/if_ver*.vim \

View File

@ -2,6 +2,7 @@
[![Travis Build Status](https://travis-ci.org/vim/vim.svg?branch=master)](https://travis-ci.org/vim/vim)
[![Appveyor Build status](https://ci.appveyor.com/api/projects/status/o2qht2kjm02sgghk?svg=true)](https://ci.appveyor.com/project/chrisbra/vim)
[![Github Build status](https://github.com/vim/vim/workflows/GitHub%20CI/badge.svg)](https://github.com/vim/vim/actions?query=workflow%3A%22GitHub+CI%22)
[![Cirrus Build Status](https://api.cirrus-ci.com/github/vim/vim.svg)](https://cirrus-ci.com/github/vim/vim)
[![Coverage Status](https://codecov.io/gh/vim/vim/coverage.svg?branch=master)](https://codecov.io/gh/vim/vim?branch=master)
[![Coverity Scan](https://scan.coverity.com/projects/241/badge.svg)](https://scan.coverity.com/projects/vim)

View File

@ -5,16 +5,17 @@ skip_tags: true
environment:
matrix:
- FEATURE: HUGE
- FEATURE: NORMAL
# disabled
# - FEATURE: TINY
# - FEATURE: SMALL
# - FEATURE: NORMAL
# - FEATURE: BIG
matrix:
fast_finish: true
before_build:
# Use Windows SDK 7.1 (= MSVC 2010)
- '"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 /release'
- 'set INCLUDE=%INCLUDE%C:\Program Files (x86)\Windows Kits\8.1\Include\um'
@ -25,9 +26,9 @@ test_script:
- cd src/testdir
# Testing with MSVC gvim
- path C:\Python35-x64;%PATH%
- nmake -f Make_dos.mak POSTSCRIPT=yes VIMPROG=..\gvim
- nmake -f Make_dos.mak VIMPROG=..\gvim
- nmake -f Make_dos.mak clean
# Testing with MingW console version
- nmake -f Make_dos.mak POSTSCRIPT=yes VIMPROG=..\vim
# Testing with MSVC console version
- nmake -f Make_dos.mak VIMPROG=..\vim
# vim: sw=2 sts=2 et ts=8 sr

View File

@ -5,48 +5,32 @@ setlocal ENABLEDELAYEDEXPANSION
cd %APPVEYOR_BUILD_FOLDER%
cd src
echo "Building MinGW 32bit console version"
set PATH=c:\msys64\mingw32\bin;%PATH%
mingw32-make.exe -f Make_ming.mak GUI=no OPTIMIZE=speed IME=yes ICONV=yes DEBUG=no FEATURES=%FEATURE% || exit 1
.\vim -u NONE -c "redir @a | ver |0put a | wq" ver_ming.txt
:: Save vim.exe before Make clean, moved back below.
copy vim.exe testdir
mingw32-make.exe -f Make_ming.mak clean
:: Build Mingw huge version with python and channel support, or
:: with specified features without python.
echo "Building MinGW 32bit GUI version"
if "%FEATURE%" == "HUGE" (
mingw32-make.exe -f Make_ming.mak OPTIMIZE=speed CHANNEL=yes GUI=yes IME=yes ICONV=yes DEBUG=no PYTHON_VER=27 DYNAMIC_PYTHON=yes PYTHON=C:\Python27 PYTHON3_VER=35 DYNAMIC_PYTHON3=yes PYTHON3=C:\Python35 FEATURES=%FEATURE% || exit 1
) ELSE (
mingw32-make.exe -f Make_ming.mak OPTIMIZE=speed GUI=yes IME=yes ICONV=yes DEBUG=no FEATURES=%FEATURE% || exit 1
)
.\gvim -u NONE -c "redir @a | ver |0put a | wq" ver_ming_gui.txt
:: Filter out the progress bar from the build log
sed -e "s/@<<$/@<< | sed -e 's#.*\\\\r.*##'/" Make_mvc.mak > Make_mvc2.mak
echo "Building MSVC 64bit console Version"
nmake -f Make_mvc2.mak CPU=AMD64 OLE=no GUI=no IME=yes ICONV=yes DEBUG=no FEATURES=%FEATURE% || exit 1
:: The executable is not used
nmake -f Make_mvc2.mak clean
nmake -f Make_mvc2.mak CPU=AMD64 ^
OLE=no GUI=no IME=yes ICONV=yes DEBUG=no ^
FEATURES=%FEATURE% || exit 1
:: build MSVC huge version with python and channel support
:: GUI needs to be last, so that testing works
echo "Building MSVC 64bit GUI Version"
if "%FEATURE%" == "HUGE" (
nmake -f Make_mvc2.mak DIRECTX=yes CPU=AMD64 CHANNEL=yes OLE=no GUI=yes IME=yes ICONV=yes DEBUG=no PYTHON_VER=27 DYNAMIC_PYTHON=yes PYTHON=C:\Python27-x64 PYTHON3_VER=35 DYNAMIC_PYTHON3=yes PYTHON3=C:\Python35-x64 FEATURES=%FEATURE% || exit 1
nmake -f Make_mvc2.mak CPU=AMD64 ^
OLE=no GUI=yes IME=yes ICONV=yes DEBUG=no POSTSCRIPT=yes ^
PYTHON_VER=27 DYNAMIC_PYTHON=yes PYTHON=C:\Python27-x64 ^
PYTHON3_VER=35 DYNAMIC_PYTHON3=yes PYTHON3=C:\Python35-x64 ^
FEATURES=%FEATURE% || exit 1
) ELSE (
nmake -f Make_mvc2.mak CPU=AMD64 OLE=no GUI=yes IME=yes ICONV=yes DEBUG=no FEATURES=%FEATURE% || exit 1
nmake -f Make_mvc2.mak CPU=AMD64 ^
OLE=no GUI=yes IME=yes ICONV=yes DEBUG=no ^
FEATURES=%FEATURE% || exit 1
)
.\gvim -u NONE -c "redir @a | ver |0put a | wq" ver_msvc.txt
:: Restore vim.exe, tests will run with this.
move /Y testdir\vim.exe .
echo "version output MinGW"
type ver_ming.txt
echo "version output MinGW GUI"
type ver_ming_gui.txt
echo "version output MVC"
echo "version output MSVC console"
.\vim --version
echo "version output MSVC GUI"
type ver_msvc.txt
cd ..

View File

@ -118,9 +118,13 @@ Functions and variables are script-local by default ~
*vim9-scopes*
When using `:function` or `:def` to specify a new function at the script level
in a Vim9 script, the function is local to the script, as if "s:" was
prefixed. Using the "s:" prefix is optional.
To define or use a global function or variable the "g:" prefix must be used.
prefixed. Using the "s:" prefix is optional. To define or use a global
function or variable the "g:" prefix must be used. For functions in an
autoload script the "name#" prefix is sufficient. >
def ThisFunction() # script-local
def s:ThisFunction() # script-local
def g:ThatFunction() # global
def scriptname#function() # autoload
When using `:function` or `:def` to specify a new function inside a function,
the function is local to the function. It is not possible to define a

5
src/auto/configure vendored
View File

@ -7417,7 +7417,7 @@ $as_echo_n "checking for location of Tcl include... " >&6; }
if test "x$MACOS_X" != "xyes"; then
tclinc="$tclloc/include $tclloc/include/tcl $tclloc/include/tcl$tclver /usr/local/include /usr/local/include/tcl$tclver /usr/include /usr/include/tcl$tclver"
else
tclinc="/System/Library/Frameworks/Tcl.framework/Headers"
tclinc="$tclloc/include $tclloc/include/tcl $tclloc/include/tcl$tclver /System/Library/Frameworks/Tcl.framework/Headers `xcrun --show-sdk-path`/System/Library/Frameworks/Tcl.framework/Versions/Current/Headers"
fi
TCL_INC=
for try in $tclinc; do
@ -7440,7 +7440,8 @@ $as_echo_n "checking for location of tclConfig.sh script... " >&6; }
tclcnf=`echo $tclinc | sed s/include/lib/g`
tclcnf="$tclcnf `echo $tclinc | sed s/include/lib64/g`"
else
tclcnf="/System/Library/Frameworks/Tcl.framework"
tclcnf=`echo $tclinc | sed s/include/lib/g`
tclcnf="$tclcnf /System/Library/Frameworks/Tcl.framework `xcrun --show-sdk-path`/System/Library/Frameworks/Tcl.framework"
fi
for try in $tclcnf; do
if test -f "$try/tclConfig.sh"; then

View File

@ -1820,8 +1820,10 @@ if test "$enable_tclinterp" = "yes" -o "$enable_tclinterp" = "dynamic"; then
if test "x$MACOS_X" != "xyes"; then
tclinc="$tclloc/include $tclloc/include/tcl $tclloc/include/tcl$tclver /usr/local/include /usr/local/include/tcl$tclver /usr/include /usr/include/tcl$tclver"
else
dnl For all macOS, use the value from TCL in case use of, say, homebrew
dnl For Mac OS X 10.3, use the OS-provided framework location
tclinc="/System/Library/Frameworks/Tcl.framework/Headers"
dnl For Mac OS X 10.14, the OS-provided framework location doesn't contain the headers, so also check the Xcode SDK
tclinc="$tclloc/include $tclloc/include/tcl $tclloc/include/tcl$tclver /System/Library/Frameworks/Tcl.framework/Headers `xcrun --show-sdk-path`/System/Library/Frameworks/Tcl.framework/Versions/Current/Headers"
fi
TCL_INC=
for try in $tclinc; do
@ -1841,8 +1843,11 @@ if test "$enable_tclinterp" = "yes" -o "$enable_tclinterp" = "dynamic"; then
tclcnf=`echo $tclinc | sed s/include/lib/g`
tclcnf="$tclcnf `echo $tclinc | sed s/include/lib64/g`"
else
dnl For all macOS, use the value from TCL in case use of, say, homebrew
dnl For Mac OS X 10.3, use the OS-provided framework location
tclcnf="/System/Library/Frameworks/Tcl.framework"
dnl For Mac OS X 10.14, the OS-provided framework location doesn't contain the headers, so also check the Xcode SDK
tclcnf=`echo $tclinc | sed s/include/lib/g`
tclcnf="$tclcnf /System/Library/Frameworks/Tcl.framework `xcrun --show-sdk-path`/System/Library/Frameworks/Tcl.framework"
fi
for try in $tclcnf; do
if test -f "$try/tclConfig.sh"; then

View File

@ -838,6 +838,10 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
: eval1(arg, &tvkey, evalarg)) == FAIL) // recursive!
goto failret;
// the colon should come right after the key, but this wasn't checked
// previously, so only require it in Vim9 script.
if (!vim9script)
*arg = skipwhite(*arg);
if (**arg != ':')
{
if (evaluate)
@ -891,7 +895,10 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
}
clear_tv(&tvkey);
// the comma must come after the value
// the comma should come right after the value, but this wasn't checked
// previously, so only require it in Vim9 script.
if (!vim9script)
*arg = skipwhite(*arg);
had_comma = **arg == ',';
if (had_comma)
{

View File

@ -1913,27 +1913,28 @@ eval_func(
char_u *
eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext)
{
char_u *p = skipwhite(arg);
*getnext = FALSE;
if (in_vim9script()
&& evalarg != NULL
&& (evalarg->eval_cookie != NULL || evalarg->eval_cctx != NULL)
&& (*arg == NUL || (VIM_ISWHITE(arg[-1])
&& vim9_comment_start(arg))))
&& (*p == NUL || (VIM_ISWHITE(p[-1]) && vim9_comment_start(p))))
{
char_u *p;
char_u *next;
if (evalarg->eval_cookie != NULL)
p = getline_peek(evalarg->eval_getline, evalarg->eval_cookie);
next = getline_peek(evalarg->eval_getline, evalarg->eval_cookie);
else
p = peek_next_line_from_context(evalarg->eval_cctx);
next = peek_next_line_from_context(evalarg->eval_cctx);
if (p != NULL)
if (next != NULL)
{
*getnext = TRUE;
return skipwhite(p);
return skipwhite(next);
}
}
return arg;
return p;
}
/*
@ -2039,6 +2040,7 @@ eval0(
p = skipwhite(arg);
ret = eval1(&p, rettv, evalarg);
p = skipwhite(p);
if (ret == FAIL || !ends_excmd2(arg, p))
{
@ -2107,6 +2109,8 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
if (getnext)
*arg = eval_next_line(evalarg_used);
else
*arg = p;
result = FALSE;
if (evaluate)
@ -2142,6 +2146,8 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
}
if (getnext)
*arg = eval_next_line(evalarg_used);
else
*arg = p;
/*
* Get the third variable. Recursive!
@ -2234,6 +2240,8 @@ eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
{
if (getnext)
*arg = eval_next_line(evalarg_used);
else
*arg = p;
/*
* Get the second variable.
@ -2349,6 +2357,8 @@ eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
{
if (getnext)
*arg = eval_next_line(evalarg_used);
else
*arg = p;
/*
* Get the second variable.
@ -2420,9 +2430,9 @@ eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
{
char_u *p;
int getnext;
int i;
exptype_T type = EXPR_UNKNOWN;
int len = 2;
int type_is = FALSE;
/*
* Get the first variable.
@ -2431,44 +2441,7 @@ eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
return FAIL;
p = eval_next_non_blank(*arg, evalarg, &getnext);
switch (p[0])
{
case '=': if (p[1] == '=')
type = EXPR_EQUAL;
else if (p[1] == '~')
type = EXPR_MATCH;
break;
case '!': if (p[1] == '=')
type = EXPR_NEQUAL;
else if (p[1] == '~')
type = EXPR_NOMATCH;
break;
case '>': if (p[1] != '=')
{
type = EXPR_GREATER;
len = 1;
}
else
type = EXPR_GEQUAL;
break;
case '<': if (p[1] != '=')
{
type = EXPR_SMALLER;
len = 1;
}
else
type = EXPR_SEQUAL;
break;
case 'i': if (p[1] == 's')
{
if (p[2] == 'n' && p[3] == 'o' && p[4] == 't')
len = 5;
i = p[len];
if (!isalnum(i) && i != '_')
type = len == 2 ? EXPR_IS : EXPR_ISNOT;
}
break;
}
type = get_compare_type(p, &len, &type_is);
/*
* If there is a comparative operator, use it.
@ -2482,6 +2455,13 @@ eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
if (getnext)
*arg = eval_next_line(evalarg);
if (vim9script && type_is && (p[len] == '?' || p[len] == '#'))
{
semsg(_(e_invexpr2), p);
clear_tv(rettv);
return FAIL;
}
// extra question mark appended: ignore case
if (p[len] == '?')
{
@ -2605,6 +2585,8 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
if (getnext)
*arg = eval_next_line(evalarg);
else
*arg = p;
evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
if ((op != '+' || (rettv->v_type != VAR_LIST
&& rettv->v_type != VAR_BLOB))
@ -2786,6 +2768,7 @@ eval6(
int evaluate;
int getnext;
typval_T var2;
char_u *p;
int op;
varnumber_T n1, n2;
#ifdef FEAT_FLOAT
@ -2793,12 +2776,15 @@ eval6(
#endif
int error;
op = *eval_next_non_blank(*arg, evalarg, &getnext);
p = eval_next_non_blank(*arg, evalarg, &getnext);
op = *p;
if (op != '*' && op != '/' && op != '%')
break;
if (getnext)
*arg = eval_next_line(evalarg);
else
*arg = p;
#ifdef FEAT_FLOAT
f1 = 0;
@ -3145,8 +3131,6 @@ eval7(
vim_free(alias);
}
*arg = skipwhite(*arg);
// Handle following '[', '(' and '.' for expr[expr], expr.name,
// expr(expr), expr->name(expr)
if (ret == OK)
@ -5182,7 +5166,7 @@ handle_subscript(
p = eval_next_non_blank(*arg, evalarg, &getnext);
if (getnext
&& ((rettv->v_type == VAR_DICT && *p == '.' && eval_isdictc(p[1]))
|| (*p == '-' && p[1] == '>'
|| (p[0] == '-' && p[1] == '>'
&& (p[2] == '{' || ASCII_ISALPHA(p[2])))))
{
*arg = eval_next_line(evalarg);
@ -5208,8 +5192,9 @@ handle_subscript(
dict_unref(selfdict);
selfdict = NULL;
}
else if (**arg == '-' && (*arg)[1] == '>')
else if (p[0] == '-' && p[1] == '>')
{
*arg = p;
if (ret == OK)
{
if ((*arg)[2] == '{')

View File

@ -801,13 +801,13 @@ ex_let(exarg_T *eap)
else
++expr;
if (vim9script && (!VIM_ISWHITE(*argend) || !VIM_ISWHITE(*expr)))
if (vim9script && (!VIM_ISWHITE(*argend)
|| !IS_WHITE_OR_NUL(*expr)))
{
vim_strncpy(op, expr - len, len);
semsg(_(e_white_both), op);
i = FAIL;
}
expr = skipwhite(expr);
if (eap->skip)
++emsg_skip;
@ -818,6 +818,7 @@ ex_let(exarg_T *eap)
evalarg.eval_getline = eap->getline;
evalarg.eval_cookie = eap->cookie;
}
expr = skipwhite_and_linebreak(expr, &evalarg);
i = eval0(expr, &rettv, eap, &evalarg);
if (eap->skip)
--emsg_skip;

View File

@ -3277,7 +3277,7 @@ find_ex_command(
char_u *pskip = (*eap->cmd == '&' || *eap->cmd == '$'
|| *eap->cmd == '@') ? eap->cmd + 1 : eap->cmd;
if (vim_strchr((char_u *)"{('[", *p) != NULL
if (vim_strchr((char_u *)"{('[\"", *p) != NULL
|| ((p = to_name_const_end(pskip)) > eap->cmd && *p != NUL))
{
int oplen;
@ -3293,6 +3293,8 @@ find_ex_command(
*eap->cmd == '{'
// "'string'->func()" is an expression.
|| *eap->cmd == '\''
// '"string"->func()' is an expression.
|| *eap->cmd == '"'
// "g:varname" is an expression.
|| eap->cmd[1] == ':'
)

View File

@ -1194,12 +1194,15 @@ eval_list(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int do_error)
else
clear_tv(&tv);
}
// Legacy Vim script allowed a space before the comma.
if (!vim9script)
*arg = skipwhite(*arg);
// the comma must come after the value
had_comma = **arg == ',';
if (had_comma)
{
if (vim9script && (*arg)[1] != NUL && !VIM_ISWHITE((*arg)[1]))
if (vim9script && !IS_WHITE_OR_NUL((*arg)[1]))
{
semsg(_(e_white_after), ",");
goto failret;
@ -1231,7 +1234,7 @@ failret:
return FAIL;
}
*arg = skipwhite(*arg + 1);
*arg += 1;
if (evaluate)
rettv_list_set(rettv, l);

View File

@ -2027,6 +2027,41 @@ ga_clear_strings(garray_T *gap)
ga_clear(gap);
}
/*
* Copy a growing array that contains a list of strings.
*/
int
ga_copy_strings(garray_T *from, garray_T *to)
{
int i;
ga_init2(to, sizeof(char_u *), 1);
if (ga_grow(to, from->ga_len) == FAIL)
return FAIL;
for (i = 0; i < from->ga_len; ++i)
{
char_u *orig = ((char_u **)from->ga_data)[i];
char_u *copy;
if (orig == NULL)
copy = NULL;
else
{
copy = vim_strsave(orig);
if (copy == NULL)
{
to->ga_len = i;
ga_clear_strings(to);
return FAIL;
}
}
((char_u **)to->ga_data)[i] = copy;
}
to->ga_len = from->ga_len;
return OK;
}
/*
* Initialize a growing array. Don't forget to set ga_itemsize and
* ga_growsize! Or use ga_init2().

View File

@ -56,6 +56,7 @@ char_u *vim_strrchr(char_u *string, int c);
int vim_isspace(int x);
void ga_clear(garray_T *gap);
void ga_clear_strings(garray_T *gap);
int ga_copy_strings(garray_T *from, garray_T *to);
void ga_init(garray_T *gap);
void ga_init2(garray_T *gap, int itemsize, int growsize);
int ga_grow(garray_T *gap, int n);

View File

@ -5,6 +5,7 @@ int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, garray_T
char_u *get_lambda_name(void);
char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state);
int get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
void copy_func(char_u *lambda, char_u *global);
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, evalarg_T *evalarg, funcexe_T *funcexe);

View File

@ -16,6 +16,7 @@ int vim9_comment_start(char_u *p);
char_u *peek_next_line_from_context(cctx_T *cctx);
char_u *next_line_from_context(cctx_T *cctx, int skip_comment);
char_u *to_name_const_end(char_u *arg);
exptype_T get_compare_type(char_u *p, int *len, int *type_is);
int assignment_len(char_u *p, int *heredoc);
void vim9_declare_error(char_u *name);
int check_vim9_unlet(char_u *name);

View File

@ -1546,6 +1546,7 @@ typedef enum {
/*
* Structure to hold info for a user function.
* When adding a field check copy_func().
*/
typedef struct
{
@ -1618,6 +1619,7 @@ typedef struct
#define FC_NOARGS 0x200 // no a: variables in lambda
#define FC_VIM9 0x400 // defined in vim9 script file
#define FC_CFUNC 0x800 // defined as Lua C func
#define FC_COPY 0x1000 // copy of another function by copy_func()
#define MAX_FUNC_ARGS 20 // maximum number of function arguments
#define VAR_SHORT_LEN 20 // short variable name length

View File

@ -0,0 +1,9 @@
vim9script
func auto9#getsome()
return 'some'
endfunc
def auto9#add42(count: number): number
return count + 42
enddef

View File

@ -17,3 +17,8 @@ func Test_source_autoload()
source sautest/autoload/sourced.vim
call assert_equal(1, g:loaded_sourced_vim)
endfunc
func Test_autoload_vim9script()
call assert_equal('some', auto9#getsome())
call assert_equal(49, auto9#add42(7))
endfunc

View File

@ -23,6 +23,9 @@ func Test_list_create()
call assert_equal(10, x)
endfunc
" This was allowed in legacy Vim script
let s:list_with_spaces = [1 , 2 , 3]
" List slices
func Test_list_slice()
let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
@ -202,6 +205,10 @@ func Test_dict()
call assert_fails("let d={'k' : i}", 'E121:')
endfunc
" This was allowed in legacy Vim script
let s:dict_with_spaces = {'one' : 1 , 'two' : 2 , 'three' : 3}
let s:dict_with_spaces_lit = #{one : 1 , two : 2 , three : 3}
" Dictionary identity
func Test_dict_identity()
let d = {001: 'asd', 'b': [1, 2, function('strlen')], -1: {'a': 1},}

View File

@ -699,6 +699,24 @@ def Test_disassemble_lambda()
instr)
enddef
def NestedOuter()
def g:Inner()
echomsg "inner"
enddef
enddef
def Test_nested_func()
let instr = execute('disassemble NestedOuter')
assert_match('NestedOuter\_s*' ..
'def g:Inner()\_s*' ..
'echomsg "inner"\_s*' ..
'enddef\_s*' ..
'\d NEWFUNC <lambda>\d\+ Inner\_s*' ..
'\d PUSHNR 0\_s*' ..
'\d RETURN',
instr)
enddef
def AndOr(arg: any): string
if arg == 1 && arg != 2 || arg == 4
return 'yes'

View File

@ -831,7 +831,7 @@ def Test_expr5()
enddef
def Test_expr5_vim9script()
# only checks line continuation
# check line continuation
let lines =<< trim END
vim9script
let var = 11
@ -848,6 +848,30 @@ def Test_expr5_vim9script()
assert_equal('onetwo', var)
END
CheckScriptSuccess(lines)
lines =<< trim END
vim9script
echo 'abc' is# 'abc'
END
CheckScriptFailure(lines, 'E15:')
lines =<< trim END
vim9script
echo 'abc' is? 'abc'
END
CheckScriptFailure(lines, 'E15:')
lines =<< trim END
vim9script
echo 'abc' isnot# 'abc'
END
CheckScriptFailure(lines, 'E15:')
lines =<< trim END
vim9script
echo 'abc' isnot? 'abc'
END
CheckScriptFailure(lines, 'E15:')
enddef
def Test_expr5_float()
@ -1638,8 +1662,9 @@ enddef
def Test_expr7_method_call()
new
setline(1, ['first', 'last'])
eval 'second'->append(1)
assert_equal(['first', 'second', 'last'], getline(1, '$'))
'second'->append(1)
"third"->append(2)
assert_equal(['first', 'second', 'third', 'last'], getline(1, '$'))
bwipe!
let bufnr = bufnr()

View File

@ -133,6 +133,28 @@ def Test_nested_function()
CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:')
enddef
def Test_nested_global_function()
let lines =<< trim END
vim9script
def Outer()
def g:Inner(): string
return 'inner'
enddef
enddef
disass Outer
Outer()
assert_equal('inner', g:Inner())
delfunc g:Inner
Outer()
assert_equal('inner', g:Inner())
delfunc g:Inner
Outer()
assert_equal('inner', g:Inner())
delfunc g:Inner
END
CheckScriptSuccess(lines)
enddef
func Test_call_default_args_from_func()
call assert_equal('string', MyDefaultArgs())
call assert_equal('one', MyDefaultArgs('one'))
@ -502,8 +524,11 @@ def Test_vim9script_call()
assert_equal('some', var)
# line starting with single quote is not a mark
# line starting with double quote can be a method call
'asdfasdf'->MyFunc()
assert_equal('asdfasdf', var)
"xyz"->MyFunc()
assert_equal('xyz', var)
def UseString()
'xyork'->MyFunc()
@ -511,6 +536,12 @@ def Test_vim9script_call()
UseString()
assert_equal('xyork', var)
def UseString2()
"knife"->MyFunc()
enddef
UseString2()
assert_equal('knife', var)
# prepending a colon makes it a mark
new
setline(1, ['aaa', 'bbb', 'ccc'])

View File

@ -109,6 +109,9 @@ def Test_assignment()
call CheckDefFailure(['&ts = 3', 'let asdf'], 'E1022:')
&ts = 8
call CheckDefFailure(['let s:var = 123'], 'E1101:')
call CheckDefFailure(['let s:var: number'], 'E1101:')
g:inc_counter += 1
assert_equal(2, g:inc_counter)
@ -136,6 +139,28 @@ def Test_assignment()
assert_equal('noneagain', v:errmsg)
call CheckDefFailure(['v:errmsg += "more"'], 'E1013:')
call CheckDefFailure(['v:errmsg += 123'], 'E1013:')
# single letter variables
a = 123
assert_equal(123, a)
let b: number
b = 123
assert_equal(123, b)
let g: number
g = 123
assert_equal(123, g)
let s: number
s = 123
assert_equal(123, s)
let t: number
t = 123
assert_equal(123, t)
let v: number
v = 123
assert_equal(123, v)
let w: number
w = 123
assert_equal(123, w)
enddef
def Test_vim9_single_char_vars()
@ -333,6 +358,25 @@ def Test_assignment_var_list()
assert_equal(['three'], vrem)
enddef
def Test_assignment_vim9script()
let lines =<< trim END
vim9script
def Func(): list<number>
return [1, 2]
enddef
let var1: number
let var2: number
[var1, var2] =
Func()
assert_equal(1, var1)
assert_equal(2, var2)
let ll =
Func()
assert_equal([1, 2], ll)
END
CheckScriptSuccess(lines)
enddef
def Mess(): string
v:foldstart = 123
return 'xxx'

View File

@ -366,7 +366,7 @@ register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state)
if (fp == NULL)
return NULL;
fp->uf_dfunc_idx = UF_NOT_COMPILED;
fp->uf_def_status = UF_NOT_COMPILED;
fp->uf_refcount = 1;
fp->uf_varargs = TRUE;
fp->uf_flags = FC_CFUNC;
@ -642,6 +642,10 @@ get_func_tv(
break;
}
++argcount;
// The comma should come right after the argument, but this wasn't
// checked previously, thus only enforce it in Vim9 script.
if (!in_vim9script())
argp = skipwhite(argp);
if (*argp != ',')
break;
}
@ -1065,7 +1069,8 @@ func_remove(ufunc_T *fp)
{
// When there is a def-function index do not actually remove the
// function, so we can find the index when defining the function again.
if (fp->uf_def_status == UF_COMPILED)
// Do remove it when it's a copy.
if (fp->uf_def_status == UF_COMPILED && (fp->uf_flags & FC_COPY) == 0)
fp->uf_flags |= FC_DEAD;
else
hash_remove(&func_hashtab, hi);
@ -1118,6 +1123,7 @@ func_clear(ufunc_T *fp, int force)
// clear this function
func_clear_items(fp);
funccal_unref(fp->uf_scoped, fp, force);
if ((fp->uf_flags & FC_COPY) == 0)
clear_def_function(fp);
}
@ -1146,12 +1152,83 @@ func_free(ufunc_T *fp, int force)
func_clear_free(ufunc_T *fp, int force)
{
func_clear(fp, force);
if (force || fp->uf_dfunc_idx == 0)
if (force || fp->uf_dfunc_idx == 0 || (fp->uf_flags & FC_COPY))
func_free(fp, force);
else
fp->uf_flags |= FC_DEAD;
}
/*
* Copy already defined function "lambda" to a new function with name "global".
* This is for when a compiled function defines a global function.
*/
void
copy_func(char_u *lambda, char_u *global)
{
ufunc_T *ufunc = find_func_even_dead(lambda, TRUE, NULL);
ufunc_T *fp;
if (ufunc == NULL)
semsg(_("E1102: lambda function not found: %s"), lambda);
else
{
// TODO: handle ! to overwrite
fp = find_func(global, TRUE, NULL);
if (fp != NULL)
{
semsg(_(e_funcexts), global);
return;
}
fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(global) + 1);
if (fp == NULL)
return;
fp->uf_varargs = ufunc->uf_varargs;
fp->uf_flags = (ufunc->uf_flags & ~FC_VIM9) | FC_COPY;
fp->uf_def_status = ufunc->uf_def_status;
fp->uf_dfunc_idx = ufunc->uf_dfunc_idx;
if (ga_copy_strings(&fp->uf_args, &ufunc->uf_args) == FAIL
|| ga_copy_strings(&fp->uf_def_args, &ufunc->uf_def_args)
== FAIL
|| ga_copy_strings(&fp->uf_lines, &ufunc->uf_lines) == FAIL)
goto failed;
fp->uf_name_exp = ufunc->uf_name_exp == NULL ? NULL
: vim_strsave(ufunc->uf_name_exp);
if (ufunc->uf_arg_types != NULL)
{
fp->uf_arg_types = ALLOC_MULT(type_T *, fp->uf_args.ga_len);
if (fp->uf_arg_types == NULL)
goto failed;
mch_memmove(fp->uf_arg_types, ufunc->uf_arg_types,
sizeof(type_T *) * fp->uf_args.ga_len);
}
if (ufunc->uf_def_arg_idx != NULL)
{
fp->uf_def_arg_idx = ALLOC_MULT(int, fp->uf_def_args.ga_len + 1);
if (fp->uf_def_arg_idx == NULL)
goto failed;
mch_memmove(fp->uf_def_arg_idx, ufunc->uf_def_arg_idx,
sizeof(int) * fp->uf_def_args.ga_len + 1);
}
if (ufunc->uf_va_name != NULL)
{
fp->uf_va_name = vim_strsave(ufunc->uf_va_name);
if (fp->uf_va_name == NULL)
goto failed;
}
fp->uf_refcount = 1;
STRCPY(fp->uf_name, global);
hash_add(&func_hashtab, UF2HIKEY(fp));
}
return;
failed:
func_clear_free(fp, TRUE);
}
/*
* Call a user function.
@ -2517,6 +2594,8 @@ list_functions(regmatch_T *regmatch)
/*
* ":function" also supporting nested ":def".
* When "name_arg" is not NULL this is a nested function, using "name_arg" for
* the function name.
* Returns a pointer to the function or NULL if no function defined.
*/
ufunc_T *

View File

@ -754,6 +754,34 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1330,
/**/
1329,
/**/
1328,
/**/
1327,
/**/
1326,
/**/
1325,
/**/
1324,
/**/
1323,
/**/
1322,
/**/
1321,
/**/
1320,
/**/
1319,
/**/
1318,
/**/
1317,
/**/
1316,
/**/

View File

@ -79,6 +79,7 @@ typedef enum {
ISN_PCALL_END, // cleanup after ISN_PCALL with cpf_top set
ISN_RETURN, // return, result is on top of stack
ISN_FUNCREF, // push a function ref to dfunc isn_arg.funcref
ISN_NEWFUNC, // create a global function from a lambda function
// expression operations
ISN_JUMP, // jump if condition is matched isn_arg.jump
@ -237,6 +238,12 @@ typedef struct {
int fr_var_idx; // variable to store partial
} funcref_T;
// arguments to ISN_NEWFUNC
typedef struct {
char_u *nf_lambda; // name of the lambda already defined
char_u *nf_global; // name of the global function to be created
} newfunc_T;
// arguments to ISN_CHECKLEN
typedef struct {
int cl_min_len; // minimum length
@ -281,6 +288,7 @@ struct isn_S {
script_T script;
unlet_T unlet;
funcref_T funcref;
newfunc_T newfunc;
checklen_T checklen;
shuffle_T shuffle;
} isn_arg;

View File

@ -1522,6 +1522,27 @@ generate_FUNCREF(cctx_T *cctx, int dfunc_idx)
return OK;
}
/*
* Generate an ISN_NEWFUNC instruction.
*/
static int
generate_NEWFUNC(cctx_T *cctx, char_u *lambda_name, char_u *func_name)
{
isn_T *isn;
char_u *name;
RETURN_OK_IF_SKIP(cctx);
name = vim_strsave(lambda_name);
if (name == NULL)
return FAIL;
if ((isn = generate_instr(cctx, ISN_NEWFUNC)) == NULL)
return FAIL;
isn->isn_arg.newfunc.nf_lambda = name;
isn->isn_arg.newfunc.nf_global = func_name;
return OK;
}
/*
* Generate an ISN_JUMP instruction.
*/
@ -3633,7 +3654,7 @@ get_vim_constant(char_u **arg, typval_T *rettv)
}
}
static exptype_T
exptype_T
get_compare_type(char_u *p, int *len, int *type_is)
{
exptype_T type = EXPR_UNKNOWN;
@ -4875,11 +4896,13 @@ exarg_getline(
static char_u *
compile_nested_function(exarg_T *eap, cctx_T *cctx)
{
int is_global = *eap->arg == 'g' && eap->arg[1] == ':';
char_u *name_start = eap->arg;
char_u *name_end = to_name_end(eap->arg, FALSE);
char_u *name_end = to_name_end(eap->arg, is_global);
char_u *name = get_lambda_name();
lvar_T *lvar;
ufunc_T *ufunc;
int r;
eap->arg = name_end;
eap->getline = exarg_getline;
@ -4894,16 +4917,28 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
&& compile_def_function(ufunc, TRUE, cctx) == FAIL)
return NULL;
if (is_global)
{
char_u *func_name = vim_strnsave(name_start + 2,
name_end - name_start - 2);
if (func_name == NULL)
r = FAIL;
else
r = generate_NEWFUNC(cctx, name, func_name);
}
else
{
// Define a local variable for the function reference.
lvar = reserve_local(cctx, name_start, name_end - name_start,
TRUE, ufunc->uf_func_type);
if (generate_FUNCREF(cctx, ufunc->uf_dfunc_idx) == FAIL
|| generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL) == FAIL)
if (generate_FUNCREF(cctx, ufunc->uf_dfunc_idx) == FAIL)
return NULL;
r = generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL);
}
// TODO: warning for trailing text?
return (char_u *)"";
return r == FAIL ? NULL : (char_u *)"";
}
/*
@ -5237,7 +5272,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
}
else if (STRNCMP(var_start, "g:", 2) == 0)
else if (varlen > 1 && STRNCMP(var_start, "g:", 2) == 0)
{
dest = dest_global;
if (is_decl)
@ -5246,7 +5281,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
}
else if (STRNCMP(var_start, "b:", 2) == 0)
else if (varlen > 1 && STRNCMP(var_start, "b:", 2) == 0)
{
dest = dest_buffer;
if (is_decl)
@ -5255,7 +5290,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
}
else if (STRNCMP(var_start, "w:", 2) == 0)
else if (varlen > 1 && STRNCMP(var_start, "w:", 2) == 0)
{
dest = dest_window;
if (is_decl)
@ -5264,7 +5299,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
}
else if (STRNCMP(var_start, "t:", 2) == 0)
else if (varlen > 1 && STRNCMP(var_start, "t:", 2) == 0)
{
dest = dest_tab;
if (is_decl)
@ -5273,7 +5308,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
}
else if (STRNCMP(var_start, "v:", 2) == 0)
else if (varlen > 1 && STRNCMP(var_start, "v:", 2) == 0)
{
typval_T *vtv;
int di_flags;
@ -5337,13 +5372,17 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
}
else if (STRNCMP(var_start, "s:", 2) == 0
else if ((varlen > 1 && STRNCMP(var_start, "s:", 2) == 0)
|| lookup_script(var_start, varlen) == OK
|| find_imported(var_start, varlen, cctx) != NULL)
{
dest = dest_script;
if (is_decl)
{
if ((varlen > 1 && STRNCMP(var_start, "s:", 2) == 0))
semsg(_("E1101: Cannot declare a script variable in a function: %s"),
name);
else
semsg(_("E1054: Variable already declared in the script: %s"),
name);
goto theend;
@ -7637,6 +7676,11 @@ delete_instr(isn_T *isn)
}
break;
case ISN_NEWFUNC:
vim_free(isn->isn_arg.newfunc.nf_lambda);
vim_free(isn->isn_arg.newfunc.nf_global);
break;
case ISN_2BOOL:
case ISN_2STRING:
case ISN_ADDBLOB:

View File

@ -723,8 +723,11 @@ call_def_function(
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ ufunc->uf_dfunc_idx;
if (dfunc->df_instr == NULL)
{
iemsg("using call_def_function() on not compiled function");
return FAIL;
}
}
CLEAR_FIELD(ectx);
ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx;
@ -1726,6 +1729,15 @@ call_def_function(
}
break;
// Create a global function from a lambda.
case ISN_NEWFUNC:
{
newfunc_T *newfunc = &iptr->isn_arg.newfunc;
copy_func(newfunc->nf_lambda, newfunc->nf_global);
}
break;
// jump if a condition is met
case ISN_JUMP:
{
@ -2912,6 +2924,15 @@ ex_disassemble(exarg_T *eap)
}
break;
case ISN_NEWFUNC:
{
newfunc_T *newfunc = &iptr->isn_arg.newfunc;
smsg("%4d NEWFUNC %s %s", current,
newfunc->nf_lambda, newfunc->nf_global);
}
break;
case ISN_JUMP:
{
char *when = "?";