Skip to content

Commit c91b43a

Browse files
authored
Merge pull request #120 from vim-jp/heredoc
Add heredoc
2 parents 02c2d5b + 276981e commit c91b43a

File tree

6 files changed

+263
-9
lines changed

6 files changed

+263
-9
lines changed

autoload/vimlparser.vim

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ let s:NODE_LAMBDA = 92
140140
let s:NODE_BLOB = 93
141141
let s:NODE_CONST = 94
142142
let s:NODE_EVAL = 95
143+
let s:NODE_HEREDOC = 96
143144

144145
let s:TOKEN_EOF = 1
145146
let s:TOKEN_EOL = 2
@@ -209,6 +210,7 @@ let s:TOKEN_ARROW = 65
209210
let s:TOKEN_BLOB = 66
210211
let s:TOKEN_LITCOPEN = 67
211212
let s:TOKEN_DOTDOT = 68
213+
let s:TOKEN_HEREDOC = 69
212214

213215
let s:MAX_FUNC_ARGS = 20
214216

@@ -412,6 +414,7 @@ endfunction
412414
" CURLYNAMEPART .value
413415
" CURLYNAMEEXPR .value
414416
" LAMBDA .rlist .left
417+
" HEREDOC .rlist .op .body
415418
function! s:Node(type) abort
416419
return {'type': a:type}
417420
endfunction
@@ -1500,6 +1503,44 @@ function! s:VimLParser.parse_cmd_call() abort
15001503
call self.add_node(node)
15011504
endfunction
15021505

1506+
function! s:VimLParser.parse_heredoc() abort
1507+
let node = s:Node(s:NODE_HEREDOC)
1508+
let node.pos = self.ea.cmdpos
1509+
let node.op = ''
1510+
let node.rlist = []
1511+
let node.body = []
1512+
1513+
while s:TRUE
1514+
call self.reader.skip_white()
1515+
let key = self.reader.read_word()
1516+
if key == ''
1517+
break
1518+
endif
1519+
if !s:islower(key[0])
1520+
let node.op = key
1521+
break
1522+
else
1523+
call add(node.rlist, key)
1524+
endif
1525+
endwhile
1526+
if node.op ==# ''
1527+
throw s:Err('E172: Missing marker', self.reader.getpos())
1528+
endif
1529+
call self.parse_trail()
1530+
while s:TRUE
1531+
if self.reader.peek() ==# '<EOF>'
1532+
break
1533+
endif
1534+
let line = self.reader.getn(-1)
1535+
if line ==# node.op
1536+
return node
1537+
endif
1538+
call add(node.body, line)
1539+
call self.reader.get()
1540+
endwhile
1541+
throw s:Err(printf("E990: Missing end marker '%s'", node.op), self.reader.getpos())
1542+
endfunction
1543+
15031544
function! s:VimLParser.parse_cmd_let() abort
15041545
let pos = self.reader.tell()
15051546
call self.reader.skip_white()
@@ -1518,10 +1559,12 @@ function! s:VimLParser.parse_cmd_let() abort
15181559
" TODO check scriptversion?
15191560
if s2 ==# '..'
15201561
let s2 = self.reader.peekn(3)
1562+
elseif s2 ==# '=<'
1563+
let s2 = self.reader.peekn(3)
15211564
endif
15221565

