Compare commits

..

5 Commits

Author SHA1 Message Date
Bram Moolenaar
eeb27bfe28 patch 8.2.1126: Vim9: using :copen causes an error
Problem:    Vim9: using :copen causes an error.
Solution:   Add flag LET_NO_COMMAND in set_var().
2020-07-04 17:39:10 +02:00
Bram Moolenaar
962d721319 patch 8.2.1125: Vim9: double quote can be a string or a comment
Problem:    Vim9: double quote can be a string or a comment.
Solution:   Only support comments starting with # to avoid confusion.
2020-07-04 14:15:00 +02:00
Bram Moolenaar
1c991144c5 patch 8.2.1124: Vim9: no line break allowed in :import command
Problem:    Vim9: no line break allowed in :import command.
Solution:   Skip over line breaks.
2020-07-04 13:15:31 +02:00
Bram Moolenaar
effb0cd75d patch 8.2.1123: Python 3 test is old style
Problem:    Python 3 test is old style.
Solution:   Turn into new style test. (Yegappan Lakshmanan, closes #6385)
2020-07-03 21:17:34 +02:00
Bram Moolenaar
442af2f89e patch 8.2.1122: Vim9: line continuation in dict member not recognized
Problem:    Vim9: line continuation in dict member not recognized.
Solution:   Check for line continuation.
2020-07-03 21:09:52 +02:00
18 changed files with 3619 additions and 3351 deletions

View File

@@ -2308,7 +2308,6 @@ test1 \
test42 test44 test49 \ test42 test44 test49 \
test52 test59 \ test52 test59 \
test70 \ test70 \
test87 \
test99: test99:
cd testdir; rm -f $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTESTTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) cd testdir; rm -f $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTESTTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)

View File

