var TOK_WHITE = 0
var TOK_COMMENT = 1
var TOK_DOT = 2
var TOK_END = 3
var TOK_CM = 4
var TOK_COL = 5
var TOK_OP_BOOL = 6
var TOK_EQ = 7
var TOK_BR_L = 8
var TOK_BR_R = 9
var TOK_ME_L = 10
var TOK_ME_R = 11
var TOK_AR_L = 12
var TOK_AR_R = 13
var TOK_NOT = 14
var TOK_DEC = 15
var TOK_NUM = 16
var TOK_OP = 17
var TOK_CHAR = 18
var TOK_QU = 19
var TOK_VIS = 20
var TOK_CLASS = 21
var TOK_STATIC = 22
var TOK_PRIM = 23
var TOK_IMPORT = 24
var TOK_EXT = 25
var TOK_RET = 26
var TOK_IF = 27
var TOK_FOR = 28
var TOK_WHILE = 29
var TOK_DO = 30
var TOK_SWITCH = 31
var TOK_CASE = 32
var TOK_DEF = 33
var TOK_BOOL = 34
var TOK_ELSE = 35
var TOK_NEW = 36
var TOK_BREAK = 37
var TOK_TRY = 38
var TOK_CATCH = 39
var TOK_FIN = 40
var TOK_THROW = 41
var TOK_NULL = 42
var TOK_IMP = 43
var TOK_INTER = 44
var TOK_FINAL = 45
var TOK_IS = 46
var TOK_TYPE = 47
var TOK_STR = 48
var TOK_CUSTOM = 49
var TOK_ERR = 50
var TOK_BYTECODE = 51


