private Delegate CreateDefaultDelegate() { return(CompileVisitor.CompileAst( EngineIntrinsics, (ScriptBlockAst)ScriptBlock.Ast, Locals.Values.ToArray())); }
private Delegate ConvertToDelegate(PSDelegate psDelegate, Type destinationType) { lock (s_syncObject) { Dictionary <Type, Delegate> cacheEntry; if (!s_delegateCache.TryGetValue(psDelegate, out cacheEntry)) { cacheEntry = new Dictionary <Type, Delegate>(); s_delegateCache.Add(psDelegate, cacheEntry); } Delegate compiledDelegate; if (!cacheEntry.TryGetValue(destinationType, out compiledDelegate)) { compiledDelegate = CompileVisitor.CompileAst( psDelegate.EngineIntrinsics, (ScriptBlockAst)psDelegate.ScriptBlock.Ast, psDelegate.Locals.Values.ToArray(), destinationType); cacheEntry.Add(destinationType, compiledDelegate); } return(compiledDelegate); } }
/// <summary> /// Creates a Linq expression for a <see cref="CommandAst" /> representing /// the "lock" command. /// </summary> /// <param name="commandAst">The AST to convert.</param> /// <param name="targetAst">The AST containing the target of the keyword.</param> /// <param name="bodyAst">The AST containing the body of the keyword.</param> /// <param name="visitor">The <see cref="CompileVisitor" /> requesting the expression.</param> /// <returns>An expression representing the command.</returns> protected override Expression ProcessObjectAndBody( CommandAst commandAst, CommandElementAst targetAst, ScriptBlockExpressionAst bodyAst, CompileVisitor visitor) { var lockVar = Expression.Variable(typeof(object)); var lockTakenVar = Expression.Variable(typeof(bool)); return(visitor.NewBlock(() => Expression.Block( typeof(void), new[] { lockVar, lockTakenVar }, Expression.Call( ReflectionCache.Monitor_Enter, Expression.Assign( lockVar, Expression.Convert( targetAst.Compile(visitor), typeof(object))), lockTakenVar), Expression.TryFinally( bodyAst.ScriptBlock.EndBlock.Compile(visitor), Expression.IfThen( lockTakenVar, Expression.Call( ReflectionCache.Monitor_Exit, lockVar)))))); }
/// <summary> /// Creates a Linq expression for a <see cref="CommandAst" /> representing /// a custom command. /// </summary> /// <param name="commandAst">The AST to convert.</param> /// <param name="visitor">The <see cref="CompileVisitor" /> requesting the expression.</param> /// <returns>An expression representing the command.</returns> public Expression ProcessAst(CommandAst commandAst, CompileVisitor visitor) { if (commandAst.CommandElements.Count != 3) { visitor.Errors.ReportParseError( commandAst.Extent, nameof(ErrorStrings.MissingKeywordElements), string.Format( CultureInfo.CurrentCulture, ErrorStrings.MissingKeywordElements, CommandName)); return(Expression.Empty()); } if (!(commandAst.CommandElements[2] is ScriptBlockExpressionAst bodyAst)) { visitor.Errors.ReportParseError( commandAst.Extent, nameof(ErrorStrings.MissingKeywordBody), string.Format( CultureInfo.CurrentCulture, ErrorStrings.MissingKeywordBody, CommandName)); return(Expression.Empty()); } return(ProcessObjectAndBody( commandAst, commandAst.CommandElements[1], bodyAst, visitor)); }
/// <summary> /// Creates a Linq expression for a <see cref="CommandAst" /> representing /// the "default" command. /// </summary> /// <param name="commandAst">The AST to convert.</param> /// <param name="visitor">The <see cref="CompileVisitor" /> requesting the expression.</param> /// <returns>An expression representing the command.</returns> public Expression ProcessAst(CommandAst commandAst, CompileVisitor visitor) { if (commandAst.CommandElements == null || commandAst.CommandElements.Count != 2) { visitor.TryResolveType(null, out _); return(Expression.Empty()); } // Is using syntax "default([TypeName])" if (commandAst.CommandElements[1] is ParenExpressionAst paren && paren.Pipeline is PipelineAst pipeline && pipeline.PipelineElements.Count == 1 && pipeline.PipelineElements[0] is CommandExpressionAst commandExpression && commandExpression.Expression is TypeExpressionAst && visitor.TryResolveType(commandExpression.Expression, out Type resolvedType)) { return(Expression.Default(resolvedType)); } // Is using syntax "default TypeName" if (commandAst.CommandElements[1] is StringConstantExpressionAst stringConstant && LanguagePrimitives.TryConvertTo(stringConstant.Value, out resolvedType)) { return(Expression.Default(resolvedType)); } // Unknown syntax, but this method will produce parse errors for us. if (visitor.TryResolveType(commandAst.CommandElements[1], out resolvedType)) { return(Expression.Default(resolvedType)); } return(Expression.Empty()); }
private void RewriteIL(MethodBody body, Dictionary <Expr, Instruction> instructionLookup, Expr remove, Expr insert) { var il = body.GetILProcessor(); Instruction instInsertBefore; if (remove != null) { var vInstExtent = new InstructionExtentVisitor(instructionLookup); vInstExtent.Visit(remove); instInsertBefore = vInstExtent.Instructions.Last().Next; foreach (var instRemove in vInstExtent.Instructions) { il.Remove(instRemove); } } else { instInsertBefore = body.Instructions [0]; } if (insert != null) { var compiler = new CompileVisitor(il, instructionLookup, inst => il.InsertBefore(instInsertBefore, inst)); compiler.Visit(insert); } }
private Expression ReportInvalidSyntax(IScriptExtent extent, CompileVisitor visitor) { visitor.Errors.ReportParseError( extent, nameof(ErrorStrings.InvalidGenericSyntax), ErrorStrings.InvalidGenericSyntax); return(Expression.Empty()); }
/// <summary> /// Creates a Linq expression for a <see cref="CommandAst" /> representing /// the "generic" command. /// </summary> /// <param name="commandAst">The AST to convert.</param> /// <param name="visitor">The <see cref="CompileVisitor" /> requesting the expression.</param> /// <returns>An expression representing the command.</returns> public Expression ProcessAst(CommandAst commandAst, CompileVisitor visitor) { if (commandAst.CommandElements.Count != 2) { return(ReportInvalidSyntax(commandAst.Extent, visitor)); } var paren = commandAst.CommandElements[1] as ParenExpressionAst; if (paren == null) { return(ReportInvalidSyntax(commandAst.Extent, visitor)); } var pipeline = paren.Pipeline as PipelineAst; if (pipeline == null || pipeline.PipelineElements.Count != 1) { return(ReportInvalidSyntax(commandAst.Extent, visitor)); } var commandExpression = pipeline.PipelineElements[0] as CommandExpressionAst; if (commandExpression == null) { return(ReportInvalidSyntax(commandAst.Extent, visitor)); } var arrayLiteral = commandExpression.Expression as ArrayLiteralAst; if (arrayLiteral.Elements.Count < 2) { return(ReportInvalidSyntax(commandAst.Extent, visitor)); } var memberExpression = arrayLiteral.Elements[0] as InvokeMemberExpressionAst; if (memberExpression == null) { return(ReportInvalidSyntax(commandAst.Extent, visitor)); } var genericArguments = new Type[arrayLiteral.Elements.Count - 1]; for (var i = 1; i < arrayLiteral.Elements.Count; i++) { if (visitor.TryResolveType(arrayLiteral.Elements[i], out Type resolvedType)) { genericArguments[i - 1] = resolvedType; continue; } // If a type didn't resolve then a parse error was generated, so exit. return(Expression.Empty()); } return(visitor.CompileInvokeMemberExpression(memberExpression, genericArguments)); }
/// <summary> /// Attempt to process a <see cref="CommandAst" /> as a custom command. /// </summary> /// <param name="commandAst">The <see cref="CommandAst" /> to process.</param> /// <param name="visitor"> /// The <see cref="CompileVisitor" /> requesting the expression. /// </param> /// <param name="expression"> /// The <see cref="Expression" /> result if a command handler was found. /// </param> /// <returns><c>true</c> if a commmand handler was matched, otherwise <c>false</c>.</returns> public bool TryProcessAst(CommandAst commandAst, CompileVisitor visitor, out Expression expression) { if (_commandRegistry.TryGetValue(commandAst.GetCommandName(), out ICommandHandler handler)) { expression = handler.ProcessAst(commandAst, visitor); return(true); } expression = null; return(false); }
public SlowRowVirtualChannel(IExpression virtualExpression, int virtualParameterId, int slowRowRateInMilliHz, IParametersSymbolTable symbolTable, ISlowRowStorage <TTime> slowRowStorage, ITimeUtils <TTime> timeUtils) { m_virtualParameterId = virtualParameterId; m_slowRowRateInMilliHz = slowRowRateInMilliHz; m_timeUtils = timeUtils; m_context = new SlowRowExpressionContext <TTime>(slowRowStorage); var compiler = new CompileVisitor(m_context, symbolTable, new DefaultCallContext()); virtualExpression.Accept(compiler); m_evaluate = compiler.GetCompiledExpression(); }
public SingleLoggedParameterVirtualChannel(IExpression virtualExpression, int virtualParameterId, int loggedParameterId, int loggedParameterFrequencyInMilliHz, IParametersSymbolTable symbolTable, ISlowRowStorage <TTime> slowRowStorage, ITimeUtils <TTime> timeUtils) { m_virtualParameterId = virtualParameterId; m_loggedParameterFrequencyInMilliHz = loggedParameterFrequencyInMilliHz; m_timeUtils = timeUtils; m_context = new SingleValueWithSlowRowExpressionContext <TTime>(slowRowStorage, loggedParameterId); var compiler = new CompileVisitor(m_context, symbolTable, new DefaultCallContext()); virtualExpression.Accept(compiler); m_evaluate = compiler.GetCompiledExpression(); }
public void ParseAndCompileTest() { var expression = SMExpressionParser.ParseOrThrow("log(10) + $aaa + abs(nolog($adc_Controller)) + 1*2"); var simpleExpressionContext = new TestExpressionContext(); var compiler = new CompileVisitor(simpleExpressionContext, new TestSymbolTable(), new DefaultCallContext()); expression.Accept(compiler); var compiledExpression = compiler.GetCompiledExpression(); Assert.AreEqual(14.0, compiledExpression(), 1e-9); }
public MultiLoggedParametersVirtualChannel(IExpression virtualExpression, int virtualParameterId, int[] loggedParametersIds, int loggedParametersFrequencyInMilliHz, IParametersSymbolTable symbolTable, ISlowRowStorage <TTime> slowRowStorage, ITimeUtils <TTime> timeUtils) { m_virtualParameterId = virtualParameterId; m_loggedParametersFrequencyInMilliHz = loggedParametersFrequencyInMilliHz; m_timeUtils = timeUtils; m_coverageCircularBuffer = new CoverageCircularBuffer <TTime>(loggedParametersIds, loggedParametersFrequencyInMilliHz, 30, timeUtils); m_context = new MultiValueWithSlowRowExpressionContext <TTime>(slowRowStorage, loggedParametersIds); var compiler = new CompileVisitor(m_context, symbolTable, new DefaultCallContext()); virtualExpression.Accept(compiler); m_evaluate = compiler.GetCompiledExpression(); m_timeZero = timeUtils.Zero(); }
/// <summary> /// Determines the correct member for an expression and creates a /// <see cref="Expression" /> representing it's invocation. /// </summary> /// <param name="visitor">The <see cref="CompileVisitor" /> requesting the bind.</param> /// <param name="instance">The instance <see cref="Expression" /> for the invocation.</param> /// <param name="name">The member name to use while resolving the method.</param> /// <param name="arguments">The arguments to use while resolving the method.</param> /// <param name="genericArguments">The generic arguments to use while resolving the method.</param> /// <returns> /// A <see cref="BindingResult" /> that either contains the /// <see cref="Expression" /> or the <see cref="ArgumentException" /> and /// error ID. /// </returns> internal BindingResult BindMethod( CompileVisitor visitor, Expression instance, string name, Ast[] arguments, Type[] genericArguments) { return(BindMethod( visitor, instance.Type, name, arguments, instance, genericArguments)); }
/// <summary> /// Determines the correct member for an expression and creates a /// <see cref="Expression" /> representing it's invocation. /// </summary> /// <param name="visitor">The <see cref="CompileVisitor" /> requesting the bind.</param> /// <param name="sourceType">The source <see cref="Type" /> for the invocation.</param> /// <param name="name">The member name to use while resolving the method.</param> /// <param name="arguments">The arguments to use while resolving the method.</param> /// <param name="genericArguments">The generic arguments to use while resolving the method.</param> /// <returns> /// A <see cref="BindingResult" /> that either contains the /// <see cref="Expression" /> or the <see cref="ArgumentException" /> and /// error ID. /// </returns> internal BindingResult BindMethod( CompileVisitor visitor, Type sourceType, string name, Ast[] arguments, Type[] genericArguments) { return(BindMethod( visitor, sourceType, name, arguments, null, genericArguments)); }
public Oc5Runner(string oc5Source) { Oc5Source = oc5Source; var inputStream = new AntlrInputStream(oc5Source); var lexer = new Oc5Lexer(inputStream); var tokenStream = new CommonTokenStream(lexer); var parser = new Oc5Parser(tokenStream); var ocfileContext = parser.ocfile(); var visitor = new CompileVisitor(ocfileContext); Oc5Model = visitor.Oc5Model; Oc5ModelState = visitor.Oc5ModelState; }
/// <summary> /// Compile a <see cref="Ast" /> into a <see cref="Expression" />. /// </summary> /// <param name="ast">The <see cref="Ast" /> to compile.</param> /// <param name="visitor">The <see cref="CompileVisitor" /> requesting the compile.</param> /// <returns>The compiled <see cref="Expression" /> object.</returns> public static Expression Compile(this Ast ast, CompileVisitor visitor) { try { return((Expression)ast.Visit(visitor)); } catch (ArgumentException e) { visitor.Errors.ReportParseError(ast.Extent, e); return(Expression.Empty()); } catch (InvalidOperationException e) { visitor.Errors.ReportParseError(ast.Extent, e); return(Expression.Empty()); } }
/// <summary> /// Compile all asts in a given <see cref="IList{TAst}" />. /// </summary> /// <param name="asts">The <see cref="Ast" /> objects to compile.</param> /// <param name="visitor">The <see cref="CompileVisitor" /> requesting the compile.</param> /// <typeparam name="TAst">The type of <see cref="Ast" /> to expect in the list.</typeparam> /// <returns>The compiled <see cref="Expression" /> objects.</returns> public static Expression[] CompileAll <TAst>(this IList <TAst> asts, CompileVisitor visitor) where TAst : Ast { if (asts == null || asts.Count == 0) { return(s_emptyExpressions); } var expressions = new Expression[asts.Count]; for (var i = 0; i < asts.Count; i++) { expressions[i] = (Expression)asts[i].Visit(visitor); } return(expressions); }
/// <summary> /// 准备运行代码 /// </summary> private CompileVisitor prepareForRunning(IParseTree tree) { if (tree == null) { return(null); } var visitor = new CompileVisitor(); try { visitor.generateCodes(tree); //中间代码存为字符串。 intermediateCode = ""; for (int i = 0; i < visitor.codes.Count; i++) { string newLine = i + ":\t" + visitor.codes[i].toString() + "\n"; intermediateCode += newLine; } } catch (VariableNotFountException exp) { handleCompileTimeError(new List <ErrorInfo> { exp.Error }); intermediateCode = null; return(null); } catch (VariableRedefinedException exp) { handleCompileTimeError(new List <ErrorInfo> { exp.Error }); intermediateCode = null; return(null); } if (!State.ConsoleShowed) { extraPanelButton_Click(btnConsoleWindow, null); } consoleTextBox.Text = ""; return(visitor); }
/// <summary> /// 调试代码 /// </summary> private void btnDebug_Click(object sender, RoutedEventArgs e) { IParseTree tree = prepareForCodeGen(); CompileVisitor visitor = prepareForRunning(tree); if (visitor == null) { return; } prepareForDebug(); // 断点列表 List <int> breakpoints = textEditor.GetBreakPoints(); // 初始化调试器 cmmDebuger = new CMMDebuger(visitor.codes, breakpoints); cmmDebuger.LoadDebugInformation(visitor.GetGlobalSymbolTable(), visitor.GetFunctionInformations()); cmmDebuger.setListener(this); cmmDebuger.OutputStream = this; cmmDebuger.NeedDebug += HandlerDebug; cmmDebuger.DebugFinish += CmmDebugerDebugFinish; debugThread = new Thread(() => { try { //Print("\n调试模式\n"); isDebug = true; cmmDebuger.Run(); Print("\nprogram exit\n"); isDebug = false; } catch (RuntimeException e1) { Print("Line:" + e1.line.ToString() + " " + e1.Message); } catch (Exception e2) { Print(e2.Message); } }); debugThread.Name = "Debug"; debugThread.Start(); }
/// <summary> /// Creates a Linq expression for a <see cref="CommandAst" /> representing /// the "with" command. /// </summary> /// <param name="commandAst">The AST to convert.</param> /// <param name="targetAst">The AST containing the target of the keyword.</param> /// <param name="bodyAst">The AST containing the body of the keyword.</param> /// <param name="visitor">The <see cref="CompileVisitor" /> requesting the expression.</param> /// <returns>An expression representing the command.</returns> protected override Expression ProcessObjectAndBody( CommandAst commandAst, CommandElementAst targetAst, ScriptBlockExpressionAst bodyAst, CompileVisitor visitor) { var disposeVar = Expression.Variable(typeof(IDisposable)); return(visitor.NewBlock(() => Expression.Block( typeof(void), new[] { disposeVar }, Expression.Assign( disposeVar, Expression.Convert( targetAst.Compile(visitor), typeof(IDisposable))), Expression.TryFinally( bodyAst.ScriptBlock.EndBlock.Compile(visitor), Expression.Call(disposeVar, ReflectionCache.IDisposable_Dispose))))); }
/// <summary> /// 运行代码 /// </summary> private void run_Click(object sender, RoutedEventArgs e) { IParseTree tree = prepareForCodeGen(); CompileVisitor visitor = prepareForRunning(tree); if (visitor == null) { return; } VirtualMachine vm = new VirtualMachine(); this.vm = vm; vm.register(this); vm.needInput += handleNeedInput; runnerThread = new Thread(() => { vm.interpret(visitor.codes); }); runnerThread.Start(); }
/// <summary> /// The EndProcessing method. /// </summary> protected override void EndProcessing() { var variables = SessionState.InvokeCommand.InvokeScript( "Get-Variable -Scope 0", false, PipelineResultTypes.Output, null, null) .Select(pso => pso.BaseObject) .Cast <PSVariable>() .Where(v => !SpecialVariables.IgnoreLocal.Contains(v.Name)); try { if (DelegateType == null) { WriteObject( CompileVisitor.CompileAst( (EngineIntrinsics)SessionState.PSVariable.GetValue(Strings.ExecutionContextVariableName), (ScriptBlockAst)Expression.Ast, variables.ToArray()), enumerateCollection: false); return; } WriteObject( CompileVisitor.CompileAst( (EngineIntrinsics)SessionState.PSVariable.GetValue(Strings.ExecutionContextVariableName), (ScriptBlockAst)Expression.Ast, variables.ToArray(), DelegateType), enumerateCollection: false); } catch (ParseException e) { ThrowTerminatingError(new ErrorRecord(e.ErrorRecord, e)); } }
public void ParseAndCompilePerformanceTest() { var expression = SMExpressionParser.ParseOrThrow("log(10) + $aaa + abs(nolog($adc_Controller)) + 1*2"); var simpleExpressionContext = new TestExpressionContext(); var compiler = new CompileVisitor(simpleExpressionContext, new TestSymbolTable(), new DefaultCallContext()); expression.Accept(compiler); var compiledExpression = compiler.GetCompiledExpression(); var times = 1000000; var sw = Stopwatch.StartNew(); for (int i = 0; i < times; ++i) { compiledExpression(); } var elapsed = sw.ElapsedMilliseconds; Console.WriteLine($"Compiled: {elapsed}ms"); }
private bool ShouldBind( MethodInfo method, MethodArgument[] arguments, CompileVisitor visitor, out MethodInfo resolvedMethod) { var parameters = method.GetParameters(); if (parameters.Length != arguments.Length) { resolvedMethod = null; return(false); } BindingStatus status; status._map = new Dictionary <Type, Type>(); status._hasGenericParams = method.IsGenericMethod; for (var i = 0; i < parameters.Length; i++) { if (arguments[i].Ast != null && (arguments[i].Ast is ScriptBlockExpressionAst || arguments[i].Ast is ScriptBlockAst)) { if (!(typeof(Delegate).IsAssignableFrom(parameters[i].ParameterType) || typeof(LambdaExpression).IsAssignableFrom(parameters[i].ParameterType))) { resolvedMethod = null; return(false); } if (status.IsDelegateMatch(parameters[i].ParameterType, arguments[i], visitor)) { continue; } resolvedMethod = null; return(false); } if (arguments[i].Expression == null) { arguments[i].Expression = arguments[i].Ast.Compile(visitor); } if (!status.IsTypeMatch(parameters[i].ParameterType, arguments[i].Expression.Type)) { resolvedMethod = null; return(false); } } if (!status._hasGenericParams || !method.IsGenericMethodDefinition) { resolvedMethod = method; return(true); } var genericParameters = method.GetGenericArguments(); var genericArguments = new Type[genericParameters.Length]; for (var i = 0; i < genericParameters.Length; i++) { genericArguments[i] = status._map[genericParameters[i]]; } resolvedMethod = method.MakeGenericMethod(genericArguments); return(true); }
private BindingResult BindMethod( CompileVisitor visitor, Type sourceType, string name, Ast[] arguments, Expression instance, Type[] genericArguments) { var methodArgs = new MethodArgument[arguments.Length]; for (var i = 0; i < methodArgs.Length; i++) { methodArgs[i] = (MethodArgument)arguments[i]; } var didFindName = false; var isInstance = instance != null; var methods = sourceType.GetMethods(isInstance ? _instanceFlags : _staticFlags); MethodInfo boundMethod; BindingResult bindingResult = default(BindingResult); for (var i = 0; i < methods.Length; i++) { if (!methods[i].Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) { continue; } if (!didFindName) { didFindName = true; } if (genericArguments.Length > 0 && (!methods[i].IsGenericMethod || !AreGenericArgumentsValid(methods[i], genericArguments))) { continue; } if (genericArguments.Length > 0) { methods[i] = methods[i].MakeGenericMethod(genericArguments); } if (ShouldBind(methods[i], methodArgs, visitor, out boundMethod)) { var expressions = new Expression[methodArgs.Length]; for (var j = 0; j < methodArgs.Length; j++) { expressions[j] = methodArgs[j].Expression; } bindingResult.Expression = Expression.Call(instance, boundMethod, expressions); return(bindingResult); } } if (!isInstance) { bindingResult.Reason = new ArgumentException( string.Format( CultureInfo.CurrentCulture, ErrorStrings.NoMemberArgumentMatch, sourceType.FullName, name)); bindingResult.Id = nameof(ErrorStrings.NoMemberArgumentMatch); return(bindingResult); } var extensionArgs = new MethodArgument[methodArgs.Length + 1]; extensionArgs[0] = (MethodArgument)instance; for (var i = 1; i < extensionArgs.Length; i++) { extensionArgs[i] = methodArgs[i - 1]; } methods = GetExtensionMethods(); for (var i = 0; i < methods.Length; i++) { if (!methods[i].Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) { continue; } if (!didFindName) { didFindName = true; } if (genericArguments.Length > 0 && (!methods[i].IsGenericMethod || !AreGenericArgumentsValid(methods[i], genericArguments))) { continue; } if (genericArguments.Length > 0) { methods[i] = methods[i].MakeGenericMethod(genericArguments); } if (ShouldBind(methods[i], extensionArgs, visitor, out boundMethod)) { var expressions = new Expression[extensionArgs.Length]; for (var j = 0; j < extensionArgs.Length; j++) { expressions[j] = extensionArgs[j].Expression; } bindingResult.Expression = Expression.Call(boundMethod, expressions); return(bindingResult); } } if (!didFindName) { bindingResult.Reason = new ArgumentException( string.Format( CultureInfo.CurrentCulture, ErrorStrings.NoMemberNameMatch, sourceType.FullName, name)); bindingResult.Id = nameof(ErrorStrings.NoMemberNameMatch); return(bindingResult); } bindingResult.Reason = new ArgumentException( string.Format( CultureInfo.CurrentCulture, ErrorStrings.NoMemberArgumentMatch, sourceType.FullName, name)); bindingResult.Id = nameof(ErrorStrings.NoMemberArgumentMatch); return(bindingResult); }
/// <summary> /// Creates a Linq expression for a <see cref="CommandAst" /> representing /// a custom command. /// </summary> /// <param name="commandAst">The AST to convert.</param> /// <param name="targetAst">The AST containing the target of the keyword.</param> /// <param name="bodyAst">The AST containing the body of the keyword.</param> /// <param name="visitor">The <see cref="CompileVisitor" /> requesting the expression.</param> /// <returns>An expression representing the command.</returns> protected abstract Expression ProcessObjectAndBody( CommandAst commandAst, CommandElementAst targetAst, ScriptBlockExpressionAst bodyAst, CompileVisitor visitor);
internal bool IsDelegateMatch(Type parameterType, MethodArgument argument, CompileVisitor visitor) { ScriptBlockAst sbAst; if (argument.Ast is ScriptBlockExpressionAst sbExpression) { sbAst = (ScriptBlockAst)sbExpression.ScriptBlock.Visit( new DelegateSyntaxVisitor(visitor.Errors)); } else { sbAst = (ScriptBlockAst)((ScriptBlockAst)argument.Ast).Visit( new DelegateSyntaxVisitor(visitor.Errors)); } argument.Ast = sbAst; var parameterMethod = parameterType.GetMethod(Strings.DelegateInvokeMethodName); if (parameterMethod == null && typeof(Expression).IsAssignableFrom(parameterType)) { parameterMethod = parameterType .GetGenericArguments()[0] .GetMethod(Strings.DelegateInvokeMethodName); } var astHasExplicitReturn = ExplicitReturnVisitor.TryFindExplicitReturn( sbAst, out PipelineBaseAst returnValue); if (astHasExplicitReturn) { if (parameterMethod.ReturnType == typeof(void) && returnValue != null) { return(false); } } var parameterParameters = parameterMethod.GetParameters(); ParameterAst[] sbParameters; if (sbAst.ParamBlock != null) { sbParameters = new ParameterAst[sbAst.ParamBlock.Parameters.Count]; for (var i = 0; i < sbParameters.Length; i++) { sbParameters[i] = sbAst.ParamBlock.Parameters[i]; } } else { sbParameters = s_emptyParameterAsts; } if (parameterParameters.Length != sbParameters.Length) { return(false); } var expectedParameterTypes = new Type[parameterParameters.Length]; for (var i = 0; i < parameterParameters.Length; i++) { if (parameterParameters[i].ParameterType.IsGenericParameter) { if (_map.TryGetValue(parameterParameters[i].ParameterType, out Type resolvedType)) { expectedParameterTypes[i] = resolvedType; continue; } // TODO: Check if parameter is strongly typed in the AST and use that to // resolve the targ. return(false); } expectedParameterTypes[i] = parameterParameters[i].ParameterType; } var expectedReturnType = parameterMethod.ReturnType.IsGenericParameter ? null : parameterMethod.ReturnType; if (expectedReturnType == null) { _map.TryGetValue(parameterMethod.ReturnType, out expectedReturnType); } var oldErrorWriter = visitor.Errors; try { visitor.Errors = ParseErrorWriter.CreateNull(); argument.Expression = visitor.CompileAstImpl( sbAst, s_emptyVariables, expectedParameterTypes, expectedReturnType, null); } catch (Exception) { // TODO: Better reporting here if all method resolution fails. return(false); } finally { visitor.Errors = oldErrorWriter; } if (parameterMethod.ReturnType.IsGenericParameter && !_map.ContainsKey(parameterMethod.ReturnType)) { _map.Add(parameterMethod.ReturnType, ((LambdaExpression)argument.Expression).ReturnType); } if (parameterType.IsGenericType) { var genericParameters = parameterType.GetGenericArguments(); var newGenericParameters = new Type[genericParameters.Length]; for (var i = 0; i < genericParameters.Length; i++) { if (genericParameters[i].IsGenericParameter) { _map.TryGetValue(genericParameters[i], out Type resolvedType); newGenericParameters[i] = resolvedType; continue; } newGenericParameters[i] = genericParameters[i]; } parameterType = parameterType .GetGenericTypeDefinition() .MakeGenericType(newGenericParameters); } argument.Expression = Expression.Lambda( parameterType, ((LambdaExpression)argument.Expression).Body, ((LambdaExpression)argument.Expression).Parameters); return(true); }