/// <summary> /// Call the constructor of the class, if exists. /// </summary> /// <param name="arguments">the argument values</param> internal void CreateNewInstanceCallConstructors(Collection <object> arguments) { if (arguments == null) { arguments = new Collection <object>(); } var constructor = FindCorrespondingConstructor(arguments.Count); if (constructor == null) { if (Constructors.Count > 0) { ChangeState(this, new AlgorithmInterpreterStateEventArgs(new Error(new MethodNotFoundException("ctor", $"There is no constructor with {arguments.Count} argument(s) in the class '{ClassDeclaration.Name}'.")), GetDebugInfo())); } } else { if (DebugMode) { Log(this, $"Calling a constructor of '{ClassDeclaration.Name}'"); } constructor = new MethodInterpreter(constructor.MethodDeclaration, DebugMode); constructor.StateChanged += ChangeState; constructor.OnGetParentInterpreter += new Func <ClassInterpreter>(() => this); constructor.OnDone += new Action <MethodInterpreter>((met) => { met.Dispose(); met.StateChanged -= ChangeState; }); constructor.Initialize(); constructor.Run(false, arguments, Guid.Empty); } }
/// <summary> /// Initialize a new instance of <see cref="BlockInterpreter"/> /// </summary> /// <param name="statements">the list of statements to interpret</param> /// <param name="debugMode">defines is the debug mode is enabled or not</param> /// <param name="parentProgramInterpreter">the parent program interpreter</param> /// <param name="parentMethodInterpreter">the parent method interpreter</param> /// <param name="parentBlockInterpreter">the parent block interpreter</param> /// <param name="parentClassInterpreter">the parent class interpreter</param> internal BlockInterpreter(AlgorithmStatementCollection statements, bool debugMode, ProgramInterpreter parentProgramInterpreter, MethodInterpreter parentMethodInterpreter, BlockInterpreter parentBlockInterpreter, ClassInterpreter parentClassInterpreter) : base(debugMode) { ParentProgramInterpreter = parentProgramInterpreter; ParentMethodInterpreter = parentMethodInterpreter; ParentBlockInterpreter = parentBlockInterpreter; ParentClassInterpreter = parentClassInterpreter; Statements = statements; }
/// <summary> /// Invoke the specified method /// </summary> /// <param name="callerInterpreter">The caller interpreter (usually a block)</param> /// <param name="invokeExpression">The invoke expression</param> /// <param name="argumentValues">The list of argument values</param> /// <param name="parentMethodInterpreter">The parent method interpret from where the invocation happened</param> /// <param name="callStackService">The user call stack service</param> /// <returns>Returns the result of the method</returns> internal object InvokeMethod(Interpret callerInterpreter, AlgorithmExpression invokeExpression, Collection <object> argumentValues, MethodInterpreter parentMethodInterpreter, CallStackService callStackService) { var methodName = invokeExpression._methodName.ToString(); var method = Methods.FirstOrDefault(m => m.MethodDeclaration._name.ToString() == methodName); if (method == null) { callerInterpreter.ChangeState(this, new AlgorithmInterpreterStateEventArgs(new Error(new MethodNotFoundException(methodName, $"The method '{methodName}' does not exists in the current class or is not accessible."), ClassDeclaration), callerInterpreter.GetDebugInfo())); return(null); } if (!method.MethodDeclaration._isAsync && invokeExpression._await) { callerInterpreter.ChangeState(this, new AlgorithmInterpreterStateEventArgs(new Error(new MethodNotAwaitableException(methodName), method.MethodDeclaration), callerInterpreter.GetDebugInfo())); return(null); } Guid stackTraceId; var isAsync = method.MethodDeclaration._isAsync; if (parentMethodInterpreter == null) { stackTraceId = Guid.Empty; } else { stackTraceId = parentMethodInterpreter.StacktraceId; if (DebugMode) { var callStack = callStackService.CallStacks.Single(cs => cs.TaceId == stackTraceId); var call = callStack.Stack.Pop(); if (call != null) { call.Variables = callerInterpreter.GetAllAccessibleVariable().DeepClone(); callStack.Stack.Push(call); } } } method = new MethodInterpreter(method.MethodDeclaration, DebugMode); method.StateChanged += ChangeState; method.OnGetParentInterpreter += new Func <ClassInterpreter>(() => this); method.OnDone += new Action <MethodInterpreter>((met) => { met.Dispose(); met.StateChanged -= ChangeState; }); method.Initialize(); method.Run(invokeExpression._await, argumentValues, stackTraceId); if (isAsync && !invokeExpression._await) { return(null); } return(method.ReturnedValue); }
/// <summary> /// Find the constructor which correspond to the given argument count /// </summary> /// <param name="argumentCount">The number of argument to search</param> /// <returns>Returns null if the constructor has not be found</returns> private MethodInterpreter FindCorrespondingConstructor(int argumentCount) { MethodInterpreter constructor = null; var i = 0; while (i < Constructors.Count && constructor == null) { if (Constructors[i].MethodDeclaration._arguments.Count == argumentCount) { constructor = Constructors[i]; } i++; } return(constructor); }
/// <summary> /// Initialize, after the constructor, the other properties /// </summary> internal override void Initialize() { AlgorithmClassMember member; var i = 0; IsInstance = true; Variables = new Collection <Variable>(); Constructors = new Collection <MethodInterpreter>(); Methods = new Collection <MethodInterpreter>(); while (i < ClassDeclaration.Members.Count && !FailedOrStop) { member = ClassDeclaration.Members[i]; switch (member.DomType) { case AlgorithmDomType.ClassPropertyDeclaration: AddVariable((IAlgorithmVariable)member); break; case AlgorithmDomType.ClassConstructorDeclaration: if (Constructors.Any(c => c.MethodDeclaration._arguments.Count == member._arguments.Count)) { ChangeState(this, new AlgorithmInterpreterStateEventArgs(new Error(new IdenticalConstructorsException(ClassDeclaration.Name.ToString(), "A class should not have multiple constructors with the same number of arguments.")), GetDebugInfo())); } else { Constructors.Add(new MethodInterpreter(member, DebugMode)); } break; case AlgorithmDomType.EntryPointMethod: EntryPoint = new MethodInterpreter(member, DebugMode); break; case AlgorithmDomType.ClassMethodDeclaration: Methods.Add(new MethodInterpreter(member, DebugMode)); break; } i++; } }
/// <summary> /// Dispose the resources /// </summary> public override void Dispose() { Task.Run(() => { OnDone(this); ClassDeclaration = null; if (Variables != null) { foreach (var variable in Variables) { var value = variable.Value as IDisposable; if (value != null) { value.Dispose(); } } Variables.Clear(); } Variables = null; if (Constructors != null) { Constructors.Clear(); } Constructors = null; if (Methods != null) { Methods.Clear(); } Methods = null; EntryPoint = null; }); }