From cde758769d8950fa1f5a13aebea62be3b9602d98 Mon Sep 17 00:00:00 2001
From: Eduardo Julian
Date: Sun, 14 Mar 2021 15:12:26 -0400
Subject: Frustrated with PHP's overflow/underflow logic.

---
 compilers.md                                       |  2 +
 documentation/bookmark/Optimization.md             |  1 +
 documentation/bookmark/Security.md                 |  1 +
 documentation/bookmark/browser.md                  |  1 +
 documentation/bookmark/debugging.md                |  1 +
 documentation/bookmark/floating point.md           |  4 ++
 documentation/bookmark/law.md                      |  5 ++
 documentation/bookmark/user_interface/graphic.md   |  1 +
 documentation/bookmark/web_framework.md            |  2 +
 lux-php/source/program.lux                         | 12 +----
 stdlib/source/lux/data/collection/row.lux          |  3 ++
 stdlib/source/lux/math/number/nat.lux              | 25 ++++-----
 stdlib/source/lux/target/php.lux                   |  4 +-
 .../lux/phase/extension/generation/php/host.lux    |  6 +--
 .../language/lux/phase/generation/php/loop.lux     | 14 +++--
 .../language/lux/phase/generation/php/runtime.lux  | 59 ++++++++++++++--------
 16 files changed, 84 insertions(+), 57 deletions(-)
 create mode 100644 documentation/bookmark/law.md

diff --git a/compilers.md b/compilers.md
index ae558bbea..996322c7c 100644
--- a/compilers.md
+++ b/compilers.md
@@ -31,6 +31,8 @@ cd ~/lux/lux-php/ \
 cd ~/lux/stdlib/ \
 && lein clean \
 && time java -jar ~/lux/lux-php/target/program.jar build --source ~/lux/stdlib/source --target ~/lux/stdlib/target --module test/lux
