public override IPStmt VisitReceiveStmt(PParser.ReceiveStmtContext context) { if (machine?.IsSpec == true) { throw handler.IllegalMonitorOperation(context, context.RECEIVE().Symbol, machine); } var cases = new Dictionary <PEvent, Function>(); foreach (var caseContext in context.recvCase()) { var recvHandler = new Function(caseContext.anonEventHandler()) { Scope = table.MakeChildScope(), Owner = method.Owner, ParentFunction = method, Role = FunctionRole.ReceiveHandler }; if (caseContext.anonEventHandler().funParam() is PParser.FunParamContext param) { var paramVar = recvHandler.Scope.Put(param.name.GetText(), param, VariableRole.Param); paramVar.Type = TypeResolver.ResolveType(param.type(), recvHandler.Scope, handler); recvHandler.Signature.Parameters.Add(paramVar); } FunctionBodyVisitor.PopulateMethod(handler, recvHandler); foreach (var eventIdContext in caseContext.eventList().eventId()) { if (!table.Lookup(eventIdContext.GetText(), out PEvent pEvent)) { throw handler.MissingDeclaration(eventIdContext, "event", eventIdContext.GetText()); } if (cases.ContainsKey(pEvent)) { throw handler.DuplicateReceiveCase(eventIdContext, pEvent); } var expectedType = recvHandler.Signature.ParameterTypes.ElementAtOrDefault(0) ?? PrimitiveType.Null; if (!expectedType.IsAssignableFrom(pEvent.PayloadType)) { throw handler.TypeMismatch(caseContext.anonEventHandler(), expectedType, pEvent.PayloadType); } cases.Add(pEvent, recvHandler); } } method.CanReceive = true; return(new ReceiveStmt(context, cases)); }
public static Scope AnalyzeCompilationUnit(ITranslationErrorHandler handler, params PParser.ProgramContext[] programUnits) { // Step 1: Build the global scope of declarations var globalScope = BuildGlobalScope(handler, programUnits); // Step 2: Validate machine specifications foreach (var machine in globalScope.Machines) { MachineChecker.Validate(handler, machine); } // Step 3: Fill function bodies var allFunctions = globalScope.GetAllMethods().ToList(); foreach (var machineFunction in allFunctions) { FunctionBodyVisitor.PopulateMethod(handler, machineFunction); FunctionValidator.CheckAllPathsReturn(handler, machineFunction); } // Step 2: Validate no static handlers foreach (var machine in globalScope.Machines) { MachineChecker.ValidateNoStaticHandlers(handler, machine); } // Step 4: Propagate purity properties ApplyPropagations(allFunctions, CreatePropagation(fn => fn.CanRaiseEvent, (fn, value) => fn.CanRaiseEvent = value, true), CreatePropagation(fn => fn.CanReceive, (fn, value) => fn.CanReceive = value, true), CreatePropagation(fn => fn.CanChangeState, (fn, value) => fn.CanChangeState = value, true)); // Step 5: Verify capability restrictions foreach (var machineFunction in allFunctions) { // TODO: is this checked earlier? if (machineFunction.Owner?.IsSpec == true && machineFunction.IsNondeterministic == true) { throw handler.NonDeterministicFunctionInSpecMachine(machineFunction); } if ((machineFunction.CanChangeState == true || machineFunction.CanRaiseEvent == true) && (machineFunction.Role.HasFlag(FunctionRole.TransitionFunction) || machineFunction.Role.HasFlag(FunctionRole.ExitHandler))) { throw handler.ChangedStateMidTransition(machineFunction.SourceLocation, machineFunction); } } // Step 6: Check linear type ownership LinearTypeChecker.AnalyzeMethods(handler, allFunctions); // Step 7: Check control flow well-formedness ControlFlowChecker.AnalyzeMethods(handler, allFunctions); // Step 8: Infer the creates set for each machine. foreach (var machine in globalScope.Machines) { InferMachineCreates.Populate(machine, handler); } // Step 9: Fill the module expressions ModuleSystemDeclarations.PopulateAllModuleExprs(handler, globalScope); var moduleTypeChecker = new ModuleSystemTypeChecker(handler, globalScope); // Step 10: Check that all module expressions are well-formed foreach (var moduleExpr in AllModuleExprs(globalScope)) { moduleTypeChecker.CheckWellFormedness(moduleExpr); } // Step 11: Check the test and implementation declarations foreach (var impl in globalScope.Implementations) { moduleTypeChecker.CheckImplementationDecl(impl); } foreach (var test in globalScope.SafetyTests) { moduleTypeChecker.CheckSafetyTest(test); } foreach (var test in globalScope.RefinementTests) { moduleTypeChecker.CheckRefinementTest(test); } return(globalScope); }