public override object VisitTypeDotExpression([NotNull] DoshikParser.TypeDotExpressionContext context)
        {
            SetWholeExpression(context);
            VisitChildren(context);
            _compilationContext.SetParsingAntlrContext(context);

            var node = new TypeDotExpressionNode(context);

            var foundType = GetTypeNameVisitor.Apply(_compilationContext, context.left);

            foundType.ThrowIfNotFound(_compilationContext);

            node.LeftType = foundType.DataType;

            if (context.rightIdentifier != null)
            {
                node.RightIdentifier = context.rightIdentifier.Text;
            }
            else
            {
                node.RightMethodCallData = new MethodCallExpressionNodeData();
                GetMethodCallData(context.rightMethodCall, node.RightMethodCallData);
            }

            Sequence.Sequence.Add(node);

            return(null);
        }
        // возвращает MethodDeclarationParameter
        public override object VisitFormalParameter([NotNull] DoshikParser.FormalParameterContext context)
        {
            _compilationContext.SetParsingAntlrContext(context);

            var parameter = new MethodDeclarationParameter(_currentMethodDeclaration.Parameters);

            var scope = parameter.Parent.Scope;

            parameter.IsOutput = context.OUT() != null;

            var foundType = GetTypeNameVisitor.Apply(_compilationContext, context.typeType());

            foundType.ThrowIfNotFound(_compilationContext);

            var variable = new Variable(parameter)
            {
                Type = foundType.DataType,
                Name = context.parameterName.Text
            };

            if (scope.FindVariableByName(variable.Name, true) != null)
            {
                throw _compilationContext.ThrowCompilationError($"parameter { variable.Name } is already defined");
            }

            scope.Variables[variable.Name] = variable;

            parameter.Variable = variable;

            return(parameter);
        }
        private IEnumerable <DataType> GetTypeArguments(DoshikParser.TypeArgumentsContext typeArgumentsCtx)
        {
            if (typeArgumentsCtx == null)
            {
                yield break;
            }

            foreach (var typeArgumentCtx in typeArgumentsCtx.typeArgument())
            {
                var foundType = GetTypeNameVisitor.Apply(_compilationContext, typeArgumentCtx.typeType());
                foundType.ThrowIfNotFound(_compilationContext);
                yield return(foundType.DataType);
            }
        }
        public override object VisitTypeOfExpression([NotNull] DoshikParser.TypeOfExpressionContext context)
        {
            SetWholeExpression(context);
            VisitChildren(context);
            _compilationContext.SetParsingAntlrContext(context);

            var node = new TypeOfExpressionNode(context);

            var foundType = GetTypeNameVisitor.Apply(_compilationContext, context.typeOf().typeType());

            foundType.ThrowIfNotFound(_compilationContext);
            node.Type = foundType.DataType;

            Sequence.Sequence.Add(node);

            return(null);
        }
        // возвращает LocalVariableDeclarationStatement
        public override object VisitLocalVariableDeclaration([NotNull] DoshikParser.LocalVariableDeclarationContext context)
        {
            _compilationContext.SetParsingAntlrContext(context);

            var statement = new LocalVariableDeclarationStatement(_currentNode);

            statement.Variable = new Variable(statement);

            var foundType = GetTypeNameVisitor.Apply(_compilationContext, context.typeType());

            foundType.ThrowIfNotFound(_compilationContext);
            statement.Variable.Type = foundType.DataType;

            _declaringVariable = statement.Variable;

            _currentExpressionParent = statement;

            // Он инициализирует _declaringVariable
            Visit(context.variableDeclarator());

            // Добавляем переменную ПОСЛЕ выполнения инициализации, таким образом при выполнении выражения инициализации эта переменная еще будет недоступна для референеса
            // то есть нельзя будет сделать так int a = a + 1;
            // этим отличается инициализация переменной от обычного присваивания, где референсить присваемую переменную можно
            _currentScope.Variables.Add(statement.Variable.Name, statement.Variable);

            statement.Initializer = _declaringVariableInitializerExpression;

            if (statement.Initializer == null && IsInsideOfLoop())
            {
                // Если инициализатор не задан (то есть переменная объявлена без инициализирующего выражения)
                // и при этом мы находимся в теле цикла
                // то создаем неявное инициализирующее выражение = default(T), где T = statement.Variable.Type
                statement.Initializer = ExpressionBuilder.BuildDefaultOfType(_compilationContext, _currentExpressionParent, statement.Variable.Type);

                // это нужно, чтобы при объявлении локальной переменной в теле цикла при любой итерации цикла она имела дефолтное значение, если
                // ей не был указан инициализатор, иначе получится что ее значение будет переиспользоватья с предыдущей итерации

                // впринципе можно в любом случае делать этот искусственный инициализатор (даже если не в цикле), но вроде как если переменная
                // не находится в цикле то ее значение всегда будет дефолтным, если не было инициализатора
                // возможно это изменится при реализации рекурсивных юзерских функций
            }

            return(statement);
        }
        private void HandleEventDeclaration(
            DoshikParser.TypeTypeOrVoidContext eventReturnTypeCtx,
            string eventCodeName,
            DoshikParser.FormalParametersContext eventParametersCtx,
            DoshikParser.BlockContext eventBodyCtx
            )
        {
            var eventDeclaration = new EventDeclaration(_compilationContext.CompilationUnit);

            eventDeclaration.Parameters = new MethodDeclarationParameters(eventDeclaration, _compilationContext.CompilationUnit.Scope);

            _currentMethodDeclaration = eventDeclaration;

            eventDeclaration.Name = eventCodeName;

            var foundType = GetTypeNameVisitor.Apply(_compilationContext, eventReturnTypeCtx);

            foundType.ThrowIfNotFound(_compilationContext);
            eventDeclaration.ReturnTypeOrVoid = foundType.DataType;

            eventDeclaration.ExternalEvent = _compilationContext.FindExternalApiEventByCodeName(eventDeclaration.Name);

            if (_compilationContext.CompilationUnit.Events.ContainsKey(eventDeclaration.Name))
            {
                throw _compilationContext.ThrowCompilationError($"event handler { eventDeclaration.Name } is already defined");
            }

            eventDeclaration.Parameters.Parameters.AddRange((List <MethodDeclarationParameter>)Visit(eventParametersCtx));

            eventDeclaration.AntlrBody = eventBodyCtx;

            if (eventDeclaration.IsCustom)
            {
                ValidateCustomEvent(eventDeclaration);
            }
            else
            {
                ValidateBuiltInEvent(eventDeclaration);
            }

            _compilationContext.CompilationUnit.Events[eventDeclaration.Name] = eventDeclaration;
        }
        public override object VisitNewCallExpression([NotNull] DoshikParser.NewCallExpressionContext context)
        {
            SetWholeExpression(context);
            VisitChildren(context);
            _compilationContext.SetParsingAntlrContext(context);

            var node = new NewCallExpressionNode(context);

            var newCallCtx = context.newCall();

            var foundType = GetTypeNameVisitor.Apply(_compilationContext, newCallCtx.typeType());

            foundType.ThrowIfNotFound(_compilationContext);
            node.Type = foundType.DataType;

            node.Parameters.AddRange(GetMethodCallParameters(newCallCtx.methodCallParams()));

            Sequence.Sequence.Add(node);

            return(null);
        }
        public override object VisitFieldDeclaration([NotNull] DoshikParser.FieldDeclarationContext context)
        {
            _compilationContext.SetParsingAntlrContext(context);

            var scope = _compilationContext.CompilationUnit.Scope;

            var variable = new CompilationUnitVariable(_compilationContext.CompilationUnit);

            variable.IsPublic = context.PUBLIC() != null;

            var foundType = GetTypeNameVisitor.Apply(_compilationContext, context.typeType());

            foundType.ThrowIfNotFound(_compilationContext);
            variable.Type = foundType.DataType;

            (var variableName, var variableInitializer) = ((string, DoshikParser.VariableInitializerContext))Visit(context.variableDeclarator());

            variable.Name = variableName;

            if (variableInitializer != null)
            {
                // ToDo: потом можно сделать инициализаторы полей. Прикол тут в том что их нельзя инициализировать также
                // как локальные переменные в statement-ах, потому что тут нет порядка выполнения операций, а значит
                // в инициализирующем выражении первой переменной может быть зареференшена вторвая переменная а в инициализации второй переменной референс на первую
                // таким образом будет circular reference. И такие вещи нужно определять, для этого нужно сортировать эти определения переменных и инициализировать их
                // в порядке начиная от меньшего количества референсов на другие переменные в инициализаторе до больших + трекать как то circular референсы.
                // Из-за того что тут такой гимор, я решил пока не делать инициализаторы (инициализировать переменные все равно можно будет вручную на событии Start или как там его)
                throw _compilationContext.ThrowCompilationError($"field initializer is not supported yet");
            }

            if (scope.FindVariableByName(variable.Name, true) != null)
            {
                throw _compilationContext.ThrowCompilationError($"variable { variable.Name } is already defined");
            }

            scope.Variables[variable.Name] = variable;

            return(null);
        }