Пример #1
0
        private static State FindStartState(Machine machine, ITranslationErrorHandler handler)
        {
            var foundStartState = false;

            foreach (State state in machine.AllStates())
            {
                if (state == machine.StartState || state.IsStart)
                {
                    if (!foundStartState)
                    {
                        foundStartState = true;
                    }
                    else
                    {
                        throw handler.InternalError(state.SourceLocation,
                                                    $"Two start states {state.Name} occurs twice in all states list");
                    }
                }
            }

            if (foundStartState && machine.StartState == null)
            {
                throw handler.InternalError(machine.SourceLocation, "machine has unregistered start state");
            }

            if (!foundStartState || machine.StartState == null)
            {
                // Allow machines with no start state so long as there are no other states.
                throw handler.MissingStartState(machine);
            }

            return(machine.StartState);
        }
Пример #2
0
            public override PLanguageType VisitNamedType(PParser.NamedTypeContext context)
            {
                string typeName = context.name.GetText();

                if (scope.Lookup(typeName, out PEnum pEnum))
                {
                    return(new EnumType(pEnum));
                }

                if (scope.Lookup(typeName, out TypeDef typeDef))
                {
                    if (visitedTypeDefs.Contains(typeDef))
                    {
                        throw handler.CircularTypeDef(context.name, typeDef);
                    }

                    if (typeDef.Type == null)
                    {
                        visitedTypeDefs.Push(typeDef);
                        switch (typeDef.SourceLocation)
                        {
                        case PParser.ForeignTypeDefContext foreignType:
                            typeDef.Type = new ForeignType(foreignType.name.GetText());
                            break;

                        case PParser.PTypeDefContext typedefDecl:
                            typeDef.Type = Visit(typedefDecl.type());
                            break;

                        case InterpreterRuleContext _:
                        case RuleContextWithAltNum _:
                        default:
                            throw handler.InternalError(typeDef.SourceLocation,
                                                        new ArgumentOutOfRangeException(nameof(context)));
                        }
                        visitedTypeDefs.Pop();
                    }

                    return(new TypeDefType(typeDef));
                }

                if (scope.Lookup(typeName, out NamedEventSet eventSet))
                {
                    return(new PermissionType(eventSet));
                }

                if (scope.Lookup(typeName, out Interface pInterface))
                {
                    return(new PermissionType(pInterface));
                }

                if (scope.Lookup(typeName, out Machine machine))
                {
                    return(new PermissionType(machine));
                }

                throw handler.MissingDeclaration(context.name, "enum, typedef, event set, machine, or interface",
                                                 typeName);
            }
Пример #3
0
        public override IPExpr VisitKeywordExpr(PParser.KeywordExprContext context)
        {
            switch (context.fun.Text)
            {
            case "keys":
            {
                IPExpr expr = Visit(context.expr());
                if (!(expr.Type.Canonicalize() is MapType mapType))
                {
                    throw handler.TypeMismatch(expr, TypeKind.Map);
                }

                return(new KeysExpr(context, expr, new SequenceType(mapType.KeyType)));
            }

            case "values":
            {
                IPExpr expr = Visit(context.expr());
                if (!(expr.Type.Canonicalize() is MapType mapType))
                {
                    throw handler.TypeMismatch(expr, TypeKind.Map);
                }

                return(new ValuesExpr(context, expr, new SequenceType(mapType.ValueType)));
            }

            case "sizeof":
            {
                var expr = Visit(context.expr());
                if (!(expr.Type.Canonicalize() is SequenceType) &&
                    !(expr.Type.Canonicalize() is MapType) &&
                    !(expr.Type.Canonicalize() is SetType))
                {
                    throw handler.TypeMismatch(expr, TypeKind.Map, TypeKind.Sequence, TypeKind.Set);
                }
                return(new SizeofExpr(context, expr));
            }

            case "default":
            {
                PLanguageType type = TypeResolver.ResolveType(context.type(), table, handler);
                return(new DefaultExpr(context, type.Canonicalize()));
            }

            default:
            {
                throw handler.InternalError(context,
                                            new ArgumentException($"Unknown keyword expression {context.fun.Text}", nameof(context)));
            }
            }
        }
