Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 25 additions & 35 deletions lib/eco/astanalyser.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,49 +239,44 @@ def merge_lbox_data(self, node, path):
analyser = self.get_lboxanalyser(root)
analyser.analyse(root, self.parsers)

# convert variables, functions
if node.symbol.name == "<Python + PHP>":
# merge python into php
original = "variable"
dest = "function"
max_path = 1
elif node.symbol.name == "<PHP + Python>":
# merge php into python
original = "function"
dest = "variable"
max_path = 1
else:
return
for method in analyser.data.get(original,[]):
if len(method.path) > max_path:
for kind in analyser.data:
if kind in ["File", "reference"]:
continue
uri = self.convert_uri(dest, method, path)
uri.nbrule = NBRule("none", [], {})
self.add_uri(uri)
for obj in analyser.data[kind]:
uri = self.convert_uri(kind, obj, path)
self.add_uri(uri)

# convert references
for ref in analyser.data.get("reference",[]):
# if reference couldn't be resolved, try in outer lbox
if ref.node in analyser.errors:
del analyser.errors[ref.node]
uri = self.convert_uri("reference", ref, path)
if uri.name.startswith("$"):
if uri.name.startswith("$"): # XXX PHP hack
uri.name = uri.name[1:]
else:
uri.name = "$" + uri.name
uri.nbrule = NBRule("none", [], {"references":(["variable"], ["function"])})
uri.nbrule = NBRule("none", [], {"references":(["variable", "function"], ["name"])})
self.add_uri(uri)
return

def convert_uri(self, newkind, prev, path):
uri = URI()
uri.kind = newkind
uri.astnode = prev.astnode
uri.node = prev.node
uri.path = path
uri.name = prev.name
uri.vartype = prev.vartype
uri.index = self.index
uri = prev
# There is currently no easy way to find out if a namebinding rule
# belongs to the top-level grammar rule. However, the top-level
# namebinding rule typically doesn't have a name as there is no need for
# it to have one. So we can use this to determine which rule is the
# top-level and then remove it when merging a sublanguage's rules into
# the outer language. However, if a user decides to give the top-level
# namebinding rule a name, cross-language namebinding won't work, and
# we currently can't guard against that.
if len(prev.path) > 0 and prev.path[0].name is None:
# Replace language box's top level with current location
uri.path.pop(0)
for p in reversed(path):
uri.path.insert(0, p)
else:
# Language box has no top-level (subgrammar)
for p in reversed(path):
uri.path.insert(0, p)
return uri

def add_uri(self, uri):
Expand Down Expand Up @@ -385,8 +380,6 @@ def get_completion(self, scope):
lbox = root.get_magicterminal()
analyser = self.get_lboxanalyser(root)
lboxresults = []
if analyser and analyser is not self:
lboxresults = analyser.get_completion(scope)
if analyser is self:
lbox = None
astnode = self.get_correct_astnode(scope, analyser, lbox)
Expand Down Expand Up @@ -417,9 +410,6 @@ def get_correct_astnode(self, scope, analyser=None, lbox=None):
# astnode must have a corresponding entry in self.data
if nbrule:
deftype = nbrule.get_deftype()
if lbox and lbox.symbol.name == "<Python + PHP>":
if deftype == "variable": # convert to find it in data
deftype = "function"
if self.data.has_key(deftype):
for e in self.data[deftype]:
if e.astnode is astnode:
Expand Down
7 changes: 4 additions & 3 deletions lib/eco/eco.py
Original file line number Diff line number Diff line change
Expand Up @@ -1385,9 +1385,10 @@ def btReparse(self, selected_node=[]):
def updateASTOutline(self):
self.ui.tw_astoutline.clear()
aa = self.getEditor().tm.parsers[0][3]
for uri in aa.data["class"]:
if uri.path[0].name is None and len(uri.path) == 1:
self.addToASTOutline(aa, uri, self.ui.tw_astoutline)
if aa.data.has_key("class"):
for uri in aa.data["class"]:
if not uri.path or (uri.path and uri.path[0].name is None and len(uri.path) == 1):
self.addToASTOutline(aa, uri, self.ui.tw_astoutline)
self.ui.tw_astoutline.expandAll()

