<filename>python/caty/jsontools/selector/stm.py
#coding: utf-8
from caty.jsontools import untagged, tag, tagged, TaggedValue, split_tag, xjson
from caty import UNDEFINED

class Nothing(Exception):
    u"""未定義値の検出時に発生する例外
    """

class Selector(object):
    def __init__(self):
        self.next = None
        self.is_optional = False

    def set_optional(self, o):
        self.is_optional = o
        if self.next:
            self.next.set_optional(o)

    def chain(self, next):
        if not self.next:
            self.next = next
        else:
            self.next.chain(next)
        return self

    def select(self, obj):
        o = self.run(obj)
        if self.next:
            for v in o:
                for x in self.next.select(v):
                    if x is UNDEFINED and not self.is_optional:
                        raise Nothing()
                    else:
                        yield x
        else:
            for v in o:
                if v is UNDEFINED and not self.is_optional:
                    raise Nothing()
                else:
                    yield v

    def run(self, obj):
        raise NotImplementedError()

    def _to_str(self):
        return u''

    def to_str(self):
        r = self._to_str()
        if self.next:
            r = '%s.%s' % (r, self.next.to_str())
        return r

class SelectorWrapper(object):
    def __init__(self, selector):
        self.selector = selector
        self.default = UNDEFINED

    def set_optional(self, o):
        self.selector.set_optional(o)

    def set_default(self, default):
        self.default = default

    def select(self, obj):
        for r in self.selector.select(obj):
            if r is UNDEFINED and self.default is not UNDEFINED:
                yield self.default
            else:
                yield r

    def replace(self, src, new, allow_loose=False):
        return self.selector.replace(src, new, allow_loose)

    def to_str(self):
        return self._to_str()

    def _to_str(self):
        r = self.selector.to_str()
        if self.selector.is_optional:
            r += u'?'
        if self.default is not UNDEFINED:
            r += xjson.dumps(self.default)
        return r


class AllSelector(Selector):
    def run(self, obj):
        yield obj

    def replace(self, src, new, allow_loose=False):
        if self.next:
            r = self.next.replace(src, new, allow_loose)
            if not r:
                return src
            else:
                return r
        else:
            return new

    def _to_str(self):
        return '$'

class PropertySelector(Selector):
    def __init__(self, prop, opt=False):
        Selector.__init__(self)
        self.property = prop
        self.is_optional = opt

    def run(self, obj, ignored=False):
        if isinstance(obj, dict):
            if self.property in obj:
                yield obj[self.property]
            elif self.is_optional:
                yield UNDEFINED
            else:
                raise KeyError(self.property)
        elif obj is UNDEFINED:
            yield UNDEFINED
        elif isinstance(obj, TaggedValue) and not ignored:
            for x in self.run(untagged(obj), True):
                yield x
        else:
            #if not self.is_optional:
            raise Exception('not a object')

    def replace(self, obj, new, allow_loose):
        if self.next:
            untagged(obj)[self.property] = self.next.replace(untagged(obj)[self.property], new, allow_loose)
        else:
            untagged(obj)[self.property] = new
            return obj

    def _to_str(self):
        return self.property if ' ' not in self.property else '"%s"' % self.property

class ItemSelector(Selector):
    def __init__(self, prop, optional=False):
        Selector.__init__(self)
        self.property = prop
        self.is_optional = optional

    def run(self, obj, ignored=False):
        if isinstance(obj, (list, tuple)):
            if len(obj) > self.property:
                yield obj[self.property]
            else:
                if self.is_optional:
                    yield UNDEFINED
                else:
                    raise IndexError(str(self.property))
        elif obj is UNDEFINED:
            yield UNDEFINED
        elif isinstance(obj, TaggedValue) and not ignored:
            for x in self.run(untagged(obj), True):
                yield x
        else:
            if not self.is_optional:
                raise Exception('not a array')

    def replace(self, obj, new, allow_loose):
        import caty
        if isinstance(obj, TaggedValue):
            tgt = untagged(obj)
        else:
            tgt = obj
        if self.next:
            tgt[self.property] = self.next.replace(tgt[self.property], new, allow_loose)
        else:
            if self.property < len(tgt):
                tgt[self.property] = new
                return obj
            elif self.property == len(tgt):
                tgt.append(new)
                return obj
            else:
                if allow_loose:
                    while len(tgt) < self.property:
                        tgt.append(caty.UNDEFINED)
                    tgt.append(new)
                    return obj
                else:
                    raise IndexError(self.property)

    def _to_str(self):
        return str(self.property)

class NameWildcardSelector(Selector):
    def run(self, obj):
        if isinstance(obj, dict):
            for v in obj.values():
                yield v
        elif obj is UNDEFINED:
            yield UNDEFINED
        elif isinstance(obj, TaggedValue):
            for x in self.run(untagged(obj)):
                yield x
        else:
            raise Exception('not a object')

    def replace(self, obj, new, allow_loose):
        for k in obj.keys():
            obj[k] = new

    def _to_str(self):
        return '*'

class ItemWildcardSelector(Selector):
    def run(self, obj):
        if isinstance(obj, (tuple, list)):
            for v in obj:
                yield v
        elif obj is UNDEFINED:
            yield UNDEFINED
        elif isinstance(obj, TaggedValue):
            for x in self.run(untagged(obj)):
                yield x
        else:
            raise Exception('not a array')

    def replace(self, obj, new, allow_loose):
        for k in obj.keys():
            obj[k] = new

    def _to_str(self):
        return '#'

class TagSelector(Selector):
    def __init__(self, name, explicit):
        Selector.__init__(self)
        self.name = name
        self.explicit = explicit

    def run(self, obj):
        v = untagged(obj, self.explicit)
        if self.name:
            if self.name != tag(obj):
                raise Exception('%s!=%s' % (self.name, tag(obj)))
        yield v

    def _to_str(self):
        r = '^%s*' % self.name
        if self.explicit:
            r += '!'
        return r

class TagReplacer(Selector):
    def __init__(self, name, explicit):
        Selector.__init__(self)
        self.name = name
        self.explicit = explicit

    def replace(self, obj, new, allow_loose):
        return tagged(new, obj, self.explicit)

    def _to_str(self):
        r = '^%s^' % self.name
        if self.explicit:
            r += '!'
        return r


class TagNameSelector(Selector):
    def __init__(self, explicit):
        Selector.__init__(self)
        self.explicit = explicit

    def run(self, obj):
        v = tag(obj, self.explicit)
        yield v

    def _to_str(self):
        if self.explicit:
            return 'exp-tag()'
        else:
            return 'tag()'

class TagContentSelector(Selector):
    def __init__(self, src):
        Selector.__init__(self)
        self.src= src

    def run(self, obj):
        v = untagged(obj)
        yield v


    def replace(self, obj, new, allow_loose):
        t, v = split_tag(obj)
        if self.next:
            return tagged(t, self.next.replace(v, new, allow_loose))
        else:
            assert False

    def _to_str(self):
        return self.src

class LengthSelector(Selector):

    def __init__(self):
        Selector.__init__(self)

    def run(self, obj, ignored=False):
        if isinstance(obj, (list, tuple)):
            yield len(obj)
        else:
            raise Exception('not a array')

    def _to_str(self):
        return 'length()'

class ItSelector(Selector):

    def __init__(self):
        Selector.__init__(self)

    def run(self, obj, ignored=False):
        if isinstance(obj, (list, tuple)):
            if len(obj) > 0:
                yield obj[0]
            else:
                yield UNDEFINED
        else:
            yield obj

    def _to_str(self):
        return 'it()'


<filename>python/caty/jsontools/selector/stm.py
#coding: utf-8
from caty.jsontools import untagged, tag, tagged, TaggedValue, split_tag, xjson
from caty import UNDEFINED

class Nothing(Exception):
    u"""未定義値の検出時に発生する例外
    """

class Selector(object):
    def __init__(self):
        self.next = None
        self.is_optional = False

    def set_optional(self, o):
        self.is_optional = o
        if self.next:
            self.next.set_optional(o)

    def chain(self, next):
        if not self.next:
            self.next = next
        else:
            self.next.chain(next)
        return self

    def select(self, obj):
        o = self.run(obj)
        if self.next:
            for v in o:
                for x in self.next.select(v):
                    if x is UNDEFINED and not self.is_optional:
                        raise Nothing()
                    else:
                        yield x
        else:
            for v in o:
                if v is UNDEFINED and not self.is_optional:
                    raise Nothing()
                else:
                    yield v

    def run(self, obj):
        raise NotImplementedError()

    def _to_str(self):
        return u''

    def to_str(self):
        r = self._to_str()
        if self.next:
            r = '%s.%s' % (r, self.next.to_str())
        return r

class SelectorWrapper(object):
    def __init__(self, selector):
        self.selector = selector
        self.default = UNDEFINED

    def set_optional(self, o):
        self.selector.set_optional(o)

    def set_default(self, default):
        self.default = default

    def select(self, obj):
        for r in self.selector.select(obj):
            if r is UNDEFINED and self.default is not UNDEFINED:
                yield self.default
            else:
                yield r

    def replace(self, src, new, allow_loose=False):
        return self.selector.replace(src, new, allow_loose)

    def to_str(self):
        return self._to_str()

    def _to_str(self):
        r = self.selector.to_str()
        if self.selector.is_optional:
            r += u'?'
        if self.default is not UNDEFINED:
            r += xjson.dumps(self.default)
        return r


class AllSelector(Selector):
    def run(self, obj):
        yield obj

    def replace(self, src, new, allow_loose=False):
        if self.next:
            r = self.next.replace(src, new, allow_loose)
            if not r:
                return src
            else:
                return r
        else:
            return new

    def _to_str(self):
        return '$'

