Exemplo n.º 1
0
 public static string BusSignalToValidName(AST.Process process, AST.Signal signal)
 {
     return(ToValidName(signal.Name));
 }
Exemplo n.º 2
0
 public string Type(AST.Signal signal)
 {
     return(RS.TypeScope.GetType(signal).Name);
 }
Exemplo n.º 3
0
 /// <summary>
 /// Gets the Cpp type for the signal
 /// </summary>
 /// <returns>The cpp type.</returns>
 /// <param name="signal">The input signal.</param>
 public CppType GetType(AST.Signal signal)
 {
     return(GetType(signal.CecilType));
 }
Exemplo n.º 4
0
        /// <summary>
        /// Applies the transformation
        /// </summary>
        /// <returns>The transformed item.</returns>
        /// <param name="item">The item to visit.</param>
        public ASTItem Transform(ASTItem item)
        {
            if (!(item is AST.Method) || !((Method)item).IsStateMachine)
            {
                return(item);
            }

            var method = item as AST.Method;

            if (!method.All().OfType <AwaitExpression>().Any())
            {
                return(item);
            }

            var enumname = "FSM_" + method.Name + "_State";

            // Construct an enum type that matches the desired states
            var enumtype = new Mono.Cecil.TypeDefinition("", enumname, Mono.Cecil.TypeAttributes.Public | Mono.Cecil.TypeAttributes.AutoClass | Mono.Cecil.TypeAttributes.AnsiClass | Mono.Cecil.TypeAttributes.Sealed, method.SourceMethod.Module.ImportReference(typeof(System.Enum)))
            {
                IsSealed = true,
            };

            enumtype.DeclaringType = method.SourceMethod.DeclaringType;
            enumtype.Fields.Add(new Mono.Cecil.FieldDefinition($"value__", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.SpecialName | Mono.Cecil.FieldAttributes.RTSpecialName, method.SourceMethod.Module.ImportReference(typeof(int))));

            var statenametemplate = $"{enumtype.DeclaringType.FullName}_{enumname}_State";

            var fragments = SplitIntoFragments(method.Statements);

            var statecount = fragments.Count;
            var enumfields = new Mono.Cecil.FieldDefinition[statecount];

            // Add each of the states to the type
            for (var i = 0; i < statecount; i++)
            {
                enumtype.Fields.Add(enumfields[i] = new Mono.Cecil.FieldDefinition($"State{i}", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static | Mono.Cecil.FieldAttributes.Literal, enumtype)
                {
                    Constant = i
                });
            }

            // The variable being updated internally in the method
            var run_state_var = new AST.Variable("FSM_RunState", enumfields[0])
            {
                CecilType    = enumtype,
                DefaultValue = 0,
                Source       = new Mono.Cecil.ParameterDefinition("FSM_RunState", Mono.Cecil.ParameterAttributes.None, enumtype)
            };

            // The current state used in the state machine process
            var current_state_signal = new AST.Signal("FSM_CurrentState", enumfields[0])
            {
                CecilType    = enumtype,
                DefaultValue = 0,
                Source       = new Mono.Cecil.ParameterDefinition("FSM_CurrentState", Mono.Cecil.ParameterAttributes.None, enumtype)
            };

            // The next state that is propagated to
            var next_state_signal = new AST.Signal("FSM_NextState", enumfields[0])
            {
                CecilType    = enumtype,
                DefaultValue = 0,
                Source       = new Mono.Cecil.ParameterDefinition("FSM_NextState", Mono.Cecil.ParameterAttributes.None, enumtype)
            };

            // Construct a state-machine method, that will be rendered as a process
            var stateMachineProcess = new AST.Method()
            {
                Name           = "FSM_" + method.Name + "_Method",
                Parameters     = new AST.Parameter[0],
                ReturnVariable = null,
                Parent         = method.Parent,
                Variables      = method.AllVariables.Concat(new Variable[] { run_state_var }).ToArray(),
                AllVariables   = method.AllVariables.Concat(new Variable[] { }).ToArray(),
                IsStateMachine = true
            };

            var enumdataitems = enumfields.Select(x => new Constant(x.Name, x)
            {
                CecilType = enumtype
            }).ToArray();

            var isSimpleStatePossible = fragments.SelectMany(x => x.SelectMany(y => y.All().OfType <CaseGotoStatement>())).All(x => !x.FallThrough);

            List <Statement> cases;

            // If we have no fallthrough states, we build a switch
            if (isSimpleStatePossible)
            {
                cases = new List <Statement>(new[] {
                    new EmptyStatement(),
                    CreateSwitchStatement(fragments, current_state_signal, enumdataitems)
                });
            }
            // Otherwise, we build an if-based state machine
            else
            {
                cases = WrapFragmentsWithLabels(fragments, run_state_var, enumdataitems);
                cases.Insert(0, new ExpressionStatement(
                                 new AssignmentExpression(
                                     new IdentifierExpression(run_state_var),
                                     new IdentifierExpression(current_state_signal)
                                     )
                                 ));
            }

            stateMachineProcess.Statements = cases.ToArray();
            foreach (var v in stateMachineProcess.Statements)
            {
                v.Parent = stateMachineProcess;
                v.UpdateParents();
                ReplaceGotoWithVariables(v, run_state_var, next_state_signal, enumdataitems);
            }

            method.Statements = new Statement[] {
                new ExpressionStatement(
                    new AssignmentExpression(
                        new IdentifierExpression(current_state_signal),
                        new IdentifierExpression(next_state_signal)
                        )
                    )
                {
                    Parent = method
                }
            };

            method.IsStateMachine = false;


            var proc = method.GetNearestParent <Process>();

            proc.Methods = proc.Methods.Concat(new[] { stateMachineProcess }).ToArray();

            // Move variables into the shared area
            proc.InternalDataElements =
                proc.InternalDataElements
                .Union(new[] {
                current_state_signal,
                next_state_signal
            })
                //.Union(method.AllVariables)
                .ToArray();

            proc.SharedVariables = proc.SharedVariables.Union(method.AllVariables).ToArray();
            method.Variables     = new Variable[0];
            method.AllVariables  = new Variable[0];

            return(stateMachineProcess);
        }