Hi all:

I've only been using Poly for a few days and haven't done too much SML before a project I'm working on now -- but I've noticed a couple of things that seemed a little tedious while implementing some modules as a part of that project. I may have missed something, and if that's the case please do point it out to me. However, in case what I've observed is in fact the current state of the world, I've written a small proposal and a patch to eliminate these little annoyances (suggested to me by DGASAU on freenode).


In essence, I've been building an FFI in the past few days and noticed an absence of a number of things. Namely, there seems to be a lack of support for standard C types such as uint16_t, int16_t, int8_t, int64_t and float (not sure about int64_t). This can make building FFIs a bit of a hassle sometimes, as it requires explicit checks of what value the integer/word in SML might contain before deciding to try and write it.


An example of such a workaround would be:

        if (#NOFFS a) > 0w65535 orelse (#NENOFFS a) > 0w65535
        then raise RunCall.Conversion "Invalid Word16 constant"
        else (...)

where #NOFFS a and #NENOFFS a are otherwise manipulated as Word32.words.


Moreover, this seems to sometimes cause people developing software or extracting executable specifications from proof assistants such as Isabelle that depend on things like Word16 to discard or impose a limitation on SML used with PolyML as it simply does not support these types out of the box [1, 2]


Would it make sense to support these types in PolyML, namely through Word16.word, Int16.int, Int8.int and Int64.int, where Word16 would be of WORD signature, while Int16, Int8 and Int64 would be of INTEGER signature.


I've attached a sample patch for supporting Word16, very heavily based on David Matthews' work on Word8 in order to demonstrate what a very crude implementation of the proposal would look like.


Is this a real problem, and if so, is implementing these things a sensible way forward?


Thanks!


[1]: http://rohandrape.net/?t=smlsc3&e=README

[2]: https://www.isa-afp.org/browser_info/current/AFP/Native_Word/outline.pdf


--

Domagoj

diff --git a/basis/Word16.sml b/basis/Word16.sml
new file mode 100644
index 00000000..be503012
--- /dev/null
+++ b/basis/Word16.sml
@@ -0,0 +1,134 @@
+(*
+    Title:      Standard Basis Library: Word16 Structure
+    Author:     Domagoj Stolfa
+    Copyright   Domagoj Stolfa 2018
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+    
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+    
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+
+(*
+ * This file is *heavily* based on David Matthews' work on Word8.
+ *)
+
+structure Word16 :> WORD =
+struct
+    open Word
+
+    (* 16-bit words have values that range from 0...65535 and like Word8.word
+       are implemented using tagged integers. *)
+    val wordSize = 16
+    val maxWord = 65535
+    val maxWordAsWord: word = RunCall.unsafeCast maxWord
+
+    infix 8 << >> ~>>
+
+    (* Comparison operations, min, max and compare, fmt, toString,
+       orb, andb, xorb can be inherited directly from Word.
+       Similarly div and mod since the results will always be no
+       larger than the arguments. *)
+
+    (* This only works for the bottom 16 bits *)
+    fun notb x = xorb(maxWordAsWord, x)
+
+    (* Internal function to convert from Word.word. *)
+    fun fromWord (w: Word.word) = andb(w, maxWordAsWord)
+
+    (* Converting from LargeWord.word.  First convert to Word.word and
+       then mask. *)
+    val fromLargeWord = fromWord o Word.fromLargeWord
+    and fromInt = fromWord o Word.fromInt
+    and fromLargeInt = fromWord o Word.fromLargeInt
+
+    val fromLarge = fromLargeWord
+
+    local
+        val toSignBit = Word.fromInt(Int.-(Word.wordSize,wordSize))
+    in
+        fun op ~>> (a: word, b: Word.word): word =
+            fromWord(Word.~>>(Word.<<(a, toSignBit), Word.+(b, toSignBit)))
+    end
+
+    fun op << (a: word, b: Word.word): word = andb(Word.<<(a,b), maxWordAsWord)
+
+    val toInt: word->int = RunCall.unsafeCast
+
+    (* As with Word8.toIntX, this could be implemented with a logical shift
+       followed by an arithmetic shift *)
+    fun toIntX (x: word) : int =
+        let
+            val intx = toInt x
+            open Int
+        in
+            if intx >= 32768
+            then intx-maxWord-1
+            else intx
+        end
+
+    val toLargeInt = LargeInt.fromInt o toInt
+    and toLargeIntX = LargeInt.fromInt o toIntX
+
+    fun toLargeWordX (w: word): LargeWord.word =
+        LargeWord.fromInt(toIntX w);
+    val toLargeX = toLargeWordX
+
+    val wordScan = scan;
+
+    fun scan radix getc src =
+        case wordScan radix getc src of
+            NONE => NONE
+         |  SOME(res, src') =>
+                if res > maxWordAsWord
+                then raise General.Overflow
+                else SOME(res, src')
+
+    val fromString = StringCvt.scanString (scan StringCvt.HEX)
+
+    fun op + (a, b) = fromWord(Word.+(a, b))
+    and op - (a, b) = fromWord(Word.-(a, b))
+    and op * (a, b) = fromWord(Word.*(a, b))
+
+    fun ~ x = 0w0 - x
+
+end;
+
+(* Because we are using opaque signature matching we have to install
+   type-dependent functions OUTSIDE the structure. *)
+local
+    fun convWord s : Word16.word =
+        let
+        val radix =
+            if String.sub(s, 2) = #"x" then StringCvt.HEX else StringCvt.DEC
+        in
+            case StringCvt.scanString (Word16.scan radix) s of
+                NONE => raise RunCall.Conversion "Invalid Word16 constant"
+              | SOME res => res
+        end
+
+    fun pretty _ _ x = PolyML.PrettyString("0wx" ^ Word16.toString x)
+in
+    val () = RunCall.addOverload convWord "convWord"
+    val () = PolyML.addPrettyPrinter pretty
+end;
+
+val () = RunCall.addOverload Word16.~ "~";
+val () = RunCall.addOverload Word16.+ "+";
+val () = RunCall.addOverload Word16.- "-";
+val () = RunCall.addOverload Word16.* "*";
+val () = RunCall.addOverload Word16.div "div";
+val () = RunCall.addOverload Word16.mod "mod";
+val () = RunCall.addOverload Word16.< "<";
+val () = RunCall.addOverload Word16.> ">";
+val () = RunCall.addOverload Word16.<= "<=";
+val () = RunCall.addOverload Word16.>= ">=";
diff --git a/basis/build.sml b/basis/build.sml
index 3c4439ac..dadfd2cb 100644
--- a/basis/build.sml
+++ b/basis/build.sml
@@ -65,6 +65,7 @@ val () =
     then Bootstrap.use "basis/Word32In64.sml"
     else ();
 
+val () = Bootstrap.use "basis/Word16.sml";
 val () = Bootstrap.use "basis/Word8.sml";
 val () = Bootstrap.use "basis/IntInf.sml";
 val () = Bootstrap.use "basis/Int32.sml";
diff --git a/documentation/Overview.html b/documentation/Overview.html
index 4819181e..f8e2560d 100644
--- a/documentation/Overview.html
+++ b/documentation/Overview.html
@@ -508,6 +508,7 @@
   basis/Windows.sml<br>
   basis/Word32.sml<br>
   basis/Word32.x86_64.sml<br>
+  basis/Word16.sml<br>
   basis/Word8.sml<br>
   basis/Word8Array.sml
 </p>
diff --git a/polyml.pyp b/polyml.pyp
index 32d036e5..21aa8662 100644
--- a/polyml.pyp
+++ b/polyml.pyp
@@ -92,6 +92,7 @@
 	<source name="basis\Windows.sml" />
 	<source name="basis\Word32.sml" />
 	<source name="basis\Word32In64.sml" />
+	<source name="basis\Word16.sml" />
 	<source name="basis\Word8.sml" />
 	<source name="basis\Word8Array.sml" />
 	<source name="basis\WordSignature.sml" />
diff --git a/polymlInterpreted.pyp b/polymlInterpreted.pyp
index 6b4fb130..7461b368 100644
--- a/polymlInterpreted.pyp
+++ b/polymlInterpreted.pyp
@@ -92,6 +92,7 @@
 	<source name="basis\Windows.sml" />
 	<source name="basis\Word32.sml" />
 	<source name="basis\Word32In64.sml" />
+	<source name="basis\Word16.sml" />
 	<source name="basis\Word8.sml" />
 	<source name="basis\Word8Array.sml" />
 	<source name="basis\WordSignature.sml" />
_______________________________________________
polyml mailing list
polyml@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml

Reply via email to