Beispiel #1
0
        public void SpacesInArgListTest()
        {
            var mwb = MockWorkbook.standardMockWorkbook();
            var e   = mwb.envForSheet(1);

            var f = "=SUM(A1,A2,A3, A4)";

            ExprOpt asto = Parcel.parseFormula(f, e.Path, e.WorkbookName, e.WorksheetName);

            string[] addrs = { "A1", "A2", "A3", "A4" };
            var      rng   = Utility.makeUnionRangeFromA1Addrs(addrs, e);

            Expr[] a =
            {
                Expr.NewReferenceExpr(new AST.ReferenceRange(e, rng))
            };
            ArgList args    = Utility.makeFSList(a);
            Expr    correct = Expr.NewReferenceExpr(new AST.ReferenceFunction(e, "SUM", args, AST.Arity.VarArgs));

            try
            {
                Expr ast = asto.Value;
                Assert.AreEqual(correct, ast);
            }
            catch (NullReferenceException nre)
            {
                Assert.Fail("Parse error: " + nre.Message);
            }
        }
Beispiel #2
0
        public void UnaryPrecedenceTest()
        {
            var mwb = MockWorkbook.standardMockWorkbook();
            var e   = mwb.envForSheet(1);

            var f = "=-1 * 2";

            ExprOpt asto = Parcel.parseFormula(f, e.Path, e.WorkbookName, e.WorksheetName);

            Expr correct =
                Expr.NewBinOpExpr(
                    "*",
                    Expr.NewUnaryOpExpr(
                        '-',
                        Expr.NewReferenceExpr(new AST.ReferenceConstant(e, 1.0))
                        ),
                    Expr.NewReferenceExpr(new AST.ReferenceConstant(e, 2.0))
                    );

            try
            {
                Expr ast = asto.Value;
                Assert.AreEqual(correct, ast);
            }
            catch (NullReferenceException nre)
            {
                Assert.Fail("Parse error: " + nre.Message);
            }
        }
Beispiel #3
0
        public MethodInfo EmitLambda(string name, AST.DirectVarUse variable, AST.Expression /*!*/ expression,
                                     PhpTypeCode returnType)
        {
            MethodBuilder result = linqContextBuilder.DefineMethod(name, MethodAttributes.PrivateScope | MethodAttributes.SpecialName,
                                                                   PhpTypeCodeEnum.ToType(returnType), new Type[] { typeof(object) });

            ILEmitter il = new ILEmitter(result);

            EnterLambdaDeclaration(il);

            if (variable != null)
            {
                // <variable> = COPY(<argument>);
                variable.Emit(cg);
                il.Emit(OpCodes.Ldarg_1);
                cg.EmitVariableCopy(CopyReason.Assigned, null);
                variable.EmitAssign(cg);
            }

            cg.EmitConversion(expression, returnType);
            il.Emit(OpCodes.Ret);

            LeaveLambdaDeclaration();

            return(result);
        }
Beispiel #4
0
            public Invocation GetCtorInvocation()
            {
                AST.Expression rr = LazyInit.VolatileRead(ref this.ctorInvocation);
                if (rr != null)
                {
                    return(rr as Invocation);
                }
                else
                {
                    int totalArgumentCount         = unresolved.positionalArguments.Count + unresolved.namedCtorArguments.Count;
                    AST.Expression[] arguments     = new AST.Expression[totalArgumentCount];
                    string[]         argumentNames = new string[totalArgumentCount];
                    int i = 0;
                    while (i < unresolved.positionalArguments.Count)
                    {
                        IConstantValue cv = unresolved.positionalArguments[i];
                        arguments[i] = cv.ResolveConstant(context);
                        i++;
                    }
                    foreach (var pair in unresolved.namedCtorArguments)
                    {
                        argumentNames[i] = pair.Key;
                        arguments[i]     = pair.Value.ResolveConstant(context);
                        i++;
                    }

                    rr = NewExpression.ResolveObjectCreation(context, unresolved.loc, attributeType, arguments, argumentNames);
                    return(LazyInit.GetOrSet(ref this.ctorInvocation, rr) as Invocation);
                }
            }
Beispiel #5
0
        /// <summary>
        /// Applies the transformation
        /// </summary>
        /// <returns>The transformed item.</returns>
        /// <param name="el">The item to visit.</param>
        public virtual ASTItem Transform(ASTItem el)
        {
            if (el is AST.AssignmentExpression)
            {
                var ase = ((AST.AssignmentExpression)el);
                if (ase.Operator != AssignmentOperatorType.Assign)
                {
                    AST.Expression clonedleft = ase.Left.Clone();

                    var newop = new AST.BinaryOperatorExpression()
                    {
                        Operator         = ase.Operator.ToBinaryOperator(),
                        Left             = clonedleft,
                        Right            = ase.Right,
                        Parent           = ase,
                        SourceExpression = ase.SourceExpression,
                        SourceResultType = ase.SourceResultType
                    };

                    newop.Left.Parent = newop.Right.Parent = newop;
                    ase.Operator      = AssignmentOperatorType.Assign;
                    ase.Right         = newop;

                    return(null);
                }
            }

            return(el);
        }
