Exemple #1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MethodInterpreter"/> class.
 /// </summary>
 /// <param name="baZicInterpreter">The main interpreter.</param>
 /// <param name="parentInterpreter">The parent interpreter.</param>
 /// <param name="methodDeclaration">The declaration of the method to interpret.</param>
 /// <param name="invokeMethod">The expression that performs the invocation.</param>
 /// <param name="executionFlowId">A GUID that defines in which callstack is linked.</param>
 internal MethodInterpreter(BaZicInterpreterCore baZicInterpreter, Interpreter parentInterpreter, MethodDeclaration methodDeclaration, InvokeMethodExpression invokeMethod, Guid executionFlowId)
     : base(baZicInterpreter, parentInterpreter, executionFlowId)
 {
     Requires.NotNull(methodDeclaration, nameof(methodDeclaration));
     Requires.NotNull(invokeMethod, nameof(invokeMethod));
     _methodDeclaration = methodDeclaration;
     _invokeMethod      = invokeMethod;
 }
Exemple #2
0
        /// <summary>
        /// Add a method invocation expression to the list of method invocation in the program to analyze it later when all the declared method have been discovered.
        /// </summary>
        /// <param name="invokeMethod">The method invocation to add.</param>
        private void AddMethodInvocation(InvokeMethodExpression invokeMethod)
        {
            foreach (var argument in invokeMethod.Arguments)
            {
                AnalyzeExpression(argument);
            }

            _methodInvocations.Add(invokeMethod);
        }
Exemple #3
0
        /// <summary>
        /// Invoke a public method accessible from outside of the interpreter (EXTERN FUNCTION).
        /// </summary>
        /// <param name="executionFlowId">A GUID that defines in which callstack is linked.</param>
        /// <param name="methodName">The name of the method.</param>
        /// <param name="awaitIfAsync">Await if the method is maked as asynchronous.</param>
        /// <param name="args">The arguments to pass to the method.</param>
        /// <returns>Returns the result of the invocation (a <see cref="Task"/> in the case of a not awaited asynchronous method, or the value returned by the method).</returns>
        internal object InvokeMethod(Guid executionFlowId, string methodName, bool awaitIfAsync, Code.AbstractSyntaxTree.Expression[] args)
        {
            InitializeGlobalState();

            BaZicInterpreter.CheckState(BaZicInterpreterState.Idle, BaZicInterpreterState.Stopped, BaZicInterpreterState.StoppedWithError);

            var invokeExpression = new InvokeMethodExpression(methodName, awaitIfAsync).WithParameters(args);

            BaZicInterpreter.ChangeState(this, new BaZicInterpreterStateChangeEventArgs(BaZicInterpreterState.Running));

            return(new InvokeMethodInterpreter(BaZicInterpreter, this, invokeExpression, executionFlowId, true).Run());
        }
Exemple #4
0
        /// <summary>
        /// Generates the code for an <see cref="InvokeMethodExpression"/>.
        /// </summary>
        /// <param name="expression">The expression</param>
        /// <returns>A BaZic code</returns>
        private string GenerateInvokeMethodExpression(InvokeMethodExpression expression)
        {
            Requires.NotNull(expression.MethodName, nameof(expression.MethodName));

            var wait      = string.Empty;
            var arguments = new List <string>();

            foreach (var argument in expression.Arguments)
            {
                arguments.Add(GenerateExpression(argument));
            }

            if (expression.Await)
            {
                wait = "AWAIT ";
            }

            return($"{wait}{expression.MethodName}({string.Join(", ", arguments)})");
        }
