diff options
Diffstat (limited to 'tnslc/compile/var.tnsl')
| -rw-r--r-- | tnslc/compile/var.tnsl | 319 |
1 files changed, 244 insertions, 75 deletions
diff --git a/tnslc/compile/var.tnsl b/tnslc/compile/var.tnsl index b684c33..a8d5ecf 100644 --- a/tnslc/compile/var.tnsl +++ b/tnslc/compile/var.tnsl @@ -34,7 +34,7 @@ int32 PTYPE_ARR = 1 out.push(~add) ;/ - add = 'a' + add = 'a' /; if (r < 5) add = add + r - 1 ;; else if (r == 5 || r == 7) @@ -88,6 +88,27 @@ int32 PTYPE_ARR = 1 return out.as_cstr() ;/ +# Valid value states: +# When loc is DATA value is in the data section and the name is actually the label +# When loc is STCK value is offset from rbp pointer using the offset +# When loc is 0 then offset represents a numeric literal +# When loc is positive then the variable exists in that register* +# Structs and references don't exactly exist in a register and so must +# be combined with the offset to get a resonable approximation + +# So when computing the location of a standard type... +# ...just load from the register +# ...Unless it's a ref in which case take into account the offset +# ...Or it's a DATA in which case load from rel label +# ...Or it's on the stack in which case load from +# ...Or it's a literal in which case just use the literal value + +# So when computing the location of a struct... +# ...Load as an offset from a register +# ...Unless it's on the stack (offset from rbp) +# ...Or it's in DATA (offset from rel label) +# ...Or it's a ref (lea first ref and then just load direct values from there) + struct Var { ~uint8 name, ~Struct _type, @@ -98,6 +119,11 @@ struct Var { } /; method Var + + ########################### + # Init and copy functions # + ########################### + # Initial init function, requires type node and # identifier node /; init (~parse.Node tn, id) @@ -110,12 +136,9 @@ struct Var { self._id = id ;/ + # Deep copy the variable /; copy [Var] - Var out - out.init(self._tn, self._id) - out._type = self._type - out.loc = self.loc - out.offset = self.offset + Var out = self.shallow_copy() /; loop (int i = 0; i < self.ptrc.count) [i++] ~int32 p = self.ptrc.get(i) @@ -125,15 +148,33 @@ struct Var { return out ;/ + # A copy without the pointer chain + /; shallow_copy [Var] + Var out + out.init(self._tn, self._id) + out._type = self._type + out.loc = self.loc + out.offset = self.offset + return out + ;/ + + ############################# + # Variable inspection funcs # + ############################# + + # Get a pointer to the top of the pointer chain, returns + # null if the pointer chain is empty /; top_ptrc [~int32] # Sanity /; if (self.ptrc.count < 1) return NULL ;/ + ~int32 out = self.ptrc.get(self.ptrc.count - 1) return out ;/ + # Returns true if the variable is a reference /; is_ref [bool] ~int32 p = self.top_ptrc() /; if (p == NULL) @@ -143,40 +184,50 @@ struct Var { return p` == 0 ;/ - /; _print (int idt) - _indent(idt) - _printf("{ Var : \0") - _printf(self.name) - _printf("\n\0") - - _indent(idt + 1) - _printf("type: \0") - /; if (self._type !== NULL) - _printf(self._type`.name) - ;; else - _printf("(nil)\0") + # Returns true if the variable is a pointer + /; is_ptr [bool] + ~int32 p = self.top_ptrc() + /; if (p == NULL) + return false ;/ - _printf("\n\0") - _indent(idt + 1) - _printf("ptrc: \0") - ~int32 istr - /; loop (int i = 0; i < self.ptrc.count) [i++] - istr = self.ptrc.get(i) - _print_num("%d \0", istr`) + return p` < 0 + ;/ + + # Returns true if the variable is an array + /; is_arr [bool] + ~int32 p = self.top_ptrc() + /; if (p == NULL) + return false ;/ - _printf("\n\0") - _indent(idt + 1) - _print_num("loc: %d\n\0", self.loc) + return p` > 0 + ;/ - _indent(idt + 1) - _print_num("off: %d\n\0", self.offset) + # Whether the variable can be stored within a register + /; regable [bool] + ~int p + /; if (self.ptrc.count > 0) + return true + ;/ + return _is_primitive(self._type`.name) !== 0 + ;/ - _indent(idt) - _printf("}\n\0") + /; is_struct [bool] + # Check first if we are a pointer of some sort + ~int32 p + /; loop (int i = 0; i < self.ptrc.count) [i++] + p = self.ptrc.get(i) + /; if (p` !== 0) + return false + ;/ + ;/ + + return _is_primitive(self._type`.name) == 0 ;/ + # Compute and add the correct pointer chain value for an array + # type prefix /; _arr_ptr(~parse.Node a) int32 ptr = 1 /; if (a`.sub.count > 0) @@ -189,18 +240,8 @@ struct Var { self.ptrc.push(~ptr) ;/ - # Whether the variable can be stored within a register - /; regable [bool] - ~int p - /; loop (int i = 0; i < self.ptrc.count) [i++] - p = self.ptrc.get(i) - /; if (p` !== 0) - return true - ;/ - ;/ - return _is_primitive(self._type`.name) !== 0 - ;/ - + # The "actual size" of the variable (if we were to do a mov on it + # how much space would we need) /; actual_size [uint] /; if (self.ptrc.count > 0) return 8 @@ -211,6 +252,11 @@ struct Var { return self._type`.size ;/ + ##################################### + # Variable manipulation (comp time) # + ##################################### + + # Reverse the pointer chain /; _reverse_ptrc int max = self.ptrc.count / 2 ~int32 l, r @@ -303,16 +349,11 @@ struct Var { ;/ ;/ + # Compile the variable into the data section /; _static_compile (~Module parent, ~CompBuf buf) # TODO: everything ;/ - - /; ptr [int32] - ~int32 i - i = self.ptrc.get(self.ptrc.count - 1) - return i` - ;/ - + /; ptr_push (int32 p) self.ptrc.push(~p) ;/ @@ -326,10 +367,10 @@ struct Var { self.ptrc.end() ;/ - ################################### - # Variable manipulation functions # - ################################### - + #################################### + # Variable manipulation (run time) # + #################################### + /; gen_loc [~uint8] /; if (self.loc == 0) return utils.int_to_str(self.offset) @@ -394,29 +435,119 @@ struct Var { return false ;/ - # Set this variable to the value of a literal - /; set_literal (~CompBuf buf, ~Var other) + + # Typechecking + + # Typechecking structs + /; _tc_struct (~Var other) [bool] + /; if (other`.is_struct() == false) + return false + ;/ + ~void a = self._type + ~void b = other`._type + + return a == b ;/ - /; _set_mem(~CompBuf buf, ~Var other) + /; _tc_prim (~Var other) [bool] + # Allow implicit ptr conversions + /; if (self.is_ptr() == true) + return other`.is_ptr() + ;/ + + return false + ;/ + + + # Operations + + # Helper to gen register when setting a struct + /; _set_struct_r (~CompBuf buf, int reg) + ~uint8 r = reg_string(reg, 8) - ~uint8 to_str = self.gen_loc() - ~uint8 from_str = other`.gen_loc() + buf`.add_c(" ; putting struct address into register\n\0") + + # Initial deref or move + /; if (self.ptrc.count > 0) + buf`.add_c(" mov \0") + ;; else + buf`.add_c(" lea \0") + ;/ + buf`.add_c(r) + buf`.add_c(", [\0") - ~uint8 str + # Reg, stack, or data + /; if (self.loc + VLOC_DATA == 0) + buf`.add_c("rel \0") + buf`.add_c(self.name) + ;; else if (self.loc + VLOC_STCK == 0) + ~uint8 get_reg = reg_string(8, 8) + buf`.add_c(get_reg) + _delete(get_reg) + ;; else + ~uint8 get_reg = reg_string(self.loc, 8) + buf`.add_c(get_reg) + _delete(get_reg) + ;/ - str = utils.int_to_str(self.actual_size()) + # Deal with offset + /; if (self.offset !== 0) + int o = self.offset + /; if (o < 0) + o = 0 - o + buf`.add_c(" - \0") + ;; else + buf`.add_c(" + \0") + ;/ + ;/ + + buf`.add_c("] ; initial struct addr move\n\0") + + # For as many more times as there are + /; loop (int i = 1; i < self.ptrc.count) [i++] + buf`.add_c(" mov \0") + buf`.add_c(r) + buf`.add_c(", [\0") + buf`.add_c(r) + buf`.add_c("] ; reference chain\n\0") + ;/ + + _delete(r) + ;/ + + # Helper to properly move a struct in memory + /; _set_struct(~CompBuf buf, ~Var other) + # Typecheck + /; if (self._tc_struct(other) == false) + _printf("ERROR: Types do not match when setting struct. [\0") + _printf(self._type`.name) + _printf("] !== [\0") + _printf(other`._type`.name) + _printf("]\n\0") + return + ;/ + + # Have to get struct address (to set) into rdi + self._set_struct_r(buf, 6) + # Have to get struct address (to read) into rsi + other`._set_struct_r(buf, 5) + + # Setup move size + ~uint8 str + str = utils.int_to_str(self._type`.size) buf`.add_c(" mov rcx, \0") buf`.add_c(str) - buf`.add_c("\n") + buf`.add_c(" ; size of struct [\0") + buf`.add_c(self._type`.name) + buf`.add_c("] in bytes\n\0") _delete(str) - buf`.add_c(" rep movsb\0") - - _delete(to_str) - _delete(from_str) + # Move byte (rcx times) + buf`.add_c(" rep movsb ; move struct\n\0") + ;/ + # Set this Variable to the value of other /; set (~CompBuf buf, ~Var other) # Options: @@ -424,15 +555,16 @@ struct Var { # - If pointer then move qword # - If struct then move via rep movsb - # Changes need to be made based on whether either is on the stack - # or if either is a reference - - # Can move to/from stack if only one is on stack/reference - # otherwise we must pre-mov the source into RSI and then - # we can move into the recipiant's address - - /; if () + /; if (self.is_struct() == false) + # Struct set + self._set_struct(buf, other) + return ;/ + + # Ok, we are either a builtin type or a pointer. + # First we have to typecheck and find the correct move operation + # If the typecheck fails we will get a null pointer back + # ~uint8 tc_mov = ;/ # Set the address which this reference points to @@ -599,6 +731,43 @@ struct Var { Var out return out ;/ + + + # Printing + + /; _print (int idt) + _indent(idt) + _printf("{ Var : \0") + _printf(self.name) + _printf("\n\0") + + _indent(idt + 1) + _printf("type: \0") + /; if (self._type !== NULL) + _printf(self._type`.name) + ;; else + _printf("(nil)\0") + ;/ + _printf("\n\0") + + _indent(idt + 1) + _printf("ptrc: \0") + ~int32 istr + /; loop (int i = 0; i < self.ptrc.count) [i++] + istr = self.ptrc.get(i) + _print_num("%d \0", istr`) + ;/ + _printf("\n\0") + + _indent(idt + 1) + _print_num("loc: %d\n\0", self.loc) + + _indent(idt + 1) + _print_num("off: %d\n\0", self.offset) + + _indent(idt) + _printf("}\n\0") + ;/ ;/ |