parse and compile argumentless lambdas

This commit is contained in:
Qi Xiao 2016-02-05 01:00:54 +01:00
parent 6a5f6bf244
commit 3e0dc9c57b
3 changed files with 41 additions and 21 deletions

View File

@ -600,10 +600,15 @@ func (cp *compiler) popScope() {
func (cp *compiler) lambda(n *parse.Primary) valuesOp {
// Collect argument names
argNames := make([]string, len(n.List.Compounds))
for i, arg := range n.List.Compounds {
name := mustString(cp, arg, "expect string")
argNames[i] = name
var argNames []string
if n.List != nil {
argNames = make([]string, len(n.List.Compounds))
for i, arg := range n.List.Compounds {
name := mustString(cp, arg, "expect string")
argNames[i] = name
}
} else {
argNames = []string{}
}
// XXX The fiddlings with cp.capture is likely wrong.

View File

@ -475,21 +475,12 @@ func (pn *Primary) lbracket(ps *parser) {
ps.error = shouldBeRBracket
return
}
if !parseSep(pn, ps, '{') {
// List
if parseSep(pn, ps, '{') {
pn.lambda(ps)
} else {
pn.Type = List
return
}
pn.Type = Lambda
if !startsChunk(ps.peek(), nil) && ps.peek() != '}' {
ps.error = shouldBeChunk
return
}
pn.setChunk(parseChunk(ps, nil))
if !parseSep(pn, ps, '}') {
ps.error = shouldBeRBrace
return
}
case r == '&':
pn.Type = Map
// parseSep(pn, ps, '&')
@ -527,9 +518,16 @@ var (
// Braced = '{' Compound { (','|'-') Compounds } '}'
// Comma = { Space } [ ',' ] { Space }
func (pn *Primary) braced(ps *parser) {
pn.Type = Braced
func (pn *Primary) lbrace(ps *parser) {
parseSep(pn, ps, '{')
if r := ps.peek(); r == ';' || r == '\n' || isSpace(r) {
pn.lambda(ps)
return
}
pn.Type = Braced
// XXX: we don't actually know what happens with an empty Compound.
pn.addToBraced(parseCompound(ps, isBracedSep))
for isBracedSep(ps.peek()) {
@ -550,6 +548,19 @@ func (pn *Primary) braced(ps *parser) {
}
}
// lambda parses a lambda expression. The opening brace has been seen.
func (pn *Primary) lambda(ps *parser) {
pn.Type = Lambda
if !startsChunk(ps.peek(), nil) && ps.peek() != '}' {
ps.error = shouldBeChunk
return
}
pn.setChunk(parseChunk(ps, nil))
if !parseSep(pn, ps, '}') {
ps.error = shouldBeRBrace
}
}
func startsPrimary(r rune, cut runePred) bool {
if cut.matches(r) {
return false
@ -584,7 +595,7 @@ func (pn *Primary) parse(ps *parser, cut runePred) {
case '[':
pn.lbracket(ps)
case '{':
pn.braced(ps)
pn.lbrace(ps)
default:
pn.bareword(ps, cut)
}

View File

@ -126,7 +126,7 @@ var goodCases = []struct {
ast{"Compound/Indexing/Primary", fs{"Type": Map, "text": "[ & ]"}},
)},
// Lambda
{"a []{} [ ]{ } []{ echo 233 } [ $x $y ]{puts $x $y}", a(
{"a []{} [ ]{ } []{ echo 233 } [ $x $y ]{puts $x $y} { put $1}", a(
ast{"Compound/Indexing/Primary", fs{
"Type": Lambda,
}},
@ -142,6 +142,10 @@ var goodCases = []struct {
"List": "$x $y ",
"Chunk": "puts $x $y",
}},
ast{"Compound/Indexing/Primary", fs{
"Type": Lambda,
"Chunk": " put $1",
}},
)},
// Output capture
{"a () (b;c)", a(