Commit 0f33a5ff authored by Sergio Costas's avatar Sergio Costas

Added full aliasing support

Added two unitary tests for aliasing support
parent 5dd00dfd
...@@ -93,6 +93,7 @@ class crusty(object): ...@@ -93,6 +93,7 @@ class crusty(object):
self.errors = [] self.errors = []
self.debug = [] self.debug = []
self.print_debug = print_debug self.print_debug = print_debug
self.uid_counter = 1
with open(headerpath,"r") as header: with open(headerpath,"r") as header:
do_process = False do_process = False
...@@ -147,7 +148,7 @@ class crusty(object): ...@@ -147,7 +148,7 @@ class crusty(object):
def _do_debug(self,var_container): def _do_debug(self,var_container):
if self.print_debug: if self.print_debug:
print("Debug:") print("Debug:")
for block in var_container: for block in var_container["variables"]:
print(" Block:") print(" Block:")
for variable in block: for variable in block:
print(" Variable: {:s}".format(variable)) print(" Variable: {:s}".format(variable))
...@@ -235,6 +236,21 @@ class crusty(object): ...@@ -235,6 +236,21 @@ class crusty(object):
group = (err_type, err_value) + argv group = (err_type, err_value) + argv
if self.errors.count( group ) == 0: if self.errors.count( group ) == 0:
self.errors.append( group ) self.errors.append( group )
# this line allows to detect formatting errors in the error messages in the line
# where they have been produced, and not at the end, when they will be printed
msg = _(err_value).format(*argv)
def _find_variable_by_id(self,var_container,var_id,line_number,searching_function = False):
""" Returns a variable using its unique id """
for var_group in var_container["variables"]:
for name in var_group:
if var_group[name]["uid"] == var_id:
return var_group[name]
if not searching_function:
self._add_error(var_container,self.MSG_CRITICAL,"Unknown variable ID '{:d}' at line {:d}",var_id,line_number)
raise self.VarNotFoundException()
def _find_variable(self,var_container,var_name,line_number,searching_function = False): def _find_variable(self,var_container,var_name,line_number,searching_function = False):
...@@ -268,7 +284,7 @@ class crusty(object): ...@@ -268,7 +284,7 @@ class crusty(object):
self._add_error(var_container,self.MSG_CRITICAL,"Trying to assign a value to the function name '{:s}' at line {:d}",str(var_name),line_number) self._add_error(var_container,self.MSG_CRITICAL,"Trying to assign a value to the function name '{:s}' at line {:d}",str(var_name),line_number)
return return
if variable["alias"] and (variable["aliases"] is not None): if variable["alias"] and (variable["aliases"] is not None):
variable = variable["aliases"] # when modifying an alias, we really want to modify the original one variable = self._find_variable_by_id(var_container,variable["aliases"],line_number) # when modifying an alias, we really want to modify the original one
if (not force) and variable["crust"]: if (not force) and variable["crust"]:
status = variable["status"] status = variable["status"]
if (status == crusty.STATUS_NOT_NULL) or (status == crusty.STATUS_NOT_NULL_OR_NULL): if (status == crusty.STATUS_NOT_NULL) or (status == crusty.STATUS_NOT_NULL_OR_NULL):
...@@ -279,8 +295,9 @@ class crusty(object): ...@@ -279,8 +295,9 @@ class crusty(object):
variable["status"] = value variable["status"] = value
if isinstance(variable["aliases"],list): # if this variable has aliases, we must update all of them if isinstance(variable["aliases"],list): # if this variable has aliases, we must update all of them
for element in variable["aliases"]: for element in variable["aliases"]:
element["status"] = value alias = self._find_variable_by_id(var_container,element,line_number)
element["init_line"] = variable["init_line"] alias["status"] = value
alias["init_line"] = variable["init_line"]
def _status_to_condition(self,retval): def _status_to_condition(self,retval):
...@@ -321,8 +338,8 @@ class crusty(object): ...@@ -321,8 +338,8 @@ class crusty(object):
if var_crust is not None: if var_crust is not None:
if var_crust["aliases"] is None: if var_crust["aliases"] is None:
var_crust["aliases"] = [] var_crust["aliases"] = []
var_crust["aliases"].append(var_alias) var_crust["aliases"].append(var_alias["uid"])
var_alias["aliases"] = var_crust var_alias["aliases"] = var_crust["uid"]
var_alias["status"] = status var_alias["status"] = status
...@@ -669,6 +686,7 @@ class crusty(object): ...@@ -669,6 +686,7 @@ class crusty(object):
""" Process a node that represents a variable or function definition, and returns a dictionary with its properties. """ Process a node that represents a variable or function definition, and returns a dictionary with its properties.
Properties: Properties:
name: the variable or function name name: the variable or function name
uid: unique number for aliases reference
crust: if TRUE, it is a crust_type variable crust: if TRUE, it is a crust_type variable
borrowed: if TRUE, it is a borrowed, crust_type function parameter borrowed: if TRUE, it is a borrowed, crust_type function parameter
recycle: if TRUE, it is a recycle, crust_type function parameter recycle: if TRUE, it is a recycle, crust_type function parameter
...@@ -686,10 +704,11 @@ class crusty(object): ...@@ -686,10 +704,11 @@ class crusty(object):
array: TRUE if this variable is an array array: TRUE if this variable is an array
function: TRUE if this is a function, or a pointer to a function. In the first case, status will be STATUS_FUNCTION function: TRUE if this is a function, or a pointer to a function. In the first case, status will be STATUS_FUNCTION
function_params: a list with the return values and the parameters of the function or function pointer, or None if this is not a function or function pointer function_params: a list with the return values and the parameters of the function or function pointer, or None if this is not a function or function pointer
aliases: None if this function is not an alias or has no aliases. In case this variable HAS one or more aliases, this will be a list with all the dictionaries of this variable. If this variable IS an alias of other, this will be just the dictionary of that alias variable, or None if it hasn't been still assigned to a crust variable aliases: None if this variable is not an alias or has no aliases. In case this variable HAS one or more aliases, this will be a list with all the UIDs of this variable. If this variable IS an alias of other, this will be just the UID of that alias variable, or None if it hasn't been still assigned to a crust variable
""" """
retval = {"name": None, "crust": False, "borrowed": False, "recycle": False, "alias": False, "enum": False, "status": self.STATUS_UNINITIALIZED, "pointer": pointers, "struct": False, "array": False, "function": False, "function_params": None, "aliases": None } retval = {"name": None, "uid": self.uid_counter, "crust": False, "borrowed": False, "recycle": False, "alias": False, "enum": False, "status": self.STATUS_UNINITIALIZED, "pointer": pointers, "struct": False, "array": False, "function": False, "function_params": None, "aliases": None }
self.uid_counter += 1
if not isinstance(node,self.AST_node): if not isinstance(node,self.AST_node):
return retval return retval
......
...@@ -285,6 +285,12 @@ class Test(unittest.TestCase): ...@@ -285,6 +285,12 @@ class Test(unittest.TestCase):
def testAssignmentToAndFromMemberOfBorrowBlock(self): def testAssignmentToAndFromMemberOfBorrowBlock(self):
self._all_fine_test("unitest/test71.c") self._all_fine_test("unitest/test71.c")
def testAliasFreesBlock(self):
self._all_fine_test("unitest/test72.c")
def testAliasFreesBlock2(self):
self._generic_test("unitest/test73.c",[ (crusty.crusty.MSG_ERROR,"Parameter {:d} when calling function '{:s}' at line {:d} was freed at line {:d}",1,"main",10,9) ])
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
typedef __crust_t__ int *crust_t;
#define NULL ((void *)0)
void main(crust_t param) {
crust_t __crust_alias__ an_alias = param;
__crust_debug__
main(an_alias); // this must work, and no error has to be emited because 'param' has been freed, because it is aliased by 'an_alias'
}
typedef __crust_t__ int *crust_t;
#define NULL ((void *)0)
void main(crust_t param) {
crust_t __crust_alias__ an_alias = param;
__crust_debug__
main(an_alias); // this must work, but now "param" must be marked as "free", so this code must not return an error
main(param); // ERROR: param has been freed when the alias "an_alias" has been used
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment