Пример #1
0
        /// <summary>
        /// Runs the validator and loads all busses
        /// </summary>
        /// <param name="state">The state to examine</param>
        public void Validate(ValidationState state)
        {
            foreach (var busitem in state.Modules.SelectMany(x => x.Value.All().OfType <AST.BusDeclaration>()))
            {
                var bus   = busitem.Current;
                var scope = state.FindScopeForItem(busitem);

                // Resolve signals from the typename
                if (bus.Signals == null)
                {
                    var signalsource = state.ResolveTypeName(bus.TypeName, scope);
                    var signaldef    = (AST.TypeDefinition)state.FindTypeDefinition(bus.TypeName.Alias, scope);

                    if (!signalsource.IsBus)
                    {
                        throw new ParserException($"The typename {bus.TypeName.Alias} resolves to {signalsource.Type} but a bus type is required", bus.TypeName);
                    }
                    bus.Signals = signalsource.Shape.Signals.Select(x => new AST.BusSignalDeclaration(
                                                                        bus.TypeName.SourceToken,
                                                                        new AST.Identifier(new ParseToken(0, 0, 0, x.Key)),
                                                                        x.Value.Type,
                                                                        signaldef.Initializers[x.Key],
                                                                        x.Value.Direction
                                                                        )).ToArray();
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Loads the module and its imports
        /// </summary>
        /// <param name="file">The main module</param>
        /// <param name="toplevel">The top-level network or null</param>
        /// <returns>The state for the loaded modules</returns>
        public static Validation.ValidationState LoadModuleAndImports(string file, string toplevel, string[] arguments)
        {
            // Basic setup
            var state     = new Validation.ValidationState();
            var rootscope = state.CurrentScope;
            var toResolve = new Stack <AST.Module>();

            state.TopLevel.Module         = LoadModule(file);
            state.TopLevel.ModuleInstance = new Instance.Module(state.TopLevel.Module);

            // Find the entry network
            var networks = state.TopLevel.Module.Entities.OfType <AST.Network>().ToList();

            if (string.IsNullOrWhiteSpace(toplevel))
            {
                if (networks.Count == 0)
                {
                    throw new ArgumentException("The main module contains no networks?");
                }
                if (networks.Count != 1)
                {
                    throw new ArgumentException($"The main module contains {networks.Count} networks, please specify a network name");
                }
                state.TopLevel.SourceNetwork = networks.First();
            }
            else
            {
                var namednetworks = networks.Where(x => string.Equals(x.Name.Name, toplevel, StringComparison.OrdinalIgnoreCase)).ToList();
                if (networks.Count == 0)
                {
                    throw new ArgumentException($"The main module contains no networks named \"{toplevel}\"");
                }
                if (networks.Count != 1)
                {
                    throw new ArgumentException($"The main module contains {networks.Count} network named \"{toplevel}\"");
                }
                state.TopLevel.SourceNetwork = namednetworks.First();
            }

            // Wire up the top-level network parameters
            var dummyparsetoken = new ParseToken(0, 0, 0, "__commandline__");
            var name            = new AST.Identifier(new ParseToken(0, 0, 0, "__main__"));

            state.TopLevel.CommandlineArguments = arguments = arguments ?? new string[0];
            state.Modules[file] = state.TopLevel.Module;
            state.LocalScopes[state.TopLevel.Module] = rootscope;


            // Recursively load and resolve imports
            LoadImports(file, state, state.TopLevel.Module);

            // Register the symbols from the main module in the root scope
            state.RegisterSymbols(state.TopLevel.Module, rootscope);

            // Check that all parameters in the top-level network are explicitly typed
            var untypedparam = state.TopLevel.SourceNetwork.Parameters.FirstOrDefault(x => x.ExplictType == null);

            if (untypedparam != null)
            {
                throw new ParserException("All parameters to the top-level network must have an explict type", untypedparam);
            }

            // Prepare for the parameters to the top-level network
            var pmap = new AST.ParameterMap[state.TopLevel.SourceNetwork.Parameters.Length];
            var externalargumentindex = 0;

            for (var i = 0; i < pmap.Length; i++)
            {
                var p        = state.TopLevel.SourceNetwork.Parameters[i];
                var realtype = state.ResolveTypeName(p.ExplictType, rootscope);
                if (realtype == null)
                {
                    throw new ParserException($"Unable to find type: {p.ExplictType.SourceToken.Text}", p);
                }

                if (realtype.IsValue)
                {
                    if (p.Direction == AST.ParameterDirection.Out)
                    {
                        throw new ParserException($"A value-type parameter cannot be sent as output: {p.Name}", p);
                    }
                    if (externalargumentindex >= state.TopLevel.CommandlineArguments.Length)
                    {
                        throw new ParserException($"No value provided for the parameter {p.Name} in the commandline inputs", p);
                    }
                    var argtext = state.TopLevel.CommandlineArguments[externalargumentindex++];
                    var literal = ParseAsLiteral(argtext);
                    var littype = new AST.DataType(new ParseToken(0, 0, 0, argtext), literal.Value.Type, -1);
                    if (!state.CanTypeCast(littype, realtype, rootscope))
                    {
                        throw new ParserException($"Parsed {argtext} to {littype} but cannot interpret as {realtype} which is required for parameter {p.Name}", p);
                    }

                    pmap[i] = new AST.ParameterMap(p.SourceToken, p.Name, literal);
                    rootscope.TryAddSymbol(p.Name.Name, literal, p.Name);
                }
                else if (realtype.IsBus)
                {
                    var typedef = (AST.TypeDefinition)state.FindTypeDefinition(p.ExplictType.Alias, rootscope);

                    // Create a new bus as a stand-in for the input or output
                    var newbus = new Instance.Bus(
                        new AST.BusDeclaration(
                            dummyparsetoken,
                            p.Name,
                            realtype
                            .Shape
                            .Signals
                            .Select(x =>
                                    new AST.BusSignalDeclaration(
                                        dummyparsetoken,
                                        new AST.Identifier(new ParseToken(0, 0, 0, x.Key)),
                                        x.Value.Type,
                                        typedef.Initializers[x.Key],
                                        x.Value.Direction
                                        )
                                    ).ToArray(),
                            null
                            )
                        );

                    newbus.Instances.AddRange(
                        newbus
                        .Source
                        .Signals
                        .Select(x =>
                                new Instance.Signal(newbus, x)
                    {
                        ResolvedType = state.ResolveTypeName(x.Type, rootscope)
                    }
                                )
                        );

                    newbus.ResolvedSignalTypes =
                        newbus
                        .Instances
                        .OfType <Instance.Signal>()
                        .ToDictionary(x => x.Name, x => x.ResolvedType);

                    if (p.Direction == AST.ParameterDirection.Out)
                    {
                        state.TopLevel.OutputBusses.Add(newbus);
                    }
                    else if (p.Direction == AST.ParameterDirection.In)
                    {
                        state.TopLevel.InputBusses.Add(newbus);
                    }
                    else
                    {
                        throw new ParserException($"Cannot use a top-level bus with direction {p.Direction}", p);
                    }

                    pmap[i] = new AST.ParameterMap(p.SourceToken, p.Name, AST.EnumerationExtensions.AsExpression(p.Name));
                    rootscope.TryAddSymbol(p.Name.Name, newbus, p.Name);

                    // Register signals
                    using (var sc = state.StartScope(newbus))
                        foreach (var s in newbus.Instances.OfType <Instance.Signal>())
                        {
                            sc.TryAddSymbol(s.Name, s, s.Source);
                        }

                    state.TopLevel.ModuleInstance.Instances.Add(newbus);
                }
                else
                {
                    throw new ParserException($"Unexpected type: {realtype}", p);
                }
            }

            // Check that we have at least one output bus
            if (state.TopLevel.OutputBusses.Count == 0)
            {
                throw new ParserException("The top-level network must have at least one output bus", state.TopLevel.SourceNetwork);
            }
            if (state.TopLevel.CommandlineArguments.Length > externalargumentindex)
            {
                throw new ParserException($"Too many arguments on commandline, expected {externalargumentindex} but got {state.TopLevel.CommandlineArguments.Length}", state.TopLevel.SourceNetwork);
            }

            state.TopLevel.NetworkDeclaration = new AST.InstanceDeclaration(
                dummyparsetoken,
                new AST.InstanceName(dummyparsetoken, name, null),
                name,
                pmap
                );

            state.TopLevel.NetworkInstance = new Instance.Network(
                state.TopLevel.NetworkDeclaration,
                state.TopLevel.SourceNetwork
                );

            return(state);
        }