/*
 * Copyright (C) 2008 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#ifndef Escapes_h
#define Escapes_h

#include <wtf/Platform.h>

#if ENABLE(WREC)

#include <wtf/Assertions.h>

namespace JSC { namespace WREC {

    class CharacterClass;

    class Escape {
    public:
        enum Type {
            PatternCharacter,
            CharacterClass,
            Backreference,
            WordBoundaryAssertion,
            Error,
        };
        
        Escape(Type type)
            : m_type(type)
        {
        }

        Type type() const { return m_type; }

    private:
        Type m_type;
        
    protected:
        // Used by subclasses to store data.
        union {
            int i;
            const WREC::CharacterClass* c;
        } m_u;
        bool m_invert;
    };

    class PatternCharacterEscape : public Escape {
    public:
        static const PatternCharacterEscape& cast(const Escape& escape)
        {
            ASSERT(escape.type() == PatternCharacter);
            return static_cast<const PatternCharacterEscape&>(escape);
        }
        
        PatternCharacterEscape(int character)
            : Escape(PatternCharacter)
        {
            m_u.i = character;
        }
        
        operator Escape() const { return *this; }
        
        int character() const { return m_u.i; }
    };

    class CharacterClassEscape : public Escape {
    public:
        static const CharacterClassEscape& cast(const Escape& escape)
        {
            ASSERT(escape.type() == CharacterClass);
            return static_cast<const CharacterClassEscape&>(escape);
        }
        
        CharacterClassEscape(const WREC::CharacterClass& characterClass, bool invert)
            : Escape(CharacterClass)
        {
            m_u.c = &characterClass;
            m_invert = invert;
        }
        
        operator Escape() { return *this; }
        
        const WREC::CharacterClass& characterClass() const { return *m_u.c; }
        bool invert() const { return m_invert; }
    };

    class BackreferenceEscape : public Escape {
    public:
        static const BackreferenceEscape& cast(const Escape& escape)
        {
            ASSERT(escape.type() == Backreference);
            return static_cast<const BackreferenceEscape&>(escape);
        }
        
        BackreferenceEscape(int subpatternId)
            : Escape(Backreference)
        {
            m_u.i = subpatternId;
        }
        
        operator Escape() const { return *this; }
        
        int subpatternId() const { return m_u.i; }
    };

    class WordBoundaryAssertionEscape : public Escape {
    public:
        static const WordBoundaryAssertionEscape& cast(const Escape& escape)
        {
            ASSERT(escape.type() == WordBoundaryAssertion);
            return static_cast<const WordBoundaryAssertionEscape&>(escape);
        }
        
        WordBoundaryAssertionEscape(bool invert)
            : Escape(WordBoundaryAssertion)
        {
            m_invert = invert;
        }
        
        operator Escape() const { return *this; }
        
        bool invert() const { return m_invert; }
    };

} } // namespace JSC::WREC

#endif // ENABLE(WREC)

#endif // Escapes_h
