Beispiel #1
0
        public ArmadaStruct(Program prog, ClassDecl c)
        {
            name       = c.Name;
            fieldTypes = new Dictionary <string, Type>();
            fieldNames = new List <string>();

            foreach (MemberDecl member in c.Members)
            {
                if (member is Field)
                {
                    var f = (Field)member;
                    if (!f.IsStatic)
                    {
                        fieldNames.Add(f.Name);
                        fieldTypes[f.Name] = f.Type;
                        if (f.InitialValue != null)
                        {
                            AH.PrintError(prog, $"Ignoring initializer {f.InitialValue} of field {f.Name} of struct {name}");
                        }
                    }
                    else
                    {
                        AH.PrintError(prog, $"Ignoring static field {f.Name} in struct");
                    }
                }
            }
        }
Beispiel #2
0
 public override void GenerateProof()
 {
     if (!CheckEquivalence())
     {
         AH.PrintError(pgp.prog, "Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the variable-hiding strategy");
         return;
     }
     GetWeakenedPCSet();
     AddIncludesAndImports();
     MakeTrivialPCMap();
     GenerateNextRoutineMap();
     GenerateProofHeader();
     GenerateStarWeakeningRequest();
     GenerateStateAbstractionFunctions_LH();
     GeneratePCFunctions_L();
     foreach (var globalVarName in strategy.GlobalVars)
     {
         GenerateNoStoreBufferEntriesLemmas(globalVarName);
     }
     GenerateConvertTraceEntry_LH();
     GenerateStepRefiner();
     GenerateLocalViewCommutativityLemmas();
     GenerateLiftNextLemmas();
     GenerateAllActionsLiftableWeakenedLemmas();
     GenerateInitStatesEquivalentLemma();
     GenerateIsInvariantPredicateLemma();
     GenerateFinalProof();
 }
        private string InsertExtraMaterial(string name, string contents, int minPos = 0)
        {
            // Remove any "ProofCustomizationGoesHere();" and note its position.

            int insertionPos = contents.IndexOf("ProofCustomizationGoesHere();", minPos);

            if (insertionPos >= 0)
            {
                contents = contents.Substring(0, insertionPos) + contents.Substring(insertionPos + 29);
            }

            if (extraMaterial.ContainsKey(name))
            {
                string extra = extraMaterial[name];

                // If there was no "ProofCustomizationGoesHere();", use the position right after the first open brace.

                if (insertionPos < 0)
                {
                    var bracePos = contents.IndexOf("{", minPos);
                    if (bracePos < 0)
                    {
                        AH.PrintError(prog, $"Could not find place in contents of {name} to insert extra material");
                        return(contents);
                    }
                    insertionPos = bracePos + 1;
                }

                return(contents.Substring(0, insertionPos) + "\n" + extra + "\n" + contents.Substring(insertionPos));
            }
            else
            {
                return(contents);
            }
        }
Beispiel #4
0
 public void AddClassInfo(Program prog, ClassDecl c)
 {
     if (!c.IsDefaultClass)
     {
         AH.PrintError(prog, "Internal error:  ArmadaGlobalVariableSymbolTable.AddClassInfo called on non-default class");
         return;
     }
     foreach (MemberDecl member in c.Members)
     {
         if (member is Field)
         {
             var f = (Field)member;
             variableNames.Add(f.Name);
             ArmadaVariable av = null;
             if (f.IsGhost)
             {
                 av = new GlobalGhostArmadaVariable(f.Name, f.Type, f.InitialValue);
             }
             else if (f.IsNoAddr)
             {
                 av = new GlobalUnaddressableArmadaVariable(f.Name, f.Type, f.InitialValue);
             }
             else
             {
                 av = new GlobalAddressableArmadaVariable(f.Name, f.Type, f.InitialValue);
             }
             table.Add(f.Name, av);
         }
     }
 }
Beispiel #5
0
        ////////////////////////////////////////////////////////////////////////
        /// Checking that the layers are similar enough to generate a proof
        ////////////////////////////////////////////////////////////////////////

        // We have to override the default implementation of CheckGlobalsEquivalence because we need to
        // skip hidden variables.

        protected override bool CheckGlobalsEquivalence()
        {
            var globalVarsLow  = pgp.symbolsLow.Globals.VariableNames.Where(s => !hiddenVariables.Contains(s)).ToArray();
            var globalVarsHigh = pgp.symbolsHigh.Globals.VariableNames.ToArray();

            if (globalVarsLow.Length != globalVarsHigh.Length)
            {
                AH.PrintError(pgp.prog, $"There are {globalVarsLow.Length} global variables in level {pgp.mLow.Name} (not counting hidden ones) but {globalVarsHigh.Length} in level {pgp.mHigh.Name}");
                return(false);
            }

            for (int i = 0; i < globalVarsLow.Length; ++i)
            {
                if (globalVarsLow[i] != globalVarsHigh[i])
                {
                    AH.PrintError(pgp.prog, $"Global variable number {i+1} (not counting hidden ones) in level {pgp.mLow.Name} is {globalVarsLow[i]}, which doesn't match global variable number {i+1} in level {pgp.mHigh.Name} which is {globalVarsHigh[i]}");
                    return(false);
                }
                var name = globalVarsLow[i];
                if (!CheckGlobalVariableEquivalence(name, pgp.symbolsLow.Globals.Lookup(name), pgp.symbolsHigh.Globals.Lookup(name)))
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #6
0
        public override void GenerateProof()
        {
            if (!CheckEquivalence())
            {
                AH.PrintError(pgp.prog, "Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the variable-hiding strategy");
                return;
            }
            AddIncludesAndImports();

            GeneratePCFunctions_L();
            MakeTrivialPCMap();
            GenerateNextRoutineMap();
            GenerateProofHeader();
            GenerateAtomicSpecs();
            GenerateInvariantProof(pgp);
            GenerateStateAbstractionFunctions_LH();
            GenerateConvertStep_LH();
            GenerateConvertAtomicPath_LH();
            GenerateLocalViewCommutativityLemmas();
            GenerateLiftingRelation();
            GenerateLiftAtomicPathLemmas();
            GenerateEstablishInitRequirementsLemma();
            GenerateEstablishStateOKRequirementLemma();
            GenerateEstablishRelationRequirementLemma();
            GenerateEstablishAtomicPathLiftableLemma();
            GenerateEstablishAtomicPathsLiftableLemma(false, false);
            GenerateLiftLAtomicToHAtomicLemma(false, false);
            GenerateFinalProof();
        }
Beispiel #7
0
        protected override void GenerateConvertGhosts_LH()
        {
            var ps = new List <string>();

            foreach (var varName in pgp.symbolsHigh.Globals.VariableNames)
            {
                var v = pgp.symbolsLow.Globals.Lookup(varName);
                if (v == null)
                {
                    v = pgp.symbolsHigh.Globals.Lookup(varName);
                    if (v is GlobalGhostArmadaVariable ghost)
                    {
                        var p = ResolveInit(ghost.initialValue);
                        if (p == null)
                        {
                            AH.PrintError(pgp.prog, $"Introduced ghost variable {varName} must be initialized");
                        }
                        ps.Add(p);
                    }
                }
                else if (v is GlobalGhostArmadaVariable)
                {
                    ps.Add($"ghosts.{v.FieldName}");
                }
            }
            var fn = $@"
        function ConvertGhosts_LH(ghosts: L.Armada_Ghosts) : H.Armada_Ghosts
        {{
          H.Armada_Ghosts({AH.CombineStringsWithCommas(ps)})
        }}
      ";

            pgp.AddFunction(fn, "convert");
        }
Beispiel #8
0
 public void Fail(IToken tok, string reason)
 {
     valid = false;
     if (reason != null)
     {
         AH.PrintError(prog, tok, reason);
     }
 }
Beispiel #9
0
 public void UseMethodAsThreadRoutine(string methodName)
 {
     if (allMethodsInfo.LookupMethod(methodName).AtomicCallsAndReturns)
     {
         AH.PrintError(prog, $"It's illegal to use create_thread on {methodName} since it uses atomic calls and returns.");
     }
     threadRoutines.Add(methodName);
 }
Beispiel #10
0
        public void AssociateLabelWithPC(string labelStr, ArmadaPC pc)
        {
            var fullLabelStr = pc.methodName + "_" + labelStr;

            if (methodAndLabelToPCMap.ContainsKey(fullLabelStr))
            {
                AH.PrintError(prog, $"ERROR:  More than one label named {labelStr} in method {pc.methodName}");
            }
            methodAndLabelToPCMap[fullLabelStr] = pc;
            pcToLabelMap[pc] = labelStr;
        }
Beispiel #11
0
        public StackVarIntroProofGenerator(ProofGenerationParams i_pgp, StackVariableIntroStrategyDecl i_strategy)
            : base(i_pgp, false)
        {
            strategy = i_strategy;
            var v = pgp.symbolsHigh.Lookup(strategy.MethodName, strategy.VariableName);

            if (!(v is MethodStackFrameUnaddressableLocalArmadaVariable))
            {
                AH.PrintError(pgp.prog, $"Variable {strategy.MethodName}.{strategy.VariableName} isn't a noaddr stack variable, but stack_var_intro can only introduce noaddr stack variables");
            }
        }
Beispiel #12
0
        public MethodInfo AddMethod(ArmadaSymbolTable symbols, Method method)
        {
            if (methodPCInfo.ContainsKey(method.Name))
            {
                AH.PrintError(prog, Token.NoToken, $"Attempt to add method {method.Name} twice to AllMethodsInfo");
                return(methodPCInfo[method.Name]);
            }
            var info = new MethodInfo(prog, symbols, method);

            methodPCInfo[method.Name] = info;
            return(info);
        }
Beispiel #13
0
 public Expression ReserveVariableName(string varName, Type ty)
 {
     if (variableUseCount.ContainsKey(varName))
     {
         AH.PrintError(prog, $"Internal error:  Attempt to reserve variable name that's already in use ({varName}).");
         return(null);
     }
     else
     {
         variableUseCount[varName] = 1;
         return(AH.MakeNameSegment(varName, ty));
     }
 }
Beispiel #14
0
        private void GenerateVarHidingPCMapForMethod(string methodName)
        {
            if (!pgp.symbolsHigh.DoesMethodNameExist(methodName))
            {
                AH.PrintError(pgp.prog, $"There's a method named {methodName} in the low level but not the high level.");
                return;
            }

            var bodyLow  = pgp.symbolsLow.AllMethods.LookupMethod(methodName).ParsedBody;
            var bodyHigh = pgp.symbolsHigh.AllMethods.LookupMethod(methodName).ParsedBody;

            GenerateVarHidingPCMapForBlocks(methodName, bodyLow, bodyHigh);
        }
Beispiel #15
0
 public string ReserveVariableName(string varName)
 {
     if (variableUseCount.ContainsKey(varName))
     {
         AH.PrintError(prog, $"Internal error:  Attempt to reserve variable name that's already in use ({varName}).");
         return(null);
     }
     else
     {
         variableUseCount[varName] = 1;
         return(varName);
     }
 }
Beispiel #16
0
        protected MatchCaseExpr GetTraceEntryCaseForUpdateToSomehowNextRoutine_LH(NextRoutine nextRoutine)
        {
            var highNextRoutine = nextRoutineMap[nextRoutine];
            var lowStmt         = (UpdateStmt)nextRoutine.armadaStatement.Stmt;
            var lowExprs        = lowStmt.Lhss;

            var highStmt  = (SomehowStmt)highNextRoutine.armadaStatement.Stmt;
            var highExprs = highStmt.Mod.Expressions;

            var pi = GetMatchingLowLevelLhssForHighLevelLhss(lowExprs, highExprs);

            var bvs = new List <BoundVar> {
                AH.MakeBoundVar("tid", "Armada_ThreadHandle")
            };

            bvs.AddRange(nextRoutine.Formals.Select(f => AH.MakeBoundVar(f.LocalVarName, AddModuleNameToArmadaType(f.VarType, "L"))));

            var ps = new List <Expression> {
                AH.MakeNameSegment("tid", "Armada_ThreadHandle")
            };

            ps.AddRange(nextRoutine.Formals.Select(f => AH.MakeNameSegment(f.LocalVarName, f.VarType))); // Use the tid (and any other) parameters from the bound vars in the case statement

            for (int i = 0; i < highExprs.Count; i++)
            {
                var context = new NormalResolutionContext(nextRoutine, pgp.symbolsLow);
                // Add the pi[i]'th rhs from the low-level update statement
                var        rhs = lowStmt.Rhss.ElementAt(pi[i]);
                Expression newRhs;
                if (rhs is ExprRhs)
                {
                    var erhs         = (ExprRhs)rhs;
                    var newRhsRValue = context.ResolveAsRValue(erhs.Expr);
                    newRhs = newRhsRValue.Val;
                }
                else
                {
                    AH.PrintError(pgp.prog, "Havoc RHS not yet supported");
                    return(null);
                }

                ps.Add(newRhs);
            }

            string nextRoutineName = nextRoutine.NameSuffix;
            string hname           = nextRoutineMap[nextRoutine].NameSuffix;
            var    case_body       = AH.MakeApplyN($"H.Armada_TraceEntry_{hname}", ps, "H.Armada_TraceEntry");
            var    case0           = AH.MakeMatchCaseExpr($"Armada_TraceEntry_{nextRoutineName}", bvs, case_body);

            return(case0);
        }
Beispiel #17
0
        protected override string GetStepCaseForNextRoutine_LH(NextRoutine nextRoutine)
        {
            var hNextRoutine = LiftNextRoutine(nextRoutine);

            if (hNextRoutine == null)
            {
                return(GetStepCaseForSuppressedNextRoutine_LH(nextRoutine));
            }

            if (hNextRoutine.nextType == NextType.Update &&
                nextRoutine.nextType == NextType.Update)
            {
                // e.g.  low-level: v_1 := e_1;
                //      high-level: v_1 := *
                //
                // Also low-level: v_1 ::= e_1;
                //      high-level: v_1 ::= *
                return(GetStepCaseForUpdateToUpdateNextRoutine_LH(nextRoutine));
            }
            else if ((hNextRoutine.nextType == NextType.IfTrue || hNextRoutine.nextType == NextType.IfFalse) &&
                     (nextRoutine.nextType == NextType.IfTrue || nextRoutine.nextType == NextType.IfFalse))
            {
                // e.g.  low-level: if p {}
                //      high-level: if * {}
                return(GetStepCaseForIfToIfNextRoutine_LH(nextRoutine));
            }
            else if (hNextRoutine.nextType == NextType.Somehow &&
                     nextRoutine.nextType == NextType.Update)
            {
                // low-level: v_1, ..., v_n ::= e_1, ..., e_n;
                // high-level: for some permutation pi \in S_n,
                // somehow modifies v_{pi_1}
                //         ...
                //         modifies v_{pi_n}
                //
                // In order for star weakening to be possible, it is necessary for a permutation as above to exist.
                // This can be made part of CheckEquivalence
                //
                // Then, the low level step of NextStep()
                // newval{j} is the non-det variable that holds the new value of v_{pi_j}. So,
                // the j'th value in the list of hstep params given in the constructor called by
                // ConvertStep_LH should be e_{pi_j}.
                return(GetStepCaseForUpdateToSomehowNextRoutine_LH(nextRoutine));
            }
            else if (hNextRoutine.nextType == nextRoutine.nextType)
            {
                return(GetStepCaseForNormalNextRoutine_LH(nextRoutine));
            }
            AH.PrintError(pgp.prog, "Invalid statement for weakening.");
            return(null);
        }
Beispiel #18
0
        public void AddTypeSynonym(string contents)
        {
            Match match = Regex.Match(contents, @"^\s*type\s+([^\s<(=]+)");

            if (match.Success)
            {
                string name = match.Groups[1].Value;
                AddTopLevelDecl((TypeSynonymDecl)AH.ParseTopLevelDecl(prog, name, contents));
            }
            else
            {
                AH.PrintError(prog, $"Could not find type synonym name in {contents}");
            }
        }
Beispiel #19
0
        public void AddFunction(string contents)
        {
            Match match = Regex.Match(contents, @"^\s*function\s+({[^}]*}\s*)*([^\s<(]+)");

            if (match.Success)
            {
                string name = match.Groups[2].Value;
                AddDefaultClassDecl((Function)AH.ParseTopLevelDecl(prog, name, contents));
            }
            else
            {
                AH.PrintError(prog, $"Could not find function name in {contents}");
            }
        }
Beispiel #20
0
        public string GetConstructorString(AtomicPath atomicPath)
        {
            if (atomicPath.NextRoutines.Where(r => r.HasFormals).Any())
            {
                // TODO: this does not work with introduced statements with *
                AH.PrintError(pgp.prog, "Armada currently doesn't support introducing a non-deterministic statement.");
            }

            var str = $"{prefix}_Path_{atomicPath.Name}({prefix}_PathSteps_{atomicPath.Name}(";

            str += String.Join(", ", atomicPath.NextRoutines.Select(r => $"{moduleName}.Armada_Step_{r.NameSuffix}()"));
            str += "))";
            return(str);
        }
        public void AddDatatype(string contents, string auxName = null)
        {
            Match match = Regex.Match(contents, @"^\s*datatype\s+([^\s<(]+)");

            if (match.Success)
            {
                string name = match.Groups[1].Value;
                AddTopLevelDecl((DatatypeDecl)AH.ParseTopLevelDecl(prog, name, contents), auxName);
            }
            else
            {
                AH.PrintError(prog, $"Could not find datatype name in {contents}");
            }
        }
Beispiel #22
0
 private void GetWeakenedPCSet()
 {
     foreach (var lbl in strategy.Labels)
     {
         var pc = pgp.symbolsLow.GetPCForMethodAndLabel(lbl.val);
         if (pc == null)
         {
             AH.PrintError(pgp.prog, $"Specified non-existent label {lbl.val} in star-weakening strategy description.  Remember to prefix label names with the method name and an underscore, e.g., use main_lb1 if you have label lb1: in method main.");
         }
         else
         {
             weakenedPCs.Add(pc);
         }
     }
 }
Beispiel #23
0
        public void AddPredicate(string contents)
        {
            Match match = Regex.Match(contents, @"^\s*predicate\s+({[^}]*}\s*)*([^\s<(]+)");

            if (match.Success)
            {
                string name = match.Groups[2].Value;
                AddDefaultClassDecl((Predicate)AH.ParseTopLevelDecl(prog, name, contents));
            }
            else
            {
                AH.PrintError(prog, $"Could not find predicate name in {contents}");
                return;
            }
        }
Beispiel #24
0
        public override void GenerateProof()
        {
            if (!CheckEquivalence())
            {
                AH.PrintError(pgp.prog, "Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the variable-hiding strategy");
                return;
            }

            AddIncludesAndImports();

            GenerateVarHidingPCMap();
            ExtendPCMapWithExternalAndStructsMethods();
            GenerateNextRoutineMap(false); // Don't warn on missing next routines, since some low-level routines don't map to high-level ones
            GenerateProofGivenMap();
        }
        public void AddLemma(string contents, string auxName = null)
        {
            Match match = Regex.Match(contents, @"^\s*lemma\s+([^\s<(]+)");

            if (match.Success)
            {
                string name             = match.Groups[1].Value;
                string expandedContents = InsertExtraMaterial(name, contents);
                AddDefaultClassDecl((Lemma)AH.ParseTopLevelDecl(prog, name, expandedContents), auxName);
            }
            else
            {
                AH.PrintError(prog, $"Could not find lemma name in {contents}");
            }
        }
Beispiel #26
0
        private bool GetLevelsAndStrategy()
        {
            foreach (var d in mProof.TopLevelDecls)
            {
                if (d is RefinementParametersDecl)
                {
                    var refinement = (RefinementParametersDecl)d;
                    if (mLow != null || mHigh != null)
                    {
                        AH.PrintError(prog, $"More than one 'refinement' declaration found in proof module {mProof.Name}");
                        return(false);
                    }
                    if (!LookupLevel(refinement.LowLevel, "low-level", out mLow))
                    {
                        return(false);
                    }
                    if (!LookupLevel(refinement.HighLevel, "high-level", out mHigh))
                    {
                        return(false);
                    }
                }
                else if (d is StrategyDecl)
                {
                    if (strategy != null)
                    {
                        AH.PrintError(prog, $"More than one strategy found in proof module {mProof.Name}");
                        return(false);
                    }
                    strategy = (StrategyDecl)d;
                }
            }

            if (mLow == null || mHigh == null)
            {
                AH.PrintError(prog, $"No 'refinement' declaration found in proof module {mProof.Name}");
                return(false);
            }
            if (strategy == null)
            {
                AH.PrintError(prog, $"No strategy given in proof module {mProof.Name}");
                return(false);
            }

            symbolsLow  = mLow.ModuleDef.ArmadaSymbols;
            symbolsHigh = mHigh.ModuleDef.ArmadaSymbols;

            return(true);
        }
Beispiel #27
0
        public StackVarHidingProofGenerator(ProofGenerationParams i_pgp, StackVariableHidingStrategyDecl i_strategy)
            : base(i_pgp, false)
        {
            strategy = i_strategy;
            hiddenVariablesMethodName = strategy.MethodName;
            hiddenVariables           = new HashSet <string>(strategy.Variables);

            foreach (var varName in strategy.Variables)
            {
                var v = pgp.symbolsLow.Lookup(hiddenVariablesMethodName, varName);
                if (!(v is MethodStackFrameUnaddressableLocalArmadaVariable))
                {
                    AH.PrintError(pgp.prog, $"Variable {hiddenVariablesMethodName}.{varName} isn't a noaddr stack variable, but stack_var_hiding can only hide noaddr stack variables");
                }
            }
        }
Beispiel #28
0
        public override void GenerateProof()
        {
            if (!CheckEquivalence())
            {
                AH.PrintError(pgp.prog, $"Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the combining strategy");
                return;
            }

            if (!MakePCMap())
            {
                return;
            }

            AddIncludesAndImports();
            GenerateProofGivenMap();
        }
Beispiel #29
0
        public void AddMethodInfo(Program prog, ClassDecl c, ArmadaSymbolTable symbols, Method meth, bool fromStructsModule,
                                  ArmadaStructs structs)
        {
            bool isExternal = (meth.Body is null || Attributes.Contains(meth.Attributes, "extern"));

            var smst = new ArmadaSingleMethodSymbolTable(meth, isExternal, fromStructsModule);

            foreach (var formal in meth.Ins)
            {
                var v = new MethodStackFrameUnaddressableLocalArmadaVariable(formal.Name, formal.Type, null, ArmadaVarType.Input, meth.Name);
                smst.AddVariable(prog, v);
            }

            foreach (var formal in meth.Outs)
            {
                var v = new MethodStackFrameUnaddressableLocalArmadaVariable(formal.Name, formal.Type, null, ArmadaVarType.Output, meth.Name);
                smst.AddVariable(prog, v);
            }

            ExtractLocalVariables(prog, meth.Body, meth.Name, smst, structs);

            if (isExternal && meth.Reads.Expressions != null)
            {
                var reads = meth.Reads.Expressions;
                for (int i = 0; i < reads.Count; ++i)
                {
                    Expression read_expr = reads.ElementAt(i);
                    var        varName   = $"Armada_Extern{i}";
                    var        v         = new MethodStackFrameUnaddressableLocalArmadaVariable(varName, read_expr.Type, null, ArmadaVarType.ExternRead, meth.Name);
                    smst.AddVariable(prog, v);
                }
            }

            if (methodTable.ContainsKey(meth.Name))
            {
                AH.PrintError(prog, $"Method {meth.Name} already defined");
            }
            else
            {
                methodTable[meth.Name] = smst;
            }

            if (isExternal && meth.Body == null)
            {
                ExtractOldVariablesForBodylessMethod(prog, symbols, meth, smst);
            }
        }
Beispiel #30
0
        public ProofFile CreateAuxiliaryProofFile(string auxName, bool includeImportedFiles = true)
        {
            if (auxiliaryProofs.ContainsKey(auxName))
            {
                AH.PrintError(prog, Token.NoToken, $"Attempt to create an auxiliary proof file with an already-existing name ({auxName})");
                return(null);
            }

            var proof = new ProofFile(name, auxName, includeImportedFiles);

            if (pg != null)
            {
                pg.AddCommonHeaderElements(proof);
            }
            auxiliaryProofs[auxName] = proof;
            return(proof);
        }