From b8bebe9bbc095177739156a22f99d3e1644c71cf Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Wed, 11 Aug 2021 19:27:49 -0700 Subject: [PATCH] . --- html/browse-slack/environment.mu.html | 339 +++++++++++++++++ html/browse-slack/main.mu.html | 518 ++++++++++++++++++++++++++ 2 files changed, 857 insertions(+) create mode 100644 html/browse-slack/environment.mu.html create mode 100644 html/browse-slack/main.mu.html diff --git a/html/browse-slack/environment.mu.html b/html/browse-slack/environment.mu.html new file mode 100644 index 00000000..50872a6c --- /dev/null +++ b/html/browse-slack/environment.mu.html @@ -0,0 +1,339 @@ + + + + +Mu - browse-slack/environment.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/browse-slack/environment.mu +
+  1 # The environment is a thin layer in this app, just a history of 'tabs' that
+  2 # are fully specified by the operations used to generate them.
+  3 
+  4 type environment {
+  5   item-index: int
+  6 }
+  7 
+  8 # static buffer sizes in this file:
+  9 #   main-panel-hor            # in characters
+ 10 #   item-padding-hor          # in pixels
+ 11 #   item-padding-ver          # in characters
+ 12 #   avatar-side               # in pixels
+ 13 #   avatar-space-hor          # in characters
+ 14 #   avatar-space-ver          # in characters
+ 15 #   search-position-x         # in characters
+ 16 #   search-space-ver          # in characters
+ 17 #   author-name-padding-ver   # in characters
+ 18 #   post-right-coord          # in characters
+ 19 #   channel-offset-x          # in characters
+ 20 #   menu-space-ver            # in characters
+ 21 
+ 22 fn initialize-environment _self: (addr environment), _items: (addr item-list) {
+ 23   var self/esi: (addr environment) <- copy _self
+ 24   var items/eax: (addr item-list) <- copy _items
+ 25   var newest-item-a/eax: (addr int) <- get items, newest
+ 26   var newest-item/eax: int <- copy *newest-item-a
+ 27   var dest/edi: (addr int) <- get self, item-index
+ 28   copy-to *dest, newest-item
+ 29 }
+ 30 
+ 31 fn render-environment screen: (addr screen), env: (addr environment), users: (addr array user), channels: (addr array channel), items: (addr item-list) {
+ 32   clear-screen screen
+ 33   render-search-input screen, env
+ 34   render-channels screen, env, channels
+ 35   render-item-list screen, env, items, users
+ 36   render-menu screen
+ 37 }
+ 38 
+ 39 fn render-channels screen: (addr screen), env: (addr environment), _channels: (addr array channel) {
+ 40   var channels/esi: (addr array channel) <- copy _channels
+ 41   var y/ebx: int <- copy 2/search-space-ver
+ 42   y <- add 1/item-padding-ver
+ 43   var i/ecx: int <- copy 0
+ 44   var max/edx: int <- length channels
+ 45   {
+ 46     compare i, max
+ 47     break-if->=
+ 48     var offset/eax: (offset channel) <- compute-offset channels, i
+ 49     var curr/eax: (addr channel) <- index channels, offset
+ 50     var name-ah/eax: (addr handle array byte) <- get curr, name
+ 51     var name/eax: (addr array byte) <- lookup *name-ah
+ 52     compare name, 0
+ 53     break-if-=
+ 54     set-cursor-position screen, 2/x y
+ 55     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "#", 0xf/grey 0/black
+ 56     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, name, 0xf/grey 0/black
+ 57     y <- add 2/channel-padding
+ 58     i <- increment
+ 59     loop
+ 60   }
+ 61 }
+ 62 
+ 63 fn render-item-list screen: (addr screen), _env: (addr environment), _items: (addr item-list), users: (addr array user) {
+ 64   var env/esi: (addr environment) <- copy _env
+ 65   var tmp-width/eax: int <- copy 0
+ 66   var tmp-height/ecx: int <- copy 0
+ 67   tmp-width, tmp-height <- screen-size screen
+ 68   var screen-width: int
+ 69   copy-to screen-width, tmp-width
+ 70   var screen-height: int
+ 71   copy-to screen-height, tmp-height
+ 72   #
+ 73   var y/ecx: int <- copy 2/search-space-ver
+ 74   y <- add 1/item-padding-ver
+ 75   var newest-item/eax: (addr int) <- get env, item-index
+ 76   var i/ebx: int <- copy *newest-item
+ 77   var items/esi: (addr item-list) <- copy _items
+ 78   var items-data-ah/eax: (addr handle array item) <- get items, data
+ 79   var _items-data/eax: (addr array item) <- lookup *items-data-ah
+ 80   var items-data/edi: (addr array item) <- copy _items-data
+ 81   {
+ 82     compare i, 0
+ 83     break-if-<
+ 84     compare y, screen-height
+ 85     break-if->=
+ 86     var offset/eax: (offset item) <- compute-offset items-data, i
+ 87     var curr-item/eax: (addr item) <- index items-data, offset
+ 88     y <- render-item screen, curr-item, users, y, screen-height
+ 89     i <- decrement
+ 90     loop
+ 91   }
+ 92   var top/eax: int <- copy screen-height
+ 93   top <- subtract 2/menu-space-ver
+ 94   clear-rect screen, 0 top, screen-width screen-height, 0/bg
+ 95 }
+ 96 
+ 97 fn render-search-input screen: (addr screen), env: (addr environment) {
+ 98   set-cursor-position 0/screen, 0x22/x=search-position-x 1/y
+ 99   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "search ", 7/fg 0/bg
+100   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "________________________________", 0xf/fg 0/bg
+101 }
+102 
+103 fn render-menu screen: (addr screen) {
+104   var width/eax: int <- copy 0
+105   var y/ecx: int <- copy 0
+106   width, y <- screen-size screen
+107   y <- decrement
+108   set-cursor-position screen, 2/x, y
+109   draw-text-rightward-from-cursor screen, " / ", width, 0/fg 0xf/bg
+110   draw-text-rightward-from-cursor screen, " search  ", width, 0xf/fg, 0/bg
+111   draw-text-rightward-from-cursor screen, " ^f ", width, 0/fg 0xf/bg
+112   draw-text-rightward-from-cursor screen, " next page  ", width, 0xf/fg, 0/bg
+113   draw-text-rightward-from-cursor screen, " ^b ", width, 0/fg 0xf/bg
+114   draw-text-rightward-from-cursor screen, " previous page  ", width, 0xf/fg, 0/bg
+115 }
+116 
+117 fn render-item screen: (addr screen), _item: (addr item), _users: (addr array user), y: int, screen-height: int -> _/ecx: int {
+118   var item/esi: (addr item) <- copy _item
+119   var users/edi: (addr array user) <- copy _users
+120   var author-index-addr/ecx: (addr int) <- get item, by
+121   var author-index/ecx: int <- copy *author-index-addr
+122   var author-offset/ecx: (offset user) <- compute-offset users, author-index
+123   var author/ecx: (addr user) <- index users, author-offset
+124   # author avatar
+125   var author-avatar-ah/eax: (addr handle image) <- get author, avatar
+126   var _author-avatar/eax: (addr image) <- lookup *author-avatar-ah
+127   var author-avatar/ebx: (addr image) <- copy _author-avatar
+128   {
+129     compare author-avatar, 0
+130     break-if-=
+131     var y/edx: int <- copy y
+132     y <- shift-left 4/log2font-height
+133     var x/eax: int <- copy 0x20/main-panel-hor
+134     x <- shift-left 3/log2font-width
+135     x <- add 0x18/item-padding-hor
+136     render-image screen, author-avatar, x, y, 0x50/avatar-side, 0x50/avatar-side
+137   }
+138   # channel
+139   var channel-name-ah/eax: (addr handle array byte) <- get item, channel
+140   var channel-name/eax: (addr array byte) <- lookup *channel-name-ah
+141   {
+142     var x/eax: int <- copy 0x20/main-panel-hor
+143     x <- add 0x40/channel-offset-x
+144     set-cursor-position screen, x y
+145   }
+146   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "#", 7/grey 0/black
+147   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, channel-name, 7/grey 0/black
+148   # author name
+149   var author-real-name-ah/eax: (addr handle array byte) <- get author, real-name
+150   var author-real-name/eax: (addr array byte) <- lookup *author-real-name-ah
+151   {
+152     var x/ecx: int <- copy 0x20/main-panel-hor
+153     x <- add 0x10/avatar-space-hor
+154     set-cursor-position screen, x y
+155     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, author-real-name, 0xf/white 0/black
+156   }
+157   increment y
+158   # text
+159   var text-ah/eax: (addr handle array byte) <- get item, text
+160   var _text/eax: (addr array byte) <- lookup *text-ah
+161   var text/edx: (addr array byte) <- copy _text
+162   var x/eax: int <- copy 0x20/main-panel-hor
+163   x <- add 0x10/avatar-space-hor
+164   var text-y/ecx: int <- copy y
+165   text-y <- add 1/author-name-padding-ver
+166   x, text-y <- draw-text-wrapping-right-then-down screen, text, x text-y, 0x70/xmax=post-right-coord screen-height, x text-y, 7/fg 0/bg
+167   text-y <- add 2/item-padding-ver
+168   # flush
+169   add-to y, 6/avatar-space-ver
+170   compare y, text-y
+171   {
+172     break-if-<
+173     return y
+174   }
+175   return text-y
+176 }
+177 
+178 fn update-environment env: (addr environment), key: byte, items: (addr item-list) {
+179   {
+180     compare key, 6/ctrl-f
+181     break-if-!=
+182     page-down env, items
+183     return
+184   }
+185   {
+186     compare key, 2/ctrl-b
+187     break-if-!=
+188     page-up env, items
+189     return
+190   }
+191 }
+192 
+193 fn page-down _env: (addr environment), _items: (addr item-list) {
+194   var env/edi: (addr environment) <- copy _env
+195   var items/esi: (addr item-list) <- copy _items
+196   var items-data-ah/eax: (addr handle array item) <- get items, data
+197   var _items-data/eax: (addr array item) <- lookup *items-data-ah
+198   var items-data/ebx: (addr array item) <- copy _items-data
+199   var src/eax: (addr int) <- get env, item-index
+200   var new-item-index/ecx: int <- copy *src
+201   var y/edx: int <- copy 2
+202   {
+203     compare new-item-index, 0
+204     break-if-<
+205     compare y, 0x28/screen-height-minus-menu
+206     break-if->=
+207     var offset/eax: (offset item) <- compute-offset items-data, new-item-index
+208     var item/eax: (addr item) <- index items-data, offset
+209     var item-text-ah/eax: (addr handle array byte) <- get item, text
+210     var item-text/eax: (addr array byte) <- lookup *item-text-ah
+211     var h/eax: int <- estimate-height item-text
+212     set-cursor-position 0/screen, 0 0
+213     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, h, 4/fg 0/bg
+214     y <- add h
+215     new-item-index <- decrement
+216     loop
+217   }
+218   new-item-index <- increment
+219   var dest/eax: (addr int) <- get env, item-index
+220   copy-to *dest, new-item-index
+221 }
+222 
+223 fn page-up _env: (addr environment), _items: (addr item-list) {
+224   var env/edi: (addr environment) <- copy _env
+225   var items/esi: (addr item-list) <- copy _items
+226   var items-data-ah/eax: (addr handle array item) <- get items, data
+227   var _items-data/eax: (addr array item) <- lookup *items-data-ah
+228   var items-data/ebx: (addr array item) <- copy _items-data
+229   var newest-item-index-a/esi: (addr int) <- get items, newest
+230   var src/eax: (addr int) <- get env, item-index
+231   var new-item-index/ecx: int <- copy *src
+232   var y/edx: int <- copy 2
+233   {
+234     compare new-item-index, *newest-item-index-a
+235     break-if->
+236     compare y, 0x28/screen-height-minus-menu
+237     break-if->=
+238     var offset/eax: (offset item) <- compute-offset items-data, new-item-index
+239     var item/eax: (addr item) <- index items-data, offset
+240     var item-text-ah/eax: (addr handle array byte) <- get item, text
+241     var item-text/eax: (addr array byte) <- lookup *item-text-ah
+242     var h/eax: int <- estimate-height item-text
+243     set-cursor-position 0/screen, 0 0
+244     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, h, 4/fg 0/bg
+245     y <- add h
+246     new-item-index <- increment
+247     loop
+248   }
+249   new-item-index <- decrement
+250   var dest/eax: (addr int) <- get env, item-index
+251   copy-to *dest, new-item-index
+252 }
+253 
+254 # keep sync'd with render-item
+255 fn estimate-height _message-text: (addr array byte) -> _/eax: int {
+256   var message-text/esi: (addr array byte) <- copy _message-text
+257   var result/eax: int <- length message-text
+258   var remainder/edx: int <- copy 0
+259   result, remainder <- integer-divide result, 0x40/post-width
+260   compare remainder, 0
+261   {
+262     break-if-=
+263     result <- increment
+264   }
+265   result <- add 2/item-padding-ver
+266   compare result, 6/avatar-space-ver
+267   {
+268     break-if->
+269     return 6/avatar-space-ver
+270   }
+271   return result
+272 }
+
+ + + diff --git a/html/browse-slack/main.mu.html b/html/browse-slack/main.mu.html new file mode 100644 index 00000000..17dea13b --- /dev/null +++ b/html/browse-slack/main.mu.html @@ -0,0 +1,518 @@ + + + + +Mu - browse-slack/main.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/browse-slack/main.mu +
+  1 type channel {
+  2   name: (handle array byte)
+  3   posts: (handle array int)  # item indices
+  4   newest-post-index: int
+  5 }
+  6 
+  7 type user {
+  8   id: (handle array byte)
+  9   name: (handle array byte)
+ 10   real-name: (handle array byte)
+ 11   avatar: (handle image)
+ 12 }
+ 13 
+ 14 type item {
+ 15   id: (handle array byte)
+ 16   channel: (handle array byte)
+ 17   by: int  # user index
+ 18   text: (handle array byte)
+ 19   parent: int  # item index
+ 20   comments: (handle array int)
+ 21   newest-comment-index: int
+ 22 }
+ 23 
+ 24 type item-list {
+ 25   data: (handle array item)
+ 26   newest: int
+ 27 }
+ 28 
+ 29 # globals:
+ 30 #   users: (handle array user)
+ 31 #   channels: (handle array channel)
+ 32 #   items: (handle array item)
+ 33 #
+ 34 # flows:
+ 35 #   channel -> posts
+ 36 #   user -> posts|comments
+ 37 #   post -> comments
+ 38 #   comment -> post|comments
+ 39 #   keywords -> posts|comments
+ 40 
+ 41 # static buffer sizes in this program:
+ 42 #   data-size
+ 43 #   data-size-in-sectors
+ 44 #   num-channels
+ 45 #   num-users
+ 46 #   num-items
+ 47 #   num-comments
+ 48 #   message-text-limit
+ 49 #   channel-capacity
+ 50 
+ 51 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+ 52   # load entire disk contents to a single enormous stream
+ 53   var s-h: (handle stream byte)  # the stream is too large to put on the stack
+ 54   var s-ah/eax: (addr handle stream byte) <- address s-h
+ 55   populate-stream s-ah, 0x4000000/data-size
+ 56   var _s/eax: (addr stream byte) <- lookup *s-ah
+ 57   var s/ebx: (addr stream byte) <- copy _s
+ 58   var sector-count/eax: int <- copy 0x400  # test_data
+ 59 #?   var sector-count/eax: int <- copy 0x20000  # largest size tested; slow
+ 60   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "loading ", 3/fg 0/bg
+ 61   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, sector-count, 3/fg 0/bg
+ 62   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " sectors from data disk..", 3/fg 0/bg
+ 63   load-sectors data-disk, 0/lba, sector-count, s
+ 64   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "done", 3/fg 0/bg
+ 65   # parse global data structures out of the stream
+ 66   var users-h: (handle array user)
+ 67   var users-ah/eax: (addr handle array user) <- address users-h
+ 68   populate users-ah, 0x800/num-users
+ 69   var _users/eax: (addr array user) <- lookup *users-ah
+ 70   var users/edi: (addr array user) <- copy _users
+ 71   var channels-h: (handle array channel)
+ 72   var channels-ah/eax: (addr handle array channel) <- address channels-h
+ 73   populate channels-ah, 0x20/num-channels
+ 74   var _channels/eax: (addr array channel) <- lookup *channels-ah
+ 75   var channels/esi: (addr array channel) <- copy _channels
+ 76   var items-storage: item-list
+ 77   var items/edx: (addr item-list) <- address items-storage
+ 78   var items-data-ah/eax: (addr handle array item) <- get items, data
+ 79   populate items-data-ah, 0x10000/num-items
+ 80   parse s, users, channels, items
+ 81   # render
+ 82   var env-storage: environment
+ 83   var env/ebx: (addr environment) <- address env-storage
+ 84   initialize-environment env, items
+ 85   {
+ 86     render-environment screen, env, users, channels, items
+ 87     {
+ 88       var key/eax: byte <- read-key keyboard
+ 89       compare key, 0
+ 90       loop-if-=
+ 91       update-environment env, key, items
+ 92     }
+ 93     loop
+ 94   }
+ 95 }
+ 96 
+ 97 fn parse in: (addr stream byte), users: (addr array user), channels: (addr array channel), _items: (addr item-list) {
+ 98   var items/esi: (addr item-list) <- copy _items
+ 99   var items-data-ah/eax: (addr handle array item) <- get items, data
+100   var _items-data/eax: (addr array item) <- lookup *items-data-ah
+101   var items-data/edi: (addr array item) <- copy _items-data
+102   # 'in' consists of a long, flat sequence of records surrounded by parens
+103   var record-storage: (stream byte 0x18000)
+104   var record/ecx: (addr stream byte) <- address record-storage
+105   var user-idx/edx: int <- copy 0
+106   var item-idx/ebx: int <- copy 0
+107   {
+108     var done?/eax: boolean <- stream-empty? in
+109     compare done?, 0/false
+110     break-if-!=
+111     var c/eax: byte <- peek-byte in
+112     compare c, 0
+113     break-if-=
+114     set-cursor-position 0/screen, 0x20 0x20
+115     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, user-idx, 3/fg 0/bg
+116     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, item-idx, 4/fg 0/bg
+117     clear-stream record
+118     parse-record in, record
+119     var user?/eax: boolean <- user-record? record
+120     {
+121       compare user?, 0/false
+122       break-if-=
+123       parse-user record, users, user-idx
+124       user-idx <- increment
+125     }
+126     {
+127       compare user?, 0/false
+128       break-if-!=
+129       parse-item record, channels, items-data, item-idx
+130       item-idx <- increment
+131     }
+132     loop
+133   }
+134   var dest/eax: (addr int) <- get items, newest
+135   copy-to *dest, item-idx
+136   decrement *dest
+137 }
+138 
+139 fn parse-record in: (addr stream byte), out: (addr stream byte) {
+140   var paren/eax: byte <- read-byte in
+141   compare paren, 0x28/open-paren
+142   {
+143     break-if-=
+144     set-cursor-position 0/screen, 0x20 0x10
+145     var c/eax: int <- copy paren
+146     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen c, 5/fg 0/bg
+147     abort "parse-record: ("
+148   }
+149   var paren-int/eax: int <- copy paren
+150   append-byte out, paren-int
+151   {
+152     {
+153       var eof?/eax: boolean <- stream-empty? in
+154       compare eof?, 0/false
+155       break-if-=
+156       abort "parse-record: truncated; increase the sector-count to load from disk"
+157     }
+158     var c/eax: byte <- read-byte in
+159     {
+160       var c-int/eax: int <- copy c
+161       append-byte out, c-int
+162     }
+163     compare c, 0x29/close-paren
+164     break-if-=
+165     compare c, 0x22/double-quote
+166     {
+167       break-if-!=
+168       slurp-json-string in, out
+169     }
+170     loop
+171   }
+172   skip-chars-matching-whitespace in
+173 }
+174 
+175 fn user-record? record: (addr stream byte) -> _/eax: boolean {
+176   rewind-stream record
+177   var c/eax: byte <- read-byte record  # skip paren
+178   var c/eax: byte <- read-byte record  # skip double quote
+179   var c/eax: byte <- read-byte record
+180   compare c, 0x55/U
+181   {
+182     break-if-!=
+183     return 1/true
+184   }
+185   rewind-stream record
+186   return 0/false
+187 }
+188 
+189 fn parse-user record: (addr stream byte), _users: (addr array user), user-idx: int {
+190   var users/esi: (addr array user) <- copy _users
+191   var offset/eax: (offset user) <- compute-offset users, user-idx
+192   var user/esi: (addr user) <- index users, offset
+193   #
+194   var s-storage: (stream byte 0x100)
+195   var s/ecx: (addr stream byte) <- address s-storage
+196   #
+197   rewind-stream record
+198   var paren/eax: byte <- read-byte record
+199   compare paren, 0x28/open-paren
+200   {
+201     break-if-=
+202     abort "parse-user: ("
+203   }
+204   # user id
+205   skip-chars-matching-whitespace record
+206   var double-quote/eax: byte <- read-byte record
+207   compare double-quote, 0x22/double-quote
+208   {
+209     break-if-=
+210     abort "parse-user: id"
+211   }
+212   next-json-string record, s
+213   var dest/eax: (addr handle array byte) <- get user, id
+214   stream-to-array s, dest
+215   # user name
+216   skip-chars-matching-whitespace record
+217   var double-quote/eax: byte <- read-byte record
+218   compare double-quote, 0x22/double-quote
+219   {
+220     break-if-=
+221     abort "parse-user: name"
+222   }
+223   clear-stream s
+224   next-json-string record, s
+225   var dest/eax: (addr handle array byte) <- get user, name
+226   stream-to-array s, dest
+227   # real name
+228   skip-chars-matching-whitespace record
+229   var double-quote/eax: byte <- read-byte record
+230   compare double-quote, 0x22/double-quote
+231   {
+232     break-if-=
+233     abort "parse-user: real-name"
+234   }
+235   clear-stream s
+236   next-json-string record, s
+237   var dest/eax: (addr handle array byte) <- get user, real-name
+238   stream-to-array s, dest
+239   # avatar
+240   skip-chars-matching-whitespace record
+241   var open-bracket/eax: byte <- read-byte record
+242   compare open-bracket, 0x5b/open-bracket
+243   {
+244     break-if-=
+245     abort "parse-user: avatar"
+246   }
+247   skip-chars-matching-whitespace record
+248   var c/eax: byte <- peek-byte record
+249   {
+250     compare c, 0x5d/close-bracket
+251     break-if-=
+252     var dest-ah/eax: (addr handle image) <- get user, avatar
+253     allocate dest-ah
+254     var dest/eax: (addr image) <- lookup *dest-ah
+255     initialize-image dest, record
+256   }
+257 }
+258 
+259 fn parse-item record: (addr stream byte), _channels: (addr array channel), _items: (addr array item), item-idx: int {
+260   var items/esi: (addr array item) <- copy _items
+261   var offset/eax: (offset item) <- compute-offset items, item-idx
+262   var item/edi: (addr item) <- index items, offset
+263   #
+264   var s-storage: (stream byte 0x40)
+265   var s/ecx: (addr stream byte) <- address s-storage
+266   #
+267   rewind-stream record
+268   var paren/eax: byte <- read-byte record
+269   compare paren, 0x28/open-paren
+270   {
+271     break-if-=
+272     abort "parse-item: ("
+273   }
+274   # item id
+275   skip-chars-matching-whitespace record
+276   var double-quote/eax: byte <- read-byte record
+277   compare double-quote, 0x22/double-quote
+278   {
+279     break-if-=
+280     abort "parse-item: id"
+281   }
+282   next-json-string record, s
+283   var dest/eax: (addr handle array byte) <- get item, id
+284   stream-to-array s, dest
+285   # parent index
+286   {
+287     var word-slice-storage: slice
+288     var word-slice/ecx: (addr slice) <- address word-slice-storage
+289     next-word record, word-slice
+290     var src/eax: int <- parse-decimal-int-from-slice word-slice
+291     compare src, -1
+292     break-if-=
+293     var dest/edx: (addr int) <- get item, parent
+294     copy-to *dest, src
+295     # cross-link to parent
+296     var parent-offset/eax: (offset item) <- compute-offset items, src
+297     var parent-item/esi: (addr item) <- index items, parent-offset
+298     var parent-comments-ah/ebx: (addr handle array int) <- get parent-item, comments
+299     var parent-comments/eax: (addr array int) <- lookup *parent-comments-ah
+300     compare parent-comments, 0
+301     {
+302       break-if-!=
+303       populate parent-comments-ah, 0x200/num-comments
+304       parent-comments <- lookup *parent-comments-ah
+305     }
+306     var parent-newest-comment-index-addr/edi: (addr int) <- get parent-item, newest-comment-index
+307     var parent-newest-comment-index/edx: int <- copy *parent-newest-comment-index-addr
+308     var dest/eax: (addr int) <- index parent-comments, parent-newest-comment-index
+309     var src/ecx: int <- copy item-idx
+310     copy-to *dest, src
+311     increment *parent-newest-comment-index-addr
+312   }
+313   # channel name
+314   skip-chars-matching-whitespace record
+315   var double-quote/eax: byte <- read-byte record
+316   compare double-quote, 0x22/double-quote
+317   {
+318     break-if-=
+319     abort "parse-item: channel"
+320   }
+321   clear-stream s
+322   next-json-string record, s
+323   var dest/eax: (addr handle array byte) <- get item, channel
+324   stream-to-array s, dest
+325   # cross-link to channels
+326   {
+327     var channels/esi: (addr array channel) <- copy _channels
+328     var channel-index/eax: int <- find-or-insert channels, s
+329     var channel-offset/eax: (offset channel) <- compute-offset channels, channel-index
+330     var channel/eax: (addr channel) <- index channels, channel-offset
+331     var channel-posts-ah/ecx: (addr handle array int) <- get channel, posts
+332     var channel-newest-post-index-addr/edx: (addr int) <- get channel, newest-post-index
+333     var channel-newest-post-index/edx: int <- copy *channel-newest-post-index-addr
+334     var channel-posts/eax: (addr array int) <- lookup *channel-posts-ah
+335     var dest/eax: (addr int) <- index channel-posts, channel-newest-post-index
+336   }
+337   # user index
+338   {
+339     var word-slice-storage: slice
+340     var word-slice/ecx: (addr slice) <- address word-slice-storage
+341     next-word record, word-slice
+342     var src/eax: int <- parse-decimal-int-from-slice word-slice
+343     var dest/edx: (addr int) <- get item, by
+344     copy-to *dest, src
+345   }
+346   # text
+347   var s-storage: (stream byte 0x4000)  # message-text-limit
+348   var s/ecx: (addr stream byte) <- address s-storage
+349   skip-chars-matching-whitespace record
+350   var double-quote/eax: byte <- read-byte record
+351   compare double-quote, 0x22/double-quote
+352   {
+353     break-if-=
+354     abort "parse-item: text"
+355   }
+356   next-json-string record, s
+357   var dest/eax: (addr handle array byte) <- get item, text
+358   stream-to-array s, dest
+359 }
+360 
+361 fn find-or-insert _channels: (addr array channel), name: (addr stream byte) -> _/eax: int {
+362   var channels/esi: (addr array channel) <- copy _channels
+363   var i/ecx: int <- copy 0
+364   var max/edx: int <- length channels
+365   {
+366     compare i, max
+367     break-if->=
+368     var offset/eax: (offset channel) <- compute-offset channels, i
+369     var curr/ebx: (addr channel) <- index channels, offset
+370     var curr-name-ah/edi: (addr handle array byte) <- get curr, name
+371     var curr-name/eax: (addr array byte) <- lookup *curr-name-ah
+372     {
+373       compare curr-name, 0
+374       break-if-!=
+375       rewind-stream name
+376       stream-to-array name, curr-name-ah
+377       var posts-ah/eax: (addr handle array int) <- get curr, posts
+378       populate posts-ah, 0x8000/channel-capacity
+379       return i
+380     }
+381     var found?/eax: boolean <- stream-data-equal? name, curr-name
+382     {
+383       compare found?, 0/false
+384       break-if-=
+385       return i
+386     }
+387     i <- increment
+388     loop
+389   }
+390   abort "out of channels"
+391   return -1
+392 }
+393 
+394 # includes trailing double quote
+395 fn slurp-json-string in: (addr stream byte), out: (addr stream byte) {
+396   # open quote is already slurped
+397   {
+398     {
+399       var eof?/eax: boolean <- stream-empty? in
+400       compare eof?, 0/false
+401       break-if-=
+402       abort "slurp-json-string: truncated"
+403     }
+404     var c/eax: byte <- read-byte in
+405     {
+406       var c-int/eax: int <- copy c
+407       append-byte out, c-int
+408     }
+409     compare c, 0x22/double-quote
+410     break-if-=
+411     compare c, 0x5c/backslash
+412     {
+413       break-if-!=
+414       # read next byte raw
+415       c <- read-byte in
+416       var c-int/eax: int <- copy c
+417       append-byte out, c-int
+418     }
+419     loop
+420   }
+421 }
+422 
+423 # drops trailing double quote
+424 fn next-json-string in: (addr stream byte), out: (addr stream byte) {
+425   # open quote is already read
+426   {
+427     {
+428       var eof?/eax: boolean <- stream-empty? in
+429       compare eof?, 0/false
+430       break-if-=
+431       abort "next-json-string: truncated"
+432     }
+433     var c/eax: byte <- read-byte in
+434     compare c, 0x22/double-quote
+435     break-if-=
+436     {
+437       var c-int/eax: int <- copy c
+438       append-byte out, c-int
+439     }
+440     compare c, 0x5c/backslash
+441     {
+442       break-if-!=
+443       # read next byte raw
+444       c <- read-byte in
+445       var c-int/eax: int <- copy c
+446       append-byte out, c-int
+447     }
+448     loop
+449   }
+450 }
+
+ + +