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