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 { func (cp *compiler) lambda(n *parse.Primary) valuesOp {
// Collect argument names // Collect argument names
argNames := make([]string, len(n.List.Compounds)) var argNames []string
for i, arg := range n.List.Compounds { if n.List != nil {
name := mustString(cp, arg, "expect string") argNames = make([]string, len(n.List.Compounds))
argNames[i] = name 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. // XXX The fiddlings with cp.capture is likely wrong.

View File

@ -475,21 +475,12 @@ func (pn *Primary) lbracket(ps *parser) {
ps.error = shouldBeRBracket ps.error = shouldBeRBracket
return return
} }
if !parseSep(pn, ps, '{') { if parseSep(pn, ps, '{') {
// List pn.lambda(ps)
} else {
pn.Type = List 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 == '&': case r == '&':
pn.Type = Map pn.Type = Map
// parseSep(pn, ps, '&') // parseSep(pn, ps, '&')
@ -527,9 +518,16 @@ var (
// Braced = '{' Compound { (','|'-') Compounds } '}' // Braced = '{' Compound { (','|'-') Compounds } '}'
// Comma = { Space } [ ',' ] { Space } // Comma = { Space } [ ',' ] { Space }
func (pn *Primary) braced(ps *parser) { func (pn *Primary) lbrace(ps *parser) {
pn.Type = Braced
parseSep(pn, ps, '{') 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. // XXX: we don't actually know what happens with an empty Compound.
pn.addToBraced(parseCompound(ps, isBracedSep)) pn.addToBraced(parseCompound(ps, isBracedSep))
for isBracedSep(ps.peek()) { 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 { func startsPrimary(r rune, cut runePred) bool {
if cut.matches(r) { if cut.matches(r) {
return false return false
@ -584,7 +595,7 @@ func (pn *Primary) parse(ps *parser, cut runePred) {
case '[': case '[':
pn.lbracket(ps) pn.lbracket(ps)
case '{': case '{':
pn.braced(ps) pn.lbrace(ps)
default: default:
pn.bareword(ps, cut) pn.bareword(ps, cut)
} }

View File

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