diff --git a/AkitaCode/document.py b/AkitaCode/document.py index 408d467..b361d41 100644 --- a/AkitaCode/document.py +++ b/AkitaCode/document.py @@ -5,9 +5,10 @@ from .protocol import Protocol, Vector from .conditionals import generate_combinations import pickle +import time from queue import Queue -VERSION = "2.0.2-beta" +VERSION = "2.0.2" class Document(object): """ @@ -25,7 +26,7 @@ def __init__(self, file="", db="") -> None: self.__protocol_id = None if not Path(file).exists(): self._error = True - self._error_msg = "[PathError] The selected file does not exist or is not accessible at this time." + self._error_msg = f"[PathError] The selected file '{str(Path(file))}' does not exist or is not accessible at this time." else: if not Path(db).exists(): self._error = True @@ -123,7 +124,7 @@ def check_syntax(self, q: Queue) -> bool: return False elif level == 5: - if isinstance(instance,VariableInstance): #(VariableInstance, FunctionInstance)): // Quan estiguin disponibles les funcions. + if isinstance(instance,(VariableInstance, FunctionInstance)): # // Quan estiguin disponibles les funcions. if time_statement: for_instance.nsituations += 1 time_statement = False @@ -187,12 +188,12 @@ def check_spell(self, q:Queue): if instance.value is None: instance.value = v_info["variable_default"] try: - print("Instance Value A:",instance.value, type(instance.value)) + # print("Instance Value A:",instance.value, type(instance.value)) if not isinstance(instance.value,int): v_value:int = int(instance.value,0) else: v_value = instance.value - print("Instance Value B:",instance.value) + # print("Instance Value B:",instance.value) instance.value = v_value if nbits > 1: mult = int(v_info["variable_mul"]) @@ -338,7 +339,7 @@ def check_spell(self, q:Queue): return False except: v_value = instance.arguments[arg] - if (v_value == "True" and nbits.count("1") == 1) or (v_value == "False" and nbits.count("1") == 1): + if (v_value == "True" and nbits.count("1") == 1) or (v_value == "False" and nbits.count("1") == 1) or (v_value is None): instance.arguments[arg] = 1 if v_value == "True" else 0 elif v_value in list(const_vars.keys()): # Busquem la informació de la variable de la qual es vol afegir el valor. @@ -360,7 +361,8 @@ def check_spell(self, q:Queue): q.put("[ValueError ] Value of {value} cannot be used as the value of argument {name} because they differ in the type of variable.".format( line=instance.nline, value=v_value, name=instance.name)) return False - instance.arguments[arg] = const_vars[v_value] + if not inside_for: + instance.arguments[arg] = const_vars[v_value] elif v_value not in list(const_vars.keys()): q.put("[AssignmentError ] Value {value} is not defined previously and cannot be assigned.".format( line=instance.nline, value=v_value, name=instance.name)) @@ -379,6 +381,7 @@ def check_spell(self, q:Queue): q.put("[VariableError ] Variable ''{name}'' is not defined in ''{protocol}'' protocol.".format( line=instance.nline, name=item, protocol=self.__db.get_protocol_name(self.__protocol_id))) return False + # print(instance.iter) v_info = self.__db.get_info_from_variable(v_id)["variable_direction"] if v_info == 1: q.put("[ForVariableError ] Variable ''{name}'' is defined as input, not as output. For instance not allow input variables.".format( @@ -423,7 +426,15 @@ def makec(self,q:Queue,pathname:Path|str,emulate:bool=False,autoclose:bool=False for_number_of_situations:int = 0 for_situations:list[dict]|None = None instance_level = 0 + timeTotal = 0 + timeA = time.perf_counter() for instance in self.__document: + + if time.perf_counter()-timeA >= 1: + timeTotal += time.perf_counter()-timeA + timeA = time.perf_counter() + print(timeTotal) + if isinstance(instance,ProtocolInstance): p_id = self.__db.get_protocol_id(instance.name) protocol = Protocol(instance.name) @@ -449,11 +460,22 @@ def makec(self,q:Queue,pathname:Path|str,emulate:bool=False,autoclose:bool=False for_situations[i][instance.name] = for_situations[i][instance.value] elif isinstance(instance,FunctionInstance): - exportable += [Vector(instance.ids,"F",None)] - for arg in tuple(instance.arguments.keys()): - exportable += [Vector(ids=self.__db.get_argument_id(instance.ids,arg),data_type="A",value=instance.arguments[arg])] - - # ####### Falta acabar aquest punt + if not in_for: + exportable += [Vector(instance.ids,"F",None)] + for arg in tuple(instance.arguments.keys()): + exportable += [Vector(ids=self.__db.get_argument_id(instance.ids,arg),data_type="A",value=instance.arguments[arg])] + else: + # Recorrem el llistat de situacions + for i in range(current_for_situation-1,len(for_situations),for_number_of_situations): + for_situations[i]["**functions"][instance.name] = {} + for argument in tuple(instance.arguments.keys()): + if isinstance(instance.arguments[argument],int): + for_situations[i]["**functions"][instance.name][argument] = instance.arguments[argument] + else: + for_situations[i]["**functions"][instance.name][argument] = for_situations[i][instance.arguments[argument]] + # Es possible que pugui donar error d'indexació quan s'intenta afegir el valor d'una variable anterior definida a l'hora de passar-ho com argument. + # Intentar detectar l'error i, si es possible, manipular-ho amb conseqüència. + # ####### Revisar!! elif isinstance(instance, EndInstance): instance_level -=1 @@ -462,6 +484,10 @@ def makec(self,q:Queue,pathname:Path|str,emulate:bool=False,autoclose:bool=False curr_env_name = None # Itera per totes les situacions for i in range(0, len(for_situations)): + if time.perf_counter()-timeA >= 1: + timeTotal += time.perf_counter()-timeA + timeA = time.perf_counter() + q.put(timeTotal) # Busca la primera situació de cada entorn i inicialitza l'entorn. if i % for_number_of_situations == 0: exportable += [Vector(ids=curr_env_name,data_type="E",value=None)] @@ -493,7 +519,7 @@ def makec(self,q:Queue,pathname:Path|str,emulate:bool=False,autoclose:bool=False exportable += [Vector( ids=fn_arg_id[arg], data_type="A", - value=sit_fn[fn][fn_arg_names[arg]] + value=for_situations[i]["**functions"][fn][fn_arg_names[arg]] )] diff --git a/AkitaCode/instances.py b/AkitaCode/instances.py index fc2cddc..2c92c60 100644 --- a/AkitaCode/instances.py +++ b/AkitaCode/instances.py @@ -156,7 +156,8 @@ def __check(self,args:list[str]): try: open_query = args.index("(") close_query = args.index(")") - self.iter = args[open_query+1:close_query] + args = args[open_query+1:close_query] + self.iter=[args[e] for e in range(0,close_query-open_query,2)] except: self.error = True self.error_msg = "For description error." diff --git a/AkitaCode/keys.py b/AkitaCode/keys.py index 10aa80c..6162e69 100644 --- a/AkitaCode/keys.py +++ b/AkitaCode/keys.py @@ -3,8 +3,6 @@ class State(object): Representa la classe Estat de Línia. Permet crear diferents estats en funció de la línia del document específica. D'aquesta manera, es permet l'abstracció de la màquina d'estats durant la sintaxi d'una línia. """ - - def __init__(self, id:int, required:bool=True, strict:bool=True, command:str|None=None, allow_reserved_words=False, error_msg:str="Undefined error."): """ Crea una instància de la classe State. @@ -69,7 +67,7 @@ def is_next(self, command:str|None) -> bool: self._error = True self._error_command = command return False - + def get_next(self, command:str|None): """ diff --git a/AkitaCode/numerics.py b/AkitaCode/numerics.py index 0679e90..05d28eb 100644 --- a/AkitaCode/numerics.py +++ b/AkitaCode/numerics.py @@ -60,32 +60,74 @@ def list_to_int(l:list): return int.from_bytes(bytes(l)) -def int_reverse(i:int): +def ss_to_signed_format(n): """ - Gira els bits lògics del + Convierte un entero negativo a su representación en complemento a dos. + + :param n: Entero que se quiere convertir a complemento a dos. + :type n: int + :return: Representación en binario signado en complemento a dos o False si n no es un entero negativo. + :rtype: str or bool + """ + if isinstance(n, int): + if n < 0: + # Obtener el número binario sin el signo + nbits = len(bin(n)[2:]) + binary = bin(n & (2**(nbits)-1))[2:] + # Extender el número binario a 64 bits si es necesario + # binary = binary.zfill(64) + return int(binary,2) + else: + return False + else: + return False + + + +def ss_to_int_format(n): + """ + Convierte un entero en formato de complemento a dos a un entero negativo. + + :param n: Valor que se quiere convertir a formato de complemento a dos. + :type n: int + :return: Valor resultante de la conversión o False si n no es un entero. + :rtype: int or bool """ + if isinstance(n, int): + if n & (1 << 63): # Comprueba si el bit más significativo está encendido + complement = n ^ ((1 << 64) - 1) # Calcula el complemento a uno + return -(complement + 1) # Calcula el complemento a dos + else: + return False + else: + return False if __name__ == "__main__": + # a = -4 + # print(to_signed_format(a)) a = -12 b = -5 c = -27 d = -1 e = -129 - print(to_signed_format(a)) - print(to_signed_format(b)) - print(to_signed_format(c)) - print(to_signed_format(d)) - print(to_signed_format(e)) + # print(to_signed_format(a)) + print(ss_to_signed_format(a)) + print(ss_to_signed_format(b)) + print(ss_to_signed_format(c)) + print(ss_to_signed_format(d)) + print(ss_to_signed_format(e)) a = 20 b = 11 c = 37 - d = 1 + d = 3 e = 383 - print(to_int_format(a)) - print(to_int_format(b)) - print(to_int_format(c)) - print(to_int_format(d)) - print(to_int_format(e)) \ No newline at end of file + print(ss_to_int_format(a)) + print(ss_to_int_format(b)) + print(ss_to_int_format(c)) + print(ss_to_int_format(d)) + print(ss_to_int_format(e)) + # print(to_int_format(d)) + \ No newline at end of file diff --git a/README.md b/README.md index 625c836..5b052b7 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,19 @@ Documentation is pending to be added. ## History log +### Version 2.0.2 + +- Fixed an issue during the call to a *for* instance, where the evaluated variables were not correctly set as environment constants. + +- Deleted some debug print to stdout. + +- The conditions for the correct evaluation of arguments dependent on the specified environment when using a *for* instance are modified. + +- Fixed an indexing error during export of functions and arguments. + +- Support is added for the use of functions within "for" instances, allowing environment constants to be set as the value of the arguments. + + ### Version 2.0.2-beta - Fixed problem during *for* line statement. Now, *for* statements can be used as following: diff --git a/setup.py b/setup.py index 096a249..2f0abf9 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='AkitaCode', - version='2.0.2-beta', + version='2.0.2', packages=find_packages(), install_requires=[ 'python-can==4.2.2', diff --git a/tests/v2_0_2_prova_for_var_fn.py b/tests/v2_0_2_prova_for_var_fn.py new file mode 100644 index 0000000..b9758a0 --- /dev/null +++ b/tests/v2_0_2_prova_for_var_fn.py @@ -0,0 +1,37 @@ +import queue +import pickle +from AkitaCode.document import Document +# Create a database instance. +# import config_mod +q = queue.Queue() +# db = config_mod.get_db_path() +db = "C:/Users/aamat/.akitacan/data.db" +# Get path of file. +filename = "(v.2.0.2)_prova_var_fn_inside_for_statement" +in_filename = "E:/Akitacan/dev/test/{}{}".format(filename,".atd") +out_filename = "E:/Akitacan/dev/test/{}{}".format(filename,".akita") + +# Create a document instance. +doc = Document(in_filename, db) + +# print(doc._error) +# print(doc._error_msg) if doc._error_msg is not None else print("Success!!") + +fase_A = doc.check_syntax(q) +print("FASE A: {}".format(fase_A)) +print(q.get()) +if fase_A: + fase_B = doc.check_spell(q) + print("FASE B: {}".format(fase_B)) + print(q.get()) + if fase_B: + fase_C = doc.makec(q,out_filename,autoclose=True) + print("FASE C: {}".format(fase_C)) + print(q.get()) + if fase_C == 0: + f = pickle.load(open(out_filename,"rb")) + f = f["data"] + for l in f: + print(repr(l)+"\r") + # print(f) + print(q.get()) \ No newline at end of file diff --git a/tests/v2_0_2_prova_for_var_fn_wt_dependences.py b/tests/v2_0_2_prova_for_var_fn_wt_dependences.py new file mode 100644 index 0000000..9b9fa23 --- /dev/null +++ b/tests/v2_0_2_prova_for_var_fn_wt_dependences.py @@ -0,0 +1,40 @@ +import queue +import pickle +from AkitaCode.document import Document +# Create a database instance. +# import config_mod +q = queue.Queue() +# db = config_mod.get_db_path() +db = "C:/Users/aamat/.akitacan/data.db" +# Get path of file. +filename = "(v.2.0.2)_prova_var_fn_inside_for_statement_wt_depencences" +in_filename = "E:/Akitacan/dev/test/{}{}".format(filename,".atd") +out_filename = "E:/Akitacan/dev/test/{}{}".format(filename,".akita") + +# Create a document instance. +doc = Document(in_filename, db) + +# print(doc._error) +# print(doc._error_msg) if doc._error_msg is not None else print("Success!!") + +fase_A = doc.check_syntax(q) +print("FASE A: {}".format(fase_A)) +print(q.get()) +if fase_A: + fase_B = doc.check_spell(q) + print("FASE B: {}".format(fase_B)) + print(q.get()) + if fase_B: + fase_C = doc.makec(q,out_filename,autoclose=True) + print("FASE C: {}".format(fase_C)) + while True: + msg = q.get() + if msg == True: + break + if fase_C == 0: + f = pickle.load(open(out_filename,"rb")) + f = f["data"] + # for l in f: + # print(repr(l)+"\r") + # print(f) + print(msg) \ No newline at end of file