Пример #4
0
        public void CheckWellFormedness(IPModuleExpr moduleExpr)
        {
            switch (moduleExpr)
            {
            case AssertModuleExpr assertExpr:
                CheckWellFormedness(assertExpr);
                break;

            case BindModuleExpr bindExpr:
                CheckWellFormedness(bindExpr);
                break;

            case RenameModuleExpr renameExpr:
                CheckWellFormedness(renameExpr);
                break;

            case UnionOrComposeModuleExpr uOrCExpr:
                CheckWellFormedness(uOrCExpr);
                break;

            case HideEventModuleExpr hideEExpr:
                CheckWellFormedness(hideEExpr);
                break;

            case HideInterfaceModuleExpr hideIExpr:
                CheckWellFormedness(hideIExpr);
                break;

            default:
                throw handler.InternalError(moduleExpr.SourceLocation,
                                            new ArgumentOutOfRangeException(nameof(moduleExpr)));
            }
        }
Пример #5
0
            public override PLanguageType VisitNamedType(PParser.NamedTypeContext context)
            {
                string typeName = context.name.GetText();

                if (scope.Lookup(typeName, out PEnum pEnum))
                {
                    return(new EnumType(pEnum));
                }

                if (scope.Lookup(typeName, out TypeDef typeDef))
                {
                    if (visitedTypeDefs.Contains(typeDef))
                    {
                        throw handler.CircularTypeDef(context.name, typeDef);
                    }

                    if (typeDef.Type == null)
                    {
                        visitedTypeDefs.Add(typeDef);
                        switch (typeDef.SourceLocation)
                        {
                        case PParser.ForeignTypeDefContext foreignType:
                            typeDef.Type = new ForeignType(foreignType.name.GetText());
                            break;

                        case PParser.PTypeDefContext typedefDecl:
                            typeDef.Type = Visit(typedefDecl.type());
                            break;

                        default:
                            throw handler.InternalError(typeDef.SourceLocation,
                                                        $"Grammar changed without updating {nameof(TypeVisitor)}");
                        }
                    }

                    return(new TypeDefType(typeDef));
                }

                if (scope.Lookup(typeName, out NamedEventSet eventSet))
                {
                    return(new PermissionType(eventSet));
                }

                if (scope.Lookup(typeName, out Interface pInterface))
                {
                    return(new PermissionType(pInterface));
                }

                if (scope.Lookup(typeName, out Machine machine))
                {
                    return(new PermissionType(machine));
                }

                throw handler.MissingDeclaration(context.name, "enum, typedef, event set, machine, or interface", typeName);
            }
Пример #6
0
        public static void ValidateNoStaticHandlers(ITranslationErrorHandler handler, Machine machine)
        {
            foreach (State state in machine.AllStates())
            {
                bool illegalUsage = state.Entry != null && IsStaticOrForeign(state.Entry);
                if (illegalUsage)
                {
                    throw handler.StaticFunctionNotAllowedAsHandler(state.SourceLocation,
                                                                    state.Entry.Name);
                }

                illegalUsage = state.Exit != null && IsStaticOrForeign(state.Exit);
                if (illegalUsage)
                {
                    throw handler.StaticFunctionNotAllowedAsHandler(state.SourceLocation,
                                                                    state.Exit.Name);
                }

                foreach (KeyValuePair <PEvent, AST.IStateAction> pair in state.AllEventHandlers)
                {
                    switch (pair.Value)
                    {
                    case EventDoAction eventDoAction:
                        if (eventDoAction.Target != null && IsStaticOrForeign(eventDoAction.Target))
                        {
                            throw handler.StaticFunctionNotAllowedAsHandler(eventDoAction.SourceLocation,
                                                                            eventDoAction.Target.Name);
                        }

                        break;

                    case EventGotoState eventGotoState:
                        if (eventGotoState.TransitionFunction != null &&
                            IsStaticOrForeign(eventGotoState.TransitionFunction))
                        {
                            throw handler.StaticFunctionNotAllowedAsHandler(eventGotoState.SourceLocation,
                                                                            eventGotoState.TransitionFunction.Name);
                        }

                        break;

                    case EventDefer _:
                    case EventIgnore _:
                    case EventPushState _:
                        break;

                    default:
                        throw handler.InternalError(pair.Value.SourceLocation,
                                                    new System.Exception("Unknown transition type parsed, report to the P team"));
                    }
                }
            }
        }
