Skip to content

Commit

Permalink
Fixed some bugs of *for* instances.
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
aamat-ausa committed Apr 9, 2024
1 parent e5dee34 commit a1f79fc
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 31 deletions.
52 changes: 39 additions & 13 deletions AkitaCode/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
"""
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"])
Expand Down Expand Up @@ -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.
Expand All @@ -360,7 +361,8 @@ def check_spell(self, q:Queue):
q.put("[ValueError <Line {line}>] 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 <Line {line}>] Value {value} is not defined previously and cannot be assigned.".format(
line=instance.nline, value=v_value, name=instance.name))
Expand All @@ -379,6 +381,7 @@ def check_spell(self, q:Queue):
q.put("[VariableError <Line {line}>] 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 <Line {line}>] Variable ''{name}'' is defined as input, not as output. For instance not allow input variables.".format(
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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)]
Expand Down Expand Up @@ -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]]
)]


Expand Down
3 changes: 2 additions & 1 deletion AkitaCode/instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down
4 changes: 1 addition & 3 deletions AkitaCode/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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):
"""
Expand Down
68 changes: 55 additions & 13 deletions AkitaCode/numerics.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
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))

13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
37 changes: 37 additions & 0 deletions tests/v2_0_2_prova_for_var_fn.py
Original file line number Diff line number Diff line change
@@ -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())
40 changes: 40 additions & 0 deletions tests/v2_0_2_prova_for_var_fn_wt_dependences.py
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit a1f79fc

Please sign in to comment.