parse_expr.mx raw
1 package syntax
2
3 import (
4 "unsafe"
5 "git.smesh.lol/moxie/pkg/token"
6 )
7
8 func (p *Parser) expr() (ex Expr) {
9 if trace {
10 defer p.trace("expr")()
11 }
12
13 return p.binaryExpr(nil, 0)
14 }
15
16 // Expression = UnaryExpr | Expression binary_op Expression .
17 func (p *Parser) binaryExpr(x Expr, prec int32) (ex Expr) {
18 // don't trace binaryExpr - only leads to overly nested trace output
19
20 if x == nil {
21 x = p.unaryExpr()
22 }
23 for (p.Tok == token.OperatorType || p.Tok == token.Star) && p.Prec > prec {
24 t := (*Operation)(p.nodeAlloc(unsafe.Sizeof(Operation{})))
25 t.pos = p.pos()
26 t.Op = p.Op
27 tprec := p.Prec
28 p.Next()
29 t.X = x
30 t.Y = p.binaryExpr(nil, tprec)
31 x = t
32 }
33 return x
34 }
35
36 // UnaryExpr = PrimaryExpr | unary_op UnaryExpr .
37 func (p *Parser) unaryExpr() (ex Expr) {
38 if trace {
39 defer p.trace("unaryExpr")()
40 }
41
42 switch p.Tok {
43 case token.OperatorType, token.Star:
44 switch p.Op {
45 case token.Mul, token.Add, token.Sub, token.Not, token.Xor, token.Tilde:
46 x := (*Operation)(p.nodeAlloc(unsafe.Sizeof(Operation{})))
47 x.pos = p.pos()
48 x.Op = p.Op
49 p.Next()
50 x.X = p.unaryExpr()
51 return x
52
53 case token.And:
54 x := (*Operation)(p.nodeAlloc(unsafe.Sizeof(Operation{})))
55 x.pos = p.pos()
56 x.Op = token.And
57 p.Next()
58 // unaryExpr may have returned a parenthesized composite literal
59 // (see comment in operand) - remove parentheses if any
60 x.X = Unparen(p.unaryExpr())
61 return x
62 }
63
64 case token.Arrow:
65 // receive op (<-x) or receive-only channel (<-chan E)
66 pos := p.pos()
67 p.Next()
68
69 // If the next token is _Chan we still don't know if it is
70 // a channel (<-chan int32) or a receive op (<-chan int32(ch)).
71 // We only know once we have found the end of the unaryExpr.
72
73 x := p.unaryExpr()
74
75 // There are two cases:
76 //
77 // <-chan... => <-x is a channel type
78 // <-x => <-x is a receive operation
79 //
80 // In the first case, <- must be re-associated with
81 // the channel type parsed already:
82 //
83 // <-(chan E) => (<-chan E)
84 // <-(chan<-E) => (<-chan (<-E))
85
86 if _, ok := x.(*ChanType); ok {
87 // x is a channel type => re-associate <-
88 dir := SendOnly
89 t := x
90 for dir == SendOnly {
91 c, ok2 := t.(*ChanType)
92 if !ok2 {
93 break
94 }
95 dir = c.Dir
96 if dir == RecvOnly {
97 // t is type <-chan E but <-<-chan E is not permitted
98 // (report same error as for "type _ <-<-chan E")
99 p.syntaxError("unexpected <-, expected chan")
100 // already progressed, no need to advance
101 }
102 c.Dir = RecvOnly
103 t = c.Elem
104 }
105 if dir == SendOnly {
106 // channel dir is <- but channel element E is not a channel
107 // (report same error as for "type _ <-chan<-E")
108 p.syntaxError("unexpected " | String(t) | ", expected chan")
109 // already progressed, no need to advance
110 }
111 return x
112 }
113
114 // x is not a channel type => we have a receive op
115 o := (*Operation)(p.nodeAlloc(unsafe.Sizeof(Operation{})))
116 o.pos = pos
117 o.Op = token.Recv
118 o.X = x
119 return o
120 }
121
122 // TODO(mdempsky): We need parens here so we can report an
123 // error for "(x) := true". It should be possible to detect
124 // and reject that more efficiently though.
125 return p.pexpr(nil, true)
126 }
127
128 // callStmt parses call-like statements that can be preceded by 'defer' and 'go'.
129 func (p *Parser) callStmt() (c *CallStmt) {
130 if trace {
131 defer p.trace("callStmt")()
132 }
133
134 s := (*CallStmt)(p.nodeAlloc(unsafe.Sizeof(CallStmt{})))
135 s.pos = p.pos()
136 s.Tok = p.Tok // _Defer or _Go
137 p.Next()
138
139 x := p.pexpr(nil, p.Tok == token.Lparen) // keep_parens so we can report error below
140 if t := Unparen(x); t != x {
141 p.errorAt(x.Pos(), "expression in " | s.Tok.String() | " must not be parenthesized")
142 // already progressed, no need to advance
143 x = t
144 }
145
146 s.Call = x
147 return s
148 }
149
150 // Operand = Literal | OperandName | MethodExpr + "(" Expression ")" .
151 // Literal = BasicLit | CompositeLit | FunctionLit .
152 // BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit .
153 // OperandName = identifier | QualifiedIdent.
154 func (p *Parser) operand(keep_parens bool) (ex Expr) {
155 if trace {
156 defer p.trace("operand " | p.Tok.String())()
157 }
158
159 switch p.Tok {
160 case token.NameType:
161 return p.name()
162
163 case token.Literal:
164 return p.oliteral()
165
166 case token.Lparen:
167 pos := p.pos()
168 p.Next()
169 p.Xnest++
170 x := p.expr()
171 p.Xnest--
172 p.want(token.Rparen)
173
174 // Optimization: Record presence of ()'s only where needed
175 // for error reporting. Don't bother in other cases; it is
176 // just a waste of memory and time.
177 //
178 // Parentheses are not permitted around T in a composite
179 // literal T{}. If the next token is a {, assume x is a
180 // composite literal type T (it may not be, { could be
181 // the opening brace of a block, but we don't know yet).
182 if p.Tok == token.Lbrace {
183 keep_parens = true
184 }
185
186 // Parentheses are also not permitted around the expression
187 // in a go/defer statement. In that case, operand is called
188 // with keep_parens set.
189 if keep_parens {
190 px := (*ParenExpr)(p.nodeAlloc(unsafe.Sizeof(ParenExpr{})))
191 px.pos = pos
192 px.X = x
193 x = px
194 }
195 return x
196
197 case token.Func:
198 pos := p.pos()
199 p.Next()
200 _, ftyp := p.funcType("function type")
201 if p.Tok == token.Lbrace {
202 p.Xnest++
203
204 f := (*FuncLit)(p.nodeAlloc(unsafe.Sizeof(FuncLit{})))
205 f.pos = pos
206 f.Type = ftyp
207 f.Body = p.funcBody()
208
209 p.Xnest--
210 return f
211 }
212 return ftyp
213
214 case token.Lbrack, token.Chan, token.Map, token.Struct, token.Interface:
215 return p.type_() // othertype
216
217 default:
218 x := p.badExpr()
219 p.syntaxError("expected expression")
220 p.advance(token.Rparen, token.Rbrack, token.Rbrace)
221 return x
222 }
223
224 // Syntactically, composite literals are operands. Because a complit
225 // type may be a qualified identifier which is handled by pexpr
226 // (together with selector expressions), complits are parsed there
227 // as well (operand is only called from pexpr).
228 }
229
230 // pexpr parses a PrimaryExpr.
231 //
232 // PrimaryExpr =
233 // Operand |
234 // Conversion |
235 // PrimaryExpr Selector |
236 // PrimaryExpr Index |
237 // PrimaryExpr Slice |
238 // PrimaryExpr TypeAssertion |
239 // PrimaryExpr Arguments .
240 //
241 // Selector = "." identifier .
242 // Index = "[" Expression "]" .
243 // Slice = "[" ( [ Expression ] ":" [ Expression ] ) |
244 // ( [ Expression ] ":" Expression ":" Expression )
245 // "]" .
246 // TypeAssertion = "." "(" Type ")" .
247 // Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
248 func (p *Parser) pexpr(x Expr, keep_parens bool) (ex Expr) {
249 if trace {
250 defer p.trace("pexpr")()
251 }
252
253 if x == nil {
254 x = p.operand(keep_parens)
255 }
256
257 loop:
258 for {
259 pos := p.pos()
260 switch p.Tok {
261 case token.Dot:
262 p.Next()
263 switch p.Tok {
264 case token.NameType:
265 // pexpr '.' sym
266 t := (*SelectorExpr)(p.nodeAlloc(unsafe.Sizeof(SelectorExpr{})))
267 t.pos = pos
268 t.X = x
269 t.Sel = p.name()
270 x = t
271
272 case token.Lparen:
273 p.Next()
274 if p.got(token.TypeType) {
275 t := (*TypeSwitchGuard)(p.nodeAlloc(unsafe.Sizeof(TypeSwitchGuard{})))
276 // t.Lhs is filled in by parser.simpleStmt
277 t.pos = pos
278 t.X = x
279 x = t
280 } else {
281 t := (*AssertExpr)(p.nodeAlloc(unsafe.Sizeof(AssertExpr{})))
282 t.pos = pos
283 t.X = x
284 t.Type = p.type_()
285 x = t
286 }
287 p.want(token.Rparen)
288
289 default:
290 p.syntaxError("expected name or (")
291 p.advance(token.Semi, token.Rparen)
292 }
293
294 case token.Lbrack:
295 p.Next()
296
297 var i Expr
298 if p.Tok != token.Colon {
299 var comma bool
300 if p.Tok == token.Rbrack {
301 // invalid empty instance, slice or index expression; accept but complain
302 p.syntaxError("expected operand")
303 i = p.badExpr()
304 } else {
305 i, comma = p.typeList(false)
306 }
307 if comma || p.Tok == token.Rbrack {
308 p.want(token.Rbrack)
309 // x[], x[i,] or x[i, j, ...]
310 ie := (*IndexExpr)(p.nodeAlloc(unsafe.Sizeof(IndexExpr{})))
311 ie.pos = pos
312 ie.X = x
313 ie.Index = i
314 x = ie
315 break
316 }
317 }
318
319 // x[i:...
320 // For better error message, don't simply use p.want(_Colon) here (go.dev/issue/47704).
321 if !p.got(token.Colon) {
322 p.syntaxError("expected comma, : or ]")
323 p.advance(token.Comma, token.Colon, token.Rbrack)
324 }
325 p.Xnest++
326 t := (*SliceExpr)(p.nodeAlloc(unsafe.Sizeof(SliceExpr{})))
327 t.pos = pos
328 t.X = x
329 t.Index[0] = i
330 if p.Tok != token.Colon && p.Tok != token.Rbrack {
331 // x[i:j...
332 t.Index[1] = p.expr()
333 }
334 if p.Tok == token.Colon {
335 t.Full = true
336 // x[i:j:...]
337 if t.Index[1] == nil {
338 p.error("middle index required in 3-index slice")
339 t.Index[1] = p.badExpr()
340 }
341 p.Next()
342 if p.Tok != token.Rbrack {
343 // x[i:j:k...
344 t.Index[2] = p.expr()
345 } else {
346 p.error("final index required in 3-index slice")
347 t.Index[2] = p.badExpr()
348 }
349 }
350 p.Xnest--
351 p.want(token.Rbrack)
352 x = t
353
354 case token.Lparen:
355 t := (*CallExpr)(p.nodeAlloc(unsafe.Sizeof(CallExpr{})))
356 t.pos = pos
357 p.Next()
358 t.Fun = x
359 t.ArgList, t.HasDots = p.argList()
360 x = t
361
362 case token.Lbrace:
363 // operand may have returned a parenthesized complit
364 // type; accept it but complain if we have a complit
365 t := Unparen(x)
366 // determine if '{' belongs to a composite literal or a block statement
367 complit_ok := false
368 switch t.(type) {
369 case *Name, *SelectorExpr:
370 if p.Xnest >= 0 {
371 // x is possibly a composite literal type
372 complit_ok = true
373 }
374 case *IndexExpr:
375 if p.Xnest >= 0 && !isValue(t) {
376 // x is possibly a composite literal type
377 complit_ok = true
378 }
379 case *ArrayType, *SliceType, *StructType, *MapType:
380 // x is a comptype
381 complit_ok = true
382 }
383 if !complit_ok {
384 break loop
385 }
386 if t != x {
387 p.syntaxError("cannot parenthesize type in composite literal")
388 // already progressed, no need to advance
389 }
390 n := p.complitexpr()
391 n.Type = x
392 x = n
393
394 default:
395 break loop
396 }
397 }
398
399 return x
400 }
401
402 // isValue reports whether x syntactically must be a value (and not a type) expression.
403 func isValue(x Expr) (ok bool) {
404 switch v := x.(type) {
405 case *BasicLit, *CompositeLit, *FuncLit, *SliceExpr, *AssertExpr, *TypeSwitchGuard, *CallExpr:
406 return true
407 case *Operation:
408 return v.Op != token.Mul || v.Y != nil // *T may be a type
409 case *ParenExpr:
410 return isValue(v.X)
411 case *IndexExpr:
412 return isValue(v.X) || isValue(v.Index)
413 }
414 return false
415 }
416
417 // Element = Expression | LiteralValue .
418 func (p *Parser) bare_complitexpr() (ex Expr) {
419 if trace {
420 defer p.trace("bare_complitexpr")()
421 }
422
423 if p.Tok == token.Lbrace {
424 // '{' start_complit braced_keyval_list '}'
425 return p.complitexpr()
426 }
427
428 return p.expr()
429 }
430
431 // LiteralValue = "{" [ ElementList [ "," ] ] "}" .
432 func (p *Parser) complitexpr() (c *CompositeLit) {
433 if trace {
434 defer p.trace("complitexpr")()
435 }
436
437 x := (*CompositeLit)(p.nodeAlloc(unsafe.Sizeof(CompositeLit{})))
438 x.pos = p.pos()
439
440 p.Xnest++
441 p.want(token.Lbrace)
442 x.Rbrace = p.list("composite literal", token.Comma, token.Rbrace, func() bool {
443 // value
444 e := p.bare_complitexpr()
445 if p.Tok == token.Colon {
446 // key ':' value
447 l := (*KeyValueExpr)(p.nodeAlloc(unsafe.Sizeof(KeyValueExpr{})))
448 l.pos = p.pos()
449 p.Next()
450 l.Key = e
451 l.Value = p.bare_complitexpr()
452 e = l
453 x.NKeys++
454 }
455 push(x.ElemList, e)
456 return false
457 })
458 p.Xnest--
459
460 return x
461 }
462
463 // ----------------------------------------------------------------------------
464 // Common productions
465
466 // argList parses a possibly empty, comma-separated list of arguments,
467 // optionally followed by a comma (if not empty), and closed by ")".
468 // The last argument may be followed by "...".
469 //
470 // argList = [ arg { "," arg } [ "..." ] [ "," ] ] ")" .
471 func (p *Parser) argList() (list []Expr, hasDots bool) {
472 if trace {
473 defer p.trace("argList")()
474 }
475
476 p.Xnest++
477 p.list("argument list", token.Comma, token.Rparen, func() bool {
478 push(list, p.expr())
479 hasDots = p.got(token.DotDotDot)
480 return hasDots
481 })
482 p.Xnest--
483
484 return
485 }
486
487 func (p *Parser) name() (n *Name) {
488 // no tracing to avoid overly verbose output
489
490 if p.Tok == token.NameType {
491 n = NewName(p.pos(), p.Lit)
492 p.Next()
493 return n
494 }
495
496 n = NewName(p.pos(), "_")
497 p.syntaxError("expected name")
498 p.advance()
499 return n
500 }
501
502 // IdentifierList = identifier { "," identifier } .
503 // The first name must be provided.
504 func (p *Parser) nameList(First *Name) (ns []*Name) {
505 if trace {
506 defer p.trace("nameList")()
507 }
508
509 if debug && First == nil {
510 panic("first name not provided")
511 }
512
513 l := []*Name{First}
514 for p.got(token.Comma) {
515 push(l, p.name())
516 }
517
518 return l
519 }
520
521 // The first name may be provided, or nil.
522 func (p *Parser) qualifiedName(name *Name) (ex Expr) {
523 if trace {
524 defer p.trace("qualifiedName")()
525 }
526
527 var x Expr
528 switch {
529 case name != nil:
530 x = name
531 case p.Tok == token.NameType:
532 x = p.name()
533 default:
534 x = NewName(p.pos(), "_")
535 p.syntaxError("expected name")
536 p.advance(token.Dot, token.Semi, token.Rbrace)
537 }
538
539 if p.Tok == token.Dot {
540 s := (*SelectorExpr)(p.nodeAlloc(unsafe.Sizeof(SelectorExpr{})))
541 s.pos = p.pos()
542 p.Next()
543 s.X = x
544 s.Sel = p.name()
545 x = s
546 }
547
548 if p.Tok == token.Lbrack {
549 x = p.typeInstance(x)
550 }
551
552 return x
553 }
554
555 // ExpressionList = Expression { "," Expression } .
556 func (p *Parser) exprList() (ex Expr) {
557 if trace {
558 defer p.trace("exprList")()
559 }
560
561 x := p.expr()
562 if p.got(token.Comma) {
563 list := []Expr{x, p.expr()}
564 for p.got(token.Comma) {
565 push(list, p.expr())
566 }
567 t := (*ListExpr)(p.nodeAlloc(unsafe.Sizeof(ListExpr{})))
568 t.pos = x.Pos()
569 t.ElemList = list
570 x = t
571 }
572 return x
573 }
574
575 // typeList parses a non-empty, comma-separated list of types,
576 // optionally followed by a comma. If strict is set to false,
577 // the first element may also be a (non-type) expression.
578 // If there is more than one argument, the result is a *ListExpr.
579 // The comma result indicates whether there was a (separating or
580 // trailing) comma.
581 //
582 // typeList = arg { "," arg } [ "," ] .
583 func (p *Parser) typeList(strict bool) (x Expr, comma bool) {
584 if trace {
585 defer p.trace("typeList")()
586 }
587
588 p.Xnest++
589 if strict {
590 x = p.type_()
591 } else {
592 x = p.expr()
593 }
594 if p.got(token.Comma) {
595 comma = true
596 if t := p.typeOrNil(); t != nil {
597 list := []Expr{x, t}
598 for p.got(token.Comma) {
599 if t = p.typeOrNil(); t == nil {
600 break
601 }
602 push(list, t)
603 }
604 l := (*ListExpr)(p.nodeAlloc(unsafe.Sizeof(ListExpr{})))
605 l.pos = x.Pos() // == list[0].Pos()
606 l.ElemList = list
607 x = l
608 }
609 }
610 p.Xnest--
611 return
612 }
613
614 // Unparen returns e with any enclosing parentheses stripped.
615 func Unparen(x Expr) (ex Expr) {
616 for {
617 p, ok := x.(*ParenExpr)
618 if !ok {
619 break
620 }
621 x = p.X
622 }
623 return x
624 }
625
626 // UnpackListExpr unpacks a *ListExpr into a []Expr.
627 func UnpackListExpr(x Expr) (es []Expr) {
628 switch v := x.(type) {
629 case nil:
630 return nil
631 case *ListExpr:
632 return v.ElemList
633 default:
634 return []Expr{x}
635 }
636 }
637