Пример #7
0
 private static PLanguageType GetStatePayload(State startState, ITranslationErrorHandler handler)
 {
     if (!(startState.Entry?.Signature.Parameters.Count > 0))
     {
         return(PrimitiveType.Null);
     }
     if (startState.Entry.Signature.Parameters.Count != 1)
     {
         throw handler.InternalError(startState.OwningMachine.SourceLocation,
                                     "Allowed start state entry with multiple parameters");
     }
     return(startState.Entry.Signature.Parameters[0].Type);
 }
Пример #8
0
        public override IPStmt VisitAssignStmt(PParser.AssignStmtContext context)
        {
            IPExpr variable = exprVisitor.Visit(context.lvalue());
            IPExpr value    = exprVisitor.Visit(context.rvalue());

            // If we're doing a move/swap assignment
            if (value is ILinearRef linearRef)
            {
                Variable refVariable = linearRef.Variable;
                switch (linearRef.LinearType)
                {
                case LinearType.Move:
                    // Moved values must be subtypes of their destinations
                    if (!variable.Type.IsAssignableFrom(refVariable.Type))
                    {
                        throw handler.TypeMismatch(context.rvalue(), refVariable.Type, variable.Type);
                    }

                    return(new MoveAssignStmt(context, variable, refVariable));

                case LinearType.Swap:
                    // Within a function, swaps must only be subtyped in either direction
                    // the actual types are checked at runtime. This is to allow swapping
                    // with the `any` type.
                    if (!variable.Type.IsAssignableFrom(refVariable.Type) &&
                        !refVariable.Type.IsAssignableFrom(variable.Type))
                    {
                        throw handler.TypeMismatch(context.rvalue(), refVariable.Type, variable.Type);
                    }

                    return(new SwapAssignStmt(context, variable, refVariable));

                default:
                    throw handler.InternalError(linearRef.SourceLocation,
                                                new ArgumentOutOfRangeException(nameof(context)));
                }
            }

            // If this is a value assignment, we just need subtyping
            if (!variable.Type.IsAssignableFrom(value.Type))
            {
                throw handler.TypeMismatch(context.rvalue(), value.Type, variable.Type);
            }

            return(new AssignStmt(context, variable, value));
        }
Пример #9
0
        private static void ValidateEventPayloadToTransitionTarget(ITranslationErrorHandler handler,
                                                                   ParserRuleContext sourceLocation,
                                                                   PLanguageType eventPayloadType,
                                                                   Function targetFunction)
        {
            IReadOnlyList <PLanguageType> entrySignature = targetFunction.Signature.ParameterTypes.ToList();

            if (entrySignature.Count == 0)
            {
                return;
            }

            if (entrySignature.Count > 1)
            {
                throw handler.InternalError(sourceLocation, new System.Exception("Target function cannot have multiple parameters (report this to the P developers)"));
            }

            if (entrySignature.Count == 1 && entrySignature[0].IsAssignableFrom(eventPayloadType))
            {
                return;
            }

            if (entrySignature.Count == 1 && eventPayloadType.Canonicalize() is TupleType tuple &&
                tuple.Types.Count == 1 && entrySignature[0].IsAssignableFrom(tuple.Types[0]))
            {
                return;
            }

            if (entrySignature.Count == 1)
            {
                throw handler.TypeMismatch(sourceLocation, eventPayloadType, entrySignature[0]);
            }

            PLanguageType entrySignatureType = new TupleType(entrySignature.ToArray());

            if (!entrySignatureType.IsAssignableFrom(eventPayloadType))
            {
                throw handler.TypeMismatch(sourceLocation, eventPayloadType, entrySignatureType);
            }
        }
