internal Type ParseStaticTypeExtension(TokenStore ts, Type t, bool allowArrayType) { // check nullable if (t.IsValueType && ts.CurrentValue == "?" && NullableType.ContainsKey(t)) { t = NullableType[t]; ts.Next(); // skip "?" } // check nested type Type t2=null; while (ts.CurrentValue == "." && ts.PeekToken(1) != null && ts.PeekToken(1).tok_type == TOKEN_TYPE.IDENTIFIER && (t2 = t.GetNestedType(ts.PeekToken(1).value)) != null) { t = t2; ts.Next(); // skip '.' ts.Next(); // skip nested type } // check array: t[,][], if after new operater, do not check array here if (allowArrayType) { while (ts.CurrentValue == "[") { StringBuilder arr = new StringBuilder("["); AToken tok = ts.Next(); // skip "[" while ((tok = ts.Current) != null && tok.value != "]") arr.Append(tok.value); Assert((t = t.Assembly.GetType(t.FullName + arr.Append("]").ToString())) != null, tok); Assert(tok.value == "]", tok); tok = ts.Next(); // skip "]" } } return t; }
internal List<Expression> ParseParameters(TokenStore ts, ParseInfo parseInfo, List<Type> param_types, bool typeByValue) { TokenStore sub_ts = ts.NextUntilOperatorClose(); List<Expression> param_list = new List<Expression>(); while (sub_ts.Current != null) { bool isRef = false; if (sub_ts.CurrentValue == "ref" || sub_ts.CurrentValue == "out") { isRef = true; sub_ts.Next(); } Expression e = ParseNextExpression(sub_ts, AnOperator.dicSystemOperator[","], parseInfo); param_list.Add(e); if (param_types != null) { if (isRef) { if (typeByValue) param_types.Add(((Type)((ConstantExpression)e).Value).MakeByRefType()); else param_types.Add(e.Type.MakeByRefType()); } else { if (typeByValue) param_types.Add((Type)((ConstantExpression)e).Value); else param_types.Add(e.Type); } } Assert(sub_ts.Current == null || sub_ts.CurrentValue == "," && sub_ts.Next() != null, sub_ts.Current); // skip ',' } //if (param_types != null) //{ // if(typeByValue) // foreach (Expression e in param_list) param_types.Add((Type)((ConstantExpression)e).Value); // else // foreach (Expression e in param_list) param_types.Add(e.Type); //} return param_list; }
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 Expression ParseNextStatement(TokenStore ts, ParseInfo parseInfo) { Expression test, exp1, exp2, statement = null, statement2; AToken tok = ts.Current; if (tok.tok_type == TOKEN_TYPE.IDENTIFIER) { switch (tok.value) { case "if": #region if(test) statement else statement2 Assert((tok = ts.Next()) != null && tok.value == "(", tok); Assert((test = ParseNextExpression(ts.NextUntilOperatorClose(), null, parseInfo)) != null && ts.Current != null, ts.Current); statement = ParseNextStatement(ts, parseInfo); //if (ts.CurrentValue == "{") // statement = ParseStatementBlock(ts.NextUntilOperatorClose(), parseInfo); //else //{ // statement = GetNextExpression(ts, AnOperator.dicSystemOperator[";"], parseInfo); // Assert(ts.CurrentValue == ";", ts.Current); ts.Next(); //} if (statement == null) statement = Expression.Empty(); if (ts.CurrentValue == "else") { ts.Next(); // skip "else" statement2 = ParseNextStatement(ts, parseInfo); //if (ts.CurrentValue == "{") // statement2 = ParseStatementBlock(ts.NextUntilOperatorClose(), parseInfo); //else // statement2 = GetNextExpression(ts, AnOperator.dicSystemOperator[";"], parseInfo); if (statement2 == null) statement2 = Expression.Empty(); statement = Expression.IfThenElse(test, statement, statement2); } else statement = Expression.IfThen(test, statement); break; #endregion case "while": #region while(test) statement : loop { if(test) statement; continueLabel; } breakLabel; parseInfo.jumpInfoStack.Push(new JumpInfo()); Assert((tok = ts.Next()) != null && tok.value == "(", tok); // skip "while" Assert((test = ParseNextExpression(ts.NextUntilOperatorClose(), null, parseInfo)) != null && ts.Current != null, ts.Current); statement = ParseNextStatement(ts, parseInfo); //if (ts.CurrentValue == "{") // statement = ParseStatementBlock(ts.NextUntilOperatorClose(), parseInfo); //else // statement = GetNextExpression(ts, AnOperator.dicSystemOperator[";"], parseInfo); if (statement == null) statement = Expression.Empty(); JumpInfo jumpInfo = parseInfo.jumpInfoStack.Pop(); if (jumpInfo.breakLabel == null) jumpInfo.breakLabel = Expression.Label(Expression.Label()); statement = Expression.Loop(Expression.IfThenElse(test, statement, Expression.Break(jumpInfo.breakLabel.Target)), jumpInfo.breakLabel.Target, (jumpInfo.continueLabel == null) ? null : jumpInfo.continueLabel.Target); break; #endregion case "do": #region do statement while(test) : loop { statement; if(test) break; continueLabel } breakLabel ts.Next(); // skip "do" parseInfo.jumpInfoStack.Push(new JumpInfo()); statement = ParseNextStatement(ts, parseInfo); //if (ts.CurrentValue == "{") // statement = ParseStatementBlock(ts.NextUntilOperatorClose(), parseInfo); //else // statement = GetNextExpression(ts, AnOperator.dicSystemOperator[";"], parseInfo); if (statement == null) statement = Expression.Empty(); Assert(ts.CurrentValue == "while", ts.Current); Assert((tok = ts.Next()) != null && tok.value == "(", tok); // skip "while" Assert((test = ParseNextExpression(ts.NextUntilOperatorClose(), null, parseInfo)) != null, ts.Current); //Assert(ts.CurrentValue == ";", ts.Current); ts.Next(); // skip ";" jumpInfo = parseInfo.jumpInfoStack.Pop(); if (jumpInfo.breakLabel == null) jumpInfo.breakLabel = Expression.Label(Expression.Label()); statement = Expression.Loop(Expression.Block(statement, Expression.IfThenElse(test, Expression.Empty(), Expression.Break(jumpInfo.breakLabel.Target))), jumpInfo.breakLabel.Target, (jumpInfo.continueLabel == null) ? null : jumpInfo.continueLabel.Target); break; #endregion case "for": #region for(exp1,test,exp2) statement : exp1; loop{if(test) statement; continuelabel;exp2;} breaklabel; parseInfo.localVariableStack.Push(new Dictionary<string, ParameterExpression>()); // exp1 can contain local variable only for "for statement" parseInfo.jumpInfoStack.Push(new JumpInfo()); Assert((tok = ts.Next()) != null && tok.value == "(", tok); // skip "for" TokenStore sub_ts = ts.NextUntilOperatorClose(); exp1 = ParseNextExpression(sub_ts, AnOperator.dicSystemOperator[";"], parseInfo); if (exp1 == null) exp1 = Expression.Empty(); Assert(sub_ts.CurrentValue == ";", sub_ts.Current); sub_ts.Next(); // skip ";" test = ParseNextExpression(sub_ts, AnOperator.dicSystemOperator[";"], parseInfo); Assert(sub_ts.CurrentValue == ";", sub_ts.Current); sub_ts.Next(); // skip ";" exp2 = ParseNextExpression(sub_ts, null, parseInfo); statement = ParseNextStatement(ts, parseInfo); //if (ts.CurrentValue == "{") // statement = ParseStatementBlock(ts.NextUntilOperatorClose(), parseInfo); //else // statement = GetNextExpression(ts, AnOperator.dicSystemOperator[";"], parseInfo); if (statement == null) statement = Expression.Empty(); var lv = parseInfo.localVariableStack.Pop(); jumpInfo = parseInfo.jumpInfoStack.Pop(); if (jumpInfo.breakLabel == null) jumpInfo.breakLabel = Expression.Label(Expression.Label()); //if (exp1 != null) expr_list.Add(exp1); List<Expression> sub_exp_list = new List<Expression>(); if (test != null) statement = Expression.IfThenElse(test, statement, Expression.Break(jumpInfo.breakLabel.Target)); sub_exp_list.Add(statement); if (jumpInfo.continueLabel != null) sub_exp_list.Add(jumpInfo.continueLabel); if (exp2 != null) sub_exp_list.Add(exp2); statement = Expression.Loop(Expression.Block(sub_exp_list), jumpInfo.breakLabel.Target); //expr_list.Add(jumpInfo.breakLabel); statement = Expression.Block(lv.Values, exp1, statement); break; #endregion case "foreach": #region foreach(exp1 var in exp2) statement : IEnumerator ie=exp2.GetEnumerator(); Loop { if(ie.MoveNext()) {var=ie.Current; statement;} continueLabel } breakLabel // begin stack lv = new Dictionary<string, ParameterExpression>(); parseInfo.localVariableStack.Push(lv); // exp1 can contain local variable only for "for statement" parseInfo.jumpInfoStack.Push(new JumpInfo()); Assert(ts.Next() != null && ts.CurrentValue == "(", ts.Current); // skip "foreach" to "(" sub_ts = ts.NextUntilOperatorClose(); // parse T Assert((exp1 = ParseReferredParameterOrType(sub_ts, parseInfo, true, false, true)) != null && exp1 is ConstantExpression && ((ConstantExpression)exp1).Value is Type, sub_ts.Current); Type t = (Type)((ConstantExpression)exp1).Value; // parse var Assert(sub_ts.Current != null && sub_ts.Current.tok_type == TOKEN_TYPE.IDENTIFIER, sub_ts.Current); // to var ParameterExpression var = Expression.Variable(t, sub_ts.Current.value); parseInfo.localVariableStack.Peek().Add(sub_ts.Current.value, var); // parse exp - IEnumerator Assert((tok = sub_ts.Next()) != null && tok.value == "in", tok); sub_ts.Next(); // skip "in" Assert((exp2 = ParseNextExpression(sub_ts, null, parseInfo)) != null, (AToken)null); // organize expressions ParameterExpression ie = Expression.Variable(typeof(IEnumerator)); lv.Add("$$$$ie$$$$", ie); exp1 = Expression.Assign(ie, Expression.Call(exp2, "GetEnumerator", null, null)); // IEnumerator ie=exp2.GetEnumerator(); test = Expression.Call(ie, "MoveNext", null, null); // ie.MoveNext() exp2 = Expression.Assign(var, Expression.Convert(Expression.Property(ie, "Current"), var.Type)); // var=ie.Current; // parse statement statement = ParseNextStatement(ts, parseInfo); //if (ts.CurrentValue == "{") // statement = ParseStatementBlock(ts.NextUntilOperatorClose(), parseInfo); //else // statement = GetNextExpression(ts, AnOperator.dicSystemOperator[";"], parseInfo); if (statement == null) statement = Expression.Empty(); // end stack lv = parseInfo.localVariableStack.Pop(); jumpInfo = parseInfo.jumpInfoStack.Pop(); if (jumpInfo.breakLabel == null) jumpInfo.breakLabel = Expression.Label(Expression.Label()); // create foreach //expr_list.Add(exp1); statement = Expression.Loop(Expression.IfThenElse(test, Expression.Block(exp2, statement), Expression.Break(jumpInfo.breakLabel.Target)), jumpInfo.breakLabel.Target, jumpInfo.continueLabel == null ? null : jumpInfo.continueLabel.Target); statement = Expression.Block(lv.Values, exp1, statement); break; #endregion case "break": #region break; ts.Next(); // skip "break" jumpInfo = parseInfo.jumpInfoStack.Peek(); if (jumpInfo.breakLabel == null) jumpInfo.breakLabel = Expression.Label(Expression.Label()); statement = Expression.Break(jumpInfo.breakLabel.Target); break; #endregion case "continue": #region continue; ts.Next(); // skip "continue" jumpInfo = parseInfo.jumpInfoStack.Peek(); if (jumpInfo.continueLabel == null) jumpInfo.continueLabel = Expression.Label(Expression.Label()); statement = Expression.Continue(jumpInfo.continueLabel.Target); break; #endregion case "switch": #region switch(test) { case test_values: case_statements; default:default_statements; } // start stack parseInfo.localVariableStack.Push(new Dictionary<string, ParameterExpression>()); parseInfo.jumpInfoStack.Push(new JumpInfo()); // parse exp Assert(ts.Next() != null && ts.CurrentValue == "(", ts.Current); // skip "switch" to "(" Assert((test = ParseNextExpression(ts.NextUntilOperatorClose(), null, parseInfo)) != null, ts.Current); // parse case list Assert(ts.CurrentValue == "{", ts.Current); sub_ts = ts.NextUntilOperatorClose(); List<SwitchCase> case_list = new List<SwitchCase>(); List<Expression> test_values = new List<Expression>(); List<Expression> case_statements = new List<Expression>(); Expression default_statements = null; bool isDefault = false; while ((tok = sub_ts.Current) != null) { if (tok.value == "case") { Assert(!isDefault, tok); if (test_values.Count > 0 && case_statements.Count > 0) { case_list.Add(Expression.SwitchCase(Expression.Block(case_statements), test_values)); case_statements.Clear(); test_values.Clear(); } sub_ts.Next(); // skip "case" test_values.Add(ParseNextExpression(sub_ts, AnOperator.dicSystemOperator[":"], parseInfo)); Assert(sub_ts.CurrentValue == ":" && sub_ts.Next() != null, sub_ts.Current); // skip : } else if (tok.value == "default") { isDefault = true; if (test_values.Count > 0 && case_statements.Count > 0) { case_list.Add(Expression.SwitchCase(Expression.Block(case_statements), test_values)); case_statements.Clear(); test_values.Clear(); } Assert(sub_ts.Next() != null && sub_ts.CurrentValue == ":" && sub_ts.Next() != null, sub_ts.Current); // skip "default" and ":" } else { statement = ParseNextStatement(sub_ts, parseInfo); if (statement != null) case_statements.Add(statement); } //else if (tok.value == "{") // case_statements.Add(ParseStatementBlock(sub_ts.NextUntilOperatorClose(), parseInfo)); //else // case_statements.Add(GetNextExpression(sub_ts, AnOperator.dicSystemOperator[";"], parseInfo)); } if (case_statements.Count > 0) { if (test_values.Count > 0) case_list.Add(Expression.SwitchCase(Expression.Block(case_statements), test_values)); if (isDefault) default_statements = Expression.Block(case_statements); } // end stack lv = parseInfo.localVariableStack.Pop(); jumpInfo = parseInfo.jumpInfoStack.Pop(); if (jumpInfo.breakLabel == null) jumpInfo.breakLabel = Expression.Label(Expression.Label()); // create switch statement = Expression.Switch(test, default_statements, case_list.ToArray()); statement = Expression.Block(lv.Values, statement, jumpInfo.breakLabel); break; #endregion case "try": #region try { statement } catch(T var) { statement2 } finally { statement2 } // parse try block Assert((tok = ts.Next()) != null && tok.value == "{", tok); // skip "try" to "{" statement = ParseStatementBlock(ts.NextUntilOperatorClose(), parseInfo, true); if (statement == null) statement = Expression.Empty(); // parse catch blocks List<CatchBlock> catch_list = new List<CatchBlock>(); while (ts.CurrentValue == "catch") { ts.Next(); // skip "catch" bool hasParameter = false; if (ts.CurrentValue == "(") { hasParameter = true; parseInfo.localVariableStack.Push(new Dictionary<string, ParameterExpression>()); Assert(ParseNextExpression(ts.NextUntilOperatorClose(), null, parseInfo) == null && parseInfo.localVariableStack.Peek().Count == 1, "Invalid syntax for catch."); // can only have one variable declare and no value assignment } Assert(ts.CurrentValue == "{", ts.Current); statement2 = ParseStatementBlock(ts.NextUntilOperatorClose(), parseInfo, true); if (statement2 == null) statement2 = Expression.Empty(); if (hasParameter) { Dictionary<string, ParameterExpression> dic = parseInfo.localVariableStack.Pop(); foreach (string key in dic.Keys) // there is only one key catch_list.Add(Expression.Catch(dic[key], statement2)); } else catch_list.Add(Expression.Catch(typeof(Exception), statement2)); } // parse finally block statement2 = null; if (ts.CurrentValue == "finally") { Assert((tok = ts.Next()) != null && tok.value == "{", tok); // skip "finally" statement2 = ParseStatementBlock(ts.NextUntilOperatorClose(), parseInfo, false); if (statement2 == null) statement2 = Expression.Empty(); } statement = Expression.TryCatchFinally(statement, statement2, catch_list.ToArray()); break; #endregion case "throw": #region throw new T; ts.Next(); // skip "throw" statement2 = ParseNextExpression(ts, AnOperator.dicSystemOperator[";"], parseInfo); if (statement2 == null) statement = Expression.Rethrow(); else statement = Expression.Throw(statement2); break; #endregion case "return": #region return exp; ts.Next(); // skip "return" exp1 = ParseNextExpression(ts, AnOperator.dicSystemOperator[";"], parseInfo); if (exp1 == null) { if (parseInfo.returnLabel == null) parseInfo.returnLabel = Expression.Label(Expression.Label()); statement = Expression.Return(parseInfo.returnLabel.Target); } else { if (exp1.Type != typeof(object)) exp1 = Expression.Convert(exp1, typeof(object)); // convert all return value to object in case return different type if (parseInfo.returnLabel == null) parseInfo.returnLabel = Expression.Label(Expression.Label(exp1.Type), Expression.Default(exp1.Type)); statement = Expression.Return(parseInfo.returnLabel.Target, exp1); } break; #endregion } } if (statement == null) { if (tok.value == "{") statement = ParseStatementBlock(ts.NextUntilOperatorClose(), parseInfo, false); else statement = ParseNextExpression(ts, AnOperator.dicSystemOperator[";"], parseInfo); } if (ts.CurrentValue == ";") ts.Next(); // skip ";" return statement; }
internal Expression ParseStatementBlock(TokenStore ts, ParseInfo parseInfo, bool isVoid) { List<Expression> expr_list = new List<Expression>(); parseInfo.localVariableStack.Push(new Dictionary<string, ParameterExpression>()); //AToken tok; //Expression test, exp1, exp2, statement, statement2; if (ts != null) while (ts.Current != null) { Expression statement = ParseNextStatement(ts, parseInfo); if (statement != null) expr_list.Add(statement); } if (isVoid && expr_list.Count > 0 && expr_list[expr_list.Count - 1].Type != typeof(void)) expr_list.Add(Expression.Empty()); var localVariable = parseInfo.localVariableStack.Pop(); if (parseInfo.localVariableStack.Count == 0 && parseInfo.returnLabel != null) // this is the initial block, add return label if has been referred inside the block. expr_list.Add(parseInfo.returnLabel); if (expr_list.Count == 0) return Expression.Empty(); //.Constant(null); else if (expr_list.Count == 1 && localVariable.Count==0) return expr_list[0]; else return Expression.Block(localVariable.Values, expr_list.ToArray()); }
internal static TokenStore Parse(string exp_string, out TokenStore declare_ts) { List<AToken> list = new List<AToken>(); List<AToken> declare_list = null; int start_pos = 0; TOKEN_TYPE tok_type = TOKEN_TYPE.NONE; bool isHex = false; // 0xFFFF bool isExponent = false; // 1e10, 1E-2 bool isVerbatim = false; // @"xxx" char start_quotation = '"'; StringBuilder text_value = new StringBuilder(); // blank : c <= ' ' // text: '"' // number : 0-9 // decimal : . // variable : A-Z,a-z,_ // operator: else for (int idx = 0; idx < exp_string.Length; idx++) { char c = exp_string[idx]; char c2 = (idx + 1) < exp_string.Length ? exp_string[idx + 1] : (char)0; switch (tok_type) { case TOKEN_TYPE.NONE: #region NONE if (c <= ' ') continue; // skip space start_pos = idx; if (c == '/' && c2 == '/') { idx++; tok_type = TOKEN_TYPE.COMMENT; } else if (c == '/' && c2 == '*') { idx++; tok_type = TOKEN_TYPE.COMMENT_BLOCK; } else if (c == '@' && (c2 == '"' || c2 == '\'')) { idx++; start_quotation = c2; tok_type = TOKEN_TYPE.TEXT; isVerbatim = true; } else if (c == '"' || c == '\'') { start_quotation = c; tok_type = TOKEN_TYPE.TEXT; } else if (c == '0' && (c2 == 'x' || c2 == 'X')) { idx++; tok_type = TOKEN_TYPE.INT; isHex = true; } else if (c >= '0' && c <= '9') tok_type = TOKEN_TYPE.INT; else if (c == '.') { if (c2 >= '0' && c2 <= '9') tok_type = TOKEN_TYPE.DOUBLE; // no leading digit number else tok_type = TOKEN_TYPE.OPERATOR; // (x).y; x[idx].y } else if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c == '_') tok_type = TOKEN_TYPE.IDENTIFIER; else tok_type = TOKEN_TYPE.OPERATOR; break; #endregion NONE case TOKEN_TYPE.COMMENT: // // xxxx \n if (c == '\n') tok_type = TOKEN_TYPE.NONE; // skip eveything until new line; break; case TOKEN_TYPE.COMMENT_BLOCK: // /* xxxx */ if (c == '*' && c2 == '/') { idx++; tok_type = TOKEN_TYPE.NONE; } // skip eveything until "*/"; break; case TOKEN_TYPE.TEXT: // "xxxx" or 'xxxx' #region TEXT if (!isVerbatim && c == '\\') // escape for string { idx++; // use c2 switch (c2) { case '0': text_value.Append('\0'); break; // \0 case 'n': text_value.Append('\n'); break; // new line case 't': text_value.Append('\t'); break; // tab case 'r': text_value.Append('\r'); break; // carriage return case 'a': text_value.Append('\a'); break; // alert case 'b': text_value.Append('\b'); break; // back space case 'v': text_value.Append('\v'); break; // vertical tab case 'f': text_value.Append('\f'); break; // Form Feed case 'x': // hexadecimal \xF \xFF \xFFF \xFFFF case 'u': // unicode \uFFFF case 'U': // unicode \UFFFFFFFF { int additional_digits = 0; while (additional_digits < (c2 == 'U' ? 8 : 4) && (c = exp_string.Length > idx + additional_digits + 1 ? exp_string[idx + additional_digits + 1] : (char)0) != (char)0 && (c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f')) additional_digits++; if(additional_digits==0 || c2=='u' && additional_digits<4 || c2=='U'&&additional_digits<8) throw new ExprException("Expecting hexadecimal for operator: '\\" + c2 + "'"); else { text_value.Append((char)Convert.ToInt16("0x" + exp_string.Substring(idx + 1, additional_digits), 16)); idx += additional_digits; } } break; default: text_value.Append(c2); break; // '\\', '\"', '\'' } } else if (isVerbatim && c == start_quotation && c2 == start_quotation) // escape for verbatim string { text_value.Append(c); idx++; } else if (c == start_quotation) // end text { list.Add(new AToken(start_pos, TOKEN_TYPE.TEXT, null, text_value.ToString())); text_value = new StringBuilder(); tok_type = TOKEN_TYPE.NONE; isVerbatim = false; } else text_value.Append(c); break; #endregion TEXT case TOKEN_TYPE.INT: #region INT if (c >= '0' && c <= '9') { } else if (isHex && (c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F')) { } else if (c == '.' && !isHex) tok_type = TOKEN_TYPE.DOUBLE; else if ((c == 'e' || c == 'E') && !isHex) { tok_type = TOKEN_TYPE.DOUBLE; isExponent = true; } else { string val = isHex ? Convert.ToUInt64(exp_string.Substring(start_pos, idx - start_pos), 16).ToString() : exp_string.Substring(start_pos, idx - start_pos); if (c <= ' ') // space, \t, \n, ... control charaters { list.Add(new AToken(start_pos, tok_type, null, val)); tok_type = TOKEN_TYPE.NONE; } else if (c == '/' && c2 == '/') { list.Add(new AToken(start_pos, tok_type, null, val)); tok_type = TOKEN_TYPE.COMMENT; idx++; } else if (c == '/' && c2 == '*') { list.Add(new AToken(start_pos, tok_type, null, val)); tok_type = TOKEN_TYPE.COMMENT_BLOCK; idx++; } else if (c == 'U' || c == 'u') { if (c2 == 'L' || c2 == 'l') { list.Add(new AToken(start_pos, TOKEN_TYPE.ULONG, null, val)); tok_type = TOKEN_TYPE.NONE; idx++; } else { list.Add(new AToken(start_pos, TOKEN_TYPE.UINT, null, val)); tok_type = TOKEN_TYPE.NONE; } } else if (c == 'L' || c == 'l') { if (c2 == 'U' || c2 == 'u') { list.Add(new AToken(start_pos, TOKEN_TYPE.ULONG, null, val)); tok_type = TOKEN_TYPE.NONE; idx++; } else { list.Add(new AToken(start_pos, TOKEN_TYPE.LONG, null, val)); tok_type = TOKEN_TYPE.NONE; } } else if (!isHex && (c == 'F' || c == 'f')) { list.Add(new AToken(start_pos, TOKEN_TYPE.FLOAT, null, exp_string.Substring(start_pos, idx - start_pos))); tok_type = TOKEN_TYPE.NONE; } else if (!isHex && (c == 'D' || c == 'd')) { list.Add(new AToken(start_pos, TOKEN_TYPE.DOUBLE, null, exp_string.Substring(start_pos, idx - start_pos))); tok_type = TOKEN_TYPE.NONE; } else if (!isHex && (c == 'M' || c == 'm')) { list.Add(new AToken(start_pos, TOKEN_TYPE.DECIMAL, null, exp_string.Substring(start_pos, idx - start_pos))); tok_type = TOKEN_TYPE.NONE; } else if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c == '_') { list.Add(new AToken(start_pos, tok_type, null, val)); start_pos = idx; tok_type = TOKEN_TYPE.IDENTIFIER; // report error later } else { // operator, add previous token list.Add(new AToken(start_pos, tok_type, null, val)); start_pos = idx; tok_type = TOKEN_TYPE.OPERATOR; } isHex = false; } break; #endregion NUMBER case TOKEN_TYPE.DOUBLE: #region DOUBLE if (c >= '0' && c <= '9') { } else if ((c == '-' || c == '+') && isExponent) { } // 1e-2. can only have one sign else { if (c <= ' ') // space, \t, \n, ... control charaters { list.Add(new AToken(start_pos, tok_type, null, exp_string.Substring(start_pos, idx - start_pos))); tok_type = TOKEN_TYPE.NONE; } else if (c == '/' && c2 == '/') { list.Add(new AToken(start_pos, tok_type, null, exp_string.Substring(start_pos, idx - start_pos))); tok_type = TOKEN_TYPE.COMMENT; idx++; } else if (c == '/' && c2 == '*') { list.Add(new AToken(start_pos, tok_type, null, exp_string.Substring(start_pos, idx - start_pos))); tok_type = TOKEN_TYPE.COMMENT_BLOCK; idx++; } else if (c == 'F' || c == 'f') { list.Add(new AToken(start_pos, TOKEN_TYPE.FLOAT, null, exp_string.Substring(start_pos, idx - start_pos))); tok_type = TOKEN_TYPE.NONE; } else if (c == 'D' || c == 'd') { list.Add(new AToken(start_pos, TOKEN_TYPE.DOUBLE, null, exp_string.Substring(start_pos, idx - start_pos))); tok_type = TOKEN_TYPE.NONE; } else if (c == 'M' || c == 'm') { list.Add(new AToken(start_pos, TOKEN_TYPE.DECIMAL, null, exp_string.Substring(start_pos, idx - start_pos))); tok_type = TOKEN_TYPE.NONE; } else if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c == '_') { list.Add(new AToken(start_pos, tok_type, null, exp_string.Substring(start_pos, idx - start_pos))); start_pos = idx; tok_type = TOKEN_TYPE.IDENTIFIER; // report error later } else { // token change, save previous token list.Add(new AToken(start_pos, tok_type, null, exp_string.Substring(start_pos, idx - start_pos))); start_pos = idx; tok_type = TOKEN_TYPE.OPERATOR; } } isExponent = false; // can only have one sign right after 'e' break; #endregion DOUBLE case TOKEN_TYPE.IDENTIFIER: #region VARIABLE // VARIABLE(x or ns.x) can be a token of // - boolean: true / false => BOOL // - null: null => TEXT // - is => operator // - new => operator // - property: .x => VARIABLE. continue to see operator '[' and '(' for x[] and x() // - static type: ns.x => TYPE. continue to see operator '[' and '(' for x[] and x() // - parameter: x => VARIABLE // - un-typed parameter: error => VARIABLE, will report error later if (c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c == '_') { } else { string variable_name = exp_string.Substring(start_pos, idx - start_pos); if (variable_name == "true" || variable_name == "false") // boolean list.Add(new AToken(start_pos, TOKEN_TYPE.BOOL, null, variable_name)); else if (variable_name == "null") // null list.Add(new AToken(start_pos, TOKEN_TYPE.TEXT, null, null)); else if (variable_name == "is" // is || variable_name == "as" // as || variable_name == "new" // new || variable_name == "typeof" // typeof || variable_name == "sizeof" // sizeof ) ParseOperatorTokens(start_pos, variable_name, ref list, ref declare_list); else // un-typed parameter, will return error later list.Add(new AToken(start_pos, tok_type, null, variable_name)); // set next token type if (c <= ' ') tok_type = TOKEN_TYPE.NONE; else if (c == '/' && c2 == '/') { tok_type = TOKEN_TYPE.COMMENT; idx++; } else if (c == '/' && c2 == '*') { tok_type = TOKEN_TYPE.COMMENT_BLOCK; idx++; } else tok_type = TOKEN_TYPE.OPERATOR; start_pos = idx; } break; #endregion VARIABLE case TOKEN_TYPE.OPERATOR: #region OPERATOR if (c <= ' ') // space, \t, \n, ... control charaters { ParseOperatorTokens(start_pos, exp_string.Substring(start_pos, idx - start_pos), ref list, ref declare_list); tok_type = TOKEN_TYPE.NONE; } else if (c == '/' && c2 == '/') { ParseOperatorTokens(start_pos, exp_string.Substring(start_pos, idx - start_pos), ref list, ref declare_list); tok_type = TOKEN_TYPE.COMMENT; idx++; } else if (c == '/' && c2 == '*') { ParseOperatorTokens(start_pos, exp_string.Substring(start_pos, idx - start_pos), ref list, ref declare_list); tok_type = TOKEN_TYPE.COMMENT_BLOCK; idx++; } else if (c == '0' && (c2 == 'x' || c2 == 'X')) { ParseOperatorTokens(start_pos, exp_string.Substring(start_pos, idx - start_pos), ref list, ref declare_list); start_pos = idx; isHex = true; tok_type = TOKEN_TYPE.INT; idx++; } else if (c >= '0' && c <= '9') { ParseOperatorTokens(start_pos, exp_string.Substring(start_pos, idx - start_pos), ref list, ref declare_list); start_pos = idx; tok_type = TOKEN_TYPE.INT; } else if (c == '@' && (c2 == '"' || c2 == '\'')) { ParseOperatorTokens(start_pos, exp_string.Substring(start_pos, idx - start_pos), ref list, ref declare_list); idx++; start_pos = idx; // start from " instead of @ tok_type = TOKEN_TYPE.TEXT; start_quotation = c2; isVerbatim = true; } else if (c == '"' || c == '\'') { ParseOperatorTokens(start_pos, exp_string.Substring(start_pos, idx - start_pos), ref list, ref declare_list); start_pos = idx; tok_type = TOKEN_TYPE.TEXT; start_quotation = c; } else if (c == '.' && c2 >= '0' && c2 <= '9') // no leading digit decimal, like .999 { ParseOperatorTokens(start_pos, exp_string.Substring(start_pos, idx - start_pos), ref list, ref declare_list); start_pos = idx; OPERATOR_TYPE previous_token_op_type = (list.Count > 0 && list[list.Count - 1].op != null) ? list[list.Count - 1].op.op_type : OPERATOR_TYPE.UNKNOWN; if (previous_token_op_type == OPERATOR_TYPE.CLOSE) tok_type = TOKEN_TYPE.OPERATOR; // (x).y; x[idx].y else tok_type = TOKEN_TYPE.DOUBLE; // no leading digit number } else if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c == '_') { ParseOperatorTokens(start_pos, exp_string.Substring(start_pos, idx - start_pos), ref list, ref declare_list); start_pos = idx; tok_type = TOKEN_TYPE.IDENTIFIER; } else { } // continue operator break; #endregion OPERATOR } } if (tok_type == TOKEN_TYPE.COMMENT_BLOCK || tok_type == TOKEN_TYPE.TEXT) throw new ExprException("Unexpected end of the expression."); else if (tok_type != TOKEN_TYPE.NONE && tok_type != TOKEN_TYPE.COMMENT) { if (tok_type == TOKEN_TYPE.OPERATOR) ParseOperatorTokens(start_pos, exp_string.Substring(start_pos, exp_string.Length - start_pos), ref list, ref declare_list); else list.Add(new AToken(start_pos, tok_type, null, exp_string.Substring(start_pos, exp_string.Length - start_pos))); } declare_ts = declare_list != null && declare_list.Count > 0 ? new TokenStore(exp_string, declare_list) : null; return new TokenStore(exp_string, list); }
internal Expression ParseReferredParameterOrType(TokenStore ts, ParseInfo parseInfo, bool allowType, bool allowVariable, bool allowArrayType) { Type t = null; Expression exp = null; StringBuilder var_fullname = new StringBuilder(); AToken tok = ts.Current; while (exp == null && tok != null && tok.tok_type == TOKEN_TYPE.IDENTIFIER) { var_fullname.Append(tok.value); // try local variable if (allowVariable && (exp = parseInfo.GetReferredVariable(var_fullname.ToString())) != null) { ts.Next(); break; } // try referred parameter else if (allowVariable && (t = this.QueryParameterType(var_fullname.ToString())) != null) { exp = parseInfo.GetReferredParameter(t, tok.value); ts.Next(); break; } // try static Generic Type else if (allowType && ts.PeekTokenValue(1) == "<") { // v1.1: Generic Type reference tok = ts.Next(); // to "<" List<Type> param_types = new List<Type>(); List<Expression> param_list = ParseParameters(ts, parseInfo, param_types, true); Assert((t = this.QueryStaticType(var_fullname.Append("`").Append(param_list.Count).ToString()).MakeGenericType(param_types.ToArray())) != null, tok); t = ParseStaticTypeExtension(ts, t, allowArrayType); exp = Expression.Constant(t); // Type: (T)x or T.xxx break; } // try static Type else if (allowType && (t = this.QueryStaticType(var_fullname.ToString())) != null) { // Static Type reference ts.Next(); t = ParseStaticTypeExtension(ts, t, allowArrayType); exp = Expression.Constant(t); break; } // neither parameter or static type if ((tok = ts.Next()) == null || tok.value != ".") break; // unexpected var_fullname.Append("."); tok = ts.Next(); // skip "." } return exp; }