open Ast
open LatticeCreation
open PrintLattice
open SemanticAnalysis
open Clone

(***********************************************************************************************************************************)
type comparison = Eq | Lt | Gt | NilEncountered

type evalEnvType = {
	mutable parentStack: latticeFields list;
	mutable currentLat: latticeFields;
}

let evalEnv = {
    parentStack = [];
    currentLat = LatticeCreation.createEmptyLattice [];
}

let preEvalEnv = {
    parentStack = [];
    currentLat = LatticeCreation.createEmptyLattice [];
}

let isValueEpsilon = function
	| ConstValue(Epsilon) -> true
	| _ -> false 

(***********************************************************************************************************************************)
let isBooleanValue = function ConstValue(True) -> true | ConstValue(False) -> true | ConstValue(Nil) -> true | ConstValue(Epsilon) -> true | _ -> false
 
(***********************************************************************************************************************************)
(*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*)
let rec eval lattice =
    evalEnv.currentLat <- lattice;
		processLattice lattice

and processLattice lattice = (*input a latticeFields, which is our AST*)    
    let listOfEval = (match lattice.lattice with 
   	| Seqlat(seqlat) -> 
				evalEnv.parentStack <- evalEnv.currentLat :: evalEnv.parentStack (*PUSH*); 
				evalEnv.currentLat <- lattice;
				let listOfEval = processSeqlat seqlat in 
				(if (List.length evalEnv.parentStack) > 0 then
	    	evalEnv.currentLat <- List.hd evalEnv.parentStack (*POP*)
				else rf("BUG: Stack is not being built Correctly!!!\n");
	    	evalEnv.parentStack <- List.tl evalEnv.parentStack; (*Remove*)
				listOfEval)
		| Altlat(altlat) ->
				let listOfEval = processAltlat altlat in listOfEval
    | Predicate(pred) -> [processPredicate pred]
    | Expr(expr) -> [processExpr expr]
		) in 
		let optListOfEval = if lattice.optimize then
			List.fold_left (fun x y -> x @ (if isValueEpsilon(y) then [] else [y])) [] listOfEval
		else
			listOfEval 
		in (
		let latClone = Clone.cloneLattice lattice false in
		latClone.latEval <- Some(optListOfEval);
		if (List.length optListOfEval)>1 then LatticeValue(latClone) else if (List.length optListOfEval)>0 then (List.hd optListOfEval)
		else ConstValue(Epsilon)
		)
		
(*--------------------------------------------------------------------*)
and processSeqlat _seqlat  = (*do the seq lat *)
		if (List.length _seqlat.elements) > 0 then
			List.map (processLattice) _seqlat.elements
		else rf ("BUG: Seqlat has no elements!") 

(*--------------------------------------------------------------------*)
and processAlternatives = function 
		| [] -> []
		| hd::tl ->
		    let headEval = (processLattice hd) in
			    (*match headEval.lattice with
		    		| Expr(expr) ->*) (match headEval with
				        | ConstValue(Nil) -> (processAlternatives tl)
				        | _ -> [headEval]
      					)
       			(*| _ -> [headEval]
					*)

(*--------------------------------------------------------------------*)
and processAltlat _altlat = (*do the alt lat *)
		if _altlat.each then
			List.map processLattice _altlat.alternatives
		else
			processAlternatives _altlat.alternatives

(*--------------------------------------------------------------------*)
and processPredicate _pred =
		let condExpr = processExpr _pred.condition in
			_pred.condition.exprEval <- condExpr;
	  	let condVal =  (match condExpr with
	    | ConstValue(constVal) -> ( match constVal with
	        | True -> true
	        | False -> false
	        | _ -> false
					)
	    | _ -> false (*Lattice*)
	    ) in
	    if condVal = true then
	    	processExpr _pred.expr
	    else
	    	ConstValue(Nil)
		
(*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*)
and processExpr _expr =
    _expr.exprEval <-
	    (match _expr.exprCode with
			| ConstExpr(const) -> processConst const
			| OpExpr(op) -> processOperation op
	    | NameListExpr(nameList) -> processNameList nameList.nameList
	    | LatticeExpr(latticeFields) -> processLattice latticeFields
	    );
    _expr.exprEval

