about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--120allocate.subx8
-rw-r--r--308allocate-array.subx2
-rw-r--r--309stream.subx2
-rw-r--r--310copy-bytes.subx57
-rw-r--r--400.mu2
-rw-r--r--405screen.mu118
-rwxr-xr-xapps/mubin388415 -> 388957 bytes
-rw-r--r--apps/mu.subx61
8 files changed, 240 insertions, 10 deletions
diff --git a/120allocate.subx b/120allocate.subx
index 20595e64..c482ae07 100644
--- a/120allocate.subx
+++ b/120allocate.subx
@@ -879,7 +879,7 @@ zero-out:  # start: (addr byte), size: int
     #   curr/esi = start
     #   i/ecx = 0
     #   while true
-    #     if (i >= len) break
+    #     if (i >= size) break
     #     *curr = 0
     #     ++curr
     #     ++i
@@ -896,10 +896,10 @@ zero-out:  # start: (addr byte), size: int
     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
     # var i/ecx: int = 0
     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
-    # edx = len
+    # edx = size
     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
 $zero-out:loop:
-    # if (i >= len) break
+    # if (i >= size) break
     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
     7d/jump-if->=  $zero-out:end/disp8
     # *curr = 0
@@ -929,7 +929,7 @@ test-zero-out:
     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
     # zero-out(ecx, 3)
     # . . push args
-    68/push  3/imm32/len
+    68/push  3/imm32/size
     51/push-ecx
     # . . call
     e8/call  zero-out/disp32
diff --git a/308allocate-array.subx b/308allocate-array.subx
index 2d3d1a9d..760b8090 100644
--- a/308allocate-array.subx
+++ b/308allocate-array.subx
@@ -1,5 +1,7 @@
 # 2-arg version of allocate-array.
 
+== code
+
 allocate-array2:  # ad: (addr allocation-descriptor), array-len: int, elem-size: int, out: (addr handle array _)
     # . prologue
     55/push-ebp
diff --git a/309stream.subx b/309stream.subx
index 8e6d0fbf..84642def 100644
--- a/309stream.subx
+++ b/309stream.subx
@@ -1,6 +1,8 @@
 # Some unsafe methods not intended to be used directly in SubX, only through
 # Mu after proper type-checking.
 
+== code
+
 stream-empty?:  # s: (addr stream _) -> result/eax: boolean
     # . prologue
     55/push-ebp
