@@ -138,6 +138,7 @@ let s:NODE_CURLYNAMEPART = 90
138138let s: NODE_CURLYNAMEEXPR = 91
139139let s: NODE_LAMBDA = 92
140140let s: NODE_BLOB = 93
141+ let s: NODE_CONST = 94
141142
142143let s: TOKEN_EOF = 1
143144let 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)
805807endfunction
806808
809+ " TODO: self[a:parser]
807810function ! 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)
15331538endfunction
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+
15351575function ! 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)
18661906endfunction
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+
18681932function ! 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
19151979endfunction
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+
19172015function ! s: VimLParser .ends_excmds (c )
19182016 return a: c == # ' ' || a: c == # ' |' || a: c == # ' "' || a: c == # ' <EOF>' || a: c == # ' <EOL>'
19192017endfunction
@@ -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 )
49095011endfunction
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+
49115029function ! s: Compiler .compile_unlet (node)
49125030 let list = map (a: node .list , ' self.compile(v:val)' )
49135031 call self .out (' (unlet %s)' , join (list , ' ' ))
0 commit comments