# Source code for ly.lex.scheme

    # This file is part of python-ly, https://pypi.python.org/pypi/python-ly
    #
    # Copyright (c) 2008 - 2015 by Wilbert Berendsen
    #
    # This program is free software; you can redistribute it and/or
    # modify it under the terms of the GNU General Public License
    # as published by the Free Software Foundation; either version 2
    # of the License, or (at your option) any later version.
    #
    # This program is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU General Public License
    # along with this program; if not, write to the Free Software
    # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    # See http://www.gnu.org/licenses/ for more information.

    """
    Parses and tokenizes Scheme input.
    """

    from __future__ import unicode_literals

    from . import _token
    from . import Parser, FallthroughParser

    class Scheme(_token.Token):
        """Baseclass for Scheme tokens."""
        pass

    class String(_token.String):
        pass

    class StringQuotedStart(String, _token.StringStart):
        rx = r'"'
        def update_state(self, state):
            state.enter(ParseString())

    class StringQuotedEnd(String, _token.StringEnd):
        rx = r'"'
        def update_state(self, state):
            state.leave()
            state.endArgument()

    class StringQuoteEscape(_token.Character):
        rx = r'\\[\\"]'

    class Comment(_token.Comment):
        pass

    class LineComment(Comment, _token.LineComment):
        rx = r";.*$"

    class BlockCommentStart(Comment, _token.BlockCommentStart):
        rx = r"#!"
        def update_state(self, state):
            state.enter(ParseBlockComment())

    class BlockCommentEnd(Comment, _token.BlockCommentEnd, _token.Leaver):
        rx = "!#"

    class BlockComment(Comment, _token.BlockComment):
        pass

    class OpenParen(Scheme, _token.MatchStart, _token.Indent):
        rx = r"\("
        matchname = "schemeparen"
        def update_state(self, state):
            state.enter(ParseScheme())

    class CloseParen(Scheme, _token.MatchEnd, _token.Dedent):
        rx = r"\)"
        matchname = "schemeparen"
        def update_state(self, state):
            state.leave()
            state.endArgument()

    class Quote(Scheme):
        rx = r"['`,]"

    class Dot(Scheme):
        rx = r"\.(?!\S)"

    class Bool(Scheme, _token.Item):
        rx = r"#[tf]\b"

    class Char(Scheme, _token.Item):
        rx = r"#\\([a-z]+|.)"

    class Word(Scheme, _token.Item):
        rx = r'[^()"{}\s]+'

    class Keyword(Word):
        @classmethod
        def test_match(cls, match):
            from .. import data
            return match.group() in data.scheme_keywords()

    class Function(Word):
        @classmethod
        def test_match(cls, match):
            from .. import data
            return match.group() in data.scheme_functions()

    class Variable(Word):
        @classmethod
        def test_match(cls, match):
            from .. import data
            return match.group() in data.scheme_variables()

    class Constant(Word):
        @classmethod
        def test_match(cls, match):
            from .. import data
            return match.group() in data.scheme_constants()

    class Number(_token.Item, _token.Numeric):
        rx = (r"("
              r"-?\d+|"
              r"#(b[0-1]+|o[0-7]+|x[0-9a-fA-F]+)|"
              r"[-+]inf.0|[-+]?nan.0"
              r")(?=$|[)\s])")

    class Fraction(Number):
        rx = r"-?\d+/\d+(?=$|[)\s])"

    class Float(Number):
        rx = r"-?((\d+(\.\d*)|\.\d+)(E\d+)?)(?=$|[)\s])"

    class VectorStart(OpenParen):
        rx = r"#\("

    class LilyPond(_token.Token):
        pass

    class LilyPondStart(LilyPond, _token.MatchStart, _token.Indent):
        rx = r"#{"
        matchname = "schemelily"
        def update_state(self, state):
            state.enter(ParseLilyPond())

    class LilyPondEnd(LilyPond, _token.Leaver, _token.MatchEnd, _token.Dedent):
        rx = r"#}"
        matchname = "schemelily"

    # Parsers

    class ParseScheme(Parser):
        mode = 'scheme'
        items = (
            _token.Space,
            OpenParen,
            CloseParen,
            LineComment,
            BlockCommentStart,
            LilyPondStart,
            VectorStart,
            Dot,
            Bool,
            Char,
            Quote,
            Fraction,
            Float,
            Number,
            Constant,
            Keyword,
            Function,
            Variable,
            Word,
            StringQuotedStart,
        )

    class ParseString(Parser):
        default = String
        items = (
            StringQuotedEnd,
            StringQuoteEscape,
        )

    class ParseBlockComment(Parser):
        default = BlockComment
        items = (
            BlockCommentEnd,
        )

    from . import lilypond

    class ParseLilyPond(lilypond.ParseMusic):
        items = (LilyPondEnd,) + lilypond.ParseMusic.items