Exemple #5
0
        /// <summary>
        /// Analyze a method invocation.
        /// </summary>
        /// <param name="invokeMethod">The expression to analyze.</param>
        private void ValidateMethodInvocation(InvokeMethodExpression invokeMethod)
        {
            var methodDeclaration = _declaredMethods.LastOrDefault(method => string.Compare(method.Name.Identifier, invokeMethod.MethodName.Identifier, StringComparison.Ordinal) == 0); // The name is case sensitive.

            if (methodDeclaration == null)
            {
                AddIssue(invokeMethod, BaZicParserExceptionLevel.Error, L.BaZic.Optimizer.FormattedUndeclaredName(invokeMethod.MethodName));
            }
            else
            {
                if (invokeMethod.Await)
                {
                    if (!methodDeclaration.IsAsync)
                    {
                        AddIssue(invokeMethod, BaZicParserExceptionLevel.Error, L.BaZic.Parser.CannotAwait);
                    }
                }

                if (methodDeclaration.Arguments.Count != invokeMethod.Arguments.Count)
                {
                    AddIssue(invokeMethod, BaZicParserExceptionLevel.Error, L.BaZic.Optimizer.FormattedMethodNoMatchArguments(invokeMethod.MethodName, invokeMethod.Arguments.Count));
                }
            }
        }
Exemple #6
0
        /// <summary>
        /// Parse a part of an expression that can be a reference or primary value followed by an accesser like array indexer or method invocation.
        ///
        /// Corresponding grammar :
        ///     Primary_Expression_Start Bracket_Expression* ((Member_Access | Method_Invocation) Bracket_Expression* )*
        /// </summary>
        /// <param name="isRequired">Defines whether it is required/expected to parse an expression. If true, throw an exception if no expression is parsed.</param>
        /// <returns>Returns an expression.</returns>
        private Expression ParsePrimaryExpression(bool isRequired)
        {
            Expression[] bracketExpression      = null;
            var          expressionLine         = CurrentToken.Line;
            var          expressionColumn       = CurrentToken.Column;
            var          expressionStartOffset  = CurrentToken.StartOffset;
            var          expressionParsedLength = CurrentToken.ParsedLength;

            // Primary_Expression_Start
            var expression = ParsePrimaryExpressionStart(isRequired);

            // Bracket_Expression *
            do
            {
                var bracketToken = CurrentToken;
                bracketExpression = ParseBracketExpression();
                if (bracketExpression != null)
                {
                    var referenceExpression = expression as ReferenceExpression;

                    if (referenceExpression == null)
                    {
                        AddIssue(new BaZicParserException(expressionLine, expressionColumn, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.UnexpectedIndexer));
                    }

                    if (bracketExpression.Length == 0)
                    {
                        AddIssue(new BaZicParserException(bracketToken.Line, bracketToken.Column, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.IndexerExpected));
                        return(null);
                    }

                    var arrayIndexer = new ArrayIndexerExpression(referenceExpression, bracketExpression)
                    {
                        Line        = bracketToken.Line,
                        Column      = bracketToken.Column,
                        StartOffset = bracketToken.StartOffset,
                        NodeLength  = bracketToken.ParsedLength
                    };

                    ValidateArrayIndexerExpression(arrayIndexer);
                    expression = arrayIndexer;
                }
            } while (bracketExpression != null);

            // ((Member_Access | Method_Invocation) Bracket_Expression* )*
            while (CurrentToken.TokenType == TokenType.Dot || CurrentToken.TokenType == TokenType.LeftParenth)
            {
                if (CurrentToken.TokenType == TokenType.Dot)
                {
                    // Member_Access
                    var memberNameToken = CurrentToken;
                    var memberAccess    = ParseMemberAccessPart(true);

                    if (!string.IsNullOrEmpty(memberAccess))
                    {
                        var referenceExpression = expression as ReferenceExpression;

                        if (referenceExpression == null)
                        {
                            AddIssue(new BaZicParserException(expressionLine, expressionColumn, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.IllegalPropertyAccess));
                        }

                        expression = new PropertyReferenceExpression(referenceExpression, memberAccess)
                        {
                            Line        = memberNameToken.Line,
                            Column      = memberNameToken.Column + 1,      // +1 because we don't want to show a potential error on the dot.
                            StartOffset = memberNameToken.StartOffset + 1, // +1 because we don't want to show a potential error on the dot.
                            NodeLength  = memberNameToken.ParsedLength
                        };
                    }
                }
                else if (CurrentToken.TokenType == TokenType.LeftParenth)
                {
                    // Method_Invocation
                    var methodInvocationParameters  = ParseMethodInvocation();
                    var propertyReferenceExpression = expression as PropertyReferenceExpression;

                    if (expression is VariableReferenceExpression variableReferenceExpression)
                    {
                        var methodInvoke = new InvokeMethodExpression(variableReferenceExpression.Name.ToString(), false)
                        {
                            Line        = variableReferenceExpression.Line,
                            Column      = variableReferenceExpression.Column,
                            StartOffset = variableReferenceExpression.StartOffset,
                            NodeLength  = variableReferenceExpression.NodeLength
                        }
                        .WithParameters(methodInvocationParameters);

                        AddMethodInvocation(methodInvoke);
                        expression = methodInvoke;
                    }
                    else if (propertyReferenceExpression != null)
                    {
                        var methodInvoke = new InvokeCoreMethodExpression(propertyReferenceExpression.TargetObject, propertyReferenceExpression.PropertyName.ToString(), false)
                        {
                            Line        = propertyReferenceExpression.Line,
                            Column      = propertyReferenceExpression.Column,
                            StartOffset = propertyReferenceExpression.StartOffset,
                            NodeLength  = propertyReferenceExpression.NodeLength
                        };
                        methodInvoke.WithParameters(methodInvocationParameters);

                        ValidateCoreMethodInvocation(methodInvoke);
                        expression = methodInvoke;
                    }
                    else
                    {
                        AddIssue(new BaZicParserException(expressionLine, expressionColumn, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.MethodNameExpected));
                    }
                }
                else
                {
                    AddIssue(new BaZicParserException(expressionLine, expressionColumn, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.MethodNameExpected));
                }

                // Bracket_Expression*
                do
                {
                    var bracketToken = CurrentToken;
                    bracketExpression = ParseBracketExpression();
                    if (bracketExpression != null)
                    {
                        var referenceExpression = expression as ReferenceExpression;

                        if (referenceExpression == null)
                        {
                            AddIssue(new BaZicParserException(expressionLine, expressionColumn, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.UnexpectedIndexer));
                        }

                        if (bracketExpression.Length == 0)
                        {
                            AddIssue(new BaZicParserException(bracketToken.Line, bracketToken.Column, expressionStartOffset, expressionParsedLength, L.BaZic.Parser.Expressions.IndexerExpected));
                        }

                        var arrayIndexer = new ArrayIndexerExpression(referenceExpression, bracketExpression)
                        {
                            Line        = bracketToken.Line,
                            Column      = bracketToken.Column,
                            StartOffset = bracketToken.StartOffset,
                            NodeLength  = bracketToken.ParsedLength
                        };

                        ValidateArrayIndexerExpression(arrayIndexer);
                        expression = arrayIndexer;
                    }
                } while (bracketExpression != null);
            }

            return(expression);
        }
