public void Add(Token token, bool isOperator = false) { _source = _source ?? token.Source; /////////////////////////////// // SCRIPTING if (isOperator && _stack.Count < 2 && token.Type == TokenType.LogicalAnd && token.Lexeme == ";") { // most probably script char that represents empty statement // => ignore return; } // ////////////////////////////// _stack.Push(token); if (!isOperator) { return; } try { var ast = _astBuilder.PopExpression(_stack, _p); _stack.Push(ast.ToToken()); } catch (XPressionException) { throw; } catch (Exception ex) { throw new XPressionException(token.Source, ex.Message, token.Position, ex); } }
// C# equivalents: // if(test,body) => return test ? body() : true; // if(test,trueBody,falseBody) => return test ? trueBody() : falseBody(); // if parametercount==2 (falseBody is omitted), then the falseBody always // returns true (so then the trueBody MUST return a boolean value as well) public bool TryBuildExpression(ASTBuilder treeBuilder, FunctionToken functionToken, Stack <Token> stack, ParameterExpression p, out Expression output) { var ifFalse = functionToken.ParameterCount >= 3 ? treeBuilder.PopExpression(stack, p) : Expression.Constant(true); var ifTrue = treeBuilder.PopExpression(stack, p); var test = treeBuilder.PopExpression(stack, p); output = Expression.Condition(test.Convert <bool>(), ifTrue, ifFalse); return(true); }
public bool TryBuildExpression(ASTBuilder treeBuilder, FunctionToken functionToken, Stack <Token> stack, ParameterExpression p, out Expression output) { if (functionToken.ParameterCount == 0) { throw new XPressionException(functionToken.Source, "format requires at least one argument", functionToken.Position); } var args = new List <Expression>(); for (var i = 0; i < functionToken.ParameterCount; i++) { args.Add(treeBuilder.PopExpression(stack, p)); } args.Reverse(); // reverse stack order output = Expression.Call( MemberTokens.String.FormatWithProvider, Expression.Constant(CultureInfo.InvariantCulture), args[0], Expression.NewArrayInit( typeof(object), args.Skip(1).Select(e => e.Type == typeof(object) ? e : Expression.Convert(e, typeof(object))) ) ); return(true); }
public bool TryBuildExpression(ASTBuilder treeBuilder, FunctionToken functionToken, Stack <Token> stack, ParameterExpression p, out Expression output) { var rightToken = stack.Pop(); // must be a constant string var target = treeBuilder.PopExpression(stack, p); if (target.IsNullConstant()) { output = Expression.Convert(Expression.Constant(null), typeof(bool?)); return(true); } Type type; try { type = treeBuilder.Grammar.GetType(rightToken.Lexeme); } catch (Exception ex) { throw new XPressionException(functionToken.Source, "Invalid type: " + rightToken.Lexeme, rightToken.Position, ex); } if ((!target.Type.IsValueType || target.Type.IsNullable()) && type.IsValueType && !type.IsNullable()) { type = typeof(Nullable <>).MakeGenericType(type); } output = Expression.TypeEqual(target, type); return(true); }
public bool TryBuildExpression(ASTBuilder treeBuilder, FunctionToken functionToken, Stack <Token> stack, ParameterExpression p, out Expression output) { var target = treeBuilder.PopExpression(stack, p); if (target.Type.EnsureNotNullable() != typeof(DateTimeOffset)) { throw new XPressionException(functionToken.Source, "expected a datatimeoffset argument", functionToken.Position); } if (target.IsNullConstant()) { output = Expression.Convert(Expression.Constant(null), typeof(int?)); return(true); } if (target.Type.IsNullable()) { output = Expression.Convert(target, target.Type.EnsureNotNullable()); return(true); } output = Expression.MakeMemberAccess(Expression.MakeMemberAccess(target, MemberTokens.DateTimeOffset.Offset), MemberTokens.TimeSpan.TotalMinutes); return(true); }
// in our case else is syntactic sugar: simply return the first expression on the stack public bool TryBuildExpression(ASTBuilder treeBuilder, FunctionToken functionToken, Stack <Token> stack, ParameterExpression p, out Expression output) { output = treeBuilder.PopExpression(stack, p); return(true); }
public bool TryBuildExpression(ASTBuilder astBuilder, FunctionToken functionToken, Stack <Token> stack, ParameterExpression p, out Expression output) { output = null; IFunctionBuilder builder; if (_builders.TryGetValue(functionToken.Lexeme, out builder)) { if (builder.TryBuildExpression(astBuilder, functionToken, stack, p, out output)) { return(true); } } ConcurrentDictionary <FunctionSignature, FunctionBuilder> lookup; if (!_members.TryGetValue(functionToken.Lexeme, out lookup)) { return(false); } var args = new List <Expression>(); for (var i = 0; i < functionToken.ParameterCount; i++) { args.Add(astBuilder.PopExpression(stack, p)); } args.Add(p); // always initially probe instance call args.Reverse(); // reverse stack order FunctionBuilder factory; FunctionSignature fs1 = null, // instance fs2 = null; // static if (!TryFindFactory(lookup, fs1 = new FunctionSignature(args.Select(fp => fp.Type)), out factory)) { if (TryFindFactory(lookup, fs2 = new FunctionSignature(args.Skip(1).Select(fp => fp.Type)), out factory)) { args = args.Skip(1).ToList(); } } if (factory != null) { // found if (args.Any() && factory.ParameterTypes.Any()) { if (factory.ParameterTypes.Last().IsArray&& !args.Last().Type.IsArray) { // we need an argument conversion to params <some-type>[] if (fs2 != null) { // static invocation if (factory.ParameterTypes[0] == typeof(object[])) { args = new List <Expression>(new[] { Expression.NewArrayInit(typeof(object), args.Select(a => a.Convert <object>())) }); } else { args = new List <Expression>(new[] { Expression.NewArrayInit(args[0].Type, args) }); } } else { // instane invocation if (factory.ParameterTypes[1] == typeof(object[])) { args = new List <Expression>(new[] { args[0], Expression.NewArrayInit(typeof(object), args.Skip(1).Select(a => a.Convert <object>())) }); } else { args = new List <Expression>(new[] { args[0], Expression.NewArrayInit(args[0].Type, args.Skip(1)) }); } } } } output = factory.BuildExpression(args, p); return(true); } FunctionSignature signature; ///////////////////////////////////////////////////////////////////////////////////////////////////////// // 1. try instance if (args.Count == 2 || args.Skip(1).Select(x => x.Type).Distinct().Count() == 1) { signature = new FunctionSignature(new[] { args[0].Type, args[1].Type.MakeArrayType() }); if (TryFindFactory(lookup, signature, out factory)) { // probably params <type>[] arg args = new List <Expression> { args[0], Expression.NewArrayInit(args[1].Type, args.Skip(1)) }; lookup.TryAdd(fs1, factory);// register in lookup output = factory.BuildExpression(args, p); return(true); } } // any delegates? var args1 = args; var factories = lookup.Values.Where(f => f.HasDelegateArg && f.ParameterTypes.Count == args1.Count); foreach (var f in factories) { var ismatch = true; var i = 0; foreach (var t in f.ParameterTypes) { if (!(typeof(Delegate).IsAssignableFrom(t) || t.IsAssignableFrom(args[i].Type))) { ismatch = false; break; } i++; } if (ismatch) { lookup.TryAdd(fs1, f);// register in lookup output = f.BuildExpression(args, p); return(true); } } // params object[] ? signature = new FunctionSignature(new[] { args[0].Type, typeof(object).MakeArrayType() }); if (TryFindFactory(lookup, signature, out factory)) { // probably params object[] arg args = new List <Expression> { args[0], Expression.NewArrayInit(typeof(object), args.Skip(1).Select(e => e.Convert <object>())) }; lookup.TryAdd(fs1, factory);// register in lookup output = factory.BuildExpression(args, p); return(true); } // ////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////// // 2. try static args = args.Skip(1).ToList(); if (args.Count == 1 || args.Select(x => x.Type).Distinct().Count() == 1) { // all argumens have same type, look for array type signature = new FunctionSignature(new[] { args[0].Type.MakeArrayType() }); if (TryFindFactory(lookup, signature, out factory)) { // probably params <type>[] arg args = new List <Expression> { Expression.NewArrayInit(args[0].Type, args) }; lookup.TryAdd(fs2, factory);// register in lookup output = factory.BuildExpression(args, p); return(true); } } // any delegate? var args2 = args; factories = lookup.Values.Where(f => f.HasDelegateArg && f.ParameterTypes.Count - 1 == args2.Count); foreach (var f in factories) { var ismatch = true; var i = 0; foreach (var t in f.ParameterTypes.Skip(1)) { if (!(typeof(Delegate).IsAssignableFrom(t) || t.IsAssignableFrom(args[i].Type))) { ismatch = false; break; } i++; } if (ismatch) { lookup.TryAdd(fs2, f);// register in lookup output = f.BuildExpression(args, p); return(true); } } // params object[] ? signature = new FunctionSignature(new[] { typeof(object).MakeArrayType() }); if (TryFindFactory(lookup, signature, out factory)) { // probably params object[] arg args = new List <Expression> { args[0], Expression.NewArrayInit(typeof(object), args.Skip(1).Select(e => e.Convert <object>())) }; lookup.TryAdd(fs2, factory);// register in lookup output = factory.BuildExpression(args, p); return(true); } throw new XPressionException(functionToken.Source, "invalid arguments, overload not found for method " + functionToken.Lexeme, functionToken.Position); }