Skip to content

support lambda #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 95 additions & 6 deletions autoload/vimlparser.vim
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ let s:NODE_ENV = 88
let s:NODE_REG = 89
let s:NODE_CURLYNAMEPART = 90
let s:NODE_CURLYNAMEEXPR = 91
let s:NODE_LAMBDA = 92

let s:TOKEN_EOF = 1
let s:TOKEN_EOL = 2
Expand Down Expand Up @@ -201,6 +202,7 @@ let s:TOKEN_SEMICOLON = 61
let s:TOKEN_BACKTICK = 62
let s:TOKEN_DOTDOTDOT = 63
let s:TOKEN_SHARP = 64
let s:TOKEN_ARROW = 65

let s:MAX_FUNC_ARGS = 20

Expand Down Expand Up @@ -400,6 +402,7 @@ endfunction
" REG .value
" CURLYNAMEPART .value
" CURLYNAMEEXPR .value
" LAMBDA .rlist .left
function! s:Node(type)
return {'type': a:type}
endfunction
Expand Down Expand Up @@ -2652,8 +2655,13 @@ function! s:ExprTokenizer.get2()
call r.seek_cur(1)
return self.token(s:TOKEN_PLUS, '+', pos)
elseif c ==# '-'
call r.seek_cur(1)
return self.token(s:TOKEN_MINUS, '-', pos)
if r.p(1) ==# '>'
call r.seek_cur(2)
return self.token(s:TOKEN_ARROW, '->', pos)
else
call r.seek_cur(1)
return self.token(s:TOKEN_MINUS, '-', pos)
endif
elseif c ==# '.'
if r.p(1) ==# '.' && r.p(2) ==# '.'
call r.seek_cur(3)
Expand Down Expand Up @@ -3290,6 +3298,7 @@ endfunction
" 'string'
" [expr1, ...]
" {expr1: expr1, ...}
" {args -> expr1}
" &option
" (expr1)
" variable
Expand Down Expand Up @@ -3342,13 +3351,20 @@ function! s:ExprParser.parse_expr9()
endwhile
endif
elseif token.type == s:TOKEN_COPEN
let node = s:Node(s:NODE_DICT)
let node.pos = token.pos
let node.value = []
let node = s:Node(-1)
let p = token.pos
let token = self.tokenizer.peek()
if token.type == s:TOKEN_CCLOSE
" dict
call self.tokenizer.get()
else
let node = s:Node(s:NODE_DICT)
let node.pos = p
let node.value = []
elseif token.type == s:TOKEN_DQUOTE || token.type == s:TOKEN_SQUOTE
" dict
let node = s:Node(s:NODE_DICT)
let node.pos = p
let node.value = []
while s:TRUE
let key = self.parse_expr1()
let token = self.tokenizer.get()
Expand Down Expand Up @@ -3377,6 +3393,72 @@ function! s:ExprParser.parse_expr9()
throw s:Err(printf('unexpected token: %s', token.value), token.pos)
endif
endwhile
else
" lambda ref: s:NODE_FUNCTION
let node = s:Node(s:NODE_LAMBDA)
let node.pos = p
let node.rlist = []
let named = {}
while 1
let token = self.tokenizer.get()
if token.type == s:TOKEN_ARROW
break
elseif token.type == s:TOKEN_IDENTIFIER
if !s:isargname(token.value)
throw s:Err(printf('E125: Illegal argument: %s', token.value), token.pos)
elseif has_key(named, token.value)
throw s:Err(printf('E853: Duplicate argument name: %s', token.value), token.pos)
endif
let named[token.value] = 1
let varnode = s:Node(s:NODE_IDENTIFIER)
let varnode.pos = token.pos
let varnode.value = token.value
" XXX: Vim doesn't skip white space before comma. {a ,b -> ...} => E475
if s:iswhite(self.reader.p(0)) && self.tokenizer.peek().type == s:TOKEN_COMMA
throw s:Err('E475: Invalid argument: White space is not allowed before comma', self.reader.getpos())
endif
let token = self.tokenizer.get()
" handle curly_parts
if token.type == s:TOKEN_COPEN || token.type == s:TOKEN_CCLOSE
if !empty(node.rlist)
throw s:Err(printf('unexpected token: %s', token.value), token.pos)
endif
call self.reader.seek_set(pos)
let node = self.parse_identifier()
return node
endif
call add(node.rlist, varnode)
if token.type == s:TOKEN_COMMA
" XXX: Vim allows last comma. {a, b, -> ...} => OK
if self.reader.peekn(2) == '->'
call self.tokenizer.get()
break
endif
elseif token.type == s:TOKEN_ARROW
break
else
throw s:Err(printf('unexpected token: %s, type: %d', token.value, token.type), token.pos)
endif
elseif token.type == s:TOKEN_DOTDOTDOT
let varnode = s:Node(s:NODE_IDENTIFIER)
let varnode.pos = token.pos
let varnode.value = token.value
call add(node.rlist, varnode)
let token = self.tokenizer.get()
if token.type == s:TOKEN_ARROW
break
else
throw s:Err(printf('unexpected token: %s', token.value), token.pos)
endif
else
throw s:Err(printf('unexpected token: %s', token.value), token.pos)
endif
endwhile
let node.left = self.parse_expr1()
let token = self.tokenizer.get()
if token.type != s:TOKEN_CCLOSE
throw s:Err(printf('unexpected token: %s', token.value), token.pos)
endif
endif
elseif token.type == s:TOKEN_POPEN
let node = self.parse_expr1()
Expand Down Expand Up @@ -4048,6 +4130,8 @@ function! s:Compiler.compile(node)
return self.compile_curlynamepart(a:node)
elseif a:node.type == s:NODE_CURLYNAMEEXPR
return self.compile_curlynameexpr(a:node)
elseif a:node.type == s:NODE_LAMBDA
return self.compile_lambda(a:node)
else
throw printf('Compiler: unknown node: %s', string(a:node))
endif
Expand Down Expand Up @@ -4506,6 +4590,11 @@ function! s:Compiler.compile_curlynameexpr(node)
return '{' . self.compile(a:node.value) . '}'
endfunction

