parse_stmt.mx raw
1 package syntax
2
3 import (
4 "unsafe"
5 "git.smesh.lol/moxie/pkg/token"
6 )
7
8 // SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
9 func (p *Parser) simpleStmt(lhs Expr, keyword token.Token) (ss SimpleStmt) {
10 if trace {
11 defer p.trace("simpleStmt")()
12 }
13
14 if keyword == token.For && p.Tok == token.Range {
15 // _Range expr
16 if debug && lhs != nil {
17 panic("invalid call of simpleStmt")
18 }
19 return p.newRangeClause(nil, false)
20 }
21
22 if lhs == nil {
23 lhs = p.exprList()
24 }
25
26 if _, ok := lhs.(*ListExpr); !ok && p.Tok != token.Assign && p.Tok != token.Define {
27 // expr
28 pos := p.pos()
29 switch p.Tok {
30 case token.AssignOp:
31 // lhs op= rhs
32 op := p.Op
33 p.Next()
34 return p.newAssignStmt(pos, op, lhs, p.expr())
35
36 case token.IncOp:
37 // lhs++ or lhs--
38 op := p.Op
39 p.Next()
40 return p.newAssignStmt(pos, op, lhs, nil)
41
42 case token.Arrow:
43 // lhs <- rhs
44 sc := (*SendStmt)(p.nodeAlloc(unsafe.Sizeof(SendStmt{})))
45 sc.pos = pos
46 p.Next()
47 sc.Chan = lhs
48 sc.Value = p.expr()
49 return sc
50
51 default:
52 // expr
53 sc := (*ExprStmt)(p.nodeAlloc(unsafe.Sizeof(ExprStmt{})))
54 sc.pos = lhs.Pos()
55 sc.X = lhs
56 return sc
57 }
58 }
59
60 // expr_list
61 switch p.Tok {
62 case token.Assign, token.Define:
63 pos := p.pos()
64 var op token.Operator
65 if p.Tok == token.Define {
66 op = token.Def
67 }
68 p.Next()
69
70 if keyword == token.For && p.Tok == token.Range {
71 // expr_list op= _Range expr
72 return p.newRangeClause(lhs, op == token.Def)
73 }
74
75 // expr_list op= expr_list
76 rhs := p.exprList()
77
78 if x, ok := rhs.(*TypeSwitchGuard); ok && keyword == token.Switch && op == token.Def {
79 if lhsName, ok2 := lhs.(*Name); ok2 {
80 // switch ... lhs := rhs.(type)
81 x.Lhs = lhsName
82 sc := (*ExprStmt)(p.nodeAlloc(unsafe.Sizeof(ExprStmt{})))
83 sc.pos = x.Pos()
84 sc.X = x
85 return sc
86 }
87 }
88
89 return p.newAssignStmt(pos, op, lhs, rhs)
90
91 default:
92 p.syntaxError("expected := or = or comma")
93 p.advance(token.Semi, token.Rbrace)
94 // make the best of what we have
95 if x, ok := lhs.(*ListExpr); ok {
96 lhs = x.ElemList[0]
97 }
98 sc := (*ExprStmt)(p.nodeAlloc(unsafe.Sizeof(ExprStmt{})))
99 sc.pos = lhs.Pos()
100 sc.X = lhs
101 return sc
102 }
103 }
104
105 func (p *Parser) newRangeClause(lhs Expr, def bool) (r *RangeClause) {
106 r := (*RangeClause)(p.nodeAlloc(unsafe.Sizeof(RangeClause{})))
107 r.pos = p.pos()
108 p.Next() // consume _Range
109 r.Lhs = lhs
110 r.Def = def
111 r.X = p.expr()
112 return r
113 }
114
115 func (p *Parser) newAssignStmt(pos token.Pos, op token.Operator, lhs, rhs Expr) (a *AssignStmt) {
116 a := (*AssignStmt)(p.nodeAlloc(unsafe.Sizeof(AssignStmt{})))
117 a.pos = pos
118 a.Op = op
119 a.Lhs = lhs
120 a.Rhs = rhs
121 return a
122 }
123
124 func (p *Parser) labeledStmtOrNil(label *Name) (st Stmt) {
125 if trace {
126 defer p.trace("labeledStmt")()
127 }
128
129 s := (*LabeledStmt)(p.nodeAlloc(unsafe.Sizeof(LabeledStmt{})))
130 s.pos = p.pos()
131 s.Label = label
132
133 p.want(token.Colon)
134
135 if p.Tok == token.Rbrace {
136 // We expect a statement (incl. an empty statement), which must be
137 // terminated by a semicolon. Because semicolons may be omitted before
138 // an _Rbrace, seeing an _Rbrace implies an empty statement.
139 e := (*EmptyStmt)(p.nodeAlloc(unsafe.Sizeof(EmptyStmt{})))
140 e.pos = p.pos()
141 s.Stmt = e
142 return s
143 }
144
145 s.Stmt = p.stmtOrNil()
146 if s.Stmt != nil {
147 return s
148 }
149
150 // report error at line of ':' token
151 p.syntaxErrorAt(s.pos, "missing statement after label")
152 // we are already at the end of the labeled statement - no need to advance
153 return nil // avoids follow-on errors (see e.g., fixedbugs/bug274.go)
154 }
155
156 // context must be a non-empty string unless we know that p.tok == _Lbrace.
157 func (p *Parser) blockStmt(context string) (b *BlockStmt) {
158 if trace {
159 defer p.trace("blockStmt")()
160 }
161
162 s := (*BlockStmt)(p.nodeAlloc(unsafe.Sizeof(BlockStmt{})))
163 s.pos = p.pos()
164
165 // people coming from C may forget that braces are mandatory in Go
166 if !p.got(token.Lbrace) {
167 p.syntaxError("expected { after " | context)
168 p.advance(token.NameType, token.Rbrace)
169 s.Rbrace = p.pos() // in case we found "}"
170 if p.got(token.Rbrace) {
171 return s
172 }
173 }
174
175 s.List = p.stmtList()
176 s.Rbrace = p.pos()
177 p.want(token.Rbrace)
178
179 return s
180 }
181
182 func (p *Parser) declStmt(f func(*Group) Decl) (d *DeclStmt) {
183 if trace {
184 defer p.trace("declStmt")()
185 }
186
187 s := (*DeclStmt)(p.nodeAlloc(unsafe.Sizeof(DeclStmt{})))
188 s.pos = p.pos()
189
190 p.Next() // _Const, _Type, or _Var
191 s.DeclList = p.appendGroup(nil, f)
192
193 return s
194 }
195
196 func (p *Parser) forStmt() (st Stmt) {
197 if trace {
198 defer p.trace("forStmt")()
199 }
200
201 s := (*ForStmt)(p.nodeAlloc(unsafe.Sizeof(ForStmt{})))
202 s.pos = p.pos()
203
204 s.Init, s.Cond, s.Post = p.header(token.For)
205 s.Body = p.blockStmt("for clause")
206
207 return s
208 }
209
210 func (p *Parser) header(keyword token.Token) (init SimpleStmt, cond Expr, post SimpleStmt) {
211 p.want(keyword)
212
213 if p.Tok == token.Lbrace {
214 if keyword == token.If {
215 p.syntaxError("missing condition in if statement")
216 cond = p.badExpr()
217 }
218 return
219 }
220 // p.tok != _Lbrace
221
222 outer := p.Xnest
223 p.Xnest = -1
224
225 if p.Tok != token.Semi {
226 // accept potential varDecl but complain
227 if p.got(token.Var) {
228 p.syntaxError("var declaration not allowed in " | keyword.String() | " initializer")
229 }
230 init = p.simpleStmt(nil, keyword)
231 // If we have a range clause, we are done (can only happen for keyword == _For).
232 if _, ok := init.(*RangeClause); ok {
233 p.Xnest = outer
234 return
235 }
236 }
237
238 var condStmt SimpleStmt
239 var semi struct {
240 pos token.Pos
241 lit string // valid if pos.IsKnown()
242 }
243 if p.Tok != token.Lbrace {
244 if p.Tok == token.Semi {
245 semi.pos = p.pos()
246 semi.lit = p.Lit
247 p.Next()
248 } else {
249 // asking for a '{' rather than a ';' here leads to a better error message
250 p.want(token.Lbrace)
251 if p.Tok != token.Lbrace {
252 p.advance(token.Lbrace, token.Rbrace) // for better synchronization (e.g., go.dev/issue/22581)
253 }
254 }
255 if keyword == token.For {
256 if p.Tok != token.Semi {
257 if p.Tok == token.Lbrace {
258 p.syntaxError("expected for loop condition")
259 goto done
260 }
261 condStmt = p.simpleStmt(nil, 0 /* range not permitted */)
262 }
263 p.want(token.Semi)
264 if p.Tok != token.Lbrace {
265 post = p.simpleStmt(nil, 0 /* range not permitted */)
266 if a, _ := post.(*AssignStmt); a != nil && a.Op == token.Def {
267 p.syntaxErrorAt(a.Pos(), "cannot declare in post statement of for loop")
268 }
269 }
270 } else if p.Tok != token.Lbrace {
271 condStmt = p.simpleStmt(nil, keyword)
272 }
273 } else {
274 condStmt = init
275 init = nil
276 }
277
278 done:
279 // unpack condStmt
280 switch s := condStmt.(type) {
281 case nil:
282 if keyword == token.If && semi.pos.IsKnown() {
283 if semi.lit != "semicolon" {
284 p.syntaxErrorAt(semi.pos, "unexpected " | semi.lit | ", expected { after if clause")
285 } else {
286 p.syntaxErrorAt(semi.pos, "missing condition in if statement")
287 }
288 b := (*BadExpr)(p.nodeAlloc(unsafe.Sizeof(BadExpr{})))
289 b.pos = semi.pos
290 cond = b
291 }
292 case *ExprStmt:
293 cond = s.X
294 default:
295 // A common syntax error is to write '=' instead of '==',
296 // which turns an expression into an assignment. Provide
297 // a more explicit error message in that case to prevent
298 // further confusion.
299 var str string
300 if as, ok := s.(*AssignStmt); ok && as.Op == 0 {
301 // Emphasize complex Lhs and Rhs of assignment with parentheses to highlight '='.
302 str = "assignment " | emphasize(as.Lhs) | " = " | emphasize(as.Rhs)
303 } else {
304 str = String(s)
305 }
306 p.syntaxErrorAt(s.Pos(), "cannot use " | str | " as value")
307 }
308
309 p.Xnest = outer
310 return
311 }
312
313 // emphasize returns a string representation of x, with (top-level)
314 // binary expressions emphasized by enclosing them in parentheses.
315 func emphasize(x Expr) (s string) {
316 s = String(x)
317 if op, _ := x.(*Operation); op != nil && op.Y != nil {
318 // binary expression
319 return "(" | s | ")"
320 }
321 return s
322 }
323
324 func (p *Parser) ifStmt() (i *IfStmt) {
325 if trace {
326 defer p.trace("ifStmt")()
327 }
328
329 s := (*IfStmt)(p.nodeAlloc(unsafe.Sizeof(IfStmt{})))
330 s.pos = p.pos()
331
332 s.Init, s.Cond, _ = p.header(token.If)
333 s.Then = p.blockStmt("if clause")
334
335 if p.got(token.Else) {
336 switch p.Tok {
337 case token.If:
338 s.Else = p.ifStmt()
339 case token.Lbrace:
340 s.Else = p.blockStmt("")
341 default:
342 p.syntaxError("else must be followed by if or statement block")
343 p.advance(token.NameType, token.Rbrace)
344 }
345 }
346
347 return s
348 }
349
350 func (p *Parser) switchStmt() (s *SwitchStmt) {
351 if trace {
352 defer p.trace("switchStmt")()
353 }
354
355 s := (*SwitchStmt)(p.nodeAlloc(unsafe.Sizeof(SwitchStmt{})))
356 s.pos = p.pos()
357
358 s.Init, s.Tag, _ = p.header(token.Switch)
359
360 if !p.got(token.Lbrace) {
361 p.syntaxError("missing { after switch clause")
362 p.advance(token.Case, token.Default, token.Rbrace)
363 }
364 for p.Tok != token.EOF && p.Tok != token.Rbrace {
365 push(s.Body, p.caseClause())
366 }
367 s.Rbrace = p.pos()
368 p.want(token.Rbrace)
369
370 return s
371 }
372
373 func (p *Parser) selectStmt() (s *SelectStmt) {
374 if trace {
375 defer p.trace("selectStmt")()
376 }
377
378 s := (*SelectStmt)(p.nodeAlloc(unsafe.Sizeof(SelectStmt{})))
379 s.pos = p.pos()
380
381 p.want(token.Select)
382 if !p.got(token.Lbrace) {
383 p.syntaxError("missing { after select clause")
384 p.advance(token.Case, token.Default, token.Rbrace)
385 }
386 for p.Tok != token.EOF && p.Tok != token.Rbrace {
387 push(s.Body, p.commClause())
388 }
389 s.Rbrace = p.pos()
390 p.want(token.Rbrace)
391
392 return s
393 }
394
395 func (p *Parser) caseClause() (c *CaseClause) {
396 if trace {
397 defer p.trace("caseClause")()
398 }
399
400 c := (*CaseClause)(p.nodeAlloc(unsafe.Sizeof(CaseClause{})))
401 c.pos = p.pos()
402
403 switch p.Tok {
404 case token.Case:
405 p.Next()
406 c.Cases = p.exprList()
407
408 case token.Default:
409 p.Next()
410
411 default:
412 p.syntaxError("expected case or default or }")
413 p.advance(token.Colon, token.Case, token.Default, token.Rbrace)
414 }
415
416 c.Colon = p.pos()
417 p.want(token.Colon)
418 c.Body = p.stmtList()
419
420 return c
421 }
422
423 func (p *Parser) commClause() (c *CommClause) {
424 if trace {
425 defer p.trace("commClause")()
426 }
427
428 c := (*CommClause)(p.nodeAlloc(unsafe.Sizeof(CommClause{})))
429 c.pos = p.pos()
430
431 switch p.Tok {
432 case token.Case:
433 p.Next()
434 c.Comm = p.simpleStmt(nil, 0)
435
436 // The syntax restricts the possible simple statements here to:
437 //
438 // lhs <- x (send statement)
439 // <-x
440 // lhs = <-x
441 // lhs := <-x
442 //
443 // All these (and more) are recognized by simpleStmt and invalid
444 // syntax trees are flagged later, during type checking.
445
446 case token.Default:
447 p.Next()
448
449 default:
450 p.syntaxError("expected case or default or }")
451 p.advance(token.Colon, token.Case, token.Default, token.Rbrace)
452 }
453
454 c.Colon = p.pos()
455 p.want(token.Colon)
456 c.Body = p.stmtList()
457
458 return c
459 }
460
461 // stmtOrNil parses a statement if one is present, or else returns nil.
462 //
463 // Statement =
464 // Declaration | LabeledStmt | SimpleStmt |
465 // GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
466 // FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
467 // DeferStmt .
468 func (p *Parser) stmtOrNil() (st Stmt) {
469 if trace {
470 defer p.trace("stmt " | p.Tok.String())()
471 }
472
473 // Most statements (assignments) start with an identifier;
474 // look for it first before doing anything more expensive.
475 if p.Tok == token.NameType {
476 p.clearPragma()
477 lhs := p.exprList()
478 if label, ok := lhs.(*Name); ok && p.Tok == token.Colon {
479 return p.labeledStmtOrNil(label)
480 }
481 return p.simpleStmt(lhs, 0)
482 }
483
484 switch p.Tok {
485 case token.Var:
486 return p.declStmt(p.varDecl)
487
488 case token.Const:
489 return p.declStmt(p.constDecl)
490
491 case token.TypeType:
492 return p.declStmt(p.typeDecl)
493 }
494
495 p.clearPragma()
496
497 switch p.Tok {
498 case token.Lbrace:
499 return p.blockStmt("")
500
501 case token.OperatorType, token.Star:
502 switch p.Op {
503 case token.Add, token.Sub, token.Mul, token.And, token.Xor, token.Not:
504 return p.simpleStmt(nil, 0) // unary operators
505 }
506
507 case token.Literal, token.Func, token.Lparen, // operands
508 token.Lbrack, token.Struct, token.Map, token.Chan, token.Interface, // composite types
509 token.Arrow: // receive operator
510 return p.simpleStmt(nil, 0)
511
512 case token.For:
513 return p.forStmt()
514
515 case token.Switch:
516 return p.switchStmt()
517
518 case token.Select:
519 return p.selectStmt()
520
521 case token.If:
522 return p.ifStmt()
523
524 case token.Fallthrough:
525 sc := (*BranchStmt)(p.nodeAlloc(unsafe.Sizeof(BranchStmt{})))
526 sc.pos = p.pos()
527 p.Next()
528 sc.Tok = token.Fallthrough
529 return sc
530
531 case token.Break, token.Continue:
532 sc := (*BranchStmt)(p.nodeAlloc(unsafe.Sizeof(BranchStmt{})))
533 sc.pos = p.pos()
534 sc.Tok = p.Tok
535 p.Next()
536 if p.Tok == token.NameType {
537 sc.Label = p.name()
538 }
539 return sc
540
541 case token.Go, token.Defer:
542 return p.callStmt()
543
544 case token.Goto:
545 sc := (*BranchStmt)(p.nodeAlloc(unsafe.Sizeof(BranchStmt{})))
546 sc.pos = p.pos()
547 sc.Tok = token.Goto
548 p.Next()
549 sc.Label = p.name()
550 return sc
551
552 case token.Return:
553 sc := (*ReturnStmt)(p.nodeAlloc(unsafe.Sizeof(ReturnStmt{})))
554 sc.pos = p.pos()
555 p.Next()
556 if p.Tok != token.Semi && p.Tok != token.Rbrace {
557 sc.Results = p.exprList()
558 }
559 return sc
560
561 case token.Semi:
562 sc := (*EmptyStmt)(p.nodeAlloc(unsafe.Sizeof(EmptyStmt{})))
563 sc.pos = p.pos()
564 return sc
565 }
566
567 return nil
568 }
569
570 // StatementList = { Statement ";" } .
571 func (p *Parser) stmtList() (l []Stmt) {
572 if trace {
573 defer p.trace("stmtList")()
574 }
575
576 for p.Tok != token.EOF && p.Tok != token.Rbrace && p.Tok != token.Case && p.Tok != token.Default {
577 s := p.stmtOrNil()
578 p.clearPragma()
579 if s == nil {
580 break
581 }
582 push(l, s)
583 // ";" is optional before "}"
584 if !p.got(token.Semi) && p.Tok != token.Rbrace {
585 p.syntaxError("at end of statement")
586 p.advance(token.Semi, token.Rbrace, token.Case, token.Default)
587 p.got(token.Semi) // avoid spurious empty statement
588 }
589 }
590 return
591 }
592