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