public override TranslationResult Translate(TranslationContext context) { // Translate parts var conditionResult = this.Condition.Translate(context.ChangePurityContext(PurityContext.Purifiable)); var statementResult = this.Statement.Translate(context); // Put them together var statementBlock = ((StatementSilvernode)statementResult.Silvernode).EncloseInBlockIfNotAlready(); var errors = new List <Error>(); errors.AddRange(conditionResult.Errors); errors.AddRange(statementResult.Errors); statementBlock.Statements.AddRange(conditionResult.PrependTheseSilvernodes); return(TranslationResult.FromSilvernode( new SimpleSequenceSilvernode(this.OriginalNode, new StatementsSequenceSilvernode(statementBlock.OriginalNode, statementBlock.Statements.ToArray()), "\n", new StatementsSequenceSilvernode(null, conditionResult.PrependTheseSilvernodes.ToArray()), new WhileSilvernode( conditionResult.Silvernode, statementResult.Contracts, statementBlock, null ) ), errors )); }
public override TranslationResult Translate(TranslationContext context) { SymbolInfo symbolInfo = context.Semantics.GetSymbolInfo(this.Expression); ISymbol symbol = symbolInfo.Symbol; // Special cases first: TranslationResult contractResult = context.Process.ContractsTranslator.TranslateIdentifierAsContract(symbol, this.Expression, context); if (contractResult != null) { return(contractResult); } TranslationResult constantResult = context.Process.ConstantsTranslator.TranslateIdentifierAsConstant(symbol, this.Expression); if (constantResult != null) { return(constantResult); } var errors = new List <Error>(); var container = this.Container.Translate(context); if (symbol.GetQualifiedName() == SeqTranslator.SeqLength) { errors.AddRange(container.Errors); return(TranslationResult.FromSilvernode( new AbsoluteValueSilvernode(container.Silvernode, this.OriginalNode), errors )); } if (symbol.GetQualifiedName() == ArraysTranslator.ArrayLength) { errors.AddRange(container.Errors); return(TranslationResult.FromSilvernode( new AbsoluteValueSilvernode(new SimpleSequenceSilvernode(null, container.Silvernode, ".", ArraysTranslator.IntegerArrayContents), this.OriginalNode), errors )); } // Normal case: Identifier lastIdentifier = context.Process.IdentifierTranslator.GetIdentifierReference(symbol); errors.AddRange(container.Errors); return(TranslationResult.FromSilvernode( new SimpleSequenceSilvernode(this.OriginalNode, container.Silvernode, ".", new IdentifierSilvernode(lastIdentifier, this.Expression.Name) ), errors )); // TODO (future) what if I access something on the result of a method, such as GetSomething().Hello? }
/// <summary> /// Translates a constant, given as an identifier or a member access, to Viper text. /// </summary> /// <param name="symbol">The Roslyn symbol that represents the constant.</param> /// <param name="syntaxNode">The Roslyn node that reads the constant.</param> /// <returns></returns> public TranslationResult TranslateIdentifierAsConstant(ISymbol symbol, SyntaxNode syntaxNode) { if (symbol is IFieldSymbol) { IFieldSymbol field = (IFieldSymbol)symbol; if (field.IsConst && field.HasConstantValue) { return (TranslationResult.FromSilvernode(new TextSilvernode(ConstantToString(field.ConstantValue), syntaxNode))); } } return(null); }
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)); }
public override TranslationResult Translate(TranslationContext context) { ISymbol symbol = GetIdentifierSymbol(context); // Special case translations first: TranslationResult contractResult = context.Process.ContractsTranslator.TranslateIdentifierAsContract(symbol, this.IdentifierName, context); if (contractResult != null) { return(contractResult); } TranslationResult constantResult = context.Process.ConstantsTranslator.TranslateIdentifierAsConstant(symbol, this.IdentifierName); if (constantResult != null) { return(constantResult); } // Normal translation: var identifierNode = new IdentifierSilvernode(context.Process.IdentifierTranslator.GetIdentifierReference(symbol)); if (symbol.ContainingSymbol.Kind == SymbolKind.Method) { return(TranslationResult.FromSilvernode(identifierNode)); } else if (symbol.ContainingSymbol.Kind == SymbolKind.NamedType) { return(TranslationResult.FromSilvernode(new SimpleSequenceSilvernode(this.OriginalNode, Constants.SilverThis, ".", identifierNode))); } else { return(TranslationResult.Error(this.OriginalNode, Diagnostics.SSIL108_FeatureNotSupported, "members of unnamed types")); } }
/// <summary> /// If the symbol corresponds to a known member of the <see cref="Contract"/> class, it is translated /// into Viper, otherwise null is returned. /// </summary> /// <param name="symbol">The C# symbol of a possible property of Contract.</param> /// <param name="originalNode">The Roslyn node that is being translated.</param> /// <param name="context">The context.</param> public TranslationResult TranslateIdentifierAsContract(ISymbol symbol, SyntaxNode originalNode, TranslationContext context) { string silvertext = null; switch (symbol.GetQualifiedName()) { case ContractTruth: silvertext = "true"; break; case ContractIntResult: silvertext = context.IsFunctionOrPredicateBlock ? "result" : Constants.SilverReturnVariableName; break; case PermissionNone: silvertext = "none"; break; case PermissionHalf: silvertext = "1/2"; break; case PermissionWildcard: silvertext = "wildcard"; break; case PermissionWrite: silvertext = "write"; break; } if (silvertext != null) { return(TranslationResult.FromSilvernode( new TextSilvernode(silvertext, originalNode) )); } return(null); }
/// <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); }