Exemple #7
0
        /// <summary>
        /// Inline, if possible a local method invocation.
        /// </summary>
        /// <param name="invokeMethod">The method invocation expression.</param>
        /// <param name="returnedValueAssignation">The expression that must receive the invocation result.</param>
        /// <returns>A set of statements that represents the inlined method.</returns>
        private List <Statement> InlineMethodInvocation(InvokeMethodExpression invokeMethod, Expression returnedValueAssignation)
        {
            var methodDeclaration = _program.Methods.SingleOrDefault(method => string.Compare(method.Name.Identifier, invokeMethod.MethodName.Identifier, StringComparison.Ordinal) == 0);

            if (methodDeclaration == null)
            {
                throw new BaZicParserException(invokeMethod.Line, invokeMethod.Column, invokeMethod.StartOffset, invokeMethod.NodeLength, L.BaZic.Optimizer.FormattedUndeclaredName(invokeMethod.MethodName));
            }
            else if (invokeMethod.Arguments.Count != methodDeclaration.Arguments.Count)
            {
                throw new BaZicParserException(invokeMethod.Line, invokeMethod.Column, invokeMethod.StartOffset, invokeMethod.NodeLength, L.BaZic.Optimizer.FormattedMethodNoMatchArguments(invokeMethod.MethodName, invokeMethod.Arguments.Count));
            }
            else if (methodDeclaration.IsAsync)
            {
                return(null);
            }
            else if (_methodInformations.Count(method => method.MethodDeclaration.Id == methodDeclaration.Id) >= Consts.RecursivityLimit)
            {
                // After a certain number of recursive call, we stop to perform a recursive call.
                return(null);
            }


            var newStatements = new List <Statement>();

            var startMethod = CreateNewLabel();
            var endMethod   = CreateNewLabel();

            var arguments = new Dictionary <Guid, VariableDeclaration>();

            for (var i = 0; i < methodDeclaration.Arguments.Count; i++)
            {
                var argument = methodDeclaration.Arguments[i];
                arguments.Add(argument.Id, new VariableDeclaration(argument.Name.Identifier, argument.IsArray).WithDefaultValue(OptimizeExpression(invokeMethod.Arguments[i])));
            }

            var methodInfo = new MethodInformation()
            {
                MethodDeclaration = methodDeclaration,
                SubstituteVariableDeclarations = arguments,
                StartLabel          = startMethod,
                EndLabel            = endMethod,
                ReturnValueRecepter = new VariableDeclaration($"RET{startMethod.Name}", false)
            };

            _methodInformations.Insert(0, methodInfo);

            foreach (var substituteArgument in methodInfo.SubstituteVariableDeclarations)
            {
                newStatements.Add(substituteArgument.Value);
            }

            newStatements.Add(methodInfo.ReturnValueRecepter);
            newStatements.Add(startMethod);
            newStatements.AddRange(OptimizeStatementBlock(methodDeclaration.Statements));
            newStatements.Add(endMethod);

            if (returnedValueAssignation != null)
            {
                newStatements.Add(new AssignStatement(OptimizeExpression(returnedValueAssignation), new VariableReferenceExpression(methodInfo.ReturnValueRecepter.Name.Identifier)
                {
                    VariableDeclarationID = methodInfo.ReturnValueRecepter.Id
                }));
            }

            _methodInformations.RemoveAt(0);

            return(newStatements);
        }
