예제 #1
0
		/// <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;
		}
예제 #2
0
		/// <summary>
		/// Find Actionscript expression at cursor position
		/// TODO  Improve this method
		/// </summary>
		/// <param name="sci">Scintilla Control</param>
		/// <param name="position">Cursor position</param>
		/// <returns></returns>
		static private ASExpr GetExpression(ScintillaNet.ScintillaControl Sci, int position)
		{
			ASExpr expression = new ASExpr();
			int startPos = position;
			expression.Position = position;
			expression.separator = ' ';
			
			// get last expression (until ';') excluding comments
			int stylemask = (1 << Sci.StyleBits) -1;
			int style = (position > 0) ? Sci.StyleAt(position-1) & stylemask : 0;
			bool ignoreKey = false;
			if (style == 19)
			{
				DebugConsole.Trace("Ignore keyword");
				ignoreKey = true;
			}
			StringBuilder sb = new StringBuilder();
			char c;
			while ((position > 0) && (style != 19 || ignoreKey)) 
			{
				position--;
				style = Sci.StyleAt(position) & stylemask;
				if (IsTextStyle(style) || ignoreKey)
				{
					c = (char)Sci.CharAt(position);
					if (c == ';')
					{
						expression.separator = c;
						break;
					}
					else if (c == '\n' || c == '\r')
					{
						if (sb.ToString().Trim().Length == 0) 
							break;
					}
					sb.Insert(0,c);
					if (ignoreKey && IsTextStyle(style)) ignoreKey = false;
				}
				// we found a keyword
				else if (style == 19)
				{
					expression.separator = ' ';
					int keywordPos = position;
					string keyword = GetWordLeft(Sci, ref keywordPos);
					
					if ((keyword == "function") || (keyword == "get") || (keyword == "set"))
					{
						// we found a function declaration
						string test = sb.ToString().Trim();
						
						// ignore anonymous function
						if ((keyword == "function") && test.StartsWith("("))
						{
							keyword = null;
							break;
						}
						
						// guess context more precisely
						bool hasBraces = (test.IndexOf('{') >= 0);
						test = re_balancedBraces.Replace(test, ";");
						
						// is it inside the function?
						if (test.IndexOf('{') >= 0)
						{
							c = ' ';
							while ((position < startPos) && (sb.Length > 0))
							{
								position++;
								c = (char)Sci.CharAt(position);
								sb.Remove(0,1);
								if (c == '{') break;
							}
							expression.separator = c;
						}
						// is it NOT inside function parameters?
						else if (test.IndexOf(')') >= 0)
						{
							if (hasBraces)
							{
								expression.separator = '}';
								expression.Value = "";
								return expression;
							}
							else
							{
								// is it before the return type declaration?
								int colon = test.LastIndexOf(':');
								if ((colon < 0) || (colon < test.LastIndexOf(')')))
									// this is invalid
									return expression;
							}
						}
						// inside function parameters?
						else
						{
							int colon = test.LastIndexOf(':');
							if ((colon < 0) || (colon < test.LastIndexOf(',')))
								return expression;
						}
					}
					else expression.Keyword = keyword;
					
					// note that we found a "case" statement
					//else if (keyword == "case") expression.Keyword = "case";
					
					DebugConsole.Trace("Stopped at '"+keyword+"'");
					DebugConsole.Trace("Raw '"+sb.ToString()+"'");
					break;
				}
			}
			position++;
			string expr = sb.ToString();
			
			sb = null;
			if (expr.Length > 0 && (expr[expr.Length-1] <= 32 && Sci.CharAt(startPos) != '('))
			{
				expr = "";
				expression.separator = ' ';
				expression.Position = Sci.CurrentPos;
			}
			else expression.PositionExpression = position;
			
			// refine last expression
			if (expr.Length > 0) 
			{
				expr = re_balancedBraces.Replace(expr, ";");
				expression.SubExpressions = ExtractedSubex = new StringCollection();
				expr = re_balancedParenthesis.Replace(expr, new MatchEvaluator(ExtractSubex));
				//DebugConsole.Trace("Raw '"+expr+"' @"+expression.PositionExpression);
				Match m = re_refineExpression.Match(expr);
				if (!m.Success) return expression;
				if (m.Index > 0)
				{
					expression.separator = expr[m.Index-1];
					expression.PositionExpression = position += m.Index;
					// treat ':' as ';' after a case statement
					if (expression.separator == ':' && expression.Keyword == "case") expression.separator = ';';
					expression.Keyword = null;
				}
				//DebugConsole.Trace("Refined '"+m.Value+"' @"+m.Index);
				expr = re_dot.Replace( re_whiteSpace.Replace(m.Value, " ") , ".");
				expr = re_subexMarker.Replace(expr, "#").Trim();
				int space = Math.Max(expr.LastIndexOf(' '), expr.LastIndexOf(';'));
				if (space > 0) 
				{
					expression.separator = ' ';
					expr = expr.Substring(space+1);
				}
				//ErrorHandler.ShowInfo("Clean '"+expr+"' @"+expression.PositionExpression);
			}
			expression.Value = expr;
			
			// get context function body
			int braceCount = 0;
			StringBuilder body = new StringBuilder();
			StringBuilder context = new StringBuilder();
			while (braceCount >= 0)
			{
				while (position > 0) 
				{
					position--;
					style = Sci.StyleAt(position) & stylemask;
					if (IsTextStyleEx(style))
					{
						c = (char)Sci.CharAt(position);
						if (c == '}') 
						{
							body.Insert(0,c);
							braceCount++;
						}
						else if ((c == '{') && (--braceCount < 0)) break;
						if (braceCount == 0) body.Insert(0,c);
					}
				}
				if (braceCount >= 0) break;
				
				// get context function definition
				while (position > 0) 
				{
					position--;
					style = Sci.StyleAt(position) & stylemask;
					if (IsTextStyleEx(style))
					{
						c = (char)Sci.CharAt(position);
						if ((c == ';') || (c == '}') || (c == '{')) break;
						context.Insert(0,c);
					}
				}
				expression.ContextFunction = context.ToString();
				
				// ignore dynamic function definition
				if (!re_validFunction.IsMatch(expression.ContextFunction)) 
				{
					// stop if we reached the class definition
					if (re_classDefinition.IsMatch(expression.ContextFunction)) 
					{
						expression.ContextFunction = null;
						expression.PositionContext = 0;
						break;
					}
					// continue search for function definition
					body.Insert(0,'{').Insert(0,context.ToString());
					context = new StringBuilder();
					position++;
					braceCount++;
				}
				else {
					expression.ContextBody = body.ToString();
					expression.PositionContext = position+1;
				}
			}
			// result
			LastExpression = expression;
			return expression;
		}
