WSL needs float and double support
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Sep 2017 00:31:53 +0000 (00:31 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Sep 2017 00:31:53 +0000 (00:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=177058

Reviewed by Filip Pizlo.

Use the existing int and uint types as a model. The types themselves are straighforward. Just like int and uint,
you can't pass a float as a double argument and vice-versa. This patch adds operator+, -, *, and / for floats
and doubles.

Float literals are more complicated. If your number has a "." character in it, it is treated as a float literal.
You can add a suffix of "f" or "d" to force the literal to pretend to be a float or a double. These literals are
able to masquerade as either floats or doubles (unlike an explicit type). However, these literals are not able
to masquerade as ints or uints. There's also a nice check that your float literal can actually fit in a float.

* WebGPUShadingLanguageRI/All.js:
* WebGPUShadingLanguageRI/DoubleLiteral.js: Copied from Tools/WebGPUShadingLanguageRI/Type.js.
(let.DoubleLiteral.createLiteral.createType):
* WebGPUShadingLanguageRI/DoubleLiteralType.js: Copied from Tools/WebGPUShadingLanguageRI/Type.js.
(let.DoubleLiteralType.createLiteralType.verifyAsArgument):
* WebGPUShadingLanguageRI/FloatLiteral.js: Copied from Tools/WebGPUShadingLanguageRI/Type.js.
(let.FloatLiteral.createLiteral.createType):
* WebGPUShadingLanguageRI/FloatLiteralType.js: Copied from Tools/WebGPUShadingLanguageRI/Type.js.
(let.FloatLiteralType.createLiteralType.verifyAsArgument):
* WebGPUShadingLanguageRI/Intrinsics.js:
(Intrinsics):
* WebGPUShadingLanguageRI/Lexer.js:
(Lexer.prototype.next):
(Lexer):
* WebGPUShadingLanguageRI/NativeType.js:
(NativeType):
(NativeType.prototype.get isFloating):
(NativeType.prototype.set isFloating):
(NativeType.prototype.get isFloat): Deleted.
(NativeType.prototype.set isFloat): Deleted.
* WebGPUShadingLanguageRI/Parse.js:
(parseTerm):
* WebGPUShadingLanguageRI/Rewriter.js:
(Rewriter.prototype.visitGenericLiteral):
* WebGPUShadingLanguageRI/StandardLibrary.js:
(uint.operator):
(int.operator):
* WebGPUShadingLanguageRI/Test.html:
* WebGPUShadingLanguageRI/Test.js:
(makeFloat):
(makeDouble):
(checkNumber):
(checkFloat):
(checkDouble):
* WebGPUShadingLanguageRI/Type.js:
(Type.prototype.get isFloating):
(Type.prototype.get isFloat): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@222138 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Tools/ChangeLog
Tools/WebGPUShadingLanguageRI/All.js
Tools/WebGPUShadingLanguageRI/DoubleLiteral.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/DoubleLiteralType.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/FloatLiteral.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/FloatLiteralType.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/Intrinsics.js
Tools/WebGPUShadingLanguageRI/Lexer.js
Tools/WebGPUShadingLanguageRI/NativeType.js
Tools/WebGPUShadingLanguageRI/Parse.js
Tools/WebGPUShadingLanguageRI/Rewriter.js
Tools/WebGPUShadingLanguageRI/StandardLibrary.js
Tools/WebGPUShadingLanguageRI/Test.html
Tools/WebGPUShadingLanguageRI/Test.js
Tools/WebGPUShadingLanguageRI/Type.js

index 8ba064a..52cadc4 100644 (file)
@@ -1,3 +1,57 @@
+2017-09-17  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        WSL needs float and double support
+        https://bugs.webkit.org/show_bug.cgi?id=177058
+
+        Reviewed by Filip Pizlo.
+
+        Use the existing int and uint types as a model. The types themselves are straighforward. Just like int and uint,
+        you can't pass a float as a double argument and vice-versa. This patch adds operator+, -, *, and / for floats
+        and doubles.
+
+        Float literals are more complicated. If your number has a "." character in it, it is treated as a float literal.
+        You can add a suffix of "f" or "d" to force the literal to pretend to be a float or a double. These literals are
+        able to masquerade as either floats or doubles (unlike an explicit type). However, these literals are not able
+        to masquerade as ints or uints. There's also a nice check that your float literal can actually fit in a float.
+
+        * WebGPUShadingLanguageRI/All.js:
+        * WebGPUShadingLanguageRI/DoubleLiteral.js: Copied from Tools/WebGPUShadingLanguageRI/Type.js.
+        (let.DoubleLiteral.createLiteral.createType):
+        * WebGPUShadingLanguageRI/DoubleLiteralType.js: Copied from Tools/WebGPUShadingLanguageRI/Type.js.
+        (let.DoubleLiteralType.createLiteralType.verifyAsArgument):
+        * WebGPUShadingLanguageRI/FloatLiteral.js: Copied from Tools/WebGPUShadingLanguageRI/Type.js.
+        (let.FloatLiteral.createLiteral.createType):
+        * WebGPUShadingLanguageRI/FloatLiteralType.js: Copied from Tools/WebGPUShadingLanguageRI/Type.js.
+        (let.FloatLiteralType.createLiteralType.verifyAsArgument):
+        * WebGPUShadingLanguageRI/Intrinsics.js:
+        (Intrinsics):
+        * WebGPUShadingLanguageRI/Lexer.js:
+        (Lexer.prototype.next):
+        (Lexer):
+        * WebGPUShadingLanguageRI/NativeType.js:
+        (NativeType):
+        (NativeType.prototype.get isFloating):
+        (NativeType.prototype.set isFloating):
+        (NativeType.prototype.get isFloat): Deleted.
+        (NativeType.prototype.set isFloat): Deleted.
+        * WebGPUShadingLanguageRI/Parse.js:
+        (parseTerm):
+        * WebGPUShadingLanguageRI/Rewriter.js:
+        (Rewriter.prototype.visitGenericLiteral):
+        * WebGPUShadingLanguageRI/StandardLibrary.js:
+        (uint.operator):
+        (int.operator):
+        * WebGPUShadingLanguageRI/Test.html:
+        * WebGPUShadingLanguageRI/Test.js:
+        (makeFloat):
+        (makeDouble):
+        (checkNumber):
+        (checkFloat):
+        (checkDouble):
+        * WebGPUShadingLanguageRI/Type.js:
+        (Type.prototype.get isFloating):
+        (Type.prototype.get isFloat): Deleted.
+
 2017-09-17  Michael Saboff  <msaboff@apple.com>
 
         https://bugs.webkit.org/show_bug.cgi?id=177038
index 57ae387..82fadd1 100644 (file)
@@ -61,6 +61,8 @@ load("ConvertPtrToArrayRefExpression.js");
 load("DereferenceExpression.js");
 load("DoWhileLoop.js");
 load("DotExpression.js");
+load("DoubleLiteral.js");
+load("DoubleLiteralType.js");
 load("EArrayRef.js");
 load("EBuffer.js");
 load("EBufferBuilder.js");
@@ -70,6 +72,8 @@ load("Evaluator.js");
 load("ExpressionFinder.js");
 load("Field.js");
 load("FlattenProtocolExtends.js");
+load("FloatLiteral.js");
+load("FloatLiteralType.js");
 load("ForLoop.js");
 load("Func.js");
 load("FuncDef.js");
diff --git a/Tools/WebGPUShadingLanguageRI/DoubleLiteral.js b/Tools/WebGPUShadingLanguageRI/DoubleLiteral.js
new file mode 100644 (file)
index 0000000..e9fb6ed
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+let DoubleLiteral = createLiteral({
+    preferredTypeName: "double",
+    
+    createType(origin, value)
+    {
+        return new DoubleLiteralType(origin, value);
+    }
+});
+
diff --git a/Tools/WebGPUShadingLanguageRI/DoubleLiteralType.js b/Tools/WebGPUShadingLanguageRI/DoubleLiteralType.js
new file mode 100644 (file)
index 0000000..1442fb5
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+let DoubleLiteralType = createLiteralType({
+    preferredTypeName: "double",
+    
+    verifyAsArgument(unificationContext)
+    {
+        let realThis = unificationContext.find(this);
+        if (!realThis.isFloating)
+            return {result: false, reason: "Cannot use double literal with non-floating type " + realThis};
+        if (!realThis.canRepresent(this.value))
+            return {result: false, reason: "Float literal " + this.value + " does not fit in type " + realThis};
+        return {result: true};
+    }
+});
diff --git a/Tools/WebGPUShadingLanguageRI/FloatLiteral.js b/Tools/WebGPUShadingLanguageRI/FloatLiteral.js
new file mode 100644 (file)
index 0000000..8779d20
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+let FloatLiteral = createLiteral({
+    preferredTypeName: "float",
+    
+    createType(origin, value)
+    {
+        return new FloatLiteralType(origin, value);
+    }
+});
+
diff --git a/Tools/WebGPUShadingLanguageRI/FloatLiteralType.js b/Tools/WebGPUShadingLanguageRI/FloatLiteralType.js
new file mode 100644 (file)
index 0000000..f7bb7f2
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+"use strict";
+
+let FloatLiteralType = createLiteralType({
+    preferredTypeName: "float",
+    
+    verifyAsArgument(unificationContext)
+    {
+        let realThis = unificationContext.find(this);
+        if (!realThis.isFloating)
+            return {result: false, reason: "Cannot use float literal with non-floating type " + realThis};
+        if (!realThis.canRepresent(this.value))
+            return {result: false, reason: "Float literal " + this.value + " does not fit in type " + realThis};
+        return {result: true};
+    }
+});
index e9d3530..f2d3dd2 100644 (file)
@@ -85,11 +85,22 @@ class Intrinsics {
             });
 
         this._map.set(
+            "native primitive type float<>",
+            type => {
+                this.float = type;
+                type.size = 1;
+                type.isFloating = true;
+                type.isNumber = true;
+                type.canRepresent = value => isBitwiseEquivalent(Math.fround(value), value);
+                type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+            });
+
+        this._map.set(
             "native primitive type double<>",
             type => {
                 this.double = type;
                 type.size = 1;
-                type.isFloat = true;
+                type.isFloating = true;
                 type.isNumber = true;
                 type.canRepresent = value => true;
                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
@@ -116,6 +127,18 @@ class Intrinsics {
             });
         
         this._map.set(
+            "native operator float<>(double)",
+            func => {
+                func.implementation = ([value]) => EPtr.box(Math.fround(value.loadValue()));
+            });
+        
+        this._map.set(
+            "native operator double<>(float)",
+            func => {
+                func.implementation = ([value]) => EPtr.box(value.loadValue());
+            });
+        
+        this._map.set(
             "native int operator+<>(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
@@ -130,6 +153,20 @@ class Intrinsics {
             });
         
         this._map.set(
+            "native float operator+<>(float,float)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(Math.fround(left.loadValue() + right.loadValue()));
+            });
+        
+        this._map.set(
+            "native double operator+<>(double,double)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() + right.loadValue());
+            });
+        
+        this._map.set(
             "native int operator-<>(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
@@ -144,6 +181,20 @@ class Intrinsics {
             });
         
         this._map.set(
+            "native float operator-<>(float,float)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(Math.fround(left.loadValue() - right.loadValue()));
+            });
+        
+        this._map.set(
+            "native double operator-<>(double,double)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() - right.loadValue());
+            });
+        
+        this._map.set(
             "native int operator*<>(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
@@ -158,6 +209,20 @@ class Intrinsics {
             });
         
         this._map.set(
+            "native float operator*<>(float,float)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(Math.fround(left.loadValue() * right.loadValue()));
+            });
+        
+        this._map.set(
+            "native double operator*<>(double,double)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() * right.loadValue());
+            });
+        
+        this._map.set(
             "native int operator/<>(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
@@ -172,6 +237,20 @@ class Intrinsics {
             });
         
         this._map.set(
+            "native float operator/<>(float,float)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(Math.fround(left.loadValue() / right.loadValue()));
+            });
+        
+        this._map.set(
+            "native double operator/<>(double,double)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() / right.loadValue());
+            });
+        
+        this._map.set(
             "native bool operator==<>(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
@@ -193,6 +272,20 @@ class Intrinsics {
             });
         
         this._map.set(
+            "native bool operator==<>(float,float)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() == right.loadValue());
+            });
+        
+        this._map.set(
+            "native bool operator==<>(double,double)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() == right.loadValue());
+            });
+        
+        this._map.set(
             "native bool operator<<>(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
@@ -207,6 +300,20 @@ class Intrinsics {
             });
         
         this._map.set(
+            "native bool operator<<>(float,float)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() < right.loadValue());
+            });
+        
+        this._map.set(
+            "native bool operator<<>(double,double)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() < right.loadValue());
+            });
+        
+        this._map.set(
             "native bool operator<=<>(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
@@ -221,6 +328,20 @@ class Intrinsics {
             });
         
         this._map.set(
+            "native bool operator<=<>(float,float)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() <= right.loadValue());
+            });
+        
+        this._map.set(
+            "native bool operator<=<>(double,double)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() <= right.loadValue());
+            });
+        
+        this._map.set(
             "native bool operator><>(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
@@ -235,6 +356,20 @@ class Intrinsics {
             });
         
         this._map.set(
+            "native bool operator><>(float,float)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() > right.loadValue());
+            });
+        
+        this._map.set(
+            "native bool operator><>(double,double)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() > right.loadValue());
+            });
+        
+        this._map.set(
             "native bool operator>=<>(int,int)",
             func => {
                 func.implementation = ([left, right]) =>
@@ -248,6 +383,20 @@ class Intrinsics {
                     EPtr.box(left.loadValue() >= right.loadValue());
             });
         
+        this._map.set(
+            "native bool operator>=<>(float,float)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() >= right.loadValue());
+            });
+        
+        this._map.set(
+            "native bool operator>=<>(double,double)",
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box(left.loadValue() >= right.loadValue());
+            });
+        
         let arrayElementPtr = func => {
             func.implementation = ([ref, index], node) => {
                 ref = ref.loadValue();
index ef2d7e0..e2f3eb2 100644 (file)
@@ -101,6 +101,10 @@ class Lexer {
         
         if (this._index >= this._text.length)
             return null;
+
+        // FIXME: Make this handle exp-form literals like 1e1.
+        if (/^(([0-9]*\.[0-9]+[fd]?)|([0-9]+\.[0-9]*[fd]?))/.test(relevantText))
+            return result("floatLiteral");
         
         // FIXME: Make this do Unicode.
         if (/^[^\d\W]\w*/.test(relevantText)) {
@@ -118,10 +122,6 @@ class Lexer {
 
         if (/^[0-9]+/.test(relevantText))
             return result("intLiteral");
-
-        // FIXME: Make this handle exp-form literals like 1e1.
-        if (/^([0-9]*\.[0-9]+)|([0-9]+\.[0-9]*)/.test(relevantText))
-            return result("doubleLiteral");
         
         if (/^->|>=|<=|==|!=|\+=|-=|\*=|\/=|%=|^=|\|=|&=|\+\+|--|([{}()\[\]?:=+*\/,.%!~^&|<>@;-])/.test(relevantText))
             return result("punctuation");
index 62e8adc..bd273c7 100644 (file)
@@ -34,7 +34,7 @@ class NativeType extends Type {
         this._typeParameters = typeParameters;
         this._isNumber = false;
         this._isInt = false;
-        this._isFloat = false;
+        this._isFloating = false;
     }
     
     get origin() { return this._origin; }
@@ -48,8 +48,8 @@ class NativeType extends Type {
     set isNumber(value) { this._isNumber = value; }
     get isInt() { return this._isInt; }
     set isInt(value) { this._isInt = value; }
-    get isFloat() { return this._isFloat; }
-    set isFloat(value) { this._isFloat = value; }
+    get isFloating() { return this._isFloating; }
+    set isFloating(value) { this._isFloating = value; }
     
     instantiate(typeArguments)
     {
index 6ed00ad..3b81931 100644 (file)
@@ -183,11 +183,22 @@ function parse(program, origin, originKind, lineNumberOffset, text)
                 lexer.fail("Integer literal is not 32-bit unsigned integer");
             return new UintLiteral(token, uintVersion);
         }
-        if (token = tryConsumeKind("doubleLiteral"))
-            return new DoubleLiteral(token, +token.text);
+        if (token = tryConsumeKind("floatLiteral")) {
+            let text = token.text;
+            let d = token.text.endsWith("d");
+            let f = token.text.endsWith("f");
+            if (d && f)
+                throw new Error("Literal cannot be both a double literal and a float literal.");
+            if (d || f)
+                text = text.substring(0, text.length - 1);
+            let value = parseFloat(text);
+            if (d)
+                return new DoubleLiteral(token, value);
+            return new FloatLiteral(token, Math.fround(value));
+        }
         if (token = tryConsume("true", "false"))
             return new BoolLiteral(token, token.text == "true");
-        // FIXME: Need support for float literals and probably other literals too.
+        // FIXME: Need support for other literals too.
         consume("(");
         let result = parseExpression();
         consume(")");
index c75727d..a81b87f 100644 (file)
@@ -231,6 +231,7 @@ class Rewriter extends VisitorBase {
     
     visitGenericLiteral(node)
     {
+        // FIXME: This doesn't seem right.
         let result = new IntLiteral(node.origin, node.value);
         result.type = node.type.visit(this);
         result.ePtr = node.ePtr;
index cd7a1f4..03e94cc 100644 (file)
@@ -39,34 +39,55 @@ native primitive typedef bool;
 typedef int = int32;
 typedef uint = uint32;
 
+native primitive typedef float;
 native primitive typedef double;
 
 native operator int32(uint32);
 native operator uint32(int32);
+native operator float(double);
+native operator double(float);
 
 native int operator+(int, int);
 native uint operator+(uint, uint);
+native float operator+(float, float);
+native double operator+(double, double);
 int operator++(int value) { return value + 1; }
 uint operator++(uint value) { return value + 1; }
-int operator--(int value) { return value - 1; }
-uint operator--(uint value) { return value - 1; }
 native int operator-(int, int);
 native uint operator-(uint, uint);
+native float operator-(float, float);
+native double operator-(double, double);
+int operator--(int value) { return value - 1; }
+uint operator--(uint value) { return value - 1; }
 native int operator*(int, int);
 native uint operator*(uint, uint);
+native float operator*(float, float);
+native double operator*(double, double);
 native int operator/(int, int);
 native uint operator/(uint, uint);
+native float operator/(float, float);
+native double operator/(double, double);
 native bool operator==(int, int);
 native bool operator==(uint, uint);
 native bool operator==(bool, bool);
+native bool operator==(float, float);
+native bool operator==(double, double);
 native bool operator<(int, int);
 native bool operator<(uint, uint);
+native bool operator<(float, float);
+native bool operator<(double, double);
 native bool operator<=(int, int);
 native bool operator<=(uint, uint);
+native bool operator<=(float, float);
+native bool operator<=(double, double);
 native bool operator>(int, int);
 native bool operator>(uint, uint);
+native bool operator>(float, float);
+native bool operator>(double, double);
 native bool operator>=(int, int);
 native bool operator>=(uint, uint);
+native bool operator>=(float, float);
+native bool operator>=(double, double);
 
 protocol Equatable {
     bool operator==(Equatable, Equatable);
index c80d387..4ed96db 100644 (file)
@@ -37,6 +37,8 @@
 <script src="ConvertPtrToArrayRefExpression.js"></script>
 <script src="DoWhileLoop.js"></script>
 <script src="DotExpression.js"></script>
+<script src="DoubleLiteral.js"></script>
+<script src="DoubleLiteralType.js"></script>
 <script src="DereferenceExpression.js"></script>
 <script src="EArrayRef.js"></script>
 <script src="EBuffer.js"></script>
@@ -47,6 +49,8 @@
 <script src="ExpressionFinder.js"></script>
 <script src="Field.js"></script>
 <script src="FlattenProtocolExtends.js"></script>
+<script src="FloatLiteral.js"></script>
+<script src="FloatLiteralType.js"></script>
 <script src="ForLoop.js"></script>
 <script src="Func.js"></script>
 <script src="FuncDef.js"></script>
index be36f0d..e11c04b 100644 (file)
@@ -57,14 +57,6 @@ function makeInt(program, value)
     return TypedValue.box(program.intrinsics.int32, value);
 }
 
-function checkNumber(program, result, expected)
-{
-    if (!result.type.isNumber)
-        throw new Error("Wrong result type; result: " + result);
-    if (result.value != expected)
-        throw new Error("Wrong result: " + result + " (expected " + expected + ")");
-}
-
 function makeUint(program, value)
 {
     return TypedValue.box(program.intrinsics.uint32, value);
@@ -75,6 +67,24 @@ function makeBool(program, value)
     return TypedValue.box(program.intrinsics.bool, value);
 }
 
+function makeFloat(program, value)
+{
+    return TypedValue.box(program.intrinsics.float, value);
+}
+
+function makeDouble(program, value)
+{
+    return TypedValue.box(program.intrinsics.double, value);
+}
+
+function checkNumber(program, result, expected)
+{
+    if (!result.type.isNumber)
+        throw new Error("Wrong result type; result: " + result);
+    if (result.value != expected)
+        throw new Error("Wrong result: " + result + " (expected " + expected + ")");
+}
+
 function checkInt(program, result, expected)
 {
     if (!result.type.equals(program.intrinsics.int32))
@@ -98,6 +108,22 @@ function checkBool(program, result, expected)
         throw new Error("Wrong result: " + result.value + " (expected " + expected + ")");
 }
 
+function checkFloat(program, result, expected)
+{
+    if (!result.type.equals(program.intrinsics.float))
+        throw new Error("Wrong result type: " + result.type);
+    if (result.value != expected)
+        throw new Error("Wrong result: " + result.value + " (expected " + expected + ")");
+}
+
+function checkDouble(program, result, expected)
+{
+    if (!result.type.equals(program.intrinsics.double))
+        throw new Error("Wrong result type: " + result.type);
+    if (result.value != expected)
+        throw new Error("Wrong result: " + result.value + " (expected " + expected + ")");
+}
+
 function checkLexerToken(result, expectedIndex, expectedKind, expectedText)
 {
     if (result._index != expectedIndex)
@@ -501,22 +527,32 @@ function TEST_badAdd()
 
 function TEST_lexerKeyword()
 {
-    let result = doLex("ident for while 123 123u { } {asd asd{ 1a3");
-    if (result.length != 13)
-        throw new Error("Lexer emitted an incorrect number of tokens (expected 12): " + result.length);
-    checkLexerToken(result[0],  0,  "identifier", "ident");
-    checkLexerToken(result[1],  6,  "keyword",     "for");
-    checkLexerToken(result[2],  10, "keyword",     "while");
-    checkLexerToken(result[3],  16, "intLiteral",  "123");
-    checkLexerToken(result[4],  20, "uintLiteral", "123u");
-    checkLexerToken(result[5],  25, "punctuation", "{");
-    checkLexerToken(result[6],  27, "punctuation", "}");
-    checkLexerToken(result[7],  29, "punctuation", "{");
-    checkLexerToken(result[8],  30, "identifier",  "asd");
-    checkLexerToken(result[9],  34, "identifier",  "asd");
-    checkLexerToken(result[10], 37, "punctuation", "{");
-    checkLexerToken(result[11], 39, "intLiteral",  "1");
-    checkLexerToken(result[12], 40, "identifier",  "a3");
+    let result = doLex("ident for while 123 123u { } {asd asd{ 1a3 1.2 + 3.4 + 1. + .2 1.2d 0.d .3d");
+    if (result.length != 23)
+        throw new Error("Lexer emitted an incorrect number of tokens (expected 23): " + result.length);
+    checkLexerToken(result[0],  0,  "identifier",    "ident");
+    checkLexerToken(result[1],  6,  "keyword",       "for");
+    checkLexerToken(result[2],  10, "keyword",       "while");
+    checkLexerToken(result[3],  16, "intLiteral",    "123");
+    checkLexerToken(result[4],  20, "uintLiteral",   "123u");
+    checkLexerToken(result[5],  25, "punctuation",   "{");
+    checkLexerToken(result[6],  27, "punctuation",   "}");
+    checkLexerToken(result[7],  29, "punctuation",   "{");
+    checkLexerToken(result[8],  30, "identifier",    "asd");
+    checkLexerToken(result[9],  34, "identifier",    "asd");
+    checkLexerToken(result[10], 37, "punctuation",   "{");
+    checkLexerToken(result[11], 39, "intLiteral",    "1");
+    checkLexerToken(result[12], 40, "identifier",    "a3");
+    checkLexerToken(result[13], 43, "floatLiteral",  "1.2");
+    checkLexerToken(result[14], 47, "punctuation",   "+");
+    checkLexerToken(result[15], 49, "floatLiteral",  "3.4");
+    checkLexerToken(result[16], 53, "punctuation",   "+");
+    checkLexerToken(result[17], 55, "floatLiteral",  "1.");
+    checkLexerToken(result[18], 58, "punctuation",   "+");
+    checkLexerToken(result[19], 60, "floatLiteral",  ".2");
+    checkLexerToken(result[20], 63, "floatLiteral",  "1.2d");
+    checkLexerToken(result[21], 68, "floatLiteral",  "0.d");
+    checkLexerToken(result[22], 72, "floatLiteral",  ".3d");
 }
 
 function TEST_simpleNoReturn()
@@ -2566,6 +2602,194 @@ function TEST_makeArrayRefFromArrayRef()
         (e) => e instanceof WTypeError);
 }
 
+function TEST_floatMath()
+{
+    let program = doPrep(`
+        bool foo()
+        {
+            return 42.5 == 42.5;
+        }
+        bool foo2()
+        {
+            return 42.5f == 42.5;
+        }
+        bool foo3()
+        {
+            return 42.5 == 42.5f;
+        }
+        bool foo4()
+        {
+            return 42.5f == 42.5f;
+        }
+        bool foo5()
+        {
+            return 42.5d == 42.5d;
+        }
+        float bar(float x)
+        {
+            return x;
+        }
+        float foo6()
+        {
+            return bar(7.5);
+        }
+        float foo7()
+        {
+            return bar(7.5f);
+        }
+        float foo8()
+        {
+            return bar(7.5d);
+        }
+        float foo9()
+        {
+            return float(7.5);
+        }
+        float foo10()
+        {
+            return float(7.5f);
+        }
+        float foo11()
+        {
+            return float(7.5d);
+        }
+        float foo12()
+        {
+            return float(7);
+        }
+        float foo13()
+        {
+            double x = 7.5d;
+            return float(x);
+        }
+        double foo14()
+        {
+            double x = 7.5f;
+            return double(x);
+        }
+    `);
+    checkBool(program, callFunction(program, "foo", [], []), true);
+    checkBool(program, callFunction(program, "foo2", [], []), true);
+    checkBool(program, callFunction(program, "foo3", [], []), true);
+    checkBool(program, callFunction(program, "foo4", [], []), true);
+    checkBool(program, callFunction(program, "foo5", [], []), true);
+    checkFloat(program, callFunction(program, "foo6", [], []), 7.5);
+    checkFloat(program, callFunction(program, "foo7", [], []), 7.5);
+    checkFloat(program, callFunction(program, "foo8", [], []), 7.5);
+    checkFloat(program, callFunction(program, "foo9", [], []), 7.5);
+    checkFloat(program, callFunction(program, "foo10", [], []), 7.5);
+    checkFloat(program, callFunction(program, "foo11", [], []), 7.5);
+    checkFloat(program, callFunction(program, "foo12", [], []), 7);
+    checkFloat(program, callFunction(program, "foo13", [], []), 7.5);
+    checkDouble(program, callFunction(program, "foo14", [], []), 7.5);
+    checkFail(
+        () => doPrep(`
+            int bar(int x)
+            {
+                return x;
+            }
+            int foo()
+            {
+                bar(4.);
+            }
+        `),
+        (e) => e instanceof WTypeError);
+    checkFail(
+        () => doPrep(`
+            int bar(int x)
+            {
+                return x;
+            }
+            int foo()
+            {
+                bar(4.d);
+            }
+        `),
+        (e) => e instanceof WTypeError);
+    checkFail(
+        () => doPrep(`
+            int bar(int x)
+            {
+                return x;
+            }
+            int foo()
+            {
+                bar(4.f);
+            }
+        `),
+        (e) => e instanceof WTypeError);
+    checkFail(
+        () => doPrep(`
+            uint bar(uint x)
+            {
+                return x;
+            }
+            int foo()
+            {
+                bar(4.);
+            }
+        `),
+        (e) => e instanceof WTypeError);
+    checkFail(
+        () => doPrep(`
+            uint bar(uint x)
+            {
+                return x;
+            }
+            int foo()
+            {
+                bar(4.d);
+            }
+        `),
+        (e) => e instanceof WTypeError);
+    checkFail(
+        () => doPrep(`
+            uint bar(uint x)
+            {
+                return x;
+            }
+            int foo()
+            {
+                bar(4.f);
+            }
+        `),
+        (e) => e instanceof WTypeError);
+    checkFail(
+        () => doPrep(`
+            float bar(float x)
+            {
+                return x;
+            }
+            void foo()
+            {
+                bar(16777217.d);
+            }
+        `),
+        (e) => e instanceof WTypeError);
+    checkFail(
+        () => doPrep(`
+            float bar(float x)
+            {
+                return x;
+            }
+            float foo()
+            {
+                double x = 7.;
+                return bar(x);
+            }
+        `),
+        (e) => e instanceof WTypeError);
+    checkFail(
+        () => doPrep(`
+            float foo()
+            {
+                double x = 7.;
+                return x;
+            }
+        `),
+        (e) => e instanceof WTypeError);
+}
+
 let filter = /.*/; // run everything by default
 if (this["arguments"]) {
     for (let i = 0; i < arguments.length; i++) {
index 12e1051..0c11f6f 100644 (file)
@@ -31,7 +31,7 @@ class Type extends Node {
     get isArrayRef() { return false; }
     get isNumber() { return false; }
     get isInt() { return false; }
-    get isFloat() { return false; }
+    get isFloating() { return false; }
     
     inherits(protocol)
     {