1
2
3
4
5
6
7
8
9
10
11
12
13 package resolve
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 import (
85 "fmt"
86 "log"
87 "sort"
88 "strings"
89
90 "go.starlark.net/internal/spell"
91 "go.starlark.net/syntax"
92 )
93
94 const debug = false
95 const doesnt = "this Starlark dialect does not "
96
97
98
99
100 var (
101 AllowSet = false
102 AllowGlobalReassign = false
103 AllowRecursion = false
104 LoadBindsGlobally = false
105
106
107 AllowNestedDef = true
108 AllowLambda = true
109 AllowFloat = true
110 AllowBitwise = true
111 )
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 func File(file *syntax.File, isPredeclared, isUniversal func(name string) bool) error {
127 return REPLChunk(file, nil, isPredeclared, isUniversal)
128 }
129
130
131
132 func REPLChunk(file *syntax.File, isGlobal, isPredeclared, isUniversal func(name string) bool) error {
133 r := newResolver(isGlobal, isPredeclared, isUniversal)
134 r.stmts(file.Stmts)
135
136 r.env.resolveLocalUses()
137
138
139
140
141 r.resolveNonLocalUses(r.env)
142
143 file.Module = &Module{
144 Locals: r.moduleLocals,
145 Globals: r.moduleGlobals,
146 }
147
148 if len(r.errors) > 0 {
149 return r.errors
150 }
151 return nil
152 }
153
154
155
156
157
158 func Expr(expr syntax.Expr, isPredeclared, isUniversal func(name string) bool) ([]*Binding, error) {
159 r := newResolver(nil, isPredeclared, isUniversal)
160 r.expr(expr)
161 r.env.resolveLocalUses()
162 r.resolveNonLocalUses(r.env)
163 if len(r.errors) > 0 {
164 return nil, r.errors
165 }
166 return r.moduleLocals, nil
167 }
168
169
170 type ErrorList []Error
171
172 func (e ErrorList) Error() string { return e[0].Error() }
173
174
175 type Error struct {
176 Pos syntax.Position
177 Msg string
178 }
179
180 func (e Error) Error() string { return e.Pos.String() + ": " + e.Msg }
181
182 func newResolver(isGlobal, isPredeclared, isUniversal func(name string) bool) *resolver {
183 file := new(block)
184 return &resolver{
185 file: file,
186 env: file,
187 isGlobal: isGlobal,
188 isPredeclared: isPredeclared,
189 isUniversal: isUniversal,
190 globals: make(map[string]*Binding),
191 predeclared: make(map[string]*Binding),
192 }
193 }
194
195 type resolver struct {
196
197
198
199 env *block
200 file *block
201
202
203
204
205 moduleLocals []*Binding
206 moduleGlobals []*Binding
207
208
209
210 globals map[string]*Binding
211 predeclared map[string]*Binding
212
213
214
215
216
217 isGlobal, isPredeclared, isUniversal func(name string) bool
218
219 loops int
220 ifstmts int
221
222 errors ErrorList
223 }
224
225
226
227
228 func (r *resolver) container() *block {
229 for b := r.env; ; b = b.parent {
230 if b.function != nil || b == r.file {
231 return b
232 }
233 }
234 }
235
236 func (r *resolver) push(b *block) {
237 r.env.children = append(r.env.children, b)
238 b.parent = r.env
239 r.env = b
240 }
241
242 func (r *resolver) pop() { r.env = r.env.parent }
243
244 type block struct {
245 parent *block
246
247
248 function *Function
249 comp *syntax.Comprehension
250
251
252
253
254 bindings map[string]*Binding
255
256
257 children []*block
258
259
260
261
262
263
264 uses []use
265 }
266
267 func (b *block) bind(name string, bind *Binding) {
268 if b.bindings == nil {
269 b.bindings = make(map[string]*Binding)
270 }
271 b.bindings[name] = bind
272 }
273
274 func (b *block) String() string {
275 if b.function != nil {
276 return "function block at " + fmt.Sprint(b.function.Pos)
277 }
278 if b.comp != nil {
279 return "comprehension block at " + fmt.Sprint(b.comp.Span())
280 }
281 return "file block"
282 }
283
284 func (r *resolver) errorf(posn syntax.Position, format string, args ...interface{}) {
285 r.errors = append(r.errors, Error{posn, fmt.Sprintf(format, args...)})
286 }
287
288
289 type use struct {
290 id *syntax.Ident
291 env *block
292 }
293
294
295
296
297
298
299
300 func (r *resolver) bind(id *syntax.Ident) bool {
301
302 if r.env == r.file {
303 bind, ok := r.file.bindings[id.Name]
304 if !ok {
305 bind, ok = r.globals[id.Name]
306 if !ok {
307
308 bind = &Binding{
309 First: id,
310 Scope: Global,
311 Index: len(r.moduleGlobals),
312 }
313 r.globals[id.Name] = bind
314 r.moduleGlobals = append(r.moduleGlobals, bind)
315 }
316 }
317 if ok && !AllowGlobalReassign {
318 r.errorf(id.NamePos, "cannot reassign %s %s declared at %s",
319 bind.Scope, id.Name, bind.First.NamePos)
320 }
321 id.Binding = bind
322 return ok
323 }
324
325 return r.bindLocal(id)
326 }
327
328 func (r *resolver) bindLocal(id *syntax.Ident) bool {
329
330
331 _, ok := r.env.bindings[id.Name]
332 if !ok {
333 var locals *[]*Binding
334 if fn := r.container().function; fn != nil {
335 locals = &fn.Locals
336 } else {
337 locals = &r.moduleLocals
338 }
339 bind := &Binding{
340 First: id,
341 Scope: Local,
342 Index: len(*locals),
343 }
344 r.env.bind(id.Name, bind)
345 *locals = append(*locals, bind)
346 }
347
348 r.use(id)
349 return ok
350 }
351
352 func (r *resolver) use(id *syntax.Ident) {
353 use := use{id, r.env}
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385 if AllowGlobalReassign && r.env == r.file {
386 r.useToplevel(use)
387 return
388 }
389
390 b := r.container()
391 b.uses = append(b.uses, use)
392 }
393
394
395
396 func (r *resolver) useToplevel(use use) (bind *Binding) {
397 id := use.id
398
399 if prev, ok := r.file.bindings[id.Name]; ok {
400
401 bind = prev
402 } else if prev, ok := r.globals[id.Name]; ok {
403
404 bind = prev
405 } else if r.isGlobal != nil && r.isGlobal(id.Name) {
406
407 bind = &Binding{
408 First: id,
409 Scope: Global,
410 Index: len(r.moduleGlobals),
411 }
412 r.globals[id.Name] = bind
413 r.moduleGlobals = append(r.moduleGlobals, bind)
414 } else if prev, ok := r.predeclared[id.Name]; ok {
415
416 bind = prev
417 } else if r.isPredeclared(id.Name) {
418
419 bind = &Binding{Scope: Predeclared}
420 r.predeclared[id.Name] = bind
421 } else if r.isUniversal(id.Name) {
422
423 if !AllowSet && id.Name == "set" {
424 r.errorf(id.NamePos, doesnt+"support sets")
425 }
426 bind = &Binding{Scope: Universal}
427 r.predeclared[id.Name] = bind
428 } else {
429 bind = &Binding{Scope: Undefined}
430 var hint string
431 if n := r.spellcheck(use); n != "" {
432 hint = fmt.Sprintf(" (did you mean %s?)", n)
433 }
434 r.errorf(id.NamePos, "undefined: %s%s", id.Name, hint)
435 }
436 id.Binding = bind
437 return bind
438 }
439
440
441
442 func (r *resolver) spellcheck(use use) string {
443 var names []string
444
445
446 for b := use.env; b != nil; b = b.parent {
447 for name := range b.bindings {
448 names = append(names, name)
449 }
450 }
451
452
453
454
455
456
457 for _, bind := range r.moduleGlobals {
458 names = append(names, bind.First.Name)
459 }
460
461 sort.Strings(names)
462 return spell.Nearest(use.id.Name, names)
463 }
464
465
466
467 func (b *block) resolveLocalUses() {
468 unresolved := b.uses[:0]
469 for _, use := range b.uses {
470 if bind := lookupLocal(use); bind != nil && (bind.Scope == Local || bind.Scope == Cell) {
471 use.id.Binding = bind
472 } else {
473 unresolved = append(unresolved, use)
474 }
475 }
476 b.uses = unresolved
477 }
478
479 func (r *resolver) stmts(stmts []syntax.Stmt) {
480 for _, stmt := range stmts {
481 r.stmt(stmt)
482 }
483 }
484
485 func (r *resolver) stmt(stmt syntax.Stmt) {
486 switch stmt := stmt.(type) {
487 case *syntax.ExprStmt:
488 r.expr(stmt.X)
489
490 case *syntax.BranchStmt:
491 if r.loops == 0 && (stmt.Token == syntax.BREAK || stmt.Token == syntax.CONTINUE) {
492 r.errorf(stmt.TokenPos, "%s not in a loop", stmt.Token)
493 }
494
495 case *syntax.IfStmt:
496 if !AllowGlobalReassign && r.container().function == nil {
497 r.errorf(stmt.If, "if statement not within a function")
498 }
499 r.expr(stmt.Cond)
500 r.ifstmts++
501 r.stmts(stmt.True)
502 r.stmts(stmt.False)
503 r.ifstmts--
504
505 case *syntax.AssignStmt:
506 r.expr(stmt.RHS)
507 isAugmented := stmt.Op != syntax.EQ
508 r.assign(stmt.LHS, isAugmented)
509
510 case *syntax.DefStmt:
511 r.bind(stmt.Name)
512 fn := &Function{
513 Name: stmt.Name.Name,
514 Pos: stmt.Def,
515 Params: stmt.Params,
516 Body: stmt.Body,
517 }
518 stmt.Function = fn
519 r.function(fn, stmt.Def)
520
521 case *syntax.ForStmt:
522 if !AllowGlobalReassign && r.container().function == nil {
523 r.errorf(stmt.For, "for loop not within a function")
524 }
525 r.expr(stmt.X)
526 const isAugmented = false
527 r.assign(stmt.Vars, isAugmented)
528 r.loops++
529 r.stmts(stmt.Body)
530 r.loops--
531
532 case *syntax.WhileStmt:
533 if !AllowRecursion {
534 r.errorf(stmt.While, doesnt+"support while loops")
535 }
536 if !AllowGlobalReassign && r.container().function == nil {
537 r.errorf(stmt.While, "while loop not within a function")
538 }
539 r.expr(stmt.Cond)
540 r.loops++
541 r.stmts(stmt.Body)
542 r.loops--
543
544 case *syntax.ReturnStmt:
545 if r.container().function == nil {
546 r.errorf(stmt.Return, "return statement not within a function")
547 }
548 if stmt.Result != nil {
549 r.expr(stmt.Result)
550 }
551
552 case *syntax.LoadStmt:
553
554 if r.container().function != nil {
555 r.errorf(stmt.Load, "load statement within a function")
556 } else if r.loops > 0 {
557 r.errorf(stmt.Load, "load statement within a loop")
558 } else if r.ifstmts > 0 {
559 r.errorf(stmt.Load, "load statement within a conditional")
560 }
561
562 for i, from := range stmt.From {
563 if from.Name == "" {
564 r.errorf(from.NamePos, "load: empty identifier")
565 continue
566 }
567 if from.Name[0] == '_' {
568 r.errorf(from.NamePos, "load: names with leading underscores are not exported: %s", from.Name)
569 }
570
571 id := stmt.To[i]
572 if LoadBindsGlobally {
573 r.bind(id)
574 } else if r.bindLocal(id) && !AllowGlobalReassign {
575
576
577
578 r.errorf(id.NamePos, "cannot reassign top-level %s", id.Name)
579 }
580 }
581
582 default:
583 log.Panicf("unexpected stmt %T", stmt)
584 }
585 }
586
587 func (r *resolver) assign(lhs syntax.Expr, isAugmented bool) {
588 switch lhs := lhs.(type) {
589 case *syntax.Ident:
590
591 r.bind(lhs)
592
593 case *syntax.IndexExpr:
594
595 r.expr(lhs.X)
596 r.expr(lhs.Y)
597
598 case *syntax.DotExpr:
599
600 r.expr(lhs.X)
601
602 case *syntax.TupleExpr:
603
604 if isAugmented {
605 r.errorf(syntax.Start(lhs), "can't use tuple expression in augmented assignment")
606 }
607 for _, elem := range lhs.List {
608 r.assign(elem, isAugmented)
609 }
610
611 case *syntax.ListExpr:
612
613 if isAugmented {
614 r.errorf(syntax.Start(lhs), "can't use list expression in augmented assignment")
615 }
616 for _, elem := range lhs.List {
617 r.assign(elem, isAugmented)
618 }
619
620 case *syntax.ParenExpr:
621 r.assign(lhs.X, isAugmented)
622
623 default:
624 name := strings.ToLower(strings.TrimPrefix(fmt.Sprintf("%T", lhs), "*syntax."))
625 r.errorf(syntax.Start(lhs), "can't assign to %s", name)
626 }
627 }
628
629 func (r *resolver) expr(e syntax.Expr) {
630 switch e := e.(type) {
631 case *syntax.Ident:
632 r.use(e)
633
634 case *syntax.Literal:
635
636 case *syntax.ListExpr:
637 for _, x := range e.List {
638 r.expr(x)
639 }
640
641 case *syntax.CondExpr:
642 r.expr(e.Cond)
643 r.expr(e.True)
644 r.expr(e.False)
645
646 case *syntax.IndexExpr:
647 r.expr(e.X)
648 r.expr(e.Y)
649
650 case *syntax.DictEntry:
651 r.expr(e.Key)
652 r.expr(e.Value)
653
654 case *syntax.SliceExpr:
655 r.expr(e.X)
656 if e.Lo != nil {
657 r.expr(e.Lo)
658 }
659 if e.Hi != nil {
660 r.expr(e.Hi)
661 }
662 if e.Step != nil {
663 r.expr(e.Step)
664 }
665
666 case *syntax.Comprehension:
667
668
669 clause := e.Clauses[0].(*syntax.ForClause)
670 r.expr(clause.X)
671
672
673
674
675
676 r.push(&block{comp: e})
677
678 const isAugmented = false
679 r.assign(clause.Vars, isAugmented)
680
681 for _, clause := range e.Clauses[1:] {
682 switch clause := clause.(type) {
683 case *syntax.IfClause:
684 r.expr(clause.Cond)
685 case *syntax.ForClause:
686 r.assign(clause.Vars, isAugmented)
687 r.expr(clause.X)
688 }
689 }
690 r.expr(e.Body)
691 r.pop()
692
693 case *syntax.TupleExpr:
694 for _, x := range e.List {
695 r.expr(x)
696 }
697
698 case *syntax.DictExpr:
699 for _, entry := range e.List {
700 entry := entry.(*syntax.DictEntry)
701 r.expr(entry.Key)
702 r.expr(entry.Value)
703 }
704
705 case *syntax.UnaryExpr:
706 r.expr(e.X)
707
708 case *syntax.BinaryExpr:
709 r.expr(e.X)
710 r.expr(e.Y)
711
712 case *syntax.DotExpr:
713 r.expr(e.X)
714
715
716 case *syntax.CallExpr:
717 r.expr(e.Fn)
718 var seenVarargs, seenKwargs bool
719 var seenName map[string]bool
720 var n, p int
721 for _, arg := range e.Args {
722 pos, _ := arg.Span()
723 if unop, ok := arg.(*syntax.UnaryExpr); ok && unop.Op == syntax.STARSTAR {
724
725 if seenKwargs {
726 r.errorf(pos, "multiple **kwargs not allowed")
727 }
728 seenKwargs = true
729 r.expr(arg)
730 } else if ok && unop.Op == syntax.STAR {
731
732 if seenKwargs {
733 r.errorf(pos, "*args may not follow **kwargs")
734 } else if seenVarargs {
735 r.errorf(pos, "multiple *args not allowed")
736 }
737 seenVarargs = true
738 r.expr(arg)
739 } else if binop, ok := arg.(*syntax.BinaryExpr); ok && binop.Op == syntax.EQ {
740
741 n++
742 if seenKwargs {
743 r.errorf(pos, "keyword argument may not follow **kwargs")
744 } else if seenVarargs {
745 r.errorf(pos, "keyword argument may not follow *args")
746 }
747 x := binop.X.(*syntax.Ident)
748 if seenName[x.Name] {
749 r.errorf(x.NamePos, "keyword argument %q is repeated", x.Name)
750 } else {
751 if seenName == nil {
752 seenName = make(map[string]bool)
753 }
754 seenName[x.Name] = true
755 }
756 r.expr(binop.Y)
757 } else {
758
759 p++
760 if seenVarargs {
761 r.errorf(pos, "positional argument may not follow *args")
762 } else if seenKwargs {
763 r.errorf(pos, "positional argument may not follow **kwargs")
764 } else if len(seenName) > 0 {
765 r.errorf(pos, "positional argument may not follow named")
766 }
767 r.expr(arg)
768 }
769 }
770
771
772 if p >= 256 {
773 pos, _ := e.Span()
774 r.errorf(pos, "%v positional arguments in call, limit is 255", p)
775 }
776 if n >= 256 {
777 pos, _ := e.Span()
778 r.errorf(pos, "%v keyword arguments in call, limit is 255", n)
779 }
780
781 case *syntax.LambdaExpr:
782 fn := &Function{
783 Name: "lambda",
784 Pos: e.Lambda,
785 Params: e.Params,
786 Body: []syntax.Stmt{&syntax.ReturnStmt{Result: e.Body}},
787 }
788 e.Function = fn
789 r.function(fn, e.Lambda)
790
791 case *syntax.ParenExpr:
792 r.expr(e.X)
793
794 default:
795 log.Panicf("unexpected expr %T", e)
796 }
797 }
798
799 func (r *resolver) function(function *Function, pos syntax.Position) {
800
801 for _, param := range function.Params {
802 if binary, ok := param.(*syntax.BinaryExpr); ok {
803 r.expr(binary.Y)
804 }
805 }
806
807
808 b := &block{function: function}
809 r.push(b)
810
811 var seenOptional bool
812 var star *syntax.UnaryExpr
813 var starStar *syntax.Ident
814 var numKwonlyParams int
815 for _, param := range function.Params {
816 switch param := param.(type) {
817 case *syntax.Ident:
818
819 if starStar != nil {
820 r.errorf(param.NamePos, "required parameter may not follow **%s", starStar.Name)
821 } else if star != nil {
822 numKwonlyParams++
823 } else if seenOptional {
824 r.errorf(param.NamePos, "required parameter may not follow optional")
825 }
826 if r.bind(param) {
827 r.errorf(param.NamePos, "duplicate parameter: %s", param.Name)
828 }
829
830 case *syntax.BinaryExpr:
831
832 if starStar != nil {
833 r.errorf(param.OpPos, "optional parameter may not follow **%s", starStar.Name)
834 } else if star != nil {
835 numKwonlyParams++
836 }
837 if id := param.X.(*syntax.Ident); r.bind(id) {
838 r.errorf(param.OpPos, "duplicate parameter: %s", id.Name)
839 }
840 seenOptional = true
841
842 case *syntax.UnaryExpr:
843
844 if param.Op == syntax.STAR {
845 if starStar != nil {
846 r.errorf(param.OpPos, "* parameter may not follow **%s", starStar.Name)
847 } else if star != nil {
848 r.errorf(param.OpPos, "multiple * parameters not allowed")
849 } else {
850 star = param
851 }
852 } else {
853 if starStar != nil {
854 r.errorf(param.OpPos, "multiple ** parameters not allowed")
855 }
856 starStar = param.X.(*syntax.Ident)
857 }
858 }
859 }
860
861
862
863
864
865
866 if star != nil {
867 if id, _ := star.X.(*syntax.Ident); id != nil {
868
869 if r.bind(id) {
870 r.errorf(id.NamePos, "duplicate parameter: %s", id.Name)
871 }
872 function.HasVarargs = true
873 } else if numKwonlyParams == 0 {
874 r.errorf(star.OpPos, "bare * must be followed by keyword-only parameters")
875 }
876 }
877 if starStar != nil {
878 if r.bind(starStar) {
879 r.errorf(starStar.NamePos, "duplicate parameter: %s", starStar.Name)
880 }
881 function.HasKwargs = true
882 }
883
884 function.NumKwonlyParams = numKwonlyParams
885 r.stmts(function.Body)
886
887
888
889 b.resolveLocalUses()
890
891
892 r.pop()
893
894
895
896 }
897
898 func (r *resolver) resolveNonLocalUses(b *block) {
899
900 for _, child := range b.children {
901 r.resolveNonLocalUses(child)
902 }
903 for _, use := range b.uses {
904 use.id.Binding = r.lookupLexical(use, use.env)
905 }
906 }
907
908
909 func lookupLocal(use use) *Binding {
910 for env := use.env; env != nil; env = env.parent {
911 if bind, ok := env.bindings[use.id.Name]; ok {
912 if bind.Scope == Free {
913
914 log.Panicf("%s: internal error: %s, %v", use.id.NamePos, use.id.Name, bind)
915 }
916 return bind
917 }
918 if env.function != nil {
919 break
920 }
921 }
922 return nil
923 }
924
925
926
927 func (r *resolver) lookupLexical(use use, env *block) (bind *Binding) {
928 if debug {
929 fmt.Printf("lookupLexical %s in %s = ...\n", use.id.Name, env)
930 defer func() { fmt.Printf("= %v\n", bind) }()
931 }
932
933
934 if env == r.file {
935 return r.useToplevel(use)
936 }
937
938
939 bind, ok := env.bindings[use.id.Name]
940 if !ok {
941
942 bind = r.lookupLexical(use, env.parent)
943 if env.function != nil && (bind.Scope == Local || bind.Scope == Free || bind.Scope == Cell) {
944
945
946
947
948 if bind.Scope == Local {
949 bind.Scope = Cell
950 }
951 index := len(env.function.FreeVars)
952 env.function.FreeVars = append(env.function.FreeVars, bind)
953 bind = &Binding{
954 First: bind.First,
955 Scope: Free,
956 Index: index,
957 }
958 if debug {
959 fmt.Printf("creating freevar %v in function at %s: %s\n",
960 len(env.function.FreeVars), env.function.Pos, use.id.Name)
961 }
962 }
963
964
965
966 env.bind(use.id.Name, bind)
967 }
968 return bind
969 }
970
View as plain text