(*--------------------------------------------------------------------*)
and processConst const = 
		match const with
	  | StringLiteral(stringLit) -> ConstValue(StringLiteral(stringLit))       
	  | IntLiteral(intLit) -> ConstValue(IntLiteral(intLit))    
  	| FloatLiteral(floatLit) -> ConstValue(FloatLiteral(floatLit))
	  | Epsilon -> ConstValue(Epsilon)
	  | Nil -> ConstValue(Nil)
    | True -> ConstValue(True)
    | False -> ConstValue(False)			
			
(*--------------------------------------------------------------------*)
and processOperation op  = 
    let op1Val = if doCheckOperandsBeforeCheckingOperator op.operator then processExpr op.operand1 else ConstValue(Nil) in
    let op2Val = if doCheckOperandsBeforeCheckingOperator op.operator then (
			      match op.operand2 with 
			      |	None -> ConstValue(Nil)
			      |	Some(opr) -> processExpr opr
				) else ConstValue(Nil) in
	  
		(match op.operator with
			| Plus -> (match (op1Val, op2Val) with 
				    | (ConstValue(IntLiteral(intLit1)),ConstValue(IntLiteral(intLit2))) -> ConstValue(IntLiteral(intLit1+intLit2))    
				    | (ConstValue(StringLiteral(strLit1)),ConstValue(StringLiteral(strLit2))) -> ConstValue(StringLiteral(strLit1^strLit2))
				    | (ConstValue(FloatLiteral(floatLit1)),ConstValue(FloatLiteral(floatLit2))) -> ConstValue(FloatLiteral(floatLit1 +. floatLit2))
				    | (ConstValue(Nil),x) -> ConstValue(Nil)
				    | (x,ConstValue(Nil)) -> ConstValue(Nil)
				    | (ConstValue(Epsilon),x) -> x
				    | (x,ConstValue(Epsilon)) -> x
				    | _ -> raise (Failure("Runtime Exception: Type Mismatch.\n")) )
(*.......................................................................................*)    
			| Minus -> 	(match (op1Val, op2Val) with 
				    | (ConstValue(IntLiteral(intLit1)),ConstValue(IntLiteral(intLit2))) -> ConstValue(IntLiteral(intLit1-intLit2))
				    | (ConstValue(FloatLiteral(floatLit1)),ConstValue(FloatLiteral(floatLit2))) -> ConstValue(FloatLiteral(floatLit1 -. floatLit2))
				    | (ConstValue(Nil),x) -> ConstValue(Nil)
				    | (x,ConstValue(Nil)) -> ConstValue(Nil)
				    | (ConstValue(Epsilon),x) -> x
				    | (x,ConstValue(Epsilon)) -> x
				    | _ ->raise (Failure("Runtime Exception: Type Mismatch.\n")) )
(*.......................................................................................*)    
	    | Times -> (match (op1Val, op2Val) with 
				    | (ConstValue(IntLiteral(intLit1)),ConstValue(IntLiteral(intLit2))) -> ConstValue(IntLiteral(intLit1*intLit2))
				    | (ConstValue(FloatLiteral(floatLit1)),ConstValue(FloatLiteral(floatLit2))) -> ConstValue(FloatLiteral(floatLit1 *. floatLit2))
				    | (ConstValue(Nil),x) -> ConstValue(Nil)
				    | (x,ConstValue(Nil)) -> ConstValue(Nil)
				    | (ConstValue(Epsilon),x) -> x
				    | (x,ConstValue(Epsilon)) -> x
				    | _ ->raise (Failure("Runtime Exception: Type Mismatch.\n")) )
(*.......................................................................................*)    
    	| Divide -> (match (op1Val, op2Val) with 
				    | (ConstValue(IntLiteral(intLit1)),ConstValue(IntLiteral(intLit2))) -> if intLit2 = 0 then raise (Division_by_zero) else ConstValue(IntLiteral(intLit1/intLit2))
				    | (ConstValue(FloatLiteral(floatLit1)),ConstValue(FloatLiteral(floatLit2))) -> if floatLit2 = 0.0 then raise (Division_by_zero) else ConstValue(FloatLiteral(floatLit1 /. floatLit2))
				    | (ConstValue(Nil),x) -> ConstValue(Nil)
				    | (x,ConstValue(Nil)) -> ConstValue(Nil)
				    | (ConstValue(Epsilon),x) -> x
				    | (x,ConstValue(Epsilon)) -> x
				    | _ ->raise (Failure("Runtime Exception:Type Mismatch.\n")) )
(*.......................................................................................*)    
    	| Percent -> (match (op1Val, op2Val) with 
						| (ConstValue(IntLiteral(intLit1)),ConstValue(IntLiteral(intLit2))) -> ConstValue(IntLiteral(intLit1 mod intLit2))
				    | (ConstValue(Nil),x) -> ConstValue(Nil)
				    | (x,ConstValue(Nil)) -> ConstValue(Nil)
				    | (ConstValue(Epsilon),x) -> x
				    | (x,ConstValue(Epsilon)) -> x
						| _ ->raise (Failure("Runtime Exception: Type Mismatch.\n")) )
(*.......................................................................................*)    
    	| UniMinus -> (match (op1Val) with 
				    | (ConstValue(IntLiteral(intLit1))) -> ConstValue(IntLiteral(-intLit1))
				    | (ConstValue(FloatLiteral(floatLit1))) -> ConstValue(FloatLiteral(0.0 -. floatLit1))
				    | (ConstValue(Nil)) -> ConstValue(Nil)
				    | (ConstValue(Epsilon)) -> ConstValue(Epsilon)
				    | _ ->raise (Failure("Runtime Exception: Type Mismatch in '-' (unary minus) operand!\n")) )
(*.......................................................................................*)    
    	| Less -> (match compareExprValues(op1Val, op2Val) with
						| NilEncountered -> ConstValue(Nil)
						| Gt -> ConstValue(False)
						| Eq -> ConstValue(False)
						| Lt -> ConstValue(True)
				)
(*.......................................................................................*)    
    	| LessOrEqual -> (match compareExprValues(op1Val, op2Val) with
						| NilEncountered -> ConstValue(Nil)
						| Gt -> ConstValue(False)
						| Eq -> ConstValue(True)
						| Lt -> ConstValue(True)
				)
(*.......................................................................................*)    
    | Greater -> (match compareExprValues(op1Val, op2Val) with
						| NilEncountered -> ConstValue(Nil)
						| Gt -> ConstValue(True)
						| Eq -> ConstValue(False)
						| Lt -> ConstValue(False)
				)
(*.......................................................................................*)    
    | GreaterOrEqual -> (match compareExprValues(op1Val, op2Val) with
						| NilEncountered -> ConstValue(Nil)
						| Gt -> ConstValue(True)
						| Eq -> ConstValue(True)
						| Lt -> ConstValue(False)
				)
(*.......................................................................................*)    
    | Equal -> (match compareExprValues(op1Val, op2Val) with
						| NilEncountered -> ConstValue(Nil)
						| Gt -> ConstValue(False)
						| Eq -> ConstValue(True)
						| Lt -> ConstValue(False)
				)
(*.......................................................................................*)    
    | NotEqual -> (match compareExprValues(op1Val, op2Val) with
						| NilEncountered -> ConstValue(Nil)
						| Gt -> ConstValue(True)
						| Eq -> ConstValue(False)
						| Lt -> ConstValue(True)
				)
(*.......................................................................................*)    
    | And -> if isBooleanValue(op1Val) && isBooleanValue(op2Val) then 
				(match (op1Val, op2Val) with 
				    | (ConstValue(Nil),x) -> ConstValue(Nil)
				    | (x,ConstValue(Nil)) -> ConstValue(Nil)
						| (ConstValue(Epsilon), x) -> x
						| (x, ConstValue(Epsilon)) -> x
				    | (ConstValue(False),_) | (_,ConstValue(False)) -> ConstValue(False)
				    | _-> ConstValue(True)
				) else raise (Failure("Runtime Exception: Type Mismatch: '&&' operands must be of type boolean!\n")) 
(*.......................................................................................*)    
    | Or -> if isBooleanValue(op1Val) && isBooleanValue(op2Val) then 
				(match (op1Val, op2Val) with 
				    | (ConstValue(Nil),x) -> ConstValue(Nil)
				    | (x,ConstValue(Nil)) -> ConstValue(Nil)
						| (ConstValue(Epsilon), x) -> x
						| (x, ConstValue(Epsilon)) -> x
				    | (ConstValue(False),ConstValue(False)) -> ConstValue(False)
				    | _-> ConstValue(True)
				) else raise (Failure("Runtime Exception: Type Mismatch: '||' operands must be of type boolean!\n\t Found: "^(gs (processExprValue op1Val) "FATAL ERROR: NOT EVALUATED")^" || "^(gs (processExprValue op2Val) "FATAL ERROR: NOT EVALUATED")))
(*.......................................................................................*)    
    | Not -> (match (op1Val) with 
				    | (ConstValue(Nil)) -> ConstValue(Nil)
						| (ConstValue(Epsilon)) -> ConstValue(Epsilon)
				    | ConstValue(False) -> ConstValue(True)
				    | ConstValue(True) -> ConstValue(False)
						| _ -> raise (Failure("Runtime Exception: Type Mismatch: '!' (negation) operand must be of type boolean!\n")) )
(*.......................................................................................*)    
    | Tilde -> raise (Failure("Err2.\n")) (*op1Val ^ "~" ^ op2Val *)
(*.......................................................................................*)    
    | Eval  -> op1Val (*Maybe here we should clone the expression*)
(*.......................................................................................*)    
    | DontOpt  -> raise (Failure("Err5.\n"))  (*"^" ^ op1Val*)
(*.......................................................................................*)    
    | Let -> ConstValue(Epsilon)
(*.......................................................................................*)    
    | DirectAccess -> raise (Failure("Err11.\n")) 
(*.......................................................................................*)    
    | FuncCall ->  
				let funcNameList = (match op.operand1.exprCode with NameListExpr(nameListEx) -> nameListEx.nameList | _ -> rf("BUG: SemanticAnalysis.processOpReturnType(): FuncCall: funcLattice!")) in
				let (idSymOpt, idLatOpt) = try findNameListSymbolAndLatticeInLatticeFields(ref (evalEnv.currentLat), funcNameList) 
						with Not_found -> addToErrorTable(SemUndefinedIdentifier(PrintLattice.processNameList {parent = None; hash = StringMap.empty} funcNameList), None); (None, None)
				in
				(match idLatOpt with
					| None -> raise (Failure ("Runtime Exception: error in function call: function not declared:\n\t"^PrintLattice.processOperation (op)))
					| Some(funcLatticeRef) -> ( let funcLattice = !funcLatticeRef in
						
							let expr = (gs op.operand2 "") in
							let lattice = (match expr.exprCode with LatticeExpr(lat) -> lat | _ -> createEmptyLattice [createLatticeFieldsFromLatticeType (Expr(expr))]) in
							let funcLattice = (if funcLattice.paramNameList = None then 
								(match funcLattice.lattice with Expr(expr) -> 
									(match expr.exprCode with LatticeExpr(lat) -> lat | _ -> funcLattice) 
									| _ -> funcLattice)
								 else funcLattice) in
							let doRunFunc = (if funcLattice.paramNameList = None then (*no param list*)
								 raise (Failure ("Runtime Exception: error in function call: Not a function:\n\t"^PrintLattice.processOperation (op)))
							else if funcLattice.paramTypeList = None then (  (*first call*)
								if calcParamTypeList(lattice, funcLattice) then 
									true
								else
									raise (Failure ("Runtime Exception: error in function call: Parameter List Signature Length Difference:\n\t"^PrintLattice.processOperation (op)))
								)
							else false) in
							if (doRunFunc) then (
								if SemanticAnalysis.checkParameterTypes(funcLattice.paramTypeList, lattice) then (
									funcLattice.lattice <- (!(setSymbolTableInLattice(ref funcLattice, (getSymbolTableFromSeqlat funcLattice).hash)).lattice);
									processLattice (funcLattice)								
									)
								else 
									raise (Failure ("Runtime Exception: error in function call: Parameter List Signature Type Mismatch:\n\t"^PrintLattice.processOperation (op)))
								)
							else
								ConstValue(Nil)
							))
(*.......................................................................................*)    
    | Assign -> assignExprToNameList(op.operand1, op.operand2); processExpr op.operand1
(*.......................................................................................*)    
    | Define -> assignExprToNameList(op.operand1, op.operand2); processExpr op.operand1
(*.......................................................................................*)    
    )

