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"); } } } }
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); } }
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); } } }
//////////////////////////////////////////////////////////////////////// /// 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); }
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(); }
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"); }
public void Fail(IToken tok, string reason) { valid = false; if (reason != null) { AH.PrintError(prog, tok, reason); } }
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); }
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; }
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"); } }
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); }
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)); } }
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); }
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); } }
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); }
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); }
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}"); } }
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}"); } }
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}"); } }
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); } } }
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; } }
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}"); } }
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); }
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"); } } }
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(); }
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); } }
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); }