var J_TOKENS = [
	{tok: TOK_WHITE, reg:new RegExp("^[ \\n\\t]+"), name:""},
	{tok: TOK_COMMENT, reg:new RegExp("^((\\/\\/[^\\n]*\\n)|(\\/\\*((?!\\*\\/)[\\s\\S])*(\\*\\/)?))"), name:"comment section"},
	
	{tok: TOK_DOT, reg:new RegExp("^\\."), quick: ".", name:"."},
	{tok: TOK_END, reg:new RegExp("^;"), quick: ";", name:";"},
	{tok: TOK_CM, reg:new RegExp("^,"), quick: ",", name:","},
	{tok: TOK_COL, reg:new RegExp("^:"), quick: ":", name:":"},
	
	{tok: TOK_OP_BOOL, reg:new RegExp("^(\\<=|\\>=|==|\\<|\\>|\\|\\||\\&\\&|\\||\\&|\\!\\=)"), name:"boolean op"},
	{tok: TOK_EQ, reg:new RegExp("^=(?!=)"), name:"equals"},
	
	{tok: TOK_BR_L, reg:new RegExp("^\\("), name:"left bracket"},
	{tok: TOK_BR_R, reg:new RegExp("^\\)"), name:"right bracket"},
	{tok: TOK_ME_L, reg:new RegExp("^\\{"), name:"left curly bracket"},
	{tok: TOK_ME_R, reg:new RegExp("^\\}"), name:"right curly bracket"},
	{tok: TOK_AR_L, reg:new RegExp("^\\["), name:"left square bracket"},
	{tok: TOK_AR_R, reg:new RegExp("^\\]"), name:"right square bracket"},
	
	{tok: TOK_NOT, reg:new RegExp("^\\!"), name:"boolean not"},
	{tok: TOK_DEC, reg:new RegExp("^[0-9]+(\\.[0-9]+)"), name:"decimal number"},
	{tok: TOK_NUM, reg:new RegExp("^[0-9]+"), name:"natural number"},
	{tok: TOK_OP, reg:new RegExp("^(\\+|\\-|\\*|\\\/|\\%)"), name:"operator"},
	{tok: TOK_CHAR, reg:new RegExp("^'(\\\\)?.'"), name:"character"},
	{tok: TOK_QU, reg:new RegExp("^\\?"), name:"question mark"},
	
	{tok: TOK_VIS, reg:new RegExp("^(public|private)(?![a-zA-Z0-9_])"), name:"visibility"},
	{tok: TOK_CLASS, reg:new RegExp("^class(?![a-zA-Z0-9_])"), name:"class"},
	{tok: TOK_STATIC, reg:new RegExp("^static(?![a-zA-Z0-9_])"), name:"static"},
	{tok: TOK_PRIM, reg:new RegExp("^(void|byte|short|int|long|boolean|char|double|float)(?![a-zA-Z0-9_])"), name:"primitive type"},
	{tok: TOK_IMPORT, reg:new RegExp("^import(?![a-zA-Z0-9_])"), name:"import"},
	{tok: TOK_EXT, reg:new RegExp("^extends(?![a-zA-Z0-9_])"), name:"extends"},
	{tok: TOK_RET, reg:new RegExp("^return(?![a-zA-Z0-9_])"), name:"return"},
	{tok: TOK_IF, reg:new RegExp("^if(?![a-zA-Z0-9_])"), name:"if"},
	{tok: TOK_FOR, reg:new RegExp("^for(?![a-zA-Z0-9_])"), name:"for"},
	{tok: TOK_WHILE, reg:new RegExp("^while(?![a-zA-Z0-9_])"), name:"while"},
	{tok: TOK_DO, reg:new RegExp("^do(?![a-zA-Z0-9_])"), name:"do"},
	{tok: TOK_SWITCH, reg:new RegExp("^switch(?![a-zA-Z0-9_])"), name:"switch"},
	{tok: TOK_CASE, reg:new RegExp("^case(?![a-zA-Z0-9_])"), name:"case"},
	{tok: TOK_DEF, reg:new RegExp("^default(?![a-zA-Z0-9_])"), name:"default"},
	{tok: TOK_BOOL, reg:new RegExp("^(true|false)(?![a-zA-Z0-9_])"), name:"boolean"},
	{tok: TOK_ELSE, reg:new RegExp("^else(?![a-zA-Z0-9_])"), name:"else"},
	{tok: TOK_NEW, reg:new RegExp("^new(?![a-zA-Z0-9_])"), name:"new"},
	{tok: TOK_BREAK, reg:new RegExp("^(break|continue)(?![a-zA-Z0-9_])"), name:"break/continue"},
	{tok: TOK_TRY, reg:new RegExp("^try(?![a-zA-Z0-9_])"), name:"try"},
	{tok: TOK_CATCH, reg:new RegExp("^catch(?![a-zA-Z0-9_])"), name:"catch"},
	{tok: TOK_FIN, reg:new RegExp("^finally(?![a-zA-Z0-9_])"), name:"finally"},
	{tok: TOK_THROW, reg:new RegExp("^throw(?![a-zA-Z0-9_])"), name:"finally"},
	{tok: TOK_NULL, reg:new RegExp("^null(?![a-zA-Z0-9_])"), name:"null pointer"},
	{tok: TOK_IMP, reg:new RegExp("^implements(?![a-zA-Z0-9_])"), name:"implements"},
	{tok: TOK_INTER, reg:new RegExp("^interface(?![a-zA-Z0-9_])"), name:"interface"},
	{tok: TOK_FINAL, reg:new RegExp("^final(?![a-zA-Z0-9_])"), name:"final"},
	{tok: TOK_IS, reg:new RegExp("^is(?![a-zA-Z0-9_])"), name:"is"},
	{tok: TOK_TYPE, reg:new RegExp("^[a-zA-Z0-9][a-zA-Z0-9_]*"), name:"class type/name"},
	{tok: TOK_STR, reg:null, name:"string"},
	{tok: TOK_CUSTOM, reg:null, name:"custom function"},
	{tok: TOK_ERR, reg:null, name:"..."}
]

function TOKEN(t,n,l,c){
	this.type = t
	this.data = n
	this.line = l
	this.ch = c
}
var line, charPos
var alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
var alphaTok = J_TOKENS.slice(20)
var nonTok = J_TOKENS.slice(0,20)
var DEV = false

function badChar(t){
	var msg = "line "+t.line.toString().pad(3," ",true)+":: LEX ERROR  : unexpected char ( "+t.data+" )"
	compileError({msg:msg, token:t},true)
}