and calcParamTypeList(_paramLattice, _funcLattice) =
		let elements = getSeqlatElementsFromLatticeFields _paramLattice in
		
		if (List.length elements) <> (List.length (gs _funcLattice.paramNameList "BUG: calcParamTypeList")) then false
		else let paramTypeList = List.map (fun x -> x.latDataStructType) elements in
			_funcLattice.paramTypeList <- Some(paramTypeList); true 

and compareExprValues(_val1, _val2) = 
		match (_val1, _val2) with
	    | (ConstValue(IntLiteral(val1)),ConstValue(IntLiteral(val2))) -> 																
	    			if val1 < val2 then Lt else if val1 > val2 then Gt else Eq  
	    | (ConstValue(FloatLiteral(val1)),ConstValue(FloatLiteral(val2))) -> 																
	    			if val1 < val2 then Lt else if val1 > val2 then Gt else Eq  
			| (ConstValue(StringLiteral(val1)),ConstValue(StringLiteral(val2))) -> 
						let res = String.compare val1 val2 in if res < 0 then Lt else if res > 0 then Gt else Eq 
	    | (ConstValue(Nil),ConstValue(Nil)) -> Eq
	    | (ConstValue(Nil),x) -> NilEncountered
	    | (x,ConstValue(Nil)) -> NilEncountered
	    | (ConstValue(Epsilon),ConstValue(Epsilon)) -> Eq
	    | (ConstValue(Epsilon),x) -> Lt
	    | (x,ConstValue(Epsilon)) -> Gt
			| _ -> raise (Failure("Runtime Exception: Type Mismatch.\n")) 