Beispiel #6
0
        public OverloadResolution PerformOverloadResolution(ICompilation compilation, Expression[] arguments, string[] argumentNames = null,
                                                            bool allowExtensionMethods = true,
                                                            bool allowExpandingParams = true,
                                                            bool allowOptionalParameters = true,
                                                            bool checkForOverflow = false, VSharpConversions conversions = null)
        {

            var typeArgumentArray = this.TypeArguments.ToArray();
            OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, typeArgumentArray, conversions);
            or.AllowExpandingParams = allowExpandingParams;
            or.AllowOptionalParameters = allowOptionalParameters;
            or.CheckForOverflow = checkForOverflow;

            or.AddMethodLists(methodLists);

            if (allowExtensionMethods && !or.FoundApplicableCandidate)
            {
                // No applicable match found, so let's try extension methods.

                var extensionMethods = this.GetExtensionMethods();

                if (extensionMethods.Any())
                {

                    Expression[] extArguments = new Expression[arguments.Length + 1];
                    extArguments[0] = new AST.Expression(this.TargetType);
                    arguments.CopyTo(extArguments, 1);
                    string[] extArgumentNames = null;
                    if (argumentNames != null)
                    {
                        extArgumentNames = new string[argumentNames.Length + 1];
                        argumentNames.CopyTo(extArgumentNames, 1);
                    }
                    var extOr = new OverloadResolution(compilation, extArguments, extArgumentNames, typeArgumentArray, conversions);
                    extOr.AllowExpandingParams = allowExpandingParams;
                    extOr.AllowOptionalParameters = allowOptionalParameters;
                    extOr.IsExtensionMethodInvocation = true;
                    extOr.CheckForOverflow = checkForOverflow;

                    foreach (var g in extensionMethods)
                    {
                        foreach (var method in g)
                            extOr.AddCandidate(method);

                        if (extOr.FoundApplicableCandidate)
                            break;
                    }
                    // For the lack of a better comparison function (the one within OverloadResolution
                    // cannot be used as it depends on the argument set):
                    if (extOr.FoundApplicableCandidate || or.BestCandidate == null)
                    {
                        // Consider an extension method result better than the normal result only
                        // if it's applicable; or if there is no normal result.
                        or = extOr;
                    }
                }
            }

            return or;
        }
Beispiel #7
0
        static AST.Expression MapToNewContext(AST.Expression rr, ITypeResolveContext newContext)
        {
            if (rr is TypeOfExpression)
            {
                return new TypeOfExpression(
                    rr.Type.ToTypeReference().Resolve(newContext),
                    ((TypeOfExpression)rr).TargetType.ToTypeReference().Resolve(newContext));
            }
            else if (rr is ArrayCreation)
            {
                ArrayCreation acrr = (ArrayCreation)rr;
                return new ArrayCreation(
                    acrr.Type.ToTypeReference().Resolve(newContext),
                    MapToNewContext(acrr.arguments, newContext),
                    MapToNewContext(acrr.initializers != null ? acrr.initializers.Elements : null, newContext));
            }
            else if (rr.IsCompileTimeConstant)
            {
                return Constant.CreateConstantFromValue(newContext.Compilation, rr.Type.ToTypeReference().Resolve(newContext),
                    rr.ConstantValue, rr.Location);

            }
            else
            {
                return new ErrorExpression(rr.Type.ToTypeReference().Resolve(newContext));
            }
        }
Beispiel #8
0
        public void Arity2Test2()
        {
            var mwb = MockWorkbook.standardMockWorkbook();
            var e   = mwb.envForSheet(1);

            var f = "=SUMX2MY2(A$4:A$10,B$4:B$10)";

            ExprOpt asto = Parcel.parseFormula(f, e.Path, e.WorkbookName, e.WorksheetName);

            Expr[] a =
            {
                Expr.NewReferenceExpr(new AST.ReferenceRange(e, Utility.makeRangeForA1("A$4:A$10", e))),
                Expr.NewReferenceExpr(new AST.ReferenceRange(e, Utility.makeRangeForA1("B$4:B$10", e)))
            };
            ArgList args    = Utility.makeFSList <AST.Expression>(a);
            Expr    correct = Expr.NewReferenceExpr(new AST.ReferenceFunction(e, "SUMX2MY2", args, AST.Arity.NewFixed(2)));

            try
            {
                Expr ast = asto.Value;
                Assert.AreEqual(correct, ast);
            }
            catch (NullReferenceException nre)
            {
                Assert.Fail("Parse error: " + nre.Message);
            }
        }
Beispiel #9
0
        public void basicIfExpression()
        {
            var    mwb = MockWorkbook.standardMockWorkbook();
            var    e   = mwb.envForSheet(1);
            string f   = "=IF(TRUE, 1, 2)";

            ExprOpt asto = Parcel.parseFormula(f, e.Path, e.WorkbookName, e.WorksheetName);

            Expr[] a =
            {
                Expr.NewReferenceExpr(new AST.ReferenceBoolean(e,  true)),
                Expr.NewReferenceExpr(new AST.ReferenceConstant(e,  1.0)),
                Expr.NewReferenceExpr(new AST.ReferenceConstant(e, 2.0))
            };
            ArgList args    = Utility.makeFSList <AST.Expression>(a);
            Expr    correct = Expr.NewReferenceExpr(new AST.ReferenceFunction(e, "IF", args, AST.Arity.NewFixed(3)));

            try
            {
                Expr ast = asto.Value;
                Assert.AreEqual(ast, correct);
            } catch (NullReferenceException nre)
            {
                Assert.Fail("Parse error: " + nre.Message);
            }
        }
