@@ -138,6 +138,7 @@ let s:NODE_CURLYNAMEPART = 90
138
138
let s: NODE_CURLYNAMEEXPR = 91
139
139
let s: NODE_LAMBDA = 92
140
140
let s: NODE_BLOB = 93
141
+ let s: NODE_CONST = 94
141
142
142
143
let s: TOKEN_EOF = 1
143
144
let s: TOKEN_EOL = 2
@@ -324,6 +325,7 @@ endfunction
324
325
" RETURN .ea .left
325
326
" EXCALL .ea .left
326
327
" LET .ea .op .left .list .rest .right
328
+ " CONST .ea .op .left .list .rest .right
327
329
" UNLET .ea .list
328
330
" LOCKVAR .ea .depth .list
329
331
" UNLOCKVAR .ea .depth .list
@@ -804,6 +806,7 @@ function! s:VimLParser.parse_command()
804
806
call self ._parse_command (self .ea .cmd.parser)
805
807
endfunction
806
808
809
+ " TODO: self[a:parser]
807
810
function ! s: VimLParser ._parse_command (parser) abort
808
811
if a: parser == # ' parse_cmd_append'
809
812
call self .parse_cmd_append ()
@@ -859,6 +862,8 @@ function! s:VimLParser._parse_command(parser) abort
859
862
call self .parse_cmd_insert ()
860
863
elseif a: parser == # ' parse_cmd_let'
861
864
call self .parse_cmd_let ()
865
+ elseif a: parser == # ' parse_cmd_const'
866
+ call self .parse_cmd_const ()
862
867
elseif a: parser == # ' parse_cmd_loadkeymap'
863
868
call self .parse_cmd_loadkeymap ()
864
869
elseif a: parser == # ' parse_cmd_lockvar'
@@ -1532,6 +1537,41 @@ function! s:VimLParser.parse_cmd_let()
1532
1537
call self .add_node (node)
1533
1538
endfunction
1534
1539
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
+
1535
1575
function ! s: VimLParser .parse_cmd_unlet ()
1536
1576
let node = s: Node (s: NODE_UNLET )
1537
1577
let node.pos = self .ea .cmdpos
@@ -1865,6 +1905,30 @@ function! s:VimLParser.parse_lvalue()
1865
1905
throw s: Err (' Invalid Expression' , node.pos)
1866
1906
endfunction
1867
1907
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
+
1868
1932
function ! s: VimLParser .parse_lvaluelist ()
1869
1933
let list = []
1870
1934
let node = self .parse_expr ()
@@ -1914,6 +1978,40 @@ function! s:VimLParser.parse_letlhs()
1914
1978
return lhs
1915
1979
endfunction
1916
1980
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
+
1917
2015
function ! s: VimLParser .ends_excmds (c )
1918
2016
return a: c == # ' ' || a: c == # ' |' || a: c == # ' "' || a: c == # ' <EOF>' || a: c == # ' <EOL>'
1919
2017
endfunction
@@ -2192,6 +2290,7 @@ let s:VimLParser.builtin_commands = [
2192
2290
\ {' name' : ' left' , ' minlen' : 2 , ' flags' : ' TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY' , ' parser' : ' parse_cmd_common' },
2193
2291
\ {' name' : ' leftabove' , ' minlen' : 5 , ' flags' : ' NEEDARG|EXTRA|NOTRLCOM' , ' parser' : ' parse_cmd_common' },
2194
2292
\ {' 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' },
2195
2294
\ {' name' : ' lexpr' , ' minlen' : 3 , ' flags' : ' NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG' , ' parser' : ' parse_cmd_common' },
2196
2295
\ {' name' : ' lfile' , ' minlen' : 2 , ' flags' : ' TRLBAR|FILE1|BANG' , ' parser' : ' parse_cmd_common' },
2197
2296
\ {' name' : ' lfirst' , ' minlen' : 4 , ' flags' : ' RANGE|NOTADR|COUNT|TRLBAR|BANG' , ' parser' : ' parse_cmd_common' },
@@ -4669,6 +4768,9 @@ function! s:Compiler.compile(node)
4669
4768
elseif a: node .type == s: NODE_LET
4670
4769
call self .compile_let (a: node )
4671
4770
return s: NIL
4771
+ elseif a: node .type == s: NODE_CONST
4772
+ call self .compile_const (a: node )
4773
+ return s: NIL
4672
4774
elseif a: node .type == s: NODE_UNLET
4673
4775
call self .compile_unlet (a: node )
4674
4776
return s: NIL
@@ -4908,6 +5010,22 @@ function! s:Compiler.compile_let(node)
4908
5010
call self .out (' (let %s %s %s)' , a: node .op , left , right )
4909
5011
endfunction
4910
5012
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
+
4911
5029
function ! s: Compiler .compile_unlet (node)
4912
5030
let list = map (a: node .list , ' self.compile(v:val)' )
4913
5031
call self .out (' (unlet %s)' , join (list , ' ' ))
0 commit comments