/// <summary> /// Parse import statements in source /// </summary> /// <param name="src">Class source</param> /// <param name="aClass">Class object to update</param> static private void ParseImports(string src, ASClass aClass) { aClass.Imports.Clear(); src = src.Replace('\r', '\n'); // fix .NET Regex line-ends detection MatchCollection mcImports = re_import.Matches(src); if (mcImports.Count > 0) { ArrayList known = new ArrayList(); string package; string cname; ASMember newImport; foreach (Match mImport in mcImports) { package = mImport.Groups["package"].Value; //DebugConsole.Trace("IMPORT '"+package+"'"); int p = package.LastIndexOf("."); cname = (p >= 0) ? package.Substring(p + 1) : package; // resolve wildcard if (cname.Length == 0) { context.ResolveWildcards(package, aClass, known); } else if (!known.Contains(package)) { known.Add(package); newImport = new ASMember(); newImport.Name = cname; newImport.Type = package; aClass.Imports.Add(newImport); } } } //else DebugConsole.Trace("NO IMPORTS"); }
static public string ClassDeclaration(ASClass oClass) { // package if (oClass.Flags == FlagType.Package) { return("package " + oClass.ClassName.Replace('\\', '.')); } else { // modifiers string modifiers = ""; if ((oClass.Flags & FlagType.Intrinsic) > 0) { modifiers += "intrinsic "; } if ((oClass.Flags & FlagType.Dynamic) > 0) { modifiers += "dynamic "; } string classType = ((oClass.Flags & FlagType.Interface) > 0) ? "interface" : "class"; // signature return(String.Format("{0}{1} {2}", modifiers, classType, oClass.ClassName)); } }
public void UpdateAndActive(ASClass aClass) { try { classTree.BeginUpdate(); if (aClass.IsVoid()) { AddInView(ASContext.MainForm.CurFile); } else { UpdateView(aClass); } SetActiveClass(aClass); } finally { classTree.EndUpdate(); Win32.Scrolling.scrollToLeft(classTree); } }
/// <summary> /// Parse a class from file /// </summary> /// <param name="aClass">Class object</param> /// <param name="filename">Class filename</param> static public void ParseClass(ASClass aClass) { string src; // read file content try { if (!File.Exists(aClass.FileName)) { return; } StreamReader sr = new StreamReader(aClass.FileName); src = sr.ReadToEnd(); sr.Close(); } catch (Exception ex) { context.DisplayError(ex.Message); return; } // parse ParseClass(aClass, src); }
/// <summary> /// Recursively convert classes /// </summary> /// <param name="path">folder to convert</param> static void ExploreFolder(string path) { currentFile = path; known.Add(path); // convert classes string[] files = Directory.GetFiles(path, "*.as"); ASClass fClass; string destFile; DateTime timestamp; int codepage; foreach(string file in files) { currentFile = file; destFile = destPath+file.Substring(srcPath.Length); // not modified: ignore timestamp = File.GetLastWriteTime(file); if (File.Exists(destFile) && File.GetLastWriteTime(destFile) == timestamp) continue; // parse class codepage = GetFileCodepage(file); fClass = new ASClass(); fClass.FileName = file; ASClassParser.ParseClass(fClass); if (fClass.IsVoid()) continue; // create intrinsic Directory.CreateDirectory(Path.GetDirectoryName(destFile)); Write(destFile, fClass.GenerateIntrinsic(), Encoding.GetEncoding(codepage)); File.SetCreationTime(destFile, timestamp); File.SetLastWriteTime(destFile, timestamp); total++; } // explore subfolders currentFile = path; string[] dirs = Directory.GetDirectories(path); foreach(string dir in dirs) { if (!known.Contains(dir)) ExploreFolder(dir); } }
public void SetActiveClass(ASClass aClass) { try { classTree.BeginUpdate(); string filename; if (aClass.IsVoid()) filename = ASContext.MainForm.CurFile; else filename = aClass.FileName; DebugConsole.Trace("UI: set active "+filename); // bool found = false; foreach(TreeNode node in classTree.Nodes) if ((string)node.Tag == filename) { if (!found) { found = true; classTree.SelectedNode = node; int index = 0; if (showExtend) index++; if (showImports) index++; for (int i=0; i<memberGroups; i++) node.Nodes[index++].Expand(); node.Expand(); } else classTree.Nodes.Remove(node); } else node.Collapse(); // if (classTree.SelectedNode != null) classTree.SelectedNode.EnsureVisible(); } catch { classTree.SelectedNode = null; } finally { classTree.EndUpdate(); Win32.Scrolling.scrollToLeft(classTree); } }
static private string MemberTooltipText(ASMember member, ASClass inClass) { // modifiers FlagType ft = member.Flags; string modifiers = ""; if ((ft & FlagType.Class) == 0) { if ((ft & FlagType.Static) > 0) modifiers += "static "; if ((ft & FlagType.Private) > 0) modifiers += "private "; else if ((ft & FlagType.Public) > 0) modifiers += "public "; } // signature if ((ft & FlagType.Function) > 0) return String.Format("{0}function {1}\nin {2}", modifiers, member.ToString(), inClass.ClassName); else if ((ft & FlagType.Variable) > 0) return String.Format("{0}var {1}\nin {2}", modifiers, member.ToString(), inClass.ClassName); else if ((ft & (FlagType.Getter | FlagType.Setter)) > 0) return String.Format("{0}property {1}\nin {2}", modifiers, member.ToString(), inClass.ClassName); else return String.Format("{0}{1}\nin {2}", modifiers, member.ToString(), inClass.ClassName); }
/// <summary> /// Parse a class from source /// </summary> /// <param name="aClass">Class object</param> /// <param name="src">Class source</param> static public void ParseClass(ASClass aClass, string src) { // remove comments StringCollection comments = new StringCollection(); src = CleanClassSource(src, comments); // check class definition Match mClass = re_class.Match(src); if (!mClass.Success) { aClass.ClassName = null; return; } // classname string prevCName = aClass.ClassName; aClass.ClassName = mClass.Groups["cname"].Value; // HACK AS3 package support string preClassSrc = src.Substring(0,mClass.Groups["ctype"].Index); string AS3package = null; Match mPackage = re_AS3package.Match(preClassSrc); if (mPackage.Success) { aClass.IsAS3 = true; AS3package = mPackage.Groups["name"].Value; if (AS3package != null && AS3package.Length > 0) aClass.ClassName = AS3package+"."+aClass.ClassName; } else aClass.IsAS3 = false; // check classname int p = aClass.ClassName.LastIndexOf("."); string constructor = (p >= 0) ? aClass.ClassName.Substring(p+1) : aClass.ClassName; string classType = mClass.Groups["ctype"].Value; if (src.Substring(0, mClass.Groups["cname"].Index).IndexOf(" comment0 ") >= 0) aClass.Comments = comments[0]; // class base path bool validClassFile = true; int basepos = aClass.FileName.LastIndexOf( aClass.ClassName.Replace('.', Path.DirectorySeparatorChar)+".as" ); if (basepos < 0) { // this class name & file don't match, it can lead to dangerous errors validClassFile = false; // warm about the misspelled class name if (!aClass.FileName.EndsWith("/"+constructor+".as") || !aClass.FileName.ToUpper().EndsWith("\\"+aClass.ClassName.ToUpper().Replace('.','\\')+".AS")) { if (prevCName != aClass.ClassName) { string msg = String.Format("The {0} '{1}' does not match the file name:\n{2}", classType, aClass.ClassName, aClass.FileName); context.DisplayError(msg); } } aClass.BasePath = System.IO.Path.GetDirectoryName(aClass.FileName)+"\\"; } else { aClass.BasePath = aClass.FileName.Substring(0, basepos); } // add to classpath context.SetTemporaryBasePath(aClass.FileName, aClass.BasePath); // class flag aClass.Flags = FlagType.Class; if (classType == "interface") aClass.Flags |= FlagType.Interface; if (mClass.Groups["keys"].Value.IndexOf("intrinsic") >= 0) aClass.Flags |= FlagType.Intrinsic; if (mClass.Groups["keys"].Value.IndexOf("dynamic") >= 0) aClass.Flags |= FlagType.Dynamic; // import statements ParseImports(preClassSrc, aClass); preClassSrc = null; // inheritance string herit = mClass.Groups["herit"].Value; Match mExtends = re_extends.Match(herit); string extends = (validClassFile && mExtends.Success) ? mExtends.Groups["cname"].ToString() : "Object"; if ((extends != aClass.ClassName) && (aClass.ClassName != "TopLevel")) { aClass.Extends = null; // resolve extended class ASClass extendsClass = context.GetClassByName(extends, aClass); // detect infinite extension loop ASClass tmpClass = extendsClass; while (tmpClass != null) { if (tmpClass == aClass) { string msg = String.Format("The {0} '{1}' extends itself.", classType, aClass.ClassName); context.DisplayError(msg); extendsClass = null; break; } tmpClass = tmpClass.Extends; } if (extendsClass != null) aClass.Extends = extendsClass; else aClass.Extends = new ASClass(); } Match mImplements = re_implements.Match(herit); if (mImplements.Success) { string implements; if (!mExtends.Success || mImplements.Index > mExtends.Index) implements = herit.Substring(mImplements.Index+mImplements.Length).Trim(); else implements = herit.Substring(mImplements.Index+mImplements.Length, mExtends.Index-mImplements.Index-mImplements.Length).Trim(); aClass.Implements = re_parametersSeparator.Replace(implements, ", "); } else aClass.Implements = null; // clean class body src = "; "+src.Substring(mClass.Groups["herit"].Index + mClass.Groups["herit"].Value.Length+1); src = re_balancedBraces.Replace(src, ";"); // if updating, clear aClass.Methods.Clear(); aClass.Properties.Clear(); aClass.Vars.Clear(); // parse functions string keys; bool isStatic; MatchCollection mcFunc = re_functions.Matches(src); Match mFunc; Match mType; Match mComments; ASMember member; foreach(Match m in mcFunc) { mFunc = re_splitFunction.Match(m.Value); if (!mFunc.Success) continue; // keywords keys = mFunc.Groups["keys"].Value; member = new ASMember(); member.Flags = FlagType.Function; if (keys.IndexOf("private") >= 0) member.Flags |= FlagType.Private; else member.Flags |= FlagType.Public; isStatic = (keys.IndexOf("static") >= 0); if (isStatic) member.Flags |= FlagType.Static; else member.Flags |= FlagType.Dynamic; // comments if (comments.Count > 0) { mComments = re_commentIndex.Match(keys); if (mComments.Success) { member.Comments = comments[ Convert.ToInt16(mComments.Groups["index"].Value) ]; } } // method member.Name = mFunc.Groups["fname"].Value.Trim(); if (member.Name.Length == 0) continue; // parameters member.Parameters = re_colonParams.Replace( re_parametersSeparator.Replace(mFunc.Groups["params"].Value.Trim(), ", "), ":"); // return type mType = re_variableType.Match(mFunc.Groups["type"].Value); if (mType.Success) member.Type = mType.Groups["type"].Value; else member.Type = ""; // constructor type if (member.Name == constructor) { member.Flags |= FlagType.Constructor; member.Type = constructor; } // getter/setter if ((member.Name.Length > 4) && ((int)member.Name[3] < 33)) { Match mProp = re_isGetterSetter.Match(member.Name); if (mProp.Success) { string pname = mProp.Groups["pname"].Value; ASMember prop = aClass.Properties.Search(pname, 0); if (prop == null) { prop = member; prop.Name = pname; prop.Flags -= FlagType.Function; aClass.Properties.Add(prop); } if (mProp.Groups["type"].Value == "g") { prop.Flags |= FlagType.Getter; prop.Type = member.Type; if (!mType.Success) prop.Type = "Object"; } else { prop.Flags |= FlagType.Setter; prop.Parameters = member.Parameters; } if ((member.Comments != null) && ((prop.Comments == null) || (prop.Comments.Length < member.Comments.Length))) prop.Comments = member.Comments; } // store method else aClass.Methods.Add(member); } // store method else aClass.Methods.Add(member); } // parse variables MatchCollection mcVars = re_variable.Matches(src); Match mVar; foreach(Match m in mcVars) { mVar = re_splitVariable.Match(m.Value); if (!mVar.Success) continue; // parse method definition keys = mVar.Groups["keys"].Value; member = new ASMember(); member.Flags = FlagType.Variable; // keywords if (keys.IndexOf("private") >= 0) member.Flags |= FlagType.Private; else member.Flags |= FlagType.Public; isStatic = (keys.IndexOf("static") >= 0); if (isStatic) member.Flags |= FlagType.Static; else member.Flags |= FlagType.Dynamic; // comments mComments = re_commentIndex.Match(keys); if (mComments.Success) member.Comments = comments[ Convert.ToInt16(mComments.Groups["index"].Value) ]; // name member.Name = mVar.Groups["pname"].Value; // type mType = re_variableType.Match(mVar.Groups["type"].Value); if (mType.Success) member.Type = mType.Groups["type"].Value; else member.Type = "Object"; // store aClass.Vars.Add(member); } // HACK AS3 'const' declarations if (AS3package != null) { mcVars = re_constant.Matches(src); foreach(Match m in mcVars) { mVar = re_splitConstant.Match(m.Value); if (!mVar.Success) continue; // parse method definition keys = mVar.Groups["keys"].Value; member = new ASMember(); member.Flags = FlagType.Variable; // keywords if (keys.IndexOf("private") >= 0) member.Flags |= FlagType.Private; else member.Flags |= FlagType.Public; isStatic = (keys.IndexOf("static") >= 0); if (isStatic) member.Flags |= FlagType.Static; else member.Flags |= FlagType.Dynamic; // comments mComments = re_commentIndex.Match(keys); if (mComments.Success) member.Comments = comments[ Convert.ToInt16(mComments.Groups["index"].Value) ]; // name member.Name = mVar.Groups["pname"].Value; // type mType = re_variableType.Match(mVar.Groups["type"].Value); if (mType.Success) member.Type = mType.Groups["type"].Value; else member.Type = "Object"; // store aClass.Vars.Add(member); } } // is also a package? //DebugConsole.Trace("check folder "+aClass.FileName.Substring(0, aClass.FileName.Length-3)); if (System.IO.Directory.Exists(aClass.FileName.Substring(0, aClass.FileName.Length-3))) { string package = aClass.FileName.Substring(aClass.BasePath.Length); package = package.Substring(0, package.IndexOf('.')); ASMemberList pList = context.GetSubClasses(package); if ((pList != null) && (pList.Count > 0)) { //DebugConsole.Trace("Sub classes/packages "+package+" "+pList.Count); aClass.Flags |= FlagType.Package; aClass.Package = pList; // if intrinsic class, inherit flag if ((aClass.Flags & FlagType.Intrinsic) == FlagType.Intrinsic) foreach(ASMember import in pList) import.Flags |= FlagType.Intrinsic; } } // done }
private void delayedClassTreeSelect(Object sender, System.Timers.ElapsedEventArgs e) { TreeNode node = classTree.SelectedNode; if (node == null) { return; } try { // class node if (node.Parent == null) { if (node.Tag != null) { ASContext.MainForm.OpenSelectedFile((string)node.Tag); } } // group node else if (node.Nodes.Count > 0) { node.Toggle(); } // leaf node else if ((node.Parent != null) && (node.Parent.Tag == null)) { TreeNode classNode = node.Parent.Parent; ScintillaNet.ScintillaControl sci = ASContext.MainForm.CurSciControl; // for Back command: if (sci != null) { SetLastLookupPosition(ASContext.CurrentFile, sci.CurrentPos); } // int index = node.Parent.Index; // extends if (showExtend && index == 0) { if (node.Tag != null) { ASContext.MainForm.OpenSelectedFile((string)node.Tag); } } // import else if (showImports && ((showExtend && index == 1) || (!showExtend && index == 0))) { ASClass aClass = ASContext.FindClassFromFile((string)classNode.Tag); if (aClass.IsVoid()) { return; } ASContext.OpenFileFromClass(node.Text, aClass); } // members else if (node.Tag != null) { ASContext.MainForm.OpenSelectedFile((string)classNode.Tag); sci = ASContext.MainForm.CurSciControl; if (sci == null) { return; } // look for declaration string pname = Regex.Escape((string)node.Tag); Match m = null; switch (node.ImageIndex) { case 12: // method case 3: m = Regex.Match(sci.Text, "function[\\s]+(?<pname>" + pname + ")[\\s]*\\("); break; case 13: // property case 4: m = Regex.Match(sci.Text, "function[\\s]+(?<pname>(g|s)et[\\s]+" + pname + ")[\\s]*\\("); break; case 14: // variables case 5: m = Regex.Match(sci.Text, "var[\\s]+(?<pname>" + pname + ")[^\\w]"); break; } // show if (m != null && m.Success) { GotoPosAndFocus(sci, m.Groups["pname"].Index); sci.SetSel(sci.CurrentPos, sci.CurrentPos + m.Groups["pname"].Length); } } } } catch (Exception ex) { ErrorHandler.ShowError(ex.Message, ex); } }
public static string ClassDeclaration(ASClass oClass) { // package if (oClass.Flags == FlagType.Package) { return "package "+oClass.ClassName.Replace('\\', '.'); } else { // modifiers string modifiers = ""; if ((oClass.Flags & FlagType.Intrinsic) > 0) modifiers += "intrinsic "; if ((oClass.Flags & FlagType.Dynamic) > 0) modifiers += "dynamic "; string classType = ((oClass.Flags & FlagType.Interface) > 0) ? "interface" : "class"; // signature return String.Format("{0}{1} {2}", modifiers, classType, oClass.ClassName); } }
public void ResolveWildcards(string package, ASClass inClass, ArrayList known) { ASContext.ResolveImports(package, inClass, known); }
public ASClass GetClassByName(string cname, ASClass inClass) { // avoid class inheritance infinite loop if (inClass != null && ASContext.classes[inClass.ClassName] == null) { ASContext.classes[inClass.ClassName] = inClass; } return ASContext.FindClassFromName(cname, inClass); }
/// <summary> /// Prepare Flash intrinsic know vars/methods/classes /// </summary> static private void ResolveTopLevelElements() { // // search top-level class // if (useMtascClasses) { topLevel = FindClassFromName("TopLevel",null); } else { topLevel = new ASClass(); topLevel.FileName = MMClassPath+"toplevel.as"; topLevel.OutOfDate = true; string src; // read file content try { StreamReader sr = new StreamReader(topLevel.FileName); src = sr.ReadToEnd(); sr.Close(); } catch (System.IO.FileNotFoundException) { // ignore files that don't exist (i.e. "Untitled.as") return; } catch(Exception ex) { ErrorHandler.ShowError(ex.Message+"\n"+topLevel.FileName, ex); return; } // make it look like a valid class src = "class toplevel {"+src+"}"; // parse ASClassParser.ParseClass(topLevel, src); } // not found if (topLevel.IsVoid()) { ErrorHandler.ShowInfo("Top-level elements class not found. Please check your Program Settings."); return; } // // init top-level elements // topLevel.ClassName = "top-level"; topLevel.Extends = new ASClass(); // special vars ASMember special; if (topLevel.Vars.Search("_root",0) == null) { special = new ASMember(); special.Name = "_root"; special.Flags = FlagType.Variable; special.Type = "MovieClip"; topLevel.Vars.Add(special); } if (topLevel.Vars.Search("_global",0) == null) { special = new ASMember(); special.Name = "_global"; special.Flags = FlagType.Variable; special.Type = "Object"; topLevel.Vars.Add(special); } if (topLevel.Vars.Search("this",0) == null) { special = new ASMember(); special.Name = "this"; special.Flags = FlagType.Variable; special.Type = "Object"; topLevel.Vars.Add(special); } if (topLevel.Vars.Search("super",0) == null) { special = new ASMember(); special.Name = "super"; special.Flags = FlagType.Variable; special.Type = "Object"; topLevel.Vars.Add(special); } // pre-sort topLevel.Sort(); // all intrinsic methods/vars foreach(ASMember member in topLevel.Methods) member.Flags |= FlagType.Intrinsic; foreach(ASMember member in topLevel.Vars) member.Flags |= FlagType.Intrinsic; // list instrinsic classes string package; ASMember newImport; foreach(string path in classPath) try { string[] files = System.IO.Directory.GetFiles(path, "*.as"); if (files == null) continue; // add classes found string iname; int plen = path.Length; foreach(string file in files) { package = file.Substring(plen,file.Length-3-plen).Replace(dirSeparator, "."); iname = GetLastStringToken(package, "."); newImport = new ASMember(); newImport.Name = iname; newImport.Type = package; newImport.Flags = FlagType.Intrinsic; if (!iname.Equals("TopLevel") && !iname.Equals("StdPresent") && (iname.IndexOf(' ') < 0) && (topLevel.Imports.Search(iname, 0) == null)) topLevel.Imports.Add(newImport); } } catch(Exception ex) { ErrorHandler.ShowError(ex.Message+"\n"+path, ex); continue; } // special case newImport = new ASMember(); newImport.Name = newImport.Type = "Void"; newImport.Flags = FlagType.Intrinsic; topLevel.Imports.Add(newImport); topLevel.Imports.Sort(); }
/// <summary> /// Generate an instrinsic class /// </summary> /// <param name="files">Semicolon-separated source & destination files</param> static public void MakeIntrinsic(string files) { string src = cFile; string dest = null; if ((files != null) && (files.Length > 0)) { string[] list = files.Split(';'); if (list.Length == 1) dest = list[0]; else { src = list[0]; dest = list[1]; } } ASClass aClass; if (src == cFile) aClass = cClass; else { aClass = new ASClass(); aClass.FileName = src; ASClassParser.ParseClass(aClass); } if (aClass.IsVoid()) return; // string code = aClass.GenerateIntrinsic(); // no destination, replace text if (dest == null) { MainForm.CallCommand("New", null); MainForm.CurSciControl.CurrentPos = 0; MainForm.CurSciControl.Text = code; return; } // write destination try { StreamWriter writer = System.IO.File.CreateText(dest); writer.Write(code); writer.Close(); } catch (Exception ex) { ErrorHandler.ShowError("IO error while writing the intrinsic class.", ex); } }
/// <summary> /// Search a class in classpath and open the file in editor /// </summary> /// <param name="classname">Class name</param> /// <returns>Success</returns> static public bool OpenFileFromClass(string classname, ASClass fromClass) { ASClass aClass = FindClassFromName(classname, fromClass); if (!aClass.IsVoid()) { MainForm.OpenSelectedFile(aClass.FileName); return true; } else { ErrorHandler.ShowInfo("Class not found: "+classname); return false; } }
/// <summary> /// (Re)Parse and cache a class file /// </summary> /// <param name="aClass">Class object</param> /// <returns>The class object</returns> public ASClass UpdateClass(ASClass aClass) { return aClass; }
/// <summary> /// Retrieves a parsed class from its filename /// </summary> /// <param name="fileName">Class' file name</param> /// <returns>A parsed class or an empty ASClass if the class is not found or invalid</returns> public ASClass FindClassFromFile(string fileName) { ASClass aClass = new ASClass(); aClass.FileName = fileName; return aClass; }
/// <summary> /// Retrieves a parsed class from its filename /// </summary> /// <param name="fileName">Class' file name</param> /// <returns>A parsed class or an empty ASClass if the class is not found or invalid</returns> public ASClass GetClassByFile(string fileName) { ASClass aClass = new ASClass(); aClass.FileName = fileName; return aClass; }
/// <summary> /// (Re)Parse and cache a class file /// </summary> /// <param name="aClass">Class object</param> /// <returns>The class object</returns> public ASClass GetCachedClass(ASClass aClass) { return ASContext.UpdateClass(aClass); }
/// <summary> /// Retrieves a parsed class from its name /// </summary> /// <param name="cname">Class (short or full) name</param> /// <param name="inClass">Current class</param> /// <returns>A parsed class or an empty ASClass if the class is not found</returns> public ASClass FindClassFromName(string cname, ASClass inClass) { ASClass aClass = new ASClass(); aClass.ClassName = cname; return aClass; }
/// <summary> /// (Re)Parse and cache a class file /// </summary> /// <param name="aClass">Class object</param> /// <returns>The class object</returns> static public ASClass UpdateClass(ASClass aClass) { if (!aClass.OutOfDate || (classes == null)) return aClass; // remove from cache if (!aClass.IsVoid()) classes.Remove(aClass.ClassName); // (re)parse aClass.OutOfDate = false; ASClassParser.ParseClass(aClass); // add to cache AddClassToCache(aClass); return aClass; }
/** * Handles the incoming events */ public void HandleEvent(object sender, NotifyEvent e) { if (e.Type != EventType.UIRefresh) { DebugConsole.Trace("*** " + e.Type.ToString()); } // editor context ScintillaNet.ScintillaControl sci = ASContext.MainForm.CurSciControl; if (sci == null) { DebugConsole.Trace("null SCI"); return; } /** * Other events always handled */ bool isValid; switch (e.Type) { // key combinations case EventType.Shortcut: DebugConsole.Trace("Key " + ((KeyEvent)e).Value); e.Handled = ASComplete.OnShortcut(((KeyEvent)e).Value, sci); return; // // File management // case EventType.FileSave: // update view if needed ASContext.CurrentClass.IsVoid(); // toolbar isValid = ASContext.IsClassValid(); this.SetItemsEnabled(isValid); if (isValid) { if (ASContext.CheckOnSave) { AutoCheckActionScript(); } ASContext.RemoveClassASO(); } return; case EventType.LanguageChange: case EventType.FileSwitch: DebugConsole.Trace("Switch to " + ASContext.MainForm.CurFile); if (e.Type == EventType.LanguageChange) { // remove file from the treeview (it will be re-checked and re-added later) ASContext.Panel.RemoveFromView(ASContext.MainForm.CurFile); } // check class if ((sci.ConfigurationLanguage == "as2" || sci.ConfigurationLanguage == "as3") && !ASContext.MainForm.CurDocIsUntitled()) { ASContext.CurrentFile = ASContext.MainForm.CurFile; } else { ASContext.CurrentFile = ""; } // toolbar isValid = ASContext.IsClassValid(); this.SetItemsEnabled(isValid); // check on open /*if (justOpenFile) * { * justOpenFile = true; * if (isValid && ASContext.CheckOnSave) * AutoCheckActionScript(); * }*/ return; /*case EventType.FileOpen: * justOpenFile = true; * return;*/ case EventType.FileClose: DebugConsole.Trace("Close " + ASContext.MainForm.CurFile); this.pluginUI.RemoveFromView(ASContext.MainForm.CurFile); return; case EventType.SettingUpdate: ASContext.UpdateSettings(); AS3.Flex2Shell.UpdateSettings(); break; // some commands work all the time case EventType.Command: string command = ((TextEvent)e).Text; // add a custom classpath if (command.StartsWith("ASCompletion;ClassPath;")) { int p = command.IndexOf(';', 15); ASContext.ExternalClassPath = command.Substring(p + 1); e.Handled = true; } // clear the classes cache else if (command.StartsWith("ASCompletion;ClearClassCache")) { ClearClassCache(null, null); e.Handled = true; } else if (command == "ASCompletion.SendContext") { DataEvent de = new DataEvent(EventType.CustomData, "ASCompletion.Context", new ASContext()); MainForm.DispatchEvent(de); e.Handled = true; } // call the Flash IDE else if (command.StartsWith("CallFlashIDE")) { string flashexe = MainForm.MainSettings.GetValue(SETTING_MACROMEDIA_FLASHIDE); if ((flashexe.Length == 0) || !System.IO.File.Exists(flashexe)) { ErrorHandler.ShowInfo("The path to Flash.exe is not configured properly."); } // save modified files this.mainForm.CallCommand("SaveAllModified", null); // run the Flash IDE if (command.IndexOf(';') > 0) { string args = MainForm.ProcessArgString(command.Substring(command.IndexOf(';') + 1)); if (args.IndexOf('"') < 0) { args = '"' + args + '"'; } System.Diagnostics.Process.Start(flashexe, args); } else { System.Diagnostics.Process.Start(flashexe); } e.Handled = true; } // run the Flex 2 compilet else if (command.StartsWith("RunMxmlc;")) { AS3.Flex2Shell.Instance.RunMxmlc(command.Substring(9)); } break; } /** * Actionscript context specific */ if ((sci.Lexer == 3) && ASContext.IsClassValid()) { switch (e.Type) { case EventType.ProcessArgs: TextEvent te = (TextEvent)e; string cmd = te.Text; if (cmd.IndexOf("@") > 0) { // resolve current element Hashtable details = ASComplete.ResolveElement(sci, null); // resolve current class details if (details == null) { ASClass oClass = ASContext.CurrentClass; details = new Hashtable(); details.Add("@CLASSDECL", ASClass.MemberDeclaration(oClass.ToASMember())); int p = oClass.ClassName.LastIndexOf('.'); if (p > 0) { details.Add("@CLASSPACKAGE", oClass.ClassName.Substring(0, p)); details.Add("@CLASSNAME", oClass.ClassName.Substring(p + 1)); } else { details.Add("@CLASSPACKAGE", ""); details.Add("@CLASSNAME", oClass.ClassName); } details.Add("@CLASSFULLNAME", oClass.ClassName); details.Add("@MEMBERKIND", ""); details.Add("@MEMBERNAME", ""); details.Add("@MEMBERDECL", ""); details.Add("@MEMBERCLASSPACKAGE", ""); details.Add("@MEMBERCLASSNAME", ""); details.Add("@MEMBERCLASSFILE", ""); details.Add("@MEMBERCLASSDECL", ""); } // complete command foreach (string key in details.Keys) { cmd = cmd.Replace(key, (string)details[key]); } te.Text = cmd; } break; // menu commands case EventType.Command: string command = ((TextEvent)e).Text; DebugConsole.Trace(command); if (command.StartsWith("ASCompletion;")) { // run MTASC if (command.StartsWith("ASCompletion;MtascRun")) { int p = command.IndexOf(';', 15); if (p > 15) { ASContext.RunMTASC(command.Substring(p + 1)); } else { ASContext.RunMTASC(""); } e.Handled = true; } // build the SWF using MTASC else if (command.StartsWith("ASCompletion;MtascBuild")) { ASContext.BuildMTASC(false); e.Handled = true; } // resolve element under cusor and open declaration else if (command.StartsWith("ASCompletion;GotoDeclaration")) { ASComplete.DeclarationLookup(sci); e.Handled = true; } // resolve element under cursor and send a CustomData event else if (command.StartsWith("ASCompletion;ResolveElement;")) { int p = command.IndexOf(';', 15); ASComplete.ResolveElement(sci, command.Substring(p + 1)); e.Handled = true; } else if (command.StartsWith("ASCompletion;MakeIntrinsic")) { int p = command.IndexOf(';', 15); if (p > 15) { ASContext.MakeIntrinsic(command.Substring(p + 1)); } else { ASContext.MakeIntrinsic(null); } e.Handled = true; } } return; case EventType.ProcessEnd: string result = ((TextEvent)e).Text; ASContext.OnProcessEnd(result); break; } } }
/// <summary> /// Add the class object to a cache /// </summary> /// <param name="aClass">Class object to cache</param> static private bool AddClassToCache(ASClass aClass) { if (!aClass.IsVoid()) { ASClass check = (ASClass)classes[aClass.ClassName]; if (check != null && lastClassWarning != aClass.ClassName) { // if this class was defined in another file, check if it is still open if (String.CompareOrdinal(check.FileName, aClass.FileName) != 0) { ScintillaNet.ScintillaControl sci = MainForm.CurSciControl; WeifenLuo.WinFormsUI.DockContent[] docs = MainForm.GetDocuments(); int found = 0; bool isActive = false; string tabFile; // check if the classes are open foreach(WeifenLuo.WinFormsUI.DockContent doc in docs) { tabFile = (string)MainForm.GetSciControl(doc).Tag; //FileName; if (String.CompareOrdinal(check.FileName, tabFile) == 0 || String.CompareOrdinal(aClass.FileName, tabFile) == 0) { if (MainForm.GetSciControl(doc) == sci) isActive = true; found++; } } // if there are several files declaring the same class if (found > 1 && isActive) { lastClassWarning = aClass.ClassName; Match cdecl = Regex.Match(sci.Text, "[\\s]class[\\s]+(?<cname>"+aClass.ClassName+")[^\\w]"); int line = 1; if (cdecl.Success) { line = 1+sci.LineFromPosition( sci.MBSafeCharPosition(cdecl.Groups["cname"].Index) ); } string msg = String.Format("The class '{2}' is already declared in {3}", aClass.FileName, line, aClass.ClassName, check.FileName); MessageBar.ShowWarning(msg); } else lastClassWarning = null; } } classes[aClass.ClassName] = aClass; return true; } return false; }
/// <summary> /// Parse a class from file /// </summary> /// <param name="aClass">Class object</param> /// <param name="filename">Class filename</param> static public void ParseClass(ASClass aClass) { string src; // read file content try { if (!File.Exists(aClass.FileName)) return; StreamReader sr = new StreamReader(aClass.FileName); src = sr.ReadToEnd(); sr.Close(); } catch (Exception ex) { context.DisplayError(ex.Message); return; } // parse ParseClass(aClass, src); }
/// <summary> /// Resolve wildcards in imports /// </summary> /// <param name="package">Package to explore</param> /// <param name="inClass">Current class</param> /// <param name="known">Packages already added</param> static public void ResolveImports(string package, ASClass inClass, ArrayList known) { string subpath; string path; string[] files; // validation if ((package == null) || (inClass == null)) return; subpath = package.Replace(".", dirSeparator); // search in classpath ASMember newImport; foreach(string basepath in classPath) try { if (System.IO.Directory.Exists(basepath+subpath)) { path = basepath+subpath; DebugConsole.Trace("Search "+path); files = System.IO.Directory.GetFiles(path, "*.as"); if (files == null) continue; // add classes found int plen = basepath.Length; foreach(string file in files) { package = file.Substring(plen,file.Length-3-plen).Replace(dirSeparator,"."); if (known.Contains(package)) continue; known.Add(package); // newImport = new ASMember(); newImport.Name = GetLastStringToken(package, "."); newImport.Type = package; inClass.Imports.Add(newImport); } } } catch(Exception ex) { ErrorHandler.ShowError(ex.Message+"\n"+basepath+subpath, ex); } }
/// <summary> /// Parse import statements in source /// </summary> /// <param name="src">Class source</param> /// <param name="aClass">Class object to update</param> static private void ParseImports(string src, ASClass aClass) { aClass.Imports.Clear(); src = src.Replace('\r', '\n'); // fix .NET Regex line-ends detection MatchCollection mcImports = re_import.Matches(src); if (mcImports.Count > 0) { ArrayList known = new ArrayList(); string package; string cname; ASMember newImport; foreach(Match mImport in mcImports) { package = mImport.Groups["package"].Value; //DebugConsole.Trace("IMPORT '"+package+"'"); int p = package.LastIndexOf("."); cname = (p >= 0) ? package.Substring(p+1) : package; // resolve wildcard if (cname.Length == 0) { context.ResolveWildcards(package, aClass, known); } else if (!known.Contains(package)) { known.Add(package); newImport = new ASMember(); newImport.Name = cname; newImport.Type = package; aClass.Imports.Add(newImport); } } } //else DebugConsole.Trace("NO IMPORTS"); }
/// <summary> /// Retrieves a parsed class from its name /// </summary> /// <param name="cname">Class (short or full) name</param> /// <param name="inClass">Current class</param> /// <returns>A parsed class or an empty ASClass if the class is not found</returns> static public ASClass FindClassFromName(string cname, ASClass inClass) { ASClass aClass; if ((cname == null) || (cname.Length == 0)) cname = defaultMethodReturnType; if (inClass != null) DebugConsole.Trace("Find class "+cname+" in "+inClass.ClassName); else DebugConsole.Trace("Find class "+cname); // unknown if (cname.ToLower() == "void" || classes == null) return new ASClass(); if (inClass != null && !inClass.IsVoid()) { // current class if (inClass.Extends != null && (inClass.ClassName.IndexOf('.') > 0) && (cname == GetLastStringToken(inClass.ClassName, "."))) { cname = inClass.ClassName; } // complete class name else if (cname.IndexOf(".") < 0) { // search in imported classes foreach(ASMember path in inClass.Imports) if (path.Name == cname) { cname = path.Type; break; } } } // retrieve class from cache aClass = (ASClass)classes[cname]; if (aClass != null) return UpdateClass(aClass); // search in intrinsic classes /*if ((topLevel != null) && !topLevel.IsVoid() && (cname.IndexOf(".") < 0)) foreach(ASMember import in topLevel.Imports) { if (import.Name == cname) { DebugConsole.Trace("Use intrinsic class "+cname); if (cname.ToLower() == "void") return new ASClass(); else return FindClassFromFile(topLevel.BasePath+cname+".as"); } }*/ DebugConsole.Trace("In classpath "+cname); // search in classpath aClass = new ASClass(); string file = cname.Replace(".", dirSeparator)+".as"; foreach(string path in classPath) try { DebugConsole.Trace("Try "+path+file); if (System.IO.File.Exists(path+file)) { // case sensitive check string[] check = System.IO.Directory.GetFiles(path, file); if (check.Length == 0) continue; if (check[0].LastIndexOf(file) != check[0].Length-file.Length) continue; // parse file aClass.FileName = check[0]; ASClassParser.ParseClass(aClass); if (!aClass.IsVoid()) { classes[aClass.ClassName] = aClass; break; } } } catch(Exception ex) { ErrorHandler.ShowError(ex.Message+"\n"+path+file, ex); } // no match return aClass; }
/// <summary> /// Parse a class from source /// </summary> /// <param name="aClass">Class object</param> /// <param name="src">Class source</param> static public void ParseClass(ASClass aClass, string src) { // remove comments StringCollection comments = new StringCollection(); src = CleanClassSource(src, comments); // check class definition Match mClass = re_class.Match(src); if (!mClass.Success) { aClass.ClassName = null; return; } // classname string prevCName = aClass.ClassName; aClass.ClassName = mClass.Groups["cname"].Value; // HACK AS3 package support string preClassSrc = src.Substring(0, mClass.Groups["ctype"].Index); string AS3package = null; Match mPackage = re_AS3package.Match(preClassSrc); if (mPackage.Success) { aClass.IsAS3 = true; AS3package = mPackage.Groups["name"].Value; if (AS3package != null && AS3package.Length > 0) { aClass.ClassName = AS3package + "." + aClass.ClassName; } } else { aClass.IsAS3 = false; } // check classname int p = aClass.ClassName.LastIndexOf("."); string constructor = (p >= 0) ? aClass.ClassName.Substring(p + 1) : aClass.ClassName; string classType = mClass.Groups["ctype"].Value; if (src.Substring(0, mClass.Groups["cname"].Index).IndexOf(" comment0 ") >= 0) { aClass.Comments = comments[0]; } // class base path bool validClassFile = true; int basepos = aClass.FileName.LastIndexOf(aClass.ClassName.Replace('.', Path.DirectorySeparatorChar) + ".as"); if (basepos < 0) { // this class name & file don't match, it can lead to dangerous errors validClassFile = false; // warm about the misspelled class name if (!aClass.FileName.EndsWith("/" + constructor + ".as") || !aClass.FileName.ToUpper().EndsWith("\\" + aClass.ClassName.ToUpper().Replace('.', '\\') + ".AS")) { if (prevCName != aClass.ClassName) { string msg = String.Format("The {0} '{1}' does not match the file name:\n{2}", classType, aClass.ClassName, aClass.FileName); context.DisplayError(msg); } } aClass.BasePath = System.IO.Path.GetDirectoryName(aClass.FileName) + "\\"; } else { aClass.BasePath = aClass.FileName.Substring(0, basepos); } // add to classpath context.SetTemporaryBasePath(aClass.FileName, aClass.BasePath); // class flag aClass.Flags = FlagType.Class; if (classType == "interface") { aClass.Flags |= FlagType.Interface; } if (mClass.Groups["keys"].Value.IndexOf("intrinsic") >= 0) { aClass.Flags |= FlagType.Intrinsic; } if (mClass.Groups["keys"].Value.IndexOf("dynamic") >= 0) { aClass.Flags |= FlagType.Dynamic; } // import statements ParseImports(preClassSrc, aClass); preClassSrc = null; // inheritance string herit = mClass.Groups["herit"].Value; Match mExtends = re_extends.Match(herit); string extends = (validClassFile && mExtends.Success) ? mExtends.Groups["cname"].ToString() : "Object"; if ((extends != aClass.ClassName) && (aClass.ClassName != "TopLevel")) { aClass.Extends = null; // resolve extended class ASClass extendsClass = context.GetClassByName(extends, aClass); // detect infinite extension loop ASClass tmpClass = extendsClass; while (tmpClass != null) { if (tmpClass == aClass) { string msg = String.Format("The {0} '{1}' extends itself.", classType, aClass.ClassName); context.DisplayError(msg); extendsClass = null; break; } tmpClass = tmpClass.Extends; } if (extendsClass != null) { aClass.Extends = extendsClass; } else { aClass.Extends = new ASClass(); } } Match mImplements = re_implements.Match(herit); if (mImplements.Success) { string implements; if (!mExtends.Success || mImplements.Index > mExtends.Index) { implements = herit.Substring(mImplements.Index + mImplements.Length).Trim(); } else { implements = herit.Substring(mImplements.Index + mImplements.Length, mExtends.Index - mImplements.Index - mImplements.Length).Trim(); } aClass.Implements = re_parametersSeparator.Replace(implements, ", "); } else { aClass.Implements = null; } // clean class body src = "; " + src.Substring(mClass.Groups["herit"].Index + mClass.Groups["herit"].Value.Length + 1); src = re_balancedBraces.Replace(src, ";"); // if updating, clear aClass.Methods.Clear(); aClass.Properties.Clear(); aClass.Vars.Clear(); // parse functions string keys; bool isStatic; MatchCollection mcFunc = re_functions.Matches(src); Match mFunc; Match mType; Match mComments; ASMember member; foreach (Match m in mcFunc) { mFunc = re_splitFunction.Match(m.Value); if (!mFunc.Success) { continue; } // keywords keys = mFunc.Groups["keys"].Value; member = new ASMember(); member.Flags = FlagType.Function; if (keys.IndexOf("private") >= 0) { member.Flags |= FlagType.Private; } else { member.Flags |= FlagType.Public; } isStatic = (keys.IndexOf("static") >= 0); if (isStatic) { member.Flags |= FlagType.Static; } else { member.Flags |= FlagType.Dynamic; } // comments if (comments.Count > 0) { mComments = re_commentIndex.Match(keys); if (mComments.Success) { member.Comments = comments[Convert.ToInt16(mComments.Groups["index"].Value)]; } } // method member.Name = mFunc.Groups["fname"].Value.Trim(); if (member.Name.Length == 0) { continue; } // parameters member.Parameters = re_colonParams.Replace(re_parametersSeparator.Replace(mFunc.Groups["params"].Value.Trim(), ", "), ":"); // return type mType = re_variableType.Match(mFunc.Groups["type"].Value); if (mType.Success) { member.Type = mType.Groups["type"].Value; } else { member.Type = ""; } // constructor type if (member.Name == constructor) { member.Flags |= FlagType.Constructor; member.Type = constructor; } // getter/setter if ((member.Name.Length > 4) && ((int)member.Name[3] < 33)) { Match mProp = re_isGetterSetter.Match(member.Name); if (mProp.Success) { string pname = mProp.Groups["pname"].Value; ASMember prop = aClass.Properties.Search(pname, 0); if (prop == null) { prop = member; prop.Name = pname; prop.Flags -= FlagType.Function; aClass.Properties.Add(prop); } if (mProp.Groups["type"].Value == "g") { prop.Flags |= FlagType.Getter; prop.Type = member.Type; if (!mType.Success) { prop.Type = "Object"; } } else { prop.Flags |= FlagType.Setter; prop.Parameters = member.Parameters; } if ((member.Comments != null) && ((prop.Comments == null) || (prop.Comments.Length < member.Comments.Length))) { prop.Comments = member.Comments; } } // store method else { aClass.Methods.Add(member); } } // store method else { aClass.Methods.Add(member); } } // parse variables MatchCollection mcVars = re_variable.Matches(src); Match mVar; foreach (Match m in mcVars) { mVar = re_splitVariable.Match(m.Value); if (!mVar.Success) { continue; } // parse method definition keys = mVar.Groups["keys"].Value; member = new ASMember(); member.Flags = FlagType.Variable; // keywords if (keys.IndexOf("private") >= 0) { member.Flags |= FlagType.Private; } else { member.Flags |= FlagType.Public; } isStatic = (keys.IndexOf("static") >= 0); if (isStatic) { member.Flags |= FlagType.Static; } else { member.Flags |= FlagType.Dynamic; } // comments mComments = re_commentIndex.Match(keys); if (mComments.Success) { member.Comments = comments[Convert.ToInt16(mComments.Groups["index"].Value)]; } // name member.Name = mVar.Groups["pname"].Value; // type mType = re_variableType.Match(mVar.Groups["type"].Value); if (mType.Success) { member.Type = mType.Groups["type"].Value; } else { member.Type = "Object"; } // store aClass.Vars.Add(member); } // HACK AS3 'const' declarations if (AS3package != null) { mcVars = re_constant.Matches(src); foreach (Match m in mcVars) { mVar = re_splitConstant.Match(m.Value); if (!mVar.Success) { continue; } // parse method definition keys = mVar.Groups["keys"].Value; member = new ASMember(); member.Flags = FlagType.Variable; // keywords if (keys.IndexOf("private") >= 0) { member.Flags |= FlagType.Private; } else { member.Flags |= FlagType.Public; } isStatic = (keys.IndexOf("static") >= 0); if (isStatic) { member.Flags |= FlagType.Static; } else { member.Flags |= FlagType.Dynamic; } // comments mComments = re_commentIndex.Match(keys); if (mComments.Success) { member.Comments = comments[Convert.ToInt16(mComments.Groups["index"].Value)]; } // name member.Name = mVar.Groups["pname"].Value; // type mType = re_variableType.Match(mVar.Groups["type"].Value); if (mType.Success) { member.Type = mType.Groups["type"].Value; } else { member.Type = "Object"; } // store aClass.Vars.Add(member); } } // is also a package? //DebugConsole.Trace("check folder "+aClass.FileName.Substring(0, aClass.FileName.Length-3)); if (System.IO.Directory.Exists(aClass.FileName.Substring(0, aClass.FileName.Length - 3))) { string package = aClass.FileName.Substring(aClass.BasePath.Length); package = package.Substring(0, package.IndexOf('.')); ASMemberList pList = context.GetSubClasses(package); if ((pList != null) && (pList.Count > 0)) { //DebugConsole.Trace("Sub classes/packages "+package+" "+pList.Count); aClass.Flags |= FlagType.Package; aClass.Package = pList; // if intrinsic class, inherit flag if ((aClass.Flags & FlagType.Intrinsic) == FlagType.Intrinsic) { foreach (ASMember import in pList) { import.Flags |= FlagType.Intrinsic; } } } } // done }
/// <summary> /// Look for a class in cache or parse a new class /// </summary> /// <param name="filename">Wanted class file</param> /// <returns>Parsed class</returns> static public ASClass FindClassFromFile(string filename) { if ((filename == null) || (filename.Length == 0)) return new ASClass(); // search existing class string fname = filename.ToUpper(); DebugConsole.Trace("FromFile "+filename); IDictionaryEnumerator de = classes.GetEnumerator(); while (de.MoveNext()) if ( ((ASClass)de.Value).FileName.ToUpper() == fname ) { DebugConsole.Trace("Found "+((ASClass)de.Value).ClassName); return UpdateClass( (ASClass)de.Value ); } // if unknown, parse and cache ASClass aClass = new ASClass(); aClass.FileName = filename; aClass.OutOfDate = true; return UpdateClass(aClass); }
public void UpdateAndActive(ASClass aClass) { try { classTree.BeginUpdate(); if (aClass.IsVoid()) AddInView(ASContext.MainForm.CurFile); else UpdateView(aClass); SetActiveClass(aClass); } finally { classTree.EndUpdate(); Win32.Scrolling.scrollToLeft(classTree); } }
/// <summary> /// Resolve wildcards in imports /// </summary> /// <param name="package">Package to explore</param> /// <param name="inClass">Current class</param> /// <param name="known">Packages already added</param> public void ResolveWildcards(string package, ASClass inClass, ArrayList known) { if (!known.Contains(package)) { known.Add(package); ASMember pMember = new ASMember(); pMember.Name = package+"*"; pMember.Type = package+"*"; inClass.Imports.Add(pMember); } }
public void UpdateView(ASClass aClass) { bool updateToken = false; try { DebugConsole.Trace("UI: update "+aClass.ClassName); if (aClass.IsVoid()) return; // compute class data "checksum" to know if it changed string fileName = aClass.FileName; string prevDataCheck = (string)checkEntries[fileName]; StringBuilder sb = new StringBuilder().Append(aClass.Extends.ClassName); foreach(ASMember import in aClass.Imports) sb.Append(import.Name); foreach(ASMember method in aClass.Methods) sb.Append(method.Flags.ToString()).Append(method.ToString()); foreach(ASMember prop in aClass.Properties) sb.Append(prop.Flags.ToString()).Append(prop.ToString()); foreach(ASMember var in aClass.Vars) sb.Append(var.Flags.ToString()).Append(var.ToString()); string classDataCheck = sb.ToString(); // for tree exploration TreeNodeCollection nodes = classTree.Nodes; TreeNode node = null; TreeNode insertBefore = null; // re-sort imports by package aClass.Sort(); ASMemberList import2 = new ASMemberList(); ASMember newImport; foreach(ASMember import in aClass.Imports) { newImport = new ASMember(); newImport.Name = import.Type; import2.Add(newImport); } import2.Sort(); // search item insertion/update position string cname = aClass.ClassName; bool entryExists = false; foreach(TreeNode sub in nodes) { if (sub.Text == cname) { node = sub; entryExists = true; break; } else if (sub.Text.CompareTo(cname) > 0) { insertBefore = sub; break; } } // New class if (node == null) { updateToken = true; classTree.BeginStatefulUpdate(); // create class node node = new TreeNode(cname); node.Tag = aClass.FileName; if (insertBefore != null) nodes.Insert(insertBefore.Index, node); else nodes.Add(node); // class details nodes if (showExtend) node.Nodes.Add(new TreeNode("Extends",1,1)); if (showImports) node.Nodes.Add(new TreeNode("Imports",1,1)); // class members nodes if (memberGroups == 1) { node.Nodes.Add(new TreeNode("Members",1,1)); } else { if (memberGroups > 1) { node.Nodes.Add(new TreeNode("Methods",1,1)); node.Nodes.Add(new TreeNode("Properties",1,1)); } if (memberGroups > 2) node.Nodes.Add(new TreeNode("Variables",1,1)); } } // Check class infos else { if (classDataCheck == prevDataCheck) return; updateToken = true; classTree.BeginStatefulUpdate(); } // // UPDATE CLASS INFO // checkEntries[fileName] = classDataCheck; int index = 0; TreeNode sub2; // entends if (showExtend) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); if (!aClass.Extends.IsVoid()) { if ((aClass.Extends.Flags & FlagType.Intrinsic) > 0) sub2 = new TreeNode(aClass.Extends.ClassName, 7,7); else sub2 = new TreeNode(aClass.Extends.ClassName, 0,0); sub2.Tag = aClass.Extends.FileName; nodes.Add(sub2); } } // imports if (showImports) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); foreach(ASMember import in import2) { if ((import.Flags & FlagType.Intrinsic) > 0) nodes.Add(new TreeNode(import.Name, 7,7)); else nodes.Add(new TreeNode(import.Name, 0,0)); } } // methods int img; if (memberGroups > 0) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); foreach(ASMember method in aClass.Methods) { img = ((method.Flags & FlagType.Private) > 0) ? 12 : 3; sub2 = new TreeNode(method.ToString(), img,img); sub2.Tag = method.Name; nodes.Add(sub2); } // properties if (memberGroups > 1) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); } foreach(ASMember prop in aClass.Properties) { img = ((prop.Flags & FlagType.Private) > 0) ? 13 : 4; sub2 = new TreeNode(prop.ToString(), img,img); sub2.Tag = prop.Name; nodes.Add(sub2); } // variables if (memberGroups > 2) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); } foreach(ASMember var in aClass.Vars) { img = ((var.Flags & FlagType.Private) > 0) ? 14 : 5; sub2 = new TreeNode(var.ToString(),img,img); sub2.Tag = var.Name; nodes.Add(sub2); } } // expand index = 0; if (showExtend) index++; if (showImports) index++; for (int i=0; i<memberGroups; i++) node.Nodes[index++].Expand(); node.Expand(); if (!entryExists) node.EnsureVisible(); } finally { if (updateToken) classTree.EndStatefulUpdate(); } }
/// <summary> /// Check wether 'aClass' has acces to 'bClass' private methods /// </summary> static public bool FriendClasses(ASClass aClass, ASClass bClass) { ASClass tmpClass = aClass; while (tmpClass != null) { if (tmpClass == bClass) return true; tmpClass = tmpClass.Extends; } return false; }
/// <summary> /// Retrieves a parsed class from its name /// </summary> /// <param name="cname">Class (short or full) name</param> /// <param name="inClass">Current class</param> /// <returns>A parsed class or an empty ASClass if the class is not found</returns> public ASClass GetClassByName(string cname, ASClass inClass) { ASClass aClass = new ASClass(); aClass.ClassName = cname; return aClass; }
public void UpdateView(ASClass aClass) { bool updateToken = false; try { DebugConsole.Trace("UI: update " + aClass.ClassName); if (aClass.IsVoid()) { return; } // compute class data "checksum" to know if it changed string fileName = aClass.FileName; string prevDataCheck = (string)checkEntries[fileName]; StringBuilder sb = new StringBuilder().Append(aClass.Extends.ClassName); foreach (ASMember import in aClass.Imports) { sb.Append(import.Name); } foreach (ASMember method in aClass.Methods) { sb.Append(method.Flags.ToString()).Append(method.ToString()); } foreach (ASMember prop in aClass.Properties) { sb.Append(prop.Flags.ToString()).Append(prop.ToString()); } foreach (ASMember var in aClass.Vars) { sb.Append(var.Flags.ToString()).Append(var.ToString()); } string classDataCheck = sb.ToString(); // for tree exploration TreeNodeCollection nodes = classTree.Nodes; TreeNode node = null; TreeNode insertBefore = null; // re-sort imports by package aClass.Sort(); ASMemberList import2 = new ASMemberList(); ASMember newImport; foreach (ASMember import in aClass.Imports) { newImport = new ASMember(); newImport.Name = import.Type; import2.Add(newImport); } import2.Sort(); // search item insertion/update position string cname = aClass.ClassName; bool entryExists = false; foreach (TreeNode sub in nodes) { if (sub.Text == cname) { node = sub; entryExists = true; break; } else if (sub.Text.CompareTo(cname) > 0) { insertBefore = sub; break; } } // New class if (node == null) { updateToken = true; classTree.BeginStatefulUpdate(); // create class node node = new TreeNode(cname); node.Tag = aClass.FileName; if (insertBefore != null) { nodes.Insert(insertBefore.Index, node); } else { nodes.Add(node); } // class details nodes if (showExtend) { node.Nodes.Add(new TreeNode("Extends", 1, 1)); } if (showImports) { node.Nodes.Add(new TreeNode("Imports", 1, 1)); } // class members nodes if (memberGroups == 1) { node.Nodes.Add(new TreeNode("Members", 1, 1)); } else { if (memberGroups > 1) { node.Nodes.Add(new TreeNode("Methods", 1, 1)); node.Nodes.Add(new TreeNode("Properties", 1, 1)); } if (memberGroups > 2) { node.Nodes.Add(new TreeNode("Variables", 1, 1)); } } } // Check class infos else { if (classDataCheck == prevDataCheck) { return; } updateToken = true; classTree.BeginStatefulUpdate(); } // // UPDATE CLASS INFO // checkEntries[fileName] = classDataCheck; int index = 0; TreeNode sub2; // entends if (showExtend) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); if (!aClass.Extends.IsVoid()) { if ((aClass.Extends.Flags & FlagType.Intrinsic) > 0) { sub2 = new TreeNode(aClass.Extends.ClassName, 7, 7); } else { sub2 = new TreeNode(aClass.Extends.ClassName, 0, 0); } sub2.Tag = aClass.Extends.FileName; nodes.Add(sub2); } } // imports if (showImports) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); foreach (ASMember import in import2) { if ((import.Flags & FlagType.Intrinsic) > 0) { nodes.Add(new TreeNode(import.Name, 7, 7)); } else { nodes.Add(new TreeNode(import.Name, 0, 0)); } } } // methods int img; if (memberGroups > 0) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); foreach (ASMember method in aClass.Methods) { img = ((method.Flags & FlagType.Private) > 0) ? 12 : 3; sub2 = new TreeNode(method.ToString(), img, img); sub2.Tag = method.Name; nodes.Add(sub2); } // properties if (memberGroups > 1) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); } foreach (ASMember prop in aClass.Properties) { img = ((prop.Flags & FlagType.Private) > 0) ? 13 : 4; sub2 = new TreeNode(prop.ToString(), img, img); sub2.Tag = prop.Name; nodes.Add(sub2); } // variables if (memberGroups > 2) { nodes = node.Nodes[index++].Nodes; nodes.Clear(); } foreach (ASMember var in aClass.Vars) { img = ((var.Flags & FlagType.Private) > 0) ? 14 : 5; sub2 = new TreeNode(var.ToString(), img, img); sub2.Tag = var.Name; nodes.Add(sub2); } } // expand index = 0; if (showExtend) { index++; } if (showImports) { index++; } for (int i = 0; i < memberGroups; i++) { node.Nodes[index++].Expand(); } node.Expand(); if (!entryExists) { node.EnsureVisible(); } } finally { if (updateToken) { classTree.EndStatefulUpdate(); } } }
/// <summary> /// (Re)Parse and cache a class file /// </summary> /// <param name="aClass">Class object</param> /// <returns>The class object</returns> public ASClass GetCachedClass(ASClass aClass) { return aClass; }
/// <summary> /// Find expression type in function context /// </summary> /// <param name="expression">To evaluate</param> /// <param name="context">In context</param> /// <param name="inClass">In class</param> /// <param name="complete">Complete (sub-expression) or partial (dot-completion) evaluation</param> /// <returns>Class/member struct</returns> static private ASResult EvalExpression(string expression, ASExpr context, ASClass inClass, bool complete) { DebugConsole.Trace("** EvalExpression"); DebugConsole.Trace(expression); ASResult notFound = new ASResult(); Match mSub = null; string[] tokens = expression.Split('.'); // eval first token string token = tokens[0]; ASResult head; if (token.StartsWith("#")) { mSub = re_sub.Match(token); if (mSub.Success) { string subExpr = context.SubExpressions[ Convert.ToInt16(mSub.Groups["index"].Value) ]; // parse sub expression subExpr = subExpr.Substring(1,subExpr.Length-2).Trim(); ASExpr subContext = new ASExpr(); subContext.SubExpressions = ExtractedSubex = new StringCollection(); subExpr = re_balancedParenthesis.Replace(subExpr, new MatchEvaluator(ExtractSubex)); Match m = re_refineExpression.Match(subExpr); if (!m.Success) return notFound; subExpr = re_dot.Replace( re_whiteSpace.Replace(m.Value, " ") , ".").Trim(); int space = subExpr.LastIndexOf(' '); if (space > 0) subExpr = subExpr.Substring(space+1); // eval sub expression head = EvalExpression(subExpr, subContext, inClass, true); if (head.Member != null) head.Class = ASContext.FindClassFromName(head.Member.Type, head.Class); } else { token = token.Substring(token.IndexOf('~')+1); head = EvalVariable(token, context, inClass); } } else head = EvalVariable(token, context, inClass); // no head, exit if (head.IsNull()) return notFound; if (!head.IsStatic) DebugConsole.Trace(0+" "+token+":"+head.Class.ClassName); else if (head.Member != null) DebugConsole.Trace(0+" "+token+":"+head.Class.ClassName); else DebugConsole.Trace(0+" "+token+"="+head.Class.ClassName); // eval tail int n = tokens.Length; if (!complete) n--; // context ASResult step = head; ASClass resultClass = head.Class; // look for static or dynamic members? FlagType mask = (head.IsStatic) ? FlagType.Static : FlagType.Dynamic; // look for public only members? ASClass curClass = ASContext.CurrentClass; if (!FriendClasses(curClass, step.Class)) mask |= FlagType.Public; // explore for (int i=1; i<n; i++) { resultClass = step.Class; token = tokens[i]; DebugConsole.Trace(i+" "+token+" "+mask); FindMember(token, resultClass, step, mask); if (step.Class == null) return step; if (!step.IsStatic) //(resultClass.Flags != FlagType.Package) && ((step.Class.Flags & FlagType.Class) == 0)) { if ((mask & FlagType.Static) > 0) { mask -= FlagType.Static; mask |= FlagType.Dynamic; } } if (!FriendClasses(curClass, step.Class)) mask |= FlagType.Public; } // eval package if (step.Class.Flags == FlagType.Package) { DebugConsole.Trace("Complete package "+step.Class.ClassName); step.Class.Package = ASContext.FindPackage(step.Class.ClassName, true); } return step; }
public void SetActiveClass(ASClass aClass) { try { classTree.BeginUpdate(); string filename; if (aClass.IsVoid()) { filename = ASContext.MainForm.CurFile; } else { filename = aClass.FileName; } DebugConsole.Trace("UI: set active " + filename); // bool found = false; foreach (TreeNode node in classTree.Nodes) { if ((string)node.Tag == filename) { if (!found) { found = true; classTree.SelectedNode = node; int index = 0; if (showExtend) { index++; } if (showImports) { index++; } for (int i = 0; i < memberGroups; i++) { node.Nodes[index++].Expand(); } node.Expand(); } else { classTree.Nodes.Remove(node); } } else { node.Collapse(); } } // if (classTree.SelectedNode != null) { classTree.SelectedNode.EnsureVisible(); } } catch { classTree.SelectedNode = null; } finally { classTree.EndUpdate(); Win32.Scrolling.scrollToLeft(classTree); } }
/// <summary> /// Match token to a class' member /// </summary> /// <param name="token">To match</param> /// <param name="inClass">In given class</param> /// <param name="result">Class/Member struct</param> static private void FindMember(string token, ASClass inClass, ASResult result, FlagType mask) { DebugConsole.Trace("FindMember "+token+" "+mask); ASMember found = null; ASClass tmpClass = inClass; if (inClass == null) return; // variable int p = token.IndexOf('#'); if (p < 0) { // member while ((tmpClass != null) && !tmpClass.IsVoid()) { found = tmpClass.Properties.Search(token, mask); if (found != null) break; found = tmpClass.Vars.Search(token, mask); if (found != null) break; found = tmpClass.Methods.Search(token, mask); if (found != null) { // static members not inherited in AS3 if (tmpClass != inClass && (found.Flags & FlagType.Static) > 0 && inClass.IsAS3) return; //DebugConsole.Trace("Method of "+tmpClass.ClassName); result.Member = found; if ((result.Member.Flags & FlagType.Constructor) > 0) { result.Class = tmpClass; result.IsStatic = true; } else { result.inClass = tmpClass; result.Class = ASContext.FindClassFromName("Function", null); result.IsStatic = false; //((found.Flags & FlagType.Static) > 0); } //DebugConsole.Trace("Found static "+found.Name+":"+result.Class.ClassName+" in "+tmpClass.ClassName); return; } tmpClass = tmpClass.Extends; } } // method else { token = token.Substring(0,p); while ((tmpClass != null) && !tmpClass.IsVoid()) { found = tmpClass.Methods.Search(token, mask); if (found != null) { // static members not inherited in AS3 if (tmpClass != inClass && (found.Flags & FlagType.Static) > 0 && inClass.IsAS3) return; if ((found.Flags & FlagType.Constructor) > 0) { result.Class = tmpClass; result.Member = found; result.IsStatic = false; return; } break; } tmpClass = tmpClass.Extends; } } // result found! if (found != null) { result.inClass = tmpClass; result.Class = ASContext.FindClassFromName(found.Type, tmpClass); result.Member = found; result.IsStatic = false; //((found.Flags & FlagType.Static) > 0); DebugConsole.Trace("Found "+found.Name+":"+result.Class.ClassName+" in "+tmpClass.ClassName); return; } // try subpackages else if (inClass.Package != null) { DebugConsole.Trace("Find "+token+" as "+inClass.ClassName+"."+token); result.Class = ASContext.FindClassFromName(inClass.ClassName.Replace(System.IO.Path.DirectorySeparatorChar,'.')+"."+token, null); if (!result.Class.IsVoid()) return; // sub packages? ASMemberList list = ASContext.FindPackage(inClass.ClassName, false); if (list != null || inClass.Flags == FlagType.Package) { result.Class = new ASClass(); result.Class.ClassName = inClass.ClassName+System.IO.Path.DirectorySeparatorChar+token; result.Class.Flags = FlagType.Package; result.Class.Package = list; result.IsStatic = true; return; } } // not found result.Class = null; result.Member = null; DebugConsole.Trace(token+" not found in "+inClass.ClassName); }