Skip to content

Commit a1618b6

Browse files
authored
Merge pull request #220 from softdevteam/fix_namebinding
Fix namebinding
2 parents 763146e + ee40c06 commit a1618b6

7 files changed

Lines changed: 57 additions & 46 deletions

File tree

lib/eco/astanalyser.py

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -239,49 +239,44 @@ def merge_lbox_data(self, node, path):
239239
analyser = self.get_lboxanalyser(root)
240240
analyser.analyse(root, self.parsers)
241241

242-
# convert variables, functions
243-
if node.symbol.name == "<Python + PHP>":
244-
# merge python into php
245-
original = "variable"
246-
dest = "function"
247-
max_path = 1
248-
elif node.symbol.name == "<PHP + Python>":
249-
# merge php into python
250-
original = "function"
251-
dest = "variable"
252-
max_path = 1
253-
else:
254-
return
255-
for method in analyser.data.get(original,[]):
256-
if len(method.path) > max_path:
242+
for kind in analyser.data:
243+
if kind in ["File", "reference"]:
257244
continue
258-
uri = self.convert_uri(dest, method, path)
259-
uri.nbrule = NBRule("none", [], {})
260-
self.add_uri(uri)
245+
for obj in analyser.data[kind]:
246+
uri = self.convert_uri(kind, obj, path)
247+
self.add_uri(uri)
261248

262249
# convert references
263250
for ref in analyser.data.get("reference",[]):
264251
# if reference couldn't be resolved, try in outer lbox
265252
if ref.node in analyser.errors:
266253
del analyser.errors[ref.node]
267254
uri = self.convert_uri("reference", ref, path)
268-
if uri.name.startswith("$"):
255+
if uri.name.startswith("$"): # XXX PHP hack
269256
uri.name = uri.name[1:]
270-
else:
271-
uri.name = "$" + uri.name
272-
uri.nbrule = NBRule("none", [], {"references":(["variable"], ["function"])})
257+
uri.nbrule = NBRule("none", [], {"references":(["variable", "function"], ["name"])})
273258
self.add_uri(uri)
274259
return
275260

276261
def convert_uri(self, newkind, prev, path):
277-
uri = URI()
278-
uri.kind = newkind
279-
uri.astnode = prev.astnode
280-
uri.node = prev.node
281-
uri.path = path
282-
uri.name = prev.name
283-
uri.vartype = prev.vartype
284-
uri.index = self.index
262+
uri = prev
263+
# There is currently no easy way to find out if a namebinding rule
264+
# belongs to the top-level grammar rule. However, the top-level
265+
# namebinding rule typically doesn't have a name as there is no need for
266+
# it to have one. So we can use this to determine which rule is the
267+
# top-level and then remove it when merging a sublanguage's rules into
268+
# the outer language. However, if a user decides to give the top-level
269+
# namebinding rule a name, cross-language namebinding won't work, and
270+
# we currently can't guard against that.
271+
if len(prev.path) > 0 and prev.path[0].name is None:
272+
# Replace language box's top level with current location
273+
uri.path.pop(0)
274+
for p in reversed(path):
275+
uri.path.insert(0, p)
276+
else:
277+
# Language box has no top-level (subgrammar)
278+
for p in reversed(path):
279+
uri.path.insert(0, p)
285280
return uri
286281

287282
def add_uri(self, uri):
@@ -385,8 +380,6 @@ def get_completion(self, scope):
385380
lbox = root.get_magicterminal()
386381
analyser = self.get_lboxanalyser(root)
387382
lboxresults = []
388-
if analyser and analyser is not self:
389-
lboxresults = analyser.get_completion(scope)
390383
if analyser is self:
391384
lbox = None
392385
astnode = self.get_correct_astnode(scope, analyser, lbox)
@@ -417,9 +410,6 @@ def get_correct_astnode(self, scope, analyser=None, lbox=None):
417410
# astnode must have a corresponding entry in self.data
418411
if nbrule:
419412
deftype = nbrule.get_deftype()
420-
if lbox and lbox.symbol.name == "<Python + PHP>":
421-
if deftype == "variable": # convert to find it in data
422-
deftype = "function"
423413
if self.data.has_key(deftype):
424414
for e in self.data[deftype]:
425415
if e.astnode is astnode:

lib/eco/eco.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,9 +1385,10 @@ def btReparse(self, selected_node=[]):
13851385
def updateASTOutline(self):
13861386
self.ui.tw_astoutline.clear()
13871387
aa = self.getEditor().tm.parsers[0][3]
1388-
for uri in aa.data["class"]:
1389-
if uri.path[0].name is None and len(uri.path) == 1:
1390-
self.addToASTOutline(aa, uri, self.ui.tw_astoutline)
1388+
if aa.data.has_key("class"):
1389+
for uri in aa.data["class"]:
1390+
if not uri.path or (uri.path and uri.path[0].name is None and len(uri.path) == 1):
1391+
self.addToASTOutline(aa, uri, self.ui.tw_astoutline)
13911392
self.ui.tw_astoutline.expandAll()
13921393

13931394
def addToASTOutline(self, aa, uri, parent):

lib/eco/grammars/grammars.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2020
# IN THE SOFTWARE.
2121

22+
import os
23+
2224
class Language(object):
2325

2426
def __init__(self, name, grammar, priorities, base=""):
@@ -51,6 +53,7 @@ def __init__(self, name, filename, base=""):
5153
self.extract = None
5254
self.auto_include = None
5355
self.auto_exclude = None
56+
self.nb_file = os.path.splitext(filename)[0] + ".nb"
5457

5558
def load(self, buildlexer=True):
5659
from grammar_parser.bootstrap import BootstrapParser
@@ -118,6 +121,9 @@ def set_auto_exclude(self, lang, tokentype):
118121
self.auto_exclude = {}
119122
self.auto_exclude[lang] = tokentype
120123

124+
def set_custom_nb(self, basename):
125+
self.nb_file = "{}/{}".format(os.path.dirname(self.filename), basename)
126+
121127
def auto_allows(self, lang, tokentype):
122128
if self.auto_include and self.auto_include.has_key(lang):
123129
return tokentype in self.auto_include[lang]
@@ -194,6 +200,7 @@ def __hash__(self):
194200
python_class.change_start("classdef")
195201

196202
phppython = EcoFile("PHP + Python", "grammars/php.eco", "Php")
203+
phppython.set_custom_nb("phppython.nb")
197204
pythonphp = EcoFile("Python + PHP", "grammars/python275.eco", "Python")
198205
phppython.add_alternative("top_statement", pythonphp)
199206
phppython.add_alternative("class_statement", pythonphp)

lib/eco/grammars/phppython.nb

1.7 KB
Binary file not shown.

lib/eco/grammars/python275.nb

352 Bytes
Binary file not shown.

lib/eco/nodeeditor.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,9 @@ def resizeEvent(self, event):
146146

147147
def analysis_timer(self):
148148
if self.getWindow().show_namebinding():
149-
self.tm.analyse()
150-
self.update()
151-
self.getWindow().updateASTOutline()
149+
if self.tm.analyse() is not False:
150+
self.update()
151+
self.getWindow().updateASTOutline()
152152
self.timer.stop()
153153

154154
# save swap
@@ -1083,6 +1083,7 @@ def action():
10831083
def createCCFunc(self, text):
10841084
def action():
10851085
self.tm.pasteCompletion(text)
1086+
self.update()
10861087
return action
10871088

10881089
def selectSubgrammar(self, item):

lib/eco/treemanager.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -544,10 +544,12 @@ def load_analyser(self, language):
544544
return
545545
if isinstance(lang, EcoFile):
546546
import os
547-
filename = os.path.splitext(lang.filename)[0] + ".nb"
548-
if os.path.exists(filename):
547+
if os.path.exists(lang.nb_file):
549548
from astanalyser import AstAnalyser
550-
return AstAnalyser(filename)
549+
return AstAnalyser(lang.nb_file)
550+
else:
551+
print("Namebinding file '%s' not found." % (lang.nb_file))
552+
551553

552554
def get_languagebox(self, node):
553555
root = node.get_root()
@@ -604,10 +606,20 @@ def get_error_presentation(self, node):
604606
return None
605607

606608
def analyse(self):
607-
if self.parsers[0][2] == "PHP + Python":
608-
self.parsers[0][3].analyse(self.parsers[0][0].previous_version.parent, self.parsers)
609+
# for now only do cross-scope analysing for certain grammars
610+
crossscope = ["PHP + Python", "Java + Python"]
611+
lang = self.parsers[0][2]
612+
parser = self.parsers[0][0]
613+
analyser = self.parsers[0][3]
614+
615+
if not analyser:
616+
return False
617+
618+
if lang in crossscope:
619+
analyser.analyse(parser.previous_version.parent, self.parsers)
609620
return
610621

622+
# analyse all parsers individually
611623
for p in self.parsers:
612624
if p[0].last_status:
613625
if p[3]:

0 commit comments

Comments
 (0)