Skip to content

Commit b6dc199

Browse files
authored
Merge pull request #106 from vim-jp/dotdot
Fix ..
2 parents edd6a79 + 088d1fb commit b6dc199

File tree

5 files changed

+143
-12
lines changed

5 files changed

+143
-12
lines changed

autoload/vimlparser.vim

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ let s:TOKEN_SHARP = 64
206206
let s:TOKEN_ARROW = 65
207207
let s:TOKEN_BLOB = 66
208208
let s:TOKEN_LITCOPEN = 67
209+
let s:TOKEN_DOTDOT = 68
209210

210211
let s:MAX_FUNC_ARGS = 20
211212

@@ -1497,9 +1498,13 @@ function! s:VimLParser.parse_cmd_let()
14971498
call self.reader.skip_white()
14981499
let s1 = self.reader.peekn(1)
14991500
let s2 = self.reader.peekn(2)
1501+
" TODO check scriptversion?
1502+
if s2 ==# '..'
1503+
let s2 = self.reader.peekn(3)
1504+
endif
15001505

15011506
" :let {var-name} ..
1502-
if self.ends_excmds(s1) || (s2 !=# '+=' && s2 !=# '-=' && s2 !=# '.=' && s2 !=# '*=' && s2 !=# '/=' && s2 !=# '%=' && s1 !=# '=')
1507+
if self.ends_excmds(s1) || (s2 !=# '+=' && s2 !=# '-=' && s2 !=# '.=' && s2 !=# '..=' && s2 !=# '*=' && s2 !=# '/=' && s2 !=# '%=' && s1 !=# '=')
15031508
call self.reader.seek_set(pos)
15041509
call self.parse_cmd_common()
15051510
return
@@ -1514,8 +1519,8 @@ function! s:VimLParser.parse_cmd_let()
15141519
let node.list = lhs.list
15151520
let node.rest = lhs.rest
15161521
let node.right = s:NIL
1517-
if s2 ==# '+=' || s2 ==# '-=' || s2 ==# '.=' || s2 ==# '*=' || s2 ==# '/=' || s2 ==# '%='
1518-
call self.reader.getn(2)
1522+
if s2 ==# '+=' || s2 ==# '-=' || s2 ==# '.=' || s2 ==# '..=' || s2 ==# '*=' || s2 ==# '/=' || s2 ==# '%='
1523+
call self.reader.getn(len(s2))
15191524
let node.op = s2
15201525
elseif s1 ==# '='
15211526
call self.reader.getn(1)
@@ -2750,9 +2755,12 @@ function! s:ExprTokenizer.get2()
27502755
if r.p(1) ==# '.' && r.p(2) ==# '.'
27512756
call r.seek_cur(3)
27522757
return self.token(s:TOKEN_DOTDOTDOT, '...', pos)
2758+
elseif r.p(1) ==# '.'
2759+
call r.seek_cur(2)
2760+
return self.token(s:TOKEN_DOTDOT, '..', pos) " TODO check scriptversion?
27532761
else
27542762
call r.seek_cur(1)
2755-
return self.token(s:TOKEN_DOT, '.', pos)
2763+
return self.token(s:TOKEN_DOT, '.', pos) " TODO check scriptversion?
27562764
endif
27572765
elseif c ==# '*'
27582766
call r.seek_cur(1)
@@ -3209,6 +3217,7 @@ endfunction
32093217
" expr5: expr6 + expr6 ..
32103218
" expr6 - expr6 ..
32113219
" expr6 . expr6 ..
3220+
" expr6 .. expr6 ..
32123221
function! s:ExprParser.parse_expr5()
32133222
let left = self.parse_expr6()
32143223
while s:TRUE
@@ -3226,7 +3235,13 @@ function! s:ExprParser.parse_expr5()
32263235
let node.left = left
32273236
let node.right = self.parse_expr6()
32283237
let left = node
3229-
elseif token.type == s:TOKEN_DOT
3238+
elseif token.type == s:TOKEN_DOTDOT " TODO check scriptversion?
3239+
let node = s:Node(s:NODE_CONCAT)
3240+
let node.pos = token.pos
3241+
let node.left = left
3242+
let node.right = self.parse_expr6()
3243+
let left = node
3244+
elseif token.type == s:TOKEN_DOT " TODO check scriptversion?
32303245
let node = s:Node(s:NODE_CONCAT)
32313246
let node.pos = token.pos
32323247
let node.left = left
@@ -3389,7 +3404,7 @@ function! s:ExprParser.parse_expr8()
33893404
endif
33903405
let left = node
33913406
unlet node
3392-
elseif !s:iswhite(c) && token.type == s:TOKEN_DOT
3407+
elseif !s:iswhite(c) && token.type == s:TOKEN_DOT " TODO check scriptversion?
33933408
let node = self.parse_dot(token, left)
33943409
if node is s:NIL
33953410
call self.reader.seek_set(pos)
@@ -3654,6 +3669,31 @@ function! s:ExprParser.parse_dot(token, left)
36543669
return node
36553670
endfunction
36563671

3672+
" CONCAT
3673+
" str ".." expr6 => (concat str expr6)
3674+
function! s:ExprParser.parse_concat(token, left)
3675+
if a:left.type != s:NODE_IDENTIFIER && a:left.type != s:NODE_CURLYNAME && a:left.type != s:NODE_DICT && a:left.type != s:NODE_SUBSCRIPT && a:left.type != s:NODE_CALL && a:left.type != s:NODE_DOT
3676+
return s:NIL
3677+
endif
3678+
if !s:iswordc(self.reader.p(0))
3679+
return s:NIL
3680+
endif
3681+
let pos = self.reader.getpos()
3682+
let name = self.reader.read_word()
3683+
if s:isnamec(self.reader.p(0))
3684+
" XXX: foo is str => ok, foo is obj => invalid expression
3685+
" foo.s:bar or foo.bar#baz
3686+
return s:NIL
3687+
endif
3688+
let node = s:Node(s:NODE_CONCAT)
3689+
let node.pos = a:token.pos
3690+
let node.left = a:left
3691+
let node.right = s:Node(s:NODE_IDENTIFIER)
3692+
let node.right.pos = pos
3693+
let node.right.value = name
3694+
return node
3695+
endfunction
3696+
36573697
function! s:ExprParser.parse_identifier()
36583698
call self.reader.skip_white()
36593699
let npos = self.reader.getpos()

js/vimlparser.js

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ var TOKEN_SHARP = 64;
398398
var TOKEN_ARROW = 65;
399399
var TOKEN_BLOB = 66;
400400
var TOKEN_LITCOPEN = 67;
401+
var TOKEN_DOTDOT = 68;
401402
var MAX_FUNC_ARGS = 20;
402403
function isalpha(c) {
403404
return viml_eqregh(c, "^[A-Za-z]$");
@@ -1799,8 +1800,12 @@ VimLParser.prototype.parse_cmd_let = function() {
17991800
this.reader.skip_white();
18001801
var s1 = this.reader.peekn(1);
18011802
var s2 = this.reader.peekn(2);
1803+
// TODO check scriptversion?
1804+
if (s2 == "..") {
1805+
var s2 = this.reader.peekn(3);
1806+
}
18021807
// :let {var-name} ..
1803-
if (this.ends_excmds(s1) || s2 != "+=" && s2 != "-=" && s2 != ".=" && s2 != "*=" && s2 != "/=" && s2 != "%=" && s1 != "=") {
1808+
if (this.ends_excmds(s1) || s2 != "+=" && s2 != "-=" && s2 != ".=" && s2 != "..=" && s2 != "*=" && s2 != "/=" && s2 != "%=" && s1 != "=") {
18041809
this.reader.seek_set(pos);
18051810
this.parse_cmd_common();
18061811
return;
@@ -1814,8 +1819,8 @@ VimLParser.prototype.parse_cmd_let = function() {
18141819
node.list = lhs.list;
18151820
node.rest = lhs.rest;
18161821
node.right = NIL;
1817-
if (s2 == "+=" || s2 == "-=" || s2 == ".=" || s2 == "*=" || s2 == "/=" || s2 == "%=") {
1818-
this.reader.getn(2);
1822+
if (s2 == "+=" || s2 == "-=" || s2 == ".=" || s2 == "..=" || s2 == "*=" || s2 == "/=" || s2 == "%=") {
1823+
this.reader.getn(viml_len(s2));
18191824
node.op = s2;
18201825
}
18211826
else if (s1 == "=") {
@@ -2523,9 +2528,15 @@ ExprTokenizer.prototype.get2 = function() {
25232528
r.seek_cur(3);
25242529
return this.token(TOKEN_DOTDOTDOT, "...", pos);
25252530
}
2531+
else if (r.p(1) == ".") {
2532+
r.seek_cur(2);
2533+
return this.token(TOKEN_DOTDOT, "..", pos);
2534+
// TODO check scriptversion?
2535+
}
25262536
else {
25272537
r.seek_cur(1);
25282538
return this.token(TOKEN_DOT, ".", pos);
2539+
// TODO check scriptversion?
25292540
}
25302541
}
25312542
else if (c == "*") {
@@ -3040,6 +3051,7 @@ ExprParser.prototype.parse_expr4 = function() {
30403051
// expr5: expr6 + expr6 ..
30413052
// expr6 - expr6 ..
30423053
// expr6 . expr6 ..
3054+
// expr6 .. expr6 ..
30433055
ExprParser.prototype.parse_expr5 = function() {
30443056
var left = this.parse_expr6();
30453057
while (TRUE) {
@@ -3059,7 +3071,16 @@ ExprParser.prototype.parse_expr5 = function() {
30593071
node.right = this.parse_expr6();
30603072
var left = node;
30613073
}
3074+
else if (token.type == TOKEN_DOTDOT) {
3075+
// TODO check scriptversion?
3076+
var node = Node(NODE_CONCAT);
3077+
node.pos = token.pos;
3078+
node.left = left;
3079+
node.right = this.parse_expr6();
3080+
var left = node;
3081+
}
30623082
else if (token.type == TOKEN_DOT) {
3083+
// TODO check scriptversion?
30633084
var node = Node(NODE_CONCAT);
30643085
node.pos = token.pos;
30653086
node.left = left;
@@ -3237,6 +3258,7 @@ ExprParser.prototype.parse_expr8 = function() {
32373258
delete node;
32383259
}
32393260
else if (!iswhite(c) && token.type == TOKEN_DOT) {
3261+
// TODO check scriptversion?
32403262
var node = this.parse_dot(token, left);
32413263
if (node === NIL) {
32423264
this.reader.seek_set(pos);
@@ -3528,6 +3550,31 @@ ExprParser.prototype.parse_dot = function(token, left) {
35283550
return node;
35293551
}
35303552

3553+
// CONCAT
3554+
// str ".." expr6 => (concat str expr6)
3555+
ExprParser.prototype.parse_concat = function(token, left) {
3556+
if (left.type != NODE_IDENTIFIER && left.type != NODE_CURLYNAME && left.type != NODE_DICT && left.type != NODE_SUBSCRIPT && left.type != NODE_CALL && left.type != NODE_DOT) {
3557+
return NIL;
3558+
}
3559+
if (!iswordc(this.reader.p(0))) {
3560+
return NIL;
3561+
}
3562+
var pos = this.reader.getpos();
3563+
var name = this.reader.read_word();
3564+
if (isnamec(this.reader.p(0))) {
3565+
// XXX: foo is str => ok, foo is obj => invalid expression
3566+
// foo.s:bar or foo.bar#baz
3567+
return NIL;
3568+
}
3569+
var node = Node(NODE_CONCAT);
3570+
node.pos = token.pos;
3571+
node.left = left;
3572+
node.right = Node(NODE_IDENTIFIER);
3573+
node.right.pos = pos;
3574+
node.right.value = name;
3575+
return node;
3576+
}
3577+
35313578
ExprParser.prototype.parse_identifier = function() {
35323579
this.reader.skip_white();
35333580
var npos = this.reader.getpos();

py/vimlparser.py

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ def viml_type(obj):
352352
TOKEN_ARROW = 65
353353
TOKEN_BLOB = 66
354354
TOKEN_LITCOPEN = 67
355+
TOKEN_DOTDOT = 68
355356
MAX_FUNC_ARGS = 20
356357
def isalpha(c):
357358
return viml_eqregh(c, "^[A-Za-z]$")
@@ -1427,8 +1428,11 @@ def parse_cmd_let(self):
14271428
self.reader.skip_white()
14281429
s1 = self.reader.peekn(1)
14291430
s2 = self.reader.peekn(2)
1431+
# TODO check scriptversion?
1432+
if s2 == "..":
1433+
s2 = self.reader.peekn(3)
14301434
# :let {var-name} ..
1431-
if self.ends_excmds(s1) or s2 != "+=" and s2 != "-=" and s2 != ".=" and s2 != "*=" and s2 != "/=" and s2 != "%=" and s1 != "=":
1435+
if self.ends_excmds(s1) or s2 != "+=" and s2 != "-=" and s2 != ".=" and s2 != "..=" and s2 != "*=" and s2 != "/=" and s2 != "%=" and s1 != "=":
14321436
self.reader.seek_set(pos)
14331437
self.parse_cmd_common()
14341438
return
@@ -1441,8 +1445,8 @@ def parse_cmd_let(self):
14411445
node.list = lhs.list
14421446
node.rest = lhs.rest
14431447
node.right = NIL
1444-
if s2 == "+=" or s2 == "-=" or s2 == ".=" or s2 == "*=" or s2 == "/=" or s2 == "%=":
1445-
self.reader.getn(2)
1448+
if s2 == "+=" or s2 == "-=" or s2 == ".=" or s2 == "..=" or s2 == "*=" or s2 == "/=" or s2 == "%=":
1449+
self.reader.getn(viml_len(s2))
14461450
node.op = s2
14471451
elif s1 == "=":
14481452
self.reader.getn(1)
@@ -2002,9 +2006,14 @@ def get2(self):
20022006
if r.p(1) == "." and r.p(2) == ".":
20032007
r.seek_cur(3)
20042008
return self.token(TOKEN_DOTDOTDOT, "...", pos)
2009+
elif r.p(1) == ".":
2010+
r.seek_cur(2)
2011+
return self.token(TOKEN_DOTDOT, "..", pos)
2012+
# TODO check scriptversion?
20052013
else:
20062014
r.seek_cur(1)
20072015
return self.token(TOKEN_DOT, ".", pos)
2016+
# TODO check scriptversion?
20082017
elif c == "*":
20092018
r.seek_cur(1)
20102019
return self.token(TOKEN_STAR, "*", pos)
@@ -2421,6 +2430,7 @@ def parse_expr4(self):
24212430
# expr5: expr6 + expr6 ..
24222431
# expr6 - expr6 ..
24232432
# expr6 . expr6 ..
2433+
# expr6 .. expr6 ..
24242434
def parse_expr5(self):
24252435
left = self.parse_expr6()
24262436
while TRUE:
@@ -2438,7 +2448,15 @@ def parse_expr5(self):
24382448
node.left = left
24392449
node.right = self.parse_expr6()
24402450
left = node
2451+
elif token.type == TOKEN_DOTDOT:
2452+
# TODO check scriptversion?
2453+
node = Node(NODE_CONCAT)
2454+
node.pos = token.pos
2455+
node.left = left
2456+
node.right = self.parse_expr6()
2457+
left = node
24412458
elif token.type == TOKEN_DOT:
2459+
# TODO check scriptversion?
24422460
node = Node(NODE_CONCAT)
24432461
node.pos = token.pos
24442462
node.left = left
@@ -2582,6 +2600,7 @@ def parse_expr8(self):
25822600
left = node
25832601
del node
25842602
elif not iswhite(c) and token.type == TOKEN_DOT:
2603+
# TODO check scriptversion?
25852604
node = self.parse_dot(token, left)
25862605
if node is NIL:
25872606
self.reader.seek_set(pos)
@@ -2812,6 +2831,27 @@ def parse_dot(self, token, left):
28122831
node.right.value = name
28132832
return node
28142833

2834+
# CONCAT
2835+
# str ".." expr6 => (concat str expr6)
2836+
def parse_concat(self, token, left):
2837+
if left.type != NODE_IDENTIFIER and left.type != NODE_CURLYNAME and left.type != NODE_DICT and left.type != NODE_SUBSCRIPT and left.type != NODE_CALL and left.type != NODE_DOT:
2838+
return NIL
2839+
if not iswordc(self.reader.p(0)):
2840+
return NIL
2841+
pos = self.reader.getpos()
2842+
name = self.reader.read_word()
2843+
if isnamec(self.reader.p(0)):
2844+
# XXX: foo is str => ok, foo is obj => invalid expression
2845+
# foo.s:bar or foo.bar#baz
2846+
return NIL
2847+
node = Node(NODE_CONCAT)
2848+
node.pos = token.pos
2849+
node.left = left
2850+
node.right = Node(NODE_IDENTIFIER)
2851+
node.right.pos = pos
2852+
node.right.value = name
2853+
return node
2854+
28152855
def parse_identifier(self):
28162856
self.reader.skip_white()
28172857
npos = self.reader.getpos()

test/test1.ok

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,5 @@
5151
(let *= a 3)
5252
(let /= a 4)
5353
(let %= a 5)
54+
(let ..= a 'foo')
55+
(echo (concat (concat 'foo' 'bar') 'baz'))

test/test1.vim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,5 @@ let a += 2
5656
let a *= 3
5757
let a /= 4
5858
let a %= 5
59+
let a ..= 'foo'
60+
echo ('foo' .. 'bar')..'baz'

0 commit comments

Comments
 (0)