|
|
|
@ -1,131 +1,17 @@
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include "parser.h"
|
|
|
|
|
#include "../vars/vars.h"
|
|
|
|
|
#include "../hashmap/map.h"
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include "../vars/vars.c"
|
|
|
|
|
|
|
|
|
|
//TODO put in header
|
|
|
|
|
void ex();
|
|
|
|
|
//hashmaps/link list heads
|
|
|
|
|
extern map_void_t *_var_map;
|
|
|
|
|
extern node_info *_temp_statement_head;
|
|
|
|
|
//struct variable *_var_head = NULL;
|
|
|
|
|
extern map_void_t *_function_list;
|
|
|
|
|
|
|
|
|
|
//TODO make a seperate file for this
|
|
|
|
|
typedef struct print {
|
|
|
|
|
node_info* create_var_assignment_string(char *pName, char *pString) {
|
|
|
|
|
|
|
|
|
|
int opperation;
|
|
|
|
|
double value;
|
|
|
|
|
char *string;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} print;
|
|
|
|
|
|
|
|
|
|
//TODO make a seperate file for this
|
|
|
|
|
typedef struct logic {
|
|
|
|
|
|
|
|
|
|
int opperation;
|
|
|
|
|
int expr;
|
|
|
|
|
struct nodeInfo *if_true;
|
|
|
|
|
struct nodeInfo *else_false;
|
|
|
|
|
struct nodeInfo *while_true;
|
|
|
|
|
|
|
|
|
|
} logic;
|
|
|
|
|
|
|
|
|
|
//TODO make a seperate file for this.
|
|
|
|
|
typedef struct nodeInfo {
|
|
|
|
|
|
|
|
|
|
int opperation;
|
|
|
|
|
|
|
|
|
|
enum type{
|
|
|
|
|
|
|
|
|
|
ASSIGNMENT,
|
|
|
|
|
EXPRESSION,
|
|
|
|
|
STATEMENT,
|
|
|
|
|
LOGIC,
|
|
|
|
|
FUNCTION,
|
|
|
|
|
FUNCTION_CALL
|
|
|
|
|
|
|
|
|
|
}type;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char *name;
|
|
|
|
|
Variable *var;
|
|
|
|
|
print printExpression;
|
|
|
|
|
logic logicalExpression;
|
|
|
|
|
struct nodeInfo *next;
|
|
|
|
|
struct nodeInfo *_function_body;
|
|
|
|
|
struct nodeInfo *statement_list;
|
|
|
|
|
struct nodeInfo *local_list;
|
|
|
|
|
struct map_void_t *local_var_list;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} nodeInfo;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//linked list heads. (move to a header file.)
|
|
|
|
|
|
|
|
|
|
//TODO put in header.
|
|
|
|
|
struct nodeInfo *statementHead = NULL;
|
|
|
|
|
struct Variable *head = NULL;
|
|
|
|
|
struct map_void_t *_function_list = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nodeInfo *createFunctionCall(char *_name) {
|
|
|
|
|
|
|
|
|
|
nodeInfo *newNode = malloc(sizeof(nodeInfo));
|
|
|
|
|
newNode->type = FUNCTION_CALL;
|
|
|
|
|
newNode->name = _name;
|
|
|
|
|
newNode->next = NULL;
|
|
|
|
|
return newNode;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* free's a list's links.
|
|
|
|
|
* @param list of linked list to be free'ed
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
void freeLinkedList(nodeInfo *list) {
|
|
|
|
|
|
|
|
|
|
statementHead = NULL;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* returns a copy of list
|
|
|
|
|
* @param nodeInfo list to be copied
|
|
|
|
|
* @return copied list
|
|
|
|
|
*/
|
|
|
|
|
nodeInfo *copyLinkedList(nodeInfo *list) {
|
|
|
|
|
|
|
|
|
|
nodeInfo *newList = malloc(sizeof(nodeInfo));
|
|
|
|
|
newList->next = NULL;
|
|
|
|
|
nodeInfo *copy_list = newList;
|
|
|
|
|
while(list->next != NULL) {
|
|
|
|
|
|
|
|
|
|
list = list->next;
|
|
|
|
|
copy_list->next = list;
|
|
|
|
|
copy_list = copy_list->next;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return newList;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nodeInfo *createFunction(char *_name, nodeInfo *_stmts) {
|
|
|
|
|
|
|
|
|
|
nodeInfo *newNode = malloc(sizeof(nodeInfo));
|
|
|
|
|
newNode->type = FUNCTION;
|
|
|
|
|
newNode->name = _name;
|
|
|
|
|
newNode->_function_body = malloc(sizeof(nodeInfo));
|
|
|
|
|
newNode->_function_body->next = copyLinkedList(_stmts);
|
|
|
|
|
freeLinkedList(_stmts);
|
|
|
|
|
return newNode;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nodeInfo* createVarAssignmentString(char *name, char *string) {
|
|
|
|
|
|
|
|
|
|
nodeInfo *newNode = malloc(sizeof(nodeInfo));
|
|
|
|
|
Variable *newVar = makeVariableString(name, string);
|
|
|
|
|
node_info *newNode = malloc(sizeof(node_info));
|
|
|
|
|
variable *newVar = make_variable_string(pName, pString);
|
|
|
|
|
newNode->type = ASSIGNMENT;
|
|
|
|
|
newNode->opperation = 1;
|
|
|
|
|
newNode->var = newVar;
|
|
|
|
@ -133,10 +19,10 @@ nodeInfo* createVarAssignmentString(char *name, char *string) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nodeInfo* createVarAssignmentInt(char *name, int number) {
|
|
|
|
|
node_info* create_var_assignment_int(char *pName, int number) {
|
|
|
|
|
|
|
|
|
|
nodeInfo *newNode = malloc(sizeof(nodeInfo));
|
|
|
|
|
Variable *newVar = makeVariableInt(name, number);
|
|
|
|
|
node_info *newNode = malloc(sizeof(node_info));
|
|
|
|
|
variable *newVar = make_variable_int(pName, number);
|
|
|
|
|
newNode->type = ASSIGNMENT;
|
|
|
|
|
newNode->opperation = 1;
|
|
|
|
|
newNode->var = newVar;
|
|
|
|
@ -144,10 +30,10 @@ nodeInfo* createVarAssignmentInt(char *name, int number) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nodeInfo* createVarAssignmentChar(char *name, char Char) {
|
|
|
|
|
node_info* create_var_assignment_char(char *pName, char Char) {
|
|
|
|
|
|
|
|
|
|
nodeInfo *newNode = malloc(sizeof(nodeInfo));
|
|
|
|
|
Variable *newVar = makeVariableChar(name, Char);
|
|
|
|
|
node_info *newNode = malloc(sizeof(node_info));
|
|
|
|
|
variable *newVar = make_variable_char(pName, Char);
|
|
|
|
|
newNode->type = ASSIGNMENT;
|
|
|
|
|
newNode->opperation = 1;
|
|
|
|
|
newNode->var = newVar;
|
|
|
|
@ -155,216 +41,59 @@ nodeInfo* createVarAssignmentChar(char *name, char Char) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nodeInfo* createVarAssignmentDouble(char *name, double Double) {
|
|
|
|
|
|
|
|
|
|
nodeInfo *newNode = malloc(sizeof(nodeInfo));
|
|
|
|
|
|
|
|
|
|
Variable *newVar = makeVariableDouble(name, Double);
|
|
|
|
|
node_info* create_var_assignment_double(char *pName, double Double) {
|
|
|
|
|
|
|
|
|
|
node_info *newNode = malloc(sizeof(node_info));
|
|
|
|
|
variable *newVar = make_variable_double(pName, Double);
|
|
|
|
|
|
|
|
|
|
//new node stuff
|
|
|
|
|
newNode->type = ASSIGNMENT;
|
|
|
|
|
newNode->opperation = 1;
|
|
|
|
|
newNode->var = newVar;
|
|
|
|
|
|
|
|
|
|
return newNode;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nodeInfo *createPrintVarNode(char *varname) {
|
|
|
|
|
|
|
|
|
|
nodeInfo *newNode = malloc(sizeof(nodeInfo));
|
|
|
|
|
newNode->opperation = 6;
|
|
|
|
|
newNode->name = varname;
|
|
|
|
|
return newNode;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @params opperation value, see print struct for info
|
|
|
|
|
* @params int value to be printed
|
|
|
|
|
* @params string to be printed
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
nodeInfo *createPrintStatement(int opperation, int value, char *string) {
|
|
|
|
|
|
|
|
|
|
nodeInfo *n = malloc(sizeof(nodeInfo));
|
|
|
|
|
print a;
|
|
|
|
|
//if we are going to print a varibles
|
|
|
|
|
//or we are going to print an int
|
|
|
|
|
switch(opperation) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
|
|
|
|
n->opperation = 3;//this needs to not be a magic number lol
|
|
|
|
|
a.value = value;
|
|
|
|
|
a.opperation = 1;
|
|
|
|
|
n->printExpression = a;
|
|
|
|
|
return n;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
//else we are printing a string
|
|
|
|
|
case 2:
|
|
|
|
|
|
|
|
|
|
n->opperation = 3;
|
|
|
|
|
a.string = string;
|
|
|
|
|
a.opperation = 2;
|
|
|
|
|
n->printExpression = a;
|
|
|
|
|
return n;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
|
|
|
|
|
|
n->opperation = 3;
|
|
|
|
|
a.string = string;
|
|
|
|
|
a.opperation = 3;
|
|
|
|
|
a.value = value;
|
|
|
|
|
n->printExpression = a;
|
|
|
|
|
return n;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
|
|
printf("Something wrong with your print statement\n");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nodeInfo *createLogic(int opperation, int expr, nodeInfo *statement_list, nodeInfo *else_false) {
|
|
|
|
|
nodeInfo *n = malloc(sizeof(nodeInfo));
|
|
|
|
|
|
|
|
|
|
switch (opperation) {
|
|
|
|
|
//if statement
|
|
|
|
|
case 1:
|
|
|
|
|
//logical expression, see nodeInfo for opperation info
|
|
|
|
|
n->opperation = 4;
|
|
|
|
|
logic a;
|
|
|
|
|
a.opperation = 1;
|
|
|
|
|
a.expr = expr;
|
|
|
|
|
|
|
|
|
|
while (statement_list->statement_list != NULL) {
|
|
|
|
|
|
|
|
|
|
statement_list = statement_list->statement_list;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//now that we have the statement list, we need to make the head opperation 5
|
|
|
|
|
nodeInfo *newNode = malloc(sizeof(nodeInfo));
|
|
|
|
|
newNode->opperation = 5;
|
|
|
|
|
newNode->next = copyLinkedList(statement_list);
|
|
|
|
|
freeLinkedList(statement_list);
|
|
|
|
|
a.if_true = newNode;
|
|
|
|
|
|
|
|
|
|
//this removes the last statement list in statementHead
|
|
|
|
|
statement_list = NULL;
|
|
|
|
|
n->logicalExpression = a;
|
|
|
|
|
return n;
|
|
|
|
|
break;
|
|
|
|
|
//while loop
|
|
|
|
|
case 2:
|
|
|
|
|
|
|
|
|
|
/*n->opperation = 4;
|
|
|
|
|
logic b;
|
|
|
|
|
b.opperation = 2;
|
|
|
|
|
b.expr = expr;
|
|
|
|
|
b.while_true = if_true;
|
|
|
|
|
|
|
|
|
|
n->logicalExpression = b;
|
|
|
|
|
return n;*/
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
printf("check your yacc file for logical statements\n");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nodeInfo *createCompoundStatement(nodeInfo *n) {
|
|
|
|
|
|
|
|
|
|
if(statementHead == NULL) {
|
|
|
|
|
statementHead = malloc(sizeof(nodeInfo));
|
|
|
|
|
|
|
|
|
|
nodeInfo *newNode = malloc(sizeof(nodeInfo));
|
|
|
|
|
|
|
|
|
|
statementHead->opperation = 5;
|
|
|
|
|
statementHead->next = n;
|
|
|
|
|
statementHead->next->next = NULL;
|
|
|
|
|
statementHead->statement_list = NULL;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
nodeInfo *p = statementHead;
|
|
|
|
|
//tereverse the list for the end
|
|
|
|
|
while(p->statement_list != NULL) {
|
|
|
|
|
|
|
|
|
|
p = p->statement_list;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p->next = malloc(sizeof(nodeInfo));
|
|
|
|
|
p->next = n;
|
|
|
|
|
p->next->next = NULL;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return statementHead;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Adds statement to linked list.
|
|
|
|
|
|
|
|
|
|
@param nodeInfo link to be added.
|
|
|
|
|
@return head of linked list.
|
|
|
|
|
*/
|
|
|
|
|
node_info* add_to_compound_statement(node_info *new_statement, node_info *statement_head) {
|
|
|
|
|
|
|
|
|
|
nodeInfo *addToCompoundStatement(nodeInfo *n) {
|
|
|
|
|
if(statement_head == NULL) {
|
|
|
|
|
|
|
|
|
|
if(statementHead == NULL) {
|
|
|
|
|
|
|
|
|
|
statementHead = malloc(sizeof(nodeInfo));
|
|
|
|
|
statementHead->opperation = 5;
|
|
|
|
|
statementHead->next = n;
|
|
|
|
|
statementHead->next->next = NULL;
|
|
|
|
|
statementHead->statement_list = NULL;
|
|
|
|
|
statement_head = malloc(sizeof(node_info));
|
|
|
|
|
statement_head->opperation = 5;
|
|
|
|
|
statement_head->next = new_statement;
|
|
|
|
|
statement_head->next->next = NULL;
|
|
|
|
|
statement_head->statement_list = NULL;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
nodeInfo *p = statementHead;
|
|
|
|
|
node_info *p = statement_head; //make a temp of list head, so we can traverse it.
|
|
|
|
|
|
|
|
|
|
//TODO replace with double linked list end
|
|
|
|
|
while (p->statement_list != NULL) {
|
|
|
|
|
|
|
|
|
|
p = p->statement_list;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//TODO replace with double linked list end
|
|
|
|
|
while (p->next != NULL) {
|
|
|
|
|
|
|
|
|
|
p = p->next;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p->next = malloc(sizeof(nodeInfo));
|
|
|
|
|
p->next = n;
|
|
|
|
|
p->next = malloc(sizeof(node_info));
|
|
|
|
|
p->next = new_statement;
|
|
|
|
|
p->next->next = NULL;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return statementHead;
|
|
|
|
|
|
|
|
|
|
return statement_head;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -376,12 +105,12 @@ Executes a statment.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
//TODO return bool or int detailing the status of execution.
|
|
|
|
|
void ex(nodeInfo *n) {
|
|
|
|
|
void ex(node_info *n) {
|
|
|
|
|
|
|
|
|
|
switch(n->opperation){
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
addVar(n->var->name, n->var->value);
|
|
|
|
|
add_var(n->var->name, n->var->value, _var_map);
|
|
|
|
|
break;
|
|
|
|
|
//TODO expression stuff
|
|
|
|
|
case 2:
|
|
|
|
@ -405,7 +134,7 @@ void ex(nodeInfo *n) {
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
printf("something wrong with your if statement, check yacc file\n");
|
|
|
|
|
printf("{ERROR} CHECK YACC FILE FOR INCORRECT PRINT\n");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -434,7 +163,8 @@ void ex(nodeInfo *n) {
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
|
|
printf("something wrong with logical expression check yacc\n");
|
|
|
|
|
printf("{ERROR} SOMETHING WRONG WITH LOGICAL EXPRESSION CHECK YACC\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
@ -446,76 +176,79 @@ void ex(nodeInfo *n) {
|
|
|
|
|
ex(n);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
statementHead = NULL;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 6:
|
|
|
|
|
;
|
|
|
|
|
VariableValues *value = getValue(n->name);
|
|
|
|
|
variable_values *value = get_value(n->name, _var_map);
|
|
|
|
|
|
|
|
|
|
switch(value->type) {
|
|
|
|
|
|
|
|
|
|
case STRINGVAR:
|
|
|
|
|
case VAR_STRING:
|
|
|
|
|
|
|
|
|
|
printf("%s\n", value->String);
|
|
|
|
|
printf("%s\n", value->_string);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case INT:
|
|
|
|
|
case VAR_INT:
|
|
|
|
|
|
|
|
|
|
printf("%d\n", value->Int);
|
|
|
|
|
printf("%d\n", value->_int);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CHARVAR:
|
|
|
|
|
case VAR_CHAR:
|
|
|
|
|
|
|
|
|
|
printf("%c\n", value->Char);
|
|
|
|
|
printf("%c\n", value->_char);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DOUBLE:
|
|
|
|
|
case VAR_DOUBLE:
|
|
|
|
|
|
|
|
|
|
printf("%f\n", value->Double);
|
|
|
|
|
printf("%f\n", value->_double);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VAR_VOID: //TODO add void variable type
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
|
|
printf("no such variable type called , keep coding!\n");
|
|
|
|
|
printf("{ERROR} NO SUCH VARIABLE TYPE CHECK YACC!\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
//TODO update default to case 7 for functions
|
|
|
|
|
default:
|
|
|
|
|
;
|
|
|
|
|
//TODO add error/exit here
|
|
|
|
|
|
|
|
|
|
switch(n->type) {
|
|
|
|
|
|
|
|
|
|
case FUNCTION_CALL:
|
|
|
|
|
;
|
|
|
|
|
nodeInfo *_stmts = *map_get(&*((map_void_t* ) _function_list), n->name);
|
|
|
|
|
|
|
|
|
|
while (_stmts->next != NULL) {
|
|
|
|
|
|
|
|
|
|
//gets the statements of a function with the provided name
|
|
|
|
|
node_info *_stmts = *map_get(&*((map_void_t* ) _function_list), n->name);
|
|
|
|
|
while (_stmts->next != NULL) { //loop over all the statements and execute them
|
|
|
|
|
_stmts = _stmts->next;
|
|
|
|
|
ex(_stmts);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FUNCTION:
|
|
|
|
|
|
|
|
|
|
;
|
|
|
|
|
//if the list of functions already defined is null then we malloc space for it.
|
|
|
|
|
if (_function_list == NULL) {
|
|
|
|
|
|
|
|
|
|
_function_list = malloc(sizeof(map_void_t));
|
|
|
|
|
n->local_var_list = malloc(sizeof(map_void_t));
|
|
|
|
|
n->_var_list = malloc(sizeof(node_info));
|
|
|
|
|
|
|
|
|
|
n->next = NULL;
|
|
|
|
|
n->local_list = NULL;
|
|
|
|
|
map_init(&*((map_void_t *) _function_list));
|
|
|
|
|
map_init(&*((map_void_t *) n->local_var_list));
|
|
|
|
|
map_init(&*((map_void_t *) n->_var_list));
|
|
|
|
|
//put the function in the hashmap
|
|
|
|
|
map_set(&*((map_void_t* ) _function_list), n->name, &*n->_function_body);
|
|
|
|
|
} else {
|
|
|
|
|
} else { //else we dont malloc, we just put the function inside of the hashmap.
|
|
|
|
|
|
|
|
|
|
map_set(&*((map_void_t* ) _function_list), n->name, &*n->_function_body);
|
|
|
|
|
|
|
|
|
@ -525,10 +258,8 @@ void ex(nodeInfo *n) {
|
|
|
|
|
default:
|
|
|
|
|
;
|
|
|
|
|
//TODO add error here and close
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|