public dynamic Visit(FuncImplementation impl)
 {
     impl.CodeGenMethod = _currentMethod;
     foreach (var param in impl.Parameters)
     {
         _currentMethod.Parameter(param.Value.CodeGenType(), param.Key);
     }
     foreach (var param in impl.Parameters)
     {
         impl.Namespace.Symbols
         .SingleOrDefault(x => x.Name == param.Key)
         .CodeGenField = _codeGen.Arg(param.Key);
     }
     if (impl.ReturnExpression != null)
     {
         _codeGen.Return(Visit((dynamic)impl.ReturnExpression));
     }
     if (impl.Code != null)
     {
         foreach (var statement in impl.Code.Statements)
         {
             Visit((dynamic)statement);
         }
     }
     return(null);
 }
Esempio n. 2
0
        public dynamic Visit(FuncImplementation impl)
        {
            var node = new TreeNode($"{impl.Name} Implementation")
            {
                Tag = impl.Node
            };
            var argNode = new TreeNode("Arguments");

            argNode.Nodes.AddRange(impl.ArgumentsTypes.Select(x => new TreeNode(x.ToString())).ToArray());
            node.Nodes.Add(argNode);
            if (impl.ReturnExpression != null)
            {
                node.Nodes.Add(new TreeNode("ReturnExpr")
                {
                    Nodes = { Visit(impl.ReturnExpression) }
                });
            }
            if (impl.Code != null)
            {
                node.Nodes.Add(new TreeNode("Code")
                {
                    Nodes = { Visit(impl.Code) }
                });
            }
            node.Nodes.Add(new TreeNode("ReturnType")
            {
                Nodes = { new TreeNode(impl.ReturnType.ToString()) }
            });
            return(node);
        }
 public dynamic Visit(FuncImplementation impl)
 {
     impl.Code?.Optimize();
     //if (impl.Code != null && !(impl.Code.Statements.LastOrDefault() is ReturnStm))
     //{
     //    var retType = impl.ReturnType;
     //    impl.Code.Statements.Add(new ReturnStm
     //    {
     //        Namespace = impl.Namespace,
     //        ReturnExpression = new LiteralExpr
     //        {
     //            Namespace = impl.Namespace,
     //            Value = retType.CodeGenType() == typeof(void)? null: GetDefault(retType.CodeGenType()) ?? "",
     //            SymbolType = retType
     //        }
     //    });
     //}
     impl.ReturnExpression?.Optimize();
     return(null);
 }
 public dynamic Visit(FuncImplementation impl)
 {
     Visit(impl.Code);
     return(null);
 }
Esempio n. 5
0
        /// <summary>
        /// Rule: Variable -> IDENTIFIER ((Array | Call))? ;
        /// </summary>
        protected override object EvalVariable(ParseTree tree, params object[] paramlist)
        {
            var identNode  = GetNode(TokenType.IDENTIFIER);
            var name       = identNode.Token.Text;
            var isLeftSide = paramlist != null && paramlist.Any() && (bool)paramlist.First();

            if (GetNode(TokenType.Array) == null && GetNode(TokenType.Call) == null)
            {
                if (isLeftSide)
                {
                    return(new LeftSideExprVariable {
                        Name = name, Type = LeftSideExprType.Variable, Node = this
                    });
                }
                var existingSymbol = Namespaces.Current.Symbols.SingleOrDefault(x => x.Name == name);
                if (existingSymbol != null && existingSymbol.Type == SymbolType.Array)
                {
                    throw new ParseException($"Использование массива {name} без индексатора", identNode);
                }
                if (existingSymbol != null && existingSymbol.Type == SymbolType.Function)
                {
                    throw new ParseException($"Использование функции {name} без скобок", identNode);
                }
                if (existingSymbol != null && existingSymbol.Type != SymbolType.Unknown)
                {
                    existingSymbol.UsagesCount++;
                    return(new GetVariableExpr {
                        Type = existingSymbol.Type, Node = this, Name = name
                    });
                }

                throw new ParseException($"Использование непроинициализированной переменной {name}", identNode);
            }

            if (GetNode(TokenType.Array) != null)
            {
                var expr     = (ExpressionBase)GetNode(TokenType.Array).Eval(tree);
                var exprType = expr.GetExprType();
                if (isLeftSide)
                {
                    return(new LeftSideExprArray
                    {
                        ArrayKeyType = exprType,
                        Index = expr,
                        Node = this,
                        Type = LeftSideExprType.Array,
                        Name = name
                    });
                }
                var existingSymbol = Namespaces.Current.Symbols.SingleOrDefault(x => x.Name == name && x.Type == SymbolType.Array && x.ArrayKeyType == exprType);
                if (existingSymbol != null)
                {
                    existingSymbol.UsagesCount++;
                    return(new GetArrayExpr {
                        ValuesType = existingSymbol.ArrayValueType, Node = this, Name = name, Index = expr, KeysType = existingSymbol.ArrayKeyType
                    });
                }
                if (Namespaces.Current.Symbols.Any(x => x.Name == name && x.Type == SymbolType.Array))
                {
                    throw new ParseException("Невозможно изменить тип ключа у массива", identNode);
                }
                throw new ParseException($"Использование непроинициализированного массива {name}", identNode);
            }

            if (GetNode(TokenType.Call) != null)
            {
                var arguments       = ((Arguments)GetNode(TokenType.Call).Eval(tree));
                var funcDeclaration = AstCreator.FuncDeclarations.SingleOrDefault(x => x.Name == name && x.Arguments.Count == arguments.Values.Count);
                if (funcDeclaration == null)
                {
                    throw new ParseException($"Попытка использовать необъявленную функцию {name}", identNode);
                }

                var argumentsTypes = arguments.Values.Select(av => av.GetExprType()).ToList();
                if (AstCreator.FuncImplementation.Count > 0)
                {
                    if (AstCreator.FuncImplementation.Any(x => x.Name == name && x.ArgumentsTypes.SequenceEqual(argumentsTypes)))
                    {
                        throw new ParseException("Рекурсия не поддерживается", identNode);
                    }
                }
                var funcImplementation = AstCreator.FuncImplementations.SingleOrDefault(x => x.Name == name && x.ArgumentsTypes.SequenceEqual(argumentsTypes));
                if (funcImplementation == null)
                {
                    funcImplementation = new FuncImplementation {
                        Name = name, Node = this, ArgumentsTypes = argumentsTypes, Declaration = funcDeclaration
                    };
                    AstCreator.FuncImplementation.Push(funcImplementation);

                    var currentNamespace = Namespaces.Current;
                    Namespaces.Current = Namespaces.Root;
                    Namespaces.LevelDown(new Namespace($"{name}({string.Join(", ", argumentsTypes)})"));

                    for (var index = 0; index < arguments.Values.Count; index++)
                    {
                        var symbolType = argumentsTypes[index];
                        var symbol     = new Symbol(symbolType, funcDeclaration.Arguments[index]);
                        Namespaces.Current.AddSymbol(symbol, identNode);
                    }

                    funcDeclaration.Node.Eval(tree, true, this);
                    funcImplementation.Namespace = Namespaces.Current;
                    Namespaces.Current           = currentNamespace;
                    AstCreator.FuncImplementations.Add(AstCreator.FuncImplementation.Pop());
                }

                var callFuncExpr = new CallFuncExpr {
                    Node = this, Function = funcImplementation, Arguments = arguments
                };
                if (isLeftSide)
                {
                    return(new LeftSideExprCall {
                        Name = name, Type = LeftSideExprType.Call, Node = this, CallFunc = callFuncExpr
                    });
                }
                if (funcImplementation.ReturnType == SymbolType.Void || funcImplementation.ReturnType == SymbolType.Unknown)
                {
                    throw new ParseException("Невозможно использовать функции, возвращающие void в выражениях", this);
                }
                return(callFuncExpr);
            }
            return(null);
        }