and processNameList _nameList =
		let (idSymOpt, idLatOpt) = try findNameListSymbolAndLatticeInLatticeFields(ref (evalEnv.currentLat), _nameList) 
				with Not_found -> addToErrorTable(SemUndefinedIdentifier(PrintLattice.processNameList {parent = None; hash = StringMap.empty} _nameList), None); (None, None)
				in
		(match idLatOpt with
			| None -> ConstValue(Nil)
			| Some(lat) -> processLattice (!lat)
		) 
	
(***********************************************************************************************************************************)
(**********************************                     Pre-Evaluate Lattice                      **********************************)
(***********************************************************************************************************************************)
and preEvalLattice lattice =
		if lattice.paramNameList = None then
	    match lattice.lattice with 
	   	| Seqlat(seqlat) -> (
					preEvalEnv.parentStack <- preEvalEnv.currentLat :: preEvalEnv.parentStack (*PUSH*); 
					preEvalEnv.currentLat <- lattice;
					ignore(List.map (preEvalLattice) seqlat.elements); 
					if (List.length preEvalEnv.parentStack) > 0 then
		    		preEvalEnv.currentLat <- List.hd preEvalEnv.parentStack (*POP*)
					else rf("BUG: preEvalLattice(): Stack is not being built Correctly!!!\n");
		    		preEvalEnv.parentStack <- List.tl preEvalEnv.parentStack; (*Remove*)
					)
			| Altlat(altlat) -> ignore(List.map (preEvalLattice) altlat.alternatives)
	    | Predicate(pred) -> ignore(preEvalExpr pred.condition); ignore(preEvalExpr pred.expr) 
	    | Expr(expr) -> ignore(preEvalExpr expr)
			
