Example #1
0
        public static TranslationResult Constructor(List <ExpressionSharpnode> arguments, TranslationContext context, ITypeSymbol typeArgument, SyntaxNode originalNode)
        {
            var silvernodes = new List <Silvernode>();
            var errors      = new List <Error>();
            List <StatementSilvernode> prepend = new List <Trees.Silver.StatementSilvernode>();

            // Translate initial members
            foreach (var arg in arguments)
            {
                var res = arg.Translate(context.ChangePurityContext(PurityContext.Purifiable));
                silvernodes.Add(res.Silvernode);
                errors.AddRange(res.Errors);
                prepend.AddRange(res.PrependTheseSilvernodes);
            }
            Silvernode result;

            if (arguments.Count == 0)
            {
                // No arguments = use the Seq[Int] construction
                Error      err;
                SilverType silverType = TypeTranslator.TranslateType(typeArgument, null, out err);
                if (err != null)
                {
                    errors.Add(err);
                }
                result = new SimpleSequenceSilvernode(originalNode,
                                                      "Seq[", new TypeSilvernode(null, silverType), "]()");
            }
            else
            {
                // Some arguments - use the Seq construction with type inference
                // ReSharper disable once UseObjectOrCollectionInitializer
                List <Silvernode> args = new List <Silvernode>();
                args.Add("Seq(");
                for (int i = 0; i < silvernodes.Count; i++)
                {
                    args.Add(silvernodes[i]);
                    if (i != silvernodes.Count - 1)
                    {
                        args.Add(", ");
                    }
                }
                args.Add(")");
                result = new SimpleSequenceSilvernode(originalNode, args.ToArray());
            }
            return(TranslationResult.FromSilvernode(result, errors).AndPrepend(prepend));
        }