Пример #10
0
        public static void ValidateMachine(ITranslationErrorHandler handler, Machine machine)
        {
            State         startState            = FindStartState(machine, handler);
            PLanguageType startStatePayloadType = GetStatePayload(startState, handler);

            if (!startStatePayloadType.IsSameTypeAs(machine.PayloadType))
            {
                throw handler.InternalError(machine.SourceLocation,
                                            "machine payload type is not the same as start state's entry payload type");
            }

            foreach (Interface machineInterface in machine.Interfaces)
            {
                if (!machine.PayloadType.IsAssignableFrom(machineInterface.PayloadType))
                {
                    // TODO: add special "invalid machine interface" error
                    throw handler.TypeMismatch(machine.StartState.Entry?.SourceLocation ?? machine.SourceLocation,
                                               machine.PayloadType,
                                               machineInterface.PayloadType);
                }
            }
        }
Пример #11
0
        private ISet <Variable> ProcessStatement(ISet <Variable> unavailable, IPStmt statement)
        {
            Contract.Requires(statement != null);
            switch (statement)
            {
            case CompoundStmt compoundStmt:
                unavailable = compoundStmt.Statements.Aggregate(unavailable, ProcessStatement);
                break;

            case AssertStmt assertStmt:
                unavailable = ProcessExpr(unavailable, assertStmt.Assertion);
                break;

            case PrintStmt printStmt:
                unavailable = ProcessArgList(printStmt.Args, unavailable, ArgOptions.SwapNotAllowed);
                break;

            case ReturnStmt returnStmt:
                if (returnStmt.ReturnValue != null)
                {
                    unavailable = ProcessExpr(unavailable, returnStmt.ReturnValue);
                }

                break;

            case AssignStmt assignStmt:
                unavailable = ProcessExpr(unavailable, assignStmt.Value);
                if (assignStmt.Location is VariableAccessExpr assignAccess)
                {
                    unavailable.Remove(assignAccess.Variable);
                }
                else
                {
                    unavailable = ProcessExpr(unavailable, assignStmt.Location);
                }

                break;

            case MoveAssignStmt moveAssignStmt:
                if (moveAssignStmt.FromVariable.Role.Equals(VariableRole.Field))
                {
                    throw handler.MovedField(moveAssignStmt);
                }

                unavailable.Add(moveAssignStmt.FromVariable);

                if (moveAssignStmt.ToLocation is VariableAccessExpr moveAssignAccess)
                {
                    unavailable.Remove(moveAssignAccess.Variable);
                }
                else
                {
                    unavailable = ProcessExpr(unavailable, moveAssignStmt.ToLocation);
                }

                break;

            case SwapAssignStmt swapAssignStmt:
                if (swapAssignStmt.NewLocation is VariableAccessExpr swapAssignAccess)
                {
                    if (unavailable.Contains(swapAssignAccess.Variable))
                    {
                        throw handler.SwapAssignUnavailable(swapAssignStmt, swapAssignAccess.Variable);
                    }
                }
                else
                {
                    unavailable = ProcessExpr(unavailable, swapAssignStmt.NewLocation);
                }

                if (unavailable.Contains(swapAssignStmt.OldLocation))
                {
                    throw handler.SwapAssignUnavailable(swapAssignStmt, swapAssignStmt.OldLocation);
                }

                break;

            case InsertStmt insertStmt:
                unavailable = ProcessExpr(unavailable, insertStmt.Variable);
                unavailable = ProcessExpr(unavailable, insertStmt.Index);
                unavailable = ProcessExpr(unavailable, insertStmt.Value);
                break;

            case RemoveStmt removeStmt:
                unavailable = ProcessExpr(unavailable, removeStmt.Variable);
                unavailable = ProcessExpr(unavailable, removeStmt.Value);
                break;

            case WhileStmt whileStmt:
                unavailable = ProcessExpr(unavailable, whileStmt.Condition);
                // process running the body twice. on the first go, the loop can potentially
                // relinquish additional variables on the second go, either the body will use
                // one of these variables and throw or reach a fixed point since all paths are
                // considered simultaneously. Then, we continue our overapproximation by taking
                // the union of no runs and one or more runs.
                var bodyUnavailable =
                    ProcessStatement(new HashSet <Variable>(unavailable), whileStmt.Body);
                bodyUnavailable = ProcessExpr(bodyUnavailable, whileStmt.Condition);
                // TODO: more efficient way of doing this?
                bodyUnavailable = ProcessStatement(bodyUnavailable, whileStmt.Body);
                bodyUnavailable = ProcessExpr(bodyUnavailable, whileStmt.Condition);
                unavailable.UnionWith(bodyUnavailable);
                break;

            case IfStmt ifStmt:
                unavailable = ProcessExpr(unavailable, ifStmt.Condition);
                var thenUnavailable =
                    ProcessStatement(new HashSet <Variable>(unavailable), ifStmt.ThenBranch);
                var elseUnavailable =
                    ProcessStatement(new HashSet <Variable>(unavailable), ifStmt.ElseBranch);
                thenUnavailable.UnionWith(elseUnavailable);
                unavailable = thenUnavailable;
                break;

            case CtorStmt ctorStmt:
                unavailable = ProcessArgList(ctorStmt.Arguments, unavailable, ArgOptions.SwapNotAllowed);
                break;

            case FunCallStmt funCallStmt:
                unavailable = ProcessArgList(funCallStmt.ArgsList, unavailable);
                funCallStmts.Add(funCallStmt);
                break;

            case RaiseStmt raiseStmt:
                unavailable = ProcessExpr(unavailable, raiseStmt.PEvent);
                unavailable = ProcessArgList(raiseStmt.Payload, unavailable, ArgOptions.SwapNotAllowed);
                break;

            case SendStmt sendStmt:
                unavailable = ProcessExpr(unavailable, sendStmt.MachineExpr);
                unavailable = ProcessExpr(unavailable, sendStmt.Evt);
                unavailable = ProcessArgList(sendStmt.Arguments, unavailable, ArgOptions.SwapNotAllowed);
                break;

            case AnnounceStmt announceStmt:
                unavailable = ProcessExpr(unavailable, announceStmt.PEvent);
                if (announceStmt.Payload != null)
                {
                    unavailable = ProcessExpr(unavailable, announceStmt.Payload);
                }

                break;

            case GotoStmt gotoStmt:
                if (gotoStmt.Payload != null)
                {
                    unavailable = ProcessExpr(unavailable, gotoStmt.Payload);
                }

                break;

            case ReceiveStmt receiveStmt:
                var postUnavailable = new HashSet <Variable>();
                var caseVariables   = new HashSet <Variable>();
                foreach (var recvCase in receiveStmt.Cases)
                {
                    var caseUnavailable =
                        ProcessStatement(new HashSet <Variable>(unavailable), recvCase.Value.Body);
                    postUnavailable.UnionWith(caseUnavailable);
                    caseVariables.UnionWith(recvCase.Value.Signature.Parameters);
                }

                unavailable = postUnavailable;
                unavailable.ExceptWith(caseVariables);
                break;

            case PopStmt _:
            case NoStmt _:
                // nothing to check
                break;

            default:
                throw handler.InternalError(statement.SourceLocation,
                                            new ArgumentOutOfRangeException(nameof(statement)));
            }

            return(unavailable);
        }
Пример #12
0
        private static IEnumerable <Interface> InferCreates(IPAST tree, ITranslationErrorHandler handler)
        {
            switch (tree)
            {
            case Function function:
                if (function.IsForeign)
                {
                    return(function.CreatesInterfaces);
                }

                return(InferCreates(function.Body, handler));

            case AddStmt addStmt:
                return(InferCreatesForExpr(addStmt.Variable, handler)
                       .Union(InferCreatesForExpr(addStmt.Value, handler)));

            case AnnounceStmt announce:
                return(InferCreatesForExpr(announce.PEvent, handler)
                       .Union(InferCreatesForExpr(announce.Payload, handler)));

            case AssertStmt assertStmt:
                return(InferCreatesForExpr(assertStmt.Assertion, handler));

            case AssignStmt assignStmt:
                return(InferCreatesForExpr(assignStmt.Location, handler)
                       .Union(InferCreatesForExpr(assignStmt.Value, handler)));

            case CompoundStmt compoundStmt:
                return(compoundStmt.Statements.SelectMany(tree1 => InferCreates(tree1, handler)));

            case CtorStmt ctorStmt:
                Interface[] res = new[] { ctorStmt.Interface };
                return(res.Union(ctorStmt.Arguments.SelectMany(expr => InferCreatesForExpr(expr, handler))));

            case FunCallStmt funCallStmt:
                return(InferCreates(funCallStmt.Function, handler)
                       .Union(funCallStmt.ArgsList.SelectMany(expr => InferCreatesForExpr(expr, handler))));

            case GotoStmt gotoStmt:
                return(InferCreatesForExpr(gotoStmt.Payload, handler));

            case IfStmt ifStmt:
                return(InferCreatesForExpr(ifStmt.Condition, handler)
                       .Union(InferCreates(ifStmt.ThenBranch, handler))
                       .Union(InferCreates(ifStmt.ElseBranch, handler)));

            case InsertStmt insertStmt:
                return(InferCreatesForExpr(insertStmt.Variable, handler)
                       .Union(InferCreatesForExpr(insertStmt.Index, handler))
                       .Union(InferCreatesForExpr(insertStmt.Value, handler)));

            case MoveAssignStmt moveAssignStmt:
                return(InferCreatesForExpr(moveAssignStmt.ToLocation, handler));

            case NoStmt _:
                return(Enumerable.Empty <Interface>());

            case PopStmt _:
                return(Enumerable.Empty <Interface>());

            case PrintStmt printStmt:
                return(printStmt.Args.SelectMany(expr => InferCreatesForExpr(expr, handler)));

            case RaiseStmt raiseStmt:
                return(InferCreatesForExpr(raiseStmt.PEvent, handler)
                       .Union(raiseStmt.Payload.SelectMany(expr => InferCreatesForExpr(expr, handler))));

            case ReceiveStmt receiveStmt:
                return(receiveStmt.Cases.SelectMany(x => InferCreates(x.Value, handler)));

            case RemoveStmt removeStmt:
                return(InferCreatesForExpr(removeStmt.Variable, handler)
                       .Union(InferCreatesForExpr(removeStmt.Value, handler)));

            case ReturnStmt returnStmt:
                return(InferCreatesForExpr(returnStmt.ReturnValue, handler));

            case StringAssignStmt stringAssignStmt:
                return(InferCreatesForExpr(stringAssignStmt.Location, handler)
                       .Union(stringAssignStmt.Args.SelectMany(expr => InferCreatesForExpr(expr, handler))));

            case BreakStmt breakStmt:
                return(Enumerable.Empty <Interface>());

            case ContinueStmt continueStmt:
                return(Enumerable.Empty <Interface>());

            case SendStmt sendStmt:
                return(InferCreatesForExpr(sendStmt.MachineExpr, handler)
                       .Union(InferCreatesForExpr(sendStmt.Evt, handler))
                       .Union(sendStmt.Arguments.SelectMany(expr => InferCreatesForExpr(expr, handler))));

            case SwapAssignStmt swapAssignStmt:
                return(InferCreatesForExpr(swapAssignStmt.NewLocation, handler));

            case WhileStmt whileStmt:
                return(InferCreatesForExpr(whileStmt.Condition, handler)
                       .Union(InferCreates(whileStmt.Body, handler)));

            default:
                throw handler.InternalError(tree.SourceLocation, new ArgumentOutOfRangeException(nameof(tree)));
            }
        }