1// Copyright 2017 The Wuffs Authors. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package parse 16 17// TODO: write a formal grammar for the language. 18 19import ( 20 "fmt" 21 22 a "github.com/google/wuffs/lang/ast" 23 t "github.com/google/wuffs/lang/token" 24) 25 26type Options struct { 27 AllowBuiltInNames bool 28 AllowDoubleUnderscoreNames bool 29} 30 31func isDoubleUnderscore(s string) bool { 32 return len(s) >= 2 && s[0] == '_' && s[1] == '_' 33} 34 35func Parse(tm *t.Map, filename string, src []t.Token, opts *Options) (*a.File, error) { 36 p := &parser{ 37 tm: tm, 38 filename: filename, 39 src: src, 40 } 41 if len(src) > 0 { 42 p.lastLine = src[len(src)-1].Line 43 } 44 if opts != nil { 45 p.opts = *opts 46 } 47 return p.parseFile() 48} 49 50func ParseExpr(tm *t.Map, filename string, src []t.Token, opts *Options) (*a.Expr, error) { 51 p := &parser{ 52 tm: tm, 53 filename: filename, 54 src: src, 55 } 56 if len(src) > 0 { 57 p.lastLine = src[len(src)-1].Line 58 } 59 if opts != nil { 60 p.opts = *opts 61 } 62 return p.parseExpr() 63} 64 65type parser struct { 66 tm *t.Map 67 filename string 68 src []t.Token 69 opts Options 70 lastLine uint32 71 funcEffect a.Effect 72 allowVar bool 73} 74 75func (p *parser) line() uint32 { 76 if len(p.src) != 0 { 77 return p.src[0].Line 78 } 79 return p.lastLine 80} 81 82func (p *parser) peek1() t.ID { 83 if len(p.src) > 0 { 84 return p.src[0].ID 85 } 86 return 0 87} 88 89func (p *parser) parseFile() (*a.File, error) { 90 topLevelDecls := []*a.Node(nil) 91 for len(p.src) > 0 { 92 d, err := p.parseTopLevelDecl() 93 if err != nil { 94 return nil, err 95 } 96 topLevelDecls = append(topLevelDecls, d) 97 } 98 return a.NewFile(p.filename, topLevelDecls), nil 99} 100 101func (p *parser) parseTopLevelDecl() (*a.Node, error) { 102 flags := a.Flags(0) 103 line := p.src[0].Line 104 switch k := p.peek1(); k { 105 case t.IDUse: 106 p.src = p.src[1:] 107 path := p.peek1() 108 if !path.IsStrLiteral(p.tm) { 109 got := p.tm.ByID(path) 110 return nil, fmt.Errorf(`parse: expected string literal, got %q at %s:%d`, got, p.filename, p.line()) 111 } 112 p.src = p.src[1:] 113 if x := p.peek1(); x != t.IDSemicolon { 114 got := p.tm.ByID(x) 115 return nil, fmt.Errorf(`parse: expected (implicit) ";", got %q at %s:%d`, got, p.filename, p.line()) 116 } 117 p.src = p.src[1:] 118 return a.NewUse(p.filename, line, path).AsNode(), nil 119 120 case t.IDPub: 121 flags |= a.FlagsPublic 122 fallthrough 123 case t.IDPri: 124 p.src = p.src[1:] 125 switch p.peek1() { 126 case t.IDConst: 127 p.src = p.src[1:] 128 id, err := p.parseIdent() 129 if err != nil { 130 return nil, err 131 } 132 // TODO: check AllowDoubleUnderscoreNames? 133 134 typ, err := p.parseTypeExpr() 135 if err != nil { 136 return nil, err 137 } 138 if p.peek1() != t.IDEq { 139 return nil, fmt.Errorf(`parse: const %q has no value at %s:%d`, 140 p.tm.ByID(id), p.filename, p.line()) 141 } 142 p.src = p.src[1:] 143 value, err := p.parsePossibleListExpr() 144 if err != nil { 145 return nil, err 146 } 147 if x := p.peek1(); x != t.IDSemicolon { 148 got := p.tm.ByID(x) 149 return nil, fmt.Errorf(`parse: expected (implicit) ";", got %q at %s:%d`, got, p.filename, p.line()) 150 } 151 p.src = p.src[1:] 152 return a.NewConst(flags, p.filename, line, id, typ, value).AsNode(), nil 153 154 case t.IDFunc: 155 p.src = p.src[1:] 156 id0, id1, err := p.parseQualifiedIdent() 157 if err != nil { 158 return nil, err 159 } 160 if !p.opts.AllowBuiltInNames { 161 switch id1 { 162 case t.IDInitialize, t.IDReset: 163 return nil, fmt.Errorf(`parse: cannot have a method named %q at %s:%d`, 164 id1.Str(p.tm), p.filename, p.line()) 165 } 166 } 167 // TODO: should we require id0 != 0? In other words, always methods 168 // (attached to receivers) and never free standing functions? 169 if !p.opts.AllowDoubleUnderscoreNames && isDoubleUnderscore(p.tm.ByID(id1)) { 170 return nil, fmt.Errorf(`parse: double-underscore %q used for func name at %s:%d`, 171 p.tm.ByID(id1), p.filename, p.line()) 172 } 173 174 p.funcEffect = p.parseEffect() 175 flags |= p.funcEffect.AsFlags() 176 argFields, err := p.parseList(t.IDCloseParen, (*parser).parseFieldNode) 177 if err != nil { 178 return nil, err 179 } 180 out := (*a.TypeExpr)(nil) 181 if p.peek1() != t.IDOpenCurly { 182 out, err = p.parseTypeExpr() 183 if err != nil { 184 return nil, err 185 } 186 } 187 asserts := []*a.Node(nil) 188 if p.peek1() == t.IDComma { 189 p.src = p.src[1:] 190 asserts, err = p.parseList(t.IDOpenCurly, (*parser).parseAssertNode) 191 if err != nil { 192 return nil, err 193 } 194 if err := p.assertsSorted(asserts); err != nil { 195 return nil, err 196 } 197 } 198 199 p.allowVar = true 200 body, err := p.parseBlock() 201 if err != nil { 202 return nil, err 203 } 204 p.allowVar = false 205 206 if x := p.peek1(); x != t.IDSemicolon { 207 got := p.tm.ByID(x) 208 return nil, fmt.Errorf(`parse: expected (implicit) ";", got %q at %s:%d`, got, p.filename, p.line()) 209 } 210 p.src = p.src[1:] 211 p.funcEffect = 0 212 in := a.NewStruct(0, p.filename, line, t.IDArgs, argFields) 213 return a.NewFunc(flags, p.filename, line, id0, id1, in, out, asserts, body).AsNode(), nil 214 215 case t.IDStatus: 216 p.src = p.src[1:] 217 218 message := p.peek1() 219 if !message.IsStrLiteral(p.tm) { 220 got := p.tm.ByID(message) 221 return nil, fmt.Errorf(`parse: expected string literal, got %q at %s:%d`, got, p.filename, p.line()) 222 } 223 p.src = p.src[1:] 224 if x := p.peek1(); x != t.IDSemicolon { 225 got := p.tm.ByID(x) 226 return nil, fmt.Errorf(`parse: expected (implicit) ";", got %q at %s:%d`, got, p.filename, p.line()) 227 } 228 p.src = p.src[1:] 229 return a.NewStatus(flags, p.filename, line, message).AsNode(), nil 230 231 case t.IDStruct: 232 p.src = p.src[1:] 233 name, err := p.parseIdent() 234 if err != nil { 235 return nil, err 236 } 237 if !p.opts.AllowDoubleUnderscoreNames && isDoubleUnderscore(p.tm.ByID(name)) { 238 return nil, fmt.Errorf(`parse: double-underscore %q used for struct name at %s:%d`, 239 p.tm.ByID(name), p.filename, p.line()) 240 } 241 242 if p.peek1() == t.IDQuestion { 243 flags |= a.FlagsClassy 244 p.src = p.src[1:] 245 } 246 fields, err := p.parseList(t.IDCloseParen, (*parser).parseFieldNode) 247 if err != nil { 248 return nil, err 249 } 250 if x := p.peek1(); x == t.IDOpenParen { 251 extraFields, err := p.parseList(t.IDCloseParen, (*parser).parseExtraFieldNode) 252 if err != nil { 253 return nil, err 254 } 255 fields = append(fields, extraFields...) 256 } 257 if x := p.peek1(); x != t.IDSemicolon { 258 got := p.tm.ByID(x) 259 return nil, fmt.Errorf(`parse: expected (implicit) ";", got %q at %s:%d`, got, p.filename, p.line()) 260 } 261 p.src = p.src[1:] 262 return a.NewStruct(flags, p.filename, line, name, fields).AsNode(), nil 263 } 264 } 265 return nil, fmt.Errorf(`parse: unrecognized top level declaration at %s:%d`, p.filename, line) 266} 267 268// parseQualifiedIdent parses "foo.bar" or "bar". 269func (p *parser) parseQualifiedIdent() (t.ID, t.ID, error) { 270 x, err := p.parseIdent() 271 if err != nil { 272 return 0, 0, err 273 } 274 275 if p.peek1() != t.IDDot { 276 return 0, x, nil 277 } 278 p.src = p.src[1:] 279 280 y, err := p.parseIdent() 281 if err != nil { 282 return 0, 0, err 283 } 284 return x, y, nil 285} 286 287func (p *parser) parseIdent() (t.ID, error) { 288 if len(p.src) == 0 { 289 return 0, fmt.Errorf(`parse: expected identifier at %s:%d`, p.filename, p.line()) 290 } 291 x := p.src[0] 292 if !x.ID.IsIdent(p.tm) { 293 got := p.tm.ByID(x.ID) 294 return 0, fmt.Errorf(`parse: expected identifier, got %q at %s:%d`, got, p.filename, p.line()) 295 } 296 p.src = p.src[1:] 297 return x.ID, nil 298} 299 300func (p *parser) parseList(stop t.ID, parseElem func(*parser) (*a.Node, error)) ([]*a.Node, error) { 301 if stop == t.IDCloseParen { 302 if x := p.peek1(); x != t.IDOpenParen { 303 return nil, fmt.Errorf(`parse: expected "(", got %q at %s:%d`, 304 p.tm.ByID(x), p.filename, p.line()) 305 } 306 p.src = p.src[1:] 307 } 308 309 ret := []*a.Node(nil) 310 for len(p.src) > 0 { 311 if p.src[0].ID == stop { 312 if stop == t.IDCloseParen || stop == t.IDCloseBracket { 313 p.src = p.src[1:] 314 } 315 return ret, nil 316 } 317 318 elem, err := parseElem(p) 319 if err != nil { 320 return nil, err 321 } 322 ret = append(ret, elem) 323 324 switch x := p.peek1(); x { 325 case stop: 326 if stop == t.IDCloseParen || stop == t.IDCloseBracket { 327 p.src = p.src[1:] 328 } 329 return ret, nil 330 case t.IDComma: 331 p.src = p.src[1:] 332 default: 333 return nil, fmt.Errorf(`parse: expected %q, got %q at %s:%d`, 334 p.tm.ByID(stop), p.tm.ByID(x), p.filename, p.line()) 335 } 336 } 337 return nil, fmt.Errorf(`parse: expected %q at %s:%d`, p.tm.ByID(stop), p.filename, p.line()) 338} 339 340func (p *parser) parseFieldNode() (*a.Node, error) { 341 return p.parseFieldNode1(0) 342} 343 344func (p *parser) parseExtraFieldNode() (*a.Node, error) { 345 n, err := p.parseFieldNode1(a.FlagsPrivateData) 346 if err != nil { 347 return nil, err 348 } 349 typ := n.AsField().XType() 350 for typ.Decorator() == t.IDArray { 351 typ = typ.Inner() 352 } 353 if (typ.Decorator() != 0) || 354 (typ.QID()[0] == t.IDBase) && (!typ.IsNumType() || typ.IsRefined()) { 355 356 return nil, fmt.Errorf(`parse: invalid extra-field type %q at %s:%d`, 357 n.AsField().XType().Str(p.tm), p.filename, p.line()) 358 } 359 return n, nil 360} 361 362func (p *parser) parseFieldNode1(flags a.Flags) (*a.Node, error) { 363 name, err := p.parseIdent() 364 if err != nil { 365 return nil, err 366 } 367 typ, err := p.parseTypeExpr() 368 if err != nil { 369 return nil, err 370 } 371 if pkg := typ.Innermost().QID()[0]; (pkg != 0) && (pkg != t.IDBase) { 372 flags |= a.FlagsPrivateData 373 } 374 return a.NewField(flags, name, typ).AsNode(), nil 375} 376 377func (p *parser) parseTypeExpr() (*a.TypeExpr, error) { 378 if x := p.peek1(); x == t.IDNptr || x == t.IDPtr { 379 p.src = p.src[1:] 380 rhs, err := p.parseTypeExpr() 381 if err != nil { 382 return nil, err 383 } 384 return a.NewTypeExpr(x, 0, 0, nil, nil, rhs), nil 385 } 386 387 decorator, arrayLength := t.ID(0), (*a.Expr)(nil) 388 switch p.peek1() { 389 case t.IDArray: 390 decorator = t.IDArray 391 p.src = p.src[1:] 392 393 if x := p.peek1(); x != t.IDOpenBracket { 394 got := p.tm.ByID(x) 395 return nil, fmt.Errorf(`parse: expected "[", got %q at %s:%d`, got, p.filename, p.line()) 396 } 397 p.src = p.src[1:] 398 399 var err error 400 arrayLength, err = p.parseExpr() 401 if err != nil { 402 return nil, err 403 } 404 405 if x := p.peek1(); x != t.IDCloseBracket { 406 got := p.tm.ByID(x) 407 return nil, fmt.Errorf(`parse: expected "]", got %q at %s:%d`, got, p.filename, p.line()) 408 } 409 p.src = p.src[1:] 410 411 case t.IDSlice: 412 decorator = t.IDSlice 413 p.src = p.src[1:] 414 415 case t.IDTable: 416 decorator = t.IDTable 417 p.src = p.src[1:] 418 } 419 420 if decorator != 0 { 421 rhs, err := p.parseTypeExpr() 422 if err != nil { 423 return nil, err 424 } 425 return a.NewTypeExpr(decorator, 0, 0, arrayLength.AsNode(), nil, rhs), nil 426 } 427 428 pkg, name, err := p.parseQualifiedIdent() 429 if err != nil { 430 return nil, err 431 } 432 433 lhs, mhs := (*a.Expr)(nil), (*a.Expr)(nil) 434 if p.peek1() == t.IDOpenBracket { 435 _, lhs, mhs, err = p.parseBracket(t.IDDotDot) 436 if err != nil { 437 return nil, err 438 } 439 } 440 441 return a.NewTypeExpr(0, pkg, name, lhs.AsNode(), mhs, nil), nil 442} 443 444// parseBracket parses "[i:j]", "[i:]", "[:j]" and "[:]". A double dot replaces 445// the colon if sep is t.IDDotDot instead of t.IDColon. If sep is t.IDColon, it 446// also parses "[x]". The returned op is sep for a range or refinement and 447// t.IDOpenBracket for an index. 448func (p *parser) parseBracket(sep t.ID) (op t.ID, ei *a.Expr, ej *a.Expr, err error) { 449 if x := p.peek1(); x != t.IDOpenBracket { 450 got := p.tm.ByID(x) 451 return 0, nil, nil, fmt.Errorf(`parse: expected "[", got %q at %s:%d`, got, p.filename, p.line()) 452 } 453 p.src = p.src[1:] 454 455 if p.peek1() != sep { 456 ei, err = p.parseExpr() 457 if err != nil { 458 return 0, nil, nil, err 459 } 460 } 461 462 switch x := p.peek1(); { 463 case x == sep: 464 p.src = p.src[1:] 465 466 case x == t.IDCloseBracket && sep == t.IDColon: 467 p.src = p.src[1:] 468 return t.IDOpenBracket, nil, ei, nil 469 470 default: 471 extra := `` 472 if sep == t.IDColon { 473 extra = ` or "]"` 474 } 475 got := p.tm.ByID(x) 476 return 0, nil, nil, fmt.Errorf(`parse: expected %q%s, got %q at %s:%d`, 477 p.tm.ByID(sep), extra, got, p.filename, p.line()) 478 } 479 480 if p.peek1() != t.IDCloseBracket { 481 ej, err = p.parseExpr() 482 if err != nil { 483 return 0, nil, nil, err 484 } 485 } 486 487 if x := p.peek1(); x != t.IDCloseBracket { 488 got := p.tm.ByID(x) 489 return 0, nil, nil, fmt.Errorf(`parse: expected "]", got %q at %s:%d`, got, p.filename, p.line()) 490 } 491 p.src = p.src[1:] 492 493 return sep, ei, ej, nil 494} 495 496func (p *parser) parseBlock() ([]*a.Node, error) { 497 if x := p.peek1(); x != t.IDOpenCurly { 498 got := p.tm.ByID(x) 499 return nil, fmt.Errorf(`parse: expected "{", got %q at %s:%d`, got, p.filename, p.line()) 500 } 501 p.src = p.src[1:] 502 503 block := []*a.Node(nil) 504 for len(p.src) > 0 { 505 if p.src[0].ID == t.IDCloseCurly { 506 p.src = p.src[1:] 507 return block, nil 508 } 509 510 s, err := p.parseStatement() 511 if err != nil { 512 return nil, err 513 } 514 block = append(block, s) 515 516 if x := p.peek1(); x != t.IDSemicolon { 517 got := p.tm.ByID(x) 518 return nil, fmt.Errorf(`parse: expected (implicit) ";", got %q at %s:%d`, got, p.filename, p.line()) 519 } 520 p.src = p.src[1:] 521 } 522 return nil, fmt.Errorf(`parse: expected "}" at %s:%d`, p.filename, p.line()) 523} 524 525func (p *parser) assertsSorted(asserts []*a.Node) error { 526 seenInv, seenPost := false, false 527 for _, a := range asserts { 528 switch a.AsAssert().Keyword() { 529 case t.IDAssert: 530 return fmt.Errorf(`parse: assertion chain cannot contain "assert", `+ 531 `only "pre", "inv" and "post" at %s:%d`, p.filename, p.line()) 532 case t.IDPre: 533 if seenPost || seenInv { 534 break 535 } 536 continue 537 case t.IDInv: 538 if seenPost { 539 break 540 } 541 seenInv = true 542 continue 543 default: 544 seenPost = true 545 continue 546 } 547 return fmt.Errorf(`parse: assertion chain not in "pre", "inv", "post" order at %s:%d`, 548 p.filename, p.line()) 549 } 550 return nil 551} 552 553func (p *parser) parseAssertNode() (*a.Node, error) { 554 switch x := p.peek1(); x { 555 case t.IDAssert, t.IDPre, t.IDInv, t.IDPost: 556 p.src = p.src[1:] 557 condition, err := p.parseExpr() 558 if err != nil { 559 return nil, err 560 } 561 if condition.Effect() != 0 { 562 return nil, fmt.Errorf(`parse: assert-condition %q is not effect-free at %s:%d`, 563 condition.Str(p.tm), p.filename, p.line()) 564 } 565 reason, args := t.ID(0), []*a.Node(nil) 566 if p.peek1() == t.IDVia { 567 p.src = p.src[1:] 568 reason = p.peek1() 569 if !reason.IsStrLiteral(p.tm) { 570 got := p.tm.ByID(reason) 571 return nil, fmt.Errorf(`parse: expected string literal, got %q at %s:%d`, got, p.filename, p.line()) 572 } 573 p.src = p.src[1:] 574 args, err = p.parseList(t.IDCloseParen, (*parser).parseArgNode) 575 if err != nil { 576 return nil, err 577 } 578 } 579 return a.NewAssert(x, condition, reason, args).AsNode(), nil 580 } 581 return nil, fmt.Errorf(`parse: expected "assert", "pre" or "post" at %s:%d`, p.filename, p.line()) 582} 583 584func (p *parser) parseStatement() (*a.Node, error) { 585 line := uint32(0) 586 if len(p.src) > 0 { 587 line = p.src[0].Line 588 } 589 n, err := p.parseStatement1() 590 if n != nil { 591 n.AsRaw().SetFilenameLine(p.filename, line) 592 if n.Kind() == a.KIterate { 593 for _, o := range n.AsIterate().Assigns() { 594 o.AsRaw().SetFilenameLine(p.filename, line) 595 } 596 } 597 } 598 return n, err 599} 600 601func (p *parser) parseLabel() (t.ID, error) { 602 if p.peek1() == t.IDColon { 603 p.src = p.src[1:] 604 return p.parseIdent() 605 } 606 return 0, nil 607} 608 609func (p *parser) parseStatement1() (*a.Node, error) { 610 x := p.peek1() 611 if x == t.IDVar { 612 if !p.allowVar { 613 return nil, fmt.Errorf(`parse: var statement not at the top of a function at %s:%d`, 614 p.filename, p.line()) 615 } 616 p.src = p.src[1:] 617 return p.parseVarNode() 618 } 619 p.allowVar = false 620 621 switch x { 622 case t.IDAssert, t.IDPre, t.IDPost: 623 return p.parseAssertNode() 624 625 case t.IDBreak, t.IDContinue: 626 p.src = p.src[1:] 627 label, err := p.parseLabel() 628 if err != nil { 629 return nil, err 630 } 631 return a.NewJump(x, label).AsNode(), nil 632 633 case t.IDIOBind, t.IDIOLimit: 634 return p.parseIOBindNode() 635 636 case t.IDIf: 637 o, err := p.parseIf() 638 return o.AsNode(), err 639 640 case t.IDIterate: 641 return p.parseIterateNode() 642 643 case t.IDReturn, t.IDYield: 644 p.src = p.src[1:] 645 if x == t.IDYield { 646 if !p.funcEffect.Coroutine() { 647 return nil, fmt.Errorf(`parse: yield within non-coroutine at %s:%d`, p.filename, p.line()) 648 } 649 if p.peek1() != t.IDQuestion { 650 return nil, fmt.Errorf(`parse: yield not followed by '?' at %s:%d`, p.filename, p.line()) 651 } 652 p.src = p.src[1:] 653 } 654 value, err := p.parseExpr() 655 if err != nil { 656 return nil, err 657 } 658 return a.NewRet(x, value).AsNode(), nil 659 660 case t.IDWhile: 661 p.src = p.src[1:] 662 label, err := p.parseLabel() 663 if err != nil { 664 return nil, err 665 } 666 condition, err := p.parseExpr() 667 if err != nil { 668 return nil, err 669 } 670 if condition.Effect() != 0 { 671 return nil, fmt.Errorf(`parse: while-condition %q is not effect-free at %s:%d`, 672 condition.Str(p.tm), p.filename, p.line()) 673 } 674 asserts, err := p.parseAsserts() 675 if err != nil { 676 return nil, err 677 } 678 body, err := p.parseBlock() 679 if err != nil { 680 return nil, err 681 } 682 return a.NewWhile(label, condition, asserts, body).AsNode(), nil 683 } 684 return p.parseAssignNode() 685} 686 687func (p *parser) parseAssignNode() (*a.Node, error) { 688 lhs := (*a.Expr)(nil) 689 rhs, err := p.parseExpr() 690 if err != nil { 691 return nil, err 692 } 693 694 op := p.peek1() 695 if op.IsAssign() { 696 p.src = p.src[1:] 697 lhs = rhs 698 if lhs.Effect() != 0 { 699 return nil, fmt.Errorf(`parse: assignment LHS %q is not effect-free at %s:%d`, 700 lhs.Str(p.tm), p.filename, p.line()) 701 } 702 703 for l := lhs; l != nil; l = l.LHS().AsExpr() { 704 switch l.Operator() { 705 case 0: 706 if id := l.Ident(); id.IsLiteral(p.tm) { 707 return nil, fmt.Errorf(`parse: assignment LHS %q is a literal at %s:%d`, 708 l.Str(p.tm), p.filename, p.line()) 709 } else if id.IsCannotAssignTo() { 710 if l == lhs { 711 return nil, fmt.Errorf(`parse: cannot assign to %q at %s:%d`, 712 id.Str(p.tm), p.filename, p.line()) 713 } 714 if !p.funcEffect.Impure() { 715 return nil, fmt.Errorf(`parse: cannot assign to %q in a pure function at %s:%d`, 716 lhs.Str(p.tm), p.filename, p.line()) 717 } 718 } 719 case t.IDDot, t.IDOpenBracket: 720 // No-op. 721 default: 722 return nil, fmt.Errorf(`parse: invalid assignment LHS %q at %s:%d`, 723 lhs.Str(p.tm), p.filename, p.line()) 724 } 725 } 726 727 rhs, err = p.parseExpr() 728 if err != nil { 729 return nil, err 730 } 731 732 if op == t.IDEqQuestion { 733 if (rhs.Operator() != t.IDOpenParen) || (!rhs.Effect().Coroutine()) { 734 return nil, fmt.Errorf(`parse: expected ?-function call after "=?", got %q at %s:%d`, 735 rhs.Str(p.tm), p.filename, p.line()) 736 } 737 } 738 } else { 739 op = t.IDEq 740 } 741 742 if p.funcEffect.WeakerThan(rhs.Effect()) { 743 return nil, fmt.Errorf(`parse: value %q's effect %q is stronger than the func's effect %q at %s:%d`, 744 rhs.Str(p.tm), rhs.Effect(), p.funcEffect, p.filename, p.line()) 745 } 746 747 return a.NewAssign(op, lhs, rhs).AsNode(), nil 748} 749 750func (p *parser) parseIterateAssignNode() (*a.Node, error) { 751 n, err := p.parseAssignNode() 752 if err != nil { 753 return nil, err 754 } 755 o := n.AsAssign() 756 if op := o.Operator(); op != t.IDEq { 757 return nil, fmt.Errorf(`parse: expected "=", got %q at %s:%d`, op.Str(p.tm), p.filename, p.line()) 758 } 759 if lhs := o.LHS(); lhs.Operator() != 0 { 760 return nil, fmt.Errorf(`parse: expected variable, got %q at %s:%d`, lhs.Str(p.tm), p.filename, p.line()) 761 } 762 if rhs := o.RHS(); rhs.Effect() != 0 { 763 return nil, fmt.Errorf(`parse: value %q is not effect-free at %s:%d`, rhs.Str(p.tm), p.filename, p.line()) 764 } 765 return o.AsNode(), nil 766} 767 768func (p *parser) parseAsserts() ([]*a.Node, error) { 769 asserts := []*a.Node(nil) 770 if p.peek1() == t.IDComma { 771 p.src = p.src[1:] 772 var err error 773 if asserts, err = p.parseList(t.IDOpenCurly, (*parser).parseAssertNode); err != nil { 774 return nil, err 775 } 776 if err := p.assertsSorted(asserts); err != nil { 777 return nil, err 778 } 779 } 780 return asserts, nil 781} 782 783func (p *parser) parseIOBindNode() (*a.Node, error) { 784 keyword := p.peek1() 785 p.src = p.src[1:] 786 787 if x := p.peek1(); x != t.IDOpenParen { 788 got := p.tm.ByID(x) 789 return nil, fmt.Errorf(`parse: expected "(", got %q at %s:%d`, got, p.filename, p.line()) 790 } 791 p.src = p.src[1:] 792 793 if x := p.peek1(); x != t.IDIO { 794 got := p.tm.ByID(x) 795 return nil, fmt.Errorf(`parse: expected "io", got %q at %s:%d`, got, p.filename, p.line()) 796 } 797 p.src = p.src[1:] 798 799 if x := p.peek1(); x != t.IDColon { 800 got := p.tm.ByID(x) 801 return nil, fmt.Errorf(`parse: expected ":", got %q at %s:%d`, got, p.filename, p.line()) 802 } 803 p.src = p.src[1:] 804 805 io, err := p.parseExpr() 806 if err != nil { 807 return nil, err 808 } 809 if io.Effect() != 0 { 810 return nil, fmt.Errorf(`parse: argument %q is not effect-free at %s:%d`, 811 io.Str(p.tm), p.filename, p.line()) 812 } 813 814 if x := p.peek1(); x != t.IDComma { 815 got := p.tm.ByID(x) 816 return nil, fmt.Errorf(`parse: expected ",", got %q at %s:%d`, got, p.filename, p.line()) 817 } 818 p.src = p.src[1:] 819 820 arg1Name := t.IDData 821 if keyword == t.IDIOLimit { 822 arg1Name = t.IDLimit 823 } 824 if x := p.peek1(); x != arg1Name { 825 got := p.tm.ByID(x) 826 return nil, fmt.Errorf(`parse: expected %q, got %q at %s:%d`, arg1Name.Str(p.tm), got, p.filename, p.line()) 827 } 828 p.src = p.src[1:] 829 830 if x := p.peek1(); x != t.IDColon { 831 got := p.tm.ByID(x) 832 return nil, fmt.Errorf(`parse: expected ":", got %q at %s:%d`, got, p.filename, p.line()) 833 } 834 p.src = p.src[1:] 835 836 arg1, err := p.parseExpr() 837 if err != nil { 838 return nil, err 839 } 840 if arg1.Effect() != 0 { 841 return nil, fmt.Errorf(`parse: argument %q is not effect-free at %s:%d`, 842 io.Str(p.tm), p.filename, p.line()) 843 } 844 845 if x := p.peek1(); x != t.IDCloseParen { 846 got := p.tm.ByID(x) 847 return nil, fmt.Errorf(`parse: expected ")", got %q at %s:%d`, got, p.filename, p.line()) 848 } 849 p.src = p.src[1:] 850 851 body, err := p.parseBlock() 852 if err != nil { 853 return nil, err 854 } 855 856 return a.NewIOBind(keyword, io, arg1, body).AsNode(), nil 857} 858 859func (p *parser) parseIf() (*a.If, error) { 860 if x := p.peek1(); x != t.IDIf { 861 got := p.tm.ByID(x) 862 return nil, fmt.Errorf(`parse: expected "if", got %q at %s:%d`, got, p.filename, p.line()) 863 } 864 p.src = p.src[1:] 865 condition, err := p.parseExpr() 866 if err != nil { 867 return nil, err 868 } 869 if condition.Effect() != 0 { 870 return nil, fmt.Errorf(`parse: if-condition %q is not effect-free at %s:%d`, 871 condition.Str(p.tm), p.filename, p.line()) 872 } 873 bodyIfTrue, err := p.parseBlock() 874 if err != nil { 875 return nil, err 876 } 877 elseIf, bodyIfFalse := (*a.If)(nil), ([]*a.Node)(nil) 878 if p.peek1() == t.IDElse { 879 p.src = p.src[1:] 880 if p.peek1() == t.IDIf { 881 elseIf, err = p.parseIf() 882 if err != nil { 883 return nil, err 884 } 885 } else { 886 bodyIfFalse, err = p.parseBlock() 887 if err != nil { 888 return nil, err 889 } 890 } 891 } 892 return a.NewIf(condition, bodyIfTrue, bodyIfFalse, elseIf), nil 893} 894 895func (p *parser) parseIterateNode() (*a.Node, error) { 896 if x := p.peek1(); x != t.IDIterate { 897 got := p.tm.ByID(x) 898 return nil, fmt.Errorf(`parse: expected "iterate", got %q at %s:%d`, got, p.filename, p.line()) 899 } 900 p.src = p.src[1:] 901 label, err := p.parseLabel() 902 if err != nil { 903 return nil, err 904 } 905 assigns, err := p.parseList(t.IDCloseParen, (*parser).parseIterateAssignNode) 906 if err != nil { 907 return nil, err 908 } 909 n, err := p.parseIterateBlock(label, assigns) 910 if err != nil { 911 return nil, err 912 } 913 return n.AsNode(), nil 914} 915 916func (p *parser) parseIterateBlock(label t.ID, assigns []*a.Node) (*a.Iterate, error) { 917 if x := p.peek1(); x != t.IDOpenParen { 918 got := p.tm.ByID(x) 919 return nil, fmt.Errorf(`parse: expected "(", got %q at %s:%d`, got, p.filename, p.line()) 920 } 921 p.src = p.src[1:] 922 923 if x := p.peek1(); x != t.IDLength { 924 got := p.tm.ByID(x) 925 return nil, fmt.Errorf(`parse: expected "length", got %q at %s:%d`, got, p.filename, p.line()) 926 } 927 p.src = p.src[1:] 928 929 if x := p.peek1(); x != t.IDColon { 930 got := p.tm.ByID(x) 931 return nil, fmt.Errorf(`parse: expected ":", got %q at %s:%d`, got, p.filename, p.line()) 932 } 933 p.src = p.src[1:] 934 935 length := p.peek1() 936 if length.SmallPowerOf2Value() == 0 { 937 return nil, fmt.Errorf(`parse: expected power-of-2 length count in [1..256], got %q at %s:%d`, 938 p.tm.ByID(length), p.filename, p.line()) 939 } 940 p.src = p.src[1:] 941 942 if x := p.peek1(); x != t.IDComma { 943 got := p.tm.ByID(x) 944 return nil, fmt.Errorf(`parse: expected ",", got %q at %s:%d`, got, p.filename, p.line()) 945 } 946 p.src = p.src[1:] 947 948 if x := p.peek1(); x != t.IDUnroll { 949 got := p.tm.ByID(x) 950 return nil, fmt.Errorf(`parse: expected "unroll", got %q at %s:%d`, got, p.filename, p.line()) 951 } 952 p.src = p.src[1:] 953 954 if x := p.peek1(); x != t.IDColon { 955 got := p.tm.ByID(x) 956 return nil, fmt.Errorf(`parse: expected ":", got %q at %s:%d`, got, p.filename, p.line()) 957 } 958 p.src = p.src[1:] 959 960 unroll := p.peek1() 961 if unroll.SmallPowerOf2Value() == 0 { 962 return nil, fmt.Errorf(`parse: expected power-of-2 unroll count in [1..256], got %q at %s:%d`, 963 p.tm.ByID(unroll), p.filename, p.line()) 964 } 965 p.src = p.src[1:] 966 967 if x := p.peek1(); x != t.IDCloseParen { 968 got := p.tm.ByID(x) 969 return nil, fmt.Errorf(`parse: expected ")", got %q at %s:%d`, got, p.filename, p.line()) 970 } 971 p.src = p.src[1:] 972 973 asserts, err := p.parseAsserts() 974 if err != nil { 975 return nil, err 976 } 977 body, err := p.parseBlock() 978 if err != nil { 979 return nil, err 980 } 981 982 elseIterate := (*a.Iterate)(nil) 983 if x := p.peek1(); x == t.IDElse { 984 p.src = p.src[1:] 985 elseIterate, err = p.parseIterateBlock(0, nil) 986 if err != nil { 987 return nil, err 988 } 989 } 990 991 return a.NewIterate(label, assigns, length, unroll, asserts, body, elseIterate), nil 992} 993 994func (p *parser) parseArgNode() (*a.Node, error) { 995 name, err := p.parseIdent() 996 if err != nil { 997 return nil, err 998 } 999 if x := p.peek1(); x != t.IDColon { 1000 got := p.tm.ByID(x) 1001 return nil, fmt.Errorf(`parse: expected ":", got %q at %s:%d`, got, p.filename, p.line()) 1002 } 1003 p.src = p.src[1:] 1004 value, err := p.parseExpr() 1005 if err != nil { 1006 return nil, err 1007 } 1008 if value.Effect() != 0 { 1009 return nil, fmt.Errorf(`parse: arg-value %q is not effect-free at %s:%d`, 1010 value.Str(p.tm), p.filename, p.line()) 1011 } 1012 return a.NewArg(name, value).AsNode(), nil 1013} 1014 1015func (p *parser) parseIOBindExprNode() (*a.Node, error) { 1016 e, err := p.parseExpr() 1017 if err != nil { 1018 return nil, err 1019 } 1020 switch e.Operator() { 1021 case 0: 1022 return e.AsNode(), nil 1023 case t.IDDot: 1024 if lhs := e.LHS().AsExpr(); lhs.Operator() == 0 && lhs.Ident() == t.IDArgs { 1025 return e.AsNode(), nil 1026 } 1027 } 1028 return nil, fmt.Errorf(`parse: expected "args.something", got %q at %s:%d`, e.Str(p.tm), p.filename, p.line()) 1029} 1030 1031func (p *parser) parseVarNode() (*a.Node, error) { 1032 id, err := p.parseIdent() 1033 if err != nil { 1034 return nil, err 1035 } 1036 typ, err := p.parseTypeExpr() 1037 if err != nil { 1038 return nil, err 1039 } 1040 return a.NewVar(id, typ).AsNode(), nil 1041} 1042 1043func (p *parser) parsePossibleListExprNode() (*a.Node, error) { 1044 n, err := p.parsePossibleListExpr() 1045 if err != nil { 1046 return nil, err 1047 } 1048 return n.AsNode(), err 1049} 1050 1051func (p *parser) parsePossibleListExpr() (*a.Expr, error) { 1052 // TODO: put the [ and ] parsing into parseExpr. 1053 if x := p.peek1(); x != t.IDOpenBracket { 1054 return p.parseExpr() 1055 } 1056 p.src = p.src[1:] 1057 args, err := p.parseList(t.IDCloseBracket, (*parser).parsePossibleListExprNode) 1058 if err != nil { 1059 return nil, err 1060 } 1061 return a.NewExpr(0, t.IDComma, 0, 0, nil, nil, nil, args), nil 1062} 1063 1064func (p *parser) parseExpr() (*a.Expr, error) { 1065 e, err := p.parseExpr1() 1066 if err != nil { 1067 return nil, err 1068 } 1069 if e.SubExprHasEffect() { 1070 return nil, fmt.Errorf(`parse: expression %q has an effect-ful sub-expression at %s:%d`, 1071 e.Str(p.tm), p.filename, p.line()) 1072 } 1073 return e, nil 1074} 1075 1076func (p *parser) parseExpr1() (*a.Expr, error) { 1077 lhs, err := p.parseOperand() 1078 if err != nil { 1079 return nil, err 1080 } 1081 if x := p.peek1(); x.IsBinaryOp() { 1082 p.src = p.src[1:] 1083 rhs := (*a.Node)(nil) 1084 if x == t.IDAs { 1085 o, err := p.parseTypeExpr() 1086 if err != nil { 1087 return nil, err 1088 } 1089 rhs = o.AsNode() 1090 } else { 1091 o, err := p.parseOperand() 1092 if err != nil { 1093 return nil, err 1094 } 1095 rhs = o.AsNode() 1096 } 1097 1098 if !x.IsAssociativeOp() || x != p.peek1() { 1099 op := x.BinaryForm() 1100 if op == 0 { 1101 return nil, fmt.Errorf(`parse: internal error: no binary form for token 0x%02X`, x) 1102 } 1103 return a.NewExpr(0, op, 0, 0, lhs.AsNode(), nil, rhs, nil), nil 1104 } 1105 1106 args := []*a.Node{lhs.AsNode(), rhs} 1107 for p.peek1() == x { 1108 p.src = p.src[1:] 1109 arg, err := p.parseOperand() 1110 if err != nil { 1111 return nil, err 1112 } 1113 args = append(args, arg.AsNode()) 1114 } 1115 op := x.AssociativeForm() 1116 if op == 0 { 1117 return nil, fmt.Errorf(`parse: internal error: no associative form for token 0x%02X`, x) 1118 } 1119 return a.NewExpr(0, op, 0, 0, nil, nil, nil, args), nil 1120 } 1121 return lhs, nil 1122} 1123 1124func (p *parser) parseOperand() (*a.Expr, error) { 1125 switch x := p.peek1(); { 1126 case x.IsUnaryOp(): 1127 p.src = p.src[1:] 1128 rhs, err := p.parseOperand() 1129 if err != nil { 1130 return nil, err 1131 } 1132 op := x.UnaryForm() 1133 if op == 0 { 1134 return nil, fmt.Errorf(`parse: internal error: no unary form for token 0x%02X`, x) 1135 } 1136 return a.NewExpr(0, op, 0, 0, nil, nil, rhs.AsNode(), nil), nil 1137 1138 case x.IsLiteral(p.tm): 1139 p.src = p.src[1:] 1140 return a.NewExpr(0, 0, 0, x, nil, nil, nil, nil), nil 1141 1142 case x == t.IDOpenParen: 1143 p.src = p.src[1:] 1144 expr, err := p.parseExpr() 1145 if err != nil { 1146 return nil, err 1147 } 1148 if x := p.peek1(); x != t.IDCloseParen { 1149 got := p.tm.ByID(x) 1150 return nil, fmt.Errorf(`parse: expected ")", got %q at %s:%d`, got, p.filename, p.line()) 1151 } 1152 p.src = p.src[1:] 1153 return expr, nil 1154 } 1155 1156 id, err := p.parseIdent() 1157 if err != nil { 1158 return nil, err 1159 } 1160 lhs := a.NewExpr(0, 0, 0, id, nil, nil, nil, nil) 1161 1162 for first := true; ; first = false { 1163 flags := a.Flags(0) 1164 switch p.peek1() { 1165 default: 1166 return lhs, nil 1167 1168 case t.IDExclam, t.IDQuestion: 1169 flags |= p.parseEffect().AsFlags() 1170 fallthrough 1171 1172 case t.IDOpenParen: 1173 args, err := p.parseList(t.IDCloseParen, (*parser).parseArgNode) 1174 if err != nil { 1175 return nil, err 1176 } 1177 lhs = a.NewExpr(flags, t.IDOpenParen, 0, 0, lhs.AsNode(), nil, nil, args) 1178 1179 case t.IDOpenBracket: 1180 id0, mhs, rhs, err := p.parseBracket(t.IDColon) 1181 if err != nil { 1182 return nil, err 1183 } 1184 lhs = a.NewExpr(0, id0, 0, 0, lhs.AsNode(), mhs.AsNode(), rhs.AsNode(), nil) 1185 1186 case t.IDDot: 1187 p.src = p.src[1:] 1188 1189 if x := p.peek1(); x.IsLiteral(p.tm) { 1190 if x.IsNumLiteral(p.tm) { 1191 return nil, fmt.Errorf(`parse: dot followed by numeric literal at %s:%d`, p.filename, p.line()) 1192 } 1193 if !first { 1194 return nil, fmt.Errorf(`parse: string literal %s has too many package qualifiers at %s:%d`, 1195 x.Str(p.tm), p.filename, p.line()) 1196 } 1197 p.src = p.src[1:] 1198 return a.NewExpr(0, 0, id, x, nil, nil, nil, nil), nil 1199 } 1200 1201 selector, err := p.parseIdent() 1202 if err != nil { 1203 return nil, err 1204 } 1205 lhs = a.NewExpr(0, t.IDDot, 0, selector, lhs.AsNode(), nil, nil, nil) 1206 } 1207 } 1208} 1209 1210func (p *parser) parseEffect() a.Effect { 1211 switch p.peek1() { 1212 case t.IDExclam: 1213 p.src = p.src[1:] 1214 return a.EffectImpure 1215 case t.IDQuestion: 1216 p.src = p.src[1:] 1217 return a.EffectImpureCoroutine 1218 } 1219 return 0 1220} 1221