## ## LOG UTILITIES ## # Log levels: # 0 - Visual queues and errors only # 1 - Info (default) # 2 - Debugging information (useful for me, probably less for you) # 3 - Also logs the state changes of the log itself ;{}uint8 log_level = "2" ;{}uint8 log_mode = "single" /; log_state({}uint8 new_state) ;~{}uint8 l = ~log_mode /; if (!string_equate(new_state, log_mode)) ;tnsl.io.println("") /; if (string_to_int(log_level) > 2) ;tnsl.io.print("[TNSLC] [LOG]: Swapping to state [") ;tnsl.io.print(new_state) ;tnsl.io.println("]") ;/ ;/ ;l` = new_state ;/ /; log_err ({}uint8 msg) ;log_state("err") ;tnsl.io.print("[TNSLC] [ERR]: ") ;tnsl.io.println(msg) ;tnsl.exit() ;/ /; log_info ({}uint8 msg) /; if (string_to_int(log_level) > 0) ;log_state("info") ;tnsl.io.print("[TNSLC] [INFO]: ") ;tnsl.io.println(msg) ;/ ;/ /; log_vis ({}uint8 msg) ;log_state("vis") ;tnsl.io.print(msg) ;/ /; log_debug ({}uint8 msg) /; if (string_to_int(log_level) > 1) ;log_state("debug") ;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 ;/ /; if (str{1} !== '\\') ;return str{1} ;/ ;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' ;; else if (cmp == '\'') ;return '\'' ;/ ;/ /; 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 } /; method CompData /; add (CompData data) ;self.hsec = string_add(self.hsec, data.hsec) ;self.dsec = string_add(self.dsec, data.dsec) ;self.csec = string_add(self.csec, data.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) ;/ /; 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) ;/ /; 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 ;/ ;/ ## ## Tokenizer funcs ## /; is_whitespace (uint8 c) [bool] ;return (c == '\n' || c == '\t' || c == ' ') ;/ ;{}uint8 MULTI_PARENS = "/;:#" ;{}uint8 PARENS = "()[]{}" ;{}uint8 SEPS = "\n;:," ;{}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_separator ({}uint8 str) [bool] /; if (len str < 1) ;return false ;/ ;return string_contains(SEPS, 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 (is_separator(t.data)) ;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)) ;log_vis(".") /; 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) ;/ ;/ ;log_vis("OK\n") /; if (!(current.cmp("")) && !(current.cmp("\n"))) ;current.tokenType = gen_type(current) ;out.append(current) ;/ ;fd.close() ;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 ;/ /; size [int] /; loop (int i = 0; i < len(self.ptr_chain)) [i++] /; if (self.ptr_chain{i} !== PTYPE.REFERENCE) ;return 8 ;/ ;/ ;return self.s ;/ ;/ ;{}{}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 ;/ /; to_jmp({}uint8 cmp) [{}uint8] /; if (string_equate(cmp, "==")) ;return "\tje " ;; else if (string_equate(cmp, "!==")) ;return "\tjne " ;; else if (string_equate(cmp, "!<") || string_equate(cmp, ">==")) ;return "\tjge " ;; else if (string_equate(cmp, "!>") || string_equate(cmp, "<==")) ;return "\tjle " ;; else if (string_equate(cmp, ">")) ;return "\tjg " ;; else if (string_equate(cmp, "<")) ;return "\tjl " ;/ ;return "\tjnz " ;/ /; not_jmp({}uint8 cmp) [{}uint8] /; if (string_equate(cmp, "==")) ;return "\tjne " ;; else if (string_equate(cmp, "!==")) ;return "\tje " ;; else if (string_equate(cmp, "!<") || string_equate(cmp, ">==")) ;return "\tjl " ;; else if (string_equate(cmp, "!>") || string_equate(cmp, "<==")) ;return "\tjg " ;; else if (string_equate(cmp, ">")) ;return "\tjle " ;; else if (string_equate(cmp, "<")) ;return "\tjge " ;/ ;return "\tjz " ;/ # Methods on variables assume that the rax, rdx, rsi, and rdi registers are fair game. # ONLY USES RDI ON SOME ASSIGNMENTS. SAFE FOR BOOLEAN STORAGE /; 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 ;/ /; el_size [int] ;int index = len(self.data_type.ptr_chain) - 1 /; loop (index > 0 && self.data_type.ptr_chain{index} == PTYPE.REFERENCE) ;index-- ;/ ;bool arr = false /; loop (index !< 0) /; if (self.data_type.ptr_chain{index} !== PTYPE.REFERENCE) /; if (arr) ;return 8 ;/ ;arr = true ;index-- ;; else ;index-- ;/ ;/ ;return self.data_type.s ;/ # 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 ;; if (!(to_match.is_prim()) || (len(to_match.data_type.ptr_chain) > 0 && !(to_match.is_ref()))) ;return to_match ;/ ;Variable out = {"#match", self.data_type, 4, LOCATION.REGISTER} ;{}uint8 mov = "mov" /; if (self.data_type.name{0} == 'i' && out.norm_size() > to_match.norm_size()) ;mov = string_add(mov, "sx") /; if (out.norm_size() == 8 && to_match.norm_size() == 4) ;mov.append('d') ;/ ;; else if (self.data_type.name{0} == 'u' && out.norm_size() > to_match.norm_size() && out.norm_size() !== 8) ;mov = string_add(mov, "zx") ;; else ;return to_match ;/ ;data`.csec = string_join( { data`.csec, "\t", mov, " ", out.norm_loc(out.norm_size()), ", ", to_match.norm_loc(to_match.norm_size()), "\n" }, "") ;return out ;/ /; 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.data_type.ptr_chain{pc - 2} !== PTYPE.ARRAY) ;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_variable("true", "", data), 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 if (v.is_prim() && self.is_prim()) ;self.norm_op("cmp", 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" }, "") ;/ ;/ /; inc (~CompData data) /; if (self.loc_type == LOCATION.LITERAL) ;self.location++ ;; else ;data`.csec = string_join( { data`.csec, "\tinc ", self.norm_loc(self.norm_size()), "\n" }, "") ;/ ;/ /; dec (~CompData data) /; if (self.loc_type == LOCATION.LITERAL) ;self.location-- ;; else ;data`.csec = string_join( { data`.csec, "\tdec ", self.norm_loc(self.norm_size()), "\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 rsi, ", v.norm_loc(8), "\n" }, "") ;; else ;data`.csec = string_join( { data`.csec, "\tlea rsi, ", v.norm_loc(8), "\n" }, "") ;/ ;data`.csec = string_join( { data`.csec, "\tmov rcx, ", int_to_string(sz), "\n", "\trep movsb\n" }, "") ;/ ;/ # Only to be called from a boolean variable /; bool_from (Variable v, ~CompData data, {}uint8 landing_pad) ;int sz = v.norm_size() ;data`.csec = string_join( { data`.csec, "\tmov ", get_reg(4, sz), ", ", v.norm_loc(sz), "\n", "\ttest ", get_reg(4, sz), ", ", get_reg(4, sz), "\n", "\tmov ", self.norm_loc(1), ", 1\n", "\tjnz ", skip_pad, "\n", "\tmov ", self.norm_loc(1), ", 0\n", landing_pad, ":\n" }, "") ;/ /; move_register (int new_reg, ~CompData data) ;int sz = self.norm_size() /; if (self.is_ref()) ;sz = 8 ;/ ;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] ;int sz = self.el_size() ;log_debug(string_add("Index starting: ", self.sprint())) ;Variable out = self.strip_refs(data) ;int opc = len (out.data_type.ptr_chain) /; if (opc == 0 || (out.is_ref() && opc == 1)) ;log_err(string_add("Unable to index a type if it is not a pointer or array ", out.sprint())) ;/ ;Variable ind = {"#index", {8, "void", "", {PTYPE.POINTER}, {}}, 3, LOCATION.REGISTER} ;ind.set(i, data) ;ind.mul({"#mul", {8, "uint", "", {}, {}}, sz, LOCATION.LITERAL}, data) /; if (out.is_ref()) ;data`.csec = string_join( { data`.csec, "\tadd rsi, 8\n" }, "") ;/ ;data`.csec = string_join( { data`.csec, "\tlea rsi, [rsi + rdx]\n" }, "") /; if (out.is_ref()) ;out.data_type.ptr_chain = strip_int(out.data_type.ptr_chain) ;out.data_type.ptr_chain{len (out.data_type.ptr_chain) - 1} = PTYPE.REFERENCE ;/ ;log_debug(string_add("Index returning: ", out.sprint())) ;return out.deref(data) ;/ /; length_of (Variable a, ~CompData data) ;a = a.strip_refs() ;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, bool r } /; method Scope /; sprint [{}uint8] ;{}uint8 out = string_join( { "SCOPE PRINT [", self.name, "] num:", int_to_string(self.num), " C:", int_to_string(self.c), " vars:", int_to_string(len (self.vars)), " { " }, "") /; loop (int i = 0; i < len (self.vars)) [i++] ;out = string_add(out, self.vars{i}.sprint()) ;out.append(' ') ;/ ;return string_add(out, "}") ;/ /; 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) /; if (!(self.r)) ;{}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) /; if (!(self.r)) ;{}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" ;{}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" ;{}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, {}, self.r} ;/ /; 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} /; 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" }, "") ;/ ;log_debug(string_add("Created new variable ", new.sprint())) ;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())) ;log_err(string_add("Can't move variable to stack as it does not exist in the current context ", int_to_string(reg))) ;/ ;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) ;log_err(string_add("Can't move a register to stack as it is not in scope. ", int_to_string(reg))) ;/ ;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] ;{}uint8 out = string_add(self.full_label(), 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(string_add("Artifact: ", 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] /; loop (i < len (tok`)) [i++] /; if (tok`{i}.cmp("{")) ;i = find_closing(tok, ~i) ;; else if (tok`{i}.cmp("(")) ;return true ;; else if (tok`{i}.cmp(".") || tok`{i}.cmp("`") || tok`{i}.type_is(TOKEN.DEFWORD)) ;continue ;; else ;break ;/ ;/ ;return false ;/ /; 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, t)) ;cur`++ ;; else ;out`.dsec = string_add(out`.dsec, decompose_empty(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 (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, 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 (len(t.ptr_chain) > 0) ;t.ptr_chain = strip_int(t.ptr_chain) ;arr = string_add(arr, decompose_array(tok, cur, t)) ;cur` = next_non_nl(tok, cur` + 1) ;; else ;decompose_struct(tok, cur, t) ;cur` = next_non_nl(tok, cur` + 1) ;/ ;; else ;arr = string_add(arr, decompose_data(tok, cur, t)) ;cur` = next_non_nl(tok, cur` + 1) ;/ ;/ ;cur` = max ;{}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, 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) ;/ ;out = string_add(out, decompose_data(tok, cur, t.members{m}.data_type)) ;m++ ;/ /; if (m < len (t.members) - 1) /; loop (m < len (t.members)) [m++] ;out = string_add(out, decompose_empty(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, Type t) [{}uint8] /; if (tok`{cur`}.cmp("{")) /; if (len (t.ptr_chain) > 0) ;t.ptr_chain = strip_int(t.ptr_chain) ;return decompose_array(tok, cur, t) ;; else ;return decompose_struct(tok, cur, 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(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, 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 - inc/dec # 4 - mul/div/mod # 5 - add/sub # 6 - bitwise # 7 - boolean cmp # 8 - boolean logic # 9 - 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 4 ;; else if (tok.cmp("-") || tok.cmp("+")) ;return 5 ;; else if (tok.cmp("&") || tok.cmp("|") || tok.cmp("^") || tok.cmp("!")) ;return 6 ;; else if (tok.cmp("<") || tok.cmp(">")) ;return 7 ;; else if (tok.cmp("=")) ;return 9 ;/ ;; else if (len (tok.data) == 2) /; if (tok.data{0} == tok.data{1}) /; if (tok.data{0} == '<' || tok.data{0} == '>') ;return 6 ;; else if (tok.data{0} == '=') ;return 7 ;; else if (tok.data{0} == '+' || tok.data{0} == '-') ;return 3 ;/ ;return 8 ;; else if (tok.data{1} == '=') ;return 9 ;; else if (tok.data{1} == '<' || tok.data{1} == '>') ;return 7 ;/ ;return 6 ;; else if (len (tok.data) == 3) ;return 7 ;/ ;return -1 ;/ /; first_match(~{}Token tok, ~int i, int max, ~Module current, ~Scope scope) [Variable] ;Variable wk ;{}{}uint8 art = {} ;log_debug(string_join( { "Variable match with s:", int_to_string(i`), " m:", int_to_string(max), " first:", tok`{i`}.sprint() }, "")) /; loop (tok`{i`}.type_is(TOKEN.DEFWORD) && i` < max) [i`++] ;art.append(tok`{i`}.data) ;wk = scope`.find_var(art, current) /; if (!string_equate(wk.name, "")) ;i`++ ;break ;/ /; if (tok`{i` + 1}.cmp(".")) ;i`++ ;; else ;i`++ ;break ;/ ;/ /; if (string_equate(wk.name, "")) ;log_err(string_add("Unable to find variable within artifact ", string_join(art, "."))) ;/ ;log_info(string_add("Found ", wk.sprint())) ;return wk ;/ /; _eval_dot (~{}Token tok, int start, max, ~CompData out, ~Module current, ~Scope scope, Type t, bool alt) [Variable] ;Variable wk = first_match(tok, ~start, max, current, scope) /; if (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 ;/ # FIXME: Important step before the language can be considered remotely usable /; _eval_call (~{}Token tok, int start, max, ~CompData out, ~Module current, ~Scope scope, Type t) [Variable] ;return {"#null", NO_TYPE, 0, LOCATION.LITERAL} ;/ /; literal_variable ({}uint8 data, l, ~CompData out) [Variable] ;Variable v = {"#literal", NO_TYPE, 0, LOCATION.LITERAL} /; if (data{0} == '"') ;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(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 ;/ /; num_elements(~{}Token tok, int start, max) [int] ;int out = 1 /; loop (start < max) [start++] /; if (tok`{start}.type_is(TOKEN.DELIMITER)) ;start = find_closing(tok, ~start) ;; else if (tok`{start}.cmp(",")) ;out++ ;/ ;/ ;/ /; element_end(~{}Token tok, int start, max) [int] /; loop (out < max + 1 && !(tok`{start}.cmp(","))) [start++] ;/ ;return start ;/ /; _eval_composite (~{}Token tok, int start, max, ~CompData out, mov, ~Module current, ~Scope scope, Type t, bool alt) [Variable] ;{}uint8 l = scope`.next_const() /; if (start == max - 1) ;out`.dsec = string_join( { out`.dsec, l, decompose_empty(t) }, "") ;return {l, t, 0, LOCATION.LABEL} ;; else if (len(t.ptr_chain) > 0) ;Variable vout = {l, t, 0, LOCATION.LABEL} ;t.ptr_chain = strip_int(t.ptr_chain) ;int count = num_elements(tok, start, max) ;{}uint8 out_text = string_join( { l, "\tdq ", int_to_string(count), "\n" }, "") ;{}uint8 one_el = "\tdb 0" /; loop (int i = 1; i < t.size()) [i++] ;one_el = string_add(one_el, ", 0") ;/ ;one_el.append('\n') ;int ind = 0 /; loop (start < max) [start = next_non_nl(tok, start + 1)] ;Variable v = _eval_value(tok, start, element_end(tok, start, max), out, mov, current, scope, t, alt) /; if (v.loc_type == LOCATION.LITERAL) ;out_text = string_join( { out_text, declare_size(t.size()), int_to_string(v.location), "\n" }, "") ;; else ;out_text = string_add(out_text, one_el) ;Variable tos = vout.index({"#literal", get_primitive(is_primitive("uint")), ind, LOCATION.LITERAL}, out) ;tos.set(v, out) ;/ ;ind++ ;/ ;out`.dsec = string_add(out`.dsec, out_text) ;return out ;/ ;/ /; _eval_value(~{}Token tok, int start, max, ~CompData out, mov, ~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) ;/ ;/ ;Variable wk = {"#wk", t, 1, LOCATION.REGISTER} /; if (alt) ;wk.location = 2 ;/ /; if (pa !< 0 && pr < 2) /; if (tok`{pa}.cmp("(") && first == pa) ;return _eval_value(tok, pa + 1, find_closing(tok, ~pa), out, mov, current, scope, t, alt) ;; else if (tok`{pa}.cmp("{")) /; if (pa !== first) ;log_debug("Index") ;Variable i = _eval_value(tok, pa + 1, find_closing(tok, ~pa), out, mov, current, scope, t, alt) ;Variable vout = _eval_dot(tok, start, pa, out, current, scope, t, !alt) ;vout = vout.index(i, out) ;wk.data_type = vout.data_type ;out`.csec = string_join( { out`.csec, "\tmov ", get_reg(wk.location, 8), ", rsi\n" }, "") ;return wk ;; else ;log_debug("Composite") ;return _eval_composite(tok, pa + 1, find_closing(tok, ~pa), out, current, scope, t, alt) ;/ ;; else if (tok`{pa}.cmp("[")) # code for converting value to another type here ;/ ;/ # This is all kinda garbage, to fix. /; if (is_call(tok, start)) ;log_debug("Attempt to invoke a call") ;return _eval_call(tok, start, max, out, current, scope, t, alt) ;; else if (pr < 2) ;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, mov, current, scope, t, alt) ;; else if (first == max - 1) ;s1 = _eval_value(tok, start, first, out, mov, current, scope, t, alt) ;; else ;s1 = _eval_value(tok, start, first, out, mov, current, scope, t, alt) /; if (tok`{first}.cmp("=")) ;t = s1.data_type ;/ ;s2 = _eval_value(tok, first + 1, max, out, mov, 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() }, " ")) # Inc and dec /; else if (tok`{first}.cmp("++") || tok`{first}.cmp("--")) ;wk.data_type = s1.data_type ;wk.set(s1, out) /; if (tok`{first}.cmp("++")) ;s1.inc(out) ;; else ;s1.dec(out) ;/ /; if (first == max - 1) ;return wk ;/ ;return s1 ;/ # TODO: Boolean logic /; if (pr == 7) ;wk.set(s1, out) ;wk.cmp(s2, out) ;wk.data_type = {1, "bool", "_bool", {}, {}} ;wk.set(literal_variable("true", "", out), out) ;{}uint8 l = scope`.next_const() # ;log_debug(l) ;out`.csec = string_join( { out`.csec, to_jmp(tok`{first}.data), l, "\n" }, "") ;wk.set(literal_variable("false", "", out), out) ;out`.csec = string_join( { out`.csec, l, ":\n" }, "") ;return wk ;/ /; 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, mov) ;/ ;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, mov, ~Module current, ~Scope scope, Type t, bool save) [Variable] ;int end = cur` /; loop (end < len tok`) [end++] /; if (tok`{end}.type_is(TOKEN.SEPARATOR) || tok`{end}.cmp(";/") || 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, mov, current, scope, t, false) ;cur` = end /; if (save) ;Variable set = {"#tmp", t, 0, LOCATION.REGISTER} ;set.set(val, out) ;return val ;/ ;return { "", NO_TYPE, 0, 0 } ;/ /; eval_def (~{}Token tok, ~int cur, ~CompData out, mov, ~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, mov, current, scope, t, false) /; if (tok`{cur`}.cmp(",")) ;cur` = next_non_nl(tok, cur` + 1) ;; else ;break ;/ ;/ ;/ /; is_bool_statement (~{}Token tok, int start, max, ~Module current, ~Scope parent) [bool] ;int i = start /; loop (i < max) [i++] /; if (tok`{i}.type_is(TOKEN.AUGMENT)) /; if (priority(tok`{i}) == 7 || priority(tok`{i}) == 8) ;return true ;/ ;; else if (tok`{i}.type_is(TOKEN.LITERAL)) /; if (string_equate(tok`{i}.data, "false") || string_equate(tok`{i}.data, "true")) ;return true ;/ ;; else if (tok`{i}.type_is(TOKEN.DEFWORD)) ;int j = i ;Variable v = first_match(tok, ~j, max, current, parent) /; if (string_equate(v.data_type.name, "bool")) ;int j = len(v.data_type.ptr_chain) /; if (j == 0 || (j == 1 && v.is_ref())) ;return true ;/ ;/ ;; else if (tok`{i}.type_is(TOKEN.DELIMITER)) ;i = find_closing(tok, ~i) ;; else if (tok`{i}.cmp(";") || tok`{i}.cmp("\n")) ;break ;/ ;/ ;return false ;/ /; statement_list(~{}Token tok, int start, end, ~Module current, ~CompData out, mov, ~Scope parent) [{}uint8] ;log_debug("Statement list!") ;int b = -1 ;CompData carry = {"", "", ""} ;int s = next_non_nl(tok, start + 1) /; loop (s < end) [s = next_non_nl(tok, s + 1)] ;out`.add(carry) ;carry = {"", "", ""} ;b = -1 /; if (is_definition(tok, ~s, current)) ;log_debug("Block def") ;eval_def(tok, ~s, out, mov, current, parent) ;; else ;log_debug("Block val") /; if (is_bool_statement(tok, s, end, current, parent)) ;b = s ;/ ;Type t = NO_TYPE /; if (b !< 0) ;t = {1, "bool", "_bool", {}, {}} ;log_debug("Boolish") ;/ ;eval_value(tok, ~s, out, mov, current, parent, t, b > 0) ;/ ;/ ;{}uint str = "" /; if (b > 0) ;str = int_to_string(b) ;/ ;return str ;/ # 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, mov, ~Scope parent, Type ret) ;int max = find_closing(tok, cur) ;Scope cf = parent`.new_sub_cf("wrap") ;CompData outro = {"", "", ""} ;{}uint8 condition = "" /; loop (cur`++; cur` < max) [cur`++] /; if (tok`{cur`}.type_is(TOKEN.KEYWORD)) /; if (tok`{cur` + 1}.cmp("if")) ;cf = parent`.new_sub_cf("elif") ;cur`++ ;; else ;cf = cf.new_sub_cf(tok`{cur`}.data) ;/ ;; else if (tok`{cur`}.cmp("(") || tok`{cur`}.cmp("[")) ;int psl = find_closing(tok, cur) /; if (tok`{cur`}.cmp("[")) ;outro.csec = string_add(cf.scope_rep_label(), ":\n") ;{}uint8 tmp = statement_list(tok, cur`, psl, current, ~outro, mov, ~cf) /; if (cf.cf_type("loop")) /; if (len (tmp) == 0 && len (condition) > 0) /; if (len (condition) > 0) ;int tmps = string_to_int(condition) ;eval_value(tok, ~tmps, ~outro, mov, current, ~cf, {1, "bool", "", {}, {}}, true) ;; else ;outro.csec = string_join( { outro.csec, "\tjmp ", cf.scope_start_label(), "\n" }, "") ;/ ;/ /; if (len (tmp) > 0 || len(condition) > 0) ;outro.csec = string_join( { outro.csec, "\ttest al, al\n", "\tjnz ", cf.scope_start_label(), "\n", "\tjmp ", cf.scope_end_label(), "\n" }, "") ;/ ;/ ;; else ;condition = statement_list(tok, cur`, psl, current, out, mov, ~cf) /; if (len (condition) == 0) ;out`.csec = string_join( { out`.csec, "\tjmp ", cf.scope_start_label(), "\n" }, "") ;; else ;out`.csec = string_join( { out`.csec, "\ttest al, al\n", "\tjnz ", cf.scope_start_label(), "\n", "\tjmp ", cf.scope_end_label(), "\n" }, "") ;/ ;/ ;cur` = psl ;; else ;break ;/ ;/ ;out`.csec = string_join( { out`.csec, cf.scope_start_label(), ":\n" }, "") /; if (tok`{cur`}.cmp("\n")) ;cur` = next_non_nl(tok, cur` + 1) ;/ ;bool returned = false /; loop (cur` < max && !returned) [cur` = next_non_nl(tok, cur` + 1)] /; if (tok`{cur`}.cmp("/;") || tok`{cur`}.cmp(";;")) ;log_debug("Block in block") ;_compile_block(tok, cur, current, out, mov, ~cf, ret) /; 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, mov, current, ~cf, ret, true) ;cf.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 (!(cf.r)) ;log_err("Unable to perform a raw return from a non-raw block.") ;/ ;cur` = cur` + 2 ;eval_value(tok, cur, out, mov, current, ~cf, 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 ;log_err(string_add("Keyword not impl: ", tok`{cur`}.data)) ;/ ;; else if (is_definition(tok, cur, current)) ;log_debug("Block def") ;eval_def(tok, cur, out, mov, current, ~cf) ;; else ;log_debug("Block val") ;eval_value(tok, cur, out, mov, current, ~cf, NO_TYPE, false) ;/ ;/ ;log_debug("Passing gauntlet 2") /; if (len (outro.csec) > 0) ;out`.add(outro) ;; else ;out`.csec = string_join( { out`.csec, cf.scope_rep_label(), ":\n" }, "") /; if (cf.cf_type("loop")) /; if (len (condition) > 0) ;int tmps = string_to_int(condition) ;eval_value(tok, ~tmps, out, mov, current, ~cf, {1, "bool", "", {}, {}}, true) ;out`.csec = string_join( { out`.csec, "\ttest al, al\n", "\tjnz ", cf.scope_start_label(), "\n", "\tjmp ", cf.scope_end_label(), "\n" }, "") ;; else ;out`.csec = string_join( { out`.csec, "\tjmp ", cf.scope_start_label(), "\n" }, "") ;/ ;/ ;/ ;out`.csec = string_join( { out`.csec, cf.scope_end_label(), ":\n" }, "") /; if (cf.is_cf()) ;out`.csec = string_join( { out`.csec, "\t", cf.parent`.scope_end_label(), ":\n" }, "") ;/ ;/ /; compile_block (~{}Token tok, ~int cur, ~Module current, ~CompData out) ;Scope root = {0, 0, 0, "", {}, false} ;int max = find_closing(tok, cur) ;bool 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")) ;root.r = true ;; else if (tok`{cur`}.cmp("method")) ;m = true ;current = current`.find_sub(tok`{cur` + 1}.data) ;; else ;log_err(string_join( { "Keyword ", tok`{cur`}.data, " not impl on mod level blocks" }, "")) ;/ ;; 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 (len (current`.name) > 2) /; if (current`.name{0} == '_' && current`.name{1} == '#') ;{}{}uint8 split = string_split(current`.name, '#') ;Type st = current`.find_type( {split{1}} )` ;st.ptr_chain = {PTYPE.REFERENCE} ;root.vars.append({"self", st, 0, 0}) ;/ ;/ /; 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") ;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(";;")) ;log_debug("Block in block") /; if (m) ;compile_block(tok, cur, current, out) ;; else ;CompData mov = {"", "", ""}, tmp = {"", "", ""} ;log_debug("PRE COMPUTATION OF BLOCK\n") ;int tcr = cur` ;_compile_block(tok, ~tcr, current, ~tmp, ~mov, ~root, ret) ;out`.add(mov) ;log_debug("POST COMPUTATION OF BLOCK") ;_compile_block(tok, cur, current, out, ~tmp, ~root, ret) ;/ /; 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, 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 (!(root.r)) ;log_err("Unable to perform a raw return from a non-raw block.") ;/ ;cur` = cur` + 2 ;eval_value(tok, cur, out, 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 ;log_err(string_add("Keyword not impl: ", tok`{cur`}.data)) ;/ ;; else if (is_definition(tok, cur, current)) ;log_debug("Block def") ;eval_def(tok, cur, out, out, current, ~root) ;; else ;log_debug("Block val") ;eval_value(tok, cur, out, out, current, ~root, NO_TYPE, false) ;/ ;/ ;cur` = max /; if (!returned && !string_equate(ret.name, "")) ;log_err("Block must return a value.") ;/ /; if (!m && !returned) ;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`++] ;log_vis(".") /; if (tok`{cur`}.cmp(":")) ;log_debug("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)] ;log_vis(".") /; if (tok`{cur`}.cmp(":")) ;log_debug("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"))) ;log_err(string_add("Failed to recognize file-level statement ", tok`{cur`}.sprint())) ;/ ;/ ;/ # First compiler pass on a file # Only creates structs, enums, and moduless /; compile_file_pass_one (Path f, ~Module current) ;{}Token tok = tokenize(f) ;log_info(string_add("Number of tokens generated: ", int_to_string(len tok))) /; loop (int i = 0; i < len tok) [i++] ;log_vis(".") /; if (tok{i}.cmp(":")) ;log_debug("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 ;log_debug("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 ;/ ;/ ;log_debug(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)] ;log_vis(".") /; if (tok{i}.cmp(":")) ;log_debug("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"))) ;log_err(string_add("Failed to recognize file-level statement", tok{i}.sprint())) ;/ ;/ ;log_info(string_add("File compiled! Generated code length: ", int_to_string(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) ;log_info("First pass DONE") ;CompData data = compile_file_pass_two(f, ~root) ;log_info("Second pass DONE") ;out = string_join({ data.hsec, "section .data\n", data.dsec, "section .text\n", data.csec}, "") ;return out ;/ ## ## Main ## /; main ({}{}uint8 args) [int] ;log_debug("TNSLC version 0.0.1, built with debugging enabled") /; if (len args < 1) ;log_info("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}) ;/ ;log_info("Path: ") ;log_info(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++] ;log_vis(".") ;code = string_add(code, tok{i}.sprint()) ;/ ;log_vis("OK\n") ;/ ;p.name = string_add(p.name, ".asm") ;p.write(code) ;return 0 ;/