public ArmadaSymbolTable(Program i_prog, ArmadaStructs i_structs) { prog = i_prog; globalVariables = new ArmadaGlobalVariableSymbolTable(); localVariables = new ArmadaMethodLocalVariableSymbolTable(); defaultClass = null; if (i_structs == null) { structs = new ArmadaStructs(null); } else { structs = i_structs; } threadRoutines = new HashSet <string> { "main" }; functionNames = new List <string> { }; nextRoutines = new List <NextRoutine>(); allMethodsInfo = new AllMethodsInfo(prog); tauNextRoutine = null; methodAndLabelToPCMap = new Dictionary <string, ArmadaPC>(); pcToLabelMap = new Dictionary <ArmadaPC, string>(); globalInvariants = new Dictionary <string, GlobalInvariantInfo>(); yieldPredicates = new Dictionary <string, YieldPredicateInfo>(); }
public void AddClass(ClassDecl c, bool fromStructsModule, ArmadaStructs structs) { if (c.IsDefaultClass) { defaultClass = c; globalVariables.AddClassInfo(prog, defaultClass, structs); foreach (MemberDecl member in defaultClass.Members) { if (member is Method) { var meth = (Method)member; localVariables.AddMethodInfo(prog, defaultClass, this, meth, fromStructsModule, structs); } else if (member is Function) { functionNames.Add(member.Name); } else if (member is GlobalInvariantDecl) { AddGlobalInvariant((GlobalInvariantDecl)member); } else if (member is YieldPredicateDecl) { AddYieldPredicate((YieldPredicateDecl)member); } else if (member is UniversalStepConstraintDecl) { AddUniversalStepConstraint((UniversalStepConstraintDecl)member); } } } }
public static bool IsValidType(Type type, ArmadaStructs structs) { if (type is PointerType pt) { return(IsValidHeapType(pt.Arg, structs)); // Pointer types are only valid if they point to heap types } else if (IsPrimitiveType(type)) { return(true); } else if (type is UserDefinedType ut) { return(true); } else if (type is SizedArrayType at) { return(IsValidType(at.Range, structs)); } else if (type is SeqType seqt) { return(IsValidType(seqt.Arg, structs)); } else if (type is SetType sett) { return(IsValidType(sett.Arg, structs)); } else if (type is MultiSetType mst) { return(IsValidType(mst.Arg, structs)); } else if (type is MapType mt) { return(IsValidType(mt.Domain, structs) && IsValidType(mt.Range, structs)); } else if (type is ArrowType arrowt) { return(arrowt.Args.All(subtype => IsValidType(subtype, structs)) && IsValidType(arrowt.Result, structs)); } else if (type == null) { return(false); } else { return(true); } }
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 void AddClassInfo(Program prog, ClassDecl c, ArmadaStructs structs) { 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 (!AH.IsValidType(f.Type, structs)) { AH.PrintError(prog, $"Global variable {f.Name} has invalid type {f.Type}"); av = null; } else 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 { if (AH.IsValidHeapType(f.Type, structs)) { av = new GlobalAddressableArmadaVariable(f.Name, f.Type, f.InitialValue); } else { AH.PrintError(prog, $"Global variable {f.Name} has type {f.Type} that can't be used on the heap. Consider making it noaddr or ghost."); av = null; } } table.Add(f.Name, av); } } }
public static bool IsValidHeapType(Type type, ArmadaStructs structs) { if (type is PointerType pt) { return(IsValidHeapType(pt.Arg, structs)); } else if (IsPrimitiveType(type)) { return(true); } else if (type is UserDefinedType ut) { return(structs.DoesStructExist(ut.Name)); // Datatypes aren't allowed on the heap, only structs } else if (type is SizedArrayType at) { return(IsValidHeapType(at.Range, structs)); } else { return(false); } }
private void ExtractLocalVariables(Program prog, Statement stmt, string methodName, ArmadaSingleMethodSymbolTable smst, ArmadaStructs structs) { if (stmt is BlockStmt) { var s = (BlockStmt)stmt; foreach (var substmt in s.Body) { ExtractLocalVariables(prog, substmt, methodName, smst, structs); } } else if (stmt is IfStmt) { var s = (IfStmt)stmt; ExtractLocalVariables(prog, s.Thn, methodName, smst, structs); ExtractLocalVariables(prog, s.Els, methodName, smst, structs); } else if (stmt is WhileStmt) { var s = (WhileStmt)stmt; ExtractLocalVariables(prog, s.Body, methodName, smst, structs); } else if (stmt is VarDeclStmt) { var s = (VarDeclStmt)stmt; UpdateStmt update = null; if (s.Update != null) { if (!(s.Update is UpdateStmt)) { AH.PrintError(prog, stmt.Tok, "Armada only supports *concrete* assignment of local variables during assignment."); return; } else { update = (UpdateStmt)s.Update; if (s.Locals.Count != update.Rhss.Count) { AH.PrintError(prog, s.Tok, $"Number of left-hand sides for assignment ({s.Locals.Count}) statement doesn't match number of right-hand sides ({update.Rhss.Count})."); return; } } } for (int i = 0; i < s.Locals.Count; ++i) { var local = s.Locals[i]; if (local.OptionalType is InferredTypeProxy) { AH.PrintError(prog, local.EndTok, "Local variables in Armada layer methods must be given explicit types."); continue; } Expression initialValue = null; if (update != null) { var rhs = update.Rhss[i]; if (rhs is HavocRhs) { // No need to do anything special here because in the absence of an initializer we already havoc } else if (rhs is ExprRhs) { var erhs = (ExprRhs)rhs; initialValue = erhs.Expr; } else if (rhs is CreateThreadRhs) { AH.PrintError(prog, rhs.Tok, "Create-thread can't be done in a variable-declaration statement"); continue; } else if (rhs is MallocRhs || rhs is CallocRhs) { AH.PrintError(prog, rhs.Tok, "Allocation can't be done in a variable-declaration statement"); continue; } else { AH.PrintError(prog, rhs.Tok, "Right-hand side of variable-declaration isn't a valid rvalue"); continue; } } if (!AH.IsValidType(local.OptionalType, structs)) { AH.PrintError(prog, stmt.Tok, $"Local variable {local.Name} in method {methodName} has invalid type {local.OptionalType}"); continue; } ArmadaVariable v; if (local.IsNoAddr) { v = new MethodStackFrameUnaddressableLocalArmadaVariable(local.Name, local.OptionalType, initialValue, ArmadaVarType.Local, methodName); } else { if (!AH.IsValidHeapType(local.OptionalType, structs)) { AH.PrintError(prog, stmt.Tok, $"Local variable {local.Name} in method {methodName} has type {local.OptionalType} that can't be used on the heap. Consider using noaddr instead."); continue; } v = new MethodStackFrameAddressableLocalArmadaVariable(local.Name, local.OptionalType, initialValue, s.BypassStoreBuffers, methodName); } smst.AddVariable(prog, v); } } }