Source code for quickly.lang.scheme
# -*- coding: utf-8 -*-
#
# This file is part of `quickly`, a library for LilyPond and the `.ly` format
#
# Copyright © 2019-2020 by Wilbert Berendsen <info@wilbertberendsen.nl>
#
# This module 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 3 of the License, or
# (at your option) any later version.
#
# This module 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, see <https://www.gnu.org/licenses/>.
"""
Scheme language and transformation definition.
"""
import itertools
import parce.lang.scheme
import parce.action as a
from quickly.dom import base, element, lily, scm
[docs]class Scheme(parce.lang.scheme.SchemeLily):
"""Scheme language definition."""
[docs] @classmethod
def common(cls, pop=0):
from . import lilypond
yield r"#{", a.Bracket.LilyPond.Start, pop, lilypond.LilyPond.schemelily
yield from super(parce.lang.scheme.SchemeLily, cls).common(pop)
[docs]class SchemeTransform(base.Transform):
"""Transform Scheme quickly.dom."""
# mapping is used in common, below
_common_mapping = {
a.Character: scm.Char,
a.Delimiter.Dot: scm.Dot,
a.Keyword: scm.Identifier,
a.Name: scm.Identifier,
a.Literal.Number.Boolean: scm.Bool,
}
## helper method
[docs] def common(self, items):
"""Yield dom nodes from tokens."""
quotes = []
def nodes():
for i in items:
node = None
if i.is_token:
if i.action == a.Delimiter.Scheme.Quote:
quotes.append(i)
else:
yield self.factory(self._common_mapping[i.action], (i,))
elif isinstance(i.obj, element.Element):
yield i.obj
for node in nodes():
for q in reversed(quotes):
node = self.factory(scm.Quote, (q,), (), node)
quotes.clear()
yield node
### transforming methods
[docs] def root(self, items):
"""Build a full ``scm.Document``."""
return scm.Document(*self.common(items))
[docs] def list(self, items):
"""Build a scm.List ``(`` ... ``)``."""
head = items[:1]
tail = (items.pop(),) if items[-1] == ')' else ()
return self.factory(scm.List, head, tail, *self.common(items[1:]))
[docs] def vector(self, items):
"""Build a scm.Vector ``#(`` ... ``)``."""
head = items[:1]
tail = (items.pop(),) if items[-1] == ')' else ()
return self.factory(scm.Vector, head, tail, *self.common(items[1:]))
_radix_mapping = {
2: scm.Bin,
8: scm.Oct,
10: scm.Number,
16: scm.Hex,
}
[docs] def number(self, items):
"""Create a Number node."""
radix = items.arg or 10
try:
return self.factory(self._radix_mapping[radix], items)
except (ValueError, ZeroDivisionError):
return self.factory(scm.NaN, items)
[docs] def multiline_comment(self, items):
"""Create a MultilineComment node."""
return self.factory(scm.MultilineComment, items)
[docs] def singleline_comment(self, items):
"""Create a SinglelineComment node."""
return self.factory(scm.SinglelineComment, items)
[docs] def scheme(self, items):
"""Create a Scheme node in LilyPond."""
head = items[:1] # $, #, $@ or #@ token introducing scheme mode
scheme = self.factory(lily.Scheme, head)
for i in self.common(items[1:]):
scheme.append(i)
break
return scheme
[docs] def argument(self, items):
"""One scheme object, from within LilyPond."""
for i in self.common(items):
return i
[docs]class SchemeAdHocTransform(base.AdHocTransform, SchemeTransform):
"""SchemeTransform that does not keep the origin tokens."""
pass