diff options
Diffstat (limited to 'qface/generator.py')
-rw-r--r-- | qface/generator.py | 98 |
1 files changed, 74 insertions, 24 deletions
diff --git a/qface/generator.py b/qface/generator.py index c2e018b..572cedf 100644 --- a/qface/generator.py +++ b/qface/generator.py @@ -20,6 +20,7 @@ from .idl.parser.TListener import TListener from .idl.domain import System from .idl.listener import DomainListener from .utils import merge +from .filters import filters try: @@ -34,17 +35,6 @@ logger = logging.getLogger(__name__) Provides an API for accessing the file system and controlling the generator """ - -def upper_first_filter(s): - s = str(s) - return s[0].upper() + s[1:] - - -def lower_first_filter(s): - s = str(s) - return s[0].lower() + s[1:] - - class ReportingErrorListener(ErrorListener.ErrorListener): def __init__(self, document): self.document = document @@ -69,7 +59,7 @@ class Generator(object): strict = False """ enables strict code generation """ - def __init__(self, search_path: str): + def __init__(self, search_path: str, context: dict={}): loader = ChoiceLoader([ FileSystemLoader(search_path), PackageLoader('qface') @@ -79,9 +69,9 @@ class Generator(object): trim_blocks=True, lstrip_blocks=True ) - self.env.filters['upperfirst'] = upper_first_filter - self.env.filters['lowerfirst'] = lower_first_filter + self.env.filters.update(filters) self._destination = Path() + self.context = context @property def destination(self): @@ -90,7 +80,16 @@ class Generator(object): @destination.setter def destination(self, dst: str): - self._destination = Path(dst) + if dst: + self._destination = Path(self.apply(dst, self.context)) + + @property + def filters(self): + return self.env.filters + + @filters.setter + def filters(self, filters): + self.env.filters.update(filters) def get_template(self, name: str): """Retrieves a single template file from the template loader""" @@ -106,10 +105,12 @@ class Generator(object): """Return the rendered text of a template instance""" return self.env.from_string(template).render(context) - def write(self, file_path: Path, template: str, context: dict, preserve: bool = False): + def write(self, file_path: Path, template: str, context: dict={}, preserve: bool = False): """Using a template file name it renders a template into a file given a context """ + if not context: + context = self.context error = False try: self._write(file_path, template, context, preserve) @@ -153,6 +154,49 @@ class Generator(object): self.env.filters[name] = callback +class RuleGenerator(Generator): + """Generates documents based on a rule YAML document""" + def __init__(self, search_path: str, destination: Path, context: dict= {}): + super().__init__(search_path, context) + self.context.update({ + 'dst': destination, + 'project': Path(destination).name, + }) + self.destination = '{{dst}}' + + def process_rules(self, document: Path, system: System): + """writes the templates read from the rules document""" + self.context.update({'system': system}) + rules = FileSystem.load_yaml(document, required=True) + for name, target in rules.items(): + click.secho('process target: {0}'.format(name), fg='green') + self._process_target(target, system) + + def _process_target(self, rules: dict, system: System): + """ process a set of rules for a target """ + self.context.update(rules.get('context', {})) + self.destination = rules.get('destination', '{{dst}}') + self._process_rule(rules.get('system', None), {'system': system}) + for module in system.modules: + self._process_rule(rules.get('module', None), {'module': module}) + for interface in module.interfaces: + self._process_rule(rules.get('interface', None), {'interface': interface}) + for struct in module.structs: + self._process_rule(rules.get('struct', None), {'struct': struct}) + for enum in module.enums: + self._process_rule(rules.get('enum', None), {'enum': enum}) + + def _process_rule(self, rule: dict, context: dict): + """ process a single rule """ + if not rule: + return + self.context.update(context) + self.context.update(rule.get('context', {})) + self.destination = rule.get('destination', None) + for target, source in rule.get('documents', {}).items(): + self.write(target, source) + + class FileSystem(object): """QFace helper functions to work with the file system""" strict = False @@ -172,7 +216,6 @@ class FileSystem(object): if error and FileSystem.strict: sys.exit(-1) - @staticmethod def _parse_document(document: Path, system: System = None): """Parses a document and returns the resulting domain system @@ -205,13 +248,7 @@ class FileSystem(object): """Read a YAML document and for each root symbol identifier updates the tag information of that symbol """ - if not document.exists(): - return - meta = {} - try: - meta = yaml.load(document.text(), Loader=Loader) - except yaml.YAMLError as exc: - click.secho(exc, fg='red') + meta = FileSystem.load_yaml(document) click.secho('merge tags from {0}'.format(document), fg='blue') for identifier, data in meta.items(): symbol = system.lookup(identifier) @@ -252,3 +289,16 @@ class FileSystem(object): if use_cache: cache[identifier] = system return system + + @staticmethod + def load_yaml(document: Path, required=False): + document = Path(document) + if not document.exists(): + if required: + click.secho('yaml document does not exists: {0}'.format(document), fg='red') + return {} + try: + return yaml.load(document.text(), Loader=Loader) + except yaml.YAMLError as exc: + click.secho(exc, fg='red') + return {} |