uint TTYPE_DELIM = 0
uint TTYPE_SEP   = 1
uint TTYPE_KEYWD = 2
uint TTYPE_KEYTP = 3
uint TTYPE_LITRL = 4
uint TTYPE_AUG   = 5
uint TTYPE_USRWD = 6
uint TTYPE_COMNT = 7

uint TTYPE_UNKNOWN = 998
uint TTYPE_ERR   = 999

struct Token {
	uint _type,
	~uint8 data,
	uint
		line,
		col
}

/; method Token
	/; eq (~uint8 str) [bool]
		return utils.strcmp(self.data, str)
	;/

	/; end
		_delete(self.data)
	;/
;/

/; _in_csv (~uint8 csv, ~uint8 str) [bool]
	int along = 0

	/; loop (csv` !== 0) [csv++]
		/; if (csv` == ',')
			/; if (along !< 0 && str{along} == 0)
				return true
			;/
			along = 0
		;; else if (along !< 0 && str{along} == csv`)
			along++
		;; else
			along = 0
			along--
		;/
	;/

	return along !< 0 && str{along} == 0
;/

/; _str_contains (~uint8 str, uint8 ch) [bool]
	/; loop (str` !== 0) [str++]
		/; if (str` == ch)
			return true
		;/
	;/
	return false
;/


~uint8 KEYWORDS   = "import,using,module,export,struct,method,implements,interface,operator,enum,if,else,loop,continue,break,return,label,goto,asm\0"
~uint8 KEYTYPES   = "uint8,uint16,uint32,uint64,uint,int8,int16,int32,int64,int,float32,float64,float,bool,void,vect,type\0"
~uint8 LITERALS   = "false,true,null,iota\0"

~uint8 RESERVED   = "~`!@#$%^&*()[]{}-+=\"\'\\|;:/?.>,<\0"

~uint8 OP         = "`~!%^&|*-=+./><\0"
~uint8 MULTI_OP   = "==,&&,||,^^,!==,!&&,!||,!^^,!<,!>,<<,>>,!&,!|,!^,++,--,>==,<==\0"
uint   MAX_MULTI  = 3
~uint8 MULTI_OP_W = "is,len\0"

~uint8 DELIMS     = "()[]{}\0"


/; produce_word_token (~utils.File fin, Token prev) [Token]
	Token out
	out.line = prev.line
	out.col = prev.col
	out._type = TTYPE_USRWD

	utils.Vector tmp
	tmp.init(1)

	uint8 ch = fin`.read()

	/; loop (ch !== 0 && is_reserved(ch) == false && is_whitespace(ch) == false)
		tmp.push(~ch)
		ch = fin`.read()
	;/

	/; if (ch !== 0)
		fin`.unread()
	;/

	out.data = tmp.as_cstr()
	/; if (_in_csv(KEYWORDS, out.data) == true)
		out._type = TTYPE_KEYWD
	;; else if (_in_csv(KEYTYPES, out.data) == true)
		out._type = TTYPE_KEYTP
	;; else if (_in_csv(LITERALS, out.data) == true)
		out._type = TTYPE_LITRL
	;; else if (_in_csv(MULTI_OP_W, out.data) == true)
		out._type = TTYPE_AUG
	;/

	return out
;/

/; produce_string_token (~utils.File fin, Token prev) [Token]
	Token out
	out.line = prev.line
	out.col = prev.col
	out._type = TTYPE_LITRL

	utils.Vector tmp
	tmp.init(1)

	uint8 delim = fin`.read()
	tmp.push(~delim)

	/; loop (fin`.at_end == false && delim !== 0)
		uint8 ch = fin`.read()
		/; if (ch == '\\')
			tmp.push(~ch)
			ch = fin`.read()
		;; else if (ch == '\n')
			out.line++
		;; else if (ch == delim)
			delim = 0
		;/
		
		/; if (ch !== 0)
			tmp.push(~ch)
		;/
	;/

	out.data = tmp.as_cstr()
	return out
;/

/; comment_line (~utils.File fin)
	uint8 ch = fin`.read()

	/; loop (fin`.at_end == false && ch !== '\n')
		ch = fin`.read()
	;/

	/; if (fin`.at_end == false)
		fin`.unread()
	;/
;/

/; comment_block (~utils.File fin, ~Token out)
	uint8 ch = 1
	/; loop (fin`.at_end == false && ch !== 0)
		ch = fin`.read()
		/; if (ch == '#')
			ch = fin`.read()
			/; if (ch == '/')
				ch = 0
			;; else
				comment_line(fin)
			;/
		;/

		/; if (ch == '\n')
			out`.line++
		;/
	;/
;/

/; is_comment_block (~uint8 str) [bool]
	return utils.strcmp(str, "/#\0")
;/

/; is_multi_delim(~uint8 str) [bool]
	/; if (utils.strcmp(str, "/;\0") == true)
		return true
	;; else if (utils.strcmp(str, ";;\0") == true)
		return true
	;; else if (utils.strcmp(str, ";/\0") == true)
		return true
	;/
	return false
;/

/; produce_reserved_token (~utils.File fin, Token prev) [Token]
	Token out
	out.line = prev.line
	out.col = prev.col
	out._type = TTYPE_USRWD

	utils.Vector tmp
	tmp.init(1)

	uint8 ch = fin`.read()

	/; if (ch == '#')
		tmp.push(~ch)
		out._type = TTYPE_COMNT
		out.data = tmp.as_cstr()
		comment_line(fin)
		return out
	;/

	tmp.push(~ch)
	/; loop (int i = 1; i < MAX_MULTI) [i++]
		ch = fin`.read()
		/; if (is_reserved(ch) == false)
			i = MAX_MULTI
			fin`.unread()
		;; else
			tmp.push(~ch)
		;/
	;/

	/; loop (bool run = true; run == true)
		~uint8 str = tmp.as_cstr()
		/; if (tmp.count == 1)
			/; if (str` == ',' || str` == ';')
				out._type = TTYPE_SEP
			;; else if (_str_contains(OP, str`))
				out._type = TTYPE_AUG
			;; else if (_str_contains(DELIMS, str`))
				out._type = TTYPE_DELIM
			;; else
				out._type = TTYPE_UNKNOWN
			;/
			run = false
		;; else if (_in_csv(MULTI_OP, str) == true)
			out._type = TTYPE_AUG
			run = false
		;; else if (is_comment_block(str) == true)
			out._type = TTYPE_COMNT
			comment_block(fin, ~out)
			run = false
		;; else if (is_multi_delim(str) == true)
			out._type = TTYPE_DELIM
			run = false
		;; else
			tmp.pop()
			fin`.unread()
		;/
	;/

	out.data = tmp.as_cstr()
	return out
;/

/; produce_numeric_token (~utils.File fin, Token prev) [Token]
	Token out
	out.line = prev.line
	out.col = prev.col
	out._type = TTYPE_LITRL

	utils.Vector tmp
	tmp.init(1)
	
	uint8 ch = fin`.read()
	tmp.push(~ch)
	bool base = false
	/; if (ch == '0')
		ch = fin`.read()
		/; if (ch == 0)
			out.data = tmp.as_cstr()
			return out
		;; else if (is_reserved(ch) == true || is_whitespace(ch) == true)
			fin`.unread()
			out.data = tmp.as_cstr()
			return out
		;; else if (is_numeric(ch) == false)
			base = true
			tmp.push(~ch)
		;/
	;/

	bool decimal = false
	/; loop (bool run = true; run == true && fin`.at_end == false)
		ch = fin`.read()
		/; if (ch == 0)
			run = false
		;; else if (decimal == false && ch == '.')
			decimal = true
			tmp.push(~ch)
		;; else if (is_reserved(ch) == true || is_whitespace(ch) == true)
			fin`.unread()
			run = false
		;; else if (is_numeric(ch) == false && base == false)
			fin`.unread()
			run = false
		;; else if (ch !== 0)
			tmp.push(~ch)
		;/
	;/

	out.data = tmp.as_cstr()
	return out
;/

/; is_whitespace (uint8 ch) [bool]
	/; if (ch > 8 && ch < 14)
		return true
	;; else if (ch == ' ')
		return true
	;/
	return false
;/

/; is_reserved (uint8 ch) [bool]
	return _str_contains(RESERVED, ch) == true
;/

/; is_numeric (uint8 ch) [bool]
	/; if (ch !< '0' && ch !> '9')
		return true
	;/
	return false
;/

/; produce_next_token (~utils.File fin, Token prev) [Token]
	/; if (prev._type !== TTYPE_ERR)
		prev.col = prev.col + utils.strlen(prev.data)
	;/

	uint8 first = fin`.read()
	/; loop (is_whitespace(first) == true)
		/; if (first == '\n')
			prev.line++
			prev.col = 0
		;/
		first = fin`.read()
		prev.col++
	;/
	fin`.unread()
	
	/; if (first == '\'' || first == '\"')
		return produce_string_token(fin, prev)
	;; else if (is_reserved(first) == true)
		Token out = produce_reserved_token(fin, prev)
		/; loop (out._type == TTYPE_COMNT)
			Token tmp = produce_next_token(fin, out)
			out.end()
			out = tmp
		;/
		return out
	;; else if (is_numeric(first) == true)
		return produce_numeric_token(fin, prev)
	;; else if (first !== 0)
		return produce_word_token(fin, prev)
	;/

	Token out
	out.line = prev.line
	out.col = prev.col
	out._type = TTYPE_ERR
	out.data = utils.strcpy("\0")
	return out
;/

/; produce_first_token (~utils.File fin) [Token]
	Token tmp
	tmp.line = 1
	tmp.col = 1
	tmp._type = TTYPE_ERR
	
	return produce_next_token(fin, tmp)
;/

/; gen_token_list (~utils.File fin) [utils.Vector]
	utils.Vector out
	Token tmp
	out.init(len tmp)
	
	fin`.open()
	tmp = produce_first_token(fin)
	/; loop (tmp._type !== TTYPE_ERR)
		/; if (tmp._type !== TTYPE_COMNT)
			out.push(~tmp)
			tmp = produce_next_token(fin, tmp)
		;; else
			Token com = tmp
			tmp = produce_next_token(fin, com)
			com.end()
		;/
	;/
	tmp.end()
	fin`.close()

	return out
;/

/; print_token_type(Token t)
	
	/; if (t._type == TTYPE_DELIM)
		_printf("DELIM\0")
	;; else if (t._type == TTYPE_SEP)
		_printf("SEP\0")
	;; else if (t._type == TTYPE_KEYWD)
		_printf("KEYWD\0")
	;; else if (t._type ==TTYPE_KEYTP)
		_printf("KEYTP\0")
	;; else if (t._type == TTYPE_LITRL)
		_printf("LITRL\0")
	;; else if (t._type == TTYPE_AUG)
		_printf("AUG\0")
	;; else if (t._type == TTYPE_USRWD)
		_printf("USRWD\0")
	;; else if (t._type == TTYPE_COMNT)
		_printf("COMNT\0")
	;; else if (t._type == TTYPE_UNKNOWN)
		_printf("UNKNOWN\0")
	;; else if (t._type == TTYPE_ERR)
		_printf("ERR\0")
	;/

;/

/; print_token (Token t)
	_printf("Token { \"\0")
	_printf(t.data)
	_print_num("\", line: %u\0", t.line)
	_print_num(", col: %u, type: \0", t.col)
	print_token_type(t)
	_printf(" }\n\0")
;/

/; print_token_list (~utils.Vector vec)
	~Token tok
	/; loop (uint i = 0; i < vec`.count) [i++]
		tok = vec.get(i)
		print_token(tok`)
	;/
;/

/; end_token_list (~utils.Vector vec)
	~Token tok
	
	/; loop (uint i = 0; i < vec`.count) [i++]
		tok = vec`.get(i)
		tok`.end()
	;/
	vec`.end()
;/