Skip to content

Instantly share code, notes, and snippets.

@SnowyMouse
Last active June 26, 2021 21:53
Show Gist options
  • Save SnowyMouse/0fe2f8d9f60430c0fd1a847cd5f4287f to your computer and use it in GitHub Desktop.
Save SnowyMouse/0fe2f8d9f60430c0fd1a847cd5f4287f to your computer and use it in GitHub Desktop.
Parse an hs_doc.txt file and output a JSON file
#
# genscriptdefs.py by Snowy Mouse (2021)
#
# Parses an hs_doc.txt file (from using script_doc) and outputs a JSON file to
# be used with a tool
#
# Note that this will specifically ignore begin, begin_random, set, cond, if,
# and any passthrough functions, as these are written in a way that can't really
# be automatically parsed. (The parameter text is probably handwritten)
#
# This script is licensed under version 3 of the GNU General Public License as
# published by the Free Software Foundation. For more information, you can read
# the license here:
#
# https://www.gnu.org/licenses/gpl-3.0.en.html
#
import sys
import json
# Check to make sure we have our arguments
if len(sys.argv) != 3:
print("Usage: {} <hs_doc.txt> <output.json>".format(sys.argv[0]))
sys.exit(1)
# Read the text file line-by-line and use rstrip on each line to remove newlines
with open(sys.argv[1]) as f:
lines = [i.rstrip() for i in f.readlines()]
# Set these here
scripts = []
globals = None
last_script = None
# Go through each line
for m in lines:
# Ignore empty lines
if len(m) == 0:
continue
# If it starts with a left parenthesis, then it's a script/global
if m[0] == "(":
# If we aren't parsing globals yet, add it to the scripts list
if globals is None:
last_script = len(scripts)
scripts.append([m, None])
# If we are parsing globals, add it to the globals
else:
globals.append([m, None])
# Next line
continue
# If the line is this, we start parsing globals then
if m == "; AVAILABLE EXTERNAL GLOBALS:":
globals = []
last_script = None
# If it starts with a semicolon, it's a comment. But hs_doc.txt also has descriptions commented after the command.
if m[0] == ";" and last_script is not None:
scripts[last_script][1] = m
last_script = None
continue
# Function to further process an array of scripts or globals
def parse_array(what):
# Start with an empty array to return later
rv = []
# Go through each object
for i in what:
# Remove the parenthesis and split into words on space
stripped = i[0][1:len(i[0])-1].split(" ")
value = {
# Name is the 2nd object
"name": stripped[1],
# Type is the 1st object - remove the angle brackets
"type": stripped[0][1:len(stripped[0])-1]
}
# We can't really handle these nicely in an automated way so don't include them
if value["name"] == "begin" or value["name"] == "set" or value["name"] == "cond" or value["name"] == "if" or value["name"] == "begin_random":
continue
# If we have a description, set it (remove the first two characters since it's a semicolon and space)
if i[1] is not None:
value["description"] = i[1][2:]
# If we have more than three words, this thing takes parameters then!
if len(stripped) >= 3:
params = []
# Go through each parameter
for n_raw in stripped[2:]:
n = n_raw
param = {}
if n[0] == "[":
n = n[1:len(n)-1]
param["optional"] = True
# Remove the brackets
value_bracketless = n[1:len(n)-1]
# If it ends with "(s)" then it can be multiple values of the same type that go here
if value_bracketless.endswith("(s)"):
value_bracketless = value_bracketless.replace("(s)", "")
param["many"] = True
# And here's the final type
param["type"] = value_bracketless
# Add it
params.append(param)
# Set our parameters to this
value["parameters"] = params
# Add our object
rv.append(value)
# Return the array - we're done
return rv
# Process scripts and globals here
parsed = {
"scripts": parse_array(scripts),
"globals": parse_array(globals)
}
# Write it with four whitespace idents (not necessary and costs space, but it makes the output look pretty)
with open(sys.argv[2], "w") as f:
f.write(json.dumps(parsed, indent=" ") + "\n")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment