From 09df1bb48823631228af3df647111af1eebc854b Mon Sep 17 00:00:00 2001 From: Kyle Gunger Date: Thu, 16 Feb 2023 05:14:31 -0500 Subject: Collapse tnslc into a single file --- tnslc/compile.tnsl | 1503 +++++++++++++++++++++++++++++++++++ tnslc/compile/compile.tnsl | 768 ------------------ tnslc/compile/isa_x86.tnsl | 182 ----- tnslc/compile/value.tnsl | 362 --------- tnslc/copy.tnsl | 30 - tnslc/dummy.tnsl | 33 - tnslc/inc.tnsl | 3 - tnslc/parse/parse.tnsl | 87 -- tnslc/parse/token.tnsl | 331 -------- tnslc/parse/tokenizer.tnsl | 114 --- tnslc/paths.tnsl | 103 --- tnslc/test.tnsl | 21 + tnslc/tests/complex/enums.tnsl | 84 ++ tnslc/tests/complex/generics.tnsl | 35 + tnslc/tests/complex/if_else.tnsl | 46 ++ tnslc/tests/complex/interfaces.tnsl | 0 tnslc/tests/complex/loops.tnsl | 0 tnslc/tests/complex/switch.tnsl | 0 tnslc/tests/simple/comments.tnsl | 52 ++ tnslc/tests/simple/if_else.tnsl | 0 tnslc/tests/simple/includes_a.tnsl | 1 + tnslc/tests/simple/includes_b.tnsl | 0 tnslc/tests/simple/modules_a.tnsl | 0 tnslc/tests/simple/modules_b.tnsl | 0 tnslc/tests/simple/structs.tnsl | 0 tnslc/tnslc.tnsl | 43 - tnslc/util.tnsl | 199 ----- 27 files changed, 1742 insertions(+), 2255 deletions(-) create mode 100644 tnslc/compile.tnsl delete mode 100644 tnslc/compile/compile.tnsl delete mode 100644 tnslc/compile/isa_x86.tnsl delete mode 100644 tnslc/compile/value.tnsl delete mode 100644 tnslc/copy.tnsl delete mode 100644 tnslc/dummy.tnsl delete mode 100644 tnslc/inc.tnsl delete mode 100644 tnslc/parse/parse.tnsl delete mode 100644 tnslc/parse/token.tnsl delete mode 100644 tnslc/parse/tokenizer.tnsl delete mode 100644 tnslc/paths.tnsl create mode 100644 tnslc/test.tnsl create mode 100644 tnslc/tests/complex/enums.tnsl create mode 100644 tnslc/tests/complex/generics.tnsl create mode 100644 tnslc/tests/complex/if_else.tnsl create mode 100644 tnslc/tests/complex/interfaces.tnsl create mode 100644 tnslc/tests/complex/loops.tnsl create mode 100644 tnslc/tests/complex/switch.tnsl create mode 100644 tnslc/tests/simple/comments.tnsl create mode 100644 tnslc/tests/simple/if_else.tnsl create mode 100644 tnslc/tests/simple/includes_a.tnsl create mode 100644 tnslc/tests/simple/includes_b.tnsl create mode 100644 tnslc/tests/simple/modules_a.tnsl create mode 100644 tnslc/tests/simple/modules_b.tnsl create mode 100644 tnslc/tests/simple/structs.tnsl delete mode 100644 tnslc/tnslc.tnsl delete mode 100644 tnslc/util.tnsl (limited to 'tnslc') diff --git a/tnslc/compile.tnsl b/tnslc/compile.tnsl new file mode 100644 index 0000000..8bad758 --- /dev/null +++ b/tnslc/compile.tnsl @@ -0,0 +1,1503 @@ +## +## 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' + ;/ + +;/ + +/; 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 +;/ + +/; int_to_string (int i) [{}uint8] + /; if (i == 0) + ;return "0" + ;/ + + ;{}uint8 out = "" + + /; if (i < 0) + ;out.append('-') + ;i = -i + ;/ + + /; loop [i = i / 10; i > 0] + ;out.append('0' + (i % 10)) + ;/ + + ;return 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 +} + +;{}{}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 +;/ + +# 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 + 2) +;/ + +# 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') + ;/ + + ;string_add(out, common) + + ;; else + + ;out.append('r') + ;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 + ;/ + + ;return out +;/ + +/; get_reg (int r, sz) [{}uint8] + ;return reg_by_name_size(reg_by_num(r), sz) +;/ + +# Most methods make use of one or more temporary variables. +# These are denoted by tr +/; method Variable + + /; norm_loc (int sz) [{}uint8] + /; if (self.loc_type == LOCATION.LABEL) + ;return "" + ;; else if (self.loc_type == LOCATION.REGISTER) + ;return get_reg(self.location, sz) + ;; else if (self.loc_type == LOCATION.STACK) + ;return string_join( { "[ rsp + ", int_to_string(self.location), " ]" } , "") + ;/ + ;/ + + /; norm_size [int] + /; if (len (self.data_type.ptr_chain) > 0) + ;return 8 + ;; else + ;return self.data_type.s + ;/ + ;/ + + /; norm_op ({}uint8 op, {}{}uint8 args) [{}uint8] + ;return string_join( + { + "\t", op, " ", + string_join(args, ", "), "\n" + }, + "" + ) + ;/ + + # functions that do work on this variable + /; add (Variable v, int tr) [{}uint8] + /; if (self.loc_type == LOCATION.LITERAL) + /; if (v.loc_type !== LOCATION.LITERAL) + ;return v.add(self) + ;/ + ;self.location = self.location + v.location + ;return "" + ;; if (self.loc_type == LOCATION.STACK && v.loc_type == LOCATION.STACK) + ;{}uint8 tmp = get_reg(tr, self.norm_size()) + ;{}uint8 out = self.norm_op("mov", { tmp, v.norm_loc(self.norm_size()) }) + ;return string_add(out, self.norm_op("add", { self.norm_loc(self.norm_size()), tmp })) + ;/ + ;return self.norm_op("add", { self.norm_loc(self.norm_size()), get_reg(tr, self.norm_size()) }) + ;/ + + /; sub (Variable v) + /; if (self.loc_type == LOCATION.LITERAL) + /; if (v.loc_type !== LOCATION.LITERAL) + ;return v.add(self) + ;/ + ;self.location = self.location - v.location + ;return "" + ;; if (self.loc_type == LOCATION.STACK && v.loc_type == LOCATION.STACK) + ;{}uint8 tmp = get_reg(tr, self.norm_size()) + ;{}uint8 out = self.norm_op("mov", { tmp, v.norm_loc(self.norm_size()) }) + ;return string_add(out, self.norm_op("sub", { self.norm_loc(self.norm_size()), tmp })) + ;/ + ;return self.norm_op("sub", { self.norm_loc(self.norm_size()), get_reg(tr, self.norm_size()) }) + ;/ + + /; div (Variable v) + /; if (self.loc_type == LOCATION.LITERAL) + /; if (v.loc_type !== LOCATION.LITERAL) + ;return v.div(self) + ;/ + ;self.location = self.location + v.location + ;return "" + ;; if (self.loc_type == LOCATION.STACK && v.loc_type == LOCATION.STACK) + ;{}uint8 out = "" + # TODO + ;return out + ;/ + ;return self.norm_op("div", { self.norm_loc(self.norm_size()), v.norm_loc(self.norm_size) }) + ;/ + + /; mul (Variable v) + /; if (self.loc_type == LOCATION.LITERAL) + /; if (v.loc_type !== LOCATION.LITERAL) + ;return v.mul(self) + ;/ + ;self.location = self.location * v.location + ;return "" + ;; if (self.loc_type == LOCATION.STACK && v.loc_type == LOCATION.STACK) + ;{}uint8 out = "" + # TODO + ;return out + ;/ + ;return self.norm_op("mul", { self.norm_loc(self.norm_size()), v.norm_loc(self.norm_size) }) + ;/ + + /; set (Variable v) + /; if (self.loc_type == LOCATION.LITERAL) + /; if (v.loc_type !== LOCATION.LITERAL) + ;return v.set(self) + ;/ + ;self.location = v.location + ;return "" + ;; if (self.loc_type == LOCATION.STACK && v.loc_type == LOCATION.STACK) + ;{}uint8 out = "" + # TODO + ;return out + ;/ + ;return self.norm_op("mov", { self.norm_loc(self.norm_size()), v.norm_loc(self.norm_size) }) + ;/ + + # functions that do work on another variable + /; ref (Variable out) + ;/ + + /; deref (Variable out) + ;/ + + /; member (Variable out, {}uint8 name) + ;/ + + /; index (Variable out, Variable i) + /; + + ;/ + ;/ + + /; call (Variable out, {}uint8 name) + ;/ +;/ + +;struct Scope { + {}Variable vars +} + +;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._find_type(artifact, r + 1) + ;/ + ;/ + ;/ + + /; loop (int i = 0; i < len (self.types)) [i++] + /; if (string_equate(self.types{i}.name, artifact{r})) + ;return ~(self.types{i}) + ;/ + ;/ + + ;Type nt = {0, artifact{len artifact - 1}, "", {}, {}} + ;return ~nt + ;/ + + # 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) + ;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.defs)) [i++] + /; if (string_equate(self.defs{i}.name, artifact{r})) + ;return self.defs{i} + ;/ + ;/ + + ;return {{}, "", 0, 0, 0} + ;/ + + /; find_def ({}{}uint8 artifact) [Variable] + ;return _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) + ;/ + + /; 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 +;/ + +/; 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) [bool] + ;return false +;/ + +/; compile_file_def (~{}Token tok, ~int cur, Type t, ~Module current) [{}Variable] + ;return {} +;/ + +/; next_non_nl (~{}Token tok, int c) [int] + /; 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 = string_add(current`.full_path(), "_#") + ;out.mod_name = string_add(out.mod_name, out.name) + ;current`.sub.append({current, current`.exp, out.mod_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++] + ;tnsl.io.print(string_join({"[", out.members{i}.name, ":", out.members{i}.data_type.name, "]"}, "")) + ;/ + + ;tnsl.io.print(string_add("Generated type ", string_add(out.name, string_add(":", out.mod_name)))) + ;current`.types.append(out) +;/ + +/; decompose_empty (~Module current, Type t) [{}uint8] + ;return "" +;/ + +# 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`++; cur` < max) [cur`++] + ;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`++ + ;; else + ;decompose_struct(tok, cur, current, t) + ;cur`++ + ;/ + ;; 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`++; cur` < max) [cur`++] + /; if (tok`{cur`}.cmp("}")) + ;break + ;; else if (tok`{cur`}.cmp(",")) + ;cur`++ + ;/ + ;out = string_add(out, decompose_data(tok, cur, current, t.members{m}.data_type)) + ;m++ + ;/ + + /; 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 (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) [{}uint8] + ;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), {}, {}, {}, {}} + + ;{}uint8 out = "" + + /; 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) + ;l.append(':') + ;l.append('\n') + ;cur` = cur` + 2 + ;l = string_add(l, decompose_data(tok, cur, current, et)) + ;out = string_add(out, l) + ;/ + ;/ + + ;current`.sub.append(enum_mod) + + ;return out +;/ + +# Generates opposite closing bracket +/; closing_for (Token d) [{}uint8] + /; if (d.cmp("(")) + ;return ")" + ;; else if (d.cmp("[")) + ;return "]" + ;; else if (d.cmp("{")) + ;return "}" + ;/ + ;tnsl.io.println(string_add("Error, unrecognized delim: ", d)) +;/ + +# 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) + ;{}uint8 name = tok`{cur` + 1}.data + /; loop (cur` < len tok`) [cur`++] + /; if (tok`{cur`}.cmp("{")) + ;cur` = find_closing(tok, cur) + ;break + ;/ + ;/ +;/ + +# TODO: +/; compile_function (~{}Token tok, ~int cur, ~CompData out, ~Module current, ~Scope scope) [Function] + +;/ + +# TODO: +/; compile_method (~{}Token tok, ~int cur, ~CompData out, ~Module current, ~Scope scope) [Function] + +;/ + +# First pass on a module +# Generates structs, enums, and submodules +/; module_pass_one (~{}Token tok, ~int cur, ~Module current) + +;/ + +# 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) + +;/ + +# 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) + ;/ + ;; 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 + ;~Type tp = m`.find_type(t`.members{i}.data_type.name) + /; 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 = 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_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(";;")) + ;tnsl.io.print("block") + /; if (tok{i + 1}.cmp("export") || tok{i + 1}.cmp("module")) + ;module_pass_two(~tok, ~i, current) + ;/ + ;; else if (tok{i}.cmp("struct")) + ;tnsl.io.print("struct") + ;skip_struct(~tok, ~i) + ;; else if (tok{i}.cmp("enum")) + ;tnsl.io.print("enum") + ;out.dsec = string_add(out.dsec, compile_enum(~tok, ~i, current)) + ;; else if (is_definition(~tok, ~i)) + ;tnsl.io.print("def") + ;Type t = get_type(~tok, ~i, current) + ;out.dsec = string_add(out.dsec, compile_file_def(~tok, ~i, t, current)) + ;; 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", + + "extends", + "override" +} + +;{}{}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 + ;/ + + ;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) +;/ + +/; 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 == '#' && (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') + ;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] + /; 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 +;/ diff --git a/tnslc/compile/compile.tnsl b/tnslc/compile/compile.tnsl deleted file mode 100644 index 034304c..0000000 --- a/tnslc/compile/compile.tnsl +++ /dev/null @@ -1,768 +0,0 @@ -/## - Copyright 2021-2022 Kyle Gunger - - This file is licensed under the CDDL 1.0 (the License) - and may only be used in accordance with the License. - You should have received a copy of the License with this - software/source code. If you did not, a copy can be found - at the following URL: - - https://opensource.org/licenses/CDDL-1.0 - - THIS SOFTWARE/SOURCE CODE IS PROVIDED "AS IS" WITH NO - WARRANTY, GUARANTEE, OR CLAIM OF FITNESS FOR ANY PURPOSE - EXPRESS OR IMPLIED -#/ - - -;{}{}uint8 COMMON_ASM = { - "\tret\n" -} - -# Represents a type -;struct VType { - uint - _size, - int - ptr, - - {}uint8 name, - - {}VType sub_types, - {}{}uint8 sub_names -} - -/; method VType - /; get_sub_type({}uint8 name) [VType] - /; loop (int i = 0; i < len (self.sub_types)) [i++] - /; if (string_equate(~name, ~(self.sub_names{i}))) - ;return self.sub_types{i} - ;/ - ;/ - ;return NT - ;/ - - /; get_offset({}uint8 name) [int] - ;int out = 0 - /; loop (int i = 0; i < len (self.on_stack)) [i++] - /; if (string_equate(~name, ~(self.sub_types{i*2 + 1}))) - ;return out - ;; else if (self.on_stack{i}) - ;VType tmp = vtype_by_name(self.sub_types{i*2}) - ;out = out + tmp.size - ;/ - ;/ - ;return -1 - ;/ - - /; print - ;tnsl.io.print("Size: ") - ;tnsl.io.print(self._size) - ;tnsl.io.print(" | Ptr: ") - ;tnsl.io.print(self.ptr) - ;tnsl.io.print(" | Name: ") - ;tnsl.io.println(self.name) - ;/ -;/ - -# Tracks defined variables in a block -;struct VTrack { - {}{}uint8 - sym_names, - - {}Value - sym_vals -} - -/; method VTrack - - /; next_loc(VType vt) [int] - /; if (is_struct(vt) && vt.ptr == 0) - ;return -1 - ;/ - - ;int count = 0 - /; loop (int i = 0; i < len (self.sym_vals)) [i++] - /; if (!(self.sym_vals{i}.on_stack)) - ;count++ - ;/ - - /; if (count > 7) - ;return -1 - ;/ - ;/ - - ;return count + 6 - ;/ - - # returns with init commands - /; add_track({}uint8 name, VType _type) [{}uint8] - ;Value v = track_val(_type, to_stack, self.next_loc(_type)) - - /; if (v.loc < 0) - ;v.loc = 0 - ;/ - - ;self.sym_names.append(name) - ;self.sym_vals.append(v) - ;return v.init_val() - ;/ - - # Returns true if the variable is being tracked - /; in_vtrack({}uint8 name) [bool] - /; loop (int i = 0; i < len (self.sym_names)) [i++] - /; if (string_equate(name, self.sym_names{i})) - ;return true - ;/ - ;/ - ;return false - ;/ - - # Returns the total allocated memory on the stack for this tracker - /; stack_total [int] - ;int out = 0 - /; loop (int i = 0; i < len (self.on_stack)) [i++] - /; if (self.on_stack{i}) - ;out = out + (self.sym_vals{i}._type._size) - ;/ - ;/ - ;return out - ;/ - - # returns the type of the named variable - /; get_val ({}uint8 name) [Value] - /; loop (int i = 0; i < len (self.sym_names)) [i++] - /; if (string_equate(name, self.sym_names{i})) - ;return (self.sym_vals{i}) - ;/ - ;/ - ;/ - - # push stack updates loc for every value on the stack - /; push_stack (VType vt) [{}uint8] - ;int tsz = vt._size - /; if (vt.ptr !== 0) - ;tsz = 8 - ;/ - - /; loop (int i = 0; i < len (self.sym_vals)) [i++] - /; if (self.sym_vals{i}.on_stack) - ;self.sym_vals{i}.loc = self.sym_vals{i}.loc + tsz - ;/ - ;/ - - ;{}uint8 out = "\tsub $" - ;{}uint8 tmp = string_from_int(tsz) - ;add_strings(~out, ~tmp) - ;out.append(',') - ;out.append(' ') - ;tmp = "%rsp" - ;add_strings(~out, ~tmp) - ;return out - ;/ -;/ - -# Sizes of items -;{}VType type_table = { - {1, 0, "int8", {}, {}}, - {2, 0, "int16", {}, {}}, - {4, 0, "int32", {}, {}}, - {8, 0, "int64", {}, {}}, - {8, 0, "int", {}, {}}, - {1, 0, "uint8", {}, {}}, - {2, 0, "uint16", {}, {}}, - {4, 0, "uint32", {}, {}}, - {8, 0, "uint64", {}, {}}, - {8, 0, "uint", {}, {}}, - {4, 0, "float32", {}, {}}, - {8, 0, "float64", {}, {}}, - {8, 0, "float", {}, {}}, - {1, 0, "bool", {}, {}}, - {8, 0, "void", {}, {}} -} - -# Null type -;VType NT = {0, 0, "null", {}, {}} - -# Returns an index in the vtrack for a given variable name -/; name_to_index ({}uint8 name, ~VTrack tab) [int] - /; loop (int i = 0; i < len (tab`.sym_names)) [i++] - /; if (string_equate(tab`.sym_names{i}, name)) - ;return i - ;/ - ;/ - - ;tnsl.io.print("Failed to find vairable ") - ;tnsl.io.println(name) - - ;return -1 -;/ - -# Bool to j -/; cmp_to_jxt ({}uint8 c) [{}uint8] - /; if (string_equate(c, "<")) - ;return "l" - ;; else if (string_equate(c, ">")) - ;return "g" - ;; else if (string_equate(c, "!<") || string_equate(c, ">==")) - ;return "nl" - ;; else if (string_equate(c, "!>") || string_equate(c, "<==")) - ;return "ng" - ;; else if (string_equate(c, "==")) - ;return "e" - ;; else if (string_equate(c, "!==")) - ;return "ne" - ;/ - ;return "nz" -;/ - -# Is struct returns true if the type name given is a struct -/; is_struct (VType t) [bool] - ;VType tmp = NT - /; loop (int i = 0; i < 15) [i++] - ;tmp = tnslc.type_table{i} - /; if (string_equate(tmp.name, t.name)) - ;return false - ;/ - ;/ - - ;return true -;/ - -# Using the given offset (in bytes), return an asm value of form ".quad " -/; construct_value (int size, int offset) [{}uint8] - ;{}uint8 out = ".byte " - /; if (size == 2) - ;out = ".word " - ;; if (size == 4) - ;out = ".long" - ;; if (size == 8) - ;out = ".quad " - ;/ - ;{}uint8 tmp = string_from_int(offset) - ;add_strings(~out, ~tmp) - ;return out -;/ - -/; construct_text_value ({}uint8 t) [{}uint8] - ;{}uint8 tmp = "\n\t.ascii " - ;add_strings(~tmp, ~t) - ;return tmp -;/ - -/; construct_mov_literal({}uint8 value, reg) [{}uint8] - ;{}uint8 tmp = "$" - ;add_strings(~tmp, ~value) - ;return mov_asm(tmp, reg) -;/ - -# Parse a struct and add it to the table -/; def_struct (~int cur, ~{}Token data, ~{}uint8 dsec) [VType] - ;VType out = {0, 0, "", {}, {}} - ;cur`++ - - ;out.name = data`{cur`}.data` - - ;cur`++ - ;cur`++ - # Should be indexed at first type in the type list - - /; if (token_is(cur, data, "}")) - ;return NT - ;/ - - ;VType ctype = get_vtype(cur, data) - ;cur`++ - - /; loop (cur` < len data`) [cur`++] - /; if (token_is(cur, data, "}")) - ;break - ;; else if (token_is(cur, data, ",")) - ;cur`++ - ;/ - - ;cur`++ - /; if (token_is(cur, data, ",") || token_is(cur, data, "}")) - # Use ctype - ;cur`-- - - /; if (ctype.ptr > 0) - ;out._size = out._size + 8 - ;; else - ;out._size = out._size + ctype._size - ;/ - ;out.sub_types.append(ctype) - ;out.sub_names.append(data`{cur`}.data`) - - ;; else - # Get type - ;cur`-- - ;ctype = get_vtype(cur, data) - ;/ - ;/ - ;out.print() - ;type_table.append(out) - - ;return out -;/ - -# Checks if the current token's data member is equal to a given string -/; token_is(~int cur, ~{}Token data, {}uint8 str) [bool] - ;return string_equate(data`{cur`}.data`, str) -;/ - -# Skips in a definition or list until it finds a name -/; skip_to_name (~int cur, ~{}Token data) - ;int tmp = 0 - /; loop (cur` < len data`) [cur`++] - ;tmp = cur` + 1 - /; if (data`{cur`}.token_type == TOKEN_TYPE.DEFWORD && - ( token_is(~tmp, data, ",") || token_is(~tmp, data, ")") || token_is(~tmp, data, "}") || token_is(~tmp, data, ";") )) - ;break - ;/ - ;/ -;/ - -# Searches the type table for a type -/; vtype_by_name ({}uint8 name) [VType] - /; loop (int i = 0; i < len type_table) [i++] - ;VType tmp = tnslc.type_table{i} - /; if (string_equate(name, tmp.name)) - ;return tmp - ;/ - ;/ - ;return NT -;/ - -# Parses a type in a definition or list -/; get_vtype (~int cur, ~{}Token data) [VType] - ;uint ptr = 0 - ;VType out = NT - - /; loop (cur` < len data`) [cur`++] - ;int i = data`{cur`}.token_type - /; if (token_is(cur, data, "~") || token_is(cur, data, "{")) - ;ptr++ - ;; else if (i == TOKEN_TYPE.DEFWORD || i == TOKEN_TYPE.KEYTYPE) - ;out = vtype_by_name(data`{cur`}.data`) - ;break - ;; else if (!token_is(cur, data, "}")) - ;break - ;/ - ;/ - - ;out.ptr = ptr - - ;return out -;/ - -# Assumes cur points to the beginning of the arguments list -# Sets up the VTrack struct that is pointed to. -/; setup_vtrack (~int cur, ~{}Token data, ~VTrack tab, ~{}uint8 csec) - ;cur`++ - - ;VType last = NT - ;Value tmp = {false, false, 0, 0, last} - - /; loop (cur` < len data`) [cur`++] - ;int pre_skip = cur` - /; if (token_is(cur, data, ")")) - - ;break - ;; else if (!token_is(cur, data, ",")) - - ;skip_to_name(cur, data) - - /; if (pre_skip !== cur`) - ;last = get_vtype(~pre_skip, data) - ;tmp._type = last - ;/ - - ;tab`.sym_names.append(data`{cur`}.data`) - ;int nloc = tab`.next_loc(last) - - ;Value store = {false, false, nloc, 0, last} - /; if (store.loc !< 0 && tmp.loc !> 5) - ;{}uint8 tstr = store.set_value(tmp) - ;add_strings(csec, ~tstr) - ;tmp.loc = tmp.loc + 1 - ;; else - ;store.loc = 0 - ;store.on_stack = true - ;tab`.push_stack(last) - ;/ - - ;tab`.sym_vals.append(store) - ;/ - ;/ -;/ - -# Mostly deals with structs and enums -/; compile_global (~int cur, ~{}Token data, ~{}uint8 hsec, csec, dsec) - ;cur`++ - /; if (token_is(cur, data, "struct")) - ;def_struct(cur, data, dsec) - ;/ -;/ - -# Evaluate a value -/; eval_value (~int cur, ~{}Token data, ~VTrack tab, ~{}uint8 hsec, csec, dsec, int val_layer) [Value] - /; if (token_is(cur, data, ";/")) - ;return NV - ;/ - - ;Value tmp = {false, false, val_layer % 5, 0, NT} - - /; if (val_layer > 5) - ;tmp.on_stack = true - ;/ - - /; loop (cur` < len data`) - ;tnsl.io.println("looping") - /; if (data`{cur`}.token_type == TOKEN_TYPE.LITERAL) - /; if (data`{cur`}.data`{0} == '"') - # String literal - ;tmp._type = type_table{5} - ;tmp._type.ptr = 1 - ;; else if (data`{cur`}.data`{0} == '\'') - # Char literal - ;int val = unquote_char(data`{cur`}.data`) - ;Value lit = {false, true, 0, val, type_table{5}} - ;{}uint8 tmp = out.set_value(lit) - ;add_strings(csec, ~tmp) - ;; else - # int literal - ;tnsl.io.print("int literal ") - ;tnsl.io.println(data`{cur`}.data`) - ;tmp.val = int_from_string(data`{cur`}.data`) - ;tmp.literal = true - ;tmp._type = tnslc.type_table{4} - ;cur`++ - ;tnsl.io.print("next tok ") - ;tnsl.io.println(data`{cur`}.data`) - ;/ - ;; else if (data`{cur`}.token_type == TOKEN_TYPE.DEFWORD) - - /; if (is_call(cur, data)) - ;; else if (tab`.in_vtrack(data`{cur`}.data`)) - ;tmp = tab`.get_val(data`{cur`}.data`) - ;cur`++ - /; loop (token_is(cur, data, ".")) - ;cur`++ - ;tmp = tmp.get_member_value(data`{cur`}.data`) - ;cur`++ - ;/ - ;/ - - ;; else if (token_is(cur, data, "~")) - ;; else if (data`{cur`}.token_type == TOKEN_TYPE.AUGMENT) - - ;int acr = cur` - ;cur`++ - ;Value nxt = eval_value(cur, data, tab, hsec, csec, dsec, val_layer + 1) - ;{}uint8 code = "" - /; if (token_is(~acr, data, "=")) - ;code = tmp.set_value(nxt) - ;; if (token_is(~acr, data, "+")) - ;code = tmp.add_value(nxt) - ;; if (token_is(~acr, data, "-")) - ;tnsl.io.println("here") - ;code = tmp.sub_value(nxt) - ;; if (token_is(~acr, data, "*")) - ;code = tmp.mul_value(nxt) - ;; if (token_is(~acr, data, "/")) - ;code = tmp.div_value(nxt) - ;/ - ;add_strings(csec, ~code) - ;break - ;; else - ;break - ;/ - ;/ - ;return tmp -;/ - -/; get_function_label(~int cur, ~{}Token data) [{}uint8] - /; if (string_equate(data`{cur` + 1}.data`, "(")) - ;return data`{cur`}.data` - ;/ - - ;{}{}uint8 func_path = {} - - /; loop (cur` < len data`) [cur`++] - /; if (token_is(cur, data, "(")) - ;break - ;; else if (!token_is(cur, data, ".")) - ;func_path.append(data`{cur`}.data`) - ;/ - ;/ - ;{}uint8 out = "_." - ;{}uint8 jn_tmp = join(func_path, '.') - ;add_strings(~out, ~jn_tmp) - ;return out -;/ - -# Sets up a call and reports back where the return value is stored -/; eval_call (~int cur, ~{}Token data, ~VTrack tab, ~{}uint8 hsec, csec, dsec) [{}uint8] - - # Store the name of the function we are calling - ;{}uint8 to_call = get_function_label(cur, data) - ;tnsl.io.println(to_call) - # Set read head to first parameter - ;cur`++ - /; loop (!token_is(cur, data, ")")) - /; if (token_is(cur, data, ",")) - ;cur`++ - ;; else - /; if (reg < 7) - ;eval_value(cur, data, tab, hsec, csec, dsec) - ;reg++ - ;; else - ;eval_value(cur, data, tab, hsec, csec, dsec) - ;push_asm(get_reg(8, "bp")) - ;/ - ;/ - ;/ - ;cur`++ - - ;{}uint8 call_ist = call_asm(to_call) - - ;add_strings(csec, ~call_ist) - ;return "ax" -;/ - -/; is_call (~int cur, ~{}Token data) [bool] - ;bool look_def = true - /; loop (int i = cur`; i < len data`) [i++] - /; if (look_def && data`{i}.token_type == TOKEN_TYPE.DEFWORD) - ;look_def = false - ;; else if (!look_def && token_is(~i, data, ".")) - ;look_def = true - ;; else if (!look_def && token_is(~i, data, "(")) - ;return true - ;; else - ;break - ;/ - ;/ - ;return false -;/ - -# Compile a statement in a function -/; compile_statement (~int cur, ~{}Token data, ~VTrack tab, ~{}uint8 hsec, csec, dsec) [bool] - ;cur`++ - ;bool r = false - /; if (cur` !< len data`) - ;return false - ;/ - - /; if (token_is(cur, data, "asm")) - ;cur`++ - ;{}uint8 raw_asm = unquote_string(data`{cur`}.data`) - ;raw_asm.append('\n') - ;csec`.append('\t') - ;add_strings(csec, ~raw_asm) - ;cur`++ - ;; else if (token_is(cur, data, "raw")) - ;cur`++ - ;r = true - ;; else if (token_is(cur, data, "return")) - ;cur`++ - ;Value out = eval_value(cur, data, tab, hsec, csec, dsec, 0) - ;{}uint8 mv = out.mov_to_reg(0) - ;add_strings(csec, ~mv) - ;tail_guard(csec) - ;add_strings(csec, ~(tnslc.COMMON_ASM{0})) - ;return true - ;; else if (is_call(cur, data)) - # Function call - ;eval_call(cur, data, tab, hsec, csec, dsec) - ;; else if (tab.in_vtrack(data`{cur`}.data`)) - # set value - ;int i = name_to_index(data`{cur`}.data`, tab) - ;{}uint8 tmp = index_to_loc(i) - ;eval_value(cur, data, tab, hsec, csec, dsec) - ;tmp = mov_asm(get_reg(tab`.sym_types{i}._size, "ax"), tmp) - ;add_strings(csec, ~tmp) - ;; else - #Definition - ;VType def_t = get_vtype(cur, data) - ;cur`++ - - /; loop (data`{cur`}.token_type == TOKEN_TYPE.DEFWORD) - ;{}uint8 init = tab`.add_track(data`{cur`}.data`, def_t) - ;add_strings(~out, ~init) - ;cur`++ - /; if (token_is(cur, data, ",")) - ;cur`++ - ;; else if (token_is(cur, data, "=")) - ;{}uint8 set = index_to_loc(len tab`.sym_names - 1, tab) - ;eval_value(cur, data, tab, hsec, csec, dsec, loc) - /; if (token_is(cur, data, ",")) - ;cur`++ - ;/ - ;; else - ;break - ;/ - ;/ - /; if (string_equate(data`{cur`+1}.data`, "=")) - ;/ - ;; if (token_is(cur, data, "return")) - ;add_strings(csec, ~(tnslc.COMMON_ASM{0})) - ;return true - ;/ - - ;return false -;/ - - - -/; compile_block (~int cur, ~{}Token data, ~{}uint8 hsec, csec, dsec, {}{}uint8 mod_path, Path rel) - ;VTrack tab = { {}, {} } - ;VType out_type = tnslc.type_table{14} - ;{}uint8 name = "" - ;bool r = false - - /; loop (cur`++; cur` < len data`) [cur`++] - /; if (token_is(cur, data, "module")) - ;mod_path.append(data`{cur` + 1}.data`) - ;cur` = cur` + 2 - ;break - ;/ - /; if (data`{cur`}.token_type == TOKEN_TYPE.DEFWORD && len name == 0) - ;name = data`{cur`}.data` - /; if (len mod_path > 0) - ;{}uint8 frs = "_." - ;{}uint8 jn = join(mod_path, '.') - ;add_strings(~frs, ~jn) - ;add_strings(csec, ~frs) - ;csec`.append('.') - ;/ - ;add_strings(csec, ~name) - ;csec`.append(':') - ;csec`.append('\n') - /; if (!r) - ;header_guard(csec) - ;/ - ;; else if (token_is(cur, data, "(")) - ;setup_vtrack(cur, data, ~tab, csec) - ;; else if (token_is(cur, data, "[")) - ;cur`++ - ;out_type = get_vtype(cur, data) - ;cur`++ - ;; else if (token_is(cur, data, "raw")) - ;r = true - ;; else - ;break - ;/ - ;/ - - ;tnsl.io.println(out_type.name) - - ;bool ret = false - /; loop (cur` < len data` && !ret) - /; if (token_is(cur, data, ";/")) - /; if (!r) - ;tail_guard(csec) - ;/ - ;add_strings(csec, ~(tnslc.COMMON_ASM{0})) - ;break - ;; else if (token_is(cur, data, "/;")) - ;bool ch = true - /; loop (ch) - ;compile_block(cur, data, hsec, csec, dsec, mod_path) - /; if (cur` !< len data`) - ;break - ;/ - ;ch = token_is(cur, data, ";;") - ;/ - ;; else if (string_equate(data`{cur`}.data`, ":")) - ;cur` = cur` + 2 - ;Path inc = rel.rel_file(unquote_string(data`{cur`}.data`)) - ;compile_include(inc, hsec, csec, dsec, mod_path) - ;cur`++ - ;; else if (string_equate(data`{cur`}.data`, ";")) - ;ret = compile_statement(cur, data, ~tab, hsec, csec, dsec) - ;; else - ;tnsl.io.print("Failed to compile token [compile_block]: ") - ;data`{cur`}.print() - ;tnsl.io.println("") - ;break - ;/ - ;/ - - ;csec`.append('\n') -;/ - -/; compile_include (Path file_path, ~{}uint8 hsec, csec, dsec, {}{}uint8 mod_path) - # Autocomplete in the case of module syntax - ;bool d = file_path.extension_is("tnsl") - /; if (!d) - ;file_path.dirs.append(file_path.file) - ;{}uint8 ftmp = file_path.file - ;{}uint8 tmp = ".tnsl" - ;add_strings(~ftmp, ~tmp) - ;file_path.file = ftmp - ;/ - - ;tnsl.io.print("[TNSLC:INCLUDE] ") - ;tnsl.io.println(file_path.full_path()) - - ;tnsl.io.File inc = file_path.open_r() - ;~{}Token data = parse.tokenize(inc) - ;inc.close() - - ;tnsl.io.print(len data`) - ;tnsl.io.println(" tokens parsed.") - - ;compile_file(file_path, data, hsec, csec, dsec, mod_path) -;/ - -/; compile_file (Path rel, ~{}Token data, ~{}uint8 hsec, csec, dsec, {}{}uint8 mod_path) - - ;int j = len data` - - /; loop (int i = 0; i < j) [i++] - /; if (string_equate(data`{i}.data`, "/;")) - ;compile_block(~i, data, hsec, csec, dsec, mod_path, rel) - ;; else if (string_equate(data`{i}.data`, ";")) - ;compile_global(~i, data, hsec, csec, dsec) - ;; else if (string_equate(data`{i}.data`, ":")) - ;i = i + 2 - ;Path inc = rel.rel_file(unquote_string(data`{i}.data`)) - ;compile_include(inc, hsec, csec, dsec, mod_path) - ;; else - ;break - ;/ - ;/ - -;/ - -/; do_compile ({}uint8 file_out, Path rel) - ;{}uint8 hsec = ".global main\n" - ;{}uint8 csec = ".text\n" - ;{}uint8 dsec = ".data\n" - - ;tnslc.compile_include(rel, ~hsec, ~csec, ~dsec, {}) - - ;tnsl.io.File out = tnsl.io.writeFile(file_out) - - /; loop (int i = 0; i < len hsec) [i++] - ;out.write(hsec{i}) - ;/ - - ;out.write('\n') - - /; loop (int i = 0; i < len dsec) [i++] - ;out.write(dsec{i}) - ;/ - - ;out.write('\n') - - /; loop (int i = 0; i < len csec) [i++] - ;out.write(csec{i}) - ;/ - - ;out.write('\n') - ;out.close() -;/ - diff --git a/tnslc/compile/isa_x86.tnsl b/tnslc/compile/isa_x86.tnsl deleted file mode 100644 index 1cb09ab..0000000 --- a/tnslc/compile/isa_x86.tnsl +++ /dev/null @@ -1,182 +0,0 @@ -/## - Copyright 2021-2022 Kyle Gunger - - This file is licensed under the CDDL 1.0 (the License) - and may only be used in accordance with the License. - You should have received a copy of the License with this - software/source code. If you did not, a copy can be found - at the following URL: - - https://opensource.org/licenses/CDDL-1.0 - - THIS SOFTWARE/SOURCE CODE IS PROVIDED "AS IS" WITH NO - WARRANTY, GUARANTEE, OR CLAIM OF FITNESS FOR ANY PURPOSE - EXPRESS OR IMPLIED -#/ - -/; construct_statement({}uint8 base, {}{}uint8 args) [{}uint8] - /; loop (int i = 0; i < len args) [i++] - ;add_strings(~base, ~(args{i})) - /; if (i < len args - 1) - ;base.append(',') - ;base.append(' ') - ;/ - ;/ - ;base.append('\n') - ;return base -;/ - -/; literal_num ({}uint8 num) [{}uint8] - ;{}uint8 out = "$" - ;add_strings(~out, ~num) - ;return out -;/ - -/; add_asm ({}uint8 from, to) [{}uint8] - ;return construct_statement("\tadd ", {from, to}) -;/ - -/; sub_asm({}uint8 from, to) [{}uint8] - ;return construct_statement("\tsub ", {from, to}) -;/ - -/; push_asm ({}uint8 reg) [{}uint8] - ;return construct_statement("\tpush ", {reg}) -;/ - -/; pop_asm ({}uint8 reg) [{}uint8] - ;return construct_statement("\tpop ", {reg}) -;/ - -/; cmp_asm ({}uint8 a, b) [{}uint8] - ;return construct_statement("\tcmp ", {a, b}) -;/ - -/; mov_asm ({}uint8 a, b) [{}uint8] - ;return construct_statement("\tmov ", {a, b}) -;/ - -/; jmp_asm ({}uint8 pos) [{}uint8] - ;return construct_statement("\tjmp ", {pos}) -;/ - -/; call_asm ({}uint8 pos) [{}uint8] - ;return construct_statement("\tcall ", {pos}) -;/ - -/; cjmp_asm ({}uint8 suffix, pos) [{}uint8] - ;{}uint8 p = "\tj" - ;add_strings(~p, ~suffix) - ;p.append(' ') - ;return construct_statement(p, {pos}) -;/ - -/; mem_offset ({}uint8 pos, offset, scale) [{}uint8] - ;{}uint8 tmp = construct_statement("(", {pos, offset, scale}) - ;tmp{len tmp - 1} = ')' - ;return tmp -;/ - -/; header_guard (~{}uint8 csec) [{}uint8] - ;{}uint8 out = "", tmp = "" - ;tmp = push_asm("%r8") - ;add_strings(~out, ~tmp) - ;tmp = push_asm("%r9") - ;add_strings(~out, ~tmp) - ;tmp = push_asm("%r10") - ;add_strings(~out, ~tmp) - ;tmp = push_asm("%r11") - ;add_strings(~out, ~tmp) - ;tmp = push_asm("%r12") - ;add_strings(~out, ~tmp) - ;tmp = push_asm("%r13") - ;add_strings(~out, ~tmp) - ;tmp = push_asm("%r14") - ;add_strings(~out, ~tmp) - ;tmp = push_asm("%r15") - ;add_strings(~out, ~tmp) - ;add_strings(csec, ~out) -;/ - -/; tail_guard (~{}uint8 csec) [{}uint8] - ;{}uint8 out = "", tmp = "" - ;tmp = pop_asm("%r15") - ;add_strings(~out, ~tmp) - ;tmp = pop_asm("%r14") - ;add_strings(~out, ~tmp) - ;tmp = pop_asm("%r13") - ;add_strings(~out, ~tmp) - ;tmp = pop_asm("%r12") - ;add_strings(~out, ~tmp) - ;tmp = pop_asm("%r11") - ;add_strings(~out, ~tmp) - ;tmp = pop_asm("%r10") - ;add_strings(~out, ~tmp) - ;tmp = pop_asm("%r9") - ;add_strings(~out, ~tmp) - ;tmp = pop_asm("%r8") - ;add_strings(~out, ~tmp) - ;add_strings(csec, ~out) -;/ - -/; is_common_reg ({}uint8 n) [bool] - ;return string_equate(n, "ax") || string_equate(n, "bx") || string_equate(n, "cx") || string_equate(n, "dx") - || string_equate(n, "sp") || string_equate(n, "bp") || string_equate(n, "si") || string_equate(n, "di") - || string_equate(n, "8") || string_equate(n, "9") || string_equate(n, "10") || string_equate(n, "11") - || string_equate(n, "12") || string_equate(n, "13") || string_equate(n, "14") || string_equate(n, "15") -;/ - -/# Accepted common names: -# - ax -# - bx -# - cx -# - dx -# - si -# - di -# - bp -# - sp -# - 8-15 -#/ -/; get_reg (uint size, {}uint8 common) [{}uint8] - ;{}uint8 out = "%" - - /; if (common{0} !< 'a') - - /; if (size == 1) - /; if(common{1} == 'x') - ;common{1} = 'l' - ;; else - ;common.append('l') - ;/ - ;; else if (size == 4) - ;out.append('e') - ;; else if (size == 8) - ;out.append('r') - ;/ - - ;add_strings(~out, ~common) - - ;; else - - ;out.append('r') - ;add_strings(~out, ~common) - /; if (size == 1) - ;out.append('b') - ;; else if (size == 2) - ;out.append('w') - ;; else if (size == 4) - ;out.append('d') - ;/ - ;return out - ;/ - - ;return out -;/ - -/; make_label ({}uint8 func_name, func_place, ~{}uint8 csec) - ;func_name.append("_") - ;add_strings(~func_name, ~func_place) - ;func_name.append(':') - ;func_name.append('\n') - ;add_strings(csec, ~func_name) -;/ diff --git a/tnslc/compile/value.tnsl b/tnslc/compile/value.tnsl deleted file mode 100644 index da76ac8..0000000 --- a/tnslc/compile/value.tnsl +++ /dev/null @@ -1,362 +0,0 @@ -;struct Value { - bool - on_stack, - literal, - - int - loc, - val, - - VType - _type -} - -;Value NV = {false, false, 0, 0, 0, {0, 0, "null", {}, {}}} - -/; val_from_address (int offset, {}uint8 reg) [{}uint8] - ;{}uint8 out = string_from_int(offset) - ;out.append('(') - ;add_strings(~out, ~reg) - ;out.append(')') - ;return out -;/ - - -# The temp registers in order -/; 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" - ;/ - ;return string_from_int(r + 2) -;/ - -/; ext_by_size(int s) [uint8] - /; if (r == 1) - ;return 'b' - ;; if (r == 2) - ;return 'w' - ;; if (r == 4) - ;return 'l' - ;/ - ;return 'q' -;/ - - -/; method Value - - /; get_norm_sz [int] - /; if (self._type.ptr !== 0) - ;return 8 - ;/ - ;returnself._type._size - ;/ - - /; get_norm_loc [{}uint8] - /; if (self.on_stack) - ;return val_from_address(self.loc, "%rsp") - ;; if (!(self.on_stack) && self._type.ptr == 0 && is_struct(self._type)) - ;{}uint8 out = "(" - ;{}uint8 tmp = get_reg(8, reg_by_num(self.loc)) - ;add_strings(~out, ~tmp) - ;out.append(')') - ;return out - ;/ - - /; if (self.literal) - ;{}uint8 out = "$" - ;{}uint8 num = string_from_int(self.val) - ;add_strings(~out, ~num) - ;return out - ;/ - - ;int sz = self._type._size - /; if (self._type.ptr !== 0) - ;sz = 8 - ;/ - - ;return get_reg(sz, reg_by_num(self.loc)) - ;/ - - /; init_val [{}uint8] - /; if (self.literal || !self.on_stack) - ;return "" - ;/ - - ;{}uint8 out = "\tsub $" - ;{}uint8 tmp = string_from_int(self._type._size) - ;add_strings(~out, ~tmp) - ;tmp = ", %rsp\n" - ;add_strings(~out, ~tmp) - ;return out - ;/ - - /; standard_op(Value other, {}uint8 op) [{}uint8] - ;tnsl.io.print("Std op ") - ;tnsl.io.println(op) - ;int tsz = other._type._size - ;other._type._size = self._type._size - ;{}uint8 tmp = other.get_norm_loc() - ;other._type._size = tsz - ;{}uint8 out = "\t" - ;add_strings(~out, ~op) - ;out.append(' ') - ;add_strings(~out, ~tmp) - ;out.append(',') - ;out.append(' ') - ;tmp = self.get_norm_loc() - ;add_strings(~out, ~tmp) - ;out.append('\n') - ;return out - ;/ - - /; add_value (Value v) [{}uint8] - /; if (self.literal) - ;self.val = self.val + v.val - ;return "" - ;; else if (!(self.on_stack)) - ;return self.standard_op(v, "add") - ;/ - ;/ - - /; sub_value (Value v) [{}uint8] - /; if (self.literal) - ;self.val = self.val - v.val - ;return "" - ;; else if (!(self.on_stack)) - ;return self.standard_op(v, "sub") - ;/ - ;/ - - /; ax_compute(Value v, {}uint8 op, bool save_dx) - ;{}uint8 out = "\tpush %rax\n\tpush %rdx\n" - - /; if (v.on_stack) - ;v.loc = v.loc + 16 - ;; if (self.on_stack) - ;self.loc = self.loc + 16 - ;/ - - ;{}uint8 tmp = "\tmov " - ;{}uint8 t2 = v.get_norm_loc() - ;add_strings(~tmp, ~t2) - ;t2 = ", %rax\n" - ;add_strings(~tmp, ~t2) - ;add_strings(~out, ~tmp) - - ;tmp = "\txor %rdx, %rdx\n" - ;add_strings(~out, ~tmp) - - ;tmp = "\t" - ;add_strings(~tmp, ~op) - ;tmp.append(' ') - ;{}uint8 t2 = self.get_norm_loc() - ;add_strings(~tmp, ~t2) - ;tmp.append('\n') - ;add_strings(~out, ~tmp) - - /; if (save_dx) - ;tmp = "\tmov %rdx, " - ;; else - ;tmp = "\tmov %rax, " - ;/ - ;add_strings(~tmp, ~t2) - ;tmp.append('\n') - ;add_strings(~out, ~tmp) - - /; if (v.on_stack) - ;v.loc = v.loc - 16 - ;; if (self.on_stack) - ;self.loc = self.loc - 16 - ;/ - - ;tmp = "\tpop %rdx\n\tpop %rax" - ;add_strings(~out, ~tmp) - ;return out - ;/ - - /; mul_value (Value v) [{}uint8] - /; if (self.literal) - ;self.val = self.val * v.val - ;return "" - ;; else if (!(self.on_stack)) - /; if (self._type.name{0} !== 'u') - ;return self.standard_op(v, "imul") - ;/ - - ;return self.ax_compute(v, "mul", false) - ;/ - ;/ - - /; div_value (Value v) [{}uint8] - /; if (self.literal) - ;self.val = self.val + v.val - ;return "" - ;; else if (!(self.on_stack)) - /; if (self._type.name{0} !== 'u') - ;return self.ax_compute(v, "idiv", false) - ;/ - - ;return self.ax_compute(v, "div", false) - ;/ - ;/ - - /; mod_value (Value v) [{}uint8] - /; if (self.literal) - ;self.val = self.val / v.val - ;return "" - ;; else if (!self.on_stack) - /; if (self._type.name{0} !== 'u') - ;return self.ax_compute(v, "idiv", true) - ;/ - - ;return self.ax_compute(v, "div", true) - ;/ - ;/ - - /; ref_value (Value to_ref) [{}uint8] - /; if (!to_ref.on_stack) - ;return "" - ;/ - - ;return self.standard_op(to_ref, "lea") - ;/ - - /; deref_value [{}uint8] - /; if (self._type.ptr == 0) - ;return "" - ;/ - - ;Value new = self - ;new._type.ptr = new._type.ptr - 1 - ;{}uint8 out = "\tmov (" - ;{}uint8 tmp = self.get_norm_loc() - ;add_strings(~out, ~tmp) - ;out.append(')') - ;out.append(',') - ;out.append(' ') - ;tmp = new.get_norm_loc() - ;add_strings(~out, ~tmp) - - ;self = new - ;return out - ;/ - - /; get_index (Value index) [Value] - /; if (self._type.ptr == 0) - ;return NV - ;/ - ;/ - - /; set_value (Value v) [{}uint8] - /; if (self.literal) - ;self.val = v.val - ;return "" - ;; else if (!(self.on_stack)) - /; if (!is_struct(self._type)) - ;return self.standard_op(v, "mov") - ;/ - # This is the case where we are storing an address to - # a struct in a register. - ;{}charp out = "\tpush %rcx\n\tmov " - ;{}charp tmp = self.get_norm_loc() - ;add_strings(~out, ~tmp) - ;tmp = ", %rcx\n" - ;add_strings(~out, ~tmp) - ;tmp = self.standard_op(v, "movsb") - ;add_strings(~out, ~tmp) - ;tmp = "\tpop %rcx" - ;add_strings(~out, ~tmp) - ;return out - ;/ - - /; if (self._type._size !> 8) - /; if (!v.on_stack) - ;return self.standard_op(v, "mov") - ;/ - ;{}charp out = "\tpush %rax\n\tmov " - ;{}charp tmp = v.get_norm_loc() - ;add_strings(~out, ~tmp) - ;tmp = ", %rax\n" - ;add_strings(~out, ~tmp) - ;tmp = self.standard_op(v, "mov") - ;add_strings(~out, ~tmp) - ;return out - ;/ - - ;/ - - /; load_label_address ({}uint8 lab) [{}uint8] - ;{}uint8 out = "\tlea " - ;{}uint8 tmp = "(%rip), " - ;add_strings(~out, ~lab) - ;add_strings(~out, ~tmp) - ;tmp = self.get_norm_loc() - ;add_strings(~out, tmp) - ;out.append('\n') - ;return out - ;/ - - /; get_member_value ({}uint8 name) [Value] - ;Value out = self - /; if (self.on_stack) - ;out.loc = out.loc + self._type.get_offset(name) - ;; else - ;out.val = out.val + self._type.get_offset(name) - ;/ - ;out._type = self._type.get_sub_type(name) - ;out._type.ptr = -1 - ;return out - ;/ - - /; mov_to_reg (int reg) [{}uint8] - /; if (!(self.on_stack)) - ;return self.update_loc(0) - ;/ - ;/ - - /; update_loc(int loc) [{}uint8] - /; if (self.on_stack) - ;self.loc = self.loc + loc - ;; else if (!(self.literal)) - ;{}uint8 out = "\tmov " - ;int tsz = self._type._size - ;self._type._size = 8 - - ;{}uint8 tmp = self.get_norm_loc() - ;add_strings(~out, ~tmp) - ;out.append(',') - ;out.append(' ') - - ;self.loc = loc - - ;tmp = self.get_norm_loc() - ;add_strings(~out, ~tmp) - ;out.append('\n') - - ;self._type._size = tsz - ;return out - ;/ - ;return "" - ;/ - -;/ - -/; literal_val (int l, VType t) [Value] - ;return {false, true, 0, l, t} -;/ - -/; track_val(VType ty, bool on_stack, int loc) [Value] - ;return {on_stack, false, loc, 0, ty} -;/ diff --git a/tnslc/copy.tnsl b/tnslc/copy.tnsl deleted file mode 100644 index 0cc594e..0000000 --- a/tnslc/copy.tnsl +++ /dev/null @@ -1,30 +0,0 @@ -/# - Proof of concept that the language can copy any file. - - For testing with executibles to make sure that the language's current state - would be able to produce one from data alone. - - Seems to work. -#/ - -/; main ({}{}uint8 args) [int] - /; if (len args < 2) - ;tnsl.io.println("Usage: copy [file to copy] [path to copy to]") - ;return 1 - ;/ - - ;tnsl.io.File in = tnsl.io.readFile(args{0}) - ;tnsl.io.File out = tnsl.io.writeFile(args{1}) - - /; loop (int chk = in.read(); chk !< 0) [chk = in.read()] - ;uint8 write = chk - ;out.write(write) - ;/ - - ;tnsl.io.println("Copy complete.") - - ;in.close() - ;out.close() - - ;return 0 -;/ diff --git a/tnslc/dummy.tnsl b/tnslc/dummy.tnsl deleted file mode 100644 index 741a0e0..0000000 --- a/tnslc/dummy.tnsl +++ /dev/null @@ -1,33 +0,0 @@ -;struct test { - int8 i, j, k, l -} - -;struct test2 { - test a, b -} - -/; add (int a, b) [int] - ;return a + b - 9 - 30 -;/ - -/; main (uint argc, ~~uint8 argv) [int] - # Fix for main func - ;asm "mov %rdi, %r8" - ;asm "mov %rsi, %r9" - # ;~void ptr = _alloc(10) - # ;_delete(ptr) - # ;return add(argc, 2) -;/ - - -/; _alloc (uint bytes) [~void] - ;asm "mov %rax, %rdi" - ;asm "mov $0, %r10" - ;asm "call malloc" -;/ - -/; _delete (~void ptr) - ;asm "mov %rax, %rdi" - ;asm "mov $0, %r10" - ;asm "call free" -;/ diff --git a/tnslc/inc.tnsl b/tnslc/inc.tnsl deleted file mode 100644 index 6e17855..0000000 --- a/tnslc/inc.tnsl +++ /dev/null @@ -1,3 +0,0 @@ -/; module main - :include "dummy.tnsl" -;/ \ No newline at end of file diff --git a/tnslc/parse/parse.tnsl b/tnslc/parse/parse.tnsl deleted file mode 100644 index 8919c3a..0000000 --- a/tnslc/parse/parse.tnsl +++ /dev/null @@ -1,87 +0,0 @@ -/## - Copyright 2021-2022 Kyle Gunger - - This file is licensed under the CDDL 1.0 (the License) - and may only be used in accordance with the License. - You should have received a copy of the License with this - software/source code. If you did not, a copy can be found - at the following URL: - - https://opensource.org/licenses/CDDL-1.0 - - THIS SOFTWARE/SOURCE CODE IS PROVIDED "AS IS" WITH NO - WARRANTY, GUARANTEE, OR CLAIM OF FITNESS FOR ANY PURPOSE - EXPRESS OR IMPLIED -#/ - -/; export module parse - :include "parse/token.tnsl" - :include "parse/tokenizer.tnsl" -;/ - -/; create_panic ({}uint8 err) - ;tnsl.io.println("ABOUT TO INDUCE PANIC... STAND BY") - ;tnsl.io.print("Error code given: ") - ;tnsl.io.println(err) - ;{}int i = {0} - ;i{2} -;/ - -/# The various types of tokens #/ -; enum TOKEN_TYPE [int] { - LINESEP = 0, - INLNSEP = 1, - DELIMIT = 2, - AUGMENT = 3, - LITERAL = 4, - KEYTYPE = 5, - PREWORD = 6, - KEYWORD = 7, - DEFWORD = 8 -} - -/# Token struct definition #/ -; struct Token { - int - token_type, - line, - col, - - ~{}uint8 - data -} - -/; method Token - - /; print - ;tnsl.io.print("{ ") - ;tnsl.io.print(self.token_type) - ;tnsl.io.print(" ") - ;tnsl.io.print(self.data`) - ;tnsl.io.print(" ") - ;tnsl.io.print(self.line) - ;tnsl.io.print(" ") - ;tnsl.io.print(self.col) - ;tnsl.io.print(" } ") - ;/ - - /; operator delete - ;delete self.data - ;/ - - /; add_char (~{}uint8 part) - # ;uint l = len self.data` - # ;realloc self.data, l + len part - /; loop (int i = 0; i < len part`) [i++] - # ;self.data`{l + i} = part{i} - ;self.data`.append(part`{i}) - ;/ - ;/ -;/ - -/; print_tokens(~{}Token dat) - /; loop (int i = 0; i < len dat`) [i++] - ;dat`{i}.print() - ;/ - ;tnsl.io.print("\n") -;/ diff --git a/tnslc/parse/token.tnsl b/tnslc/parse/token.tnsl deleted file mode 100644 index fecc7f7..0000000 --- a/tnslc/parse/token.tnsl +++ /dev/null @@ -1,331 +0,0 @@ -/# - Copyright 2021-2022 Kyle Gunger - - This file is licensed under the CDDL 1.0 (the License) - and may only be used in accordance with the License. - You should have received a copy of the License with this - software/source code. If you did not, a copy can be found - at the following URL: - - https://opensource.org/licenses/CDDL-1.0 - - THIS SOFTWARE/SOURCE CODE IS PROVIDED "AS IS" WITH NO - WARRANTY, GUARANTEE, OR CLAIM OF FITNESS FOR ANY PURPOSE - EXPRESS OR IMPLIED -#/ - -/# - Reserved words and characters, as well as - helper funcs for checking their token types. -#/ - -;{}{}uint8 PREWORDS = { - "include", - "define", - "extern", - "size", - "align", - "address", - "rootfile", - "if", - "else", - "abi" -} - -;{}{}uint8 KEYTYPES = { - "int8", - "int16", - "int32", - "int64", - "int", - - "uint8", - "uint16", - "uint32", - "uint64", - "uint", - - "float32", - "float64", - "float", - - "bool", - "void", - "type" -} - -;{}{}uint8 KEYWORDS = { - "struct", - "interface", - "enum", - "extends", - - "loop", - "continue", - "break", - - "match", - "case", - "default", - - "label", - "goto", - - "if", - "else", - - "const", - "static", - "volatile", - - "method", - "override", - "operator", - - "raw", - "asm", - "inline", - "virtual", - - "delete", - "alloc", - "salloc", - "realloc", - - "module", - "export" -} - -;{}{}uint8 LITERALS = { - "true", - "false", - - "null", - - "self", - "super" -} - -;{}uint8 RESERVED = "`~!#%^&*()-=+[]{}|;:,.<>/" - -;{}uint8 DELIMITS = "()[]{}" -;{}uint8 LINESEPS = ";:#" -;{}uint8 INLNSEPS = "," -;{}uint8 AUGMENTS = "~`.&|^>>", - - # PREaugmented augmentors - "&=", - "|=", - "^=", - "+=", - "-=", - "*=", - "/=", - "%=", - "~=", - "`=", - - # POSTaugmented augmentors - "!&", - "!|", - "!^", - "!==", - "!&&", - "!||", - "!>", - "!<", - ">==", - "<==", - - # Increment and De-increment - "++", - "--", - - "is", - "len", - "size" -} - -;int MAX_MRESERVED = 3 - -/## - Checks if the character point p is in the string cmp - -#; is_in_string (~{}uint8 cmp, uint8 p) [bool] - - /; loop (int i = 0; i < len cmp`) [i++] - /; if (p == cmp`{i}) - ;return true - ;/ - ;/ - - ;return false -;/ - -/## - Checks if the string s is in the list cmp - -#; is_in_string_list (~{}{}uint8 cmp, ~{}uint8 s) [bool] - - /; loop (int i = 0; i < len cmp`) [i++] - - /; if (len s` == len cmp`{i}) - - /; loop (int j = 0; j < len s`) [j++] - - /; if (s`{j} !== cmp`{i}{j}) - ;break 1 - ;/ - ;/ - - ;return true - ;/ - - ;/ - - ;return false -;/ - -/; is_numeric_literal(~{}uint8 dat) [bool] - /; if (len dat` == 0) - ;return false - ;/ - - ;bool dec = true, flt = false - - ;int i = 0 - - /; if (len dat` > 1) - /; if (dat`{0} == '0' && !is_digit(dat`{1}) && dat`{1} !== '.') - ;dec = false - ;i = 2 - ;/ - ;/ - - /; loop (i < len dat`) [i++] - /; if (!is_digit(dat`{i}) && dec) - /; if (dat`{i} == '.') - /; if (flt) - ;return false - ;/ - ;flt = true - ;; else if (dec) - ;return false - ;/ - ;/ - ;/ - - ;return true -;/ - -/; is_text_literal(~{}uint8 dat) [bool] - /; if (len dat` < 1) - ;return false - ;/ - ;return dat`{0} == '"' || dat`{0} == '\'' -;/ - -/; string_closed ({}uint8 dat, uint8 c) [bool] - /; if (len dat < 2) - ;return false - ;/ - - ;uint8 closing = dat{0} - ;bool escaping = false - - /; loop (int i = 1; i < len dat) [i++] - /; if (dat{i} == closing && !escaping) - ;return true - ;; else if (dat{i} == '\\' && !escaping) - ;escaping = true - ;; else - ;escaping = false - ;/ - ;/ - - ;return false -;/ - -/# - Get the token_type value for a given string of character points - -#; get_token_type (~{}uint8 s) [int] - - /; if (len s` > 1) - - /; if (is_numeric_literal(s) || s`{0} == '"' || s`{0} == '\'') - ;return TOKEN_TYPE.LITERAL - ;/ - - /; if (is_in_string_list(~PREWORDS, s)) - ;return TOKEN_TYPE.PREWORD - ;; else if (is_in_string_list(~KEYTYPES, s)) - ;return TOKEN_TYPE.KEYTYPE - ;; else if (is_in_string_list(~KEYWORDS, s)) - ;return TOKEN_TYPE.KEYWORD - ;; else if (is_in_string_list(~LITERALS, s)) - ;return TOKEN_TYPE.LITERAL - ;; else if (is_in_string_list(~MDELIMITS, s)) - ;return TOKEN_TYPE.DELIMIT - ;; else if (is_in_string_list(~MAUGMENTS, s)) - ;return TOKEN_TYPE.AUGMENT - ;/ - - ;return TOKEN_TYPE.DEFWORD - - ;;else if (len s` == 1) - - /; if (is_digit(s`{0})) - ;return TOKEN_TYPE.LITERAL - ;/ - - /; if (is_in_string(~DELIMITS, s`{0})) - ;return TOKEN_TYPE.DELIMIT - ;; else if (is_in_string(~LINESEPS, s`{0})) - ;return TOKEN_TYPE.LINESEP - ;; else if (is_in_string(~INLNSEPS, s`{0})) - ;return TOKEN_TYPE.INLNSEP - ;; else if (is_in_string(~AUGMENTS, s`{0})) - ;return TOKEN_TYPE.AUGMENT - ;/ - - ;return TOKEN_TYPE.DEFWORD - ;/ - - # What, we just produce vacant tokens now? - # Something has gone wrong. - - ;return -1 -;/ \ No newline at end of file diff --git a/tnslc/parse/tokenizer.tnsl b/tnslc/parse/tokenizer.tnsl deleted file mode 100644 index 30ccd4b..0000000 --- a/tnslc/parse/tokenizer.tnsl +++ /dev/null @@ -1,114 +0,0 @@ -/# - Copyright 2021-2022 Kyle Gunger - - This file is licensed under the CDDL 1.0 (the License) - and may only be used in accordance with the License. - You should have received a copy of the License with this - software/source code. If you did not, a copy can be found - at the following URL: - - https://opensource.org/licenses/CDDL-1.0 - - THIS SOFTWARE/SOURCE CODE IS PROVIDED "AS IS" WITH NO - WARRANTY, GUARANTEE, OR CLAIM OF FITNESS FOR ANY PURPOSE - EXPRESS OR IMPLIED -#/ - -/; is_float (~{}uint8 dat) [bool] - ;return is_numeric_literal(dat) && is_in_string(dat, '.') -;/ - -/; break_token ({}uint8 dat, uint8 c) [bool] - /; if (len dat == 0) - ;return false - - ;; else if (dat{0} == '"' || dat{0} == '\'') - ;return string_closed(dat, c) - - ;; else if (is_in_string(~RESERVED, dat{len dat - 1})) - - /; if (is_in_string(~RESERVED, c)) - ;dat.append(c) - ;return get_token_type(~dat) == TOKEN_TYPE.DEFWORD - - ;; else if (len dat == 1 && dat{0} == '.') - ;return !is_digit(c) - - ;/ - - ;return true - - ;; else if (is_in_string(~RESERVED, c)) - - /; if (is_numeric_literal(~dat) && !is_float(~dat) && c == '.') - ;return false - - ;/ - - ;return true - ;/ - - ;return is_whitespace(c) -;/ - -/; strip_and_expand (~{}Token dat) [{}Token] - ;{}Token out = {} - - ;bool cblk = false - - /; loop (int i = 0; i < len dat`) [i++] - /; if (!cblk) - /; if (string_equate(dat`{i}.data`, "/#")) - ;cblk = true - ;; else - ;out.append(dat`{i}) - ;/ - - ;; else if (string_equate(dat`{i}.data`, "#/")) - ;cblk = false - ;/ - ;/ - - ;return out -;/ - -/; tokenize (tnsl.io.File fstr) [~{}Token] - ;{}Token out = {} - ;{}uint8 tdat = {} - ;bool comment = false - ;int line = 1, col = 1 - - /; loop (int i = fstr.read(); i !== -1) [i = fstr.read()] - /; if (break_token(tdat, i) && !comment) - /; if (len tdat == 1 && tdat{0} == '#') - ;tdat = {} - ;comment = true - ;; else if (len tdat > 0) - ;{}uint8 tmp = tdat - ;Token ttk = {get_token_type(~tmp), line, col, ~tmp} - ;out.append(ttk) - ;tdat = {} - ;/ - ;/ - - /; if ( (!is_whitespace(i) || is_text_literal(~tdat)) && !comment ) - ;tdat.append(i) - ;; else if (i == '\n') - ;line++ - ;col = 0 - /; if (comment) - ;comment = false - ;/ - ;/ - - ;col++ - ;/ - - /; if (len tdat > 0) - ;Token ttk = {get_token_type(~tdat), line, col, ~tdat} - ;out.append(ttk) - ;/ - - ;out = strip_and_expand(~out) - ;return ~out -;/ diff --git a/tnslc/paths.tnsl b/tnslc/paths.tnsl deleted file mode 100644 index 17719a0..0000000 --- a/tnslc/paths.tnsl +++ /dev/null @@ -1,103 +0,0 @@ -# Requires util.tnsl -;struct Path { - {}{}uint8 dirs, - {}uint8 file -} - -/; method Path - /; rel_file ({}uint8 rpath) [Path] - ;{}{}uint8 spl = split(rpath, '/') - ;Path out = {{}, ""} - - /; loop (int i = 0; i < len (self.dirs)) [i++] - ;out.dirs.append(self.dirs{i}) - ;/ - - /; loop (int i = 0; i < len spl - 1) [i++] - ;out.dirs.append(spl{i}) - ;/ - - ;out.file = spl{len spl - 1} - ;return out - ;/ - - /; full_path [{}uint8] - ;{}uint8 out = join((self.dirs), '/') - /; if (len (self.dirs) > 0) - ;out.append('/') - ;/ - ;add_strings(~out, ~(self.file)) - ;return out - ;/ - - /; open_w [tnsl.io.File] - ;return tnsl.io.writeFile(self.full_path()) - ;/ - - /; open_r [tnsl.io.File] - ;return tnsl.io.readFile(self.full_path()) - ;/ - - /; extension_is ({}uint8 chk) [bool] - ;{}uint8 ext = "" - ;int dot = -1 - /; loop (int i = len (self.file) - 1; i > 0) [i = i - 1] - /; if (self.file{i} == '.') - ;dot = i - ;break - ;/ - ;/ - - /; if (dot > 0) - ;dot++ - /; loop (dot < len (self.file)) [dot++] - ;ext.append(self.file{dot}) - ;/ - ;/ - - ;return string_equate(chk, ext) - ;/ - -;/ - -/; split({}uint8 str, uint8 c) [{}{}uint8] - ;{}{}uint8 out = {} - ;{}uint8 tmp = "" - - /; loop (int i = 0; i < len str) [i++] - /; if (str{i} == c) - ;out.append(tmp) - ;{}uint8 tmp = "" - ;true # work around for interpreter bug - ;; else - ;tmp.append(str{i}) - ;/ - ;/ - ;out.append(tmp) - - ;return out -;/ - -/; join ({}{}uint8 s, uint8 jc) [{}uint8] - ;{}uint8 out = "" - /; loop (int i = 0; i < len s) [i++] - /; loop (int j = 0; j < len s{i}) [j++] - ;out.append(s{i}{j}) - ;/ - /; if (i < len s - 1) - ;out.append(jc) - ;/ - ;/ - - ;return out -;/ - -/; path_from_str ({}uint8 f) [Path] - ;{}{}uint8 spl = split(f, '/') - ;Path out = {{}, ""} - /; loop (int i = 0; i < len spl - 1) [i++] - ;out.dirs.append(spl{i}) - ;/ - ;out.file = spl{len spl - 1} - ;return out -;/ diff --git a/tnslc/test.tnsl b/tnslc/test.tnsl new file mode 100644 index 0000000..b274dfd --- /dev/null +++ b/tnslc/test.tnsl @@ -0,0 +1,21 @@ +struct PTR_TEST { + int dat, in +} + +struct ARRAY_TEST { + {}PTR_TEST dat +} + +enum ENUM_TEST [{}int] { + A = {2, 3, 4, 5, 623459}, + B = {1, 2} +} + +enum EN_ARR [PTR_TEST] { + A = {1, 2}, + B = {3, 4} +} + +/; main [int] + return EN_ARR.A.dat +;/ \ No newline at end of file diff --git a/tnslc/tests/complex/enums.tnsl b/tnslc/tests/complex/enums.tnsl new file mode 100644 index 0000000..80776f0 --- /dev/null +++ b/tnslc/tests/complex/enums.tnsl @@ -0,0 +1,84 @@ +# Enums should be able to store structs as well +struct EnumTester { + int i, j + ~EnumTester ptr +} + +# Simple integer enum +enum IntEnum [int] { + A = 0, + B = 1, + C = -2 +} + +# Simple float enum +enum FloatEnum[float] { + A = 0.1, + B = 0.2, + C = 3.1415 +} + +# More complex struct enum +enum TestEnum [EnumTester] { + A = {1, 2, null}, + B = {2, 3, ~TestEnum.A}, + C = {3, 3, null} +} + +# Type enum +enum TypeEnum [type] { + A = int, + B = float, + C = EnumTester +} + +enum SurfaceType [int] { + LAND = 0, + WATER = 1, + AIR = 2, + + SPACE = -1 +} + +/; interface Vehicle + /; fuel [float] ;/ + /; max_speed [float] ;/ + /; min_speed [float] ;/ + /; can_travel (SurfaceType surface) [bool] ;/ +;/ + +struct Car extends Vehicle { + int wheels +} + +struct Boat extends Vehicle { + int propellers +} + +struct Plane extends Vehicle { + bool biplane, passenger + int engines, +} + +struct Rocket extends Vehicle { + int + engines, + stages +} + +struct HoverCraft extends Vehicle { + {3}float + max_antigrav, + bool + space_ready +} + +# Enums can also handle interfaces (and extended types) +# but only if the given standard library has support for those things +enum CommonVehicles [Vehicle] { + A = {4}[Car], + B = {1}[Boat], + C = {false, true, 2}[Plane], + D = {4, 5}[Rocket], + E = {{5, 14.8, 5}, false}[HoverCraft] +} diff --git a/tnslc/tests/complex/generics.tnsl b/tnslc/tests/complex/generics.tnsl new file mode 100644 index 0000000..3f62474 --- /dev/null +++ b/tnslc/tests/complex/generics.tnsl @@ -0,0 +1,35 @@ +struct ListNode (type T) { + T element, + ~ListNode(T) next +} + +/; method ListNode + /; get_el [T] + return self.element + ;/ + + /; get_next [ListNode(T)] + return self.next` + ;/ +;/ + +struct ReferenceNode (type T) extends ListNode(T`) { + super +} + +/; method ReferenceNode + /; change_ref (~T new_ref) + ~self.element = new_ref + ;/ +;/ + +struct List(type T) { + +} + +# Generic (type T) +# Unknown generic (?) +# Ref to a type (type T) -> T` +# Ref types can be used interchangably with their referenced type while pointer types can not +# Variables typed by reference have the additional trait that you can +# set the address of that variable \ No newline at end of file diff --git a/tnslc/tests/complex/if_else.tnsl b/tnslc/tests/complex/if_else.tnsl new file mode 100644 index 0000000..d965e6b --- /dev/null +++ b/tnslc/tests/complex/if_else.tnsl @@ -0,0 +1,46 @@ +/; main [int] + /; if () + + ;/ + + /; if () + + ;; else + + ;/ + + /; if () + + ;//; else + + ;/ + + /; if () + + ;; else if () + + ;/ + + /; if () [] + ;; else if () [] + ;; else [] + ;/ + + /; if () [] + ;; if () [] + ;; else [] + ;/ + + /; if () [] + ;; if () [] + ;; else if () [] + ;; else [] + ;/ + + int i = 0 + + # Short if syntax for variable declaration + i = if (i < 1) [7] else [9] + + ;return 0 +;/ \ No newline at end of file diff --git a/tnslc/tests/complex/interfaces.tnsl b/tnslc/tests/complex/interfaces.tnsl new file mode 100644 index 0000000..e69de29 diff --git a/tnslc/tests/complex/loops.tnsl b/tnslc/tests/complex/loops.tnsl new file mode 100644 index 0000000..e69de29 diff --git a/tnslc/tests/complex/switch.tnsl b/tnslc/tests/complex/switch.tnsl new file mode 100644 index 0000000..e69de29 diff --git a/tnslc/tests/simple/comments.tnsl b/tnslc/tests/simple/comments.tnsl new file mode 100644 index 0000000..dbece20 --- /dev/null +++ b/tnslc/tests/simple/comments.tnsl @@ -0,0 +1,52 @@ +# These are tests for where comments may be located +# as well as the type of comments that may be parsed. +# A '#' denotes a single line comment, and will +# ignore everything on the line. +# '/#' denotes the start of a multi line comment +# if you want to use '#/' (the end of a multiline comment) +# inside of a multiline comment, use '#' at the start of the line +# to escape the whole line. + +/# + This is an example + of a multiline comment. +#/ + +/# +# This is also a multiline comment +# however, you can use #/ +# inside of it because we have '#' at +# the start of each line +#/ + +/## +# This is an example of a doc comment. +# It is a doc comment of a code block because it starts with '/##' instead of '/#' +# and ends with '# ;' which ends the comment and opens a block. +# This doc comment is on the main function +#; main /# Comment inside function declaration #/ [int /# Comment inside this list of outputs #/ ] + return 0 # line comment inside a function + /# Block comment inside function #/ +;/ + +/# Comment before block opens #/ /; interface /# Comment in interface block definition #/ ITest + # Comment in interface block + /; test_method [int] ;/ +/# Comment before block closes #/ ;/ + +struct Test { + # comment inside a list of member variables + int /# Comment btwn type and variable name #/ i +} + +/; method /# Comment in method block definition #/ Test + # Comment in method block + /; /# Comment before method name#/ test_method (/# Comment inside function params #/) [/# comment inside return type again#/ int] +/# Comment at start of line before statement#/ return /# Comment btwn return and value #/ i + ;/ + + /; cf_comment [int] + + ;/ +;/ + diff --git a/tnslc/tests/simple/if_else.tnsl b/tnslc/tests/simple/if_else.tnsl new file mode 100644 index 0000000..e69de29 diff --git a/tnslc/tests/simple/includes_a.tnsl b/tnslc/tests/simple/includes_a.tnsl new file mode 100644 index 0000000..930098a --- /dev/null +++ b/tnslc/tests/simple/includes_a.tnsl @@ -0,0 +1 @@ +:include "includes_b.tnsl" \ No newline at end of file diff --git a/tnslc/tests/simple/includes_b.tnsl b/tnslc/tests/simple/includes_b.tnsl new file mode 100644 index 0000000..e69de29 diff --git a/tnslc/tests/simple/modules_a.tnsl b/tnslc/tests/simple/modules_a.tnsl new file mode 100644 index 0000000..e69de29 diff --git a/tnslc/tests/simple/modules_b.tnsl b/tnslc/tests/simple/modules_b.tnsl new file mode 100644 index 0000000..e69de29 diff --git a/tnslc/tests/simple/structs.tnsl b/tnslc/tests/simple/structs.tnsl new file mode 100644 index 0000000..e69de29 diff --git a/tnslc/tnslc.tnsl b/tnslc/tnslc.tnsl deleted file mode 100644 index 7ca1dfb..0000000 --- a/tnslc/tnslc.tnsl +++ /dev/null @@ -1,43 +0,0 @@ -/## - Copyright 2021-2022 Kyle Gunger - - This file is licensed under the CDDL 1.0 (the License) - and may only be used in accordance with the License. - You should have received a copy of the License with this - software/source code. If you did not, a copy can be found - at the following URL: - - https://opensource.org/licenses/CDDL-1.0 - - THIS SOFTWARE/SOURCE CODE IS PROVIDED "AS IS" WITH NO - WARRANTY, GUARANTEE, OR CLAIM OF FITNESS FOR ANY PURPOSE - EXPRESS OR IMPLIED -#/ - -:include "util.tnsl" -:include "paths.tnsl" - -/; export module tnslc - :include "parse/parse.tnsl" - :include "compile/compile.tnsl" - :include "compile/isa_x86.tnsl" - :include "compile/value.tnsl" -;/ - -/; main ({}{}uint8 args) [int] - /; if (len args < 1) - ;tnsl.io.println("Usage: tnslc [file in]") - ;return 1 - ;/ - - ;{}uint8 file = args{0} - - # ;tnslc.Node tree_node = tnslc.ast.make_tree(psrc, args{0}) - - ;Path rel = path_from_str(file) - ;file.append('.') - ;file.append('S') - ;tnslc.do_compile(file, rel) - - ;return 0 -;/ diff --git a/tnslc/util.tnsl b/tnslc/util.tnsl deleted file mode 100644 index d4a7b4b..0000000 --- a/tnslc/util.tnsl +++ /dev/null @@ -1,199 +0,0 @@ -/## - Copyright 2021-2022 Kyle Gunger - - This file is licensed under the CDDL 1.0 (the License) - and may only be used in accordance with the License. - You should have received a copy of the License with this - software/source code. If you did not, a copy can be found - at the following URL: - - https://opensource.org/licenses/CDDL-1.0 - - THIS SOFTWARE/SOURCE CODE IS PROVIDED "AS IS" WITH NO - WARRANTY, GUARANTEE, OR CLAIM OF FITNESS FOR ANY PURPOSE - EXPRESS OR IMPLIED -#/ - -/# util.tnsl - Utility functions that may be useful in many places. -#/ - -/; string_equate({}uint8 s1, s2) [bool] - /; if (len s1 !== len s2) - ;return false - ;/ - - /; loop (int i = 0; i < len s1) [i++] - /; if (s1{i} !== s2{i}) - ;return false - ;/ - ;/ - - ;return true -;/ - -/; add_strings (~{}uint8 a, b) - /; loop (int i = 0; i < len b`) [i++] - ;a`.append(b`{i}) - ;/ -;/ - -/; reverse_string({}uint8 str) [{}uint8] - ;{}uint8 out = "" - - /; loop (int i = len str; i > 0) [i = i - 1] - ;out.append(str{i - 1}) - ;/ - - ;return out -;/ - -/; is_whitespace (uint8 c) [bool] - ;return c == '\t' || c == '\n' || c == ' ' -;/ - -/; is_digit (uint8 c) [bool] - ;return c !< '0' && c !> '9' -;/ - -/; is_alpha (uint8 c) [bool] - ;bool low = c !< 'A' && c !> 'Z', high = c !< 'a' && c >! 'z' - ;return low || high -;/ - -/; digit_to_char(int i) [uint8] - ;uint8 out = '0' - ;out = out + (i % 10) - ;return out -;/ - -/; string_from_int(int i) [{}uint8] - ;{}uint8 c = "" - ;bool n = false - - /; if (i < 0) - ;n = true - ;i = -i - ;/ - - ;c.append(digit_to_char(i)) - ;i = i / 10 - - /; loop (i !== 0) [i = i / 10] - ;c.append(digit_to_char(i)) - ;/ - - /;if (n) - ;c.append('-') - ;/ - - ;return reverse_string(c) -;/ - -/; int_from_string ({}uint8 str) [int] - ;bool inv = str{0} == '-' - ;int out = 0 - ;int fac = 10 - ;int i = 0 - - /; if (inv) - ;i++ - ;/ - - /; loop (i < len str) [i++] - ;out = out * fac - ;out = out + str{i} - '0' - ;/ - - /; if (inv) - ;out = -out - ;/ - - ;return out -;/ - -/; get_escape_code (uint8 c) [uint8] - /; if (c == '\'') - ;return '\'' - ;; else if (c == '"') - ;return '"' - ;; else if (c == 'a') - ;return '\a' - ;; else if (c == 'b') - ;return '\b' - ;; else if (c == 'e') - ;return '\e' - ;; else if (c == 'f') - ;return '\f' - ;; else if (c == 'n') - ;return '\n' - ;; else if (c == 'r') - ;return '\r' - ;; else if (c == 't') - ;return '\t' - ;; else if (c == 'v') - ;return '\v' - ;/ - - ;return 0 -;/ - -/; parse_hex_code ({}uint8 c) [uint8] - ;uint8 out = 0 - - /; loop (int i = 0; i < len c) [i++] - ;out = out * 16 - ;uint8 tmp = c{i} - /; if (tmp !< 'a') - ;tmp = tmp - 'a' + 'A' - ;/ - - /; if (tmp !< '0' && tmp !> '9') - ;out = out + tmp - '0' - ;; else if (tmp !< 'A' && tmp !> 'F') - ;out = out + 10 + (tmp - 'A') - ;; else - ;break - ;/ - ;/ - - ;return out -;/ - -/; unquote_char ({}uint8 c) [uint8] - /; if (c{1} == '\\') - /; if (c{2} == 'x') - ;{}uint8 d = {c{3}, c{4}} - ;return parse_hex_code(d) - ;/ - ;return get_escape_code(c{2}) - ;/ - - ;return c{1} -;/ - -/; unquote_string ({}uint8 str) [{}uint8] - ;{}uint8 out = "" - ;{}uint8 unc = "'" - - /; loop (int i = 1; i < len str - 1) [i++] - /; if (str{i} == '\\') - ;unc.append('\\') - ;unc.append(str{i + 1}) - ;i++ - - /; if (str{i} == 'x') - ;unc.append(str{i + 1}) - ;unc.append(str{i + 2}) - ;i = i + 2 - ;/ - - ;out.append(unquote_char(unc)) - ;unc = "'" - ;; else - ;out.append(str{i}) - ;/ - ;/ - - ;return out -;/ -- cgit v1.2.3