def test_attr_formula1(): text = r""" package example struct Image { scalar w: built_in.uint32 (.defaultValue=1, .maxValue=1000) scalar h: built_in.uint32 (.defaultValue=1, .maxValue=1000) array pixel : built_in.float[w*h] } """ mm = metamodel_for_language("item") assert mm is not None model = mm.model_from_str(text) assert model is not None items = get_children_of_type("Struct", model) assert len(items) == 1 model._tx_filename = "example.item" path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "src-gen") gen1 = generator_for_language_target("item", "cpp") gen2 = generator_for_language_target("item", "python") if os.path.exists(path): shutil.rmtree(path) os.mkdir(path) gen1(mm, model, output_path=path, overwrite=True, debug=False) gen2(mm, model, output_path=path, overwrite=True, debug=False) cpp_code = open(os.path.join(path, "example", "Image.h")).read() print(cpp_code) assert "struct Image" in cpp_code assert "s.w*s.h" in cpp_code
def pytest_configure(config): this_folder = abspath(dirname(__file__)) mm = metamodel_for_language("item") assert mm is not None inpath = join(this_folder, "tests/model/*.item") outpath = join(this_folder, "src-gen") sys.path.append(outpath) # add generated code to python path mm2 = metamodel_for_language("algo") assert mm2 is not None inpath2 = join(this_folder, "tests/model/*.algo") if exists(outpath): rmtree(outpath) mkdir(outpath) for f in glob(inpath, recursive=True): model = mm.model_from_file(f) assert model is not None gen = generator_for_language_target("item", "python") gen(mm, model, output_path=outpath, overwrite=True, debug=False) for f in glob(inpath2, recursive=True): model = mm2.model_from_file(f) assert model is not None gen = generator_for_language_target("algo", "python") gen(mm2, model, output_path=outpath, overwrite=True, debug=False)
def main(debug = False): metamodel_export(data_dsl_mm, join(this_folder, 'family-tree_meta.dot')) family_tree_model = data_dsl_mm.model_from_file(join(this_folder, "miljkovic.family")) model_export(family_tree_model, join(this_folder, 'family-tree.dot')) family_tree_to_txt = generator_for_language_target('family_tree_dsl', 'txt') family_tree_to_txt(data_dsl_mm, family_tree_model,this_folder,True) family_tree_to_html = generator_for_language_target('family_tree_dsl', 'html') family_tree_to_html(data_dsl_mm, family_tree_model,this_folder,True)
def test_big_example(): mm = metamodel_for_language("item") assert mm is not None inpath = join(this_folder, "model") model = mm.model_from_file(join(inpath, "big_example.item")) assert model is not None outpath = join(this_folder, "src-gen") gen = generator_for_language_target("item", "cpp_v2") if exists(outpath): rmtree(outpath) mkdir(outpath) gen(mm, model, output_path=outpath, overwrite=True, debug=False) refpath = join(inpath, "ref") structs = get_children_of_type("Struct", model) enums = get_children_of_type("Enum", model) constants = get_children_of_type("Constants", model) for s in structs + enums + constants: outputfile = output_filename(refpath, s, "regex_ref") if exists(outputfile): check_file( filename=output_filename(outpath, s), regex_reference_filename=outputfile, )
def test_props_load_and_import(): mm = metamodel_for_language("item") assert mm is not None model = mm.model_from_file( os.path.join( os.path.abspath(os.path.dirname(__file__)), "model", "props_example.item" ) ) assert model is not None model._tx_filename = "example.item" path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "src-gen") gen1 = generator_for_language_target("item", "cpp") if os.path.exists(path): shutil.rmtree(path) os.mkdir(path) gen1(mm, model, output_path=path, overwrite=True, debug=False) cpp_code = open(os.path.join(path, "example", "X.h")).read() print(cpp_code) assert "minValue" in cpp_code assert "maxValue" in cpp_code assert "myprop1" in cpp_code assert "myprop2" in cpp_code assert "myprop3" not in cpp_code
def test_example2(): text = r""" package example struct Point { scalar x : built_in.float scalar y : built_in.float } struct Line { scalar p1 : Point scalar p2 : Point } struct Circle { scalar center : Point scalar radius : built_in.float } struct VariantExample { scalar selector: built_in.uint32 variant payload: selector -> { 10: Point 11: Line 12: Circle } } """ mm = metamodel_for_language("item") assert mm is not None model = mm.model_from_str(text) assert model is not None model._tx_filename = "example.item" path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "src-gen") gen1 = generator_for_language_target("item", "cpp") gen2 = generator_for_language_target("item", "python") if os.path.exists(path): shutil.rmtree(path) os.mkdir(path) gen1(mm, model, output_path=path, overwrite=True, debug=False) gen2(mm, model, output_path=path, overwrite=True, debug=False) cpp_code = open(os.path.join(path, "example", "VariantExample.h")).read() print(cpp_code) assert "switch(s.selector)" in cpp_code assert "std::variant" in cpp_code
def generate_extension(target: str, dest_dir: str, **cmd_args: Optional[dict]) -> None: """Generates client installable extension. Args: target: target (client) to generate extension for (e.g. `vscode`) dest_dir: destination directory where extension will be written cmd_args: other optional arguments Returns: None Raises: GenerateExtensionError: if generator does not exists (`TextXRegistrationError`) or any other error that happened while generating the extension """ try: extension_gen = generator_for_language_target("textX", target) extension_gen(None, None, dest_dir, **cmd_args) except Exception as e: raise GenerateExtensionError(target, cmd_args) from e
def test_codegen(): path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "basic", "mean_algo2.algo") mm = metamodel_for_language("algo") assert mm is not None model = mm.model_from_file(path) assert model is not None path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "src-gen") gen = generator_for_language_target("algo", "cpp") if os.path.exists(path): shutil.rmtree(path) os.mkdir(path) gen(mm, model, output_path=path, overwrite=True, debug=False) cpp_code = open(os.path.join(path, "P1", "P2", "MeanAlgo.h")).read() print(cpp_code) assert "struct MeanAlgo" in cpp_code assert "shared_ptr<const Items::MeanAlgo" not in cpp_code assert "shared_ptr<Items::MeanAlgo" not in cpp_code
def test_codegen_python(): path = os.path.join( os.path.abspath(os.path.dirname(__file__)), "basic", "mean_algo_with_shared_ptr.algo", ) mm = metamodel_for_language("algo") assert mm is not None model = mm.model_from_file(path) assert model is not None path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "src-gen") gen = generator_for_language_target("algo", "python") if os.path.exists(path): shutil.rmtree(path) os.mkdir(path) gen(mm, model, output_path=path, overwrite=True, debug=False) py_code = open(os.path.join(path, "P1", "MeanAlgo.py")).read() print(py_code) assert "class MeanAlgo" in py_code assert "i:Items.MeanAlgoInput.MeanAlgoInput" in py_code
def generate_syntaxes(project_name: str, target: str, **cmd_args: Optional[dict]) -> Mapping[str, Any]: """Generates syntax highlighting files for all project languages. NOTE: This is called on grammar changes and it collects new language keywords. (project must be installed in editable mode) Args: project_name: project for which to generate syntax highlightings target: syntax highlight file type (e.g. `vscode`) cmd_args: other optional arguments Returns: A map where keys are language names and values are corresponding syntax highlighting files Raises: GenerateSyntaxHighlightError: if generator does not exists (`TextXRegistrationError`) or any other error that happened while generating syntax highlighting files """ try: syntax_gen = generator_for_language_target("textX", target) lang_syntax_map = {} for lang in get_languages_by_project_name(project_name): lang_name = lang.name.lower() lang_desc = get_language_desc(lang_name) syntax_file = syntax_gen(None, lang_desc.metamodel(), **{ "name": lang_name, **cmd_args }) if syntax_file: lang_syntax_map[lang_name] = syntax_file return lang_syntax_map except Exception as e: raise GenerateSyntaxHighlightError(project_name, target) from e
def test_constants_with_formulas(): text = """ package abc { constants MyConstants (.description = "example") { constant c1: built_in.uint32 = 1 (.description = "constant") constant c2: built_in.float = 3.4 (.description = "constant") constant c3: built_in.uint32 = MyConstants.c1 (.description = "constant") constant c4: built_in.uint32 = c1 (.description = "constant") } struct A { array a: built_in.uint32[2*abc.MyConstants.c1] array b: built_in.uint32[3*MyConstants.c1] array c: built_in.uint32[4*CONST MyConstants.c1] } } """ mm = metamodel_for_language("item") assert mm is not None model = mm.model_from_str(text) assert model is not None model._tx_filename = os.path.join( os.path.abspath(os.path.dirname(__file__)), "mymodel.txt" ) path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "src-gen") gen1 = generator_for_language_target("item", "cpp") if os.path.exists(path): shutil.rmtree(path) os.mkdir(path) gen1(mm, model, output_path=path, overwrite=True, debug=False) cpp_code = open(os.path.join(path, "abc", "A.h")).read() print(cpp_code) assert "2*abc::MyConstants::c1" in cpp_code assert "3*abc::MyConstants::c1" in cpp_code assert "4*abc::MyConstants::c1" in cpp_code
def generate(ctx, model_files, output_path, language, target, overwrite, grammar=None, ignore_case=False): """ Run code generator on a provided model(s). For example:: \b # Generate PlantUML output from .flow models textx generate mymodel.flow --target PlantUML \b # or with defined output folder textx generate mymodel.flow -o rendered_model/ --target PlantUML \b # To chose language by name and not by file pattern use --language textx generate *.flow --language flow --target PlantUML \b # Use --overwrite to overwrite target files textx generate mymodel.flow --target PlantUML --overwrite \b # In all above cases PlantUML generator must be registered, i.e.: $ textx list-generators flow-dsl -> PlantUML Generating PlantUML visualization from flow-dsl \b # If the source language is not registered you can use the .tx grammar # file for parsing but the language name used will be `any`. textx generate --grammar Flow.tx --target dot mymodel.flow """ debug = ctx.obj['debug'] click.echo('Generating {} target from models:'.format(target)) try: per_file_metamodel = False if grammar: metamodel = metamodel_from_file(grammar, debug=debug, ignore_case=ignore_case) language = 'any' elif language: metamodel = metamodel_for_language(language) else: per_file_metamodel = True # Find all custom arguments model_files = list(model_files) model_files_without_args = [] custom_args = {} while model_files: m = model_files.pop(0) if m.startswith('--'): arg_name = m[2:] if not model_files or model_files[0].startswith('--'): # Boolean argument custom_args[arg_name] = True else: custom_args[arg_name] = model_files.pop(0).strip('"\'') else: model_files_without_args.append(m) # Call generator for each model file for model_file in model_files_without_args: click.echo(os.path.abspath(model_file)) if per_file_metamodel: language = language_for_file(model_file).name metamodel = metamodel_for_file(model_file) # Get custom args that match defined model parameters and pass # them in to be available to model processors. model_params = { k: v for k, v in custom_args.items() if k in metamodel.model_param_defs } model = metamodel.model_from_file(model_file, **model_params) generator = generator_for_language_target( language, target, any_permitted=per_file_metamodel) generator(metamodel, model, output_path, overwrite, debug, **custom_args) except TextXRegistrationError as e: raise click.ClickException(e.message) except TextXError as e: raise click.ClickException(str(e))
def generate(ctx, model_files, output_path, language, target, overwrite, grammar=None, ignore_case=False): """ Run code generator on a provided model(s). For example:: \b # Generate PlantUML output from .flow models textx generate mymodel.flow --target PlantUML \b # or with defined output folder textx generate mymodel.flow -o rendered_model/ --target PlantUML \b # To chose language by name and not by file pattern use --language textx generate *.flow --language flow --target PlantUML \b # Use --overwrite to overwrite target files textx generate mymodel.flow --target PlantUML --overwrite \b # In all above cases PlantUML generator must be registered, i.e.: $ textx list-generators flow-dsl -> PlantUML Generating PlantUML visualization from flow-dsl \b # If the source language is not registered you can use the .tx grammar # file for parsing but the language name used will be `any`. textx generate --grammar Flow.tx --target dot mymodel.flow """ debug = ctx.obj['debug'] click.echo('Generating {} target from models:'.format(target)) try: per_file_metamodel = False if grammar: metamodel = metamodel_from_file(grammar, debug=debug, ignore_case=ignore_case) language = 'any' elif language: metamodel = metamodel_for_language(language) else: per_file_metamodel = True # Find all custom arguments model_files = list(model_files) model_files_without_args = [] custom_args = {} while model_files: m = model_files.pop(0) if m.startswith('--'): custom_args[m[2:]] = model_files.pop(0).strip('"\'') else: model_files_without_args.append(m) # Call generator for each model file for model_file in model_files_without_args: click.echo(os.path.abspath(model_file)) if per_file_metamodel: language = language_for_file(model_file).name metamodel = metamodel_for_file(model_file) model = metamodel.model_from_file(model_file) generator = generator_for_language_target( language, target, any_permitted=per_file_metamodel) generator(metamodel, model, output_path, overwrite, debug, **custom_args) except TextXRegistrationError as e: click.echo(e.message) except TextXError as e: click.echo(e)