about summary refs log blame commit diff stats
path: root/prototypes/tile/5.mu
blob: c7785df66c6665371918aa9e307422c8bab7ff1d (plain) (tree)
1
2
3
4
5
6




                                              
                                         






                                                                             
 







                                       
                                 





























                                                                          
                                               
                                       
                 

 



                                                               








                                                       



















                                                                                                          























                                                             











                                                     
                                                        




























                                                        
# rendering a tree with a single child
#
# To run (on Linux and x86):
#   $ git clone https://github.com/akkartik/mu
#   $ cd mu
#   $ ./translate_mu prototypes/tile/5.mu
#   $ ./a.elf
#
# You should see a single rectangle representing a singleton tree node.
# Press a key. You should see the tree grow a single child.
# It seems useful as a visual idiom to represent nodes with a single child as
# slightly larger than the child.
# Once we get to multiple children we'll start tiling more regularly.

type cell {
  val: int  # single chars only for now
  parent: (handle cell)
  first-child: (handle cell)
  next-sibling: (handle cell)
  prev-sibling: (handle cell)
}

fn main -> exit-status/ebx: int {
  var root-handle: (handle cell)
  var root/esi: (addr handle cell) <- address root-handle
  allocate root
  var cursor/edi: (addr handle cell) <- copy root
  enable-keyboard-immediate-mode
  var root-addr/eax: (addr cell) <- lookup *root
  render root-addr
$main:loop: {
    # process key
    {
      var c/eax: byte <- read-key
      compare c, 4  # ctrl-d
      break-if-= $main:loop
      process c, root, cursor
    }
    # render tree
    root-addr <- lookup root-handle
    render root-addr
    loop
  }
  clear-screen
  enable-keyboard-type-mode
  exit-status <- copy 0
}

#######################################################
# Tree mutations
#######################################################

fn process c: byte, root: (addr handle cell), cursor: (addr handle cell) {
  var c1/eax: (addr handle cell) <- copy cursor
  var c2/eax: (addr cell) <- lookup *c1
  create-child c2
}

fn create-child node: (addr cell) {
  var n/ecx: (addr cell) <- copy node
  var first-child/esi: (addr handle cell) <- get n, first-child
  allocate first-child
}

#######################################################
# Tree drawing
#######################################################

fn render root: (addr cell) {
  clear-screen
  var depth/eax: int <- tree-depth root
  var viewport-width/ecx: int <- copy 0x64  # col2
  viewport-width <- subtract 5  # col1
  var column-width/eax: int <- try-divide viewport-width, depth
  render-tree root, column-width, 5, 5, 0x20, 0x64
}

fn render-tree c: (addr cell), column-width: int, row-min: int, col-min: int, row-max: int, col-max: int {
  var root-max/ecx: int <- copy col-min
  root-max <- add column-width
  draw-box row-min, col-min, row-max, root-max
  var c2/eax: (addr cell) <- copy c
  var child/eax: (addr handle cell) <- get c2, first-child
  var child-addr/eax: (addr cell) <- lookup *child
  {
    compare child-addr, 0
    break-if-=
    increment row-min
    decrement row-max
    render-tree child-addr, column-width, row-min, root-max, row-max, col-max
  }
}

fn tree-depth node-on-stack: (addr cell) -> result/eax: int {
  var tmp-result/edi: int <- copy 0
  var node/eax: (addr cell) <- copy node-on-stack
  var child/ecx: (addr handle cell) <- get node, first-child
  var child-addr/eax: (addr cell) <- lookup *child
  {
    compare child-addr, 0
    break-if-=
    {
      var tmp/eax: int <- tree-depth child-addr
      compare tmp, tmp-result
      break-if-<=
      tmp-result <- copy tmp
    }
    child <- get child-addr, next-sibling
    child-addr <- lookup *child
    loop
  }
  result <- copy tmp-result
  result <- increment
}

# slow, iterative divide instruction
fn try-divide _nr: int, _dr: int -> result/eax: int {
  result <- copy _nr
  result <- shift-right 2
#?   var nr/ecx: int <- copy _nr
#?   var tmp/ecx: int <- copy 2
#?   # find nearest power of 2
#?   {
#?     k
#?   }
}

fn draw-box row1: int, col1: int, row2: int, col2: int {
  draw-horizontal-line row1, col1, col2
  draw-vertical-line row1, row2, col1
  draw-horizontal-line row2, col1, col2
  draw-vertical-line row1, row2, col2
}

fn draw-horizontal-line row: int, col1: int, col2: int {
  var col/eax: int <- copy col1
  move-cursor-on-screen row, col
  {
    compare col, col2
    break-if->=
    print-string-to-screen "-"
    col <- increment
    loop
  }
}

fn draw-vertical-line row1: int, row2: int, col: int {
  var row/eax: int <- copy row1
  {
    compare row, row2
    break-if->=
    move-cursor-on-screen row, col
    print-string-to-screen "|"
    row <- increment
    loop
  }
}