about summary refs log blame commit diff stats
path: root/archive/2.transect/compiler6
blob: 48a7030f654081d49a9ab00d7cffea9a02934456 (plain) (tree)



































                                                                                           
== Goal

A memory-safe language with a simple translator to x86 that can be feasibly written in x86.

== Definitions of terms

Memory-safe: it should be impossible to:
  a) create a pointer out of arbitrary data, or
  b) to access heap memory after it's been freed.

Simple: do all the work in a 2-pass translator:
  Pass 1: check each instruction's types in isolation.
  Pass 2: emit code for each instruction in isolation.

== types

int
char
(address _)
(array _ n)
(ref _)

addresses can't be saved to stack or global,
      or included in compound types
      or used across a call (to eliminate possibility of free)

<reg x> : (address T) <- advance <reg/mem> : (array T), <reg offset> : (index T)

arrays require a size
(ref array _) may not include a size

== open questions
Is argv an address?
Global variables are easiest to map to addresses.
Ideally we'd represent 'indirect' as a '*' and we could just count to make
sure that an instruction never has more than one '*'.
tor.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
scenario array-from-args [
  run [
    local-scope
    x:&:@:num <- new-array 0, 1, 2
    10:@:num/raw <- copy *x
  ]
  memory-should-contain [
    10 <- 3  # array length
    11 <- 0
    12 <- 1
    13 <- 2
  ]
]

# create an array out of a list of args
def new-array -> result:&:@:_elem [
  local-scope
  capacity:num <- copy 0
  {
    # while read curr-value
    curr-value:_elem, exists?:bool <- next-input
    break-unless exists?
    capacity <- add capacity, 1
    loop
  }
  result <- new _elem:type, capacity
  rewind-inputs
  i:num <- copy 0
  {
    # while read curr-value
    done?:bool <- greater-or-equal i, capacity
    break-if done?
    curr-value:_elem, exists?:bool <- next-input
    assert exists?, [error in rewinding inputs to new-array]
    *result <- put-index *result, i, curr-value
    i <- add i, 1
    loop
  }
  return result
]

# fill an existing array with a set of numbers
# (contributed by Caleb Couch)
def fill array:&:@:num -> array:&:@:num [
  local-scope
  load-inputs
  loopn:num <- copy 0
  length:num <- length *array
  {
    length?:bool <- equal loopn, length
    break-if length?
    object:num, arg-received?:bool <- next-input
    break-unless arg-received?
    *array <- put-index *array, loopn, object
    loopn <- add loopn, 1
    loop
  }
]

scenario fill-on-an-empty-array [
  local-scope
  array:&:@:num <- new number:type, 3
  run [
    array <- fill array, 1 2 3
    10:@:num/raw <- copy *array
  ]
  memory-should-contain [
    10 <- 3
    11 <- 1
    12 <- 2
    13 <- 3
  ]
]

scenario fill-overwrites-existing-values [
  local-scope
  array:&:@:num <- new number:type, 3
  *array <- put-index *array, 0, 4
  run [
    array <- fill array, 1 2 3
    10:@:num/raw <- copy *array
  ]
  memory-should-contain [
    10 <- 3
    11 <- 1
    12 <- 2
    13 <- 3
  ]
]

scenario fill-exits-gracefully-when-given-no-inputs [
  local-scope
  array:&:@:num <- new number:type, 3
  run [
    array <- fill array
    10:@:num/raw <- copy *array
  ]
  memory-should-contain [
    10 <- 3
    11 <- 0
    12 <- 0
    13 <- 0
  ]
]

# swap two elements of an array
# (contributed by Caleb Couch)
def swap array:&:@:num, index1:num, index2:num -> array:&:@:num [
  local-scope
  load-inputs
  object1:num <- index *array, index1
  object2:num <- index *array, index2
  *array <- put-index *array, index1, object2
  *array <- put-index *array, index2, object1
]

scenario swap-works [
  local-scope
  array:&:@:num <- new number:type, 4
  array <- fill array, 4 3 2 1
  run [
    array <- swap array, 0, 2
    10:num/raw <- index *array, 0
    11:num/raw <- index *array, 2
  ]
  memory-should-contain [
    10 <- 2
    11 <- 4
  ]
]

# reverse the elements of an array
# (contributed by Caleb Couch)
def reverse array:&:@:_elem -> array:&:@:_elem [
  local-scope
  load-inputs
  start:num <- copy 0
  length:num <- length *array
  end:num <- subtract length, 1
  {
    done?:bool <- greater-or-equal start, end
    break-if done?
    array <- swap array, start, end
    start <- add start, 1
    end <- subtract end, 1
    loop
  }
]

scenario reverse-array-odd-length [
  local-scope
  array:&:@:num <- new number:type, 3
  array <- fill array, 3 2 1
  run [
    array <- reverse array
    10:@:num/raw <- copy *array
  ]
  memory-should-contain [
    10 <- 3
    11 <- 1
    12 <- 2
    13 <- 3
  ]
]

scenario reverse-array-even-length [
  local-scope
  array:&:@:num <- new number:type, 4
  array <- fill array, 4 3 2 1
  run [
    array <- reverse array
    10:@:num/raw <- copy *array
  ]
  memory-should-contain [
    10 <- 4
    11 <- 1
    12 <- 2
    13 <- 3
    14 <- 4
  ]
]