(*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*)
and preEvalExpr _expr =
    _expr.exprEval <-
	    (match _expr.exprCode with
			| OpExpr(op) -> preEvalOperation op
	    | _ -> NotEvaluated
	    );
    _expr.exprEval

(*--------------------------------------------------------------------*)
and preEvalOperation op  = 
    let _ = preEvalExpr op.operand1 in
    let _ = ( match op.operand2 with 
			      |	None -> NotEvaluated
			      |	Some(opr) -> preEvalExpr opr
				) in
	  
		(match op.operator with
(*.......................................................................................*)    
			| Assign -> 
				assignExprToNameList(op.operand1, op.operand2); NotEvaluated
(*.......................................................................................*)    
			| Define -> 
				assignExprToNameList(op.operand1, op.operand2); NotEvaluated
(*.......................................................................................*)    
			| Eval -> processExpr op.operand1
(*.......................................................................................*)    
	    | _ -> NotEvaluated
		)
		
(*--------------------------------------------------------------------*)		
and assignExprToNameList(_lvalueExpr, _rvalueExpr) =
		let nameList = (match _lvalueExpr.exprCode with NameListExpr(n) -> n.nameList | _ -> rf("BUG: Evaluate: preEvalOperation(): Assign: NameList-2!")) in 
		let (idSymOpt, idLatOpt) = try findNameListSymbolAndLatticeInLatticeFields(ref (evalEnv.currentLat), nameList) 
				with Not_found -> addToErrorTable(SemUndefinedIdentifier(PrintLattice.processNameList {parent = None; hash = StringMap.empty} nameList), None); (None, None)
				in
		(match idSymOpt with
			| None -> ()
			| Some(idSymbol) -> (*let exprF = createExprFieldsFromExprCodeType(convertExprValueTypeToExprCodeType op2Val) in*) 
					(match (!idSymbol).symValue with
						| LabelIndex(index) -> (			
								try setSeqlatElementForLatticeFields(ref evalEnv.currentLat, index, createLatticeFieldsFromLatticeType (Expr(gs _rvalueExpr "")))
								with Invalid_argument(_) -> rf("BUG: preEvalOperation! Not a seqlat") )
						| LocalValueLattice(latFRef) -> (!idSymbol).symValue <- (LocalValueLattice(ref (createLatticeFieldsFromLatticeType (Expr(gs _rvalueExpr "")))))
						; ignore(setNameListSymbolInLatticeFields(ref (evalEnv.currentLat), nameList, (!idSymbol)) )
						
					)
			)