Beispiel #10
0
 /// <summary>
 /// Initializes a new instance of the <see cref="T:SMEIL.Parser.AST.DataType"/> class.
 /// </summary>
 /// <param name="token">The source token.</param>
 /// <param name="width">The length of the array</param>
 /// <param name="SourceConstExpression">The constant expression defining the length of the array</param>
 /// <param name="elementType">The element type.</param>
 public DataType(ParseToken token, int width, Expression sourceConstExpr, DataType elementType)
     : base(token)
 {
     Type     = ILType.Array;
     BitWidth = width;
     SourceConstExpression = sourceConstExpr;
     ElementType           = elementType ?? throw new ArgumentNullException(nameof(elementType));
 }
Beispiel #11
0
 public virtual bool DoResolve(ResolveContext rc)
 {
     // DoResolve type definition
     AST.Expression rr = ResolveTypeDefinition(name, typeParameters.Count, rc);
     if (rr.IsError)
     {
     }
     return(true);
 }
Beispiel #12
0
        private AST.Statement ParseSetVariableStatement(Lexer lexer)
        {
            var text  = string.Empty;
            var token = lexer.InputToken(out text);

            if (token != Token.V名称符号)
            {
                throw new Exception($"语法错误,不是预期的输入:{text}。 在 {lexer.Line} 行,{lexer.Column}列");
            }
            var name = ParseName(text);

            AST.Expression row = null;
            AST.Expression col = null;
            token = lexer.InputToken(out text);
            if (token == Token.的第)
            {
                row   = ParseExpression(lexer);
                token = lexer.InputToken(out text);
                if (token != Token.行)
                {
                    throw new Exception($"语法错误,不是预期的输入:{text}。 在 {lexer.Line} 行,{lexer.Column}列");
                }

                col   = ParseExpression(lexer);
                token = lexer.InputToken(out text);
                if (token != Token.列)
                {
                    throw new Exception($"语法错误,不是预期的输入:{text}。 在 {lexer.Line} 行,{lexer.Column}列");
                }
                token = lexer.InputToken(out text);
            }

            if (token != Token.的值为)
            {
                throw new Exception($"语法错误,不是预期的输入:{text}。 在 {lexer.Line} 行,{lexer.Column}列");
            }

            token = lexer.InputToken(out text);
            if (token != Token.冒号)
            {
                lexer.ReturnToken(token, text);
            }

            var expr = ParseExpression(lexer);

            token = lexer.InputToken(out text);
            if (token != Token.的结果)
            {
                lexer.ReturnToken(token, text);
            }
            if (row != null || col != null)
            {
                return(new AST.SetArrayVariableStatement(name, row, col, expr));
            }
            return(new AST.SetVariableStatement(name, expr));
        }
Beispiel #13
0
 static void WriteExpression(StreamWriter writer, AST.Expression expression)
 {
     if (expression is AST.Constant constant)
     {
         writer.Write(Assembly.format_constant, Assembly.register_A_32, constant.Value);
     }
     else if (expression is AST.UnaryOperator unary)
     {
         WriteUnaryOperator(writer, unary);
     }
 }
Beispiel #14
0
 static AST.Expression[] MapToNewContext(IList<AST.Expression> input, ITypeResolveContext newContext)
 {
     if (input == null)
         return null;
     AST.Expression[] output = new AST.Expression[input.Count];
     for (int i = 0; i < output.Length; i++)
     {
         output[i] = MapToNewContext(input[i], newContext);
     }
     return output;
 }
Beispiel #15
0
        private AST.Expression ParseExpressionL1(Lexer lexer)
        {
            var lexpr = ParseExpressionL2(lexer);
            var text  = string.Empty;
            var token = lexer.InputToken(out text);

            switch (token)
            {
            case Token.顿号:
            {
                var rexpr = ParseExpression(lexer);
                token = lexer.InputToken(out text);
                AST.Expression expr = null;
                switch (token)
                {
                case Token.相加:
                    expr = new AST.AddExpression(lexpr, rexpr);
                    break;

                case Token.相减:
                    expr = new AST.SubExpression(lexpr, rexpr);
                    break;

                case Token.相乘:
                    expr = new AST.MulExpression(lexpr, rexpr);
                    break;

                case Token.相除:
                    expr = new AST.DivExpression(lexpr, rexpr);
                    break;

                case Token.取余数:
                    expr = new AST.ModExpression(lexpr, rexpr);
                    break;

                default:
                    throw new Exception($"语法错误,不是预期的输入:{text}。 在 {lexer.Line} 行,{lexer.Column}列");
                }
                token = lexer.InputToken(out text);
                if (token != Token.的结果)
                {
                    lexer.ReturnToken(token, text);
                }
                return(expr);
            }

            default:
                lexer.ReturnToken(token, text);
                break;
            }
            return(lexpr);
        }
Beispiel #16
0
        /// <summary>
        /// Helper function that digs out the primitive expression underneath casting and formatting expressions
        /// </summary>
        /// <returns>The primitive expression or null.</returns>
        /// <param name="e">The expression to unwrap.</param>
        private static AST.PrimitiveExpression UnwrapPrimitive(AST.Expression e)
        {
            if (e is CustomNodes.ConversionExpression)
            {
                e = ((CustomNodes.ConversionExpression)e).Expression;
            }
            if (e is AST.PrimitiveExpression)
            {
                return((AST.PrimitiveExpression)e);
            }

            return(null);
        }