diff --git a/310copy-bytes.subx b/310copy-bytes.subx
new file mode 100644
index 00000000..f33388a9
--- /dev/null
+++ b/310copy-bytes.subx
@@ -0,0 +1,57 @@
+# Fill a region of memory with zeroes.
+
+== code
+
+copy-bytes:  # src: (addr byte), dest: (addr byte), size: int
+    # pseudocode:
+    #   curr-src/esi = src
+    #   curr-dest/edi = dest
+    #   i/ecx = 0
+    #   while true
+    #     if (i >= size) break
+    #     *curr-dest = *curr-src
+    #     ++curr-src
+    #     ++curr-dest
+    #     ++i
+    #
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    50/push-eax
+    51/push-ecx
+    52/push-edx
+    56/push-esi
+    57/push-edi
+    # curr-src/esi = src
+    8b/-> *(ebp+8) 6/r32/esi
+    # curr-dest/edi = dest
+    8b/-> *(ebp+0xc) 7/r32/edi
+    # var i/ecx: int = 0
+    b9/copy-to-ecx 0/imm32
+    # edx = size
+    8b/-> *(ebp+0x10) 2/r32/edx
+    {
+      # if (i >= size) break
+      39/compare %ecx 2/r32/edx
+      7d/jump-if->=  break/disp8
+      # *curr-dest = *curr-src
+      8a/byte-> *esi 0/r32/AL
+      88/byte<- *edi 0/r32/AL
+      # update
+      46/increment-esi
+      47/increment-edi
+      41/increment-ecx
+      eb/jump loop/disp8
+    }
+$copy-bytes:end:
+    # . restore registers
+    5f/pop-to-edi
+    5e/pop-to-esi
+    5a/pop-to-edx
+    59/pop-to-ecx
+    58/pop-to-eax
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
diff --git a/400.mu b/400.mu
index 0bcf7e64..b1970f15 100644
--- a/400.mu
+++ b/400.mu
@@ -162,3 +162,5 @@ sig open filename: (addr array byte), write?: boolean, out: (addr handle buffere
 
 sig stream-empty? s: (addr stream _) -> result/eax: boolean
 sig stream-full? s: (addr stream _) -> result/eax: boolean
+
+sig copy-bytes src: (addr byte), dest: (addr byte), n: int
diff --git a/405screen.mu b/405screen.mu
index f7e04c53..8555b494 100644
--- a/405screen.mu
+++ b/405screen.mu
@@ -258,8 +258,10 @@ $print-grapheme:body: {
     var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data
     var data/eax: (addr array screen-cell) <- lookup *data-ah
     var offset/ecx: (offset screen-cell) <- compute-offset data, idx
-    var cell/eax: (addr screen-cell) <- index data, offset
-    var dest/eax: (addr grapheme) <- get cell, data
+    var dest-cell/ecx: (addr screen-cell) <- index data, offset
+    var src-cell/eax: (addr screen-cell) <- get screen-addr, curr-attributes
+    copy-object src-cell, dest-cell
+    var dest/eax: (addr grapheme) <- get dest-cell, data
     var c2/ecx: grapheme <- copy c
 #?     print-grapheme-to-real-screen c2
 #?     print-string-to-real-screen "\n"
@@ -315,6 +317,23 @@ fn screen-grapheme-at-idx screen-on-stack: (addr screen), idx-on-stack: int -> r
   result <- copy *src
 }
 
+fn screen-color-at screen-on-stack: (addr screen), row: int, col: int -> result/eax: int {
+  var screen-addr/esi: (addr screen) <- copy screen-on-stack
+  var idx/ecx: int <- screen-cell-index screen-addr, row, col
+  result <- screen-color-at-idx screen-addr, idx
+}
+
+fn screen-color-at-idx screen-on-stack: (addr screen), idx-on-stack: int -> result/eax: int {
+  var screen-addr/esi: (addr screen) <- copy screen-on-stack
+  var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data
+  var data/eax: (addr array screen-cell) <- lookup *data-ah
+  var idx/ecx: int <- copy idx-on-stack
+  var offset/ecx: (offset screen-cell) <- compute-offset data, idx
+  var cell/eax: (addr screen-cell) <- index data, offset
+  var src/eax: (addr int) <- get cell, color
+  result <- copy *src
+}
+
 fn print-code-point screen: (addr screen), c: code-point {
   var g/eax: grapheme <- to-grapheme c
   print-grapheme screen, g
@@ -346,6 +365,11 @@ $reset-formatting:body: {
   {
     break-if-=
     # fake screen
+    var screen-addr/esi: (addr screen) <- copy screen
+    var dest/ecx: (addr screen-cell) <- get screen-addr, curr-attributes
+    var empty-cell: screen-cell
+    var empty-cell-addr/eax: (addr screen-cell) <- address empty-cell
+    copy-object empty-cell-addr, dest
   }
 }
 }
@@ -361,6 +385,14 @@ $start-color:body: {
   {
     break-if-=
     # fake screen
+    var screen-addr/esi: (addr screen) <- copy screen
+    var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes
+    var dest/edx: (addr int) <- get attr, color
+    var src/eax: int <- copy fg
+    copy-to *dest, src
+    var dest/edx: (addr int) <- get attr, background-color
+    var src/eax: int <- copy bg
+    copy-to *dest, src
   }
 }
 }
@@ -376,6 +408,10 @@ $start-bold:body: {
   {
     break-if-=
     # fake screen
+    var screen-addr/esi: (addr screen) <- copy screen
+    var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes
+    var dest/edx: (addr boolean) <- get attr, bold?
+    copy-to *dest, 1
   }
 }
 }
@@ -391,6 +427,10 @@ $start-underline:body: {
   {
     break-if-=
     # fake screen
+    var screen-addr/esi: (addr screen) <- copy screen
+    var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes
+    var dest/edx: (addr boolean) <- get attr, underline?
+    copy-to *dest, 1
   }
 }
 }
@@ -406,6 +446,10 @@ $start-reverse-video:body: {
   {
     break-if-=
     # fake screen
+    var screen-addr/esi: (addr screen) <- copy screen
+    var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes
+    var dest/edx: (addr boolean) <- get attr, reverse?
+    copy-to *dest, 1
   }
 }
 }