Exemple #8
0
        internal void Start(object[] args)
        {
            BaZicInterpreter.CheckState(BaZicInterpreterState.Preparing);

            InitializeGlobalState();

            var entryPoint = GetEntryPointMethod();

            if (IsAborted)
            {
                return;
            }

            if (BaZicInterpreter.Verbose)
            {
                VerboseLog(L.BaZic.Runtime.Interpreters.ProgramInterpreter.EntryPointDetected);
            }

            BaZicInterpreter.ChangeState(this, new BaZicInterpreterStateChangeEventArgs(BaZicInterpreterState.Running));

            var argsExpressions = new List <Code.AbstractSyntaxTree.Expression>();

            if (args != null)
            {
                foreach (var argument in args)
                {
                    argsExpressions.Add(new PrimitiveExpression(argument));
                }
            }

            var entryPointInvocation  = new InvokeMethodExpression(Consts.EntryPointMethodName, false).WithParameters(new ArrayCreationExpression().WithValues(argsExpressions.ToArray()));
            var entryPointInterpreter = new MethodInterpreter(BaZicInterpreter, this, entryPoint, entryPointInvocation, ExecutionFlowId);

            ProgramResult = entryPointInterpreter.Invoke();

            if (IsAborted)
            {
                return;
            }

            if (_uiProgram != null && ProgramResult == null)
            {
                Exception eventException = null;

                ThreadHelper.RunOnStaThread(() =>
                {
                    if (BaZicInterpreter.Verbose)
                    {
                        VerboseLog(L.BaZic.Runtime.Interpreters.ProgramInterpreter.LoadingUi);
                    }

                    _uiThread = Thread.CurrentThread;

                    LoadUserInterface();

                    if (UserInterface == null)
                    {
                        BaZicInterpreter.ChangeState(this, new UiException(L.BaZic.Parser.XamlUnknownParsingError));
                        return;
                    }

                    UIDispatcher = UserInterface.Dispatcher;

                    if (BaZicInterpreter.Verbose)
                    {
                        VerboseLog(L.BaZic.Runtime.Interpreters.ProgramInterpreter.DeclaringEvents);
                    }

                    foreach (var uiEvent in _uiProgram.UiEvents)
                    {
                        var targetObject = UserInterface.FindName(uiEvent.ControlName);

                        if (targetObject == null)
                        {
                            BaZicInterpreter.ChangeState(this, new UiException($"Unable to find the control named '{uiEvent.ControlName}'."));
                            return;
                        }

                        var action = new Action(() =>
                        {
                            if (BaZicInterpreter.Verbose)
                            {
                                VerboseLog(L.BaZic.Runtime.Interpreters.ProgramInterpreter.EventRaised);
                            }

                            BaZicInterpreter.ChangeState(this, new BaZicInterpreterStateChangeEventArgs(BaZicInterpreterState.Running));
                            var eventMethodDeclaration = _uiProgram.Methods.Single(m => m.Id == uiEvent.MethodId);
                            var eventInvocation        = new InvokeMethodExpression(eventMethodDeclaration.Name.Identifier, false);
                            var eventMethodInterpreter = new MethodInterpreter(BaZicInterpreter, this, eventMethodDeclaration, eventInvocation, ExecutionFlowId);

                            if (targetObject is Window && uiEvent.ControlEventName == nameof(Window.Closed))
                            {
                                ProgramResult = eventMethodInterpreter.Invoke();
                            }
                            else
                            {
                                eventMethodInterpreter.Invoke();
                            }

                            BaZicInterpreter.RunningStateManager.SetIsRunningMainFunction(false); // In all cases, at this point, the main function is done. The UI is running. Idle state must be able to be setted.
                            BaZicInterpreter.RunningStateManager.UpdateState();
                        });

                        BaZicInterpreter.Reflection.SubscribeEvent(targetObject, uiEvent.ControlEventName, action);
                    }

                    if (BaZicInterpreter.Verbose)
                    {
                        VerboseLog(L.BaZic.Runtime.Interpreters.ProgramInterpreter.DeclaringBindings);
                    }

                    foreach (var controlAccessor in _uiProgram.UiControlAccessors)
                    {
                        AddVariable(controlAccessor);
                    }

                    if (BaZicInterpreter.Verbose)
                    {
                        VerboseLog(L.BaZic.Runtime.Interpreters.ProgramInterpreter.ShowUi);
                    }

                    var window = UserInterface as Window;

                    try
                    {
                        if (window != null)
                        {
                            window.Closed += (sender, e) =>
                            {
                                if (BaZicInterpreter.Verbose)
                                {
                                    VerboseLog(L.BaZic.Runtime.Interpreters.ProgramInterpreter.CloseUi);
                                }
                                UserInterface?.Dispatcher?.InvokeShutdown();
                            };
                        }

                        BaZicInterpreter.ChangeState(this, new BaZicInterpreterStateChangeEventArgs(BaZicInterpreterState.Idle));
                        window?.Show();
                        Dispatcher.Run();
                    }
                    catch (Exception exception)
                    {
                        CoreHelper.ReportException(exception);
                        eventException = exception;
                    }
                    finally
                    {
                        try
                        {
                            window?.Close();
                        }
                        catch (Exception exception)
                        {
                            CoreHelper.ReportException(exception);
                        }
                        finally
                        {
                            RuntimeResourceManager.DeleteResources(ExecutionFlowId.ToString());

                            foreach (var variable in Variables)
                            {
                                variable.Dispose();
                            }

                            BaZicInterpreter.Reflection.UnsubscribeAllEvents();
                            UserInterface = null;
                        }
                    }
                });

                if (eventException != null)
                {
                    throw eventException;
                }
            }
        }
Exemple #9
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Call"/> class.
 /// </summary>
 /// <param name="invokeMethodExpression">The reference to the called method.</param>
 public Call(InvokeMethodExpression invokeMethodExpression)
 {
     InvokeMethodExpression = invokeMethodExpression;
     Variables = new List <Variable>();
 }