Beispiel #17
0
        private AST.Statement ParseReturnStatement(Lexer lexer)
        {
            AST.Expression expr  = null;
            var            text  = string.Empty;
            var            token = lexer.InputToken(out text);

            lexer.ReturnToken(token, text);

            if (token != Token.行结束符号 && token != Token.段结束符号 && token != Token.V程序结束)
            {
                expr = ParseExpression(lexer);
            }
            return(new AST.ReturnStatement(expr));
        }
Beispiel #18
0
        IType[] OutputTypes(AST.Expression e, IType t)
        {
            // V# 4.0 spec: §7.5.2.4 Output types
            LambdaExpression lrr = e as LambdaExpression;

            if (lrr != null || e is MethodGroupExpression)
            {
                IMethod m = GetDelegateOrExpressionTreeSignature(t);
                if (m != null)
                {
                    return(new[] { m.ReturnType });
                }
            }
            return(emptyTypeArray);
        }
Beispiel #19
0
 private AST.Expression Multiplicative()
 {
     AST.Expression result = Unary();
     while (true)
     {
         if (IsMatch(TokenType.STAR))
         {
             result = new AST.BinaryExpression('*', result, Unary());
             continue;
         }
         if (IsMatch(TokenType.SLASH))
         {
             result = new AST.BinaryExpression('/', result, Unary());
             continue;
         }
         break;
     }
     return(result);
 }
Beispiel #20
0
        IType[] InputTypes(AST.Expression e, IType t)
        {
            // V# 4.0 spec: §7.5.2.3 Input types
            LambdaExpression lrr = e as LambdaExpression;

            if (lrr != null && lrr.IsImplicitlyTyped || e is MethodGroupExpression)
            {
                IMethod m = GetDelegateOrExpressionTreeSignature(t);
                if (m != null)
                {
                    IType[] inputTypes = new IType[m.Parameters.Count];
                    for (int i = 0; i < inputTypes.Length; i++)
                    {
                        inputTypes[i] = m.Parameters[i].Type;
                    }
                    return(inputTypes);
                }
            }
            return(emptyTypeArray);
        }
Beispiel #21
0
        public static AST.Statement ParseStatement(Queue <Token> tokens)
        {
            Token token = tokens.Dequeue();

            if (!Match(token, Token.TokenType.Keyword, Syntax.GetKeyword(Syntax.Keyword.Return)))
            {
                Fail(token);
            }

            AST.Expression expression = ParseExpression(tokens);
            AST.Statement  statement  = new AST.Return(expression);

            token = tokens.Dequeue();
            if (token.Type != Token.TokenType.Semicolon)
            {
                Fail(token);
            }

            return(statement);
        }
Beispiel #22
0
        private AST.Expression Additive()
        {
            AST.Expression result = Multiplicative();

            while (true)
            {
                if (IsMatch(TokenType.PLUS))
                {
                    result = new AST.BinaryExpression('+', result, Multiplicative());
                    continue;
                }
                if (IsMatch(TokenType.MINUS))
                {
                    result = new AST.BinaryExpression('-', result, Multiplicative());
                    continue;
                }
                break;
            }

            return(result);
        }
Beispiel #23
0
 public AST.Expression ResolveConstant(ITypeResolveContext context)
 {
     var csContext = (VSharpTypeResolveContext)context;
     if (context.CurrentAssembly != context.Compilation.MainAssembly)
     {
         // The constant needs to be resolved in a different compilation.
         IProjectContent pc = context.CurrentAssembly as IProjectContent;
         if (pc != null)
         {
             ICompilation nestedCompilation = context.Compilation.SolutionSnapshot.GetCompilation(pc);
             if (nestedCompilation != null)
             {
                 var nestedContext = MapToNestedCompilation(csContext, nestedCompilation);
                 AST.Expression rr = Constantify(new ResolveContext(nestedContext, CompilerContext.report));
                 return MapToNewContext(rr, context);
             }
         }
     }
     // Resolve in current context.
     return Constantify(new ResolveContext(csContext, CompilerContext.report));
 }
Beispiel #24
0
        public override Expression Resolve(ResolveContext resolver)
        {
            AliasNamespace target = new AliasNamespace(alias, Location);

            AST.Expression targetRR = target.Resolve(resolver);
            if (targetRR.IsError)
            {
                return(targetRR);
            }
            IList <IType> typeArgs = typeArgumentsrefs.Resolve(resolver.CurrentTypeResolveContext);

            if (LookForAttribute)
            {
                var wa = ResolveMemberAccess(resolver, targetRR, name + "Attribute", typeArgs, lookupMode);
                if (wa == null || wa.IsError)
                {
                    wa = ResolveMemberAccess(resolver, targetRR, name, typeArgs, lookupMode);
                    if (wa == null || wa.IsError)
                    {
                        resolver.Report.Error(6, loc, "This name `{0}' does not exist in the current context", name);
                    }
                }
                LookForAttribute = false;
                return(wa);
            }
            else
            {
                var wa = ResolveMemberAccess(resolver, targetRR, name, typeArgs, lookupMode);
                if (wa == null || wa.IsError)
                {
                    resolver.Report.Error(6, loc, "This name `{0}' does not exist in the current context", name);
                }

                return(wa);
            }
        }
Beispiel #25
0
 public If(AST.Expression condition, Statements.Statement thenBranch, Statements.Statement ElseBranch)
 {
     this.Condition  = condition;
     this.ThenBranch = thenBranch;
     this.ElseBranch = ElseBranch;
 }
Beispiel #26
0
        private AST.Expression ParseExpressionL2(Lexer lexer)
        {
            AST.Expression expr  = null;
            var            text  = string.Empty;
            var            token = lexer.InputToken(out text);

            switch (token)
            {
            case Token.V名称符号:
            {
                var name = ParseName(text);
                token = lexer.InputToken(out text);
                if (token == Token.的第)
                {
                    var row = ParseExpression(lexer);
                    token = lexer.InputToken(out text);
                    if (token != Token.行)
                    {
                        throw new Exception($"语法错误,不是预期的输入:{text}。 在 {lexer.Line} 行,{lexer.Column}列");
                    }

                    var col = ParseExpression(lexer);
                    token = lexer.InputToken(out text);
                    if (token != Token.列)
                    {
                        throw new Exception($"语法错误,不是预期的输入:{text}。 在 {lexer.Line} 行,{lexer.Column}列");
                    }

                    expr = new AST.ReadArrayVariableExpression(name, row, col);
                }
                else
                {
                    lexer.ReturnToken(token, text);
                    expr = new AST.ReadVariableExpression(name);
                }
            }
            break;

            case Token.V字符串值:
            {
                var svalue = ParseStringValue(text);
                expr = new AST.ConstantExpression(new StringValue(svalue));
            }
            break;

            case Token.V数字值:
            {
                var dvalue = ParseNumberValue(text);
                if (((long)dvalue) == dvalue)
                {
                    expr = new AST.ConstantExpression(new IntegerValue((long)dvalue));
                }
                else
                {
                    expr = new AST.ConstantExpression(new RealValue(dvalue));
                }
            }
            break;

            case Token.真:
            {
                expr = new AST.ConstantExpression(new BooleanValue(true));
            }
            break;

            case Token.假:
            {
                expr = new AST.ConstantExpression(new BooleanValue(false));
            }
            break;

            case Token.方法调用:
                expr = ParseCallExpression(lexer, ParseName(text), false);
                break;

            default:
                throw new Exception($"语法错误,不是预期的输入:{text}。 在 {lexer.Line} 行,{lexer.Column}列");
            }
            return(expr);
        }
Beispiel #27
0
 /// <summary>
 /// Renders a single expression to VHDL
 /// </summary>
 /// <returns>The VHDL equivalent of the expression.</returns>
 /// <param name="expression">The expression to render</param>
 public string RenderExpression(AST.Expression expression)
 {
     if (expression is AST.ArrayCreateExpression)
     {
         return(RenderExpression(expression as ArrayCreateExpression));
     }
     else if (expression is AST.EmptyArrayCreateExpression)
     {
         return(RenderExpression(expression as EmptyArrayCreateExpression));
     }
     else if (expression is AST.AssignmentExpression)
     {
         return(RenderExpression(expression as AssignmentExpression));
     }
     else if (expression is AST.BinaryOperatorExpression)
     {
         return(RenderExpression(expression as BinaryOperatorExpression));
     }
     else if (expression is AST.CastExpression)
     {
         return(RenderExpression(expression as CastExpression));
     }
     else if (expression is AST.CheckedExpression)
     {
         return(RenderExpression(expression as CheckedExpression));
     }
     else if (expression is AST.ConditionalExpression)
     {
         return(RenderExpression(expression as ConditionalExpression));
     }
     else if (expression is AST.EmptyExpression)
     {
         return(RenderExpression(expression as EmptyExpression));
     }
     else if (expression is AST.IdentifierExpression)
     {
         return(RenderExpression(expression as IdentifierExpression));
     }
     else if (expression is AST.IndexerExpression)
     {
         return(RenderExpression(expression as IndexerExpression));
     }
     else if (expression is AST.InvocationExpression)
     {
         return(RenderExpression(expression as InvocationExpression));
     }
     else if (expression is AST.MemberReferenceExpression)
     {
         return(RenderExpression(expression as MemberReferenceExpression));
     }
     else if (expression is AST.MethodReferenceExpression)
     {
         return(RenderExpression(expression as MethodReferenceExpression));
     }
     else if (expression is AST.ParenthesizedExpression)
     {
         return(RenderExpression(expression as ParenthesizedExpression));
     }
     else if (expression is AST.PrimitiveExpression)
     {
         return(RenderExpression(expression as PrimitiveExpression));
     }
     else if (expression is AST.UnaryOperatorExpression)
     {
         return(RenderExpression(expression as UnaryOperatorExpression));
     }
     else if (expression is AST.UncheckedExpression)
     {
         return(RenderExpression(expression as UncheckedExpression));
     }
     else
     {
         throw new Exception($"Unsupported expression type {expression.GetType().FullName}");
     }
 }
Beispiel #28
0
 public Expression(AST.Expression expression)
 {
     this.Expr = expression;
 }
Beispiel #29
0
 /// <summary>
 /// Returns the VHDL type for an expression
 /// </summary>
 /// <returns>The VHDL type.</returns>
 /// <param name="element">The expression to get the type for.</param>
 public VHDLType VHDLType(AST.Expression element)
 {
     return(Parent.VHDLType(element));
 }
