diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim index 0c11c078e7..799230a98b 100644 --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -4345,23 +4345,20 @@ def Test_lockvar_object_variable() END v9.CheckSourceFailure(lines, 'E1335: Variable "val4" in class "C" is not writable') - # TODO: the following tests use type "any" for argument. Need a run time - # check for access. Probably OK as is for now. - # read-only lockvar from object method arg lines =<< trim END vim9script class C var val5: number - def Lock(o_any: any) - lockvar o_any.val5 + def Lock(c: C) + lockvar c.val5 enddef endclass var o = C.new(3) o.Lock(C.new(5)) END - v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "o_any.val5" in class "C"') + v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "c.val5" in class "C"') # read-only lockvar from class method arg lines =<< trim END @@ -4369,14 +4366,14 @@ def Test_lockvar_object_variable() class C var val6: number - static def Lock(o_any: any) - lockvar o_any.val6 + static def Lock(c: C) + lockvar c.val6 enddef endclass var o = C.new(3) C.Lock(o) END - v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "o_any.val6" in class "C"') + v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "c.val6" in class "C"') # # lockvar of public object variable @@ -4444,14 +4441,14 @@ def Test_lockvar_object_variable() class C public var val5: number - def Lock(o_any: any) - lockvar o_any.val5 + def Lock(c: C) + lockvar c.val5 enddef endclass var o = C.new(3) o.Lock(C.new(5)) END - v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "o_any.val5" in class "C"', 1) + v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "c.val5" in class "C"', 1) # lockvar from class method arg lines =<< trim END @@ -4459,14 +4456,14 @@ def Test_lockvar_object_variable() class C public var val6: number - static def Lock(o_any: any) - lockvar o_any.val6 + static def Lock(c: C) + lockvar c.val6 enddef endclass var o = C.new(3) C.Lock(o) END - v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "o_any.val6" in class "C"', 1) + v9.CheckSourceFailure(lines, 'E1391: Cannot (un)lock variable "c.val6" in class "C"', 1) enddef " Test trying to lock a class variable from various places diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 79bb9d8216..4188f82e5d 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -4697,6 +4697,23 @@ def Test_test_override_defcompile() test_override('defcompile', 0) enddef +" Test for using a comment after the opening curly brace of an inner block. +def Test_comment_after_inner_block() + var lines =<< trim END + vim9script + + def F(G: func) + enddef + + F(() => { # comment1 + F(() => { # comment2 + echo 'ok' # comment3 + }) # comment4 + }) # comment5 + END + v9.CheckScriptSuccess(lines) +enddef + " The following messes up syntax highlight, keep near the end. if has('python3') def Test_python3_command() diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 82f808862d..550c725dd7 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -595,6 +595,27 @@ def Test_autocommand_block() unlet g:otherVar enddef +def Test_block_in_a_string() + var lines =<< trim END + vim9script + + def Foo(): string + var x = ' => { # abc' + return x + enddef + + assert_equal(' => { # abc', Foo()) + + def Bar(): string + var x = " => { # abc" + return x + enddef + + assert_equal(" => { # abc", Bar()) + END + v9.CheckSourceSuccess(lines) +enddef + func g:NoSuchFunc() echo 'none' endfunc diff --git a/src/userfunc.c b/src/userfunc.c index 5bf7e9558e..b4ee0a2675 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -859,6 +859,92 @@ function_using_block_scopes(ufunc_T *fp, cstack_T *cstack) cstack->cs_flags[i] |= CSF_FUNC_DEF; } +/* + * Skip over all the characters in a single quoted string starting at "p" and + * return a pointer to the character following the ending single quote. + * If the ending single quote is missing, then return a pointer to the NUL + * character. + */ + static char_u * +skip_single_quote_string(char_u *p) +{ + p++; // skip the beginning single quote + while (*p != NUL) + { + // Within the string, a single quote can be escaped by using + // two single quotes. + if (*p == '\'' && *(p + 1) == '\'') + p += 2; + else if (*p == '\'') + { + p++; // skip the ending single quote + break; + } + else + MB_PTR_ADV(p); + } + + return p; +} + +/* + * Skip over all the characters in a double quoted string starting at "p" and + * return a pointer to the character following the ending double quote. + * If the ending double quote is missing, then return a pointer to the NUL + * character. + */ + static char_u * +skip_double_quote_string(char_u *p) +{ + p++; // skip the beginning double quote + while (*p != NUL) + { + // Within the string, a double quote can be escaped by + // preceding it with a backslash. + if (*p == '\\' && *(p + 1) == '"') + p += 2; + else if (*p == '"') + { + p++; // skip the ending double quote + break; + } + else + MB_PTR_ADV(p); + } + + return p; +} + +/* + * Return the start of a Vim9 comment (#) in the line starting at "line". + * If a comment is not found, then returns a pointer to the end of the + * string (NUL). + */ + static char_u * +find_start_of_vim9_comment(char_u *line) +{ + char_u *p = line; + + while (*p != NUL) + { + if (*p == '\'') + // Skip a single quoted string. + p = skip_single_quote_string(p); + else if (*p == '"') + // Skip a double quoted string. + p = skip_double_quote_string(p); + else + { + if (*p == '#') + // Found the start of a Vim9 comment + break; + MB_PTR_ADV(p); + } + } + + return p; +} + /* * Read the body of a function, put every line in "newlines". * This stops at "}", "endfunction" or "enddef". @@ -1123,7 +1209,17 @@ get_function_body( if (nesting_def[nesting] ? *p != '#' : *p != '"') { // Not a comment line: check for nested inline function. - end = p + STRLEN(p) - 1; + + if (nesting_inline[nesting]) + { + // A comment (#) can follow the opening curly brace of a + // block statement. Need to ignore the comment and look + // for the opening curly brace before the comment. + end = find_start_of_vim9_comment(p) - 1; + } + else + end = p + STRLEN(p) - 1; + while (end > p && VIM_ISWHITE(*end)) --end; if (end > p + 1 && *end == '{' && VIM_ISWHITE(end[-1])) diff --git a/src/version.c b/src/version.c index 60de70238c..699ad36254 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 994, /**/ 993, /**/