summaryrefslogtreecommitdiff
path: root/tnslc
diff options
context:
space:
mode:
Diffstat (limited to 'tnslc')
-rw-r--r--tnslc/compile/var.tnsl319
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")
+ ;/
;/