[add] tool:convert

This commit is contained in:
Christian Fraß 2022-03-20 21:42:33 +01:00
parent 079d559400
commit 8fe2a17e41

167
tools/convert Executable file
View file

@ -0,0 +1,167 @@
#!/usr/bin/env python3
import sys as _sys
import re as _re
import json as _json
def coin(template, arguments):
result = template
for (key, value, ) in arguments.items():
result = result.replace("{{%s}}" % key, value)
return result
def convert_symbol(symbol):
if (symbol.startswith("<")):
return {"type": "variable", "parameters": {"id": symbol[1:-1]}}
elif (symbol.startswith("[")):
return {"type": "terminal", "parameters": {"id": symbol[1:-1]}}
elif (symbol.startswith("{")):
return {"type": "label", "parameters": {"id": symbol[1:-1]}}
else:
raise ValueError("unknown symbol: %s" % symbol)
def extract_name(symbol, type_):
conversion = convert_symbol(symbol)
if (not (conversion["type"] == type_)):
raise ValueError("type mismatch")
else:
name = conversion["parameters"]["id"]
return (None if (name == "") else name)
def main():
pattern_name = "[0-9a-zA-Z_-]*"
pattern_terminal = coin("\[{{pattern_name}}\]", {"pattern_name": pattern_name})
pattern_variable = coin("<{{pattern_name}}>", {"pattern_name": pattern_name})
pattern_label = coin("\{{{pattern_name}}\}", {"pattern_name": pattern_name})
rules = [
# version
{
"pattern": coin(
"@{{space}}(.+)",
{
"space": "\s*",
}
),
"action": lambda state, matching: {
"version": matching.group(1),
"specification": state["specification"],
},
},
# lexer_rule
{
"pattern": coin(
"{{space}}({{pattern_terminal}}){{space}}:{{space}}\"(.*)\"(?:{{space}}:{{space}}(\S+){{space}})?",
{
"space": "\s*",
"pattern_terminal": pattern_terminal,
}
),
"action": lambda state, matching: {
"version": state["version"],
"specification": {
"version": state["specification"]["version"],
"lexer_rules": (
state["specification"]["lexer_rules"]
+
[{
"pattern": matching.group(2),
"name": extract_name(matching.group(1), "terminal"),
"pass": (len(matching.groups()) >= 3),
}]
),
"parser_rules": state["specification"]["parser_rules"],
"parser_start": state["specification"]["parser_start"],
}
}
},
# parser_rule
{
"pattern": coin(
"({{pattern_label}}){{space}}:{{space}}({{pattern_variable}}){{space}}:(.*)",
{
"space": "\s*",
"pattern_variable": pattern_variable,
"pattern_label": pattern_label,
}
),
"action": lambda state, matching: {
"version": state["version"],
"specification": {
"version": state["specification"]["version"],
"lexer_rules": state["specification"]["lexer_rules"],
"parser_rules": (
state["specification"]["parser_rules"]
+
[{
"label": extract_name(matching.group(1), "label"),
"premise": extract_name(matching.group(2), "variable"),
"conclusion": list(map(
convert_symbol,
_re.findall(
coin(
"{{pattern_terminal}}|{{pattern_variable}}",
{
"pattern_terminal": pattern_terminal,
"pattern_variable": pattern_variable,
}
),
matching.group(3)
)
)),
}]
),
"parser_start": state["specification"]["parser_start"],
}
}
},
# parser_start
{
"pattern": coin(
"({{pattern_variable}})",
{
"space": "\s*",
"pattern_variable": pattern_variable,
}
),
"action": lambda state, matching: {
"version": state["version"],
"specification": {
"version": state["specification"]["version"],
"lexer_rules": state["specification"]["lexer_rules"],
"parser_rules": state["specification"]["parser_rules"],
"parser_start": extract_name(matching.group(1), "variable"),
}
}
},
# empty
{
"pattern": ".*",
"action": lambda state, matching: state,
},
]
state = {
"version": "1",
"specification": {
"version": "2",
"lexer_rules": [],
"parser_rules": [],
"parser_start": None,
},
}
content = _sys.stdin.read()
for line in content.split("\n"):
for rule in rules:
matching = _re.match("^%s$" % rule["pattern"], line)
if (not (matching is None)):
state = rule["action"](state, matching)
break
_sys.stdout.write(_json.dumps(state["specification"], indent = "\t"))
main()