@@ -421,6 +465,10 @@ $start-blinking:body: {
   {
     break-if-=
     # fake screen
+    var screen-addr/esi: (addr screen) <- copy screen
+    var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes
+    var dest/edx: (addr boolean) <- get attr, blink?
+    copy-to *dest, 1
   }
 }
 }
@@ -436,6 +484,9 @@ $hide-cursor:body: {
   {
     break-if-=
     # fake screen
+    var screen-addr/esi: (addr screen) <- copy screen
+    var hide?/ecx: (addr boolean) <- get screen-addr, cursor-hide?
+    copy-to *hide?, 1
   }
 }
 }
@@ -451,6 +502,9 @@ $show-cursor:body: {
   {
     break-if-=
     # fake screen
+    var screen-addr/esi: (addr screen) <- copy screen
+    var hide?/ecx: (addr boolean) <- get screen-addr, cursor-hide?
+    copy-to *hide?, 0
   }
 }
 }
@@ -479,14 +533,13 @@ fn check-screen-row-from screen-on-stack: (addr screen), row-idx: int, col-idx:
     var expected-grapheme/eax: grapheme <- read-grapheme e-addr
     var expected-grapheme2/eax: int <- copy expected-grapheme
     # compare graphemes
-    $check-screen-row:compare-graphemes: {
+    $check-screen-row-from:compare-graphemes: {
       # if expected-grapheme is space, null grapheme is also ok
       {
         compare expected-grapheme2, 0x20
         break-if-!=
         compare g2, 0
-        break-if-!=
-        break $check-screen-row:compare-graphemes
+        break-if-= $check-screen-row-from:compare-graphemes
       }
       check-ints-equal g2, expected-grapheme2, msg
     }
@@ -497,10 +550,47 @@ fn check-screen-row-from screen-on-stack: (addr screen), row-idx: int, col-idx:
 
 # various variants by screen-cell attribute; spaces in the 'expected' data should not match the attribute
 
-fn check-screen-row-in-color screen-on-stack: (addr screen), fg: color, row-idx: int, expected: (addr array byte), msg: (addr array byte) {
+fn check-screen-row-in-color screen: (addr screen), fg: color, row-idx: int, expected: (addr array byte), msg: (addr array byte) {
+  check-screen-row-in-color-from screen, fg, row-idx, 1, expected, msg
 }
 
 fn check-screen-row-in-color-from screen-on-stack: (addr screen), fg: color, row-idx: int, col-idx: int, expected: (addr array byte), msg: (addr array byte) {
+  var screen/esi: (addr screen) <- copy screen-on-stack
+  var idx/ecx: int <- screen-cell-index screen, row-idx, col-idx
+  # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme
+  var e: (stream byte 0x100)
+  var e-addr/edx: (addr stream byte) <- address e
+  write e-addr, expected
+  {
+    var done?/eax: boolean <- stream-empty? e-addr
+    compare done?, 0
+    break-if-!=
+    var g/eax: grapheme <- screen-grapheme-at-idx screen, idx
+    var g2/ebx: int <- copy g
+    var expected-grapheme/eax: grapheme <- read-grapheme e-addr
+    var expected-grapheme2/edx: int <- copy expected-grapheme
+    # compare graphemes
+    $check-screen-row-in-color-from:compare-graphemes: {
+      # if expected-grapheme is space, null grapheme is also ok
+      {
+        compare expected-grapheme2, 0x20
+        break-if-!=
+        compare g2, 0
+        break-if-= $check-screen-row-in-color-from:compare-graphemes
+      }
+      # if expected-grapheme is space, a different color is ok
+      {
+        compare expected-grapheme2, 0x20
+        break-if-!=
+        var color/eax: int <- screen-color-at-idx screen, idx
+        compare color, fg
+        break-if-!= $check-screen-row-in-color-from:compare-graphemes
+      }
+      check-ints-equal g2, expected-grapheme2, msg
+    }
+    idx <- increment
+    loop
+  }
 }
 
 # background color is visible even for spaces, so 'expected' behaves as an array of booleans.
@@ -704,7 +794,23 @@ fn test-check-screen-scrolls-on-overflow {
   check-screen-row-from screen, 5, 1, "b", "F - test-check-screen-scrolls-on-overflow/2"
 }
 
+fn test-check-screen-color {
+  var screen-on-stack: screen
+  var screen/esi: (addr screen) <- address screen-on-stack
+  initialize-screen screen, 5, 4
+  var c/eax: grapheme <- copy 0x61  # 'a'
+  print-grapheme screen, c
+  start-color screen, 1, 0  # foreground=1
+  c <- copy 0x62  # 'b'
+  print-grapheme screen, c
+  start-color screen, 0, 0  # back to default
+  c <- copy 0x63  # 'c'
+  print-grapheme screen, c
+  check-screen-row-in-color screen, 0, 1, "a c", "F - test-check-screen-color"
+}
+
 #? fn main -> exit-status/ebx: int {
+#? #?   test-check-screen-color
 #?   run-tests
 #?   exit-status <- copy 0
 #? }
diff --git a/apps/mu b/apps/mu
index f3c88e9c..2cf5d31c 100755
--- a/apps/mu
+++ b/apps/mu
Binary files differdiff --git a/apps/mu.subx b/apps/mu.subx
index f673045a..1b68350f 100644
--- a/apps/mu.subx
+++ b/apps/mu.subx
@@ -12695,6 +12695,10 @@ has-primitive-name?:  # stmt: (addr stmt) -> result/eax: boolean
     (string-equal? %esi "compute-offset")  # => eax
     3d/compare-eax-and 0/imm32/false
     0f 85/jump-if-!= $has-primitive-name?:end/disp32
+    # if (name == "copy-object") return true
+    (string-equal? %esi "copy-object")  # => eax
+    3d/compare-eax-and 0/imm32/false
+    0f 85/jump-if-!= $has-primitive-name?:end/disp32
     # if (name == "allocate") return true
     (string-equal? %esi "allocate")  # => eax
     3d/compare-eax-and 0/imm32/false
@@ -12820,6 +12824,14 @@ check-mu-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffer
       (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
       e9/jump $check-mu-primitive:end/disp32
     }
+    # if (op == "copy-object") check-mu-copy-object-stmt
+    {
+      (string-equal? %ecx "copy-object")  # => eax
+      3d/compare-eax-and 0/imm32/false
+      74/jump-if-= break/disp8
+      (check-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
+      e9/jump $check-mu-primitive:end/disp32
+    }
     # if (op == "allocate") check-mu-allocate-stmt
     {
       (string-equal? %ecx "allocate")  # => eax
@@ -13786,6 +13798,18 @@ $check-mu-compute-offset-stmt:end:
     5d/pop-to-ebp
     c3/return
 
+check-mu-copy-object-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+$check-mu-copy-object-stmt:end:
+    # . restore registers
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
 check-mu-allocate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
     # . prologue
     55/push-ebp
@@ -16039,6 +16063,15 @@ emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (ad
       (translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
       e9/jump $emit-subx-stmt:end/disp32
     }
+    # copy-object
+    {
+      # if (!string-equal?(stmt->operation, "copy-object")) break
+      (string-equal? %ecx "copy-object")  # => eax
+      3d/compare-eax-and 0/imm32
+      0f 84/jump-if-= break/disp32
+      (translate-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
+      e9/jump $emit-subx-stmt:end/disp32
+    }
     # allocate array
     {
       # if (!string-equal?(stmt->operation, "populate")) break
@@ -16810,6 +16843,34 @@ $translate-mu-get-stmt:end:
     5d/pop-to-ebp
     c3/return
 
+translate-mu-copy-object-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    50/push-eax
+    #
+    (emit-indent *(ebp+8) *Curr-block-depth)
+    (write-buffered *(ebp+8) "(copy-bytes")
+    # eax = stmt
+    8b/-> *(ebp+0xc) 0/r32/eax
+    # var first-inout/eax: (addr stmt-var) = stmt->inouts[0]
+    (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
+    (emit-subx-call-operand *(ebp+8) %eax)
+    (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
+    (emit-subx-call-operand *(ebp+8) %eax)
+    (write-buffered *(ebp+8) Space)
+    (addr-payload-size %eax *(ebp+0x10) *(ebp+0x14))  # => eax
+    (write-int32-hex-buffered *(ebp+8) %eax)
+    (write-buffered *(ebp+8) ")\n")
+$translate-mu-copy-object-stmt:end:
+    # . restore registers
+    58/pop-to-eax
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
 translate-mu-allocate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
     # . prologue
     55/push-ebp