var TYPES = [
    [],[],".",";",",",":",
    ["<",">","|","%","&"],"=","(",")","{","}","[","]",
    ["!"],[],[],["+","-","*","/","%"],[],"?",
    ["public","private"],"class","static",
    ["void","byte","short","int","long","double","float","boolean","char"],
    "import","extends","return",
    "if","for","while","do","switch","case","default",
    ["true","false"],
    "else","new",
    ["break","continue"],
    "try","catch","finally","throw",
    "null","implements","interface","final","is",[]
]
function splitCode(code){
	var chars = code.split("")
	var words = []
	var count = 0
	var part = ""
	var RegFst = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	var RegNum = "0123456789"
	var RegSnd = RegFst+RegNum+"_"
	var isNum = false
	while(chars.length > 0){
		var ch = chars.splice(0,1)[0]
		if(part.length == 0 && RegFst.indexOf(ch) > -1) {part = ch;isNum = false}
		else if(part.length == 0 && RegNum.indexOf(ch) > -1) {part = ch;isNum = true}
		
		else if(!isNum && part.length > 0 && RegSnd.indexOf(ch) > -1) part += ch
		else if(isNum && part.length > 0 && RegNum.indexOf(ch) > -1) part += ch
		else{
			if(part.length > 0) words.push(part)
			words.push(ch)
			part = ""
		}
	}
	return words
}
function LEX(code){
	//var toks = []
   //var words = code.searchAll(/([a-zA-Z0-9][a-zA-Z0-9_]*)|[\W\w]/)
   //words.each(function(i,item){toks.push(item.str)})
   var toks = splitCode(code)
   var white = new RegExp(/\s/)
   var next = []
   line = 1;
   charPos = 0;
   while(toks.length){
        var fst = toks.splice(0,1)[0]
        var chs = fst.charAt(0)
        var data = fst
        var ty = -1
        var offset = 0;
        if(chs == "$") {data = munchUntil(toks,"$");ty=TOK_CUSTOM;offset=2}
        else if(chs == '"') {data = munchUntil(toks,'"');ty=TOK_STR;offset=2}
        else if(chs == "'") {data = munchUntil(toks,"'");ty=TOK_CHAR;offset=2}
        else if(fst == "/" && ["/","*"].indexOf(toks[0]) > -1){
        	if(toks[0] == "/"){
        		toks.splice(0,1)
		 	data = munchUntil(toks,'\n')
			ty = TOK_COMMENT
			offset=3
        	}else if(toks[0] == "*"){
			toks.splice(0,1)
		    	data = munchUntil(toks,'*/')
		    	ty = TOK_COMMENT
		    	offset=4
        	}
        }else if(["<",">","!"].indexOf(fst) > -1  && toks[0] == "="){
            data = fst+toks.splice(0,1)[0]
            ty = TOK_OP_BOOL
        }else if(["|","&","="].indexOf(fst) > -1  && toks[0] == fst){
            data = fst+toks.splice(0,1)[0]
            ty = TOK_OP_BOOL
        }else if(("0123456789").indexOf(chs) > -1){
            ty = TOK_NUM
            data = fst
            if(toks[0] == "." && ("0123456789").indexOf(toks[1].charAt(0)) > -1){ //decimal
                ty = TOK_DEC
                data = fst + "." + toks[1]
                toks.splice(0,2)
            }
	    if(toks[0] == "f" || toks[0] == "l"){
		ty = TOK_DEC
		data += toks[0]
                toks.splice(0,1);
	    }
        }
        else if(white.test(fst)) ty = TOK_WHITE;
	else if(DEV && chs == "@") {data = munchUntil(toks,"@");ty=TOK_BYTECODE;offset=2}
        else{
            for(var i = 0; i < TYPES.length; i++){
		if(typeof TYPES[i]  == "string"){
			if(TYPES[i] == fst) {ty = i;break}
		}else{
			var index = TYPES[i].indexOf(fst)
			if(index > -1) {ty = i;break}
		}
	    }
            if(ty == -1 && alpha.indexOf(chs) != -1) ty = TYPES.length-1
        }
	if(ty > -1) next.push(new TOKEN(ty,data,line,charPos))
	else {badChar(new TOKEN(ty,data,line,charPos))}
	
	charPos+=data.length+offset
	var li = data.match("\n")
	if(li) line+=li.length
   }
   return next
}
function munchUntil(arr,ch){
    var skip = false
    var data = ""
    var finish = ""
    while(arr.length){
        var n = arr[0]
        if(!skip && n == ch[finish.length]) finish += n
        else finish = ""
        if(finish == ch) break;
        skip = (n=="\\")
        data+=n
        arr.splice(0,1)
    }
    arr.splice(0,ch.length)
    return data.substring(0,data.length-(ch.length-1))
}
