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)