package refactor
This commit is contained in:
0
thue/__init__.py
Normal file
0
thue/__init__.py
Normal file
100
thue/parser.py
Normal file
100
thue/parser.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import re
|
||||
|
||||
import lark
|
||||
from lark import Lark
|
||||
|
||||
import thue.prods
|
||||
|
||||
grammar = r'''
|
||||
program: suite
|
||||
|
||||
suite: prod*
|
||||
|
||||
?prod: _named_prod | _direct_prod
|
||||
|
||||
_named_prod : alias
|
||||
_direct_prod : _compound_prod | _rule_prod | _literal_prod | _io_prod
|
||||
_io_prod : output | input
|
||||
_compound_prod : cont | sing
|
||||
_rule_prod : full | part
|
||||
_literal_prod : lit | ref
|
||||
|
||||
alias : name "=" prod // production alias
|
||||
output: "~" prod // output production
|
||||
input: ":::" // input production
|
||||
|
||||
cont : "{" suite "}" // continual production
|
||||
sing : "[" suite "]" // singular production
|
||||
|
||||
full : _direct_prod "=>" prod // full application
|
||||
part : ctx "::=" prod // partial application
|
||||
ref : name // production reference
|
||||
|
||||
lit : STRING // literal production
|
||||
name : CNAME // named production
|
||||
|
||||
ctx : REGEX
|
||||
|
||||
CNAME : /[a-z_][a-z0-9_]*/i
|
||||
STRING: /(r)?(['"])(.*?)(?<!\\)\2/
|
||||
REGEX : /(r)?([\/])(.*?)(?<!\\)\2(i)?/
|
||||
|
||||
%import common.WS
|
||||
%ignore WS
|
||||
'''
|
||||
|
||||
STRING_PAT = re.compile(r'''(r)?(['"])(.*?)(?<!\\)\2''')
|
||||
REGEX_PAT = re.compile(r'''(r)?([/])(.*?)(?<!\\)\2(i)?''')
|
||||
ALL_PAT = re.compile(r'''^.*$''')
|
||||
|
||||
|
||||
class ProductionTransformer(lark.Transformer):
|
||||
def suite(self, prods):
|
||||
return thue.prods.Suite(prods)
|
||||
|
||||
def lit(self, prods):
|
||||
fmt, = prods
|
||||
match = STRING_PAT.match(fmt)
|
||||
return thue.prods.Literal(match[3])
|
||||
|
||||
def ctx(self, prods):
|
||||
reg, = prods
|
||||
match = REGEX_PAT.match(reg)
|
||||
return re.compile(match[3])
|
||||
|
||||
def input(self, prods):
|
||||
return thue.prods.Input()
|
||||
|
||||
def output(self, prods):
|
||||
prod, = prods
|
||||
return thue.prods.Output(prod)
|
||||
|
||||
def full(self, prods):
|
||||
lhs, rhs = prods
|
||||
return thue.prods.Full(lhs, rhs)
|
||||
|
||||
def part(self, prods):
|
||||
pat, rhs = prods
|
||||
return thue.prods.Partial(pat, rhs)
|
||||
|
||||
def cont(self, prods):
|
||||
suite, = prods
|
||||
return thue.prods.Continual(suite)
|
||||
|
||||
def sing(self, prods):
|
||||
suite, = prods
|
||||
return thue.prods.Singular(suite)
|
||||
|
||||
def program(self, prods):
|
||||
suite, = prods
|
||||
return thue.prods.Program(suite)
|
||||
|
||||
|
||||
THUE_TRANSFORMER = ProductionTransformer()
|
||||
THUE_LARK = Lark(grammar, start='program')
|
||||
|
||||
|
||||
def compile(src):
|
||||
tree = THUE_LARK.parse(src)
|
||||
pgm = THUE_TRANSFORMER.transform(tree)
|
||||
return pgm
|
||||
160
thue/prods.py
Normal file
160
thue/prods.py
Normal file
@@ -0,0 +1,160 @@
|
||||
import re
|
||||
|
||||
import thue.parser
|
||||
|
||||
|
||||
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:
|
||||
def __init__(self, fmt):
|
||||
self.fmt = fmt
|
||||
|
||||
def apply(self, ctx):
|
||||
ctx_ = ctx.enter()
|
||||
ctx_.expand(self.fmt)
|
||||
return ctx.exit(ctx_)
|
||||
|
||||
def __str__(self):
|
||||
return f'Literal[{self.fmt}]'
|
||||
|
||||
|
||||
class Full:
|
||||
def __init__(self, lhs, rhs):
|
||||
self.lhs = lhs
|
||||
self.rhs = 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}]'
|
||||
|
||||
|
||||
class Partial:
|
||||
def __init__(self, reg, rhs):
|
||||
self.reg = reg
|
||||
self.pat = re.compile(reg)
|
||||
self.rhs = rhs
|
||||
|
||||
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}]'
|
||||
|
||||
|
||||
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_)
|
||||
|
||||
def __str__(self):
|
||||
return 'Input'
|
||||
|
||||
|
||||
class Output:
|
||||
def __init__(self, prod):
|
||||
self.prod = prod
|
||||
|
||||
def apply(self, ctx):
|
||||
_ctx = ctx.enter()
|
||||
self.prod.apply(_ctx)
|
||||
print(_ctx.string)
|
||||
return False
|
||||
|
||||
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}]'
|
||||
Reference in New Issue
Block a user