Skip to content

Commit c9ac6bd

Browse files
committed
parse ast.LambdaExpr
1 parent 797c916 commit c9ac6bd

File tree

7 files changed

+259
-19
lines changed

7 files changed

+259
-19
lines changed

ast/ast_gop.go

+28
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,34 @@ func (*ErrWrapExpr) exprNode() {}
9292

9393
// -----------------------------------------------------------------------------
9494

95+
// LambdaExpr represents
96+
// `(x, y, ...) => exprOrExprTuple`
97+
// `x => exprOrExprTuple`
98+
// `=> exprOrExprTuple`
99+
// here exprOrExprTuple represents
100+
// `expr`
101+
// `(expr1, expr2, ...)`
102+
type LambdaExpr struct {
103+
First, Last token.Pos
104+
Lhs []*Ident
105+
Rarrow token.Pos
106+
Rhs []Expr
107+
LhsHasParen bool
108+
RhsHasParen bool
109+
}
110+
111+
func (p *LambdaExpr) Pos() token.Pos {
112+
return p.First
113+
}
114+
115+
func (p *LambdaExpr) End() token.Pos {
116+
return p.Last
117+
}
118+
119+
func (*LambdaExpr) exprNode() {}
120+
121+
// -----------------------------------------------------------------------------
122+
95123
// ForPhrase represents `for k, v <- listOrMap`
96124
type ForPhrase struct {
97125
For token.Pos // position of "for" keyword

parser/_testdata/lambda/lambda.gop

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package main
2+
3+
func main() {
4+
foo(=> "Hi")
5+
foo(x => x * x)
6+
foo((x, y) => x + y)
7+
foo((x) => (x, x * 2))
8+
foo(() => "Hi")
9+
}

parser/_testdata/lambda/parser.expect

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package main
2+
3+
file lambda.gop
4+
ast.FuncDecl:
5+
Name:
6+
ast.Ident:
7+
Name: main
8+
Type:
9+
ast.FuncType:
10+
Params:
11+
ast.FieldList:
12+
Body:
13+
ast.BlockStmt:
14+
List:
15+
ast.ExprStmt:
16+
X:
17+
ast.CallExpr:
18+
Fun:
19+
ast.Ident:
20+
Name: foo
21+
Args:
22+
ast.LambdaExpr:
23+
Rhs:
24+
ast.BasicLit:
25+
Kind: STRING
26+
Value: "Hi"
27+
ast.ExprStmt:
28+
X:
29+
ast.CallExpr:
30+
Fun:
31+
ast.Ident:
32+
Name: foo
33+
Args:
34+
ast.LambdaExpr:
35+
Lhs:
36+
ast.Ident:
37+
Name: x
38+
Rhs:
39+
ast.BinaryExpr:
40+
X:
41+
ast.Ident:
42+
Name: x
43+
Op: *
44+
Y:
45+
ast.Ident:
46+
Name: x
47+
ast.ExprStmt:
48+
X:
49+
ast.CallExpr:
50+
Fun:
51+
ast.Ident:
52+
Name: foo
53+
Args:
54+
ast.LambdaExpr:
55+
Lhs:
56+
ast.Ident:
57+
Name: x
58+
ast.Ident:
59+
Name: y
60+
Rhs:
61+
ast.BinaryExpr:
62+
X:
63+
ast.Ident:
64+
Name: x
65+
Op: +
66+
Y:
67+
ast.Ident:
68+
Name: y
69+
ast.ExprStmt:
70+
X:
71+
ast.CallExpr:
72+
Fun:
73+
ast.Ident:
74+
Name: foo
75+
Args:
76+
ast.LambdaExpr:
77+
Lhs:
78+
ast.Ident:
79+
Name: x
80+
Rhs:
81+
ast.Ident:
82+
Name: x
83+
ast.BinaryExpr:
84+
X:
85+
ast.Ident:
86+
Name: x
87+
Op: *
88+
Y:
89+
ast.BasicLit:
90+
Kind: INT
91+
Value: 2
92+
ast.ExprStmt:
93+
X:
94+
ast.CallExpr:
95+
Fun:
96+
ast.Ident:
97+
Name: foo
98+
Args:
99+
ast.LambdaExpr:
100+
Rhs:
101+
ast.BasicLit:
102+
Kind: STRING
103+
Value: "Hi"

parser/parser.go

+97-17
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,7 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
13341334
// types of the form [...]T. Callers must verify the result.
13351335
// If lhs is set and the result is an identifier, it is not resolved.
13361336
//
1337-
func (p *parser) parseOperand(lhs bool) ast.Expr {
1337+
func (p *parser) parseOperand(lhs, allowTuple bool) ast.Expr {
13381338
if p.trace {
13391339
defer un(trace(p, "Operand"))
13401340
}
@@ -1358,8 +1358,24 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
13581358
case token.LPAREN:
13591359
lparen := p.pos
13601360
p.next()
1361+
if allowTuple && p.tok == token.RPAREN { // () => expr
1362+
p.next()
1363+
return &tupleExpr{}
1364+
}
13611365
p.exprLev++
13621366
x := p.parseRHSOrType() // types may be parenthesized: (some type)
1367+
if allowTuple && p.tok == token.COMMA {
1368+
// (x, y, ...) => expr
1369+
items := make([]*ast.Ident, 1, 2)
1370+
items[0] = x.(*ast.Ident)
1371+
for p.tok == token.COMMA {
1372+
p.next()
1373+
items = append(items, p.parseIdent())
1374+
}
1375+
p.exprLev--
1376+
p.expect(token.RPAREN)
1377+
return &tupleExpr{items: items}
1378+
}
13631379
p.exprLev--
13641380
rparen := p.expect(token.RPAREN)
13651381
if debugParseOutput {
@@ -1759,12 +1775,12 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
17591775
}
17601776

17611777
// If lhs is set and the result is an identifier, it is not resolved.
1762-
func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr {
1778+
func (p *parser) parsePrimaryExpr(lhs, allowTuple bool) ast.Expr {
17631779
if p.trace {
17641780
defer un(trace(p, "PrimaryExpr"))
17651781
}
17661782

1767-
x := p.parseOperand(lhs)
1783+
x := p.parseOperand(lhs, allowTuple)
17681784
L:
17691785
for {
17701786
switch p.tok {
@@ -1817,7 +1833,7 @@ L:
18171833
}
18181834

18191835
// If lhs is set and the result is an identifier, it is not resolved.
1820-
func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
1836+
func (p *parser) parseUnaryExpr(lhs, allowTuple bool) ast.Expr {
18211837
if p.trace {
18221838
defer un(trace(p, "UnaryExpr"))
18231839
}
@@ -1826,7 +1842,7 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
18261842
case token.ADD, token.SUB, token.NOT, token.XOR, token.AND:
18271843
pos, op := p.pos, p.tok
18281844
p.next()
1829-
x := p.parseUnaryExpr(false)
1845+
x := p.parseUnaryExpr(false, false)
18301846
return &ast.UnaryExpr{OpPos: pos, Op: op, X: p.checkExpr(x)}
18311847

18321848
case token.ARROW:
@@ -1848,7 +1864,7 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
18481864
// <- (chan type) => (<-chan type)
18491865
// <- (chan<- type) => (<-chan (<-type))
18501866

1851-
x := p.parseUnaryExpr(false)
1867+
x := p.parseUnaryExpr(false, false)
18521868

18531869
// determine which case we have
18541870
if typ, ok := x.(*ast.ChanType); ok {
@@ -1879,11 +1895,11 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
18791895
// pointer type or unary "*" expression
18801896
pos := p.pos
18811897
p.next()
1882-
x := p.parseUnaryExpr(false)
1898+
x := p.parseUnaryExpr(false, false)
18831899
return &ast.StarExpr{Star: pos, X: p.checkExprOrType(x)}
18841900
}
18851901

1886-
return p.parsePrimaryExpr(lhs)
1902+
return p.parsePrimaryExpr(lhs, allowTuple)
18871903
}
18881904

18891905
func (p *parser) tokPrec() (token.Token, int) {
@@ -1895,12 +1911,12 @@ func (p *parser) tokPrec() (token.Token, int) {
18951911
}
18961912

18971913
// If lhs is set and the result is an identifier, it is not resolved.
1898-
func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
1914+
func (p *parser) parseBinaryExpr(lhs bool, prec1 int, allowTuple bool) ast.Expr {
18991915
if p.trace {
19001916
defer un(trace(p, "BinaryExpr"))
19011917
}
19021918

1903-
x := p.parseErrWrapExpr(lhs) // TODO: change priority level of ErrWrapExpr
1919+
x := p.parseErrWrapExpr(lhs, allowTuple) // TODO: change priority level of ErrWrapExpr
19041920
for {
19051921
op, oprec := p.tokPrec()
19061922
if oprec < prec1 {
@@ -1911,13 +1927,13 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
19111927
p.resolve(x)
19121928
lhs = false
19131929
}
1914-
y := p.parseBinaryExpr(false, oprec+1)
1930+
y := p.parseBinaryExpr(false, oprec+1, false)
19151931
x = &ast.BinaryExpr{X: p.checkExpr(x), OpPos: pos, Op: op, Y: p.checkExpr(y)}
19161932
}
19171933
}
19181934

1919-
func (p *parser) parseErrWrapExpr(lhs bool) ast.Expr { // expr! expr? expr?:defval
1920-
x := p.parseUnaryExpr(lhs)
1935+
func (p *parser) parseErrWrapExpr(lhs, allowTuple bool) ast.Expr { // expr! expr? expr?:defval
1936+
x := p.parseUnaryExpr(lhs, allowTuple)
19211937
switch p.tok {
19221938
case token.NOT: // expr!
19231939
expr := &ast.ErrWrapExpr{X: x, Tok: token.NOT, TokPos: p.pos}
@@ -1928,14 +1944,76 @@ func (p *parser) parseErrWrapExpr(lhs bool) ast.Expr { // expr! expr? expr?:defv
19281944
p.next()
19291945
if p.tok == token.COLON {
19301946
p.next()
1931-
expr.Default = p.parseUnaryExpr(false)
1947+
expr.Default = p.parseUnaryExpr(false, true)
19321948
}
19331949
return expr
19341950
default:
19351951
return x
19361952
}
19371953
}
19381954

1955+
type tupleExpr struct {
1956+
ast.Expr
1957+
items []*ast.Ident
1958+
}
1959+
1960+
func (p *parser) parseLambdaExpr() ast.Expr {
1961+
var x ast.Expr
1962+
var first = p.pos
1963+
if p.tok != token.RARROW {
1964+
x = p.parseBinaryExpr(false, token.LowestPrec+1, true)
1965+
}
1966+
if p.tok == token.RARROW { // =>
1967+
var rarrow = p.pos
1968+
var rhs []ast.Expr
1969+
var lhsHasParen, rhsHasParen bool
1970+
p.next()
1971+
switch p.tok {
1972+
case token.LPAREN: // (
1973+
rhsHasParen = true
1974+
p.next()
1975+
for {
1976+
item := p.parseExpr(false)
1977+
rhs = append(rhs, item)
1978+
if p.tok != token.COMMA {
1979+
break
1980+
}
1981+
p.next()
1982+
}
1983+
p.expect(token.RPAREN)
1984+
default:
1985+
rhs = []ast.Expr{p.parseExpr(false)}
1986+
}
1987+
var lhs []*ast.Ident
1988+
if x != nil {
1989+
switch v := x.(type) {
1990+
case *tupleExpr:
1991+
lhs, lhsHasParen = v.items, true
1992+
case *ast.ParenExpr:
1993+
lhs, lhsHasParen = []*ast.Ident{v.X.(*ast.Ident)}, true
1994+
default:
1995+
lhs = []*ast.Ident{x.(*ast.Ident)}
1996+
}
1997+
}
1998+
if debugParseOutput {
1999+
log.Printf("ast.LambdaExpr{Lhs: %v}\n", lhs)
2000+
}
2001+
return &ast.LambdaExpr{
2002+
First: first,
2003+
Last: p.pos,
2004+
Lhs: lhs,
2005+
Rarrow: rarrow,
2006+
Rhs: rhs,
2007+
LhsHasParen: lhsHasParen,
2008+
RhsHasParen: rhsHasParen,
2009+
}
2010+
}
2011+
if _, ok := x.(*tupleExpr); ok {
2012+
panic("TODO: tupleExpr")
2013+
}
2014+
return x
2015+
}
2016+
19392017
// If lhs is set and the result is an identifier, it is not resolved.
19402018
// The result may be a type or even a raw type ([...]int). Callers must
19412019
// check the result (using checkExpr or checkExprOrType), depending on
@@ -1944,8 +2022,10 @@ func (p *parser) parseExpr(lhs bool) ast.Expr {
19442022
if p.trace {
19452023
defer un(trace(p, "Expression"))
19462024
}
1947-
1948-
return p.parseBinaryExpr(lhs, token.LowestPrec+1)
2025+
if lhs {
2026+
return p.parseBinaryExpr(lhs, token.LowestPrec+1, false)
2027+
}
2028+
return p.parseLambdaExpr()
19492029
}
19502030

19512031
func (p *parser) parseRHS() ast.Expr {
@@ -2883,7 +2963,7 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
28832963
}
28842964
}
28852965
if debugParseOutput {
2886-
log.Printf("ast.FuncDecl{Name: %v}\n", ident.Name)
2966+
log.Printf("ast.FuncDecl{Name: %v, ...}\n", ident.Name)
28872967
}
28882968
return decl
28892969
}

printer/nodes.go

+18
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,24 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
10281028
p.print(token.COLON)
10291029
p.expr(x.Default)
10301030
}
1031+
case *ast.LambdaExpr:
1032+
if x.LhsHasParen {
1033+
p.print(token.LPAREN)
1034+
p.identList(x.Lhs, false)
1035+
p.print(token.RPAREN, blank)
1036+
} else if x.Lhs != nil {
1037+
p.expr(x.Lhs[0])
1038+
p.print(blank)
1039+
}
1040+
p.print(token.RARROW, blank)
1041+
if x.RhsHasParen {
1042+
p.print(token.LPAREN)
1043+
p.exprList(token.NoPos, x.Rhs, 1, noIndent, token.NoPos, false)
1044+
p.print(token.RPAREN)
1045+
} else {
1046+
p.expr(x.Rhs[0])
1047+
}
1048+
10311049
default:
10321050
log.Fatalf("unreachable %T\n", x)
10331051
}

0 commit comments

Comments
 (0)