Skip to content

Commit 267a4dc

Browse files
authored
Merge pull request #358 from boriel/feature/dependency_propagation
Feature/dependency propagation
2 parents 48b2e27 + 29f9621 commit 267a4dc

File tree

8 files changed

+1830
-33
lines changed

8 files changed

+1830
-33
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
![Boriel ZX Basic](img/zxbasic_logo.png)
22

3-
[![Build Status](https://travis-ci.org/boriel/zxbasic.svg?branch=master)](https://travis-ci.org/boriel/zxbasic)
3+
[![Build Status](https://travis-ci.com/boriel/zxbasic.svg?branch=master)](https://travis-ci.org/boriel/zxbasic)
44
[![license](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.txt)
55
[![pyversions](https://img.shields.io/pypi/pyversions/zxbasic.svg)](https://pypi.python.org/pypi/zxbasic)
66

api/check.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,17 +115,18 @@ def check_call_arguments(lineno, id_, args):
115115
if param.byref:
116116
from symbols.var import SymbolVAR
117117
if not isinstance(arg.value, SymbolVAR):
118-
syntax_error(lineno, "Expected a variable name, not an "
119-
"expression (parameter By Reference)")
118+
syntax_error(lineno, "Expected a variable name, not an expression (parameter By Reference)")
120119
return False
121120

122121
if arg.class_ not in (CLASS.var, CLASS.array):
123-
syntax_error(lineno, "Expected a variable or array name "
124-
"(parameter By Reference)")
122+
syntax_error(lineno, "Expected a variable or array name (parameter By Reference)")
125123
return False
126124

127125
arg.byref = True
128126

127+
if arg.value is not None:
128+
arg.value.add_required_symbol(param)
129+
129130
if entry.forwarded: # The function / sub was DECLARED but not implemented
130131
syntax_error(lineno, "%s '%s' declared but not implemented" % (CLASS.to_string(entry.class_), entry.name))
131132
return False
@@ -139,7 +140,7 @@ def check_pending_calls():
139140
"""
140141
result = True
141142

142-
# Check for functions defined after calls (parametres, etc)
143+
# Check for functions defined after calls (parameters, etc)
143144
for id_, params, lineno in global_.FUNCTION_CALLS:
144145
result = result and check_call_arguments(lineno, id_, params)
145146

api/optimize.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,6 @@ def _visit(self, node):
6969
return None
7070

7171
__DEBUG__("Optimizer: Visiting node {}".format(str(node.obj)), 1)
72-
73-
# print node.obj.token, node.obj.__repr__()
7472
methname = 'visit_' + node.obj.token
7573
meth = getattr(self, methname, None)
7674
if meth is None:
@@ -267,13 +265,15 @@ def _check_if_any_arg_is_an_array_and_needs_lbound_or_ubound(self, params: symbo
267265
if arg.value.lbound_used and arg.value.ubound_used:
268266
continue
269267

270-
self._update_bound_status(arg.value, param, params.parent)
268+
self._update_bound_status(arg.value)
271269

272-
def _update_bound_status(self, arg: symbols.VARARRAY, param: symbols.PARAMDECL, func: symbols.FUNCTION):
270+
def _update_bound_status(self, arg: symbols.VARARRAY):
273271
old_lbound_used = arg.lbound_used
274272
old_ubound_used = arg.ubound_used
275-
arg.lbound_used = arg.lbound_used or param.lbound_used
276-
arg.ubound_used = arg.ubound_used or param.ubound_used
273+
274+
for p in arg.requires:
275+
arg.lbound_used = arg.lbound_used or p.lbound_used
276+
arg.ubound_used = arg.ubound_used or p.ubound_used
277277

278278
if old_lbound_used != arg.lbound_used or old_ubound_used != arg.ubound_used:
279279
if arg.scope == SCOPE.global_:

symbols/symbol_.py

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
# ----------------------------------------------------------------------
1111

1212
import re
13-
from functools import reduce
14-
from typing import Set, Optional
13+
from collections import Counter
1514

1615
from ast_ import Ast
1716
import api.global_
@@ -27,33 +26,36 @@ def __init__(self, *children):
2726
assert isinstance(child, Symbol)
2827
self.appendChild(child)
2928

30-
self._required_by: Set['Symbol'] = set() # Symbols that depends on this one
31-
self._requires: Set['Symbol'] = set() # Symbols this one depends on
32-
self._cached_required_by: Optional[Set['Symbol']] = set()
29+
self._required_by: Counter = Counter() # Symbols that depends on this one
30+
self._requires: Counter = Counter() # Symbols this one depends on
3331

3432
@property
35-
def required_by(self) -> Set['Symbol']:
36-
if self._cached_required_by is not None:
37-
return self._cached_required_by
38-
39-
self._cached_required_by = reduce(lambda x: x.union, (x.required_by for x in self.children),
40-
set(self._required_by))
41-
return self._cached_required_by
33+
def required_by(self) -> Counter:
34+
return self._required_by
4235

4336
@property
44-
def requires(self) -> Set['Symbol']:
45-
return set(self._requires)
37+
def requires(self) -> Counter:
38+
return Counter(self._requires)
4639

4740
def mark_as_required_by(self, other: 'Symbol'):
48-
self._required_by.add(other)
49-
self._cached_required_by.add(other)
50-
if self.parent is not None:
51-
assert isinstance(self.parent, Symbol)
52-
self.parent.mark_as_required_by(other)
41+
if self is other:
42+
return
43+
44+
self._required_by.update([other])
45+
other._requires.update([self])
46+
47+
for sym in other.required_by:
48+
sym.add_required_symbol(self)
5349

5450
def add_required_symbol(self, other: 'Symbol'):
55-
self._requires.add(other)
56-
other.mark_as_required_by(self)
51+
if self is other:
52+
return
53+
54+
self._requires.update([other])
55+
other._required_by.update([self])
56+
57+
for sym in other.requires:
58+
sym.mark_as_required_by(self)
5759

5860
@property
5961
def token(self):

0 commit comments

Comments
 (0)