Skip to content

Commit 9cde691

Browse files
authored
Merge pull request #119 from vim-jp/const
Support :const
2 parents 5965112 + 5783913 commit 9cde691

17 files changed

+362
-2
lines changed

autoload/vimlparser.vim

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ let s:NODE_CURLYNAMEPART = 90
138138
let s:NODE_CURLYNAMEEXPR = 91
139139
let s:NODE_LAMBDA = 92
140140
let s:NODE_BLOB = 93
141+
let s:NODE_CONST = 94
141142

142143
let s:TOKEN_EOF = 1
143144
let s:TOKEN_EOL = 2
@@ -324,6 +325,7 @@ endfunction
324325
" RETURN .ea .left
325326
" EXCALL .ea .left
326327
" LET .ea .op .left .list .rest .right
328+
" CONST .ea .op .left .list .rest .right
327329
" UNLET .ea .list
328330
" LOCKVAR .ea .depth .list
329331
" UNLOCKVAR .ea .depth .list
@@ -804,6 +806,7 @@ function! s:VimLParser.parse_command()
804806
call self._parse_command(self.ea.cmd.parser)
805807
endfunction
806808

809+
" TODO: self[a:parser]
807810
function! s:VimLParser._parse_command(parser) abort
808811
if a:parser ==# 'parse_cmd_append'
809812
call self.parse_cmd_append()
@@ -859,6 +862,8 @@ function! s:VimLParser._parse_command(parser) abort
859862
call self.parse_cmd_insert()
860863
elseif a:parser ==# 'parse_cmd_let'
861864
call self.parse_cmd_let()
865+
elseif a:parser ==# 'parse_cmd_const'
866+
call self.parse_cmd_const()
862867
elseif a:parser ==# 'parse_cmd_loadkeymap'
863868
call self.parse_cmd_loadkeymap()
864869
elseif a:parser ==# 'parse_cmd_lockvar'
@@ -1532,6 +1537,41 @@ function! s:VimLParser.parse_cmd_let()
15321537
call self.add_node(node)
15331538
endfunction
15341539

1540+
function! s:VimLParser.parse_cmd_const()
1541+
let pos = self.reader.tell()
1542+
call self.reader.skip_white()
1543+
1544+
" :const
1545+
if self.ends_excmds(self.reader.peek())
1546+
call self.reader.seek_set(pos)
1547+
call self.parse_cmd_common()
1548+
return
1549+
endif
1550+
1551+
let lhs = self.parse_constlhs()
1552+
call self.reader.skip_white()
1553+
let s1 = self.reader.peekn(1)
1554+
1555+
" :const {var-name}
1556+
if self.ends_excmds(s1) || s1 !=# '='
1557+
call self.reader.seek_set(pos)
1558+
call self.parse_cmd_common()
1559+
return
1560+
endif
1561+
1562+
" :const left op right
1563+
let node = s:Node(s:NODE_CONST)
1564+
let node.pos = self.ea.cmdpos
1565+
let node.ea = self.ea
1566+
call self.reader.getn(1)
1567+
let node.op = s1
1568+
let node.left = lhs.left
1569+
let node.list = lhs.list
1570+
let node.rest = lhs.rest
1571+
let node.right = self.parse_expr()
1572+
call self.add_node(node)
1573+
endfunction
1574+
15351575
function! s:VimLParser.parse_cmd_unlet()
15361576
let node = s:Node(s:NODE_UNLET)
15371577
let node.pos = self.ea.cmdpos
@@ -1865,6 +1905,30 @@ function! s:VimLParser.parse_lvalue()
18651905
throw s:Err('Invalid Expression', node.pos)
18661906
endfunction
18671907

1908+
" TODO: merge with s:VimLParser.parse_lvalue()
1909+
function! s:VimLParser.parse_constlvalue()
1910+
let p = s:LvalueParser.new(self.reader)
1911+
let node = p.parse()
1912+
if node.type == s:NODE_IDENTIFIER
1913+
if !s:isvarname(node.value)
1914+
throw s:Err(printf('E461: Illegal variable name: %s', node.value), node.pos)
1915+
endif
1916+
endif
1917+
if node.type == s:NODE_IDENTIFIER || node.type == s:NODE_CURLYNAME
1918+
return node
1919+
elseif node.type == s:NODE_SUBSCRIPT || node.type == s:NODE_SLICE || node.type == s:NODE_DOT
1920+
throw s:Err('E996: Cannot lock a list or dict', node.pos)
1921+
elseif node.type == s:NODE_OPTION
1922+
throw s:Err('E996: Cannot lock an option', node.pos)
1923+
elseif node.type == s:NODE_ENV
1924+
throw s:Err('E996: Cannot lock an environment variable', node.pos)
1925+
elseif node.type == s:NODE_REG
1926+
throw s:Err('E996: Cannot lock a register', node.pos)
1927+
endif
1928+
throw s:Err('Invalid Expression', node.pos)
1929+
endfunction
1930+
1931+
18681932
function! s:VimLParser.parse_lvaluelist()
18691933
let list = []
18701934
let node = self.parse_expr()
@@ -1914,6 +1978,40 @@ function! s:VimLParser.parse_letlhs()
19141978
return lhs
19151979
endfunction
19161980

1981+
" TODO: merge with s:VimLParser.parse_letlhs() ?
1982+
function! s:VimLParser.parse_constlhs()
1983+
let lhs = {'left': s:NIL, 'list': s:NIL, 'rest': s:NIL}
1984+
let tokenizer = s:ExprTokenizer.new(self.reader)
1985+
if tokenizer.peek().type == s:TOKEN_SQOPEN
1986+
call tokenizer.get()
1987+
let lhs.list = []
1988+
while s:TRUE
1989+
let node = self.parse_lvalue()
1990+
call add(lhs.list, node)
1991+
let token = tokenizer.get()
1992+
if token.type == s:TOKEN_SQCLOSE
1993+
break
1994+
elseif token.type == s:TOKEN_COMMA
1995+
continue
1996+
elseif token.type == s:TOKEN_SEMICOLON
1997+
let node = self.parse_lvalue()
1998+
let lhs.rest = node
1999+
let token = tokenizer.get()
2000+
if token.type == s:TOKEN_SQCLOSE
2001+
break
2002+
else
2003+
throw s:Err(printf('E475 Invalid argument: %s', token.value), token.pos)
2004+
endif
2005+
else
2006+
throw s:Err(printf('E475 Invalid argument: %s', token.value), token.pos)
2007+
endif
2008+
endwhile
2009+
else
2010+
let lhs.left = self.parse_constlvalue()
2011+
endif
2012+
return lhs
2013+
endfunction
2014+
19172015
function! s:VimLParser.ends_excmds(c)
19182016
return a:c ==# '' || a:c ==# '|' || a:c ==# '"' || a:c ==# '<EOF>' || a:c ==# '<EOL>'
19192017
endfunction
@@ -2192,6 +2290,7 @@ let s:VimLParser.builtin_commands = [
21922290
\ {'name': 'left', 'minlen': 2, 'flags': 'TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'},
21932291
\ {'name': 'leftabove', 'minlen': 5, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'},
21942292
\ {'name': 'let', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_let'},
2293+
\ {'name': 'const', 'minlen': 4, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_const'},
21952294
\ {'name': 'lexpr', 'minlen': 3, 'flags': 'NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG', 'parser': 'parse_cmd_common'},
21962295
\ {'name': 'lfile', 'minlen': 2, 'flags': 'TRLBAR|FILE1|BANG', 'parser': 'parse_cmd_common'},
21972296
\ {'name': 'lfirst', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'},
@@ -4669,6 +4768,9 @@ function! s:Compiler.compile(node)
46694768
elseif a:node.type == s:NODE_LET
46704769
call self.compile_let(a:node)
46714770
return s:NIL
4771+
elseif a:node.type == s:NODE_CONST
4772+
call self.compile_const(a:node)
4773+
return s:NIL
46724774
elseif a:node.type == s:NODE_UNLET
46734775
call self.compile_unlet(a:node)
46744776
return s:NIL
@@ -4908,6 +5010,22 @@ function! s:Compiler.compile_let(node)
49085010
call self.out('(let %s %s %s)', a:node.op, left, right)
49095011
endfunction
49105012

5013+
" TODO: merge with s:Compiler.compile_let() ?
5014+
function! s:Compiler.compile_const(node)
5015+
let left = ''
5016+
if a:node.left isnot s:NIL
5017+
let left = self.compile(a:node.left)
5018+
else
5019+
let left = join(map(a:node.list, 'self.compile(v:val)'), ' ')
5020+
if a:node.rest isnot s:NIL
5021+
let left .= ' . ' . self.compile(a:node.rest)
5022+
endif
5023+
let left = '(' . left . ')'
5024+
endif
5025+
let right = self.compile(a:node.right)
5026+
call self.out('(const %s %s %s)', a:node.op, left, right)
5027+
endfunction
5028+
49115029
function! s:Compiler.compile_unlet(node)
49125030
let list = map(a:node.list, 'self.compile(v:val)')
49135031
call self.out('(unlet %s)', join(list, ' '))

js/vimlparser.js

Lines changed: 125 additions & 1 deletion
Large diffs are not rendered by default.

py/vimlparser.py

Lines changed: 98 additions & 1 deletion
Large diffs are not rendered by default.

test/test1.ok

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,6 @@
5454
(let ..= a 'foo')
5555
(echo (concat (concat 'foo' 'bar') 'baz'))
5656
(let = a '🐥')
57+
(const = a 1)
58+
(const = (a b) (list 1 2))
59+
(const = (a b . c) (list 1 2 3))

test/test1.vim

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,6 @@ let a %= 5
5959
let a ..= 'foo'
6060
echo ('foo' .. 'bar')..'baz'
6161
let a = '🐥'
62+
const a = 1
63+
const [a, b] = [1, 2]
64+
const [a, b; c] = [1, 2, 3]

test/test_err_const1.ok

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
vimlparser: E996: Cannot lock a list or dict: line 2 col 8

test/test_err_const1.vim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
let a = [0]
2+
const a[0] = 1

test/test_err_const2.ok

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
vimlparser: E996: Cannot lock a list or dict: line 2 col 8

test/test_err_const2.vim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
let a = {}
2+
const a["b"] = 1

test/test_err_const3.ok

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
vimlparser: E996: Cannot lock a list or dict: line 2 col 8

test/test_err_const3.vim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
let a = {}
2+
const a.b = 1

test/test_err_const4.ok

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
vimlparser: E996: Cannot lock an environment variable: line 1 col 7

test/test_err_const4.vim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
const $a = 1

test/test_err_const5.ok

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
vimlparser: E996: Cannot lock a register: line 1 col 7

test/test_err_const5.vim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
const @a = 1

test/test_err_const6.ok

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
vimlparser: E996: Cannot lock an option: line 1 col 7

test/test_err_const6.vim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
const &encoding = "foo"

0 commit comments

Comments
 (0)