internal Expression ParseNextExpression(TokenStore ts, AnOperator leftOperator, ParseInfo parseInfo) { Expression exp = null, exp2 = null, exp3 = null; Type t = null; MethodInfo mi = null; AToken tok; while ((tok = ts.Current) != null) { if (leftOperator != null && tok.op != null && tok.op.precedence >= leftOperator.precedence) return exp; // current operator has high precedence than leftOp switch (tok.tok_type) { case TOKEN_TYPE.INT: Assert(exp == null, tok); exp = Expression.Constant(int.Parse(tok.value)); break; case TOKEN_TYPE.UINT: Assert(exp == null, tok); exp = Expression.Constant(uint.Parse(tok.value)); break; case TOKEN_TYPE.LONG: Assert(exp == null, tok); exp = Expression.Constant(long.Parse(tok.value)); break; case TOKEN_TYPE.ULONG: Assert(exp == null, tok); exp = Expression.Constant(ulong.Parse(tok.value)); break; case TOKEN_TYPE.FLOAT: Assert(exp == null, tok); exp = Expression.Constant(float.Parse(tok.value)); break; case TOKEN_TYPE.DOUBLE: Assert(exp == null, tok); exp = Expression.Constant(double.Parse(tok.value)); break; case TOKEN_TYPE.DECIMAL: Assert(exp == null, tok); exp = Expression.Constant(decimal.Parse(tok.value, System.Globalization.NumberStyles.AllowExponent)); break; case TOKEN_TYPE.BOOL: Assert(exp == null, tok); exp = Expression.Constant(bool.Parse(tok.value)); break; case TOKEN_TYPE.TEXT: Assert(exp == null, tok); exp = Expression.Constant(tok.value); break; case TOKEN_TYPE.IDENTIFIER: // x, x[] #region Parameter or Static Type reference if (exp != null && exp is ConstantExpression && ((ConstantExpression)exp).Value is Type) // static type { #region declare local variable: T var1=exp1, var2=exp2; t = (Type)((ConstantExpression)exp).Value; Dictionary<string, ParameterExpression> localVaribles = parseInfo.localVariableStack.Peek(); List<Expression> exp_list = new List<Expression>(); while (ts.Current != null) { Assert(ts.Current.tok_type == TOKEN_TYPE.IDENTIFIER, ts.Current); ParameterExpression var = Expression.Variable(t, ts.Current.value); localVaribles.Add(ts.Current.value, var); ts.Next(); // skip variable if (ts.CurrentValue == "=") // variable initializer { ts.Next(); // skip "=" if (var.Type.IsArray && ts.CurrentValue == "{") // array initializer: T[] var = {1,2,3}; exp = Expression.NewArrayInit(var.Type.GetElementType(), ParseParameters(ts, parseInfo, null, false)); else exp = ParseNextExpression(ts, AnOperator.dicSystemOperator[","], parseInfo); if (exp.Type != t) exp = Expression.Convert(exp, t); exp_list.Add(Expression.Assign(var, exp)); } if (ts.Current == null || ts.Current.value == ";") break; // end of statement if (ts.Current.value == ",") ts.Next(); // skip "," to next variable } if (exp_list.Count == 0) exp = null; else if (exp_list.Count == 1) exp = exp_list[0]; else exp = Expression.Block(exp_list); #endregion } else { #region Parameter or Static Type reference Assert(exp == null && (exp = ParseReferredParameterOrType(ts, parseInfo, true, true, true)) != null, ts.Current); #endregion } break; #endregion case TOKEN_TYPE.OPERATOR: #region Operator switch (tok.op.op_type) { case OPERATOR_TYPE.OPEN: #region Open operators: (, [. "{" will be proccessed in ParseStatement() switch (tok.value) { case "(": #region ParenthesisLeft: (nested expression) Assert(exp == null, tok); exp = ParseNextExpression(ts.NextUntilOperatorClose(), null, parseInfo); if (exp is ConstantExpression && ((ConstantExpression)exp).Value is Type) // (T)x { exp2 = ParseNextExpression(ts, AnOperator.dicSystemOperator["(T)"], parseInfo); if (exp2 != null) exp = Expression.Convert(exp2, (Type)((ConstantExpression)exp).Value); } break; #endregion case "[": #region BracketLeft: indexer[] Assert(exp != null, tok); { List<Type> param_types = new List<Type>(); List<Expression> param_list = ParseParameters(ts, parseInfo, param_types, false); //TokenStore sub_ts = ts.NextUntilOperatorClose(); //List<Expression> param_list = new List<Expression>(); //while ((exp2 = GetNextExpression(sub_ts, AnOperator.dicSystemOperator[","], exprParameterList)) != null) //{ // param_list.Add(exp2); // sub_ts.Next(); // to ',' //} ////List<TokenStore> ts_list = ts.NextUntilOperatorClose().Split(OPERATOR_NAME.Comma); ////List<Expression> param_list = new List<Expression>(); ////foreach (TokenStore one_ts in ts_list) ////{ //// if(one_ts.token_list.Count>0) //// param_list.Add(GetNextExpression(one_ts, null, exprParameterList)); ////} //List<Type> param_types = new List<Type>(); //foreach (Expression e in param_list) param_types.Add(e.Type); if ((mi = exp.Type.GetMethod(tok.op.overload_name, BindingFlags.Instance | BindingFlags.Public, null, param_types.ToArray(), null)) != null) exp = Expression.Call(exp, mi, param_list.ToArray()); else exp = Expression.ArrayIndex(exp, param_list.ToArray()); } break; #endregion default: Assert(false, tok); break; } break; #endregion case OPERATOR_TYPE.PREFIX_UNARY: #region prefix unary operators Assert(exp == null && ts.Next() != null, tok); Assert((exp2 = ParseNextExpression(ts, tok.op, parseInfo)) != null, ts.Current); mi = tok.op.overload_name == null ? null : exp2.Type.GetMethod(tok.op.overload_name, new Type[] { exp2.Type }); exp = ((d1m)tok.op.exp_call)(exp2, mi); break; #endregion case OPERATOR_TYPE.POST_UNARY: #region POST_UNARY Assert(exp != null, tok); mi = tok.op.overload_name == null ? null : exp.Type.GetMethod(tok.op.overload_name, new Type[] { exp.Type }); exp = ((d1m)tok.op.exp_call)(exp, mi); break; #endregion case OPERATOR_TYPE.BINARY: case OPERATOR_TYPE.ASSIGN: #region Binary or Assign Operators Assert(exp != null && ts.Next() != null && (exp2 = ParseNextExpression(ts, tok.op, parseInfo)) != null, tok); mi = null; t = null; if (tok.value == "is") { Assert(exp2 is ConstantExpression && ((ConstantExpression)exp2).Value is Type, tok); exp = Expression.TypeIs(exp, (Type)((ConstantExpression)exp2).Value); break; } else if (tok.value == "as") { Assert(exp2 is ConstantExpression && ((ConstantExpression)exp2).Value is Type, tok); exp = Expression.TypeAs(exp, (Type)((ConstantExpression)exp2).Value); break; } if (tok.value == "+" && exp.Type == typeof(string) || exp2.Type == typeof(string)) { if (exp.Type != typeof(string)) exp = Expression.Convert(exp, typeof(string)); if (exp2.Type != typeof(string)) exp2 = Expression.Convert(exp2, typeof(string)); mi = typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) }); } else { if (tok.op.overload_name != null) { mi = exp.Type.GetMethod(tok.op.overload_name, new Type[] { exp.Type, exp2.Type }); if (mi == null) mi = exp2.Type.GetMethod(tok.op.overload_name, new Type[] { exp.Type, exp2.Type }); } if (mi == null) { // use default operator, need implicit type conversion if (tok.op.required1stType != null) exp = Expression.Convert(exp, tok.op.required1stType); if (tok.op.required2ndType != null) exp2 = Expression.Convert(exp2, tok.op.required2ndType); if (tok.op.requiredOperandType == RequiredOperandType.SAME && exp.Type != exp2.Type && (t = QueryImplicitConversionType(exp, exp2)) != null) { if (exp.Type != t) exp = Expression.Convert(exp, t); if (exp2.Type != t) exp2 = Expression.Convert(exp2, t); } } } if (tok.op.exp_call is d2) exp = ((d2)tok.op.exp_call)(exp, exp2); else if (tok.op.exp_call is d2m) exp = ((d2m)tok.op.exp_call)(exp, exp2, mi); else exp = ((d2bm)tok.op.exp_call)(exp, exp2, false, mi); break; #endregion case OPERATOR_TYPE.CONDITIONAL: #region Conditional Assert(exp != null && ts.Next()!=null && (exp2 = ParseNextExpression(ts, tok.op, parseInfo)) != null, tok); Assert(ts.CurrentValue == ":" && ts.Next() != null, tok); Assert((exp3 = ParseNextExpression(ts, tok.op, parseInfo)) != null, tok); if (exp2.Type != exp3.Type && (t = QueryImplicitConversionType(exp2, exp3)) != null) { if (exp2.Type != t) exp2 = Expression.Convert(exp2, t); if (exp3.Type != t) exp3 = Expression.Convert(exp3, t); } exp = Expression.Condition(exp, exp2, exp3); break; #endregion case OPERATOR_TYPE.PRIMARY: #region Primary: switch (tok.value) { case "new": #region New { Assert(exp == null && ts.Next() != null && ts.Current.tok_type == TOKEN_TYPE.IDENTIFIER, tok); // skip "new" Assert((exp = ParseReferredParameterOrType(ts, parseInfo, true, false, false)) != null, tok); t = (Type)((ConstantExpression)exp).Value; Assert(ts.Current != null && ts.Current.value == "(" || ts.Current.value == "[", ts.Current); // next is '(' or '[' if (ts.Current.value == "(") // new object(). { List<Type> param_types = new List<Type>(); List<Expression> param_list = ParseParameters(ts, parseInfo, param_types, false); ConstructorInfo ci = t.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, param_types.ToArray(), null); Assert(ci != null, ts.Current); // check parameter implicit conversion ParameterInfo[] pis = ci.GetParameters(); for (int idx = 0; idx < param_list.Count; idx++) { if (param_list[idx].Type != pis[idx].ParameterType) param_list[idx] = Expression.Convert(param_list[idx], pis[idx].ParameterType); } exp = Expression.New(ci, param_list.ToArray()); } else // new int[x,y] or new type[]{x,y} { List<Expression> param_list = ParseParameters(ts, parseInfo, null, false); // [x,y] if (ts.CurrentValue == "{") // array initializer {1,2,3} exp = Expression.NewArrayInit(t, ParseParameters(ts, parseInfo, null, false)); // new array[] {x,y} else exp = Expression.NewArrayBounds(t, param_list); // new array[x,y] } } break; #endregion case "typeof": #region typeof Assert(exp == null && ts.Next() != null && ts.Current.value == "(", tok); // must be "(" Assert((exp = ParseNextExpression(ts.NextUntilOperatorClose(), null, parseInfo)) != null, tok); Assert(exp is ConstantExpression && ((ConstantExpression)exp).Value is Type, "Invalid parameter for typeof(T)"); // typeof(T) break; #endregion case "sizeof": #region sizeof Assert(exp == null, tok); Assert(ts.Next() != null && ts.Current.value == "(", tok); // must be "(" Assert((exp = ParseNextExpression(ts.NextUntilOperatorClose(), null, parseInfo)) != null, tok); Assert(exp is ConstantExpression && ((ConstantExpression)exp).Value is Type && ((Type)((ConstantExpression)exp).Value).IsValueType, "Invalid parameter for sizeof(T)"); // sizeof(T) exp = Expression.Constant(System.Runtime.InteropServices.Marshal.SizeOf((Type)((ConstantExpression)exp).Value)); break; #endregion case ".": #region Property, Field or method call Assert(exp != null && (tok=ts.Next())!=null && tok.tok_type == TOKEN_TYPE.IDENTIFIER, tok); // skip "." => tok=variable ts.Next(); // skip variable if (ts.CurrentValue == "(") // method call { #region Method Call List<Type> param_types = new List<Type>(); List<Expression> param_list = ParseParameters(ts, parseInfo, param_types, false); if (exp is ConstantExpression && ((ConstantExpression)exp).Value is Type) // static call { t = (Type)(((ConstantExpression)exp).Value); Assert((mi = t.GetMethod(tok.value, BindingFlags.Static | BindingFlags.Public, null, param_types.ToArray(), null)) != null, tok); // check parameter implicit conversion ParameterInfo[] pis = mi.GetParameters(); for (int idx = 0; idx < param_list.Count; idx++) { Type et = (pis[idx].ParameterType.IsByRef) ? pis[idx].ParameterType.GetElementType() : pis[idx].ParameterType; if (param_list[idx].Type != et) param_list[idx] = Expression.Convert(param_list[idx], et); } exp = Expression.Call(mi, param_list.ToArray()); } else // instance object method call { mi = exp.Type.GetMethod(tok.value, BindingFlags.Instance | BindingFlags.Public, null, param_types.ToArray(), null); Assert(mi != null, tok); // check parameter implicit conversion ParameterInfo[] pis = mi.GetParameters(); for (int idx = 0; idx < param_list.Count; idx++) { Type et = (pis[idx].ParameterType.IsByRef) ? pis[idx].ParameterType.GetElementType() : pis[idx].ParameterType; if (param_list[idx].Type != et) param_list[idx] = Expression.Convert(param_list[idx], et); } exp = Expression.Call(exp, mi, param_list.ToArray()); } #endregion } else if (exp is ConstantExpression && ((ConstantExpression)exp).Value is Type) { #region Static property of field PropertyInfo pi = null; FieldInfo fi = null; t = (Type)(((ConstantExpression)exp).Value); if ((pi = t.GetProperty(tok.value, BindingFlags.Public | BindingFlags.Static)) != null) exp = Expression.Property(null, pi); else if ((fi = t.GetField(tok.value, BindingFlags.Public | BindingFlags.Static)) != null) exp = Expression.Field(null, fi); else if ((pi = exp.Type.GetProperty(tok.value, BindingFlags.Instance | BindingFlags.Public)) != null) exp = Expression.Property(exp, pi); else if ((fi = exp.Type.GetField(tok.value, BindingFlags.Instance | BindingFlags.Public)) != null) exp = Expression.Field(exp, fi); else if (ts.CurrentValue == "<") { // v1.1: Static Generic Method call List<Type> param_types = new List<Type>(); List<Expression> param_list = ParseParameters(ts, parseInfo, param_types, true); Assert((mi = t.GetMethod(tok.value, BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(param_types.ToArray())) != null, tok); //Assert((mi = mi.MakeGenericMethod(param_types.ToArray())) != null, tok); Assert(ts.CurrentValue == "(", ts.Current); // to "(" param_list = ParseParameters(ts, parseInfo, null, false); exp = Expression.Call(mi, param_list.ToArray()); } else Assert(false, tok); #endregion } else { #region instance property or field PropertyInfo pi = null; FieldInfo fi = null; if ((pi = exp.Type.GetProperty(tok.value, BindingFlags.Instance | BindingFlags.Public)) != null) exp = Expression.Property(exp, pi); else if ((fi = exp.Type.GetField(tok.value, BindingFlags.Instance | BindingFlags.Public)) != null) exp = Expression.Field(exp, fi); else if (ts.CurrentValue == "<") { // v1.1: Instance Generic method call List<Type> param_types = new List<Type>(); List<Expression> param_list = ParseParameters(ts, parseInfo, param_types, true); Assert((mi = exp.Type.GetMethod(tok.value, BindingFlags.Instance | BindingFlags.Public).MakeGenericMethod(param_types.ToArray())) != null, tok); //Assert((mi = mi.MakeGenericMethod(param_types.ToArray())) != null, tok); Assert(ts.CurrentValue == "(", ts.Current); // to "(" param_list = ParseParameters(ts, parseInfo, null, false); exp = Expression.Call(exp, mi, param_list.ToArray()); } else Assert(false, tok); #endregion } break; #endregion default: // ,(not in method and indexer) and ;(need ASP.NET4.0) Assert(false, tok); break; } break; #endregion } break; #endregion default: Assert(false, tok); break; } if (ts.Current == tok) ts.Next(); } return exp; }
internal AToken(int start_pos/*, int end_pos*/, TOKEN_TYPE tok_type, AnOperator op, string value) { this.start_pos = start_pos; //this.end_pos = end_pos; this.tok_type = tok_type; this.op = op; this.value = value; }