internal static async Task <string> CompileAndRunTheExpression(MonoProxy proxy, MessageId msg_id, int scope_id, string expression, CancellationToken token) { FindVariableNMethodCall findVarNMethodCall = new FindVariableNMethodCall(); string retString; SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@" using System; public class CompileAndRunTheExpression { public string Evaluate() { return (" + expression + @").ToString(); } }" ); FindThisExpression findThisExpression = new FindThisExpression(syntaxTree); var expressionTree = GetExpressionFromSyntaxTree(syntaxTree); findThisExpression.Visit(expressionTree); await findThisExpression.CheckIfIsProperty(proxy, msg_id, scope_id, token); syntaxTree = findThisExpression.syntaxTree; expressionTree = GetExpressionFromSyntaxTree(syntaxTree); findVarNMethodCall.Visit(expressionTree); syntaxTree = await findVarNMethodCall.ReplaceVars(syntaxTree, proxy, msg_id, scope_id, token); MetadataReference[] references = new MetadataReference[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location) }; CSharpCompilation compilation = CSharpCompilation.Create( "compileAndRunTheExpression", syntaxTrees: new [] { syntaxTree }, references: references, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); using (var ms = new MemoryStream()) { EmitResult result = compilation.Emit(ms); ms.Seek(0, SeekOrigin.Begin); Assembly assembly = Assembly.Load(ms.ToArray()); Type type = assembly.GetType("CompileAndRunTheExpression"); object obj = Activator.CreateInstance(type); var ret = type.InvokeMember("Evaluate", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, findVarNMethodCall.values.ToArray()); retString = ret.ToString(); } return(retString); }
internal static async Task <JObject> CompileAndRunTheExpression(string expression, MemberReferenceResolver resolver, CancellationToken token) { expression = expression.Trim(); if (!expression.StartsWith('(')) { expression = "(" + expression + ")"; } SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@" using System; public class CompileAndRunTheExpression { public static object Evaluate() { return " + expression + @"; } }", cancellationToken: token); SyntaxNode expressionTree = GetExpressionFromSyntaxTree(syntaxTree); if (expressionTree == null) { throw new Exception($"BUG: Unable to evaluate {expression}, could not get expression from the syntax tree"); } FindVariableNMethodCall findVarNMethodCall = new FindVariableNMethodCall(); findVarNMethodCall.VisitInternal(expressionTree); // this fails with `"a)"` // because the code becomes: return (a)); // and the returned expression from GetExpressionFromSyntaxTree is `a`! if (expressionTree.Kind() == SyntaxKind.IdentifierName || expressionTree.Kind() == SyntaxKind.ThisExpression) { string varName = expressionTree.ToString(); JObject value = await resolver.Resolve(varName, token); if (value == null) { throw new ReturnAsErrorException($"Cannot find member named '{varName}'.", "ReferenceError"); } return(value); } IList <JObject> memberAccessValues = await ResolveMemberAccessExpressions(findVarNMethodCall.memberAccesses, resolver, token); // eg. "this.dateTime", " dateTime.TimeOfDay" if (expressionTree.Kind() == SyntaxKind.SimpleMemberAccessExpression && findVarNMethodCall.memberAccesses.Count == 1) { return(memberAccessValues[0]); } IList <JObject> identifierValues = await ResolveIdentifiers(findVarNMethodCall.identifiers, resolver, token); syntaxTree = findVarNMethodCall.ReplaceVars(syntaxTree, memberAccessValues, identifierValues, null); if (findVarNMethodCall.hasMethodCalls) { expressionTree = GetExpressionFromSyntaxTree(syntaxTree); findVarNMethodCall.VisitInternal(expressionTree); IList <JObject> methodValues = await ResolveMethodCalls(findVarNMethodCall.methodCall, findVarNMethodCall.memberAccessValues, resolver, token); syntaxTree = findVarNMethodCall.ReplaceVars(syntaxTree, null, null, methodValues); } expressionTree = GetExpressionFromSyntaxTree(syntaxTree); if (expressionTree == null) { throw new Exception($"BUG: Unable to evaluate {expression}, could not get expression from the syntax tree"); } MetadataReference[] references = new MetadataReference[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location) }; CSharpCompilation compilation = CSharpCompilation.Create( "compileAndRunTheExpression", syntaxTrees: new[] { syntaxTree }, references: references, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); SemanticModel semanticModel = compilation.GetSemanticModel(syntaxTree); CodeAnalysis.TypeInfo TypeInfo = semanticModel.GetTypeInfo(expressionTree, cancellationToken: token); using (var ms = new MemoryStream()) { EmitResult result = compilation.Emit(ms, cancellationToken: token); if (!result.Success) { var sb = new StringBuilder(); foreach (Diagnostic d in result.Diagnostics) { sb.Append(d.ToString()); } throw new ReturnAsErrorException(sb.ToString(), "CompilationError"); } ms.Seek(0, SeekOrigin.Begin); Assembly assembly = Assembly.Load(ms.ToArray()); Type type = assembly.GetType("CompileAndRunTheExpression"); object ret = type.InvokeMember("Evaluate", BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public, null, null, findVarNMethodCall.argValues.ToArray()); return(JObject.FromObject(ConvertCSharpToJSType(ret, TypeInfo.Type))); } }
internal static async Task <JObject> CompileAndRunTheExpression(string expression, MemberReferenceResolver resolver, CancellationToken token) { expression = expression.Trim(); if (!expression.StartsWith('(')) { expression = "(" + expression + "\n)"; } SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(expression + @";", cancellationToken: token); SyntaxNode expressionTree = syntaxTree.GetCompilationUnitRoot(token); if (expressionTree == null) { throw new Exception($"BUG: Unable to evaluate {expression}, could not get expression from the syntax tree"); } FindVariableNMethodCall findVarNMethodCall = new FindVariableNMethodCall(); findVarNMethodCall.VisitInternal(expressionTree); // this fails with `"a)"` // because the code becomes: return (a)); // and the returned expression from GetExpressionFromSyntaxTree is `a`! if (expressionTree.Kind() == SyntaxKind.IdentifierName || expressionTree.Kind() == SyntaxKind.ThisExpression) { string varName = expressionTree.ToString(); JObject value = await resolver.Resolve(varName, token); if (value == null) { throw new ReturnAsErrorException($"Cannot find member named '{varName}'.", "ReferenceError"); } return(value); } IList <JObject> memberAccessValues = await ResolveMemberAccessExpressions(findVarNMethodCall.memberAccesses, resolver, token); // eg. "this.dateTime", " dateTime.TimeOfDay" if (expressionTree.Kind() == SyntaxKind.SimpleMemberAccessExpression && findVarNMethodCall.memberAccesses.Count == 1) { return(memberAccessValues[0]); } IList <JObject> identifierValues = await ResolveIdentifiers(findVarNMethodCall.identifiers, resolver, token); syntaxTree = findVarNMethodCall.ReplaceVars(syntaxTree, memberAccessValues, identifierValues, null, null); if (findVarNMethodCall.hasMethodCalls) { expressionTree = syntaxTree.GetCompilationUnitRoot(token); findVarNMethodCall.VisitInternal(expressionTree); IList <JObject> methodValues = await ResolveMethodCalls(findVarNMethodCall.methodCall, findVarNMethodCall.memberAccessValues, resolver, token); syntaxTree = findVarNMethodCall.ReplaceVars(syntaxTree, null, null, methodValues, null); } // eg. "elements[0]" if (findVarNMethodCall.hasElementAccesses) { expressionTree = syntaxTree.GetCompilationUnitRoot(token); findVarNMethodCall.VisitInternal(expressionTree); IList <JObject> elementAccessValues = await ResolveElementAccess(findVarNMethodCall.elementAccess, findVarNMethodCall.memberAccessValues, resolver, token); syntaxTree = findVarNMethodCall.ReplaceVars(syntaxTree, null, null, null, elementAccessValues); } expressionTree = syntaxTree.GetCompilationUnitRoot(token); if (expressionTree == null) { throw new Exception($"BUG: Unable to evaluate {expression}, could not get expression from the syntax tree"); } try { var newScript = script.ContinueWith( string.Join("\n", findVarNMethodCall.variableDefinitions) + "\nreturn " + syntaxTree.ToString()); var state = await newScript.RunAsync(cancellationToken : token); return(JObject.FromObject(ConvertCSharpToJSType(state.ReturnValue, state.ReturnValue?.GetType()))); } catch (CompilationErrorException cee) { throw new ReturnAsErrorException($"Cannot evaluate '{expression}': {cee.Message}", "CompilationError"); } catch (Exception ex) { throw new Exception($"Internal Error: Unable to run {expression}, error: {ex.Message}.", ex); } }