Improve syntax highlighting in TextViewer
authorlaurent
Tue, 14 Jun 2011 17:40:02 +0200
changeset 546 f28df922efbe
parent 545 2f60f3d3c9ad
child 547 2faf0964feb2
Improve syntax highlighting in TextViewer
TextViewer.py
--- a/TextViewer.py	Tue Jun 14 17:38:59 2011 +0200
+++ b/TextViewer.py	Tue Jun 14 17:40:02 2011 +0200
@@ -41,7 +41,8 @@
     LETTERS.append(chr(ord('A') + i))
 
 [STC_PLC_WORD, STC_PLC_COMMENT, STC_PLC_NUMBER, STC_PLC_STRING, 
- STC_PLC_VARIABLE, STC_PLC_FUNCTION, STC_PLC_JUMP, STC_PLC_ERROR] = range(8)
+ STC_PLC_VARIABLE, STC_PLC_PARAMETER, STC_PLC_FUNCTION, STC_PLC_JUMP, 
+ STC_PLC_ERROR] = range(9)
 [SPACE, WORD, NUMBER, STRING, WSTRING, COMMENT] = range(6)
 
 [ID_TEXTVIEWER,
@@ -120,11 +121,12 @@
         # Highlighting styles
         self.StyleSetSpec(STC_PLC_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
         self.StyleSetSpec(STC_PLC_VARIABLE, "fore:#7F0000,size:%(size)d" % faces)
+        self.StyleSetSpec(STC_PLC_PARAMETER, "fore:#7F007F,size:%(size)d" % faces)
         self.StyleSetSpec(STC_PLC_FUNCTION, "fore:#7F7F00,size:%(size)d" % faces)
         self.StyleSetSpec(STC_PLC_COMMENT, "fore:#7F7F7F,size:%(size)d" % faces)
         self.StyleSetSpec(STC_PLC_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
-        self.StyleSetSpec(STC_PLC_STRING, "fore:#7F007F,size:%(size)d" % faces)
-        self.StyleSetSpec(STC_PLC_JUMP, "fore:#007F00,size:%(size)d" % faces)
+        self.StyleSetSpec(STC_PLC_STRING, "fore:#007F00,size:%(size)d" % faces)
+        self.StyleSetSpec(STC_PLC_JUMP, "fore:#FF7FFF,size:%(size)d" % faces)
         self.StyleSetSpec(STC_PLC_ERROR, "fore:#FF0000,back:#FFFF00,size:%(size)d" % faces)
         
         # Indicators styles
@@ -155,8 +157,8 @@
         self.Errors = []
         self.Debug = debug
         self.InstancePath = instancepath
-        self.StructElementsStack = []
-        self.FunctionCallStack = []
+        self.ContextStack = []
+        self.CallStack = []
         
         self.ParentWindow = window
         self.Controler = controler
@@ -339,27 +341,27 @@
         self.Functions = {}
         for category in self.Controler.GetBlockTypes(self.TagName, self.Debug):
             for blocktype in category["list"]:
-                if blocktype["type"] == "function" and blocktype["name"] not in self.Keywords and blocktype["name"] not in self.Variables.keys():
-                    if self.Functions.has_key(blocktype["name"]):
-                        for name, type, modifier in blocktype["inputs"]:
-                            if name not in self.Functions[blocktype["name"]]["inputs"]:
-                                self.Functions[blocktype["name"]]["inputs"].append(name)
-                        for name, type, modifier in blocktype["outputs"]:
-                            if name not in self.Functions[blocktype["name"]]["outputs"]:
-                                self.Functions[blocktype["name"]]["outputs"].append(name)
-                        self.Functions[blocktype["name"]]["extensible"] |= blocktype["extensible"]
-                    else:
-                        self.Functions[blocktype["name"]] = {"inputs": [name for name, type, modifier in blocktype["inputs"]],
-                                                             "outputs": [name for name, type, modifier in blocktype["outputs"]],
-                                                             "extensible": blocktype["extensible"]}
-        
+                blockname = blocktype["name"].upper()
+                if blocktype["type"] == "function" and blockname not in self.Keywords and blockname not in self.Variables.keys():
+                    interface = dict([(name, {}) for name, type, modifier in blocktype["inputs"] + blocktype["outputs"] if name != ''])
+                    if self.Functions.has_key(blockname):
+                        self.Functions[blockname]["interface"].update(interface)
+                        self.Functions[blockname]["extensible"] |= blocktype["extensible"]
+                    else:
+                        self.Functions[blockname] = {"interface": interface,
+                                                     "extensible": blocktype["extensible"]}
         self.Colourise(0, -1)
     
     def RefreshVariableTree(self):
         words = self.TagName.split("::")
         self.Variables = self.GenerateVariableTree([(variable["Name"], variable["Type"], variable["Tree"]) for variable in self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)])
         if self.Controler.GetEditedElementType(self.TagName, self.Debug)[1] == "function" or words[0] == "T" and self.TextSyntax == "IL":
-            self.Variables[words[-1].upper()] = {}
+            return_type = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, self.Debug)
+            if return_type is not None:
+                var_tree, var_dimension = self.Controler.GenerateVarTree(return_type, self.Debug)
+                self.Variables[words[-1].upper()] = self.GenerateVariableTree(var_tree)
+            else:
+                self.Variables[words[-1].upper()] = {}
     
     def GenerateVariableTree(self, list):
         tree = {}
@@ -370,22 +372,13 @@
     def RefreshScaling(self, refresh=True):
         pass
     
-    def IsValidVariable(self, name_list, var_tree):
-        if len(name_list) == 0:
-            return True
-        else:
-            sub_tree = var_tree.get(name_list[0].upper(), None)
-            if sub_tree is not None:
-                return self.IsValidVariable(name_list[1:], sub_tree)
-        return False
-    
-    def IsFunctionParameter(self, param_name, func_name):
-        if func_name is not None:
-            func_decl = self.Functions.get(func_name, None)
-            if func_decl is not None:
-                return (param_name.upper() in func_decl["inputs"] or 
-                        param_name.upper() in func_decl["outputs"] or
-                        func_decl["extensible"] and EXTENSIBLE_PARAMETER.match(param_name.upper()) is not None)
+    def IsValidVariable(self, name, context):
+        return context is not None and context.get(name, None) is not None
+
+    def IsCallParameter(self, name, call):
+        if call is not None:
+            return (call["interface"].get(name.upper(), None) is not None or 
+                    call["extensible"] and EXTENSIBLE_PARAMETER.match(name.upper()) is not None)
         return False
         
     def OnStyleNeeded(self, event):
@@ -398,8 +391,8 @@
         end_pos = event.GetPosition()
         self.StartStyling(start_pos, 0xff)
         
-        struct_elements = []
-        current_function = None
+        current_context = self.Variables
+        current_call = None
         
         current_pos = last_styled_pos
         state = SPACE
@@ -409,7 +402,8 @@
             char = chr(self.GetCharAt(current_pos)).upper()
             line += char
             if char == NEWLINE:
-                self.StructElementsStack = []
+                self.ContextStack = []
+                current_context = self.Variables
                 if state == COMMENT:
                     self.SetStyling(current_pos - last_styled_pos + 1, STC_PLC_COMMENT)
                 elif state == NUMBER:
@@ -417,8 +411,10 @@
                 elif state == WORD:
                     if word in self.Keywords or word in self.TypeNames:
                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD)
