sflkit 0.5.2__tar.gz → 0.5.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sflkit-0.5.2/src/sflkit.egg-info → sflkit-0.5.4}/PKG-INFO +1 -1
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/__init__.py +1 -1
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/factory.py +80 -40
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/features/vector.py +1 -1
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/meta.py +5 -2
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/model/parallel.py +6 -4
- sflkit-0.5.4/src/sflkit/model/scope.py +82 -0
- {sflkit-0.5.2 → sflkit-0.5.4/src/sflkit.egg-info}/PKG-INFO +1 -1
- sflkit-0.5.4/tests/test_scope.py +43 -0
- sflkit-0.5.2/src/sflkit/model/scope.py +0 -39
- sflkit-0.5.2/tests/test_scope.py +0 -20
- {sflkit-0.5.2 → sflkit-0.5.4}/LICENSE +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/README.md +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/pyproject.toml +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/setup.cfg +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/__init__.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/analysis_type.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/analyzer.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/mapping.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/predicate.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/similarity.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/spectra.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/suggestion.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/cli.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/color.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/config.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/evaluation.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/events/__init__.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/events/event_file.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/events/mapping.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/features/__init__.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/features/handler.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/features/value.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/instrumentation/__init__.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/instrumentation/dir_instrumentation.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/instrumentation/file_instrumentation.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/__init__.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/extract.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/finder.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/java/__init__.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/java/extract.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/java/factory.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/java/finder.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/java/visitor.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/language.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/python/__init__.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/python/extract.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/python/factory.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/python/finder.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/python/visitor.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/visitor.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/logger.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/model/__init__.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/model/model.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/runners/__init__.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/runners/run.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/weights/__init__.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/weights/analyzer.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/weights/models.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit.egg-info/SOURCES.txt +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit.egg-info/dependency_links.txt +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit.egg-info/entry_points.txt +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit.egg-info/requires.txt +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit.egg-info/top_level.txt +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_analysis_objects.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_analyzer.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_cli.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_color.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_config.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_coverage.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_dependency_weights.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_evaluation.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_events.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_execution.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_features.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_instrumentation.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_language.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_parallelization.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_predicates.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_runner.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_runner_parallel.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_runner_pytest_versions.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_spectra.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_suggestions.py +0 -0
- {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_visitors.py +0 -0
|
@@ -85,7 +85,7 @@ class LineFactory(AnalysisFactory):
|
|
|
85
85
|
if key not in self.objects:
|
|
86
86
|
self.objects[key] = Line(event)
|
|
87
87
|
return [self.objects[key]]
|
|
88
|
-
return
|
|
88
|
+
return []
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
class BranchFactory(AnalysisFactory):
|
|
@@ -117,7 +117,7 @@ class BranchFactory(AnalysisFactory):
|
|
|
117
117
|
return [self.objects[key], self.objects[else_key]]
|
|
118
118
|
return [self.objects[key]]
|
|
119
119
|
|
|
120
|
-
return
|
|
120
|
+
return []
|
|
121
121
|
|
|
122
122
|
|
|
123
123
|
class FunctionFactory(AnalysisFactory):
|
|
@@ -130,7 +130,7 @@ class FunctionFactory(AnalysisFactory):
|
|
|
130
130
|
if key not in self.objects:
|
|
131
131
|
self.objects[key] = Function(event)
|
|
132
132
|
return [self.objects[key]]
|
|
133
|
-
return
|
|
133
|
+
return []
|
|
134
134
|
|
|
135
135
|
|
|
136
136
|
class LoopFactory(AnalysisFactory):
|
|
@@ -170,27 +170,70 @@ class LoopFactory(AnalysisFactory):
|
|
|
170
170
|
elif event.event_type == EventType.LOOP_END:
|
|
171
171
|
return self.objects[key][:]
|
|
172
172
|
return list()
|
|
173
|
-
return
|
|
173
|
+
return []
|
|
174
174
|
|
|
175
175
|
|
|
176
176
|
class DefUseFactory(AnalysisFactory):
|
|
177
177
|
def __init__(self):
|
|
178
178
|
super().__init__()
|
|
179
179
|
self.id_to_def: dict[EventFile, dict[tuple[str, int], DefEvent]] = dict()
|
|
180
|
+
self.def_stack: dict[EventFile, dict[int, dict[tuple[str, int], DefEvent]]] = (
|
|
181
|
+
dict()
|
|
182
|
+
)
|
|
180
183
|
|
|
181
184
|
def reset(self, event_file: EventFile):
|
|
182
|
-
|
|
183
|
-
self.id_to_def[event_file]
|
|
185
|
+
if event_file in self.id_to_def:
|
|
186
|
+
del self.id_to_def[event_file]
|
|
187
|
+
if event_file in self.def_stack:
|
|
188
|
+
del self.def_stack[event_file]
|
|
189
|
+
|
|
190
|
+
def _find_def_event(
|
|
191
|
+
self,
|
|
192
|
+
event_file: EventFile,
|
|
193
|
+
scope_id: int,
|
|
194
|
+
var_name: str,
|
|
195
|
+
var_id: int,
|
|
196
|
+
) -> DefEvent:
|
|
197
|
+
# Strategy 1: Check in scope
|
|
198
|
+
def_event = None
|
|
199
|
+
if event_file in self.def_stack and scope_id in self.def_stack[event_file]:
|
|
200
|
+
def_event = self.def_stack[event_file][scope_id].get(
|
|
201
|
+
(var_name, var_id), None
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
# Strategy 2: Look up in the global DEF stack (other threads)
|
|
205
|
+
if def_event is None:
|
|
206
|
+
if event_file in self.id_to_def:
|
|
207
|
+
def_event = self.id_to_def[event_file].get((var_name, var_id), None)
|
|
208
|
+
|
|
209
|
+
return def_event
|
|
184
210
|
|
|
185
211
|
def get_analysis(
|
|
186
212
|
self, event, event_file: EventFile, scope: Scope = None
|
|
187
213
|
) -> List[AnalysisObject]:
|
|
214
|
+
thread_id = event.thread_id
|
|
215
|
+
scope_id = scope.id if scope else 0
|
|
216
|
+
|
|
188
217
|
if event.event_type == EventType.DEF:
|
|
189
|
-
|
|
190
|
-
|
|
218
|
+
key = (event.var, event.var_id)
|
|
219
|
+
|
|
220
|
+
# Initialize structures if needed
|
|
221
|
+
if event_file not in self.id_to_def:
|
|
222
|
+
self.id_to_def[event_file] = dict()
|
|
223
|
+
if event_file not in self.def_stack:
|
|
224
|
+
self.def_stack[event_file] = dict()
|
|
225
|
+
if scope_id not in self.def_stack[event_file]:
|
|
226
|
+
self.def_stack[event_file][scope_id] = dict()
|
|
227
|
+
|
|
228
|
+
# Store the DEF event
|
|
229
|
+
self.id_to_def[event_file][key] = event
|
|
230
|
+
self.def_stack[event_file][scope_id][key] = event
|
|
231
|
+
|
|
191
232
|
elif event.event_type == EventType.USE:
|
|
192
|
-
|
|
193
|
-
|
|
233
|
+
def_event = self._find_def_event(
|
|
234
|
+
event_file, scope_id, event.var, event.var_id
|
|
235
|
+
)
|
|
236
|
+
|
|
194
237
|
if def_event:
|
|
195
238
|
key = (
|
|
196
239
|
DefUse.analysis_type(),
|
|
@@ -204,7 +247,7 @@ class DefUseFactory(AnalysisFactory):
|
|
|
204
247
|
if key not in self.objects:
|
|
205
248
|
self.objects[key] = DefUse(def_event, event)
|
|
206
249
|
return [self.objects[key]]
|
|
207
|
-
return
|
|
250
|
+
return []
|
|
208
251
|
|
|
209
252
|
|
|
210
253
|
class ConditionFactory(AnalysisFactory):
|
|
@@ -267,24 +310,23 @@ class ScalarPairFactory(ComparisonFactory):
|
|
|
267
310
|
for types in (["int", "float", "bool"], ["str"], ["bytes"]):
|
|
268
311
|
if event.type_ in types:
|
|
269
312
|
for variable in variables:
|
|
270
|
-
if variable.
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
objects.append(self.objects[key])
|
|
313
|
+
if variable.type_ in types:
|
|
314
|
+
for comp in self.comparators:
|
|
315
|
+
key = (
|
|
316
|
+
ScalarPair.analysis_type(),
|
|
317
|
+
event.file,
|
|
318
|
+
event.line,
|
|
319
|
+
event.var,
|
|
320
|
+
variable.var,
|
|
321
|
+
comp,
|
|
322
|
+
types[0],
|
|
323
|
+
)
|
|
324
|
+
with self._lock:
|
|
325
|
+
if key not in self.objects:
|
|
326
|
+
self.objects[key] = ScalarPair(
|
|
327
|
+
event, comp, variable.var
|
|
328
|
+
)
|
|
329
|
+
objects.append(self.objects[key])
|
|
288
330
|
else:
|
|
289
331
|
for variable in variables:
|
|
290
332
|
if variable.type_ == event.type_:
|
|
@@ -306,7 +348,7 @@ class ScalarPairFactory(ComparisonFactory):
|
|
|
306
348
|
)
|
|
307
349
|
objects.append(self.objects[key])
|
|
308
350
|
return objects
|
|
309
|
-
return
|
|
351
|
+
return []
|
|
310
352
|
|
|
311
353
|
|
|
312
354
|
class VariableFactory(ComparisonFactory):
|
|
@@ -333,7 +375,7 @@ class VariableFactory(ComparisonFactory):
|
|
|
333
375
|
self.objects[key] = VariablePredicate(event, comp)
|
|
334
376
|
objects.append(self.objects[key])
|
|
335
377
|
return objects
|
|
336
|
-
return
|
|
378
|
+
return []
|
|
337
379
|
|
|
338
380
|
|
|
339
381
|
class ReturnFactory(ComparisonFactory):
|
|
@@ -403,7 +445,7 @@ class ReturnFactory(ComparisonFactory):
|
|
|
403
445
|
)
|
|
404
446
|
objects.append(self.objects[key])
|
|
405
447
|
return objects
|
|
406
|
-
return
|
|
448
|
+
return []
|
|
407
449
|
|
|
408
450
|
|
|
409
451
|
class ConstantCompFactory(AnalysisFactory):
|
|
@@ -430,7 +472,7 @@ class ConstantCompFactory(AnalysisFactory):
|
|
|
430
472
|
self.objects[key] = self.class_(event)
|
|
431
473
|
objects.append(self.objects[key])
|
|
432
474
|
return objects
|
|
433
|
-
return
|
|
475
|
+
return []
|
|
434
476
|
|
|
435
477
|
|
|
436
478
|
class NoneFactory(ConstantCompFactory):
|
|
@@ -468,7 +510,7 @@ class PredicateFunctionFactory(AnalysisFactory):
|
|
|
468
510
|
# noinspection PyArgumentList
|
|
469
511
|
self.objects[key] = self.class_(event)
|
|
470
512
|
return [self.objects[key]]
|
|
471
|
-
return
|
|
513
|
+
return []
|
|
472
514
|
|
|
473
515
|
|
|
474
516
|
class IsAsciiFactory(PredicateFunctionFactory):
|
|
@@ -519,7 +561,7 @@ class LengthFactory(AnalysisFactory):
|
|
|
519
561
|
Length(event, Length.evaluate_length_more)
|
|
520
562
|
)
|
|
521
563
|
return self.objects[key][:]
|
|
522
|
-
return
|
|
564
|
+
return []
|
|
523
565
|
|
|
524
566
|
|
|
525
567
|
class FunctionErrorFactory(AnalysisFactory):
|
|
@@ -531,11 +573,9 @@ class FunctionErrorFactory(AnalysisFactory):
|
|
|
531
573
|
self, event, event_file: EventFile, scope: Scope = None
|
|
532
574
|
) -> List[AnalysisObject]:
|
|
533
575
|
if event.event_type == EventType.FUNCTION_ENTER:
|
|
534
|
-
|
|
535
|
-
self.function_mapping[event.function_id] = event.line
|
|
576
|
+
self.function_mapping[event.function_id] = event.line
|
|
536
577
|
if event.event_type in (EventType.FUNCTION_ERROR, EventType.FUNCTION_EXIT):
|
|
537
|
-
|
|
538
|
-
line = self.function_mapping.get(event.function_id, event.line)
|
|
578
|
+
line = self.function_mapping.get(event.function_id, event.line)
|
|
539
579
|
key = (
|
|
540
580
|
FunctionErrorPredicate.analysis_type(),
|
|
541
581
|
event.file,
|
|
@@ -548,7 +588,7 @@ class FunctionErrorFactory(AnalysisFactory):
|
|
|
548
588
|
event.file, line, event.function
|
|
549
589
|
)
|
|
550
590
|
return [self.objects[key]]
|
|
551
|
-
return
|
|
591
|
+
return []
|
|
552
592
|
|
|
553
593
|
|
|
554
594
|
analysis_factory_mapping = {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import random
|
|
2
2
|
from abc import ABC
|
|
3
|
+
from threading import Lock
|
|
3
4
|
from typing import List, Type, Any
|
|
4
5
|
|
|
5
6
|
from sflkitlib.events.event import Event
|
|
@@ -60,10 +61,12 @@ class Injection:
|
|
|
60
61
|
class IDGenerator:
|
|
61
62
|
def __init__(self):
|
|
62
63
|
self.current_id = 0
|
|
64
|
+
self.lock = Lock()
|
|
63
65
|
|
|
64
66
|
def get_next_id(self):
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
with self.lock:
|
|
68
|
+
id_ = self.current_id
|
|
69
|
+
self.current_id += 1
|
|
67
70
|
return id_
|
|
68
71
|
|
|
69
72
|
|
|
@@ -42,7 +42,7 @@ class ParallelModel(Model):
|
|
|
42
42
|
self.returns[event_file].add(
|
|
43
43
|
event.function, event.return_value, event.type_
|
|
44
44
|
)
|
|
45
|
-
self.handle_event(event, event_file, self.returns)
|
|
45
|
+
self.handle_event(event, event_file, self.returns[event_file])
|
|
46
46
|
else:
|
|
47
47
|
self.returns_map[event_file].setdefault(event.thread_id, Scope()).add(
|
|
48
48
|
event.function, event.return_value, event.type_
|
|
@@ -67,10 +67,10 @@ class ParallelModel(Model):
|
|
|
67
67
|
def handle_def_event(self, event: DefEvent, event_file: EventFile):
|
|
68
68
|
if event.thread_id is None:
|
|
69
69
|
self.variables[event_file].add(event.var, event.value, event.type_)
|
|
70
|
-
self.handle_event(event, event_file, self.variables)
|
|
70
|
+
self.handle_event(event, event_file, self.variables[event_file])
|
|
71
71
|
else:
|
|
72
72
|
self.variables_map[event_file].setdefault(
|
|
73
|
-
event.thread_id, self.variables
|
|
73
|
+
event.thread_id, self.variables[event_file]
|
|
74
74
|
).add(event.var, event.value, event.type_)
|
|
75
75
|
self.handle_event(
|
|
76
76
|
event, event_file, self.variables_map[event_file][event.thread_id]
|
|
@@ -83,7 +83,9 @@ class ParallelModel(Model):
|
|
|
83
83
|
self.handle_event(
|
|
84
84
|
event,
|
|
85
85
|
event_file,
|
|
86
|
-
self.variables_map[event_file].get(
|
|
86
|
+
self.variables_map[event_file].get(
|
|
87
|
+
event.thread_id, self.variables[event_file]
|
|
88
|
+
),
|
|
87
89
|
)
|
|
88
90
|
|
|
89
91
|
def enter_parallel_scope(self, thread_id: int, event_file: EventFile):
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from threading import Lock
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Var(object):
|
|
6
|
+
def __init__(self, var, value, type_, id_: int = None):
|
|
7
|
+
self.var = var
|
|
8
|
+
self.value = value
|
|
9
|
+
self.type_ = type_
|
|
10
|
+
self.id = id_ if id_ is not None else hash(self)
|
|
11
|
+
|
|
12
|
+
def __hash__(self):
|
|
13
|
+
return hash(self.var)
|
|
14
|
+
|
|
15
|
+
def __eq__(self, other):
|
|
16
|
+
return isinstance(other, Var) and self.var == other.var
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class IDGenerator:
|
|
20
|
+
def __init__(self):
|
|
21
|
+
self.current_id = 0
|
|
22
|
+
self.lock = Lock()
|
|
23
|
+
|
|
24
|
+
def get_next_id(self):
|
|
25
|
+
with self.lock:
|
|
26
|
+
self.current_id += 1
|
|
27
|
+
return self.current_id
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Scope(object):
|
|
31
|
+
|
|
32
|
+
SCOPE_ID = IDGenerator()
|
|
33
|
+
|
|
34
|
+
def __init__(self, parent=None):
|
|
35
|
+
self.parent = parent
|
|
36
|
+
self.variables = dict()
|
|
37
|
+
self.id = Scope.SCOPE_ID.get_next_id()
|
|
38
|
+
|
|
39
|
+
def __hash__(self):
|
|
40
|
+
return hash(self.id)
|
|
41
|
+
|
|
42
|
+
def __eq__(self, other):
|
|
43
|
+
return isinstance(other, Scope) and self.id == other.id
|
|
44
|
+
|
|
45
|
+
def enter(self):
|
|
46
|
+
return Scope(parent=self)
|
|
47
|
+
|
|
48
|
+
def exit(self):
|
|
49
|
+
if self.parent is not None:
|
|
50
|
+
return self.parent
|
|
51
|
+
else:
|
|
52
|
+
return self
|
|
53
|
+
|
|
54
|
+
def __contains__(self, var: str) -> bool:
|
|
55
|
+
current = self
|
|
56
|
+
while current is not None:
|
|
57
|
+
if var in current.variables:
|
|
58
|
+
return True
|
|
59
|
+
current = current.parent
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
def value(self, var: str) -> Var:
|
|
63
|
+
current = self
|
|
64
|
+
while current is not None:
|
|
65
|
+
if var in current.variables:
|
|
66
|
+
return current.variables[var].value
|
|
67
|
+
current = current.parent
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
def add(self, var, value, type_, id_: int = None):
|
|
71
|
+
self.variables[var] = Var(var, value, type_, id_)
|
|
72
|
+
|
|
73
|
+
def get_all_vars_dict(self):
|
|
74
|
+
current = self
|
|
75
|
+
variables = dict()
|
|
76
|
+
while current is not None:
|
|
77
|
+
variables = {**current.variables, **variables}
|
|
78
|
+
current = current.parent
|
|
79
|
+
return variables
|
|
80
|
+
|
|
81
|
+
def get_all_vars(self) -> List[Var]:
|
|
82
|
+
return list(self.get_all_vars_dict().values())
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from sflkit.model.scope import Var, Scope
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestScope(unittest.TestCase):
|
|
7
|
+
def test_var_eq(self):
|
|
8
|
+
var_1 = Var("x", 2, int)
|
|
9
|
+
var_2 = Var("y", 2, int)
|
|
10
|
+
var_3 = Var("x", "", str)
|
|
11
|
+
self.assertEqual(var_1, var_3)
|
|
12
|
+
self.assertNotEqual(var_1, var_2)
|
|
13
|
+
self.assertNotEqual(var_2, var_3)
|
|
14
|
+
self.assertEqual(hash(var_1), hash(var_3))
|
|
15
|
+
self.assertNotEqual(hash(var_1), hash(var_2))
|
|
16
|
+
self.assertNotEqual(hash(var_2), hash(var_3))
|
|
17
|
+
|
|
18
|
+
def test_scope_without_parent(self):
|
|
19
|
+
scope = Scope()
|
|
20
|
+
self.assertIs(scope, scope.exit())
|
|
21
|
+
|
|
22
|
+
def test_scope_with_parent(self):
|
|
23
|
+
parent_scope = Scope()
|
|
24
|
+
child_scope = parent_scope.enter()
|
|
25
|
+
self.assertIs(parent_scope, child_scope.exit())
|
|
26
|
+
|
|
27
|
+
def test_scope_contains(self):
|
|
28
|
+
scope = Scope()
|
|
29
|
+
scope.variables["x"] = Var("x", 10, int)
|
|
30
|
+
self.assertIn("x", scope)
|
|
31
|
+
self.assertNotIn("y", scope)
|
|
32
|
+
|
|
33
|
+
def test_scope_all_vars(self):
|
|
34
|
+
parent_scope = Scope()
|
|
35
|
+
parent_scope.variables["x"] = Var("x", 10, int)
|
|
36
|
+
child_scope = parent_scope.enter()
|
|
37
|
+
child_scope.variables["y"] = Var("y", 20, int)
|
|
38
|
+
|
|
39
|
+
all_vars = child_scope.get_all_vars_dict()
|
|
40
|
+
self.assertIn("x", all_vars)
|
|
41
|
+
self.assertIn("y", all_vars)
|
|
42
|
+
self.assertEqual(all_vars["x"].value, 10)
|
|
43
|
+
self.assertEqual(all_vars["y"].value, 20)
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
from typing import List
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class Var(object):
|
|
5
|
-
def __init__(self, var, value, type_):
|
|
6
|
-
self.var = var
|
|
7
|
-
self.value = value
|
|
8
|
-
self.type_ = type_
|
|
9
|
-
|
|
10
|
-
def __hash__(self):
|
|
11
|
-
return hash(self.var)
|
|
12
|
-
|
|
13
|
-
def __eq__(self, other):
|
|
14
|
-
return isinstance(other, Var) and self.var == other.var
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class Scope(object):
|
|
18
|
-
def __init__(self, parent=None, variables: dict = None):
|
|
19
|
-
self.parent = parent
|
|
20
|
-
self.variables = dict() if variables is None else variables.copy()
|
|
21
|
-
|
|
22
|
-
def enter(self):
|
|
23
|
-
return Scope(parent=self, variables=self.variables)
|
|
24
|
-
|
|
25
|
-
def exit(self):
|
|
26
|
-
if self.parent is not None:
|
|
27
|
-
return self.parent
|
|
28
|
-
else:
|
|
29
|
-
return self
|
|
30
|
-
|
|
31
|
-
def value(self, var: str) -> Var:
|
|
32
|
-
if var in self.variables:
|
|
33
|
-
return self.variables[var].value
|
|
34
|
-
|
|
35
|
-
def add(self, var, value, type_):
|
|
36
|
-
self.variables[var] = Var(var, value, type_)
|
|
37
|
-
|
|
38
|
-
def get_all_vars(self) -> List[Var]:
|
|
39
|
-
return list(self.variables.values())
|
sflkit-0.5.2/tests/test_scope.py
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
|
|
3
|
-
from sflkit.model.scope import Var, Scope
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class TestScope(unittest.TestCase):
|
|
7
|
-
def test_var_eq(self):
|
|
8
|
-
var_1 = Var("x", 2, int)
|
|
9
|
-
var_2 = Var("y", 2, int)
|
|
10
|
-
var_3 = Var("x", "", str)
|
|
11
|
-
self.assertEqual(var_1, var_3)
|
|
12
|
-
self.assertNotEqual(var_1, var_2)
|
|
13
|
-
self.assertNotEqual(var_2, var_3)
|
|
14
|
-
self.assertEqual(hash(var_1), hash(var_3))
|
|
15
|
-
self.assertNotEqual(hash(var_1), hash(var_2))
|
|
16
|
-
self.assertNotEqual(hash(var_2), hash(var_3))
|
|
17
|
-
|
|
18
|
-
def test_scope_without_parent(self):
|
|
19
|
-
scope = Scope()
|
|
20
|
-
self.assertIs(scope, scope.exit())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|