Skip to content

Commit

Permalink
Join with support function.
Browse files Browse the repository at this point in the history
  • Loading branch information
rickardlindberg committed May 26, 2020
1 parent c2a9bd2 commit c7cde4e
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 114 deletions.
5 changes: 1 addition & 4 deletions writing/rlmeta-poster2/codegenerator.rlmeta
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,6 @@ CodeGenerator {
FnCall = ast:x astItems:y -> { x "(" y ")" }
Native = .
Lookup = py:x -> { "scope.lookup(" x ")" }
astItems =
| ast:x astItem*:xs -> { x xs }
| -> { }
astItem = ast:x -> { ", " x }
astItems = ast*:xs -> #join(xs ", ")
py = .:x -> #repr(x)
}
226 changes: 145 additions & 81 deletions writing/rlmeta-poster2/index.rliterate

Large diffs are not rendered by default.

36 changes: 10 additions & 26 deletions writing/rlmeta-poster2/rlmeta.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import sys
import pprint

SUPPORT = 'def vm(instructions, labels, start_rule, stream):\n action = SemanticAction(None)\n pc = labels[start_rule]\n call_backtrack_stack = []\n stream, pos, stream_pos_stack = (stream, 0, [])\n scope, scope_stack = (None, [])\n fail_message = None\n latest_fail_message, latest_fail_pos = (None, tuple())\n memo = {}\n runtime = {\n "label": Counter().next,\n }\n while True:\n name, arg1, arg2 = instructions[pc]\n if name == "PUSH_SCOPE":\n scope_stack.append(scope)\n scope = {}\n pc += 1\n continue\n elif name == "BACKTRACK":\n call_backtrack_stack.append((\n labels[arg1], pos, len(stream_pos_stack), len(scope_stack)\n ))\n pc += 1\n continue\n elif name == "CALL":\n key = (arg1, tuple([x[1] for x in stream_pos_stack]+[pos]))\n if key in memo:\n if memo[key][0] is None:\n fail_message = memo[key][1]\n else:\n action, stream_pos_stack = memo[key]\n stream_pos_stack = stream_pos_stack[:]\n stream, pos = stream_pos_stack.pop()\n pc += 1\n continue\n else:\n call_backtrack_stack.append((pc+1, key))\n pc = labels[arg1]\n continue\n elif name == "POP_SCOPE":\n scope = scope_stack.pop()\n pc += 1\n continue\n elif name == "MATCH_OBJECT":\n if pos >= len(stream) or stream[pos] != arg1:\n fail_message = ("expected {!r}", arg1)\n else:\n action = SemanticAction(arg1)\n pos += 1\n pc += 1\n continue\n elif name == "COMMIT":\n call_backtrack_stack.pop()\n pc = labels[arg1]\n continue\n elif name == "RETURN":\n if len(call_backtrack_stack) == 0:\n return action.eval()\n pc, key = call_backtrack_stack.pop()\n memo[key] = (action, stream_pos_stack+[(stream, pos)])\n continue\n elif name == "LIST_APPEND":\n scope.append(action)\n pc += 1\n continue\n elif name == "BIND":\n scope[arg1] = action\n pc += 1\n continue\n elif name == "ACTION":\n action = SemanticAction(Scope(scope, runtime), arg1)\n pc += 1\n continue\n elif name == "MATCH_RANGE":\n if pos >= len(stream) or not (arg1 <= stream[pos] <= arg2):\n fail_message = ("expected range {!r}-{!r}", arg1, arg2)\n else:\n action = SemanticAction(stream[pos])\n pos += 1\n pc += 1\n continue\n elif name == "LIST_START":\n scope_stack.append(scope)\n scope = []\n pc += 1\n continue\n elif name == "LIST_END":\n action = SemanticAction(scope, lambda xs: [x.eval() for x in xs])\n scope = scope_stack.pop()\n pc += 1\n continue\n elif name == "MATCH_ANY":\n if pos >= len(stream):\n fail_message = ("expected any",)\n else:\n action = SemanticAction(stream[pos])\n pos += 1\n pc += 1\n continue\n elif name == "PUSH_STREAM":\n if pos >= len(stream) or not isinstance(stream[pos], list):\n fail_message = ("expected list",)\n else:\n stream_pos_stack.append((stream, pos))\n stream = stream[pos]\n pos = 0\n pc += 1\n continue\n elif name == "POP_STREAM":\n if pos < len(stream):\n fail_message = ("expected end of list",)\n else:\n stream, pos = stream_pos_stack.pop()\n pos += 1\n pc += 1\n continue\n elif name == "MATCH_CALL_RULE":\n if pos >= len(stream):\n fail_message = ("expected any",)\n else:\n fn_name = str(stream[pos])\n key = (fn_name, tuple([x[1] for x in stream_pos_stack]+[pos]))\n if key in memo:\n if memo[key][0] is None:\n fail_message = memo[key][1]\n else:\n action, stream_pos_stack = memo[key]\n stream_pos_stack = stream_pos_stack[:]\n stream, pos = stream_pos_stack.pop()\n pc += 1\n continue\n else:\n call_backtrack_stack.append((pc+1, key))\n pc = labels[fn_name]\n pos += 1\n continue\n elif name == "FAIL":\n fail_message = (arg1,)\n else:\n raise Exception("unknown instruction {}".format(name))\n fail_pos = tuple([x[1] for x in stream_pos_stack]+[pos])\n if fail_pos >= latest_fail_pos:\n latest_fail_message = fail_message\n latest_fail_pos = fail_pos\n call_backtrack_entry = tuple()\n while call_backtrack_stack:\n call_backtrack_entry = call_backtrack_stack.pop()\n if len(call_backtrack_entry) == 4:\n break\n else:\n _, key = call_backtrack_entry\n memo[key] = (None, fail_message)\n if len(call_backtrack_entry) != 4:\n raise MatchError(\n latest_fail_message[0].format(*latest_fail_message[1:]),\n latest_fail_pos,\n stream_pos_stack[0][0] if stream_pos_stack else stream\n )\n (pc, pos, stream_stack_len, scope_stack_len) = call_backtrack_entry\n if len(stream_pos_stack) > stream_stack_len:\n stream = stream_pos_stack[stream_stack_len][0]\n stream_pos_stack = stream_pos_stack[:stream_stack_len]\n if len(scope_stack) > scope_stack_len:\n scope = scope_stack[scope_stack_len]\n scope_stack = scope_stack[:scope_stack_len]\n\nclass Counter(object):\n\n def __init__(self):\n self.count = 0\n\n def next(self):\n result = self.count\n self.count += 1\n return result\n\nclass Scope(object):\n\n def __init__(self, match, runtime):\n self.match = match\n self.runtime = runtime\n\n def bind(self, name, value, continuation):\n old = self.runtime.get(name, None)\n self.runtime[name] = value\n try:\n return continuation()\n finally:\n self.runtime[name] = old\n\n def lookup(self, name):\n if name in self.match:\n return self.match[name].eval()\n else:\n return self.runtime.get(name, None)\n\nclass SemanticAction(object):\n\n def __init__(self, value, fn=lambda value: value):\n self.value = value\n self.fn = fn\n\n def eval(self):\n return self.fn(self.value)\n\nclass MatchError(Exception):\n\n def __init__(self, message, pos, stream):\n Exception.__init__(self)\n self.message = message\n self.pos = pos\n self.stream = stream\n\nclass Grammar(object):\n\n def run(self, rule_name, stream):\n instructions = []\n labels = {}\n def I(name, arg1=None, arg2=None):\n instructions.append((name, arg1, arg2))\n def LABEL(name):\n labels[name] = len(instructions)\n self.assemble(I, LABEL)\n return vm(instructions, labels, rule_name, stream)\n\ndef splice(depth, item):\n if depth == 0:\n return [item]\n else:\n return concat([splice(depth-1, subitem) for subitem in item])\n\ndef concat(lists):\n return [x for xs in lists for x in xs]\n\ndef join(items):\n return "".join(\n join(item) if isinstance(item, list) else str(item)\n for item in items\n )\n\ndef indent(text):\n return join(join([" ", line]) for line in text.splitlines(True))\n'
SUPPORT = 'def vm(instructions, labels, start_rule, stream):\n action = SemanticAction(None)\n pc = labels[start_rule]\n call_backtrack_stack = []\n stream, pos, stream_pos_stack = (stream, 0, [])\n scope, scope_stack = (None, [])\n fail_message = None\n latest_fail_message, latest_fail_pos = (None, tuple())\n memo = {}\n runtime = {\n "label": Counter().next,\n }\n while True:\n name, arg1, arg2 = instructions[pc]\n if name == "PUSH_SCOPE":\n scope_stack.append(scope)\n scope = {}\n pc += 1\n continue\n elif name == "BACKTRACK":\n call_backtrack_stack.append((\n labels[arg1], pos, len(stream_pos_stack), len(scope_stack)\n ))\n pc += 1\n continue\n elif name == "CALL":\n key = (arg1, tuple([x[1] for x in stream_pos_stack]+[pos]))\n if key in memo:\n if memo[key][0] is None:\n fail_message = memo[key][1]\n else:\n action, stream_pos_stack = memo[key]\n stream_pos_stack = stream_pos_stack[:]\n stream, pos = stream_pos_stack.pop()\n pc += 1\n continue\n else:\n call_backtrack_stack.append((pc+1, key))\n pc = labels[arg1]\n continue\n elif name == "POP_SCOPE":\n scope = scope_stack.pop()\n pc += 1\n continue\n elif name == "MATCH_OBJECT":\n if pos >= len(stream) or stream[pos] != arg1:\n fail_message = ("expected {!r}", arg1)\n else:\n action = SemanticAction(arg1)\n pos += 1\n pc += 1\n continue\n elif name == "COMMIT":\n call_backtrack_stack.pop()\n pc = labels[arg1]\n continue\n elif name == "RETURN":\n if len(call_backtrack_stack) == 0:\n return action.eval()\n pc, key = call_backtrack_stack.pop()\n memo[key] = (action, stream_pos_stack+[(stream, pos)])\n continue\n elif name == "LIST_APPEND":\n scope.append(action)\n pc += 1\n continue\n elif name == "BIND":\n scope[arg1] = action\n pc += 1\n continue\n elif name == "ACTION":\n action = SemanticAction(Scope(scope, runtime), arg1)\n pc += 1\n continue\n elif name == "MATCH_RANGE":\n if pos >= len(stream) or not (arg1 <= stream[pos] <= arg2):\n fail_message = ("expected range {!r}-{!r}", arg1, arg2)\n else:\n action = SemanticAction(stream[pos])\n pos += 1\n pc += 1\n continue\n elif name == "LIST_START":\n scope_stack.append(scope)\n scope = []\n pc += 1\n continue\n elif name == "LIST_END":\n action = SemanticAction(scope, lambda xs: [x.eval() for x in xs])\n scope = scope_stack.pop()\n pc += 1\n continue\n elif name == "MATCH_ANY":\n if pos >= len(stream):\n fail_message = ("expected any",)\n else:\n action = SemanticAction(stream[pos])\n pos += 1\n pc += 1\n continue\n elif name == "PUSH_STREAM":\n if pos >= len(stream) or not isinstance(stream[pos], list):\n fail_message = ("expected list",)\n else:\n stream_pos_stack.append((stream, pos))\n stream = stream[pos]\n pos = 0\n pc += 1\n continue\n elif name == "POP_STREAM":\n if pos < len(stream):\n fail_message = ("expected end of list",)\n else:\n stream, pos = stream_pos_stack.pop()\n pos += 1\n pc += 1\n continue\n elif name == "MATCH_CALL_RULE":\n if pos >= len(stream):\n fail_message = ("expected any",)\n else:\n fn_name = str(stream[pos])\n key = (fn_name, tuple([x[1] for x in stream_pos_stack]+[pos]))\n if key in memo:\n if memo[key][0] is None:\n fail_message = memo[key][1]\n else:\n action, stream_pos_stack = memo[key]\n stream_pos_stack = stream_pos_stack[:]\n stream, pos = stream_pos_stack.pop()\n pc += 1\n continue\n else:\n call_backtrack_stack.append((pc+1, key))\n pc = labels[fn_name]\n pos += 1\n continue\n elif name == "FAIL":\n fail_message = (arg1,)\n else:\n raise Exception("unknown instruction {}".format(name))\n fail_pos = tuple([x[1] for x in stream_pos_stack]+[pos])\n if fail_pos >= latest_fail_pos:\n latest_fail_message = fail_message\n latest_fail_pos = fail_pos\n call_backtrack_entry = tuple()\n while call_backtrack_stack:\n call_backtrack_entry = call_backtrack_stack.pop()\n if len(call_backtrack_entry) == 4:\n break\n else:\n _, key = call_backtrack_entry\n memo[key] = (None, fail_message)\n if len(call_backtrack_entry) != 4:\n raise MatchError(\n latest_fail_message[0].format(*latest_fail_message[1:]),\n latest_fail_pos,\n stream_pos_stack[0][0] if stream_pos_stack else stream\n )\n (pc, pos, stream_stack_len, scope_stack_len) = call_backtrack_entry\n if len(stream_pos_stack) > stream_stack_len:\n stream = stream_pos_stack[stream_stack_len][0]\n stream_pos_stack = stream_pos_stack[:stream_stack_len]\n if len(scope_stack) > scope_stack_len:\n scope = scope_stack[scope_stack_len]\n scope_stack = scope_stack[:scope_stack_len]\n\nclass Counter(object):\n\n def __init__(self):\n self.count = 0\n\n def next(self):\n result = self.count\n self.count += 1\n return result\n\nclass Scope(object):\n\n def __init__(self, match, runtime):\n self.match = match\n self.runtime = runtime\n\n def bind(self, name, value, continuation):\n old = self.runtime.get(name, None)\n self.runtime[name] = value\n try:\n return continuation()\n finally:\n self.runtime[name] = old\n\n def lookup(self, name):\n if name in self.match:\n return self.match[name].eval()\n else:\n return self.runtime.get(name, None)\n\nclass SemanticAction(object):\n\n def __init__(self, value, fn=lambda value: value):\n self.value = value\n self.fn = fn\n\n def eval(self):\n return self.fn(self.value)\n\nclass MatchError(Exception):\n\n def __init__(self, message, pos, stream):\n Exception.__init__(self)\n self.message = message\n self.pos = pos\n self.stream = stream\n\nclass Grammar(object):\n\n def run(self, rule_name, stream):\n instructions = []\n labels = {}\n def I(name, arg1=None, arg2=None):\n instructions.append((name, arg1, arg2))\n def LABEL(name):\n labels[name] = len(instructions)\n self.assemble(I, LABEL)\n return vm(instructions, labels, rule_name, stream)\n\ndef splice(depth, item):\n if depth == 0:\n return [item]\n else:\n return concat([splice(depth-1, subitem) for subitem in item])\n\ndef concat(lists):\n return [x for xs in lists for x in xs]\n\ndef join(items, delimiter=""):\n return delimiter.join(\n join(item, delimiter) if isinstance(item, list) else str(item)\n for item in items\n )\n\ndef indent(text):\n return join(join([" ", line]) for line in text.splitlines(True))\n'

def vm(instructions, labels, start_rule, stream):
action = SemanticAction(None)
Expand Down Expand Up @@ -238,9 +238,9 @@ def splice(depth, item):
def concat(lists):
return [x for xs in lists for x in xs]

def join(items):
return "".join(
join(item) if isinstance(item, list) else str(item)
def join(items, delimiter=""):
return delimiter.join(
join(item, delimiter) if isinstance(item, list) else str(item)
for item in items
)

Expand Down Expand Up @@ -1058,33 +1058,17 @@ def assemble(self, I, LABEL):
I('POP_SCOPE')
I('RETURN')
LABEL('astItems')
I('BACKTRACK', 8)
I('PUSH_SCOPE')
I('CALL', 'ast')
I('BIND', 'x')
I('LIST_START')
LABEL(10)
I('BACKTRACK', 11)
I('CALL', 'astItem')
LABEL(8)
I('BACKTRACK', 9)
I('CALL', 'ast')
I('LIST_APPEND')
I('COMMIT', 10)
LABEL(11)
I('COMMIT', 8)
LABEL(9)
I('LIST_END')
I('BIND', 'xs')
I('ACTION', lambda scope: join([scope.lookup('x'), scope.lookup('xs')]))
I('POP_SCOPE')
I('COMMIT', 9)
LABEL(8)
I('PUSH_SCOPE')
I('ACTION', lambda scope: join([]))
I('POP_SCOPE')
LABEL(9)
I('RETURN')
LABEL('astItem')
I('PUSH_SCOPE')
I('CALL', 'ast')
I('BIND', 'x')
I('ACTION', lambda scope: join([', ', scope.lookup('x')]))
I('ACTION', lambda scope: join(scope.lookup('xs'), ', '))
I('POP_SCOPE')
I('RETURN')
LABEL('py')
Expand Down
6 changes: 3 additions & 3 deletions writing/rlmeta-poster2/support.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,9 @@ def splice(depth, item):
def concat(lists):
return [x for xs in lists for x in xs]

def join(items):
return "".join(
join(item) if isinstance(item, list) else str(item)
def join(items, delimiter=""):
return delimiter.join(
join(item, delimiter) if isinstance(item, list) else str(item)
for item in items
)

Expand Down

0 comments on commit c7cde4e

Please sign in to comment.