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); } } }
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); } } }