Ejemplo n.º 1
0
        /// <summary>
        /// Parses a string from the commandline and provides a typed literal
        /// </summary>
        /// <param name="arg">The argument to use</param>
        /// <returns>A parsed literal</returns>
        private static AST.LiteralExpression ParseAsLiteral(string arg)
        {
            var parsetoken = new ParseToken(0, 0, 0, arg);

            if (bool.TryParse(arg, out var bres))
            {
                return(new AST.LiteralExpression(parsetoken, new AST.BooleanConstant(parsetoken, bres)));
            }
            if (int.TryParse(arg, out var ires))
            {
                return(new AST.LiteralExpression(parsetoken, new AST.IntegerConstant(parsetoken, arg)));
            }
            if (float.TryParse(arg, out var fres))
            {
                var els = arg.Split(".", 2);
                return(new AST.LiteralExpression(parsetoken, new AST.FloatingConstant(parsetoken, els.First(), els.Skip(1).FirstOrDefault() ?? string.Empty)));
            }

            return(new AST.LiteralExpression(parsetoken, new AST.StringConstant(parsetoken, arg)));
        }
Ejemplo n.º 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);
        }
Ejemplo n.º 3
0
 /// <summary>
 /// Constructs a new parserexception
 /// </summary>
 /// <param name="message">The error message</param>
 /// <param name="source">The location of the problem</param>
 public ParserException(string message, ParseToken source)
     : base(message)
 {
     Location = source;
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Splits the input into tokens
        /// </summary>
        /// <returns>The tokenized results.</returns>
        /// <param name="reader">The reader to extract the tokens for.</param>
        public static IEnumerable <ParseToken> Tokenize(TextReader reader)
        {
            var sb = new StringBuilder();
            int cur;
            int line       = 1;
            int charoffset = 1;
            int lineoffset = 1;

            while ((cur = reader.Read()) > 0)
            {
                var c            = (char)cur;
                var iswhitespace = char.IsWhiteSpace(c);
                if (iswhitespace || Array.IndexOf(DELIMITERS, c) >= 0)
                {
                    if (sb.Length != 0)
                    {
                        yield return(new ParseToken(charoffset, line, lineoffset, sb.ToString()));

                        charoffset += sb.Length;
                        lineoffset += sb.Length;
                        sb.Clear();
                    }

                    // Eat the entire line if we hit a comment
                    if (c == '/' && reader.Peek() == cur)
                    {
                        var ct = new ParseToken(charoffset, line, lineoffset, '/' + reader.ReadLine());

                        charoffset += ct.Text.Length;
                        lineoffset  = 1;
                        line++;

                        //yield return ct;
                        continue;
                    }

                    // Combine to a single token
                    if (MULTI_CHAR_TOKENS.TryGetValue(c, out var followers) && followers.Contains(reader.Peek()))
                    {
                        var n  = (char)reader.Read();
                        var ct = new ParseToken(charoffset, line, lineoffset, c.ToString() + n);

                        charoffset += ct.Text.Length;
                        lineoffset += ct.Text.Length;

                        yield return(ct);

                        continue;
                    }

                    if (!iswhitespace)
                    {
                        yield return(new ParseToken(charoffset, line, lineoffset, c.ToString()));
                    }

                    charoffset++;
                    lineoffset++;
                    if (c == '\r' || c == '\n')
                    {
                        if (c == '\r' && reader.Peek() == (int)'\n')
                        {
                            reader.Read();
                        }

                        line++;
                        lineoffset = 1;
                    }
                }
                else
                {
                    sb.Append(c);
                }
            }

            if (sb.Length != 0)
            {
                yield return(new ParseToken(charoffset, line, lineoffset, sb.ToString()));
            }
        }