WebKit Bugzilla
Attachment 348702 Details for
Bug 187738
: [WHLSL] Test suite for Metal code generation
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
WIP
bug-187738-20180831201342.patch (text/plain), 426.37 KB, created by
Thomas Denney
on 2018-08-31 20:13:43 PDT
(
hide
)
Description:
WIP
Filename:
MIME Type:
Creator:
Thomas Denney
Created:
2018-08-31 20:13:43 PDT
Size:
426.37 KB
patch
obsolete
>Subversion Revision: 235579 >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 7d898d414ce68f81a23e3bd2156f75d3e230e938..d7d937187782accb2ad5dc274f6576e53baf053e 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,108 @@ >+2018-08-31 Thomas Denney <tdenney@apple.com> >+ >+ [WHLSL] Test suite for Metal code generation >+ https://bugs.webkit.org/show_bug.cgi?id=187738 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * WebGPUShadingLanguageRI/MakeArrayRefExpression.js: >+ (MakeArrayRefExpression): >+ * WebGPUShadingLanguageRI/Metal/.gitignore: Added. >+ * WebGPUShadingLanguageRI/Metal/ArrayRefDefinition.ts: Copied from Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js. >+ * WebGPUShadingLanguageRI/Metal/CompileResult.ts: Copied from Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js. >+ * WebGPUShadingLanguageRI/Metal/ConstexprEmitter.ts: Copied from Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js. >+ * WebGPUShadingLanguageRI/Metal/Counter.ts: Copied from Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js. >+ * WebGPUShadingLanguageRI/Metal/ForwardDeclarations.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/FunctionLikeBlockCanBeInlined.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/LineNumbers.ts: Copied from Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js. >+ * WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.ts: Copied from Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js. >+ * WebGPUShadingLanguageRI/Metal/MSLFunctionForwardDeclaration.ts: Copied from Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js. >+ * WebGPUShadingLanguageRI/Metal/MSLLexer.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLTypeNamer.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/MetalCodegen.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/NameMangler.ts: Copied from Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js. >+ * WebGPUShadingLanguageRI/Metal/README.md: Added. >+ * WebGPUShadingLanguageRI/Metal/SortTypeDeclarations.ts: Copied from Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js. >+ * WebGPUShadingLanguageRI/Metal/StructDefinition.ts: Copied from Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js. >+ * WebGPUShadingLanguageRI/Metal/Token.ts: Copied from Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js. >+ * WebGPUShadingLanguageRI/Metal/TypeAttributeMap.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/TypeAttributes.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/TypeOf.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/TypeUnifier.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/VarDeclaration.ts: Copied from Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/.gitignore: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/AppIcon.appiconset/Contents.json: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/Contents.json: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Base.lproj/Main.storyboard: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Default.whlsl: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Julia.whlsl: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Mandelbrot.whlsl: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Info.plist: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Metal equivalents/Shaders.metal: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/WHLSL.entitlements: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/_Shared.whlsl: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/main.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL Tests.xcodeproj/project.pbxproj: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/Info.plist: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/WHLSL_ToyTests.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSLLexer.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/index.html: Added. >+ * WebGPUShadingLanguageRI/Metal/metal.css: Added. >+ (textarea, .code-source): >+ (input[type=button]): >+ (.code-source): >+ (td): >+ (body): >+ (h1, h2): >+ (table): >+ (.container-cell): >+ (th, td): >+ (.code-comment): >+ (.code-comment-note): >+ (.code-keyword, .code-type): >+ (.code-literal): >+ (.code-attribute): >+ (.code-whitespace): >+ (.code-error): >+ (.code-directive): >+ (.line-no): >+ (.line-no::before): >+ (.line): >+ * WebGPUShadingLanguageRI/Metal/tsconfig.json: Added. >+ * WebGPUShadingLanguageRI/SynthesizeStructAccessors.js: >+ (synthesizeStructAccessors.setupImplementationData): >+ * WebGPUShadingLanguageRI/Test.js: >+ (makeInt): >+ (makeUint): >+ (makeUchar): >+ (makeBool): >+ > 2018-08-31 Aditya Keerthi <akeerthi@apple.com> > > Unreviewed, add an alternate email for Aditya Keerthi. >diff --git a/Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js b/Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js >index 0cc6f6ecd23bf03f0ae223f192b1a07ad443709e..ab3c0194fadb92a8c3f0d91787107811929df4e7 100644 >--- a/Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js >+++ b/Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js >@@ -29,8 +29,19 @@ class MakeArrayRefExpression extends Expression { > { > super(origin); > this._lValue = lValue; >- if (this.lValue.variable && this.lValue.variable.type && this.lValue.variable.type.isArray && this.lValue.variable.type.elementType) { >- this._type = new ArrayRefType(origin, "thread", this.lValue.variable.type.elementType); >+ let lValueType; >+ if (lValue instanceof DereferenceExpression) >+ lValueType = lValue.type; >+ else if (this.lValue.variable && this.lValue.variable.type) >+ lValueType = this.lValue.variable.type; >+ >+ if (lValueType) { >+ while (lValueType instanceof TypeRef && lValueType.type) >+ lValueType = lValueType.type; >+ if (lValueType.isArray && lValueType.elementType) >+ this._type = new ArrayRefType(origin, "thread", lValueType.elementType); >+ else >+ this._type = new ArrayRefType(origin, "thread", lValueType); > } > } > >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/.gitignore b/Tools/WebGPUShadingLanguageRI/Metal/.gitignore >new file mode 100644 >index 0000000000000000000000000000000000000000..35434ffb59d05621b1d662b7d989a497bf8dd9fa >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/.gitignore >@@ -0,0 +1,2 @@ >+compiler.js >+compiler.js.map >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/ArrayRefDefinition.ts b/Tools/WebGPUShadingLanguageRI/Metal/ArrayRefDefinition.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..acb2cf9edd7e9356d9e221d7ffe10b18cc3abd40 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/ArrayRefDefinition.ts >@@ -0,0 +1,39 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+function metalSourceForArrayRefDefinition(arrayRefType, typeNamer) >+{ >+ let src = `struct ${typeNamer.uniqueTypeId(arrayRefType)} {\n`; >+ const fakePtrType = new PtrType(arrayRefType.origin, arrayRefType.addressSpace, arrayRefType.elementType); >+ src += ` ${metalSourceForVarDeclaration(typeNamer, fakePtrType, "ptr")};\n`; >+ src += " uint32_t length;\n"; >+ src += "};"; >+ return src; >+} >+ >+function metalSourceForArrayRefForwardDeclaration(arrayRefType, typeNamer) >+{ >+ return `struct ${typeNamer.uniqueTypeId(arrayRefType)};`; >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/CompileResult.ts b/Tools/WebGPUShadingLanguageRI/Metal/CompileResult.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..e059ddefef709e5283ad5094f0275bc394722d8a >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/CompileResult.ts >@@ -0,0 +1,65 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class CompileResult { >+ >+ private _metalShaderLanguageSource: string; >+ private _error: Error; >+ private _originalFunctionNameToMangledNames: any; >+ private _functionSources: Map<string, string>; >+ >+ constructor(src: string, err: Error, mangledNameMap: any, functionSources: Map<string, string>) >+ { >+ this._metalShaderLanguageSource = src; >+ this._error = err; >+ this._originalFunctionNameToMangledNames = mangledNameMap; >+ this._functionSources = functionSources; >+ } >+ >+ get metalShaderLanguageSource(): string >+ { >+ return this._metalShaderLanguageSource; >+ } >+ >+ get error(): Error >+ { >+ return this._error; >+ } >+ >+ get originalFunctionNameToMangledNames() >+ { >+ return this._originalFunctionNameToMangledNames; >+ } >+ >+ get functionSources() >+ { >+ return this._functionSources; >+ } >+ >+ get didSucceed() >+ { >+ return !this.error; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/ConstexprEmitter.ts b/Tools/WebGPUShadingLanguageRI/Metal/ConstexprEmitter.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..8ae12f389a09e7ab87ca18039984a7904e5ee664 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/ConstexprEmitter.ts >@@ -0,0 +1,48 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+// Used in scenarios where having an auxiliary variable is not possible (e.g. switch cases). >+class ConstexprEmitter extends Visitor >+{ >+ visitBoolLiteral(node) >+ { >+ return node.value.toString(); >+ } >+ >+ visitEnumLiteral(node) >+ { >+ return node.member.value.toString(); >+ } >+ >+ visitGenericLiteral(node) >+ { >+ return node.value.toString(); >+ } >+ >+ visitNullLiteral(node) >+ { >+ return "(nullptr)"; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/Counter.ts b/Tools/WebGPUShadingLanguageRI/Metal/Counter.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..9ef38cdf412082487991237b7d7ab1b916468e86 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/Counter.ts >@@ -0,0 +1,41 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+// Provides unique names to variables, functions, and types. >+class Counter { >+ private _prefix: string; >+ private _value: number; >+ >+ constructor(prefix: string) >+ { >+ this._prefix = prefix; >+ this._value = 0; >+ } >+ >+ fresh(): string >+ { >+ return `${this._prefix}${this._value++}`; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/ForwardDeclarations.ts b/Tools/WebGPUShadingLanguageRI/Metal/ForwardDeclarations.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..8fc7a2a732b01f061033506ccc5bc8959ae0e619 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/ForwardDeclarations.ts >@@ -0,0 +1,360 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+// To avoid having to convert all of the existing classes in the interpreter to >+// TypeScript we instead just include all of the methods that we need here to >+// avoid type errors with TypeScript. >+ >+declare class Console { >+ log(message: string, ...args: any[]); >+} >+ >+declare const console: Console; >+ >+declare class Visitor { >+ visitAnonymousVariable(node: AnonymousVariable); >+ visitArrayRefType(node: ArrayRefType); >+ visitArrayType(node: ArrayType); >+ visitAssignment(node: Assignment); >+ visitBlock(node: Block); >+ visitBoolLiteral(node: BoolLiteral); >+ visitBreak(node: Break); >+ visitCallExpression(node: CallExpression); >+ visitCommaExpression(node: CommaExpression); >+ visitConstexprTypeParameter(node: ConstexprTypeParameter); >+ visitContinue(node: Continue); >+ visitConvertPtrToArrayRefExpression(node: ConvertPtrToArrayRefExpression); >+ visitDereferenceExpression(node: DereferenceExpression); >+ visitDotExpression(node: DotExpression); >+ visitDoWhileLoop(node: DoWhileLoop); >+ visitElementalType(node: ElementalType); >+ visitEnumLiteral(node: EnumLiteral); >+ visitEnumMember(node: EnumMember); >+ visitEnumType(node: EnumType); >+ visitField(node: Field); >+ visitForLoop(node: ForLoop); >+ visitFunc(node: Func); >+ visitFuncDef(node: FuncDef); >+ visitFuncParameter(node: FuncParameter); >+ visitFunctionLikeBlock(node: FunctionLikeBlock); >+ visitGenericLiteral(node: GenericLiteral); >+ visitGenericLiteralType(node: GenericLiteralType); >+ visitIdentityExpression(node: IdentityExpression); >+ visitIfStatement(node: IfStatement); >+ visitIndexExpression(node: IndexExpression); >+ visitLogicalExpression(node: LogicalExpression); >+ visitLogicalNot(node: LogicalNot); >+ visitMakeArrayRefExpression(node: MakeArrayRefExpression); >+ visitMakePtrExpression(node: MakePtrExpression); >+ visitNativeFunc(node: NativeFunc); >+ visitNativeType(node: NativeType); >+ visitNativeTypeInstance(node: NativeTypeInstance); >+ visitNullLiteral(node: NullLiteral); >+ visitNullType(node: NullType); >+ visitProgram(node: Program); >+ visitProtocolDecl(node: ProtocolDecl); >+ visitProtocolFuncDecl(node: ProtocolFuncDecl); >+ visitProtocolRef(node: ProtocolRef); >+ visitPtrType(node: PtrType); >+ visitReadModifyWriteExpression(node: ReadModifyWriteExpression); >+ visitReferenceType(node: ReferenceType); >+ visitReturn(node: Return); >+ visitStructType(node: StructType); >+ visitSwitchCase(node: SwitchCase); >+ visitSwitchStatement(node: SwitchStatement); >+ visitTrapStatement(node: TrapStatement); >+ visitTypeDef(node: TypeDef); >+ visitTypeRef(node: TypeRef); >+ visitTypeVariable(node: TypeVariable); >+ visitVariableDecl(node: VariableDecl); >+ visitVariableRef(node: VariableRef); >+ visitWhileLoop(node: WhileLoop); >+} >+ >+declare class Rewriter {} >+ >+declare class Lexer { >+ constructor(a, b, c, d); >+ next(): any; >+} >+ >+declare class Assignment extends Node { >+ lhs: Node; >+ rhs: Node; >+} >+ >+declare class AnonymousVariable extends Node {} >+ >+declare class ArrayRefType extends Type { >+ constructor(origin, addressSpace, elementType); >+ >+ addressSpace: string; >+ elementType: Type; >+} >+ >+declare class ArrayType extends Type { >+ constructor(origin, elementType, numElements); >+ >+ elementType: Type; >+ numElements: any; >+ numElementsValue: number; >+} >+ >+declare class Block extends Node { >+ constructor(origin: any); >+ >+ add(node: Node); >+ >+ statements: Node[]; >+} >+ >+declare class BoolLiteral extends Node { >+ constructor(origin, value); >+} >+ >+declare class CallExpression extends Node { >+ constructor(origin, name, argumentList); >+ >+ argumentTypes: any; >+ func: any; >+ possibleOverloads: any; >+ resultType: any; >+ resultEPtr: any; >+ >+ setCastData(any); >+} >+ >+declare class CommaExpression extends Node { >+ list: Node[]; >+} >+ >+declare class DereferenceExpression extends Node { >+ ptr: Node; >+} >+ >+declare class DoWhileLoop extends Node { >+ constructor(origin, body, conditional); >+ >+ body: Node; >+ conditional: Node; >+} >+ >+declare class EnumType extends Type { >+ constructor(origin, name, baseType); >+} >+ >+declare class Field extends Node { >+ constructor(origin, name, type); >+ >+ name: string; >+ type: Type; >+} >+ >+declare class ForLoop extends Node { >+ initialization: Node; >+ condition: Node; >+ increment: Node; >+ body: Node; >+} >+ >+declare class Func extends Node { >+ constructor(origin, name, returnType, typeParameters, parameters, isCast, shaderType); >+ >+ name: string; >+ origin: Origin; >+ parameters: FuncParameter[]; >+ returnType: Type; >+ shaderType: string; >+ isEntryPoint: boolean; >+} >+ >+declare class FunctionLikeBlock extends Node { >+ func: Func; >+} >+ >+declare class FuncDef extends Func { >+ constructor(origin, name, returnType, typeParameters, parameters, body, isCast, shaderType); >+ >+ body: Node; >+} >+ >+declare class FuncInstantiator { >+ instances: any[]; >+} >+ >+declare class FuncParameter extends Value { >+ constructor(origin: Origin, name: string, type: Type); >+ >+ origin: Origin; >+ name: string; >+ type: Type; >+ varIsLValue: boolean; >+} >+ >+declare class IdentityExpression extends Node { >+ target: Node; >+} >+ >+declare class IfStatement { >+ constructor(origin, conditional, body, elseBody); >+ >+ conditional: Node; >+ body: Node; >+ elseBody: Node; >+} >+ >+declare class IndexExpression extends Node { >+ array: Node; >+ index: Node; >+} >+ >+declare class LogicalExpression extends Node { >+ text: string; >+ left: Node; >+ right: Node; >+} >+ >+declare class LogicalNot extends Node { >+ operand: Node; >+} >+ >+declare class MakeArrayRefExpression extends Node { >+ lValue: any; >+ numElements: any; >+} >+ >+declare class MakePtrExpression extends Node { >+ lValue: any; >+} >+ >+declare class Node { >+ static visit(func: any, visitor: Visitor | Rewriter); >+ visit(visitor: Visitor); >+ >+ origin: Origin; >+} >+ >+declare class Origin { >+ index: number; >+} >+ >+declare class Program { >+ topLevelStatements: Node[]; >+ functions: Map<string, Func[]>; >+ types: Type[]; >+ funcInstantiator: FuncInstantiator; >+} >+ >+declare class PtrType extends Type { >+ constructor(origin, addressSpace, elementType); >+ >+ addressSpace: string; >+ elementType: Type; >+} >+ >+declare class StructType extends Type { >+ constructor(origin, name, typeParameters); >+ >+ fieldMap: Map<string, Field>; >+ fields: Field[]; >+ >+ add(field: Field); >+} >+ >+declare class SwitchCase extends Node { >+ isDefault: boolean; >+ value: Node; >+ body: Node; >+} >+ >+declare class SwitchStatement extends Node { >+ switchCases: SwitchCase[]; >+} >+ >+declare class Type extends Node { >+ name: string; >+ isArray: boolean; >+ isPtr: boolean; >+} >+ >+declare class VariableRef extends Node {} >+ >+declare class Value extends Node {} >+ >+declare class WhileLoop extends Node { >+ constructor(origin, condition, body); >+ >+ conditional: Node; >+ body: Node; >+} >+ >+declare function prepare(file: string, lineOffset: number, src: string): Program; >+ >+// TODO >+declare class Break extends Node {} >+declare class ConstexprTypeParameter extends Node {} >+declare class Continue extends Node {} >+declare class ConvertPtrToArrayRefExpression extends Node {} >+declare class DotExpression extends Node {} >+declare class ElementalType extends Node {} >+declare class EnumLiteral extends Node {} >+declare class EnumMember extends Node {} >+declare class GenericLiteral extends Node {} >+declare class GenericLiteralType extends Node {} >+declare class NativeFunc extends Func {} >+declare class NativeType extends Node {} >+declare class NativeTypeInstance extends Node {} >+declare class NullLiteral extends Node {} >+declare class NullType extends Node {} >+declare class ProtocolDecl extends Node {} >+declare class ProtocolFuncDecl extends Node {} >+declare class ProtocolRef extends Node {} >+declare class ReadModifyWriteExpression extends Node {} >+declare class ReferenceType extends Node {} >+declare class Return extends Node {} >+declare class TrapStatement extends Node {} >+declare class TypeDef extends Node {} >+declare class TypeRef extends Node {} >+declare class TypeVariable extends Node {} >+declare class VariableDecl extends Node {} >+ >+declare class BuiltinVectorGetter { >+ baseTypeName: any; >+ size: any; >+ elementName: any; >+ index: any; >+} >+ >+declare class BuiltinVectorSetter { >+ baseTypeName: any; >+ size: any; >+ elementName: any; >+ index: any; >+} >+ >+declare class BuiltinMatrixGetter {}; >+declare class BuiltinMatrixSetter {}; >+declare class MatrixType {}; >+declare class VectorType {}; >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/FunctionLikeBlockCanBeInlined.ts b/Tools/WebGPUShadingLanguageRI/Metal/FunctionLikeBlockCanBeInlined.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..756b5483d9c9c35a5b056243e2eafa76f9dab70e >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/FunctionLikeBlockCanBeInlined.ts >@@ -0,0 +1,386 @@ >+/* >+ * 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. >+ */ >+ >+// Determines whether a function has reducible control flow or potential early returns. >+// This is a conservative estimate (e.g. in the case of loops). >+function functionLikeBlockCanBeInlined(node: FunctionLikeBlock) >+{ >+ enum ReturnStyle { >+ Never, >+ SometimesEarly, >+ Always >+ }; >+ >+ // A loop body might always return, but the loop body is only executed if the loop's condition holds. >+ // We therefore downgrade our certainty for the whole loop. >+ const beConservativeWithAlways = (a: ReturnStyle) => { >+ return a == ReturnStyle.Always ? ReturnStyle.SometimesEarly : a; >+ }; >+ >+ // Used wheere statement a immediately preceeds statement b. >+ const combineReturnStylesForSubsequents = (a: ReturnStyle, b: ReturnStyle) => { >+ if (a == ReturnStyle.Always || a == ReturnStyle.SometimesEarly) >+ return a; >+ return b; >+ }; >+ >+ // Used when statement a is the if branch, statement b is the else branch >+ const combineReturnStylesForAlternatives = (a: ReturnStyle, b: ReturnStyle) => { >+ switch (a) { >+ case ReturnStyle.Never: >+ switch (b) { >+ case ReturnStyle.Never: >+ return ReturnStyle.Never; >+ case ReturnStyle.Always: >+ return ReturnStyle.SometimesEarly; >+ case ReturnStyle.SometimesEarly: >+ return ReturnStyle.SometimesEarly; >+ } >+ case ReturnStyle.SometimesEarly: >+ return ReturnStyle.SometimesEarly; >+ case ReturnStyle.Always: >+ switch (b) { >+ case ReturnStyle.Never: >+ case ReturnStyle.SometimesEarly: >+ return ReturnStyle.SometimesEarly; >+ case ReturnStyle.Always: >+ return ReturnStyle.Always; >+ } >+ } >+ } >+ >+ class ReturnStyleVisitor extends Visitor { >+ private _visitList(list: Node[]) >+ { >+ let style = ReturnStyle.Never; >+ for (let statement of list) { >+ style = combineReturnStylesForSubsequents(style, returnStyleForNodeOrNull(statement)); >+ if (style != ReturnStyle.Never) >+ return style; >+ } >+ return style; >+ } >+ >+ visitAnonymousVariable(node: AnonymousVariable) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitAssignment(node: Assignment) >+ { >+ return this._visitList([ node.lhs, node.rhs ]); >+ } >+ >+ visitBlock(node: Block) >+ { >+ return this._visitList(node.statements); >+ } >+ >+ visitBreak(node: Break) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitCallExpression(node: CallExpression) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitCommaExpression(node: CommaExpression) >+ { >+ return this._visitList(node.list); >+ } >+ >+ visitContinue(node: Continue) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitDereferenceExpression(node: DereferenceExpression) >+ { >+ return returnStyleForNodeOrNull(node.ptr); >+ } >+ >+ visitDotExpression(node: DotExpression) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitDoWhileLoop(node: DoWhileLoop) >+ { >+ return beConservativeWithAlways(this._visitList([ node.body, node.conditional ])); >+ } >+ >+ visitForLoop(node: ForLoop) >+ { >+ return beConservativeWithAlways(this._visitList([ node.initialization, node.condition, node.body, node.increment ])); >+ } >+ >+ visitFuncDef(node: FuncDef) >+ { >+ return returnStyleForNodeOrNull(node.body); >+ } >+ >+ visitFunctionLikeBlock(node: FunctionLikeBlock) >+ { >+ return returnStyleForNodeOrNull(node.func) == ReturnStyle.SometimesEarly ? ReturnStyle.SometimesEarly : ReturnStyle.Never; >+ } >+ >+ visitGenericLiteral(node: GenericLiteral) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitIdentityExpression(node: IdentityExpression) >+ { >+ return returnStyleForNodeOrNull(node.target); >+ } >+ >+ visitIfStatement(node: IfStatement) >+ { >+ const conditional = returnStyleForNodeOrNull(node.conditional); >+ const body = returnStyleForNodeOrNull(node.body); >+ const elseBody = returnStyleForNodeOrNull(node.elseBody); >+ return combineReturnStylesForSubsequents(conditional, combineReturnStylesForAlternatives(body, elseBody)); >+ } >+ >+ visitIndexExpression(node: IndexExpression) >+ { >+ return this._visitList([ node.array, node.index ]); >+ } >+ >+ visitLogicalExpression(node: LogicalExpression) >+ { >+ return this._visitList([ node.left, node.right ]); >+ } >+ >+ visitLogicalNot(node: LogicalNot) >+ { >+ return returnStyleForNodeOrNull(node.operand); >+ } >+ >+ visitMakeArrayRefExpression(node: MakeArrayRefExpression) >+ { >+ return returnStyleForNodeOrNull(node.lValue); >+ } >+ >+ visitMakePtrExpression(node: MakePtrExpression) >+ { >+ return returnStyleForNodeOrNull(node.lValue); >+ } >+ >+ visitNullLiteral(node: NullLiteral) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitReturn(node: Return) >+ { >+ return ReturnStyle.Always; >+ } >+ >+ visitSwitchCase(node: SwitchCase) >+ { >+ return returnStyleForNodeOrNull(node.body); >+ } >+ >+ visitSwitchStatement(node: SwitchStatement) >+ { >+ // return within switch statements is awkward, so we prevent their inlining. >+ // Its fine if the switch is a top level statement of the function and every branch returns, >+ // including a default case, but if that switch is inside a loop or similar we start hitting issues. >+ return beConservativeWithAlways(this._visitList(node.switchCases)); >+ } >+ >+ visitTrapStatement(node: TrapStatement) >+ { >+ return ReturnStyle.Always; >+ } >+ >+ visitVariableDecl(node: VariableDecl) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitVariableRef(node: VariableRef) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitWhileLoop(node: WhileLoop) >+ { >+ return beConservativeWithAlways(this._visitList([ node.conditional, node.body ])); >+ } >+ >+ visitArrayRefType(node: ArrayRefType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitArrayRefType"); >+ } >+ >+ visitArrayType(node: ArrayType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitArrayType"); >+ } >+ >+ visitBoolLiteral(node: BoolLiteral) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitBoolLiteral"); >+ } >+ >+ visitConstexprTypeParameter(node: ConstexprTypeParameter) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitConstexprTypeParameter"); >+ } >+ >+ visitConvertPtrToArrayRefExpression(node: ConvertPtrToArrayRefExpression) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitConvertPtrToArrayRefExpression"); >+ } >+ >+ visitElementalType(node: ElementalType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitElementalType"); >+ } >+ >+ visitEnumLiteral(node: EnumLiteral) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitEnumLiteral"); >+ } >+ >+ visitEnumMember(node: EnumMember) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitEnumMember"); >+ } >+ >+ visitEnumType(node: EnumType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitEnumType"); >+ } >+ >+ visitField(node: Field) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitField"); >+ } >+ >+ visitFunc(node: Func) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitFunc"); >+ } >+ >+ visitFuncParameter(node: FuncParameter) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitFuncParameter"); >+ } >+ >+ visitGenericLiteralType(node: GenericLiteralType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitGenericLiteralType"); >+ } >+ >+ visitNativeFunc(node: NativeFunc) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitNativeFunc"); >+ } >+ >+ visitNativeType(node: NativeType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitNativeType"); >+ } >+ >+ visitNativeTypeInstance(node: NativeTypeInstance) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitNativeTypeInstance"); >+ } >+ >+ visitNullType(node: NullType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitNullType"); >+ } >+ >+ visitProgram(node: Program) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitProgram"); >+ } >+ >+ visitProtocolDecl(node: ProtocolDecl) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitProtocolDecl"); >+ } >+ >+ visitProtocolFuncDecl(node: ProtocolFuncDecl) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitProtocolFuncDecl"); >+ } >+ >+ visitProtocolRef(node: ProtocolRef) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitProtocolRef"); >+ } >+ >+ visitPtrType(node: PtrType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitPtrType"); >+ } >+ >+ visitReadModifyWriteExpression(node: ReadModifyWriteExpression) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitReadModifyWriteExpression"); >+ } >+ >+ visitReferenceType(node: ReferenceType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitReferenceType"); >+ } >+ >+ visitStructType(node: StructType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitStructType"); >+ } >+ >+ visitTypeDef(node: TypeDef) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitTypeDef"); >+ } >+ >+ visitTypeRef(node: TypeRef) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitTypeRef"); >+ } >+ >+ visitTypeVariable(node: TypeVariable) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitTypeVariable"); >+ } >+ } >+ >+ const returnStyleVisitor = new ReturnStyleVisitor(); >+ >+ function returnStyleForNodeOrNull(node: Node) >+ { >+ return node ? Node.visit(node, returnStyleVisitor) : ReturnStyle.Never; >+ } >+ >+ return returnStyleForNodeOrNull(node) != ReturnStyle.SometimesEarly; >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/LineNumbers.ts b/Tools/WebGPUShadingLanguageRI/Metal/LineNumbers.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..9c7c988439ef401c226839f1053c03e1f6779191 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/LineNumbers.ts >@@ -0,0 +1,38 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+// This must be called on the original WHLSL source before MSL compilation >+// to allow translation from character indices to line numbers. >+function lineNumbers(src: string): number[] >+{ >+ const lineNumbers = []; >+ let lineNumber = 1; >+ for (let i = 0; i < src.length; i++) { >+ lineNumbers.push(lineNumber); >+ if (src[i] == '\n') >+ lineNumber++; >+ } >+ return lineNumbers; >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.ts b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..2071165e1519021376da2c9117cd439e922100c2 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.ts >@@ -0,0 +1,135 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+// Emits code for for the first line of a function declaration or definition. >+class MSLFunctionDeclaration { >+ private _funcMangler: NameMangler; >+ private _func: FuncDef; >+ private _typeNamer: MSLTypeNamer; >+ private _lineNumbers: number[]; >+ private _typeAttributes: TypeAttributesMap; >+ >+ constructor(funcMangler, funcDef, typeNamer, lineNos, typeAttributes) >+ { >+ this._funcMangler = funcMangler; >+ this._func = funcDef; >+ this._typeNamer = typeNamer; >+ this._lineNumbers = lineNos; >+ this._typeAttributes = typeAttributes; >+ } >+ >+ get funcMangler(): NameMangler >+ { >+ return this._funcMangler; >+ } >+ >+ get func(): FuncDef >+ { >+ return this._func; >+ } >+ >+ get typeNamer(): MSLTypeNamer >+ { >+ return this._typeNamer; >+ } >+ >+ get lineNumbers(): number[] >+ { >+ return this._lineNumbers; >+ } >+ >+ get typeAttributes(): TypeAttributesMap >+ { >+ return this._typeAttributes; >+ } >+ >+ get isVertexShader() >+ { >+ return this._func.shaderType == "vertex"; >+ } >+ >+ get paramMap() >+ { >+ const map = new Map(); >+ let counter = 0; >+ for (let param of this._func.parameters) >+ map.set(param.name, `P${counter++}`); >+ return map; >+ } >+ >+ commentLine() >+ { >+ const params = []; >+ for (let paramName of this.paramMap.keys()) >+ params.push(paramName); >+ let line = `// ${this._func.name}(${params.join(", ")})`; >+ if (this._lineNumbers && this._func.origin.index && this._lineNumbers[this._func.origin.index]) >+ line += ` @ line ${this._lineNumbers[this._func.origin.index]}`; >+ return line + "\n"; >+ } >+ >+ toString() >+ { >+ let declLine = this.commentLine(); >+ >+ // TODO: Support shader types other than fragment and vertex. >+ // What WSL calls `compute` shaders Metal calls `kernel` shaders. >+ // We're only focussing on `vertex` and `fragment` for now. >+ if (this._func.shaderType === "vertex" || this._func.shaderType === "fragment") >+ declLine += `${this._func.shaderType} `; >+ declLine += `${this._typeNamer.mslTypeName(this._func.returnType)} `; >+ declLine += this._funcMangler.mangle(this.func); >+ declLine += "(" >+ >+ let params = []; >+ const paramMap = this.paramMap; >+ for (let param of this._func.parameters) { >+ let pStr = `${this._typeNamer.mslTypeName(param.type)} ${paramMap.get(param.name)}`; >+ // FIXME: The parser doesn't currently support vertex shaders having uint parameters, so this doesn't work. >+ if (this.parameterIsVertexId(param) && this.isVertexShader) >+ pStr += " [[vertex_id]]"; >+ else if (this.parameterIsAttribute(param)) >+ pStr += " [[stage_in]]"; >+ params.push(pStr); >+ } >+ >+ declLine += params.join(", ") + ")"; >+ >+ return declLine; >+ } >+ >+ parameterIsAttribute(node) >+ { >+ // We currently assuming that all parameters to entry points are attributes. >+ // TODO: Better logic for this, i.e. support samplers. >+ return this._func.isEntryPoint; >+ } >+ >+ parameterIsVertexId(node) >+ { >+ // FIXME: This isn't final, and isn't formally specified yet. >+ return this.isVertexShader && node.name == "wsl_vertexID" && node.type.name == "uint32"; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.ts b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..d77b5d8839e50ce60e980a5979c45ff8a392d0f0 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.ts >@@ -0,0 +1,37 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class MSLFunctionDefinition extends MSLFunctionDeclaration >+{ >+ toString() >+ { >+ let src = super.toString(); >+ src += "\n{\n"; >+ let emitter = new MSLStatementEmitter(this.funcMangler, this.typeNamer, this.func, this.paramMap, this.func.name, this.lineNumbers, this.typeAttributes); >+ src += emitter.indentedSource(); >+ src += "}"; >+ return src; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionForwardDeclaration.ts b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionForwardDeclaration.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..57c6f81353c1f381f967345f8987f3cfb91da518 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionForwardDeclaration.ts >@@ -0,0 +1,32 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class MSLFunctionForwardDeclaration extends MSLFunctionDeclaration >+{ >+ toString() >+ { >+ return super.toString() + ";" >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLLexer.ts b/Tools/WebGPUShadingLanguageRI/Metal/MSLLexer.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..21cad324f809dd4211cecb6495b7818cb084ebfe >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLLexer.ts >@@ -0,0 +1,125 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+// Does sufficient lexing for the output of the compiler, not for MSL in general! >+class MSLLexer { >+ private _tokens: Token[]; >+ >+ constructor(src) >+ { >+ this._tokens = this._lex(src); >+ } >+ >+ get tokens(): Token[] >+ { >+ return this._tokens; >+ } >+ >+ private get commentMatchers() >+ { >+ return [ >+ { type: "comment", regex: /^(\/\/|\/\*)(\s+)?/ }, >+ { type: "comment-note", regex: /^(TODO:|FIXME:)/ }, >+ { type: "comment", regex: /.*(\n|$)/ } >+ ] >+ } >+ >+ private get defaultMatchers() >+ { >+ return [ >+ { type: "comment", regex: /^\/\/(.*?)(\n|$)/, inner: this.commentMatchers }, >+ { type: "directive", regex: /^#(.*?)(\n|$)/ }, >+ { type: "whitespace", regex: /^\s+/ }, >+ { type: "literal", regex: /^([0-9]+)(\.([0-9]*?))?/ }, >+ { type: "type", regex: /^(struct|vertex|fragment|constant|const|threadgroup|thread|device|size_t|uint8_t|uint16_t|uint32_t|int8_t|int16_t|int32_t|((bool|half|float)(2|3|4)x(2|3|4))|((bool|uchar|char|ushort|short|uint|int|half|float)(2|3|4))|float|half|bool)/ }, >+ { type: "keyword", regex: /^(return|if|else|do|while|switch|case|default|break|continue|nullptr|true|false|using|namespace)/ }, >+ { type: "attribute", regex: /^\[\[([A-z][A-z_\(\)0-9]+)\]\]/, inner: [ >+ { type: "attribute", regex: /^\[\[[A-z]+\(/ }, >+ { type: "literal", regex: /^[0-9]+/ }, >+ { type: "attribute", regex: /^\)\]\]/ }, >+ { type: "attribute", regex: /^\[\[([A-z][A-z_\(\)0-9]+)\]\]/ } >+ ] }, >+ { type: "error", regex: /^undefined/ }, >+ { type: "identifier", regex: /^[A-z]([A-z0-9_]*)?/ }, >+ { type: "punctuation", regex: /^(;|\.|\(|\)|,|\+|\-|=|->|>|<|\!|\}|\{|\*|\?|\:|\[|\])/}, >+ { type: "unknown", regex: /^(.*?)(\n|$)/ } >+ ]; >+ } >+ >+ private _lex(src, initMatchers = null): Token[] >+ { >+ const tokens: Token[] = []; >+ const matchers = initMatchers ? initMatchers : this.defaultMatchers; >+ >+ const startOfMultilineComment = /^\/\*/; >+ const endOfMultilineComment = /\*\//; >+ >+ const originalLength = src.length; >+ >+ while (src.length) { >+ // Special case for multiline comments. >+ const startMatch = startOfMultilineComment.exec(src); >+ if (startMatch) { >+ const endMatch = endOfMultilineComment.exec(src); >+ if (endMatch) { >+ // Important to ignore the first two characters to avoid recursion. >+ tokens.push(new Token("comment", startMatch[0], originalLength - src.length)); >+ const commentText = src.substring(2, endMatch.index + 2); >+ for (let innerTok of this._lex(commentText, this.commentMatchers)) >+ tokens.push(innerTok); >+ src = src.substring(endMatch.index + 2); >+ } else >+ throw new Error("Unmatched multiline comment"); >+ } >+ >+ let didMatch = false; >+ for (let matcher of matchers) { >+ const match = matcher.regex.exec(src); >+ if (match) { >+ if (matcher.inner) { >+ let innerToks = this._lex(match[0], matcher.inner); >+ for (let innerTok of innerToks) { >+ innerTok.startIndex += originalLength - src.length; >+ tokens.push(innerTok); >+ } >+ } else >+ tokens.push(new Token(matcher.type, match[0], originalLength - src.length)); >+ src = src.substring(match[0].length); >+ didMatch = true; >+ break; >+ } >+ } >+ if (!didMatch) >+ throw new Error(`Nothing matched ${src}`); >+ } >+ >+ return tokens; >+ } >+} >+ >+function lexMsl(msl: string): Token[] >+{ >+ return new MSLLexer(msl).tokens; >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.ts b/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..619ea710a5dd529320d8c4619bb112addcf6eb2a >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.ts >@@ -0,0 +1,978 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class MSLStatementEmitter extends Visitor { >+ private _funcMangler: NameMangler; >+ private _typeNamer: MSLTypeNamer; >+ private _func: Func; >+ private _nameMap: Map<string, string>; >+ private _nameMapStack: Array<Map<string, string>>; >+ private _debugName: string; >+ private _lineNumbers: number[]; >+ private _typeAttributes: TypeAttributesMap; >+ private _resultVar: string; >+ private _counter : Counter; >+ private _indentLevel: number; >+ private _lines: string[]; >+ private _ancestorReturnType : Type; >+ private _actualResult: string; >+ private _loopConditionVariableStack: string[] = []; >+ private _loopConditionNodeStack: Node[] = []; >+ private _loopIncrementNodeStack: Node[] = []; >+ >+ constructor(funcMangler: NameMangler, typeNamer: MSLTypeNamer, func: Func, paramMap: Map<string, string>, debugName: string, lineNos: number[], typeAttributes: TypeAttributesMap, resultVar: string = null, counter: Counter = null, ancestorReturnType: Type = null) >+ { >+ super(); >+ this._funcMangler = funcMangler; >+ this._typeNamer = typeNamer; >+ this._func = func; >+ this._nameMap = paramMap; >+ this._nameMapStack = []; >+ this._debugName = debugName; >+ this._lineNumbers = lineNos; >+ this._typeAttributes = typeAttributes; >+ this._resultVar = resultVar; >+ this._counter = counter ? counter : new Counter("V"); >+ this._indentLevel = 0; >+ this._lines = []; >+ this._ancestorReturnType = ancestorReturnType ? ancestorReturnType : func.returnType; >+ >+ this._actualResult = Node.visit(this._func, this); >+ } >+ >+ get ancestorReturnType() >+ { >+ return this._ancestorReturnType; >+ } >+ >+ private _emitReturnZeroValue() >+ { >+ if (this.ancestorReturnType.name === "void") >+ this._add(`return;`); >+ else { >+ const resultVar = this._fresh(); >+ this._add(metalSourceForVarDeclaration(this._typeNamer, this.ancestorReturnType, resultVar) + ";"); >+ this._zeroInitialize(this.ancestorReturnType, resultVar); >+ this._add(`return ${resultVar};`); >+ } >+ } >+ >+ private _zeroInitialize(type, variableName, allowComment = true) >+ { >+ const emitter = this; >+ >+ class ZeroInitializer extends Visitor { >+ visitNativeType(node) >+ { >+ if (node.name == "bool") >+ emitter._add(`${variableName} = false;`); >+ else >+ emitter._add(`${variableName} = 0;`); >+ } >+ >+ visitPtrType(node) >+ { >+ emitter._add(`${variableName} = nullptr;`); >+ } >+ >+ visitArrayType(node) >+ { >+ for (let i = 0; i < node.numElements.value; i++) >+ emitter._zeroInitialize(node.elementType, `${variableName}[${i}]`, false); >+ } >+ >+ visitArrayRefType(node) >+ { >+ emitter._add(`${variableName}.ptr = nullptr;`); >+ emitter._add(`${variableName}.length = 0;`); >+ } >+ >+ visitEnumType(node) >+ { >+ emitter._zeroInitialize(node.baseType, variableName, false); >+ } >+ >+ visitStructType(node) >+ { >+ const typeAttributes = emitter._typeAttributes.attributesForType(node); >+ >+ for (let field of node.fields) { >+ const fieldName = typeAttributes.mangledFieldName(field.name); >+ emitter._zeroInitialize(field.type, `${variableName}.${fieldName}`, false); >+ } >+ } >+ >+ visitVectorType(node) >+ { >+ const elementNames = [ "x", "y", "z", "w" ]; >+ for (let i = 0; i < node.numElementsValue; i++) >+ emitter._add(`${variableName}.${elementNames[i]} = 0;`); >+ } >+ >+ visitMatrixType(node) >+ { >+ for (let i = 0; i < node.numRowsValue; i++) { >+ for (let j = 0; j < node.numRowsValue; j++) { >+ emitter._zeroInitialize(node.elementType, `${variableName}[${i}][${j}]`, false); >+ } >+ } >+ } >+ >+ visitTypeRef(node) >+ { >+ node.type.visit(this); >+ } >+ } >+ if (allowComment) >+ this._add(`// Zero initialization of ${variableName}`); >+ Node.visit(type, new ZeroInitializer()); >+ } >+ >+ get actualResult() >+ { >+ return this._actualResult; >+ } >+ >+ get lines() >+ { >+ return this._lines; >+ } >+ >+ indentedSource() >+ { >+ return this._lines.map(line => " " + line + "\n").join(""); >+ } >+ >+ private get _loopConditionVariable(): string >+ { >+ return this._loopConditionVariableStack[this._loopConditionVariableStack.length - 1]; >+ } >+ >+ private get _loopCondition(): Node >+ { >+ return this._loopConditionNodeStack[this._loopConditionNodeStack.length - 1]; >+ } >+ >+ private get _loopIncrement(): Node >+ { >+ return this._loopIncrementNodeStack[this._loopIncrementNodeStack.length - 1]; >+ } >+ >+ private _add(linesString) >+ { >+ for (let line of linesString.split('\n')) { >+ for (let i = 0; i < this._indentLevel; i++) >+ line = " " + line; >+ this._lines.push(line); >+ } >+ } >+ >+ private _addLines(lines) >+ { >+ for (let line of lines) >+ this._add(line); >+ } >+ >+ private _fresh() >+ { >+ return this._counter.fresh(); >+ } >+ >+ private _indent() >+ { >+ this._indentLevel++; >+ } >+ >+ private _unindent() >+ { >+ this._indentLevel--; >+ } >+ >+ // Atomic statements. >+ >+ visitBreak(node) >+ { >+ this._add("break;") >+ } >+ >+ visitContinue(node) >+ { >+ // This is necessary because for loops are compiled as while loops, so we need to do >+ // the loop increment and condition check before returning to the beginning of the loop. >+ this._emitLoopBodyEnd(); >+ this._add("continue;"); >+ } >+ >+ // Basic compound statements. >+ >+ visitBlock(block) >+ { >+ this._nameMapStack.push(this._nameMap); >+ this._nameMap = new Map(this._nameMap); >+ for (let stmt of block.statements) { >+ if (stmt.origin && stmt.origin.index && this._lineNumbers && this._lineNumbers[stmt.origin.index]) >+ this._add(`// ${this._debugName} @ line ${this._lineNumbers[stmt.origin.index]}`); >+ Node.visit(stmt, this); >+ } >+ this._nameMap = this._nameMapStack.pop(); >+ } >+ >+ visitReturn(node) >+ { >+ let expr = node.value.visit(this); >+ if (this._resultVar) >+ this._add(`${this._resultVar} = ${expr};`); >+ else >+ this._add(`return ${expr};`); >+ } >+ >+ private _inScope(emitBraces = false, emitBlock: () => any) >+ { >+ if (emitBraces) >+ this._add("{"); >+ this._indent(); >+ >+ this._nameMapStack.push(this._nameMap); >+ this._nameMap = new Map(this._nameMap); >+ >+ const res = emitBlock(); >+ >+ this._nameMap = this._nameMapStack.pop(); >+ if (emitBraces) >+ this._add("}"); >+ >+ this._unindent(); >+ >+ return res; >+ } >+ >+ private _emitScoped(node: Node, emitBraces = false) >+ { >+ if (!node) >+ throw new Error(`Can't emit scoped null node`); >+ >+ return this._inScope(emitBraces, () => Node.visit(node, this)); >+ } >+ >+ visitIfStatement(node) >+ { >+ let condition = node.conditional.visit(this); >+ this._add(`if (${condition}) {`); >+ this._emitScoped(node.body); >+ // At the moment the parser emits Block nodes for the if and else bodies, so this allows us >+ // to check whether or not the else body is actually empty, and therefore doesn't need to be emitted. >+ // (This isn't necessary, it just yields shorter, easier to read output). >+ const shouldEmitElseBody = node.elseBody && (!(node.elseBody instanceof Block) || node.elseBody.statements.length); >+ if (shouldEmitElseBody) { >+ this._add(`} else {`); >+ this._emitScoped(node.elseBody); >+ this._add('}'); >+ } else >+ this._add('}'); >+ } >+ >+ visitIdentityExpression(node) >+ { >+ return node.target.visit(this); >+ } >+ >+ visitLogicalNot(node) >+ { >+ const type = typeOf(node); >+ if (type) { >+ let expr = Node.visit(node.operand, this); >+ let id = this._fresh(); >+ this._add(metalSourceForVarDeclaration(this._typeNamer, type, id) + ";"); >+ this._add(`${id} = !(${expr});`); >+ return id; >+ } else >+ throw new Error(`Couldn't determine type of ! expression ${node}'`); >+ } >+ >+ visitDereferenceExpression(node) >+ { >+ // An assignment such as someStruct.field = someValue is parsed as >+ // *((&someStruct)->value) = someValue >+ if (this._canAvoidDereferenceBecauseDereferencingReferenceNode(node.ptr)) >+ return this._doNotProduceReferenceFromReferenceNode(node.ptr); >+ else >+ return `(*(${node.ptr.visit(this)}))`; >+ } >+ >+ private _canAvoidDereferenceBecauseDereferencingReferenceNode(node) >+ { >+ const emitter = this; >+ >+ class PossibleRefVisitor extends Visitor { >+ visitMakePtrExpression(node) { return true; } >+ >+ visitCallExpression(node) >+ { >+ return emitter._isOperatorAnder(node.func) || emitter._isOperatorIndexer(node.func); >+ } >+ } >+ >+ // To avoid returning undefined/issues with functions not being defined. >+ return Node.visit(node, new PossibleRefVisitor()) ? true : false; >+ } >+ >+ private _isOperatorAnder(node) >+ { >+ const anderRegex = /^operator\&\.(.*?)$/; >+ return node instanceof NativeFunc && anderRegex.test(node.name); >+ } >+ >+ private _isOperatorGetter(node) >+ { >+ const getterRegex = /^operator\.(.*?)$/; >+ return node instanceof NativeFunc && getterRegex.test(node.name); >+ } >+ >+ private _isOperatorIndexer(node) >+ { >+ return node instanceof NativeFunc && node.name == "operator&[]"; >+ } >+ >+ private _isOperatorSetter(node) >+ { >+ const setterRegex = /^operator\.(.*?)=$/; >+ return node instanceof NativeFunc && setterRegex.test(node.name) >+ } >+ >+ private _isOperatorCast(node: Func) >+ { >+ return node instanceof NativeFunc && node.name == "operator cast"; >+ } >+ >+ private _isUnaryOperator(node) >+ { >+ const operatorRegex = /^operator\~$/; >+ return node instanceof NativeFunc && operatorRegex.test(node.name); >+ } >+ >+ private _isBinaryOperator(node) >+ { >+ const operatorRegex = /operator(\+|\-|\*|\/|\^|\&|\||\&\&|\|\||\<\<|\>\>|\<|\<\=|\>|\>\=|\=\=|\!\=)$/; >+ return node instanceof NativeFunc && operatorRegex.test(node.name); >+ } >+ >+ private _isOperatorValue(node) >+ { >+ return node instanceof NativeFunc && node.name == "operator.value"; >+ } >+ >+ private _isOperatorLength(node) >+ { >+ return node instanceof NativeFunc && node.name == "operator.length"; >+ } >+ >+ private _extractOperatorName(node) >+ { >+ return node.name.substring("operator".length); >+ } >+ >+ private _doNotProduceReferenceFromReferenceNode(node) >+ { >+ const emitter = this; >+ >+ class DefiniteRefVisitor extends Visitor { >+ >+ visitMakePtrExpression(node) >+ { >+ return Node.visit(node.lValue, emitter); >+ } >+ >+ visitCallExpression(node) >+ { >+ const anderRegex = /^operator\&\.(.*?)$/; >+ if (anderRegex.test(node.func.name)) >+ return emitter._handleFieldAccess(node.func.implementationData, node.argumentList[0]); >+ else if (node.func.name === "operator&[]") >+ return emitter._handleIndexAccess(node); >+ } >+ } >+ >+ return Node.visit(node, new DefiniteRefVisitor()); >+ } >+ >+ visitVariableDecl(node) >+ { >+ let id = this._fresh(); >+ this._nameMap.set(node.name, id); >+ >+ this._add(`${metalSourceForVarDeclaration(this._typeNamer, node.type, id)}; // ${node.name}`); >+ >+ if (node.initializer) { >+ let expr = node.initializer.visit(this); >+ this._add(`${id} = ${expr};`); >+ } else >+ this._zeroInitialize(node.type, id); >+ } >+ >+ visitVariableRef(node) >+ { >+ if (node.variable instanceof AnonymousVariable) >+ return Node.visit(node.variable, this); >+ let name = node.name; >+ if (!this._nameMap.has(name)) >+ throw new Error(`${node.name} not found in this function's variable map`); >+ return this._nameMap.get(name); >+ } >+ >+ visitMakeArrayRefExpression(node) >+ { >+ const elemName = Node.visit(node.lValue, this); >+ const arrayType = <ArrayRefType>typeOf(node.lValue); >+ const id = this._fresh(); >+ this._add(metalSourceForVarDeclaration(this._typeNamer, node.type, id) + ";"); >+ this._add(`${id}.length = ${node.numElements.value};`); >+ if (arrayType.isArray) >+ this._add(`${id}.ptr = ${elemName};`); >+ else >+ this._add(`${id}.ptr = &(${elemName});`); >+ return id; >+ } >+ >+ visitConvertPtrToArrayRefExpression(node) >+ { >+ const lValue = node.lValue.visit(this); >+ const type = typeOf(node); >+ const id = this._fresh(); >+ this._add(metalSourceForVarDeclaration(this._typeNamer, type, id) + ";"); >+ this._add(`${id}.length = 1;`); >+ this._add(`${id}.ptr = ${lValue};`); >+ return id; >+ } >+ >+ visitAnonymousVariable(node) >+ { >+ // Anonymous variable names are of the form anonVar<i> (where i is an integer), i.e. >+ // the set of anonymous variable names is disjoint from the set of definable variable names. >+ if (!this._nameMap.has(node.name)) { >+ let id = this._fresh(); >+ this._nameMap.set(node.name, id); >+ this._add(metalSourceForVarDeclaration(this._typeNamer, node.type, id) + `; // ${node.name}`); >+ this._zeroInitialize(node.type, id); >+ return id; >+ } else >+ return this._nameMap.get(node.name); >+ } >+ >+ visitAssignment(node) >+ { >+ const lhs = Node.visit(node.lhs, this); >+ const rhs = Node.visit(node.rhs, this); >+ this._add(`${lhs} = ${rhs};`); >+ return rhs; >+ } >+ >+ visitCommaExpression(node: CommaExpression) >+ { >+ let result; >+ for (let expr of node.list) >+ result = Node.visit(expr, this); >+ return result; >+ } >+ >+ visitCallExpression(node) >+ { >+ // Evaluate the arguments right-to-left. >+ let argIds = []; >+ for (let i = node.argumentList.length - 1; i >= 0; i--) { >+ let id = node.argumentList[i].visit(this); >+ argIds.unshift(id); >+ } >+ let result = this._fresh(); >+ if (node.func.returnType.name !== "void") { >+ this._add(`// Result variable for call ${node.func.name}(${argIds.join(", ")})`); >+ this._add(`${metalSourceForVarDeclaration(this._typeNamer, node.resultType, result)};`); >+ } >+ this._makeFunctionCall(node.func, result, argIds); >+ >+ return result; >+ } >+ >+ private _makeFunctionCall(node, result, args) >+ { >+ if (!node) >+ throw new Error(`Can't compile call ${node} of non-native functions'`); >+ >+ if (this._isOperatorAnder(node)) >+ this._emitOperatorAnder(node, result, args); >+ else if (node.implementationData instanceof BuiltinVectorGetter) >+ this._emitBuiltinVectorGetter(node, result, args); >+ else if (node.implementationData instanceof BuiltinVectorSetter) >+ this._emitBuiltinVectorSetter(node, result, args); >+ else if (node.implementationData instanceof BuiltinMatrixGetter) >+ this._emitBuiltinMatrixGetter(node, result, args); >+ else if (node.implementationData instanceof BuiltinMatrixSetter) >+ this._emitBuiltinMatrixSetter(node, result, args); >+ else if (this._isOperatorValue(node)) >+ this._add(`${result} = ${args[0]};`); >+ else if (this._isOperatorLength(node)) >+ this._emitOperatorLength(node, result, args); >+ else if (this._isOperatorSetter(node)) >+ this._add(`// TODO: (Native function) ${node.name}`); >+ else if (this._isOperatorGetter(node)) >+ this._emitOperatorGetter(node, result, args); >+ else if (this._isOperatorIndexer(node)) >+ this._emitOperatorIndexer(node, result, args); >+ else if (this._isOperatorCast(node)) { >+ this._emitOperatorCast(node, result, args); >+ } else if (this._isUnaryOperator(node)) { >+ const op = this._extractOperatorName(node); >+ this._add(`${result} = ${op}(${args[0]});`); >+ } else if (this._isBinaryOperator(node)) { >+ const op = this._extractOperatorName(node); >+ this._add(`${result} = ${args[0]} ${op} ${args[1]};`); >+ } else if (node.name == "log" || node.name == "pow" || node.name == "sin" || node.name == "cos" || node.name == "atan2") >+ this._emitCallToMetalFunction(node.name, result, args); >+ else >+ throw new Error(`Unimplemented native function '${node.name}' at MSLStatementEmitter.makeFunctionCall`); >+ >+ return result; >+ } >+ >+ private _emitCallToMetalFunction(name, result, args) >+ { >+ this._add(`${result} = ${name}(${args.join(", ")});`); >+ } >+ >+ private _emitBuiltinVectorGetter(node, result, args) >+ { >+ this._add(`${result} = ${args[0]}.${node.implementationData.elementName};`); >+ } >+ >+ private _emitBuiltinVectorSetter(node, result, args) >+ { >+ this._add(`${result} = ${args[0]};`); >+ this._add(`${result}.${node.implementationData.elementName} = ${args[1]};`); >+ } >+ >+ private _emitBuiltinMatrixGetter(node, result, args) >+ { >+ this._add(`if (${args[1]} < 0 || ${args[1]} >= ${node.implementationData.height}) {`); >+ this._indent(); >+ this._emitReturnZeroValue(); >+ this._unindent(); >+ this._add('}'); >+ this._add(`${result} = ${args[0]}[${args[1]}];`); >+ } >+ >+ private _emitBuiltinMatrixSetter(node, result, args) >+ { >+ this._add(`if (${args[1]} < 0 || ${args[1]} >= ${node.implementationData.height}) {`); >+ this._indent(); >+ this._emitReturnZeroValue(); >+ this._unindent(); >+ this._add('}'); >+ this._add(`${result} = ${args[0]};`); >+ this._add(`${result}[${args[1]}] = ${args[2]};`); >+ } >+ >+ private _emitOperatorLength(node, result, args) >+ { >+ const paramType = typeOf(node.parameters[0]); >+ if (paramType instanceof ArrayRefType) >+ this._add(`${result} = ${args[0]}.length;`); >+ else if (paramType instanceof ArrayType) >+ this._add(`${result} = ${paramType.numElements.visit(this)};`); >+ else >+ throw new Error(`Unhandled paramter type ${paramType} for operator.length`); >+ } >+ >+ private _emitOperatorCast(node, result, args) >+ { >+ const retType = this._typeNamer.mslTypeName(node.returnType); >+ this._add(`${result} = ${retType}(${args.join(", ")});`); >+ } >+ >+ private _emitOperatorIndexer(node, result, args) >+ { >+ if (!(typeOf(node.parameters[0]) instanceof ArrayRefType)) >+ throw new Error(`Support for operator&[] ${node.parameters[0]} not implemented.`); >+ >+ this._add(`if (${args[1]} >= ${args[0]}.length) {`); >+ this._indent(); >+ this._emitReturnZeroValue(); >+ this._unindent(); >+ this._add(`}`); >+ this._add(`${result} = (${this._typeNamer.mslTypeName(node.returnType)})&(${args[0]}.ptr[${args[1]}]);`); >+ } >+ >+ private _handleFieldAccess(implementationData, arg) >+ { >+ const type = implementationData.type; >+ const field = this._typeAttributes.attributesForType(type).mangledFieldName(implementationData.name); >+ >+ if (arg instanceof MakePtrExpression) { >+ const argId = Node.visit(arg.lValue, this); >+ if (arg.lValue && arg.lValue instanceof VariableRef) >+ return `${argId}.${field}`; >+ else >+ return `(${argId}).${field}`; >+ } else >+ return `${arg.visit(this)}->${field}`; >+ } >+ >+ private _emitOperatorAnder(node, result, args) >+ { >+ const type = node.implementationData.type; >+ const field = this._typeAttributes.attributesForType(type).mangledFieldName(node.implementationData.name); >+ this._add(`${result} = (${this._typeNamer.mslTypeName(node.returnType)})&((${args[0]})->${field});`); >+ } >+ >+ private _emitOperatorGetter(node, result, args) >+ { >+ const type = node.implementationData.type; >+ const field = this._typeAttributes.attributesForType(type).mangledFieldName(node.implementationData.name); >+ this._add(`${result} = ${args[0]}.${field};`); >+ } >+ >+ private _handleIndexAccess(node) >+ { >+ const array = node.argumentList[0]; >+ const index = node.argumentList[1]; >+ >+ // FIXME: Avoid so much special casing. >+ >+ if (array instanceof MakeArrayRefExpression) { >+ if (index.isLiteral) { >+ // Type checking will hopefully have already ensured this... >+ if (index.value >= 0 && index.value < array.numElements.value) { >+ const variable = Node.visit(array.lValue, this); >+ return `${variable}[${index.value}]`; >+ } else >+ throw new Error(`Index out of bounds in ${node}`); >+ } else { >+ // TODO: It would be interesting to see what kind of BCE could be done here. >+ // Index checks aren't necessary for values < 0 because the type checker will >+ // have already ensured that the index value type is an unsigned integer. >+ const variable = Node.visit(array.lValue, this); >+ const indexId = Node.visit(index, this); >+ this._add(`if (${indexId} >= ${array.numElements.value}) {`); >+ this._indent(); >+ this._emitReturnZeroValue(); >+ this._unindent(); >+ this._add(`}`); >+ return `${variable}[${indexId}]`; >+ } >+ } else if (typeOf(array) instanceof ArrayRefType) { >+ const variable = array.visit(this); >+ const indexId = index.visit(this); >+ this._add(`if (${indexId} >= ${variable}.length) {`); >+ this._indent(); >+ this._emitReturnZeroValue(); >+ this._unindent(); >+ this._add('}'); >+ return `${variable}.ptr[${indexId}]`; >+ } else >+ this._add(`// TODO: Handle ${array} in MSLStatementEmitter._handleIndexAccess`); >+ } >+ >+ visitMakePtrExpression(node) >+ { >+ const expr = node.lValue.visit(this); >+ return `&(${expr})`; >+ } >+ >+ visitFunctionLikeBlock(node) >+ { >+ const canBeInlined = functionLikeBlockCanBeInlined(node); >+ if (canBeInlined) >+ this._add(`// inline ${node.origin.text}`); >+ else >+ this._add(`// call to ${node.origin.text}`); >+ >+ // 1. Create result variable if necessary. >+ let resultVar = null; >+ if (node.returnType.name != "void") { >+ resultVar = this._fresh(); >+ this._add(`${this._typeNamer.mslTypeName(node.returnType)} ${resultVar};`); >+ } >+ >+ this._add("{"); >+ this._indent(); >+ >+ // 2. Evaluate the arguments. >+ const args = []; >+ for (let i = node.argumentList.length - 1; i >= 0; i--) { >+ let id = node.argumentList[i].visit(this); >+ args.unshift(id); >+ } >+ >+ // 3. Emit the call inline or as a real call. >+ if (canBeInlined) >+ this._callFunctionLikeBlockInline(node, resultVar, args); >+ else >+ this._callFunctionLikeBlockWithCall(node, resultVar, args); >+ >+ this._unindent(); >+ this._add("}"); >+ >+ return resultVar; >+ } >+ >+ private _callFunctionLikeBlockInline(node, resultVar, args) >+ { >+ const nameMap = new Map(this._nameMap); >+ const params = node.parameters; >+ for (let i = 0; i < params.length; i++) >+ nameMap.set(params[i].name, args[i]); >+ >+ const emitter = new MSLStatementEmitter(this._funcMangler, this._typeNamer, node.body, nameMap, node.origin.text, this._lineNumbers, this._typeAttributes, resultVar, this._counter, this.ancestorReturnType); >+ this._addLines(emitter.lines); >+ } >+ >+ private _callFunctionLikeBlockWithCall(node, resultVar, args) >+ { >+ const mangledCallName = this._funcMangler.mangle(node.func); >+ this._add(`${resultVar} = ${mangledCallName}(${args.join(", ")});`); >+ } >+ >+ // Loop code generation. Loops all follow the same style where they declare a conditional variable (boolean) >+ // which is checked on each iteration (all loops are compiled to a while loop or do/while loop). The check is >+ // emitted in _emitLoopCondition. For loops additionally have _emitLoopBodyEnd for the increment on each iteration. >+ >+ visitForLoop(node: ForLoop) >+ { >+ this._emitAsLoop(node.condition, node.increment, (conditionVar) => { >+ Node.visit(node.initialization, this); // initalization can be null >+ this._emitLoopCondition(); >+ this._add(`while (${conditionVar}) {`); >+ this._emitScoped(node.body); >+ this._emitLoopBodyEnd(); >+ this._add('}'); >+ }); >+ } >+ >+ visitWhileLoop(node) >+ { >+ this._emitAsLoop(node.conditional, null, (conditionVar) => { >+ this._add(`while (${conditionVar}) {`); >+ this._emitScoped(node.body); >+ this._emitLoopCondition(); >+ this._add('}'); >+ }); >+ } >+ >+ visitDoWhileLoop(node) >+ { >+ this._emitAsLoop(node.conditional, null, (conditionVar: string) => { >+ this._add("do {"); >+ this._emitScoped(node.body); >+ this._emitLoopBodyEnd(); >+ this._add(`} while (${conditionVar});`); >+ }); >+ } >+ >+ private _emitAsLoop(conditional: Node, increment: Node, emitLoopBody: (conditionalVar: string) => void) >+ { >+ const conditionVar = this._fresh(); >+ this._loopConditionVariableStack.push(conditionVar); >+ this._loopConditionNodeStack.push(conditional); >+ this._loopIncrementNodeStack.push(increment); >+ this._add(`bool ${conditionVar} = true;`); >+ >+ emitLoopBody(conditionVar); >+ >+ this._loopIncrementNodeStack.pop(); >+ this._loopConditionVariableStack.pop(); >+ this._loopConditionNodeStack.pop(); >+ } >+ >+ private _emitLoopBodyEnd() >+ { >+ this._emitLoopIncrement(); >+ this._emitLoopCondition(); >+ } >+ >+ private _emitLoopIncrement() >+ { >+ if (this._loopIncrement) >+ this._emitScoped(this._loopIncrement); >+ } >+ >+ private _emitLoopCondition() >+ { >+ if (this._loopCondition) { >+ const conditionResult: Node = this._emitScoped(this._loopCondition); >+ this._add(`${this._loopConditionVariable} = ${conditionResult};`); >+ } >+ } >+ >+ // Switch statements. >+ >+ visitSwitchStatement(node) >+ { >+ const caseValueEmitter = new ConstexprEmitter(); >+ >+ let switchValue = Node.visit(node.value, this); >+ this._add(`switch (${switchValue}) {`); >+ this._indent(); >+ >+ for (let i = 0; i < node.switchCases.length; i++) { >+ let switchCase = node.switchCases[i]; >+ if (!switchCase.isDefault) >+ this._add(`case ${switchCase.value.visit(caseValueEmitter)}: {`); >+ else >+ this._add("default: {"); >+ this._emitScoped(switchCase.body); >+ this._add("}"); >+ } >+ >+ this._unindent(); >+ this._add("}"); >+ } >+ >+ visitSwitchCase(node) >+ { >+ throw new Error(`// FIXME: Hit |visitSwitchCase|, should be handled by |visitSwitchStatement|`); >+ } >+ >+ // Literals >+ >+ visitBoolLiteral(node) >+ { >+ const fresh = this._fresh(); >+ this._add(`bool ${fresh} = ${node.value};`); >+ return fresh; >+ } >+ >+ visitEnumLiteral(node) >+ { >+ return node.member.value.visit(this); >+ } >+ >+ visitGenericLiteral(node) >+ { >+ const fresh = this._fresh(); >+ this._add(metalSourceForVarDeclaration(this._typeNamer, node.type, fresh) + ";"); >+ this._add(`${fresh} = ${node.value};`); >+ return fresh; >+ } >+ >+ visitNullLiteral(node) >+ { >+ return `(nullptr)`; >+ } >+ >+ visitDotExpression(node) >+ { >+ throw new Error(`Dot expressions ${node} should have been converted to an operator`); >+ } >+ >+ visitTrapStatement(node) >+ { >+ this._emitReturnZeroValue(); >+ } >+ >+ visitLogicalExpression(node) >+ { >+ const result = this._fresh(); >+ this._add(`// Result variable for ${node.text}`); >+ this._add(`bool ${result};`); >+ if (node.text == "&&") { >+ const left = node.left.visit(this); >+ this._add(`if (!${left}) {`) >+ this._indent(); >+ this._add(`${result} = false;`); >+ this._unindent(); >+ this._add('} else {'); >+ this._indent(); >+ const right = node.right.visit(this); >+ this._add(`${result} = ${right};`); >+ this._unindent(); >+ this._add('}'); >+ } else if (node.text == "||") { >+ const left = node.left.visit(this); >+ this._add(`${result} = ${left};`); >+ this._add(`if (!${result}) {`); >+ this._indent(); >+ const right = node.right.visit(this); >+ this._add(`${result} = ${right};`); >+ this._unindent(); >+ this._add("}"); >+ } else >+ throw new Error(`Unrecognized logical expression ${node.text}`); >+ return result; >+ } >+ >+ visitTernaryExpression(node) >+ { >+ // FIXME: If each of the three expression isn't a compound expression or statement then just user ternary syntax. >+ let resultType = typeOf(node.bodyExpression); >+ if (node.isLValue) >+ resultType = new PtrType(node.origin, "thread", resultType); >+ let resultVar = this._fresh(); >+ this._add(metalSourceForVarDeclaration(this._typeNamer, resultType, resultVar) + ";"); >+ const predicate = node.predicate.visit(this); >+ this._add(`if (${predicate}) {`); >+ this._indent(); >+ const bodyExpression = node.bodyExpression.visit(this); >+ if (node.isLValue) >+ this._add(`${resultVar} = &(${bodyExpression});`); >+ else >+ this._add(`${resultVar} = ${bodyExpression};`); >+ this._unindent(); >+ this._add("} else {"); >+ this._indent(); >+ const elseExpression = node.elseExpression.visit(this); >+ if (node.isLValue) >+ this._add(`${resultVar} = &(${elseExpression});`); >+ else >+ this._add(`${resultVar} = ${elseExpression};`); >+ this._unindent(); >+ this._add("}"); >+ >+ if (node.isLValue) >+ resultVar = `*(${resultVar})`; >+ >+ return resultVar; >+ } >+ >+ // Unimplemented methods. I write out comments for these rather than throwing exceptions because it makes it easier for me >+ // to see where the nodes occur in the abstract syntax tree >+ >+ visitIndexExpression(node) >+ { >+ this._add("// TODO: visitIndexExpression"); >+ } >+ >+ visitNativeFunc(node) >+ { >+ this._add("// TODO: visitNativeFunc"); >+ } >+ >+ visitNativeTypeInstance(node) >+ { >+ this._add("// TODO: visitNativeTypeInstance"); >+ } >+ >+ visitReadModifyWriteExpression(node) >+ { >+ this._add("// TODO: visitReadModifyWriteExpression"); >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeNamer.ts b/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeNamer.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..922aad874ae23b790848f9ba6a084d713b485080 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeNamer.ts >@@ -0,0 +1,150 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class MSLTypeNamer { >+ private _typeUnifier: TypeUnifier; >+ >+ constructor(typeUnifier) >+ { >+ this._typeUnifier = typeUnifier; >+ } >+ >+ get typeUnifier() >+ { >+ return this._typeUnifier; >+ } >+ >+ uniqueTypeId(type) >+ { >+ return this.typeUnifier.uniqueTypeId(type); >+ } >+ >+ // Yields the string that should be used in MSL source for the type. >+ mslTypeName(type) >+ { >+ let name; >+ >+ const typeUnifier = this.typeUnifier; >+ const typeNamer = this; >+ >+ class TypeNameVisitor extends Visitor { >+ visitNativeType(node) >+ { >+ const nativeTypeNameMap = { >+ "void": "void", >+ "bool": "bool", >+ "uchar": "uint8_t", >+ "ushort": "uint16_t", >+ "uint": "uint32_t", >+ "char": "int8_t", >+ "short": "int16_t", >+ "int": "int32_t", >+ "half": "half", >+ "float": "float", >+ "atomic_int": "atomic_int", >+ "atomic_uint": "atomic_uint" >+ }; >+ >+ name = nativeTypeNameMap[node.name]; >+ } >+ >+ visitStructType(node) >+ { >+ name = typeUnifier.uniqueTypeId(node); >+ } >+ >+ visitEnumType(node) >+ { >+ return Node.visit(node.baseType, this); >+ } >+ >+ visitReferenceType(node) >+ { >+ name = `${node.addressSpace} ${typeNamer.mslTypeName(node.elementType)}*`; >+ } >+ >+ visitArrayType(node) >+ { >+ // The address space can be null if the array is nested within another. >+ name = `${node.addressSpace ? node.addressSpace + " " : ""}${typeNamer.mslTypeName(node.elementType)}*`; >+ } >+ >+ visitArrayRefType(node) >+ { >+ name = typeUnifier.uniqueTypeId(node); >+ } >+ >+ visitVectorType(node) >+ { >+ // Vector type names work slightly differently to native type names >+ const elementTypeNameMap = { >+ "bool": "bool", >+ "char": "char", >+ "uchar": "uchar", >+ "short": "short", >+ "ushort": "ushort", >+ "int": "int", >+ "uint": "uint", >+ "half": "half", >+ "float": "float" >+ }; >+ >+ const elementTypeName = elementTypeNameMap[node.elementType.name]; >+ if (!elementTypeName) >+ throw new Error(`${node.elementType.name} is not a supported vector element type`); >+ >+ name = `${elementTypeName}${node.numElementsValue}`; >+ } >+ >+ visitTypeRef(node) >+ { >+ node.type.visit(this); >+ } >+ >+ visitMatrixType(node) >+ { >+ // Matrix type names work slightly differently to native type names >+ const elementTypeNameMap = { >+ "bool": "bool", >+ "half": "half", >+ "float": "float" >+ }; >+ >+ const elementTypeName = elementTypeNameMap[node.elementType.name]; >+ if (!elementTypeName) >+ throw new Error(`${node.elementType.name} is not a supported vector element type`); >+ >+ name = `${elementTypeName}${node.numRowsValue}x${node.numColumnsValue}`; >+ } >+ } >+ >+ type.visit(new TypeNameVisitor()); >+ >+ if (!name) >+ throw new Error(`${type} doesn't have a name`); >+ >+ return name; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MetalCodegen.ts b/Tools/WebGPUShadingLanguageRI/Metal/MetalCodegen.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..590afad021c42c548404e87a405741ea7641caaf >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MetalCodegen.ts >@@ -0,0 +1,254 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+const DefaultMetalSource = `#include <metal_stdlib> >+using namespace metal; >+ >+`; >+ >+// Handles the compilation of Program AST instances to CompileResult instances, which >+// include the raw MSL. In general clients should call |whlslToMsl|, which parses, >+// typechecks, and inlines the WHLSL before passing it to this compiler. >+class MetalCodegen { >+ private _program: Program; >+ private _lineNumbers: number[]; >+ private _declarations: any[]; >+ private _allowComments: boolean; >+ private _typeUnifier: TypeUnifier; >+ private _typeNamer: MSLTypeNamer; >+ private _forwardTypeDecls: any[]; >+ private _typeDefinitions: any[]; >+ private _forwardFunctionDecls: any[]; >+ private _functionDefintions: MSLFunctionDefinition[]; >+ private _allTypeAttributes: TypeAttributesMap; >+ private _funcNameMangler: NameMangler; >+ private _functionSources: Map<string, string>; >+ >+ constructor(program: Program, lineNos: number[] = null) >+ { >+ this._program = program; >+ this._lineNumbers = lineNos; >+ this._declarations = []; >+ this._funcNameMangler = new NameMangler("F"); >+ } >+ >+ get program() >+ { >+ return this._program; >+ } >+ >+ get declarations() >+ { >+ return this._declarations; >+ } >+ >+ get functionSources(): Map<string, string> >+ { >+ return this._functionSources; >+ } >+ >+ // The main entry point for the compiler, however clients should generally call whlslToMsl, >+ // which is defined at the bottom of this file. >+ generateMsl(): CompileResult >+ { >+ // try { >+ const src = this._tryGenerateMsl(); >+ const mangledMap = {}; >+ for (let func of this._functionDefintions) { >+ const key = func.func.name; >+ const value = this._funcNameMangler.mangle(func.func); >+ mangledMap[key] = value; >+ } >+ >+ return new CompileResult(src, null, mangledMap, this._functionSources); >+ // } catch (e) { >+ // return new CompileResult(null, e, null, null); >+ // } >+ } >+ >+ private _tryGenerateMsl(): string >+ { >+ this._typeUnifier = new TypeUnifier(); >+ this._typeNamer = new MSLTypeNamer(this._typeUnifier); >+ this._forwardTypeDecls = []; >+ this._typeDefinitions = []; >+ this._forwardFunctionDecls = []; >+ this._functionDefintions = []; >+ >+ // Step 1: Find all the functions to compile >+ >+ const entryPointFunctionDefinitions = this._findEntryPointDefinitions(); >+ for (let entryPoint of entryPointFunctionDefinitions) >+ entryPoint.visit(this._typeUnifier); >+ >+ const functionsToCompile = this._findFunctionDefinitionsToCompile(entryPointFunctionDefinitions); >+ >+ // Step 2: Find properties of the types and create type and function declarations. >+ >+ this._allTypeAttributes = new TypeAttributesMap(functionsToCompile, this._typeUnifier); >+ this._createTypeDecls(); >+ this._createFunctionDecls(functionsToCompile); >+ >+ // Step 3: Generate the actual MSL source code. >+ >+ let outputStr = DefaultMetalSource; >+ >+ const addSection = (title, decls) => { >+ outputStr += `#pragma mark - ${title}\n\n${decls.join("\n\n")}\n\n`; >+ }; >+ >+ addSection("Forward type declarations", this._forwardTypeDecls); >+ addSection("Type definitions", this._typeDefinitions); >+ addSection("Forward function declarations", this._forwardFunctionDecls); >+ addSection("Function definitions", this._functionDefintions); >+ >+ if (!this._allowComments) >+ outputStr = this._removeCommentsAndEmptyLines(outputStr); >+ >+ return outputStr; >+ } >+ >+ private _findEntryPointDefinitions() >+ { >+ const entryPointFunctions = []; >+ for (let [name, instances] of this._program.functions) { >+ for (let instance of instances) { >+ if (instance.isEntryPoint) >+ entryPointFunctions.push(instance); >+ } >+ } >+ const functions = new Set(entryPointFunctions); >+ >+ class FindFunctionsThatGetCalled extends Visitor { >+ visitCallExpression(node) >+ { >+ if (!(node.func instanceof NativeFunc)) { >+ if (!functions.has(node.func)) >+ node.func.visit(this); >+ functions.add(node.func); >+ } >+ } >+ } >+ const findFunctionsThatGetCalledVisitor = new FindFunctionsThatGetCalled(); >+ >+ for (let entryPoint of entryPointFunctions) >+ entryPoint.visit(findFunctionsThatGetCalledVisitor); >+ >+ return Array.from(functions); >+ } >+ >+ // Finds FunctionLikeBlocks that can't be inlined because they don't have reducible control flow, so promotes them >+ // to full function definitions. >+ private _findFunctionDefinitionsToCompile(functionDefinitions) >+ { >+ const functionSet = new Set<Node>(); >+ >+ class FindFunctionsToDeclare extends Visitor { >+ visitFunctionLikeBlock(node: FunctionLikeBlock) >+ { >+ // FIXME: Once we have made inlining an option, the inliner should use functionLikeBlockCanBeInlined to determine >+ // whether or not a function can possibly be inlined. Then this stage can be removed. >+ if (!functionSet.has(node.func)) { >+ if (!functionLikeBlockCanBeInlined(node)) >+ functionSet.add(node.func); >+ super.visitFunctionLikeBlock(node); >+ } >+ } >+ } >+ >+ const visitor = new FindFunctionsToDeclare(); >+ >+ for (let funcDef of functionDefinitions) >+ Node.visit(funcDef, visitor); >+ >+ functionDefinitions.push(...functionSet); >+ console.log(functionDefinitions); >+ >+ return functionDefinitions; >+ } >+ >+ private _createTypeDecls() >+ { >+ const typesThatNeedDeclaration = this._typeUnifier.typesThatNeedDeclaration(); >+ const typeDeclsInOrder = this._sortTypeDeclarationsInTopologicalOrder(typesThatNeedDeclaration); >+ >+ for (let type of typeDeclsInOrder) { >+ if (type instanceof StructType) { >+ this._forwardTypeDecls.push(metalSourceForStructForwardDeclaration(type, this._typeNamer)); >+ this._typeDefinitions.push(metalSourceForStructDefinition(type, this._typeNamer, this._allTypeAttributes.attributesForType(type))); >+ } else if (type instanceof ArrayRefType) { >+ this._forwardTypeDecls.push(metalSourceForArrayRefForwardDeclaration(type, this._typeNamer)); >+ this._typeDefinitions.push(metalSourceForArrayRefDefinition(type, this._typeNamer)); >+ } else >+ throw new Error(`${type} cannot be declared in Metal`); >+ } >+ } >+ >+ private _createFunctionDecls(unifiedFunctionDefs) >+ { >+ for (let func of unifiedFunctionDefs) { >+ this._forwardFunctionDecls.push(new MSLFunctionForwardDeclaration(this._funcNameMangler, func, this._typeNamer, this._lineNumbers, this._allTypeAttributes)); >+ this._functionDefintions.push(new MSLFunctionDefinition(this._funcNameMangler, func, this._typeNamer, this._lineNumbers, this._allTypeAttributes)); >+ } >+ } >+ >+ private _sortTypeDeclarationsInTopologicalOrder(typesToDeclare) >+ { >+ const declarations = new Array(); >+ for (let type of typesToDeclare) >+ declarations.push(type); >+ const typeOrder = sortTypeDeclarations(typesToDeclare, this._typeUnifier); >+ const typeOrderMap = new Map<Type, number>(); >+ for (let i = 0; i < typeOrder.length; i++) >+ typeOrderMap.set(typeOrder[i], i); >+ return declarations.sort((a, b) => typeOrderMap.get(a) - typeOrderMap.get(b)); >+ } >+ >+ // Also removes #pragma marks. >+ private _removeCommentsAndEmptyLines(src) >+ { >+ const singleLineCommentRegex = /(\/\/|\#pragma)(.*?)($|\n)/; >+ const lines = src.split('\n') >+ .map(line => line.replace(singleLineCommentRegex, '').trimEnd()) >+ .filter(line => line.length > 0); >+ return lines.join('\n'); >+ } >+} >+ >+// Main wrapper for the compiler. Clients should use this function to compile WHLSL. >+function whlslToMsl(src: string): CompileResult { >+ let parsedProgram; >+ try { >+ parsedProgram = prepare("/internal/test", 0, src); >+ } catch (e) { >+ return new CompileResult(null, e, null, null); >+ } >+ >+ if (!(parsedProgram instanceof Program)) >+ return new CompileResult(null, new Error("Compilation failed"), null, null); >+ >+ const compiler = new MetalCodegen(parsedProgram, lineNumbers(src)); >+ return compiler.generateMsl(); >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/NameMangler.ts b/Tools/WebGPUShadingLanguageRI/Metal/NameMangler.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..7d51184feef26ac5bc5fcd496ffc11d351848b24 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/NameMangler.ts >@@ -0,0 +1,44 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class NameMangler { >+ private _prefix: string; >+ private _counter: number; >+ private _mangledNameMap: Map<any, string>; >+ >+ constructor(prefix: string) >+ { >+ this._prefix = prefix; >+ this._counter = 0; >+ this._mangledNameMap = new Map(); >+ } >+ >+ mangle(key: any): string >+ { >+ if (!this._mangledNameMap.has(key)) >+ this._mangledNameMap.set(key, `${this._prefix}${this._counter++}`); >+ return this._mangledNameMap.get(key); >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/README.md b/Tools/WebGPUShadingLanguageRI/Metal/README.md >new file mode 100644 >index 0000000000000000000000000000000000000000..97cd86451de65695ad5b3b56338a81b721145093 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/README.md >@@ -0,0 +1,16 @@ >+# Metal Shader Language code generation >+ >+## Building >+ >+The MSL compiler is based around the existing WSL interpreter in the parent directory. The compiler is written in TypeScript, a typed superset of JavaScript. To compile and run the compiler: >+ >+1. Install [Node.js][Node] LTS >+2. Install [TypeScript][typescript] by running `npm install -g typescript` >+3. Either: >+ (a) Open Visual Studio Code, press CMD + SHIFT + B, click `build` or `watch` >+ (b) Run `tsc -p tsconfig.js` inside this directory >+4. Start a web browser in the parent directory >+5. Go to [http://localhost:8000/Metal][] to run the compiler >+ >+[Node]: https://nodejs.org >+[typescript]: https://www.typescriptlang.org >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/SortTypeDeclarations.ts b/Tools/WebGPUShadingLanguageRI/Metal/SortTypeDeclarations.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..90c05c46c0dbc4fc9036363ee13481f0b6c13b51 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/SortTypeDeclarations.ts >@@ -0,0 +1,51 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+function sortTypeDeclarations(types, typeUnifier) >+{ >+ let visitedSet: Set<String> = new Set(); >+ let visitedOrder: Type[] = []; >+ >+ class TypeOrderer extends Visitor { >+ visitStructType(node) >+ { >+ const id = typeUnifier.uniqueTypeId(node); >+ if (!visitedSet.has(id)) { >+ visitedOrder.push(node); >+ super.visitStructType(node); >+ } >+ visitedSet.add(id); >+ } >+ >+ // An empty implementation ensures that we don't recurse into the element type and needlessly create dependencies. >+ visitReferenceType(node) {} >+ } >+ >+ const typeOrderer = new TypeOrderer(); >+ for (let type of types) >+ type.visit(typeOrderer); >+ >+ return visitedOrder.reverse(); >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/StructDefinition.ts b/Tools/WebGPUShadingLanguageRI/Metal/StructDefinition.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..50acd4287260fea6ded6d08024bfb3e041dfcc4b >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/StructDefinition.ts >@@ -0,0 +1,55 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+function metalSourceForStructForwardDeclaration(structType, typeNamer) >+{ >+ return `struct ${typeNamer.uniqueTypeId(structType)};`; >+} >+ >+function metalSourceForStructDefinition(structType, typeNamer, structTypeAttributes) >+{ >+ let src = `struct ${typeNamer.uniqueTypeId(structType)} {\n`; >+ >+ let index = 0; >+ for (let [fieldName, field] of structType.fieldMap) { >+ const mangledFieldName = structTypeAttributes.mangledFieldName(fieldName); >+ src += ` ${metalSourceForVarDeclaration(typeNamer, field.type, mangledFieldName)}`; >+ >+ const annotations = []; >+ if (structTypeAttributes.isVertexAttribute) >+ annotations.push(`attribute(${index++})`); >+ if (structTypeAttributes.isVertexOutputOrFragmentInput && fieldName === "wsl_Position") >+ annotations.push("position"); >+ if (structTypeAttributes.isFragmentOutput && fieldName === "wsl_Color") >+ annotations.push("color(0)"); >+ if (annotations.length) >+ src += ` [[${annotations.join(", ")}]]`; >+ src += ";\n"; >+ } >+ >+ src += "};"; >+ >+ return src; >+} >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/Token.ts b/Tools/WebGPUShadingLanguageRI/Metal/Token.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..f2a364dd4839e8af4d328e5f8058fc6088d1e51c >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/Token.ts >@@ -0,0 +1,58 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+// The output of MSLLexer. >+class Token { >+ private _type: string; >+ private _src: string; >+ private _startIndex: number; >+ >+ constructor(type, src, start) >+ { >+ this._type = type; >+ this._src = src; >+ this._startIndex = start; >+ } >+ >+ get type(): string >+ { >+ return this._type; >+ } >+ >+ get src(): string >+ { >+ return this._src; >+ } >+ >+ get startIndex(): number >+ { >+ return this._startIndex; >+ } >+ >+ set startIndex(i: number) >+ { >+ this._startIndex = i; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/TypeAttributeMap.ts b/Tools/WebGPUShadingLanguageRI/Metal/TypeAttributeMap.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..f5ece1a3bb516786d82a9f68020fb5ca6bed6eeb >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/TypeAttributeMap.ts >@@ -0,0 +1,69 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+// Provides lookup for all the top level types in the program. >+class TypeAttributesMap { >+ private _typeUnifier : TypeUnifier; >+ private _typeAttributeMap : Map<string, TypeAttributes>; >+ >+ constructor(functionDefs, typeUnifier) >+ { >+ this._typeUnifier = typeUnifier; >+ >+ this._typeAttributeMap = new Map(); >+ >+ for (let funcDef of functionDefs) { >+ if (funcDef.shaderType == "vertex") >+ this.visitVertexShader(funcDef); >+ else if (funcDef.shaderType == "fragment") >+ this.visitFragmentShader(funcDef); >+ } >+ } >+ >+ attributesForType(type) >+ { >+ const key = this._typeUnifier.uniqueTypeId(type); >+ let attrs = this._typeAttributeMap.get(key); >+ if (!attrs) >+ this._typeAttributeMap.set(key, attrs = new TypeAttributes(type)); >+ return attrs; >+ } >+ >+ private visitVertexShader(func) >+ { >+ this.attributesForType(func.returnType).isVertexOutputOrFragmentInput = true; >+ for (let param of func.parameters) >+ this.attributesForType(param.type).isVertexAttribute = true; >+ } >+ >+ private visitFragmentShader(func) >+ { >+ this.attributesForType(func.returnType).isFragmentOutput = true; >+ for (let param of func.parameters) >+ this.attributesForType(param.type).isVertexOutputOrFragmentInput = true; >+ } >+ >+ // FIXME: Support compute shaders. >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/TypeAttributes.ts b/Tools/WebGPUShadingLanguageRI/Metal/TypeAttributes.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..467d47e56d51ca4a1695a3ac0e9c79ad050d52f7 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/TypeAttributes.ts >@@ -0,0 +1,91 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class TypeAttributes { >+ private _type: any; >+ private _isVertexAttribute: boolean; >+ private _isVertexOutputOrFragmentInput: boolean; >+ private _isFragmentOutput: boolean; >+ private _fieldMangler: NameMangler; >+ >+ constructor(type) >+ { >+ this._type = type; >+ this._isVertexAttribute = false; >+ this._isVertexOutputOrFragmentInput = false; >+ this._isFragmentOutput = false; >+ this._fieldMangler = new NameMangler('field'); >+ >+ if (type instanceof StructType) { >+ for (let field of type.fields) >+ this._fieldMangler.mangle(field.name) >+ } >+ } >+ >+ get type() >+ { >+ return this._type; >+ } >+ >+ get isVertexAttribute() >+ { >+ return this._isVertexAttribute; >+ } >+ >+ set isVertexAttribute(va) >+ { >+ this._isVertexAttribute = va; >+ } >+ >+ get isVertexOutputOrFragmentInput() >+ { >+ return this._isVertexOutputOrFragmentInput; >+ } >+ >+ set isVertexOutputOrFragmentInput(vo) >+ { >+ this._isVertexOutputOrFragmentInput = vo; >+ } >+ >+ get isFragmentOutput() >+ { >+ return this._isFragmentOutput; >+ } >+ >+ set isFragmentOutput(fo) >+ { >+ this._isFragmentOutput = fo; >+ } >+ >+ get fieldMangler() >+ { >+ return this._fieldMangler; >+ } >+ >+ mangledFieldName(fieldName: string) >+ { >+ return this.fieldMangler.mangle(fieldName); >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/TypeOf.ts b/Tools/WebGPUShadingLanguageRI/Metal/TypeOf.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..7cd004ed168fb7b219776beda7481f9103b1019a >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/TypeOf.ts >@@ -0,0 +1,323 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+function typeOf(node: Node): Type { >+ class TypeVisitor extends Visitor { >+ visitAnonymousVariable(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitArrayRefType(node) >+ { >+ return node; >+ } >+ >+ visitArrayType(node) >+ { >+ return node; >+ } >+ >+ visitAssignment(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitCallExpression(node) >+ { >+ return node.func.visit(this); >+ } >+ >+ visitCommaExpression(node) >+ { >+ return node.list[node.list.length - 1].visit(this); >+ } >+ >+ visitConvertPtrToArrayRefExpression(node) >+ { >+ const ptrType = <PtrType>typeOf(node.lValue); >+ return new ArrayRefType(ptrType.origin, ptrType.addressSpace, ptrType.elementType); >+ } >+ >+ visitDotExpression(node) >+ { >+ return node.struct.fieldMap.get(node.fieldName).type.visit(this); >+ } >+ >+ visitElementalType(node) >+ { >+ return node; >+ } >+ >+ visitEnumType(node) >+ { >+ return node; >+ } >+ >+ visitField(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitFunc(node) >+ { >+ return node.returnType.visit(this); >+ } >+ >+ visitFuncDef(node) >+ { >+ return node.returnType.visit(this); >+ } >+ >+ visitFuncParameter(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitFunctionLikeBlock(node) >+ { >+ return node.returnType.visit(this); >+ } >+ >+ visitGenericLiteralType(node) >+ { >+ return node; >+ } >+ >+ visitIdentityExpression(node) >+ { >+ return node.target.visit(this); >+ } >+ >+ visitIndexExpression(node) >+ { >+ return node.array.elementType.visit(this); >+ } >+ >+ visitLogicalExpression(node) >+ { >+ throw new Error("FIXME: Implement TypeVisitor.visitLogicalExpression"); >+ } >+ >+ visitLogicalNot(node) >+ { >+ return node.operand.visit(this); >+ } >+ >+ visitMakeArrayRefExpression(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitMakePtrExpression(node) >+ { >+ throw new Error("FIXME: Implement TypeVisitor.visitMakePtrExpression"); >+ } >+ >+ visitMatrixType(node) >+ { >+ return node; >+ } >+ >+ visitNativeFunc(node) >+ { >+ return node.returnType.visit(this); >+ } >+ >+ visitNativeFuncInstance(node) >+ { >+ return node.returnType.visit(this); >+ } >+ >+ visitNativeType(node) >+ { >+ return node; >+ } >+ >+ visitNativeTypeInstance(node) >+ { >+ return node; >+ } >+ >+ visitNullLiteral(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitNullType(node) >+ { >+ return node; >+ } >+ >+ visitPtrType(node) >+ { >+ return node; >+ } >+ >+ visitReadModifyWriteExpression(node) >+ { >+ throw new Error("FIXME: Implement TypeVisitor.visitReadModifyWriteExpression"); >+ } >+ >+ visitReferenceType(node) >+ { >+ return node; >+ } >+ >+ visitStructType(node) >+ { >+ return node; >+ } >+ >+ visitTypeDef(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitTypeRef(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitVariableDecl(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitVariableRef(node) >+ { >+ return node.variable.type.visit(this); >+ } >+ >+ visitVectorType(node) >+ { >+ return node; >+ } >+ >+ visitBlock(node) >+ { >+ throw new Error("Block has no type"); >+ } >+ >+ visitBoolLiteral(node) >+ { >+ throw new Error("BoolLiteral has no type"); >+ } >+ >+ visitBreak(node) >+ { >+ throw new Error("Break has no type"); >+ } >+ >+ visitConstexprTypeParameter(node) >+ { >+ throw new Error("ConstexprTypeParameter has no type"); >+ } >+ >+ visitContinue(node) >+ { >+ throw new Error("Continue has no type"); >+ } >+ >+ visitDereferenceExpression(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitDoWhileLoop(node) >+ { >+ throw new Error("DoWhileLoop has no type"); >+ } >+ >+ visitEnumLiteral(node) >+ { >+ throw new Error("EnumLiteral has no type"); >+ } >+ >+ visitEnumMember(node) >+ { >+ throw new Error("EnumMember has no type"); >+ } >+ >+ visitForLoop(node) >+ { >+ throw new Error("ForLoop has no type"); >+ } >+ visitGenericLiteral(node) >+ { >+ return node.type.visit(this); >+ } >+ visitIfStatement(node) >+ { >+ throw new Error("IfStatement has no type"); >+ } >+ >+ visitProgram(node) >+ { >+ throw new Error("Program has no type"); >+ } >+ >+ visitProtocolDecl(node) >+ { >+ throw new Error("ProtocolDecl has no type"); >+ } >+ >+ visitProtocolFuncDecl(node) >+ { >+ throw new Error("ProtocolFuncDecl has no type"); >+ } >+ >+ visitProtocolRef(node) >+ { >+ throw new Error("ProtocolRef has no type"); >+ } >+ >+ visitReturn(node) >+ { >+ throw new Error("Return has no type"); >+ } >+ >+ visitSwitchCase(node) >+ { >+ throw new Error("SwitchCase has no type"); >+ } >+ >+ visitSwitchStatement(node) >+ { >+ throw new Error("SwitchStatement has no type"); >+ } >+ >+ visitTrapStatement(node) >+ { >+ throw new Error("TrapStatement has no type"); >+ } >+ >+ visitWhileLoop(node) >+ { >+ throw new Error("WhileLoop has no type"); >+ } >+ } >+ return node.visit(new TypeVisitor()); >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/TypeUnifier.ts b/Tools/WebGPUShadingLanguageRI/Metal/TypeUnifier.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..703e6bbded2155217047c99810cec7ffbfc172d7 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/TypeUnifier.ts >@@ -0,0 +1,136 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+ // FIXME: This class needs a better name. >+class TypeUnifier extends Visitor { >+ >+ private _typeNameMangler: NameMangler; >+ private _allTypes: Set<any>; >+ >+ constructor() >+ { >+ super(); >+ >+ this._typeNameMangler = new NameMangler('T'); >+ this._allTypes = new Set(); >+ } >+ >+ get allTypes() >+ { >+ return this._allTypes; >+ } >+ >+ uniqueTypeId(type) >+ { >+ return type.visit(this); >+ } >+ >+ visitTypeRef(node) >+ { >+ if ((node.typeArguments && node.typeArguments.length) || !node.name) { >+ return node.type.visit(this); >+ } >+ >+ if (!this._allTypes.has(node.type)) >+ node.type.visit(this); >+ >+ const baseType = typeOf(node); >+ >+ if (baseType instanceof NativeType || baseType instanceof VectorType) >+ return baseType.visit(this); >+ >+ return this._typeNameMangler.mangle(node.name); >+ } >+ >+ visitStructType(node) >+ { >+ this._allTypes.add(node); >+ for (let field of node.fields) >+ field.visit(this); >+ return this._typeNameMangler.mangle(node.name); >+ } >+ >+ visitEnumType(node) >+ { >+ this._allTypes.add(node); >+ node.baseType.visit(this); >+ return this._typeNameMangler.mangle(node.name); >+ } >+ >+ visitNativeType(node) >+ { >+ this._allTypes.add(node); >+ return node.name; >+ } >+ >+ visitPtrType(node) >+ { >+ this._allTypes.add(node); >+ node.elementType.visit(this); >+ return `${node.elementType.visit(this)}* ${node.addressSpace}`; >+ } >+ >+ visitArrayType(node) >+ { >+ this._allTypes.add(node); >+ node.elementType.visit(this); >+ return `${node.elementType.visit(this)}[${node.numElements}]`; >+ } >+ >+ visitArrayRefType(node) >+ { >+ this._allTypes.add(node); >+ // The name mangler is used here because array refs are "user-defined" types in the sense >+ // that they will need to be defined as structs in the Metal output. >+ return this._typeNameMangler.mangle(`${node.elementType.visit(this)}[] ${node.addressSpace}`); >+ } >+ >+ visitVectorType(node) >+ { >+ this._allTypes.add(node); >+ return node.toString(); >+ } >+ >+ visitMakeArrayRefExpression(node) >+ { >+ if (!node.type) >+ throw new Error(node); >+ return node.type.visit(this); >+ } >+ >+ typesThatNeedDeclaration() >+ { >+ const declSet = new Set(); >+ const nameSet = new Set(); >+ for (let type of this._allTypes) { >+ const name = type.visit(this); >+ if ((type instanceof StructType || type instanceof ArrayRefType) && !nameSet.has(name)) { >+ declSet.add(type); >+ nameSet.add(name); >+ } >+ } >+ return declSet; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/VarDeclaration.ts b/Tools/WebGPUShadingLanguageRI/Metal/VarDeclaration.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..fe921c2eb78f2f8916b2076b89712cd71ac4ee1a >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/VarDeclaration.ts >@@ -0,0 +1,43 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+function metalSourceForVarDeclaration(typeNamer, type, name) >+{ >+ type = typeOf(type); // Unwrap TypeRef if necessary >+ if (type.isArray) { >+ let arrayType = <ArrayType>type; >+ const sizes = [ arrayType.numElementsValue ]; >+ let elementType = typeOf(arrayType.elementType); >+ while (elementType.isArray) { >+ arrayType = <ArrayType>elementType; >+ sizes.push(arrayType.numElementsValue); >+ elementType = arrayType.elementType; >+ } >+ return `${typeNamer.mslTypeName(elementType)} ${name}${sizes.map(size => `[${size}]`).join('')}`; >+ } else if (type.isPtr) >+ return (<PtrType>type).addressSpace + " " + metalSourceForVarDeclaration(typeNamer, (<PtrType>type).elementType, `(*${name})`); >+ else >+ return `${typeNamer.mslTypeName(type)} ${name}`; >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/.gitignore b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/.gitignore >new file mode 100644 >index 0000000000000000000000000000000000000000..c3b9a22cb1aceb00014bf5682b83c33126c9632b >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/.gitignore >@@ -0,0 +1,3 @@ >+WHLSL Tests.xcodeproj/xcuserdata >+WHLSL Tests.xcodeproj/project.xcworkspace/xcshareddata >+WHLSL Tests.xcodeproj/project.xcworkspace/xcuserdata >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.h >new file mode 100644 >index 0000000000000000000000000000000000000000..8529948d2a69df8fc1c861d7850bc503e9f5e9e6 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.h >@@ -0,0 +1,15 @@ >+// >+// AppDelegate.h >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Cocoa/Cocoa.h> >+ >+@interface AppDelegate : NSObject <NSApplicationDelegate> >+ >+ >+@end >+ >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.m >new file mode 100644 >index 0000000000000000000000000000000000000000..368a84a73fdb85b52447560386af20ce25e86cbc >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.m >@@ -0,0 +1,27 @@ >+// >+// AppDelegate.m >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "AppDelegate.h" >+ >+@interface AppDelegate () >+ >+@end >+ >+@implementation AppDelegate >+ >+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { >+ // Insert code here to initialize your application >+} >+ >+ >+- (void)applicationWillTerminate:(NSNotification *)aNotification { >+ // Insert code here to tear down your application >+} >+ >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/AppIcon.appiconset/Contents.json b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/AppIcon.appiconset/Contents.json >new file mode 100644 >index 0000000000000000000000000000000000000000..2db2b1c7c6c316500a7a34807648434289494ba1 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/AppIcon.appiconset/Contents.json >@@ -0,0 +1,58 @@ >+{ >+ "images" : [ >+ { >+ "idiom" : "mac", >+ "size" : "16x16", >+ "scale" : "1x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "16x16", >+ "scale" : "2x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "32x32", >+ "scale" : "1x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "32x32", >+ "scale" : "2x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "128x128", >+ "scale" : "1x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "128x128", >+ "scale" : "2x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "256x256", >+ "scale" : "1x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "256x256", >+ "scale" : "2x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "512x512", >+ "scale" : "1x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "512x512", >+ "scale" : "2x" >+ } >+ ], >+ "info" : { >+ "version" : 1, >+ "author" : "xcode" >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/Contents.json b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/Contents.json >new file mode 100644 >index 0000000000000000000000000000000000000000..da4a164c918651cdd1e11dca5cc62c333f097601 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/Contents.json >@@ -0,0 +1,6 @@ >+{ >+ "info" : { >+ "version" : 1, >+ "author" : "xcode" >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Base.lproj/Main.storyboard b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Base.lproj/Main.storyboard >new file mode 100644 >index 0000000000000000000000000000000000000000..c676d9f74cc567bff56bed1dd565dcdd70beb3df >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Base.lproj/Main.storyboard >@@ -0,0 +1,847 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14269.14" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS"> >+ <dependencies> >+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14269.14"/> >+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> >+ </dependencies> >+ <scenes> >+ <!--Application--> >+ <scene sceneID="JPo-4y-FX3"> >+ <objects> >+ <application id="hnw-xV-0zn" sceneMemberID="viewController"> >+ <menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6"> >+ <items> >+ <menuItem title="WHLSL Tests" id="1Xt-HY-uBw"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="WHLSL Tests" systemMenu="apple" id="uQy-DD-JDr"> >+ <items> >+ <menuItem title="About WHLSL Tests" id="5kV-Vb-QxS"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/> >+ <menuItem title="Preferencesâ¦" keyEquivalent="," id="BOF-NM-1cW"/> >+ <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/> >+ <menuItem title="Services" id="NMo-om-nkz"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/> >+ <menuItem title="Hide WHLSL Tests" keyEquivalent="h" id="Olw-nP-bQN"> >+ <connections> >+ <action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO"> >+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> >+ <connections> >+ <action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Show All" id="Kd2-mp-pUS"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/> >+ <menuItem title="Quit WHLSL Tests" keyEquivalent="q" id="4sb-4s-VLi"> >+ <connections> >+ <action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="File" id="dMs-cI-mzQ"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="File" id="bib-Uj-vzu"> >+ <items> >+ <menuItem title="New" keyEquivalent="n" id="Was-JA-tGl"> >+ <connections> >+ <action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Openâ¦" keyEquivalent="o" id="IAo-SY-fd9"> >+ <connections> >+ <action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Open Default" keyEquivalent="D" id="aei-2z-FdS"> >+ <connections> >+ <action selector="loadDefault:" target="Ady-hI-5gd" id="Qkc-mo-M8q"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Open Mandelbrot" keyEquivalent="d" id="Oo7-Lv-ixZ"> >+ <connections> >+ <action selector="loadMandelbrot:" target="Ady-hI-5gd" id="rBu-TY-q9u"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Open Julia" keyEquivalent="j" id="ghn-TO-Pf8"> >+ <connections> >+ <action selector="loadJulia:" target="Ady-hI-5gd" id="Ld3-NY-hjZ"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Open Recent" id="tXI-mr-wws"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ"> >+ <items> >+ <menuItem title="Clear Menu" id="vNY-rz-j42"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Open Native Flat Color" id="4fF-le-bz2"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="loadNativeFlatColor:" target="Ady-hI-5gd" id="D8V-tT-Uue"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Open Native Mandelbrot" id="vkA-g5-K5f"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="loadNativeMandelbrot:" target="Ady-hI-5gd" id="f0f-zP-EXZ"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Open Native Julia" id="rag-hI-17H"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="loadNativeJulia:" target="Ady-hI-5gd" id="lVh-ll-sg8"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="m54-Is-iLE"/> >+ <menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG"> >+ <connections> >+ <action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Saveâ¦" keyEquivalent="s" id="pxx-59-PXV"> >+ <connections> >+ <action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Save Asâ¦" keyEquivalent="S" id="Bw7-FT-i3A"> >+ <connections> >+ <action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H"> >+ <connections> >+ <action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="aJh-i4-bef"/> >+ <menuItem title="Page Setupâ¦" keyEquivalent="P" id="qIS-W8-SiK"> >+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/> >+ <connections> >+ <action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Printâ¦" keyEquivalent="p" id="aTl-1u-JFS"> >+ <connections> >+ <action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Edit" id="5QF-Oa-p0T"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Edit" id="W48-6f-4Dl"> >+ <items> >+ <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg"> >+ <connections> >+ <action selector="undo:" target="Ady-hI-5gd" id="M6e-cu-g7V"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam"> >+ <connections> >+ <action selector="redo:" target="Ady-hI-5gd" id="oIA-Rs-6OD"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/> >+ <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG"> >+ <connections> >+ <action selector="cut:" target="Ady-hI-5gd" id="YJe-68-I9s"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU"> >+ <connections> >+ <action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL"> >+ <connections> >+ <action selector="paste:" target="Ady-hI-5gd" id="UvS-8e-Qdg"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk"> >+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> >+ <connections> >+ <action selector="pasteAsPlainText:" target="Ady-hI-5gd" id="cEh-KX-wJQ"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Delete" id="pa3-QI-u2k"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m"> >+ <connections> >+ <action selector="selectAll:" target="Ady-hI-5gd" id="VNm-Mi-diN"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/> >+ <menuItem title="Find" id="4EN-yA-p0u"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Find" id="1b7-l0-nxx"> >+ <items> >+ <menuItem title="Findâ¦" tag="1" keyEquivalent="f" id="Xz5-n4-O0W"> >+ <connections> >+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="cD7-Qs-BN4"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Find and Replaceâ¦" tag="12" keyEquivalent="f" id="YEy-JH-Tfz"> >+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> >+ <connections> >+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="WD3-Gg-5AJ"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye"> >+ <connections> >+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="NDo-RZ-v9R"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV"> >+ <connections> >+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="HOh-sY-3ay"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt"> >+ <connections> >+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="U76-nv-p5D"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd"> >+ <connections> >+ <action selector="centerSelectionInVisibleArea:" target="Ady-hI-5gd" id="IOG-6D-g5B"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Spelling" id="3IN-sU-3Bg"> >+ <items> >+ <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI"> >+ <connections> >+ <action selector="showGuessPanel:" target="Ady-hI-5gd" id="vFj-Ks-hy3"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7"> >+ <connections> >+ <action selector="checkSpelling:" target="Ady-hI-5gd" id="fz7-VC-reM"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/> >+ <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleContinuousSpellChecking:" target="Ady-hI-5gd" id="7w6-Qz-0kB"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleGrammarChecking:" target="Ady-hI-5gd" id="muD-Qn-j4w"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleAutomaticSpellingCorrection:" target="Ady-hI-5gd" id="2lM-Qi-WAP"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Substitutions" id="9ic-FL-obx"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Substitutions" id="FeM-D8-WVr"> >+ <items> >+ <menuItem title="Show Substitutions" id="z6F-FW-3nz"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="orderFrontSubstitutionsPanel:" target="Ady-hI-5gd" id="oku-mr-iSq"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/> >+ <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleSmartInsertDelete:" target="Ady-hI-5gd" id="3IJ-Se-DZD"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Smart Quotes" id="hQb-2v-fYv"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleAutomaticQuoteSubstitution:" target="Ady-hI-5gd" id="ptq-xd-QOA"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Smart Dashes" id="rgM-f4-ycn"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleAutomaticDashSubstitution:" target="Ady-hI-5gd" id="oCt-pO-9gS"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Smart Links" id="cwL-P1-jid"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleAutomaticLinkDetection:" target="Ady-hI-5gd" id="Gip-E3-Fov"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Data Detectors" id="tRr-pd-1PS"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleAutomaticDataDetection:" target="Ady-hI-5gd" id="R1I-Nq-Kbl"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Text Replacement" id="HFQ-gK-NFA"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleAutomaticTextReplacement:" target="Ady-hI-5gd" id="DvP-Fe-Py6"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Transformations" id="2oI-Rn-ZJC"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Transformations" id="c8a-y6-VQd"> >+ <items> >+ <menuItem title="Make Upper Case" id="vmV-6d-7jI"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="uppercaseWord:" target="Ady-hI-5gd" id="sPh-Tk-edu"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Make Lower Case" id="d9M-CD-aMd"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="lowercaseWord:" target="Ady-hI-5gd" id="iUZ-b5-hil"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Capitalize" id="UEZ-Bs-lqG"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="capitalizeWord:" target="Ady-hI-5gd" id="26H-TL-nsh"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Speech" id="xrE-MZ-jX0"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Speech" id="3rS-ZA-NoH"> >+ <items> >+ <menuItem title="Start Speaking" id="Ynk-f8-cLZ"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="startSpeaking:" target="Ady-hI-5gd" id="654-Ng-kyl"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Stop Speaking" id="Oyz-dy-DGm"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="stopSpeaking:" target="Ady-hI-5gd" id="dX8-6p-jy9"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Format" id="jxT-CU-nIS"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Format" id="GEO-Iw-cKr"> >+ <items> >+ <menuItem title="Font" id="Gi5-1S-RQB"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq"> >+ <items> >+ <menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq"> >+ <connections> >+ <action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27"> >+ <connections> >+ <action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq"> >+ <connections> >+ <action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S"> >+ <connections> >+ <action selector="underline:" target="Ady-hI-5gd" id="FYS-2b-JAY"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/> >+ <menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL"> >+ <connections> >+ <action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST"> >+ <connections> >+ <action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/> >+ <menuItem title="Kern" id="jBQ-r6-VK2"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Kern" id="tlD-Oa-oAM"> >+ <items> >+ <menuItem title="Use Default" id="GUa-eO-cwY"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="useStandardKerning:" target="Ady-hI-5gd" id="6dk-9l-Ckg"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Use None" id="cDB-IK-hbR"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="turnOffKerning:" target="Ady-hI-5gd" id="U8a-gz-Maa"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Tighten" id="46P-cB-AYj"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="tightenKerning:" target="Ady-hI-5gd" id="hr7-Nz-8ro"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Loosen" id="ogc-rX-tC1"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="loosenKerning:" target="Ady-hI-5gd" id="8i4-f9-FKE"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Ligatures" id="o6e-r0-MWq"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Ligatures" id="w0m-vy-SC9"> >+ <items> >+ <menuItem title="Use Default" id="agt-UL-0e3"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="useStandardLigatures:" target="Ady-hI-5gd" id="7uR-wd-Dx6"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Use None" id="J7y-lM-qPV"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="turnOffLigatures:" target="Ady-hI-5gd" id="iX2-gA-Ilz"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Use All" id="xQD-1f-W4t"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="useAllLigatures:" target="Ady-hI-5gd" id="KcB-kA-TuK"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Baseline" id="OaQ-X3-Vso"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Baseline" id="ijk-EB-dga"> >+ <items> >+ <menuItem title="Use Default" id="3Om-Ey-2VK"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="unscript:" target="Ady-hI-5gd" id="0vZ-95-Ywn"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Superscript" id="Rqc-34-cIF"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="superscript:" target="Ady-hI-5gd" id="3qV-fo-wpU"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Subscript" id="I0S-gh-46l"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="subscript:" target="Ady-hI-5gd" id="Q6W-4W-IGz"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Raise" id="2h7-ER-AoG"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="raiseBaseline:" target="Ady-hI-5gd" id="4sk-31-7Q9"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Lower" id="1tx-W0-xDw"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="lowerBaseline:" target="Ady-hI-5gd" id="OF1-bc-KW4"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/> >+ <menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk"> >+ <connections> >+ <action selector="orderFrontColorPanel:" target="Ady-hI-5gd" id="mSX-Xz-DV3"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/> >+ <menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD"> >+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> >+ <connections> >+ <action selector="copyFont:" target="Ady-hI-5gd" id="GJO-xA-L4q"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH"> >+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> >+ <connections> >+ <action selector="pasteFont:" target="Ady-hI-5gd" id="JfD-CL-leO"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Text" id="Fal-I4-PZk"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Text" id="d9c-me-L2H"> >+ <items> >+ <menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1"> >+ <connections> >+ <action selector="alignLeft:" target="Ady-hI-5gd" id="zUv-R1-uAa"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb"> >+ <connections> >+ <action selector="alignCenter:" target="Ady-hI-5gd" id="spX-mk-kcS"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Justify" id="J5U-5w-g23"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="alignJustified:" target="Ady-hI-5gd" id="ljL-7U-jND"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4"> >+ <connections> >+ <action selector="alignRight:" target="Ady-hI-5gd" id="r48-bG-YeY"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/> >+ <menuItem title="Writing Direction" id="H1b-Si-o9J"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd"> >+ <items> >+ <menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ </menuItem> >+ <menuItem id="YGs-j5-SAR"> >+ <string key="title"> Default</string> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="makeBaseWritingDirectionNatural:" target="Ady-hI-5gd" id="qtV-5e-UBP"/> >+ </connections> >+ </menuItem> >+ <menuItem id="Lbh-J2-qVU"> >+ <string key="title"> Left to Right</string> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="makeBaseWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="S0X-9S-QSf"/> >+ </connections> >+ </menuItem> >+ <menuItem id="jFq-tB-4Kx"> >+ <string key="title"> Right to Left</string> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="makeBaseWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="5fk-qB-AqJ"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="swp-gr-a21"/> >+ <menuItem title="Selection" enabled="NO" id="cqv-fj-IhA"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ </menuItem> >+ <menuItem id="Nop-cj-93Q"> >+ <string key="title"> Default</string> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="makeTextWritingDirectionNatural:" target="Ady-hI-5gd" id="lPI-Se-ZHp"/> >+ </connections> >+ </menuItem> >+ <menuItem id="BgM-ve-c93"> >+ <string key="title"> Left to Right</string> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="makeTextWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="caW-Bv-w94"/> >+ </connections> >+ </menuItem> >+ <menuItem id="RB4-Sm-HuC"> >+ <string key="title"> Right to Left</string> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="makeTextWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="EXD-6r-ZUu"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/> >+ <menuItem title="Show Ruler" id="vLm-3I-IUL"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleRuler:" target="Ady-hI-5gd" id="FOx-HJ-KwY"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5"> >+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> >+ <connections> >+ <action selector="copyRuler:" target="Ady-hI-5gd" id="71i-fW-3W2"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI"> >+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> >+ <connections> >+ <action selector="pasteRuler:" target="Ady-hI-5gd" id="cSh-wd-qM2"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="View" id="H8h-7b-M4v"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="View" id="HyV-fh-RgO"> >+ <items> >+ <menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5"> >+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> >+ <connections> >+ <action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Customize Toolbarâ¦" id="1UK-8n-QPP"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/> >+ <menuItem title="Reset viewport" keyEquivalent="R" id="0RE-Am-xSc"> >+ <connections> >+ <action selector="resetViewport:" target="Ady-hI-5gd" id="PdF-ub-35F"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE"> >+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> >+ <connections> >+ <action selector="toggleSourceList:" target="Ady-hI-5gd" id="iwa-gc-5KM"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa"> >+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> >+ <connections> >+ <action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Window" id="aUF-d1-5bR"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo"> >+ <items> >+ <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV"> >+ <connections> >+ <action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Zoom" id="R4o-n2-Eq4"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/> >+ <menuItem title="Bring All to Front" id="LE2-aR-0XJ"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Help" id="wpr-3q-Mcd"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ"> >+ <items> >+ <menuItem title="WHLSL Tests Help" keyEquivalent="?" id="FKE-Sm-Kum"> >+ <connections> >+ <action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ </items> >+ </menu> >+ <connections> >+ <outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/> >+ </connections> >+ </application> >+ <customObject id="Voe-Tx-rLC" customClass="AppDelegate"/> >+ <customObject id="YLy-65-1bz" customClass="NSFontManager"/> >+ <customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> >+ </objects> >+ <point key="canvasLocation" x="75" y="0.0"/> >+ </scene> >+ <!--Window Controller--> >+ <scene sceneID="R2V-B0-nI4"> >+ <objects> >+ <windowController id="B8D-0N-5wS" sceneMemberID="viewController"> >+ <window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA"> >+ <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> >+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> >+ <rect key="contentRect" x="196" y="240" width="480" height="270"/> >+ <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/> >+ <connections> >+ <outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/> >+ </connections> >+ </window> >+ <connections> >+ <segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/> >+ </connections> >+ </windowController> >+ <customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> >+ </objects> >+ <point key="canvasLocation" x="75" y="250"/> >+ </scene> >+ <!--View Controller--> >+ <scene sceneID="hIz-AP-VOD"> >+ <objects> >+ <viewController id="XfG-lQ-9wD" customClass="ViewController" sceneMemberID="viewController"> >+ <view key="view" wantsLayer="YES" id="m2S-Jp-Qdl"> >+ <rect key="frame" x="0.0" y="0.0" width="1256" height="439"/> >+ <autoresizingMask key="autoresizingMask"/> >+ <subviews> >+ <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zWA-us-Fkf"> >+ <rect key="frame" x="14" y="13" width="90" height="32"/> >+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> >+ <buttonCell key="cell" type="push" title="Compile" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="1K5-PN-nLE"> >+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> >+ <font key="font" metaFont="system"/> >+ <string key="keyEquivalent">r</string> >+ <modifierMask key="keyEquivalentModifierMask" command="YES"/> >+ </buttonCell> >+ <connections> >+ <action selector="compileClicked:" target="XfG-lQ-9wD" id="1FR-KE-nty"/> >+ </connections> >+ </button> >+ <scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="egF-8L-cI6"> >+ <rect key="frame" x="20" y="61" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/> >+ <clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="HW8-L7-3PX"> >+ <rect key="frame" x="0.0" y="0.0" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> >+ <subviews> >+ <textView ambiguous="YES" importsGraphics="NO" richText="NO" verticallyResizable="YES" findStyle="bar" smartInsertDelete="YES" id="pRP-9d-8nB"> >+ <rect key="frame" x="0.0" y="0.0" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> >+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/> >+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> >+ <size key="minSize" width="400" height="358"/> >+ <size key="maxSize" width="1317" height="10000000"/> >+ <attributedString key="textStorage"> >+ <fragment content="WHLSLâ¨TextView"> >+ <attributes> >+ <color key="NSColor" name="textColor" catalog="System" colorSpace="catalog"/> >+ <font key="NSFont" size="12" name="Menlo-Regular"/> >+ <paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/> >+ </attributes> >+ </fragment> >+ </attributedString> >+ <color key="insertionPointColor" name="textColor" catalog="System" colorSpace="catalog"/> >+ </textView> >+ </subviews> >+ </clipView> >+ <scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="1T4-PL-dI4"> >+ <rect key="frame" x="384" y="0.0" width="16" height="358"/> >+ <autoresizingMask key="autoresizingMask"/> >+ </scroller> >+ </scrollView> >+ <scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tuu-uc-Dxg"> >+ <rect key="frame" x="428" y="61" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/> >+ <clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="1Us-pH-zAs"> >+ <rect key="frame" x="0.0" y="0.0" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> >+ <subviews> >+ <textView ambiguous="YES" importsGraphics="NO" richText="NO" verticallyResizable="YES" findStyle="bar" smartInsertDelete="YES" id="82n-yv-OVo"> >+ <rect key="frame" x="0.0" y="0.0" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> >+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/> >+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> >+ <size key="minSize" width="400" height="358"/> >+ <size key="maxSize" width="1391" height="10000000"/> >+ <color key="insertionPointColor" name="textColor" catalog="System" colorSpace="catalog"/> >+ </textView> >+ </subviews> >+ </clipView> >+ <scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="ev9-xr-MSP"> >+ <rect key="frame" x="384" y="0.0" width="16" height="358"/> >+ <autoresizingMask key="autoresizingMask"/> >+ </scroller> >+ </scrollView> >+ <customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9FG-iv-6pr" customClass="CustomMetalView"> >+ <rect key="frame" x="836" y="61" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> >+ </customView> >+ <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="aSY-2r-vMu"> >+ <rect key="frame" x="106" y="20" width="1132" height="18"/> >+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> >+ <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="JK0-3q-epW"> >+ <font key="font" metaFont="system"/> >+ <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> >+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> >+ </textFieldCell> >+ </textField> >+ </subviews> >+ </view> >+ <connections> >+ <outlet property="debugLabel" destination="aSY-2r-vMu" id="hSC-9N-nj9"/> >+ <outlet property="metalView" destination="9FG-iv-6pr" id="d1K-E7-8zL"/> >+ <outlet property="mslTextView" destination="82n-yv-OVo" id="eoE-3h-vhV"/> >+ <outlet property="mslViewContainer" destination="tuu-uc-Dxg" id="Z3D-cP-qY2"/> >+ <outlet property="whlslTextView" destination="pRP-9d-8nB" id="Muf-bo-NKk"/> >+ <outlet property="whlslViewContainer" destination="egF-8L-cI6" id="DIG-j2-2tb"/> >+ </connections> >+ </viewController> >+ <customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> >+ </objects> >+ <point key="canvasLocation" x="-332" y="911.5"/> >+ </scene> >+ </scenes> >+</document> >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.h >new file mode 100644 >index 0000000000000000000000000000000000000000..3d09cfbed5678372ebbefa2c5b8272bce2fab9fe >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.h >@@ -0,0 +1,22 @@ >+// >+// CompileResult.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 7/12/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface CompileResult : NSObject >+ >+- (instancetype)initWithMetalSource:(NSString*)source functionNameMap:(NSDictionary<NSString*,NSArray<NSString*>*>*)map; >+ >+@property (readonly) NSString *source; >+@property (readonly) NSDictionary<NSString*, NSString*>* functionNameMap; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.m >new file mode 100644 >index 0000000000000000000000000000000000000000..e207bb437cc05044be3bc2ef6e5ae0dc0bb8dbff >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.m >@@ -0,0 +1,29 @@ >+// >+// CompileResult.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 7/12/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "CompileResult.h" >+ >+@interface CompileResult () >+ >+@property NSString *source; >+@property NSDictionary<NSString*, NSString*>* functionNameMap; >+ >+@end >+ >+@implementation CompileResult >+ >+- (instancetype)initWithMetalSource:(NSString *)source functionNameMap:(NSDictionary<NSString *, NSString *> *)map >+{ >+ if (self = [super init]) { >+ self.source = source; >+ self.functionNameMap = map; >+ } >+ return self; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.h >new file mode 100644 >index 0000000000000000000000000000000000000000..cd66b74f5f4060b3a292db890cd0e1427df29835 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.h >@@ -0,0 +1,25 @@ >+// >+// Compiler.h >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+@import Foundation; >+@import JavaScriptCore; >+ >+#import "CompileResult.h" >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface Compiler : NSObject >+ >+- (CompileResult*)compileWhlslToMetal:(NSString*)whlslSource error:(NSError**)error; >+ >+- (void)lexWhlsl:(NSMutableAttributedString *)msl withPreferredFontSize:(CGFloat)fontSize; >+- (void)lexMsl:(NSMutableAttributedString*)msl withPreferredFontSize:(CGFloat)fontSize; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.m >new file mode 100644 >index 0000000000000000000000000000000000000000..d744371e83a01adcf1486811247782f04a799f7b >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.m >@@ -0,0 +1,130 @@ >+// >+// Compiler.m >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "Compiler.h" >+ >+@import Cocoa; >+@import JavaScriptCore; >+ >+@interface Compiler () >+ >+@property JSContext* context; >+ >+@end >+ >+@implementation Compiler >+ >+- (instancetype)init >+{ >+ self = [super init]; >+ if (self) { >+ self.context = [[JSContext alloc] init]; >+ [self loadScripts]; >+ } >+ return self; >+} >+ >+- (void)loadScripts >+{ >+ __weak JSContext* weakContext = self.context; >+ __block NSMutableSet<NSString*>* alreadyLoaded = [NSMutableSet new]; >+ void (^loadFunction)(NSString *) = ^void(NSString* name) { >+ if (![alreadyLoaded containsObject:name]) { >+ NSString* path = [[NSBundle mainBundle] pathForResource:[name stringByDeletingPathExtension] ofType:@"js"]; >+ NSError* loadError = nil; >+ NSString* src = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&loadError]; >+ if (loadError) >+ NSLog(@"Loading %@ failed: %@", name, loadError.localizedDescription); >+ else { >+ [weakContext evaluateScript:src]; >+ [alreadyLoaded addObject:name]; >+ } >+ } else >+ NSLog(@"Attempting to load duplicate file %@", name); >+ }; >+ self.context[@"load"] = loadFunction; >+ >+ loadFunction(@"All.js"); >+ loadFunction(@"compiler.js"); >+} >+ >+- (CompileResult*)compileWhlslToMetal:(NSString *)whlslSource error:(NSError * _Nullable __autoreleasing *)error >+{ >+ JSValue *compileFunction = [self.context objectForKeyedSubscript:@"whlslToMsl"]; >+ if (compileFunction) { >+ JSValue * result = [compileFunction callWithArguments:@[whlslSource]]; >+ if (result) { >+ if ([result hasProperty:@"_error"] && [result hasProperty:@"_metalShaderLanguageSource"] && [result hasProperty:@"_originalFunctionNameToMangledNames"]) { >+ if ([[result valueForProperty:@"_error"] isNull]) { >+ NSString *src = [[result valueForProperty:@"_metalShaderLanguageSource"] toString]; >+ NSDictionary *map = [[result valueForProperty:@"_originalFunctionNameToMangledNames"] toDictionary]; >+ return [[CompileResult alloc] initWithMetalSource:src functionNameMap:map]; >+ } >+ >+ *error = [NSError errorWithDomain:@"WhlslCompiler" code:1 userInfo:@{ NSLocalizedDescriptionKey: [[result valueForProperty:@"_error"] toString]}]; >+ return nil; >+ } >+ >+ *error = [NSError errorWithDomain:@"WhlslCompiler" code:2 userInfo:@{ NSLocalizedDescriptionKey: @"Keys not present in result" }]; >+ return nil; >+ } >+ >+ *error = [NSError errorWithDomain:@"WhlslCompiler" code:3 userInfo:@{ NSLocalizedDescriptionKey: @"Compilation failed" }]; >+ return nil; >+ >+ } >+ >+ *error = [NSError errorWithDomain:@"WhlslCompiler" code:4 userInfo:@{ NSLocalizedDescriptionKey: @"Didn't find compilation function" }]; >+ return nil; >+} >+ >+- (void)lexWhlsl:(NSMutableAttributedString *)whlsl withPreferredFontSize:(CGFloat)fontSize >+{ >+ [self applyStyleInformationWithFunction:@"lexWHLSL" toAttributedString:whlsl withPreferredFontSize:fontSize]; >+} >+ >+- (void)lexMsl:(NSMutableAttributedString *)msl withPreferredFontSize:(CGFloat)fontSize >+{ >+ [self applyStyleInformationWithFunction:@"lexMsl" toAttributedString:msl withPreferredFontSize:fontSize]; >+} >+ >+- (void)applyStyleInformationWithFunction:(NSString*)functionName toAttributedString:(NSMutableAttributedString*)attrString withPreferredFontSize:(CGFloat)fontSize >+{ >+ if (!attrString) >+ return; >+ >+ JSValue *lexFunction = [self.context objectForKeyedSubscript:functionName]; >+ if (lexFunction) { >+ JSValue *result = [lexFunction callWithArguments:@[ attrString.string ]]; >+ if (result) { >+ [attrString setAttributes:@{} range:NSMakeRange(0, attrString.length)]; >+ >+ for (NSDictionary* value in result.toArray) { >+ NSUInteger startIndex = [(NSNumber*)[value objectForKeyedSubscript:@"_startIndex"] unsignedIntegerValue]; >+ NSUInteger length = [(NSString*)[value objectForKeyedSubscript:@"_src"] length]; >+ NSRange range = NSMakeRange(startIndex, length); >+ NSString *style = [value objectForKeyedSubscript:@"_type"]; >+ >+ if ([style isEqualToString:@"comment"]) >+ [attrString setAttributes:@{ NSForegroundColorAttributeName: [NSColor colorWithWhite:158.0 / 255 alpha:1], NSFontAttributeName: [NSFont fontWithName:@"Menlo" size:fontSize] } range:range]; >+ else if ([style isEqualToString:@"directive"]) >+ [attrString setAttributes:@{ NSForegroundColorAttributeName: [NSColor colorWithDeviceRed:252.0 / 255 green:143.0 / 255 blue:63.0 / 255 alpha:1], NSFontAttributeName: [NSFont fontWithName:@"Menlo" size:fontSize] } range:range]; >+ else if ([style isEqualToString:@"literal"]) >+ [attrString setAttributes:@{ NSForegroundColorAttributeName: [NSColor colorWithDeviceRed:150.0 / 255 green:134.0 / 255 blue:245.0 / 255 alpha:1], NSFontAttributeName: [NSFont fontWithName:@"Menlo" size:fontSize]} range:range]; >+ else if ([style isEqualToString:@"type"] || [style isEqualToString:@"keyword"]) >+ [attrString setAttributes:@{ NSForegroundColorAttributeName: [NSColor colorWithDeviceRed:253.0 / 255 green:95.0 / 255 blue:162.0 / 255 alpha:1], NSFontAttributeName: [NSFont fontWithName:@"Menlo" size:fontSize]} range:range]; >+ else >+ [attrString setAttributes:@{ NSForegroundColorAttributeName: [NSColor whiteColor], NSFontAttributeName: [NSFont fontWithName:@"Menlo" size:fontSize] } range:range]; >+ } >+ } else >+ NSLog(@"Lexing failed"); >+ } else >+ NSLog(@"No lex function"); >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.h >new file mode 100644 >index 0000000000000000000000000000000000000000..25771b57e3bcc24b3aa6853bab86d1551004c4f5 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.h >@@ -0,0 +1,28 @@ >+// >+// CustomMetalView.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+#import <MetalKit/MetalKit.h> >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@class CustomMetalView; >+ >+@protocol CustomMetalViewDelegate <NSObject> >+ >+- (void)customMetalView:(CustomMetalView*)metalView scrolledDeltaX:(CGFloat)deltaX deltaY:(CGFloat)deltaY; >+ >+@end >+ >+@interface CustomMetalView : MTKView >+ >+@property id<CustomMetalViewDelegate> scrollDelegate; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.m >new file mode 100644 >index 0000000000000000000000000000000000000000..9bf02a5b1514e6e3f3a74f0d1984539b21a04f47 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.m >@@ -0,0 +1,18 @@ >+// >+// CustomMetalView.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "CustomMetalView.h" >+ >+@implementation CustomMetalView >+ >+- (void)scrollWheel:(NSEvent *)event >+{ >+ [self.scrollDelegate customMetalView:self scrolledDeltaX:event.deltaX deltaY:event.deltaY]; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Default.whlsl b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Default.whlsl >new file mode 100644 >index 0000000000000000000000000000000000000000..2419df7a0bb9ef7b8477ef029dfe89459417eb73 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Default.whlsl >@@ -0,0 +1,26 @@ >+struct VertexInput { >+ float2 position; >+ float2 uv; >+} >+ >+struct VertexOutput { >+ float4 wsl_Position; >+ float4 color; >+} >+ >+struct FragmentOutput { >+ float4 wsl_Color; >+} >+ >+vertex VertexOutput vertexShader(VertexInput vertexInput) { >+ VertexOutput result; >+ result.wsl_Position = float4(vertexInput.position, 0., 1.); >+ result.color = float4(vertexInput.uv, 0.0, 1.0); >+ return result; >+} >+ >+fragment FragmentOutput fragmentShader(VertexOutput stageIn) { >+ FragmentOutput result; >+ result.wsl_Color = stageIn.color; >+ return result; >+} >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Julia.whlsl b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Julia.whlsl >new file mode 100644 >index 0000000000000000000000000000000000000000..54bee30748181d2db81b52f0c1f2fd72b2925577 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Julia.whlsl >@@ -0,0 +1,103 @@ >+struct VertexInput { >+ float2 position; >+ float2 uv; >+} >+ >+struct VertexOutput { >+ float4 wsl_Position; >+ float2 uv; >+} >+ >+struct FragmentOutput { >+ float4 wsl_Color; >+} >+ >+vertex VertexOutput vertexShader(VertexInput vertexInput) { >+ VertexOutput result; >+ result.wsl_Position = float4(vertexInput.position, 0., 1.); >+ result.uv = vertexInput.uv; >+ return result; >+} >+ >+fragment FragmentOutput fragmentShader(VertexOutput stageIn) { >+ FragmentOutput result; >+ float m = julia(stageIn.uv); >+ float3 hot = float3(1, 1, 1); >+ float3 cold = float3(0, 1, 0.1); >+ float3 res = interpolate(cold, hot, m); >+ res = hslToRgb(res); >+ result.wsl_Color = float4(res, 1); >+ return result; >+} >+ >+float3 interpolate(float3 x, float3 y, float z) >+{ >+ float3 res; >+ res.x = x.x + (y.x - x.x) * z; >+ res.y = x.y + (y.y - x.y) * z; >+ res.z = x.z + (y.z - x.z) * z; >+ return res; >+} >+ >+float hueToRgb(float p, float q, float t) >+{ >+if(t < 0.0) t += 1.0; >+ if(t > 1.0) t -= 1.0; >+ if(t < 1.0/6.0) return p + (q - p) * 6.0 * t; >+ if(t < 1.0/2.0) return q; >+ if(t < 2.0/3.0) return p + (q - p) * (2.0/3.0 - t) * 6.0; >+ return p; >+} >+ >+float3 hslToRgb(float3 hsl) >+{ >+ float3 rgb; >+ float h = hsl.x; >+ float s = hsl.y; >+ float l = hsl.z; >+ if(s == 0){ >+ rgb = float3(l, l, l); >+ } else { >+ float q; >+ if (l < 0.5) { q = l * (1.0 + s); } else { q = l + s - l * s; } >+ float p = 2.0 * l - q; >+ rgb.x = hueToRgb(p, q, h + 1.0/3.0); >+ rgb.y = hueToRgb(p, q, h); >+ rgb.z = hueToRgb(p, q, h - 1.0/3.0); >+ } >+ >+ return rgb; >+ >+} >+ >+float julia(float2 uv) >+{ >+ float n = 2.0f; >+ float2 z; >+ float2 c; >+ float2 scale = float2(2, 2.9); >+ float2 center = float2(0.7, 0); >+ int iter = 100; >+ c.x = 1.3333 * (uv.x - 0.5) * scale.x - center.x; >+ c.y = (uv.y - 0.5) * scale.y - center.y; >+ z = c; >+ int i; >+ for (i = 0; i < iter; i++) { >+ float x = pow(z.x * z.x + z.y * z.y, n / 2.0) * cos(n * atan2(z.y, z.x)) + c.x; >+ float y = pow(z.x * z.x + z.y * z.y, n / 2.0) * sin(n * atan2(z.y, z.x)) + c.y; >+ >+ if(pow(x, 2.0f) + pow(y, 2.0f) > 16.0f) break; >+ z.x = x; >+ z.y = y; >+ } >+ float res; >+ if (i < iter) { >+ float log_zn = log( z.x*z.x + z.y*z.y ) / 2.0f; >+ float nu = log( log_zn / log(n) ) / log(2.0f); >+ res = (float(i) + 1 - nu) / float(iter); >+ } else { >+ res = 1; >+ } >+ return res; >+} >+ >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Mandelbrot.whlsl b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Mandelbrot.whlsl >new file mode 100644 >index 0000000000000000000000000000000000000000..521f0ced4060597803d0f867e6cc0d7729b4e91a >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Mandelbrot.whlsl >@@ -0,0 +1,98 @@ >+struct VertexInput { >+ float2 position; >+ float2 uv; >+} >+ >+struct VertexOutput { >+ float4 wsl_Position; >+ float2 uv; >+} >+ >+struct FragmentOutput { >+ float4 wsl_Color; >+} >+ >+vertex VertexOutput vertexShader(VertexInput vertexInput) { >+ VertexOutput result; >+ result.wsl_Position = float4(vertexInput.position, 0., 1.); >+ result.uv = vertexInput.uv; >+ return result; >+} >+ >+fragment FragmentOutput fragmentShader(VertexOutput stageIn) { >+ FragmentOutput result; >+ float m = mandelbrot(stageIn.uv); >+ float3 hot = float3(1, 1, 1); >+ float3 cold = float3(0, 1, 0.1); >+ float3 res = interpolate(cold, hot, m); >+ res = hslToRgb(res); >+ result.wsl_Color = float4(res, 1); >+ return result; >+} >+ >+float3 interpolate(float3 x, float3 y, float z) >+{ >+ float3 res; >+ res.x = x.x + (y.x - x.x) * z; >+ res.y = x.y + (y.y - x.y) * z; >+ res.z = x.z + (y.z - x.z) * z; >+ return res; >+} >+ >+float hueToRgb(float p, float q, float t) >+{ >+ if(t < 0.0) t += 1.0; >+ if(t > 1.0) t -= 1.0; >+ if(t < 1.0/6.0) return p + (q - p) * 6.0 * t; >+ if(t < 1.0/2.0) return q; >+ if(t < 2.0/3.0) return p + (q - p) * (2.0/3.0 - t) * 6.0; >+ return p; >+} >+ >+float3 hslToRgb(float3 hsl) >+{ >+ float3 rgb; >+ float h = hsl.x; >+ float s = hsl.y; >+ float l = hsl.z; >+ if(s == 0){ >+ rgb = float3(l, l, l); >+ } else { >+ float q; >+ if (l < 0.5) { q = l * (1.0 + s); } else { q = l + s - l * s; } >+ float p = 2.0 * l - q; >+ rgb.x = hueToRgb(p, q, h + 1.0/3.0); >+ rgb.y = hueToRgb(p, q, h); >+ rgb.z = hueToRgb(p, q, h - 1.0/3.0); >+ } >+ >+ return rgb; >+} >+ >+float mandelbrot(float2 uv) >+{ >+ float2 z; >+ float2 c = uv; >+ int iter = 100; >+ z = c; >+ int i; >+ for (i = 0; i < iter; i++) { >+ float x = (z.x * z.x - z.y * z.y) + c.x; >+ float y = (z.y * z.x + z.x * z.y) + c.y; >+ >+ if(pow(x, 2.0f) + pow(y, 2.0f) > 256.0) break; >+ z.x = x; >+ z.y = y; >+ } >+ float res; >+ if (i < iter) { >+ float log_zn = log( z.x*z.x + z.y*z.y ) / 2; >+ float nu = log( log_zn / log(2.0f) ) / log(2.0f); >+ res = (float(i) + 1 - nu) / float(iter); >+ } else { >+ res = 1; >+ } >+return res; >+} >+ >+ >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Info.plist b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Info.plist >new file mode 100644 >index 0000000000000000000000000000000000000000..01857f52dab33c6e0e0c3c3f28da60461a07a57e >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Info.plist >@@ -0,0 +1,32 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> >+<plist version="1.0"> >+<dict> >+ <key>CFBundleDevelopmentRegion</key> >+ <string>$(DEVELOPMENT_LANGUAGE)</string> >+ <key>CFBundleExecutable</key> >+ <string>$(EXECUTABLE_NAME)</string> >+ <key>CFBundleIconFile</key> >+ <string></string> >+ <key>CFBundleIdentifier</key> >+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> >+ <key>CFBundleInfoDictionaryVersion</key> >+ <string>6.0</string> >+ <key>CFBundleName</key> >+ <string>$(PRODUCT_NAME)</string> >+ <key>CFBundlePackageType</key> >+ <string>APPL</string> >+ <key>CFBundleShortVersionString</key> >+ <string>1.0</string> >+ <key>CFBundleVersion</key> >+ <string>1</string> >+ <key>LSMinimumSystemVersion</key> >+ <string>$(MACOSX_DEPLOYMENT_TARGET)</string> >+ <key>NSHumanReadableCopyright</key> >+ <string>Copyright © 2018 Apple, Inc. All rights reserved.</string> >+ <key>NSMainStoryboardFile</key> >+ <string>Main</string> >+ <key>NSPrincipalClass</key> >+ <string>NSApplication</string> >+</dict> >+</plist> >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Metal equivalents/Shaders.metal b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Metal equivalents/Shaders.metal >new file mode 100644 >index 0000000000000000000000000000000000000000..111c34b0fce9e72989632bd68f46afbf9fc39da2 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Metal equivalents/Shaders.metal >@@ -0,0 +1,179 @@ >+// >+// FlatColor.metal >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+// This file is a hand-modified version of the WHLSL compiler output >+ >+#include <metal_stdlib> >+using namespace metal; >+ >+struct VertexOutput { >+ float4 position [[position]]; >+ float2 uv; >+}; >+ >+struct VertexInput { >+ float2 position [[attribute(0)]]; >+ float2 uv [[attribute(1)]]; >+}; >+ >+struct FragmentOutput { >+ float4 color [[color(0)]]; >+}; >+ >+vertex VertexOutput flatColorVertexShader(VertexInput in [[stage_in]]) >+{ >+ VertexOutput out; >+ out.position = float4(in.position, 0, 1); >+ return out; >+} >+ >+fragment FragmentOutput flatColorFragmentShader(VertexOutput in [[stage_in]]) >+{ >+ FragmentOutput out; >+ out.color = float4(0, 1, 0, 1); >+ return out; >+} >+ >+float3 interpolate(float3 x, float3 y, float z); >+float hueToRgb(float p, float q, float t); >+float3 hslToRgb(float3 hsl); >+float mandelbrot(float2 uv); >+ >+vertex VertexOutput mandelbrotVertexShader(VertexInput vertexInput [[stage_in]]) { >+ VertexOutput result; >+ result.position = float4(vertexInput.position, 0., 1.); >+ result.uv = vertexInput.uv; >+ return result; >+} >+ >+fragment FragmentOutput mandelbrotFragmentShader(VertexOutput stageIn [[stage_in]]) { >+ FragmentOutput result; >+ const float m = mandelbrot(stageIn.uv); >+ const float3 hot = float3(1, 1, 1); >+ const float3 cold = float3(0, 1, 0.1); >+ const float3 res = hslToRgb(interpolate(cold, hot, m)); >+ result.color = float4(res, 1); >+ return result; >+} >+ >+float3 interpolate(float3 x, float3 y, float z) >+{ >+ float3 res; >+ res.x = x.x + (y.x - x.x) * z; >+ res.y = x.y + (y.y - x.y) * z; >+ res.z = x.z + (y.z - x.z) * z; >+ return res; >+} >+ >+float hueToRgb(float p, float q, float t) >+{ >+ if(t < 0.0) t += 1.0; >+ if(t > 1.0) t -= 1.0; >+ if(t < 1.0/6.0) return p + (q - p) * 6.0 * t; >+ if(t < 1.0/2.0) return q; >+ if(t < 2.0/3.0) return p + (q - p) * (2.0/3.0 - t) * 6.0; >+ return p; >+} >+ >+float3 hslToRgb(float3 hsl) >+{ >+ float3 rgb; >+ float h = hsl.x; >+ float s = hsl.y; >+ float l = hsl.z; >+ if(s == 0){ >+ rgb = float3(l, l, l); >+ } else { >+ float q; >+ if (l < 0.5) { q = l * (1.0 + s); } else { q = l + s - l * s; } >+ float p = 2.0 * l - q; >+ rgb.x = hueToRgb(p, q, h + 1.0/3.0); >+ rgb.y = hueToRgb(p, q, h); >+ rgb.z = hueToRgb(p, q, h - 1.0/3.0); >+ } >+ >+ return rgb; >+} >+ >+float mandelbrot(float2 uv) >+{ >+ float2 z; >+ float2 c = uv; >+ int iter = 100; >+ z = c; >+ int i; >+ for (i = 0; i < iter; i++) { >+ float x = (z.x * z.x - z.y * z.y) + c.x; >+ float y = (z.y * z.x + z.x * z.y) + c.y; >+ >+ if(pow(x, 2.0f) + pow(y, 2.0f) > 256.0) break; >+ z.x = x; >+ z.y = y; >+ } >+ float res; >+ if (i < iter) { >+ float log_zn = log( z.x*z.x + z.y*z.y ) / 2; >+ float nu = log( log_zn / log(2.0f) ) / log(2.0f); >+ res = (float(i) + 1 - nu) / float(iter); >+ } else { >+ res = 1; >+ } >+ return res; >+} >+ >+float julia(float2 uv); >+ >+vertex VertexOutput juliaVertexShader(VertexInput vertexInput [[stage_in]]) { >+ VertexOutput result; >+ result.position = float4(vertexInput.position, 0., 1.); >+ result.uv = vertexInput.uv; >+ return result; >+} >+ >+fragment FragmentOutput juliaFragmentShader(VertexOutput stageIn [[stage_in]]) { >+ FragmentOutput result; >+ float m = julia(stageIn.uv); >+ float3 hot = float3(1, 1, 1); >+ float3 cold = float3(0, 1, 0.1); >+ float3 res = interpolate(cold, hot, m); >+ res = hslToRgb(res); >+ result.color = float4(res, 1); >+ return result; >+} >+ >+float julia(float2 uv) >+{ >+ float n = 2.0f; >+ float2 z; >+ float2 c; >+ float2 scale = float2(2, 2.9); >+ float2 center = float2(0.7, 0); >+ int iter = 100; >+ c.x = 1.3333 * (uv.x - 0.5) * scale.x - center.x; >+ c.y = (uv.y - 0.5) * scale.y - center.y; >+ z = c; >+ int i; >+ for (i = 0; i < iter; i++) { >+ float x = pow(z.x * z.x + z.y * z.y, n / 2.0) * cos(n * atan2(z.y, z.x)) + c.x; >+ float y = pow(z.x * z.x + z.y * z.y, n / 2.0) * sin(n * atan2(z.y, z.x)) + c.y; >+ >+ if(pow(x, 2.0f) + pow(y, 2.0f) > 16.0f) break; >+ z.x = x; >+ z.y = y; >+ } >+ float res; >+ if (i < iter) { >+ float log_zn = log( z.x*z.x + z.y*z.y ) / 2.0f; >+ float nu = log( log_zn / log(n) ) / log(2.0f); >+ res = (float(i) + 1 - nu) / float(iter); >+ } else { >+ res = 1; >+ } >+ return res; >+} >+ >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.h >new file mode 100644 >index 0000000000000000000000000000000000000000..54e4e08d3897fdca7a34ffeecd3f02b8bbd43629 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.h >@@ -0,0 +1,26 @@ >+// >+// OffscreenRenderer.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 7/11/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "Renderer.h" >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface OffscreenRenderer : Renderer >+ >+@property MTLPixelFormat outputPixelFormat; >+ >+- (void)setLibrary:(id<MTLLibrary>)library vertexShaderName:(NSString*)vertexShader fragmentShaderName:(NSString*)fragmentShaderName; >+- (void)readTextureDataToBuffer:(uint8_t*)buffer bytesPerRow:(NSUInteger)bytesPerRow; >+ >+- (int)intValue; >+- (unsigned int)uintValue; >+- (float)floatValue; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.m >new file mode 100644 >index 0000000000000000000000000000000000000000..95f7c4f7f982de11c763305b89f268a7b3e37c6b >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.m >@@ -0,0 +1,87 @@ >+// >+// OffscreenRenderer.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 7/11/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "OffscreenRenderer.h" >+ >+@interface OffscreenRenderer () >+{ >+ id<MTLTexture> _outputTexture; >+} >+ >+@end >+ >+@implementation OffscreenRenderer >+ >+- (void)setLibrary:(id<MTLLibrary>)library vertexShaderName:(NSString*)vertexShader fragmentShaderName:(NSString*)fragmentShaderName >+{ >+ [super setLibrary:library vertexShaderName:vertexShader fragmentShaderName:fragmentShaderName pixelFormat:self.outputPixelFormat]; >+} >+ >+- (void)setTargetWidth:(NSUInteger)width setTargetHeight:(NSUInteger)height >+{ >+ [super setTargetWidth:width setTargetHeight:height]; >+ MTLTextureDescriptor *outputDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:self.outputPixelFormat width:self.targetWidth height:self.targetHeight mipmapped:NO]; >+ outputDescriptor.usage = MTLTextureUsageRenderTarget; >+ outputDescriptor.storageMode = MTLStorageModeManaged; >+ _outputTexture = [self.device newTextureWithDescriptor:outputDescriptor]; >+} >+ >+- (MTLRenderPassDescriptor*)renderPassDescriptor >+{ >+ MTLRenderPassDescriptor *renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; >+ renderPassDescriptor.colorAttachments[0].texture = _outputTexture; >+ return renderPassDescriptor; >+} >+ >+- (void)configureCommandBufferBeforeCommit:(id<MTLCommandBuffer>)commandBuffer >+{ >+ id <MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder]; >+ [blitEncoder synchronizeResource:_outputTexture]; >+ [blitEncoder endEncoding]; >+} >+ >+- (void)readTextureDataToBuffer:(uint8_t *)buffer bytesPerRow:(NSUInteger)bytesPerRow >+{ >+ // The texture isn't mipmapped, so we use the default level of 0 >+ [_outputTexture getBytes:buffer bytesPerRow:bytesPerRow fromRegion:MTLRegionMake2D(0, 0, self.targetWidth, self.targetHeight) mipmapLevel:0]; >+} >+ >+- (int)intValue >+{ >+ // We always have 4 bytes per pixel >+ NSUInteger length = self.targetWidth * self.targetHeight * 4; >+ uint8_t *buffer = calloc(length, sizeof(uint8_t)); >+ [self readTextureDataToBuffer:(uint8_t*)buffer bytesPerRow:4 * self.targetWidth]; >+ int intValue = ((int*)buffer)[0]; >+ free(buffer); >+ return intValue; >+} >+ >+- (unsigned int)uintValue >+{ >+ // We always have 4 bytes per pixel >+ NSUInteger length = self.targetWidth * self.targetHeight * 4; >+ uint8_t *buffer = calloc(length, sizeof(uint8_t)); >+ [self readTextureDataToBuffer:(uint8_t*)buffer bytesPerRow:4 * self.targetWidth]; >+ unsigned int uintValue = ((unsigned int*)buffer)[0]; >+ free(buffer); >+ return uintValue; >+} >+ >+- (float)floatValue >+{ >+ // We always have 4 bytes per pixel >+ NSUInteger length = self.targetWidth * self.targetHeight * 4; >+ uint8_t *buffer = calloc(length, sizeof(uint8_t)); >+ [self readTextureDataToBuffer:(uint8_t*)buffer bytesPerRow:4 * self.targetWidth]; >+ float floatValue = ((float*)buffer)[0]; >+ free(buffer); >+ return floatValue; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.h >new file mode 100644 >index 0000000000000000000000000000000000000000..14a3b02078725ffdc4a736f057c9c59353b5c11e >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.h >@@ -0,0 +1,25 @@ >+// >+// Renderer.h >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+ >+#import "Renderer.h" >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface OnscreenRenderer : Renderer<MTKViewDelegate> >+ >+- (instancetype)initWithView:(MTKView*)view device:(id<MTLDevice>)device; >+ >+@property (readonly) MTKView *view; >+ >+- (void)setShaderSource:(NSString*)source vertexShaderName:(NSString*)vertexShader fragmentShaderName:(NSString*)fragmentShader; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.m >new file mode 100644 >index 0000000000000000000000000000000000000000..f01b44f8e2c9624de15630aa41971b722c5085ca >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.m >@@ -0,0 +1,65 @@ >+// >+// Renderer.m >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "OnscreenRenderer.h" >+ >+#import <simd/simd.h> >+ >+@interface OnscreenRenderer () >+ >+@property MTKView *view; >+@property CGSize drawableSize; >+ >+@end >+ >+@implementation OnscreenRenderer >+ >+- (instancetype)initWithView:(MTKView *)view device:(nonnull id<MTLDevice>)device >+{ >+ self = [super initWithDevice:device]; >+ if (self) { >+ self.view = view; >+ self.view.delegate = self; >+ } >+ return self; >+} >+ >+- (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size >+{ >+ [self setTargetWidth:size.width setTargetHeight:size.height]; >+} >+ >+- (void)drawInMTKView:(MTKView *)view >+{ >+ [self draw]; >+} >+ >+- (MTLRenderPassDescriptor*)renderPassDescriptor >+{ >+ return self.view.currentRenderPassDescriptor; >+} >+ >+- (void)configureCommandBufferBeforeCommit:(id<MTLCommandBuffer>)commandBuffer >+{ >+ [commandBuffer presentDrawable:self.view.currentDrawable]; >+} >+ >+- (void)setShaderSource:(NSString *)source vertexShaderName:(NSString *)vertexShaderName fragmentShaderName:(NSString *)fragmentShaderName >+{ >+ MTLCompileOptions *compileOptions = [[MTLCompileOptions alloc] init]; >+ NSError *error = nil; >+ id<MTLLibrary> library = [self.device newLibraryWithSource:source options:compileOptions error:&error]; >+ if (!library && error) { >+ NSLog(@"Compile error: %@", error.localizedDescription); >+ return; >+ } >+ >+ [self setLibrary:library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName pixelFormat:self.view.colorPixelFormat]; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.h >new file mode 100644 >index 0000000000000000000000000000000000000000..e3ccfb7205c5909aa14835132d0c2e8d99d8b62d >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.h >@@ -0,0 +1,37 @@ >+// >+// Renderer.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 7/11/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+#import <MetalKit/MetalKit.h> >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface Renderer : NSObject >+ >+- (instancetype)initWithDevice:(id<MTLDevice>)device; >+ >+@property (nonatomic) simd_float3x3 transformMatrix; >+ >+@property (readonly) id<MTLDevice> device; >+ >+@property (readonly) NSUInteger targetWidth; >+@property (readonly) NSUInteger targetHeight; >+ >+- (void)setTargetWidth:(NSUInteger)width setTargetHeight:(NSUInteger)height; >+ >+- (void)setLibrary:(id<MTLLibrary>)library vertexShaderName:(NSString*)vertexShader fragmentShaderName:(NSString*)fragmentShaderName pixelFormat:(MTLPixelFormat)pixelFormat; >+ >+- (void)draw; >+ >+// Methods that can be overloaded to configure the render pipeline >+- (MTLRenderPassDescriptor*)renderPassDescriptor; >+- (void)configureCommandBufferBeforeCommit:(id<MTLCommandBuffer>)commandBuffer; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.m >new file mode 100644 >index 0000000000000000000000000000000000000000..b678160a6b2219c8cfcccdf35ffa13ccc17e2b10 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.m >@@ -0,0 +1,155 @@ >+// >+// Renderer.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 7/11/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "Renderer.h" >+ >+// This should mirror the structure that is used for the vertex shaders >+typedef struct { >+ vector_float2 position; >+ vector_float2 uv; >+} VertexStruct; >+ >+// A quad that fills the viewport >+static VertexStruct vertexData[] = >+{ >+ // 2D positions >+ { { -1.0, -1.0 }, { 0, 0 } }, >+ { { 1.0, -1.0 }, { 1, 0 } }, >+ { { -1.0, 1.0 }, { 0, 1 } }, >+ { { 1.0, 1.0 }, { 1, 1 } } >+}; >+ >+@interface Renderer () >+ >+@property id<MTLDevice> device; >+@property NSUInteger targetWidth; >+@property NSUInteger targetHeight; >+ >+@end >+ >+@implementation Renderer { >+ id<MTLCommandQueue> _commandQueue; >+ id<MTLLibrary> _library; >+ >+ MTLRenderPipelineDescriptor *_pipelineStateDescriptor; >+ >+ id<MTLRenderPipelineState> _pipelineState; >+} >+ >+- (instancetype)initWithDevice:(id<MTLDevice>)device >+{ >+ self = [super init]; >+ if (self) { >+ _device = device; >+ _commandQueue = [_device newCommandQueue]; >+ self.transformMatrix = matrix_identity_float3x3; >+ } >+ return self; >+} >+ >+- (void)setLibrary:(id<MTLLibrary>)library vertexShaderName:(NSString*)vertexShaderName fragmentShaderName:(NSString*)fragmentShaderName pixelFormat:(MTLPixelFormat)pixelFormat >+{ >+ _library = library; >+ id<MTLFunction> vertexFunction = [_library newFunctionWithName:vertexShaderName]; >+ id<MTLFunction> fragmentFunction = [_library newFunctionWithName:fragmentShaderName]; >+ >+ // Configure a pipeline descriptor that is used to create a pipeline state >+ _pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; >+ >+ MTLVertexDescriptor *vertexDescriptor = [MTLVertexDescriptor vertexDescriptor]; >+ vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; >+ vertexDescriptor.attributes[0].bufferIndex = 0; >+ vertexDescriptor.attributes[0].offset = 0; >+ >+ vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2; >+ vertexDescriptor.attributes[1].bufferIndex = 0; >+ vertexDescriptor.attributes[1].offset = offsetof(VertexStruct, uv); >+ >+ vertexDescriptor.layouts[0].stride = sizeof(VertexStruct); >+ vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex; >+ >+ _pipelineStateDescriptor.vertexDescriptor = vertexDescriptor; >+ >+ _pipelineStateDescriptor.label = @"Simple Pipeline"; >+ _pipelineStateDescriptor.vertexFunction = vertexFunction; >+ _pipelineStateDescriptor.fragmentFunction = fragmentFunction; >+ _pipelineStateDescriptor.colorAttachments[0].pixelFormat = pixelFormat; >+ >+ NSError *error = nil; >+ _pipelineState = [_device newRenderPipelineStateWithDescriptor:_pipelineStateDescriptor error:&error]; >+ >+ NSAssert(_pipelineState, @"Failed to created pipeline state: %@", error.localizedDescription); >+} >+ >+- (void)setTargetWidth:(NSUInteger)width setTargetHeight:(NSUInteger)height >+{ >+ _targetWidth = width; >+ _targetHeight = height; >+} >+ >+- (void)draw >+{ >+ if (!_pipelineState) >+ return; >+ >+ // Create a new command buffer for each render pass to the current drawable >+ id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer]; >+ commandBuffer.label = @"MyCommand"; >+ >+ MTLRenderPassDescriptor *renderPassDescriptor = [self renderPassDescriptor]; >+ >+ NSAssert(renderPassDescriptor, @"nil MTLRenderPassDescriptor"); >+ >+ renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(1, 1, 1, 1); >+ renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; >+ renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; >+ >+ // Create a render command encoder so we can render into something >+ id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; >+ renderEncoder.label = @"MyRenderEncoder"; >+ >+ [renderEncoder setViewport:(MTLViewport) { 0.0, 0.0, _targetWidth, _targetHeight, -1.0, 1.0 }]; >+ >+ [renderEncoder setRenderPipelineState:_pipelineState]; >+ >+ [renderEncoder setVertexBytes:vertexData length:sizeof(vertexData) atIndex:0]; >+ >+ [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; >+ >+ [renderEncoder endEncoding]; >+ >+ [self configureCommandBufferBeforeCommit:commandBuffer]; >+ >+ [commandBuffer commit]; >+ [commandBuffer waitUntilCompleted]; >+} >+ >+- (void)setTransformMatrix:(simd_float3x3)transformMatrix >+{ >+ _transformMatrix = transformMatrix; >+ simd_float3 v0 = matrix_multiply(_transformMatrix, vector3(0.0f, 0.0f, 1.0f)); >+ simd_float3 v1 = matrix_multiply(_transformMatrix, vector3(1.0f, 0.0f, 1.0f)); >+ simd_float3 v2 = matrix_multiply(_transformMatrix, vector3(0.0f, 1.0f, 1.0f)); >+ simd_float3 v3 = matrix_multiply(_transformMatrix, vector3(1.0f, 1.0f, 1.0f)); >+ >+ vertexData[0].uv = vector2(v0.x, v0.y); >+ vertexData[1].uv = vector2(v1.x, v1.y); >+ vertexData[2].uv = vector2(v2.x, v2.y); >+ vertexData[3].uv = vector2(v3.x, v3.y); >+} >+ >+- (MTLRenderPassDescriptor *)renderPassDescriptor >+{ >+ return nil; >+} >+ >+- (void)configureCommandBufferBeforeCommit:(id<MTLCommandBuffer>)commandBuffer >+{ >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.h >new file mode 100644 >index 0000000000000000000000000000000000000000..27bf88ff197a7ef7a0ff0641fdf57ae9f0f59b9b >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.h >@@ -0,0 +1,34 @@ >+// >+// TestCallArgument.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+ >+typedef enum : NSUInteger { >+ WHLSLTypeInt32, >+ WHLSLTypeUint32, >+ WHLSLTypeUint8, >+ WHLSLTypeFloat, >+ WHLSLTypeBool >+} WHLSLType; >+ >+NSString* WHLSLTypeString(WHLSLType type); >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface TestCallArgument : NSObject >+ >+- (instancetype)initWithValue:(NSNumber*)value type:(WHLSLType)type; >+ >+@property (readonly) NSNumber* value; >+@property (readonly) WHLSLType type; >+ >+- (NSString*)whlslSource; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.m >new file mode 100644 >index 0000000000000000000000000000000000000000..d302c2fd5de80d0f2ef1522f55cb85e09193b637 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.m >@@ -0,0 +1,63 @@ >+// >+// TestCallArgument.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "TestCallArgument.h" >+ >+NSString* WHLSLTypeString(WHLSLType type) >+{ >+ switch (type) { >+ case WHLSLTypeUint32: >+ return @"uint"; >+ case WHLSLTypeBool: >+ return @"bool"; >+ case WHLSLTypeFloat: >+ return @"float"; >+ case WHLSLTypeInt32: >+ return @"int"; >+ case WHLSLTypeUint8: >+ return @"uchar"; >+ default: >+ return nil; >+ } >+} >+ >+@interface TestCallArgument () >+ >+@property NSNumber* value; >+@property WHLSLType type; >+ >+@end >+ >+@implementation TestCallArgument >+ >+- (instancetype)initWithValue:(NSNumber *)value type:(WHLSLType)type >+{ >+ if (self = [super init]) { >+ self.value = value; >+ self.type = type; >+ } >+ return self; >+} >+ >+- (NSString*)whlslSource >+{ >+ switch (self.type) { >+ case WHLSLTypeUint8: >+ return [NSString stringWithFormat:@"uchar(%uu)", self.value.unsignedIntValue]; >+ case WHLSLTypeUint32: >+ return [NSString stringWithFormat:@"%uu", self.value.unsignedIntValue]; >+ case WHLSLTypeFloat: >+ return [NSString stringWithFormat:@"%f", self.value.floatValue]; >+ case WHLSLTypeBool: >+ return self.value.boolValue ? @"true" : @"false"; >+ case WHLSLTypeInt32: >+ return [NSString stringWithFormat:@"%d", self.value.intValue]; >+ } >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.h >new file mode 100644 >index 0000000000000000000000000000000000000000..eca11ffba46065c13670d292074dc72e790ccbe0 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.h >@@ -0,0 +1,34 @@ >+// >+// TestDescription.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+@import Foundation; >+#import "TestCallArgument.h" >+ >+@class TestFamily; >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface TestDescription : NSObject >+ >+- (instancetype)initWithFunctionName:(NSString*)functionName arguments:(NSArray<TestCallArgument*>*)arguments; >+ >+@property NSString* functionName; >+@property NSArray<TestCallArgument*>* arguments; >+ >+@property WHLSLType returnType; >+@property NSNumber* expectation; >+ >+@property (weak) TestFamily* testFamily; >+@property NSString* fragmentShaderName; >+ >+- (NSString*)callString; >+- (NSString*)fragmentShaderSource; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.m >new file mode 100644 >index 0000000000000000000000000000000000000000..986202167d065ec5fe92167fb539d6df9f0ae91d >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.m >@@ -0,0 +1,114 @@ >+// >+// TestDescription.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "TestDescription.h" >+ >+@implementation TestDescription >+ >+- (instancetype)initWithFunctionName:(NSString *)functionName arguments:(NSArray<TestCallArgument *> *)arguments >+{ >+ if (self = [super init]) { >+ self.functionName = functionName; >+ self.arguments = arguments; >+ } >+ return self; >+} >+ >+- (NSString*)callString >+{ >+ NSMutableString* string = [NSMutableString new]; >+ [string appendFormat:@"%@(", self.functionName]; >+ >+ BOOL first = YES; >+ for (TestCallArgument* argument in self.arguments) { >+ if (!first) >+ [string appendFormat:@", %@", argument.whlslSource]; >+ else >+ [string appendString:argument.whlslSource]; >+ first = NO; >+ } >+ >+ [string appendString:@")"]; >+ return string; >+} >+ >+- (NSString*)description >+{ >+ NSMutableString* string = [NSMutableString new]; >+ [string appendFormat:@"%@ %@(", WHLSLTypeString(self.returnType), self.functionName]; >+ BOOL first = YES; >+ for (TestCallArgument* argument in self.arguments) { >+ if (!first) >+ [string appendFormat:@", %@ %@", WHLSLTypeString(self.returnType), argument.whlslSource]; >+ else >+ [string appendFormat:@"%@ %@", WHLSLTypeString(self.returnType), argument.whlslSource]; >+ first = NO; >+ } >+ [string appendString:@")"]; >+ return string; >+} >+ >+- (NSString*)fragmentShaderSource >+{ >+ NSMutableString* string = [NSMutableString new]; >+ [string appendString:@"fragment "]; >+ switch (self.returnType) { >+ case WHLSLTypeUint8: >+ case WHLSLTypeUint32: >+ [string appendString:@"FragmentOutputUint"]; >+ break; >+ case WHLSLTypeInt32: >+ case WHLSLTypeBool: >+ [string appendString:@"FragmentOutputInt"]; >+ break; >+ case WHLSLTypeFloat: >+ [string appendString:@"FragmentOutputFloat"]; >+ break; >+ } >+ [string appendFormat:@" %@(VertexOutput stageIn)\n", self.fragmentShaderName]; >+ [string appendString:@"{\n"]; >+ >+ switch (self.returnType) { >+ case WHLSLTypeUint8: >+ case WHLSLTypeUint32: >+ [string appendString:@" FragmentOutputUint fragmentOutput;\n"]; >+ break; >+ case WHLSLTypeInt32: >+ case WHLSLTypeBool: >+ [string appendString:@" FragmentOutputInt fragmentOutput;\n"]; >+ break; >+ case WHLSLTypeFloat: >+ [string appendString:@" FragmentOutputFloat fragmentOutput;\n"]; >+ break; >+ } >+ >+ NSString * call = [self callString]; >+ >+ switch (self.returnType) { >+ case WHLSLTypeBool: >+ [string appendFormat:@" if(%@)\n", call]; >+ [string appendString:@" fragmentOutput.wsl_Color = 1;\n"]; >+ [string appendString:@" else\n"]; >+ [string appendString:@" fragmentOutput.wsl_Color = 0;\n"]; >+ break; >+ case WHLSLTypeUint8: >+ [string appendFormat:@" fragmentOutput.wsl_Color = uint(%@);\n", call]; >+ break; >+ case WHLSLTypeUint32: >+ case WHLSLTypeInt32: >+ case WHLSLTypeFloat: >+ [string appendFormat:@" fragmentOutput.wsl_Color = %@;\n", call]; >+ } >+ >+ [string appendString:@" return fragmentOutput;\n"]; >+ [string appendString:@"}\n"]; >+ >+ return string; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.h >new file mode 100644 >index 0000000000000000000000000000000000000000..aa5a8550a37aaeace13afd18f23494200f3ebd33 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.h >@@ -0,0 +1,31 @@ >+// >+// TestFamily.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+#import "TestCallArgument.h" >+#import "TestDescription.h" >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface TestFamily : NSObject >+ >+- (instancetype)initWithName:(NSString*)name source:(NSString*)source; >+ >+@property (readonly) NSString* name; >+@property (readonly) NSString* source; >+ >+- (void)addTestDescription:(TestDescription*)testDescription; >+- (NSArray<TestDescription*>*)testsForReturnType:(WHLSLType)type; >+ >+- (NSString*)fullTestSource; >+ >++ (NSArray<TestFamily*>*)allTests; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.m >new file mode 100644 >index 0000000000000000000000000000000000000000..f6b80272bb46d81e7561380a86aff710ca87324f >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.m >@@ -0,0 +1,164 @@ >+// >+// TestFamily.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "TestFamily.h" >+ >+@import JavaScriptCore; >+ >+@interface TestFamily () >+ >+@property NSString* name; >+@property NSString* source; >+@property NSUInteger fragmentShaderIndex; >+ >+@property NSMutableDictionary<NSNumber*, NSMutableArray<TestDescription*>*>* tests; >+ >+@end >+ >+@implementation TestFamily >+ >+- (instancetype)initWithName:(NSString *)name source:(NSString *)source >+{ >+ if (self = [super init]) { >+ self.name = name; >+ self.source = source; >+ self.tests = [NSMutableDictionary new]; >+ self.tests[@(WHLSLTypeUint8)] = [NSMutableArray new]; >+ self.tests[@(WHLSLTypeUint32)] = [NSMutableArray new]; >+ self.tests[@(WHLSLTypeInt32)] = [NSMutableArray new]; >+ self.tests[@(WHLSLTypeFloat)] = [NSMutableArray new]; >+ self.tests[@(WHLSLTypeBool)] = [NSMutableArray new]; >+ } >+ return self; >+} >+ >+- (void)addTestDescription:(TestDescription *)testDescription >+{ >+ [self.tests[@(testDescription.returnType)] addObject:testDescription]; >+ testDescription.testFamily = self; >+ testDescription.fragmentShaderName = [NSString stringWithFormat:@"%@%lu", self.name, self.fragmentShaderIndex++]; >+} >+ >+- (NSArray<TestDescription*>*)testsForReturnType:(WHLSLType)type >+{ >+ return self.tests[@(type)]; >+} >+ >+- (NSString*)fullTestSource >+{ >+ NSMutableString* source = [NSMutableString new]; >+ >+ [source appendString:[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"_Shared" ofType:@"whlsl"] encoding:NSUTF8StringEncoding error:nil]]; >+ [source appendString:self.source]; >+ [source appendString:@"\n"]; >+ >+ [self.tests enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull type, NSMutableArray<TestDescription *> * _Nonnull tests, BOOL * _Nonnull stop) { >+ for (TestDescription* testDescription in tests) { >+ [source appendFormat:@"%@\n", [testDescription fragmentShaderSource]]; >+ } >+ }]; >+ >+ return source; >+} >+ >++ (NSArray<TestFamily*>*)allTests >+{ >+ JSContext* compilerContext = [JSContext new]; >+ >+ NSString* testFile = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Test" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil]; >+ [compilerContext evaluateScript:testFile]; >+ >+ __block NSString *currentTestName = nil; >+ __block BOOL includeTest = YES; >+ >+ NSMutableArray<TestFamily*>* testFamilies = [NSMutableArray new]; >+ >+ // See the bottom of Test.js >+ compilerContext[@"runningInCocoaHost"] = [JSValue valueWithBool:YES inContext:compilerContext]; >+ >+ compilerContext[@"doPrep"] = ^TestFamily*(NSString* code) { >+ TestFamily* family = [[TestFamily alloc] initWithName:currentTestName source:code]; >+ [testFamilies addObject:family]; >+ includeTest = YES; >+ return family; >+ }; >+ >+ compilerContext.exceptionHandler = ^(JSContext *context, JSValue *exception) { >+ includeTest = NO; >+ }; >+ >+ compilerContext[@"makeInt"] = ^TestCallArgument*(TestFamily* program, NSNumber* number) { >+ return [[TestCallArgument alloc] initWithValue:number type:WHLSLTypeInt32]; >+ }; >+ >+ compilerContext[@"makeUint"] = ^TestCallArgument*(TestFamily* program, NSNumber* number) { >+ return [[TestCallArgument alloc] initWithValue:number type:WHLSLTypeUint32]; >+ }; >+ >+ compilerContext[@"makeUchar"] = ^TestCallArgument*(TestFamily* program, NSNumber* number) { >+ return [[TestCallArgument alloc] initWithValue:number type:WHLSLTypeUint8]; >+ }; >+ >+ compilerContext[@"makeBool"] = ^TestCallArgument*(TestFamily* program, NSNumber* number) { >+ return [[TestCallArgument alloc] initWithValue:number type:WHLSLTypeBool]; >+ }; >+ >+ compilerContext[@"makeFloat"] = ^TestCallArgument*(TestFamily* program, NSNumber* number) { >+ return [[TestCallArgument alloc] initWithValue:number type:WHLSLTypeFloat]; >+ }; >+ >+ compilerContext[@"callFunction"] = ^TestDescription*(TestFamily* program, NSString* functionName, NSArray* args) { >+ return [[TestDescription alloc] initWithFunctionName:functionName arguments:args]; >+ }; >+ >+ void(^addTest)(TestFamily*,TestDescription*,NSNumber*,WHLSLType) = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation, WHLSLType type) { >+ if (includeTest) { >+ testDesc.returnType = type; >+ testDesc.expectation = expectation; >+ [program addTestDescription:testDesc]; >+ } >+ }; >+ >+ compilerContext[@"checkInt"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) { >+ addTest(program, testDesc, expectation, WHLSLTypeInt32); >+ }; >+ >+ compilerContext[@"checkUint"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) { >+ addTest(program, testDesc, expectation, WHLSLTypeUint32); >+ }; >+ >+ compilerContext[@"checkFloat"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) { >+ addTest(program, testDesc, expectation, WHLSLTypeFloat); >+ }; >+ >+ compilerContext[@"checkBool"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) { >+ addTest(program, testDesc, expectation, WHLSLTypeBool); >+ }; >+ >+ compilerContext[@"checkUchar"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) { >+ addTest(program, testDesc, expectation, WHLSLTypeUint8); >+ }; >+ >+ // Deliberately not included >+ compilerContext[@"checkEnum"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) {}; >+ compilerContext[@"checkFail"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) {}; >+ compilerContext[@"checkLexerToken"] = ^void(NSString* token, NSNumber* id, NSString* name, NSString* tokenText) {}; >+ >+ JSValue* tests = [compilerContext evaluateScript:@"tests"]; >+ >+ NSArray<NSString*>* testNames = [tests.toDictionary.allKeys sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; >+ >+ for (currentTestName in testNames) { >+ JSValue* func = [tests objectForKeyedSubscript:currentTestName]; >+ [func callWithArguments:@[]]; >+ } >+ >+ return testFamilies; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.h >new file mode 100644 >index 0000000000000000000000000000000000000000..1589e3e8cd081018fa1f7dc3caab67812830f92e >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.h >@@ -0,0 +1,26 @@ >+// >+// TestFamilyRunner.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+#import "TestFamily.h" >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface TestFamilyRunner : NSObject >+ >+- (instancetype)initWithTestFamily:(TestFamily*)testFamily; >+ >+@property (readonly) TestFamily* testFamily; >+ >+- (BOOL)executeAllTests; >+ >++ (NSUInteger)executionCount; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.m >new file mode 100644 >index 0000000000000000000000000000000000000000..5786c46b84e0ab652c5c0b1a3f48f2f34cae9515 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.m >@@ -0,0 +1,197 @@ >+// >+// TestFamilyRunner.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "TestFamilyRunner.h" >+ >+#import "Compiler.h" >+#import "OffscreenRenderer.h" >+ >+static NSUInteger executionCount = 0; >+ >+@interface TestFamilyRunner () >+ >+@property TestFamily* testFamily; >+ >+@end >+ >+@implementation TestFamilyRunner >+ >+- (instancetype)initWithTestFamily:(TestFamily *)testFamily >+{ >+ if (self = [super init]) { >+ self.testFamily = testFamily; >+ } >+ return self; >+} >+ >++ (id<MTLDevice>)defaultTestingDevice >+{ >+ NSArray<id<MTLDevice>>* allDevices = MTLCopyAllDevices(); >+ for (id<MTLDevice> device in allDevices) { >+ if (device.isLowPower) >+ return device; >+ } >+ return MTLCreateSystemDefaultDevice(); >+} >+ >++ (OffscreenRenderer*)intOffscreenRenderer >+{ >+ static OffscreenRenderer* offscreenRenderer; >+ static dispatch_once_t onceToken; >+ dispatch_once(&onceToken, ^{ >+ offscreenRenderer = [[OffscreenRenderer alloc] initWithDevice:[TestFamilyRunner defaultTestingDevice]]; >+ [offscreenRenderer setOutputPixelFormat:MTLPixelFormatR32Sint]; >+ [offscreenRenderer setTargetWidth:1 setTargetHeight:1]; >+ }); >+ return offscreenRenderer; >+} >+ >++ (OffscreenRenderer*)uintOffscreenRenderer >+{ >+ static OffscreenRenderer* offscreenRenderer; >+ static dispatch_once_t onceToken; >+ dispatch_once(&onceToken, ^{ >+ offscreenRenderer = [[OffscreenRenderer alloc] initWithDevice:[TestFamilyRunner defaultTestingDevice]]; >+ [offscreenRenderer setOutputPixelFormat:MTLPixelFormatR32Uint]; >+ [offscreenRenderer setTargetWidth:1 setTargetHeight:1]; >+ }); >+ return offscreenRenderer; >+} >+ >++ (OffscreenRenderer*)floatOffscreenRenderer >+{ >+ static OffscreenRenderer* offscreenRenderer; >+ static dispatch_once_t onceToken; >+ dispatch_once(&onceToken, ^{ >+ offscreenRenderer = [[OffscreenRenderer alloc] initWithDevice:[TestFamilyRunner defaultTestingDevice]]; >+ [offscreenRenderer setOutputPixelFormat:MTLPixelFormatR32Float]; >+ [offscreenRenderer setTargetWidth:1 setTargetHeight:1]; >+ }); >+ return offscreenRenderer; >+} >+ >++ (Compiler*)compiler >+{ >+ static Compiler* compiler; >+ static dispatch_once_t onceToken; >+ dispatch_once(&onceToken, ^{ >+ compiler = [Compiler new]; >+ }); >+ return compiler; >+} >+ >+- (BOOL)executeAllTests >+{ >+ NSString* whlslSource = self.testFamily.fullTestSource; >+ NSError* whlslCompileError = nil; >+ CompileResult* result = [[TestFamilyRunner compiler] compileWhlslToMetal:whlslSource error:&whlslCompileError]; >+ if (!result) { >+ NSLog(@"[%@]: WHLSL Compile Error: %@", self.testFamily.name, whlslCompileError.localizedDescription); >+ return NO; >+ } >+ >+ NSLog(@"Compiled WHLSL"); >+ >+ id<MTLDevice> device = MTLCreateSystemDefaultDevice(); >+ NSError *error = nil; >+ id<MTLLibrary> library = [device newLibraryWithSource:result.source options:nil error:&error]; >+ if (!library) { >+ NSLog(@"[Library]: %@", error.localizedDescription); >+ return NO; >+ } >+ >+ if (error) >+ NSLog(@"[Library compiled with warnings]: %@", error.localizedDescription); >+ NSLog(@"Compiled metal"); >+ >+ BOOL status = YES; >+ >+ NSString *vertexShaderName = result.functionNameMap[@"vertexShader"]; >+ >+ OffscreenRenderer *intRenderer = [TestFamilyRunner intOffscreenRenderer]; >+ for (TestDescription* test in [self.testFamily testsForReturnType:WHLSLTypeInt32]) { >+ NSString* fragmentShaderName = result.functionNameMap[test.fragmentShaderName]; >+ [intRenderer setLibrary:library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName]; >+ [intRenderer draw]; >+ >+ int result = intRenderer.intValue; >+ if (result != test.expectation.intValue) { >+ NSLog(@"%@ = %d, should be %d", test, result, test.expectation.intValue); >+ status = NO; >+ } else >+ NSLog(@"%@ = %d", test, result); >+ executionCount++; >+ } >+ >+ OffscreenRenderer *uintRenderer = [TestFamilyRunner uintOffscreenRenderer]; >+ for (TestDescription* test in [self.testFamily testsForReturnType:WHLSLTypeUint32]) { >+ NSString* fragmentShaderName = result.functionNameMap[test.fragmentShaderName]; >+ [uintRenderer setLibrary:library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName]; >+ [uintRenderer draw]; >+ >+ unsigned int result = uintRenderer.uintValue; >+ if (result != test.expectation.unsignedIntValue) { >+ NSLog(@"%@ = %u, should be %u", test, result, test.expectation.unsignedIntValue); >+ status = NO; >+ } else >+ NSLog(@"%@ = %u", test, result); >+ executionCount++; >+ } >+ >+ for (TestDescription* test in [self.testFamily testsForReturnType:WHLSLTypeUint8]) { >+ NSString* fragmentShaderName = result.functionNameMap[test.fragmentShaderName]; >+ [uintRenderer setLibrary:library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName]; >+ [uintRenderer draw]; >+ >+ unsigned int result = uintRenderer.uintValue; >+ if (result != test.expectation.unsignedIntValue) { >+ NSLog(@"%@ = %u, should be %u", test, result, test.expectation.unsignedIntValue); >+ status = NO; >+ } else >+ NSLog(@"%@ = %u", test, result); >+ executionCount++; >+ } >+ >+ OffscreenRenderer *floatRenderer = [TestFamilyRunner floatOffscreenRenderer]; >+ for (TestDescription* test in [self.testFamily testsForReturnType:WHLSLTypeFloat]) { >+ NSString* fragmentShaderName = result.functionNameMap[test.fragmentShaderName]; >+ [floatRenderer setLibrary:library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName]; >+ [floatRenderer draw]; >+ >+ float result = floatRenderer.floatValue; >+ if (result != test.expectation.floatValue) { >+ NSLog(@"%@ = %f, should be %f", test, result, test.expectation.floatValue); >+ status = NO; >+ } else >+ NSLog(@"%@ = %f", test, result); >+ executionCount++; >+ } >+ >+ for (TestDescription* test in [self.testFamily testsForReturnType:WHLSLTypeBool]) { >+ NSString* fragmentShaderName = result.functionNameMap[test.fragmentShaderName]; >+ [intRenderer setLibrary:library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName]; >+ [intRenderer draw]; >+ >+ int result = intRenderer.intValue; >+ if (result != test.expectation.intValue) { >+ NSLog(@"%@ = %@, should be %@", test.fragmentShaderName, result ? @"true" : @"false", test.expectation.intValue ? @"true" : @"false"); >+ status = NO; >+ } else >+ NSLog(@"%@ = %@", test, result ? @"true" : @"false"); >+ executionCount++; >+ } >+ >+ return status; >+} >+ >++ (NSUInteger)executionCount >+{ >+ return executionCount; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.h >new file mode 100644 >index 0000000000000000000000000000000000000000..9f5fcfb69a1059476fe1660a1558e81cf381da72 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.h >@@ -0,0 +1,24 @@ >+// >+// ViewController.h >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Cocoa/Cocoa.h> >+#import <MetalKit/MetalKit.h> >+#import "CustomMetalView.h" >+ >+#import "Compiler.h" >+ >+@interface ViewController : NSViewController<NSGestureRecognizerDelegate, CustomMetalViewDelegate, NSTextViewDelegate> >+ >+@property (unsafe_unretained) IBOutlet NSTextView *whlslTextView; >+@property (unsafe_unretained) IBOutlet NSTextView *mslTextView; >+@property (weak) IBOutlet CustomMetalView *metalView; >+ >+@property Compiler *compiler; >+ >+@end >+ >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.m >new file mode 100644 >index 0000000000000000000000000000000000000000..fdeea1482435ff0f8247a74e06ea84ab40c399e3 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.m >@@ -0,0 +1,232 @@ >+// >+// ViewController.m >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "ViewController.h" >+#import "OnscreenRenderer.h" >+ >+@interface ViewController () >+ >+@property OnscreenRenderer *renderer; >+@property NSMagnificationGestureRecognizer *magnifyGesture; >+@property NSRotationGestureRecognizer *rotationGesture; >+@property (weak) IBOutlet NSTextField *debugLabel; >+@property (weak) IBOutlet NSScrollView *whlslViewContainer; >+@property (weak) IBOutlet NSScrollView *mslViewContainer; >+@property id<MTLLibrary> library; >+ >+@end >+ >+@implementation ViewController >+ >+- (void)viewDidLoad { >+ [super viewDidLoad]; >+ >+ [self loadFile:@"Default"]; >+ >+ self.compiler = [[Compiler alloc] init]; >+ >+ self.metalView.device = MTLCreateSystemDefaultDevice(); >+ self.renderer = [[OnscreenRenderer alloc] initWithView:self.metalView device:self.metalView.device]; >+ >+ self.magnifyGesture = [[NSMagnificationGestureRecognizer alloc] initWithTarget:self action:@selector(zoom:)]; >+ self.magnifyGesture.delegate = self; >+ [self.metalView addGestureRecognizer:self.magnifyGesture]; >+ >+ self.rotationGesture = [[NSRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotate:)]; >+ self.rotationGesture.delegate = self; >+ [self.metalView addGestureRecognizer:self.rotationGesture]; >+ >+ self.metalView.scrollDelegate = self; >+ >+ [self viewDidLayout]; >+ >+ self.whlslTextView.delegate = self; >+ >+ self.library = [self.renderer.device newDefaultLibraryWithBundle:[NSBundle mainBundle] error:nil]; >+} >+ >+- (void)viewDidAppear >+{ >+ [super viewDidAppear]; >+ [self updateHighlighting]; >+} >+ >+- (BOOL)gestureRecognizer:(NSGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(nonnull NSGestureRecognizer *)otherGestureRecognizer >+{ >+ return YES; >+} >+ >+- (void)viewDidLayout >+{ >+ [super viewDidLayout]; >+ >+ CGFloat width = CGRectGetWidth(self.view.frame); >+ CGFloat boxWidth = (width - 20 * 2 - 10 * 2) / 3; >+ CGFloat height = CGRectGetHeight(self.view.frame); >+ CGFloat boxHeight = height - 60 - 20; >+ >+ self.whlslViewContainer.frame = CGRectMake(20, 60, boxWidth, boxHeight); >+ self.mslViewContainer.frame = CGRectMake(20 + boxWidth + 10, 60, boxWidth, boxHeight); >+ self.metalView.frame = CGRectMake(20 + boxWidth + 10 + boxWidth + 10, 60, boxWidth, boxHeight); >+ >+ float ratio = boxHeight / (boxWidth / 3); >+ // NOTE: simd_matrix takes columns, not rows! >+ self.renderer.transformMatrix = simd_matrix(simd_make_float3(3, 0, 0), >+ simd_make_float3(0, ratio, 0), >+ simd_make_float3(-2.2, -ratio / 2, 1)); >+ >+ self.debugLabel.stringValue = [NSString stringWithFormat:@"Width = %f, height = %f", boxWidth, boxHeight]; >+} >+ >+- (IBAction)resetViewport:(id)sender >+{ >+ [self viewDidLayout]; >+ [self.metalView setNeedsDisplay:YES]; >+} >+ >+- (IBAction)loadDefault:(id)sender >+{ >+ [self loadFile:@"Default"]; >+} >+ >+- (IBAction)loadMandelbrot:(id)sender >+{ >+ [self loadFile:@"Mandelbrot"]; >+} >+ >+- (IBAction)loadJulia:(id)sender >+{ >+ [self loadFile:@"Julia"]; >+} >+ >+- (void)loadFile:(NSString*)name >+{ >+ NSString* defaultFilePath = [[NSBundle mainBundle] pathForResource:name ofType:@"whlsl"]; >+ NSString* defaultContents = [NSString stringWithContentsOfFile:defaultFilePath encoding:NSUTF8StringEncoding error:nil]; >+ >+ // Do any additional setup after loading the view. >+ self.whlslTextView.string = defaultContents; >+ self.mslTextView.string = @""; >+ self.metalView.hidden = YES; >+ >+ [self updateHighlighting]; >+} >+ >+- (IBAction)compileClicked:(id)sender { >+ NSError *error = nil; >+ CompileResult *output = [self.compiler compileWhlslToMetal:self.whlslTextView.string error:&error]; >+ if (error) >+ self.mslTextView.string = error.localizedDescription; >+ else { >+ self.metalView.hidden = NO; >+ self.mslTextView.string = output.source; >+ NSString *vertexShaderName = output.functionNameMap[@"vertexShader"]; >+ NSString *fragmentShaderName = output.functionNameMap[@"fragmentShader"]; >+ [self viewDidLayout]; >+ [self.renderer setShaderSource:output.source vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName]; >+ [self.metalView setNeedsDisplay:YES]; >+ } >+ self.mslTextView.font = [NSFont fontWithName:@"Menlo" size:12]; >+ >+ [self updateHighlighting]; >+} >+ >+- (IBAction)loadNativeFlatColor:(id)sender >+{ >+ [self loadNativeFlatColor:@"flatColor"]; >+} >+ >+- (IBAction)loadNativeMandelbrot:(id)sender >+{ >+ [self loadNativeMetalShaderWithName:@"mandelbrot"]; >+} >+ >+- (IBAction)loadNativeJulia:(id)sender >+{ >+ [self loadNativeMetalShaderWithName:@"julia"]; >+} >+ >+- (void)loadNativeMetalShaderWithName:(NSString*)name >+{ >+ NSString* vertexShaderName = [name stringByAppendingString:@"VertexShader"]; >+ NSString* fragmentShaderName = [name stringByAppendingString:@"FragmentShader"]; >+ [self viewDidLayout]; >+ [self.renderer setLibrary:self.library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName pixelFormat:self.metalView.colorPixelFormat]; >+ [self.metalView setNeedsDisplay:YES]; >+} >+ >+- (void)updateHighlighting >+{ >+ [self.compiler lexMsl:self.mslTextView.textStorage withPreferredFontSize:26]; >+ [self.compiler lexWhlsl:self.whlslTextView.textStorage withPreferredFontSize:26]; >+} >+ >+- (IBAction)zoom:(id)sender >+{ >+ float factor = 1.0f / (1 + self.magnifyGesture.magnification); >+ NSPoint location = [self.magnifyGesture locationInView:self.metalView]; >+ float normalizedX = location.x / CGRectGetWidth(self.metalView.frame); >+ float normalizedY = location.y / CGRectGetHeight(self.metalView.frame); >+ simd_float3 normalized = simd_make_float3(normalizedX, normalizedY, 1); >+ normalized = matrix_multiply(self.renderer.transformMatrix, normalized); >+ simd_float3x3 initTransform = simd_matrix(simd_make_float3(1, 0, 0), >+ simd_make_float3(0, 1, 0), >+ simd_make_float3(-normalized.x, -normalized.y, 1)); >+ simd_float3x3 scaleMatrix = simd_matrix(simd_make_float3(factor, 0.f, 0.f), >+ simd_make_float3(0.f, factor, 0.f), >+ simd_make_float3(0.f, 0.f, 1)); >+ simd_float3x3 backTransform = simd_matrix(simd_make_float3(1, 0, 0), >+ simd_make_float3(0, 1, 0), >+ simd_make_float3(normalized.x, normalized.y, 1)); >+ self.renderer.transformMatrix = matrix_multiply(matrix_multiply(backTransform, matrix_multiply(scaleMatrix, initTransform)), self.renderer.transformMatrix); >+ self.magnifyGesture.magnification = 0; >+ [self.metalView setNeedsDisplay:YES]; >+} >+ >+- (IBAction)rotate:(id)sender >+{ >+ float angle = -self.rotationGesture.rotation; >+ NSPoint location = [self.rotationGesture locationInView:self.metalView]; >+ float normalizedX = location.x / CGRectGetWidth(self.metalView.frame); >+ float normalizedY = location.y / CGRectGetHeight(self.metalView.frame); >+ simd_float3 normalized = simd_make_float3(normalizedX, normalizedY, 1); >+ normalized = matrix_multiply(self.renderer.transformMatrix, normalized); >+ // NSLog(@"%f %f", normalized.x, normalized.y); >+ simd_float3x3 initTransform = simd_matrix(simd_make_float3(1, 0, 0), >+ simd_make_float3(0, 1, 0), >+ simd_make_float3(-normalized.x, -normalized.y, 1)); >+ simd_float3x3 rotationMatrix = simd_matrix(simd_make_float3(cos(angle), sin(angle), 0.f), >+ simd_make_float3(-sin(angle), cos(angle), 0.f), >+ simd_make_float3(0.f, 0.f, 1)); >+ simd_float3x3 backTransform = simd_matrix(simd_make_float3(1, 0, 0), >+ simd_make_float3(0, 1, 0), >+ simd_make_float3(normalized.x, normalized.y, 1)); >+ self.renderer.transformMatrix = matrix_multiply(matrix_multiply(backTransform, matrix_multiply(rotationMatrix, initTransform)), self.renderer.transformMatrix); >+ self.rotationGesture.rotation = 0; >+ [self.metalView setNeedsDisplay:YES]; >+} >+ >+- (void)customMetalView:(CustomMetalView *)metalView scrolledDeltaX:(CGFloat)deltaX deltaY:(CGFloat)deltaY >+{ >+ float width = self.metalView.bounds.size.width; >+ float height = self.metalView.bounds.size.height; >+ float scrollVelocity = 6; >+ float x = -deltaX / width * scrollVelocity; >+ float y = deltaY / height * scrollVelocity; >+ simd_float3x3 m = simd_matrix(simd_make_float3(1, 0, 0), >+ simd_make_float3(0, 1, 0), >+ simd_make_float3(x, y, 1)); >+ self.renderer.transformMatrix = matrix_multiply(self.renderer.transformMatrix, m); >+} >+ >+- (void)textDidChange:(NSNotification *)notification >+{ >+ [self updateHighlighting]; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/WHLSL.entitlements b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/WHLSL.entitlements >new file mode 100644 >index 0000000000000000000000000000000000000000..f2ef3ae0265b40c475e8ef90e3a311c31786c594 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/WHLSL.entitlements >@@ -0,0 +1,10 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> >+<plist version="1.0"> >+<dict> >+ <key>com.apple.security.app-sandbox</key> >+ <true/> >+ <key>com.apple.security.files.user-selected.read-only</key> >+ <true/> >+</dict> >+</plist> >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/_Shared.whlsl b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/_Shared.whlsl >new file mode 100644 >index 0000000000000000000000000000000000000000..2b5dc3618b3fe2e555399105a385cc06a1b7a653 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/_Shared.whlsl >@@ -0,0 +1,12 @@ >+struct VertexInput { float2 position; float2 uv; } >+struct VertexOutput { float4 wsl_Position; } >+struct FragmentOutputFloat { float wsl_Color; } >+struct FragmentOutputInt { int wsl_Color; } >+struct FragmentOutputUint { uint wsl_Color; } >+ >+vertex VertexOutput vertexShader(VertexInput vertexInput) >+{ >+ VertexOutput result; >+ result.wsl_Position = float4(vertexInput.position, 0., 1.); >+ return result; >+} >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/main.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/main.m >new file mode 100644 >index 0000000000000000000000000000000000000000..22bf7ee48b4d29565d0b7256054a624fc5f47994 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/main.m >@@ -0,0 +1,14 @@ >+// >+// main.m >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Cocoa/Cocoa.h> >+ >+int main(int argc, const char * argv[]) >+{ >+ return NSApplicationMain(argc, argv); >+} >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL Tests.xcodeproj/project.pbxproj b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL Tests.xcodeproj/project.pbxproj >new file mode 100644 >index 0000000000000000000000000000000000000000..a68b3abe3bff7a709c9dfae0263270b813e27994 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL Tests.xcodeproj/project.pbxproj >@@ -0,0 +1,1218 @@ >+// !$*UTF8*$! >+{ >+ archiveVersion = 1; >+ classes = { >+ }; >+ objectVersion = 50; >+ objects = { >+ >+/* Begin PBXBuildFile section */ >+ E906B04621139B7700AD1C5E /* Julia.whlsl in Resources */ = {isa = PBXBuildFile; fileRef = E906B04521139B7700AD1C5E /* Julia.whlsl */; }; >+ E921D6362138C02600775099 /* OperatorAnderIndexer.js in Resources */ = {isa = PBXBuildFile; fileRef = E921D6322138C02600775099 /* OperatorAnderIndexer.js */; }; >+ E921D6372138C02600775099 /* MatrixType.js in Resources */ = {isa = PBXBuildFile; fileRef = E921D6332138C02600775099 /* MatrixType.js */; }; >+ E921D6382138C02600775099 /* BuiltinMatrixGetter.js in Resources */ = {isa = PBXBuildFile; fileRef = E921D6342138C02600775099 /* BuiltinMatrixGetter.js */; }; >+ E921D6392138C02600775099 /* BuiltinMatrixSetter.js in Resources */ = {isa = PBXBuildFile; fileRef = E921D6352138C02600775099 /* BuiltinMatrixSetter.js */; }; >+ E92D108A20F56F0600D776B2 /* Compiler.m in Sources */ = {isa = PBXBuildFile; fileRef = E92D108920F56F0600D776B2 /* Compiler.m */; }; >+ E92D108D20F56F4500D776B2 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E92D108C20F56F4500D776B2 /* MetalKit.framework */; }; >+ E92D108F20F56F4F00D776B2 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E92D108E20F56F4F00D776B2 /* Metal.framework */; }; >+ E92D109120F56F5700D776B2 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E92D109020F56F5700D776B2 /* JavaScriptCore.framework */; }; >+ E92D109320F5734900D776B2 /* Default.whlsl in Resources */ = {isa = PBXBuildFile; fileRef = E92D109220F5734900D776B2 /* Default.whlsl */; }; >+ E92D10AF20F57C9F00D776B2 /* OnscreenRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = E92D10AE20F57C9F00D776B2 /* OnscreenRenderer.m */; }; >+ E92D111520F6FFB600D776B2 /* Renderer.m in Sources */ = {isa = PBXBuildFile; fileRef = E92D111420F6FFB600D776B2 /* Renderer.m */; }; >+ E92D111620F7060E00D776B2 /* AddressSpace.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569BA20F56CD600F5CF34 /* AddressSpace.js */; }; >+ E92D111720F7060E00D776B2 /* All.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569BC20F56CD700F5CF34 /* All.js */; }; >+ E92D111820F7060E00D776B2 /* AnonymousVariable.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569BD20F56CD700F5CF34 /* AnonymousVariable.js */; }; >+ E92D111920F7060E00D776B2 /* ArrayRefType.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B520F56CD600F5CF34 /* ArrayRefType.js */; }; >+ E92D111A20F7060E00D776B2 /* ArrayType.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B420F56CD600F5CF34 /* ArrayType.js */; }; >+ E92D111B20F7060E00D776B2 /* Assignment.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B920F56CD600F5CF34 /* Assignment.js */; }; >+ E92D111C20F7060E00D776B2 /* AutoWrapper.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569BE20F56CD700F5CF34 /* AutoWrapper.js */; }; >+ E92D111D20F7060E00D776B2 /* Block.js in Resources */ = {isa = PBXBuildFile; fileRef = E94C06FC20F56CA300672992 /* Block.js */; }; >+ E92D111E20F7060E00D776B2 /* BoolLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B120F56CD600F5CF34 /* BoolLiteral.js */; }; >+ E92D111F20F7060E00D776B2 /* Break.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B020F56CD600F5CF34 /* Break.js */; }; >+ E92D112020F7060E00D776B2 /* CallExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569BF20F56CD700F5CF34 /* CallExpression.js */; }; >+ E92D112120F7060E00D776B2 /* CallFunction.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569C020F56CD700F5CF34 /* CallFunction.js */; }; >+ E92D112220F7060E00D776B2 /* Check.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B820F56CD600F5CF34 /* Check.js */; }; >+ E92D112320F7060E00D776B2 /* Checker.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569C120F56CD700F5CF34 /* Checker.js */; }; >+ E92D112420F7060E00D776B2 /* CheckLiteralTypes.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B620F56CD600F5CF34 /* CheckLiteralTypes.js */; }; >+ E92D112520F7060E00D776B2 /* CheckLoops.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B320F56CD600F5CF34 /* CheckLoops.js */; }; >+ E92D112620F7060E00D776B2 /* CheckRecursion.js in Resources */ = {isa = PBXBuildFile; fileRef = E94C06FA20F56CA300672992 /* CheckRecursion.js */; }; >+ E92D112720F7060E00D776B2 /* CheckRecursiveTypes.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569BB20F56CD600F5CF34 /* CheckRecursiveTypes.js */; }; >+ E92D112820F7060E00D776B2 /* CheckReturns.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B220F56CD600F5CF34 /* CheckReturns.js */; }; >+ E92D112920F7060E00D776B2 /* CheckUnreachableCode.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B720F56CD600F5CF34 /* CheckUnreachableCode.js */; }; >+ E92D112A20F7060E00D776B2 /* CheckWrapped.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569D420F56CED00F5CF34 /* CheckWrapped.js */; }; >+ E92D112B20F7060E00D776B2 /* CloneProgram.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569DB20F56CEE00F5CF34 /* CloneProgram.js */; }; >+ E92D112C20F7060E00D776B2 /* CommaExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569DC20F56CEE00F5CF34 /* CommaExpression.js */; }; >+ E92D112D20F7060E00D776B2 /* compiler.js in Resources */ = {isa = PBXBuildFile; fileRef = E94C06F720F56C6000672992 /* compiler.js */; }; >+ E92D112E20F7060E00D776B2 /* ConstexprFolder.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569D520F56CED00F5CF34 /* ConstexprFolder.js */; }; >+ E92D113020F7060E00D776B2 /* Continue.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569D720F56CED00F5CF34 /* Continue.js */; }; >+ E92D113120F7060E00D776B2 /* ConvertPtrToArrayRefExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569D920F56CED00F5CF34 /* ConvertPtrToArrayRefExpression.js */; }; >+ E92D113220F7060E00D776B2 /* CreateLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569D820F56CED00F5CF34 /* CreateLiteral.js */; }; >+ E92D113320F7060E00D776B2 /* CreateLiteralType.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569D620F56CED00F5CF34 /* CreateLiteralType.js */; }; >+ E92D113420F7060E00D776B2 /* DereferenceExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E94C06F920F56CA300672992 /* DereferenceExpression.js */; }; >+ E92D113520F7060E00D776B2 /* DotExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD074B20F56D5B007F2466 /* DotExpression.js */; }; >+ E92D113820F7060E00D776B2 /* DoWhileLoop.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD074620F56D5A007F2466 /* DoWhileLoop.js */; }; >+ E92D113920F7060E00D776B2 /* EArrayRef.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD074920F56D5A007F2466 /* EArrayRef.js */; }; >+ E92D113A20F7060E00D776B2 /* EBuffer.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD074820F56D5A007F2466 /* EBuffer.js */; }; >+ E92D113B20F7060E00D776B2 /* EBufferBuilder.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD074A20F56D5B007F2466 /* EBufferBuilder.js */; }; >+ E92D113C20F7060E00D776B2 /* EnumLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E94C06FD20F56CA300672992 /* EnumLiteral.js */; }; >+ E92D113D20F7060E00D776B2 /* EnumMember.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075520F56D69007F2466 /* EnumMember.js */; }; >+ E92D113E20F7060E00D776B2 /* EnumType.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075A20F56D69007F2466 /* EnumType.js */; }; >+ E92D113F20F7060E00D776B2 /* EPtr.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569E720F56D0500F5CF34 /* EPtr.js */; }; >+ E92D114020F7060E00D776B2 /* EvaluationCommon.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075320F56D69007F2466 /* EvaluationCommon.js */; }; >+ E92D114120F7060E00D776B2 /* Evaluator.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075720F56D69007F2466 /* Evaluator.js */; }; >+ E92D114220F7060E00D776B2 /* Expression.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075420F56D69007F2466 /* Expression.js */; }; >+ E92D114320F7060E00D776B2 /* ExpressionFinder.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075920F56D69007F2466 /* ExpressionFinder.js */; }; >+ E92D114420F7060E00D776B2 /* ExternalOrigin.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075B20F56D69007F2466 /* ExternalOrigin.js */; }; >+ E92D114520F7060E00D776B2 /* Field.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB5B20F56D93009B3629 /* Field.js */; }; >+ E92D114620F7060E00D776B2 /* FindHighZombies.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075820F56D69007F2466 /* FindHighZombies.js */; }; >+ E92D114720F7060E00D776B2 /* FlattenedStructOffsetGatherer.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075620F56D69007F2466 /* FlattenedStructOffsetGatherer.js */; }; >+ E92D114920F7060E00D776B2 /* FloatLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075C20F56D69007F2466 /* FloatLiteral.js */; }; >+ E92D114A20F7060E00D776B2 /* FloatLiteralType.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569EA20F56D0500F5CF34 /* FloatLiteralType.js */; }; >+ E92D114B20F7060E00D776B2 /* FoldConstexprs.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569EB20F56D0500F5CF34 /* FoldConstexprs.js */; }; >+ E92D114C20F7060E00D776B2 /* ForLoop.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB5A20F56D93009B3629 /* ForLoop.js */; }; >+ E92D114D20F7060E00D776B2 /* Func.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB5520F56D92009B3629 /* Func.js */; }; >+ E92D114E20F7060E00D776B2 /* FuncDef.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569E820F56D0500F5CF34 /* FuncDef.js */; }; >+ E92D115020F7060E00D776B2 /* FuncParameter.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569E920F56D0500F5CF34 /* FuncParameter.js */; }; >+ E92D115120F7060E00D776B2 /* FunctionLikeBlock.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569E620F56D0500F5CF34 /* FunctionLikeBlock.js */; }; >+ E92D115220F7060E00D776B2 /* HighZombieFinder.js in Resources */ = {isa = PBXBuildFile; fileRef = E94C06FB20F56CA300672992 /* HighZombieFinder.js */; }; >+ E92D115320F7060E00D776B2 /* IdentityExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB5820F56D93009B3629 /* IdentityExpression.js */; }; >+ E92D115420F7060E00D776B2 /* IfStatement.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB5720F56D93009B3629 /* IfStatement.js */; }; >+ E92D115520F7060E00D776B2 /* IndexExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB6320F56DA4009B3629 /* IndexExpression.js */; }; >+ E92D115620F7060E00D776B2 /* InferTypesForCall.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB6520F56DA5009B3629 /* InferTypesForCall.js */; }; >+ E92D115720F7060E00D776B2 /* Inline.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB6620F56DA5009B3629 /* Inline.js */; }; >+ E92D115820F7060E00D776B2 /* Inliner.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FE820F56DDD00D776B2 /* Inliner.js */; }; >+ E92D115A20F7060E00D776B2 /* IntLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FE420F56DDD00D776B2 /* IntLiteral.js */; }; >+ E92D115B20F7060E00D776B2 /* IntLiteralType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FE520F56DDD00D776B2 /* IntLiteralType.js */; }; >+ E92D115C20F7060E00D776B2 /* Intrinsics.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FE720F56DDD00D776B2 /* Intrinsics.js */; }; >+ E92D115D20F7060E00D776B2 /* LateChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB6420F56DA5009B3629 /* LateChecker.js */; }; >+ E92D115E20F7060E00D776B2 /* Lexer.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FF120F56DEC00D776B2 /* Lexer.js */; }; >+ E92D115F20F7060E00D776B2 /* LexerToken.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FF020F56DEB00D776B2 /* LexerToken.js */; }; >+ E92D116020F7060E00D776B2 /* LiteralTypeChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FF220F56DEC00D776B2 /* LiteralTypeChecker.js */; }; >+ E92D116120F7060E00D776B2 /* LogicalExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FEE20F56DEB00D776B2 /* LogicalExpression.js */; }; >+ E92D116220F7060E00D776B2 /* LogicalNot.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FEF20F56DEB00D776B2 /* LogicalNot.js */; }; >+ E92D116320F7060E00D776B2 /* LoopChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FFB20F56DFB00D776B2 /* LoopChecker.js */; }; >+ E92D116420F7060E00D776B2 /* MakeArrayRefExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FFC20F56DFB00D776B2 /* MakeArrayRefExpression.js */; }; >+ E92D116520F7060E00D776B2 /* MakePtrExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FF920F56DFA00D776B2 /* MakePtrExpression.js */; }; >+ E92D116620F7060E00D776B2 /* NameContext.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FF820F56DFA00D776B2 /* NameContext.js */; }; >+ E92D116720F7060E00D776B2 /* NameFinder.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FFA20F56DFB00D776B2 /* NameFinder.js */; }; >+ E92D116820F7060E00D776B2 /* NameResolver.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100320F56E0900D776B2 /* NameResolver.js */; }; >+ E92D116920F7060E00D776B2 /* NativeFunc.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100520F56E0900D776B2 /* NativeFunc.js */; }; >+ E92D116B20F7060E00D776B2 /* NativeType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100620F56E0900D776B2 /* NativeType.js */; }; >+ E92D116D20F7060E00D776B2 /* Node.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100F20F56E1500D776B2 /* Node.js */; }; >+ E92D116E20F7060E00D776B2 /* NormalUsePropertyResolver.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100D20F56E1500D776B2 /* NormalUsePropertyResolver.js */; }; >+ E92D116F20F7060E00D776B2 /* NullLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100C20F56E1500D776B2 /* NullLiteral.js */; }; >+ E92D117020F7060E00D776B2 /* NullType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D101020F56E1500D776B2 /* NullType.js */; }; >+ E92D117120F7060E00D776B2 /* OriginKind.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100E20F56E1500D776B2 /* OriginKind.js */; }; >+ E92D117220F7060E00D776B2 /* OverloadResolutionFailure.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D101920F56E2200D776B2 /* OverloadResolutionFailure.js */; }; >+ E92D117320F7060E00D776B2 /* Parse.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D101720F56E2200D776B2 /* Parse.js */; }; >+ E92D117420F7060E00D776B2 /* Prepare.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D101820F56E2200D776B2 /* Prepare.js */; }; >+ E92D117520F7060E00D776B2 /* Program.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D101A20F56E2200D776B2 /* Program.js */; }; >+ E92D117620F7060E00D776B2 /* ProgramWithUnnecessaryThingsRemoved.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D101620F56E2100D776B2 /* ProgramWithUnnecessaryThingsRemoved.js */; }; >+ E92D117720F7060E00D776B2 /* PropertyAccessExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102320F56E2F00D776B2 /* PropertyAccessExpression.js */; }; >+ E92D117820F7060E00D776B2 /* PropertyResolver.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102020F56E2F00D776B2 /* PropertyResolver.js */; }; >+ E92D117D20F7060E00D776B2 /* PtrType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102B20F56E3F00D776B2 /* PtrType.js */; }; >+ E92D117E20F7060E00D776B2 /* ReadModifyWriteExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102A20F56E3F00D776B2 /* ReadModifyWriteExpression.js */; }; >+ E92D117F20F7060E00D776B2 /* RecursionChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102C20F56E3F00D776B2 /* RecursionChecker.js */; }; >+ E92D118020F7060E00D776B2 /* RecursiveTypeChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102E20F56E4000D776B2 /* RecursiveTypeChecker.js */; }; >+ E92D118120F7060E00D776B2 /* ReferenceType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103520F56E4F00D776B2 /* ReferenceType.js */; }; >+ E92D118220F7060E00D776B2 /* ResolveNames.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103420F56E4F00D776B2 /* ResolveNames.js */; }; >+ E92D118320F7060E00D776B2 /* ResolveOverloadImpl.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103820F56E4F00D776B2 /* ResolveOverloadImpl.js */; }; >+ E92D118420F7060E00D776B2 /* ResolveProperties.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103620F56E4F00D776B2 /* ResolveProperties.js */; }; >+ E92D118520F7060E00D776B2 /* ResolveTypeDefs.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103720F56E4F00D776B2 /* ResolveTypeDefs.js */; }; >+ E92D118620F7060E00D776B2 /* Return.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103E20F56E6100D776B2 /* Return.js */; }; >+ E92D118720F7060E00D776B2 /* ReturnChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104020F56E6200D776B2 /* ReturnChecker.js */; }; >+ E92D118820F7060E00D776B2 /* ReturnException.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104220F56E6200D776B2 /* ReturnException.js */; }; >+ E92D118920F7060E00D776B2 /* Rewriter.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104120F56E6200D776B2 /* Rewriter.js */; }; >+ E92D118A20F7060E00D776B2 /* StandardLibrary.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103F20F56E6200D776B2 /* StandardLibrary.js */; }; >+ E92D118B20F7060E00D776B2 /* StatementCloner.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104820F56E7300D776B2 /* StatementCloner.js */; }; >+ E92D118C20F7060E00D776B2 /* StructLayoutBuilder.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104920F56E7300D776B2 /* StructLayoutBuilder.js */; }; >+ E92D118D20F7060E00D776B2 /* StructType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104A20F56E7300D776B2 /* StructType.js */; }; >+ E92D118F20F7060E00D776B2 /* SwitchCase.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104B20F56E7300D776B2 /* SwitchCase.js */; }; >+ E92D119020F7060E00D776B2 /* SwitchStatement.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105220F56E8400D776B2 /* SwitchStatement.js */; }; >+ E92D119120F7060E00D776B2 /* SynthesizeEnumFunctions.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105420F56E8500D776B2 /* SynthesizeEnumFunctions.js */; }; >+ E92D119220F7060E00D776B2 /* SynthesizeStructAccessors.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105320F56E8400D776B2 /* SynthesizeStructAccessors.js */; }; >+ E92D119320F7060E00D776B2 /* TrapStatement.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105620F56E8500D776B2 /* TrapStatement.js */; }; >+ E92D119420F7060E00D776B2 /* Type.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105520F56E8500D776B2 /* Type.js */; }; >+ E92D119520F7060E00D776B2 /* TypeDef.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105F20F56E9500D776B2 /* TypeDef.js */; }; >+ E92D119620F7060E00D776B2 /* TypeDefResolver.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105E20F56E9500D776B2 /* TypeDefResolver.js */; }; >+ E92D119720F7060E00D776B2 /* TypedValue.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D106020F56E9500D776B2 /* TypedValue.js */; }; >+ E92D119A20F7060E00D776B2 /* TypeRef.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D106620F56EA400D776B2 /* TypeRef.js */; }; >+ E92D119D20F7060E00D776B2 /* UintLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D106820F56EA400D776B2 /* UintLiteral.js */; }; >+ E92D119E20F7060E00D776B2 /* UintLiteralType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D106720F56EA400D776B2 /* UintLiteralType.js */; }; >+ E92D119F20F7060E00D776B2 /* UnificationContext.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107220F56EBB00D776B2 /* UnificationContext.js */; }; >+ E92D11A020F7060E00D776B2 /* UnreachableCodeChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107320F56EBC00D776B2 /* UnreachableCodeChecker.js */; }; >+ E92D11A120F7060E00D776B2 /* Value.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107420F56EBC00D776B2 /* Value.js */; }; >+ E92D11A220F7060E00D776B2 /* VariableDecl.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107020F56EBB00D776B2 /* VariableDecl.js */; }; >+ E92D11A320F7060E00D776B2 /* VariableRef.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107120F56EBB00D776B2 /* VariableRef.js */; }; >+ E92D11A420F7060E00D776B2 /* VisitingSet.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107C20F56ECF00D776B2 /* VisitingSet.js */; }; >+ E92D11A520F7060E00D776B2 /* Visitor.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107A20F56ECF00D776B2 /* Visitor.js */; }; >+ E92D11A620F7060E00D776B2 /* WhileLoop.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107D20F56ECF00D776B2 /* WhileLoop.js */; }; >+ E92D11A720F7060E00D776B2 /* WrapChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107B20F56ECF00D776B2 /* WrapChecker.js */; }; >+ E92D11A820F7060E00D776B2 /* WSyntaxError.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D108220F56EDE00D776B2 /* WSyntaxError.js */; }; >+ E92D11A920F7060E00D776B2 /* WTrapError.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D108420F56EDE00D776B2 /* WTrapError.js */; }; >+ E92D11AA20F7060E00D776B2 /* WTypeError.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D108320F56EDE00D776B2 /* WTypeError.js */; }; >+ E92D11AD20F7081500D776B2 /* OffscreenRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = E92D11AC20F7081500D776B2 /* OffscreenRenderer.m */; }; >+ E92D11BB20F7F67300D776B2 /* CompileResult.m in Sources */ = {isa = PBXBuildFile; fileRef = E92D11BA20F7F67300D776B2 /* CompileResult.m */; }; >+ E92EDFFB211546A40042F960 /* CustomMetalView.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EDFF6211546A40042F960 /* CustomMetalView.m */; }; >+ E92EDFFC211546A40042F960 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EDFF7211546A40042F960 /* AppDelegate.m */; }; >+ E92EDFFD211546A40042F960 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EDFFA211546A40042F960 /* ViewController.m */; }; >+ E92EE000211546AB0042F960 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E92EDFFE211546AB0042F960 /* Main.storyboard */; }; >+ E92EE004211549C50042F960 /* TestCallArgument.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EE003211549C50042F960 /* TestCallArgument.m */; }; >+ E92EE00721154AC40042F960 /* TestFamily.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EE00621154AC40042F960 /* TestFamily.m */; }; >+ E92EE00A21154B5A0042F960 /* TestDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EE00921154B5A0042F960 /* TestDescription.m */; }; >+ E92EE00C211554980042F960 /* _Shared.whlsl in Resources */ = {isa = PBXBuildFile; fileRef = E92EE00B211554980042F960 /* _Shared.whlsl */; }; >+ E92EE00F211563300042F960 /* TestFamilyRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EE00E211563300042F960 /* TestFamilyRunner.m */; }; >+ E941ACBF2134A5BC00392BA9 /* CheckTypesWithArguments.js in Resources */ = {isa = PBXBuildFile; fileRef = E941ACAE2134A5BA00392BA9 /* CheckTypesWithArguments.js */; }; >+ E941ACC02134A5BC00392BA9 /* SynthesizeCopyConstructorOperator.js in Resources */ = {isa = PBXBuildFile; fileRef = E941ACAF2134A5BA00392BA9 /* SynthesizeCopyConstructorOperator.js */; }; >+ E941ACC42134A5BC00392BA9 /* SynthesizeDefaultConstructorOperator.js in Resources */ = {isa = PBXBuildFile; fileRef = E941ACB32134A5BB00392BA9 /* SynthesizeDefaultConstructorOperator.js */; }; >+ E941ACC62134A5BC00392BA9 /* TernaryExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E941ACB52134A5BB00392BA9 /* TernaryExpression.js */; }; >+ E941ACC72134A5BC00392BA9 /* OperatorArrayRefLength.js in Resources */ = {isa = PBXBuildFile; fileRef = E941ACB62134A5BB00392BA9 /* OperatorArrayRefLength.js */; }; >+ E941ACC82134A5BC00392BA9 /* SynthesizeArrayOperatorLength.js in Resources */ = {isa = PBXBuildFile; fileRef = E941ACB72134A5BB00392BA9 /* SynthesizeArrayOperatorLength.js */; }; >+ E941ACCA2134A5BC00392BA9 /* BuiltinVectorGetter.js in Resources */ = {isa = PBXBuildFile; fileRef = E941ACB92134A5BB00392BA9 /* BuiltinVectorGetter.js */; }; >+ E941ACCB2134A5BC00392BA9 /* TypeOverloadResolutionFailure.js in Resources */ = {isa = PBXBuildFile; fileRef = E941ACBA2134A5BB00392BA9 /* TypeOverloadResolutionFailure.js */; }; >+ E941ACCC2134A5BC00392BA9 /* VectorType.js in Resources */ = {isa = PBXBuildFile; fileRef = E941ACBB2134A5BB00392BA9 /* VectorType.js */; }; >+ E941ACCD2134A5BC00392BA9 /* BuiltinVectorSetter.js in Resources */ = {isa = PBXBuildFile; fileRef = E941ACBC2134A5BB00392BA9 /* BuiltinVectorSetter.js */; }; >+ E94C06CA20F56A4200672992 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E94C06C920F56A4200672992 /* Assets.xcassets */; }; >+ E94C06D020F56A4200672992 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E94C06CF20F56A4200672992 /* main.m */; }; >+ E94C06DB20F56A4200672992 /* WHLSL_ToyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E94C06DA20F56A4200672992 /* WHLSL_ToyTests.m */; }; >+ E94D124F2114BD7600B0F967 /* Mandelbrot.whlsl in Resources */ = {isa = PBXBuildFile; fileRef = E94D124E2114BD7600B0F967 /* Mandelbrot.whlsl */; }; >+ E94D127F2114C6FF00B0F967 /* Test.js in Resources */ = {isa = PBXBuildFile; fileRef = E94D127E2114C6FF00B0F967 /* Test.js */; }; >+ E9E11933211E61640014D553 /* Shaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = E9E11932211E61640014D553 /* Shaders.metal */; }; >+/* End PBXBuildFile section */ >+ >+/* Begin PBXContainerItemProxy section */ >+ E94C06D720F56A4200672992 /* PBXContainerItemProxy */ = { >+ isa = PBXContainerItemProxy; >+ containerPortal = E94C06B820F56A4000672992 /* Project object */; >+ proxyType = 1; >+ remoteGlobalIDString = E94C06BF20F56A4000672992; >+ remoteInfo = "WHLSL Toy"; >+ }; >+/* End PBXContainerItemProxy section */ >+ >+/* Begin PBXFileReference section */ >+ E906B04521139B7700AD1C5E /* Julia.whlsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Julia.whlsl; sourceTree = "<group>"; }; >+ E921D6322138C02600775099 /* OperatorAnderIndexer.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = OperatorAnderIndexer.js; path = ../../../OperatorAnderIndexer.js; sourceTree = "<group>"; }; >+ E921D6332138C02600775099 /* MatrixType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = MatrixType.js; path = ../../../MatrixType.js; sourceTree = "<group>"; }; >+ E921D6342138C02600775099 /* BuiltinMatrixGetter.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = BuiltinMatrixGetter.js; path = ../../../BuiltinMatrixGetter.js; sourceTree = "<group>"; }; >+ E921D6352138C02600775099 /* BuiltinMatrixSetter.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = BuiltinMatrixSetter.js; path = ../../../BuiltinMatrixSetter.js; sourceTree = "<group>"; }; >+ E92D0FE420F56DDD00D776B2 /* IntLiteral.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = IntLiteral.js; path = ../../../IntLiteral.js; sourceTree = "<group>"; }; >+ E92D0FE520F56DDD00D776B2 /* IntLiteralType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = IntLiteralType.js; path = ../../../IntLiteralType.js; sourceTree = "<group>"; }; >+ E92D0FE720F56DDD00D776B2 /* Intrinsics.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Intrinsics.js; path = ../../../Intrinsics.js; sourceTree = "<group>"; }; >+ E92D0FE820F56DDD00D776B2 /* Inliner.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Inliner.js; path = ../../../Inliner.js; sourceTree = "<group>"; }; >+ E92D0FEE20F56DEB00D776B2 /* LogicalExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = LogicalExpression.js; path = ../../../LogicalExpression.js; sourceTree = "<group>"; }; >+ E92D0FEF20F56DEB00D776B2 /* LogicalNot.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = LogicalNot.js; path = ../../../LogicalNot.js; sourceTree = "<group>"; }; >+ E92D0FF020F56DEB00D776B2 /* LexerToken.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = LexerToken.js; path = ../../../LexerToken.js; sourceTree = "<group>"; }; >+ E92D0FF120F56DEC00D776B2 /* Lexer.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Lexer.js; path = ../../../Lexer.js; sourceTree = "<group>"; }; >+ E92D0FF220F56DEC00D776B2 /* LiteralTypeChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = LiteralTypeChecker.js; path = ../../../LiteralTypeChecker.js; sourceTree = "<group>"; }; >+ E92D0FF820F56DFA00D776B2 /* NameContext.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NameContext.js; path = ../../../NameContext.js; sourceTree = "<group>"; }; >+ E92D0FF920F56DFA00D776B2 /* MakePtrExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = MakePtrExpression.js; path = ../../../MakePtrExpression.js; sourceTree = "<group>"; }; >+ E92D0FFA20F56DFB00D776B2 /* NameFinder.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NameFinder.js; path = ../../../NameFinder.js; sourceTree = "<group>"; }; >+ E92D0FFB20F56DFB00D776B2 /* LoopChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = LoopChecker.js; path = ../../../LoopChecker.js; sourceTree = "<group>"; }; >+ E92D0FFC20F56DFB00D776B2 /* MakeArrayRefExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = MakeArrayRefExpression.js; path = ../../../MakeArrayRefExpression.js; sourceTree = "<group>"; }; >+ E92D100320F56E0900D776B2 /* NameResolver.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NameResolver.js; path = ../../../NameResolver.js; sourceTree = "<group>"; }; >+ E92D100520F56E0900D776B2 /* NativeFunc.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NativeFunc.js; path = ../../../NativeFunc.js; sourceTree = "<group>"; }; >+ E92D100620F56E0900D776B2 /* NativeType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NativeType.js; path = ../../../NativeType.js; sourceTree = "<group>"; }; >+ E92D100C20F56E1500D776B2 /* NullLiteral.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NullLiteral.js; path = ../../../NullLiteral.js; sourceTree = "<group>"; }; >+ E92D100D20F56E1500D776B2 /* NormalUsePropertyResolver.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NormalUsePropertyResolver.js; path = ../../../NormalUsePropertyResolver.js; sourceTree = "<group>"; }; >+ E92D100E20F56E1500D776B2 /* OriginKind.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = OriginKind.js; path = ../../../OriginKind.js; sourceTree = "<group>"; }; >+ E92D100F20F56E1500D776B2 /* Node.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Node.js; path = ../../../Node.js; sourceTree = "<group>"; }; >+ E92D101020F56E1500D776B2 /* NullType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NullType.js; path = ../../../NullType.js; sourceTree = "<group>"; }; >+ E92D101620F56E2100D776B2 /* ProgramWithUnnecessaryThingsRemoved.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ProgramWithUnnecessaryThingsRemoved.js; path = ../../../ProgramWithUnnecessaryThingsRemoved.js; sourceTree = "<group>"; }; >+ E92D101720F56E2200D776B2 /* Parse.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Parse.js; path = ../../../Parse.js; sourceTree = "<group>"; }; >+ E92D101820F56E2200D776B2 /* Prepare.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Prepare.js; path = ../../../Prepare.js; sourceTree = "<group>"; }; >+ E92D101920F56E2200D776B2 /* OverloadResolutionFailure.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = OverloadResolutionFailure.js; path = ../../../OverloadResolutionFailure.js; sourceTree = "<group>"; }; >+ E92D101A20F56E2200D776B2 /* Program.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Program.js; path = ../../../Program.js; sourceTree = "<group>"; }; >+ E92D102020F56E2F00D776B2 /* PropertyResolver.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = PropertyResolver.js; path = ../../../PropertyResolver.js; sourceTree = "<group>"; }; >+ E92D102320F56E2F00D776B2 /* PropertyAccessExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = PropertyAccessExpression.js; path = ../../../PropertyAccessExpression.js; sourceTree = "<group>"; }; >+ E92D102A20F56E3F00D776B2 /* ReadModifyWriteExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ReadModifyWriteExpression.js; path = ../../../ReadModifyWriteExpression.js; sourceTree = "<group>"; }; >+ E92D102B20F56E3F00D776B2 /* PtrType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = PtrType.js; path = ../../../PtrType.js; sourceTree = "<group>"; }; >+ E92D102C20F56E3F00D776B2 /* RecursionChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = RecursionChecker.js; path = ../../../RecursionChecker.js; sourceTree = "<group>"; }; >+ E92D102E20F56E4000D776B2 /* RecursiveTypeChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = RecursiveTypeChecker.js; path = ../../../RecursiveTypeChecker.js; sourceTree = "<group>"; }; >+ E92D103420F56E4F00D776B2 /* ResolveNames.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ResolveNames.js; path = ../../../ResolveNames.js; sourceTree = "<group>"; }; >+ E92D103520F56E4F00D776B2 /* ReferenceType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ReferenceType.js; path = ../../../ReferenceType.js; sourceTree = "<group>"; }; >+ E92D103620F56E4F00D776B2 /* ResolveProperties.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ResolveProperties.js; path = ../../../ResolveProperties.js; sourceTree = "<group>"; }; >+ E92D103720F56E4F00D776B2 /* ResolveTypeDefs.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ResolveTypeDefs.js; path = ../../../ResolveTypeDefs.js; sourceTree = "<group>"; }; >+ E92D103820F56E4F00D776B2 /* ResolveOverloadImpl.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ResolveOverloadImpl.js; path = ../../../ResolveOverloadImpl.js; sourceTree = "<group>"; }; >+ E92D103E20F56E6100D776B2 /* Return.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Return.js; path = ../../../Return.js; sourceTree = "<group>"; }; >+ E92D103F20F56E6200D776B2 /* StandardLibrary.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = StandardLibrary.js; path = ../../../StandardLibrary.js; sourceTree = "<group>"; }; >+ E92D104020F56E6200D776B2 /* ReturnChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ReturnChecker.js; path = ../../../ReturnChecker.js; sourceTree = "<group>"; }; >+ E92D104120F56E6200D776B2 /* Rewriter.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Rewriter.js; path = ../../../Rewriter.js; sourceTree = "<group>"; }; >+ E92D104220F56E6200D776B2 /* ReturnException.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ReturnException.js; path = ../../../ReturnException.js; sourceTree = "<group>"; }; >+ E92D104820F56E7300D776B2 /* StatementCloner.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = StatementCloner.js; path = ../../../StatementCloner.js; sourceTree = "<group>"; }; >+ E92D104920F56E7300D776B2 /* StructLayoutBuilder.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = StructLayoutBuilder.js; path = ../../../StructLayoutBuilder.js; sourceTree = "<group>"; }; >+ E92D104A20F56E7300D776B2 /* StructType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = StructType.js; path = ../../../StructType.js; sourceTree = "<group>"; }; >+ E92D104B20F56E7300D776B2 /* SwitchCase.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = SwitchCase.js; path = ../../../SwitchCase.js; sourceTree = "<group>"; }; >+ E92D105220F56E8400D776B2 /* SwitchStatement.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = SwitchStatement.js; path = ../../../SwitchStatement.js; sourceTree = "<group>"; }; >+ E92D105320F56E8400D776B2 /* SynthesizeStructAccessors.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = SynthesizeStructAccessors.js; path = ../../../SynthesizeStructAccessors.js; sourceTree = "<group>"; }; >+ E92D105420F56E8500D776B2 /* SynthesizeEnumFunctions.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = SynthesizeEnumFunctions.js; path = ../../../SynthesizeEnumFunctions.js; sourceTree = "<group>"; }; >+ E92D105520F56E8500D776B2 /* Type.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Type.js; path = ../../../Type.js; sourceTree = "<group>"; }; >+ E92D105620F56E8500D776B2 /* TrapStatement.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TrapStatement.js; path = ../../../TrapStatement.js; sourceTree = "<group>"; }; >+ E92D105E20F56E9500D776B2 /* TypeDefResolver.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypeDefResolver.js; path = ../../../TypeDefResolver.js; sourceTree = "<group>"; }; >+ E92D105F20F56E9500D776B2 /* TypeDef.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypeDef.js; path = ../../../TypeDef.js; sourceTree = "<group>"; }; >+ E92D106020F56E9500D776B2 /* TypedValue.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypedValue.js; path = ../../../TypedValue.js; sourceTree = "<group>"; }; >+ E92D106620F56EA400D776B2 /* TypeRef.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypeRef.js; path = ../../../TypeRef.js; sourceTree = "<group>"; }; >+ E92D106720F56EA400D776B2 /* UintLiteralType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = UintLiteralType.js; path = ../../../UintLiteralType.js; sourceTree = "<group>"; }; >+ E92D106820F56EA400D776B2 /* UintLiteral.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = UintLiteral.js; path = ../../../UintLiteral.js; sourceTree = "<group>"; }; >+ E92D107020F56EBB00D776B2 /* VariableDecl.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = VariableDecl.js; path = ../../../VariableDecl.js; sourceTree = "<group>"; }; >+ E92D107120F56EBB00D776B2 /* VariableRef.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = VariableRef.js; path = ../../../VariableRef.js; sourceTree = "<group>"; }; >+ E92D107220F56EBB00D776B2 /* UnificationContext.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = UnificationContext.js; path = ../../../UnificationContext.js; sourceTree = "<group>"; }; >+ E92D107320F56EBC00D776B2 /* UnreachableCodeChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = UnreachableCodeChecker.js; path = ../../../UnreachableCodeChecker.js; sourceTree = "<group>"; }; >+ E92D107420F56EBC00D776B2 /* Value.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Value.js; path = ../../../Value.js; sourceTree = "<group>"; }; >+ E92D107A20F56ECF00D776B2 /* Visitor.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Visitor.js; path = ../../../Visitor.js; sourceTree = "<group>"; }; >+ E92D107B20F56ECF00D776B2 /* WrapChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = WrapChecker.js; path = ../../../WrapChecker.js; sourceTree = "<group>"; }; >+ E92D107C20F56ECF00D776B2 /* VisitingSet.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = VisitingSet.js; path = ../../../VisitingSet.js; sourceTree = "<group>"; }; >+ E92D107D20F56ECF00D776B2 /* WhileLoop.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = WhileLoop.js; path = ../../../WhileLoop.js; sourceTree = "<group>"; }; >+ E92D108220F56EDE00D776B2 /* WSyntaxError.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = WSyntaxError.js; path = ../../../WSyntaxError.js; sourceTree = "<group>"; }; >+ E92D108320F56EDE00D776B2 /* WTypeError.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = WTypeError.js; path = ../../../WTypeError.js; sourceTree = "<group>"; }; >+ E92D108420F56EDE00D776B2 /* WTrapError.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = WTrapError.js; path = ../../../WTrapError.js; sourceTree = "<group>"; }; >+ E92D108820F56F0600D776B2 /* Compiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Compiler.h; sourceTree = "<group>"; }; >+ E92D108920F56F0600D776B2 /* Compiler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Compiler.m; sourceTree = "<group>"; }; >+ E92D108C20F56F4500D776B2 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; >+ E92D108E20F56F4F00D776B2 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; >+ E92D109020F56F5700D776B2 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; >+ E92D109220F5734900D776B2 /* Default.whlsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Default.whlsl; sourceTree = "<group>"; }; >+ E92D10AD20F57C9F00D776B2 /* OnscreenRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OnscreenRenderer.h; sourceTree = "<group>"; }; >+ E92D10AE20F57C9F00D776B2 /* OnscreenRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OnscreenRenderer.m; sourceTree = "<group>"; }; >+ E92D111320F6FFB600D776B2 /* Renderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Renderer.h; sourceTree = "<group>"; }; >+ E92D111420F6FFB600D776B2 /* Renderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Renderer.m; sourceTree = "<group>"; }; >+ E92D11AB20F7081500D776B2 /* OffscreenRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OffscreenRenderer.h; sourceTree = "<group>"; }; >+ E92D11AC20F7081500D776B2 /* OffscreenRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OffscreenRenderer.m; sourceTree = "<group>"; }; >+ E92D11B920F7F67300D776B2 /* CompileResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CompileResult.h; sourceTree = "<group>"; }; >+ E92D11BA20F7F67300D776B2 /* CompileResult.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CompileResult.m; sourceTree = "<group>"; }; >+ E92EDFF5211546A40042F960 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; >+ E92EDFF6211546A40042F960 /* CustomMetalView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomMetalView.m; sourceTree = "<group>"; }; >+ E92EDFF7211546A40042F960 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; >+ E92EDFF8211546A40042F960 /* CustomMetalView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomMetalView.h; sourceTree = "<group>"; }; >+ E92EDFF9211546A40042F960 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; }; >+ E92EDFFA211546A40042F960 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; }; >+ E92EDFFF211546AB0042F960 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; >+ E92EE002211549C50042F960 /* TestCallArgument.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestCallArgument.h; sourceTree = "<group>"; }; >+ E92EE003211549C50042F960 /* TestCallArgument.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestCallArgument.m; sourceTree = "<group>"; }; >+ E92EE00521154AC40042F960 /* TestFamily.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestFamily.h; sourceTree = "<group>"; }; >+ E92EE00621154AC40042F960 /* TestFamily.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestFamily.m; sourceTree = "<group>"; }; >+ E92EE00821154B5A0042F960 /* TestDescription.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestDescription.h; sourceTree = "<group>"; }; >+ E92EE00921154B5A0042F960 /* TestDescription.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestDescription.m; sourceTree = "<group>"; }; >+ E92EE00B211554980042F960 /* _Shared.whlsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = _Shared.whlsl; sourceTree = "<group>"; }; >+ E92EE00D211563300042F960 /* TestFamilyRunner.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestFamilyRunner.h; sourceTree = "<group>"; }; >+ E92EE00E211563300042F960 /* TestFamilyRunner.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestFamilyRunner.m; sourceTree = "<group>"; }; >+ E941ACAE2134A5BA00392BA9 /* CheckTypesWithArguments.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CheckTypesWithArguments.js; path = ../../../CheckTypesWithArguments.js; sourceTree = "<group>"; }; >+ E941ACAF2134A5BA00392BA9 /* SynthesizeCopyConstructorOperator.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = SynthesizeCopyConstructorOperator.js; path = ../../../SynthesizeCopyConstructorOperator.js; sourceTree = "<group>"; }; >+ E941ACB32134A5BB00392BA9 /* SynthesizeDefaultConstructorOperator.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = SynthesizeDefaultConstructorOperator.js; path = ../../../SynthesizeDefaultConstructorOperator.js; sourceTree = "<group>"; }; >+ E941ACB52134A5BB00392BA9 /* TernaryExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TernaryExpression.js; path = ../../../TernaryExpression.js; sourceTree = "<group>"; }; >+ E941ACB62134A5BB00392BA9 /* OperatorArrayRefLength.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = OperatorArrayRefLength.js; path = ../../../OperatorArrayRefLength.js; sourceTree = "<group>"; }; >+ E941ACB72134A5BB00392BA9 /* SynthesizeArrayOperatorLength.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = SynthesizeArrayOperatorLength.js; path = ../../../SynthesizeArrayOperatorLength.js; sourceTree = "<group>"; }; >+ E941ACB92134A5BB00392BA9 /* BuiltinVectorGetter.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = BuiltinVectorGetter.js; path = ../../../BuiltinVectorGetter.js; sourceTree = "<group>"; }; >+ E941ACBA2134A5BB00392BA9 /* TypeOverloadResolutionFailure.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypeOverloadResolutionFailure.js; path = ../../../TypeOverloadResolutionFailure.js; sourceTree = "<group>"; }; >+ E941ACBB2134A5BB00392BA9 /* VectorType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = VectorType.js; path = ../../../VectorType.js; sourceTree = "<group>"; }; >+ E941ACBC2134A5BB00392BA9 /* BuiltinVectorSetter.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = BuiltinVectorSetter.js; path = ../../../BuiltinVectorSetter.js; sourceTree = "<group>"; }; >+ E94C06C020F56A4000672992 /* WHLSL Tests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "WHLSL Tests.app"; sourceTree = BUILT_PRODUCTS_DIR; }; >+ E94C06C920F56A4200672992 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; >+ E94C06CE20F56A4200672992 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; >+ E94C06CF20F56A4200672992 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; >+ E94C06D120F56A4200672992 /* WHLSL.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WHLSL.entitlements; sourceTree = "<group>"; }; >+ E94C06D620F56A4200672992 /* WHLSL TestsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "WHLSL TestsTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; >+ E94C06DA20F56A4200672992 /* WHLSL_ToyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WHLSL_ToyTests.m; sourceTree = "<group>"; }; >+ E94C06DC20F56A4200672992 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; >+ E94C06F720F56C6000672992 /* compiler.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = compiler.js; path = ../../compiler.js; sourceTree = "<group>"; }; >+ E94C06F920F56CA300672992 /* DereferenceExpression.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = DereferenceExpression.js; path = ../../../DereferenceExpression.js; sourceTree = "<group>"; }; >+ E94C06FA20F56CA300672992 /* CheckRecursion.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = CheckRecursion.js; path = ../../../CheckRecursion.js; sourceTree = "<group>"; }; >+ E94C06FB20F56CA300672992 /* HighZombieFinder.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = HighZombieFinder.js; path = ../../../HighZombieFinder.js; sourceTree = "<group>"; }; >+ E94C06FC20F56CA300672992 /* Block.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = Block.js; path = ../../../Block.js; sourceTree = "<group>"; }; >+ E94C06FD20F56CA300672992 /* EnumLiteral.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = EnumLiteral.js; path = ../../../EnumLiteral.js; sourceTree = "<group>"; }; >+ E94D124E2114BD7600B0F967 /* Mandelbrot.whlsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Mandelbrot.whlsl; sourceTree = "<group>"; }; >+ E94D127E2114C6FF00B0F967 /* Test.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Test.js; path = ../../../Test.js; sourceTree = "<group>"; }; >+ E95569B020F56CD600F5CF34 /* Break.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Break.js; path = ../../../Break.js; sourceTree = "<group>"; }; >+ E95569B120F56CD600F5CF34 /* BoolLiteral.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = BoolLiteral.js; path = ../../../BoolLiteral.js; sourceTree = "<group>"; }; >+ E95569B220F56CD600F5CF34 /* CheckReturns.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CheckReturns.js; path = ../../../CheckReturns.js; sourceTree = "<group>"; }; >+ E95569B320F56CD600F5CF34 /* CheckLoops.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CheckLoops.js; path = ../../../CheckLoops.js; sourceTree = "<group>"; }; >+ E95569B420F56CD600F5CF34 /* ArrayType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ArrayType.js; path = ../../../ArrayType.js; sourceTree = "<group>"; }; >+ E95569B520F56CD600F5CF34 /* ArrayRefType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ArrayRefType.js; path = ../../../ArrayRefType.js; sourceTree = "<group>"; }; >+ E95569B620F56CD600F5CF34 /* CheckLiteralTypes.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CheckLiteralTypes.js; path = ../../../CheckLiteralTypes.js; sourceTree = "<group>"; }; >+ E95569B720F56CD600F5CF34 /* CheckUnreachableCode.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CheckUnreachableCode.js; path = ../../../CheckUnreachableCode.js; sourceTree = "<group>"; }; >+ E95569B820F56CD600F5CF34 /* Check.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Check.js; path = ../../../Check.js; sourceTree = "<group>"; }; >+ E95569B920F56CD600F5CF34 /* Assignment.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Assignment.js; path = ../../../Assignment.js; sourceTree = "<group>"; }; >+ E95569BA20F56CD600F5CF34 /* AddressSpace.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = AddressSpace.js; path = ../../../AddressSpace.js; sourceTree = "<group>"; }; >+ E95569BB20F56CD600F5CF34 /* CheckRecursiveTypes.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CheckRecursiveTypes.js; path = ../../../CheckRecursiveTypes.js; sourceTree = "<group>"; }; >+ E95569BC20F56CD700F5CF34 /* All.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = All.js; path = ../../../All.js; sourceTree = "<group>"; }; >+ E95569BD20F56CD700F5CF34 /* AnonymousVariable.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = AnonymousVariable.js; path = ../../../AnonymousVariable.js; sourceTree = "<group>"; }; >+ E95569BE20F56CD700F5CF34 /* AutoWrapper.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = AutoWrapper.js; path = ../../../AutoWrapper.js; sourceTree = "<group>"; }; >+ E95569BF20F56CD700F5CF34 /* CallExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CallExpression.js; path = ../../../CallExpression.js; sourceTree = "<group>"; }; >+ E95569C020F56CD700F5CF34 /* CallFunction.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CallFunction.js; path = ../../../CallFunction.js; sourceTree = "<group>"; }; >+ E95569C120F56CD700F5CF34 /* Checker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Checker.js; path = ../../../Checker.js; sourceTree = "<group>"; }; >+ E95569D420F56CED00F5CF34 /* CheckWrapped.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CheckWrapped.js; path = ../../../CheckWrapped.js; sourceTree = "<group>"; }; >+ E95569D520F56CED00F5CF34 /* ConstexprFolder.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ConstexprFolder.js; path = ../../../ConstexprFolder.js; sourceTree = "<group>"; }; >+ E95569D620F56CED00F5CF34 /* CreateLiteralType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CreateLiteralType.js; path = ../../../CreateLiteralType.js; sourceTree = "<group>"; }; >+ E95569D720F56CED00F5CF34 /* Continue.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Continue.js; path = ../../../Continue.js; sourceTree = "<group>"; }; >+ E95569D820F56CED00F5CF34 /* CreateLiteral.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CreateLiteral.js; path = ../../../CreateLiteral.js; sourceTree = "<group>"; }; >+ E95569D920F56CED00F5CF34 /* ConvertPtrToArrayRefExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ConvertPtrToArrayRefExpression.js; path = ../../../ConvertPtrToArrayRefExpression.js; sourceTree = "<group>"; }; >+ E95569DB20F56CEE00F5CF34 /* CloneProgram.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CloneProgram.js; path = ../../../CloneProgram.js; sourceTree = "<group>"; }; >+ E95569DC20F56CEE00F5CF34 /* CommaExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CommaExpression.js; path = ../../../CommaExpression.js; sourceTree = "<group>"; }; >+ E95569E620F56D0500F5CF34 /* FunctionLikeBlock.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FunctionLikeBlock.js; path = ../../../FunctionLikeBlock.js; sourceTree = "<group>"; }; >+ E95569E720F56D0500F5CF34 /* EPtr.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = EPtr.js; path = ../../../EPtr.js; sourceTree = "<group>"; }; >+ E95569E820F56D0500F5CF34 /* FuncDef.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FuncDef.js; path = ../../../FuncDef.js; sourceTree = "<group>"; }; >+ E95569E920F56D0500F5CF34 /* FuncParameter.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FuncParameter.js; path = ../../../FuncParameter.js; sourceTree = "<group>"; }; >+ E95569EA20F56D0500F5CF34 /* FloatLiteralType.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FloatLiteralType.js; path = ../../../FloatLiteralType.js; sourceTree = "<group>"; }; >+ E95569EB20F56D0500F5CF34 /* FoldConstexprs.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FoldConstexprs.js; path = ../../../FoldConstexprs.js; sourceTree = "<group>"; }; >+ E9AD074620F56D5A007F2466 /* DoWhileLoop.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = DoWhileLoop.js; path = ../../../DoWhileLoop.js; sourceTree = "<group>"; }; >+ E9AD074820F56D5A007F2466 /* EBuffer.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = EBuffer.js; path = ../../../EBuffer.js; sourceTree = "<group>"; }; >+ E9AD074920F56D5A007F2466 /* EArrayRef.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = EArrayRef.js; path = ../../../EArrayRef.js; sourceTree = "<group>"; }; >+ E9AD074A20F56D5B007F2466 /* EBufferBuilder.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = EBufferBuilder.js; path = ../../../EBufferBuilder.js; sourceTree = "<group>"; }; >+ E9AD074B20F56D5B007F2466 /* DotExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = DotExpression.js; path = ../../../DotExpression.js; sourceTree = "<group>"; }; >+ E9AD075320F56D69007F2466 /* EvaluationCommon.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = EvaluationCommon.js; path = ../../../EvaluationCommon.js; sourceTree = "<group>"; }; >+ E9AD075420F56D69007F2466 /* Expression.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = Expression.js; path = ../../../Expression.js; sourceTree = "<group>"; }; >+ E9AD075520F56D69007F2466 /* EnumMember.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = EnumMember.js; path = ../../../EnumMember.js; sourceTree = "<group>"; }; >+ E9AD075620F56D69007F2466 /* FlattenedStructOffsetGatherer.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FlattenedStructOffsetGatherer.js; path = ../../../FlattenedStructOffsetGatherer.js; sourceTree = "<group>"; }; >+ E9AD075720F56D69007F2466 /* Evaluator.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = Evaluator.js; path = ../../../Evaluator.js; sourceTree = "<group>"; }; >+ E9AD075820F56D69007F2466 /* FindHighZombies.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FindHighZombies.js; path = ../../../FindHighZombies.js; sourceTree = "<group>"; }; >+ E9AD075920F56D69007F2466 /* ExpressionFinder.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = ExpressionFinder.js; path = ../../../ExpressionFinder.js; sourceTree = "<group>"; }; >+ E9AD075A20F56D69007F2466 /* EnumType.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = EnumType.js; path = ../../../EnumType.js; sourceTree = "<group>"; }; >+ E9AD075B20F56D69007F2466 /* ExternalOrigin.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = ExternalOrigin.js; path = ../../../ExternalOrigin.js; sourceTree = "<group>"; }; >+ E9AD075C20F56D69007F2466 /* FloatLiteral.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FloatLiteral.js; path = ../../../FloatLiteral.js; sourceTree = "<group>"; }; >+ E9E11932211E61640014D553 /* Shaders.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Shaders.metal; sourceTree = "<group>"; }; >+ E9FCEB5520F56D92009B3629 /* Func.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Func.js; path = ../../../Func.js; sourceTree = "<group>"; }; >+ E9FCEB5720F56D93009B3629 /* IfStatement.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = IfStatement.js; path = ../../../IfStatement.js; sourceTree = "<group>"; }; >+ E9FCEB5820F56D93009B3629 /* IdentityExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = IdentityExpression.js; path = ../../../IdentityExpression.js; sourceTree = "<group>"; }; >+ E9FCEB5A20F56D93009B3629 /* ForLoop.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ForLoop.js; path = ../../../ForLoop.js; sourceTree = "<group>"; }; >+ E9FCEB5B20F56D93009B3629 /* Field.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Field.js; path = ../../../Field.js; sourceTree = "<group>"; }; >+ E9FCEB6320F56DA4009B3629 /* IndexExpression.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = IndexExpression.js; path = ../../../IndexExpression.js; sourceTree = "<group>"; }; >+ E9FCEB6420F56DA5009B3629 /* LateChecker.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = LateChecker.js; path = ../../../LateChecker.js; sourceTree = "<group>"; }; >+ E9FCEB6520F56DA5009B3629 /* InferTypesForCall.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = InferTypesForCall.js; path = ../../../InferTypesForCall.js; sourceTree = "<group>"; }; >+ E9FCEB6620F56DA5009B3629 /* Inline.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = Inline.js; path = ../../../Inline.js; sourceTree = "<group>"; }; >+/* End PBXFileReference section */ >+ >+/* Begin PBXFrameworksBuildPhase section */ >+ E94C06BD20F56A4000672992 /* Frameworks */ = { >+ isa = PBXFrameworksBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ E92D109120F56F5700D776B2 /* JavaScriptCore.framework in Frameworks */, >+ E92D108F20F56F4F00D776B2 /* Metal.framework in Frameworks */, >+ E92D108D20F56F4500D776B2 /* MetalKit.framework in Frameworks */, >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ }; >+ E94C06D320F56A4200672992 /* Frameworks */ = { >+ isa = PBXFrameworksBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ }; >+/* End PBXFrameworksBuildPhase section */ >+ >+/* Begin PBXGroup section */ >+ E906B04A2114BD1D00AD1C5E /* Demo shaders */ = { >+ isa = PBXGroup; >+ children = ( >+ E92D109220F5734900D776B2 /* Default.whlsl */, >+ E906B04521139B7700AD1C5E /* Julia.whlsl */, >+ E94D124E2114BD7600B0F967 /* Mandelbrot.whlsl */, >+ ); >+ path = "Demo shaders"; >+ sourceTree = "<group>"; >+ }; >+ E92D108B20F56F4400D776B2 /* Frameworks */ = { >+ isa = PBXGroup; >+ children = ( >+ E92D109020F56F5700D776B2 /* JavaScriptCore.framework */, >+ E92D108E20F56F4F00D776B2 /* Metal.framework */, >+ E92D108C20F56F4500D776B2 /* MetalKit.framework */, >+ ); >+ name = Frameworks; >+ sourceTree = "<group>"; >+ }; >+ E92D11AE20F70BAE00D776B2 /* Renderer */ = { >+ isa = PBXGroup; >+ children = ( >+ E92D11AB20F7081500D776B2 /* OffscreenRenderer.h */, >+ E92D11AC20F7081500D776B2 /* OffscreenRenderer.m */, >+ E92D10AD20F57C9F00D776B2 /* OnscreenRenderer.h */, >+ E92D10AE20F57C9F00D776B2 /* OnscreenRenderer.m */, >+ E92D111320F6FFB600D776B2 /* Renderer.h */, >+ E92D111420F6FFB600D776B2 /* Renderer.m */, >+ ); >+ path = Renderer; >+ sourceTree = "<group>"; >+ }; >+ E92EDFF4211546910042F960 /* App */ = { >+ isa = PBXGroup; >+ children = ( >+ E92EDFF5211546A40042F960 /* AppDelegate.h */, >+ E92EDFF7211546A40042F960 /* AppDelegate.m */, >+ E92EDFF8211546A40042F960 /* CustomMetalView.h */, >+ E92EDFF6211546A40042F960 /* CustomMetalView.m */, >+ E92EDFFE211546AB0042F960 /* Main.storyboard */, >+ E92EDFF9211546A40042F960 /* ViewController.h */, >+ E92EDFFA211546A40042F960 /* ViewController.m */, >+ ); >+ name = App; >+ sourceTree = "<group>"; >+ }; >+ E92EE0012115499E0042F960 /* Test execution */ = { >+ isa = PBXGroup; >+ children = ( >+ E92EE00B211554980042F960 /* _Shared.whlsl */, >+ E92EE002211549C50042F960 /* TestCallArgument.h */, >+ E92EE003211549C50042F960 /* TestCallArgument.m */, >+ E92EE00821154B5A0042F960 /* TestDescription.h */, >+ E92EE00921154B5A0042F960 /* TestDescription.m */, >+ E92EE00521154AC40042F960 /* TestFamily.h */, >+ E92EE00621154AC40042F960 /* TestFamily.m */, >+ E92EE00D211563300042F960 /* TestFamilyRunner.h */, >+ E92EE00E211563300042F960 /* TestFamilyRunner.m */, >+ ); >+ name = "Test execution"; >+ sourceTree = "<group>"; >+ }; >+ E94C06B720F56A4000672992 = { >+ isa = PBXGroup; >+ children = ( >+ E94C06C220F56A4000672992 /* Core */, >+ E92D108B20F56F4400D776B2 /* Frameworks */, >+ E94C06C120F56A4000672992 /* Products */, >+ E94C06D920F56A4200672992 /* WHLSL Tests */, >+ ); >+ sourceTree = "<group>"; >+ }; >+ E94C06C120F56A4000672992 /* Products */ = { >+ isa = PBXGroup; >+ children = ( >+ E94C06C020F56A4000672992 /* WHLSL Tests.app */, >+ E94C06D620F56A4200672992 /* WHLSL TestsTests.xctest */, >+ ); >+ name = Products; >+ sourceTree = "<group>"; >+ }; >+ E94C06C220F56A4000672992 /* Core */ = { >+ isa = PBXGroup; >+ children = ( >+ E92EDFF4211546910042F960 /* App */, >+ E906B04A2114BD1D00AD1C5E /* Demo shaders */, >+ E9E11931211E614D0014D553 /* Metal equivalents */, >+ E92D11AE20F70BAE00D776B2 /* Renderer */, >+ E94C06F620F56C4F00672992 /* Scripts */, >+ E92EE0012115499E0042F960 /* Test execution */, >+ E94C06C920F56A4200672992 /* Assets.xcassets */, >+ E92D108820F56F0600D776B2 /* Compiler.h */, >+ E92D108920F56F0600D776B2 /* Compiler.m */, >+ E92D11B920F7F67300D776B2 /* CompileResult.h */, >+ E92D11BA20F7F67300D776B2 /* CompileResult.m */, >+ E94C06CE20F56A4200672992 /* Info.plist */, >+ E94C06CF20F56A4200672992 /* main.m */, >+ E94C06D120F56A4200672992 /* WHLSL.entitlements */, >+ ); >+ path = Core; >+ sourceTree = "<group>"; >+ }; >+ E94C06D920F56A4200672992 /* WHLSL Tests */ = { >+ isa = PBXGroup; >+ children = ( >+ E94C06DC20F56A4200672992 /* Info.plist */, >+ E94C06DA20F56A4200672992 /* WHLSL_ToyTests.m */, >+ ); >+ name = "WHLSL Tests"; >+ path = "WHLSL ToyTests"; >+ sourceTree = "<group>"; >+ }; >+ E94C06F620F56C4F00672992 /* Scripts */ = { >+ isa = PBXGroup; >+ children = ( >+ E95569BA20F56CD600F5CF34 /* AddressSpace.js */, >+ E95569BC20F56CD700F5CF34 /* All.js */, >+ E95569BD20F56CD700F5CF34 /* AnonymousVariable.js */, >+ E95569B520F56CD600F5CF34 /* ArrayRefType.js */, >+ E95569B420F56CD600F5CF34 /* ArrayType.js */, >+ E95569B920F56CD600F5CF34 /* Assignment.js */, >+ E95569BE20F56CD700F5CF34 /* AutoWrapper.js */, >+ E94C06FC20F56CA300672992 /* Block.js */, >+ E95569B120F56CD600F5CF34 /* BoolLiteral.js */, >+ E95569B020F56CD600F5CF34 /* Break.js */, >+ E921D6342138C02600775099 /* BuiltinMatrixGetter.js */, >+ E921D6352138C02600775099 /* BuiltinMatrixSetter.js */, >+ E941ACB92134A5BB00392BA9 /* BuiltinVectorGetter.js */, >+ E941ACBC2134A5BB00392BA9 /* BuiltinVectorSetter.js */, >+ E95569BF20F56CD700F5CF34 /* CallExpression.js */, >+ E95569C020F56CD700F5CF34 /* CallFunction.js */, >+ E95569B820F56CD600F5CF34 /* Check.js */, >+ E95569C120F56CD700F5CF34 /* Checker.js */, >+ E95569B620F56CD600F5CF34 /* CheckLiteralTypes.js */, >+ E95569B320F56CD600F5CF34 /* CheckLoops.js */, >+ E94C06FA20F56CA300672992 /* CheckRecursion.js */, >+ E95569BB20F56CD600F5CF34 /* CheckRecursiveTypes.js */, >+ E95569B220F56CD600F5CF34 /* CheckReturns.js */, >+ E941ACAE2134A5BA00392BA9 /* CheckTypesWithArguments.js */, >+ E95569B720F56CD600F5CF34 /* CheckUnreachableCode.js */, >+ E95569D420F56CED00F5CF34 /* CheckWrapped.js */, >+ E95569DB20F56CEE00F5CF34 /* CloneProgram.js */, >+ E95569DC20F56CEE00F5CF34 /* CommaExpression.js */, >+ E94C06F720F56C6000672992 /* compiler.js */, >+ E95569D520F56CED00F5CF34 /* ConstexprFolder.js */, >+ E95569D720F56CED00F5CF34 /* Continue.js */, >+ E95569D920F56CED00F5CF34 /* ConvertPtrToArrayRefExpression.js */, >+ E95569D820F56CED00F5CF34 /* CreateLiteral.js */, >+ E95569D620F56CED00F5CF34 /* CreateLiteralType.js */, >+ E94C06F920F56CA300672992 /* DereferenceExpression.js */, >+ E9AD074B20F56D5B007F2466 /* DotExpression.js */, >+ E9AD074620F56D5A007F2466 /* DoWhileLoop.js */, >+ E9AD074920F56D5A007F2466 /* EArrayRef.js */, >+ E9AD074820F56D5A007F2466 /* EBuffer.js */, >+ E9AD074A20F56D5B007F2466 /* EBufferBuilder.js */, >+ E94C06FD20F56CA300672992 /* EnumLiteral.js */, >+ E9AD075520F56D69007F2466 /* EnumMember.js */, >+ E9AD075A20F56D69007F2466 /* EnumType.js */, >+ E95569E720F56D0500F5CF34 /* EPtr.js */, >+ E9AD075320F56D69007F2466 /* EvaluationCommon.js */, >+ E9AD075720F56D69007F2466 /* Evaluator.js */, >+ E9AD075420F56D69007F2466 /* Expression.js */, >+ E9AD075920F56D69007F2466 /* ExpressionFinder.js */, >+ E9AD075B20F56D69007F2466 /* ExternalOrigin.js */, >+ E9FCEB5B20F56D93009B3629 /* Field.js */, >+ E9AD075820F56D69007F2466 /* FindHighZombies.js */, >+ E9AD075620F56D69007F2466 /* FlattenedStructOffsetGatherer.js */, >+ E9AD075C20F56D69007F2466 /* FloatLiteral.js */, >+ E95569EA20F56D0500F5CF34 /* FloatLiteralType.js */, >+ E95569EB20F56D0500F5CF34 /* FoldConstexprs.js */, >+ E9FCEB5A20F56D93009B3629 /* ForLoop.js */, >+ E9FCEB5520F56D92009B3629 /* Func.js */, >+ E95569E820F56D0500F5CF34 /* FuncDef.js */, >+ E95569E920F56D0500F5CF34 /* FuncParameter.js */, >+ E95569E620F56D0500F5CF34 /* FunctionLikeBlock.js */, >+ E94C06FB20F56CA300672992 /* HighZombieFinder.js */, >+ E9FCEB5820F56D93009B3629 /* IdentityExpression.js */, >+ E9FCEB5720F56D93009B3629 /* IfStatement.js */, >+ E9FCEB6320F56DA4009B3629 /* IndexExpression.js */, >+ E9FCEB6520F56DA5009B3629 /* InferTypesForCall.js */, >+ E9FCEB6620F56DA5009B3629 /* Inline.js */, >+ E92D0FE820F56DDD00D776B2 /* Inliner.js */, >+ E92D0FE420F56DDD00D776B2 /* IntLiteral.js */, >+ E92D0FE520F56DDD00D776B2 /* IntLiteralType.js */, >+ E92D0FE720F56DDD00D776B2 /* Intrinsics.js */, >+ E9FCEB6420F56DA5009B3629 /* LateChecker.js */, >+ E92D0FF120F56DEC00D776B2 /* Lexer.js */, >+ E92D0FF020F56DEB00D776B2 /* LexerToken.js */, >+ E92D0FF220F56DEC00D776B2 /* LiteralTypeChecker.js */, >+ E92D0FEE20F56DEB00D776B2 /* LogicalExpression.js */, >+ E92D0FEF20F56DEB00D776B2 /* LogicalNot.js */, >+ E92D0FFB20F56DFB00D776B2 /* LoopChecker.js */, >+ E92D0FFC20F56DFB00D776B2 /* MakeArrayRefExpression.js */, >+ E92D0FF920F56DFA00D776B2 /* MakePtrExpression.js */, >+ E921D6332138C02600775099 /* MatrixType.js */, >+ E92D0FF820F56DFA00D776B2 /* NameContext.js */, >+ E92D0FFA20F56DFB00D776B2 /* NameFinder.js */, >+ E92D100320F56E0900D776B2 /* NameResolver.js */, >+ E92D100520F56E0900D776B2 /* NativeFunc.js */, >+ E92D100620F56E0900D776B2 /* NativeType.js */, >+ E92D100F20F56E1500D776B2 /* Node.js */, >+ E92D100D20F56E1500D776B2 /* NormalUsePropertyResolver.js */, >+ E92D100C20F56E1500D776B2 /* NullLiteral.js */, >+ E92D101020F56E1500D776B2 /* NullType.js */, >+ E921D6322138C02600775099 /* OperatorAnderIndexer.js */, >+ E941ACB62134A5BB00392BA9 /* OperatorArrayRefLength.js */, >+ E92D100E20F56E1500D776B2 /* OriginKind.js */, >+ E92D101920F56E2200D776B2 /* OverloadResolutionFailure.js */, >+ E92D101720F56E2200D776B2 /* Parse.js */, >+ E92D101820F56E2200D776B2 /* Prepare.js */, >+ E92D101A20F56E2200D776B2 /* Program.js */, >+ E92D101620F56E2100D776B2 /* ProgramWithUnnecessaryThingsRemoved.js */, >+ E92D102320F56E2F00D776B2 /* PropertyAccessExpression.js */, >+ E92D102020F56E2F00D776B2 /* PropertyResolver.js */, >+ E92D102B20F56E3F00D776B2 /* PtrType.js */, >+ E92D102A20F56E3F00D776B2 /* ReadModifyWriteExpression.js */, >+ E92D102C20F56E3F00D776B2 /* RecursionChecker.js */, >+ E92D102E20F56E4000D776B2 /* RecursiveTypeChecker.js */, >+ E92D103520F56E4F00D776B2 /* ReferenceType.js */, >+ E92D103420F56E4F00D776B2 /* ResolveNames.js */, >+ E92D103820F56E4F00D776B2 /* ResolveOverloadImpl.js */, >+ E92D103620F56E4F00D776B2 /* ResolveProperties.js */, >+ E92D103720F56E4F00D776B2 /* ResolveTypeDefs.js */, >+ E92D103E20F56E6100D776B2 /* Return.js */, >+ E92D104020F56E6200D776B2 /* ReturnChecker.js */, >+ E92D104220F56E6200D776B2 /* ReturnException.js */, >+ E92D104120F56E6200D776B2 /* Rewriter.js */, >+ E92D103F20F56E6200D776B2 /* StandardLibrary.js */, >+ E92D104820F56E7300D776B2 /* StatementCloner.js */, >+ E92D104920F56E7300D776B2 /* StructLayoutBuilder.js */, >+ E92D104A20F56E7300D776B2 /* StructType.js */, >+ E92D104B20F56E7300D776B2 /* SwitchCase.js */, >+ E92D105220F56E8400D776B2 /* SwitchStatement.js */, >+ E941ACB72134A5BB00392BA9 /* SynthesizeArrayOperatorLength.js */, >+ E941ACAF2134A5BA00392BA9 /* SynthesizeCopyConstructorOperator.js */, >+ E941ACB32134A5BB00392BA9 /* SynthesizeDefaultConstructorOperator.js */, >+ E92D105420F56E8500D776B2 /* SynthesizeEnumFunctions.js */, >+ E92D105320F56E8400D776B2 /* SynthesizeStructAccessors.js */, >+ E941ACB52134A5BB00392BA9 /* TernaryExpression.js */, >+ E94D127E2114C6FF00B0F967 /* Test.js */, >+ E92D105620F56E8500D776B2 /* TrapStatement.js */, >+ E92D105520F56E8500D776B2 /* Type.js */, >+ E92D105F20F56E9500D776B2 /* TypeDef.js */, >+ E92D105E20F56E9500D776B2 /* TypeDefResolver.js */, >+ E92D106020F56E9500D776B2 /* TypedValue.js */, >+ E941ACBA2134A5BB00392BA9 /* TypeOverloadResolutionFailure.js */, >+ E92D106620F56EA400D776B2 /* TypeRef.js */, >+ E92D106820F56EA400D776B2 /* UintLiteral.js */, >+ E92D106720F56EA400D776B2 /* UintLiteralType.js */, >+ E92D107220F56EBB00D776B2 /* UnificationContext.js */, >+ E92D107320F56EBC00D776B2 /* UnreachableCodeChecker.js */, >+ E92D107420F56EBC00D776B2 /* Value.js */, >+ E92D107020F56EBB00D776B2 /* VariableDecl.js */, >+ E92D107120F56EBB00D776B2 /* VariableRef.js */, >+ E941ACBB2134A5BB00392BA9 /* VectorType.js */, >+ E92D107C20F56ECF00D776B2 /* VisitingSet.js */, >+ E92D107A20F56ECF00D776B2 /* Visitor.js */, >+ E92D107D20F56ECF00D776B2 /* WhileLoop.js */, >+ E92D107B20F56ECF00D776B2 /* WrapChecker.js */, >+ E92D108220F56EDE00D776B2 /* WSyntaxError.js */, >+ E92D108420F56EDE00D776B2 /* WTrapError.js */, >+ E92D108320F56EDE00D776B2 /* WTypeError.js */, >+ ); >+ name = Scripts; >+ sourceTree = "<group>"; >+ }; >+ E9E11931211E614D0014D553 /* Metal equivalents */ = { >+ isa = PBXGroup; >+ children = ( >+ E9E11932211E61640014D553 /* Shaders.metal */, >+ ); >+ path = "Metal equivalents"; >+ sourceTree = "<group>"; >+ }; >+/* End PBXGroup section */ >+ >+/* Begin PBXNativeTarget section */ >+ E94C06BF20F56A4000672992 /* WHLSL Tests */ = { >+ isa = PBXNativeTarget; >+ buildConfigurationList = E94C06EA20F56A4200672992 /* Build configuration list for PBXNativeTarget "WHLSL Tests" */; >+ buildPhases = ( >+ E925653C21234AA1001A89D9 /* ShellScript */, >+ E94C06BC20F56A4000672992 /* Sources */, >+ E94C06BD20F56A4000672992 /* Frameworks */, >+ E94C06BE20F56A4000672992 /* Resources */, >+ ); >+ buildRules = ( >+ ); >+ dependencies = ( >+ ); >+ name = "WHLSL Tests"; >+ productName = "WHLSL Toy"; >+ productReference = E94C06C020F56A4000672992 /* WHLSL Tests.app */; >+ productType = "com.apple.product-type.application"; >+ }; >+ E94C06D520F56A4200672992 /* WHLSL TestsTests */ = { >+ isa = PBXNativeTarget; >+ buildConfigurationList = E94C06ED20F56A4200672992 /* Build configuration list for PBXNativeTarget "WHLSL TestsTests" */; >+ buildPhases = ( >+ E94C06D220F56A4200672992 /* Sources */, >+ E94C06D320F56A4200672992 /* Frameworks */, >+ E94C06D420F56A4200672992 /* Resources */, >+ ); >+ buildRules = ( >+ ); >+ dependencies = ( >+ E94C06D820F56A4200672992 /* PBXTargetDependency */, >+ ); >+ name = "WHLSL TestsTests"; >+ productName = "WHLSL ToyTests"; >+ productReference = E94C06D620F56A4200672992 /* WHLSL TestsTests.xctest */; >+ productType = "com.apple.product-type.bundle.unit-test"; >+ }; >+/* End PBXNativeTarget section */ >+ >+/* Begin PBXProject section */ >+ E94C06B820F56A4000672992 /* Project object */ = { >+ isa = PBXProject; >+ attributes = { >+ LastUpgradeCheck = 1000; >+ ORGANIZATIONNAME = "Apple, Inc."; >+ TargetAttributes = { >+ E94C06BF20F56A4000672992 = { >+ CreatedOnToolsVersion = 10.0; >+ }; >+ E94C06D520F56A4200672992 = { >+ CreatedOnToolsVersion = 10.0; >+ TestTargetID = E94C06BF20F56A4000672992; >+ }; >+ }; >+ }; >+ buildConfigurationList = E94C06BB20F56A4000672992 /* Build configuration list for PBXProject "WHLSL Tests" */; >+ compatibilityVersion = "Xcode 9.3"; >+ developmentRegion = en; >+ hasScannedForEncodings = 0; >+ knownRegions = ( >+ en, >+ Base, >+ ); >+ mainGroup = E94C06B720F56A4000672992; >+ productRefGroup = E94C06C120F56A4000672992 /* Products */; >+ projectDirPath = ""; >+ projectRoot = ""; >+ targets = ( >+ E94C06BF20F56A4000672992 /* WHLSL Tests */, >+ E94C06D520F56A4200672992 /* WHLSL TestsTests */, >+ ); >+ }; >+/* End PBXProject section */ >+ >+/* Begin PBXResourcesBuildPhase section */ >+ E94C06BE20F56A4000672992 /* Resources */ = { >+ isa = PBXResourcesBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ E92EE00C211554980042F960 /* _Shared.whlsl in Resources */, >+ E92D111620F7060E00D776B2 /* AddressSpace.js in Resources */, >+ E92D111720F7060E00D776B2 /* All.js in Resources */, >+ E92D111820F7060E00D776B2 /* AnonymousVariable.js in Resources */, >+ E92D111920F7060E00D776B2 /* ArrayRefType.js in Resources */, >+ E92D111A20F7060E00D776B2 /* ArrayType.js in Resources */, >+ E94C06CA20F56A4200672992 /* Assets.xcassets in Resources */, >+ E92D111B20F7060E00D776B2 /* Assignment.js in Resources */, >+ E92D111C20F7060E00D776B2 /* AutoWrapper.js in Resources */, >+ E92D111D20F7060E00D776B2 /* Block.js in Resources */, >+ E92D111E20F7060E00D776B2 /* BoolLiteral.js in Resources */, >+ E92D111F20F7060E00D776B2 /* Break.js in Resources */, >+ E921D6382138C02600775099 /* BuiltinMatrixGetter.js in Resources */, >+ E921D6392138C02600775099 /* BuiltinMatrixSetter.js in Resources */, >+ E941ACCA2134A5BC00392BA9 /* BuiltinVectorGetter.js in Resources */, >+ E941ACCD2134A5BC00392BA9 /* BuiltinVectorSetter.js in Resources */, >+ E92D112020F7060E00D776B2 /* CallExpression.js in Resources */, >+ E92D112120F7060E00D776B2 /* CallFunction.js in Resources */, >+ E92D112220F7060E00D776B2 /* Check.js in Resources */, >+ E92D112320F7060E00D776B2 /* Checker.js in Resources */, >+ E92D112420F7060E00D776B2 /* CheckLiteralTypes.js in Resources */, >+ E92D112520F7060E00D776B2 /* CheckLoops.js in Resources */, >+ E92D112620F7060E00D776B2 /* CheckRecursion.js in Resources */, >+ E92D112720F7060E00D776B2 /* CheckRecursiveTypes.js in Resources */, >+ E92D112820F7060E00D776B2 /* CheckReturns.js in Resources */, >+ E941ACBF2134A5BC00392BA9 /* CheckTypesWithArguments.js in Resources */, >+ E92D112920F7060E00D776B2 /* CheckUnreachableCode.js in Resources */, >+ E92D112A20F7060E00D776B2 /* CheckWrapped.js in Resources */, >+ E92D112B20F7060E00D776B2 /* CloneProgram.js in Resources */, >+ E92D112C20F7060E00D776B2 /* CommaExpression.js in Resources */, >+ E92D112D20F7060E00D776B2 /* compiler.js in Resources */, >+ E92D112E20F7060E00D776B2 /* ConstexprFolder.js in Resources */, >+ E92D113020F7060E00D776B2 /* Continue.js in Resources */, >+ E92D113120F7060E00D776B2 /* ConvertPtrToArrayRefExpression.js in Resources */, >+ E92D113220F7060E00D776B2 /* CreateLiteral.js in Resources */, >+ E92D113320F7060E00D776B2 /* CreateLiteralType.js in Resources */, >+ E92D109320F5734900D776B2 /* Default.whlsl in Resources */, >+ E92D113420F7060E00D776B2 /* DereferenceExpression.js in Resources */, >+ E92D113520F7060E00D776B2 /* DotExpression.js in Resources */, >+ E92D113820F7060E00D776B2 /* DoWhileLoop.js in Resources */, >+ E92D113920F7060E00D776B2 /* EArrayRef.js in Resources */, >+ E92D113A20F7060E00D776B2 /* EBuffer.js in Resources */, >+ E92D113B20F7060E00D776B2 /* EBufferBuilder.js in Resources */, >+ E92D113C20F7060E00D776B2 /* EnumLiteral.js in Resources */, >+ E92D113D20F7060E00D776B2 /* EnumMember.js in Resources */, >+ E92D113E20F7060E00D776B2 /* EnumType.js in Resources */, >+ E92D113F20F7060E00D776B2 /* EPtr.js in Resources */, >+ E92D114020F7060E00D776B2 /* EvaluationCommon.js in Resources */, >+ E92D114120F7060E00D776B2 /* Evaluator.js in Resources */, >+ E92D114220F7060E00D776B2 /* Expression.js in Resources */, >+ E92D114320F7060E00D776B2 /* ExpressionFinder.js in Resources */, >+ E92D114420F7060E00D776B2 /* ExternalOrigin.js in Resources */, >+ E92D114520F7060E00D776B2 /* Field.js in Resources */, >+ E92D114620F7060E00D776B2 /* FindHighZombies.js in Resources */, >+ E92D114720F7060E00D776B2 /* FlattenedStructOffsetGatherer.js in Resources */, >+ E92D114920F7060E00D776B2 /* FloatLiteral.js in Resources */, >+ E92D114A20F7060E00D776B2 /* FloatLiteralType.js in Resources */, >+ E92D114B20F7060E00D776B2 /* FoldConstexprs.js in Resources */, >+ E92D114C20F7060E00D776B2 /* ForLoop.js in Resources */, >+ E92D114D20F7060E00D776B2 /* Func.js in Resources */, >+ E92D114E20F7060E00D776B2 /* FuncDef.js in Resources */, >+ E92D115020F7060E00D776B2 /* FuncParameter.js in Resources */, >+ E92D115120F7060E00D776B2 /* FunctionLikeBlock.js in Resources */, >+ E92D115220F7060E00D776B2 /* HighZombieFinder.js in Resources */, >+ E92D115320F7060E00D776B2 /* IdentityExpression.js in Resources */, >+ E92D115420F7060E00D776B2 /* IfStatement.js in Resources */, >+ E92D115520F7060E00D776B2 /* IndexExpression.js in Resources */, >+ E92D115620F7060E00D776B2 /* InferTypesForCall.js in Resources */, >+ E92D115720F7060E00D776B2 /* Inline.js in Resources */, >+ E92D115820F7060E00D776B2 /* Inliner.js in Resources */, >+ E92D115A20F7060E00D776B2 /* IntLiteral.js in Resources */, >+ E92D115B20F7060E00D776B2 /* IntLiteralType.js in Resources */, >+ E92D115C20F7060E00D776B2 /* Intrinsics.js in Resources */, >+ E906B04621139B7700AD1C5E /* Julia.whlsl in Resources */, >+ E92D115D20F7060E00D776B2 /* LateChecker.js in Resources */, >+ E92D115E20F7060E00D776B2 /* Lexer.js in Resources */, >+ E92D115F20F7060E00D776B2 /* LexerToken.js in Resources */, >+ E92D116020F7060E00D776B2 /* LiteralTypeChecker.js in Resources */, >+ E92D116120F7060E00D776B2 /* LogicalExpression.js in Resources */, >+ E92D116220F7060E00D776B2 /* LogicalNot.js in Resources */, >+ E92D116320F7060E00D776B2 /* LoopChecker.js in Resources */, >+ E92EE000211546AB0042F960 /* Main.storyboard in Resources */, >+ E92D116420F7060E00D776B2 /* MakeArrayRefExpression.js in Resources */, >+ E92D116520F7060E00D776B2 /* MakePtrExpression.js in Resources */, >+ E94D124F2114BD7600B0F967 /* Mandelbrot.whlsl in Resources */, >+ E921D6372138C02600775099 /* MatrixType.js in Resources */, >+ E92D116620F7060E00D776B2 /* NameContext.js in Resources */, >+ E92D116720F7060E00D776B2 /* NameFinder.js in Resources */, >+ E92D116820F7060E00D776B2 /* NameResolver.js in Resources */, >+ E92D116920F7060E00D776B2 /* NativeFunc.js in Resources */, >+ E92D116B20F7060E00D776B2 /* NativeType.js in Resources */, >+ E92D116D20F7060E00D776B2 /* Node.js in Resources */, >+ E92D116E20F7060E00D776B2 /* NormalUsePropertyResolver.js in Resources */, >+ E92D116F20F7060E00D776B2 /* NullLiteral.js in Resources */, >+ E92D117020F7060E00D776B2 /* NullType.js in Resources */, >+ E921D6362138C02600775099 /* OperatorAnderIndexer.js in Resources */, >+ E941ACC72134A5BC00392BA9 /* OperatorArrayRefLength.js in Resources */, >+ E92D117120F7060E00D776B2 /* OriginKind.js in Resources */, >+ E92D117220F7060E00D776B2 /* OverloadResolutionFailure.js in Resources */, >+ E92D117320F7060E00D776B2 /* Parse.js in Resources */, >+ E92D117420F7060E00D776B2 /* Prepare.js in Resources */, >+ E92D117520F7060E00D776B2 /* Program.js in Resources */, >+ E92D117620F7060E00D776B2 /* ProgramWithUnnecessaryThingsRemoved.js in Resources */, >+ E92D117720F7060E00D776B2 /* PropertyAccessExpression.js in Resources */, >+ E92D117820F7060E00D776B2 /* PropertyResolver.js in Resources */, >+ E92D117D20F7060E00D776B2 /* PtrType.js in Resources */, >+ E92D117E20F7060E00D776B2 /* ReadModifyWriteExpression.js in Resources */, >+ E92D117F20F7060E00D776B2 /* RecursionChecker.js in Resources */, >+ E92D118020F7060E00D776B2 /* RecursiveTypeChecker.js in Resources */, >+ E92D118120F7060E00D776B2 /* ReferenceType.js in Resources */, >+ E92D118220F7060E00D776B2 /* ResolveNames.js in Resources */, >+ E92D118320F7060E00D776B2 /* ResolveOverloadImpl.js in Resources */, >+ E92D118420F7060E00D776B2 /* ResolveProperties.js in Resources */, >+ E92D118520F7060E00D776B2 /* ResolveTypeDefs.js in Resources */, >+ E92D118620F7060E00D776B2 /* Return.js in Resources */, >+ E92D118720F7060E00D776B2 /* ReturnChecker.js in Resources */, >+ E92D118820F7060E00D776B2 /* ReturnException.js in Resources */, >+ E92D118920F7060E00D776B2 /* Rewriter.js in Resources */, >+ E92D118A20F7060E00D776B2 /* StandardLibrary.js in Resources */, >+ E92D118B20F7060E00D776B2 /* StatementCloner.js in Resources */, >+ E92D118C20F7060E00D776B2 /* StructLayoutBuilder.js in Resources */, >+ E92D118D20F7060E00D776B2 /* StructType.js in Resources */, >+ E92D118F20F7060E00D776B2 /* SwitchCase.js in Resources */, >+ E92D119020F7060E00D776B2 /* SwitchStatement.js in Resources */, >+ E941ACC82134A5BC00392BA9 /* SynthesizeArrayOperatorLength.js in Resources */, >+ E941ACC02134A5BC00392BA9 /* SynthesizeCopyConstructorOperator.js in Resources */, >+ E941ACC42134A5BC00392BA9 /* SynthesizeDefaultConstructorOperator.js in Resources */, >+ E92D119120F7060E00D776B2 /* SynthesizeEnumFunctions.js in Resources */, >+ E92D119220F7060E00D776B2 /* SynthesizeStructAccessors.js in Resources */, >+ E941ACC62134A5BC00392BA9 /* TernaryExpression.js in Resources */, >+ E94D127F2114C6FF00B0F967 /* Test.js in Resources */, >+ E92D119320F7060E00D776B2 /* TrapStatement.js in Resources */, >+ E92D119420F7060E00D776B2 /* Type.js in Resources */, >+ E92D119520F7060E00D776B2 /* TypeDef.js in Resources */, >+ E92D119620F7060E00D776B2 /* TypeDefResolver.js in Resources */, >+ E92D119720F7060E00D776B2 /* TypedValue.js in Resources */, >+ E941ACCB2134A5BC00392BA9 /* TypeOverloadResolutionFailure.js in Resources */, >+ E92D119A20F7060E00D776B2 /* TypeRef.js in Resources */, >+ E92D119D20F7060E00D776B2 /* UintLiteral.js in Resources */, >+ E92D119E20F7060E00D776B2 /* UintLiteralType.js in Resources */, >+ E92D119F20F7060E00D776B2 /* UnificationContext.js in Resources */, >+ E92D11A020F7060E00D776B2 /* UnreachableCodeChecker.js in Resources */, >+ E92D11A120F7060E00D776B2 /* Value.js in Resources */, >+ E92D11A220F7060E00D776B2 /* VariableDecl.js in Resources */, >+ E92D11A320F7060E00D776B2 /* VariableRef.js in Resources */, >+ E941ACCC2134A5BC00392BA9 /* VectorType.js in Resources */, >+ E92D11A420F7060E00D776B2 /* VisitingSet.js in Resources */, >+ E92D11A520F7060E00D776B2 /* Visitor.js in Resources */, >+ E92D11A620F7060E00D776B2 /* WhileLoop.js in Resources */, >+ E92D11A720F7060E00D776B2 /* WrapChecker.js in Resources */, >+ E92D11A820F7060E00D776B2 /* WSyntaxError.js in Resources */, >+ E92D11A920F7060E00D776B2 /* WTrapError.js in Resources */, >+ E92D11AA20F7060E00D776B2 /* WTypeError.js in Resources */, >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ }; >+ E94C06D420F56A4200672992 /* Resources */ = { >+ isa = PBXResourcesBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ }; >+/* End PBXResourcesBuildPhase section */ >+ >+/* Begin PBXShellScriptBuildPhase section */ >+ E925653C21234AA1001A89D9 /* ShellScript */ = { >+ isa = PBXShellScriptBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ ); >+ inputFileListPaths = ( >+ ); >+ inputPaths = ( >+ ); >+ outputFileListPaths = ( >+ ); >+ outputPaths = ( >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ shellPath = /bin/sh; >+ shellScript = "# Type a script or drag a script file from your workspace to insert its path.\ncd \"$SRCROOT/..\"\ntsc\n"; >+ }; >+/* End PBXShellScriptBuildPhase section */ >+ >+/* Begin PBXSourcesBuildPhase section */ >+ E94C06BC20F56A4000672992 /* Sources */ = { >+ isa = PBXSourcesBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ E92EDFFC211546A40042F960 /* AppDelegate.m in Sources */, >+ E92D108A20F56F0600D776B2 /* Compiler.m in Sources */, >+ E92D11BB20F7F67300D776B2 /* CompileResult.m in Sources */, >+ E92EDFFB211546A40042F960 /* CustomMetalView.m in Sources */, >+ E94C06D020F56A4200672992 /* main.m in Sources */, >+ E92D11AD20F7081500D776B2 /* OffscreenRenderer.m in Sources */, >+ E92D10AF20F57C9F00D776B2 /* OnscreenRenderer.m in Sources */, >+ E92D111520F6FFB600D776B2 /* Renderer.m in Sources */, >+ E9E11933211E61640014D553 /* Shaders.metal in Sources */, >+ E92EE004211549C50042F960 /* TestCallArgument.m in Sources */, >+ E92EE00A21154B5A0042F960 /* TestDescription.m in Sources */, >+ E92EE00721154AC40042F960 /* TestFamily.m in Sources */, >+ E92EE00F211563300042F960 /* TestFamilyRunner.m in Sources */, >+ E92EDFFD211546A40042F960 /* ViewController.m in Sources */, >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ }; >+ E94C06D220F56A4200672992 /* Sources */ = { >+ isa = PBXSourcesBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ E94C06DB20F56A4200672992 /* WHLSL_ToyTests.m in Sources */, >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ }; >+/* End PBXSourcesBuildPhase section */ >+ >+/* Begin PBXTargetDependency section */ >+ E94C06D820F56A4200672992 /* PBXTargetDependency */ = { >+ isa = PBXTargetDependency; >+ target = E94C06BF20F56A4000672992 /* WHLSL Tests */; >+ targetProxy = E94C06D720F56A4200672992 /* PBXContainerItemProxy */; >+ }; >+/* End PBXTargetDependency section */ >+ >+/* Begin PBXVariantGroup section */ >+ E92EDFFE211546AB0042F960 /* Main.storyboard */ = { >+ isa = PBXVariantGroup; >+ children = ( >+ E92EDFFF211546AB0042F960 /* Base */, >+ ); >+ name = Main.storyboard; >+ sourceTree = "<group>"; >+ }; >+/* End PBXVariantGroup section */ >+ >+/* Begin XCBuildConfiguration section */ >+ E94C06E820F56A4200672992 /* Debug */ = { >+ isa = XCBuildConfiguration; >+ buildSettings = { >+ ALWAYS_SEARCH_USER_PATHS = NO; >+ CLANG_ANALYZER_NONNULL = YES; >+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; >+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; >+ CLANG_CXX_LIBRARY = "libc++"; >+ CLANG_ENABLE_MODULES = YES; >+ CLANG_ENABLE_OBJC_ARC = YES; >+ CLANG_ENABLE_OBJC_WEAK = YES; >+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; >+ CLANG_WARN_BOOL_CONVERSION = YES; >+ CLANG_WARN_COMMA = YES; >+ CLANG_WARN_CONSTANT_CONVERSION = YES; >+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; >+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; >+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; >+ CLANG_WARN_EMPTY_BODY = YES; >+ CLANG_WARN_ENUM_CONVERSION = YES; >+ CLANG_WARN_INFINITE_RECURSION = YES; >+ CLANG_WARN_INT_CONVERSION = YES; >+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; >+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; >+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; >+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; >+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; >+ CLANG_WARN_STRICT_PROTOTYPES = YES; >+ CLANG_WARN_SUSPICIOUS_MOVE = YES; >+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; >+ CLANG_WARN_UNREACHABLE_CODE = YES; >+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; >+ CODE_SIGN_IDENTITY = "Mac Developer"; >+ COPY_PHASE_STRIP = NO; >+ DEBUG_INFORMATION_FORMAT = dwarf; >+ ENABLE_STRICT_OBJC_MSGSEND = YES; >+ ENABLE_TESTABILITY = YES; >+ GCC_C_LANGUAGE_STANDARD = gnu11; >+ GCC_DYNAMIC_NO_PIC = NO; >+ GCC_NO_COMMON_BLOCKS = YES; >+ GCC_OPTIMIZATION_LEVEL = 0; >+ GCC_PREPROCESSOR_DEFINITIONS = ( >+ "DEBUG=1", >+ "$(inherited)", >+ ); >+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; >+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; >+ GCC_WARN_UNDECLARED_SELECTOR = YES; >+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; >+ GCC_WARN_UNUSED_FUNCTION = YES; >+ GCC_WARN_UNUSED_VARIABLE = YES; >+ MACOSX_DEPLOYMENT_TARGET = 10.14; >+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; >+ ONLY_ACTIVE_ARCH = YES; >+ SDKROOT = macosx; >+ }; >+ name = Debug; >+ }; >+ E94C06E920F56A4200672992 /* Release */ = { >+ isa = XCBuildConfiguration; >+ buildSettings = { >+ ALWAYS_SEARCH_USER_PATHS = NO; >+ CLANG_ANALYZER_NONNULL = YES; >+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; >+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; >+ CLANG_CXX_LIBRARY = "libc++"; >+ CLANG_ENABLE_MODULES = YES; >+ CLANG_ENABLE_OBJC_ARC = YES; >+ CLANG_ENABLE_OBJC_WEAK = YES; >+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; >+ CLANG_WARN_BOOL_CONVERSION = YES; >+ CLANG_WARN_COMMA = YES; >+ CLANG_WARN_CONSTANT_CONVERSION = YES; >+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; >+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; >+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; >+ CLANG_WARN_EMPTY_BODY = YES; >+ CLANG_WARN_ENUM_CONVERSION = YES; >+ CLANG_WARN_INFINITE_RECURSION = YES; >+ CLANG_WARN_INT_CONVERSION = YES; >+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; >+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; >+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; >+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; >+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; >+ CLANG_WARN_STRICT_PROTOTYPES = YES; >+ CLANG_WARN_SUSPICIOUS_MOVE = YES; >+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; >+ CLANG_WARN_UNREACHABLE_CODE = YES; >+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; >+ CODE_SIGN_IDENTITY = "Mac Developer"; >+ COPY_PHASE_STRIP = NO; >+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; >+ ENABLE_NS_ASSERTIONS = NO; >+ ENABLE_STRICT_OBJC_MSGSEND = YES; >+ GCC_C_LANGUAGE_STANDARD = gnu11; >+ GCC_NO_COMMON_BLOCKS = YES; >+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; >+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; >+ GCC_WARN_UNDECLARED_SELECTOR = YES; >+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; >+ GCC_WARN_UNUSED_FUNCTION = YES; >+ GCC_WARN_UNUSED_VARIABLE = YES; >+ MACOSX_DEPLOYMENT_TARGET = 10.14; >+ MTL_ENABLE_DEBUG_INFO = NO; >+ SDKROOT = macosx; >+ }; >+ name = Release; >+ }; >+ E94C06EB20F56A4200672992 /* Debug */ = { >+ isa = XCBuildConfiguration; >+ buildSettings = { >+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; >+ CODE_SIGN_ENTITLEMENTS = Core/WHLSL.entitlements; >+ CODE_SIGN_IDENTITY = "-"; >+ CODE_SIGN_STYLE = Automatic; >+ COMBINE_HIDPI_IMAGES = YES; >+ DEVELOPMENT_TEAM = ""; >+ INFOPLIST_FILE = Core/Info.plist; >+ LD_RUNPATH_SEARCH_PATHS = ( >+ "$(inherited)", >+ "@executable_path/../Frameworks", >+ ); >+ PRODUCT_BUNDLE_IDENTIFIER = "com.apple.WHLSL-Toy"; >+ PRODUCT_NAME = "$(TARGET_NAME)"; >+ }; >+ name = Debug; >+ }; >+ E94C06EC20F56A4200672992 /* Release */ = { >+ isa = XCBuildConfiguration; >+ buildSettings = { >+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; >+ CODE_SIGN_ENTITLEMENTS = Core/WHLSL.entitlements; >+ CODE_SIGN_IDENTITY = "-"; >+ CODE_SIGN_STYLE = Automatic; >+ COMBINE_HIDPI_IMAGES = YES; >+ DEVELOPMENT_TEAM = ""; >+ INFOPLIST_FILE = Core/Info.plist; >+ LD_RUNPATH_SEARCH_PATHS = ( >+ "$(inherited)", >+ "@executable_path/../Frameworks", >+ ); >+ PRODUCT_BUNDLE_IDENTIFIER = "com.apple.WHLSL-Toy"; >+ PRODUCT_NAME = "$(TARGET_NAME)"; >+ }; >+ name = Release; >+ }; >+ E94C06EE20F56A4200672992 /* Debug */ = { >+ isa = XCBuildConfiguration; >+ buildSettings = { >+ BUNDLE_LOADER = "$(TEST_HOST)"; >+ CODE_SIGN_IDENTITY = "-"; >+ CODE_SIGN_STYLE = Automatic; >+ COMBINE_HIDPI_IMAGES = YES; >+ DEVELOPMENT_TEAM = ""; >+ INFOPLIST_FILE = "WHLSL ToyTests/Info.plist"; >+ LD_RUNPATH_SEARCH_PATHS = ( >+ "$(inherited)", >+ "@executable_path/../Frameworks", >+ "@loader_path/../Frameworks", >+ ); >+ PRODUCT_BUNDLE_IDENTIFIER = "com.apple.WHLSL-ToyTests"; >+ PRODUCT_NAME = "$(TARGET_NAME)"; >+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WHLSL Tests.app/Contents/MacOS/WHLSL Tests"; >+ }; >+ name = Debug; >+ }; >+ E94C06EF20F56A4200672992 /* Release */ = { >+ isa = XCBuildConfiguration; >+ buildSettings = { >+ BUNDLE_LOADER = "$(TEST_HOST)"; >+ CODE_SIGN_IDENTITY = "-"; >+ CODE_SIGN_STYLE = Automatic; >+ COMBINE_HIDPI_IMAGES = YES; >+ DEVELOPMENT_TEAM = ""; >+ INFOPLIST_FILE = "WHLSL ToyTests/Info.plist"; >+ LD_RUNPATH_SEARCH_PATHS = ( >+ "$(inherited)", >+ "@executable_path/../Frameworks", >+ "@loader_path/../Frameworks", >+ ); >+ PRODUCT_BUNDLE_IDENTIFIER = "com.apple.WHLSL-ToyTests"; >+ PRODUCT_NAME = "$(TARGET_NAME)"; >+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WHLSL Tests.app/Contents/MacOS/WHLSL Tests"; >+ }; >+ name = Release; >+ }; >+/* End XCBuildConfiguration section */ >+ >+/* Begin XCConfigurationList section */ >+ E94C06BB20F56A4000672992 /* Build configuration list for PBXProject "WHLSL Tests" */ = { >+ isa = XCConfigurationList; >+ buildConfigurations = ( >+ E94C06E820F56A4200672992 /* Debug */, >+ E94C06E920F56A4200672992 /* Release */, >+ ); >+ defaultConfigurationIsVisible = 0; >+ defaultConfigurationName = Release; >+ }; >+ E94C06EA20F56A4200672992 /* Build configuration list for PBXNativeTarget "WHLSL Tests" */ = { >+ isa = XCConfigurationList; >+ buildConfigurations = ( >+ E94C06EB20F56A4200672992 /* Debug */, >+ E94C06EC20F56A4200672992 /* Release */, >+ ); >+ defaultConfigurationIsVisible = 0; >+ defaultConfigurationName = Release; >+ }; >+ E94C06ED20F56A4200672992 /* Build configuration list for PBXNativeTarget "WHLSL TestsTests" */ = { >+ isa = XCConfigurationList; >+ buildConfigurations = ( >+ E94C06EE20F56A4200672992 /* Debug */, >+ E94C06EF20F56A4200672992 /* Release */, >+ ); >+ defaultConfigurationIsVisible = 0; >+ defaultConfigurationName = Release; >+ }; >+/* End XCConfigurationList section */ >+ }; >+ rootObject = E94C06B820F56A4000672992 /* Project object */; >+} >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/Info.plist b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/Info.plist >new file mode 100644 >index 0000000000000000000000000000000000000000..6c40a6cd0c4af2f0d93b697fbfb066793681b045 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/Info.plist >@@ -0,0 +1,22 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> >+<plist version="1.0"> >+<dict> >+ <key>CFBundleDevelopmentRegion</key> >+ <string>$(DEVELOPMENT_LANGUAGE)</string> >+ <key>CFBundleExecutable</key> >+ <string>$(EXECUTABLE_NAME)</string> >+ <key>CFBundleIdentifier</key> >+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> >+ <key>CFBundleInfoDictionaryVersion</key> >+ <string>6.0</string> >+ <key>CFBundleName</key> >+ <string>$(PRODUCT_NAME)</string> >+ <key>CFBundlePackageType</key> >+ <string>BNDL</string> >+ <key>CFBundleShortVersionString</key> >+ <string>1.0</string> >+ <key>CFBundleVersion</key> >+ <string>1</string> >+</dict> >+</plist> >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/WHLSL_ToyTests.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/WHLSL_ToyTests.m >new file mode 100644 >index 0000000000000000000000000000000000000000..555305078c63b7512c4f6e5757f29eb81d689a44 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/WHLSL_ToyTests.m >@@ -0,0 +1,65 @@ >+// >+// WHLSL_ToyTests.m >+// WHLSL ToyTests >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <XCTest/XCTest.h> >+ >+#import "TestFamily.h" >+#import "TestFamilyRunner.h" >+ >+/// The actual implementation of tests is in Test.h/m >+@interface WHLSLShaderTest : XCTestCase >+ >+@end >+ >+@implementation WHLSLShaderTest >+ >++ (WHLSLShaderTest*)testCaseInstanceFromImplementation:(TestFamily*)test >+{ >+ NSMethodSignature *testSignature = [WHLSLShaderTest instanceMethodSignatureForSelector:@selector(testShaderCompilationAndExecution:)]; >+ NSInvocation *testInvocation = [NSInvocation invocationWithMethodSignature:testSignature]; >+ testInvocation.selector = @selector(testShaderCompilationAndExecution:); >+ [testInvocation setArgument:&test atIndex:2]; >+ [testInvocation retainArguments]; >+ >+ WHLSLShaderTest *testCase = [[WHLSLShaderTest alloc] initWithInvocation:testInvocation]; >+ return testCase; >+} >+ >+- (void)testShaderCompilationAndExecution:(TestFamily*)test { >+ TestFamilyRunner* runner = [[TestFamilyRunner alloc] initWithTestFamily:test]; >+ BOOL result = [runner executeAllTests]; >+ if (result) >+ NSLog(@"\u2705 %@", test.name); >+ XCTAssert(result, @"%@", test.name); >+ NSLog(@"Total test case count: %lu", [TestFamilyRunner executionCount]); >+} >+ >+@end >+ >+@interface WHLSL_ToyTests : XCTestCase >+ >+@end >+ >+@implementation WHLSL_ToyTests >+ >++ (XCTestSuite*)defaultTestSuite >+{ >+ XCTestSuite* suite = [XCTestSuite testSuiteWithName:@"WHLSL tests"]; >+ NSArray<TestFamily*>* testDescriptions = [TestFamily allTests]; >+ NSRegularExpression* testFilter = [NSRegularExpression regularExpressionWithPattern:@".*" options:0 error:nil]; >+ for (TestFamily* test in testDescriptions) { >+ if ([testFilter firstMatchInString:test.name options:0 range:NSMakeRange(0, test.name.length)]) >+ [suite addTest:[WHLSLShaderTest testCaseInstanceFromImplementation:test]]; >+ } >+ >+ NSLog(@"Will execute %ld tests", suite.tests.count); >+ >+ return suite; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSLLexer.ts b/Tools/WebGPUShadingLanguageRI/Metal/WHLSLLexer.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..e82bcd126a0b9d689c2d2398972e15bed0994397 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSLLexer.ts >@@ -0,0 +1,86 @@ >+function lexWhitespaceAndComment(src, startIndex) { >+ // WHLSL permits multiline comments, but the (restricted) MSL lexer doesn't >+ const wsRegex = /^\s+/; >+ const oneLineCommentRegex = /^\/\/(.*?)(\n|$)/; >+ const multilineCommentStartRegex = /^\/\*/; >+ const multilineCommentEndRegex = /\*\//; >+ >+ const tokens: Token[] = []; >+ >+ const originalLength = src.length; >+ >+ while (src.length) { >+ const wsMatch = wsRegex.exec(src); >+ if (wsMatch) { >+ tokens.push(new Token("whitespace", wsMatch[0], originalLength - src.length + startIndex)); >+ src = src.substring(wsMatch[0].length); >+ continue; >+ } >+ >+ const oneLineCommentMatch = oneLineCommentRegex.exec(src); >+ if (oneLineCommentMatch) { >+ tokens.push(new Token("comment", oneLineCommentMatch[0], originalLength - src.length + startIndex)); >+ src = src.substring(oneLineCommentMatch[0].length); >+ continue; >+ } >+ >+ const multilineCommentStartMatch = multilineCommentStartRegex.exec(src); >+ if (multilineCommentStartMatch) { >+ const multilineCommentEndMatch = multilineCommentEndRegex.exec(src); >+ if (multilineCommentEndMatch) { >+ const index = multilineCommentEndMatch.index + 2; >+ tokens.push(new Token("comment", src.substring(0, index), originalLength - src.length + startIndex)); >+ src = src.substring(index); >+ } else { >+ throw new Error(`Multiline comment not terminated properly: '${src}'`); >+ } >+ continue; >+ } >+ >+ throw new Error(`Failed to tokenize whitespace/comment string '${src}'`); >+ } >+ >+ return tokens; >+} >+ >+function lexWHLSL(src) >+{ >+ const lexer = new Lexer("/internal/test", "user", 0, src); >+ let index = 0; >+ let hasTokens = true; >+ let tokens: Token[] = []; >+ >+ const mapWHLSLTokens = { >+ "floatLiteral": "literal", >+ "intHexLiteral": "literal", >+ "uintHexLiteral": "literal", >+ "intLiteral": "literal", >+ "uintLiteral": "literal" >+ }; >+ const identifiersThatAreTypes = new Set([ >+ "int", "uint", "float", "int32", "uint32", "uint8", "float2", "float3", "float4", "vertex", "fragment", "void", "bool" >+ ]); >+ >+ while (hasTokens) { >+ const next = lexer.next(); >+ if (next) { >+ // tokens.push(next); >+ if (next.index > index) { >+ tokens = tokens.concat(lexWhitespaceAndComment(src.substring(index, next.index), index)); >+ } >+ index = next.index + next.text.length; >+ let kind = next.kind; >+ if (kind in mapWHLSLTokens) >+ kind = mapWHLSLTokens[kind]; >+ if (kind == "identifier" && identifiersThatAreTypes.has(next.text)) >+ kind = "type"; >+ tokens.push(new Token(kind, next.text, next.index)); >+ } else { >+ hasTokens = false; >+ } >+ } >+ if (index != src.length) { >+ tokens = tokens.concat(lexWhitespaceAndComment(src.substring(index), index)); >+ } >+ return tokens; >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/index.html b/Tools/WebGPUShadingLanguageRI/Metal/index.html >new file mode 100644 >index 0000000000000000000000000000000000000000..c23549d0493e44f0d637e1fd40076f5a945ec71b >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/index.html >@@ -0,0 +1,431 @@ >+<!DOCTYPE html> >+<html> >+<head> >+ <title>WebGPU Shading Language (WHLSL) → Metal Shading Language</title> >+ <script src="../Node.js"></script> >+ <script src="../Type.js"></script> >+ <script src="../ReferenceType.js"></script> >+ <script src="../Value.js"></script> >+ <script src="../Expression.js"></script> >+ <script src="../Rewriter.js"></script> >+ <script src="../Visitor.js"></script> >+ <script src="../CreateLiteral.js"></script> >+ <script src="../CreateLiteralType.js"></script> >+ <script src="../PropertyAccessExpression.js"></script> >+ <script src="../NativeType.js"></script> >+ >+ <script src="../AddressSpace.js"></script> >+ <script src="../AnonymousVariable.js"></script> >+ <script src="../ArrayRefType.js"></script> >+ <script src="../ArrayType.js"></script> >+ <script src="../Assignment.js"></script> >+ <script src="../AutoWrapper.js"></script> >+ <script src="../Block.js"></script> >+ <script src="../BoolLiteral.js"></script> >+ <script src="../Break.js"></script> >+ <script src="../BuiltinMatrixGetter.js"></script> >+ <script src="../BuiltinMatrixSetter.js"></script> >+ <script src="../BuiltinVectorGetter.js"></script> >+ <script src="../BuiltinVectorSetter.js"></script> >+ <script src="../CallExpression.js"></script> >+ <script src="../CallFunction.js"></script> >+ <script src="../Check.js"></script> >+ <script src="../CheckLiteralTypes.js"></script> >+ <script src="../CheckLoops.js"></script> >+ <script src="../CheckRecursion.js"></script> >+ <script src="../CheckRecursiveTypes.js"></script> >+ <script src="../CheckReturns.js"></script> >+ <script src="../CheckTypesWithArguments.js"></script> >+ <script src="../CheckUnreachableCode.js"></script> >+ <script src="../CheckWrapped.js"></script> >+ <script src="../Checker.js"></script> >+ <script src="../CloneProgram.js"></script> >+ <script src="../CommaExpression.js"></script> >+ <script src="../ConstexprFolder.js"></script> >+ <script src="../Continue.js"></script> >+ <script src="../ConvertPtrToArrayRefExpression.js"></script> >+ <script src="../DoWhileLoop.js"></script> >+ <script src="../DotExpression.js"></script> >+ <script src="../DereferenceExpression.js"></script> >+ <script src="../EArrayRef.js"></script> >+ <script src="../EBuffer.js"></script> >+ <script src="../EBufferBuilder.js"></script> >+ <script src="../EPtr.js"></script> >+ <script src="../EnumLiteral.js"></script> >+ <script src="../EnumMember.js"></script> >+ <script src="../EnumType.js"></script> >+ <script src="../EvaluationCommon.js"></script> >+ <script src="../Evaluator.js"></script> >+ <script src="../ExpressionFinder.js"></script> >+ <script src="../ExternalOrigin.js"></script> >+ <script src="../Field.js"></script> >+ <script src="../FindHighZombies.js"></script> >+ <script src="../FlattenedStructOffsetGatherer.js"></script> >+ <script src="../FloatLiteral.js"></script> >+ <script src="../FloatLiteralType.js"></script> >+ <script src="../FoldConstexprs.js"></script> >+ <script src="../ForLoop.js"></script> >+ <script src="../Func.js"></script> >+ <script src="../FuncDef.js"></script> >+ <script src="../FuncParameter.js"></script> >+ <script src="../FunctionLikeBlock.js"></script> >+ <script src="../HighZombieFinder.js"></script> >+ <script src="../IdentityExpression.js"></script> >+ <script src="../IfStatement.js"></script> >+ <script src="../IndexExpression.js"></script> >+ <script src="../InferTypesForCall.js"></script> >+ <script src="../Inline.js"></script> >+ <script src="../Inliner.js"></script> >+ <script src="../IntLiteral.js"></script> >+ <script src="../IntLiteralType.js"></script> >+ <script src="../Intrinsics.js"></script> >+ <script src="../LateChecker.js"></script> >+ <script src="../Lexer.js"></script> >+ <script src="../LexerToken.js"></script> >+ <script src="../LiteralTypeChecker.js"></script> >+ <script src="../LogicalExpression.js"></script> >+ <script src="../LogicalNot.js"></script> >+ <script src="../LoopChecker.js"></script> >+ <script src="../MakeArrayRefExpression.js"></script> >+ <script src="../MakePtrExpression.js"></script> >+ <script src="../MatrixType.js"></script> >+ <script src="../NameContext.js"></script> >+ <script src="../NameFinder.js"></script> >+ <script src="../NameResolver.js"></script> >+ <script src="../NativeFunc.js"></script> >+ <script src="../NormalUsePropertyResolver.js"></script> >+ <script src="../NullLiteral.js"></script> >+ <script src="../NullType.js"></script> >+ <script src="../OperatorAnderIndexer.js"></script> >+ <script src="../OperatorArrayRefLength.js"></script> >+ <script src="../OriginKind.js"></script> >+ <script src="../OverloadResolutionFailure.js"></script> >+ <script src="../Parse.js"></script> >+ <script src="../Prepare.js"></script> >+ <script src="../PropertyResolver.js"></script> >+ <script src="../Program.js"></script> >+ <script src="../ProgramWithUnnecessaryThingsRemoved.js"></script> >+ <script src="../PtrType.js"></script> >+ <script src="../ReadModifyWriteExpression.js"></script> >+ <script src="../RecursionChecker.js"></script> >+ <script src="../RecursiveTypeChecker.js"></script> >+ <script src="../ResolveNames.js"></script> >+ <script src="../ResolveOverloadImpl.js"></script> >+ <script src="../ResolveProperties.js"></script> >+ <script src="../ResolveTypeDefs.js"></script> >+ <script src="../Return.js"></script> >+ <script src="../ReturnChecker.js"></script> >+ <script src="../ReturnException.js"></script> >+ <script src="../StandardLibrary.js"></script> >+ <script src="../StatementCloner.js"></script> >+ <script src="../StructLayoutBuilder.js"></script> >+ <script src="../StructType.js"></script> >+ <script src="../SwitchCase.js"></script> >+ <script src="../SwitchStatement.js"></script> >+ <script src="../SynthesizeArrayOperatorLength.js"></script> >+ <script src="../SynthesizeEnumFunctions.js"></script> >+ <script src="../SynthesizeStructAccessors.js"></script> >+ <script src="../SynthesizeCopyConstructorOperator.js"></script> >+ <script src="../SynthesizeDefaultConstructorOperator.js"></script> >+ <script src="../TernaryExpression.js"></script> >+ <script src="../TrapStatement.js"></script> >+ <script src="../TypeDef.js"></script> >+ <script src="../TypeDefResolver.js"></script> >+ <script src="../TypeRef.js"></script> >+ <script src="../TypeOverloadResolutionFailure.js"></script> >+ <script src="../TypedValue.js"></script> >+ <script src="../UintLiteral.js"></script> >+ <script src="../UintLiteralType.js"></script> >+ <script src="../UnificationContext.js"></script> >+ <script src="../UnreachableCodeChecker.js"></script> >+ <script src="../VariableDecl.js"></script> >+ <script src="../VariableRef.js"></script> >+ <script src="../VectorType.js"></script> >+ <script src="../VisitingSet.js"></script> >+ <script src="../WSyntaxError.js"></script> >+ <script src="../WTrapError.js"></script> >+ <script src="../WTypeError.js"></script> >+ <script src="../WhileLoop.js"></script> >+ <script src="../WrapChecker.js"></script> >+ >+ <script src="compiler.js"></script> >+ >+<link rel="stylesheet" type="text/css" href="metal.css" /> >+ >+<script> >+let defaultShaderSource = `struct VertexInput { >+ float2 position; >+ float3 color; >+} >+ >+struct VertexOutput { >+ float4 wsl_Position; >+ float3 color; >+} >+ >+struct FragmentOutput { >+ float4 wsl_Color; >+} >+ >+vertex VertexOutput vertexShader(VertexInput vertexInput) { >+ VertexOutput result; >+ result.wsl_Position = float4(vertexInput.position, 0., 1.); >+ result.color = vertexInput.color; >+ return result; >+} >+ >+fragment FragmentOutput fragmentShader(VertexOutput stageIn) { >+ FragmentOutput result; >+ result.wsl_Color = float4(stageIn.color, 1.); >+ return result; >+}`; >+ >+let whlslContainer; >+let mslContainer; >+ >+let whlslSourceView; >+let mslSourceView; >+ >+const LocalStorageWhlslKeyName = "ShaderSource"; >+const LocalStorageMslKeyName = "ShaderMSLResult"; >+ >+window.addEventListener("load", () => { >+ mslContainer = document.getElementById("MetalOutput"); >+ mslSourceView = new SourceView("MSL (previous compilation)", mslContainer, (src) => new MSLLexer(src).tokens); >+ >+ try { >+ const localStorage = window.localStorage; >+ const mslSource = localStorage.getItem(LocalStorageMslKeyName); >+ mslSourceView.src = mslSource; >+ } catch(e) { >+ } >+ >+ whlslContainer = document.getElementById("WHLSLInput"); >+ whlslSourceView = new SourceView("WHLSL", whlslContainer, lexWHLSL, compileWHLSL, true); >+ >+ try { >+ const localStorage = window.localStorage; >+ let whlslSource = localStorage.getItem(LocalStorageWhlslKeyName); >+ if (!whlslSource) >+ whlslSource = defaultShaderSource; >+ whlslSourceView.src = whlslSource; >+ whlslSourceView.compile(); >+ } catch (e) { >+ console.log(e); >+ } >+}); >+ >+function compileWHLSL(src) { >+ window.localStorage.setItem(LocalStorageWhlslKeyName, src); >+ const compileResult = whlslToMsl(src); >+ >+ if (compileResult.didSucceed) { >+ mslSourceView.src = compileResult.metalShaderLanguageSource; >+ mslSourceView.name = "MSL"; >+ window.localStorage.setItem(LocalStorageMslKeyName, compileResult.metalShaderLanguageSource); >+ } else { >+ mslSourceView.name = "MSL (previous compilation)"; >+ whlslSourceView.errorText = compileResult.error.message; >+ } >+} >+ >+// Wraps a textarea and a bunch of buttons >+class SourceView { >+ constructor(name, container, lexer, compiler = null, editable = false) >+ { >+ this._name = name; >+ this._container = container; >+ this._lexingDelegate = lexer; >+ this._compiler = compiler; >+ this._copySources = new Map(); >+ this._src = ""; >+ this._tokens = []; >+ this._editable = editable; >+ this._errorText = ""; >+ } >+ >+ get name() { return this._name; } >+ get editable() { return this._editable; } >+ get src() { return this._src; } >+ >+ set src(newSrc) >+ { >+ this._src = newSrc; >+ this._tokens = this._lexingDelegate(this._src); >+ this._updateView(); >+ } >+ >+ get copySources() { return this._copySources; } >+ set copySources(cs) >+ { >+ this._copySources = cs; >+ this._updateView(); >+ } >+ >+ get errorText() { return this._errorText; } >+ >+ set errorText(newErrorText) >+ { >+ this._errorText = newErrorText; >+ if (this._errorBox && newErrorText) >+ this._errorBox.innerText = this._errorText; >+ } >+ >+ set name(newName) >+ { >+ this._name = newName; >+ if (this._header) >+ this._header.innerText = this.name; >+ } >+ >+ _updateView() >+ { >+ this._presentSource(this._tokens, this._container); >+ } >+ >+ _removeAllChildren(node) >+ { >+ while (node.hasChildNodes()) { >+ node.removeChild(node.lastChild); >+ } >+ } >+ >+ _splitTokensIntoLines(tokens) >+ { >+ const lines = []; >+ let currentLine = []; >+ lines.push(currentLine); >+ >+ for (let tok of tokens) { >+ let tokSections = tok.src.split('\n'); >+ for (let i = 0; i < tokSections.length; i++) { >+ let tokSection = tokSections[i]; >+ >+ let span = document.createElement('span'); >+ span.innerText = tokSection; >+ span.className = `code-${tok.type}`; >+ currentLine.push(span); >+ >+ if (i != tokSections.length - 1) { >+ currentLine = []; >+ lines.push(currentLine); >+ } >+ } >+ } >+ >+ return lines; >+ } >+ >+ _presentSource(tokens, container) >+ { >+ this._removeAllChildren(container); >+ >+ this._header = document.createElement('h2'); >+ this._header.innerText = this.name; >+ container.appendChild(this._header); >+ >+ const lines = this._splitTokensIntoLines(tokens); >+ >+ const srcTable = document.createElement('table'); >+ srcTable.className = 'code-source'; >+ >+ for (let i = 0; i < lines.length; i++) { >+ const currentRow = document.createElement('tr'); >+ >+ const currentLineNumber = document.createElement('td'); >+ currentLineNumber.className = 'line-no'; >+ currentLineNumber.dataset.content = (i + 1).toString(); // line-no shown with CSS >+ currentRow.appendChild(currentLineNumber); >+ >+ const currentLineElement = document.createElement('td'); >+ currentLineElement.className = 'line'; >+ for (let span of lines[i]) { >+ currentLineElement.appendChild(span); >+ } >+ currentRow.appendChild(currentLineElement); >+ >+ srcTable.appendChild(currentRow); >+ } >+ >+ container.appendChild(srcTable); >+ >+ if (this.editable) { >+ const editButton = document.createElement('input'); >+ editButton.type = "button"; >+ editButton.value = "Edit"; >+ editButton.addEventListener("click", () => this.edit()); >+ container.appendChild(editButton); >+ } >+ >+ for (let [name, source] of this.copySources) { >+ const copyButton = document.createElement('input'); >+ copyButton.type = "button"; >+ copyButton.value = `Copy ${name}`; >+ copyButton.addEventListener("click", () => { >+ const fakeTextarea = document.createElement('textarea'); >+ fakeTextarea.value = source; >+ document.body.appendChild(fakeTextarea); >+ fakeTextarea.focus(); >+ fakeTextarea.select(); >+ document.execCommand("copy"); >+ document.body.removeChild(fakeTextarea); >+ }); >+ container.appendChild(copyButton); >+ } >+ >+ this._createErrorBox(); >+ } >+ >+ edit() >+ { >+ this._removeAllChildren(this._container); >+ >+ this._header = document.createElement('h2'); >+ this._header.innerText = this.name; >+ this._container.appendChild(this._header); >+ >+ this._textarea = document.createElement('textarea'); >+ this._textarea.value = this.src; >+ this._container.appendChild(this._textarea); >+ >+ const compileButton = document.createElement('input'); >+ compileButton.type = "button"; >+ compileButton.value = "Compile"; >+ compileButton.addEventListener("click", () => this.compile()); >+ this._container.appendChild(compileButton); >+ >+ this._createErrorBox(); >+ } >+ >+ _createErrorBox() >+ { >+ this._errorBox = document.createElement('div'); >+ if (this.errorText) { >+ this._errorBox.innerText = this.errorText; >+ this._errorText = null; >+ } >+ this._container.appendChild(this._errorBox); >+ } >+ >+ compile() >+ { >+ let src = this._textarea ? this._textarea.value : this._src; >+ this._compiler(src); >+ this.src = src; >+ } >+} >+</script> >+</head> >+<body> >+<table cellspacing="0" cellpadding="0"> >+ <tr> >+ <td class="container-cell"> >+ <div id="WHLSLInput"></div> >+ </td> >+ <td class="container-cell"> >+ <div id="MetalOutput"></div> >+ </td> >+ </tr> >+</table> >+</body> >+</html> >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/metal.css b/Tools/WebGPUShadingLanguageRI/Metal/metal.css >new file mode 100644 >index 0000000000000000000000000000000000000000..d315d02232c6244a8c1597461ee88c00db6d2c55 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/metal.css >@@ -0,0 +1,113 @@ >+textarea, .code-source { >+ font-family: "SF Mono", monospace; >+ font-size: 11pt; >+ padding: 5px; >+ width: 800px; >+ height: 800px; >+ margin: 1em 0; >+ display: block; >+} >+ >+input[type=button] { >+ font-size: 16pt; >+} >+ >+.code-source { >+ overflow-x: scroll; >+ overflow-y: scroll; >+ border: 1px solid black; >+ display: block; >+ background-color: #1F1F24; >+ color: white; >+ white-space: nowrap; >+} >+ >+td { >+ border: 1px solid black; >+} >+ >+body { >+ font-family: -apple-system, sans-serif; >+} >+ >+h1, h2 { >+ text-align: center; >+} >+ >+table { >+ width:100%; >+ border:none; >+ border-collapse: collapse; >+ >+} >+ >+.container-cell { >+ width:50%; >+} >+ >+th, td { >+ border:none; >+ vertical-align:top; >+ margin: 0; >+ -webkit-border-horizontal-spacing: 0px; >+ -webkit-border-vertical-spacing: 0px; >+ border-collapse: collapse; >+ box-sizing: border-box; >+ border-spacing: 0; >+} >+ >+.code-comment { >+ color: #9e9e9e; >+ font-style: italic; >+ white-space: pre; >+} >+ >+.code-comment-note { >+ color: #F4E218; >+ font-style: italic; >+ font-weight:bold; >+} >+ >+.code-keyword, .code-type { >+ color: #FD5FA2; >+ font-weight: bold; >+} >+ >+.code-literal { >+ color: #9686F5; >+} >+ >+.code-attribute { >+ color: #AEF29D; >+ font-weight: bold; >+} >+ >+.code-whitespace { >+ white-space: pre; >+} >+ >+.code-error { >+ color: #fc5a3a; >+ text-decoration: underline; >+} >+ >+.code-directive { >+ color: #FC8F3F; >+} >+ >+.line-no { >+ color: #616065; >+ text-align: right; >+ -webkit-user-select:none; >+ padding-left: 5px; >+ padding-right: 5px; >+ border-right: 1px solid #616065; >+} >+ >+.line-no::before { >+ content: attr(data-content); >+} >+ >+.line { >+ padding-left: 5px; >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/tsconfig.json b/Tools/WebGPUShadingLanguageRI/Metal/tsconfig.json >new file mode 100644 >index 0000000000000000000000000000000000000000..04f370c3827a319a7c27e1803f0e4740ed7fcd88 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/tsconfig.json >@@ -0,0 +1,26 @@ >+{ >+ "version": "2.0.0", >+ "tasks": [ >+ { >+ "type": "typescript", >+ "tsconfig": "tsconfig.json", >+ "problemMatcher": [ >+ "$tsc" >+ ], >+ "group": { >+ "kind": "build", >+ "isDefault": true >+ } >+ } >+ ], >+ "compilerOptions": { >+ "target": "es6", >+ "module": "amd", >+ "sourceMap": true, >+ "lib": [ >+ "es6" >+ ], >+ "types": [], >+ "outFile": "compiler.js" >+ } >+} >diff --git a/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js b/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js >index a0181468a25ed4c09050d7bf1d61f44ed3a0aa66..24a209433bde0c1bbc2085654a0612c8c65fe9cd 100644 >--- a/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js >+++ b/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js >@@ -42,6 +42,13 @@ function synthesizeStructAccessors(program) > nativeFunc.implementation = (argumentList, node) => { > return implementation(argumentList, field.offset, type.size, field.type.size); > }; >+ >+ nativeFunc.implementationData = { >+ name: field.name, >+ type: type, >+ offset: field.offset, >+ size: field.type.size >+ }; > } > > function createFieldType() >diff --git a/Tools/WebGPUShadingLanguageRI/Test.js b/Tools/WebGPUShadingLanguageRI/Test.js >index 4a11c1858599778ff391b04f2635c5b71005df7f..3d2144c4ae3ffeba8771b26c33a90bfee80f5e88 100644 >--- a/Tools/WebGPUShadingLanguageRI/Test.js >+++ b/Tools/WebGPUShadingLanguageRI/Test.js >@@ -32,7 +32,7 @@ if (this.window) { > window.scrollTo(0,document.body.scrollHeight); > }; > this.preciseTime = () => performance.now() / 1000; >-} else >+} else if (this.load) > load("All.js"); > > function doPrep(code) >@@ -55,22 +55,22 @@ function doLex(code) > > function makeInt(program, value) > { >- return TypedValue.box(program.intrinsics.int, value); >+ return TypedValue.box(program.intrinsics.int, (value | 0)); > } > > function makeUint(program, value) > { >- return TypedValue.box(program.intrinsics.uint, value); >+ return TypedValue.box(program.intrinsics.uint, (value >>> 0)); > } > > function makeUchar(program, value) > { >- return TypedValue.box(program.intrinsics.uchar, value); >+ return TypedValue.box(program.intrinsics.uchar, (value >>> 0) & 0xff); > } > > function makeBool(program, value) > { >- return TypedValue.box(program.intrinsics.bool, value); >+ return TypedValue.box(program.intrinsics.bool, !!value); > } > > function makeFloat(program, value) >@@ -321,6 +321,27 @@ tests.intSimpleMath = function() { > checkInt(program, callFunction(program, "foo", [makeInt(program, 7), makeInt(program, -2)]), -3); > } > >+tests.incrementAndDecrement = function() { >+ let program = doPrep(` >+ int foo1() { int x = 0; return x++; } >+ int foo2() { int x = 0; x++; return x; } >+ int foo3() { int x = 0; return ++x; } >+ int foo4() { int x = 0; ++x; return x; } >+ int foo5() { int x = 0; return x--; } >+ int foo6() { int x = 0; x--; return x; } >+ int foo7() { int x = 0; return --x; } >+ int foo8() { int x = 0; --x; return x; } >+ `); >+ checkInt(program, callFunction(program, "foo1", []), 0); >+ checkInt(program, callFunction(program, "foo2", []), 1); >+ checkInt(program, callFunction(program, "foo3", []), 1); >+ checkInt(program, callFunction(program, "foo4", []), 1); >+ checkInt(program, callFunction(program, "foo5", []), 0); >+ checkInt(program, callFunction(program, "foo6", []), -1); >+ checkInt(program, callFunction(program, "foo7", []), -1); >+ checkInt(program, callFunction(program, "foo8", []), -1); >+} >+ > tests.uintSimpleMath = function() { > let program = doPrep("uint foo(uint x, uint y) { return x + y; }"); > checkUint(program, callFunction(program, "foo", [makeUint(program, 7), makeUint(program, 5)]), 12); >@@ -921,13 +942,13 @@ tests.passNullToPtrMonomorphicArrayRef = function() > tests.returnIntLiteralUint = function() > { > let program = doPrep("uint foo() { return 42; }"); >- checkNumber(program, callFunction(program, "foo", []), 42); >+ checkUint(program, callFunction(program, "foo", [], []), 42); > } > > tests.returnIntLiteralFloat = function() > { > let program = doPrep("float foo() { return 42; }"); >- checkNumber(program, callFunction(program, "foo", []), 42); >+ checkFloat(program, callFunction(program, "foo", [], []), 42); > } > > tests.badIntLiteralForInt = function() >@@ -2237,6 +2258,149 @@ tests.nestedSubscriptLValueEmulationSimple = function() > checkInt(program, callFunction(program, "testSetValuesMutateValuesAndSum", []), 5565); > } > >+tests.nestedSubscriptWithArraysInStructs = function() >+{ >+ let program = doPrep(` >+ struct Foo { >+ int[7] array; >+ } >+ int sum(Foo foo) >+ { >+ int result = 0; >+ for (uint i = 0; i < foo.array.length; i++) >+ result += foo.array[i]; >+ return result; >+ } >+ struct Bar { >+ Foo[6] array; >+ } >+ int sum(Bar bar) >+ { >+ int result = 0; >+ for (uint i = 0; i < bar.array.length; i++) >+ result += sum(bar.array[i]); >+ return result; >+ } >+ struct Baz { >+ Bar[5] array; >+ } >+ int sum(Baz baz) >+ { >+ int result = 0; >+ for (uint i = 0; i < baz.array.length; i++) >+ result += sum(baz.array[i]); >+ return result; >+ } >+ void setValues(thread Baz* baz) >+ { >+ for (uint i = 0; i < baz->array.length; i++) { >+ for (uint j = 0; j < baz->array[i].array.length; j++) { >+ for (uint k = 0; k < baz->array[i].array[j].array.length; k++) >+ baz->array[i].array[j].array[k] = int(i + j + k); >+ } >+ } >+ } >+ int testSetValuesAndSum() >+ { >+ Baz baz; >+ setValues(&baz); >+ return sum(baz); >+ } >+ int testSetValuesMutateValuesAndSum() >+ { >+ Baz baz; >+ setValues(&baz); >+ for (uint i = baz.array.length; i--;) { >+ for (uint j = baz.array[i].array.length; j--;) { >+ for (uint k = baz.array[i].array[j].array.length; k--;) >+ baz.array[i].array[j].array[k] = baz.array[i].array[j].array[k] * int(k); >+ } >+ } >+ return sum(baz); >+ } >+ `); >+ checkInt(program, callFunction(program, "testSetValuesAndSum", []), 1575); >+ checkInt(program, callFunction(program, "testSetValuesMutateValuesAndSum", []), 5565); >+} >+ >+tests.nestedSubscript = function() >+{ >+ let program = doPrep(` >+ int sum(int[7] array) >+ { >+ int result = 0; >+ for (uint i = array.length; i--;) >+ result += array[i]; >+ return result; >+ } >+ int sum(int[6][7] array) >+ { >+ int result = 0; >+ for (uint i = array.length; i--;) >+ result += sum(array[i]); >+ return result; >+ } >+ int sum(int[5][6][7] array) >+ { >+ int result = 0; >+ for (uint i = array.length; i--;) >+ result += sum(array[i]); >+ return result; >+ } >+ void setValues(thread int[][6][7] array) >+ { >+ for (uint i = array.length; i--;) { >+ for (uint j = array[i].length; j--;) { >+ for (uint k = array[i][j].length; k--;) >+ array[i][j][k] = int(i + j + k); >+ } >+ } >+ } >+ int testSetValuesAndSum() >+ { >+ int[5][6][7] array; >+ setValues(@array); >+ return sum(array); >+ } >+ int testSetValuesMutateValuesAndSum() >+ { >+ int[5][6][7] array; >+ setValues(@array); >+ for (uint i = array.length; i--;) { >+ for (uint j = array[i].length; j--;) { >+ for (uint k = array[i][j].length; k--;) >+ array[i][j][k] = array[i][j][k] * int(k); >+ } >+ } >+ return sum(array); >+ } >+ `); >+ checkInt(program, callFunction(program, "testSetValuesAndSum", []), 1575); >+ checkInt(program, callFunction(program, "testSetValuesMutateValuesAndSum", []), 5565); >+} >+ >+tests.lotsOfLocalVariables = function() >+{ >+ let src = "int sum() {\n"; >+ src += " int i = 0;\n"; >+ let target = 0; >+ const numVars = 1024; >+ for (let i = 0; i < numVars; i++) { >+ const value = i * 3; >+ src += ` i = ${i};\n`; >+ src += ` int V${i} = (i + 3) * (i + 3);\n`; >+ target += (i + 3) * (i + 3); >+ } >+ src += " int result = 0;\n"; >+ for (let i = 0; i < numVars; i++) { >+ src += ` result += V${i};\n`; >+ } >+ src += " return result;\n"; >+ src += "}"; >+ let program = doPrep(src); >+ checkInt(program, callFunction(program, "sum", []), target); >+} >+ > tests.operatorBool = function() > { > let program = doPrep(` >@@ -2264,26 +2428,6 @@ tests.operatorBool = function() > > checkBool(program, callFunction(program, "boolFromFloatFalse", []), false); > checkBool(program, callFunction(program, "boolFromFloatTrue", []), true); >- >- checkFail( >- () => doPrep(` >- void foo() >- { >- float3 x; >- bool r = bool(x); >- } >- `), >- e => e instanceof WTypeError); >- >- checkFail( >- () => doPrep(` >- void foo() >- { >- float3x3 x; >- bool r = bool(x); >- } >- `), >- e => e instanceof WTypeError); > } > > tests.boolBitAnd = function() >@@ -2573,7 +2717,6 @@ tests.ucharLShift = function() > } > `); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, 1), makeUint(program, 7)]), 128); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, 65535), makeUint(program, 2)]), 252); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, -1), makeUint(program, 5)]), 224); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, 0), makeUint(program, 3)]), 0); > } >@@ -2587,8 +2730,6 @@ tests.ucharRShift = function() > } > `); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, 1), makeUint(program, 7)]), 0); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, 65535), makeUint(program, 2)]), 255); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, -1), makeUint(program, 5)]), 255); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, 0), makeUint(program, 3)]), 0); > } > >@@ -5582,7 +5723,7 @@ tests.arrayIndex = function() { > checkInt(program, callFunction(program, "arrayIndexing", [ makeUint(program, 0), makeUint(program, 2) ]), 3); > checkInt(program, callFunction(program, "arrayIndexing", [ makeUint(program, 1), makeUint(program, 0) ]), 4); > checkInt(program, callFunction(program, "arrayIndexing", [ makeUint(program, 1), makeUint(program, 1) ]), 5); >- checkInt(program, callFunction(program, "arrayIndexing", [ makeUint(program, 1), makeUint(program, 2) ]), 6); >+ checkInt(program, callFunction(program, "arrayIndexing", [ makeUint(program, 1), makeUint(program, 2) ]), 6); > } > > okToTest = true; >@@ -5637,7 +5778,7 @@ function* doTest(testFilter) > print("That took " + (after - before) * 1000 + " ms."); > } > >-if (!this.window) { >+if (!this.window && !this.runningInCocoaHost) { > Error.stackTraceLimit = Infinity; > for (let _ of doTest(testFilter)) { } > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 187738
:
345192
|
345267
|
346955
|
347094
|
347104
|
347142
|
348258
|
348410
|
348702
|
349746
|
349818
|
350453
|
350779