(***********************************************************************************************************************************)
and setSeqlatElementForLatticeFields(_latticeRef, _index, (_value: latticeFields)) =
		let seqlatRef = try getSeqlatFromLatticeFields(_latticeRef) with e -> raise (Invalid_argument("Not found!!")) in 
		let array = Array.of_list (!seqlatRef).elements in
		Array.set array _index _value;
		(!seqlatRef).elements <- Array.to_list array;
		_latticeRef := !(setSeqlatFromLatticeFields(_latticeRef, seqlatRef))
		

(*--------------------------------------------------------------------*)
and findNameListSymbolAndLatticeInLatticeFields(_latticeF, _nameList) =
		match _nameList with
			| [hd] -> findNameTypeSymbolAndLatticeInLatticeFields(_latticeF, hd)
			| hd::tl -> let (symOpt, latOpt) = findNameTypeSymbolAndLatticeInLatticeFields(_latticeF, hd) in 
				(match latOpt with
					| None -> (symOpt, None)
					| Some(lat) -> findNameListSymbolAndLatticeInLatticeFields(lat, tl)
				)
			| [] -> rf("BUG: getNameListFromSymbolTable!")
		
and findNameTypeSymbolAndLatticeInLatticeFields(_latticeF, _nameType) = 
		let symbolTable = try getSymbolTableFromSeqlat (!_latticeF) with e -> raise Not_found in  
		match _nameType with
			| This -> rf("Not Implemented: 'This'!") 
			| PredefinedLabel(predefinedLabel) -> rf("Not Implemented: 'This'!")
			| IndexingOp(structureType, latticeT) -> (*uses: Seq (for []), Alt (for {}), and UndeterminedStruct (for @)*) 
						rf("Not Implemented: 'This'!")
			| HashOp(exprF) -> rf("Not Implemented: 'Hash'!")
			| Id(str) -> 
					let symbolOpt = findRefInSymbolTable(symbolTable, str) in 
					let latticeOpt = (match symbolOpt with
						| None -> raise (Not_found) 
						| Some(symbolRef) -> (match (!symbolRef).symValue with 
								| LabelIndex(ind) -> Some(ref (getLatticeFieldsByIndex(!_latticeF, ind)))
								| LocalValueLattice(latFRef) -> Some(latFRef)
				)) in
				(symbolOpt, latticeOpt)
			| Each(latticeT) -> rf("Not Implemented: 'This'!")

(*--------------------------------------------------------------------*)
and setNameListSymbolInLatticeFields(_latticeF, _nameList, _symbol) =
		match _nameList with
			| [hd] -> setNameTypeSymbolInLatticeFields(_latticeF, hd, _symbol, true)
			| hd::tl -> let (symOpt, latOpt) = setNameTypeSymbolInLatticeFields(_latticeF, hd, _symbol, false) in 
				(match latOpt with
					| None -> (symOpt, None)
					| Some(lat) -> setNameListSymbolInLatticeFields(lat, tl, _symbol)
				)
			| [] -> rf("BUG: getNameListFromSymbolTable!")
		
