diff --git a/.idea/misc.xml b/.idea/misc.xml index e0595e7..ab1f664 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/.idea/thue.iml b/.idea/thue.iml index b9b1fff..ab3ffc2 100644 --- a/.idea/thue.iml +++ b/.idea/thue.iml @@ -4,7 +4,7 @@ - + diff --git a/testing.ret b/testing.ret index 4335af4..3f89ae2 100644 --- a/testing.ret +++ b/testing.ret @@ -1,7 +1,17 @@ ::: => { - ~ "\g<0>" - /[aeiou]/ ::= '_' - /[^aeiou_\W]/ ::= ':' + ~ '\g<0>' + '\g<0>_'=> { + /0_/ ::= '1' + /01_/ ::= '10' + /11_/ ::= '1_0' + /^1_/ ::= '10' + } +} - /_:/ ::= [~ "a" ":"] -} \ No newline at end of file +::: => { + ~ '\g<0>' + /[aei]/ ::= ~ 'aei' + /[ou]/ ::= ~ 'ou' + + /[aeiou]/ ::= '_' +} diff --git a/thue/core.py b/thue/core.py new file mode 100644 index 0000000..75d8d6f --- /dev/null +++ b/thue/core.py @@ -0,0 +1,61 @@ +import re + +import thue.parser + + +class Context: + def __init__(self, string, match=None): + self.string = self.match = None + self.set(string, match) + + def enter(self): + return Context(self.string, self.match) + + def set(self, string, match=None): + if match is None: + match = re.match(r'^.*$', string) + self.string = string + self.match = match + + def exit(self, ctx): + diff = self.string != ctx.string + self.string = ctx.string + self.match = ctx.match + return diff + + def expand(self, fmt): + self.match = thue.parser.ALL_PAT.match(self.string) + self.string = self.match.expand(fmt) + + def __str__(self): + return f'Ctx[{self.string!r} {self.match[0]!r} {self.match.groups()}]' + + +class Production: + fields = () + + def apply_local(self, local): + pass + + def apply(self, ctx): + local = ctx.enter() + self.apply_local(local) + return ctx.exit(local) + + def __str__(self): + field_list = ' '.join(map(str, self.fields)) + return f'{type(self)}[{field_list}]' + + +class Program(Production): + def __init__(self, prod): + self.prod = prod + self.fields = prod, + + def apply_local(self, local): + self.prod.apply(local) + + def run(self, init=''): + ctx = Context(init) + self.prod.apply(ctx) + return ctx.string \ No newline at end of file diff --git a/thue/parser.py b/thue/parser.py index 2f2b8d6..adbdc37 100644 --- a/thue/parser.py +++ b/thue/parser.py @@ -3,6 +3,7 @@ import re import lark from lark import Lark +import thue.core import thue.prods grammar = r''' @@ -87,7 +88,7 @@ class ProductionTransformer(lark.Transformer): def program(self, prods): suite, = prods - return thue.prods.Program(suite) + return thue.core.Program(suite) THUE_TRANSFORMER = ProductionTransformer() diff --git a/thue/prods.py b/thue/prods.py index 98ea052..b52a041 100644 --- a/thue/prods.py +++ b/thue/prods.py @@ -1,160 +1,88 @@ import re -import thue.parser +import thue.core -class Context: - def __init__(self, string, match=None): - if match is None: - match = re.match(r'^.*$', string) - - self.string = string - self.match = match - - def enter(self): - return Context(self.string, self.match) - - def exit(self, ctx): - diff = self.string != ctx.string - self.string = ctx.string - self.match = ctx.match - return diff - - def expand(self, fmt): - self.match = thue.parser.ALL_PAT.match(self.string) - self.string = self.match.expand(fmt) - - def __str__(self): - return f'Ctx[{self.string!r} {self.match[0]!r} {self.match.groups()}]' - - -class Literal: +class Literal(thue.core.Production): def __init__(self, fmt): self.fmt = fmt + self.fields = fmt, - def apply(self, ctx): - ctx_ = ctx.enter() - ctx_.expand(self.fmt) - return ctx.exit(ctx_) - - def __str__(self): - return f'Literal[{self.fmt}]' + def apply_local(self, local): + local.expand(self.fmt) -class Full: +class Full(thue.core.Production): def __init__(self, lhs, rhs): self.lhs = lhs self.rhs = rhs + self.fields = (lhs, '=>', rhs) - def apply(self, ctx): - ctx_ = ctx.enter() - self.lhs.apply(ctx_) - self.rhs.apply(ctx_) - return ctx.exit(ctx_) - - def __str__(self): - return f'Full[{self.lhs} => {self.rhs}]' + def apply_local(self, local): + self.lhs.apply(local) + self.rhs.apply(local) -class Partial: +class Partial(thue.core.Production): def __init__(self, reg, rhs): self.reg = reg self.pat = re.compile(reg) self.rhs = rhs + self.fields = reg, '::=', rhs + + def apply_local(self, local): + match = self.pat.search(local.string) + if not match: + return + + sub = thue.core.Context(match[0], match) + self.rhs.apply(sub) + + local.string = local.string[:match.start()] + sub.string + local.string[match.end():] + + +class Input(thue.core.Production): + def apply_local(self, local): + local.set(input()) + + +class Output(thue.core.Production): + def __init__(self, prod): + self.prod = prod + self.fields = prod, def apply(self, ctx): - match = self.pat.search(ctx.string) - - if match: - inner = Context(match[0], match) - self.rhs.apply(inner) - inner.string = ctx.string[:match.start()] + inner.string + ctx.string[match.end():] - return ctx.exit(inner) - - return False - - def __str__(self): - return f'Part[{self.reg} ::= {self.rhs}]' + local = ctx.enter() + self.prod.apply(local) + print(local.string) -class Input: - def apply(self, ctx): - ctx_ = ctx.enter() - ctx_.string = input() - ctx_.match = thue.parser.ALL_PAT.match(ctx_.string) - return ctx.exit(ctx_) +class Continual(thue.core.Production): + def __init__(self, prod): + self.prod = prod + self.fields = prod, - def __str__(self): - return 'Input' + def apply_local(self, local): + while self.prod.apply(local): + pass -class Output: +class Suite(thue.core.Production): + def __init__(self, prods): + self.prods = prods + self.fields = prods + + def apply_local(self, local): + for prod in self.prods: + if prod.apply(local): + break + + +class Singular(thue.core.Production): def __init__(self, prod): self.prod = prod - def apply(self, ctx): - _ctx = ctx.enter() - self.prod.apply(_ctx) - print(_ctx.string) - return False + self.fields = prod, - def __str__(self): - return f'Output[{self.prod}]' - - -class Suite: - def __init__(self, prods, ctx=None): - if ctx is None: - ctx = Context('') - - self.prods = prods - self.ctx = ctx - - def apply(self, ctx): - ctx_ = ctx.enter() - for prod in self.prods: - if prod.apply(ctx_): - break - return ctx.exit(ctx_) - - def __str__(self): - prod_list = ' '.join(map(str, self.prods)) - return f'Suite[{prod_list}]' - - -class Continual: - def __init__(self, suite): - self.suite = suite - - def apply(self, ctx): - res = False - while self.suite.apply(ctx): - res = True - return res - - def __str__(self): - return f'Continual[{self.suite}]' - - -class Singular: - def __init__(self, suite): - self.suite = suite - - def apply(self, ctx): - self.suite.apply(ctx) - - def __str__(self): - return f'Singular[{self.suite}]' - - -class Program: - def __init__(self, suite): - self.suite = suite - - def run(self, init=''): - ctx = Context(init) - self.suite.apply(ctx) - return ctx.string - - def __str__(self): - return f'Program[{self.suite}]' + def apply_local(self, local): + self.prod.apply(local)