Example #2
0
        /// <summary>
        /// Translates the method or constructor.
        /// </summary>
        public TranslationResult TranslateSelf()
        {
            Identifier        identifier = GetSubroutineIdentifier();
            SilverKind        silverKind = SilverKind.Method;
            TranslationResult result     = new TranslationResult();
            bool isAbstract = false;

            // Determine whether it should be translated at all.
            var attributes = this.MethodSymbol.GetAttributes();

            switch (VerificationSettings.ShouldVerify(attributes, this.Context.VerifyUnmarkedItems))
            {
            case VerificationSetting.DoNotVerify:
                return(TranslationResult.FromSilvernode(new SinglelineCommentSilvernode($"Method {this.MethodSymbol.GetQualifiedName()} skipped because it was marked [Unverified].", this.OriginalNode)));

            case VerificationSetting.Contradiction:
                return(TranslationResult.Error(this.OriginalNode, Diagnostics.SSIL113_VerificationSettingsContradiction));

            case VerificationSetting.Verify:
                break;

            default:
                throw new InvalidOperationException("Nonexistent verification settings.");
            }

            // Determine whether it will result in a predicate, function or method, and whether it's abstract.
            foreach (var attribute in attributes)
            {
                switch (attribute.AttributeClass.GetQualifiedName())
                {
                case ContractsTranslator.PredicateAttribute:
                    if (silverKind == SilverKind.Method && !this.IsConstructor)
                    {
                        silverKind = SilverKind.Predicate;
                    }
                    else
                    {
                        return(TranslationResult.Error(this.OriginalNode, Diagnostics.SSIL116_MethodAttributeContradiction));
                    }
                    break;

                case ContractsTranslator.PureAttribute:
                    if (silverKind == SilverKind.Method && !this.IsConstructor)
                    {
                        silverKind = SilverKind.Function;
                    }
                    else
                    {
                        return(TranslationResult.Error(this.OriginalNode, Diagnostics.SSIL116_MethodAttributeContradiction));
                    }
                    break;

                case ContractsTranslator.AbstractAttribute:
                case ContractsTranslator.SignatureOnlyAttribute:
                    if (this.IsConstructor)
                    {
                        return(TranslationResult.Error(this.OriginalNode, Diagnostics.SSIL117_ConstructorMustNotBeAbstract));
                    }
                    isAbstract = true;
                    break;

                    // Ignore other attributes.
                }
            }
            if (Context.MarkEverythingAbstract)
            {
                isAbstract = true;
            }

            // Translate the method body
            TranslationContext bodyContext = this.Context;

            if (silverKind == SilverKind.Function || silverKind == SilverKind.Predicate)
            {
                bodyContext = new TranslationContext(this.Context)
                {
                    IsFunctionOrPredicateBlock = true,
                    PurityContext = PurityContext.PureOrFail
                };
            }
            TranslationResult body = this.BodySharpnode.Translate(bodyContext);

            result.Errors.AddRange(body.Errors);

            // Translate parameters
            var silverParameters = new List <ParameterSilvernode>();

            if (!this.IsConstructor && !this.MethodSymbol.IsStatic)
            {
                silverParameters.Add(new ParameterSilvernode(new Identifier(Constants.SilverThis), new TypeSilvernode(null, SilverType.Ref), null));
            }
            for (int i = 0; i < this.Parameters.Count; i++)
            {
                ParameterSharpnode sharpnode = this.Parameters[i];
                var symbol = this.MethodSymbol.Parameters[i];
                var rrs    = sharpnode.Translate(this.Context, symbol);
                silverParameters.Add(rrs.Silvernode as ParameterSilvernode);
                result.Errors.AddRange(rrs.Errors);
            }

            // Prepare silvernodes before composing them
            var    silName            = new IdentifierSilvernode(identifier);
            var    silOriginalnode    = this.OriginalNode;
            var    silParameters      = silverParameters;
            string silReturnValueName = Constants.SilverReturnVariableName;

            if (this.IsConstructor)
            {
                silReturnValueName = Constants.SilverThis;
            }
            if (silverKind != SilverKind.Method)
            {
                silReturnValueName = "result"; // "result" is a Silver keyword
            }
            Error      diagnostic;
            SilverType silverReturnType = TypeTranslator.TranslateType(this.IsConstructor ? this.ConstructorClass : this.MethodSymbol.ReturnType, null, out diagnostic);

            if (diagnostic != null)
            {
                result.Errors.Add(diagnostic);
            }
            var silTypeSilvernode         = new TypeSilvernode(null, silverReturnType);
            var silVerificationConditions = body.Contracts;
            var silBlock = body.Silvernode as BlockSilvernode;

            // Error checking
            if (silverReturnType == SilverType.Void && silverKind == SilverKind.Function)
            {
                return(TranslationResult.Error(this.OriginalNode, Diagnostics.SSIL118_FunctionsMustHaveAReturnType));
            }
            if (silverReturnType != SilverType.Bool && silverKind == SilverKind.Predicate)
            {
                return(TranslationResult.Error(this.OriginalNode, Diagnostics.SSIL119_PredicateMustBeBool));
            }

            // Constructors first need to call the initializer
            if (this.IsConstructor)
            {
                silBlock.Prepend(new AssignmentSilvernode(Constants.SilverThis, new CallSilvernode(this.Context.Process.IdentifierTranslator.GetIdentifierReferenceWithTag(this.ConstructorClass, Constants.InitializerTag), new List <Silvernode>(), SilverType.Ref, null), null));
            }

            // Methods need "label end" at the end; this may be removed by optimization further in the translation process
            if (silverKind == SilverKind.Method)
            {
                silBlock.Add(new LabelSilvernode(Constants.SilverMethodEndLabel, null));
            }

            // Put it all together
            switch (silverKind)
            {
            case SilverKind.Method:
                result.Silvernode = new MethodSilvernode(silOriginalnode, silName, silParameters, silReturnValueName, silTypeSilvernode, silVerificationConditions, isAbstract ? null : silBlock);
                break;

            case SilverKind.Function:
                result.Silvernode = new FunctionSilvernode(silOriginalnode, silName, silParameters, silReturnValueName, silTypeSilvernode, silVerificationConditions, isAbstract ? null : silBlock);
                break;

            case SilverKind.Predicate:
                result.Silvernode = new PredicateSilvernode(silOriginalnode, silName, silParameters, silReturnValueName, silTypeSilvernode, silVerificationConditions, isAbstract ? null : silBlock);
                break;

            default:
                throw new InvalidOperationException("Nonexistent silverkind.");
            }

            return(result);
        }