+
+php -f ~/lux/stdlib/target/program.php
 ```
 
 ---
diff --git a/documentation/bookmark/Optimization.md b/documentation/bookmark/Optimization.md
index e31686963..4fb4656c9 100644
--- a/documentation/bookmark/Optimization.md
+++ b/documentation/bookmark/Optimization.md
@@ -12,6 +12,7 @@
 
 # Reference
 
+1. [Towards a Domain-Extensible Compiler: Optimizingan Image Processing Pipeline on Mobile CPUs](https://thok.eu/publications/2021/cgo.pdf)
 1. [Compiler Detection of Function Call Side Effects](https://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=B3D92D05C88C3D9C165785594350C169?doi=10.1.1.70.2096&rep=rep1&type=pdf)
 1. [A Language for Describing Optimization Strategies](https://arxiv.org/abs/2002.02268)
 1. https://docs.google.com/presentation/d/1tpeJZFObkeick4CF-mx0L3CeCgvT15B96aJeRpxEPcE/preview?slide=id.p
diff --git a/documentation/bookmark/Security.md b/documentation/bookmark/Security.md
index b9d45faff..4ea9b1b46 100644
--- a/documentation/bookmark/Security.md
+++ b/documentation/bookmark/Security.md
@@ -4,6 +4,7 @@
 
 # Privacy
 
+1. [Programming Differential Privacy](https://uvm-plaid.github.io/programming-dp/intro.html)
 1. https://privacypatterns.org/
 
 # Inspiration
diff --git a/documentation/bookmark/browser.md b/documentation/bookmark/browser.md
index 7579e468b..2521275e8 100644
--- a/documentation/bookmark/browser.md
+++ b/documentation/bookmark/browser.md
@@ -46,4 +46,5 @@
 1. https://v8project.blogspot.com/2018/08/embedded-builtins.html
 1. https://developers.google.com/web/updates/2018/09/inside-browser-part1
 1. https://addons.mozilla.org/en-US/firefox/addon/tree-style-tab/
+1. [Web Browser Engineering](https://browser.engineering/index.html)
 
diff --git a/documentation/bookmark/debugging.md b/documentation/bookmark/debugging.md
index 99071f483..f870c5d94 100644
--- a/documentation/bookmark/debugging.md
+++ b/documentation/bookmark/debugging.md
@@ -32,6 +32,7 @@
 
 # Reference
 
+1. [The Debugging Book: Tools and Techniques for Automated Software Debugging](https://www.debuggingbook.org/)
 1. [The Power Of Collaborative Debugging](https://robert.ocallahan.org/2019/11/the-power-of-collaborative-debugging.html)
 1. [Multiverse Debugging: Non-Deterministic Debugging for Non-Deterministic Programs](https://stefan-marr.de/2019/07/what-if-we-could-see-all-concurrency-bugs-in-the-debugger/)
 1. [Writing a Debugger](http://system.joekain.com/debugger/)
diff --git a/documentation/bookmark/floating point.md b/documentation/bookmark/floating point.md
index 9268449d9..93921b0a9 100644
--- a/documentation/bookmark/floating point.md	
+++ b/documentation/bookmark/floating point.md	
@@ -1,3 +1,7 @@
+# Reference
+
+1. [What aspect of portable floating point did Java back down on?](https://retrocomputing.stackexchange.com/questions/18143/what-aspect-of-portable-floating-point-did-java-back-down-on)
+
 # Algorithm
 
 1. [Kahan summation algorithm](https://en.wikipedia.org/wiki/Kahan_summation_algorithm)
diff --git a/documentation/bookmark/law.md b/documentation/bookmark/law.md
new file mode 100644
index 000000000..39a2b18fb
--- /dev/null
+++ b/documentation/bookmark/law.md
@@ -0,0 +1,5 @@
+# Reference
+
+1. [Catala: A Programming Language for the Law](https://arxiv.org/abs/2103.03198)
+1. []()
+
diff --git a/documentation/bookmark/user_interface/graphic.md b/documentation/bookmark/user_interface/graphic.md
index 9b53bddae..51e78c16d 100644
--- a/documentation/bookmark/user_interface/graphic.md
+++ b/documentation/bookmark/user_interface/graphic.md
@@ -10,6 +10,7 @@
 
 1. [Ant Design](https://ant.design/)
 1. [7 Practical Tips for Cheating at Design](https://medium.com/refactoring-ui/7-practical-tips-for-cheating-at-design-40c736799886)
+1. [Smart progress bars](https://honeypot.net/post/smart-progress-bars/)
 
 # Dark Patterns
 
diff --git a/documentation/bookmark/web_framework.md b/documentation/bookmark/web_framework.md
index 741895072..76485f924 100644
--- a/documentation/bookmark/web_framework.md
+++ b/documentation/bookmark/web_framework.md
@@ -139,6 +139,8 @@
 1. https://medium.com/@devdevcharlie/things-nobody-ever-taught-me-about-css-5d16be8d5d0e
 1. https://medium.freecodecamp.org/the-css-handbook-a-handy-guide-to-css-for-developers-b56695917d11
 1. https://css-tricks.com/look-ma-no-media-queries-responsive-layouts-using-css-grid/
+1. [You want enabling CSS selectors, not disabling ones](https://www.silvestar.codes/articles/you-want-a-single-enabling-selector-not-the-one-that-disables-the-rule-of-the-previous-one/)
+1. []()
 
 # Design system
 
diff --git a/lux-php/source/program.lux b/lux-php/source/program.lux
index 14a1646a0..a13039760 100644
--- a/lux-php/source/program.lux
+++ b/lux-php/source/program.lux
@@ -555,14 +555,6 @@
   (-> Any (Promise Any))
   (promise.future (\ world/program.default exit +0)))
 
-(def: (scope body)
-  (-> _.Statement _.Statement)
-  (let [@program (_.constant "lux_program")]
-    ($_ _.then
-        (_.define_function @program (list) body)
-        (_.; (_.apply/* (list) @program))
-        )))
-
 (`` (program: [{service /cli.service}]
       (let [extension ".php"]
         (do io.monad
@@ -581,10 +573,10 @@
                                  [(& Nat _.Label) _.Expression _.Statement]
                                  ..extender
                                  service
-                                 [(packager.package (_.manual "")
+                                 [(packager.package (_.manual "<?php")
                                                     _.code
                                                     _.then
-                                                    ..scope)
+                                                    (|>>))
                                   (format (/cli.target service)
                                           (\ file.default separator)
                                           "program"
diff --git a/stdlib/source/lux/data/collection/row.lux b/stdlib/source/lux/data/collection/row.lux
index 560f7618a..dd1cbcc42 100644
--- a/stdlib/source/lux/data/collection/row.lux
+++ b/stdlib/source/lux/data/collection/row.lux
@@ -1,3 +1,6 @@
+## https://hypirion.com/musings/understanding-persistent-vector-pt-1
+## https://hypirion.com/musings/understanding-persistent-vector-pt-2
+## https://hypirion.com/musings/understanding-persistent-vector-pt-3
 (.module:
   [lux #*
    ["@" target]
diff --git a/stdlib/source/lux/math/number/nat.lux b/stdlib/source/lux/math/number/nat.lux
index 7edc60be4..d0fb348fa 100644
--- a/stdlib/source/lux/math/number/nat.lux
+++ b/stdlib/source/lux/math/number/nat.lux
@@ -287,22 +287,15 @@
 (def: (hexadecimal-value digit)
   (-> Nat (Maybe Nat))
   (case digit
-    (^ (char "0")) (#.Some 0)
-    (^ (char "1")) (#.Some 1)
-    (^ (char "2")) (#.Some 2)
-    (^ (char "3")) (#.Some 3)
-    (^ (char "4")) (#.Some 4)
-    (^ (char "5")) (#.Some 5)
-    (^ (char "6")) (#.Some 6)
-    (^ (char "7")) (#.Some 7)
-    (^ (char "8")) (#.Some 8)
-    (^ (char "9")) (#.Some 9)
-    (^or (^ (char "a")) (^ (char "A"))) (#.Some 10)
-    (^or (^ (char "b")) (^ (char "B"))) (#.Some 11)
-    (^or (^ (char "c")) (^ (char "C"))) (#.Some 12)
-    (^or (^ (char "d")) (^ (char "D"))) (#.Some 13)
-    (^or (^ (char "e")) (^ (char "E"))) (#.Some 14)
-    (^or (^ (char "f")) (^ (char "F"))) (#.Some 15)
+    (^template [<character> <number>]
+      [(^ (char <character>)) (#.Some <number>)])
+    (["0" 0] ["1" 1] ["2" 2] ["3" 3] ["4" 4]
+     ["5" 5] ["6" 6] ["7" 7] ["8" 8] ["9" 9])
+
+    (^template [<lower> <upper> <number>]
+      [(^or (^ (char <lower>)) (^ (char <upper>))) (#.Some <number>)])
+    (["a" "A" 10] ["b" "B" 11] ["c" "C" 12]
+     ["d" "D" 13] ["e" "E" 14] ["f" "F" 15])
     _ #.None))
 
 (template [<shift> <struct> <to-character> <to-value> <error>]
diff --git a/stdlib/source/lux/target/php.lux b/stdlib/source/lux/target/php.lux
index b1eb0b553..f76d9cdc0 100644
--- a/stdlib/source/lux/target/php.lux
+++ b/stdlib/source/lux/target/php.lux
@@ -267,7 +267,8 @@
       ["phpversion"]]]
 
     [1
-     [["var_dump"]
+     [["isset"]
+      ["var_dump"]
       ["is_null"]
       ["empty"]
       ["count"]
@@ -284,6 +285,7 @@
 
     [2
      [["intdiv"]
+      ["array_key_exists"]
       ["call_user_func_array"]
       ["array_slice"]
       ["array_push"]
diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/host.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/host.lux
index f523f1647..794d4aff2 100644
--- a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/host.lux
+++ b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/host.lux
@@ -36,10 +36,6 @@
   (Unary Expression)
   (//runtime.tuple//make size (_.array_fill/3 [(_.int +0) size _.null])))
 
-(def: array::length
-  (Unary Expression)
-  //runtime.array//length)
-
 (def: (array::read [indexG arrayG])
   (Binary Expression)
   (_.nth indexG arrayG))
@@ -57,7 +53,7 @@
   (<| (/.prefix "array")
       (|> /.empty
           (/.install "new" (unary array::new))
-          (/.install "length" (unary array::length))
+          (/.install "length" (unary //runtime.array//length))
           (/.install "read" (binary array::read))
           (/.install "write" (trinary array::write))
           (/.install "delete" (binary array::delete))
diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/loop.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/loop.lux
index 30e325363..d3e91b925 100644
--- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/loop.lux
+++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/loop.lux
@@ -8,7 +8,7 @@
      ["%" format (#+ format)]]
     [collection
      ["." list ("#\." functor fold)]
-     ["." set]]]
+     ["." set (#+ Set)]]]
    [math
     [number
      ["n" nat]]]
@@ -81,11 +81,15 @@
                         list.enumeration
                         (list\map (|>> product.left (n.+ start) //case.register _.parameter)))
              @loop (_.constant (///reference.artifact [loop_module loop_artifact]))
+             loop_variables (set.from_list _.hash (list\map product.right locals))
+             referenced_variables (: (-> Synthesis (Set Var))
+                                     (|>> synthesis.path/then
+                                          //case.dependencies
+                                          (set.from_list _.hash)))
              [directive instantiation] (: [Statement Expression]
-                                          (case (|> (synthesis.path/then bodyS)
-                                                    //case.dependencies
-                                                    (set.from_list _.hash)
-                                                    (set.difference (set.from_list _.hash (list\map product.right locals)))
+                                          (case (|> (list\map referenced_variables initsS+)
+                                                    (list\fold set.union (referenced_variables bodyS))
+                                                    (set.difference loop_variables)
                                                     set.to_list)
                                             #.Nil
                                             [(_.define_function @loop (list) scope!)
diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/runtime.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/runtime.lux
index 5e1c36112..bdf18462a 100644
--- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/runtime.lux
+++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/runtime.lux
@@ -149,7 +149,7 @@
 (def: #export tuple_size_field
   "_lux_size")
 
-(def: #export tuple_size
+(def: tuple_size
   (_.nth (_.string ..tuple_size_field)))
 
 (def: jphp?
@@ -158,9 +158,7 @@
 (runtime: (array//length array)
   ## TODO: Get rid of this as soon as JPHP is no longer necessary.
   (_.if ..jphp?
-    (_.if (..tuple_size array)
-      (_.return (..tuple_size array))
-      (_.return (_.count/1 array)))
+    (_.return (..tuple_size array))
     (_.return (_.count/1 array))))
 
 (runtime: (array//write idx value array)
@@ -175,22 +173,34 @@
       @array//write
       ))
 
-(def: last_index
+(def: jphp_last_index
   (|>> ..tuple_size (_.- (_.int +1))))
 
+(def: normal_last_index
+  (|>> _.count/1 (_.- (_.int +1))))
+
 (with_expansions [<recur> (as_is ($_ _.then
                                      (_.; (_.set lefts (_.- last_index_right lefts)))
                                      (_.; (_.set tuple (_.nth last_index_right tuple)))))]
   (runtime: (tuple//make size values)
-    ($_ _.then
-        (_.; (_.set (..tuple_size values) size))
-        (_.return values)))
+    (_.if ..jphp?
+      ($_ _.then
+          (_.; (_.set (..tuple_size values) size))
+          (_.return values))
+      ## https://www.php.net/manual/en/language.operators.assignment.php
+      ## https://www.php.net/manual/en/language.references.php
+      ## https://www.php.net/manual/en/functions.arguments.php
+      ## https://www.php.net/manual/en/language.oop5.references.php
+      ## https://www.php.net/manual/en/class.arrayobject.php
+      (_.return (_.new (_.constant "ArrayObject") (list values)))))
 
   (runtime: (tuple//left lefts tuple)
     (with_vars [last_index_right]
       (<| (_.while (_.bool true))
           ($_ _.then
-              (_.; (_.set last_index_right (..last_index tuple)))
+              (_.if ..jphp?
+                (_.; (_.set last_index_right (..jphp_last_index tuple)))
+                (_.; (_.set last_index_right (..normal_last_index tuple))))
               (_.if (_.> lefts last_index_right)
                 ## No need for recursion
                 (_.return (_.nth lefts tuple))
@@ -216,7 +226,9 @@
     (with_vars [last_index_right right_index]
       (<| (_.while (_.bool true))
           ($_ _.then
-              (_.; (_.set last_index_right (..last_index tuple)))
+              (_.if ..jphp?
+                (_.; (_.set last_index_right (..jphp_last_index tuple)))
+                (_.; (_.set last_index_right (..normal_last_index tuple))))
               (_.; (_.set right_index (_.+ (_.int +1) lefts)))
               (_.cond (list [(_.=== last_index_right right_index)
                              (_.return (_.nth right_index tuple))]
@@ -226,7 +238,7 @@
                       (_.if ..jphp?
                         (_.return (..tuple//make (_.- right_index (..tuple_size tuple))
                                                  (..tuple//slice right_index tuple)))
-                        (_.return (..tuple//make (_.- right_index (..tuple_size tuple))
+                        (_.return (..tuple//make (_.- right_index (_.count/1 tuple))
                                                  (_.array_slice/2 [tuple right_index])))))
               )))))
 
@@ -326,16 +338,23 @@
       ))
 
 (runtime: (i64//right_shift param subject)
-  (let [mask (|> (_.int +1)
-                 (_.bit_shl (_.- param (_.int +64)))
-                 (_.- (_.int +1)))]
+  (let [## The mask has to be calculated this way instead of in a more straightforward way
+        ## because in some languages, 1<<63 = max_negative_value
+        ## and max_negative_value-1 = max_positive_value.
+        ## And bitwise, max_positive_value works out to the mask that is desired when param = 0.
+        ## However, in PHP, max_negative_value-1 underflows and gets cast into a float.
+        ## And this messes up the computation.
+        ## This slightly more convoluted calculation avoids that problem.
+        mask (|> (_.int +1)
+                 (_.bit_shl (_.- param (_.int +63)))
+                 (_.- (_.int +1))
+                 (_.bit_shl (_.int +1))
+                 (_.+ (_.int +1)))]
     ($_ _.then
-        (_.; (_.set param (_.bit_and (_.int +63) param)))
-        (_.if (_.=== (_.int +0) param)
-          (_.return subject)
-          (_.return (|> subject
-                        (_.bit_and mask)
-                        (_.bit_shr param)))))))
+        (_.; (_.set param (_.% (_.int +64) param)))
+        (_.return (|> subject
+                      (_.bit_shr param)
+                      (_.bit_and mask))))))
 
 (runtime: (i64//char code)
   (_.if ..jphp?
-- 
cgit v1.2.3