/// <summary>
        /// Read a transistor model
        /// </summary>
        /// <param name="type">Type</param>
        /// <param name="st">Statement</param>
        /// <param name="netlist">Netlist</param>
        /// <returns></returns>
        public override bool Read(string type, Statement st, Netlist netlist)
        {
            // Errors
            switch (st.Parameters.Count)
            {
            case 0: throw new ParseException(st.Name, "Model name and type expected", false);
            }

            // The model depends on the model level, find the model statement
            int level = 0; string version = null;
            int lindex = -1, vindex = -1;

            for (int i = 0; i < st.Parameters.Count; i++)
            {
                if (st.Parameters[i].kind == ASSIGNMENT)
                {
                    AssignmentToken at = st.Parameters[i] as AssignmentToken;
                    if (at.Name.image.ToLower() == "level")
                    {
                        lindex = i;
                        level  = (int)Math.Round(netlist.ParseDouble(at.Value));
                    }
                    if (at.Name.image.ToLower() == "version")
                    {
                        vindex  = i;
                        version = at.Value.image.ToLower();
                    }
                    if (vindex >= 0 && lindex >= 0)
                    {
                        break;
                    }
                }
            }
            if (lindex >= 0)
            {
                st.Parameters.RemoveAt(lindex);
            }
            if (vindex >= 0)
            {
                st.Parameters.RemoveAt(vindex < lindex ? vindex : vindex - 1);
            }

            // Generate the model
            ICircuitObject model = null;

            if (Levels.ContainsKey(level))
            {
                model = Levels[level].Invoke(new CircuitIdentifier(st.Name.image), type, version);
            }
            else
            {
                throw new ParseException(st.Name, $"Unknown mosfet model level {level}");
            }

            // Read all the parameters
            netlist.ReadParameters((IParameterized)model, st.Parameters);

            // Output
            netlist.Circuit.Objects.Add(model);
            Generated = model;
            return(true);
        }
        /// <summary>
        /// Read
        /// </summary>
        /// <param name="type">Type</param>
        /// <param name="st">Statement</param>
        /// <param name="netlist">Netlist</param>
        /// <returns></returns>
        public override bool Read(string type, Statement st, Netlist netlist)
        {
            // Initialize
            List <CircuitIdentifier> instancepins = new List <CircuitIdentifier>();
            Dictionary <CircuitIdentifier, Token> instanceparameters = new Dictionary <CircuitIdentifier, Token>();
            CircuitIdentifier definition = null;

            // Get the name
            CircuitIdentifier name;

            if (netlist.Path.InstancePath != null)
            {
                name = netlist.Path.InstancePath.Grow(st.Name.image);
            }
            else
            {
                name = new CircuitIdentifier(st.Name.image);
            }

            // Format: <NAME> <NODES>* <SUBCKT> <PAR1>=<VAL1> ...
            // Or: <NAME> <NODES>* <SUBCKT> params: <PAR1>=<VAL1> ...
            bool mode = true; // true = nodes, false = parameters

            for (int i = 0; i < st.Parameters.Count; i++)
            {
                // Reading nodes
                if (mode)
                {
                    if (ReaderExtension.IsNode(st.Parameters[i]))
                    {
                        instancepins.Add(definition = new CircuitIdentifier(st.Parameters[i].image));
                    }
                    else
                    {
                        instancepins.RemoveAt(instancepins.Count - 1);
                        mode = false;
                    }
                }

                // Reading parameters
                // Don't use ELSE! We still need to read the last parameter
                if (!mode)
                {
                    if (st.Parameters[i].kind == ASSIGNMENT)
                    {
                        AssignmentToken at = st.Parameters[i] as AssignmentToken;
                        switch (at.Name.kind)
                        {
                        case WORD:
                        case IDENTIFIER:
                            instanceparameters.Add(new CircuitIdentifier(at.Name.image), at.Value);
                            break;

                        default:
                            throw new ParseException(at.Name, "Parameter name expected");
                        }
                    }
                }
            }

            // If there are only node-like tokens, then the last one is the definition by default
            if (mode)
            {
                instancepins.RemoveAt(instancepins.Count - 1);
            }

            // Modify the instancepins to be local or use the nodemap
            for (int i = 0; i < instancepins.Count; i++)
            {
                if (netlist.Path.NodeMap.TryGetValue(instancepins[i], out CircuitIdentifier node))
                {
                    instancepins[i] = node;
                }
                else if (netlist.Path.InstancePath != null)
                {
                    instancepins[i] = netlist.Path.InstancePath.Grow(instancepins[i].Name);
                }
            }

            // Find the subcircuit definition
            if (netlist.Path.DefinitionPath != null)
            {
                definition = netlist.Path.DefinitionPath.Grow(definition);
            }
            SubcircuitDefinition subcktdef = netlist.Path.FindDefinition(netlist.Definitions, definition) ??
                                             throw new ParseException(st.Parameters[st.Parameters.Count - 1], "Cannot find subcircuit definition");
            Subcircuit subckt = new Subcircuit(subcktdef, name, instancepins, instanceparameters);

            SubcircuitPath orig = netlist.Path;

            netlist.Path = new SubcircuitPath(netlist, orig, subckt);

            // Read all control statements
            foreach (var s in subcktdef.Body.Statements(StatementType.Control))
            {
                netlist.Readers.Read(s, netlist);
            }

            // Read all model statements
            foreach (var s in subcktdef.Body.Statements(StatementType.Model))
            {
                netlist.Readers.Read(s, netlist);
            }

            // Read all component statements
            foreach (var s in subcktdef.Body.Statements(StatementType.Component))
            {
                netlist.Readers.Read(s, netlist);
            }

            // Restore
            netlist.Path = orig;
            Generated    = subckt;
            return(true);
        }