Beispiel #30
0
        /// <summary>
        /// Performs the type assignment to a process instance
        /// </summary>
        /// <param name="state">The validation state to use</param>
        /// <param name="instance">The process instance to use</param>
        private static void AssignProcessTypes(ValidationState state, Instance.IInstance parent, AST.Statement[] statements, Dictionary <Expression, DataType> assignedTypes)
        {
            // Get the scope for the intance
            var defaultScope = state.LocalScopes[parent];

            // Extra expression that needs examining
            var extras = new AST.Expression[0].AsEnumerable();

            if (parent is Instance.IDeclarationContainer pdecl1)
            {
                extras = extras.Concat(
                    pdecl1.Declarations
                    // Functions are handled elsewhere and have their own scopes
                    .Where(x => !(x is AST.FunctionDefinition))
                    .SelectMany(
                        x => x.All().OfType <AST.Expression>().Select(y => y.Current)
                        )
                    );
            }

            if (parent is Instance.IParameterizedInstance pp)
            {
                extras = extras.Concat(
                    pp.MappedParameters
                    .Select(x => x.MappedItem)
                    .OfType <Instance.Bus>()
                    .SelectMany(x => x.Instances
                                .OfType <Instance.Signal>()
                                .Select(y => y.Source.Initializer)
                                .Where(y => y != null)
                                )
                    );
            }

            if (parent is Instance.IChildContainer ck)
            {
                extras = extras.Concat(
                    ck.Instances
                    .OfType <Instance.Bus>()
                    .SelectMany(x => x.Instances
                                .OfType <Instance.Signal>()
                                .Select(y => y.Source.Initializer)
                                .Where(y => y != null)
                                )
                    );
            }

            // List of statement expressions to examine for literal/constant type items
            var allExpressions = statements
                                 .All()
                                 .OfType <AST.Expression>()
                                 .Select(x => new { Item = x.Current, Scope = state.TryFindScopeForItem(x) ?? defaultScope })
                                 .Concat(extras.Select(x => new { Item = x, Scope = defaultScope }))
                                 .Concat(
                extras
                .SelectMany(x => x.All().OfType <AST.Expression>().Select(y => y.Current))
                .Select(x => new { Item = x, Scope = defaultScope })
                )
                                 .ToArray()
                                 .AsEnumerable();

            // We use multiple iterations to assign types
            // The first iteration assigns types to all literal, bus, signal and variable expressions
            foreach (var nn in allExpressions)
            {
                var item  = nn.Item;
                var scope = nn.Scope;

                // Skip duplicate assignments
                if (assignedTypes.ContainsKey(item))
                {
                    continue;
                }

                if (item is AST.LiteralExpression literal)
                {
                    if (literal.Value is AST.BooleanConstant)
                    {
                        assignedTypes[literal] = new AST.DataType(literal.SourceToken, ILType.Bool, 1);
                    }
                    else if (literal.Value is AST.IntegerConstant)
                    {
                        assignedTypes[literal] = new AST.DataType(literal.SourceToken, ILType.SignedInteger, -1);
                    }
                    else if (literal.Value is AST.FloatingConstant)
                    {
                        assignedTypes[literal] = new AST.DataType(literal.SourceToken, ILType.Float, -1);
                    }
                }
                else if (item is AST.NameExpression name)
                {
                    var symbol = state.FindSymbol(name.Name, scope);
                    var dt     = FindDataType(state, name, scope);
                    if (dt != null)
                    {
                        if (name.Name.Index.LastOrDefault() != null && dt.IsArray)
                        {
                            assignedTypes[name] = dt.ElementType;
                        }
                        else
                        {
                            assignedTypes[name] = dt;
                        }

                        if (parent is Instance.IParameterizedInstance ip)
                        {
                            state.RegisterItemUsageDirection(ip, symbol, ItemUsageDirection.Read, item);
                        }
                    }
                }
            }

            // Handle variables not used in normal expressions
            foreach (var item in statements.All().Select(x => x.Current))
            {
                var scope = defaultScope;
                if (item is AST.AssignmentStatement assignmentStatement)
                {
                    var symbol = state.FindSymbol(assignmentStatement.Name, scope);
                    if (symbol is Instance.Variable var)
                    {
                        if (var.ResolvedType == null)
                        {
                            var.ResolvedType = state.ResolveTypeName(var.Source.Type, scope);
                        }
                    }
                    else if (symbol is Instance.Signal sig)
                    {
                        if (sig.ResolvedType == null)
                        {
                            sig.ResolvedType = state.ResolveTypeName(sig.Source.Type, scope);
                        }
                    }
                    else if (symbol == null)
                    {
                        throw new ParserException($"Symbol not found: \"{assignmentStatement.Name.AsString}\"", assignmentStatement.Name.SourceToken);
                    }
                    else
                    {
                        throw new ParserException($"Can only assign to signal or variable, {assignmentStatement.Name.AsString} is {symbol.GetType().Name}", assignmentStatement.Name.SourceToken);
                    }
                }
                else if (item is AST.ForStatement forStatement)
                {
                    var forScope = state.LocalScopes[forStatement];
                    var symbol   = state.FindSymbol(forStatement.Variable.Name, forScope);
                    if (symbol is Instance.Variable var)
                    {
                        if (var.ResolvedType == null)
                        {
                            var.ResolvedType = state.ResolveTypeName(var.Source.Type, scope);
                        }
                    }
                    else if (symbol == null)
                    {
                        throw new ParserException($"Symbol not found: \"{forStatement.Variable.Name}\"", forStatement.Variable.SourceToken);
                    }
                    else
                    {
                        throw new ParserException($"Can only use variable as the counter in a for loop, {forStatement.Variable.Name} is {symbol.GetType().Name}", forStatement.Variable.SourceToken);
                    }
                }
            }

            allExpressions = statements
                             .All(AST.TraverseOrder.DepthFirstPostOrder)
                             .OfType <AST.Expression>()
                             .Select(x => new { Item = x.Current, Scope = state.TryFindScopeForItem(x) ?? defaultScope })
                             .Concat(
                extras
                .SelectMany(x => x.All(AST.TraverseOrder.DepthFirstPostOrder).OfType <AST.Expression>().Select(y => y.Current))
                .Select(x => new { Item = x, Scope = defaultScope })
                )
                             .Concat(extras.Select(x => new { Item = x, Scope = defaultScope }));

            // We are only concerned with expressions, working from leafs and up
            // At this point all literals, variables, signals, etc. should have a resolved type
            foreach (var nn in allExpressions)
            {
                var item  = nn.Item;
                var scope = nn.Scope;

                // Skip duplicate assignments
                if (assignedTypes.ContainsKey(item))
                {
                    continue;
                }

                if (item is AST.UnaryExpression unaryExpression)
                {
                    var sourceType = assignedTypes[unaryExpression.Expression];

                    switch (unaryExpression.Operation.Operation)
                    {
                    case AST.UnaryOperation.UnOp.LogicalNegation:
                        if (!sourceType.IsBoolean)
                        {
                            throw new ParserException($"Cannot perform {unaryExpression.Operation.Operation} on {sourceType}", unaryExpression);
                        }
                        break;

                    case AST.UnaryOperation.UnOp.Identity:
                    case AST.UnaryOperation.UnOp.Negation:
                        if (!sourceType.IsNumeric)
                        {
                            throw new ParserException($"Cannot perform {unaryExpression.Operation.Operation} on {sourceType}", unaryExpression);
                        }
                        break;

                    case AST.UnaryOperation.UnOp.BitwiseInvert:
                        if (!sourceType.IsInteger)
                        {
                            throw new ParserException($"Cannot perform {unaryExpression.Operation.Operation} on {sourceType}", unaryExpression);
                        }
                        break;

                    default:
                        throw new ParserException($"Unsupported unary operation: {unaryExpression.Operation.Operation}", unaryExpression);
                    }

                    // Unary operations do not change the type
                    assignedTypes[item] = sourceType;
                }
                else if (item is AST.BinaryExpression binaryExpression)
                {
                    var leftType  = assignedTypes[binaryExpression.Left];
                    var rightType = assignedTypes[binaryExpression.Right];

                    // If we have a numerical operation, verify that the operands are numeric
                    if (binaryExpression.Operation.IsNumericOperation)
                    {
                        if (!leftType.IsNumeric)
                        {
                            throw new ParserException($"The operand {binaryExpression.Left} must be numerical to be used with {binaryExpression.Operation.Operation}", binaryExpression.Left);
                        }
                        if (!rightType.IsNumeric)
                        {
                            throw new ParserException($"The operand {binaryExpression.Right} must be numerical to be used with {binaryExpression.Operation.Operation}", binaryExpression.Right);
                        }
                    }

                    // If we have a logical operation, verify that the operands are boolean
                    if (binaryExpression.Operation.IsLogicalOperation)
                    {
                        if (!leftType.IsBoolean)
                        {
                            throw new ParserException($"The operand {binaryExpression.Left} must be boolean to be used with {binaryExpression.Operation.Operation}", binaryExpression.Left);
                        }
                        if (!rightType.IsBoolean)
                        {
                            throw new ParserException($"The operand {binaryExpression.Right} must be boolean to be used with {binaryExpression.Operation.Operation}", binaryExpression.Right);
                        }
                    }

                    // If we are doing a compare operation, verify that the types can be compared
                    if (binaryExpression.Operation.IsEqualityOperation)
                    {
                        if (!state.CanEqualityCompare(leftType, rightType, scope))
                        {
                            throw new ParserException($"Cannot perform boolean operation {binaryExpression.Operation.Operation} on types {leftType} and {rightType}", binaryExpression);
                        }
                    }

                    // Special handling of bitshift, where the type of the shift count does not change they type on the input
                    if (binaryExpression.Operation.Operation == BinOp.ShiftLeft || binaryExpression.Operation.Operation == BinOp.ShiftRight)
                    {
                        if (!leftType.IsInteger)
                        {
                            throw new ParserException($"The value being shifted must be an integer type but has type {leftType}", binaryExpression.Left);
                        }
                        if (!rightType.IsInteger)
                        {
                            throw new ParserException($"The shift operand must be an integer type but has type {rightType}", binaryExpression.Right);
                        }
                        assignedTypes[binaryExpression] = leftType;
                    }
                    else
                    {
                        // Make sure we can unify the types
                        if (!state.CanUnifyTypes(leftType, rightType, scope))
                        {
                            throw new ParserException($"The types types {leftType} and {rightType} cannot be unified for use with the operation {binaryExpression.Operation.Operation}", binaryExpression);
                        }

                        // Compute the unified type
                        var unified = state.UnifiedType(leftType, rightType, scope);

                        // If the source operands do not have the unified types, inject an implicit type-cast
                        if (!object.Equals(leftType, unified))
                        {
                            assignedTypes[binaryExpression.Left = new AST.TypeCast(binaryExpression.Left, unified, false)] = unified;
                        }
                        if (!object.Equals(rightType, unified))
                        {
                            assignedTypes[binaryExpression.Right = new AST.TypeCast(binaryExpression.Right, unified, false)] = unified;
                        }

                        // Assign the type to this operation
                        switch (binaryExpression.Operation.Operation)
                        {
                        // These operations just use the unified type
                        case BinOp.Add:
                        case BinOp.Subtract:
                        case BinOp.Multiply:
                        case BinOp.Divide:
                        case BinOp.Modulo:
                        case BinOp.BitwiseAnd:
                        case BinOp.BitwiseOr:
                        case BinOp.BitwiseXor:
                            assignedTypes[binaryExpression] = unified;
                            break;

                        // These operations return a boolean result
                        case BinOp.Equal:
                        case BinOp.NotEqual:
                        case BinOp.LessThan:
                        case BinOp.LessThanOrEqual:
                        case BinOp.GreaterThan:
                        case BinOp.GreaterThanOrEqual:
                        case BinOp.LogicalAnd:
                        case BinOp.LogicalOr:
                            assignedTypes[binaryExpression] = new AST.DataType(binaryExpression.SourceToken, ILType.Bool, 1);
                            break;

                        default:
                            throw new ParserException($"Unable to handle operation: {binaryExpression.Operation.Operation}", binaryExpression);
                        }
                    }
                }
                else if (item is AST.TypeCast typecastExpression)
                {
                    // Implicit typecasts are made by the parser so we do not validate those
                    if (!typecastExpression.Explicit)
                    {
                        continue;
                    }

                    var sourceType = assignedTypes[typecastExpression.Expression];
                    var targetType = state.ResolveTypeName(typecastExpression.TargetName, scope);

                    if (!state.CanTypeCast(sourceType, targetType, scope))
                    {
                        throw new ParserException($"Cannot cast from {sourceType} to {typecastExpression.TargetName}", typecastExpression);
                    }

                    assignedTypes[typecastExpression] = targetType;
                }
                // Carry parenthesis expression types
                else if (item is AST.ParenthesizedExpression parenthesizedExpression)
                {
                    assignedTypes[item] = assignedTypes[parenthesizedExpression.Expression];
                }
            }

            // Then make sure we have assigned all targets
            foreach (var item in statements.All().OfType <AST.Statement>().Select(x => x.Current))
            {
                var scope = defaultScope;
                if (item is AST.AssignmentStatement assignmentStatement)
                {
                    var      symbol   = state.FindSymbol(assignmentStatement.Name, scope);
                    var      exprType = assignedTypes[assignmentStatement.Value];
                    DataType targetType;

                    if (symbol is Instance.Variable variableInstance)
                    {
                        targetType = state.ResolveTypeName(variableInstance.Source.Type, scope);
                    }
                    else if (symbol is Instance.Signal signalInstance)
                    {
                        targetType = state.ResolveTypeName(signalInstance.Source.Type, scope);
                    }
                    else
                    {
                        throw new ParserException($"Assignment must be to a variable or a signal", item);
                    }

                    if (targetType.IsArray && assignmentStatement.Name.Index?.LastOrDefault() != null)
                    {
                        targetType = targetType.ElementType;
                    }

                    if (!state.CanUnifyTypes(targetType, exprType, scope))
                    {
                        throw new ParserException($"Cannot assign \"{assignmentStatement.Value.SourceToken.Text}\" (with type {exprType}) to {assignmentStatement.Name.SourceToken} (with type {targetType})", item);
                    }
                    //var unified = state.UnifiedType(targetType, exprType, scope);

                    // Force the right-hand side to be the type we are assigning to
                    if (!object.Equals(exprType, targetType))
                    {
                        // Make sure we do not loose bits with implicit typecasting
                        if (exprType.BitWidth > targetType.BitWidth && targetType.BitWidth > 0)
                        {
                            throw new ParserException($"Assignment would loose precision from {exprType.BitWidth} bits to {targetType.BitWidth}", item);
                        }

                        assignedTypes[assignmentStatement.Value = new AST.TypeCast(assignmentStatement.Value, targetType, false)] = targetType;
                    }

                    if (parent is Instance.IParameterizedInstance ip)
                    {
                        state.RegisterItemUsageDirection(ip, symbol, ItemUsageDirection.Write, item);
                    }
                }
                else if (item is AST.ForStatement forStatement)
                {
                    var fromType = assignedTypes[forStatement.FromExpression];
                    var toType   = assignedTypes[forStatement.ToExpression];

                    if (!fromType.IsInteger)
                    {
                        throw new ParserException("The from/to arguments in a for loop must be integer types", forStatement.FromExpression);
                    }
                    if (!toType.IsInteger)
                    {
                        throw new ParserException("The from/to arguments in a for loop must be integer types", forStatement.ToExpression);
                    }

                    var inttype = new DataType(forStatement.Variable.Name.SourceToken, ILType.SignedInteger, -1);

                    if (fromType.BitWidth != -1)
                    {
                        assignedTypes[forStatement.FromExpression = new AST.TypeCast(forStatement.FromExpression, inttype, false)] = inttype;
                    }
                    if (toType.BitWidth != -1)
                    {
                        assignedTypes[forStatement.ToExpression = new AST.TypeCast(forStatement.ToExpression, inttype, false)] = inttype;
                    }
                }
            }
        }