• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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