function! s:Compiler.compile_lambda(node)
let rlist = map(a:node.rlist, 'self.compile(v:val)')
return printf('(lambda (%s) %s)', join(rlist, ' '), self.compile(a:node.left))
endfunction

" TODO: under construction
let s:RegexpParser = {}

Expand Down
1 change: 1 addition & 0 deletions go/typedefs.vim
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ call extend(s:typedefs.func, {
\ 'Compiler.compile_reg': { 'in': ['*VimNode'], 'out': ['string'] },
\ 'Compiler.compile_curlynamepart': { 'in': ['*VimNode'], 'out': ['string'] },
\ 'Compiler.compile_curlynameexpr': { 'in': ['*VimNode'], 'out': ['string'] },
\ 'Compiler.compile_lambda': { 'in': ['*VimNode'], 'out': ['string'] },
\ })

function! ImportTypedefs() abort
Expand Down
100 changes: 94 additions & 6 deletions go/vimlparser.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions node.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,5 @@ const (
NodeReg = 89
NodeCurlynamepart = 90
NodeCurlynameexpr = 91
NodeLambda = 92
)
1 change: 1 addition & 0 deletions test/test_err_lambdaarg.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vimlparser: E125: Illegal argument: a:bar: line 1 col 37
1 change: 1 addition & 0 deletions test/test_err_lambdaarg.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
echo {a, b, C, d_e, _f, g_, h0, i1, a:bar -> 1}
1 change: 1 addition & 0 deletions test/test_err_lambdaarg_duplicate.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vimlparser: E853: Duplicate argument name: b: line 1 col 13
1 change: 1 addition & 0 deletions test/test_err_lambdaarg_duplicate.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
echo {a, b, b, c ->1}
5 changes: 5 additions & 0 deletions test/test_lambda.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
; test_lambda
(echo (lambda () (+ 1 1)))
(echo (lambda (i v) (>= v s:x)))
(echo (lambda (...) a:000))
(echo ((lambda (x) (* x 2)) 14))
5 changes: 5 additions & 0 deletions test/test_lambda.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
" test_lambda
echo {->1 + 1}
echo {i, v -> v >= s:x}
echo {...->a:000}
echo {x->x*2}(14)
1 change: 1 addition & 0 deletions test/test_xxx_err_lambdaarg_space_comma.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vimlparser: E475: Invalid argument: White space is not allowed before comma: line 10 col 8
10 changes: 10 additions & 0 deletions test/test_xxx_err_lambdaarg_space_comma.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
echo {a->'OK1'}
echo { a->'OK2'}
echo {a ->'OK3'}
echo { a ->'OK4'}
echo {a,b->'OK5'}
echo {a, b->'OK6'}
echo { a, b->'OK7'}
echo {a, b ->'OK8'}
echo { a, b ->'OK9'}
echo {a ,b->'NG'}
2 changes: 2 additions & 0 deletions test/test_xxx_lambdaarg_last_comma.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(echo (lambda (a) 0))
(echo (lambda (a) 0))
2 changes: 2 additions & 0 deletions test/test_xxx_lambdaarg_last_comma.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
echo {a,->0}
echo {a, ->0}