-                    elif self.IsValidVariable(struct_elements + [word], self.Variables) or self.IsFunctionParameter(word, current_function):
+                    elif self.IsValidVariable(word, current_context):
                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE)
+                    elif self.IsCallParameter(word, current_call):
+                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_PARAMETER)
                     elif word in self.Functions:
                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION)
                     elif self.TextSyntax == "IL" and word in self.Jumps:
@@ -427,11 +423,10 @@
                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
                     else:
                         self.SetStyling(current_pos - last_styled_pos, 31)
-                        if word != "]" and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos):
+                        if word not in ["]", ")"] and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos):
                             self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK)
                             self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK)
                             self.StartStyling(current_pos, 0xff)
-                    struct_elements = []
                 else:
                     self.SetStyling(current_pos - last_styled_pos, 31)
                 last_styled_pos = current_pos
@@ -441,7 +436,7 @@
                 self.SetStyling(current_pos - last_styled_pos - 1, 31)
                 last_styled_pos = current_pos
                 if state == WORD:
-                    struct_elements = []
+                    current_context = self.Variables
                 state = COMMENT
             elif state == COMMENT:
                 if line.endswith("*)"):
@@ -452,7 +447,7 @@
                 self.SetStyling(current_pos - last_styled_pos, 31)
                 last_styled_pos = current_pos
                 if state == WORD:
