## ## LOG UTILITIES ## ;{}uint8 log_level = "2" /; log_err ({}uint8 msg) ;tnsl.io.print("[TNSLC] [ERR]: ") ;tnsl.io.println(msg) ;tnsl.exit() ;/ /; log_info ({}uint8 msg) ;uint l = string_to_int(log_level) /; if (l > 0) ;tnsl.io.print("[TNSLC] [INFO]: ") ;tnsl.io.println(msg) ;/ ;/ /; log_debug ({}uint8 msg) ;uint l = string_to_int(log_level) /; if (l > 1) ;tnsl.io.print("[TNSLC] [DEBUG]: ") ;tnsl.io.println(msg) ;/ ;/ ## ## UTIL FUNCS ## /; string_split ({}uint8 str, uint8 split) [{}{}uint8] /; if (len str == 0) ;return {} ;/ ;{}{}uint8 out = {} ;{}uint8 run = "" /; loop (int i = 0; i < len str) [i++] /; if (str{i} == split) ;out.append(run) ;run = "" ;; else ;run.append(str{i}) ;/ ;/ ;out.append(run) ;return out ;/ /; string_join ({}{}uint8 strs, {}uint8 join) [{}uint8] ;{}uint8 out = "" /; loop (int i = 0; i < len strs) [i++] ;out = string_add(out, strs{i}) /; if (i !== len strs - 1) ;out = string_add(out, join) ;/ ;/ ;return out ;/ /; string_add ({}uint8 base, add) [{}uint8] /; loop (int i = 0; i < len add) [i++] ;base.append(add{i}) ;/ ;return base ;/ /; string_equate ({}uint8 a, b) [bool] /; if (len a !== len b) ;return false ;/ /; loop (int i = 0; i < len a) [i++] /; if (a{i} !== b{i}) ;return false ;/ ;/ ;return true ;/ /; string_contains ({}uint8 str, uint8 chk) [bool] /; loop (int i = 0; i < len str) [i++] /; if (str{i} == chk) ;return true ;/ ;/ ;return false ;/ /; list_contains ({}{}uint8 list, {}uint8 str) [bool] /; loop (int i = 0; i < len list) [i++] /; if (string_equate(list{i}, str)) ;return true ;/ ;/ ;return false ;/ /; unqote_char ({}uint8 str) [uint8] /; if (len str < 3) ;return 0 ;/ ;uint8 cmp = str{2} /; if (cmp == '\\') ;return '\\' ;; else if (cmp == 'n') ;return '\n' ;; else if (cmp == 'r') ;return '\r' ;; else if (cmp == 't') ;return '\t' ;; else if (cmp == '0') ;return '\0' ;/ ;/ /; unquote_str({}uint8 str) [{}uint8] /; if (str{0} !== '\'' && str{0} !== '"') ;return str ;/ ;{}uint8 out = "" /; loop (int i = 1; i < len str - 1) [i++] /; if (str{i} == '\\') ;{}uint8 unq = "'\\" ;unq.append(str{i + 1}) ;out.append(unqote_char(unq)) ;i++ ;; else ;out.append(str{i}) ;/ ;/ ;return out ;/ /; string_reverse ({}uint8 str) [{}uint8] ;{}uint8 out = "" /; loop (int i = len str - 1; i !< 0) [i = i - 1] ;out.append(str{i}) ;/ ;return out ;/ /; int_to_string (int i) [{}uint8] /; if (i == 0) ;return "0" ;/ ;{}uint8 out = "" ;bool inv = i < 0 /; if (inv) ;i = -i ;/ /; loop [i = i / 10; i > 0] ;out.append('0' + (i % 10)) ;/ /; if (inv) ;out.append('-') ;/ ;return string_reverse(out) ;/ /; digit_from_base (uint8 ch, int base) [int] /; if (ch == '-') ;return 0 ;/ /; if (base !> 10) ;return ch - '0' ;; if (base == 16) /; if (ch !< 'A' && ch < 'G') ;return 11 + (ch - 'A') ;; else if (ch !< 'a' && ch < 'g') ;return 11 + (ch - 'a') ;/ ;return ch - '0' ;/ ;return 0 ;/ /; string_to_int ({}uint8 str) [int] /; if (len str < 1) ;return 0 ;/ ;int i = 0 ;bool inv = str{0} == '-' /; if (inv) ;i = 1 ;/ ;int out = 0 ;int base = 10 /; if (len str !< 3 && str{i} == '0') /; if (str{i + 1} == 'x') ;base = 16 ;i = i + 2 ;; if (str{i + 1} == 'b') ;base = 2 ;i = i + 2 ;; if (str{i + 1} == 'o') ;base = 8 ;i = i + 2 ;/ ;/ /; loop (i < len str) [i++] ;out = out * base ;out = out + digit_from_base(str{i}, base) ;/ /; if (inv) ;out = -out ;/ ;return out ;/ ## ## Structs ## # The seperated string sections that make up an asm file ;struct CompData { {}uint8 hsec, dsec, csec } # Represents a relative file path ;struct Path { {}{}uint8 path, {}uint8 name } /; method Path /; relative ({}uint8 rel_path) [Path] ;Path out = self ;{}{}uint8 rel_split = string_split(rel_path, '/') /; loop (int i = 0; i < len rel_split - 1) ;out.path.append(rel_split{i}) ;/ ;out.name = rel_split{len rel_split - 1} ;return out ;/ /; full_path [{}uint8] ;{}uint8 out = string_join(self.path, "/") /; if (len out > 0) ;out.append('/') ;/ ;return string_add(out, self.name) ;/ /; extension [{}uint8] ;{}{}uint8 split_name = string_split(self.name, '.') /; if (len split_name > 1) ;return split_name{len split_name - 1} ;/ ;return "" ;/ /; open_read [tnsl.io.File] ;return tnsl.io.readFile(self.full_path()) ;/ /; write ({}uint8 bytes) ;tnsl.io.File out = tnsl.io.writeFile(self.full_path()) /; loop (int i = 0; i < len bytes) [i++] ;out.write(bytes{i}) ;/ ;out.close() ;/ ;/ # Represents the different classes of token ;enum TOKEN [int] { SEPARATOR = 0, DELIMITER = 1, AUGMENT = 2, KEYTYPE = 3, KEYWORD = 4, LITERAL = 5, DEFWORD = 6 } # Represents a single token in a TNSL file ;struct Token { int tokenType, line, {}uint8 data } /; method Token /; type_is (int a) [bool] ;return self.tokenType == a ;/ /; cmp ({}uint8 str) [bool] ;return string_equate(self.data, str) ;/ /; print ;tnsl.io.print(self.data) ;tnsl.io.print(": { type: ") ;tnsl.io.print(self.tokenType) ;tnsl.io.print(" line: ") ;tnsl.io.print(self.line) ;tnsl.io.print(" }") ;/ /; sprint [{}uint8] ;{}uint8 out = "{ " ;out = string_add(out, self.data) ;out.append(' ') ;out = string_add(out, int_to_string(self.tokenType)) ;out.append(' ') ;out.append('}') ;return out ;/ ;/ # General defs: ## Type defs ## Function defs ## Method defs ## Module defs ## Constant and variable defs # Module ## General defs # Block ## Variable defs ## Control flow defs ## Value defs ;enum PTYPE [int] { POINTER = 0, REFERENCE = 1, ARRAY = 2 } # Represents a data type ;struct Type { int s, {}uint8 name, mod_name, {}int ptr_chain, {}Variable members } /; method Type /; sprint [{}uint8] ;{}uint8 out = string_join( {"{ ", int_to_string(self.s), ", ", self.name, ", ", self.mod_name, ", { "}, "") ;{}{}uint8 pch = {} /; loop (int i = 0; i < len(self.ptr_chain)) [i++] ;pch.append(int_to_string(self.ptr_chain{i})) ;/ ;out = string_add(out, string_join(pch, ", ")) ;out = string_add(out, " } }") ;return out ;/ ;/ ;{}{}uint8 PRIM_NAMES = { "uint8", "uint16", "uint32", "uint64", "uint", "int8", "int16", "int32", "int64", "int", "float32", "float64", "float", "bool", "void" } ;{}int PRIM_SIZES = { 1, 2, 4, 8, 8, 1, 2, 4, 8, 8, 4, 8, 8, 1, 8 } ;Type NO_TYPE = {0, "", "", {}, {}} /; is_primitive ({}uint8 t) [int] ;{}{}uint8 pn = PRIM_NAMES ;{}int ps = PRIM_SIZES /; loop (int i = 0; i < len pn) [i++] /; if (string_equate(pn{i}, t)) ;return ps{i} ;/ ;/ ;return -1 ;/ /; get_primitive (int i) [Type] ;{}{}uint8 pn = PRIM_NAMES ;{}int ps = PRIM_SIZES ;return {ps{i}, pn{i}, string_add("_", pn{i}), {}, {}} ;/ # Represents the place in memory where a variable is ;enum LOCATION [int] { REGISTER = 0, STACK = 1, LABEL = 2, LITERAL = 3 } # Represents a variable ;struct Variable { {}uint8 name, Type data_type, int location, loc_type } # Get common register name by index /; reg_by_num(int r) [{}uint8] /; if (r == 0) ;return "ax" ;; if (r == 1) ;return "bx" ;; if (r == 2) ;return "cx" ;; if (r == 3) ;return "dx" ;; if (r == 4) ;return "si" ;; if (r == 5) ;return "di" ;; if (r == -1) ;return "sp" ;; if (r == -2) ;return "bp" ;/ ;return int_to_string(r) ;/ # Get common register by common name and size /; reg_by_name_size ({}uint8 common, uint sz) [{}uint8] ;{}uint8 out = "" /; if (common{0} !< 'a') /; if (sz == 1) /; if(common{1} == 'x') ;common{1} = 'l' ;; else ;common.append('l') ;/ ;; else if (sz == 4) ;out.append('e') ;; else if (sz == 8) ;out.append('r') ;/ ;out = string_add(out, common) ;; else ;out.append('r') ;out = string_add(out, common) /; if (sz == 1) ;out.append('b') ;; else if (sz == 2) ;out.append('w') ;; else if (sz == 4) ;out.append('d') ;/ ;/ ;return out ;/ /; get_reg (int r, sz) [{}uint8] ;return reg_by_name_size(reg_by_num(r), sz) ;/ /; mov_by_size(int sz)[{}uint8] /; if (sz == 1) ;return "byte " ;; else if (sz == 2) ;return "word " ;; else if (sz == 4) ;return "dword " ;; else if (sz == 8) ;return "qword " ;/ ;return "" ;/ /; loc_from_str ({}uint8 str, offset, int sz) [{}uint8] ;{}uint8 pre = "" /; if (sz > 0) ;pre = mov_by_size(sz) ;/ ;return string_join( {pre, "[", str, offset, "]" }, "") ;/ /; strip_int({}int p) [{}int] ;{}int out = {} /; loop (int i = 0; i < len p - 1) [i++] ;out.append(p{i}) ;/ ;return out ;/ # Methods on variables assume that the rax, rdx, rsi, and rdi registers are fair game. # /; method Variable /; sprint [{}uint8] ;return string_join( { "{ ", self.name, ", ", self.data_type.sprint(), ", ", int_to_string(self.location), ", ", int_to_string(self.loc_type), " }" },"") ;/ /; norm_loc (int sz) [{}uint8] /; if (self.loc_type == LOCATION.LABEL) ;return loc_from_str(string_add("rel ", self.name), string_add(" + ", int_to_string(self.location)), sz) ;; else if (self.loc_type == LOCATION.REGISTER) /; if (self.is_ref()) ;return loc_from_str(get_reg(self.location, 8), "", sz) ;/ ;return get_reg(self.location, sz) ;; else if (self.loc_type == LOCATION.STACK) ;return string_join( { "[ rbp - ", int_to_string(self.location), " ]" }, "") ;; else if (self.loc_type == LOCATION.LITERAL) ;return int_to_string(self.location) ;/ ;/ /; norm_size [int] /; if (len (self.data_type.ptr_chain) > 1) ;return 8 ;; else if (len (self.data_type.ptr_chain) == 0) ;return self.data_type.s ;/ /; if (self.data_type.ptr_chain{0} == PTYPE.REFERENCE) ;return self.data_type.s ;/ ;return 8 ;/ # TODO: Match a type to another type if possible # this is the type inference engine /; match_types (Variable to_match, ~CompData data) [Variable] /; if (to_match.loc_type == LOCATION.LITERAL) ;return to_match ;/ ;return to_match ;/ /; norm_op ({}uint8 op, int sz, Variable v, ~CompData data) /; if (self.loc_type == LOCATION.LITERAL) ;v.norm_op(op, sz, self, data) ;; else ;v = self.match_types(v, data) /; if (self.loc_type == LOCATION.REGISTER || v.loc_type == LOCATION.REGISTER) ;data`.csec = string_join( { data`.csec, "\t", op, " ", self.norm_loc(sz), ", ", v.norm_loc(sz), "\n" }, "") ;; else ;data`.csec = string_join( { data`.csec, "\tmov ", get_reg(0, sz), ", ", v.norm_loc(sz), "\n", "\t", op, " ", self.norm_loc(sz), ", ", get_reg(0, sz), "\n" }, "") ;/ ;/ ;/ /; is_ref [bool] ;int s = len (self.data_type.ptr_chain) /; if (s > 0) ;return self.data_type.ptr_chain{s - 1} == PTYPE.REFERENCE ;/ ;return false ;/ /; is_prim [bool] ;return len(self.data_type.ptr_chain) > 1 || is_primitive(self.data_type.name) !< 0 ;/ /; strip_one (~CompData data) ;data`.csec = string_join( { data`.csec, "\tmov rsi, [rsi]\n" }, "") ;self.data_type.ptr_chain = strip_int(self.data_type.ptr_chain) ;/ /; strip_refs (~CompData data) [Variable] ;Variable out = {"#ref", self.data_type, 4, LOCATION.REGISTER} /; if (self.loc_type == LOCATION.REGISTER) ;data`.csec = string_join( { data`.csec, "\tmov rsi, ", get_reg(self.location, 8), "\n" }, "") ;; else ;data`.csec = string_join( { data`.csec, "\tlea rsi, ", self.norm_loc(8), "\n" }, "") ;out.data_type.ptr_chain.append(PTYPE.REFERENCE) ;/ ;int pc = len (out.data_type.ptr_chain) /; loop (pc > 1) [pc = len (out.data_type.ptr_chain)] /; if (out.data_type.ptr_chain{pc - 1} == PTYPE.REFERENCE) ;out.strip_one(data) ;; else ;break ;/ ;/ ;return out ;/ # functions that do work on this variable /; add (Variable v, ~CompData data) /; if (self.loc_type == LOCATION.LITERAL && v.loc_type == LOCATION.LITERAL) ;self.location = self.location + v.location ;; else ;self.norm_op("add", self.norm_size(), v, data) ;/ ;/ /; sub (Variable v, ~CompData data) /; if (self.loc_type == LOCATION.LITERAL && v.loc_type == LOCATION.LITERAL) ;self.location = self.location - v.location ;; else ;self.norm_op("sub", self.norm_size(), v, data) ;/ ;/ /; or (Variable v, ~CompData data) /; if (self.loc_type == LOCATION.LITERAL && v.loc_type == LOCATION.LITERAL) ;self.location = self.location | v.location ;; else ;self.norm_op("or", self.norm_size(), v, data) ;/ ;/ /; and (Variable v, ~CompData data) /; if (self.loc_type == LOCATION.LITERAL && v.loc_type == LOCATION.LITERAL) ;self.location = self.location & v.location ;; else ;self.norm_op("and", self.norm_size(), v, data) ;/ ;/ /; xor (Variable v, ~CompData data) /; if (self.loc_type == LOCATION.LITERAL && v.loc_type == LOCATION.LITERAL) ;self.location = self.location ^ v.location ;; else ;self.norm_op("xor", self.norm_size(), v, data) ;/ ;/ /; not (Variable v, ~CompData data) /; if (self.loc_type == LOCATION.LITERAL && v.loc_type == LOCATION.LITERAL) ;self.location = !v.location ;; else if (string_equate(v.data_type.name, "bool") && len (v.data_type.ptr_chain) == 0) ;self.xor({"#literal", get_primitive(is_primitive("bool")), 1, LOCATION.LITERAL}, data) ;; else ;v = self.match_types(v, data) ;self.set(v, data) ;data`.csec = string_join( { data`.csec, "\tnot ", self.norm_loc(self.norm_size()), "\n" }, "") ;/ ;/ /; cmp (Variable v, ~CompData data) /; if (self.loc_type == LOCATION.LITERAL && v.loc_type == LOCATION.LITERAL) /; if (self.location == v.location) ;self.location = 1 ;; else ;self.location = 0 ;/ ;; else ;self.norm_op("add", self.norm_size(), v, data) ;/ ;/ /; negative (Variable v, ~CompData data) ;int sz = self.norm_size() /; if (v.loc_type == LOCATION.LITERAL) ;data`.csec = string_join( { data`.csec, "\tmov ", mov_by_size(sz), self.norm_loc(sz), ", ", int_to_string(v.location), "\n" }, "") ;; else ;v = self.match_types(v, data) ;data`.csec = string_join( { data`.csec, "\tmov ", get_reg(0, sz), ", ", v.norm_loc(sz), "\n", "\tnot ", get_reg(0, sz), "\n", "\tmov ", self.norm_loc(sz), ", ", get_reg(0, sz), "\n" }, "") ;/ ;/ /; ax_compute ({}uint8 op, int sz, Variable v, ~CompData data, int keep) /; if (self.loc_type == LOCATION.LITERAL) ;v.ax_compute(op, sz, self, data) ;; else ;v = self.match_types(v, data) /; if (self.data_type.name{0} == 'i') ;op = string_add("i", op) ;/ /; if (self.loc_type !== LOCATION.REGISTER && v.loc_type !== LOCATION.REGISTER) ;data`.csec = string_join( { data`.csec, "\t", op, " ", self.norm_loc(sz), v.norm_loc(sz), "\n" }, "") ;; else ;data`.csec = string_join( { data`.csec, "\tmov ", get_reg(0, sz), ", ", v.norm_loc(sz), "\n", "\t", op, " ", self.norm_loc(sz), "\n", "\tmov ", self.norm_loc(sz), ", ", get_reg(keep, sz), "\n" }, "") ;/ ;/ ;/ /; div (Variable v, ~CompData data) /; if (self.loc_type == LOCATION.LITERAL && v.loc_type == LOCATION.LITERAL) ;self.location = self.location / v.location ;; else ;self.ax_compute("div", self.norm_size(), v, data, 0) ;/ ;/ /; mod (Variable v, ~CompData data) /; if (self.loc_type == LOCATION.LITERAL && v.loc_type == LOCATION.LITERAL) ;self.location = self.location % v.location ;; else ;self.ax_compute("div", self.norm_size(), v, data, 3) ;/ ;/ /; mul (Variable v, ~CompData data) /; if (self.loc_type == LOCATION.LITERAL && v.loc_type == LOCATION.LITERAL) ;self.location = self.location * v.location ;; else ;self.ax_compute("mul", self.norm_size(), v, data, 0) ;/ ;/ # Todo: Make sure this works well. /; set (Variable v, ~CompData data) ;int sz = self.norm_size() ;v = self.match_types(v, data) /; if (self.loc_type == LOCATION.LITERAL && v.loc_type == LOCATION.LITERAL) ;self.location = v.location ;; else if (self.is_prim()) /;if (self.is_ref() && v.is_ref()) ;data`.csec = string_join( { data`.csec, "\tmov ", get_reg(4, sz), ", ", v.norm_loc(sz), "\n", "\tmov ", self.norm_loc(sz), ", ", get_reg(4, sz), "\n" }, "") ;; else ;data`.csec = string_join( { data`.csec, "\tmov ", self.norm_loc(sz), ", ",v.norm_loc(sz), "\n" }, "") ;/ ;; else /; if (self.is_ref()) ;data`.csec = string_join( { data`.csec, "\tmov rdi, ", self.norm_loc(8), "\n" }, "") ;; else ;data`.csec = string_join( { data`.csec, "\tlea rdi, ", self.norm_loc(8), "\n" }, "") ;/ /; if (v.is_ref()) ;data`.csec = string_join( { data`.csec, "\tmov rdi, ", v.norm_loc(8), "\n" }, "") ;; else ;data`.csec = string_join( { data`.csec, "\tlea rdi, ", v.norm_loc(8), "\n" }, "") ;/ ;data`.csec = string_join( { data`.csec, "\tmov rcx, ", int_to_string(sz), "\n", "\trep movsb\n" }, "") ;/ ;/ /; move_register (int new_reg, ~CompData data) ;int sz = self.norm_size() ;data`.csec = string_join( { data`.csec, "\tmov ", get_reg(new_reg, sz), ", ", get_reg(self.location, sz), "\n" }, "") ;self.location = new_reg ;/ /; ref (Variable to_ref, ~CompData data) ;int l = len (to_ref.data_type.ptr_chain) /; if (to_ref.is_ref()) ;to_ref.data_type.ptr_chain{l - 1} = PTYPE.POINTER ;self.set(to_ref, data) ;; else if (to_ref.loc_type !== LOCATION.REGISTER && to_ref.loc_type !== LOCATION.LITERAL) ;data`.csec = string_join( { data`.csec, "\tlea rsi, ", to_ref.norm_loc(0), "\n", "\tmov ", self.norm_loc(8), ", rsi\n" }, "") ;; else ;log_err(string_add("Failure to create reference from register or literal value ", to_ref.sprint())) ;/ ;/ /; deref (~CompData data) [Variable] ;Variable out = self.strip_refs(data) ;int opc = len (out.data_type.ptr_chain) /; if (opc == 0) ;log_err("Can not deref a variable that is not a pointer (ERR: SNPTRC)") ;/ ;out.data_type.ptr_chain{opc - 1} = PTYPE.REFERENCE ;return out ;/ /; member ({}uint8 name, ~CompData data) [Variable] ;Variable out = self.strip_refs(data) ;int accum = 0 ;int i = 0 /; loop(i < len (out.data_type.members)) [i++] /; if (string_equate(out.data_type.members{i}.name, name)) ;break ;/ ;accum = accum + out.data_type.members{i}.data_type.s ;/ ;out.data_type = out.data_type.members{i}.data_type ;out.data_type.ptr_chain.append(PTYPE.REFERENCE) ;data`.csec = string_join( { data`.csec, "\tadd rsi, ", int_to_string(accum), "\n" }, "") ;return out ;/ /; index (Variable i, ~CompData data) [Variable] ;Variable out = self.strip_refs(data) ;int sz = out.norm_size() ;int opc = len (out.data_type.ptr_chain) ;bool ts_arr = out.data_type.ptr_chain{opc - 1} == PTYPE.ARRAY ;Variable t = {"#tmp", a.data_type, 4, LOCATION.REGISTER} /; if (ts_arr) ;data`.csec = string_join( { data`.csec, "\tadd rsi, 8\n" }, "") ;/ /; if (i.loc_type == LOCATION.LITERAL && i.location > 0) ;data`.csec = string_join( { data`.csec, "\tlea rsi, ", loc_from_str("rsi", string_add(" + ", int_to_string(sz * i)), 0), "\n" }, "") ;; else if (i.loc_type == LOCATION.REGISTER) ;data`.csec = string_join( { data`.csec, "\tlea rsi, ", loc_from_str("rsi", string_add(" + ", int_to_string(sz * i)), 0), "\n" }, "") ;; else if (i.loc_type == LOCATION.LABEL || i.loc_type == LOCATION.STACK) ;Variable t2 = {"#tmp", get_primitive(is_primitive("uint")), 5, LOCATION.REGISTER} ;t2.set(i, data) ;data`.csec = string_join( { data`.csec, "\tlea rsi, [rsi + rdi * ", int_to_string(sz), "]\n" }, "") ;/ ;return out.deref(data) ;/ /; length_of (Variable a, ~CompData data) ;a.data_type.name = "uint" ;a.data_type.s = 8 ;a.data_type.ptr_chain = {PTYPE.REFERENCE} ;self.set(a, data) ;/ # Uses rax, does not resolve any ending state after function returns /; call ({}uint8 name, ~CompData data) /; if (self.is_ref()) ;data`.csec = string_join( { data`.csec, "\tmov rax, ", self.norm_loc(8), "\n" }, "") ;; else ;data`.csec = string_join( { data`.csec, "\tlea rax, ", self.norm_loc(8), "\n" }, "") ;/ ;data`.csec = string_join( { data`.csec, "\tcall ", self.data_type.mod_name, ".", name, "\n" }, "") ;/ ;/ ;struct Scope { int num, c, ~Scope parent, {}uint8 name, {}Variable vars } /; method Scope /; is_cf [bool] /;if (len(self.name) < 1) ;return false ;/ ;return self.name{0} == '#' ;/ /; cf_type ({}uint8 cf) [bool] ;{}{}uint8 split = string_split(self.name, '_') /; if (len split !> 1) ;return false ;/ ;return string_equate(split{0}, string_add("#", cf)) ;/ /; full_label [{}uint8] ;{}uint8 out = "" /; if (self.is_cf()) ;out = self.parent`.full_label() ;/ ;out = string_add(out, self.name) ;return out ;/ /; get_size [int] ;int out = 0 /; loop (int i = 0; i < len (self.vars)) [i++] ;out = out + self.vars{i}.norm_size() ;/ ;return out ;/ /; next_register [int] ;int out = 8 /; if (self.is_cf()) ;out = self.parent`.next_register() ;/ /; loop (int i = 0; i < len (self.vars) && out < 16) [i++] /; if (self.vars{i}.loc_type == LOCATION.REGISTER) ;out++ ;/ ;/ /; if (out > 15) ;out = -1 ;/ ;return out ;/ /; get_stack [int] ;int out = 0 /; loop (int i = 0; i < len (self.vars)) [i++] /; if (self.vars{i}.loc_type == LOCATION.STACK) ;out = out + self.vars{i}.norm_size() ;/ ;/ ;return out ;/ /; get_full_stack [int] ;int out = 0 /; if (self.is_cf()) ;out = self.parent`.get_full_stack() ;/ /; loop (int i = 0; i < len (self.vars)) [i++] /; if (self.vars{i}.loc_type == LOCATION.STACK) ;out = out + self.vars{i}.norm_size() ;/ ;/ ;return out ;/ /; next_loc (Type t) [int] /; if (is_primitive(t.name) !< 0 || len (t.ptr_chain) > 0) ;log_debug("Next reg") ;return self.next_register() ;/ ;return -1 ;/ /; begin_scope (~CompData out) ;int reg = 8 ;{}uint8 intro = "\tpush rbp\n\tlea rbp, [rsp + 8]\n\tpush r8\n\tpush r9\n\tpush r10\n\tpush r11\n\tpush r12\n\tpush r13\n\tpush r14\n\tpush r15\n" ;out`.csec = string_add(out`.csec, intro) ;/ /; end_scope (~CompData out) ;{}uint8 outro = "\tlea rsp, [rbp - 72]\n\tpop r15\n\tpop r14\n\tpop r13\n\tpop r12\n\tpop r11\n\tpop r10\n\tpop r9\n\tpop r8\n\tpop rbp\n" ;out`.csec = string_add(out`.csec, outro) ;/ /; scope_cleanup (~CompData out) ;uint sz_to_clean = 0 /; loop (int i = 0; i < len (self.vars)) /; if (self.vars{i}.loc_type == LOCATION.STACK) ;sz_to_clean = sz_to_clean + self.vars{i}.s ;/ ;/ /; if (sz_to_clean > 0) ;out`.csec = string_add(out`.csec, string_add("\tadd rsp, ", int_to_string(sz_to_clean))) ;/ ;/ /; scope_start_label [{}uint8] ;return string_add(self.full_label(), "_start") ;/ /; scope_rep_label [{}uint8] ;return string_add(self.full_label(), "_rep") ;/ /; scope_end_label [{}uint8] ;return string_add(self.full_label(), "_end") ;/ /; new_sub_cf ({}uint8 cf) [Scope] ;cf = string_add("#", cf) ;cf.append('_') ;cf = string_add(cf, int_to_string(self.num)) ;self.num++ ;return {0, 0, ~self, cf, {}} ;/ /; get_continue (uint i) [{}uint8] ;~Scope top = ~self /; loop (i > 0 || top`.cf_type("")) ;top = top`.parent /; if (!(top`.cf_type(""))) ;i = i - 1 ;/ ;/ ;/ /; get_break (uint i) [{}uint8] ;~Scope top = ~self /; loop (i > 0 || top`.cf_type("")) ;top = top`.parent /; if (!(top`.cf_type(""))) ;i = i - 1 ;/ ;/ ;/ /; new_var (Type t, {}uint8 name, ~CompData out) ;Variable new = {name, t, 0, 0} ;log_debug(string_add("Creating new variable ", new.sprint())) /; if (self.next_loc(t) !< 0) ;new.loc_type = LOCATION.REGISTER ;new.location = self.next_loc(t) ;; else ;new.loc_type = LOCATION.STACK ;new.location = self.get_full_stack() + new.norm_size() ;out`.csec = string_join( { out`.csec, "\tsub rsp, ", int_to_string(new.norm_size()), "\n" }, "") ;/ ;self.vars.append(new) ;/ /; find_var ({}{}uint8 artifact, ~Module current) [Variable] /; loop (int i = 0; i < len (self.vars)) [i++] /; if (string_equate(self.vars{i}.name, artifact{0})) ;return self.vars{i} ;/ ;/ /; if (!(self.is_cf())) ;return current`.find_def(artifact) ;/ ;return self.parent`.find_var(artifact, current) ;/ /; find_reg_variable (int reg) [~Variable] /; loop (int i = 0; i < len (self.vars)) [i++] /; if (self.vars{i}.loc_type == LOCATION.REGISTER && self.vars{i}.location == reg) ;return ~(self.vars{i}) ;/ ;/ /; if (!(self.is_cf())) ;tnsl.io.print(reg) ;log_err("Can't move variable to stack as it does not exist in the current context") ;/ ;return self.parent`.find_reg_variable(reg) ;/ /; move_to_stack (int reg, ~CompData out) [Variable] ;int last_var = self.next_register() /; if (last_var < 0) ;last_var = 16 ;/ /; if (reg < 8 || reg > last_var - 1) ;tnsl.io.println(reg) ;log_err("Can't move a register to stack as it is not in scope.") ;/ ;log_debug(string_join( { "Attempting to move variable at register ", int_to_string(reg), " to stack. last_var = ", int_to_string(last_var) }, "")) ;~Variable rv = self.find_reg_variable(reg) ;Variable copy = {rv`.name, rv`.data_type, 0, 0} ;copy.loc_type = LOCATION.STACK ;copy.location = self.get_full_stack() + copy.norm_size() ;out`.csec = string_join( { out`.csec, "\tsub rsp, ", int_to_string(copy.norm_size()), "\n" }, "") ;copy.set(rv`, out) ;rv` = copy /; if (reg < last_var) ;rv = self.find_reg_variable(last_var - 1) ;log_debug(string_join({ "Moving variable from ", int_to_string(last_var - 1), " to ", int_to_string(reg), ". ", "Variable name: ", rv`.name }, "")) ;rv`.move_register(reg, out) ;/ ;return copy ;/ /; next_const [{}uint8] /; if (self.is_cf()) ;return self.parent`.next_const() ;/ ;{}uint8 out = string_add(self.name, string_add("#const_", int_to_string(self.c))) ;self.c++ ;return out ;/ ;/ ;struct Function { {}uint8 name, {}Type inputs, outputs } ;struct Module { # Parent module ~Module parent, # Export functions or not bool exp, # Name of module {}uint8 name, # Types defined in this module {}Type types, # Variables defined in this module {}Variable defs, # Functions defined in this module {}Function functions, # Sub modules {}Module sub } /; method Module # Internal recursive function /; _find_type ({}{}uint8 artifact, int r) [~Type] /; if (len artifact !> r) ;return ~NO_TYPE ;/ /; if (len artifact - 1 > r) /; loop (int i = 0; i < len (self.sub)) [i++] /; if (string_equate(artifact{r}, self.sub{i}.name)) ;return self.sub{i}._find_type(artifact, r + 1) ;/ ;/ ;; else if (len artifact - 1 == r) /; loop (int i = 0; i < len (self.types)) [i++] /; if (string_equate(self.types{i}.name, artifact{r})) ;return ~(self.types{i}) ;/ ;/ ;/ /; if (string_equate(self.name, "")) ;Type nt = {0, artifact{len artifact - 1}, "", {}, {}} ;return ~nt ;/ ;~Module m = self.parent /; loop (r > 0) [r = r - 1] ;m = m.parent ;/ ;return m`._find_type(artifact, 0) ;/ # Consumer facing function /; find_type ({}{}uint8 artifact) [~Type] ;int p = is_primitive(artifact{0}) /; if (p !< 0) ;Type out = {p, artifact{0}, {}, {}, {}} ;return ~out ;/ ;return self._find_type(artifact, 0) ;/ /; _find_def ({}{}uint8 artifact, int r) [Variable] /; if (len artifact !> r) ;return {"", NO_TYPE, 0, 0} ;/ /; if (len artifact - 1 > r) /; loop (int i = 0; i < len (self.sub)) [i++] /; if (string_equate(artifact{r}, self.sub{i}.name)) ;log_debug(artifact{r}) ;return self.sub{i}._find_def(artifact, r + 1) ;/ ;/ ;; else if (len artifact - 1 == r) ;{}uint8 true_name = self.full_path() /; if (len true_name > 0) ;true_name.append('.') ;/ ;true_name = string_add(true_name, artifact{r}) /; loop (int i = 0; i < len (self.defs)) [i++] /; if (string_equate(self.defs{i}.name, true_name)) ;return self.defs{i} ;/ ;/ ;/ /; if (string_equate(self.name, "")) ;return {"", NO_TYPE, 0, 0} ;/ ;~Module m = self.parent /; loop (r > 0) [r = r - 1] ;m = m.parent ;/ ;return m`._find_def(artifact, 0) ;/ /; find_def ({}{}uint8 artifact) [Variable] ;return self._find_def(artifact, 0) ;/ /; _find_function ({}{}uint8 artifact, int r) [Variable] /; if (len artifact !> r) ;retirn {{}, "", 0, 0, 0} ;/ /; if (len artifact - 1 > r) /; loop (int i = 0; i < len (self.sub)) [i++] /; if (string_equate(artifact{r}, self.sub{i}.name)) ;return self._find_type(artifact, r + 1) ;/ ;/ ;/ /; loop (int i = 0; i < len (self.funcs)) [i++] /; if (string_equate(self.funcs{i}.name, artifact{r})) ;return self.funcs{i} ;/ ;/ ;return {{}, "", 0, 0, 0} ;/ /; find_function ({}{}uint8 artifact) [Variable] ;return _find_function(artifact, 0) ;/ /; _find_mod ({}{}uint8 artifact, int r) [~Module] /; if (len artifact !> r) ;return ~self ;/ /; if (len artifact - 1 > r) /; loop (int i = 0; i < len (self.sub)) [i++] /; if (string_equate(artifact{r}, self.sub{i}.name)) ;return self.sub{i}._find_mod(artifact, r + 1) ;/ ;/ ;; else if (len artifact - 1 == r) ;{}uint8 v1 = string_add("_#", artifact{r}), v2 = string_add("__#", artifact{r}) /; loop (int i = 0; i < len (self.defs)) [i++] /; if (string_equate(self.sub{i}.name, artifact{r}) ||string_equate(self.sub{i}.name, v1) || string_equate(self.sub{i}.name, v2)) ;return ~(self.sub{i}) ;/ ;/ ;/ /; if (string_equate(self.name, "")) ;return ~self ;/ ;~Module m = self.parent /; loop (r > 0) [r = r - 1] ;m = m.parent ;/ ;return m`._find_mod(artifact, 0) ;/ /; find_mod({}{}uint8 artifact) [~Module] ;return self._find_mod(artifact, 0) ;/ /; find_sub ({}uint8 s_mod) [~Module] ;{}uint8 v1 = string_add("_#", s_mod) ;{}uint8 v2 = string_add("__#", s_mod) /; loop (int i = 0; i < len (self.sub)) [i++] /; if (string_equate(self.sub{i}.name, s_mod) || string_equate(self.sub{i}.name, v1) || string_equate(self.sub{i}.name, v2)) ;return ~(self.sub{i}) ;/ ;/ ;return ~self ;/ /; full_path [{}uint8] /; if (string_equate(self.name, "")) ;return "" ;/ ;{}uint8 out = self.parent`.full_path() /; if (len out > 0) ;out = string_add(out, ".") ;/ ;out = string_add(out, self.name) ;return out ;/ ;/ ## ## Compiler funcs ## /; get_artifact (~{}Token tok, ~int cur) [{}{}uint8] ;{}{}uint8 out = {} ;out.append(tok`{cur`}.data) ;cur`++ /; loop (cur` < len tok` && tok`{cur`}.cmp(".")) [cur`++] /; if (tok`{cur` + 1}.type_is(TOKEN.DEFWORD)) ;out.append(tok`{cur` + 1}.data) ;cur`++ ;/ ;/ ;return out ;/ /; is_call(~{}Token tok, int i) [bool] ;get_artifact(tok, ~i) ;return tok`{i}.cmp("(") ;/ /; get_type (~{}Token tok, ~int cur, ~Module current) [Type] ;{}int ptr_chain = {} /; loop (cur` < len tok`) [cur`++] /; if (tok`{cur`}.cmp("{")) ;ptr_chain.append(PTYPE.ARRAY) ;cur`++ ;; else if (tok`{cur`}.cmp("~")) ;ptr_chain.append(PTYPE.POINTER) ;; else ;break ;/ ;/ ;~Type pout = current`.find_type(get_artifact(tok, cur)) ;Type out = pout` /; if (string_equate(out.name, "")) ;return out ;/ ;{}Type generics = {} /; if (tok`{cur`}.cmp("(")) ;int max = find_closing(tok, cur) ;cur`++ /; loop (cur` < max) [cur`++] ;generics.append(get_type(tok, cur, current)) ;/ ;/ # TODO: References ;out.ptr_chain = ptr_chain ;return out ;/ /; is_definition (~{}Token tok, ~int cur, ~Module current) [bool] ;int i = cur` ;Type t = get_type(tok, ~i, current) ;return tok`{i}.type_is(TOKEN.DEFWORD) && !string_equate(t.name, "") ;/ /; compile_file_def (~{}Token tok, ~int cur, ~Module current, ~CompData out) ;Type t = get_type(tok, cur, current) ;{}uint8 base = current`.full_path() /; if (len base > 0) ;base.append('.') ;/ /; loop (!(tok`{cur`}.cmp("\n"))) /; loop (tok`{cur`}.cmp(",")) ;cur`++ ;/ ;{}uint8 l = string_add(base, tok`{cur`}.data) ;Variable v = {l, t, 0, LOCATION.LABEL} ;current`.defs.append(v) /; if (current`.exp) ;out`.hsec = string_add(out`.hsec, "global ") ;out`.hsec = string_add(out`.hsec, l) ;out`.hsec.append('\n') ;/ ;l.append(':') ;l.append('\n') ;out`.dsec = string_add(out`.dsec, l) ;cur`++ /; if (tok`{cur`}.cmp("=")) ;cur`++ ;out`.dsec = string_add(out`.dsec, decompose_data(tok, cur, current, t)) ;cur`++ ;; else ;out`.dsec = string_add(out`.dsec, decompose_empty(current, t)) ;/ ;/ ;/ /; next_non_nl (~{}Token tok, int c) [int] /; if (len tok` !> c) ;return c ;/ /; loop (tok`{c}.cmp("\n")) [c++] ;/ ;return c ;/ /; parse_param_list (~{}Token tok, ~int cur, ~Module current) [{}Variable] ;{}Variable out = {} ;int max = find_closing(tok, cur) ;Type t = NO_TYPE /; loop (cur` = next_non_nl(tok, cur` + 1); cur` < max) [cur` = next_non_nl(tok, cur` + 1)] ;int nnl = next_non_nl(tok, cur` + 1) /; if (tok`{nnl}.cmp(",") || nnl == max) ;out.append({tok`{cur`}.data, t, 0, 0}) /; if (tok`{nnl}.cmp(",")) ;cur`++ ;/ ;; else ;t = get_type(tok, cur, current) ;cur` = cur` - 1 ;/ ;/ ;return out ;/ # Generates new type /; new_type (~{}Token tok, ~int cur, ~Module current) ;cur`++ ;Type out = {0, tok`{cur`}.data, "", {}, {}} ;out.mod_name = current`.full_path() /; if (len (out.mod_name) > 0) ;out.mod_name.append('.') ;/ ;out.mod_name = string_add(out.mod_name, "_#") ;out.mod_name = string_add(out.mod_name, out.name) ;current`.sub.append({current, current`.exp, string_add("_#", out.name), {}, {}, {}, {}}) /; loop (cur` < len tok`) [cur`++] /; if (tok`{cur`}.cmp("{")) ;break ;/ ;/ ;out.members = parse_param_list(tok, cur, current) /; loop (int i = 0; i < len (out.members)) [i++] ;log_debug(string_join({"[", out.members{i}.name, ":", out.members{i}.data_type.name, "]"}, "")) ;/ ;log_debug(string_add("Generated type ", string_add(out.name, string_add(":", out.mod_name)))) ;current`.types.append(out) ;/ /; decompose_empty (~Module current, Type t) [{}uint8] /; if (len (t.ptr_chain) > 0) ;return "\tdq 0\n" ;/ ;{}uint8 out = "\tdb 0" /; loop (int i = 1; i < t.s) [i++] ;out = string_add(out, ", 0") ;/ ;out.append('\n') ;return out ;/ # Used to take an array literal and make it into a label /; decompose_array (~{}Token tok, ~int cur, ~Module current, Type t) [{}uint8] ;int max = find_closing(tok, cur) ;{}uint8 arr = "" ;int alen = 0 /; loop (cur` = next_non_nl(tok, cur` + 1); cur` < max) [cur` = next_non_nl(tok, cur` + 1)] ;alen++ /; if (tok`{cur`}.cmp("{")) /; if (ptr_chain{0} == PTYPE.ARRAY) ;{}int ptr = {} /; loop (int i = 1; i < len (t.ptr_chain)) [i++] ;ptr.append(t.ptr_chain{i}) ;/ ;t.ptr_chain = ptr ;arr = string_add(arr, decompose_array(tok, cur, current, t)) ;cur` = next_non_nl(tok, cur` + 1) ;; else ;decompose_struct(tok, cur, current, t) ;cur` = next_non_nl(tok, cur` + 1) ;/ ;; else ;arr = string_add(arr, decompose_data(tok, cur, current, t)) ;cur`++ ;/ ;/ ;{}uint out = string_join( { "\tdq ", int_to_string(alen), "\n", arr, "\n" }, "") ;return out ;/ # Used to take a struct literal and make it into a label /; decompose_struct (~{}Token tok, ~int cur, ~Module current, Type t) [{}uint8] ;int max = find_closing(tok, cur) ;{}uint8 out = "" ;int m = 0 /; loop (cur` = next_non_nl(tok, cur` + 1); cur` < max) [cur` = next_non_nl(tok, cur` + 1)] /; if (tok`{cur`}.cmp("}")) ;break ;; else if (tok`{cur`}.cmp(",")) ;cur` = next_non_nl(tok, cur` + 1) ;/ ;tnsl.io.println(tok`{cur`}.data) ;out = string_add(out, decompose_data(tok, cur, current, t.members{m}.data_type)) ;m++ ;/ ;tnsl.io.println("o") /; if (m < len (t.members) - 1) /; loop (m < len (t.members)) [m++] ;out = string_add(out, decompose_empty(current, t.members{m})) ;/ ;/ ;return out ;/ /; declare_size(int sz) [{}uint8] ;{}uint8 out = "\tdb " /; if (sz == 2) ;out{2} = 'w' ;; if (sz == 4) ;out{2} = 'd' ;; if (sz == 8) ;out{2} = 'q' ;/ ;return out ;/ # Used to take data from a literal and make it into a label /; decompose_data (~{}Token tok, ~int cur, ~Module current, Type t) [{}uint8] /; if (tok`{cur`}.cmp("{")) /; if (len (t.ptr_chain) > 0) ;{}int ptr = {} /; loop (int i = 1; i < len (t.ptr_chain)) [i++] ;ptr.append(t.ptr_chain{i}) ;/ ;t.ptr_chain = ptr ;return decompose_array(tok, cur, current, t) ;; else ;return decompose_struct(tok, cur, current, t) ;/ ;; if (tok`{cur`}.type_is(TOKEN.LITERAL)) /; if (string_equate(t.name, "bool")) ;{}uint data = "0" /; if (!(tok`{cur`}.cmp("false"))) ;data = "1" ;/ ;return string_add(string_add(declare_size(t.s), data), "\n") ;/ /; if (tok`{cur`}.data{0} == '"') ;return string_join({ declare_size(8), int_to_string(len unquote_str(tok`{cur`}.data)), "\n", declare_size(1), tok`{cur`}.data, "\n"}, "") ;; else if (tok`{cur`}.data{0} == '\'') ;return string_join({ declare_size(1), tok`{cur`}.data, "\n"}, "") ;/ ;return string_add(string_add(declare_size(t.s), tok`{cur`}.data), "\n") ;/ ;return decompose_empty(current, t) ;/ # Compiles new enum for the file /; compile_enum (~{}Token tok, ~int cur, ~Module current, ~CompData out) ;cur`++ ;Type et = NO_TYPE ;{}uint8 name = "" /; if (tok`{cur`}.cmp("[")) ;cur`++ ;et = get_type(tok, cur, current) ;cur`++ ;; if (!(tok`{cur`}.cmp("{"))) ;name = tok`{cur`}.data ;cur`++ /; if (tok`{cur`}.cmp("[")) ;cur`++ ;et = get_type(tok, cur, current) ;cur`++ ;/ ;/ /; if (string_equate(et.name, "")) ;et = Primitives{3} ;/ /; loop (!(tok`{cur`}.cmp("{"))) [cur`++] ;/ ;cur`++ ;Module enum_mod = {current, current`.exp, string_add("__#", name), {}, {}, {}, {}} /; loop (cur` < len tok`) [cur`++] /; if (tok`{cur`}.cmp("}")) ;break ;/ /; if (tok`{cur`}.type_is(TOKEN.DEFWORD)) ;{}uint8 l = string_add(enum_mod.full_path(), ".") ;l = string_add(l, tok`{cur`}.data) /; if (current`.exp) ;out`.hsec = string_add(out`.hsec, "global ") ;out`.hsec = string_add(out`.hsec, l) ;out`.hsec.append('\n') ;/ ;Variable v = {l, et, 0, LOCATION.LABEL} ;enum_mod.defs.append(v) ;l.append(':') ;l.append('\n') ;cur` = cur` + 2 ;l = string_add(l, decompose_data(tok, cur, current, et)) ;out`.dsec = string_add(out`.dsec, l) ;/ ;/ ;current`.sub.append(enum_mod) ;/ # Generates opposite closing bracket /; closing_for (Token d) [{}uint8] /; if (d.cmp("(")) ;return ")" ;; else if (d.cmp("[")) ;return "]" ;; else if (d.cmp("{")) ;return "}" ;; else if (d.cmp("/;")) ;return ";/" ;/ ;log_err(string_add("Error, unrecognized delim: ", d.data)) ;/ # Finds closing bracket /; find_closing (~{}Token tok, ~int cur) [int] ;int bl = 0, p = 0, br = 0, c = 0 ;{}uint8 cl = closing_for(tok`{cur`}) /; loop (int i = cur` + 1; i < len tok`) [i++] /; if (bl == 0 && p == 0 && br == 0 && c == 0) /; if ((tok`{i}.cmp(";;") || tok`{i}.cmp(";:")) && string_equate(cl, ";/")) ;return i ;; else if (tok`{i}.cmp(cl)) ;return i ;/ ;/ /; if (tok`{i}.cmp("(")) ;p++ ;; else if (tok`{i}.cmp("[")) ;br++ ;; else if (tok`{i}.cmp("{")) ;c++ ;; else if (tok`{i}.cmp("/;")) ;bl++ ;/ /; if (tok`{i}.cmp(")")) ;p = p - 1 ;; else if (tok`{i}.cmp("]")) ;br = br - 1 ;; else if (tok`{i}.cmp("}")) ;c = c - 1 ;; else if (tok`{i}.cmp(";/") || tok`{i}.cmp(";:")) ;bl = bl - 1 ;/ ;/ ;return len tok` - 1 ;/ # Skips cur to the end of a struct /; skip_struct (~{}Token tok, ~int cur) /; loop (cur` < len tok`) [cur`++] /; if (tok`{cur`}.cmp("{")) ;cur` = find_closing(tok, cur) ;break ;/ ;/ ;/ # Counts number of components in a composite value /; count_comp_el (~{}Token tok, int start) [int] ;int max = find_closing(tok, ~start) ;int out = 0 /; loop (start++; start < max) [start++] /; if (tok`{start}.type_is(TOKEN.DELIMITER)) ;start = find_closing(tok, ~start) ;; else if (tok`{start}.cmp(",")) ;out++ ;/ ;/ ;return out ;/ # Priority # 0 - deref # 1 - get # 2 - ref # 3 - mul/div/mod # 4 - add/sub # 5 - bitwise # 6 - boolean # 7 - assignment /; priority (Token tok) [int] /; if (!(tok.type_is(TOKEN.AUGMENT))) ;return -1 ;/ /; if (tok.cmp(".")) ;return 1 ;; else if (len (tok.data) == 1) /; if (tok.cmp("`")) ;return 0 ;; else if (tok.cmp("~")) ;return 2 ;; else if (tok.cmp("*") || tok.cmp("/") || tok.cmp("%")) ;return 3 ;; else if (tok.cmp("-") || tok.cmp("+")) ;return 4 ;; else if (tok.cmp("&") || tok.cmp("|") || tok.cmp("^") || tok.cmp("!")) ;return 5 ;; else if (tok.cmp("<") || tok.cmp(">")) ;return 6 ;; else if (tok.cmp("=")) ;return 7 ;/ ;; else if (len (tok.data) == 2) /; if (tok.data{0} == tok.data{1}) /; if (tok.data{0} == '<' || tok.data{0} == '>') ;return 5 ;/ ;return 6 ;; else if (tok.data{1} == '=') ;return 7 ;; else if (tok.data{1} == '<' || tok.data{1} == '>') ;return 6 ;/ ;return 5 ;; else if (len (tok.data) == 3) ;return 6 ;/ ;return -1 ;/ /; _eval_dot (~{}Token tok, int start, max, ~CompData out, ~Module current, ~Scope scope, Type t, bool alt) [Variable] ;Variable wk ;{}{}uint8 art = {} /; loop (tok`{start}.type_is(TOKEN.DEFWORD) && start < max) [start++] ;art.append(tok`{start}.data) ;wk = scope`.find_var(art, current) /; if (!string_equate(wk.name, "")) ;start++ ;break ;/ /; if (tok`{start + 1}.cmp(".")) ;start++ ;; else ;start++ ;break ;/ ;/ /; if (string_equate(wk.name, "") || start !< max) ;return wk ;/ ;log_debug(string_add("Eval dot initial val: ", wk.sprint())) /; if (tok`{start}.cmp(".")) ;log_debug("Pre loop member") ;wk = wk.member(tok`{start + 1}.data, out) ;; else ;log_debug("Pre loop deref") ;wk = wk.deref(out) ;/ ;start = start + 2 /; loop (start < max) [start++] /; if (tok`{start}.cmp("`")) ;log_debug("Loop deref") ;wk = wk.deref(out) ;; else if (tok`{start}.cmp(".") && tok`{start + 1}.type_is(TOKEN.DEFWORD)) ;log_debug("Loop member") ;wk = wk.member(tok`{start + 1}.data, out) ;start++ ;/ ;/ /; if (alt) ;wk.move_register(2, out) ;; else ;wk.move_register(1, out) ;/ ;return wk ;/ /; _eval_call (~{}Token tok, int start, max, ~CompData out, ~Module current, ~Scope scope, Type t) [Variable] ;/ /; literal_variable ({}uint8 data, l, ~CompData out) [Variable] ;Variable v = {"#literal", NO_TYPE, 0, LOCATION.LITERAL} /; if (data{0} == '"') # TODO: String literals ;out`.dsec = string_join({ out`.dsec, l, ":\n", declare_size(8), int_to_string(len unquote_str(data)), "\n", declare_size(1), data, "\n"} , "") ;v.data_type = {1, "uint8", "", {POINTER.ARRAY}, {}} ;v.loc_type = LOCATION.LABEL ;v.name = l ;; else if (data{0} == '\'') ;v.data_type = {1, "uint8", "", {}, {}} ;v.location = unqote_char(tok`{start}.data) ;; else if (string_equate(data, "true")) ;v.data_type = {1, "bool", "", {}, {}} ;v.location = 1 ;; else if (string_equate(data, "false")) ;v.data_type = {1, "bool", "", {}, {}} ;v.location = 0 ;; else ;v.data_type = {8, "int", "", {}, {}} ;v.location = string_to_int(data) ;/ ;return v ;/ # FIXME: # Need to impliment in place solving # Need to impliment auto typing /; _eval_value(~{}Token tok, int start, max, ~CompData out, ~Module current, ~Scope scope, Type t, bool alt) [Variable] /; if (start == max - 1) /; if (tok`{start}.type_is(TOKEN.LITERAL)) ;{}uint8 l = current`.full_path() /; if (len l > 0) ;l.append('.') ;/ ;l = string_add(l, scope`.next_const()) ;return literal_variable(tok`{start}.data, l, out) ;/ ;/ ;int first = -1, pr = -1, pa = -1 /; loop (int i = start; i < max) [i++] /; if (tok`{i}.type_is(TOKEN.AUGMENT) && priority(tok`{i}) !< pr) ;first = i ;pr = priority(tok`{i}) ;; else if (tok`{i}.type_is(TOKEN.DELIMITER)) ;pa = i ;i = find_closing(tok, ~i) ;/ ;/ # This is all kinda garbage, to fix. /; if (pr == -1) ;tnsl.io.println("scope var") ;return scope`.find_var( { tok`{start}.data }, current ) ;; else if (is_call(tok, start)) ;tnsl.io.println("call") ;return _eval_call(tok, start, max, out, current, scope, t, loc) ;; else if (pr == 0 || pr == 1) ;tnsl.io.println("dot") ;return _eval_dot(tok, start, max, out, current, scope, t, alt) ;/ ;Variable s1, s2 /; if (first == start) ;s1 = _eval_value(tok, first + 1, max, out, current, scope, t, alt) ;; else if (first == max - 1) ;s1 = _eval_value(tok, start, first, out, current, scope, t, alt) ;; else ;s1 = _eval_value(tok, start, first, out, current, scope, t, alt) /; if (tok`{first}.cmp("=")) ;t = s1.data_type ;/ ;s2 = _eval_value(tok, first + 1, max, out, current, scope, t, !alt) ;log_debug(string_add("Calculated s2 as ", s2.name)) ;/ ;log_debug(string_add("Calculated s2 as ", s1.name)) /; if (tok`{first}.cmp("=")) ;s1.set(s2, out) ;return s1 ;/ ;log_debug(string_join( { "_eval_value called with following type info:", t.sprint() }, " ")) ;Variable wk = {"#wk", t, 1, LOCATION.REGISTER} /; if (alt) ;wk.location = 2 ;/ /; if (tok`{first}.cmp("+")) ;wk.set(s1, out) ;wk.add(s2, out) ;; else if (tok`{first}.cmp("-")) /; if (first == start) ;wk.negative(s1, out) ;return wk ;/ ;wk.set(s1, out) ;wk.sub(s2, out) ;; else if (tok`{first}.cmp("|")) ;wk.set(s1, out) ;wk.mul(s2, out) ;; else if (tok`{first}.cmp("&")) ;wk.set(s1, out) ;wk.mul(s2, out) ;; else if (tok`{first}.cmp("^")) ;wk.set(s1, out) ;wk.mul(s2, out) ;; else if (tok`{first}.cmp("*")) ;wk.set(s1, out) ;wk.mul(s2, out) ;; else if (tok`{first}.cmp("*")) ;wk.set(s1, out) ;wk.mul(s2, out) ;; else if (tok`{first}.cmp("/")) ;wk.set(s1, out) ;wk.div(s2, out) ;; else if (tok`{first}.cmp("%")) ;wk.set(s1, out) ;wk.mod(s2, out) ;; else if (tok`{first}.cmp("~")) /; if (!(s1.is_ref()) && s1.loc_type == LOCATION.REGISTER) ;s1 = scope`.move_to_stack(s1.location, out) ;/ ;wk.ref(s1, out) ;; else if (tok`{first}.cmp("!")) ;wk.not(s1, out) ;/ ;return wk ;/ # ALWAYS put the value in rax /; eval_value (~{}Token tok, ~int cur, ~CompData out, ~Module current, ~Scope scope, Type t, bool save) ;int end = cur` /; loop (end < len tok`) [end++] /; if (tok`{end}.cmp(",") || tok`{end}.cmp("\n") || tok`{end}.cmp(";") || tok`{end}.cmp(";/")) ;break ;; else if (tok`{end}.type_is(TOKEN.DELIMITER)) ;end = find_closing(tok, ~end) ;/ ;/ ;Variable val = _eval_value(tok, cur`, end, out, current, scope, t, false) /; if (save) ;Variable set = {"#tmp", t, 0, LOCATION.REGISTER} ;set.set(val, out) ;/ ;cur` = end ;/ # FIXME: # Need to find type of definition, then add all definitions to the current scope, while evaluating the # Value (if any) to store in them /; eval_def (~{}Token tok, ~int cur, ~CompData out, ~Module current, ~Scope scope) ;Type t = get_type(tok, cur, current) /; loop (tok`{cur`}.type_is(TOKEN.DEFWORD)) ;scope`.new_var(t, tok`{cur`}.data, out) ;eval_value(tok, cur, out, current, scope, t, false) /; if (tok`{cur`}.cmp(",")) ;cur` = next_non_nl(tok, cur` + 1) ;/ ;/ ;/ /; statement_list(~{}Token tok, int start, end, ~Module current, ~CompData out, ~Scope parent) ;/ # FIXME: # Need to impl: # cf block scoping and contextual keywords such as # continue, break, and return /; _compile_block (~{}Token tok, ~int cur, ~Module current, ~CompData out, ~Scope parent) ;int max = find_closing(tok, cur) ;Scope cf = parent` /; loop (cur`++; cur` < max) [cur`++] /; if (tok`{cur`}.type_is(TOKEN.KEYWORD)) ;cf = parent`.new_sub_cf(tok`{cur`}.data) ;; else if (tok`{cur`}.cmp("(") || tok`{cur`}.cmp("[")) ;int psl = find_closing(tok, cur) ;statement_list(tok, cur`, psl, current, out, ~cf) ;cur` = psl ;; else ;break ;/ ;/ /; loop (cur`++; cur` < max) [cur`++] ;/ ;/ /; compile_block (~{}Token tok, ~int cur, ~Module current, ~CompData out) ;Scope root = {0, 0, 0, "", {}} ;int max = find_closing(tok, cur) ;bool r = false, m = false, returned = false ;Type ret = NO_TYPE /; loop (cur`++; cur` < max && !m) [cur`++] /; if (tok`{cur`}.type_is(TOKEN.DEFWORD)) ;root.name = tok`{cur`}.data ;; if (tok`{cur`}.type_is(TOKEN.KEYWORD)) /; if (tok`{cur`}.cmp("raw")) ;r = true ;; else if (tok`{cur`}.cmp("method")) ;m = true ;tnsl.io.println(tok`{cur` + 1}.data) ;tnsl.io.println(current`.sub{0}.name) ;current = current`.find_sub(tok`{cur` + 1}.data) ;; else ;tnsl.io.print("Keyword ") ;tnsl.io.print(tok`{cur`}.data) ;tnsl.io.println(" not impl on mod level blocks") ;tok`{e}.cmp() ;/ ;; if (tok`{cur`}.cmp("(")) ;root.vars = parse_param_list(tok, cur, current) ;; if (tok`{cur`}.cmp("[")) ;cur`++ ;ret = get_type(tok, cur, current) ;; if (tok`{cur`}.cmp("\n")) ;break ;/ ;/ /; if (!m) ;{}uint8 l = "" /; if (!string_equate(current`.name, "")) ;l = string_add(l, current`.full_path()) ;l.append('.') ;/ ;l = string_add(l, root.name) ;root.name = l /; if (current`.exp) ;out`.hsec = string_add(out`.hsec, "global ") ;out`.hsec = string_add(out`.hsec, l) ;out`.hsec.append('\n') ;/ ;out`.csec = string_add(out`.csec, l) ;out`.csec = string_add(out`.csec, ":\n") /; if (!r) ;root.begin_scope(out) ;/ ;/ /; loop (cur` = next_non_nl(tok, cur` + 1); cur` < max && !returned) [cur` = next_non_nl(tok, cur` + 1)] /; if (tok`{cur`}.cmp("/;") || tok`{cur`}.cmp(";;")) ;tnsl.io.println("Block block") /; if (m) ;compile_block(tok, cur, current, out) ;; else ;_compile_block(tok, cur, current, out, ~root) ;/ /; if (tok`{cur`}.cmp(";;")) ;cur` = cur` - 1 ;/ ;; else if (tok`{cur`}.type_is(TOKEN.KEYWORD)) /; if (tok`{cur`}.cmp("return")) ;cur`++ ;eval_value(tok, cur, out, current, ~root, ret, true) ;root.end_scope(out) ;out`.csec = string_add(out`.csec, "\tret\n") ;returned = true ;; else if (tok`{cur`}.cmp("raw") && tok`{cur` + 1}.cmp("return")) /; if (!r) ;tnsl.io.println("Unable to perform a raw return from a non-raw block.") ;tok`{e}.cmp() ;/ ;cur` = cur` + 2 ;eval_value(tok, cur, out, current, ~root, ret, true) ;out`.csec = string_add(out`.csec, "\tret\n") ;returned = true ;; else if (tok`{cur`}.cmp("asm")) ;cur`++ ;out`.csec.append('\t') ;out`.csec = string_add(out`.csec, unquote_str(tok`{cur`}.data)) ;out`.csec.append('\n') ;; else ;tnsl.io.print("Keyword not impl: ") ;tnsl.io.println(tok`{cur`}.data) ;/ ;; else if (is_definition(tok, cur, current)) ;log_debug("Block def") ;eval_def(tok, cur, out, current, ~root) ;; else ;log_debug("Block val") ;eval_value(tok, cur, out, current, ~root, NO_TYPE, false) ;/ ;/ ;cur` = max /; if (!returned && !string_equate(ret.name, "")) ;tnsl.io.println("Block must return a value.") ;tok`{e}.cmp() ;/ /; if (!m && !returned) /; if (!r) ;root.end_scope(out) ;/ ;out`.csec = string_add(out`.csec, "\tret\n") ;/ ;/ # First pass on a module # Generates structs, enums, and submodules /; module_pass_one (~{}Token tok, ~int cur, ~Module current, Path f) ;int max = find_closing(tok, cur) ;Module new = {current, false, "", {}, {}, {}, {}} /; loop (cur`++; cur` < len tok`) [cur`++] /; if (tok`{cur`}.type_is(TOKEN.DEFWORD)) ;new.name = tok`{cur`}.data ;; else if (tok`{cur`}.cmp("export")) ;new.exp = true ;; else if (!(tok`{cur`}.cmp("module"))) ;break ;/ ;/ /; loop (cur` < max) [cur`++] ;tnsl.io.print(".") /; if (tok`{cur`}.cmp(":")) ;tnsl.io.println("INCLUDE") /; if (tok`{cur` + 2}.type_is(TOKEN.LITERAL)) ;compile_file_pass_one(f.relative(unquote_str(tok`{cur` + 2}.data)), ~new) ;cur` = cur` + 2 ;/ ;continue ;; else if (tok`{cur`}.cmp("/;") || tok`{cur`}.cmp(";;")) /; if (tok`{cur` + 1}.cmp("export") || tok`{cur` + 1}.cmp("module")) ;module_pass_one(tok, cur, ~new, f) ;/ ;; else if (tok`{cur`}.cmp("struct")) ;new_type(tok, cur, ~new) ;/ ;/ ;current`.sub.append(new) ;/ # Second pass on a module # Generates code and calls compile_file_second_pass if an include happens /; module_pass_two (~{}Token tok, ~int cur, ~Module current, ~CompData out, Path f) ;int max = find_closing(tok, cur) /; loop (cur`++; cur` < len tok`) [cur`++] /; if (tok`{cur`}.type_is(TOKEN.DEFWORD)) ;current = current`.find_sub(tok`{cur`}.data) ;; else if (!(tok`{cur`}.cmp("module")) && !(tok`{cur`}.cmp("export"))) ;break ;/ ;/ /; loop (cur` = next_non_nl(tok, cur`); cur` < max) [cur` = next_non_nl(tok, cur` + 1)] ;tnsl.io.print(".") /; if (tok`{cur`}.cmp(":")) ;tnsl.io.println("INCLUDE") /; if (tok`{cur` + 2}.type_is(TOKEN.LITERAL)) ;CompData tmp = compile_file_pass_two(f.relative(unquote_str(tok`{cur` + 2}.data)), current) ;out`.hsec = string_add(out`.hsec, tmp.hsec) ;out`.dsec = string_add(out`.dsec, tmp.dsec) ;out`.csec = string_add(out`.csec, tmp.csec) ;cur` = cur` + 2 ;/ ;continue ;; else if (tok`{cur`}.cmp("/;") || tok`{cur`}.cmp(";;")) ;log_debug("Mod block") /; if (tok`{cur` + 1}.cmp("export") || tok`{cur` + 1}.cmp("module")) ;module_pass_two(tok, cur, current, out, f) ;; else ;compile_block(tok, cur, current, out) ;/ ;; else if (tok`{cur`}.cmp("struct")) ;log_debug("Mod struct") ;skip_struct(tok, cur) ;; else if (tok`{cur`}.cmp("enum")) ;log_debug("Mod enum") ;compile_enum(tok, cur, current, out) ;; else if (is_definition(tok, cur, current)) ;log_debug("Mod def") ;compile_file_def(tok, cur, current, out) ;; else if (!(tok`{cur`}.cmp("\n"))) ;tnsl.io.println("Failed to recognize file-level statement") ;tok`{cur`}.print() ;break ;/ ;/ ;/ # First compiler pass on a file # Only creates structs, enums, and moduless /; compile_file_pass_one (Path f, ~Module current) ;{}Token tok = tokenize(f) ;tnsl.io.print("Number of tokens generated: ") ;tnsl.io.println(len tok) /; loop (int i = 0; i < len tok) [i++] ;tnsl.io.print(".") /; if (tok{i}.cmp(":")) ;tnsl.io.println("INCLUDE") /; if (tok{i + 2}.type_is(TOKEN.LITERAL)) ;CompData tmp = compile_file_pass_one(f.relative(unquote_str(tok{i + 2}.data)), current) ;i = i + 2 ;/ ;continue ;; else if (tok{i}.cmp("/;") || tok{i}.cmp(";;")) /; if (tok{i + 1}.cmp("export") || tok{i + 1}.cmp("module")) ;module_pass_one(~tok, ~i, current, f) ;/ ;; else if (tok{i}.cmp("struct")) ;new_type(~tok, ~i, current) ;/ ;/ ;/ /; size_struct (~Type t, ~Module m) ;int s = 0 /; loop (int i = 0; i < len (t`.members)) [i++] ;int p = is_primitive(t`.members{i}.data_type.name) /; if (len (t`.members{i}.data_type.ptr_chain) > 0) ;s = s + 8 ;; else if (p >== 0) ;s = s + p ;; else ;tnsl.io.println("STRUCT!!!!!!") ;{}{}uint8 artifact = { t`.members{i}.data_type.name } ;~Type tp = m`.find_type(artifact) /; if (tp`.s == 0) ;size_struct(tp, m) ;/ ;t`.members{i}.data_type = tp` ;s = s + tp`.s ;/ ;/ ;tnsl.io.println(string_add("Sized type ", t`.name)) ;t`.s = s ;/ # Regenerates struct sizes (with support for cyclical struct definitions) /; flush_structs (~Module m) /; loop (int i = 0; i < len (m`.types)) [i++] ;size_struct(~(m`.types{i}), m) ;/ /; loop (int i = 0; i < len (m`.sub)) [i++] ;flush_structs(~(m`.sub{i})) ;/ ;/ # Second pass of compiler # Does code generation, ignores structs and enums /; compile_file_pass_two (Path f, ~Module current) [CompData] ;CompData out = {"", "", ""} ;{}Token tok = tokenize(f) /; loop (int i = next_non_nl(~tok, 0); i < len tok) [i = next_non_nl(~tok, i+1)] ;tnsl.io.print(".") /; if (tok{i}.cmp(":")) ;tnsl.io.println("INCLUDE") /; if (tok{i + 2}.type_is(TOKEN.LITERAL)) ;CompData tmp = compile_file_pass_two(f.relative(unquote_str(tok{i + 2}.data)), current) ;out.hsec = string_add(out.hsec, tmp.hsec) ;out.dsec = string_add(out.dsec, tmp.dsec) ;out.csec = string_add(out.csec, tmp.csec) ;i = i + 2 ;/ ;continue ;; else if (tok{i}.cmp("/;") || tok{i}.cmp(";;")) ;log_debug("Root block") /; if (tok{i + 1}.cmp("export") || tok{i + 1}.cmp("module")) ;module_pass_two(~tok, ~i, current, ~out, f) ;; else ;compile_block(~tok, ~i, current, ~out) ;/ ;; else if (tok{i}.cmp("struct")) ;log_debug("File struct") ;skip_struct(~tok, ~i) ;; else if (tok{i}.cmp("enum")) ;log_debug("File enum") ;compile_enum(~tok, ~i, current, ~out) ;; else if (is_definition(~tok, ~i, current)) ;log_debug("File def") ;compile_file_def(~tok, ~i, current, ~out) ;; else if (tok{i}.cmp("asm")) ;log_debug("File asm") /; if (len (out.csec) == 0 && len (out.dsec) == 0) ;out.hsec = string_add(out.hsec, unquote_str(tok{i + 1}.data)) ;out.hsec.append('\n') ;; else ;out.dsec = string_add(out.dsec, unquote_str(tok{i + 1}.data)) ;out.dsec.append('\n') ;/ ;i++ ;; else if (!(tok{i}.cmp("\n"))) ;tnsl.io.println("Failed to recognize file-level statement") ;tok{i}.print() ;break ;/ ;/ ;tnsl.io.print("Generated code length: ") ;tnsl.io.println(len (out.hsec) + len (out.dsec) + len (out.csec)) ;return out ;/ # Starts the compiler on a given path /; compile_start (Path f) [{}uint8] ;{}uint8 out = "" ;Module root = {0, true, {}, {}, {}, {}, {}} ;compile_file_pass_one(f, ~root) ;flush_structs(~root) ;tnsl.io.println("First pass DONE") ;CompData data = compile_file_pass_two(f, ~root) ;tnsl.io.println("Second pass DONE") ;out = string_join({ data.hsec, "section .data\n", data.dsec, "section .text\n", data.csec}, "") ;return out ;/ ## ## Tokenizer funcs ## /; is_whitespace (uint8 c) [bool] ;return (c == '\n' || c == '\t' || c == ' ') ;/ ;{}uint8 MULTI_PARENS = "/;:#" ;{}uint8 PARENS = "()[]{}" ;{}uint8 RESERVED = "`~!%^&*()-+=[]{}|;:/?<>.,\"" ;{}uint8 AUGMENTS = "=~!<>&|^+-*/`." ;{}{}uint8 MULTI_AUGMENTS = { "~=", "`=", "%=", "^=", "&=", "*=", "!=", "|=", "/=", "==", "!==", "&&", "||", "^^", "<==", ">==", "!>", "!<", "<<", ">>", "!&", "!|", "!^" } ;{}{}uint8 KEYWORDS = { "len", "is", "if", "else", "loop", "continue", "break", "return", "method", "struct", "enum", "interface", "export", "module", "const", "static", "volatile", "raw", "extends", "override", "asm" } ;{}{}uint8 KEYTYPES = { "uint8", "uint16", "uint32", "uint64", "uint", "int8", "int16", "int32", "int64", "int", "float32", "float64", "float", "comp32", "comp64", "comp", "vect", "bool", "type", "void" } /; is_delimiter ({}uint8 str) [bool] /; if (len str > 2 || len str < 1) ;return false ;/ /; if (len str == 2) ;return string_contains(MULTI_PARENS, str{0}) && string_contains(MULTI_PARENS, str{1}) ;/ ;return string_contains(PARENS, str{0}) ;/ /; is_reserved ({}uint8 str) [bool] /; if (len str < 1) ;return false ;/ ;return string_contains(RESERVED, str{0}) ;/ /; is_augment ({}uint8 str) [bool] /; if (len str == 1) ;return string_contains(AUGMENTS, str{0}) ;/ ;return list_contains(MULTI_AUGMENTS, str) ;/ /; is_str_literal ({}uint8 str) [bool] /; if (string_equate(str, "\"") || string_equate(str, "'")) ;return true ;/ /; if (len str < 2) ;return false ;; else if (str{0} !== '\'' && str{0} !== '"') ;return false ;/ /; loop (int i = 1; i < len str) [i++] /; if (str{i} == '\\') ;i++ ;; else if (str{i} == str{0}) ;return i == len str - 1 ;/ ;/ ;return true ;/ /; is_num_literal ({}uint8 str) [bool] /; if (len str < 1) ;return false ;; if (len str == 1 && str{0} == '.') ;return false ;/ ;bool dec = false /; loop (int i = 0; i < len str) [i++] /; if (str{i} == '.') /; if (!dec) ;dec = true ;; else ;return false ;/ ;; else if (str{i} < '0' || str{i} > '9') ;return false ;/ ;/ ;return true ;/ /; is_literal({}uint8 str) [bool] ;return is_str_literal(str) || is_num_literal(str) || string_equate(str, "true") || string_equate(str, "false") ;/ /; gen_type (Token t) [int] /; if (t.cmp("\n") || t.cmp(",")) ;return TOKEN.SEPARATOR ;/ /; if (is_literal(t.data)) ;return TOKEN.LITERAL ;/ /; if (is_reserved(t.data)) /; if (is_delimiter(t.data)) ;return TOKEN.DELIMITER ;; else if (is_augment(t.data)) ;return TOKEN.AUGMENT ;/ ;; else if (list_contains(KEYWORDS, t.data)) ;return TOKEN.KEYWORD ;; else if (list_contains(KEYTYPES, t.data)) ;return TOKEN.KEYTYPE ;/ ;return TOKEN.DEFWORD ;/ /; break_token (Token current, uint8 to_append) [bool] /; if (is_literal(current.data)) ;current.data.append(to_append) ;return !(is_literal(current.data)) ;/ /; if (is_whitespace(to_append) || current.cmp("\n")) ;return true ;/ /; if (is_reserved(current.data)) /; if (is_reserved({to_append})) ;current.data.append(to_append) ;return gen_type(current) == TOKEN.DEFWORD ;/ ;return true ;; else if (is_reserved({to_append})) ;return true ;/ ;return false ;/ /; handle_comment (tnsl.io.File fd, ~Token current, ~int line) [bool] ;bool block = false /; if (current`.cmp("/")) ;block = true ;/ /; loop (int i = fd.read(); i !== -1) [i = fd.read()] /; if (i == '\n') ;line`++ /; if (!block) ;return true ;/ ;; else if (block && i == '#') ;i = fd.read() /; if (i == '/') ;current` = {0, line, ""} ;return false ;; else if (i == ';' || i == ':') ;current`.data.append(i) ;return false ;/ /; loop (i !== '\n' && i !== -1) [i = fd.read()] ;/ ;line`++ ;/ ;/ ;/ /; tokenize (Path f) [{}Token] ;{}Token out = {} ;tnsl.io.File fd = f.open_read() ;Token current = {0, 0, ""} ;int line = 1 /; loop (int i = fd.read(); i > -1) [i = fd.read()] /; if (i == '\r') ;continue ;/ /; if (i == '#' && (break_token(current, i) || gen_type(current) !== TOKEN.LITERAL)) ;bool ln = handle_comment(fd, ~current, ~line) /; if (ln) ;current.tokenType = gen_type(current) /; if (!(current.cmp(""))) ;out.append(current) ;/ ;out.append({TOKEN.SEPARATOR, line - 1, "\n"}) ;/ ;continue ;/ /; if (i == '\n' && (break_token(current, i) || gen_type(current) !== TOKEN.LITERAL)) ;tnsl.io.print(".") /; if (!(current.cmp("\n"))) ;current.tokenType = gen_type(current) /; if (!(current.cmp(""))) ;out.append(current) ;/ ;current = {TOKEN.SEPARATOR, line, ""} ;current.data.append(i) ;/ ;line++ ;; else if (break_token(current, i)) ;current.tokenType = gen_type(current) /; if (!(current.cmp(""))) ;out.append(current) ;/ ;current = {0, line, ""} /; if (!(is_whitespace(i))) ;current.data.append(i) ;/ ;; else ;current.data.append(i) ;/ ;/ ;tnsl.io.println("OK") /; if (!(current.cmp("")) && !(current.cmp("\n"))) ;current.tokenType = gen_type(current) ;out.append(current) ;/ ;fd.close() ;return out ;/ ## ## Main ## /; main ({}{}uint8 args) [int] ;log_debug("TNSLC version 0.0.1, built with debugging enabled") /; if (len args < 1) ;tnsl.io.println("Give me something to compile!") ;return 1 ;/ ;bool tokenize_only = len args > 1 ;{}{}uint8 fsplit = string_split(args{0}, '/') ;Path p = {{}, fsplit{len fsplit - 1}} /; loop (int i = 0; i < len fsplit - 1) [i++] ;p.path.append(fsplit{i}) ;/ ;tnsl.io.print("Path: ") ;tnsl.io.println(p.full_path()) ;{}uint8 code = "" /; if (!tokenize_only) ;code = compile_start(p) ;; else ;{}Token tok = tokenize(p) /; loop(int i = 0; i < len tok) [i++] ;tnsl.io.print(".") ;code = string_add(code, tok{i}.sprint()) ;/ ;tnsl.io.println("OK") ;/ ;p.name = string_add(p.name, ".asm") ;p.write(code) ;return 0 ;/