コード例 #1
0
        async Task <bool> OnEvaluateOnCallFrame(MessageId msg_id, int scope_id, string expression, CancellationToken token)
        {
            try
            {
                var context = GetContext(msg_id);
                if (context.CallStack == null)
                {
                    return(false);
                }

                var resolver = new MemberReferenceResolver(this, context, msg_id, scope_id, logger);

                JObject retValue = await resolver.Resolve(expression, token);

                if (retValue == null)
                {
                    retValue = await EvaluateExpression.CompileAndRunTheExpression(expression, resolver, token);
                }

                if (retValue != null)
                {
                    SendResponse(msg_id, Result.OkFromObject(new
                    {
                        result = retValue
                    }), token);
                }
                else
                {
                    SendResponse(msg_id, Result.Err($"Unable to evaluate '{expression}'"), token);
                }
            }
            catch (ReturnAsErrorException ree)
            {
                SendResponse(msg_id, ree.Error, token);
            }
            catch (Exception e)
            {
                logger.LogDebug($"Error in EvaluateOnCallFrame for expression '{expression}' with '{e}.");
                SendResponse(msg_id, Result.Exception(e), token);
            }

            return(true);
        }
コード例 #2
0
        private static async Task <IList <JObject> > ResolveMemberAccessExpressions(IEnumerable <MemberAccessExpressionSyntax> member_accesses,
                                                                                    MemberReferenceResolver resolver, CancellationToken token)
        {
            var memberAccessValues = new List <JObject>();

            foreach (MemberAccessExpressionSyntax maes in member_accesses)
            {
                string  memberAccessString = maes.ToString();
                JObject value = await resolver.Resolve(memberAccessString, token);

                if (value == null)
                {
                    throw new ReturnAsErrorException($"Failed to resolve member access for {memberAccessString}", "ReferenceError");
                }

                memberAccessValues.Add(value);
            }

            return(memberAccessValues);
        }
コード例 #3
0
        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)));
            }
        }
コード例 #4
0
        private static async Task <IList <JObject> > ResolveMethodCalls(IEnumerable <InvocationExpressionSyntax> methodCalls, Dictionary <string, JObject> memberAccessValues, MemberReferenceResolver resolver, CancellationToken token)
        {
            var values = new List <JObject>();

            foreach (InvocationExpressionSyntax methodCall in methodCalls)
            {
                JObject value = await resolver.Resolve(methodCall, memberAccessValues, token);

                if (value == null)
                {
                    throw new ReturnAsErrorException($"Failed to resolve member access for {methodCall}", "ReferenceError");
                }

                values.Add(value);
            }
            return(values);
        }
コード例 #5
0
        private static async Task <IList <JObject> > ResolveIdentifiers(IEnumerable <IdentifierNameSyntax> identifiers, MemberReferenceResolver resolver, CancellationToken token)
        {
            var values = new List <JObject>();

            foreach (IdentifierNameSyntax var in identifiers)
            {
                JObject value = await resolver.Resolve(var.Identifier.Text, token);

                if (value == null)
                {
                    throw new ReturnAsErrorException($"The name {var.Identifier.Text} does not exist in the current context", "ReferenceError");
                }

                values.Add(value);
            }

            return(values);
        }
コード例 #6
0
        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);
            }
        }
コード例 #7
0
        private static async Task <IList <JObject> > ResolveElementAccess(IEnumerable <ElementAccessExpressionSyntax> elementAccesses, Dictionary <string, JObject> memberAccessValues, MemberReferenceResolver resolver, CancellationToken token)
        {
            var     values = new List <JObject>();
            JObject index  = null;

            foreach (ElementAccessExpressionSyntax elementAccess in elementAccesses.Reverse())
            {
                index = await resolver.Resolve(elementAccess, memberAccessValues, index, token);

                if (index == null)
                {
                    throw new ReturnAsErrorException($"Failed to resolve element access for {elementAccess}", "ReferenceError");
                }
            }
            values.Add(index);
            return(values);
        }