-                    struct_elements = []
+                    current_context = self.Variables
                 if line.endswith("'"):
                     state = STRING
                 else:
@@ -486,14 +481,16 @@
                 if state == WORD and char != '.':
                     word += char
             elif char == '(' and state == SPACE:
-                self.FunctionCallStack.append(current_function)
-                current_function = None
+                self.CallStack.append(current_call)
+                current_call = None
             else:
                 if state == WORD:
                     if word in self.Keywords or word in self.TypeNames:
                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD)
-                    elif self.IsValidVariable(struct_elements + [word], self.Variables) or self.IsFunctionParameter(word, current_function):
+                    elif self.IsValidVariable(word, current_context):
                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE)
+                    elif self.IsCallParameter(word, current_call):
+                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_PARAMETER)
                     elif word in self.Functions:
                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION)    
                     elif self.TextSyntax == "IL" and word in self.Jumps:
@@ -502,26 +499,27 @@
                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
                     else:
                         self.SetStyling(current_pos - last_styled_pos, 31)
-                        if word != "]" and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos):
+                        if word not in ["]", ")"] and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos):
                             self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK)
                             self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK)
                             self.StartStyling(current_pos, 0xff)
                     if char == '.':
                         if word != "]":
-                            struct_elements.append(word)
+                            if current_context is not None:
+                                current_context = current_context.get(word, None)
+                            else:
+                                current_context = None
                     elif char == '(':
-                        self.FunctionCallStack.append(current_function)
-                        if word in self.Functions:
-                            current_function = word
-                            struct_elements = []
-                        else:    
-                            if self.IsValidVariable(struct_elements + [word], self.Variables):
-                                struct_elements.append(word)
-                            current_function = None
+                        self.CallStack.append(current_call)
+                        current_call = self.Functions.get(word, None)
+                        if current_call is None and self.IsValidVariable(word, current_context):
+                            current_call = {"interface": current_context.get(word, {}),
+                                            "extensible": False}
+                        current_context = self.Variables
                     else:
                         if char == '[':
-                            self.StructElementsStack.append(struct_elements + [word])
-                        struct_elements = []
+                            self.ContextStack.append(current_context.get(word, None))
+                        current_context = self.Variables
                     
                     word = ""
                     last_styled_pos = current_pos
@@ -531,18 +529,20 @@
                     last_styled_pos = current_pos
                     state = SPACE
                 if char == ']':
-                    if len(self.StructElementsStack) > 0:
-                        struct_elements = self.StructElementsStack.pop()
-                    else:
-                        struct_elements = []
+                    if len(self.ContextStack) > 0:
+                        current_context = self.ContextStack.pop()
+                    else:
+                        current_context = self.Variables
                     word = char
                     state = WORD
                 elif char == ')':
-                    struct_elements = []
-                    if len(self.FunctionCallStack) > 0:
-                        current_function = self.FunctionCallStack.pop()
-                    else:
-                        current_function = None
+                    current_context = self.Variables
+                    if len(self.CallStack) > 0:
+                        current_call = self.CallStack.pop()
+                    else:
+                        current_call = None
+                    word = char
+                    state = WORD
             current_pos += 1
         if state == COMMENT:
             self.SetStyling(current_pos - last_styled_pos + 2, STC_PLC_COMMENT)
@@ -551,8 +551,10 @@
         elif state == WORD:
             if word in self.Keywords or word in self.TypeNames:
                 self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD)
-            elif self.IsValidVariable(struct_elements + [word], self.Variables) or self.IsFunctionParameter(word, current_function):
+            elif self.IsValidVariable(word, current_context):
                 self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE)
+            elif self.IsCallParameter(word, current_call):
+                self.SetStyling(current_pos - last_styled_pos, STC_PLC_PARAMETER)
             elif self.TextSyntax == "IL" and word in self.Functions:
                 self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION)
             elif word in self.Jumps: