Skip to content

Commit

Permalink
Make RLMeta compilable in one command and replace Bash scripts with P…
Browse files Browse the repository at this point in the history
…ython.
  • Loading branch information
rickardlindberg committed May 28, 2020
1 parent 6127d4f commit 935bb77
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 132 deletions.
54 changes: 0 additions & 54 deletions writing/rlmeta-poster2/compile.sh

This file was deleted.

58 changes: 48 additions & 10 deletions writing/rlmeta-poster2/index.rliterate
Expand Up @@ -881,6 +881,44 @@
},
{
"children":[],
"id":"f2e12455018f4d268971ecfd2805f41d",
"paragraphs":[
{
"fragments":[
{
"text":"The complete diff for this change can be found on ",
"type":"text"
},
{
"text":"GitHub",
"type":"link",
"url":"https://github.com/rickardlindberg/rickardlindberg.me/commit/6562b7baf0a28bcd1232e92ad9ab715438365694"
},
{
"text":".",
"type":"text"
}
],
"id":"e790b69ef9504bbba7a05827dfea9e14",
"type":"text"
},
{
"chunkpath":[],
"filepath":[],
"fragments":[
{
"text":"$ wc -l parser.rlmeta codegenerator.rlmeta support.py main.py\n 58 parser.rlmeta (0)\n 66 codegenerator.rlmeta (0)\n 241 support.py (0)\n( 0 compile.sh (-54))\n 46 main.py (+46)\n 411 total (-8)\n",
"type":"code"
}
],
"id":"aebcc35fdd0e40789c06292aa3f8e1bd",
"type":"code"
}
],
"title":"Remove dependency on Bash"
},
{
"children":[],
"id":"70d7264832894ca3ae30a493cb170783",
"paragraphs":[
{
Expand Down Expand Up @@ -1076,47 +1114,47 @@
},
{
"children":[],
"id":"7142a9c9c93e4aa2aaf35c7962eb3c88",
"id":"796be8e2aeb54f79b2a9a9c273ade6fd",
"paragraphs":[
{
"chunkpath":[],
"filepath":[
"compile.sh"
"main.py"
],
"fragments":[
{
"text":"#!/bin/bash\n\nset -e\n\nrlmeta_compiler=\"$1\"\n\nto_python_string() {\n python -c 'import sys; sys.stdout.write(repr(sys.stdin.read()))'\n}\n\nsupport_py_string=$(to_python_string < support.py)\nsupport_py=$(python \"$rlmeta_compiler\" --support)\nparser_py=$(python \"$rlmeta_compiler\" < parser.rlmeta)\ncodegenerator_py=$(python \"$rlmeta_compiler\" < codegenerator.rlmeta)\n\ncat <<EOF\nimport sys\nimport pprint\n\nSUPPORT = $support_py_string\n\n$support_py\n\n$parser_py\n\n$codegenerator_py\n\nif __name__ == \"__main__\":\n if \"--support\" in sys.argv:\n sys.stdout.write(SUPPORT)\n else:\n try:\n sys.stdout.write(\n CodeGenerator().run(\n \"ast\",\n [Parser().run(\"grammar\", sys.stdin.read())]\n )\n )\n except MatchError as e:\n stream = e.stream\n for pos in e.pos[:-1]:\n stream = stream[pos]\n pos = e.pos[-1]\n MARKER = \"\\\\033[0;31m<ERROR POSITION>\\\\033[0m\"\n if isinstance(stream, basestring):\n stream_string = stream[:pos] + MARKER + stream[pos:]\n else:\n stream_string = pprint.pformat(stream)\n sys.exit(\"ERROR: {}\\\\nPOSITION: {}\\\\nSTREAM:\\\\n{}\".format(\n e.message,\n pos,\n indent(stream_string)\n ))\nEOF\n",
"text":"def compile_grammar(grammar):\n return CodeGenerator().run(\n \"ast\",\n [Parser().run(\"grammar\", grammar)]\n )\n\nif __name__ == \"__main__\":\n import sys\n import pprint\n def read(path):\n if path == \"-\":\n return sys.stdin.read()\n with open(path) as f:\n return f.read()\n args = sys.argv[1:] or [\"--compile\", \"-\"]\n while args:\n command = args.pop(0)\n if command == \"--support\":\n sys.stdout.write(SUPPORT)\n elif command == \"--copy\":\n sys.stdout.write(read(args.pop(0)))\n elif command == \"--embed\":\n sys.stdout.write(\"{} = {}\\n\".format(\n args.pop(0),\n repr(read(args.pop(0)))\n ))\n elif command == \"--compile\":\n try:\n sys.stdout.write(compile_grammar(read(args.pop(0))))\n except MatchError as e:\n stream = e.stream\n for pos in e.pos[:-1]:\n stream = stream[pos]\n pos = e.pos[-1]\n MARKER = \"\\033[0;31m<ERROR POSITION>\\033[0m\"\n if isinstance(stream, basestring):\n stream_string = stream[:pos] + MARKER + stream[pos:]\n else:\n stream_string = pprint.pformat(stream)\n sys.exit(\"ERROR: {}\\nPOSITION: {}\\nSTREAM:\\n{}\".format(\n e.message,\n pos,\n indent(stream_string)\n ))\n else:\n sys.exit(\"ERROR: Unknown command '{}'\".format(command))\n",
"type":"code"
}
],
"id":"76749a4bf2c446069218a8573568dc2b",
"id":"b83db3ff07214aaab8d41e8f4239956c",
"language":"",
"type":"code"
}
],
"title":"compile.sh"
"title":"main.py"
},
{
"children":[],
"id":"8c47ff964a3f43a29a4413bbf5b0132d",
"id":"7142a9c9c93e4aa2aaf35c7962eb3c88",
"paragraphs":[
{
"chunkpath":[],
"filepath":[
"meta_compile.sh"
"make.py"
],
"fragments":[
{
"text":"#!/bin/bash\n\nset -e\n\n./compile.sh rlmeta.py > rlmeta1.py\n\n./compile.sh rlmeta1.py > rlmeta2.py\n\n./compile.sh rlmeta2.py > rlmeta3.py\n\n./compile.sh rlmeta3.py > rlmeta4.py\n\nfail() {\n echo \"FAIL!\"\n return 1\n}\n\necho \"Test: Reproduces itself\"\ndiff rlmeta3.py rlmeta4.py\n\necho \"Test: Has its own support library embedded\"\ndiff support.py <(python rlmeta4.py --support)\n\necho \"Test: Error reporting string input\"\necho \"Grammar { foo = . \" | python rlmeta4.py && fail\n\necho \"Test: Disallow semantic action in the middle\"\necho \"Grammar { x = . ->[] . }\" | (python rlmeta4.py 2>&1) > /dev/null && fail\n\nmv rlmeta4.py rlmeta3.py\n\nmv rlmeta3.py rlmeta2.py\n\nmv rlmeta2.py rlmeta1.py\n\nmv rlmeta1.py rlmeta.py\n\necho \"OK\"\n",
"text":"#!/usr/bin/env python\n\nimport os\nimport subprocess\nimport sys\n\ndef make_next_version():\n intermediate_compilers = meta_compile_rlmeta()\n final_compiler = intermediate_compilers.pop(-1)\n test(final_compiler)\n mv(final_compiler, \"rlmeta.py\")\n for compiler in intermediate_compilers:\n rm(compiler)\n log(\"OK!\")\n\ndef test(rlmeta):\n log(\"Test: Has its own support library\")\n assert run_rlmeta(rlmeta, [\"--support\"]) == read(\"support.py\")\n log(\"Test: Disallow semantic action in the middle\")\n run_rlmeta(rlmeta, [], \"Grammar { x = . -> [] . }\", expect_failure=True)\n\ndef meta_compile_rlmeta():\n compiler = \"rlmeta.py\"\n content = read(compiler)\n intermediate_compilers = []\n for i in range(4):\n next_compiler = \"rlmeta{}.py\".format(i+1)\n log(\"Compiling {} -> {}\".format(compiler, next_compiler))\n next_content = compile_rlmeta(compiler)\n write(next_compiler, next_content)\n intermediate_compilers.append(next_compiler)\n if next_content == content:\n return intermediate_compilers\n compiler = next_compiler\n content = next_content\n fail(\"Unable to produce metacompiler.\")\n\ndef compile_rlmeta(rlmeta):\n return run_rlmeta(rlmeta, [\n \"--embed\", \"SUPPORT\", \"support.py\",\n \"--support\",\n \"--compile\", \"parser.rlmeta\",\n \"--compile\", \"codegenerator.rlmeta\",\n \"--copy\", \"main.py\",\n ])\n\ndef run_rlmeta(rlmeta, args, stdin=\"\", expect_failure=False):\n process = subprocess.Popen(\n [\"python\", rlmeta]+args,\n stdin=subprocess.PIPE,\n stdout=subprocess.PIPE\n )\n stdout, _ = process.communicate(stdin)\n if expect_failure:\n if process.returncode == 0:\n fail(\"Expected failure\")\n else:\n if process.returncode != 0:\n fail(\"Expected success\")\n return stdout\n\ndef mv(src, dest):\n log(\"Move {} -> {}\".format(src, dest))\n os.remove(dest)\n os.rename(src, dest)\n\ndef rm(path):\n log(\"Delete {}\".format(path))\n os.remove(path)\n\ndef read(path):\n with open(path) as f:\n return f.read()\n\ndef write(path, content):\n with open(path, \"w\") as f:\n return f.write(content)\n\ndef log(message):\n sys.stdout.write(\"\\033[0;33m{}\\033[0m\\n\".format(message))\n\ndef fail(message):\n sys.exit(\"\\033[0;31mERROR: {}\\033[0m\".format(message))\n\nif __name__ == \"__main__\":\n make_next_version()\n",
"type":"code"
}
],
"id":"93ea6d553d104afdb03637cee08213f9",
"id":"1b424521b5b04caaa46f86422bc91cdf",
"language":"",
"type":"code"
}
],
"title":"meta_compile.sh"
"title":"make.py"
}
],
"id":"730eea3f33b24e07b3714ef4c1981fd1",
Expand Down
46 changes: 46 additions & 0 deletions writing/rlmeta-poster2/main.py
@@ -0,0 +1,46 @@
def compile_grammar(grammar):
return CodeGenerator().run(
"ast",
[Parser().run("grammar", grammar)]
)

if __name__ == "__main__":
import sys
import pprint
def read(path):
if path == "-":
return sys.stdin.read()
with open(path) as f:
return f.read()
args = sys.argv[1:] or ["--compile", "-"]
while args:
command = args.pop(0)
if command == "--support":
sys.stdout.write(SUPPORT)
elif command == "--copy":
sys.stdout.write(read(args.pop(0)))
elif command == "--embed":
sys.stdout.write("{} = {}\n".format(
args.pop(0),
repr(read(args.pop(0)))
))
elif command == "--compile":
try:
sys.stdout.write(compile_grammar(read(args.pop(0))))
except MatchError as e:
stream = e.stream
for pos in e.pos[:-1]:
stream = stream[pos]
pos = e.pos[-1]
MARKER = "\033[0;31m<ERROR POSITION>\033[0m"
if isinstance(stream, basestring):
stream_string = stream[:pos] + MARKER + stream[pos:]
else:
stream_string = pprint.pformat(stream)
sys.exit("ERROR: {}\nPOSITION: {}\nSTREAM:\n{}".format(
e.message,
pos,
indent(stream_string)
))
else:
sys.exit("ERROR: Unknown command '{}'".format(command))
86 changes: 86 additions & 0 deletions writing/rlmeta-poster2/make.py
@@ -0,0 +1,86 @@
#!/usr/bin/env python

import os
import subprocess
import sys

def make_next_version():
intermediate_compilers = meta_compile_rlmeta()
final_compiler = intermediate_compilers.pop(-1)
test(final_compiler)
mv(final_compiler, "rlmeta.py")
for compiler in intermediate_compilers:
rm(compiler)
log("OK!")

def test(rlmeta):
log("Test: Has its own support library")
assert run_rlmeta(rlmeta, ["--support"]) == read("support.py")
log("Test: Disallow semantic action in the middle")
run_rlmeta(rlmeta, [], "Grammar { x = . -> [] . }", expect_failure=True)

def meta_compile_rlmeta():
compiler = "rlmeta.py"
content = read(compiler)
intermediate_compilers = []
for i in range(4):
next_compiler = "rlmeta{}.py".format(i+1)
log("Compiling {} -> {}".format(compiler, next_compiler))
next_content = compile_rlmeta(compiler)
write(next_compiler, next_content)
intermediate_compilers.append(next_compiler)
if next_content == content:
return intermediate_compilers
compiler = next_compiler
content = next_content
fail("Unable to produce metacompiler.")

def compile_rlmeta(rlmeta):
return run_rlmeta(rlmeta, [
"--embed", "SUPPORT", "support.py",
"--support",
"--compile", "parser.rlmeta",
"--compile", "codegenerator.rlmeta",
"--copy", "main.py",
])

def run_rlmeta(rlmeta, args, stdin="", expect_failure=False):
process = subprocess.Popen(
["python", rlmeta]+args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE
)
stdout, _ = process.communicate(stdin)
if expect_failure:
if process.returncode == 0:
fail("Expected failure")
else:
if process.returncode != 0:
fail("Expected success")
return stdout

def mv(src, dest):
log("Move {} -> {}".format(src, dest))
os.remove(dest)
os.rename(src, dest)

def rm(path):
log("Delete {}".format(path))
os.remove(path)

def read(path):
with open(path) as f:
return f.read()

def write(path, content):
with open(path, "w") as f:
return f.write(content)

def log(message):
sys.stdout.write("\033[0;33m{}\033[0m\n".format(message))

def fail(message):
sys.exit("\033[0;31mERROR: {}\033[0m".format(message))

if __name__ == "__main__":
make_next_version()
38 changes: 0 additions & 38 deletions writing/rlmeta-poster2/meta_compile.sh

This file was deleted.

0 comments on commit 935bb77

Please sign in to comment.