parse_type.mx raw
1 package syntax
2
3 import (
4 "unsafe"
5 "git.smesh.lol/moxie/pkg/token"
6 )
7
8 func (p *Parser) type_() (e Expr) {
9 if trace {
10 defer p.trace("type_")()
11 }
12
13 typ := p.typeOrNil()
14 if typ == nil {
15 typ = p.badExpr()
16 p.syntaxError("expected type")
17 p.advance(token.Comma, token.Colon, token.Semi, token.Rparen, token.Rbrack, token.Rbrace)
18 }
19
20 return typ
21 }
22
23 func newIndirect(pos token.Pos, typ Expr) (e Expr) {
24 oc := &Operation{}
25 oc.pos = pos
26 oc.Op = token.Mul
27 oc.X = typ
28 return oc
29 }
30
31 // typeOrNil is like type_ but it returns nil if there was no type
32 // instead of reporting an error.
33 //
34 // Type = TypeName | TypeLit + "(" Type ")" .
35 // TypeName = identifier | QualifiedIdent .
36 // TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
37 // SliceType | MapType | Channel_Type .
38 func (p *Parser) typeOrNil() (e Expr) {
39 if trace {
40 defer p.trace("typeOrNil")()
41 }
42
43 pos := p.pos()
44 switch p.Tok {
45 case token.Star:
46 // ptrtype
47 p.Next()
48 return newIndirect(pos, p.type_())
49
50 case token.Arrow:
51 // recvchantype
52 p.Next()
53 p.want(token.Chan)
54 t := (*ChanType)(p.nodeAlloc(unsafe.Sizeof(ChanType{})))
55 t.pos = pos
56 t.Dir = RecvOnly
57 t.Elem = p.chanElem()
58 return t
59
60 case token.Func:
61 // fntype
62 p.Next()
63 _, t := p.funcType("function type")
64 return t
65
66 case token.Lbrack:
67 // '[' oexpr ']' ntype
68 // '[' _DotDotDot ']' ntype
69 p.Next()
70 if p.got(token.Rbrack) {
71 return p.sliceType(pos)
72 }
73 return p.arrayType(pos, nil)
74
75 case token.Chan:
76 // _Chan non_recvchantype
77 // _Chan _Comm ntype
78 p.Next()
79 t := (*ChanType)(p.nodeAlloc(unsafe.Sizeof(ChanType{})))
80 t.pos = pos
81 if p.got(token.Arrow) {
82 t.Dir = SendOnly
83 }
84 t.Elem = p.chanElem()
85 return t
86
87 case token.Map:
88 // _Map '[' ntype ']' ntype
89 p.Next()
90 p.want(token.Lbrack)
91 t := (*MapType)(p.nodeAlloc(unsafe.Sizeof(MapType{})))
92 t.pos = pos
93 t.Key = p.type_()
94 p.want(token.Rbrack)
95 t.Value = p.type_()
96 return t
97
98 case token.Struct:
99 return p.structType()
100
101 case token.Interface:
102 return p.interfaceType()
103
104 case token.NameType:
105 return p.qualifiedName(nil)
106
107 case token.Lparen:
108 p.Next()
109 t := p.type_()
110 p.want(token.Rparen)
111 // The parser doesn't keep unnecessary parentheses.
112 // Set the flag below to keep them, for testing
113 // (see e.g. tests for go.dev/issue/68639).
114 const keep_parens = false
115 if keep_parens {
116 px := (*ParenExpr)(p.nodeAlloc(unsafe.Sizeof(ParenExpr{})))
117 px.pos = pos
118 px.X = t
119 t = px
120 }
121 return t
122 }
123
124 return nil
125 }
126
127 func (p *Parser) typeInstance(typ Expr) (e Expr) {
128 if trace {
129 defer p.trace("typeInstance")()
130 }
131
132 pos := p.pos()
133 p.want(token.Lbrack)
134 x := (*IndexExpr)(p.nodeAlloc(unsafe.Sizeof(IndexExpr{})))
135 x.pos = pos
136 x.X = typ
137 if p.Tok == token.Rbrack {
138 p.syntaxError("expected type argument list")
139 x.Index = p.badExpr()
140 } else {
141 x.Index, _ = p.typeList(true)
142 }
143 p.want(token.Rbrack)
144 return x
145 }
146
147 // If context != "", type parameters are not permitted.
148 func (p *Parser) funcType(context string) (tparams []*Field, ft *FuncType) {
149 if trace {
150 defer p.trace("funcType")()
151 }
152 typ := (*FuncType)(p.nodeAlloc(unsafe.Sizeof(FuncType{})))
153 typ.pos = p.pos()
154
155 var tparamList []*Field
156 if p.got(token.Lbrack) {
157 if context != "" {
158 // accept but complain
159 p.syntaxErrorAt(typ.pos, context | " must have no type parameters")
160 }
161 if p.Tok == token.Rbrack {
162 p.syntaxError("empty type parameter list")
163 p.Next()
164 } else {
165 tparamList = p.paramList(nil, nil, token.Rbrack, true, false)
166 }
167 }
168
169 p.want(token.Lparen)
170 typ.ParamList = p.paramList(nil, nil, token.Rparen, false, true)
171 typ.ResultList = p.funcResult()
172
173 return tparamList, typ
174 }
175
176 // "[" has already been consumed, and pos is its position.
177 // If arrLen != nil it is the already consumed array length.
178 func (p *Parser) arrayType(pos token.Pos, arrLen Expr) (e Expr) {
179 if trace {
180 defer p.trace("arrayType")()
181 }
182
183 if arrLen == nil && !p.got(token.DotDotDot) {
184 p.Xnest++
185 arrLen = p.expr()
186 p.Xnest--
187 }
188 if p.Tok == token.Comma {
189 // Trailing commas are accepted in type parameter
190 // lists but not in array type declarations.
191 // Accept for better error handling but complain.
192 p.syntaxError("unexpected comma; expected ]")
193 p.Next()
194 }
195 p.want(token.Rbrack)
196 at := (*ArrayType)(p.nodeAlloc(unsafe.Sizeof(ArrayType{})))
197 at.pos = pos
198 at.Len = arrLen
199 at.Elem = p.type_()
200 return at
201 }
202
203 // "[" and "]" have already been consumed, and pos is the position of "[".
204 func (p *Parser) sliceType(pos token.Pos) (e Expr) {
205 tc := (*SliceType)(p.nodeAlloc(unsafe.Sizeof(SliceType{})))
206 tc.pos = pos
207 tc.Elem = p.type_()
208 return tc
209 }
210
211 func (p *Parser) chanElem() (e Expr) {
212 if trace {
213 defer p.trace("chanElem")()
214 }
215
216 typ := p.typeOrNil()
217 if typ == nil {
218 typ = p.badExpr()
219 p.syntaxError("missing channel element type")
220 // assume element type is simply absent - don't advance
221 }
222
223 return typ
224 }
225
226 // StructType = "struct" "{" { FieldDecl ";" } "}" .
227 func (p *Parser) structType() (s *StructType) {
228 if trace {
229 defer p.trace("structType")()
230 }
231
232 typ := (*StructType)(p.nodeAlloc(unsafe.Sizeof(StructType{})))
233 typ.pos = p.pos()
234
235 p.want(token.Struct)
236 p.want(token.Lbrace)
237 p.list("struct type", token.Semi, token.Rbrace, func() bool {
238 p.fieldDecl(typ)
239 return false
240 })
241
242 return typ
243 }
244
245 // InterfaceType = "interface" "{" { ( MethodDecl | EmbeddedElem ) ";" } "}" .
246 func (p *Parser) interfaceType() (i *InterfaceType) {
247 if trace {
248 defer p.trace("interfaceType")()
249 }
250
251 typ := (*InterfaceType)(p.nodeAlloc(unsafe.Sizeof(InterfaceType{})))
252 typ.pos = p.pos()
253
254 p.want(token.Interface)
255 p.want(token.Lbrace)
256 p.list("interface type", token.Semi, token.Rbrace, func() bool {
257 var f *Field
258 if p.Tok == token.NameType {
259 f = p.methodDecl()
260 }
261 if f == nil || f.Name == nil {
262 f = p.embeddedElem(f)
263 }
264 push(typ.MethodList, f)
265 return false
266 })
267
268 return typ
269 }
270
271 // Result = Parameters | Type .
272 func (p *Parser) funcResult() (fs []*Field) {
273 if trace {
274 defer p.trace("funcResult")()
275 }
276
277 if p.got(token.Lparen) {
278 return p.paramList(nil, nil, token.Rparen, false, false)
279 }
280
281 pos := p.pos()
282 if typ := p.typeOrNil(); typ != nil {
283 f := (*Field)(p.nodeAlloc(unsafe.Sizeof(Field{})))
284 f.pos = pos
285 f.Type = typ
286 return []*Field{f}
287 }
288
289 return nil
290 }
291
292 func (p *Parser) addField(styp *StructType, pos token.Pos, name *Name, typ Expr, tag *BasicLit) {
293 if tag != nil {
294 for i := len(styp.FieldList) - len(styp.TagList); i > 0; i-- {
295 push(styp.TagList, nil)
296 }
297 push(styp.TagList, tag)
298 }
299
300 f := (*Field)(p.nodeAlloc(unsafe.Sizeof(Field{})))
301 f.pos = pos
302 f.Name = name
303 f.Type = typ
304 push(styp.FieldList, f)
305
306 if debug && tag != nil && len(styp.FieldList) != len(styp.TagList) {
307 panic("inconsistent struct field list")
308 }
309 }
310
311 // FieldDecl = (IdentifierList Type | AnonymousField) [ Tag ] .
312 // AnonymousField = [ "*" ] TypeName .
313 // Tag = string_lit .
314 func (p *Parser) fieldDecl(styp *StructType) {
315 if trace {
316 defer p.trace("fieldDecl")()
317 }
318
319 pos := p.pos()
320 switch p.Tok {
321 case token.NameType:
322 name := p.name()
323 if p.Tok == token.Dot || p.Tok == token.Literal || p.Tok == token.Semi || p.Tok == token.Rbrace {
324 // embedded type
325 embedTyp := p.qualifiedName(name)
326 embedTag := p.oliteral()
327 p.addField(styp, pos, nil, embedTyp, embedTag)
328 break
329 }
330
331 // name1, name2, ... Type [ tag ]
332 names := p.nameList(name)
333 var typ Expr
334
335 // Careful dance: We don't know if we have an embedded instantiated
336 // type T[P1, P2, ...] or a field T of array/slice type [P]E or []E.
337 if len(names) == 1 && p.Tok == token.Lbrack {
338 typ = p.arrayOrTArgs()
339 if idxTyp, ok := typ.(*IndexExpr); ok {
340 // embedded type T[P1, P2, ...]
341 idxTyp.X = name // name == names[0]
342 idxTag := p.oliteral()
343 p.addField(styp, pos, nil, idxTyp, idxTag)
344 break
345 }
346 } else {
347 // T P
348 typ = p.type_()
349 }
350
351 tag := p.oliteral()
352
353 for _, nm := range names {
354 p.addField(styp, nm.Pos(), nm, typ, tag)
355 }
356
357 case token.Star:
358 p.Next()
359 var typ Expr
360 if p.Tok == token.Lparen {
361 // *(T)
362 p.syntaxError("cannot parenthesize embedded type")
363 p.Next()
364 typ = p.qualifiedName(nil)
365 p.got(token.Rparen) // no need to complain if missing
366 } else {
367 // *T
368 typ = p.qualifiedName(nil)
369 }
370 tag := p.oliteral()
371 p.addField(styp, pos, nil, newIndirect(pos, typ), tag)
372
373 case token.Lparen:
374 p.syntaxError("cannot parenthesize embedded type")
375 p.Next()
376 var typ Expr
377 if p.Tok == token.Star {
378 // (*T)
379 starPos := p.pos()
380 p.Next()
381 typ = newIndirect(starPos, p.qualifiedName(nil))
382 } else {
383 // (T)
384 typ = p.qualifiedName(nil)
385 }
386 p.got(token.Rparen) // no need to complain if missing
387 tag := p.oliteral()
388 p.addField(styp, pos, nil, typ, tag)
389
390 default:
391 p.syntaxError("expected field name or embedded type")
392 p.advance(token.Semi, token.Rbrace)
393 }
394 }
395
396 func (p *Parser) arrayOrTArgs() (e Expr) {
397 if trace {
398 defer p.trace("arrayOrTArgs")()
399 }
400
401 pos := p.pos()
402 p.want(token.Lbrack)
403 if p.got(token.Rbrack) {
404 return p.sliceType(pos)
405 }
406
407 // x [n]E or x[n,], x[n1, n2], ...
408 n, comma := p.typeList(false)
409 p.want(token.Rbrack)
410 if !comma {
411 if elem := p.typeOrNil(); elem != nil {
412 // x [n]E
413 arrT := (*ArrayType)(p.nodeAlloc(unsafe.Sizeof(ArrayType{})))
414 arrT.pos = pos
415 arrT.Len = n
416 arrT.Elem = elem
417 return arrT
418 }
419 }
420
421 // x[n,], x[n1, n2], ...
422 idxT := (*IndexExpr)(p.nodeAlloc(unsafe.Sizeof(IndexExpr{})))
423 idxT.pos = pos
424 // idxT.X will be filled in by caller
425 idxT.Index = n
426 return idxT
427 }
428
429 func (p *Parser) oliteral() (b *BasicLit) {
430 if p.Tok == token.Literal {
431 b = (*BasicLit)(p.nodeAlloc(unsafe.Sizeof(BasicLit{})))
432 b.pos = p.pos()
433 b.Value = p.Lit
434 b.Kind = p.Kind
435 b.Bad = p.Bad
436 p.Next()
437 return b
438 }
439 return nil
440 }
441
442 // MethodSpec = MethodName Signature | InterfaceTypeName .
443 // MethodName = identifier .
444 // InterfaceTypeName = TypeName .
445 func (p *Parser) methodDecl() (f *Field) {
446 if trace {
447 defer p.trace("methodDecl")()
448 }
449
450 f := (*Field)(p.nodeAlloc(unsafe.Sizeof(Field{})))
451 f.pos = p.pos()
452 name := p.name()
453
454 const context = "interface method"
455
456 switch p.Tok {
457 case token.Lparen:
458 // method
459 f.Name = name
460 _, f.Type = p.funcType(context)
461
462 case token.Lbrack:
463 // Careful dance: We don't know if we have a generic method m[T C](x T)
464 // or an embedded instantiated type T[P1, P2] (we accept generic methods
465 // for generality and robustness of parsing but complain with an error).
466 pos := p.pos()
467 p.Next()
468
469 // Empty type parameter or argument lists are not permitted.
470 // Treat as if [] were absent.
471 if p.Tok == token.Rbrack {
472 // name[]
473 rbPos := p.pos()
474 p.Next()
475 if p.Tok == token.Lparen {
476 // name[](
477 p.errorAt(rbPos, "empty type parameter list")
478 f.Name = name
479 _, f.Type = p.funcType(context)
480 } else {
481 p.errorAt(rbPos, "empty type argument list")
482 f.Type = name
483 }
484 break
485 }
486
487 // A type argument list looks like a parameter list with only
488 // types. Parse a parameter list and decide afterwards.
489 list := p.paramList(nil, nil, token.Rbrack, false, false)
490 if len(list) == 0 {
491 // The type parameter list is not [] but we got nothing
492 // due to other errors (reported by paramList). Treat
493 // as if [] were absent.
494 if p.Tok == token.Lparen {
495 f.Name = name
496 _, f.Type = p.funcType(context)
497 } else {
498 f.Type = name
499 }
500 break
501 }
502
503 // len(list) > 0
504 if list[0].Name != nil {
505 // generic method
506 f.Name = name
507 _, f.Type = p.funcType(context)
508 p.errorAt(pos, "interface method must have no type parameters")
509 break
510 }
511
512 // embedded instantiated type
513 t := (*IndexExpr)(p.nodeAlloc(unsafe.Sizeof(IndexExpr{})))
514 t.pos = pos
515 t.X = name
516 if len(list) == 1 {
517 t.Index = list[0].Type
518 } else {
519 // len(list) > 1
520 l := (*ListExpr)(p.nodeAlloc(unsafe.Sizeof(ListExpr{})))
521 l.pos = list[0].Pos()
522 l.ElemList = []Expr{:len(list)}
523 for i := range list {
524 l.ElemList[i] = list[i].Type
525 }
526 t.Index = l
527 }
528 f.Type = t
529
530 default:
531 // embedded type
532 f.Type = p.qualifiedName(name)
533 }
534
535 return f
536 }
537
538 // EmbeddedElem = MethodSpec | EmbeddedTerm { "|" EmbeddedTerm } .
539 func (p *Parser) embeddedElem(f *Field) (fv *Field) {
540 if trace {
541 defer p.trace("embeddedElem")()
542 }
543
544 if f == nil {
545 f = (*Field)(p.nodeAlloc(unsafe.Sizeof(Field{})))
546 f.pos = p.pos()
547 f.Type = p.embeddedTerm()
548 }
549
550 for p.Tok == token.OperatorType && p.Op == token.Or {
551 t := (*Operation)(p.nodeAlloc(unsafe.Sizeof(Operation{})))
552 t.pos = p.pos()
553 t.Op = token.Or
554 p.Next()
555 t.X = f.Type
556 t.Y = p.embeddedTerm()
557 f.Type = t
558 }
559
560 return f
561 }
562
563 // EmbeddedTerm = [ "~" ] Type .
564 func (p *Parser) embeddedTerm() (e Expr) {
565 if trace {
566 defer p.trace("embeddedTerm")()
567 }
568
569 if p.Tok == token.OperatorType && p.Op == token.Tilde {
570 op := (*Operation)(p.nodeAlloc(unsafe.Sizeof(Operation{})))
571 op.pos = p.pos()
572 op.Op = token.Tilde
573 p.Next()
574 op.X = p.type_()
575 return op
576 }
577
578 et := p.typeOrNil()
579 if et == nil {
580 et = p.badExpr()
581 p.syntaxError("expected ~ term or type")
582 p.advance(token.OperatorType, token.Semi, token.Rparen, token.Rbrack, token.Rbrace)
583 }
584
585 return et
586 }
587
588 // ParameterDecl = [ IdentifierList ] [ "..." ] Type .
589 func (p *Parser) paramDeclOrNil(name *Name, follow token.Token) (f *Field) {
590 if trace {
591 defer p.trace("paramDeclOrNil")()
592 }
593
594 // type set notation is ok in type parameter lists
595 typeSetsOk := follow == token.Rbrack
596
597 pos := p.pos()
598 if name != nil {
599 pos = name.pos
600 } else if typeSetsOk && p.Tok == token.OperatorType && p.Op == token.Tilde {
601 // "~" ...
602 return p.embeddedElem(nil)
603 }
604
605 f := (*Field)(p.nodeAlloc(unsafe.Sizeof(Field{})))
606 f.pos = pos
607
608 if p.Tok == token.NameType || name != nil {
609 // name
610 if name == nil {
611 name = p.name()
612 }
613
614 if p.Tok == token.Lbrack {
615 // name "[" ...
616 f.Type = p.arrayOrTArgs()
617 if typ, ok := f.Type.(*IndexExpr); ok {
618 // name "[" ... "]"
619 typ.X = name
620 } else {
621 // name "[" n "]" E
622 f.Name = name
623 }
624 if typeSetsOk && p.Tok == token.OperatorType && p.Op == token.Or {
625 // name "[" ... "]" "|" ...
626 // name "[" n "]" E "|" ...
627 f = p.embeddedElem(f)
628 }
629 return f
630 }
631
632 if p.Tok == token.Dot {
633 // name "." ...
634 f.Type = p.qualifiedName(name)
635 if typeSetsOk && p.Tok == token.OperatorType && p.Op == token.Or {
636 // name "." name "|" ...
637 f = p.embeddedElem(f)
638 }
639 return f
640 }
641
642 if typeSetsOk && p.Tok == token.OperatorType && p.Op == token.Or {
643 // name "|" ...
644 f.Type = name
645 return p.embeddedElem(f)
646 }
647
648 f.Name = name
649 }
650
651 if p.Tok == token.DotDotDot {
652 // [name] "..." ...
653 t := (*DotsType)(p.nodeAlloc(unsafe.Sizeof(DotsType{})))
654 t.pos = p.pos()
655 p.Next()
656 t.Elem = p.typeOrNil()
657 if t.Elem == nil {
658 f.Type = p.badExpr()
659 p.syntaxError("... is missing type")
660 } else {
661 f.Type = t
662 }
663 return f
664 }
665
666 if typeSetsOk && p.Tok == token.OperatorType && p.Op == token.Tilde {
667 // [name] "~" ...
668 f.Type = p.embeddedElem(nil).Type
669 return f
670 }
671
672 f.Type = p.typeOrNil()
673 if typeSetsOk && p.Tok == token.OperatorType && p.Op == token.Or && f.Type != nil {
674 // [name] type "|"
675 f = p.embeddedElem(f)
676 }
677 if f.Name != nil || f.Type != nil {
678 return f
679 }
680
681 p.syntaxError("expected " | tokstring(follow))
682 p.advance(token.Comma, follow)
683 return nil
684 }
685
686 // Parameters = "(" [ ParameterList [ "," ] ] ")" .
687 // ParameterList = ParameterDecl { "," ParameterDecl } .
688 // "(" or "[" has already been consumed.
689 // If name != nil, it is the first name after "(" or "[".
690 // If typ != nil, name must be != nil, and (name, typ) is the first field in the list.
691 // In the result list, either all fields have a name, or no field has a name.
692 func (p *Parser) paramList(name *Name, typ Expr, closeTok token.Token, requireNames, dddok bool) (list []*Field) {
693 if trace {
694 defer p.trace("paramList")()
695 }
696
697 // p.list won't invoke its function argument if we're at the end of the
698 // parameter list. If we have a complete field, handle this case here.
699 if name != nil && typ != nil && p.Tok == closeTok {
700 p.Next()
701 par := (*Field)(p.nodeAlloc(unsafe.Sizeof(Field{})))
702 par.pos = name.pos
703 par.Name = name
704 par.Type = typ
705 return []*Field{par}
706 }
707
708 var named int32 // number of parameters that have an explicit name and type
709 var typed int32 // number of parameters that have an explicit type
710 end := p.list("parameter list", token.Comma, closeTok, func() bool {
711 var par *Field
712 if typ != nil {
713 if debug && name == nil {
714 panic("initial type provided without name")
715 }
716 par = (*Field)(p.nodeAlloc(unsafe.Sizeof(Field{})))
717 par.pos = name.pos
718 par.Name = name
719 par.Type = typ
720 } else {
721 par = p.paramDeclOrNil(name, closeTok)
722 }
723 name = nil // 1st name was consumed if present
724 typ = nil // 1st type was consumed if present
725 if par != nil {
726 if debug && par.Name == nil && par.Type == nil {
727 panic("parameter without name or type")
728 }
729 if par.Name != nil && par.Type != nil {
730 named++
731 }
732 if par.Type != nil {
733 typed++
734 }
735 push(list, par)
736 }
737 return false
738 })
739
740 if len(list) == 0 {
741 return
742 }
743
744 // distribute parameter types (len(list) > 0)
745 if named == 0 && !requireNames {
746 // all unnamed and we're not in a type parameter list => found names are named types
747 for _, par := range list {
748 if parTyp := par.Name; parTyp != nil {
749 par.Type = parTyp
750 par.Name = nil
751 }
752 }
753 } else if named != len(list) {
754 // some named or we're in a type parameter list => all must be named
755 var errPos token.Pos // left-most error position (or unknown)
756 var curTyp Expr // current type (from right to left)
757 for i := len(list) - 1; i >= 0; i-- {
758 par := list[i]
759 if par.Type != nil {
760 curTyp = par.Type
761 if par.Name == nil {
762 errPos = StartPos(curTyp)
763 par.Name = NewName(errPos, "_")
764 }
765 } else if curTyp != nil {
766 par.Type = curTyp
767 } else {
768 // par.Type == nil && typ == nil => we only have a par.Name
769 errPos = par.Name.Pos()
770 t := p.badExpr()
771 t.pos = errPos // correct position
772 par.Type = t
773 }
774 }
775 if errPos.IsKnown() {
776 // Not all parameters are named because named != len(list).
777 // If named == typed, there must be parameters that have no types.
778 // They must be at the end of the parameter list, otherwise types
779 // would have been filled in by the right-to-left sweep above and
780 // there would be no error.
781 // If requireNames is set, the parameter list is a type parameter
782 // list.
783 var msg string
784 if named == typed {
785 errPos = end // position error at closing token ) or ]
786 if requireNames {
787 msg = "missing type constraint"
788 } else {
789 msg = "missing parameter type"
790 }
791 } else {
792 if requireNames {
793 msg = "missing type parameter name"
794 // go.dev/issue/60812
795 if len(list) == 1 {
796 msg = msg | " or invalid array length"
797 }
798 } else {
799 msg = "missing parameter name"
800 }
801 }
802 p.syntaxErrorAt(errPos, msg)
803 }
804 }
805
806 // check use of ... - DISABLED for gen1 debugging
807
808 return
809 }
810
811 func (p *Parser) badExpr() (b *BadExpr) {
812 b := (*BadExpr)(p.nodeAlloc(unsafe.Sizeof(BadExpr{})))
813 b.pos = p.pos()
814 return b
815 }
816