class PropertySelector(Selector):
    def __init__(self, prop, opt=False):
        Selector.__init__(self)
        self.property = prop
        self.is_optional = opt

    def run(self, obj, ignored=False):
        if isinstance(obj, dict):
            if self.property in obj:
                yield obj[self.property]
            elif self.is_optional:
                yield UNDEFINED
            else:
                raise KeyError(self.property)
        elif obj is UNDEFINED:
            yield UNDEFINED
        elif isinstance(obj, TaggedValue) and not ignored:
            for x in self.run(untagged(obj), True):
                yield x
        else:
            #if not self.is_optional:
            raise Exception('not a object')

    def replace(self, obj, new, allow_loose):
        if self.next:
            untagged(obj)[self.property] = self.next.replace(untagged(obj)[self.property], new, allow_loose)
        else:
            untagged(obj)[self.property] = new
            return obj

    def _to_str(self):
        return self.property if ' ' not in self.property else '"%s"' % self.property

class ItemSelector(Selector):
    def __init__(self, prop, optional=False):
        Selector.__init__(self)
        self.property = prop
        self.is_optional = optional

    def run(self, obj, ignored=False):
        if isinstance(obj, (list, tuple)):
            if len(obj) > self.property:
                yield obj[self.property]
            else:
                if self.is_optional:
                    yield UNDEFINED
                else:
                    raise IndexError(str(self.property))
        elif obj is UNDEFINED:
            yield UNDEFINED
        elif isinstance(obj, TaggedValue) and not ignored:
            for x in self.run(untagged(obj), True):
                yield x
        else:
            if not self.is_optional:
                raise Exception('not a array')

    def replace(self, obj, new, allow_loose):
        import caty
        if isinstance(obj, TaggedValue):
            tgt = untagged(obj)
        else:
            tgt = obj
        if self.next:
            tgt[self.property] = self.next.replace(tgt[self.property], new, allow_loose)
        else:
            if self.property < len(tgt):
                tgt[self.property] = new
                return obj
            elif self.property == len(tgt):
                tgt.append(new)
                return obj
            else:
                if allow_loose:
                    while len(tgt) < self.property:
                        tgt.append(caty.UNDEFINED)
                    tgt.append(new)
                    return obj
                else:
                    raise IndexError(self.property)

    def _to_str(self):
        return str(self.property)

class NameWildcardSelector(Selector):
    def run(self, obj):
        if isinstance(obj, dict):
            for v in obj.values():
                yield v
        elif obj is UNDEFINED:
            yield UNDEFINED
        elif isinstance(obj, TaggedValue):
            for x in self.run(untagged(obj)):
                yield x
        else:
            raise Exception('not a object')

    def replace(self, obj, new, allow_loose):
        for k in obj.keys():
            obj[k] = new

    def _to_str(self):
        return '*'

class ItemWildcardSelector(Selector):
    def run(self, obj):
        if isinstance(obj, (tuple, list)):
            for v in obj:
                yield v
        elif obj is UNDEFINED:
            yield UNDEFINED
        elif isinstance(obj, TaggedValue):
            for x in self.run(untagged(obj)):
                yield x
        else:
            raise Exception('not a array')

    def replace(self, obj, new, allow_loose):
        for k in obj.keys():
            obj[k] = new

    def _to_str(self):
        return '#'

class TagSelector(Selector):
    def __init__(self, name, explicit):
        Selector.__init__(self)
        self.name = name
        self.explicit = explicit

    def run(self, obj):
        v = untagged(obj, self.explicit)
        if self.name:
            if self.name != tag(obj):
                raise Exception('%s!=%s' % (self.name, tag(obj)))
        yield v

    def _to_str(self):
        r = '^%s*' % self.name
        if self.explicit:
            r += '!'
        return r

class TagReplacer(Selector):
    def __init__(self, name, explicit):
        Selector.__init__(self)
        self.name = name
        self.explicit = explicit

    def replace(self, obj, new, allow_loose):
        return tagged(new, obj, self.explicit)

    def _to_str(self):
        r = '^%s^' % self.name
        if self.explicit:
            r += '!'
        return r


class TagNameSelector(Selector):
    def __init__(self, explicit):
        Selector.__init__(self)
        self.explicit = explicit

    def run(self, obj):
        v = tag(obj, self.explicit)
        yield v

    def _to_str(self):
        if self.explicit:
            return 'exp-tag()'
        else:
            return 'tag()'

class TagContentSelector(Selector):
    def __init__(self, src):
        Selector.__init__(self)
        self.src= src

    def run(self, obj):
        v = untagged(obj)
        yield v


    def replace(self, obj, new, allow_loose):
        t, v = split_tag(obj)
        if self.next:
            return tagged(t, self.next.replace(v, new, allow_loose))
        else:
            assert False

    def _to_str(self):
        return self.src

class LengthSelector(Selector):

    def __init__(self):
        Selector.__init__(self)

    def run(self, obj, ignored=False):
        if isinstance(obj, (list, tuple)):
            yield len(obj)
        else:
            raise Exception('not a array')

    def _to_str(self):
        return 'length()'

class ItSelector(Selector):

    def __init__(self):
        Selector.__init__(self)

    def run(self, obj, ignored=False):
        if isinstance(obj, (list, tuple)):
            if len(obj) > 0:
                yield obj[0]
            else:
                yield UNDEFINED
        else:
            yield obj

    def _to_str(self):
        return 'it()'


#coding: utf-8 未定義値の検出時に発生する例外 #if not self.is_optional: