''' It's cheap, but it works. I'd really like to replace this with, like, Awk or something, Python is a big dependency for what is really a small text munging task, eh? Because the strings are parsed at start time, rather than compile time, it's basically the same as implementing an inscribe command and using it to write a simple Joy script to load the defs: for line in defs: print(f'[{line}] inscribe') Eh? But this way the defs get entered into the Gperf wordlist at compile time at least. I wonder if it would be possible, and worth it, to render the definition bodies as C literals? To avoid parsing them at start time? We don't want to GC them anyway, so the fact that they wouldn't be allocated by the GC shouldn't matter. ''' import sys, unicodedata #"&", def_and #"|", def_or SKIP = '''\ clear cmp first lshift rshift mod stack rest'''.splitlines() def filt(name): ''' Pass alphanumeric chars and underscores, convert other chars to their Unicode names so they can work as (portions of) C identifiers. ''' alnum = True for i, ch in enumerate(name): if alnum: if ch.isalnum() or ch == '_': yield ch else: alnum = False if i: yield '_' yield ( unicodedata .name(ch) .replace(' ', '_') .replace('-', '_') ) else: if ch.isalnum() or ch == '_': alnum = True yield '_' yield ch else: yield '_' yield ( unicodedata .name(ch) .replace(' ', '_') .replace('-', '_') ) def convert_name(name): return name if name.isidentifier() else ''.join(filt(name)) defs = [line.strip() for line in open('./defs.txt')] print(f'''\ /* Auto-generated file by {' '.join(sys.argv)} Do not edit. */ ''') if sys.argv[-1] == '--header': for line in defs: name, body = line.split(None, 1) if name in SKIP: continue name = convert_name(name) print(f'void def_{name}(JoyListPtr stack, JoyListPtr expression);') elif sys.argv[-1] == '--keywords': sys.stdout.write(open('KEYWORDS.in').read()) for line in defs: name, body = line.split(None, 1) if name in SKIP: continue print(f'{name}, def_{convert_name(name)}') else: print('''\ #include "joy.h" #include "definitions.h" /* Declare a bunch of list pointers to eventually hold the body expressions of the definitions. */ ''') for line in defs: name, body = line.split(None, 1) if name in SKIP: continue name = convert_name(name) print(f'JoyList def_{name}_body;') print(''' /* Next, we want an initializer function to fill out the body pointers. */ void init_defs(void) { ''') for line in defs: name, body = line.split(None, 1) if name in SKIP: continue name = convert_name(name) print(f'\tdef_{name}_body = text_to_expression("{body}");') print('}') print(''' /* Last, a set of functions to go in the wordlist, one for each definition. */ ''') for line in defs: name, body = line.split(None, 1) if name in SKIP: continue name = convert_name(name) print(f'void def_{name}(__attribute__((unused)) JoyListPtr stack, JoyListPtr expression) {{ push_quote_onto_expression(def_{name}_body, expression); }}')