15231566
" :let {var-name} ..
1524-
if self.ends_excmds(s1) || (s2 !=# '+=' && s2 !=# '-=' && s2 !=# '.=' && s2 !=# '..=' && s2 !=# '*=' && s2 !=# '/=' && s2 !=# '%=' && s1 !=# '=')
1567+
if self.ends_excmds(s1) || (s2 !=# '+=' && s2 !=# '-=' && s2 !=# '.=' && s2 !=# '..=' && s2 !=# '*=' && s2 !=# '/=' && s2 !=# '%=' && s2 !=# '=<<' && s1 !=# '=')
15251568
call self.reader.seek_set(pos)
15261569
call self.parse_cmd_common()
15271570
return
@@ -1539,6 +1582,13 @@ function! s:VimLParser.parse_cmd_let() abort
15391582
if s2 ==# '+=' || s2 ==# '-=' || s2 ==# '.=' || s2 ==# '..=' || s2 ==# '*=' || s2 ==# '/=' || s2 ==# '%='
15401583
call self.reader.getn(len(s2))
15411584
let node.op = s2
1585+
elseif s2 ==# '=<<'
1586+
call self.reader.getn(len(s2))
1587+
call self.reader.skip_white()
1588+
let node.op = s2
1589+
let node.right = self.parse_heredoc()
1590+
call self.add_node(node)
1591+
return
15421592
elseif s1 ==# '='
15431593
call self.reader.getn(1)
15441594
let node.op = s1
@@ -4958,6 +5008,8 @@ function! s:Compiler.compile(node) abort
49585008
return self.compile_curlynameexpr(a:node)
49595009
elseif a:node.type ==# s:NODE_LAMBDA
49605010
return self.compile_lambda(a:node)
5011+
elseif a:node.type == s:NODE_HEREDOC
5012+
return self.compile_heredoc(a:node)
49615013
else
49625014
throw printf('Compiler: unknown node: %s', string(a:node))
49635015
endif
@@ -5451,11 +5503,41 @@ function! s:Compiler.compile_curlynameexpr(node) abort
54515503
return '{' . self.compile(a:node.value) . '}'
54525504
endfunction
54535505

5506+
function! s:Compiler.escape_string(str) abort
5507+
let m = {"\n": '\n', "\t": '\t', "\r": '\r'}
5508+
let out = '"'
5509+
for i in range(len(a:str))
5510+
let c = a:str[i]
5511+
if has_key(m, c)
5512+
let out .= m[c]
5513+
else
5514+
let out .= c
5515+
endif
5516+
endfor
5517+
let out .= '"'
5518+
return out
5519+
endfunction
5520+
54545521
function! s:Compiler.compile_lambda(node) abort
54555522
let rlist = map(a:node.rlist, 'self.compile(v:val)')
54565523
return printf('(lambda (%s) %s)', join(rlist, ' '), self.compile(a:node.left))
54575524
endfunction
54585525

5526+
function! s:Compiler.compile_heredoc(node) abort
5527+
if empty(a:node.rlist)
5528+
let rlist = '(list)'
5529+
else
5530+
let rlist = '(list ' . join(map(a:node.rlist, 'self.escape_string(v:val)'), ' ') . ')'
5531+
endif
5532+
if empty(a:node.body)
5533+
let body = '(list)'
5534+
else
5535+
let body = '(list ' . join(map(a:node.body, 'self.escape_string(v:val)'), ' ') . ')'
5536+
endif
5537+
let op = self.escape_string(a:node.op)
5538+
return printf('(heredoc %s %s %s)', rlist, op, body)
5539+
endfunction
5540+
54595541
" TODO: under construction
54605542
let s:RegexpParser = {}
54615543

js/vimlparser.js

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ var NODE_LAMBDA = 92;
321321
var NODE_BLOB = 93;
322322
var NODE_CONST = 94;
323323
var NODE_EVAL = 95;
324+
var NODE_HEREDOC = 96;
324325
var TOKEN_EOF = 1;
325326
var TOKEN_EOL = 2;
326327
var TOKEN_SPACE = 3;
@@ -389,6 +390,7 @@ var TOKEN_ARROW = 65;
389390
var TOKEN_BLOB = 66;
390391
var TOKEN_LITCOPEN = 67;
391392
var TOKEN_DOTDOT = 68;
393+
var TOKEN_HEREDOC = 69;
392394
var MAX_FUNC_ARGS = 20;
393395
function isalpha(c) {
394396
return viml_eqregh(c, "^[A-Za-z]$");
@@ -590,6 +592,7 @@ function ExArg() {
590592
// CURLYNAMEPART .value
591593
// CURLYNAMEEXPR .value
592594
// LAMBDA .rlist .left
595+
// HEREDOC .rlist .op .body
593596
function Node(type) {
594597
return {"type":type};
595598
}
@@ -1795,6 +1798,44 @@ VimLParser.prototype.parse_cmd_call = function() {
17951798
this.add_node(node);
17961799
}
17971800

1801+
VimLParser.prototype.parse_heredoc = function() {
1802+
var node = Node(NODE_HEREDOC);
1803+
node.pos = this.ea.cmdpos;
1804+
node.op = "";
1805+
node.rlist = [];
1806+
node.body = [];
1807+
while (TRUE) {
1808+
this.reader.skip_white();
1809+
var key = this.reader.read_word();
1810+
if (key == "") {
1811+
break;
1812+
}
1813+
if (!islower(key[0])) {
1814+
node.op = key;
1815+
break;
1816+
}
1817+
else {
1818+
viml_add(node.rlist, key);
1819+
}
1820+
}
1821+
if (node.op == "") {
1822+
throw Err("E172: Missing marker", this.reader.getpos());
1823+
}
1824+
this.parse_trail();
1825+
while (TRUE) {
1826+
if (this.reader.peek() == "<EOF>") {
1827+
break;
1828+
}
1829+
var line = this.reader.getn(-1);
1830+
if (line == node.op) {
1831+
return node;
1832+
}
1833+
viml_add(node.body, line);
1834+
this.reader.get();
1835+
}
1836+
throw Err(viml_printf("E990: Missing end marker '%s'", node.op), this.reader.getpos());
1837+
}
1838+
17981839
VimLParser.prototype.parse_cmd_let = function() {
17991840
var pos = this.reader.tell();
18001841
this.reader.skip_white();
@@ -1812,8 +1853,11 @@ VimLParser.prototype.parse_cmd_let = function() {
18121853
if (s2 == "..") {
18131854
var s2 = this.reader.peekn(3);
18141855
}
1856+
else if (s2 == "=<") {
1857+
var s2 = this.reader.peekn(3);
1858+
}
18151859
// :let {var-name} ..
1816-
if (this.ends_excmds(s1) || s2 != "+=" && s2 != "-=" && s2 != ".=" && s2 != "..=" && s2 != "*=" && s2 != "/=" && s2 != "%=" && s1 != "=") {
1860+
if (this.ends_excmds(s1) || s2 != "+=" && s2 != "-=" && s2 != ".=" && s2 != "..=" && s2 != "*=" && s2 != "/=" && s2 != "%=" && s2 != "=<<" && s1 != "=") {
18171861
this.reader.seek_set(pos);
18181862
this.parse_cmd_common();
18191863
return;
@@ -1831,6 +1875,14 @@ VimLParser.prototype.parse_cmd_let = function() {
18311875
this.reader.getn(viml_len(s2));
18321876
node.op = s2;
18331877
}
1878+
else if (s2 == "=<<") {
1879+
this.reader.getn(viml_len(s2));
1880+
this.reader.skip_white();
1881+
node.op = s2;
1882+
node.right = this.parse_heredoc();
1883+
this.add_node(node);
1884+
return;
1885+
}
18341886
else if (s1 == "=") {
18351887
this.reader.getn(1);
18361888
node.op = s1;
@@ -4461,6 +4513,9 @@ Compiler.prototype.compile = function(node) {
44614513
else if (node.type == NODE_LAMBDA) {
44624514
return this.compile_lambda(node);
44634515
}
4516+
else if (node.type == NODE_HEREDOC) {
4517+
return this.compile_heredoc(node);
4518+
}
44644519
else {
44654520
throw viml_printf("Compiler: unknown node: %s", viml_string(node));
44664521
}
@@ -4973,11 +5028,46 @@ Compiler.prototype.compile_curlynameexpr = function(node) {
49735028
return "{" + this.compile(node.value) + "}";
49745029
}
49755030

5031+
Compiler.prototype.escape_string = function(str) {
5032+
var m = {"\n":"\\n", "\t":"\\t", "\r":"\\r"};
5033+
var out = "\"";
5034+
var __c14 = viml_range(viml_len(str));
5035+
for (var __i14 = 0; __i14 < __c14.length; ++__i14) {
5036+
var i = __c14[__i14];
5037+
var c = str[i];
5038+
if (viml_has_key(m, c)) {
5039+
out += m[c];
5040+
}
5041+
else {
5042+
out += c;
5043+
}
5044+
}
5045+
out += "\"";
5046+
return out;
5047+
}
5048+
49765049
Compiler.prototype.compile_lambda = function(node) {
49775050
var rlist = node.rlist.map((function(vval) { return this.compile(vval); }).bind(this));
49785051
return viml_printf("(lambda (%s) %s)", viml_join(rlist, " "), this.compile(node.left));
49795052
}
49805053

5054+
Compiler.prototype.compile_heredoc = function(node) {
5055+
if (viml_empty(node.rlist)) {
5056+
var rlist = "(list)";
5057+
}
5058+
else {
5059+
var rlist = "(list " + viml_join(node.rlist.map((function(vval) { return this.escape_string(vval); }).bind(this)), " ") + ")";
5060+
}
5061+
if (viml_empty(node.body)) {
5062+
var body = "(list)";
5063+
}
5064+
else {
5065+
var body = "(list " + viml_join(node.body.map((function(vval) { return this.escape_string(vval); }).bind(this)), " ") + ")";
5066+
}
5067+
var op = this.escape_string(node.op);
5068+
return viml_printf("(heredoc %s %s %s)", rlist, op, body);
5069+
}
5070+
49815071
// TODO: under construction
49825072
function RegexpParser() { this.__init__.apply(this, arguments); }
49835073
RegexpParser.prototype.RE_VERY_NOMAGIC = 1;
@@ -5658,9 +5748,9 @@ RegexpParser.prototype.get_token_sq_char_class = function() {
56585748
var r = this.reader.read_alpha();
56595749
if (this.reader.p(0) == ":" && this.reader.p(1) == "]") {
56605750
this.reader.seek_cur(2);
5661-
var __c14 = class_names;
5662-
for (var __i14 = 0; __i14 < __c14.length; ++__i14) {
5663-
var name = __c14[__i14];
5751+
var __c15 = class_names;
5752+
for (var __i15 = 0; __i15 < __c15.length; ++__i15) {
5753+
var name = __c15[__i15];
56645754
if (r == name) {
56655755
return "[:" + name + ":]";
56665756
}
@@ -5793,9 +5883,9 @@ RegexpParser.prototype.getoctchrs = function() {
57935883

57945884
RegexpParser.prototype.gethexchrs = function(n) {
57955885
var r = "";
5796-
var __c15 = viml_range(n);
5797-
for (var __i15 = 0; __i15 < __c15.length; ++__i15) {
5798-
var i = __c15[__i15];
5886+
var __c16 = viml_range(n);
5887+
for (var __i16 = 0; __i16 < __c16.length; ++__i16) {
5888+
var i = __c16[__i16];
57995889
var c = this.reader.peek();
58005890
if (!isxdigit(c)) {
58015891
break;

py/vimlfunc.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class AttributeDict(dict):
9090
"^[0-9A-Fa-f][0-9A-Fa-f]$": "^[0-9A-Fa-f][0-9A-Fa-f]$",
9191
r"^\.[0-9A-Fa-f]$": r"^\.[0-9A-Fa-f]$",
9292
"^[0-9A-Fa-f][^0-9A-Fa-f]$": "^[0-9A-Fa-f][^0-9A-Fa-f]$",
93+
"^[^a-z]\\S\\+$": "^[^a-z]\\S\\+$",
9394
}
9495

9596

0 commit comments

Comments
 (0)