#!/usr/bin/env python3 ##### # asy-list.py # # Build asy-keywords.el from a list of Asymptote global functions and # variables. This script reads definitions from 'camp.l' and writes Emacs Lisp # code to 'asy-keywords.el'. # ##### import argparse import re import textwrap parser = argparse.ArgumentParser() parser.add_argument( "--asy-list-file", type=str, required=True, help="Path to the asy list file" ) parser.add_argument("--revision", type=str, required=True, help="Revision identifier") parser.add_argument( "--output-file", type=str, required=True, help="Path to output file" ) args = parser.parse_args() # Open the file 'asy-keywords.el' for writing. with open(args.output_file, "w", encoding="utf-8") as keywords: # Write header information to 'asy-keywords.el'. # This includes comments and the definition of 'asy-keywords-version' using a # command-line argument. keywords.write( textwrap.dedent( f"""\ ;; ;; This file is automatically generated by asy-list.py. ;; Changes will be overwritten. ;; (defvar asy-keywords-version "{args.revision}") """ ) ) # Define a function 'add' that adds a keyword to the output file. def add(keyword): keywords.write(keyword + " ") # Write the beginning of the Emacs Lisp definition for 'asy-keyword-name'. keywords.write("(defvar asy-keyword-name '(\n") # Open the file 'camp.l' for reading. with open("camp.l", "r", encoding="utf-8") as camp: # Read lines from 'camp.l' until reaching a line that contains only '%%'. for line in camp: if re.search(r"^%%\s*$", line): break # Continue reading lines from 'camp.l' after the '%%' line. for line in camp: if re.search(r"^%%\s*$", line): # Exit the loop when a second '%%' line is found, indicating the end of # the section. break # Match lines that start with a word (the keyword) followed by optional # whitespace and a '{'. match = re.search(r"^(\w+)\s*\{", line) if match: # Write the keyword followed by a space. keywords.write(match.group(1) + " ") # Open an input file specified in the command-line arguments. with open(args.asy_list_file, "r", encoding="utf-8") as asylist: # Lists to store types, functions, and variables found in the file. types = [] # List to hold data types. functions = [] # List to hold function names. variables = [] # List to hold variable names. # Read each line from the file handle asylist. for line in asylist: # Match lines that define functions. # The pattern looks for: # - An optional word (\w*) representing the return type. # - Any number of non-space characters ([^ ]*), which may include # modifiers. # - A space character. # - Capture the function name (\w*). # - An opening parenthesis '(', indicating the start of the parameter # list. matchFun = re.search(r"^(\w*)[^ ]* (\w*)\(", line) if matchFun: types.append(matchFun.group(1)) functions.append(matchFun.group(2)) # Match lines that declare variables. # The pattern looks for: # - Any non-space characters before a space ([^ ]*), representing the # type. # - A space character. # - Capture the variable name (\w*). # - A semicolon ';', indicating the end of the declaration. matchVarDec = re.search(r"^([^ ]*) (\w*);", line) if matchVarDec: variables.append(matchVarDec.group(2)) # Remove duplicates and sort the lists. types = sorted(set(types)) functions = sorted(set(functions)) variables = sorted(set(variables)) # Write the closing parentheses for the 'asy-keyword-name' definition in the # output file. keywords.write("))\n\n") # Write the beginning of the 'asy-type-name' definition to the output file. keywords.write("(defvar asy-type-name '(\n") # Write each type from types to the output file. for t in types: keywords.write(t + " ") # Write the type followed by a space. # Write the closing parentheses for the 'asy-type-name' definition. keywords.write("))\n\n") # Write the beginning of the 'asy-function-name' definition to the output # file. keywords.write("(defvar asy-function-name '(\n") # Write each function name from functions to the output file. for f in functions: keywords.write(f + " ") # Write the function name followed by a space. # Write the closing parentheses for the 'asy-function-name' definition. keywords.write("))\n\n") # Write the beginning of the 'asy-variable-name' definition to the output # file. keywords.write("(defvar asy-variable-name '(\n") # Write each variable name from variables to the output file. for v in variables: keywords.write(v + " ") # Write the variable name followed by a space. # Write the closing parentheses for the 'asy-variable-name' definition. keywords.write("))\n")