R/HLL.R

#' High Level Language Class
#'
#' @description  The engine class to parse and execute HLL scripts
#' @import stringr
#' @export
HLL <- function( debug.mode = FALSE, deep.level = 1, executed.statements = 0, max.debug.deep = Inf, arr.breakpoints = c() ) {

  LLL.env <- NA
  mem.struct <- list()
  global.null.value <- ""
  global.debug.mode <- ""
  global.deep.level <- ""
  global.executed.statements <- ""
  global.max.debug.deep <- ""
  global.arr.breakpoints<- c()

  # ---------------------------------------------------------------
  # Fai il PARSE di uno script
  # (Fai anche il Parsing SEMANTICO)
  # ---------------------------------------------------------------  
  parseScript<-function( script ) {

    # setta il modo di debug
    # global.debug.mode <<- debug.mode
    # global.deep.level <<- deep.level
    
    # splitta le righe ed elimina le righe vuote
    arr.righe <- str_trim(unlist(str_split(string = script,pattern = "\n")))

    script.terminato <- FALSE
    indice.riga <- 1
    while( script.terminato == FALSE ) {
      
      # il comando in questione e' una istruzione di salto?
      # (setta il def a no)
      jump.statement <- FALSE
      
      # Se superi il numero di righe massime... esci
      if(indice.riga > length(arr.righe)) { script.terminato <- TRUE; break  }

      # trimma e skippa le righe vuote. Non dovrei averne, ma non si sa mai.
      str.riga <- str_trim(arr.righe[indice.riga])
      if(str.riga=="") { indice.riga<-indice.riga+1; next; }
      if(str_sub(str_trim(str.riga),start = 1,end = 1)==":") { indice.riga<-indice.riga+1; next; }
      if(str_sub(str_trim(str.riga),start = 1,end = 1)=="#") { indice.riga<-indice.riga+1; next; }

      # Parse della stringa:
      # SE NON E' APERTO UN CONTESTO :
      if( length(mem.struct$define.context)==0) {
      # browser()
        res <- execute(script = str.riga , complete.script = arr.righe , script.cursor = indice.riga)
      
        # Se era un return, restituisci
        if(res$operation.token=="return") return(res)
      }
      # SE E' APERTO UN CONTESTO
      # Registra le righe che incontri, senza eseguirle ed associandole alla
      # coppia <classe, metodo> opportuna
      if( length(mem.struct$define.context)>0) {
        proxy.mem.contesto.addLine(stringa = str.riga)
        # Se pero' la riga era "enddefine", be', chiudi il contesto :)
        if(!is.na(str_extract(string = str.riga, pattern = "^[ ]*enddefine[ ]*$")))  {
          proxy.mem.contesto.set(destroy.contest = TRUE)
        }
      }
      
      if(res$operation.token=="IF") { jump.statement <-TRUE ; }
      if(res$operation.token=="ENDIF") { jump.statement <-TRUE ; }
      if(res$operation.token=="ELSE") { jump.statement <-TRUE ;  }
      if(res$operation.token=="ENDFOREACH") { jump.statement <-TRUE ;  }

      # Se l'istruzione eseguita era una istruzione che prevedeva un salto, comportati di conseguenza
      # (non aggiornare il cursore in avanti di uno, ma fai il jump previsto)
      if( jump.statement == TRUE ) 
        indice.riga <- res$setScriptCursorTo
      else  
        indice.riga <- indice.riga + 1
    }
  }
  # ---------------------------------------------------------------
  # invoca.ricorsivamente.HLL
  # Risolve ricorsivamente una chiamata (crea l'oggetto, copia l'env)
  # esegue la chiamata e manipola il risultato
  # ---------------------------------------------------------------
  invoca.ricorsivamente.HLL<-function( HLL.script ) {
    
    # # DEBUGGER -im
    # if(global.debug.mode==TRUE & global.deep.level <= global.max.debug.deep  ) {
    #   cat("\n#",global.executed.statements,": HLL::execute(",HLL.script,")")
    #   global.executed.statements <<- global.executed.statements + 1
    # }
    # # DEBUGGER -fm
    # if(stringa=="set deltaInferioreGiorni = $parameter_2$") browser()
    # browser()
    # Crea un oggetto HLL
    obj.HLL<-HLL( debug.mode = global.debug.mode , deep.level = (global.deep.level+1) , 
                  executed.statements = global.executed.statements, max.debug.deep = global.max.debug.deep,
                  arr.breakpoints = global.arr.breakpoints )
    # setta l'environment
    obj.HLL$setEnv( env = LLL.env , mem = mem.struct )
    # Fai il parse dello script
    # Esegue il corrispettivo di una sola riga
    # browser()
    res <- obj.HLL$execute( script = HLL.script )
    # DEBUGGER -im (new)
    if(global.debug.mode==TRUE & global.deep.level <= global.max.debug.deep  ) {
      global.executed.statements <<- obj.HLL$getAttribute(attributo = "executed.statements")
    }
    # DEBUGGER -fm (new)
    # restituisci il risultato
    return(res)
  }
  # ---------------------------------------------------------------
  # risolvi.writeLog
  # Write di un LOG
  # ---------------------------------------------------------------  
  risolvi.writeLog<-function( lst.argomenti = list() ) {
    # browser()
    if(lst.argomenti[[1]]$type$tipo.variabile.restituita!="quoted.string") stop("ERRORE: il primo parametro deve essere la stringa che indica la coda in cui salvare il log")
    coda <- togli.apici.esterni.stringa(lst.argomenti[[1]]$value)
    quanti.in.coda <- length(mem.struct$logQueue[[as.character(coda)]])
    mem.struct$logQueue[[as.character(coda)]][[quanti.in.coda+1]] <<-lst.argomenti[2:length(lst.argomenti)]
  }  
  # ---------------------------------------------------------------
  # risolvi.funzione.HLL
  # Risolve ricorsivamente una funzione
  # deve gestire lo scoping delle variabili
  # ---------------------------------------------------------------  
  risolvi.funzione.HLL<-function( nome.funzione, lst.argomenti = list() ) {
    # setta l'environment
    
    if(nome.funzione=="writeLog") { 
      risolvi.writeLog( lst.argomenti = lst.argomenti )
      return(list( "valore"=NA, "operation.token" = "writeLog", "operation"="writeLog(...)"))
    }
    
    # devi passare LLL ed eventuali metodi definiti in HLL, NON le variabili
    tmp.mem.struct <- mem.struct
    tmp.mem.struct$var<-list()
    tmp.mem.struct$define.context<-list()
    tmp.mem.struct$implicit.PK<-NA
    tmp.mem.struct$lst.parameters<-list()
    tmp.mem.struct$functions<-list()
    tmp.mem.struct$logQueue<-list()
# browser()
    # Crea un oggetto HLL
    obj.HLL<-HLL( debug.mode = global.debug.mode, deep.level = (global.deep.level+1),
                  executed.statements = global.executed.statements, max.debug.deep = global.max.debug.deep, 
                  arr.breakpoints = global.arr.breakpoints )    
    
    HLL.script <-  mem.struct$functions[[nome.funzione]]$script
    HLL.script <- HLL.script[ 2: (length(HLL.script)-1) ]
    HLL.script <- paste(HLL.script, collapse = "\n")   
    
    # Non c'e' NESSUNA Pk implicita! definisci solo la 'running function'
    tmp.mem.struct$running.function<-nome.funzione
    tmp.mem.struct$running.class<-c()
    tmp.mem.struct$running.method<-c()
    tmp.mem.struct$functions <- mem.struct$functions
    # Aggiusta il contenuto della lista parametri in maniera da renderla conforme a come
    # verra' poi analizzata'
    # browser()
    for( i in seq(1,length(lst.argomenti))) {
      aaa <- definisci.tipo.variabile(risultatoElemento = lst.argomenti[[i]]$value)
      lst.argomenti[[i]]$type <- aaa
    }
    tmp.mem.struct$lst.parameters <- lst.argomenti
    
    # DEBUGGER -im -less important
    if(global.debug.mode==TRUE & global.deep.level <= global.max.debug.deep  ) {
      cat(paste(c("\n#",global.executed.statements,"CALL - Function : ",nome.funzione),collapse = ' '))
      if( global.executed.statements %in% global.arr.breakpoints ) handle.debug.console.GUI()      
      global.executed.statements <<- global.executed.statements + 1
    }
    # DEBUGGER -fm
    
    # browser()
    # # SETTA I PARAMETRI, PASSANDOLI COME VARIABILI NEL NUOVO ENV
    # for( i in seq(1,length(lst.argomenti))) {
    #   tmp.mem.struct$var[[  paste(c("$parameter_",i,"$"),collapse='') ]]<-lst.argomenti[[i]]
    # }
        # browser()
    # Fai il push dell'ENV
    obj.HLL$setEnv( env = LLL.env , mem = tmp.mem.struct )
    # Fai il parse dello script
    res <- obj.HLL$parseScript( script = HLL.script )
    
    # DEBUGGER -im -less important  
    if(global.debug.mode==TRUE & global.deep.level <= global.max.debug.deep  ) {
      global.executed.statements <<- obj.HLL$getAttribute(attributo = "executed.statements")
      cat(paste(c("\n#",global.executed.statements,"BACK - Function :",nome.funzione),collapse = ' '))
      if( global.executed.statements %in% global.arr.breakpoints ) handle.debug.console.GUI()      
      # global.executed.statements <<- global.executed.statements + 1
    }
    # DEBUGGER -fm    
    
    # restituisci il risultato
    return(res)    
  }
  # ---------------------------------------------------------------
  # risolvi.metodo.HLL
  # Risolve ricorsivamente una metodo. Simile invoca.ricorsivamente.HLL
  # deve gestire tuttavia differentemente lo scoping delle variabili
  # ---------------------------------------------------------------
  risolvi.metodo.HLL<-function( classe, metodo, implicit.PK, script = NA , lst.argomenti=list()) {

    # setta l'environment
    # devi passare LLL ed eventuali metodi definiti in HLL, NON le variabili
    tmp.mem.struct <- mem.struct
    tmp.mem.struct$var<-list()
    tmp.mem.struct$define.context<-list()
    tmp.mem.struct$implicit.PK<-NA
    tmp.mem.struct$lst.parameters<-list()
    tmp.mem.struct$logQueue<-list()
    # browser()
    # Crea un oggetto HLL
    # obj.HLL<-HLL()
    # browser()
    obj.HLL<-HLL( debug.mode = global.debug.mode, deep.level = (global.deep.level+1),
                  executed.statements = global.executed.statements, max.debug.deep = global.max.debug.deep, 
                  arr.breakpoints = global.arr.breakpoints )

    HLL.script <- mem.struct$class.methods[[classe]][[metodo]]$script
    HLL.script <- HLL.script[ 2: (length(HLL.script)-1) ]
    HLL.script <- paste(HLL.script, collapse = "\n")

    # Aggiungi la PK implicita (eventualmente sovrascrivendo)
    tmp.mem.struct$implicit.PK<-implicit.PK
    tmp.mem.struct$running.class<-classe
    tmp.mem.struct$running.method<-metodo
    tmp.mem.struct$running.function<-c()    
    tmp.mem.struct$lst.parameters<-lst.argomenti

    # DEBUGGER -im -less important
    if(global.debug.mode==TRUE & global.deep.level <= global.max.debug.deep  ) {
      if(is.na(script))
        cat(paste(c("\n#",global.executed.statements,"CALL - HLL::",classe,"::",metodo),collapse = ' '))
      else
        cat(paste(c("\n#",global.executed.statements,"CALL - HLL::",script),collapse = ' '))
      
      if( global.executed.statements %in% global.arr.breakpoints ) handle.debug.console.GUI()      
      global.executed.statements <<- global.executed.statements + 1
    }
    # DEBUGGER -fm    
    
    # Fai il push dell'ENV
    obj.HLL$setEnv( env = LLL.env , mem = tmp.mem.struct )
    # Fai il parse dello script
    res <- obj.HLL$parseScript( script = HLL.script )
    
    if(global.deep.level==1) mem.struct$logQueue <<- obj.HLL$getAttribute(attributo = "logQueue")
    
    # DEBUGGER -im -less important
    # browser()
    if(global.debug.mode==TRUE & global.deep.level <= global.max.debug.deep  ) {
      global.executed.statements <<- obj.HLL$getAttribute(attributo = "executed.statements")
      if(is.na(script))
        cat(paste(c("\n#",global.executed.statements,"BACK - HLL::",classe,"::",metodo),collapse = ' '))
      else
        cat(paste(c("\n#",global.executed.statements,"BACK - HLL::",script),collapse = ' '))
      if( global.executed.statements %in% global.arr.breakpoints ) handle.debug.console.GUI()      
      # global.executed.statements <<- global.executed.statements + 1
    }
    # DEBUGGER -fm    
    
    # restituisci il risultato
    return(res)
  }
  # ---------------------------------------------------------------
  # Fai il LAOD di uno script
  # ---------------------------------------------------------------  
  loadScript <- function(filename = NA, script = NA){
    if(!is.na(filename)) {  
      text <- paste(readLines(con = filename,warn = F),collapse = "\n")
      parseScript(script = text )
      return()
    }      
    if(!is.na(script)) { 
      parseScript(script = text)
      return()
    }
    stop("qualcosa devi passare...")
  }    
  # ---------------------------------------------------------------
  # proxy.mem.struct.set
  # proxy per il SET delle variabili in memoria
  # ---------------------------------------------------------------
  proxy.mem.struct.set<-function( varName=NA, value=NA, type=NA) {
    # Se la variabile non c'e', creala nella struttura
    if( !(varName %in% mem.struct[["var"]]) ) mem.struct[["var"]][[varName]] <<- list()
    mem.struct[["var"]][[varName]]$type <<- type
    mem.struct[["var"]][[varName]]$value <<- value
  }
  # ---------------------------------------------------------------
  # proxy.mem.contesto.set
  # proxy per il SET del contesto in memoria
  # ---------------------------------------------------------------
  proxy.mem.contesto.set<-function( method.name=NA, class.name=NA , destroy.contest = FALSE, nome.funzione=NA) {
    # Se devi distruggere il contesto, non perdere tempo!
    # browser()
    if(destroy.contest==TRUE ) {
      # prima di chiudere il contesto, fai il parsing di quanto fino ad ora accumulato.
      # Considera che lo script e' gia' stato aggiundo dagli "addline"
      # Se e' un METODO    
      if(!("function.name" %in% names(mem.struct$define.context))) { 
        method.name <- mem.struct$define.context$method.name
        class.name <- mem.struct$define.context$class.name
        mem.struct$class.methods[[class.name]][[method.name]]$struttura <<- preProcessing.Script( script.lines = mem.struct$define.context$script )
        mem.struct$define.context <<- list()
      } else {
      # Se invece e' una FUNZIONE
        function.name <- mem.struct$define.context$function.name
        mem.struct$functions[[function.name]]$struttura <<- preProcessing.Script( script.lines = mem.struct$define.context$script )
        mem.struct$define.context <<- list()
      }
      return()
    }
    # se no, continua...
    # Se e' un METODO'
    if(is.na(nome.funzione)) { 
      mem.struct$define.context$method.name <<- method.name
      mem.struct$define.context$class.name <<- class.name
      mem.struct$define.context$script <<- c()
      
      if(!("class.methods" %in% names(mem.struct))) mem.struct$class.methods<<-list()
      if(! ( class.name %in% names(mem.struct$class.methods) ) ) mem.struct$class.methods[[class.name]]<<-list()
      if(!(method.name %in% names(mem.struct$class.methods[[class.name]]))) mem.struct$class.methods[[class.name]][[method.name]]<<-list("script"=c(),"struttura"=c())
      
    } else {
    # Se e' una FUNZIONE
      mem.struct$define.context$function.name <<- nome.funzione
      mem.struct$define.context$script <<- c()
      # browser()      
      if(!("functions" %in% names(mem.struct))) mem.struct$functions<<-list()
      if(!(nome.funzione %in% names(mem.struct$functions))) mem.struct$functions[[nome.funzione]]<<-list("script"=c(),"struttura"=c())
      
    }

  }
  # ---------------------------------------------------------------
  # proxy.mem.contesto.addLine
  # proxy per l'aggiunta di una linea al contesto
  # ---------------------------------------------------------------
  proxy.mem.contesto.addLine<-function(  stringa ) {
    if( length(mem.struct$define.context)==0 ) stop("\n errore, non e' stato definito alcun contesto in cui copiare le righe")
    # Se stai definendo un metodo
    if(!("function.name" %in% names(mem.struct$define.context))) { 
      mem.struct$define.context$script <<- c( mem.struct$define.context$script , stringa)
      class.name <- mem.struct$define.context$class.name
      method.name <- mem.struct$define.context$method.name
      mem.struct$class.methods[[class.name]][[method.name]]$script <<- c(mem.struct$class.methods[[class.name]][[method.name]]$script,stringa)
    } else {
      # Se invece stai definendo una funzione
      # browser()
      mem.struct$define.context$script <<- c( mem.struct$define.context$script , stringa)
      function.name <- mem.struct$define.context$function.name
      mem.struct$functions[[function.name]]$script <<- c(mem.struct$functions[[function.name]]$script,stringa)
    }
  }
  # ---------------------------------------------------------------
  # execute
  # Esegui un singolo comando (o una linea: per quanto possibile
  # risolveraa' ricorsivamente le chiamate)
  # ---------------------------------------------------------------
  execute<-  function( script , complete.script = NA , script.cursor = NA ) {

    stringa <- script
    match.trovato <- FALSE
    res<-list()
    res["set"]<- str_extract(string = stringa, pattern = "^[ ]*set[ ]+[A-Za-z0-9._]+[ ]*=")
    res["obj"]<- str_extract(string = stringa, pattern = "^[ ]*^[a-zA-Z _]+\\(.*\\)[ ]*\\..*$")
    res["obj.implicit.PK"]<- str_extract(string = stringa, pattern = "^[ ]*[a-zA-Z]+[a-zA-Z0-9_]*\\.[a-zA-Z]+[a-zA-Z0-9_]*[ ]*$")
    res["obj.with.parameters"]<- str_extract(string = stringa, pattern = "^[ ]*^[a-zA-Z _]+(\\(.*\\))*\\.[a-zA-Z _]+\\(.*\\)$")    
    res["return"]<- str_extract(string = stringa, pattern = "^[ ]*return\\(.*\\)[ ]*$")
    res["define"]<- str_extract(string = stringa, pattern = "^[ ]*define[ ]+[a-zA-Z0-9_]+[ ]+as[ ]+method[ ]+of[ ]+[a-zA-Z0-9_]+[ ]*$")
    res["define.function"]<- str_extract(string = stringa, pattern = "^[ ]*define[ ]+function[ ]+[a-zA-Z0-9_]+[ ]*$")
    res["enddefine"]<- str_extract(string = stringa, pattern = "^[ ]*enddefine[ ]*$")
    res["str_cat"]<- str_extract(string = stringa, pattern = "^[ ]*str_cat\\(.*\\)[ ]*$")
    res["if"]<- str_extract(string = stringa, pattern = "^[ ]*if[ ]*\\(.*\\)[ ]*then[ ]*$")
    res["else"]<- str_extract(string = stringa, pattern = "^[ ]*else[ ]*$")
    res["endif"]<- str_extract(string = stringa, pattern = "^[ ]*endif[ ]*$")
    res["foreach"]<- str_extract(string = stringa, pattern = "^[ ]*foreach[ ]*([a-zA-Z]+[a-zA-Z0-9_]*)[ ]+as[ ]+([a-zA-Z]+[a-zA-Z0-9_]*)[ ]*do[ ]*$")
    res["endforeach"]<- str_extract(string = stringa, pattern = "^[ ]*endforeach[ ]*$")
    res["function.call"]<- str_extract(string = stringa, pattern = "^[ ]*^[a-zA-Z]+[a-zA-Z_0-9]*\\(.*\\)$")
    # res["writeLog"]<- str_extract(string = stringa, pattern = "^[ ]*writeLog\\(.*\\)$")        
    # browser()
    # if(stringa=="set deltaInferioreGiorni = $parameter_2$") browser()
    
    # if( global.executed.statements==9  ) browser()
    
    #  SET
    if(!is.na(res["set"]) & match.trovato == FALSE) {
      toReturn <- risolvi.set( stringa , script.cursor = script.cursor )
      match.trovato <- TRUE
    }
    if(!is.na(res["obj.with.parameters"]) & match.trovato == FALSE) {
      res["obj"] <- NA; res["obj.implicit.PK"] <- NA;
      toReturn <- risolvi.accessoAMetodo.con.parametri( stringa, res )
      match.trovato <- TRUE
    }     
    # Se e' un' accesso ad un oggetto
    if( (!is.na(res["obj"]) | !is.na(res["obj.implicit.PK"])) & match.trovato == FALSE ) {
      toReturn <- risolvi.accessoAMetodo( stringa, res )
      if(is.null(toReturn$valore)) toReturn$valore <- global.null.value
      match.trovato <- TRUE
    }
    #  RETURN
    if(!is.na(res["return"]) & match.trovato == FALSE) {
      toReturn <- risolvi.return( stringa )
      match.trovato <- TRUE
    }
    # DEFINE
    if(!is.na(res["define"]) & match.trovato == FALSE) {
      toReturn <- risolvi.define( stringa )
      match.trovato <- TRUE
    }
    # DEFINE
    if(!is.na(res["define.function"]) & match.trovato == FALSE) {
      toReturn <- risolvi.define.function( stringa )
      match.trovato <- TRUE
    }    
    #  ENDDEFINE
    if(!is.na(res["enddefine"]) & match.trovato == FALSE) {
      stop("\n errore, qui ci dovrei arrivare solo senza un contesto aperto... (e se sono qui vuol dire che non ci sono contesti aperti)")
    }
    # STR_CAT
    if(!is.na(res["str_cat"]) & match.trovato == FALSE) {
      toReturn <- risolvi.str_cat( stringa )
      match.trovato <- TRUE
    }
    #  IF
    if(!is.na(res["if"]) & match.trovato == FALSE) {
      toReturn <- risolvi.if( stringa, complete.script = complete.script , script.cursor = script.cursor)
      match.trovato <- TRUE
    }    
    #  ELSE
    if(!is.na(res["else"]) & match.trovato == FALSE) {
      toReturn <- risolvi.else( stringa, complete.script = complete.script , script.cursor = script.cursor)
      match.trovato <- TRUE
    }      
    #  ENDIF
    if(!is.na(res["endif"]) & match.trovato == FALSE) {
      toReturn <- risolvi.endif( stringa, complete.script = complete.script , script.cursor = script.cursor)
      match.trovato <- TRUE
    }        
    #  FOREACH
    if(!is.na(res["foreach"]) & match.trovato == FALSE) {
      toReturn <- risolvi.foreach( stringa, complete.script = complete.script , script.cursor = script.cursor)
      match.trovato <- TRUE
    }       
    #  ENDFOREACH
    if(!is.na(res["endforeach"]) & match.trovato == FALSE) {
      toReturn <- risolvi.endforeach( stringa, complete.script = complete.script , script.cursor = script.cursor)
      match.trovato <- TRUE
    } 
    # #  FUNCTION writeLog
    # if(!is.na(res["writeLog"]) & match.trovato == FALSE) {
    #   toReturn <- risolvi.writeLog( stringa, complete.script = complete.script , script.cursor = script.cursor)
    #   browser()
    #   match.trovato <- TRUE
    # }           
    #  FUNCTION CALL
    if(!is.na(res["function.call"]) & match.trovato == FALSE) {
      toReturn <- risolvi.function.call( stringa, complete.script = complete.script , script.cursor = script.cursor)
      match.trovato <- TRUE
    }       
    
    if(match.trovato== TRUE) { 
      if(global.debug.mode==TRUE & global.deep.level <= global.max.debug.deep  & is.numeric(script.cursor) ) {
        barra.t <- paste(c("|",rep("-",global.deep.level),">"),collapse='')
        cat("\n",barra.t,"Lvl:",global.deep.level,"Line:",script.cursor,":#",global.executed.statements,":",script)
        if( global.executed.statements %in% global.arr.breakpoints ) handle.debug.console.GUI()
        global.executed.statements <<- global.executed.statements + 1
      }
      return(toReturn)
    }
    
    # =========================================
    # SYNTAX ERROR!
    # =========================================
    if(match.trovato== FALSE) {
      browser()
      cat( "\n syntax error in resolving: ", stringa )
      stop()
    }
  }
  handle.debug.console.GUI <- function( ){
    keyPressed = ""
    valid.keypressed.keys = c("c","n") 
    while( !(keyPressed %in% valid.keypressed.keys) ) { 
      cat("\n ----------------------------------------------------------------------")
      cat("\n press :")
      cat("\n\t[n]+[enter]: next (1 more line)")
      cat("\n\t[c]+[enter]: continue (shutdown debug mode and continue)")
      cat("\n\t[v]+[enter]: see variables")
      cat("\n\t[q]+[enter]: quit")
      
      keyPressed = readline()
      
      if( keyPressed == "q" ) stop()
      if( keyPressed == "n" )  {
        global.arr.breakpoints <<- unique(c(global.arr.breakpoints, (global.executed.statements+1) ))
      }
      if( keyPressed == "c" )  {
        global.arr.breakpoints <<- c()
      }      
      if( keyPressed == "v" )  {
        cat("\n ----------------------------------------------------------------------")
        print.vars()
      }      
    }
    cat("\n ----------------------------------------------------------------------")
  }
  print.vars<- function( ) {
    cat("\n")
    matrice <- c()
    if(length(mem.struct$var)==0) {
      cat("\n <no vars>"); return()
    }
    for(  ct in seq(1:length(mem.struct$var))) {
      nome <- names(mem.struct$var)[ct]
      tipo <- mem.struct$var[[nome]]$type
      valore <- mem.struct$var[[nome]]$value
      if(length(valore)>1) valore <- paste(valore, collapse = ',')
      matrice <- rbind(matrice, c(nome, tipo, valore) ) 
    }
    colnames(matrice)<-c("nome","tipo","valore")
    print(matrice)
    return()
  }
  # ********************************************************************
  # INIZIO Sezione di risoluzione della semantica
  # ********************************************************************
  
  # ----------------------------------------------------
  # ENDFOREACH
  # ----------------------------------------------------   
  risolvi.endforeach<-function( stringa , complete.script , script.cursor  ) {
    runningClass <- mem.struct$running.class
    runningMethod <- mem.struct$running.method
    runningFunction <- mem.struct$running.function
    
    if( !is.null(runningClass) & !is.null(runningMethod) ) { 
      matrice <- mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$foreach$matrice
    }    
    if( !is.null(runningFunction) )  {
      matrice <- mem.struct$functions[[runningFunction]]$struttura$foreach$matrice
    }    
    
    riga.di.interesse <- matrice[ which(matrice[,"riga"]==as.character(script.cursor)), ]
    
    cursore <- riga.di.interesse["cursore"]
    arr2run <- riga.di.interesse["array"] 

    # incrementa il CURSOR.INDEX
    mem.struct$active.loops[[as.character(script.cursor)]]$cursorIndexPos <<- mem.struct$active.loops[[as.character(script.cursor)]]$cursorIndexPos +1 

    # e zompa
    return( 
      list( "valore" = NA,
            "operation.token" = "ENDFOREACH",
            "operation" = stringa,
            "setScriptCursorTo" = as.numeric(riga.di.interesse["linkedTo"] )
      )
    )      
    
  }  
  # ----------------------------------------------------
  # FOREACH
  # ----------------------------------------------------   
  risolvi.foreach<-function( stringa , complete.script , script.cursor  ) {
    # if(stringa=="foreach arr_id as cursor do") browser()
    runningClass <- mem.struct$running.class
    runningMethod <- mem.struct$running.method
    runningFunction <- mem.struct$running.function
    # Prendi la matrice della strutture dei FOREACH in funzione che sia un METODO o una FUNZIONE
    # (quella che sta correndo ora)
    if( !is.null(runningClass) & !is.null(runningMethod) ) {
      matrice <- mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$foreach$matrice
    }
    if( !is.null(runningFunction) )  {
      # browser()
      matrice <- mem.struct$functions[[runningFunction]]$struttura$foreach$matrice
    }
      
    # matrice <- mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$foreach$matrice
    riga.di.interesse <- matrice[ which(matrice[,"riga"]==as.character(script.cursor)), ]

    cursore <- riga.di.interesse["cursore"]
    arr2run <- riga.di.interesse["array"] 
    endForEachLine <- riga.di.interesse["linkedTo"] 
    
    # Prima cerca di capire se c'e' un CONTEXT aperto per questo FOREACH
    # se no, crealo (sempre che la condizione abbia senso)
    if(!(as.character(script.cursor) %in% names(mem.struct$active.loops))) {
      mem.struct$active.loops[[as.character(script.cursor)]] <<- list("active"=TRUE,
                                                                   "cursorIndexPos"=0,
                                                                   "cursorName"=cursore)
    }
    # idem, nel caso in cui fosse stato chiuso precedentemente
    if(mem.struct$active.loops[[as.character(script.cursor)]]$active==FALSE) {
      mem.struct$active.loops[[as.character(script.cursor)]] <<- list("active"=TRUE,
                                                                   "cursorIndexPos"=0,
                                                                   "cursorName"=cursore)
    }
# browser()
    # Prendi i dati dell'array (in prima battuta vedi solo se esiste nelle variabili in memoria)
    if( !(arr2run %in% names(mem.struct$var))) {
      stop("\n ERRORE, l'array per il FOREACH non e' presente fra le variabili dichiarate")
    }
    # Spiana il cursore, anche se gia' esiste nello spazion delle variabili: RUSPA!
    # (intanto mettici dentro la cosa piu' simile al 'NULL' che conosca)
    mem.struct$var[[cursore]] <<- list( "type" = "NULL", "value" = global.null.value )
    # if(stringa=="foreach arr_id as cursor do") browser()
    # Verifica la condizione per capire che fare
    # L'array ha almeno un elemento? E' diverso dal global.null.value?
    if(mem.struct$var[[arr2run]]$type=="NULL") {
      # devo zompare al ENDOFOREACH: chiudi il loop (settalo come non attivo)
      mem.struct$active.loops[[as.character(script.cursor)]] <<- list("active"=FALSE)
      # e zompa
      return( 
        list( "valore" = NA,
              "operation.token" = "ENDFOREACH",
              "operation" = stringa,
              "setScriptCursorTo" = as.numeric(endForEachLine)+1
        )
      )    
    }
    # Verifica la condizione per capire che fare
    # L'array ha almeno un elemento? E' diverso dal global.null.value?    
    if( length(mem.struct$var[[arr2run]]$value)<=1 ) { 
      if(mem.struct$var[[arr2run]]$value==global.null.value | 
         length(mem.struct$var[[arr2run]]$value)==0) {
        # devo zompare al ENDOFOREACH: chiudi il loop (settalo come non attivo)
        mem.struct$active.loops[[as.character(script.cursor)]] <<- list("active"=FALSE)
        # e zompa
        return( 
          list( "valore" = NA,
                "operation.token" = "ENDFOREACH",
                "operation" = stringa,
                "setScriptCursorTo" = as.numeric(endForEachLine)+1
          )
        )    
      }
    }
    # Ora verifica se il cursor.index e' gia' arrivato in fondo
    if(mem.struct$active.loops[[as.character(script.cursor)]]$cursorIndexPos >= length(mem.struct$var[[arr2run]]$value)) {
      # devo zompare al ENDOFOREACH: chiudi il loop (settalo come non attivo)
      mem.struct$active.loops[[as.character(script.cursor)]] <<- list("active"=FALSE)
      # e zompa
      return( 
        list( "valore" = NA,
              "operation.token" = "ENDFOREACH",
              "operation" = stringa,
              "setScriptCursorTo" = as.numeric(endForEachLine)+1
        )
      )    
    }
    # Ok, se sono qui significa che sono in ballo: 
    # aggiorna il CURSOR.INDEX
    mem.struct$active.loops[[as.character(script.cursor)]]$cursorIndexPos <<- mem.struct$active.loops[[as.character(script.cursor)]]$cursorIndexPos + 1
    # setta il valore del CURSOR
    mem.struct$var[[cursore]]$value <<- mem.struct$var[[arr2run]]$value[ mem.struct$active.loops[[as.character(script.cursor)]]$cursorIndexPos ]
    # Ora prova ad indovinare il tipo di sto' cazzo di cursore
    if( is.na(mem.struct$var[[cursore]]$value ))  { stop("\n ERRORE... vorrei proprio capire come fa ad arrivare NA il cursore, a questo punto...") }
    mem.struct$var[[cursore]]$type <<- definisci.tipo.variabile( mem.struct$var[[cursore]]$value )$tipo.variabile.restituita

    return( 
      list( "valore" = NA,
            "operation.token" = "FOREACH",
            "operation" = stringa
      )
    )  
  }
  # ----------------------------------------------------
  # ENDIF
  # ----------------------------------------------------   
  risolvi.endif<-function( stringa , complete.script , script.cursor  ) {
    
    runningClass <- mem.struct$running.class
    runningMethod <- mem.struct$running.method
    runningFunction <- mem.struct$running.function
    
    if(!is.null(runningClass) & !is.null(runningMethod)) {  
      arr.endif <- unlist(lapply(mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$if.else.endif, function(x){ x$riga.endif } ))
    }
    if(!is.null(runningFunction)) { 
      arr.endif <- unlist(lapply(mem.struct$functions[[runningFunction]]$struttura$if.else.endif, function(x){ x$riga.endif } ))
    }    

    quale_posizione <- which( arr.endif == script.cursor,arr.ind = T)
    if(length(quale_posizione)==0) stop("ERRORE: non riesco a trovare la posizione cui e' associato l'ENDIF")
    
    script.cursor <- as.numeric(script.cursor)
    
    # in ogni caso, poche seghe: devi andare alla posizione successiva :)
    return( 
      list( "valore" = NA,
            "operation.token" = "ENDIF",
            "operation" = stringa,
            "setScriptCursorTo" = script.cursor  + 1
      )
    )   
  }  
  # ----------------------------------------------------
  # ELSE
  # ----------------------------------------------------   
  risolvi.else<-function( stringa , complete.script , script.cursor  ) {
    # browser()
    runningClass <- mem.struct$running.class
    runningMethod <- mem.struct$running.method
    runningFunction <- mem.struct$running.function
    
    if(!is.null(runningClass) & !is.null(runningMethod)) { 
      arr.else <- unlist(lapply(mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$if.else.endif, function(x){ x$riga.else } ))
      # Se sto leggendo un ELSE e' perche' ero nella condizione ed ora devo saltare all'endif
      # quindi prendi l'endif associato e zompa!
      new.script.cursor <- mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$if.else.endif[[quale_posizione]]$riga.endif
    }
    if(!is.null(runningFunction)) { 
      arr.else <- unlist(lapply(mem.struct$functions[[runningFunction]]$struttura$if.else.endif, function(x){ x$riga.else } ))
      # Se sto leggendo un ELSE e' perche' ero nella condizione ed ora devo saltare all'endif
      # quindi prendi l'endif associato e zompa!
      new.script.cursor <- mem.struct$functions[[runningFunction]]$struttura$if.else.endif[[quale_posizione]]$riga.endif
    }
    quale_posizione <- which( arr.else == script.cursor,arr.ind = T)
    if(length(quale_posizione)==0) stop("ERRORE: non riesco a trovare la posizione cui e' associato l'ELSE")


    return( 
      list( "valore" = NA,
            "operation.token" = "ELSE",
            "operation" = stringa,
            "setScriptCursorTo" = as.numeric(new.script.cursor)
      )
    )     
  }

  # ----------------------------------------------------
  # IF
  # ----------------------------------------------------  
  risolvi.if<-function( stringa , complete.script , script.cursor ) {
# if(stringa=="if(valore <= 0 | valore >= 2.8 ) then") browser()
    runningClass <- mem.struct$running.class
    runningMethod <- mem.struct$running.method
    runningFunction <- mem.struct$running.function
    
    # Bene! Dato che sono stato figo ed ho costruito in pre-processing degli 
    # script la struttura degli if, facciamo che ora vado a ripigliarla!
    # (prima vediamo che ci sia, senno': ERROR! )
    if(!is.null(runningClass) & !is.null(runningMethod)) {
      if( (as.character(script.cursor) %in%  
           names(mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$if.else.endif))==FALSE) {
        stop("Errore! mi sarei aspettato di trovar parlato di questo if, dal pre-processor dello script!")
      }      
      # prendi i nomi delle sospette variabili da sostituire
      sospette.variabili <- mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$if.else.endif[[as.character(script.cursor)]]$toResolve
      # ora scorri l'array delle posizioni da ricostruire, dove abbiamo indicato con il nome
      # "token" le posizioni in cui e' stata trovata (stimata) una variabile di cui sostituire il valore
      arrayCondizioneDaRicostruire <- mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$if.else.endif[[as.character(script.cursor)]]$arrayCondizioneDaRicostruire
      # Ora cerca di capire dove il cursore di eseuczione dello script dovrebbe venire mosso!
      riga.else <- mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$if.else.endif[[as.character(script.cursor)]]$riga.else
      riga.endif <- mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$if.else.endif[[as.character(script.cursor)]]$riga.endif
    }
    if(!is.null(runningFunction)) {
      # prendi i nomi delle sospette variabili da sostituire
      sospette.variabili <- mem.struct$functions[[runningFunction]]$struttura$if.else.endif[[as.character(script.cursor)]]$toResolve
      # ora scorri l'array delle posizioni da ricostruire, dove abbiamo indicato con il nome
      # "token" le posizioni in cui e' stata trovata (stimata) una variabile di cui sostituire il valore
      arrayCondizioneDaRicostruire <- mem.struct$functions[[runningFunction]]$struttura$if.else.endif[[as.character(script.cursor)]]$arrayCondizioneDaRicostruire
      # Ora cerca di capire dove il cursore di eseuczione dello script dovrebbe venire mosso!
      riga.else <- mem.struct$functions[[runningFunction]]$struttura$if.else.endif[[as.character(script.cursor)]]$riga.else
      riga.endif <- mem.struct$functions[[runningFunction]]$struttura$if.else.endif[[as.character(script.cursor)]]$riga.endif
    }

    # prendi i nomi delle sospette variabili da sostituire
    # sospette.variabili <- mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$if.else.endif[[as.character(script.cursor)]]$toResolve
    
    valore.trovato<-list(); tipo.variabile <- list()
    for( variabile in sospette.variabili ) {
      if(!(variabile %in% names(mem.struct$var)))  {
        cat("\n Errore! La variabile'",variabile,"' non mi risulta definita....")
        stop()
      } 
      valore.trovato[[variabile]] <- mem.struct$var[[variabile]]$value
      tipo.variabile[[variabile]] <- mem.struct$var[[variabile]]$type
    }
    
    # # ora scorri l'array delle posizioni da ricostruire, dove abbiamo indicato con il nome
    # # "token" le posizioni in cui e' stata trovata (stimata) una variabile di cui sostituire il valore
    # arrayCondizioneDaRicostruire <- mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$if.else.endif[[as.character(script.cursor)]]$arrayCondizioneDaRicostruire

    condizione.finale.da.parsare<-c()
    if(length(arrayCondizioneDaRicostruire)>0) { 
      for( i in 1:length(arrayCondizioneDaRicostruire)) { 
        tipo <- names(arrayCondizioneDaRicostruire)[i]
        pezzo <- arrayCondizioneDaRicostruire[i]
        variabile <- arrayCondizioneDaRicostruire[i]
        if(tipo=="token")  { 
          if(tipo.variabile[[variabile]]=="string")
            pezzo <- paste(c("'",valore.trovato[[variabile]],"'"),collapse = '')
          else
            pezzo <- valore.trovato[[variabile]]
          
          if(tipo.variabile[[variabile]]=="null") { 
            pezzo <-  paste(c("'",global.null.value,"'"),collapse = '')
          }            
        }
        condizione.finale.da.parsare <- paste(c(condizione.finale.da.parsare,pezzo),collapse = '')
      }
    } else  { 
      condizione.finale.da.parsare <- arrayCondizioneDaRicostruire
    }
    # if(stringa=="if( idNoduli != 'null') then") browser()
    esito.condizione <- eval(parse(text=condizione.finale.da.parsare))
    
    # Ora cerca di capire dove il cursore di eseuczione dello script dovrebbe venire mosso!
    # riga.else <- mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$if.else.endif[[as.character(script.cursor)]]$riga.else
    # riga.endif <- mem.struct$class.methods[[runningClass]][[runningMethod]]$struttura$if.else.endif[[as.character(script.cursor)]]$riga.endif
    
    if(esito.condizione==TRUE) nuova.posizione.cursore <- script.cursor + 1
    if(esito.condizione==FALSE) { 
      if(!is.na(riga.else)) { nuova.posizione.cursore <- as.numeric(riga.else)+1 }
        else  { nuova.posizione.cursore <- as.numeric(riga.endif) }
    }

    return( 
      list( "valore" = esito.condizione,
            "operation.token" = "IF",
            "operation" = stringa,
            "setScriptCursorTo" = as.numeric(nuova.posizione.cursore)
      )
    )
  }
  # ----------------------------------------------------
  # STR_CAT
  # ----------------------------------------------------  
  risolvi.str_cat<-function( stringa ) {
    tmp.stringa <- str_trim(stringa)
    tmp.stringa <- str_sub(tmp.stringa,start = 9,end = str_length(tmp.stringa)-1)
    
    arr.membri <- unlist(str_split(string = tmp.stringa,pattern = ","))
    
    valore.finale <- c()
    for( membro.1 in arr.membri) {
      
      # E' una stringa?'
      if(is.a.quoted.string(membro.1)) valore.membro.1 <- togli.apici.esterni.stringa(membro.1)
      else {  # E' una variabile?
        if(membro.1 %in% names(mem.struct$var))  {
          if(mem.struct$var[[membro.1]]$type != "string") stop("errore: non posso fare lo str_cat fra non stringhe")
          valore.membro.1 <- mem.struct$var[[membro.1]]$value
        }
        else {  # ultimo tentativo: Risolvilo!
          tmp.res.HLL <- invoca.ricorsivamente.HLL( membro.1 )
          valore.membro.1 <- tmp.res.HLL$valore
        }
      }
      valore.finale <- str_c(valore.finale,valore.membro.1)
    }
    return(list( "valore"=valore.finale, "operation.token" = "str_cat", "operation"=stringa))
    # Se gnon ia' era aperta una definizione, dai errore
    stop("\n errore, qui ci dovrei arrivare solo senza un contesto aperto...")    
  }
  # ----------------------------------------------------
  # DEFINE
  # ----------------------------------------------------  
  risolvi.define<-function( stringa ) {
    # Se gia' era aperta una definizione, dai errore
    if(length(mem.struct$define.context)>0) stop("\n sono gia' nel contesto di una definizione: non posso aprirle un'altra")
    nome.metodo <- str_trim(sub("+[ ]+as[ ]+method[ ]+of[ ]+[a-zA-Z0-9_]+[ ]*$","\\1",stringa) )
    nome.metodo <- str_trim(str_sub(string = nome.metodo,start = 7,end = str_length(nome.metodo)))
    nome.classe <- str_trim(sub("^[ ]*define[ ]+[a-zA-Z0-9_]+[ ]+as[ ]+method[ ]+of[ ]+","\\1",stringa) )
    proxy.mem.contesto.set(method.name = nome.metodo,class.name = nome.classe)
    return(list( "valore"=NA, "operation.token" = "define", "operation"=stringa))    
  }
  risolvi.define.function<-function( stringa ) {
    # Se gia' era aperta una definizione, dai errore
    if(length(mem.struct$define.context)>0) stop("\n sono gia' nel contesto di una definizione: non posso aprirle un'altra")
    nome.funzione <- str_trim(sub("^[ ]*define[ ]+function[ ]+","\\1",stringa) )
    proxy.mem.contesto.set( nome.funzione = nome.funzione )
    return(list( "valore"=NA, "operation.token" = "define", "operation"=stringa))    
  }
  # ----------------------------------------------------
  # RETURN
  # ----------------------------------------------------  
  risolvi.return<-function( stringa ) {
    
    argomento <- sub("^[ ]*return\\([ ]*","\\1",stringa)
    argomento <- str_sub(argomento,start = 1,end = str_length(argomento)-1)
    argomento <- str_trim(argomento)

    # e' un intero?
    if(is.a.number(argomento)) {
      return(list( "valore"=as.numeric(argomento), "operation.token" = "return", "operation"=stringa))
    }
    # e' una stringa?
    if(is.a.quoted.string(argomento)) {
      argomento <- togli.apici.esterni.stringa(argomento)
      return(list( "valore"=argomento, "operation.token" = "return", "operation"=stringa))
    }
    # e' una variabile?
    if( argomento %in% names(mem.struct$var) ) {
      return(list( "valore"=mem.struct$var[[argomento]]$value, "operation.token" = "return", "operation"=stringa))
    }
    # ... allora dai errore perche' va risolto ricorsivamente
    stop("-TODO: invoca ricorsivamente il calcolo dell' argomento da restituire")    
  }
  risolvi.function.call  <-function(stringa, complete.script , script.cursor ) {
    
    # prendi il nome funzione
    nome.funzione <- str_trim(sub("\\(.*\\)$" ,"\\1", stringa ))
    # ora prendi gli argomenti
    tmp.val.1 <- str_trim(sub("^[ ]*^[a-zA-Z]+[a-zA-Z_0-9]*" ,"\\1", stringa ))
    stringa.argomento <- str_sub(string = tmp.val.1,start = 2,end = str_length(tmp.val.1)-1)
    tmp.str.4 <- str_split(string = stringa.argomento,pattern = ",")[[1]]   
    arr.argomento <- unlist(lapply(X = tmp.str.4, str_trim ))    
    
    # Ora sbroglia gli argomenti
    lst.argomento.valori <- c()
    ct <- 1
    for(argomento in arr.argomento) {
      assigned <- FALSE
      # Se il valore dell'argomento e' gia' passato (es: stringa o int)
      if( is.a.number(argomento) | is.a.quoted.string(argomento) & assigned==FALSE ) {
        lst.argomento.valori[[ct]] <- list("value"=argomento,"type"=definisci.tipo.variabile(argomento))
        assigned <- TRUE
      }
      # Se e' una variabile presente in memoria
      if(argomento %in% names(mem.struct$var)  & assigned==FALSE ) {
        lst.argomento.valori[[ct]] <- mem.struct$var[[argomento]]
        assigned <- TRUE
      }
      if( assigned==FALSE ) {
        # Se invece devo risolverlo
        browser()
        stop("\n Ach! non sono ancora pronto a risolvere questo tipo di arogmento... chiama il mainteiner del pacchetto!")
      }
      ct <- ct + 1
    }    
    
    
    # VERIFICA che la funzione esista
    if(!( nome.funzione %in% names(mem.struct$functions) ) & nome.funzione!="writeLog") stop("\nERRORE: Ach! la funzione non sembra esistere")
    
    # ORA risolvi L'accesso alla funzione!
    ooo <- risolvi.funzione.HLL( nome.funzione = nome.funzione, lst.argomenti = lst.argomento.valori)
    
    return(ooo)
  }
  risolvi.accessoAMetodo.con.parametri<-function( stringa , res) {
    # estrazione preliminare di sottostringhe
    tmp.pos.2 <- str_trim(str_locate(pattern = "^[a-zA-Z]+[a-zA-Z0-9_]*(\\.|\\([a-zA-Z0-9_ ]+\\))" ,string =  stringa ))
    tmp.pos.2<- as.numeric(tmp.pos.2)
    tmp.classe <- str_sub(string = stringa,start = tmp.pos.2[1],end = tmp.pos.2[2])
    last.char <- str_sub(string = tmp.classe, start = str_length(tmp.classe), end = str_length(tmp.classe))
    if(last.char==".") { 
      # prendi la classe
      classe <- str_sub(string = stringa,start = tmp.pos.2[1],end = tmp.pos.2[2]-1)
      # prendi il metodo
      tmp.str.1 <- str_trim(sub("^[a-zA-Z]+[a-zA-Z0-9_]*" ,"\\1", stringa ))
      metodo <- str_sub(string = tmp.str.1,start = 2,end = str_locate(string = tmp.str.1,pattern = "\\(")[1]-1)
      # verifica la PK      
      # Se non e' una relazione, la PK e' obbligatoria
      PK.to.pass <- NA      
      if(LLL.env$is.relation.of(className = classe, relName=metodo) == FALSE) { 
        if(is.na(mem.struct$implicit.PK)) stop("\n non e' stato dichiarata la PK implicita (4)")
      }
      PK.to.pass <- mem.struct$implicit.PK
      # prendi gli argomenti passati 
      tmp.str.2 <- str_trim(sub("^[a-zA-Z]+[a-zA-Z0-9_]*\\.[a-zA-Z0-9_]+\\(" ,"\\1", stringa ))
      tmp.str.3 <- str_sub(string = tmp.str.2,start = 1,end = -2)
      tmp.str.4 <- str_split(string = tmp.str.3,pattern = ",")[[1]]
      arr.argomento <- unlist(lapply(X = tmp.str.4, str_trim ))
    }
    if(last.char==")") { 
      classe <- str_sub(string = tmp.classe,start = 1,end = str_locate(string = tmp.classe,pattern = "\\(")[1]-1)
      PK.to.pass <- str_sub(string = tmp.classe,start = str_locate(string = tmp.classe,pattern = "\\(")[1]+1,end = str_locate(string = tmp.classe,pattern = "\\)")[1]-1)
      tmp.str.1.5 <- str_sub(string = stringa,start = str_length(tmp.classe)+2)
      # prendi il metodo
      metodo <- str_sub(string = tmp.str.1.5,start = 1,end = str_locate(string = tmp.str.1.5,pattern = "\\(")[1]-1)
      # prendi gli argomenti passati 
      tmp.str.3 <- str_trim(str_sub(string = tmp.str.1.5,start = str_locate(string = tmp.str.1.5,pattern = "\\(")[1]+1,end = -2))
      tmp.str.4 <- str_split(string = tmp.str.3,pattern = ",")[[1]]   
      arr.argomento <- unlist(lapply(X = tmp.str.4, str_trim ))
    }
    
    # Ora sbroglia gli argomenti: non vorrei dovessero risolverseli a valle!
    lst.argomento.valori <- c()
    ct <- 1
    for(argomento in arr.argomento) {
      assigned <- FALSE
      # Se il valore dell'argomento e' gia' passato (es: stringa o int)
      if( is.a.number(argomento) | is.a.quoted.string(argomento) & assigned==FALSE ) {
        lst.argomento.valori[[ct]] <- list("value"=argomento,"type"=definisci.tipo.variabile(argomento))
        assigned <- TRUE
      }
      # Se e' una variabile presente in memoria
      if(argomento %in% names(mem.struct$var)  & assigned==FALSE ) {
        lst.argomento.valori[[ct]] <- mem.struct$var[[argomento]]
        assigned <- TRUE
      }
      if( assigned==FALSE ) {
        # Se invece devo risolverlo
        browser()
        stop("\n Ach! non sono ancora pronto a risolvere questo tipo di arogmento... chiama il mainteiner del pacchetto!")
      }
      ct <- ct + 1
    }
    # if(stringa=="Tools.getDeltaDays( ultimaData, dataOdierna )") browser()
    
    ooo <- risolvi.accessoAMetodo(stringa = stringa, res = res , 
                                  nome.oggetto= classe, attributo=metodo, obj.pk=PK.to.pass, 
                                  lst.argomenti=lst.argomento.valori, complex.invokation = TRUE) 
    return(ooo)  
  }
  # ----------------------------------------------------
  # <oggetto>(<id>).<attributo> OPPURE un <oggetto>.<attributo> con un PK implicito
  # ----------------------------------------------------  
  risolvi.accessoAMetodo<-function( stringa , res , 
                                    nome.oggetto=NA, attributo=NA, obj.pk=NA, 
                                    lst.argomenti=c(), complex.invokation=FALSE) {
    # if(stringa=="Tools.addDaysToDate( dataEvento_Hook, -90 )") browser()
    # if(stringa=="Tools.addDaysToDate( dataDiRiferimento, deltaInferioreGiorni )") browser()
    # if(stringa=="EcoTiroide(hook_US).dimensioneNoduloMaggiore") browser()
    # normalizza il formato dei parametri dato che rischiano di arrivare con strutture diverse!
    # - im - normalizzazione
    for( i in seq(1,length(lst.argomenti))) {	
      if(is.list(lst.argomenti[[i]]$type))  {
        tmp.a.value <- lst.argomenti[[i]]$type$risultatoElemento
        tmp.a.type <- lst.argomenti[[i]]$type$tipo.variabile.restituita
        lst.argomenti[[i]] <- list( "type"=tmp.a.type , "value"=tmp.a.value)
      }
    }
    # - fm - normalizzazione
    
    # if(stringa=="Paziente.EventoClinicoDiTerzePartiFraDate('SCINTIGRAFIA',dataFrom,dataTo)") browser()
    # Due controlli formali di apertura, giusto per gradire (se caso implicito ma manca la PK)
    RelazioneDiTipo <- FALSE
    # browser()
    if(!is.na(res["obj.implicit.PK"])) {
      # Se non e' un oggetto complesso, estrai classe e metodo
      if(complex.invokation==FALSE) { 
        nome.oggetto <- str_trim(sub("\\.[a-zA-Z]+[a-zA-Z0-9_]*[ ]*$" ,"\\1", stringa ))
        attributo <- str_trim(sub("^[ ]*[a-zA-Z]+[a-zA-Z0-9_]*\\." ,"\\1", stringa ))
      }
      
      # Cerca di capire SE e' una relazione e, se no, dai errore in caso in cui manchi la PK'
      # (nel caso di relazione sul solo master, cio' e' ammissibile)
      RelazioneDiTipo <- LLL.env$is.relation.of( nome.oggetto , attributo , whatInfo="type" )
      if(RelazioneDiTipo!="master-only") { 
        if( !("implicit.PK" %in% names(mem.struct)) ) stop("\n non e' stato dichiarata la PK implicita (1)")
        if( is.na(mem.struct$implicit.PK)) stop("\n non e' stato dichiarata la PK implicita (2)")
      }
      obj.pk <- mem.struct$implicit.PK
    }
    else {  # CASO ESPLICITO
      # sempre nel caso non si tratti di un oggetto complesso
      if(complex.invokation==FALSE) {  
        # Estrai 'nome.oggetto', 'obj.pk' e 'attributo'
        obj.pk <- str_trim(sub("[ ]*\\..*$","\\1",stringa))
        obj.pk <- str_trim(sub("^[ ]*^[a-zA-Z _]+\\(","\\1",obj.pk))
        obj.pk <- str_sub(string = obj.pk,  start=1, end=str_length(obj.pk)-1)
        nome.oggetto <- str_trim(sub("+\\(.*\\)[ ]*\\..*$","\\1",stringa))
        attributo <- sub("^[ ]*^[a-zA-Z _]+\\(.*\\)[ ]*\\.[ ]*","\\1",stringa)
      }
    }
    
    need.PK <- LLL.env$is.relation.of( nome.oggetto , attributo , whatInfo="need.PK" )
    # if(stringa=="Paziente.EventoClinicoDiTerzePartiFraDate('SCINTIGRAFIA',dataFrom,dataTo)") browser()
    # invoca eventuali calcoli ricorsivi, per risolvere 'obj.pk' o il valore di 'secondo.membro'
    if( is.a.number(obj.pk) == FALSE & need.PK == TRUE ) {
      # Vediamo se e' una variabile :)
      if( obj.pk %in% names(mem.struct[["var"]]) ) {
        if( mem.struct[["var"]][[obj.pk]]$type=="numeric"  ) {
          obj.pk <- mem.struct[["var"]][[obj.pk]]$value
        }
        else { 
          stop("ERRORE: l'id non puo' essere usato come chiave in quanto non numerico") 
        }
      }
      else  {
        stop("-TODO: invoca ricorsivamente il calcolo dell' PK dell'oggetto")
      }
    }
    # due controlli formali, giusto per gradire
    if(obj.pk=="" & need.PK==TRUE ) {  cat( "\nmmmhhhh, sono restato senza obj.pk: ", stringa );  stop()  }
    if(nome.oggetto=="") {  cat( "\nmmmhhhh, sono restato senza nome.oggetto: ", stringa );  stop()  }
    if(attributo=="") {  cat( "\nmmmhhhh, sono restato senza attributo: ", stringa );  stop()  }
    # Se sto cercando di invocare la classe TOOLS!
    if(nome.oggetto=="Tools") {
      obj.tool <- Ste.tool.class()
      obj.tool$setEnv( mem = mem.struct, null.value = global.null.value )
      # browser()
      val.from.obj.tool <- obj.tool$proxy( stringa = attributo , lst.parametri = lst.argomenti)
      if(val.from.obj.tool$error == TRUE ) stop("Errore non identificato nell'invocare la classe Tools")
# browser()
      return(list( "valore"=val.from.obj.tool$value,
                   "operation.token" = "Tools::<method>",
                   "operation"=stringa))
    }
    # E' un metodo? (in HLL)
    if(attributo %in% names(mem.struct$class.methods[[nome.oggetto]])) {
      res <- risolvi.metodo.HLL( classe = nome.oggetto , metodo = attributo, implicit.PK = obj.pk , 
                                 lst.argomenti = lst.argomenti)
      return( res )
    }
    else {
      # E' l'attributo di una classe? ( in LLL )
      if(LLL.env$is.attribute.of(className = nome.oggetto, attrName=attributo) == TRUE) {
        res <- LLL.env$getEntityAttribute(obj.name = nome.oggetto,id = obj.pk,attr.name = attributo)
        return(list( "valore"=res,
                     "operation.token" = "getEntityAttribute",
                     "operation"=stringa))
      }
      else {
        # browser()
        # E' una relazione fra due classi?
        if(LLL.env$is.relation.of(className = nome.oggetto, relName=attributo) == TRUE) {
          res <- LLL.env$getEntityRelation(obj.name = nome.oggetto,id = obj.pk, relation.name = attributo, lst.argomenti = lst.argomenti)
          return(list( "valore"=res,
                       "operation.token" = "getEntityRelation",
                       "operation"=stringa))
        }
        else stop("\n non e' un attributo ne' un metodo ne' una relazione... errore: che e'?")
      }
      stop("\n non dovrei essere qui!!! (v2)")
    }
    stop("\n non dovrei essere qui!!! (v1)")    
  }
  
  # ----------------------------------------------------
  # SET
  # ----------------------------------------------------
  risolvi.set<-function( stringa , script.cursor = NA ) {
    # if(stringa=="set deltaInferioreGiorni = $parameter_2$") browser()
    runningClass <- mem.struct$running.class
    runningMethod <- mem.struct$running.method
    
    nome.variabile <- str_extract(string = sub("^[ ]*set[ ]*", "\\1", stringa),pattern = "[A-Za-z0-9._]*")
    secondo.membro <- sub("^[ ]*set[ ]+[A-Za-z0-9._]+[ ]*=[ ]*","\\1",stringa)
    # browser()
    # if(stringa=="set dataDiRiferimento = $parameter_3$") browser()
    
    # Se il secondo membro e' un PARAMETER, associalo
    if( !is.na(str_extract(string = secondo.membro, pattern = "^[ ]*\\$.*[0-9]+\\$[ ]*$")) ) {
      tmp.secondo.membro <- str_trim(secondo.membro)
      whichParameter <- str_sub(string = tmp.secondo.membro,start = 12,end = str_length(tmp.secondo.membro)-1)
      if( is.numeric(as.numeric(whichParameter)) == FALSE) stop("\n ERRORE: qualcosa non va in come e' stato indicato il parametro: errore di sintassi?")
      whichParameter <- as.numeric(whichParameter)
      if( whichParameter > length(mem.struct$lst.parameters) ) { 
        stop("\n ERRORE: qualcosa non va in come e' stato indicato il parametro: parametro non esistente")
      }        
      # if(stringa=="set dataDiRiferimento = $parameter_3$") browser()
      # if(stringa=="set arr_id = $parameter_1$") browser()
      # secondo.membro <- mem.struct$lst.parameters[[whichParameter]]$type$risultatoElemento
      # Proviamo cosi': se il parametro e' stato stimato, prendi la stima, senno' prendi quanto 
      # direttamente indicato
    
      if(is.list(mem.struct$lst.parameters[[whichParameter]]$type)) {
        # browser()
        secondo.membro <- mem.struct$lst.parameters[[whichParameter]]$type$risultatoElemento
        tipo.variabile <- mem.struct$lst.parameters[[whichParameter]]$type$tipo.variabile.restituita
      } else  {
        # secondo.membro <- mem.struct$lst.parameters[[whichParameter]]$value
        # browser()
        aaa <- definisci.tipo.variabile(risultatoElemento = mem.struct$lst.parameters[[whichParameter]]$value)
        secondo.membro <- aaa$risultatoElemento
        tipo.variabile <- aaa$tipo.variabile.restituita
      }
      # Visto che sono in grado di associarlo subito, associalo ed esci
      proxy.mem.struct.set(varName = nome.variabile, value = secondo.membro, type = tipo.variabile)
      return( list(
        "valore" = NA,
        "operation.token" = "SET",
        "operation"=stringa
      ) )
    }    
    
    # Se il secondo membro e' un numero non stare a farti tante seghe...
    if( is.a.number(secondo.membro) == TRUE ) {
      proxy.mem.struct.set(varName = nome.variabile, value = as.numeric(secondo.membro), type = "numeric")
      return( list(
        "valore" = NA,
        "operation.token" = "SET",
        "operation"=stringa
      ) )
    }
    if( is.a.quoted.string(secondo.membro) ) {
      proxy.mem.struct.set(varName = nome.variabile, value = togli.apici.esterni.stringa(secondo.membro), type = "string")
      return( list(
        "valore" = secondo.membro,
        "operation.token" = "SET",
        "operation"=stringa
      ) )      
    }
    # if(stringa=="set deltaInferioreGiorni = $parameter_2$") browser()
    # if(stringa=="set idNoduli = noduloTiroideo.relatedToClinicalEvent(cursor)") browser()
    # Se il secondo membro e' un oggetto, diretto od indiretto, risolvilo senza tante seghe
    test.str<-list()
    test.str["obj"]<- str_extract(string = secondo.membro, pattern = "^[ ]*^[a-zA-Z _]+\\(.*\\)[ ]*\\..*$")
    test.str["obj.implicit.PK"]<- str_extract(string = secondo.membro, pattern = "^[ ]*[a-zA-Z]+[a-zA-Z0-9_]*\\.[a-zA-Z]+[a-zA-Z0-9_]*[ ]*$")
    test.str["obj.with.parameters"]<- str_extract(string = secondo.membro, pattern = "^[ ]*^[a-zA-Z _]+(\\(.*\\))*\\.[a-zA-Z _]+\\(.*\\)$")        
    if( !is.na(test.str["obj"]) | !is.na(test.str["obj.implicit.PK"]) | !is.na(test.str["obj.with.parameters"]) ) {
      # invoca il calcolo
      risultatoElemento <- invoca.ricorsivamente.HLL(HLL.script =  secondo.membro)
      # indovina il tipo
      lst.dati.tipo.variabile <- definisci.tipo.variabile(risultatoElemento  = risultatoElemento$valore)
      # aggiorna la memoria e chiudi
      proxy.mem.struct.set(varName = nome.variabile, value = lst.dati.tipo.variabile$risultatoElemento, type = lst.dati.tipo.variabile$tipo.variabile.restituita)
      return( list(
        "valore" = lst.dati.tipo.variabile$risultatoElemento,
        "operation.token" = "SET",
        "operation"=stringa
      ) )
    }
    if(stringa=="set dataDiRiferimento = $parameter_3$") browser()
    argomento.multi.token <- FALSE
    if(!is.na(script.cursor)) { 
      if( mem.struct$class.methods[[mem.struct$running.class]][[mem.struct$running.method]]$struttura$set.statement[[as.character(script.cursor)]]$exitCode == 0 ) {
        argomento.multi.token <- TRUE
        mmatrice <- mem.struct$class.methods[[mem.struct$running.class]][[mem.struct$running.method]]$struttura$set.statement[[as.character(script.cursor)]]$matriceElementiRilevati
        # risolvi ogni elemento della matrice (escludendo il primo)
        stringa.parziale <- "";
        for(ct in seq(1:(dim(mmatrice)[1])))    {
          # if(stringa=="set idNoduli = noduloTiroideo.relatedToClinicalEvent(cursor)") browser()
          if(mmatrice[ct,"stato"] == "token" ) {
            # cerca: se e' gia' presente in memoria, usa quello, altrimenti cerca di risolverlo chiamando
            # ricorisvamente il risolutore
            if( mmatrice[ct,"substr"] %in% names(mem.struct$var)) {
              risultatoElemento <- mem.struct$var[[ mmatrice[ct,"substr"] ]]$value
            }
            else {
              tmptmp.risultato <- invoca.ricorsivamente.HLL(HLL.script =  mmatrice[ct,"substr"])
              risultatoElemento <- tmptmp.risultato$valore
            }
            
            # Fai le elucubrazioni per cercare di indovinare il tipo di variabile 
            lst.dati.tipo.variabile <- definisci.tipo.variabile(risultatoElemento  = risultatoElemento) 
            # estrai il tipo ed il valore
            tipo.variabile.restituita <- lst.dati.tipo.variabile$tipo.variabile.restituita
            risultatoElemento <- lst.dati.tipo.variabile$risultatoElemento
            if(tipo.variabile.restituita=="string") risultatoElemento <- str_c("'",risultatoElemento,"'")
            
            if((dim(mmatrice)[1])>2 & (tipo.variabile.restituita == "null" |
                                                  tipo.variabile.restituita == "numeric.array" |
                                                  tipo.variabile.restituita == "string.array") ) {
              stop("\n Errore, in un set ci sono piu' elementi che concorrono alla risoluzione ma almeno uno di essi e' un array o vale NULL")
            }

          } else {
            risultatoElemento <- mmatrice[ct,"substr"]
          }

          stringa.parziale <- str_trim(str_c( stringa.parziale , risultatoElemento ))
        }
        if(stringa.parziale!="null" ) {
          stringa.settatrice <- paste(c("stringa.parziale <- ",stringa.parziale),collapse = '')
          eval(parse(text=stringa.settatrice))              
        }
        else {
          stringa.parziale <- stringa.parziale
        }       
      }
    }
    # browser()
    if(argomento.multi.token == FALSE) { 
      res <- invoca.ricorsivamente.HLL(HLL.script =  secondo.membro)
    } else { res <- list("valore"=stringa.parziale ) }
    
    tipo.variabile.restituita <- "unknown"
    if(is.null(res$valore)==TRUE) { tipo.variabile.restituita <- "null" }
    else { 
      if(is.a.number(res$valore)==TRUE) { tipo.variabile.restituita <- "numeric" }
      if(is.a.string(res$valore)==TRUE) { tipo.variabile.restituita <- "string" }
      if(is.a.quoted.string(res$valore)==TRUE) { tipo.variabile.restituita <- "quoted.string" }
      if(is.a.numeric.array(res$valore)==TRUE) { tipo.variabile.restituita <- "numeric.array" }
      if(is.a.string.array(res$valore)==TRUE) { tipo.variabile.restituita <- "string.array" }
    }
      
    if(tipo.variabile.restituita == "null") nuovo.valore <- global.null.value
    if(tipo.variabile.restituita == "numeric") nuovo.valore <- as.numeric(res$valore)
    if(tipo.variabile.restituita == "string") nuovo.valore <- res$valore
    if(tipo.variabile.restituita == "quoted.string") nuovo.valore <- res$valore
    if(tipo.variabile.restituita == "numeric.array") nuovo.valore <- as.numeric(res$valore)
    if(tipo.variabile.restituita == "string.array") nuovo.valore <- res$valore
    
    if(tipo.variabile.restituita == "unknown") stop("\n caso strano di tipo variabile non identificata")
    
    # Aggiorna la memoria
    proxy.mem.struct.set(varName = nome.variabile,value = nuovo.valore,type = tipo.variabile.restituita)
    
    # ritorna il risultato (cioè un NA e la definizione dell'operazione effettuata)
    return( list(
      "valore" = NA,
      "operation.token" = "SET",
      "operation"=stringa
    ) ) 
    
  }
  # ----------------------------------------------------------------
  # definisci.tipo.variabile
  # cerca di indovinare il tipo della variabile in funzione del suo contenuto
  # ----------------------------------------------------------------  
  definisci.tipo.variabile<-function(risultatoElemento) { 

    tipo.variabile.restituita <- "unknown"
    if(is.null(risultatoElemento)==TRUE) { tipo.variabile.restituita <- "null" }
    else {
      if(is.a.number(risultatoElemento)==TRUE) { tipo.variabile.restituita <- "numeric" }
      if(is.a.string(risultatoElemento)==TRUE) { tipo.variabile.restituita <- "string" }
      if(is.a.quoted.string(risultatoElemento)==TRUE) { tipo.variabile.restituita <- "quoted.string" }
      if(is.a.numeric.array(risultatoElemento)==TRUE) { tipo.variabile.restituita <- "numeric.array" }
      if(is.a.string.array(risultatoElemento)==TRUE) { tipo.variabile.restituita <- "string.array" }
    }
    
    if(tipo.variabile.restituita == "numeric") risultatoElemento <- as.numeric(risultatoElemento)
    if(tipo.variabile.restituita == "string") risultatoElemento <- risultatoElemento
    if(tipo.variabile.restituita == "quoted.string") risultatoElemento <- risultatoElemento
    if(tipo.variabile.restituita == "unknown") stop("\n caso strano di tipo variabile non identificata")
    
    # i casi di 'null'  e/o di array vanno bene SOLO se e' una assegnazione diretta!!!!!
    if(tipo.variabile.restituita == "null") risultatoElemento <- global.null.value
    if(tipo.variabile.restituita == "numeric.array") risultatoElemento <- as.numeric(risultatoElemento)
    if(tipo.variabile.restituita == "string.array") risultatoElemento <- risultatoElemento
    
    return(list(
              "tipo.variabile.restituita"=tipo.variabile.restituita,
              "risultatoElemento"=risultatoElemento
              ))
  }  
  # ********************************************************************
  # FINE Sezione di risoluzione della semantica
  # ********************************************************************  

  # ----------------------------------------------------------------
  # preProcessing.Script
  # Fai il pre-processing dello script per identificare le posizioni degli 
  # if-then-else, for, etc..
  # ----------------------------------------------------------------
  preProcessing.Script<-function( script.lines ) {
    command <- list()
    
    # accorcia script.lines togliendo la prima riga che e' solo 
    # relativa alla definizione della procedura
    script.lines <- script.lines[2:length(script.lines)] 
    
    # Scorri tutte le righe alla ricerca degli elementi che possono interessare
    # (IF, FOR, etc..)
    matrice <- c(); matrice.set <- c(); matrice.foreach <- c()
    lst.tmp.ris<-list(); lst.set.stt <- list(); lst.tmp.foreach <- list()
    
    for(riga in 1:length(script.lines)) {
      command["if"]<- str_extract(string = script.lines[riga] , pattern = "^[ ]*if[ ]*\\(.*\\)[ ]*then[ ]*$")
      command["endif"]<- str_extract(string = script.lines[riga] , pattern = "^[ ]*endif[ ]*$")
      command["else"]<- str_extract(string = script.lines[riga] , pattern = "^[ ]*else[ ]*$")
      command["set"]<- str_extract(string = script.lines[riga], pattern = "^[ ]*set[ ]+[A-Za-z0-9._]+[ ]*=")
      command["foreach"]<- str_extract(string = script.lines[riga], pattern = "^[ ]*foreach[ ]*([a-zA-Z]+[a-zA-Z0-9_]*)[ ]+as[ ]+([a-zA-Z]+[a-zA-Z0-9_]*)[ ]*do[ ]*$")
      command["endforeach"]<- str_extract(string = script.lines[riga], pattern = "^[ ]*endforeach[ ]*$")
      
      # E' un FOREACH?
      if(!is.na(command["foreach"])) {
        # Fai il preprocessing della riga di IF, per estrarre su quali variabili lavora
        matrice.foreach <- rbind(matrice.foreach, pre.processing.foreach( script = script.lines, num.riga = riga))
        colnames(matrice.foreach)<-c("riga","tipo","cursore","array","linkedTo","associato")
      }  
      # E' un ENDFOREACH?
      if(!is.na(command["endforeach"])) {
        # Fai il preprocessing della riga di IF, per estrarre su quali variabili lavora
        matrice.foreach <- rbind(matrice.foreach,c(riga,"endforeach","","","",""))
      }      
      # E' un IF?
      if(!is.na(command["if"])) {
        # Fai il preprocessing della riga di IF, per estrarre su quali variabili lavora
        lst.tmp.ris[[as.character(riga)]] <- pre.processing.if( script = script.lines, num.riga = riga)
        matrice <- rbind(matrice, c(riga, "if",FALSE))
      }
      # E' un endif?
      if(!is.na(command["endif"])) {
        matrice <- rbind(matrice, c(riga, "endif",FALSE))
      } 
      # E' un else?
      if(!is.na(command["else"])) {
        matrice <- rbind(matrice, c(riga, "else",FALSE))
      }        
      # E' un set?
      if(!is.na(command["set"])) {
        tmp.poss <- str_locate(string = script.lines[riga],pattern = "=" )
        tmp.set <- str_locate(string= script.lines[riga],pattern = "set" )
        variabile <- str_trim(str_sub(string = script.lines[riga],start = tmp.set[1,"end"]+1,end = tmp.poss[1,"end"]-1))
        argomento <- str_trim(str_sub(string = script.lines[riga],start = tmp.poss[1,"end"]+1 ,end = str_length(script.lines[riga])))

        # Prendila matrice dei token con le relative posizioni
        lst.set.stt[[as.character(riga)]]  <-  ricavaElementiDaRisolvereDaStringa( argomento )
      }           
    }

    # Ora ricava la struttura degli if-then-else in tutto lo script, arricchendo la lista
    # costruita fino ad ora. (cosi' mi sara' piu' facile, a run-time, zompare qua e la' perche'
    # gia' conoscero' la struttura)
    lst.tmp.ris <- ricava.struttura.if( matrice = matrice, lst.tmp.ris = lst.tmp.ris )
    # browser()
    if(!is.null(matrice.foreach))
      matrice.foreach <- completa.matrice.foreach( matrice = matrice.foreach )

    return( 
      list( "if.else.endif"= lst.tmp.ris,
            "set.statement" = lst.set.stt,
            "foreach" = list("matrice"=matrice.foreach) )
    )
    
  }
  # ----------------------------------------------------------
  # completa.matrice.foreach
  #     Completa la matrice dei foreach associando i numeri fra i
  #     foreach e gli endforeach, cosi' da consentire in fase di calcolo di non
  #     stare a doverli cercare
  # ----------------------------------------------------------
  completa.matrice.foreach<-function( matrice  ) {
    # Fallo di default per un numero di volte pari al numero dei foreach 
    # (caso in cui siano tutti nidificati ). Se anche lo fa qualche volta di piu'
    # non succede niente
    for( i in 1:sum(matrice[,"tipo"]=="endforeach") ) { 
      # scorri tutta la matrice, a scendere
      for( numRiga in 1:nrow(matrice))  {  
        # se trovi delle coppie adiacenti, non ancora linkate, linkale
        if(matrice[numRiga,"tipo"]=="endforeach" & matrice[numRiga,"linkedTo"]=="")  {
          dove.possibile <- which(matrice[,"tipo"]=="foreach" & matrice[,"linkedTo"]=="" 
                                  & as.numeric(matrice[numRiga,"riga"])> as.numeric(matrice[,"riga"]) )
          candidato <- sort(dove.possibile,decreasing = T)[1]
          if( length(candidato)>0 )  {
            # ovviamente il link e' reciproco
            matrice[numRiga,"linkedTo"] <- matrice[candidato,"riga"]
            matrice[candidato,"linkedTo"] <- matrice[numRiga,"riga"]
          }
        }
      }
    }
    # se ancora ho qualcosa di non linkato, errore!
    aaa <- which(matrice[,"linkedTo"]=="" )
    if(length(aaa)>0) stop("\nmaremma, no.... l'architetture dei foreach/endforeach non e' corretta: verifica!")
    return(matrice)
  }
  ricava.struttura.if<-function( matrice , lst.tmp.ris ) {
    # Se ci sono degli IF, ricava le posizioni dei corrispondenti ELSE, ENDIF, cosi' da rendere
    # piu' facile il calcolo successivamente
    if(length(matrice)>0) {
      matrice <- rbind(matrice, c("dummy","dummy",FALSE))
      colnames(matrice)<-c("row","command","assigned")
      numeri.if <- length(matrice[ which( matrice[,"command"]=="if" ),"row" ])
      submatrice <- matrice
      if.assegnati <- 0

      # cicla fino a che non hai assegnato tutti gli IF
      while(if.assegnati < numeri.if)  {
        cur <- 1
        just.assigned <- FALSE
        while(cur <= nrow(submatrice)) { 
          # Se hai appena assegnato, riposiziona il cursore all'inizio
          if( just.assigned == TRUE)  {
            cur <- 1;  submatrice <- submatrice[ which( submatrice[,"assigned"]=="FALSE" ), ]
          }  
          just.assigned <- FALSE
          
          if( submatrice[cur,"command"]=="if" & submatrice[cur+1,"command"]=="endif"  ) {
            submatrice[cur,"assigned"]<-TRUE; submatrice[cur+1,"assigned"]<-TRUE
            lst.tmp.ris[[ submatrice[cur,"row"] ]]$riga.if <- submatrice[cur,"row"]
            lst.tmp.ris[[ submatrice[cur,"row"] ]]$riga.else <- NA
            lst.tmp.ris[[ submatrice[cur,"row"] ]]$riga.endif <- submatrice[cur+1,"row"]
            if.assegnati <-  if.assegnati +1
            just.assigned <- TRUE
          }
          if( submatrice[cur,"command"]=="if" & submatrice[cur+1,"command"]=="else" &
              submatrice[cur+2,"command"]=="endif" ) {
            submatrice[cur,"assigned"]<-TRUE; submatrice[cur+1,"assigned"]<-TRUE; submatrice[cur+2,"assigned"]<-TRUE
            lst.tmp.ris[[ submatrice[cur,"row"] ]]$riga.if <- submatrice[cur,"row"]
            lst.tmp.ris[[ submatrice[cur,"row"] ]]$riga.else <- submatrice[cur+1,"row"]
            lst.tmp.ris[[ submatrice[cur,"row"] ]]$riga.endif <- submatrice[cur+2,"row"]
            if.assegnati <-  if.assegnati +1
            just.assigned <- TRUE
          }
          if(if.assegnati >= numeri.if) break
          cur <- cur +1
        }
      }
    }
    
    return( "lst.tmp.ris"=lst.tmp.ris)
  }
  pre.processing.foreach<-function( script , num.riga, complete.script  ) {
    stringa <- script[num.riga]
    # browser()
    # prima di tutto estrai il nome del cursore e dell'array su cui si scorre
    pos.1 <- str_locate( string = stringa,pattern = "^[ ]*foreach[ ]*")
    array.run <- str_sub(string = stringa,start = pos.1[,"end"]+1)
    pos.2 <-str_locate(string = array.run, pattern = "[ ]+as[ ]+([a-zA-Z]+[a-zA-Z0-9_]*)[ ]*do[ ]*$")
    array.run <- str_trim(str_sub(string = array.run,start = 1, end = pos.2[,"start"]-1))
    pos.3 <- str_locate(string = stringa, pattern = "^[ ]*foreach[ ]*([a-zA-Z]+[a-zA-Z0-9_]*)[ ]+as[ ]+")
    pos.4 <- str_locate(string = stringa, pattern = "[ ]*do[ ]*$")
    cursore <- str_trim(str_sub(string = stringa, start = pos.3[ ,"end"]+1, end = pos.4[ ,"start"]-1))

    return(c(num.riga,"foreach",cursore,array.run,"",""))
  }
  
  pre.processing.if<-function(  script , num.riga , argomento.gia.estratto = NA) {
    
    if(is.na(argomento.gia.estratto)) { 
      stringa <- script[num.riga]
      # ESTRAI LA CONDIZIONE dell'IF
      tmp.stringa <- str_sub(string = stringa,
                             start = str_locate(string = stringa,pattern = "\\(")[1,1]+1,
                             end = str_length(stringa))
      finale <- str_locate_all(string = tmp.stringa, pattern = "\\)")
      tmp.stringa <- str_sub( string = tmp.stringa,
                              start = 1,
                              end = unlist(finale)[  length(unlist(finale)) ]-1 )
      tmp.stringa <- str_trim(tmp.stringa)
      # preferisco lavorare con 'stringa'
      stringa <- tmp.stringa
    } else { stringa <- argomento.gia.estratto; tmp.stringa <- argomento.gia.estratto }
    
    # sostituisci "#" laddove il contenuto della condizione e' fra virgolette
    dentro <- FALSE
    new.stringa <- ''
    for( i in 1:str_length(tmp.stringa)) {
      if( str_sub( tmp.stringa , i, i)=="'" & dentro == FALSE) { dentro <- TRUE  } 
      else {
        if( str_sub( tmp.stringa , i, i)=="'" & dentro == TRUE) {   dentro <- FALSE   }
      }
      if(dentro == TRUE ) { new.stringa <- str_c(str_sub(new.stringa,1,i-1),"#")  } 
      else {
        if( str_sub( tmp.stringa , i, i)=="'")       new.stringa <- str_c(str_sub(new.stringa,1,i-1),"#")
        else  new.stringa <- str_c(new.stringa,str_sub(tmp.stringa,i,i))
      }
    }
    # splitta il testo rispetto ai marcatori di fine per identificare le possibili variabili
    sep <- c("'","\""," ","+","-","*","/","(",")","|","&","=","!",">","<")

    lst.parole <- list()
    num.parola <- 1
    new.new.stringa <- ""
    for(i in seq(1:str_length(new.stringa))) {
      if( str_sub(string = new.stringa,start = i,end = i) %in% sep ) {
        new.new.stringa <- str_c(str_sub( new.new.stringa , start = 1,end = i-1),"#")
      }
      else { 
        new.new.stringa <- str_c(str_sub( new.new.stringa , start = 1,end = i-1),str_sub(string = new.stringa,start = i,end = i))
      }
    }
    
    # aggiungi ai margini il carattere speciale, per consentire in find anche di elementi agli estremi
    new.new.stringa <- str_c("#",new.new.stringa,"#")
    # cerca ed identifica la posizione per ogni possibile variabile
    tmp.interestingWords <- unlist(str_split(new.new.stringa,pattern = "#"))
    interestingWords <- c()
    for(i in 1:length(tmp.interestingWords)) { 
      if(str_length(tmp.interestingWords[i])>0) interestingWords <- c(interestingWords,tmp.interestingWords[i])
    }
    
    # mi basta prenderle una volta sola
    interestingWords <- unique(interestingWords)
    interestingWords <- interestingWords[ unlist(lapply(interestingWords,is.a.number)) ==FALSE ]
    
    # estrai le posizioni
    lst.Words <- list()
    matriciazza<- c()
    if( length(interestingWords) > 0 ) { 
      for(i in 1:length(interestingWords)) {
        dove <- str_locate_all(string = new.new.stringa,pattern = paste(c("#",interestingWords[i],"#"),collapse = '') )
        for(kkk in 1:nrow(dove[[1]])) {
          dove[[1]][kkk,"start"] <- dove[[1]][kkk,"start"] - 1
          dove[[1]][kkk,"end"] <- dove[[1]][kkk,"end"] - 2
          matriciazza <- rbind(matriciazza,c(  as.character(interestingWords[i]) , dove[[1]][kkk,]) )
        }
        lst.Words[[ as.character(interestingWords[i])]] <- dove
        
      }
      
      colnames(matriciazza)<-c("token","from","to")
      # mettila in ordine perche' le occorrenze multiple potrebbero non vedere 
      # le righe nello stesso ordine con cui compaiono nella stringa
      matriciazza <- matriciazza[  sort(x = as.numeric(matriciazza[,"from"]),index.return=TRUE)$ix, ]
      matriciazza <- matrix(matriciazza,ncol=3)
      colnames(matriciazza)<-c("token","from","to")
  
      
      new.new.stringa <- substr(new.new.stringa,2,str_length(new.new.stringa)-1)
      arr.da.ricomporre <- c()
      tmptmptmp <- str_sub(stringa,0,as.numeric(matriciazza[1,"from"]) )
      arr.da.ricomporre <- c(arr.da.ricomporre,tmptmptmp)
      for(riga in 1:nrow(matriciazza)-1) {
        arr.da.ricomporre <- c(arr.da.ricomporre, matriciazza[riga,"token"])
        tmptmptmp <- str_sub(stringa,as.numeric(matriciazza[riga,"to"])+1,as.numeric(matriciazza[riga+1,"from"]) )
        arr.da.ricomporre <- c(arr.da.ricomporre,tmptmptmp)
      }
      arr.da.ricomporre <- c(arr.da.ricomporre,matriciazza[nrow(matriciazza),"token"])
      tmptmptmp<-str_sub(stringa,as.numeric(matriciazza[nrow(matriciazza),"to"])+1,str_length(stringa) )
      arr.da.ricomporre <- c(arr.da.ricomporre,tmptmptmp)
    }
    else {  
      arr.da.ricomporre <- c(stringa)
      names(arr.da.ricomporre)<-""
    }

    return(list("toResolve"=interestingWords,
                "positions"=lst.Words,
                "tmp.stringa"=tmp.stringa,
                "matriceCompletaPosizioniToken" = matriciazza,
                "arrayCondizioneDaRicostruire" = arr.da.ricomporre
          )
    )    
  }
  # ----------------------------------------------------------------
  # setEnv
  # Setta il contesto, ovvero carica lo schema LLL da usare
  # ----------------------------------------------------------------
  setEnv<-function( env = list(), mem = list(), 
                    classMethods=list(), debug.mode = NA, max.debug.deep = NA, 
                    arr.breakpoints = c() ) {
    if(length(env)>0) LLL.env <<- env
    if(length(mem)>0) mem.struct <<- mem
    if(length(classMethods)>0) mem.struct$class.methods <<- classMethods
    if(!is.na(debug.mode)) global.debug.mode <<- debug.mode
    if(!is.na(max.debug.deep)) global.max.debug.deep<<- max.debug.deep
    # if(length(arr.breakpoints)!=0) global.arr.breakpoints<<- arr.breakpoints
  }
  getClassMethods<-function(  ) {
    return(mem.struct$class.methods)
  }  
  get<-function(  ) {
    return(mem.struct)
  }    
  getAttribute<-function( attributo ) {
    if(attributo=="executed.statements") return(global.executed.statements)
    if(attributo=="logQueue") return(mem.struct$logQueue)
    stop("\n ==============\n ERROR: the requested attribute is not available\n ==============")
  }    
  # ----------------------------------------------------------------
  # Costruttore
  # ----------------------------------------------------------------
  costructor<-function( debug.mode , deep.level , executed.statements, max.debug.deep, arr.breakpoints  ) {
    LLL.env<<-NA
    mem.struct<<-list()
    mem.struct$var<<-list()
    mem.struct$define.context<<-list()
    mem.struct$implicit.PK<<-NA
    mem.struct$script.structures <<-list()
    mem.struct$active.loops <<-list()
    mem.struct$lst.parameters <<- list()
    mem.struct$logQueue <<- list()
    global.null.value <<-"null"
    global.debug.mode <<- debug.mode
    global.deep.level <<- deep.level
    global.executed.statements <<- executed.statements
    global.max.debug.deep <<- max.debug.deep
    global.arr.breakpoints <<- arr.breakpoints    
  }
  costructor( debug.mode = debug.mode, deep.level = deep.level, executed.statements = executed.statements, 
              max.debug.deep = max.debug.deep, arr.breakpoints = arr.breakpoints )
  # ----------------------------------------------------------------
  # RETURN di classe
  # ----------------------------------------------------------------
  return(
    list(
      "loadScript"=loadScript,
      "parseScript"=parseScript,
      "setEnv"=setEnv,
      "get"=get,
      "getAttribute"=getAttribute,
      "execute"=execute,
      "getClassMethods"=getClassMethods
    )
  )

}
kbolab/ste documentation built on May 29, 2019, 3:01 a.m.