def addToASTOutline(self, aa, uri, parent):
Expand Down
7 changes: 7 additions & 0 deletions lib/eco/grammars/grammars.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

import os

class Language(object):

def __init__(self, name, grammar, priorities, base=""):
Expand Down Expand Up @@ -51,6 +53,7 @@ def __init__(self, name, filename, base=""):
self.extract = None
self.auto_include = None
self.auto_exclude = None
self.nb_file = os.path.splitext(filename)[0] + ".nb"

def load(self, buildlexer=True):
from grammar_parser.bootstrap import BootstrapParser
Expand Down Expand Up @@ -118,6 +121,9 @@ def set_auto_exclude(self, lang, tokentype):
self.auto_exclude = {}
self.auto_exclude[lang] = tokentype

def set_custom_nb(self, basename):
self.nb_file = "{}/{}".format(os.path.dirname(self.filename), basename)

def auto_allows(self, lang, tokentype):
if self.auto_include and self.auto_include.has_key(lang):
return tokentype in self.auto_include[lang]
Expand Down Expand Up @@ -194,6 +200,7 @@ def __hash__(self):
python_class.change_start("classdef")

phppython = EcoFile("PHP + Python", "grammars/php.eco", "Php")
phppython.set_custom_nb("phppython.nb")
pythonphp = EcoFile("Python + PHP", "grammars/python275.eco", "Python")
phppython.add_alternative("top_statement", pythonphp)
phppython.add_alternative("class_statement", pythonphp)
Expand Down
Binary file added lib/eco/grammars/phppython.nb
Binary file not shown.
Binary file modified lib/eco/grammars/python275.nb
Binary file not shown.
7 changes: 4 additions & 3 deletions lib/eco/nodeeditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ def resizeEvent(self, event):

def analysis_timer(self):
if self.getWindow().show_namebinding():
self.tm.analyse()
self.update()
self.getWindow().updateASTOutline()
if self.tm.analyse() is not False:
self.update()
self.getWindow().updateASTOutline()
self.timer.stop()

# save swap
Expand Down Expand Up @@ -1083,6 +1083,7 @@ def action():
def createCCFunc(self, text):
def action():
self.tm.pasteCompletion(text)
self.update()
return action

def selectSubgrammar(self, item):
Expand Down
22 changes: 17 additions & 5 deletions lib/eco/treemanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,10 +544,12 @@ def load_analyser(self, language):
return
if isinstance(lang, EcoFile):
import os
filename = os.path.splitext(lang.filename)[0] + ".nb"
if os.path.exists(filename):
if os.path.exists(lang.nb_file):
from astanalyser import AstAnalyser
return AstAnalyser(filename)
return AstAnalyser(lang.nb_file)
else:
print("Namebinding file '%s' not found." % (lang.nb_file))


def get_languagebox(self, node):
root = node.get_root()
Expand Down Expand Up @@ -604,10 +606,20 @@ def get_error_presentation(self, node):
return None

def analyse(self):
if self.parsers[0][2] == "PHP + Python":
self.parsers[0][3].analyse(self.parsers[0][0].previous_version.parent, self.parsers)
# for now only do cross-scope analysing for certain grammars
crossscope = ["PHP + Python", "Java + Python"]
lang = self.parsers[0][2]
parser = self.parsers[0][0]
analyser = self.parsers[0][3]

if not analyser:
return False

if lang in crossscope:
analyser.analyse(parser.previous_version.parent, self.parsers)
return

# analyse all parsers individually
for p in self.parsers:
if p[0].last_status:
if p[3]:
Expand Down