OLD | NEW |
| (Empty) |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library fasta.scope; | |
6 | |
7 import 'builder.dart' show Builder, MixedAccessor; | |
8 | |
9 import '../errors.dart' show internalError; | |
10 | |
11 class Scope { | |
12 /// Names declared in this scope. | |
13 final Map<String, Builder> local; | |
14 | |
15 /// The scope that this scope is nested within, or `null` if this is the top | |
16 /// level scope. | |
17 final Scope parent; | |
18 | |
19 /// Indicates whether an attempt to declare new names in this scope should | |
20 /// succeed. | |
21 final bool isModifiable; | |
22 | |
23 Map<String, Builder> labels; | |
24 | |
25 Map<String, Builder> forwardDeclaredLabels; | |
26 | |
27 Scope(this.local, this.parent, {this.isModifiable: true}); | |
28 | |
29 Scope createNestedScope({bool isModifiable: true}) { | |
30 return new Scope(<String, Builder>{}, this, isModifiable: isModifiable); | |
31 } | |
32 | |
33 Builder lookup(String name, int charOffset, Uri fileUri) { | |
34 Builder builder = local[name]; | |
35 if (builder != null) { | |
36 if (builder.next != null) { | |
37 return lookupAmbiguous(name, builder, false, charOffset, fileUri); | |
38 } | |
39 return builder.isSetter | |
40 ? new AccessErrorBuilder(name, builder, charOffset, fileUri) | |
41 : builder; | |
42 } else { | |
43 return parent?.lookup(name, charOffset, fileUri); | |
44 } | |
45 } | |
46 | |
47 Builder lookupSetter(String name, int charOffset, Uri fileUri) { | |
48 Builder builder = local[name]; | |
49 if (builder != null) { | |
50 if (builder.next != null) { | |
51 return lookupAmbiguous(name, builder, true, charOffset, fileUri); | |
52 } | |
53 if (builder.isField) { | |
54 if (builder.isFinal) { | |
55 return new AccessErrorBuilder(name, builder, charOffset, fileUri); | |
56 } else { | |
57 return builder; | |
58 } | |
59 } else if (builder.isSetter) { | |
60 return builder; | |
61 } else { | |
62 return new AccessErrorBuilder(name, builder, charOffset, fileUri); | |
63 } | |
64 } else { | |
65 return parent?.lookupSetter(name, charOffset, fileUri); | |
66 } | |
67 } | |
68 | |
69 Builder lookupAmbiguous( | |
70 String name, Builder builder, bool setter, int charOffset, Uri fileUri) { | |
71 assert(builder.next != null); | |
72 if (builder is MixedAccessor) { | |
73 return setter ? builder.setter : builder.getter; | |
74 } | |
75 Builder setterBuilder; | |
76 Builder getterBuilder; | |
77 Builder current = builder; | |
78 while (current != null) { | |
79 if (current.isGetter && getterBuilder == null) { | |
80 getterBuilder = current; | |
81 } else if (current.isSetter && setterBuilder == null) { | |
82 setterBuilder = current; | |
83 } else { | |
84 return new AmbiguousBuilder(name, builder, charOffset, fileUri); | |
85 } | |
86 current = current.next; | |
87 } | |
88 assert(getterBuilder != null); | |
89 assert(setterBuilder != null); | |
90 return setter ? setterBuilder : getterBuilder; | |
91 } | |
92 | |
93 bool hasLocalLabel(String name) => labels != null && labels.containsKey(name); | |
94 | |
95 void declareLabel(String name, Builder target) { | |
96 if (isModifiable) { | |
97 labels ??= <String, Builder>{}; | |
98 labels[name] = target; | |
99 } else { | |
100 internalError("Can't extend an unmodifiable scope."); | |
101 } | |
102 } | |
103 | |
104 void forwardDeclareLabel(String name, Builder target) { | |
105 declareLabel(name, target); | |
106 forwardDeclaredLabels ??= <String, Builder>{}; | |
107 forwardDeclaredLabels[name] = target; | |
108 } | |
109 | |
110 void claimLabel(String name) { | |
111 if (forwardDeclaredLabels == null) return; | |
112 forwardDeclaredLabels.remove(name); | |
113 if (forwardDeclaredLabels.length == 0) { | |
114 forwardDeclaredLabels = null; | |
115 } | |
116 } | |
117 | |
118 Map<String, Builder> get unclaimedForwardDeclarations { | |
119 return forwardDeclaredLabels; | |
120 } | |
121 | |
122 Builder lookupLabel(String name) { | |
123 return (labels == null ? null : labels[name]) ?? parent?.lookupLabel(name); | |
124 } | |
125 | |
126 // TODO(ahe): Rename to extend or something. | |
127 void operator []=(String name, Builder member) { | |
128 if (isModifiable) { | |
129 local[name] = member; | |
130 } else { | |
131 internalError("Can't extend an unmodifiable scope."); | |
132 } | |
133 } | |
134 } | |
135 | |
136 abstract class ProblemBuilder extends Builder { | |
137 final String name; | |
138 | |
139 final Builder builder; | |
140 | |
141 ProblemBuilder(this.name, this.builder, int charOffset, Uri fileUri) | |
142 : super(null, charOffset, fileUri); | |
143 | |
144 get target => null; | |
145 | |
146 bool get hasProblem => true; | |
147 | |
148 String get message; | |
149 | |
150 @override | |
151 String get fullNameForErrors => name; | |
152 } | |
153 | |
154 /// Represents a [builder] that's being accessed incorrectly. For example, an | |
155 /// attempt to write to a final field, or to read from a setter. | |
156 class AccessErrorBuilder extends ProblemBuilder { | |
157 AccessErrorBuilder(String name, Builder builder, int charOffset, Uri fileUri) | |
158 : super(name, builder, charOffset, fileUri); | |
159 | |
160 Builder get parent => builder; | |
161 | |
162 bool get isFinal => builder.isFinal; | |
163 | |
164 bool get isField => builder.isField; | |
165 | |
166 bool get isRegularMethod => builder.isRegularMethod; | |
167 | |
168 bool get isGetter => !builder.isGetter; | |
169 | |
170 bool get isSetter => !builder.isSetter; | |
171 | |
172 bool get isInstanceMember => builder.isInstanceMember; | |
173 | |
174 bool get isStatic => builder.isStatic; | |
175 | |
176 bool get isTopLevel => builder.isTopLevel; | |
177 | |
178 bool get isTypeDeclaration => builder.isTypeDeclaration; | |
179 | |
180 bool get isLocal => builder.isLocal; | |
181 | |
182 String get message => "Access error: '$name'."; | |
183 } | |
184 | |
185 class AmbiguousBuilder extends ProblemBuilder { | |
186 AmbiguousBuilder(String name, Builder builder, int charOffset, Uri fileUri) | |
187 : super(name, builder, charOffset, fileUri); | |
188 | |
189 String get message => "Duplicated named: '$name'."; | |
190 } | |
OLD | NEW |