org.jarvis.main.parser.AimlParserImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.jarvis.main.parser.AimlParserImpl.java

Source

/**
 *  Copyright 2012 Yannick Roffin
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *   limitations under the License.
 */

package org.jarvis.main.parser;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.NoSuchElementException;
import java.util.Stack;

import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.InputMismatchException;
import org.antlr.v4.runtime.RecognitionException;
import org.jarvis.main.antlr4.aimlParser;
import org.jarvis.main.exception.AimlParsingError;
import org.jarvis.main.model.impl.parser.AimlCategory;
import org.jarvis.main.model.impl.parser.AimlProperty;
import org.jarvis.main.model.impl.parser.AimlRepository;
import org.jarvis.main.model.impl.parser.AimlTopic;
import org.jarvis.main.model.impl.parser.AimlXmlImpl;
import org.jarvis.main.model.impl.parser.category.AimlAImpl;
import org.jarvis.main.model.impl.parser.category.AimlBotImpl;
import org.jarvis.main.model.impl.parser.category.AimlBrImpl;
import org.jarvis.main.model.impl.parser.category.AimlGetImpl;
import org.jarvis.main.model.impl.parser.category.AimlLiImpl;
import org.jarvis.main.model.impl.parser.category.AimlPatternImpl;
import org.jarvis.main.model.impl.parser.category.AimlSetImpl;
import org.jarvis.main.model.impl.parser.category.AimlSraiImpl;
import org.jarvis.main.model.impl.parser.category.AimlTemplateImpl;
import org.jarvis.main.model.impl.parser.category.AimlThatCategoryImpl;
import org.jarvis.main.model.impl.parser.category.AimlThinkImpl;
import org.jarvis.main.model.impl.parser.pattern.AimlThatPatternImpl;
import org.jarvis.main.model.impl.parser.template.AimlGossipImpl;
import org.jarvis.main.model.impl.parser.template.AimlInputImpl;
import org.jarvis.main.model.impl.parser.template.AimlRandomImpl;
import org.jarvis.main.model.impl.parser.template.AimlStarImpl;
import org.jarvis.main.model.impl.parser.template.AimlThatStarImpl;
import org.jarvis.main.model.impl.parser.template.AimlThatTemplateImpl;
import org.jarvis.main.model.impl.parser.template.AimlTopicStarImpl;
import org.jarvis.main.model.impl.parser.template.condition.AimlConditionImpl;
import org.jarvis.main.model.impl.parser.template.format.AimlFormalImpl;
import org.jarvis.main.model.impl.parser.template.format.AimlLowercaseImpl;
import org.jarvis.main.model.impl.parser.template.format.AimlUppercaseImpl;
import org.jarvis.main.model.impl.parser.template.system.AimlDateImpl;
import org.jarvis.main.model.impl.parser.template.system.AimlIdImpl;
import org.jarvis.main.model.impl.parser.template.system.AimlJavascriptImpl;
import org.jarvis.main.model.impl.parser.template.system.AimlSizeImpl;
import org.jarvis.main.model.impl.parser.template.system.AimlSystemImpl;
import org.jarvis.main.model.impl.parser.template.system.AimlVersionImpl;
import org.jarvis.main.model.impl.parser.template.trans.AimlGenderImpl;
import org.jarvis.main.model.impl.parser.template.trans.AimlPerson2Impl;
import org.jarvis.main.model.impl.parser.template.trans.AimlPersonImpl;
import org.jarvis.main.model.parser.IAimlCategory;
import org.jarvis.main.model.parser.IAimlElement;
import org.jarvis.main.model.parser.IAimlRepository;
import org.jarvis.main.model.parser.IAimlTopic;
import org.jarvis.main.model.parser.IAimlXml;
import org.jarvis.main.model.parser.category.IAimlA;
import org.jarvis.main.model.parser.category.IAimlBot;
import org.jarvis.main.model.parser.category.IAimlBr;
import org.jarvis.main.model.parser.category.IAimlGet;
import org.jarvis.main.model.parser.category.IAimlLi;
import org.jarvis.main.model.parser.category.IAimlPattern;
import org.jarvis.main.model.parser.category.IAimlSet;
import org.jarvis.main.model.parser.category.IAimlSrai;
import org.jarvis.main.model.parser.category.IAimlTemplate;
import org.jarvis.main.model.parser.category.IAimlThat;
import org.jarvis.main.model.parser.category.IAimlThink;
import org.jarvis.main.model.parser.template.IAimlGossip;
import org.jarvis.main.model.parser.template.IAimlInput;
import org.jarvis.main.model.parser.template.IAimlRandom;
import org.jarvis.main.model.parser.template.IAimlStar;
import org.jarvis.main.model.parser.template.IAimlThatStar;
import org.jarvis.main.model.parser.template.IAimlTopicStar;
import org.jarvis.main.model.parser.template.condition.IAimlCondition;
import org.jarvis.main.model.parser.template.format.IAimlFormal;
import org.jarvis.main.model.parser.template.format.IAimlLowercase;
import org.jarvis.main.model.parser.template.format.IAimlUppercase;
import org.jarvis.main.model.parser.template.system.IAimlDate;
import org.jarvis.main.model.parser.template.system.IAimlId;
import org.jarvis.main.model.parser.template.system.IAimlJavascript;
import org.jarvis.main.model.parser.template.system.IAimlSize;
import org.jarvis.main.model.parser.template.system.IAimlSystem;
import org.jarvis.main.model.parser.template.system.IAimlVersion;
import org.jarvis.main.model.parser.template.trans.IAimlGender;
import org.jarvis.main.model.parser.template.trans.IAimlPerson;
import org.jarvis.main.model.parser.template.trans.IAimlPerson2;
import org.jarvis.main.utils.DefaultErrorStrategyImpl;
import org.jarvis.main.utils.DiagnosticErrorListenerImpl;
import org.jarvis.main.utils.IAimlParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AimlParserImpl extends aimlParser implements IAimlParser {
    static public Logger logger = LoggerFactory.getLogger(AimlParserImpl.class);

    protected AimlLexerImpl lexer = null;

    /**
     * AIML model
     */
    private IAimlXml root = null;
    private IAimlRepository repository = null;

    private final StackAimlElement stackElements = new StackAimlElement();

    private static boolean debugParsing = false;

    public IAimlRepository getRepository() {
        return repository;
    }

    private class StackAimlStructure {
        protected Stack<IAimlElement> stack = new Stack<IAimlElement>();

        protected IAimlXml push(AimlXmlImpl e) {
            stack.push(e);
            return e;
        }

        protected IAimlRepository push(AimlRepository e) {
            stack.push(e);
            return e;
        }

        protected IAimlTopic push(AimlTopic e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        protected IAimlCategory push(AimlCategory e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        protected IAimlTemplate push(AimlTemplateImpl e) {
            /**
             * template is always a category child
             */
            IAimlCategory cat = (IAimlCategory) stack.lastElement();
            cat.setTemplate(e);
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        protected IAimlPattern push(AimlPatternImpl e) {
            /**
             * pattern is always a category child
             */
            IAimlCategory cat = (IAimlCategory) stack.lastElement();
            cat.setPattern(e);
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public void add(String value) {
            try {
                stack.lastElement().add(value);
            } catch (NoSuchElementException e) {
                /**
                 * TODO handle with exception throw
                 */
                logger.error("Internal error");
            }
        }

        public void add(AimlProperty value) {
            try {
                stack.lastElement().add(value);
            } catch (NoSuchElementException e) {
                /**
                 * TODO handle with exception throw
                 */
                logger.error("Internal error");
            }
        }

        public IAimlElement lastElement() {
            return stack.lastElement();
        }

        protected IAimlElement pop(String tagName) {
            return stack.pop();
        }
    }

    private class StackAimlElement extends StackAimlStructure {
        private final StackAimlStructure filter = new StackAimlStructure();

        @Override
        public IAimlElement pop(String tagName) {
            IAimlElement result = super.pop(tagName);
            /**
             * only pop specific tag name in filter structure
             */
            if ("xml".compareTo(tagName) == 0 || "aiml".compareTo(tagName) == 0
                    || "category".compareTo(tagName) == 0 || "template".compareTo(tagName) == 0
                    || "pattern".compareTo(tagName) == 0) {
                filter.pop(tagName);
            }
            return result;
        }

        @Override
        public IAimlXml push(AimlXmlImpl e) {
            super.push(e);
            filter.push(new AimlXmlImpl());
            return e;
        }

        @Override
        public IAimlRepository push(AimlRepository e) {
            super.push(e);
            filter.push(new AimlRepository());
            return e;
        }

        @Override
        public IAimlTopic push(AimlTopic e) {
            super.push(e);
            filter.push(new AimlTopic(e.getName()));
            return e;
        }

        @Override
        public IAimlCategory push(AimlCategory e) {
            super.push(e);
            filter.push(new AimlCategory(e.getTopic()));
            return e;
        }

        @Override
        public IAimlTemplate push(AimlTemplateImpl e) {
            super.push(e);
            filter.push(new AimlTemplateImpl(e.getTopic()));
            return e;
        }

        @Override
        public IAimlPattern push(AimlPatternImpl e) {
            super.push(e);
            filter.push(new AimlPatternImpl(e.getTopic()));
            return e;
        }

        public IAimlThat push(AimlThatCategoryImpl e) {
            /**
             * that is always a category child
             */
            IAimlCategory cat = (IAimlCategory) stack.lastElement();
            cat.setThat(e);
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlThat push(AimlThatPatternImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlThat push(AimlThatTemplateImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlSrai push(AimlSraiImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlGossip push(AimlGossipImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlGet push(AimlGetImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlSet push(AimlSetImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlDate push(AimlDateImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlId push(AimlIdImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlBr push(AimlBrImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlA push(AimlAImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlBot push(AimlBotImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlCondition push(AimlConditionImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlPerson2 push(AimlPerson2Impl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlSize push(AimlSizeImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlStar push(AimlStarImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlThatStar push(AimlThatStarImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlTopicStar push(AimlTopicStarImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlVersion push(AimlVersionImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlInput push(AimlInputImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlPerson push(AimlPersonImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlThink push(AimlThinkImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlRandom push(AimlRandomImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlLi push(AimlLiImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlFormal push(AimlFormalImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public StackAimlStructure getFilter() {
            return filter;
        }

        public IAimlUppercase push(AimlUppercaseImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlLowercase push(AimlLowercaseImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlSystem push(AimlSystemImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlGender push(AimlGenderImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }

        public IAimlJavascript push(AimlJavascriptImpl e) {
            stack.lastElement().add(e);
            stack.push(e);
            return e;
        }
    }

    private int iParserError = 0;
    private int iLexerError = 0;

    /**
     * default construtor
     * 
     * @param filename
     * @param encoding
     * @throws AimlParsingError
     */
    private AimlParserImpl(File filename, String encoding) throws AimlParsingError {
        super(AimlLexerImpl.getTokens(filename.getAbsolutePath(), encoding));
        lexer = (AimlLexerImpl) _input.getTokenSource();
        root = stackElements.push(new AimlXmlImpl());

        lexer.addErrorListener(new DiagnosticErrorListenerImpl(this, filename));
        setErrorHandler(new DefaultErrorStrategyImpl(this, filename));
        addErrorListener(new DiagnosticErrorListenerImpl(this, filename));
    }

    /**
     * another default constructor
     * 
     * @param local
     */
    private AimlParserImpl(CommonTokenStream local) {
        super(local);
        root = stackElements.push(new AimlXmlImpl());
    }

    /**
     * parse this document
     * 
     * @return
     * @throws AimlParsingError
     */
    public static IAimlRepository parse(File filename) throws AimlParsingError {
        String encoding = "UTF-8";
        try {
            /**
             * find encoding
             */
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
                CommonTokenStream local = AimlLexerImpl.getTokensFromString(br.readLine());
                br.close();
                AimlParserImpl parser = new AimlParserImpl(local);
                parser.setRepository(new AimlRepository());
                parser.getRepository().setRoot(parser.getRoot());
                parser.header();
                /**
                 * find encoding
                 */
                String enc = parser.getRepository().getRoot().get("encoding");
                if (enc != null)
                    encoding = enc;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                throw new AimlParsingError(e);
            } catch (IOException e) {
                e.printStackTrace();
                throw new AimlParsingError(e);
            }
            /**
             * parse all file
             */
            logger.info("Parsing " + filename + " - " + encoding);
            AimlParserImpl parser = new AimlParserImpl(filename, encoding);
            parser.document();

            if (parser.getParserErrors() > 0 || parser.getLexerErrors() > 0) {
                throw new AimlParsingError("Errors, while parsing");
            }
            return parser.getRepository();
        } catch (RecognitionException e) {
            logger.warn("Parsing " + filename + " - " + encoding);
            e.printStackTrace();
            throw new AimlParsingError(e);
        } catch (AimlParsingError e) {
            logger.warn("Parsing " + filename + " - " + encoding);
            e.printStackTrace();
            throw e;
        }
    }

    private int getParserErrors() {
        return iParserError;
    }

    private int getLexerErrors() {
        return iLexerError;
    }

    private IAimlXml getRoot() {
        return root;
    }

    private void setRepository(AimlRepository aimlRepository) {
        repository = aimlRepository;
    }

    @Override
    public void onAttribute(String key, String value) {
        if (logger.isDebugEnabled() && debugParsing) {
            logger.debug("onAttribute - [" + key + " = " + value + "]");
        }
        stackElements.add(new AimlProperty(key, value));
    }

    @Override
    public void onPcData(String value) {
        if (logger.isDebugEnabled() && debugParsing) {
            logger.debug("onPcData - [" + value + "]");
        }
        /**
         * register this new PCDATA element to current receiver
         */
        stackElements.add(value);
    }

    IAimlCategory category = null;
    IAimlTemplate template = null;
    IAimlPattern pattern = null;
    IAimlTopic defaultTopic = new AimlTopic("");
    IAimlTopic topic = defaultTopic;

    @Override
    public void onOpenTag(String value) {
        try {
            onPrivateOpenTag(value);
        } catch (Exception e) {
            e.printStackTrace();
            this.getErrorHandler().reportError(this, new InputMismatchException(this));
        }
    }

    public void onPrivateOpenTag(String value) {
        if (logger.isDebugEnabled() && debugParsing) {
            logger.debug("onOpenTag - " + value);
        }
        switch (decode(value)) {
        case AIML:
            /**
             * An AIML object is represented by an aiml:aiml element in an XML
             * document. The aiml:aiml element may contain the following types
             * of elements: - aiml:topic - aiml:category
             * 
             * create default repository on aiml tag detection attributes must
             * be handle next
             */
            repository = stackElements.push(new AimlRepository());
            repository.setRoot(root);
            break;
        case TOPIC:
            /**
             * A topic is an optional top-level element that contains category
             * elements. A topic element has a required name attribute that must
             * contain a simple pattern expression. A topic element may contain
             * one or more category elements.
             */
            topic = stackElements.push(new AimlTopic());
            repository.addTopic(topic);
            break;
        case CATEGORY:
            /**
             * A category is a top-level (or second-level, if contained within a
             * topic) element that contains exactly one pattern and exactly one
             * template. A category does not have any attributes.
             */
            category = stackElements.push(new AimlCategory(topic));
            repository.addCategory(category);
            break;
        case TEMPLATE:
            /**
             * A template is an element that appears within category elements.
             * The template must follow the pattern-side that element, if it
             * exists; otherwise, it follows the pattern element. A template
             * does not have any attributes.
             */
            template = stackElements.push(new AimlTemplateImpl(topic));
            break;
        case PATTERN:
            /**
             * A pattern is an element whose content is a mixed pattern
             * expression. Exactly one pattern must appear in each category. The
             * pattern must always be the first child element of the category. A
             * pattern does not have any attributes.
             */
            pattern = stackElements.push(new AimlPatternImpl(topic));
            break;
        case THAT:
            /**
             * The pattern-side that element is a special type of pattern
             * element used for context matching. The pattern-side that is
             * optional in a category, but if it occurs it must occur no more
             * than once, and must immediately follow the pattern and
             * immediately precede the template. A pattern-side that element
             * contains a simple pattern expression.
             * 
             * allocate that on category side, or template side according to the
             * parsing context
             */
            if (stackElements.getFilter().lastElement().getClass() == AimlTemplateImpl.class) {
                stackElements.push(new AimlThatTemplateImpl(template));
                return;
            }
            if (stackElements.getFilter().lastElement().getClass() == AimlPatternImpl.class) {
                stackElements.push(new AimlThatPatternImpl(pattern));
                return;
            }
            if (stackElements.getFilter().lastElement().getClass() == AimlCategory.class) {
                stackElements.push(new AimlThatCategoryImpl(category));
                return;
            }

            logger.error("Element cannot be null");
            /**
             * TODO error management
             */
            break;
        case THATSTAR:
            /**
             * The thatstar element tells the AIML interpreter that it should
             * substitute the contents of a wildcard from a pattern-side that
             * element.
             * 
             * The thatstar element has an optional integer index attribute that
             * indicates which wildcard to use; the minimum acceptable value for
             * the index is "1" (the first wildcard).
             */
            if (category != null && category.getThat() != null)
                stackElements.push(new AimlThatStarImpl(category.getThat()));
            break;
        case SRAI:
            /**
             * The srai element instructs the AIML interpreter to pass the
             * result of processing the contents of the srai element to the AIML
             * matching loop, as if the input had been produced by the user
             * (this includes stepping through the entire input normalization
             * process). The srai element does not have any attributes. It may
             * contain any AIML template elements.
             */
            stackElements.push(new AimlSraiImpl());
            break;
        case SR:
            /**
             * The sr element is a shortcut for:
             * 
             * <srai><star/></srai>
             */
            stackElements.push(new AimlSraiImpl());
            stackElements.push(new AimlStarImpl());
            stackElements.pop(value);
            break;
        case GET:
            /**
             * The get element tells the AIML interpreter that it should
             * substitute the contents of a predicate, if that predicate has a
             * value defined. If the predicate has no value defined, the AIML
             * interpreter should substitute the empty string "".
             */
            stackElements.push(new AimlGetImpl());
            break;
        case SET:
            /**
             * The set element instructs the AIML interpreter to set the value
             * of a predicate to the result of processing the contents of the
             * set element. The set element has a required attribute name, which
             * must be a valid AIML predicate name. If the predicate has not yet
             * been defined, the AIML interpreter should define it in memory.
             */
            stackElements.push(new AimlSetImpl());
            break;
        case DATE:
            /**
             * The date element tells the AIML interpreter that it should
             * substitute the system local date and time. No formatting
             * constraints on the output are specified.
             * 
             * The date element does not have any content.
             */
            stackElements.push(new AimlDateImpl());
            break;
        case ID:
            /**
             * The id element tells the AIML interpreter that it should
             * substitute the user ID. The determination of the user ID is not
             * specified, since it will vary by application. A suggested default
             * return value is "localhost".
             */
            stackElements.push(new AimlIdImpl());
            break;
        case RANDOM:
            /**
             * The random element instructs the AIML interpreter to return
             * exactly one of its contained li elements randomly. The random
             * element must contain one or more li elements of type
             * defaultListItem, and cannot contain any other elements.
             */
            stackElements.push(new AimlRandomImpl());
            break;
        case LI:
            /**
             * The random element instructs the AIML interpreter to return
             * exactly one of its contained li elements randomly. The random
             * element must contain one or more li elements of type
             * defaultListItem, and cannot contain any other elements.
             */
            stackElements.push(new AimlLiImpl());
            break;
        case FORMAL:
            /**
             * The formal element tells the AIML interpreter to render the
             * contents of the element such that the first letter of each word
             * is in uppercase, as defined (if defined) by the locale indicated
             * by the specified language (if specified). This is similar to
             * methods that are sometimes called "Title Case".
             */
            stackElements.push(new AimlFormalImpl());
            break;
        case INPUT:
            stackElements.push(new AimlInputImpl());
            break;
        case PERSON:
            stackElements.push(new AimlPersonImpl());
            break;
        case THINK:
            stackElements.push(new AimlThinkImpl());
            break;
        case BR:
            stackElements.push(new AimlBrImpl());
            break;
        case STAR:
            stackElements.push(new AimlStarImpl());
            break;
        case TOPICSTAR:
            stackElements.push(new AimlTopicStarImpl());
            break;
        case A:
            stackElements.push(new AimlAImpl());
            break;
        case BOT:
            stackElements.push(new AimlBotImpl());
            break;
        case CONDITION:
            stackElements.push(new AimlConditionImpl());
            break;
        case PERSON2:
            stackElements.push(new AimlPerson2Impl());
            break;
        case SIZE:
            stackElements.push(new AimlSizeImpl());
            break;
        case VERSION:
            stackElements.push(new AimlVersionImpl());
            break;
        case UPPER:
            stackElements.push(new AimlUppercaseImpl());
            break;
        case LOWER:
            stackElements.push(new AimlLowercaseImpl());
            break;
        case SYSTEM:
            stackElements.push(new AimlSystemImpl());
            break;
        case JAVASCRIPT:
            stackElements.push(new AimlJavascriptImpl());
            break;
        case GENDER:
            /**
             * The gender element instructs the AIML interpreter to:
             * 
             * replace male-gendered words in the result of processing the
             * contents of the gender element with the
             * grammatically-corresponding female-gendered words; and replace
             * female-gendered words in the result of processing the contents of
             * the gender element with the grammatically-corresponding
             * male-gendered words.
             */
            stackElements.push(new AimlGenderImpl());
            break;
        case GOSSIP:
            /**
             * The gossip element instructs the AIML interpreter to capture the
             * result of processing the contents of the gossip elements and to
             * store these contents in a manner left up to the implementation.
             * Most common uses of gossip have been to store captured contents
             * in a separate file.
             */
            stackElements.push(new AimlGossipImpl());
            break;
        default:
            logger.warn("Unknown tag element : " + value);
            break;
        }
    }

    @Override
    public void onCloseTag(String value) {
        try {
            onPrivateCloseTag(value);
        } catch (Exception e) {
            e.printStackTrace();
            this.getErrorHandler().reportError(this, new InputMismatchException(this));
        }
    }

    public void onPrivateCloseTag(String value) {
        if (logger.isDebugEnabled() && debugParsing) {
            logger.debug("onCloseTag - " + value);
        }
        /**
         * close current topic, category etc ...
         */
        if (value.startsWith("topic")) {
            topic = defaultTopic;
        }
        if (value.startsWith("category")) {
            category = null;
        }
        if (value.startsWith("pattern")) {
            pattern = null;
        }
        if (value.startsWith("template")) {
            template = null;
        }
        stackElements.pop(value);
    }

    @Override
    public void addLexerError(int i) {
        iLexerError += i;
    }

    @Override
    public String getStatistics() {
        return getRepository().getStatistics();
    }

    @Override
    public void addParserError(int i) {
        iParserError += i;
    }

    @Override
    public boolean reportAttemptingFullContext() {
        return false;
    }
}