and setNameTypeSymbolInLatticeFields(_latticeF, _nameType, _symbol, _doSave) = 
		let symbolTable = try getSymbolTableFromSeqlat (!_latticeF) with e -> raise Not_found in  
		match _nameType with
			| This -> rf("Not Implemented: 'This'!") 
			| PredefinedLabel(predefinedLabel) -> rf("Not Implemented: 'This'!")
			| IndexingOp(structureType, latticeT) -> (*uses: Seq (for []), Alt (for {}), and UndeterminedStruct (for @)*) 
						rf("Not Implemented: 'This'!")
			| HashOp(exprF) -> rf("Not Implemented: 'Hash'!")
			| Id(str) -> 
					let symbolOpt = findRefInSymbolTable(symbolTable, str) in
					if (_doSave) then (
						symbolTable.hash <- StringMap.add str _symbol symbolTable.hash;
						ignore(_latticeF = setSymbolTableInLattice(_latticeF, symbolTable.hash));
						(None, None)
						)
					else
						let latticeOpt = (match symbolOpt with
							| None -> raise (Not_found) 
							| Some(symbolRef) -> (match (!symbolRef).symValue with 
									| LabelIndex(ind) -> Some(ref (getLatticeFieldsByIndex(!_latticeF, ind)))
									| LocalValueLattice(latFRef) -> Some(latFRef)
				)) in
				(symbolOpt, latticeOpt)
			| Each(latticeT) -> rf("Not Implemented: 'This'!")

and setSymbolTableInLattice(_latticeF, _symbolTableHash) =
		match (!_latticeF).lattice with
		| Seqlat(seqlat) -> (seqlat.symbols.hash <- _symbolTableHash; (!_latticeF).lattice <- Seqlat(seqlat)); _latticeF
		| Expr(expr) -> (match expr.exprCode with 
			| LatticeExpr(lat) -> let _ = setSymbolTableInLattice(ref lat, _symbolTableHash) in _latticeF
			| _ -> rf("BUG: getSymbolTableFromSeqlat()!"))
		| _ -> rf("BUG: getSymbolTableFromSeqlat()!")
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		




(*Deprecated*)
(*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*)
and processCurNameList _curNamesList  =
    match _curNamesList with
    | [] -> raise (Failure("Bug"))
    | hd::tl -> if (List.length tl > 0) then
    (
        match hd with
        | Id(id) ->  (
            match evalEnv.currentLat.lattice with
            | Seqlat(seqlat) ->   (
            let mySymbol = StringMap.find id seqlat.symbols.hash in
            match mySymbol.symValue with
                | LabelIndex(index) -> (
                evalEnv.parentStack <- evalEnv.currentLat :: evalEnv.parentStack (*PUSH*); 
                let curLat =  List.nth seqlat.elements index  in         
                evalEnv.currentLat <- curLat; 
                let res = processCurNameList tl in res             
                   (* evalEnv.currentLat <- List.hd evalEnv.parentStack; (*POP*);
                evalEnv.parentStack <- List.tl evalEnv.parentStack; (*Remove*)             
                *)       
                
                )
                | LocalValueLattice(newlatFields) ->
                (
                (*    let nextLatFields = !newlatFields in
                processCurNameList tl  *)
                raise (Failure("Local"))
                )        
            
            )
            
            | _ -> raise (Failure("Bug"))
             )
        | _ ->  raise (Failure("Still Not Handled"))
           
    )
    else
    (
    match hd with
    | Id(id) ->  (
        match evalEnv.currentLat.lattice with
        | Seqlat(seqlat) ->   (
        let mySymbol = StringMap.find id seqlat.symbols.hash in
        match mySymbol.symValue with
            | LabelIndex(index) -> 
            let curElement =  List.nth seqlat.elements index  in            
            let result = (match curElement.lattice with
            |   Seqlat(seq) -> raise (Failure("Seq "))
            |   Altlat(alt) -> raise (Failure("Alt"))
            |   Predicate(pred) -> raise (Failure("Pred"))
            |   Expr(expr) -> processExpr expr
            ) in result
            | LocalValueLattice(newlatFields) ->
            
            let nextLatFields = !newlatFields in
            let result = (   match nextLatFields.lattice with
            |   Seqlat(seq) -> raise (Failure("Seq-local"))
            |   Altlat(alt) -> raise (Failure("Alt-Local"))
            |   Predicate(pred) -> raise (Failure("Pred-Local"))
            |   Expr(expr) -> processExpr expr
            ) in result

        )               
        | Altlat(altlat) -> raise (Failure("altlat"))
        | Predicate(pred) -> raise (Failure("pred"))
        | Expr(expr) ->  raise (Failure("expr"))
        (*let res = createExprFieldsFromExprCodeType(ConstExpr(IntLiteral(2))) in res *)
        )
    | IndexingOp(structType, lattice) -> raise (Failure("Still Not Handled"))
			| _ ->  raise (Failure("Still Not Handled"))
       
    )
		
