parse_decl.mx raw

   1  package syntax
   2  
   3  import (
   4  	"unsafe"
   5  	"git.smesh.lol/moxie/pkg/token"
   6  )
   7  
   8  // SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
   9  func (p *Parser) fileOrNil() (f *File) {
  10  	if trace {
  11  		defer p.trace("file")()
  12  	}
  13  
  14  	f := (*File)(p.nodeAlloc(unsafe.Sizeof(File{})))
  15  	f.pos = p.pos()
  16  
  17  	// PackageClause
  18  	f.GoVersion = p.GoVersion
  19  	p.Top = false
  20  	if !p.got(token.Package) {
  21  		p.syntaxError("package statement must be first")
  22  		return nil
  23  	}
  24  	f.Pragma = p.takePragma()
  25  	f.PkgName = p.name()
  26  	p.want(token.Semi)
  27  
  28  	// don't bother continuing if package clause has errors
  29  	if p.First != nil {
  30  		return nil
  31  	}
  32  
  33  	// Accept import declarations anywhere for error tolerance, but complain.
  34  	// { ( ImportDecl | TopLevelDecl ) ";" }
  35  	prev := token.Import
  36  	for p.Tok != token.EOF {
  37  		if p.Tok == token.Import && prev != token.Import {
  38  			p.syntaxError("imports must appear before other declarations")
  39  		}
  40  		prev = p.Tok
  41  
  42  		switch p.Tok {
  43  		case token.Import:
  44  			p.Next()
  45  			f.DeclList = p.appendGroup(f.DeclList, p.importDecl)
  46  
  47  		case token.Const:
  48  			p.Next()
  49  			f.DeclList = p.appendGroup(f.DeclList, p.constDecl)
  50  
  51  		case token.TypeType:
  52  			p.Next()
  53  			f.DeclList = p.appendGroup(f.DeclList, p.typeDecl)
  54  
  55  		case token.Var:
  56  			p.Next()
  57  			f.DeclList = p.appendGroup(f.DeclList, p.varDecl)
  58  
  59  		case token.Func:
  60  			p.Next()
  61  			if d := p.funcDeclOrNil(); d != nil {
  62  				push(f.DeclList, d)
  63  			}
  64  
  65  		default:
  66  			if p.Tok == token.Lbrace && len(f.DeclList) > 0 && isEmptyFuncDecl(f.DeclList[len(f.DeclList)-1]) {
  67  				// opening { of function declaration on next line
  68  				p.syntaxError("unexpected semicolon or newline before {")
  69  			} else {
  70  				p.syntaxError("non-declaration statement outside function body")
  71  			}
  72  			p.advance(token.Import, token.Const, token.TypeType, token.Var, token.Func)
  73  			continue
  74  		}
  75  
  76  		// Reset p.pragma BEFORE advancing to the next token (consuming ';')
  77  		// since comments before may set pragmas for the next function decl.
  78  		p.clearPragma()
  79  
  80  		if p.Tok != token.EOF && !p.got(token.Semi) {
  81  			p.syntaxError("after top level declaration")
  82  			p.advance(token.Import, token.Const, token.TypeType, token.Var, token.Func)
  83  		}
  84  	}
  85  	// p.tok == _EOF
  86  
  87  	p.clearPragma()
  88  	f.EOF = p.pos()
  89  
  90  	return f
  91  }
  92  
  93  func isEmptyFuncDecl(dcl Decl) (ok bool) {
  94  	f, ok := dcl.(*FuncDecl)
  95  	return ok && f.Body == nil
  96  }
  97  
  98  // ----------------------------------------------------------------------------
  99  // Declarations
 100  
 101  // list parses a possibly empty, sep-separated list of elements, optionally
 102  // followed by sep, and closed by close (or EOF). sep must be one of _Comma
 103  // or _Semi, and close must be one of _Rparen, _Rbrace, or _Rbrack.
 104  //
 105  // For each list element, f is called. Specifically, unless we're at close
 106  // (or EOF), f is called at least once. After f returns true, no more list
 107  // elements are accepted. list returns the position of the closing token.
 108  //
 109  // list = [ f { sep f } [sep] ] close .
 110  func (p *Parser) list(context string, sep, closeTok token.Token, f func() bool) (pv token.Pos) {
 111  	if debug && (sep != token.Comma && sep != token.Semi || closeTok != token.Rparen && closeTok != token.Rbrace && closeTok != token.Rbrack) {
 112  		panic("invalid sep or close argument for list")
 113  	}
 114  
 115  	done := false
 116  	for p.Tok != token.EOF && p.Tok != closeTok && !done {
 117  		done = f()
 118  		// sep is optional before closeTok
 119  		if !p.got(sep) && p.Tok != closeTok {
 120  			p.syntaxError("in " | context | "; possibly missing " | tokstring(sep) | " or " | tokstring(closeTok))
 121  			p.advance(token.Rparen, token.Rbrack, token.Rbrace)
 122  			if p.Tok != closeTok {
 123  				// position could be better but we had an error so we don't care
 124  				return p.pos()
 125  			}
 126  		}
 127  	}
 128  
 129  	pos := p.pos()
 130  	p.want(closeTok)
 131  	return pos
 132  }
 133  
 134  // appendGroup(f) = f + "(" { f ";" } ")" . // ";" is optional before ")"
 135  func (p *Parser) appendGroup(list []Decl, f func(*Group) Decl) (ds []Decl) {
 136  	if p.Tok == token.Lparen {
 137  		g := (*Group)(p.nodeAlloc(unsafe.Sizeof(Group{})))
 138  		p.clearPragma()
 139  		p.Next() // must consume "(" after calling clearPragma!
 140  		p.list("grouped declaration", token.Semi, token.Rparen, func() bool {
 141  			if x := f(g); x != nil {
 142  				push(list, x)
 143  			}
 144  			return false
 145  		})
 146  	} else {
 147  		if x := f(nil); x != nil {
 148  			push(list, x)
 149  		}
 150  	}
 151  	return list
 152  }
 153  
 154  // ImportSpec = [ "." + PackageName ] ImportPath .
 155  // ImportPath = string_lit .
 156  func (p *Parser) importDecl(group *Group) (ret Decl) {
 157  	if trace {
 158  		defer p.trace("importDecl")()
 159  	}
 160  
 161  	d := (*ImportDecl)(p.nodeAlloc(unsafe.Sizeof(ImportDecl{})))
 162  	d.pos = p.pos()
 163  	d.Group = group
 164  	d.Pragma = p.takePragma()
 165  
 166  	switch p.Tok {
 167  	case token.NameType:
 168  		n := p.name()
 169  		if n.Value == "_" {
 170  			p.syntaxErrorAt(n.Pos(), "blank imports are not allowed in Moxie")
 171  		}
 172  		d.LocalPkgName = n
 173  	case token.Dot:
 174  		d.LocalPkgName = NewName(p.pos(), ".")
 175  		p.Next()
 176  	}
 177  	d.Path = p.oliteral()
 178  	if d.Path == nil {
 179  		p.syntaxError("missing import path")
 180  		p.advance(token.Semi, token.Rparen)
 181  		return d
 182  	}
 183  	if !d.Path.Bad && d.Path.Kind != token.StringLit {
 184  		p.syntaxErrorAt(d.Path.Pos(), "import path must be a string")
 185  		d.Path.Bad = true
 186  	}
 187  	// d.Path.Bad || d.Path.Kind == StringLit
 188  
 189  	return d
 190  }
 191  
 192  // ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] .
 193  func (p *Parser) constDecl(group *Group) (ret Decl) {
 194  	if trace {
 195  		defer p.trace("constDecl")()
 196  	}
 197  
 198  	d := (*ConstDecl)(p.nodeAlloc(unsafe.Sizeof(ConstDecl{})))
 199  	d.pos = p.pos()
 200  	d.Group = group
 201  	d.Pragma = p.takePragma()
 202  
 203  	d.NameList = p.nameList(p.name())
 204  	if p.Tok != token.EOF && p.Tok != token.Semi && p.Tok != token.Rparen {
 205  		d.Type = p.typeOrNil()
 206  		if p.gotAssign() {
 207  			d.Values = p.exprList()
 208  		}
 209  	}
 210  
 211  	return d
 212  }
 213  
 214  // TypeSpec = identifier [ TypeParams ] [ "=" ] Type .
 215  func (p *Parser) typeDecl(group *Group) (ret Decl) {
 216  	if trace {
 217  		defer p.trace("typeDecl")()
 218  	}
 219  
 220  	d := (*TypeDecl)(p.nodeAlloc(unsafe.Sizeof(TypeDecl{})))
 221  	d.pos = p.pos()
 222  	d.Group = group
 223  	d.Pragma = p.takePragma()
 224  
 225  	d.Name = p.name()
 226  	if p.Tok == token.Lbrack {
 227  		// d.Name "[" ...
 228  		// array/slice type or type parameter list
 229  		pos := p.pos()
 230  		p.Next()
 231  		switch p.Tok {
 232  		case token.NameType:
 233  			// We may have an array type or a type parameter list.
 234  			// In either case we expect an expression x (which may
 235  			// just be a name, or a more complex expression) which
 236  			// we can analyze further.
 237  			//
 238  			// A type parameter list may have a type bound starting
 239  			// with a "[" as in: P []E. In that case, simply parsing
 240  			// an expression would lead to an error: P[] is invalid.
 241  			// But since index or slice expressions are never constant
 242  			// and thus invalid array length expressions, if the name
 243  			// is followed by "[" it must be the start of an array or
 244  			// slice constraint. Only if we don't see a "[" do we
 245  			// need to parse a full expression. Notably, name <- x
 246  			// is not a concern because name <- x is a statement and
 247  			// not an expression.
 248  			var x Expr = p.name()
 249  			if p.Tok != token.Lbrack {
 250  				// To parse the expression starting with name, expand
 251  				// the call sequence we would get by passing in name
 252  				// to parser.expr, and pass in name to parser.pexpr.
 253  				p.Xnest++
 254  				x = p.binaryExpr(p.pexpr(x, false), 0)
 255  				p.Xnest--
 256  			}
 257  			// Analyze expression x. If we can split x into a type parameter
 258  			// name, possibly followed by a type parameter type, we consider
 259  			// this the start of a type parameter list, with some caveats:
 260  			// a single name followed by "]" tilts the decision towards an
 261  			// array declaration; a type parameter type that could also be
 262  			// an ordinary expression but which is followed by a comma tilts
 263  			// the decision towards a type parameter list.
 264  			if pname, ptype := extractName(x, p.Tok == token.Comma); pname != nil && (ptype != nil || p.Tok != token.Rbrack) {
 265  				// d.Name "[" pname ...
 266  				// d.Name "[" pname ptype ...
 267  				// d.Name "[" pname ptype "," ...
 268  				d.TParamList = p.paramList(pname, ptype, token.Rbrack, true, false) // ptype may be nil
 269  				d.Alias = p.gotAssign()
 270  				d.Type = p.typeOrNil()
 271  			} else {
 272  				// d.Name "[" pname "]" ...
 273  				// d.Name "[" x ...
 274  				d.Type = p.arrayType(pos, x)
 275  			}
 276  		case token.Rbrack:
 277  			// d.Name "[" "]" ...
 278  			p.Next()
 279  			d.Type = p.sliceType(pos)
 280  		default:
 281  			// d.Name "[" ...
 282  			d.Type = p.arrayType(pos, nil)
 283  		}
 284  	} else {
 285  		d.Alias = p.gotAssign()
 286  		d.Type = p.typeOrNil()
 287  	}
 288  
 289  	if d.Type == nil {
 290  		d.Type = p.badExpr()
 291  		p.syntaxError("in type declaration")
 292  		p.advance(token.Semi, token.Rparen)
 293  	}
 294  
 295  	return d
 296  }
 297  
 298  // extractName splits the expression x into (name, expr) if syntactically
 299  // x can be written as name expr. The split only happens if expr is a type
 300  // element (per the isTypeElem predicate) or if force is set.
 301  // If x is just a name, the result is (name, nil). If the split succeeds,
 302  // the result is (name, expr). Otherwise the result is (nil, x).
 303  func extractName(x Expr, force bool) (nm *Name, ex Expr) {
 304  	switch xn := x.(type) {
 305  	case *Name:
 306  		return xn, nil
 307  	case *Operation:
 308  		if xn.Y == nil {
 309  			break // unary expr
 310  		}
 311  		switch xn.Op {
 312  		case token.Mul:
 313  			if name, _ := xn.X.(*Name); name != nil && (force || isTypeElem(xn.Y)) {
 314  				// xn = name *xn.Y
 315  				op := *xn
 316  				op.X, op.Y = op.Y, nil // change op into unary *op.Y
 317  				return name, &op
 318  			}
 319  		case token.Or:
 320  			if name, lhs := extractName(xn.X, force || isTypeElem(xn.Y)); name != nil && lhs != nil {
 321  				// xn = name lhs|xn.Y
 322  				op := *xn
 323  				op.X = lhs
 324  				return name, &op
 325  			}
 326  		}
 327  	case *CallExpr:
 328  		if name, _ := xn.Fun.(*Name); name != nil {
 329  			if len(xn.ArgList) == 1 && !xn.HasDots && (force || isTypeElem(xn.ArgList[0])) {
 330  				// The parser doesn't keep unnecessary parentheses.
 331  				// Set the flag below to keep them, for testing
 332  				// (see go.dev/issues/69206).
 333  				const keep_parens = false
 334  				if keep_parens {
 335  					// xn = name (xn.ArgList[0])
 336  					px := &ParenExpr{} // dead code (keep_parens = false)
 337  					px.pos = xn.pos // position of "(" in call
 338  					px.X = xn.ArgList[0]
 339  					return name, px
 340  				} else {
 341  					// xn = name xn.ArgList[0]
 342  					return name, Unparen(xn.ArgList[0])
 343  				}
 344  			}
 345  		}
 346  	}
 347  	return nil, x
 348  }
 349  
 350  // isTypeElem reports whether x is a (possibly parenthesized) type element expression.
 351  // The result is false if x could be a type element OR an ordinary (value) expression.
 352  func isTypeElem(x Expr) (ok bool) {
 353  	switch xn := x.(type) {
 354  	case *ArrayType, *StructType, *FuncType, *InterfaceType, *SliceType, *MapType, *ChanType:
 355  		return true
 356  	case *Operation:
 357  		return isTypeElem(xn.X) || (xn.Y != nil && isTypeElem(xn.Y)) || xn.Op == token.Tilde
 358  	case *ParenExpr:
 359  		return isTypeElem(xn.X)
 360  	}
 361  	return false
 362  }
 363  
 364  // VarSpec = IdentifierList ( Type [ "=" ExpressionList ] + "=" ExpressionList ) .
 365  func (p *Parser) varDecl(group *Group) (ret Decl) {
 366  	if trace {
 367  		defer p.trace("varDecl")()
 368  	}
 369  
 370  	d := (*VarDecl)(p.nodeAlloc(unsafe.Sizeof(VarDecl{})))
 371  	d.pos = p.pos()
 372  	d.Group = group
 373  	d.Pragma = p.takePragma()
 374  
 375  	d.NameList = p.nameList(p.name())
 376  	if p.gotAssign() {
 377  		d.Values = p.exprList()
 378  	} else {
 379  		d.Type = p.type_()
 380  		if p.gotAssign() {
 381  			d.Values = p.exprList()
 382  		}
 383  	}
 384  
 385  	return d
 386  }
 387  
 388  // FunctionDecl = "func" FunctionName [ TypeParams ] ( Function | Signature ) .
 389  // FunctionName = identifier .
 390  // Function     = Signature FunctionBody .
 391  // MethodDecl   = "func" Receiver MethodName ( Function | Signature ) .
 392  // Receiver     = Parameters .
 393  func (p *Parser) funcDeclOrNil() (f *FuncDecl) {
 394  	if trace {
 395  		defer p.trace("funcDecl")()
 396  	}
 397  
 398  	f := (*FuncDecl)(p.nodeAlloc(unsafe.Sizeof(FuncDecl{})))
 399  	f.pos = p.pos()
 400  	f.Pragma = p.takePragma()
 401  
 402  	var context string
 403  	if p.got(token.Lparen) {
 404  		context = "method"
 405  		rcvr := p.paramList(nil, nil, token.Rparen, false, false)
 406  		switch len(rcvr) {
 407  		case 0:
 408  			p.error("method has no receiver")
 409  		default:
 410  			p.error("method has multiple receivers")
 411  			f.Recv = rcvr[0]
 412  		case 1:
 413  			f.Recv = rcvr[0]
 414  		}
 415  	}
 416  
 417  	if p.Tok == token.NameType {
 418  		f.Name = p.name()
 419  		f.TParamList, f.Type = p.funcType(context)
 420  	} else {
 421  		f.Name = NewName(p.pos(), "_")
 422  		f.Type = (*FuncType)(p.nodeAlloc(unsafe.Sizeof(FuncType{})))
 423  		f.Type.pos = p.pos()
 424  		msg := "expected name or ("
 425  		if context != "" {
 426  			msg = "expected name"
 427  		}
 428  		p.syntaxError(msg)
 429  		p.advance(token.Lbrace, token.Semi)
 430  	}
 431  
 432  	if p.Tok == token.Lbrace {
 433  		f.Body = p.funcBody()
 434  	}
 435  
 436  	return f
 437  }
 438  
 439  func (p *Parser) funcBody() (b *BlockStmt) {
 440  	p.Fnest++
 441  	body := p.blockStmt("")
 442  	p.Fnest--
 443  
 444  	return body
 445  }
 446