@@ -787,8 +787,8 @@ get_literal_key(char_u **arg, typval_T *tv)
/* /*
* Allocate a variable for a Dictionary and fill it from "*arg". * Allocate a variable for a Dictionary and fill it from "*arg".
* "*arg" points to the "{".
* "literal" is TRUE for #{key: val} * "literal" is TRUE for #{key: val}
* "flags" can have EVAL_EVALUATE and other EVAL_ flags.
* Return OK or FAIL. Returns NOTDONE for {expr}. * Return OK or FAIL. Returns NOTDONE for {expr}.
*/ */
int int
@@ -830,7 +830,7 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
tvkey.v_type = VAR_UNKNOWN; tvkey.v_type = VAR_UNKNOWN;
tv.v_type = VAR_UNKNOWN; tv.v_type = VAR_UNKNOWN;
*arg = skipwhite_and_linebreak_keep_string(*arg + 1, evalarg); *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
while (**arg != '}' && **arg != NUL) while (**arg != '}' && **arg != NUL)
{ {
if ((literal if ((literal
@@ -862,7 +862,7 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
goto failret; goto failret;
} }
*arg = skipwhite_and_linebreak_keep_string(*arg + 1, evalarg); *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
if (eval1(arg, &tv, evalarg) == FAIL) // recursive! if (eval1(arg, &tv, evalarg) == FAIL) // recursive!
{ {
if (evaluate) if (evaluate)
@@ -904,7 +904,7 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
} }
// the "}" can be on the next line // the "}" can be on the next line
*arg = skipwhite_and_linebreak_keep_string(*arg, evalarg); *arg = skipwhite_and_linebreak(*arg, evalarg);
if (**arg == '}') if (**arg == '}')
break; break;
if (!had_comma) if (!had_comma)

View File

@@ -1866,9 +1866,9 @@ eval_func(
} }
/* /*
* If inside Vim9 script, "arg" points to the end of a line (ignoring comments) * If inside Vim9 script, "arg" points to the end of a line (ignoring a #
* and there is a next line, return the next line (skipping blanks) and set * comment) and there is a next line, return the next line (skipping blanks)
* "getnext". * and set "getnext".
* Otherwise just return "arg" unmodified and set "getnext" to FALSE. * Otherwise just return "arg" unmodified and set "getnext" to FALSE.
* "arg" must point somewhere inside a line, not at the start. * "arg" must point somewhere inside a line, not at the start.
*/ */
@@ -1880,7 +1880,7 @@ eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext)
&& evalarg != NULL && evalarg != NULL
&& evalarg->eval_cookie != NULL && evalarg->eval_cookie != NULL
&& (*arg == NUL || (VIM_ISWHITE(arg[-1]) && (*arg == NUL || (VIM_ISWHITE(arg[-1])
&& (*arg == '"' || *arg == '#')))) && *arg == '#' && arg[1] != '{')))
{ {
char_u *p = getline_peek(evalarg->eval_getline, evalarg->eval_cookie); char_u *p = getline_peek(evalarg->eval_getline, evalarg->eval_cookie);
@@ -1927,26 +1927,14 @@ skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg)
int getnext; int getnext;
char_u *p = skipwhite(arg); char_u *p = skipwhite(arg);
if (evalarg == NULL)
return skipwhite(arg);
eval_next_non_blank(p, evalarg, &getnext); eval_next_non_blank(p, evalarg, &getnext);
if (getnext) if (getnext)
return eval_next_line(evalarg); return eval_next_line(evalarg);
return p; return p;
} }
/*
* Call eval_next_non_blank() and get the next line if needed, but not when a
* double quote follows. Used inside an expression.
*/
char_u *
skipwhite_and_linebreak_keep_string(char_u *arg, evalarg_T *evalarg)
{
char_u *p = skipwhite(arg);
if (*p == '"')
return p;
return skipwhite_and_linebreak(arg, evalarg);
}
/* /*
* After using "evalarg" filled from "eap" free the memory. * After using "evalarg" filled from "eap" free the memory.
*/ */
@@ -3362,7 +3350,7 @@ eval_index(
* *
* Get the (first) variable from inside the []. * Get the (first) variable from inside the [].
*/ */
*arg = skipwhite(*arg + 1); *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
if (**arg == ':') if (**arg == ':')
empty1 = TRUE; empty1 = TRUE;
else if (eval1(arg, &var1, evalarg) == FAIL) // recursive! else if (eval1(arg, &var1, evalarg) == FAIL) // recursive!
@@ -3377,10 +3365,11 @@ eval_index(
/* /*
* Get the second variable from inside the [:]. * Get the second variable from inside the [:].
*/ */
*arg = skipwhite_and_linebreak(*arg, evalarg);
if (**arg == ':') if (**arg == ':')
{ {
range = TRUE; range = TRUE;
*arg = skipwhite(*arg + 1); *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
if (**arg == ']') if (**arg == ']')
empty2 = TRUE; empty2 = TRUE;
else if (eval1(arg, &var2, evalarg) == FAIL) // recursive! else if (eval1(arg, &var2, evalarg) == FAIL) // recursive!
@@ -3400,6 +3389,7 @@ eval_index(
} }
// Check for the ']'. // Check for the ']'.
*arg = skipwhite_and_linebreak(*arg, evalarg);
if (**arg != ']') if (**arg != ']')
{ {
if (verbose) if (verbose)
@@ -5043,6 +5033,21 @@ handle_subscript(
&& (evalarg->eval_flags & EVAL_EVALUATE); && (evalarg->eval_flags & EVAL_EVALUATE);
int ret = OK; int ret = OK;
dict_T *selfdict = NULL; dict_T *selfdict = NULL;
int check_white = TRUE;
// When at the end of the line and ".name" follows in the next line then
// consume the line break. Only when rettv is a dict.
if (rettv->v_type == VAR_DICT)
{
int getnext;
char_u *p = eval_next_non_blank(*arg, evalarg, &getnext);
if (getnext && *p == '.' && ASCII_ISALPHA(p[1]))
{
*arg = eval_next_line(evalarg);
check_white = FALSE;
}
}
// "." is ".name" lookup when we found a dict or when evaluating and // "." is ".name" lookup when we found a dict or when evaluating and
// scriptversion is at least 2, where string concatenation is "..". // scriptversion is at least 2, where string concatenation is "..".
@@ -5054,7 +5059,7 @@ handle_subscript(
&& current_sctx.sc_version >= 2))) && current_sctx.sc_version >= 2)))
|| (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC || (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC
|| rettv->v_type == VAR_PARTIAL))) || rettv->v_type == VAR_PARTIAL)))
&& !VIM_ISWHITE(*(*arg - 1))) && (!check_white || !VIM_ISWHITE(*(*arg - 1))))
|| (**arg == '-' && (*arg)[1] == '>'))) || (**arg == '-' && (*arg)[1] == '>')))
{ {
if (**arg == '(') if (**arg == '(')

View File

@@ -2852,7 +2852,7 @@ set_var(
typval_T *tv, typval_T *tv,
int copy) // make copy of value in "tv" int copy) // make copy of value in "tv"
{ {
set_var_const(name, NULL, tv, copy, 0); set_var_const(name, NULL, tv, copy, LET_NO_COMMAND);
} }
/* /*

View File

@@ -1177,7 +1177,7 @@ eval_list(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int do_error)
return FAIL; return FAIL;
} }
*arg = skipwhite_and_linebreak_keep_string(*arg + 1, evalarg); *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
while (**arg != ']' && **arg != NUL) while (**arg != ']' && **arg != NUL)
{ {
if (eval1(arg, &tv, evalarg) == FAIL) // recursive! if (eval1(arg, &tv, evalarg) == FAIL) // recursive!
@@ -1209,7 +1209,7 @@ eval_list(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int do_error)
// The "]" can be on the next line. But a double quoted string may // The "]" can be on the next line. But a double quoted string may
// follow, not a comment. // follow, not a comment.
*arg = skipwhite_and_linebreak_keep_string(*arg, evalarg); *arg = skipwhite_and_linebreak(*arg, evalarg);
if (**arg == ']') if (**arg == ']')
break; break;

View File

@@ -32,7 +32,6 @@ int pattern_match(char_u *pat, char_u *text, int ic);
char_u *eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext); char_u *eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext);
char_u *eval_next_line(evalarg_T *evalarg); char_u *eval_next_line(evalarg_T *evalarg);
char_u *skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg); char_u *skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg);
char_u *skipwhite_and_linebreak_keep_string(char_u *arg, evalarg_T *evalarg);
void clear_evalarg(evalarg_T *evalarg, exarg_T *eap); void clear_evalarg(evalarg_T *evalarg, exarg_T *eap);
int eval0(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T *evalarg); int eval0(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T *evalarg);
int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg); int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg);

View File

@@ -4,8 +4,8 @@ void ex_vim9script(exarg_T *eap);
void ex_export(exarg_T *eap); void ex_export(exarg_T *eap);
void free_imports(int sid); void free_imports(int sid);
void ex_import(exarg_T *eap); void ex_import(exarg_T *eap);
int find_exported(int sid, char_u **argp, int *name_len, ufunc_T **ufunc, type_T **type); int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type);
char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx); char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, evalarg_T *evalarg, void *cctx);
char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg); char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg);
int check_script_var_type(typval_T *dest, typval_T *value, char_u *name); int check_script_var_type(typval_T *dest, typval_T *value, char_u *name);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -20,15 +20,12 @@ SCRIPTS_ALL = \
# Tests that run on most systems, but not on Amiga. # Tests that run on most systems, but not on Amiga.
SCRIPTS_MORE1 = \ SCRIPTS_MORE1 = \
test52.out \ test52.out
test87.out
# Tests that run on most systems, but not on Amiga and DOS/Windows. # Tests that run on most systems, but not on Amiga and DOS/Windows.
SCRIPTS_MORE2 = \ SCRIPTS_MORE2 = \
test49.out test49.out
# Tests that run on most systems, but not on VMS # Tests that run on most systems, but not on VMS
SCRIPTS_MORE4 = \ SCRIPTS_MORE4 = \
test59.out test59.out
@@ -36,7 +33,6 @@ SCRIPTS_MORE4 = \
# Tests specifically for MS-Windows. # Tests specifically for MS-Windows.
SCRIPTS_WIN32 = SCRIPTS_WIN32 =
# Tests for the GUI. # Tests for the GUI.
SCRIPTS_GUI = SCRIPTS_GUI =
@@ -309,7 +305,6 @@ NEW_TESTS = \
test_alot_utf8 \ test_alot_utf8 \
test_alot test_alot
# Test targets that use runtest.vim. # Test targets that use runtest.vim.
# Keep test_alot*.res as the last one, sort the others. # Keep test_alot*.res as the last one, sort the others.
# test_largefile.res is omitted, it uses too much resources to run on CI. # test_largefile.res is omitted, it uses too much resources to run on CI.

View File

@@ -4,7 +4,7 @@
# Authors: Zoltan Arpadffy, <arpadffy@polarhome.com> # Authors: Zoltan Arpadffy, <arpadffy@polarhome.com>
# Sandor Kopanyi, <sandor.kopanyi@mailbox.hu> # Sandor Kopanyi, <sandor.kopanyi@mailbox.hu>
# #
# Last change: 2019 May 31 # Last change: 2020 Jul 03
# #
# This has been tested on VMS 6.2 to 8.3 on DEC Alpha, VAX and IA64. # This has been tested on VMS 6.2 to 8.3 on DEC Alpha, VAX and IA64.
# Edit the lines in the Configuration section below to select. # Edit the lines in the Configuration section below to select.
@@ -115,10 +115,6 @@ SCRIPT_ODS5 = test102.out
SCRIPT_GDIFF = test47.out SCRIPT_GDIFF = test47.out
.ENDIF .ENDIF
.IFDEF HAVE_PYTHON
SCRIPT_PYTHON = test87.out
.ENDIF
.in.out : .in.out :
-@ !clean up before doing the test -@ !clean up before doing the test
-@ if "''F$SEARCH("test.out.*")'" .NES. "" then delete/noconfirm/nolog test.out.* -@ if "''F$SEARCH("test.out.*")'" .NES. "" then delete/noconfirm/nolog test.out.*
@@ -140,7 +136,7 @@ SCRIPT_PYTHON = test87.out
-@ if "''F$SEARCH("Xtest.*")'" .NES. "" then delete/noconfirm/nolog Xtest.*.* -@ if "''F$SEARCH("Xtest.*")'" .NES. "" then delete/noconfirm/nolog Xtest.*.*
all : clean nolog $(START_WITH) $(SCRIPT) $(SCRIPT_GUI) $(SCRIPT_UNIX) $(SCRIPT_WIN) $(SCRIPT_SPELL) $(SCRIPT_ODS5) \ all : clean nolog $(START_WITH) $(SCRIPT) $(SCRIPT_GUI) $(SCRIPT_UNIX) $(SCRIPT_WIN) $(SCRIPT_SPELL) $(SCRIPT_ODS5) \
$(SCRIPT_GDIFF) $(SCRIPT_MZSCH) $(SCRIPT_LUA) $(SCRIPT_PYTHON) nolog $(SCRIPT_GDIFF) $(SCRIPT_MZSCH) $(SCRIPT_LUA) nolog
-@ write sys$output " " -@ write sys$output " "
-@ write sys$output "-----------------------------------------------" -@ write sys$output "-----------------------------------------------"
-@ write sys$output " All done" -@ write sys$output " All done"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1138,6 +1138,43 @@ def Test_expr_member()
call CheckDefExecFailure(["let d: dict<number>", "d = g:list_empty"], 'E1029: Expected dict but got list') call CheckDefExecFailure(["let d: dict<number>", "d = g:list_empty"], 'E1029: Expected dict but got list')
enddef enddef
def Test_expr_member_vim9script()
let lines =<< trim END
vim9script
let d = #{one:
'one',
two: 'two'}
assert_equal('one', d.one)
assert_equal('one', d
.one)
assert_equal('one', d[
'one'
])
END
CheckScriptSuccess(lines)
lines =<< trim END
vim9script
let l = [1,
2,
3, 4
]
assert_equal(2, l[
1
])
assert_equal([2, 3], l[1 : 2])
assert_equal([1, 2, 3], l[
:
2
])
assert_equal([3, 4], l[
2
:
])
END
CheckScriptSuccess(lines)
enddef
def Test_expr7_option() def Test_expr7_option()
" option " option
set ts=11 set ts=11

View File

@@ -686,6 +686,35 @@ def Test_vim9_import_export()
unlet g:imported_name g:imported_name_appended unlet g:imported_name g:imported_name_appended
delete('Ximport.vim') delete('Ximport.vim')
# similar, with line breaks
let import_line_break_script_lines =<< trim END
vim9script
import {
exported,
Exported,
}
from
'./Xexport.vim'
g:imported = exported
exported += 5
g:imported_added = exported
g:imported_func = Exported()
END
writefile(import_line_break_script_lines, 'Ximport_lbr.vim')
source Ximport_lbr.vim
assert_equal(9876, g:imported)
assert_equal(9881, g:imported_added)
assert_equal('Exported', g:imported_func)
# exported script not sourced again
assert_false(exists('g:result'))
unlet g:imported
unlet g:imported_added
unlet g:imported_func
delete('Ximport_lbr.vim')
# import inside :def function
let import_in_def_lines =<< trim END let import_in_def_lines =<< trim END
vim9script vim9script
def ImportInDef() def ImportInDef()
@@ -751,6 +780,21 @@ def Test_vim9_import_export()
writefile(import_star_as_lines_missing_name, 'Ximport.vim') writefile(import_star_as_lines_missing_name, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1048:') assert_fails('source Ximport.vim', 'E1048:')
let import_star_as_lbr_lines =<< trim END
vim9script
import *
as Export
from
'./Xexport.vim'
def UseExport()
g:imported = Export.exported
enddef
UseExport()
END
writefile(import_star_as_lbr_lines, 'Ximport.vim')
source Ximport.vim
assert_equal(9883, g:imported)
let import_star_lines =<< trim END let import_star_lines =<< trim END
vim9script vim9script
import * from './Xexport.vim' import * from './Xexport.vim'
@@ -2175,6 +2219,12 @@ def Test_source_vim9_from_legacy()
delete('Xvim9_script.vim') delete('Xvim9_script.vim')
enddef enddef
def Test_vim9_copen()
# this was giving an error for setting w:quickfix_title
copen
quit
enddef
" Keep this last, it messes up highlighting. " Keep this last, it messes up highlighting.
def Test_substitute_cmd() def Test_substitute_cmd()
new new

View File

@@ -754,6 +754,16 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1126,
/**/
1125,
/**/
1124,
/**/
1123,
/**/
1122,
/**/ /**/
1121, 1121,
/**/ /**/

View File

@@ -2613,7 +2613,8 @@ compile_load_scriptvar(
if (import->imp_all) if (import->imp_all)
{ {
char_u *p = skipwhite(*end); char_u *p = skipwhite(*end);
int name_len; char_u *exp_name;
int cc;
ufunc_T *ufunc; ufunc_T *ufunc;
type_T *type; type_T *type;
@@ -2630,7 +2631,17 @@ compile_load_scriptvar(
return FAIL; return FAIL;
} }
idx = find_exported(import->imp_sid, &p, &name_len, &ufunc, &type); // isolate one name
exp_name = p;
while (eval_isnamec(*p))
++p;
cc = *p;
*p = NUL;
idx = find_exported(import->imp_sid, exp_name, &ufunc, &type);
*p = cc;
p = skipwhite(p);
// TODO: what if it is a function? // TODO: what if it is a function?
if (idx < 0) if (idx < 0)
return FAIL; return FAIL;
@@ -2981,6 +2992,7 @@ to_name_end(char_u *arg, int namespace)
/* /*
* Like to_name_end() but also skip over a list or dict constant. * Like to_name_end() but also skip over a list or dict constant.
* This intentionally does not handle line continuation.
*/ */
char_u * char_u *
to_name_const_end(char_u *arg) to_name_const_end(char_u *arg)
@@ -5632,7 +5644,7 @@ compile_unletlock(char_u *arg, exarg_T *eap, cctx_T *cctx)
static char_u * static char_u *
compile_import(char_u *arg, cctx_T *cctx) compile_import(char_u *arg, cctx_T *cctx)
{ {
return handle_import(arg, &cctx->ctx_imports, 0, cctx); return handle_import(arg, &cctx->ctx_imports, 0, NULL, cctx);
} }
/* /*

View File

@@ -143,16 +143,20 @@ free_imports(int sid)
ex_import(exarg_T *eap) ex_import(exarg_T *eap)
{ {
char_u *cmd_end; char_u *cmd_end;
evalarg_T evalarg;
if (!getline_equal(eap->getline, eap->cookie, getsourceline)) if (!getline_equal(eap->getline, eap->cookie, getsourceline))
{ {
emsg(_("E1094: import can only be used in a script")); emsg(_("E1094: import can only be used in a script"));
return; return;
} }
fill_evalarg_from_eap(&evalarg, eap, eap->skip);
cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid, NULL); cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid,
&evalarg, NULL);
if (cmd_end != NULL) if (cmd_end != NULL)
eap->nextcmd = check_nextcmd(cmd_end); eap->nextcmd = check_nextcmd(cmd_end);
clear_evalarg(&evalarg, eap);
} }
/* /*
@@ -164,27 +168,16 @@ ex_import(exarg_T *eap)
int int
find_exported( find_exported(
int sid, int sid,
char_u **argp, char_u *name,
int *name_len,
ufunc_T **ufunc, ufunc_T **ufunc,
type_T **type) type_T **type)
{ {
char_u *name = *argp;
char_u *arg = *argp;
int cc;
int idx = -1; int idx = -1;
svar_T *sv; svar_T *sv;
scriptitem_T *script = SCRIPT_ITEM(sid); scriptitem_T *script = SCRIPT_ITEM(sid);
// isolate one name
while (eval_isnamec(*arg))
++arg;
*name_len = (int)(arg - name);
// find name in "script" // find name in "script"
// TODO: also find script-local user function // TODO: also find script-local user function
cc = *arg;
*arg = NUL;
idx = get_script_item_idx(sid, name, FALSE); idx = get_script_item_idx(sid, name, FALSE);
if (idx >= 0) if (idx >= 0)
{ {
@@ -192,7 +185,6 @@ find_exported(
if (!sv->sv_export) if (!sv->sv_export)
{ {
semsg(_("E1049: Item not exported in script: %s"), name); semsg(_("E1049: Item not exported in script: %s"), name);
*arg = cc;
return -1; return -1;
} }
*type = sv->sv_type; *type = sv->sv_type;
@@ -210,11 +202,8 @@ find_exported(
{ {
funcname = alloc(STRLEN(name) + 10); funcname = alloc(STRLEN(name) + 10);
if (funcname == NULL) if (funcname == NULL)
{
*arg = cc;
return -1; return -1;
} }
}
funcname[0] = K_SPECIAL; funcname[0] = K_SPECIAL;
funcname[1] = KS_EXTRA; funcname[1] = KS_EXTRA;
funcname[2] = (int)KE_SNR; funcname[2] = (int)KE_SNR;
@@ -226,13 +215,9 @@ find_exported(
if (*ufunc == NULL) if (*ufunc == NULL)
{ {
semsg(_("E1048: Item not found in script: %s"), name); semsg(_("E1048: Item not found in script: %s"), name);
*arg = cc;
return -1; return -1;
} }
} }
*arg = cc;
arg = skipwhite(arg);
*argp = arg;
return idx; return idx;
} }
@@ -243,62 +228,121 @@ find_exported(
* Returns a pointer to after the command or NULL in case of failure * Returns a pointer to after the command or NULL in case of failure
*/ */
char_u * char_u *
handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx) handle_import(
char_u *arg_start,
garray_T *gap,
int import_sid,
evalarg_T *evalarg,
void *cctx)
{ {
char_u *arg = arg_start; char_u *arg = arg_start;
char_u *cmd_end; char_u *cmd_end = NULL;
char_u *as_ptr = NULL; char_u *as_name = NULL;
char_u *from_ptr;
int as_len = 0;
int ret = FAIL; int ret = FAIL;
typval_T tv; typval_T tv;
int sid = -1; int sid = -1;
int res; int res;
garray_T names;
static char e_import_syntax[] = N_("E1047: syntax error in import");
ga_init2(&names, sizeof(char_u *), 10);
if (*arg == '{') if (*arg == '{')
{ {
// skip over {item} list // "import {item, item} from ..."
while (*arg != NUL && *arg != '}') arg = skipwhite_and_linebreak(arg + 1, evalarg);
for (;;)
{
char_u *p = arg;
int had_comma = FALSE;
while (eval_isnamec(*arg))
++arg; ++arg;
if (p == arg)
break;
if (ga_grow(&names, 1) == FAIL)
goto erret;
((char_u **)names.ga_data)[names.ga_len] =
vim_strnsave(p, arg - p);
++names.ga_len;
if (*arg == ',')
{
had_comma = TRUE;
++arg;
}
arg = skipwhite_and_linebreak(arg, evalarg);
if (*arg == '}') if (*arg == '}')
arg = skipwhite(arg + 1); {
arg = skipwhite_and_linebreak(arg + 1, evalarg);
break;
}
if (!had_comma)
{
emsg(_("E1046: Missing comma in import"));
goto erret;
}
}
if (names.ga_len == 0)
{
emsg(_(e_import_syntax));
goto erret;
}
} }
else else
{ {
if (*arg == '*') // "import Name from ..."
arg = skipwhite(arg + 1); // "import * as Name from ..."
// "import item [as Name] from ..."
arg = skipwhite_and_linebreak(arg, evalarg);
if (arg[0] == '*' && IS_WHITE_OR_NUL(arg[1]))
arg = skipwhite_and_linebreak(arg + 1, evalarg);
else if (eval_isnamec1(*arg)) else if (eval_isnamec1(*arg))
{ {
char_u *p = arg;
while (eval_isnamec(*arg)) while (eval_isnamec(*arg))
++arg; ++arg;
arg = skipwhite(arg); if (ga_grow(&names, 1) == FAIL)
goto erret;
((char_u **)names.ga_data)[names.ga_len] =
vim_strnsave(p, arg - p);
++names.ga_len;
arg = skipwhite_and_linebreak(arg, evalarg);
} }
if (STRNCMP("as", arg, 2) == 0 && VIM_ISWHITE(arg[2])) else
{ {
// skip over "as Name " emsg(_(e_import_syntax));
goto erret;
}
if (STRNCMP("as", arg, 2) == 0 && IS_WHITE_OR_NUL(arg[2]))
{
char_u *p;
// skip over "as Name "; no line break allowed after "as"
arg = skipwhite(arg + 2); arg = skipwhite(arg + 2);
as_ptr = arg; p = arg;
if (eval_isnamec1(*arg)) if (eval_isnamec1(*arg))
while (eval_isnamec(*arg)) while (eval_isnamec(*arg))
++arg; ++arg;
as_len = (int)(arg - as_ptr); if (check_defined(p, (int)(arg - p), cctx) == FAIL)
arg = skipwhite(arg); goto erret;
if (check_defined(as_ptr, as_len, cctx) == FAIL) as_name = vim_strnsave(p, arg - p);
return NULL; arg = skipwhite_and_linebreak(arg, evalarg);
} }
else if (*arg_start == '*') else if (*arg_start == '*')
{ {
emsg(_("E1045: Missing \"as\" after *")); emsg(_("E1045: Missing \"as\" after *"));
return NULL; goto erret;
} }
} }
if (STRNCMP("from", arg, 4) != 0 || !VIM_ISWHITE(arg[4]))
if (STRNCMP("from", arg, 4) != 0 || !IS_WHITE_OR_NUL(arg[4]))
{ {
emsg(_("E1070: Missing \"from\"")); emsg(_("E1070: Missing \"from\""));
return NULL; goto erret;
} }
from_ptr = arg;
arg = skipwhite(arg + 4); arg = skipwhite_and_linebreak(arg + 4, evalarg);
tv.v_type = VAR_UNKNOWN; tv.v_type = VAR_UNKNOWN;
// TODO: should we accept any expression? // TODO: should we accept any expression?
if (*arg == '\'') if (*arg == '\'')
@@ -308,11 +352,13 @@ handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx)
if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL) if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL)
{ {
emsg(_("E1071: Invalid string after \"from\"")); emsg(_("E1071: Invalid string after \"from\""));
return NULL; goto erret;
} }
cmd_end = arg; cmd_end = arg;
// find script tv.vval.v_string /*
* find script file
*/
if (*tv.vval.v_string == '.') if (*tv.vval.v_string == '.')
{ {
size_t len; size_t len;
@@ -326,7 +372,7 @@ handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx)
if (from_name == NULL) if (from_name == NULL)
{ {
clear_tv(&tv); clear_tv(&tv);
return NULL; goto erret;
} }
vim_strncpy(from_name, si->sn_name, tail - si->sn_name); vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
add_pathsep(from_name); add_pathsep(from_name);
@@ -351,7 +397,7 @@ handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx)
if (from_name == NULL) if (from_name == NULL)
{ {
clear_tv(&tv); clear_tv(&tv);
return NULL; goto erret;
} }
vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string); vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string);
res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid); res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid);
@@ -362,7 +408,7 @@ handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx)
{ {
semsg(_("E1053: Could not import \"%s\""), tv.vval.v_string); semsg(_("E1053: Could not import \"%s\""), tv.vval.v_string);
clear_tv(&tv); clear_tv(&tv);
return NULL; goto erret;
} }
clear_tv(&tv); clear_tv(&tv);
@@ -372,41 +418,44 @@ handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx)
: &SCRIPT_ITEM(import_sid)->sn_imports); : &SCRIPT_ITEM(import_sid)->sn_imports);
if (imported == NULL) if (imported == NULL)
return NULL; goto erret;
imported->imp_name = vim_strnsave(as_ptr, as_len); imported->imp_name = as_name;
as_name = NULL;
imported->imp_sid = sid; imported->imp_sid = sid;
imported->imp_all = TRUE; imported->imp_all = TRUE;
} }
else else
{ {
int i;
arg = arg_start; arg = arg_start;
if (*arg == '{') if (*arg == '{')
arg = skipwhite(arg + 1); arg = skipwhite(arg + 1);
for (;;) for (i = 0; i < names.ga_len; ++i)
{ {
char_u *name = arg; char_u *name = ((char_u **)names.ga_data)[i];
int name_len;
int idx; int idx;
imported_T *imported; imported_T *imported;
ufunc_T *ufunc = NULL; ufunc_T *ufunc = NULL;
type_T *type; type_T *type;
idx = find_exported(sid, &arg, &name_len, &ufunc, &type); idx = find_exported(sid, name, &ufunc, &type);
if (idx < 0 && ufunc == NULL) if (idx < 0 && ufunc == NULL)
return NULL; goto erret;
if (check_defined(name, name_len, cctx) == FAIL) if (check_defined(name, STRLEN(name), cctx) == FAIL)
return NULL; goto erret;
imported = new_imported(gap != NULL ? gap imported = new_imported(gap != NULL ? gap
: &SCRIPT_ITEM(import_sid)->sn_imports); : &SCRIPT_ITEM(import_sid)->sn_imports);
if (imported == NULL) if (imported == NULL)
return NULL; goto erret;
// TODO: check for "as" following // TODO: check for "as" following
// imported->imp_name = vim_strnsave(as_ptr, as_len); // imported->imp_name = vim_strsave(as_name);
imported->imp_name = vim_strnsave(name, name_len); imported->imp_name = name;
((char_u **)names.ga_data)[i] = NULL;
imported->imp_sid = sid; imported->imp_sid = sid;
if (idx >= 0) if (idx >= 0)
{ {
@@ -415,30 +464,11 @@ handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx)
} }
else else
imported->imp_funcname = ufunc->uf_name; imported->imp_funcname = ufunc->uf_name;
arg = skipwhite(arg);
if (*arg_start != '{')
break;
if (*arg == '}')
{
arg = skipwhite(arg + 1);
break;
}
if (*arg != ',')
{
emsg(_("E1046: Missing comma in import"));
return NULL;
}
arg = skipwhite(arg + 1);
}
if (arg != from_ptr)
{
// cannot happen, just in case the above has a flaw
emsg(_("E1047: syntax error in import"));
return NULL;
} }
} }
erret:
ga_clear_strings(&names);
vim_free(as_name);
return cmd_end; return cmd_end;
} }