/// <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 }