initial commit

This commit is contained in:
Louis Heredero 2023-07-11 15:10:15 +02:00
parent f9965a3b90
commit ec5c21552a
4 changed files with 309 additions and 0 deletions

2
.gitignore vendored
View File

@ -160,3 +160,5 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
config.json
out/

203
XFTGenerator.py Normal file
View File

@ -0,0 +1,203 @@
# XF Template Generator
__author__ = "Louis Heredero"
__copyright__ = "Copyright 2023, Louis Heredero"
__license__ = "GPL3.0"
__version__ = "1.0.0"
import json
import locale
import os
import re
import time
def get_input(title, default=None, non_null=False):
"""Prompts user for an input
Args:
title (str): Name of value
default (Any, optional): Default value. Defaults to None.
non_null (bool, optional): Whether the can be null. Defaults to False.
Returns:
str|None: The value
"""
while True:
txt = title
if default is not None:
txt += f" [{default}]"
txt += ": "
value = input(txt).strip()
if value:
return value
elif default:
return default
elif not non_null:
return ""
def fill_template(dir_, variables, filename):
"""Replaces values in a template file
Args:
dir_ (str): Path of src directory
variables (dict): Dictionary of values to replace
filename (str): Template file name
Returns:
str: Template content with replaced values
"""
with open(os.path.join(dir_, "templates", filename), "r") as f:
content = f.read()
def replace(m):
indent = m.group(1)
key = m.group(2)
txt = variables[key]
if indent:
lines = txt.split("\n")
lines = [indent+line for line in lines]
txt = "\n".join(lines)
return txt
return re.sub("([ \t]*)\$\{(.+?)\}", replace, content)
def output_file(dir_, filename, content):
"""Writes content to a given file. Checks before overwriting
Args:
dir_ (str): Path of src directory
filename (str): Output file name
content (str): Content to write
"""
outdir = os.path.join(dir_, "out")
if not os.path.isdir(outdir):
os.mkdir(outdir)
outpath = os.path.join(outdir, filename)
if os.path.exists(outpath):
replace = input(f"The file {filename} already exists. Overwrite it ? y/N: ")
if replace.lower() != "y":
return
with open(outpath, "w") as f:
f.write(content)
def main():
locale.setlocale(locale.LC_TIME, "en_GB.utf8")
dir_ = os.path.dirname(__file__)
conf_path = os.path.join(dir_, "config.json")
if os.path.exists(conf_path):
with open(conf_path, "r") as f:
variables = json.load(f)
else:
variables = {}
variables["date"] = time.strftime("%B %Y")
variables["author"] = get_input("Author", variables.get("author", ""), True)
variables["filename"] = get_input("Filename", None, True).upper()
variables["filename_lc"] = variables["filename"].lower()
variables["fn"] = get_input("Filename (short)", None, True).upper()
##########
# States #
##########
states = []
print("States (leave empty to end):")
print("> INIT")
while True:
state = input("> ").upper()
if state:
states.append(state)
else:
break
states = ["ST"+variables["fn"]+"_"+s for s in states]
variables["STATES_ENUM"] = ",\n".join(states)
states_cases = []
for i, state in enumerate(states):
case_ = f"case {state}:\n"
case_ += " break;"
states_cases.append(case_)
variables["STATES_CASES"] = "\n\n".join(states_cases)
##########
# Events #
##########
events = ["init = 100"]
print("Events (leave empty to end):")
print("> init")
while True:
event = input("> ").lower()
if event:
events.append(event)
else:
break
events_enum = ["ev"+variables["fn"]+e for e in events]
events_enum = ",\n".join(events_enum).split("\n")
events_enum[0] += " // TODO change this number (< 256)"
variables["EVENTS_ENUM"] = "\n".join(events_enum)
events_emits = []
emit_def = ""
emit_def += "void {filename}_emit{Event}({filename}* me, uint16_t t) {\n"
emit_def += " POST(me, &{filename}_processEvent, ev{fn}{event}, t, 0);\n"
emit_def += "}"
emit_def = emit_def.replace("{filename}", variables["filename"]).replace("{fn}", variables["fn"])
for event in events[1:]:
events_emits.append(
emit_def.replace("{event}", event).replace("{Event}", event.capitalize())
)
variables["EVENTS_EMITS_DEF"] = "\n\n".join(events_emits)
events_emits = []
emit_dec = ""
emit_dec += "/**\n"
emit_dec += " * Emit the {event} event\n"
emit_dec += " * @param me the {filename} itself\n"
emit_dec += " * @param t time to wait in ms before triggering event\n"
emit_dec += " */"
emit_dec += "void {filename}_emit{Event}({filename}* me, uint16_t t);"
emit_dec = emit_dec.replace("{filename}", variables["filename"])
for event in events[1:]:
events_emits.append(
emit_dec.replace("{event}", event).replace("{Event}", event.capitalize())
)
variables["EVENTS_EMITS_DEC"] = "\n\n".join(events_emits)
file_c = fill_template(dir_, variables, "file.c")
file_h = fill_template(dir_, variables, "file.h")
output_file(dir_, variables["filename_lc"]+".c", file_c)
output_file(dir_, variables["filename_lc"]+".h", file_h)
with open(conf_path, "w") as f:
conf = {
"author": variables["author"]
}
json.dump(conf, f)
if __name__ == "__main__":
main()

55
templates/file.c Normal file
View File

@ -0,0 +1,55 @@
/**
* @author ${author}
* @version 1.0.0
* @date ${date}
* @file ${filename_lc}.c
*/
#include "${filename_lc}.h"
void ${filename}_init(${filename}* me){
me->state = ST${fn}_INIT;
}
void ${filename}_startBehaviour(${filename}* me){
POST(me, &${filename}_processEvent, ev${fn}init, 0, 0);
}
bool ${filename}_processEvent(Event* ev) {
bool processed = false;
${filename}* me = (${filename}*)Event_getTarget(ev);
switch (me->state) { // onState
case ST${fn}_INIT:
if (ev->id == ev${fn}init) {
}
break;
${STATES_CASES}
}
if(oldState != me->state){
switch (oldState) { // onExit
case ST${fn}_INIT:
break;
${STATES_CASES}
}
switch (me->state) { // onEntry
case ST${fn}_INIT:
break;
${STATES_CASES}
}
processed = true;
}
return processed;
}
/************
* EMITTERS *
************/
${EVENTS_EMITS_DEF}

49
templates/file.h Normal file
View File

@ -0,0 +1,49 @@
/**
* @author ${author}
* @version 1.0.0
* @date ${date}
* @file ${filename_lc}.h
*/
#ifndef ${filename}_H
#define ${filename}_H
#include "../xf/xf.h"
typedef enum {
${STATES_ENUM}
} ${filename}_STATES;
typedef enum {
${EVENTS_ENUM}
} ${filename}_EVENTS;
typedef struct {
${filename}_STATES state;
} ${filename};
/**
* Initialize the ${filename}
* @param me the ${filename} itself
*/
void ${filename}_init(${filename}* me);
/**
* Start the ${filename} state machine
* @param me the ${filename} itself
*/
void ${filename}_startBehaviour(${filename}* me);
/**
* Process the event
* @param ev the event to process
* @return true if the event is processed
*/
bool ${filename}_processEvent(Event* ev);
/************
* EMITTERS *
************/
${EVENTS_EMITS_DEC}
#endif