Esempio n. 6
0
        /// <summary>
        /// Rule: Function -> IDENTIFIER (BROPEN Parameters BRCLOSE )? (ARROW Expr  | Statements) ;
        /// </summary>
        protected override object EvalFunction(ParseTree tree, params object[] paramlist)
        {
            var       functionName = GetNode(TokenType.IDENTIFIER).Token.Text;
            var       parameters   = (List <string>)GetNode(TokenType.Parameters)?.Eval(tree) ?? new List <string>();
            bool      isCalled     = false;
            ParseNode callPlace    = null;

            if (paramlist != null && paramlist.Any())
            {
                isCalled  = (bool)paramlist[0];
                callPlace = (ParseNode)paramlist[1];
            }
            if (functionName == "main")
            {
                if (isCalled)
                {
                    throw new ParseException("Нельзя вызвать main", callPlace ?? GetNode(TokenType.IDENTIFIER));
                }
                if (parameters.Count > 0)
                {
                    throw new ParseException("Main не может иметь аргументов", GetNode(TokenType.IDENTIFIER));
                }
                if (AstCreator.FuncImplementations.Any(x => x.Name == "main"))
                {
                    throw new ParseException("Повторное обявление main", GetNode(TokenType.IDENTIFIER));
                }
                var implementation = new FuncImplementation {
                    Node = this, Name = "main", Declaration = AstCreator.FuncDeclarations.SingleOrDefault(x => x.Name == "main")
                };
                AstCreator.FuncImplementation.Push(implementation);
                Namespaces.LevelDown(new Namespace("main()"));

                var codeblockNode = GetNode(TokenType.Statements);
                if (codeblockNode == null)
                {
                    throw new ParseException("Main должен иметь тело", GetNode(TokenType.IDENTIFIER));
                }
                var stms = (CodeBlock)codeblockNode.Eval(tree);
                implementation.Code      = stms;
                implementation.Namespace = Namespaces.Current;
                Namespaces.LevelUp();
                AstCreator.FuncImplementations.Add(AstCreator.FuncImplementation.Pop());
            }
            else
            {
                if (isCalled)
                {
                    var exprNode = GetNode(TokenType.Expr);
                    var funcImpl = AstCreator.FuncImplementation.Peek();
                    funcImpl.Node = this;
                    if (exprNode != null)
                    {
                        var expr = (ExpressionBase)exprNode.Eval(tree);
                        funcImpl.ReturnExpression = expr;
                        funcImpl.ReturnType       = expr.GetExprType();
                    }
                    else
                    {
                        var stms = (CodeBlock)GetNode(TokenType.Statements).Eval(tree);
                        funcImpl.Code = stms;
                    }
                }
                else
                {
                    if (AstCreator.FuncDeclarations.Any(f => f.Name == functionName && f.Arguments.Count == parameters.Count))
                    {
                        throw new ParseException($"Повтороное объявление функции {functionName}", GetNode(TokenType.IDENTIFIER));
                    }
                    AstCreator.FuncDeclarations.Add(
                        new FuncDeclaration {
                        Name = functionName, Node = this, Arguments = parameters
                    });

                    Namespaces.Current.AddSymbol(
                        new Symbol(SymbolType.Function, functionName),
                        GetNode(TokenType.IDENTIFIER));
                }
            }
            return(null);
        }