diff --git a/README.md b/README.md index d10d21f..c0e022b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,33 @@ # App architect +### Python Compiler +There is no faster way for understanding than trying it yourself. +you can execute the next command in the root of the project (this folder) and a simple code wil be generated. +```sh +python .\compiler\compiler.py c "python.json.v1" ./blueprints/examples/calculator/v2/services/processing/operations/sum.code.json code.py +``` + +You can check the base blueprint for this project in the route examples/calculator/v2/services/processing/operations/sum.code.json + +```py +def sum(number_a:int, number_b:int, *, debug:bool=False)->int: + result:str = number_a+number_b + if debug: + print(result) + return result +``` +This is the expected answer, a simple function with all that we specified in the code.json file and ready to be used. + +#### What is so special about this? +This is a basic format for you to generate code in any language, in any framework as long as the correct compiler is available. + +### Current roadmap for this project + +- Finish the basic Python compiler +- Add tests +- Work in the JS Express compiler +- Create a UI from where to Edit code and generate the proper code.json, then you can choose from your saved snippets or those that other people had made public +### App Compiler Design your application in a json like structure, this way the resulting project is going to be easily understood both by human and by machine. This json like structure will let you: diff --git a/blueprints/examples/calculator/v2/services/operate.service.json b/blueprints/examples/calculator/v2/services/operate.service.json index 3eab944..3d821b5 100644 --- a/blueprints/examples/calculator/v2/services/operate.service.json +++ b/blueprints/examples/calculator/v2/services/operate.service.json @@ -2,12 +2,11 @@ "endpoints": { "sum":{ "request":{"a":{"type":"int"}, "b":{"type":"int"}}, - "response":{"a":{"type":"int"}, "b":{"type":"int"}}, + "response":{"result":{"type":"int"}}, "processing":{ - "from": "processing.operations.sum", - "number_a": "a", - "number_b": "b", - "message": "calculating sum" + "__extends":{ + "__from": "processing.operations.sum" + } } } } diff --git a/blueprints/examples/calculator/v2/services/processing/operations/sum.code.json b/blueprints/examples/calculator/v2/services/processing/operations/sum.code.json index dc4cac6..f7dbfd4 100644 --- a/blueprints/examples/calculator/v2/services/processing/operations/sum.code.json +++ b/blueprints/examples/calculator/v2/services/processing/operations/sum.code.json @@ -1,30 +1,45 @@ { "engine": "python3.8", + "__description": "what seams like a simple sum", "__constructor":{ - "description": "what seams like a simple sum", "number_a":{"type":"str", "default":"number_a"}, "number_b":{"type":"str", "default":"number_b"}, - "message":{"type":"str", "default":"adding {__number_a} to {__number_b}"} + "message":{"type":"str", "default":"adding {__number_a} to {__number_b}"}, + "function_name":{"type":"str", "default":"sum"} }, - "inputs":{ - "__number_a":{"type":"str", "required":true}, - "__number_b":{"type":"str", "required":true} + "type": "function", + "name": "__function_name", + "args":{ + "__number_a":{"type":"int", "required":true}, + "__number_b":{"type":"int", "required":true} + }, + "kwargs":{ + "debug":{"type":"bool", "default":false} + }, + "outputs":{ + "result":{"type":"int", "required":true} }, "code": [ - { - "type": "function", - "name": "print", - "args": ["f\"__message\""] - }, { "type": "variable", "variable_type": "str", - "name": "sum_result", - "equals": ["__number_a+number_b"] + "name": "result", + "expression": "__number_a+number_b" + }, + { + "type": "conditional", + "condition": "debug", + "code": [ + { + "type": "function_call", + "function":"print", + "args": ["result"] + } + ] }, { "type": "return", - "args": ["sum_result"] + "args": ["result"] } ] } \ No newline at end of file diff --git a/blueprints/examples/facebook/main.app.json b/blueprints/examples/facebook/main.app.json index d34bfea..736898d 100644 --- a/blueprints/examples/facebook/main.app.json +++ b/blueprints/examples/facebook/main.app.json @@ -2,12 +2,28 @@ "name": "facebook", "models": { "user":"global.utils.auth.user.models.user", - "conversation":"global.communication.chat.models.conversation", - "message":"global.communication.chat.feed.models.message" + "conversation":{"__extends":{ + "__from":"global.communication.chat.models.conversation", + "user":"user" + }}, + "message":{"__extends":{ + "__from":"global.communication.chat.feed.models.message", + "user":"user" + }} }, "services": { - "user":"global.utils.services.user", - "conversation":"global.communication.chat.services.conversation", - "message":"global.communication.chat.services.message" + "user":{"__extends":{ + "__from":"global.utils.auth.user.services.user", + "user":"user" + }}, + "conversation":{"__extends":{ + "__from":"global.communication.chat.services.conversation", + "user":"user", + "conversation":"conversation" + }}, + "message":{"__extends":{ + "__from":"global.communication.chat.services.message", + "user":"user" + }} } } \ No newline at end of file diff --git a/blueprints/global/communication/chat/feed/models/feed.model.json b/blueprints/global/communication/chat/feed/models/feed.model.json index eb5f475..3b14176 100644 --- a/blueprints/global/communication/chat/feed/models/feed.model.json +++ b/blueprints/global/communication/chat/feed/models/feed.model.json @@ -1,8 +1,9 @@ { "__constructor":{ "user":{ - "description":"user to be used" - } + "description":"user model to be used", + "type":"str" + } }, "attributes":{ "id": {"type":"id"}, @@ -10,18 +11,18 @@ }, "create":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__excludes":["id"] } }, "list":{ "__extends":{ - "from":"attributes" + "__from":"attributes" } }, "get":{ "__extends":{ - "from":"create", + "__from":"create", "__excludes":[ "id"] } } diff --git a/blueprints/global/communication/chat/feed/models/message.model.json b/blueprints/global/communication/chat/feed/models/message.model.json index dc95f98..f2863a4 100644 --- a/blueprints/global/communication/chat/feed/models/message.model.json +++ b/blueprints/global/communication/chat/feed/models/message.model.json @@ -1,13 +1,15 @@ { "__constructor":{ "user":{ - "description":"user to be used" - } + "description":"user model to be used", + "type":"str" + } + }, + "__extends":{ + "__from":"global.communication.chat.models.message", + "user":"__user" }, "attributes":{ "feed":{"type":"feed", "required":true, "user":"__user"} - }, - "__extends":{ - "from":"global.communication.chat.models.message" } } \ No newline at end of file diff --git a/blueprints/global/communication/chat/feed/models/reaction.model.json b/blueprints/global/communication/chat/feed/models/reaction.model.json index 39126d8..60ca37a 100644 --- a/blueprints/global/communication/chat/feed/models/reaction.model.json +++ b/blueprints/global/communication/chat/feed/models/reaction.model.json @@ -1,8 +1,9 @@ { "__constructor":{ "user":{ - "description":"user to be used" - } + "description":"user model to be used", + "type":"str" + } }, "attributes":{ "id": {"type":"id"}, @@ -11,18 +12,18 @@ }, "create":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__excludes":["id"] } }, "list":{ "__extends":{ - "from":"attributes" + "__from":"attributes" } }, "get":{ "__extends":{ - "from":"create", + "__from":"create", "__excludes":[ "id"] } } diff --git a/blueprints/global/communication/chat/models/conversation.model.json b/blueprints/global/communication/chat/models/conversation.model.json index 19fb5cb..a76c497 100644 --- a/blueprints/global/communication/chat/models/conversation.model.json +++ b/blueprints/global/communication/chat/models/conversation.model.json @@ -2,7 +2,7 @@ "__constructor":{ "user":{ "description":"user model to be used", - "default":"global.auth.user.models.user" + "type":"str" } }, "attributes":{ @@ -12,19 +12,19 @@ }, "create":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__excludes":["id"] } }, "list":{ "__extends":{ - "from":"attributes" + "__from":"attributes" } }, "get":{ "__extends":{ - "from":"create", - "__excludes":[ "id"] + "__from":"attributes", + "__excludes":["id"] } } } \ No newline at end of file diff --git a/blueprints/global/communication/chat/models/message.model.json b/blueprints/global/communication/chat/models/message.model.json index 5424c15..ce83e85 100644 --- a/blueprints/global/communication/chat/models/message.model.json +++ b/blueprints/global/communication/chat/models/message.model.json @@ -1,7 +1,8 @@ { "__constructor":{ "user":{ - "description":"user to be used" + "description":"user model to be used", + "type":"str" } }, "attributes":{ @@ -13,18 +14,18 @@ }, "create":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__excludes":["id"] } }, "list":{ "__extends":{ - "from":"attributes" + "__from":"attributes" } }, "get":{ "__extends":{ - "from":"create", + "__from":"attributes", "__excludes":[ "id"] } } diff --git a/blueprints/global/communication/chat/services/conversation.service.json b/blueprints/global/communication/chat/services/conversation.service.json index 580b882..ef023f6 100644 --- a/blueprints/global/communication/chat/services/conversation.service.json +++ b/blueprints/global/communication/chat/services/conversation.service.json @@ -2,7 +2,7 @@ "__constructor":{ "conversation":{ "description":"conversation model to be used", - "default":"global.communication.chat.models.conversation" + "type": "str" } }, "endpoints":{ @@ -19,14 +19,14 @@ "list user conversations":{ "request":{ "__extends":{ - "from":"global.utils.models.pagination.request", + "__from":"global.utils.models.pagination.request", "include":["page", "page_size"] }, "user" : {"type": "__conversation.__user.attributes.id"} }, "response":{ "__extends":{ - "from":"global.utils.models.pagination.response", + "__from":"global.utils.models.pagination.response", "include":["total_count", "page_count"] }, "conversations" : {"many": true, "type": "__conversation.list"} diff --git a/blueprints/global/utils/auth/user/models/user.model.json b/blueprints/global/utils/auth/user/models/user.model.json index 5f7e636..0d2a65b 100644 --- a/blueprints/global/utils/auth/user/models/user.model.json +++ b/blueprints/global/utils/auth/user/models/user.model.json @@ -8,13 +8,13 @@ "create":{ "request":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__excludes":["id"] } }, "response":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__includes":["id"] } } @@ -22,7 +22,7 @@ "list":{ "response":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__excludes":["password"] } } @@ -30,13 +30,13 @@ "get":{ "request":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__includes":["id"] } }, "response":{ "__extends":{ - "from":"attributes", + "__from":"attributes", "__excludes":["id"] } } diff --git a/blueprints/global/utils/auth/user/services/user.service.json b/blueprints/global/utils/auth/user/services/user.service.json index e69de29..544b7b4 100644 --- a/blueprints/global/utils/auth/user/services/user.service.json +++ b/blueprints/global/utils/auth/user/services/user.service.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/blueprints/global/utils/models/pagination.model.json b/blueprints/global/utils/models/pagination.model.json index 2c04c41..f33d973 100644 --- a/blueprints/global/utils/models/pagination.model.json +++ b/blueprints/global/utils/models/pagination.model.json @@ -6,7 +6,7 @@ }, "response":{ "__extends":{ - "from":"request" + "__from":"request" }, "total_count":{ "type":"int", "min":0}, "page_count":{ "type":"int", "min":0}, diff --git a/compiler/compiler.py b/compiler/compiler.py index 663ce12..740fec8 100644 --- a/compiler/compiler.py +++ b/compiler/compiler.py @@ -1,22 +1,43 @@ -from json_compiler.Compiler import Compiler as json_compiler +import json import sys -COMPILERS = { - "django-postgres.v1": "under development", - "flask-mongo.v1": "under development", - "nodejs-mongo.v1": "under development", +from json_compiler.Compiler import Compiler as json_compiler +from django_compiler.Compiler import Compiler as django_compiler +from python_compiler.Compiler import Compiler as python_compiler + +COMPILERS = { # "framework.language.version: compiler" + "django.json.v1": django_compiler, + "python.json.v1": python_compiler, + "flask.json.v1": "under development", + "nodejs.json.v1": "under development", "json.v1": json_compiler } def compile(compiler_name, project_name): - compiler = COMPILERS[compiler_name](project_name) - compiler.compile() + compiler = COMPILERS[compiler_name](main_file=project_name) + compiled_project = compiler.compile() + print(compiled_project) + # TODO: propper file extension and format saving + ''' + with open(f"./{sys.argv[4]}", "w") as f: + json.dump(compiled_project, f, indent=4) + ''' OPTIONS = { "compile": compile, "c": compile } def main(): + # 1 action + # 2 compiler + # 3 project + # 4 destination folder OPTIONS[sys.argv[1]](sys.argv[2], sys.argv[3]) return main() -# python .\compiler.py c "json.v1" ../blueprints/examples/facebook/main.app.json -# python .\compiler.py c "json.v1" ./sample_blueprints/samples/import.app.json \ No newline at end of file +# python .\compiler.py c "json.v1" ../blueprints/examples/facebook/main.app.json build +# python .\compiler.py c "json.v1" ./sample_blueprints/samples/import.app.json build +# python .\compiler.py c "json.v1" ./sample_blueprints/samples/construct.app.json build +# python .\compiler.py c "json.v1" ../blueprints/examples/calculator/v2/main.app.json build + +# python .\compiler.py c "django.json.v1" ../blueprints/examples/facebook/main.app.json build +# python .\compiler.py c "python.json.v1" ../blueprints/examples/calculator/v2/services/processing/operations/sum.code.json build/build + diff --git a/compiler/django_compiler/Compiler.py b/compiler/django_compiler/Compiler.py new file mode 100644 index 0000000..76ba73e --- /dev/null +++ b/compiler/django_compiler/Compiler.py @@ -0,0 +1,119 @@ +import os +import json +from pathlib import Path + +from json_compiler.Compiler import Compiler as json_compiler, special_flags_processing, load_json_as_dict, object_route_join +from utils.CustomLogging import CustomLogging +from utils.flags import * + +DJANGO_FIELD_TYPES = { + "email":{ + "name":"CharField", + "max":"max_length" + }, + "id":{ + "name":"BigAutoField", + "required":{ + "primary_key": True + } + }, + "str":{ + "name":"CharField", + "max":"max_length" + }, + "password":{ + "name":"CharField", + "max":"max_length" + }, + "email":{ + "name":"CharField", + "max":"max_length" + }, + "foreign":{ + "name":"ForeignKey", + "required":{ + "on_delete": "models.CASCADE" + } + }, +} + +def compile_field(field_dict, model_names, *, base_folder="", object_route=""): + #compiled = "" + if field_dict["type"] == "id": + #models.BigAutoField(primary_key=True) + CustomLogging.log(f"skipping id since django already defines it") + return + field_type_name = field_dict['type'] + field_args = [] + if field_dict['type'] in model_names: + field_type_name = "foreign" + field_args = [field_dict['type']] + field_type = DJANGO_FIELD_TYPES.get(field_type_name, False) + + if not field_type: + CustomLogging.error(f"{object_route} {field_dict['type']} type is not defined") + + field_kwargs = {} + if "max" in field_dict and "max" in field_type: + field_kwargs[field_type["max"]] = field_dict["max"] + field_call_definition = { + "type":"function_call", + "function":f"models.{field_type['name']}", + "kwargs":field_kwargs, + "args":field_args + } + #field_compiled_args = ", ".join([ f"{x}={field_args[x]}" for x in field_args]) + #compiled = f"models.{field_type['name']}({field_compiled_args})" + return field_call_definition#compiled +def compile_model(model_name:str, model_dict:dict, model_names:list, *, base_folder="", base_dict={}, object_route=""): + atributes = {} + for field_name in model_dict: + compiled_field = compile_field(model_dict[field_name], model_names, base_folder=base_folder, object_route=object_route_join(object_route, field_name)) + if compiled_field: + atributes[field_name] = compiled_field + args = { + "model_name":model_name.title(), + "args": atributes, + "desc":"__model_name model class" # recursive constructor + } + dir = Path(os.path.dirname(__file__)) + model_path = dir / "templates" / "model.code.json" + model_template = load_json_as_dict(model_path) + processed = special_flags_processing(model_template, args=args, base_folder=base_folder, base_dict=base_dict, object_route=object_route) + return processed + + +class Compiler: + blueprint: dict = {} + + def __init__(self, *, main_file) -> None: + self.main_folder = Path(os.path.dirname(main_file)) + self.main_file = Path(main_file) + + jcompiler = json_compiler(self.main_file) + self.blueprint = jcompiler.compile() + + def compile_models(self, build): + if MODELS_FIELD not in build: + CustomLogging.error(f"{MODELS_FIELD} field is not defined") + models = build[MODELS_FIELD] + self.model_names = list(models.keys()) + for model in models.copy(): + compiled_model = compile_model(model, models[model]["attributes"], self.model_names, base_folder=self.main_folder, base_dict=models[model], object_route=model) + models[model] = compiled_model + build[MODELS_FIELD] = models + return build + def compile_services(self, build): + if SEVICES_FIELD not in build: + CustomLogging.error(f"{SEVICES_FIELD} field is not defined") + services = build[SEVICES_FIELD] + for service in services.copy(): + print(service) + build[SEVICES_FIELD] = services + return build + + def compile(self) -> dict: + build = self.compile_models(self.blueprint) + #build = self.compile_services(build) + #print(build) + return build diff --git a/compiler/django_compiler/templates/model.code.json b/compiler/django_compiler/templates/model.code.json new file mode 100644 index 0000000..7e924fd --- /dev/null +++ b/compiler/django_compiler/templates/model.code.json @@ -0,0 +1,17 @@ +{ + "engine": "python3.8/django3.2", + "__constructor":{ + "model_name":{"type":"str", "default":"CharField"}, + "args":{"type":"dict"}, + "desc":{"type":"str", "default":"template for django models"} + }, + "description": "__desc", + "import":{ + "models":{"from":"django.db"} + }, + "type": "class", + "name": "__model_name", + "extends": ["models.Model"], + "args":"__args", + "code": [] +} \ No newline at end of file diff --git a/compiler/json_compiler/Compiler.py b/compiler/json_compiler/Compiler.py index c7281d3..ed670d5 100644 --- a/compiler/json_compiler/Compiler.py +++ b/compiler/json_compiler/Compiler.py @@ -1,89 +1,204 @@ import json import os -import pprint import copy +from pathlib import Path from utils.searcher import search_json from utils.CustomLogging import CustomLogging +from utils.flags import * -MODELS_FIELD = "models" -SPECIAL_FIELD_FLAG = "__" -EXTENDS_FIELD = SPECIAL_FIELD_FLAG+"extends" - - +def object_route_join(old, new): + if old == "": + return new + return ".".join(old.split(".")+[new]) +def set_type(object, to_type): + # TODO: implement type serialization + return object def load_json_as_dict(file_name): with open(file_name, "r") as f: return json.load(f) -def special_flags_processing(json_dict, args = {}, *, base_folder=None, base_dict={}, object_route=""): - if SPECIAL_FIELD_FLAG+"constructor" in json_dict: - json_dict.pop(SPECIAL_FIELD_FLAG+"constructor") - if SPECIAL_FIELD_FLAG+"extends" in json_dict: - extends_from = json_dict[SPECIAL_FIELD_FLAG+"extends"]["from"].split(".") - attr_build = {} - if len(extends_from) == 1: - if extends_from[0] in base_dict: - attr_build = special_flags_processing(base_dict[extends_from[0]], base_dict=base_dict, object_route = object_route+"."+extends_from[0]) +def extends(json_dict, *, base_folder=None, base_dict={}, object_route=""): + extends_from = json_dict[FLAG_EXTENDS][FLAG_FROM].split(".") + attr_build = {} + if len(extends_from) == 1: + new_route = object_route_join(object_route,extends_from[0]) + if extends_from[0] in base_dict: + attr_build = special_flags_processing(base_dict[extends_from[0]], base_dict=base_dict, object_route = new_route) + else: + CustomLogging.error(f"Attribute {extends_from[0]} not found extending {object_route}\n{base_dict}") + else: + attr_file_name = search_json(json_dict[FLAG_EXTENDS][FLAG_FROM], base_folder=base_folder) + if not attr_file_name: + CustomLogging.error(f"{json_dict[FLAG_EXTENDS][FLAG_FROM]} path does not exists in") + attr_json = load_json_as_dict(attr_file_name) + attr_build = json_global_compile( + attr_json, + args = json_dict[FLAG_EXTENDS], + base_folder = os.path.dirname(attr_file_name), + object_route=json_dict[FLAG_EXTENDS][FLAG_FROM] + ) + is_excluding = FLAG_EXCLUDES in json_dict[FLAG_EXTENDS] + is_including = FLAG_INCLUDES in json_dict[FLAG_EXTENDS] + if is_including and is_excluding: + CustomLogging.error("can not use excludes and includes in a same block") + if is_including: + new_attr_build = {} + for include in json_dict[FLAG_EXTENDS][FLAG_INCLUDES]: + if include not in attr_build: + CustomLogging.error(f"{object_route} include error: attribute {include} not in {json_dict[SPECIAL_FIELD_FLAG+'extends'][SPECIAL_FIELD_FLAG+'from']}") + new_attr_build[include] = attr_build[include] + attr_build = new_attr_build + if is_excluding: + for exclude in json_dict[FLAG_EXTENDS][FLAG_EXCLUDES]: + if exclude in attr_build: + attr_build.pop(exclude) else: - CustomLogging.error(f"Attribute not found {object_route}.{extends_from[0]}\n{base_dict}") + CustomLogging.warning(f"exclude error {object_route}: attribute {exclude} not in {json_dict[SPECIAL_FIELD_FLAG+'extends'][SPECIAL_FIELD_FLAG+'from']}") + json_dict.update(attr_build) + json_dict.pop(FLAG_EXTENDS) + return json_dict +def cosntruct_replace(main_object, arg_replace, value , *, object_route=""): + if type(main_object) == str: + if(type(value) == str): + return main_object.replace(arg_replace, value) + if(arg_replace == main_object): + return value + return main_object + response_json = {} + for attribute in main_object: + if type(value) == str: + attribute_new_name = attribute.replace(arg_replace, value) + else: + if arg_replace in attribute: + CustomLogging.warning(f"{attribute} can not be constructed since is an attribute name and the value of {arg_replace} is not a string") + attribute_new_name = attribute + attribute_new_value = main_object[attribute] + current_object_route = object_route_join(object_route,attribute) + if type(attribute_new_value) == dict: + attribute_new_value = cosntruct_replace(attribute_new_value, arg_replace, value, object_route=current_object_route) + elif type(attribute_new_value) == list: + attribute_new_value = [ cosntruct_replace(element, arg_replace, value , object_route=object_route_join(current_object_route, str(i))) for i, element in enumerate(attribute_new_value) ] + elif type(attribute_new_value) == str: + attribute_new_value = cosntruct_replace(attribute_new_value, arg_replace, value, object_route=current_object_route) + response_json[attribute_new_name] = attribute_new_value + return response_json +def cosntructor(json_dict, *, args = {}, object_route=""): + constructor_dict = json_dict.pop(SPECIAL_FIELD_FLAG+"constructor") + response_json = copy.deepcopy(json_dict) + args_to_check = copy.deepcopy(args) + if FLAG_FROM in args_to_check: + args_to_check.pop(FLAG_FROM) + if FLAG_EXCLUDES in args_to_check: + args_to_check.pop(FLAG_EXCLUDES) + if FLAG_INCLUDES in args_to_check: + args_to_check.pop(FLAG_INCLUDES) + for arg_to_check in args_to_check: + if arg_to_check not in constructor_dict: + CustomLogging.warning(f"error in constructor: invalid parameter {arg_to_check}") else: - attr_file_name = search_json(json_dict[SPECIAL_FIELD_FLAG+"extends"]["from"], base_folder=base_folder) - if not attr_file_name: - CustomLogging.error(f"{json_dict[SPECIAL_FIELD_FLAG+'extends']['from']} path does not exists in") - attr_json = load_json_as_dict(attr_file_name) - attr_build = json_global_compile(attr_json, base_folder = os.path.dirname(attr_file_name),object_route=json_dict[SPECIAL_FIELD_FLAG+"extends"]["from"]) - is_excluding = SPECIAL_FIELD_FLAG+"excludes" in json_dict[SPECIAL_FIELD_FLAG+"extends"] - is_including = SPECIAL_FIELD_FLAG+"includes" in json_dict[SPECIAL_FIELD_FLAG+"extends"] - if is_including and is_excluding: - CustomLogging.error("can not use excludes and includes in a same block") - if is_including: - new_attr_build = {} - for include in json_dict[SPECIAL_FIELD_FLAG+"extends"][SPECIAL_FIELD_FLAG+"includes"]: - if include not in attr_build: - CustomLogging.error(f"include error: attribute {include} not in {json_dict[SPECIAL_FIELD_FLAG+'extends']['from']}") - new_attr_build[include] = attr_build[include] - attr_build = new_attr_build - if is_excluding: - for exclude in json_dict[SPECIAL_FIELD_FLAG+"extends"][SPECIAL_FIELD_FLAG+"excludes"]: - if exclude in attr_build: - attr_build.pop(exclude) - else: - CustomLogging.warning(f"exclude error: attribute {exclude} not in {json_dict[SPECIAL_FIELD_FLAG+'extends']['from']}") - json_dict.update(attr_build) - json_dict.pop(SPECIAL_FIELD_FLAG+"extends") + constructor_dict.pop(arg_to_check) # remove argument so we know it already was defined + for default_attribute in constructor_dict: + if default_attribute.startswith(SPECIAL_FIELD_FLAG): + continue + if not constructor_dict[default_attribute].get("required", False): + if "default" not in constructor_dict[default_attribute]: + CustomLogging.error(f"{object_route} non required input should have default value") + args_to_check[default_attribute] = set_type(constructor_dict[default_attribute]["default"], constructor_dict[default_attribute]["type"]) + else: + if default_attribute not in args_to_check: + CustomLogging.error(f"{object_route} {default_attribute} is required") + updates = True + while updates: # Dangerous Loop + for arg in args_to_check: + new_value = cosntruct_replace(response_json, SPECIAL_FIELD_FLAG+arg, args_to_check[arg], object_route=object_route) + if new_value == response_json: + updates = False + response_json = new_value + return response_json +def special_flags_processing(json_dict, *, args = {}, base_folder=None, base_dict={}, object_route=""): + if SPECIAL_FIELD_FLAG+"constructor" in json_dict: + json_dict = cosntructor(json_dict, args=args, object_route=object_route) + base_dict = copy.deepcopy(json_dict) + if FLAG_EXTENDS in json_dict: + json_dict = extends(json_dict, base_folder=base_folder, base_dict=base_dict, object_route=object_route) for attribute in json_dict: if type(json_dict[attribute]) == dict: - json_dict[attribute] = special_flags_processing(json_dict[attribute], args, base_folder=base_folder, base_dict=base_dict, object_route=f"{object_route}.{attribute}") + json_dict[attribute] = special_flags_processing( + json_dict[attribute], + args=args, + base_folder=base_folder, + base_dict=base_dict, + object_route=object_route_join(object_route, attribute) + ) return copy.deepcopy(json_dict) -def json_global_compile(json_dict, args = {}, *, base_folder=None, base_dict={}, object_route= ""): - data = special_flags_processing(json_dict, args, base_folder=base_folder, base_dict=json_dict, object_route=object_route) +def get_object(route, base_folder): + attr_file_name=search_json(route, base_folder=base_folder) + if not attr_file_name: + CustomLogging.error(f"{route} path does not exists") + attr_json = load_json_as_dict(attr_file_name) + attr_build = json_global_compile( + attr_json, + base_folder = os.path.dirname(attr_file_name), + object_route=route + ) + return attr_build +def json_global_compile(json_dict, *, args = {}, base_folder=None, base_dict={}, object_route= ""): + data = special_flags_processing(json_dict, args=args, base_folder=base_folder, base_dict=json_dict, object_route=object_route) return data class Compiler: blueprint: dict = {} - def __init__(self, main_file) -> None: - self.main_folder = os.path.dirname(main_file) - self.main_file = main_file - self.blueprint = load_json_as_dict(main_file) + def __init__(self, *, main_file) -> None: + self.main_folder = Path(os.path.dirname(main_file)) + self.main_file = Path(main_file) + self.blueprint = load_json_as_dict(self.main_file) - def compile_models(self): - if MODELS_FIELD not in self.blueprint and EXTENDS_FIELD not in self.blueprint: - CustomLogging.error("models is not defined") - build = json_global_compile(self.blueprint) - for model in build["models"].copy(): + def compile_models(self, build): + if MODELS_FIELD not in build: + CustomLogging.error(f"{MODELS_FIELD} field is not defined") + models = build[MODELS_FIELD] + for model in models.copy(): model_file_name = self.main_file - if type(model) == str: + if type(models[model]) == str: model_file_name = search_json( - build["models"][model], base_folder=self.main_folder) + models[model], base_folder=self.main_folder) if not model_file_name: - CustomLogging.error(build["models"][model], "path does not exists in") + CustomLogging.error(models[model], "path does not exists in") continue model_json = load_json_as_dict(model_file_name) - elif type(model) == dict: - model_json = model + elif type(models[model]) == dict: + model_json = models[model] + else: + CustomLogging.error(f"invalid model {model}") model_build = json_global_compile(model_json, base_folder = os.path.dirname(model_file_name), object_route=model) - build["models"][model] = model_build - pp = pprint.PrettyPrinter(indent=2) - pp.pprint(build) + models[model] = model_build + build[MODELS_FIELD] = models + return build + def compile_services(self, build): + if SEVICES_FIELD not in build: + CustomLogging.error(f"{SEVICES_FIELD} field is not defined") + services = build[SEVICES_FIELD] + for service in services.copy(): + service_file_name = self.main_file + if type(services[service]) == str: + service_file_name = search_json( + services[service], base_folder=self.main_folder) + if not service_file_name: + CustomLogging.error(services[service], "path does not exists in") + continue + service_json = load_json_as_dict(service_file_name) + elif type(services[service]) == dict: + service_json = services[service] + else: + CustomLogging.error(f"invalid service {service}") + service_build = json_global_compile(service_json, base_folder = os.path.dirname(service_file_name), object_route=service) + services[service] = service_build + build[SEVICES_FIELD] = services + return build - def compile(self): - self.compile_models() + def compile(self) -> dict: + build = json_global_compile(self.blueprint, base_folder=self.main_folder) + build = self.compile_models(build) + build = self.compile_services(build) + #print(build) + return build diff --git a/compiler/python_compiler/Compiler.py b/compiler/python_compiler/Compiler.py new file mode 100644 index 0000000..091e5d5 --- /dev/null +++ b/compiler/python_compiler/Compiler.py @@ -0,0 +1,34 @@ +import os +import json + +from json_compiler.Compiler import Compiler as json_compiler, special_flags_processing, load_json_as_dict +from .engines.py3_8.Compiler import compile as py3_9_compiler +from utils.CustomLogging import CustomLogging + +FLAG_ENGINE = "engine" +ENGINES = { + "python3.8":py3_9_compiler +} +class Compiler: + blueprint: dict = {} + + def __init__(self, *, main_file:str = "", blueprint:dict = {}) -> None: + if main_file: + self.main_folder = os.path.dirname(main_file) + self.main_file = main_file + if not blueprint: + raw_blueprint = load_json_as_dict(main_file) + self.blueprint = special_flags_processing(raw_blueprint, base_folder=self.main_folder) + if blueprint: + self.blueprint = special_flags_processing(blueprint, base_folder=self.main_folder) + + def compile(self) -> dict: + build = {} + if engine_type := self.blueprint.get(FLAG_ENGINE): + if engine_compiler := ENGINES.get(engine_type): + build = engine_compiler(self.blueprint) + else: + CustomLogging.error(f"Compiler {engine_type} does not exists") + else: + CustomLogging.error(f"Flag {FLAG_ENGINE} not defined") + return build diff --git a/compiler/python_compiler/engines/py3_8/Compiler.py b/compiler/python_compiler/engines/py3_8/Compiler.py new file mode 100644 index 0000000..4188e0b --- /dev/null +++ b/compiler/python_compiler/engines/py3_8/Compiler.py @@ -0,0 +1,7 @@ +from utils.flags import * +from .get_fragment_class import get_fragment_class + + +def compile(blueprint:dict, *, level = 0)->str: + build = get_fragment_class(blueprint, compile, level=level) + return build.compile() diff --git a/compiler/python_compiler/engines/py3_8/Conditional.py b/compiler/python_compiler/engines/py3_8/Conditional.py new file mode 100644 index 0000000..1e9377c --- /dev/null +++ b/compiler/python_compiler/engines/py3_8/Conditional.py @@ -0,0 +1,33 @@ +from .Fragment import Fragment +from utils.flags import * +from utils.CustomLogging import CustomLogging +from python_compiler.engines.utils.types import get_python_type_str, ANY + +def get_conditional_condition(fragment) -> str: + if not (condition := fragment.get(ATTRIBUTE_CONDITIONAL_CONDITION)): + CustomLogging.critical(f"Fragment type conditional '{ATTRIBUTE_CONDITIONAL_CONDITION}' attribute does not exist") + return condition + +def get_conditional_code(fragment) -> list: + if not (code := fragment.get(ATTRIBUTE_CONDITIONAL_CODE)): + CustomLogging.critical(f"Fragment type conditional '{ATTRIBUTE_CONDITIONAL_CODE}' attribute does not exist") + return code +class Conditional(Fragment): + condition:str + code:list + def __init__(self, blueprint, *args, **kwargs) -> None: + super().__init__( blueprint, *args, **kwargs) + self.condition = get_conditional_condition(blueprint) + self.code = get_conditional_code(blueprint) + def code_lines_compile(self) -> list: + code_build_lines = [] + for line in self.code: + code_build_lines.append(TAB*(self.level+1)+self.general_compile(line)) + return code_build_lines + def compile(self)->str: + fragment_lines = [] + fragment_lines.append(f"if {self.condition}:") + fragment_lines.extend(self.code_lines_compile()) + fragment_build = "\n".join(fragment_lines) + + return fragment_build \ No newline at end of file diff --git a/compiler/python_compiler/engines/py3_8/Fragment.py b/compiler/python_compiler/engines/py3_8/Fragment.py new file mode 100644 index 0000000..889db66 --- /dev/null +++ b/compiler/python_compiler/engines/py3_8/Fragment.py @@ -0,0 +1,11 @@ +class Fragment: + blueprint:dict + general_compile=None#:function + level=0 + def __init__(self, blueprint, *, compile, level=0) -> None: + self.general_compile = compile + self.blueprint = blueprint + self.level = level + def compile(self)->str: + fragment_build = self.blueprint.get("type","") + return fragment_build \ No newline at end of file diff --git a/compiler/python_compiler/engines/py3_8/Function.py b/compiler/python_compiler/engines/py3_8/Function.py new file mode 100644 index 0000000..d8b8b88 --- /dev/null +++ b/compiler/python_compiler/engines/py3_8/Function.py @@ -0,0 +1,74 @@ +from .Fragment import Fragment +from .FunctionArgs import FunctionArgs +from utils.flags import * +from utils.CustomLogging import CustomLogging +from python_compiler.engines.utils.types import get_python_type_str, ANY + +def get_function_name(fragment) -> str: + if not (function_name := fragment.get(ATTRIBUTE_FUNCTION_NAME)): + CustomLogging.critical(f"Fragment type functions 'name' attribute does not exist") + return function_name + +def get_function_args(fragment) -> dict: + if not (function_args := fragment.get(ATTRIBUTE_FUNCTION_ARGS)): + function_args = {} + return function_args + +def get_function_kwargs(fragment) -> dict: + if not (function_kwargs := fragment.get(ATTRIBUTE_FUNCTION_KWARGS)): + function_kwargs = {} + return function_kwargs + +def get_function_outputs(fragment) -> dict: + if not (function_outputs := fragment.get(ATTRIBUTE_FUNCTION_OUTPUTS)): + function_outputs = {} + return function_outputs + +def get_function_code(fragment) -> dict: + if not (function_code := fragment.get(ATTRIBUTE_FUNCTION_CODE)): + function_code = {} + return function_code + +class Function(Fragment): + name:str + args:dict + kwargs:dict + outputs:dict + def __init__(self, blueprint, *args, **kwargs) -> None: + super().__init__( blueprint, *args, **kwargs) + self.name = get_function_name(blueprint) + self.args = get_function_args(blueprint) + self.kwargs = get_function_kwargs(blueprint) + self.outputs = get_function_outputs(blueprint) + self.code = get_function_code(blueprint) + def inputs_compile(self) -> str: + inputs_build = "" + if self.args: + function_args = FunctionArgs(self.args, compile=self.general_compile) + inputs_build += function_args.compile() + + if self.kwargs: + function_kwargs = FunctionArgs(self.kwargs, compile=self.general_compile) + if self.args: + inputs_build += "," # TODO: disguisting but effective + inputs_build += f" *, {function_kwargs.compile()}" + return inputs_build + def outputs_compile(self) -> str: + outputs_build = "" + if len(self.outputs) == 1: + if not (arg_type_name := self.outputs[list(self.outputs)[0]].get(ATTRIBUTE_TYPE)): # TODO: Temporal Outoput test + arg_type_name = ANY + outputs_build += f"->{get_python_type_str(arg_type_name)}" + return outputs_build + def code_lines_compile(self) -> list: + code_build_lines = [] + for line in self.code: + code_build_lines.append(TAB*(self.level+1)+self.general_compile(line, level=self.level+1)) + return code_build_lines + def compile(self)->str: + fragment_lines = [] + fragment_lines.append(f"def {self.name}({self.inputs_compile()}){self.outputs_compile()}:") + fragment_lines.extend(self.code_lines_compile()) + fragment_build = "\n".join(fragment_lines) + + return fragment_build \ No newline at end of file diff --git a/compiler/python_compiler/engines/py3_8/FunctionArgs.py b/compiler/python_compiler/engines/py3_8/FunctionArgs.py new file mode 100644 index 0000000..2dd6437 --- /dev/null +++ b/compiler/python_compiler/engines/py3_8/FunctionArgs.py @@ -0,0 +1,23 @@ +from .Fragment import Fragment +from utils.flags import * +from utils.CustomLogging import CustomLogging +from python_compiler.engines.utils.types import get_python_type_str, ANY + + +class FunctionArgs(Fragment): + def __init__(self, blueprint, *args, **kwargs) -> None: + super().__init__(blueprint, *args, **kwargs) + def compile(self)->str: + fragment_build = "" + cleaned_args = [] + for arg in self.blueprint: + if not (arg_type_name := self.blueprint[arg].get(ATTRIBUTE_TYPE)): + arg_type_name = ANY + if (arg_default_value := self.blueprint[arg].get(ATTRIBUTE_DEFAULT, "")) != "": + arg_default_value = "="+str(arg_default_value) + if arg_type := get_python_type_str(arg_type_name): + arg_type = ":"+arg_type + cleaned_arg = f"{arg}{arg_type}{arg_default_value}" + cleaned_args.append(cleaned_arg) + fragment_build = ", ".join(cleaned_args) + return fragment_build \ No newline at end of file diff --git a/compiler/python_compiler/engines/py3_8/FunctionCall.py b/compiler/python_compiler/engines/py3_8/FunctionCall.py new file mode 100644 index 0000000..182a46b --- /dev/null +++ b/compiler/python_compiler/engines/py3_8/FunctionCall.py @@ -0,0 +1,43 @@ +from .Fragment import Fragment +from utils.flags import * +from utils.CustomLogging import CustomLogging +from python_compiler.engines.utils.types import get_python_type_str, ANY + +def get_function_name(fragment) -> str: + if not (function_name := fragment.get(ATTRIBUTE_FUNCTION_CALL_NAME)): + CustomLogging.critical(f"Fragment type function_call '{ATTRIBUTE_FUNCTION_CALL_NAME}' attribute does not exist") + return function_name + +def get_function_args(fragment) -> dict: + if not (function_args := fragment.get(ATTRIBUTE_FUNCTION_ARGS)): + function_args = {} + return function_args + +def get_function_kwargs(fragment) -> dict: + if not (function_kwargs := fragment.get(ATTRIBUTE_FUNCTION_KWARGS)): + function_kwargs = {} + return function_kwargs + +class FunctionCall(Fragment): + name:str + args:dict + kwargs:dict + def __init__(self, blueprint, *args, **kwargs) -> None: + super().__init__( blueprint, *args, **kwargs) + self.name = get_function_name(blueprint) + self.args = get_function_args(blueprint) + self.kwargs = get_function_kwargs(blueprint) + def inputs_compile(self) -> str: + inputs = [] + if self.args: + inputs = self.args + + if self.kwargs: + inputs.extend([ f"{x}:{self.kwargs[x]}" for x in self.kwargs]) + + inputs_build = ", ".join(inputs) + return inputs_build + def compile(self)->str: + fragment_build = f"{self.name}({self.inputs_compile()})" + + return fragment_build \ No newline at end of file diff --git a/compiler/python_compiler/engines/py3_8/Return.py b/compiler/python_compiler/engines/py3_8/Return.py new file mode 100644 index 0000000..a0b87a0 --- /dev/null +++ b/compiler/python_compiler/engines/py3_8/Return.py @@ -0,0 +1,20 @@ +from .Fragment import Fragment +from utils.flags import * +from utils.CustomLogging import CustomLogging +from python_compiler.engines.utils.types import get_python_type_str, ANY + +def get_return_attributes(fragment) -> list: + if not (return_attributes := fragment.get(ATTRIBUTE_FUNCTION_RETURN_ARGS)): + return_attributes = [] + return return_attributes + +class Return(Fragment): + return_attributes:list + def __init__(self, blueprint, *args, **kwargs) -> None: + super().__init__( blueprint, *args, **kwargs) + self.return_attributes = get_return_attributes(blueprint) + def compile(self)->str: + fragment_build = "" + return_attributes_build = ", ".join(self.return_attributes) + fragment_build = f"return {return_attributes_build}" + return fragment_build \ No newline at end of file diff --git a/compiler/python_compiler/engines/py3_8/Variable.py b/compiler/python_compiler/engines/py3_8/Variable.py new file mode 100644 index 0000000..297a9db --- /dev/null +++ b/compiler/python_compiler/engines/py3_8/Variable.py @@ -0,0 +1,61 @@ +from .Fragment import Fragment +from utils.flags import * +from utils.CustomLogging import CustomLogging +#from python_compiler.engines.utils.types import get_python_type_str, ANY + + +DEFAULT_ASSIGN_OPERATOR = "=" +ASSIGN_OPERATORS = { + "=":"=", + "+=":"+=", + "-=":"-=", + "*=":"*=", + "/=":"/=", + "//=":"//=", + "%=":"%=", + "**=":"**=", + "&=":"&=", + "|=":"|=", + "^=":"^=", + ">>=":">>=", + "<<=":"<<=", +} + +def get_variable_name(fragment) -> str: + if not (variable_name := fragment.get(ATTRIBUTE_VARIABLE_NAME)): + CustomLogging.critical(f"Fragment type variable '{ATTRIBUTE_VARIABLE_NAME}' attribute does not exist") + return variable_name + +def get_variable_type(fragment) -> str: + if not (variable_type := fragment.get(ATTRIBUTE_VARIABLE_TYPE)): + variable_type = "" + else: + variable_type = ":"+variable_type + return variable_type + +def get_variable_assign_operator(fragment) -> str: + if not (variable_assign_operator := fragment.get(ATTRIBUTE_VARIABLE_ASSIGN_OPERATOR)): + variable_assign_operator = DEFAULT_ASSIGN_OPERATOR + return ASSIGN_OPERATORS.get(variable_assign_operator) + +def get_variable_expression(fragment) -> str: + if not (variable_expression := fragment.get(ATTRIBUTE_VARIABLE_EXPRESSION)): + CustomLogging.critical(f"Fragment type variable '{ATTRIBUTE_VARIABLE_EXPRESSION}' attribute does not exist") + return variable_expression + + +class Variable(Fragment): + name:str + variable_type:str + assign_operator:str + expression:str + def __init__(self, blueprint, *args, **kwargs) -> None: + super().__init__(blueprint, *args, **kwargs) + self.name = get_variable_name(blueprint) + self.variable_type = get_variable_type(blueprint) + self.assign_operator = get_variable_assign_operator(blueprint) + self.expression = get_variable_expression(blueprint) + def compile(self)->str: + fragment_build = "" + fragment_build = f"{self.name}{self.variable_type} {self.assign_operator} {self.expression}" + return fragment_build \ No newline at end of file diff --git a/compiler/python_compiler/engines/py3_8/get_fragment_class.py b/compiler/python_compiler/engines/py3_8/get_fragment_class.py new file mode 100644 index 0000000..893d803 --- /dev/null +++ b/compiler/python_compiler/engines/py3_8/get_fragment_class.py @@ -0,0 +1,28 @@ +from utils.flags import * +from utils.CustomLogging import CustomLogging + +from .Fragment import Fragment +from .Function import Function +from .Variable import Variable +from .Conditional import Conditional +from .FunctionCall import FunctionCall +from .Return import Return + + +FRAGMENT_TYPES={ + "function": Function, + "function_call":FunctionCall, + "class":Fragment, + "variable":Variable, + "conditional":Conditional, + "return":Return +} + +def get_fragment_class(blueprint, compile, *, level=0): + if fragment_type := blueprint.get(ATTRIBUTE_FRAGMENT_TYPE): + if fragment_class := FRAGMENT_TYPES[fragment_type]: + return fragment_class(blueprint, compile=compile, level=level) + else: + CustomLogging.error(f"Fragment type {fragment_type} does not exist") + else: + CustomLogging.error(f"Flag {ATTRIBUTE_FRAGMENT_TYPE} not defined in blueprint") \ No newline at end of file diff --git a/compiler/python_compiler/engines/utils/types.py b/compiler/python_compiler/engines/utils/types.py new file mode 100644 index 0000000..44f4ddb --- /dev/null +++ b/compiler/python_compiler/engines/utils/types.py @@ -0,0 +1,13 @@ +ANY = "any" +PYTHON_TYPE_NAMES={ + ANY:False, + "str":"str", #{"name":"str", "type":str} + "int":"int", + "bool":"bool", + "list":"list", + "tuple":"tuple", + "dict":"dict", + +} +def get_python_type_str(type_name:str) -> str: + return PYTHON_TYPE_NAMES.get(type_name) \ No newline at end of file diff --git a/compiler/sample_blueprints/compiled/json/construct.app.json b/compiler/sample_blueprints/compiled/json/construct.app.json new file mode 100644 index 0000000..3ad6a4f --- /dev/null +++ b/compiler/sample_blueprints/compiled/json/construct.app.json @@ -0,0 +1,87 @@ +{ + "models":{ + "human":{ + "attributes":{ + "id":{ + "type":"id" + }, + "nacimiento":{ + "max":20, + "required":true, + "type":"date" + }, + "nombre":{ + "max":20, + "required":true, + "type":"str" + }, + "sector":{ + "max":100, + "required":true, + "type":"str" + } + }, + "create":{ + "request":{ + "nacimiento":{ + "max":20, + "required":true, + "type":"date" + }, + "nombre":{ + "max":20, + "required":true, + "type":"str" + }, + "sector":{ + "max":100, + "required":true, + "type":"str" + } + }, + "response":{ + "id":{ + "type":"id" + } + } + }, + "get":{ + "request":{ + "id":{ + "type":"id" + } + }, + "response":{ + "nacimiento":{ + "max":20, + "required":true, + "type":"date" + }, + "nombre":{ + "max":20, + "required":true, + "type":"str" + }, + "sector":{ + "max":100, + "required":true, + "type":"str" + } + } + }, + "list":{ + "response":{ + "nombre":{ + "max":20, + "required":true, + "type":"str" + } + } + } + } + }, + "name":"construct", + "services":{ + "human":"utils.services.human" + } + } \ No newline at end of file diff --git a/compiler/sample_blueprints/samples/construct.app.json b/compiler/sample_blueprints/samples/construct.app.json new file mode 100644 index 0000000..2fe5d1a --- /dev/null +++ b/compiler/sample_blueprints/samples/construct.app.json @@ -0,0 +1,15 @@ +{ + "name": "construct", + "models": { + "human":{ + "__extends":{ + "__from":"utils.models.human", + "name":"nombre", + "birth":"nacimiento" + } + } + }, + "services": { + "human":"utils.services.human" + } +} \ No newline at end of file diff --git a/compiler/sample_blueprints/samples/utils/models/human.model.json b/compiler/sample_blueprints/samples/utils/models/human.model.json new file mode 100644 index 0000000..ec96ec9 --- /dev/null +++ b/compiler/sample_blueprints/samples/utils/models/human.model.json @@ -0,0 +1,50 @@ +{ + "__description": "a human model", + "__constructor":{ + "name":{"type":"str", "default":"name"}, + "birth":{"type":"str", "default":"birth"}, + "sector":{"type":"str", "default":"sector"} + }, + "attributes":{ + "id": {"type":"id"}, + "__name":{"type":"str", "max":20, "required":true}, + "__birth":{"type":"date", "required":true}, + "__sector":{"type":"str", "max":100, "required":true} + }, + "create":{ + "request":{ + "__extends":{ + "__from":"attributes", + "__excludes":["id"] + } + }, + "response":{ + "__extends":{ + "__from":"attributes", + "__includes":["id"] + } + } + }, + "list":{ + "response":{ + "__extends":{ + "__from":"attributes", + "__includes":["__name"] + } + } + }, + "get":{ + "request":{ + "__extends":{ + "__from":"attributes", + "__includes":["id"] + } + }, + "response":{ + "__extends":{ + "__from":"attributes", + "__excludes":["id"] + } + } + } +} \ No newline at end of file diff --git a/compiler/utils/CustomLogging.py b/compiler/utils/CustomLogging.py index abd5b66..81ade3f 100644 --- a/compiler/utils/CustomLogging.py +++ b/compiler/utils/CustomLogging.py @@ -1,5 +1,9 @@ class CustomLogging(object): + def log(msg:str): + print("LOG:",msg) def error(msg:str): raise NameError(msg) + def critical(msg:str): + raise NameError(msg) def warning(msg:str): print("WARNING:",msg) \ No newline at end of file diff --git a/compiler/utils/flags.py b/compiler/utils/flags.py new file mode 100644 index 0000000..1754c76 --- /dev/null +++ b/compiler/utils/flags.py @@ -0,0 +1,39 @@ +SPECIAL_FIELD_FLAG = "__" +def is_flag(text:str): + return text.startswith(SPECIAL_FIELD_FLAG) +def to_flag(text:str): + return SPECIAL_FIELD_FLAG+text + +MODELS_FIELD = "models" +SEVICES_FIELD = "services" + +FLAG_EXTENDS = to_flag("extends") +FLAG_EXCLUDES = to_flag("excludes") +FLAG_INCLUDES = to_flag("includes") + +FLAG_FROM = to_flag("from") + + +TAB = "\t" + +ATTRIBUTE_FRAGMENT_TYPE = "type" +ATTRIBUTE_TYPE = "type" +ATTRIBUTE_DEFAULT = "default" + +ATTRIBUTE_FUNCTION_NAME = "name" +ATTRIBUTE_FUNCTION_ARGS = "args" +ATTRIBUTE_FUNCTION_KWARGS = "kwargs" +ATTRIBUTE_FUNCTION_OUTPUTS = "outputs" +ATTRIBUTE_FUNCTION_CODE = "code" + +ATTRIBUTE_FUNCTION_RETURN_ARGS = "args" + +ATTRIBUTE_FUNCTION_CALL_NAME = "function" + +ATTRIBUTE_VARIABLE_NAME = "name" +ATTRIBUTE_VARIABLE_TYPE = "variable_type" +ATTRIBUTE_VARIABLE_EXPRESSION = "expression" +ATTRIBUTE_VARIABLE_ASSIGN_OPERATOR = "assign_operator" + +ATTRIBUTE_CONDITIONAL_CONDITION = "condition" +ATTRIBUTE_CONDITIONAL_CODE = "code" \ No newline at end of file diff --git a/compiler/utils/searcher.py b/compiler/utils/searcher.py index 7756344..7e9e358 100644 --- a/compiler/utils/searcher.py +++ b/compiler/utils/searcher.py @@ -1,13 +1,16 @@ import os -GLOBAL_ROUTE = "../blueprints" +from pathlib import Path +dir = Path(os.path.dirname(__file__)) +GLOBAL_ROUTE = dir / ".." / ".." / "blueprints" + def list_dir(path): return [ x.split(".") for x in os.listdir(path)] -def get_json_file(splitted_route, dir_path): +def get_json_file(splitted_route, dir_path): # dir_path:pathlib.Path files_names = list_dir(dir_path) for file_name in files_names: if splitted_route[0] == file_name[0]: - new_path = dir_path+"/"+".".join(file_name) + new_path = dir_path / ".".join(file_name) if os.path.isfile(new_path): return new_path else: