private static bool DoSubCall(Token<TokenType> first, Interpreter interpreter, SourceReader reader, State state)
        {
            var name = reader.ReadToken();
            if (!Util.ValidateName(name.Value))
                throw new ManhoodException(reader.Source, name, "Invalid subroutine name '" + name.Value + "'");
            
            bool none = false;

            if (!reader.Take(TokenType.Colon))
            {
                if (!reader.Take(TokenType.RightSquare))
                    throw new ManhoodException(reader.Source, name, "Expected ':' or ']' after subroutine name.");
                
                none = true;
            }

            IEnumerable<Token<TokenType>>[] args = null;
            Subroutine sub = null;

            if (none)
            {
                if((sub = interpreter.Engine.Subroutines.Get(name.Value, 0)) == null)
                    throw new ManhoodException(reader.Source, name, "No subroutine was found with the name '" + name.Value + "' and 0 parameters.");
            }
            else
            {
                args = reader.ReadItemsToClosureTrimmed(TokenType.LeftSquare, TokenType.RightSquare, TokenType.Semicolon,
                    BracketPairs.All).ToArray();
                if((sub = interpreter.Engine.Subroutines.Get(name.Value, args.Length)) == null)
                    throw new ManhoodException(reader.Source, name, "No subroutine was found with the name '" + name.Value + "' and " + args.Length + " parameter" + (args.Length != 1 ? "s" : "") + ".");
            }

            state.AddPreBlueprint(new SubCallBlueprint(interpreter, reader.Source, sub, args));

            return true;
        }
        private static bool DoReplacer(Token<TokenType> name, Interpreter interpreter, SourceReader reader, State state)
        {
            reader.Read(TokenType.Colon);

            var args = reader.ReadItemsToClosureTrimmed(TokenType.LeftSquare, TokenType.RightSquare, TokenType.Semicolon, BracketPairs.All).ToArray();
            if (args.Length != 2) throw new ManhoodException(reader.Source, name, "Replacer expected 2 arguments, but got " + args.Length + ".");

            state.AddPreBlueprint(new ReplacerBlueprint(interpreter, Util.ParseRegex(name.Value), args[1]));

            interpreter.PushState(State.CreateDerivedDistinct(reader.Source, args[0], interpreter));
            return true;
        }
        private static bool DoTag(Interpreter interpreter, SourceReader reader, State state)
        {
            reader.Read(TokenType.LeftSquare);
            var name = reader.ReadToken();

            // Check if metapattern
            if (name.Identifier == TokenType.Question)
            {
                state.AddPreBlueprint(new MetapatternBlueprint(interpreter));
                interpreter.PushState(State.CreateDerivedDistinct(reader.Source, reader.ReadToScopeClose(TokenType.LeftSquare, TokenType.RightSquare, BracketPairs.All), interpreter));
                return true;
            }

            // Check if replacer
            if (name.Identifier == TokenType.Regex)
            {
                return DoReplacer(name, interpreter, reader, state);
            }

            if (name.Identifier == TokenType.Dollar)
            {
                return reader.IsNext(TokenType.Text) ? DoSubCall(name, interpreter, reader, state) : DoSubDefinition(name, interpreter, reader, state);
            }

            if (!Util.ValidateName(name.Value.Trim()))
                throw new ManhoodException(reader.Source, name, "Invalid tag name '" + name.Value + "'");

            bool none = false;
            if (!reader.Take(TokenType.Colon))
            {
                if (!reader.Take(TokenType.RightSquare))
                    throw new ManhoodException(reader.Source, name, "Expected ':' or ']' after tag name.");
                none = true;
            }

            if (none)
            {
                state.AddPreBlueprint(new TagBlueprint(interpreter, reader.Source, name));
            }
            else
            {
                var items = reader.ReadItemsToClosureTrimmed(TokenType.LeftSquare, TokenType.RightSquare,
                    TokenType.Semicolon, BracketPairs.All).ToArray();

                state.AddPreBlueprint(new TagBlueprint(interpreter, reader.Source, name, items));
            }
            return true;
        }