예제 #3
0
		/// <summary>
		/// Parse function body for local var definitions
		/// TODO  ASComplete: parse coma separated local vars definitions
		/// </summary>
		/// <param name="expression">Expression source</param>
		/// <returns>Local vars dictionnary (name, type)</returns>
		static public ASMemberList ParseLocalVars(ASExpr expression)
		{
			ASMemberList vars = new ASMemberList();
			if ((expression.ContextBody == null) || (expression.ContextBody.Length == 0)) 
				return vars;
			// parse
			MatchCollection mcVars = re_variable.Matches(";"+expression.ContextBody);
			Match mVar;
			Match mType;
			string type;
			ASMember var;
			foreach(Match m in mcVars) 
			{
				mVar = re_splitVariable.Match(m.Value);
				if (!mVar.Success) 
					continue;
				mType = re_variableType.Match(mVar.Groups["type"].Value);
				if (mType.Success) type = mType.Groups["type"].Value;
				else type = "Object";
				var = new ASMember();
				var.Flags = FlagType.Variable | FlagType.Dynamic;
				var.Name = mVar.Groups["pname"].Value;
				var.Type = type;
				vars.Add(var);
			}
			// method parameters
			vars.Merge( ParseMethodParameters(expression.ContextFunction) );
			return vars;
		}
예제 #4
0
		/// <summary>
		/// Find variable type in function context 
		/// </summary>
		/// <param name="token">Variable name</param>
		/// <param name="context">In context</param>
		/// <param name="inClass">In class</param>
		/// <returns>Class/member struct</returns>
		static private ASResult EvalVariable(string token, ASExpr context, ASClass inClass)
		{
			DebugConsole.Trace("EvalVariable "+token);
			ASResult result = new ASResult();
			
			// local vars
			if (context.LocalVars != null)
			foreach(ASMember var in context.LocalVars)
			{
				if (var.Name == token)
				{
					result.inClass = null;
					result.Class = ASContext.FindClassFromName(var.Type, inClass);
					result.Member = var;
					return result;
				}
			}
			
			// method parameters
			if (context.ContextFunction != null)
			{
				Match param = Regex.Match(context.ContextFunction, "[(,][\\s]*"+Regex.Escape(token)+"[\\s:,)]");
				if (param.Success)
				{
					//DebugConsole.Trace("Method param "+token);
					param = Regex.Match(context.ContextFunction, "[(,][\\s]*"+Regex.Escape(token)+"[\\s]*:[\\s]*(?<type>[^\\s,)]*)");
					if (param.Success && (param.Groups["type"].Value.Length > 0))
					{
						//DebugConsole.Trace("Type "+param.Groups["type"].Value);
						result.Class = ASContext.FindClassFromName(param.Groups["type"].Value, inClass);
					}
					return result;
				}
			}
			
			// class members
			FindMember(token, inClass, result, 0);
			if (!result.IsNull())
				return result;
			
			// top-level elements
			if (!ASContext.TopLevel.IsVoid())
			{
				FindMember(token, ASContext.TopLevel, result, 0);
				if (!result.IsNull())
					return result;
				// special _levelN
				if (token.StartsWith("_") && re_level.IsMatch(token))
				{
					result.Class = ASContext.FindClassFromName("MovieClip", null);
					return result;
				}
			}
			
			// classes
			int p = token.IndexOf('#');
			string ctoken = (p > 0) ? token.Substring(0,p) : token;
			ASClass aClass = ASContext.FindClassFromName(ctoken, inClass);
			if (!aClass.IsVoid())
			{
				result.Class = aClass;
				result.IsStatic = (p < 0);
				return result;
			}
			
			// packages folders
			ASMemberList package = ASContext.FindPackage(token, false);
			if (package != null)
			{
				result.Class = new ASClass();
				result.Class.ClassName = token;
				result.Class.Flags = FlagType.Package;
				result.Class.Package = package;
				result.IsStatic = true;
			}
			return result;
		}