[
  {
    "path": ".editorconfig",
    "content": "[*]\nindent_style = tab\nindent_size = 4\n"
  },
  {
    "path": ".gitignore",
    "content": "DebugClang/\n*.user\nautotuneLog.txt\nLibraryRelease/CodePack.exe\n*.exe\n*.exe.config\n*.exe.manifest\n*.pdb\n.vs\n*.VC.opendb\n*.VC.db\n*.spire.actual\nLibraryRelease/Spire.cpp\n*.sdf\nDebug/\nRelease/\nx64/\n*.TMP\n*.cse\n"
  },
  {
    "path": "Examples/hello/README.md",
    "content": "Spire \"Hello World\" Example\n===========================\n\nThe goal of this example is to demonstrate an almost minimal application that uses Spire for shading, and D3D11 for rendering.\n\nThe `hello.spire` file contains a simple declaration of a Spire *shader module*, along with a *pipeline declaration* that will be used for mapping shader code to the capabilities of the \"engine\" (in this case, just vertex and fragment shaders).\nThe `hello.cpp` file contains the C++ application code, showing how to use the Spire C API to load and compile the shader code, and construct a (trivial) executable shader from Spire modules.\n\nNote that this example is not intended to demonstrate good practices for integrating Spire into a production engine; the goal is merely to use the minimum amount of code possible to demonstrate a complete applicaiton that uses Spire.\n"
  },
  {
    "path": "Examples/hello/hello.cpp",
    "content": "// hello.cpp\n\n// In order to use the Spire API, we need to include its header\n\n#include <Spire.h>\n\n// We will be rendering with Direct3D 11, so we need to include\n// the Windows and D3D11 headers\n\n#define WIN32_LEAN_AND_MEAN\n#define NOMINMAX\n#include <Windows.h>\n#undef WIN32_LEAN_AND_MEAN\n#undef NOMINMAX\n\n#include <d3d11_2.h>\n#include <d3dcompiler.h>\n\n// We will use the C standard library just for printing error messages.\n#include <stdio.h>\n\n#ifdef _MSC_VER\n#include <stddef.h>\n#if (_MSC_VER < 1900)\n#define snprintf sprintf_s\n#endif\n#endif\n//\n\nstatic int gWindowWidth = 1024;\nstatic int gWindowHeight = 768;\n\n//\n\n//\n// For the purposes of a small example, we will define the vertex data for a\n// single triangle directly in the source file. It should be easy to extend\n// this example to load data from an external source, if desired.\n//\n\nstruct Vertex\n{\n    float position[3];\n    float color[3];\n};\n\nstatic const int kVertexCount = 3;\nstatic const Vertex kVertexData[kVertexCount] = {\n    { { 0,  0, 0.5 }, {1, 0, 0} },\n    { { 0,  1, 0.5 }, {0, 0, 1} },\n    { { 1,  0, 0.5 }, {0, 1, 0} },\n};\n\n//\n\n// Global variabels for the various D3D11 API objects to be used for rendering\nID3D11Buffer*       dxConstantBuffer;\nID3D11InputLayout*  dxInputLayout;\nID3D11Buffer*       dxVertexBuffer;\nID3D11VertexShader* dxVertexShader;\nID3D11PixelShader*  dxPixelShader;\n\n// The Spire compiler currently generates HLSL source, so we'll need a utility\n// routine (defined later) to translate that into D3D11 shader bytecode.\nID3DBlob* compileHLSLShader(\n    char const* source,\n    char const* dxProfileName);\n\n// We use a utility routine to print out any diagnostic (error/warning) output\n// from the Spire compiler.\nvoid emitSpireDiagnostics(\n    SpireDiagnosticSink* sink);\n\n//\n// At initialization time, we are going to load and compile our Spire shader\n// code, and then create the D3D11 API objects we need for rendering.\n//\nHRESULT initialize( ID3D11Device* dxDevice )\n{\n    //\n    // First, we will load and compile our Spire source code.\n    //\n\n    // The argument here is an optional directory where the Spire compiler\n    // can cache files to speed up compilation of many kernels.\n    SpireCompilationContext* spireContext = spCreateCompilationContext(NULL);\n\n    // A diagnostic sink is used to collect output messages from the Spire\n    // compiler, so that we can easily iterate over them if an operation\n    // fails.\n    SpireDiagnosticSink* spireSink = spCreateDiagnosticSink(spireContext);\n\n    // Instruct Spire to generate code as HLSL\n    spSetCodeGenTarget(spireContext, SPIRE_HLSL);\n\n    // Load a file of Spire source code, which defines our modules\n    spLoadModuleLibrary(spireContext, \"hello.spire\", spireSink);\n\n    // Inspect any error messages that got reported...\n    emitSpireDiagnostics(spireSink);\n\n    //\n    // Once the source Spire has been loaded, we can assemble the modules\n    // there to make one or more shaders. In our case, we really only\n    // have one shader that we will use, so this step is kind of redundant.\n    //\n\n    // Create a shader, which will initially be empty\n    char const* shaderName = \"HelloShader\";\n\tSpireShader* spireShader = spCreateShaderFromSource(spireContext, R\"(\n\t\ttemplate shader HelloShader(module0) targets StandardPipeline\n\t\t{\n\t\t\tusing module0;\n\t\t}\n\t)\", spireSink);\n\n\tSpireModule * helloModule = spFindModule(spireContext, \"HelloModule\");\n\n    // Compile the constructed shader\n    SpireCompilationResult* spireResult = spCompileShader(spireContext, spireShader, &helloModule, 1, nullptr, spireSink);\n\n    // Inspect any error messages that got reported...\n    emitSpireDiagnostics(spireSink);\n\n    //\n    // Once we've compiled things successfully, we can extract the HLSL kernel\n    // code for our shader, and pass it on to the D3D API.\n    //\n\n    // TODO(tfoley): The implementation should allow `NULL` for the length\n    // output parameter.\n    int sourceCodeLength;\n\n    char const* vertexShaderCode = spGetShaderStageSource(spireResult, nullptr, \"vs\", &sourceCodeLength);\n    char const* fragmentShaderCode = spGetShaderStageSource(spireResult, nullptr, \"fs\", &sourceCodeLength);\n\n    // TODO(tfoley): Query the required constant-buffer size\n    int constantBufferSize = 16 * sizeof(float);\n\n    // Compile the generated HLSL code\n    ID3DBlob* dxVertexShaderBlob = compileHLSLShader(vertexShaderCode, \"vs_4_0\");\n    if(!dxVertexShaderBlob) return E_FAIL;\n\n    ID3DBlob* dxPixelShaderBlob = compileHLSLShader(fragmentShaderCode, \"ps_4_0\");\n    if(!dxPixelShaderBlob) return E_FAIL;\n\n    HRESULT hr = S_OK;\n\n\n    D3D11_BUFFER_DESC dxConstantBufferDesc = { 0 };\n    dxConstantBufferDesc.ByteWidth = constantBufferSize;\n    dxConstantBufferDesc.Usage = D3D11_USAGE_DYNAMIC;\n    dxConstantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;\n    dxConstantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;\n\n    hr = dxDevice->CreateBuffer(\n        &dxConstantBufferDesc,\n        NULL,\n        &dxConstantBuffer);\n    if(FAILED(hr)) return hr;\n\n    // We clean up the Spire compilation context and result *after*\n    // we have done the HLSL-to-bytecode compilation, because Spire\n    // owns the memory allocation for the generated HLSL, and will\n    // free it when we destroy the compilation result.\n    spDestroyCompilationResult(spireResult);\n    spDestroyCompilationContext(spireContext);\n\n    // Input Assembler (IA)\n\n    // In Spire-generated HLSL, all vertex shader inputs have a semantic\n    // like: `A0`, `A1`, `A2`, etc., rather than trying to do by-name\n    // matching. The user is thus responsibile for ensuring that the\n    // order of their \"input element descs\" here matches the order\n    // in which inputs are declared in the shader code.\n    D3D11_INPUT_ELEMENT_DESC dxInputElements[] = {\n        {\"A\", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(Vertex, position), D3D11_INPUT_PER_VERTEX_DATA, 0 },\n        {\"A\", 1, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(Vertex, color), D3D11_INPUT_PER_VERTEX_DATA, 0 },\n    };\n    hr = dxDevice->CreateInputLayout(\n        &dxInputElements[0],\n        2,\n        dxVertexShaderBlob->GetBufferPointer(),\n        dxVertexShaderBlob->GetBufferSize(),\n        &dxInputLayout);\n    if(FAILED(hr)) return hr;\n\n    D3D11_BUFFER_DESC dxVertexBufferDesc = { 0 };\n    dxVertexBufferDesc.ByteWidth = kVertexCount * sizeof(Vertex);\n    dxVertexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE;\n    dxVertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;\n\n    D3D11_SUBRESOURCE_DATA dxVertexBufferInitData = { 0 };\n    dxVertexBufferInitData.pSysMem = &kVertexData[0];\n\n    hr = dxDevice->CreateBuffer(\n        &dxVertexBufferDesc,\n        &dxVertexBufferInitData,\n        &dxVertexBuffer);\n    if(FAILED(hr)) return hr;\n\n    // Vertex Shader (VS)\n\n    hr = dxDevice->CreateVertexShader(\n        dxVertexShaderBlob->GetBufferPointer(),\n        dxVertexShaderBlob->GetBufferSize(),\n        NULL,\n        &dxVertexShader);\n    dxVertexShaderBlob->Release();\n    if(FAILED(hr)) return hr;\n\n    // Pixel Shader (PS)\n\n    hr = dxDevice->CreatePixelShader(\n        dxPixelShaderBlob->GetBufferPointer(),\n        dxPixelShaderBlob->GetBufferSize(),\n        NULL,\n        &dxPixelShader);\n    dxPixelShaderBlob->Release();\n    if(FAILED(hr)) return hr;\n\n    return S_OK;\n}\n\nvoid emitSpireDiagnostics(\n    SpireDiagnosticSink* spireSink)\n{\n    int diagnosticCount = spGetDiagnosticCount(spireSink);\n    for(int jj = 0; jj < diagnosticCount; ++jj)\n    {\n        SpireDiagnostic diagnostic;\n        spGetDiagnosticByIndex(spireSink, jj, &diagnostic);\n\n        static const char* kSeverityNames[] =\n        {\n            \"note\",\n            \"warning\",\n            \"error\",\n            \"fatal error\",\n            \"internal error\",\n        };\n\n        static const int kBufferSize = 1024;\n        char buffer[kBufferSize];\n        snprintf(buffer, kBufferSize, \"%s(%d:%d): %s %d: %s\\n\",\n            diagnostic.FileName,\n            diagnostic.Line,\n            diagnostic.Col,\n            kSeverityNames[diagnostic.severity],\n            diagnostic.ErrorId,\n            diagnostic.Message);\n\n        OutputDebugStringA(buffer);\n    }\n\n}\n\nvoid renderFrame(ID3D11DeviceContext* dxContext)\n{\n    // We update our constant buffer per-frame, just for the purposes\n    // of the example, but we don't actually load different data\n    // per-frame (we always use an identity projection).\n    D3D11_MAPPED_SUBRESOURCE mapped;\n    HRESULT hr = dxContext->Map(dxConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);\n    if(!FAILED(hr))\n    {\n        float* data = (float*) mapped.pData;\n\n        static const float kIdentity[] =\n        { 1, 0, 0, 0,\n          0, 1, 0, 0,\n          0, 0, 1, 0,\n          0, 0, 0, 1 };\n        memcpy(data, kIdentity, sizeof(kIdentity));\n\n        dxContext->Unmap(dxConstantBuffer, 0);\n    }\n\n    // Input Assembler (IA)\n\n    dxContext->IASetInputLayout(dxInputLayout);\n    dxContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);\n\n    UINT dxVertexStride = sizeof(Vertex);\n    UINT dxVertexBufferOffset = 0;\n    dxContext->IASetVertexBuffers(0, 1, &dxVertexBuffer, &dxVertexStride, &dxVertexBufferOffset);\n\n    // Vertex Shader (VS)\n\n    dxContext->VSSetShader(dxVertexShader, NULL, 0);\n    dxContext->VSSetConstantBuffers(0, 1, &dxConstantBuffer);\n\n    // Pixel Shader (PS)\n\n    dxContext->PSSetShader(dxPixelShader, NULL, 0);\n    dxContext->VSSetConstantBuffers(0, 1, &dxConstantBuffer);\n\n    //\n\n    dxContext->Draw(3, 0);\n}\n\nvoid finalize()\n{\n}\n\n//\n// Definition of the HLSL-to-bytecode compilation logic.\n//\nID3DBlob* compileHLSLShader(\n    char const* source,\n    char const* dxProfileName )\n{\n    // Rather than statically link against the `d3dcompile` library, we\n    // dynamically load it.\n    //\n    // Note: A more realistic application would compile from HLSL text to D3D\n    // shader bytecode as part of an offline process, rather than doing it\n    // on-the-fly like this\n    //\n    static pD3DCompile D3DCompile_ = nullptr;\n    if( !D3DCompile_ )\n    {\n        // TODO(tfoley): maybe want to search for one of a few versions of the DLL\n        HMODULE d3dcompiler = LoadLibraryA(\"d3dcompiler_47.dll\");\n        if(!d3dcompiler)\n        {\n            fprintf(stderr, \"error: failed load 'd3dcompiler_47.dll'\\n\");\n            exit(1);\n        }\n\n        D3DCompile_ = (pD3DCompile)GetProcAddress(d3dcompiler, \"D3DCompile\");\n        if( !D3DCompile_ )\n        {\n            fprintf(stderr, \"error: failed load symbol 'D3DCompile'\\n\");\n            exit(1);\n        }\n    }\n\n    // For this example, we turn on debug output, and turn off all\n    // optimization. A real application would only use these flags\n    // when shader debugging is needed.\n    UINT flags = 0;\n    flags |= D3DCOMPILE_DEBUG;\n    flags |= D3DCOMPILE_OPTIMIZATION_LEVEL0 | D3DCOMPILE_SKIP_OPTIMIZATION;\n\n    // The `D3DCompile` entry point takes a bunch of parameters, but we\n    // don't really need most of them for Spire-generated code.\n    ID3DBlob* dxShaderBlob = nullptr;\n    ID3DBlob* dxErrorBlob = nullptr;\n    HRESULT hr = D3DCompile_(\n        source,\n        strlen(source),\n        \"spireGeneratedCode\", // TODO: proper path for error messages\n        nullptr,\n        nullptr,\n        \"main\",\n        dxProfileName,\n        flags,\n        0,\n        &dxShaderBlob,\n        &dxErrorBlob);\n\n    // If the HLSL-to-bytecode compilation produced any diagnostic messages\n    // then we will print them out (whether or not the compilation failed).\n    if( dxErrorBlob )\n    {\n        OutputDebugStringA(\n            (char const*)dxErrorBlob->GetBufferPointer());\n        dxErrorBlob->Release();\n    }\n\n    if( FAILED(hr) )\n    {\n        return nullptr;\n    }\n\n    return dxShaderBlob;\n}\n\n\n//\n// We use a bare-minimum window procedure to get things up and running.\n//\n\nstatic LRESULT CALLBACK windowProc(\n    HWND    windowHandle,\n    UINT    message,\n    WPARAM  wParam,\n    LPARAM  lParam)\n{\n    switch (message)\n    {\n    case WM_CLOSE:\n        PostQuitMessage(0);\n        return 0;\n    }\n\n    return DefWindowProcW(windowHandle, message, wParam, lParam);\n}\n\n//\n// Our `WinMain` handles the basic task of getting a window and rendering\n// context up and running. There should be nothing suprising or interesting\n// here.\n//\n\nint WINAPI WinMain(\n    HINSTANCE instance,\n    HINSTANCE /* prevInstance */,\n    LPSTR     /* commandLine */,\n    int       showCommand)\n{\n    // First we register a window class.\n\n    WNDCLASSEXW windowClassDesc;\n    windowClassDesc.cbSize = sizeof(windowClassDesc);\n    windowClassDesc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;\n    windowClassDesc.lpfnWndProc = &windowProc;\n    windowClassDesc.cbClsExtra = 0;\n    windowClassDesc.cbWndExtra = 0;\n    windowClassDesc.hInstance = instance;\n    windowClassDesc.hIcon = 0;\n    windowClassDesc.hCursor = 0;\n    windowClassDesc.hbrBackground = 0;\n    windowClassDesc.lpszMenuName = 0;\n    windowClassDesc.lpszClassName = L\"HelloWorld\";\n    windowClassDesc.hIconSm = 0;\n    ATOM windowClassAtom = RegisterClassExW(&windowClassDesc);\n    if(!windowClassAtom)\n    {\n        fprintf(stderr, \"error: failed to register window class\\n\");\n        return 1;\n    }\n\n    // Next, we create a window using that window class.\n\n    DWORD windowExtendedStyle = 0;\n    DWORD windowStyle = 0;\n    LPWSTR windowName = L\"Spire Hello World\";\n    HWND windowHandle = CreateWindowExW(\n        windowExtendedStyle,\n        (LPWSTR)windowClassAtom,\n        windowName,\n        windowStyle,\n        0, 0, // x, y\n        gWindowWidth, gWindowHeight,\n        NULL, // parent\n        NULL, // menu\n        instance,\n        NULL);\n    if(!windowHandle)\n    {\n        fprintf(stderr, \"error: failed to create window\\n\");\n        return 1;\n    }\n\n\n    // Rather than statically link against D3D, we load it dynamically.\n\n    HMODULE d3d11 = LoadLibraryA(\"d3d11.dll\");\n    if(!d3d11)\n    {\n        fprintf(stderr, \"error: failed load 'd3d11.dll'\\n\");\n        return 1;\n    }\n\n    PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN D3D11CreateDeviceAndSwapChain_ =\n        (PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)GetProcAddress(\n            d3d11,\n            \"D3D11CreateDeviceAndSwapChain\");\n    if(!D3D11CreateDeviceAndSwapChain_)\n    {\n        fprintf(stderr,\n            \"error: failed load symbol 'D3D11CreateDeviceAndSwapChain'\\n\");\n        return 1;\n    }\n\n    // We create our device in debug mode, just so that we can check that the\n    // example doesn't trigger warnings.\n    UINT deviceFlags = 0;\n    deviceFlags |= D3D11_CREATE_DEVICE_DEBUG;\n\n    // We will ask for the highest feature level that can be supported.\n\n    D3D_FEATURE_LEVEL featureLevels[] = {\n        D3D_FEATURE_LEVEL_11_1,\n        D3D_FEATURE_LEVEL_11_0,\n        D3D_FEATURE_LEVEL_10_1,\n        D3D_FEATURE_LEVEL_10_0,\n        D3D_FEATURE_LEVEL_9_3,\n        D3D_FEATURE_LEVEL_9_2,\n        D3D_FEATURE_LEVEL_9_1,\n    };\n    D3D_FEATURE_LEVEL dxFeatureLevel = D3D_FEATURE_LEVEL_9_1;\n\n    // Our swap chain uses RGBA8 with sRGB, with double buffering.\n\n    DXGI_SWAP_CHAIN_DESC dxSwapChainDesc = { 0 };\n    dxSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;\n    dxSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;\n    dxSwapChainDesc.SampleDesc.Count = 1;\n    dxSwapChainDesc.SampleDesc.Quality = 0;\n    dxSwapChainDesc.BufferCount = 2;\n    dxSwapChainDesc.OutputWindow = windowHandle;\n    dxSwapChainDesc.Windowed = TRUE;\n    dxSwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;\n    dxSwapChainDesc.Flags = 0;\n\n    // On a machine that does not have an up-to-date version of D3D installed,\n    // the `D3D11CreateDeviceAndSwapChain` call will fail with `E_INVALIDARG`\n    // if you ask for featuer level 11_1. The workaround is to call\n    // `D3D11CreateDeviceAndSwapChain` up to twice: the first time with 11_1\n    // at the start of the list of requested feature levels, and the second\n    // time without it.\n\n    IDXGISwapChain* dxSwapChain = NULL;\n    ID3D11Device* dxDevice = NULL;\n    ID3D11DeviceContext* dxImmediateContext = NULL;\n    HRESULT hr = S_OK;\n    for( int ii = 0; ii < 2; ++ii )\n    {\n        hr = D3D11CreateDeviceAndSwapChain_(\n            NULL,                    // adapter (use default)\n            D3D_DRIVER_TYPE_HARDWARE,\n            NULL,                    // software\n            deviceFlags,\n            &featureLevels[ii],\n            (sizeof(featureLevels) / sizeof(featureLevels[0])) - 1,\n            D3D11_SDK_VERSION,\n            &dxSwapChainDesc,\n            &dxSwapChain,\n            &dxDevice,\n            &dxFeatureLevel,\n            &dxImmediateContext);\n\n        // Failures with `E_INVALIDARG` might be due to feature level 11_1\n        // not being supported. Other failures are real, though.\n        if( hr != E_INVALIDARG )\n            break;\n    }\n    if( FAILED(hr) )\n    {\n        return 1;\n    }\n\n    // After we've created the swap chain, we can request a pointer to the\n    // back buffer as a D3D11 texture, and create a render-target view from it.\n\n    ID3D11Texture2D* dxBackBufferTexture = NULL;\n    static const IID kIID_ID3D11Texture2D = {\n        0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48,\n        0x95, 0x35, 0xd3, 0x4f, 0x9c };\n    dxSwapChain->GetBuffer(\n        0,\n        kIID_ID3D11Texture2D,\n        (void**)&dxBackBufferTexture);\n\n    ID3D11RenderTargetView* dxBackBufferRTV = NULL;\n    dxDevice->CreateRenderTargetView(\n        dxBackBufferTexture,\n        NULL,\n        &dxBackBufferRTV);\n\n    // We immediately bind the back-buffer render target view, and we aren't\n    // going to switch. We don't bother with a depth buffer.\n    dxImmediateContext->OMSetRenderTargets(\n        1,\n        &dxBackBufferRTV,\n        NULL);\n\n    // Similarly, we are going to set up a viewport once, and then never\n    // switch, since this is a simple test app.\n    D3D11_VIEWPORT dxViewport;\n    dxViewport.TopLeftX = 0;\n    dxViewport.TopLeftY = 0;\n    dxViewport.Width = (float) gWindowWidth;\n    dxViewport.Height = (float) gWindowHeight;\n    dxViewport.MaxDepth = 1; // TODO(tfoley): use reversed depth\n    dxViewport.MinDepth = 0;\n    dxImmediateContext->RSSetViewports(1, &dxViewport);\n\n    // Once we've done the general-purpose initialization, we\n    // initialize anything specific to the \"hello world\" application\n    initialize( dxDevice );\n\n    // Once initialization is all complete, we show the window...\n    ShowWindow(windowHandle, showCommand);\n\n    // ... and enter the event loop:\n    for(;;)\n    {\n        MSG message;\n\n        int result = PeekMessageW(&message, NULL, 0, 0, PM_REMOVE);\n        if (result != 0)\n        {\n            if (message.message == WM_QUIT)\n            {\n                return (int)message.wParam;\n            }\n\n            TranslateMessage(&message);\n            DispatchMessageW(&message);\n        }\n        else\n        {\n            // Whenver we don't have Windows events to process,\n            // we render a frame.\n\n            static const float kClearColor[] = { 0.25, 0.25, 0.25, 1.0 };\n            dxImmediateContext->ClearRenderTargetView(\n                dxBackBufferRTV,\n                kClearColor);\n\n            renderFrame( dxImmediateContext );\n\n            dxSwapChain->Present(0, 0);\n        }\n    }\n\n    return 0;\n}\n\n\n//\n// In order to actually use Spire in our application, we need to link in its\n// implementation. The easiest way to accomplish this is by directly inlcuding\n// the (concatenated) Spire source code into our app.\n//\n\n#include <SpireAllSource.h>\n"
  },
  {
    "path": "Examples/hello/hello.sln",
    "content": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 14\nVisualStudioVersion = 14.0.25420.1\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"hello\", \"hello.vcxproj\", \"{E6385042-1649-4803-9EBD-168F8B7EF131}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|x64.Build.0 = Debug|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|x86.Build.0 = Debug|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release|x64.ActiveCfg = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release|x64.Build.0 = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release|x86.ActiveCfg = Release|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release|x86.Build.0 = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "Examples/hello/hello.spire",
    "content": "// shaders.spire\n\n// TODO(tfoley): strip this down to a minimal pipeline\n\npipeline StandardPipeline\n{\n    [Pinned]\n    input world MeshVertex;\n\n    world CoarseVertex;// : \"glsl(vertex:projCoord)\" using projCoord export standardExport;\n    world Fragment;// : \"glsl\" export fragmentExport;\n    \n    require @CoarseVertex vec4 projCoord; \n  \n    [VertexInput]\n    extern @CoarseVertex MeshVertex vertAttribIn;\n    import(MeshVertex->CoarseVertex) vertexImport()\n    {\n        return project(vertAttribIn);\n    }\n    \n    extern @Fragment CoarseVertex CoarseVertexIn;\n    import(CoarseVertex->Fragment) standardImport()\n// TODO(tfoley): this trait doesn't seem to be implemented on `vec3`\n//        require trait IsTriviallyPassable(CoarseVertex)\n    {\n        return project(CoarseVertexIn);\n    }\n    \n    stage vs : VertexShader\n    {\n        World: CoarseVertex;\n        Position: projCoord;\n    }\n    \n    stage fs : FragmentShader\n    {\n        World: Fragment;\n    }\n}\n\nmodule HelloModule\n{\n    @MeshVertex vec3 position;\n    @MeshVertex vec3 color;\n\n    param mat4 modelViewProjection;\n\n    public vec4 projCoord = modelViewProjection * vec4(position, 1.0);\n\n    out @Fragment vec4 colorTarget = vec4(color,1);\n}\n"
  },
  {
    "path": "Examples/hello/hello.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug_VS2013|Win32\">\n      <Configuration>Debug_VS2013</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug_VS2013|x64\">\n      <Configuration>Debug_VS2013</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release_VS2013|Win32\">\n      <Configuration>Release_VS2013</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release_VS2013|x64\">\n      <Configuration>Release_VS2013</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{E6385042-1649-4803-9EBD-168F8B7EF131}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>hello</RootNamespace>\n    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n    <IncludePath>$(ProjectDir)../../;$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n    <IncludePath>$(ProjectDir)../../;$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n    <IncludePath>$(ProjectDir)../../;$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n    <IncludePath>$(ProjectDir)../../;$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <IncludePath>$(ProjectDir)../../;$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <IncludePath>$(ProjectDir)../../;$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n    <IncludePath>$(ProjectDir)../../;$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n    <IncludePath>$(ProjectDir)../../;$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"hello.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"hello.spire\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "Examples/hello/hello.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"hello.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"hello.spire\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "LICENSE.txt",
    "content": "\nSpire - The MIT License (MIT)\nCopyright (c) 2016, Carnegie Mellon University\n\nDevelopers: Yong He, Haomin Long, Teguh Hofstee\n\nPermission is hereby granted, free of charge, to any person obtaining a \ncopy of this software and associated documentation files (the \"Software\"), \nto deal in the Software without restriction, including without limitation \nthe rights to use, copy, modify, merge, publish, distribute, sublicense, \nand/or sell copies of the Software, and to permit persons to whom the \nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in \nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \nTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Spire\nSpire is a shading language and compiler framework that facilitates modular shader authoring and rapid exploration of shader optimization choices (such as frequency reduction and algorithmic approximation) afforded by modern real-time graphics engines. The current implementation of the Spire compiler can generate either GLSL or SPIR-V output for use with OpenGL and Vulkan based engines.\n\nFor an example of intergrating Spire into a game engine, head to this repository:\nhttps://github.com/csyonghe/GameEngine\n\nNote: This repository is no longer being updated. Code here is used to produce the work of our SIGGRAPH 2017 publication. Please check out our latest development of the Spire shading language at https://github.com/shader-slang/slang.\n\n# Publications\n\n[Shader Components: Modular and High Performance Shader Development](http://graphics.cs.cmu.edu/projects/shadercomp/) SIGGRAPH 2017\n\n[A System for Rapid Exploration of Shader Optimization Choices](http://graphics.cs.cmu.edu/projects/spire/) SIGGRAPH 2016\n"
  },
  {
    "path": "Source/CoreLib/Allocator.h",
    "content": "#ifndef CORE_LIB_ALLOCATOR_H\n#define CORE_LIB_ALLOCATOR_H\n\n#include <stdlib.h>\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\tinline void * AlignedAlloc(size_t size, size_t alignment)\n\t\t{\n#ifdef _MSC_VER\n\t\t\treturn _aligned_malloc(size, alignment);\n#else\n\t\t\tvoid * rs = 0;\n\t\t\tint succ = posix_memalign(&rs, alignment, size);\n\t\t\tif (succ!=0)\n\t\t\t\trs = 0;\n\t\t\treturn rs;\n#endif\n\t\t}\n\n\t\tinline void AlignedFree(void * ptr)\n\t\t{\n#ifdef _MSC_VER\n\t\t\t_aligned_free(ptr);\n#else\n\t\t\tfree(ptr);\n#endif\n\t\t}\n\n\t\tclass StandardAllocator\n\t\t{\n\t\tpublic:\n\t\t\t// not really called\n\t\t\tvoid * Alloc(size_t size)\n\t\t\t{\n\t\t\t\treturn malloc(size);\n\t\t\t}\n\t\t\tvoid Free(void * ptr)\n\t\t\t{\n\t\t\t\treturn free(ptr);\n\t\t\t}\n\t\t};\n\n\t\ttemplate<int alignment>\n\t\tclass AlignedAllocator\n\t\t{\n\t\tpublic:\n\t\t\tvoid * Alloc(size_t size)\n\t\t\t{\n\t\t\t\treturn AlignedAlloc(size, alignment);\n\t\t\t}\n\t\t\tvoid Free(void * ptr)\n\t\t\t{\n\t\t\t\treturn AlignedFree(ptr);\n\t\t\t}\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/CoreLib/Array.h",
    "content": "#ifndef CORE_LIB_ARRAY_H\n#define CORE_LIB_ARRAY_H\n\n#include \"Exception.h\"\n#include \"ArrayView.h\"\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\ttemplate<typename T, int size>\n\t\tclass Array\n\t\t{\n\t\tprivate:\n\t\t\tT _buffer[size];\n\t\t\tint _count = 0;\n\t\tpublic:\n\t\t\tT* begin() const\n\t\t\t{\n\t\t\t\treturn (T*)_buffer;\n\t\t\t}\n\t\t\tT* end() const\n\t\t\t{\n\t\t\t\treturn (T*)_buffer + _count;\n\t\t\t}\n\t\tpublic:\n\t\t\tinline int GetCapacity() const\n\t\t\t{\n\t\t\t\treturn size;\n\t\t\t}\n\t\t\tinline int Count() const\n\t\t\t{\n\t\t\t\treturn _count;\n\t\t\t}\n\t\t\tinline T & First() const\n\t\t\t{\n\t\t\t\treturn const_cast<T&>(_buffer[0]);\n\t\t\t}\n\t\t\tinline T & Last() const\n\t\t\t{\n\t\t\t\treturn const_cast<T&>(_buffer[_count - 1]);\n\t\t\t}\n\t\t\tinline void SetSize(int newSize)\n\t\t\t{\n#ifdef _DEBUG\n\t\t\t\tif (newSize > size)\n\t\t\t\t\tthrow IndexOutofRangeException(\"size too large.\");\n#endif\n\t\t\t\t_count = newSize;\n\t\t\t}\n\t\t\tinline void Add(const T & item)\n\t\t\t{\n#ifdef _DEBUG\n\t\t\t\tif (_count == size)\n\t\t\t\t\tthrow IndexOutofRangeException(\"out of range access to static array.\");\n#endif\n\t\t\t\t_buffer[_count++] = item;\n\t\t\t}\n\t\t\tinline void Add(T && item)\n\t\t\t{\n#ifdef _DEBUG\n\t\t\t\tif (_count == size)\n\t\t\t\t\tthrow IndexOutofRangeException(\"out of range access to static array.\");\n#endif\n\t\t\t\t_buffer[_count++] = _Move(item);\n\t\t\t}\n\n\t\t\tinline T & operator [](int id) const\n\t\t\t{\n#if _DEBUG\n\t\t\t\tif (id >= _count || id < 0)\n\t\t\t\t\tthrow IndexOutofRangeException(\"Operator[]: Index out of Range.\");\n#endif\n\t\t\t\treturn ((T*)_buffer)[id];\n\t\t\t}\n\n\t\t\tinline T* Buffer() const\n\t\t\t{\n\t\t\t\treturn (T*)_buffer;\n\t\t\t}\n\n\t\t\tinline void Clear()\n\t\t\t{\n\t\t\t\t_count = 0;\n\t\t\t}\n\n\t\t\ttemplate<typename T2>\n\t\t\tint IndexOf(const T2 & val) const\n\t\t\t{\n\t\t\t\tfor (int i = 0; i < _count; i++)\n\t\t\t\t{\n\t\t\t\t\tif (_buffer[i] == val)\n\t\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\ttemplate<typename T2>\n\t\t\tint LastIndexOf(const T2 & val) const\n\t\t\t{\n\t\t\t\tfor (int i = _count - 1; i >= 0; i--)\n\t\t\t\t{\n\t\t\t\t\tif (_buffer[i] == val)\n\t\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tinline ArrayView<T> GetArrayView() const\n\t\t\t{\n\t\t\t\treturn ArrayView<T>((T*)_buffer, _count);\n\t\t\t}\n\t\t\tinline ArrayView<T> GetArrayView(int start, int count) const\n\t\t\t{\n\t\t\t\treturn ArrayView<T>((T*)_buffer + start, count);\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename T, typename ...TArgs>\n\t\tstruct FirstType\n\t\t{\n\t\t\ttypedef T type;\n\t\t};\n\n\n\t\ttemplate<typename T, int size>\n\t\tvoid InsertArray(Array<T, size> &) {}\n\n\t\ttemplate<typename T, typename ...TArgs, int size>\n\t\tvoid InsertArray(Array<T, size> & arr, const T & val, TArgs... args)\n\t\t{\n\t\t\tarr.Add(val);\n\t\t\tInsertArray(arr, args...);\n\t\t}\n\n\t\ttemplate<typename ...TArgs>\n\t\tauto MakeArray(TArgs ...args)\n\t\t{\n\t\t\tArray<typename FirstType<TArgs...>::type, sizeof...(args)> rs;\n\t\t\tInsertArray(rs, args...);\n\t\t\treturn rs;\n\t\t}\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/CoreLib/ArrayView.h",
    "content": "#ifndef CORE_LIB_ARRAY_VIEW_H\n#define CORE_LIB_ARRAY_VIEW_H\n\n#include \"Exception.h\"\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\ttemplate<typename T>\n\t\tclass ArrayView\n\t\t{\n\t\tprivate:\n\t\t\tT * _buffer;\n\t\t\tint _count;\n\t\t\tint stride;\n\t\tpublic:\n\t\t\tT* begin() const\n\t\t\t{\n\t\t\t\treturn _buffer;\n\t\t\t}\n\t\t\tT* end() const\n\t\t\t{\n\t\t\t\treturn (T*)((char*)_buffer + _count*stride);\n\t\t\t}\n\t\tpublic:\n\t\t\tArrayView()\n\t\t\t{\n\t\t\t\t_buffer = 0;\n\t\t\t\t_count = 0;\n\t\t\t}\n\t\t\tArrayView(const T & singleObj)\n\t\t\t{\n\t\t\t\tSetData((T*)&singleObj, 1, sizeof(T));\n\t\t\t}\n\t\t\tArrayView(T * buffer, int count)\n\t\t\t{\n\t\t\t\tSetData(buffer, count, sizeof(T));\n\t\t\t}\n\t\t\tArrayView(void * buffer, int count, int _stride)\n\t\t\t{\n\t\t\t\tSetData(buffer, count, _stride);\n\t\t\t}\n\t\t\tvoid SetData(void * buffer, int count, int _stride)\n\t\t\t{\n\t\t\t\tthis->_buffer = (T*)buffer;\n\t\t\t\tthis->_count = count;\n\t\t\t\tthis->stride = _stride;\n\t\t\t}\n\t\t\tinline int GetCapacity() const\n\t\t\t{\n\t\t\t\treturn _count;\n\t\t\t}\n\t\t\tinline int Count() const\n\t\t\t{\n\t\t\t\treturn _count;\n\t\t\t}\n\n\t\t\tinline T & operator [](int id) const\n\t\t\t{\n#if _DEBUG\n\t\t\t\tif (id >= _count || id < 0)\n\t\t\t\t\tthrow IndexOutofRangeException(\"Operator[]: Index out of Range.\");\n#endif\n\t\t\t\treturn *(T*)((char*)_buffer+id*stride);\n\t\t\t}\n\n\t\t\tinline T* Buffer() const\n\t\t\t{\n\t\t\t\treturn _buffer;\n\t\t\t}\n\n\t\t\ttemplate<typename T2>\n\t\t\tint IndexOf(const T2 & val) const\n\t\t\t{\n\t\t\t\tfor (int i = 0; i < _count; i++)\n\t\t\t\t{\n\t\t\t\t\tif (*(T*)((char*)_buffer + i*stride) == val)\n\t\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\ttemplate<typename T2>\n\t\t\tint LastIndexOf(const T2 & val) const\n\t\t\t{\n\t\t\t\tfor (int i = _count - 1; i >= 0; i--)\n\t\t\t\t{\n\t\t\t\t\tif (*(T*)((char*)_buffer + i*stride) == val)\n\t\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\ttemplate<typename Func>\n\t\t\tint FindFirst(const Func & predicate) const\n\t\t\t{\n\t\t\t\tfor (int i = 0; i < _count; i++)\n\t\t\t\t{\n\t\t\t\t\tif (predicate(_buffer[i]))\n\t\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\ttemplate<typename Func>\n\t\t\tint FindLast(const Func & predicate) const\n\t\t\t{\n\t\t\t\tfor (int i = _count - 1; i >= 0; i--)\n\t\t\t\t{\n\t\t\t\t\tif (predicate(_buffer[i]))\n\t\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename T>\n\t\tArrayView<T> MakeArrayView(const T & obj)\n\t\t{\n\t\t\treturn ArrayView<T>(obj);\n\t\t}\n\t\t\n\t\ttemplate<typename T>\n\t\tArrayView<T> MakeArrayView(T * buffer, int count)\n\t\t{\n\t\t\treturn ArrayView<T>(buffer, count);\n\t\t}\n\t}\n}\n#endif"
  },
  {
    "path": "Source/CoreLib/Basic.h",
    "content": "#ifndef CORE_LIB_BASIC_H\n#define CORE_LIB_BASIC_H\n\n#include \"Common.h\"\n#include \"LibMath.h\"\n#include \"LibString.h\"\n#include \"Array.h\"\n#include \"List.h\"\n#include \"Link.h\"\n#include \"SmartPointer.h\"\n#include \"Exception.h\"\n#include \"Dictionary.h\"\n#include \"Func.h\"\n#include \"Linq.h\"\n\nnamespace CoreLib\n{\n\tusing namespace Basic;\n}\n\n#endif"
  },
  {
    "path": "Source/CoreLib/CMakeLists.txt",
    "content": "cmake_minimum_required (VERSION 2.6) \nproject (CoreLib) \n\nadd_library(CoreLib_Basic STATIC\n Basic.h\n Common.h\n Dictionary.h\n Exception.h\n IntSet.h\n LibIO.cpp\n LibIO.h\n LibMath.cpp\n LibMath.h\n LibString.cpp\n LibString.h\n Link.h\n List.h\n Parser.cpp\n Parser.h\n PerformanceCounter.cpp\n PerformanceCounter.h\n SmartPointer.h\n Stream.cpp\n Stream.h\n TextIO.cpp\n TextIO.h\n Threading.h\n VectorMath.cpp\n VectorMath.h\n WideChar.cpp\n WideChar.h\n SecureCRT.h\n)\nadd_subdirectory (Graphics) \nadd_subdirectory (Imaging)\nadd_subdirectory (Regex)\n"
  },
  {
    "path": "Source/CoreLib/CommandLineParser.cpp",
    "content": "#include \"CommandLineParser.h\"\n\nnamespace CoreLib\n{\n\tnamespace Text\n\t{\n\t\tCommandLineParser::CommandLineParser(const String & cmdLine)\n\t\t{\n\t\t\tstream = Split(cmdLine, L' ');\n\t\t}\n\n\t\tString CommandLineParser::GetFileName()\n\t\t{\n\t\t\tif (stream.Count())\n\t\t\t\treturn stream.First();\n\t\t\telse\n\t\t\t\treturn \"\";\n\t\t}\n\n\t\tbool CommandLineParser::OptionExists(const String & opt)\n\t\t{\n\t\t\tfor (auto & token : stream)\n\t\t\t{\n\t\t\t\tif (token.Equals(opt, false))\n\t\t\t\t{\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tString CommandLineParser::GetOptionValue(const String & opt)\n\t\t{\n\t\t\tfor (int i = 0; i < stream.Count(); i++)\n\t\t\t{\n\t\t\t\tif (stream[i].Equals(opt, false))\n\t\t\t\t{\n\t\t\t\t\tif (i < stream.Count() - 1)\n\t\t\t\t\t\treturn stream[i+1];\n\t\t\t\t\treturn \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn \"\";\n\t\t}\n\n\t\tString CommandLineParser::GetToken(int id)\n\t\t{\n\t\t\treturn stream[id];\n\t\t}\n\n\t\tint CommandLineParser::GetTokenCount()\n\t\t{\n\t\t\treturn stream.Count();\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/CoreLib/CommandLineParser.h",
    "content": "#ifndef CORE_LIB_COMMANDLINE_PARSER\n#define CORE_LIB_COMMANDLINE_PARSER\n\n#include \"Tokenizer.h\"\n\nnamespace CoreLib\n{\n\tnamespace Text\n\t{\n\t\tclass CommandLineParser : public Object\n\t\t{\n\t\tprivate:\n\t\t\tList<String> stream;\n\t\tpublic:\n\t\t\tCommandLineParser(const String & cmdLine);\n\t\t\tString GetFileName();\n\t\t\tbool OptionExists(const String & opt);\n\t\t\tString GetOptionValue(const String & opt);\n\t\t\tString GetToken(int id);\n\t\t\tint GetTokenCount();\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/CoreLib/Common.h",
    "content": "#ifndef CORE_LIB_COMMON_H\n#define CORE_LIB_COMMON_H\n\n#include <cstdint>\n\n#ifdef __GNUC__\n#define CORE_LIB_ALIGN_16(x) x __attribute__((aligned(16)))\n#else\n#define CORE_LIB_ALIGN_16(x) __declspec(align(16)) x\n#endif\n\n#define VARIADIC_TEMPLATE\n\nnamespace CoreLib\n{\n\ttypedef int64_t Int64;\n\ttypedef unsigned short Word;\n#ifdef _M_X64\n\ttypedef int64_t PtrInt;\n#else\n\ttypedef int PtrInt;\n#endif\n\tnamespace Basic\n\t{\n\t\tclass Object\n\t\t{\n\t\tpublic:\n\t\t\tvirtual ~Object()\n\t\t\t{}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tinline T&& _Move(T & obj)\n\t\t{\n\t\t\treturn static_cast<T&&>(obj);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tinline void Swap(T & v0, T & v1)\n\t\t{\n\t\t\tT tmp = _Move(v0);\n\t\t\tv0 = _Move(v1);\n\t\t\tv1 = _Move(tmp);\n\t\t}\n\t}\n}\n\n#endif\n"
  },
  {
    "path": "Source/CoreLib/CoreLibBasic.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugClang|ARM\">\n      <Configuration>DebugClang</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugClang|Win32\">\n      <Configuration>DebugClang</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugClang|x64\">\n      <Configuration>DebugClang</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug_VS2013|ARM\">\n      <Configuration>Debug_VS2013</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug_VS2013|Win32\">\n      <Configuration>Debug_VS2013</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug_VS2013|x64\">\n      <Configuration>Debug_VS2013</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|ARM\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release_VS2013|ARM\">\n      <Configuration>Release_VS2013</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release_VS2013|Win32\">\n      <Configuration>Release_VS2013</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release_VS2013|x64\">\n      <Configuration>Release_VS2013</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"TracingDebug|ARM\">\n      <Configuration>TracingDebug</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"TracingDebug|Win32\">\n      <Configuration>TracingDebug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"TracingDebug|x64\">\n      <Configuration>TracingDebug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"TracingRelease|ARM\">\n      <Configuration>TracingRelease</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"TracingRelease|Win32\">\n      <Configuration>TracingRelease</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"TracingRelease|x64\">\n      <Configuration>TracingRelease</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\" />\n  <PropertyGroup Label=\"Globals\">\n  </PropertyGroup>\n  <PropertyGroup Label=\"Globals\">\n  </PropertyGroup>\n  <PropertyGroup Label=\"Globals\">\n  </PropertyGroup>\n  <PropertyGroup Label=\"Globals\">\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>CoreLib</RootNamespace>\n    <ProjectGuid>{F9BE7957-8399-899E-0C49-E714FDDD4B65}</ProjectGuid>\n    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140_clang_3_7</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingDebug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140_Clang_3_7</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingDebug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|ARM'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|ARM'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140_clang_3_7</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingDebug|ARM'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingRelease|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingRelease|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|ARM'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingRelease|ARM'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingDebug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingDebug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|ARM'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|ARM'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingDebug|ARM'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingRelease|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingRelease|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|ARM'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingRelease|ARM'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup />\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>EnableAllWarnings</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\n      <RuntimeTypeInfo>true</RuntimeTypeInfo>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingDebug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <BrowseInformation>true</BrowseInformation>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n    <Bscmake>\n      <PreserveSbr>true</PreserveSbr>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <BrowseInformation>true</BrowseInformation>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n    <Bscmake>\n      <PreserveSbr>true</PreserveSbr>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <BrowseInformation>true</BrowseInformation>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n    <Bscmake>\n      <PreserveSbr>true</PreserveSbr>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingDebug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|ARM'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|ARM'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingDebug|ARM'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingRelease|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingRelease|x64'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <FloatingPointExceptions>false</FloatingPointExceptions>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|ARM'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='TracingRelease|ARM'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"Allocator.h\" />\n    <ClInclude Include=\"Array.h\" />\n    <ClInclude Include=\"ArrayView.h\" />\n    <ClInclude Include=\"Basic.h\" />\n    <ClInclude Include=\"Common.h\" />\n    <ClInclude Include=\"Dictionary.h\" />\n    <ClInclude Include=\"Exception.h\" />\n    <ClInclude Include=\"Func.h\" />\n    <ClInclude Include=\"Hash.h\" />\n    <ClInclude Include=\"IntSet.h\" />\n    <ClInclude Include=\"LibIO.h\" />\n    <ClInclude Include=\"LibString.h\" />\n    <ClInclude Include=\"Link.h\" />\n    <ClInclude Include=\"Linq.h\" />\n    <ClInclude Include=\"List.h\" />\n    <ClInclude Include=\"LibMath.h\" />\n    <ClInclude Include=\"Tokenizer.h\" />\n    <ClInclude Include=\"SecureCRT.h\" />\n    <ClInclude Include=\"SmartPointer.h\" />\n    <ClInclude Include=\"Stream.h\" />\n    <ClInclude Include=\"TextIO.h\" />\n    <ClInclude Include=\"TypeTraits.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"LibIO.cpp\" />\n    <ClCompile Include=\"LibMath.cpp\" />\n    <ClCompile Include=\"LibString.cpp\" />\n    <ClCompile Include=\"Tokenizer.cpp\" />\n    <ClCompile Include=\"Stream.cpp\" />\n    <ClCompile Include=\"TextIO.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"corelib.natvis\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>\n"
  },
  {
    "path": "Source/CoreLib/Dictionary.h",
    "content": "#ifndef CORE_LIB_DICTIONARY_H\n#define CORE_LIB_DICTIONARY_H\n#include \"List.h\"\n#include \"Common.h\"\n#include \"IntSet.h\"\n#include \"Exception.h\"\n#include \"LibMath.h\"\n#include \"Hash.h\"\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\ttemplate<typename TKey, typename TValue>\n\t\tclass KeyValuePair\n\t\t{\n\t\tpublic:\n\t\t\tTKey Key;\n\t\t\tTValue Value;\n\t\t\tKeyValuePair()\n\t\t\t{}\n\t\t\tKeyValuePair(const TKey & key, const TValue & value)\n\t\t\t{\n\t\t\t\tKey = key;\n\t\t\t\tValue = value;\n\t\t\t}\n\t\t\tKeyValuePair(TKey && key, TValue && value)\n\t\t\t{\n\t\t\t\tKey = _Move(key);\n\t\t\t\tValue = _Move(value);\n\t\t\t}\n\t\t\tKeyValuePair(TKey && key, const TValue & value)\n\t\t\t{\n\t\t\t\tKey = _Move(key);\n\t\t\t\tValue = value;\n\t\t\t}\n\t\t\tKeyValuePair(const KeyValuePair<TKey, TValue> & _that)\n\t\t\t{\n\t\t\t\tKey = _that.Key;\n\t\t\t\tValue = _that.Value;\n\t\t\t}\n\t\t\tKeyValuePair(KeyValuePair<TKey, TValue> && _that)\n\t\t\t{\n\t\t\t\toperator=(_Move(_that));\n\t\t\t}\n\t\t\tKeyValuePair & operator=(KeyValuePair<TKey, TValue> && that)\n\t\t\t{\n\t\t\t\tKey = _Move(that.Key);\n\t\t\t\tValue = _Move(that.Value);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tKeyValuePair & operator=(const KeyValuePair<TKey, TValue> & that)\n\t\t\t{\n\t\t\t\tKey = that.Key;\n\t\t\t\tValue = that.Value;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tint GetHashCode()\n\t\t\t{\n\t\t\t\treturn GetHashCode(Key);\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename TKey, typename TValue>\n\t\tinline KeyValuePair<TKey, TValue> KVPair(const TKey & k, const TValue & v)\n\t\t{\n\t\t\treturn KeyValuePair<TKey, TValue>(k, v);\n\t\t}\n\n\t\tconst float MaxLoadFactor = 0.7f;\n\n\t\ttemplate<typename TKey, typename TValue>\n\t\tclass Dictionary\n\t\t{\n\t\t\tfriend class Iterator;\n\t\t\tfriend class ItemProxy;\n\t\tprivate:\n\t\t\tinline int GetProbeOffset(int /*probeId*/) const\n\t\t\t{\n\t\t\t\t// quadratic probing\n\t\t\t\treturn 1;\n\t\t\t}\n\t\tprivate:\n\t\t\tint bucketSizeMinusOne, shiftBits;\n\t\t\tint _count;\n\t\t\tIntSet marks;\n\t\t\tKeyValuePair<TKey, TValue>* hashMap;\n\t\t\tvoid Free()\n\t\t\t{\n\t\t\t\tif (hashMap)\n\t\t\t\t\tdelete[] hashMap;\n\t\t\t\thashMap = 0;\n\t\t\t}\n\t\t\tinline bool IsDeleted(int pos) const\n\t\t\t{\n\t\t\t\treturn marks.Contains((pos << 1) + 1);\n\t\t\t}\n\t\t\tinline bool IsEmpty(int pos) const\n\t\t\t{\n\t\t\t\treturn !marks.Contains((pos << 1));\n\t\t\t}\n\t\t\tinline void SetDeleted(int pos, bool val)\n\t\t\t{\n\t\t\t\tif (val)\n\t\t\t\t\tmarks.Add((pos << 1) + 1);\n\t\t\t\telse\n\t\t\t\t\tmarks.Remove((pos << 1) + 1);\n\t\t\t}\n\t\t\tinline void SetEmpty(int pos, bool val)\n\t\t\t{\n\t\t\t\tif (val)\n\t\t\t\t\tmarks.Remove((pos << 1));\n\t\t\t\telse\n\t\t\t\t\tmarks.Add((pos << 1));\n\t\t\t}\n\t\t\tstruct FindPositionResult\n\t\t\t{\n\t\t\t\tint ObjectPosition;\n\t\t\t\tint InsertionPosition;\n\t\t\t\tFindPositionResult()\n\t\t\t\t{\n\t\t\t\t\tObjectPosition = -1;\n\t\t\t\t\tInsertionPosition = -1;\n\t\t\t\t}\n\t\t\t\tFindPositionResult(int objPos, int insertPos)\n\t\t\t\t{\n\t\t\t\t\tObjectPosition = objPos;\n\t\t\t\t\tInsertionPosition = insertPos;\n\t\t\t\t}\n\n\t\t\t};\n\t\t\ttemplate<typename T>\n\t\t\tinline int GetHashPos(T & key) const\n\t\t\t{\n\t\t\t\treturn ((unsigned int)(GetHashCode(key) * 2654435761)) >> shiftBits;\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tFindPositionResult FindPosition(const T & key) const\n\t\t\t{\n\t\t\t\tint hashPos = GetHashPos((T&)key);\n\t\t\t\tint insertPos = -1;\n\t\t\t\tint numProbes = 0;\n\t\t\t\twhile (numProbes <= bucketSizeMinusOne)\n\t\t\t\t{\n\t\t\t\t\tif (IsEmpty(hashPos))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (insertPos == -1)\n\t\t\t\t\t\t\treturn FindPositionResult(-1, hashPos);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn FindPositionResult(-1, insertPos);\n\t\t\t\t\t}\n\t\t\t\t\telse if (IsDeleted(hashPos))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (insertPos == -1)\n\t\t\t\t\t\t\tinsertPos = hashPos;\n\t\t\t\t\t}\n\t\t\t\t\telse if (hashMap[hashPos].Key == key)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn FindPositionResult(hashPos, -1);\n\t\t\t\t\t}\n\t\t\t\t\tnumProbes++;\n\t\t\t\t\thashPos = (hashPos + GetProbeOffset(numProbes)) & bucketSizeMinusOne;\n\t\t\t\t}\n\t\t\t\tif (insertPos != -1)\n\t\t\t\t\treturn FindPositionResult(-1, insertPos);\n\t\t\t\tthrow InvalidOperationException(\"Hash map is full. This indicates an error in Key::Equal or Key::GetHashCode.\");\n\t\t\t}\n\t\t\tTValue & _Insert(KeyValuePair<TKey, TValue> && kvPair, int pos)\n\t\t\t{\n\t\t\t\thashMap[pos] = _Move(kvPair);\n\t\t\t\tSetEmpty(pos, false);\n\t\t\t\tSetDeleted(pos, false);\n\t\t\t\treturn hashMap[pos].Value;\n\t\t\t}\n\t\t\tvoid Rehash()\n\t\t\t{\n\t\t\t\tif (bucketSizeMinusOne == -1 || _count / (float)bucketSizeMinusOne >= MaxLoadFactor)\n\t\t\t\t{\n\t\t\t\t\tint newSize = (bucketSizeMinusOne + 1) * 2;\n\t\t\t\t\tint newShiftBits = shiftBits - 1;\n\t\t\t\t\tif (newSize == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tnewSize = 16;\n\t\t\t\t\t\tnewShiftBits = 28;\n\t\t\t\t\t}\n\t\t\t\t\tDictionary<TKey, TValue> newDict;\n\t\t\t\t\tnewDict.shiftBits = newShiftBits;\n\t\t\t\t\tnewDict.bucketSizeMinusOne = newSize - 1;\n\t\t\t\t\tnewDict.hashMap = new KeyValuePair<TKey, TValue>[newSize];\n\t\t\t\t\tnewDict.marks.SetMax(newSize * 2);\n\t\t\t\t\tif (hashMap)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto & kvPair : *this)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnewDict.Add(_Move(kvPair));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t*this = _Move(newDict);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbool AddIfNotExists(KeyValuePair<TKey, TValue> && kvPair)\n\t\t\t{\n\t\t\t\tRehash();\n\t\t\t\tauto pos = FindPosition(kvPair.Key);\n\t\t\t\tif (pos.ObjectPosition != -1)\n\t\t\t\t\treturn false;\n\t\t\t\telse if (pos.InsertionPosition != -1)\n\t\t\t\t{\n\t\t\t\t\t_count++;\n\t\t\t\t\t_Insert(_Move(kvPair), pos.InsertionPosition);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"Inconsistent find result returned. This is a bug in Dictionary implementation.\");\n\t\t\t}\n\t\t\tvoid Add(KeyValuePair<TKey, TValue> && kvPair)\n\t\t\t{\n\t\t\t\tif (!AddIfNotExists(_Move(kvPair)))\n\t\t\t\t\tthrow KeyExistsException(\"The key already exists in Dictionary.\");\n\t\t\t}\n\t\t\tTValue & Set(KeyValuePair<TKey, TValue> && kvPair)\n\t\t\t{\n\t\t\t\tRehash();\n\t\t\t\tauto pos = FindPosition(kvPair.Key);\n\t\t\t\tif (pos.ObjectPosition != -1)\n\t\t\t\t\treturn _Insert(_Move(kvPair), pos.ObjectPosition);\n\t\t\t\telse if (pos.InsertionPosition != -1)\n\t\t\t\t{\n\t\t\t\t\t_count++;\n\t\t\t\t\treturn _Insert(_Move(kvPair), pos.InsertionPosition);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"Inconsistent find result returned. This is a bug in Dictionary implementation.\");\n\t\t\t}\n\t\tpublic:\n\t\t\tclass Iterator\n\t\t\t{\n\t\t\tprivate:\n\t\t\t\tconst Dictionary<TKey, TValue> * dict;\n\t\t\t\tint pos;\n\t\t\tpublic:\n\t\t\t\tKeyValuePair<TKey, TValue> & operator *() const\n\t\t\t\t{\n\t\t\t\t\treturn dict->hashMap[pos];\n\t\t\t\t}\n\t\t\t\tKeyValuePair<TKey, TValue> * operator ->() const\n\t\t\t\t{\n\t\t\t\t\treturn dict->hashMap + pos;\n\t\t\t\t}\n\t\t\t\tIterator & operator ++()\n\t\t\t\t{\n\t\t\t\t\tif (pos > dict->bucketSizeMinusOne)\n\t\t\t\t\t\treturn *this;\n\t\t\t\t\tpos++;\n\t\t\t\t\twhile (pos <= dict->bucketSizeMinusOne && (dict->IsDeleted(pos) || dict->IsEmpty(pos)))\n\t\t\t\t\t{\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\treturn *this;\n\t\t\t\t}\n\t\t\t\tIterator operator ++(int)\n\t\t\t\t{\n\t\t\t\t\tIterator rs = *this;\n\t\t\t\t\toperator++();\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tbool operator != (const Iterator & _that) const\n\t\t\t\t{\n\t\t\t\t\treturn pos != _that.pos || dict != _that.dict;\n\t\t\t\t}\n\t\t\t\tbool operator == (const Iterator & _that) const\n\t\t\t\t{\n\t\t\t\t\treturn pos == _that.pos && dict == _that.dict;\n\t\t\t\t}\n\t\t\t\tIterator(const Dictionary<TKey, TValue> * _dict, int _pos)\n\t\t\t\t{\n\t\t\t\t\tthis->dict = _dict;\n\t\t\t\t\tthis->pos = _pos;\n\t\t\t\t}\n\t\t\t\tIterator()\n\t\t\t\t{\n\t\t\t\t\tthis->dict = 0;\n\t\t\t\t\tthis->pos = 0;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tIterator begin() const\n\t\t\t{\n\t\t\t\tint pos = 0;\n\t\t\t\twhile (pos < bucketSizeMinusOne + 1)\n\t\t\t\t{\n\t\t\t\t\tif (IsEmpty(pos) || IsDeleted(pos))\n\t\t\t\t\t\tpos++;\n\t\t\t\t\telse\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\treturn Iterator(this, pos);\n\t\t\t}\n\t\t\tIterator end() const\n\t\t\t{\n\t\t\t\treturn Iterator(this, bucketSizeMinusOne + 1);\n\t\t\t}\n\t\tpublic:\n\t\t\tvoid Add(const TKey & key, const TValue & value)\n\t\t\t{\n\t\t\t\tAdd(KeyValuePair<TKey, TValue>(key, value));\n\t\t\t}\n\t\t\tvoid Add(TKey && key, TValue && value)\n\t\t\t{\n\t\t\t\tAdd(KeyValuePair<TKey, TValue>(_Move(key), _Move(value)));\n\t\t\t}\n\t\t\tbool AddIfNotExists(const TKey & key, const TValue & value)\n\t\t\t{\n\t\t\t\treturn AddIfNotExists(KeyValuePair<TKey, TValue>(key, value));\n\t\t\t}\n\t\t\tbool AddIfNotExists(TKey && key, TValue && value)\n\t\t\t{\n\t\t\t\treturn AddIfNotExists(KeyValuePair<TKey, TValue>(_Move(key), _Move(value)));\n\t\t\t}\n\t\t\tvoid Remove(const TKey & key)\n\t\t\t{\n\t\t\t\tif (_count == 0)\n\t\t\t\t\treturn;\n\t\t\t\tauto pos = FindPosition(key);\n\t\t\t\tif (pos.ObjectPosition != -1)\n\t\t\t\t{\n\t\t\t\t\tSetDeleted(pos.ObjectPosition, true);\n\t\t\t\t\t_count--;\n\t\t\t\t}\n\t\t\t}\n\t\t\tvoid Clear()\n\t\t\t{\n\t\t\t\t_count = 0;\n\n\t\t\t\tmarks.Clear();\n\t\t\t}\n\n\t\t\ttemplate<typename T>\n\t\t\tbool ContainsKey(const T & key) const\n\t\t\t{\n\t\t\t\tif (bucketSizeMinusOne == -1)\n\t\t\t\t\treturn false;\n\t\t\t\tauto pos = FindPosition(key);\n\t\t\t\treturn pos.ObjectPosition != -1;\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tbool TryGetValue(const T & key, TValue & value) const\n\t\t\t{\n\t\t\t\tif (bucketSizeMinusOne == -1)\n\t\t\t\t\treturn false;\n\t\t\t\tauto pos = FindPosition(key);\n\t\t\t\tif (pos.ObjectPosition != -1)\n\t\t\t\t{\n\t\t\t\t\tvalue = hashMap[pos.ObjectPosition].Value;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tTValue * TryGetValue(const T & key) const\n\t\t\t{\n\t\t\t\tif (bucketSizeMinusOne == -1)\n\t\t\t\t\treturn nullptr;\n\t\t\t\tauto pos = FindPosition(key);\n\t\t\t\tif (pos.ObjectPosition != -1)\n\t\t\t\t{\n\t\t\t\t\treturn &hashMap[pos.ObjectPosition].Value;\n\t\t\t\t}\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\tclass ItemProxy\n\t\t\t{\n\t\t\tprivate:\n\t\t\t\tconst Dictionary<TKey, TValue> * dict;\n\t\t\t\tTKey key;\n\t\t\tpublic:\n\t\t\t\tItemProxy(const TKey & _key, const Dictionary<TKey, TValue> * _dict)\n\t\t\t\t{\n\t\t\t\t\tthis->dict = _dict;\n\t\t\t\t\tthis->key = _key;\n\t\t\t\t}\n\t\t\t\tItemProxy(TKey && _key, const Dictionary<TKey, TValue> * _dict)\n\t\t\t\t{\n\t\t\t\t\tthis->dict = _dict;\n\t\t\t\t\tthis->key = _Move(_key);\n\t\t\t\t}\n\t\t\t\tTValue & GetValue() const\n\t\t\t\t{\n\t\t\t\t\tauto pos = dict->FindPosition(key);\n\t\t\t\t\tif (pos.ObjectPosition != -1)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn dict->hashMap[pos.ObjectPosition].Value;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow KeyNotFoundException(\"The key does not exists in dictionary.\");\n\t\t\t\t}\n\t\t\t\tinline TValue & operator()() const\n\t\t\t\t{\n\t\t\t\t\treturn GetValue();\n\t\t\t\t}\n\t\t\t\toperator TValue&() const\n\t\t\t\t{\n\t\t\t\t\treturn GetValue();\n\t\t\t\t}\n\t\t\t\tTValue & operator = (const TValue & val) const\n\t\t\t\t{\n\t\t\t\t\treturn ((Dictionary<TKey, TValue>*)dict)->Set(KeyValuePair<TKey, TValue>(_Move(key), val));\n\t\t\t\t}\n\t\t\t\tTValue & operator = (TValue && val) const\n\t\t\t\t{\n\t\t\t\t\treturn ((Dictionary<TKey, TValue>*)dict)->Set(KeyValuePair<TKey, TValue>(_Move(key), _Move(val)));\n\t\t\t\t}\n\t\t\t};\n\t\t\tItemProxy operator [](const TKey & key) const\n\t\t\t{\n\t\t\t\treturn ItemProxy(key, this);\n\t\t\t}\n\t\t\tItemProxy operator [](TKey && key) const\n\t\t\t{\n\t\t\t\treturn ItemProxy(_Move(key), this);\n\t\t\t}\n\t\t\tint Count() const\n\t\t\t{\n\t\t\t\treturn _count;\n\t\t\t}\n\t\tprivate:\n\t\t\ttemplate<typename... Args>\n\t\t\tvoid Init(const KeyValuePair<TKey, TValue> & kvPair, Args... args)\n\t\t\t{\n\t\t\t\tAdd(kvPair);\n\t\t\t\tInit(args...);\n\t\t\t}\n\t\tpublic:\n\t\t\tDictionary()\n\t\t\t{\n\t\t\t\tbucketSizeMinusOne = -1;\n\t\t\t\tshiftBits = 32;\n\t\t\t\t_count = 0;\n\t\t\t\thashMap = 0;\n\t\t\t}\n\t\t\ttemplate<typename Arg, typename... Args>\n\t\t\tDictionary(Arg arg, Args... args)\n\t\t\t{\n\t\t\t\tInit(arg, args...);\n\t\t\t}\n\t\t\tDictionary(const Dictionary<TKey, TValue> & other)\n\t\t\t\t: bucketSizeMinusOne(-1), _count(0), hashMap(0)\n\t\t\t{\n\t\t\t\t*this = other;\n\t\t\t}\n\t\t\tDictionary(Dictionary<TKey, TValue> && other)\n\t\t\t\t: bucketSizeMinusOne(-1), _count(0), hashMap(0)\n\t\t\t{\n\t\t\t\t*this = (_Move(other));\n\t\t\t}\n\t\t\tDictionary<TKey, TValue> & operator = (const Dictionary<TKey, TValue> & other)\n\t\t\t{\n\t\t\t\tif (this == &other)\n\t\t\t\t\treturn *this;\n\t\t\t\tFree();\n\t\t\t\tbucketSizeMinusOne = other.bucketSizeMinusOne;\n\t\t\t\t_count = other._count;\n\t\t\t\tshiftBits = other.shiftBits;\n\t\t\t\thashMap = new KeyValuePair<TKey, TValue>[other.bucketSizeMinusOne + 1];\n\t\t\t\tmarks = other.marks;\n\t\t\t\tfor (int i = 0; i <= bucketSizeMinusOne; i++)\n\t\t\t\t\thashMap[i] = other.hashMap[i];\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tDictionary<TKey, TValue> & operator = (Dictionary<TKey, TValue> && other)\n\t\t\t{\n\t\t\t\tif (this == &other)\n\t\t\t\t\treturn *this;\n\t\t\t\tFree();\n\t\t\t\tbucketSizeMinusOne = other.bucketSizeMinusOne;\n\t\t\t\t_count = other._count;\n\t\t\t\thashMap = other.hashMap;\n\t\t\t\tshiftBits = other.shiftBits;\n\t\t\t\tmarks = _Move(other.marks);\n\t\t\t\tother.hashMap = 0;\n\t\t\t\tother._count = 0;\n\t\t\t\tother.bucketSizeMinusOne = -1;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t~Dictionary()\n\t\t\t{\n\t\t\t\tFree();\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename TKey, typename TValue>\n\t\tclass EnumerableDictionary\n\t\t{\n\t\t\tfriend class Iterator;\n\t\t\tfriend class ItemProxy;\n\t\tprivate:\n\t\t\tinline int GetProbeOffset(int /*probeIdx*/) const\n\t\t\t{\n\t\t\t\t// quadratic probing\n\t\t\t\treturn 1;\n\t\t\t}\n\t\tprivate:\n\t\t\tint bucketSizeMinusOne, shiftBits;\n\t\t\tint _count;\n\t\t\tIntSet marks;\n\n\t\t\t// debug op\n\t\t\tstruct Op\n\t\t\t{\n\t\t\t\tTKey key;\n\t\t\t\tint opType;\n\t\t\t\tOp()\n\t\t\t\t{}\n\t\t\t\tOp(const TKey & key, int t)\n\t\t\t\t{\n\t\t\t\t\tthis->key = key;\n\t\t\t\t\topType = t;\n\t\t\t\t}\n\t\t\t};\n\t\t\tLinkedList<KeyValuePair<TKey, TValue>> kvPairs;\n\t\t\tLinkedNode<KeyValuePair<TKey, TValue>>** hashMap;\n\t\t\tvoid Free()\n\t\t\t{\n\t\t\t\tif (hashMap)\n\t\t\t\t\tdelete[] hashMap;\n\t\t\t\thashMap = 0;\n\t\t\t\tkvPairs.Clear();\n\t\t\t}\n\t\t\tinline bool IsDeleted(int pos) const\n\t\t\t{\n\t\t\t\treturn marks.Contains((pos << 1) + 1);\n\t\t\t}\n\t\t\tinline bool IsEmpty(int pos) const\n\t\t\t{\n\t\t\t\treturn !marks.Contains((pos << 1));\n\t\t\t}\n\t\t\tinline void SetDeleted(int pos, bool val)\n\t\t\t{\n\t\t\t\tif (val)\n\t\t\t\t\tmarks.Add((pos << 1) + 1);\n\t\t\t\telse\n\t\t\t\t\tmarks.Remove((pos << 1) + 1);\n\t\t\t}\n\t\t\tinline void SetEmpty(int pos, bool val)\n\t\t\t{\n\t\t\t\tif (val)\n\t\t\t\t\tmarks.Remove((pos << 1));\n\t\t\t\telse\n\t\t\t\t\tmarks.Add((pos << 1));\n\t\t\t}\n\t\t\tstruct FindPositionResult\n\t\t\t{\n\t\t\t\tint ObjectPosition;\n\t\t\t\tint InsertionPosition;\n\t\t\t\tFindPositionResult()\n\t\t\t\t{\n\t\t\t\t\tObjectPosition = -1;\n\t\t\t\t\tInsertionPosition = -1;\n\t\t\t\t}\n\t\t\t\tFindPositionResult(int objPos, int insertPos)\n\t\t\t\t{\n\t\t\t\t\tObjectPosition = objPos;\n\t\t\t\t\tInsertionPosition = insertPos;\n\t\t\t\t}\n\n\t\t\t};\n\t\t\ttemplate<typename T>\n\t\t\tinline int GetHashPos(T & key) const\n\t\t\t{\n\t\t\t\treturn ((unsigned int)(GetHashCode(key) * 2654435761)) >> shiftBits;\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tFindPositionResult FindPosition(const T & key) const\n\t\t\t{\n\t\t\t\tint hashPos = GetHashPos((T&)key);\n\t\t\t\tint insertPos = -1;\n\t\t\t\tint numProbes = 0;\n\t\t\t\twhile (numProbes <= bucketSizeMinusOne)\n\t\t\t\t{\n\t\t\t\t\tif (IsEmpty(hashPos))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (insertPos == -1)\n\t\t\t\t\t\t\treturn FindPositionResult(-1, hashPos);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn FindPositionResult(-1, insertPos);\n\t\t\t\t\t}\n\t\t\t\t\telse if (IsDeleted(hashPos))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (insertPos == -1)\n\t\t\t\t\t\t\tinsertPos = hashPos;\n\t\t\t\t\t}\n\t\t\t\t\telse if (hashMap[hashPos]->Value.Key == key)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn FindPositionResult(hashPos, -1);\n\t\t\t\t\t}\n\t\t\t\t\tnumProbes++;\n\t\t\t\t\thashPos = (hashPos + GetProbeOffset(numProbes)) & bucketSizeMinusOne;\n\t\t\t\t}\n\t\t\t\tif (insertPos != -1)\n\t\t\t\t\treturn FindPositionResult(-1, insertPos);\n\t\t\t\tthrow InvalidOperationException(\"Hash map is full. This indicates an error in Key::Equal or Key::GetHashCode.\");\n\t\t\t}\n\t\t\tTValue & _Insert(KeyValuePair<TKey, TValue> && kvPair, int pos)\n\t\t\t{\n\t\t\t\tauto node = kvPairs.AddLast();\n\t\t\t\tnode->Value = _Move(kvPair);\n\t\t\t\thashMap[pos] = node;\n\t\t\t\tSetEmpty(pos, false);\n\t\t\t\tSetDeleted(pos, false);\n\t\t\t\treturn node->Value.Value;\n\t\t\t}\n\t\t\tvoid Rehash()\n\t\t\t{\n\t\t\t\tif (bucketSizeMinusOne == -1 || _count / (float)bucketSizeMinusOne >= MaxLoadFactor)\n\t\t\t\t{\n\t\t\t\t\tint newSize = (bucketSizeMinusOne + 1) * 2;\n\t\t\t\t\tint newShiftBits = shiftBits - 1;\n\t\t\t\t\tif (newSize == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tnewSize = 16;\n\t\t\t\t\t\tnewShiftBits = 28;\n\t\t\t\t\t}\n\t\t\t\t\tEnumerableDictionary<TKey, TValue> newDict;\n\t\t\t\t\tnewDict.shiftBits = newShiftBits;\n\t\t\t\t\tnewDict.bucketSizeMinusOne = newSize - 1;\n\t\t\t\t\tnewDict.hashMap = new LinkedNode<KeyValuePair<TKey, TValue>>*[newSize];\n\t\t\t\t\tnewDict.marks.SetMax(newSize * 2);\n\t\t\t\t\tif (hashMap)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto & kvPair : *this)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnewDict.Add(_Move(kvPair));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t*this = _Move(newDict);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbool AddIfNotExists(KeyValuePair<TKey, TValue> && kvPair)\n\t\t\t{\n\t\t\t\tRehash();\n\t\t\t\tauto pos = FindPosition(kvPair.Key);\n\t\t\t\tif (pos.ObjectPosition != -1)\n\t\t\t\t\treturn false;\n\t\t\t\telse if (pos.InsertionPosition != -1)\n\t\t\t\t{\n\t\t\t\t\t_count++;\n\t\t\t\t\t_Insert(_Move(kvPair), pos.InsertionPosition);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"Inconsistent find result returned. This is a bug in Dictionary implementation.\");\n\t\t\t}\n\t\t\tvoid Add(KeyValuePair<TKey, TValue> && kvPair)\n\t\t\t{\n\t\t\t\tif (!AddIfNotExists(_Move(kvPair)))\n\t\t\t\t\tthrow KeyExistsException(\"The key already exists in Dictionary.\");\n\t\t\t}\n\t\t\tTValue & Set(KeyValuePair<TKey, TValue> && kvPair)\n\t\t\t{\n\t\t\t\tRehash();\n\t\t\t\tauto pos = FindPosition(kvPair.Key);\n\t\t\t\tif (pos.ObjectPosition != -1)\n\t\t\t\t{\n\t\t\t\t\thashMap[pos.ObjectPosition]->Delete();\n\t\t\t\t\treturn _Insert(_Move(kvPair), pos.ObjectPosition);\n\t\t\t\t}\n\t\t\t\telse if (pos.InsertionPosition != -1)\n\t\t\t\t{\n\t\t\t\t\t_count++;\n\t\t\t\t\treturn _Insert(_Move(kvPair), pos.InsertionPosition);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"Inconsistent find result returned. This is a bug in Dictionary implementation.\");\n\t\t\t}\n\t\tpublic:\n\t\t\ttypedef typename LinkedList<KeyValuePair<TKey, TValue>>::Iterator Iterator;\n\n\t\t\ttypename LinkedList<KeyValuePair<TKey, TValue>>::Iterator begin() const\n\t\t\t{\n\t\t\t\treturn kvPairs.begin();\n\t\t\t}\n\t\t\ttypename LinkedList<KeyValuePair<TKey, TValue>>::Iterator end() const\n\t\t\t{\n\t\t\t\treturn kvPairs.end();\n\t\t\t}\n\t\tpublic:\n\t\t\tvoid Add(const TKey & key, const TValue & value)\n\t\t\t{\n\t\t\t\tAdd(KeyValuePair<TKey, TValue>(key, value));\n\t\t\t}\n\t\t\tvoid Add(TKey && key, TValue && value)\n\t\t\t{\n\t\t\t\tAdd(KeyValuePair<TKey, TValue>(_Move(key), _Move(value)));\n\t\t\t}\n\t\t\tbool AddIfNotExists(const TKey & key, const TValue & value)\n\t\t\t{\n\t\t\t\treturn AddIfNotExists(KeyValuePair<TKey, TValue>(key, value));\n\t\t\t}\n\t\t\tbool AddIfNotExists(TKey && key, TValue && value)\n\t\t\t{\n\t\t\t\treturn AddIfNotExists(KeyValuePair<TKey, TValue>(_Move(key), _Move(value)));\n\t\t\t}\n\t\t\tvoid Remove(const TKey & key)\n\t\t\t{\n\t\t\t\tif (_count > 0)\n\t\t\t\t{\n\t\t\t\t\tauto pos = FindPosition(key);\n\t\t\t\t\tif (pos.ObjectPosition != -1)\n\t\t\t\t\t{\n\t\t\t\t\t\tkvPairs.Delete(hashMap[pos.ObjectPosition]);\n\t\t\t\t\t\thashMap[pos.ObjectPosition] = 0;\n\t\t\t\t\t\tSetDeleted(pos.ObjectPosition, true);\n\t\t\t\t\t\t_count--;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tvoid Clear()\n\t\t\t{\n\t\t\t\t_count = 0;\n\t\t\t\tkvPairs.Clear();\n\t\t\t\tmarks.Clear();\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tbool ContainsKey(const T & key) const\n\t\t\t{\n\t\t\t\tif (bucketSizeMinusOne == -1)\n\t\t\t\t\treturn false;\n\t\t\t\tauto pos = FindPosition(key);\n\t\t\t\treturn pos.ObjectPosition != -1;\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tTValue * TryGetValue(const T & key) const\n\t\t\t{\n\t\t\t\tif (bucketSizeMinusOne == -1)\n\t\t\t\t\treturn nullptr;\n\t\t\t\tauto pos = FindPosition(key);\n\t\t\t\tif (pos.ObjectPosition != -1)\n\t\t\t\t{\n\t\t\t\t\treturn &(hashMap[pos.ObjectPosition]->Value.Value);\n\t\t\t\t}\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tbool TryGetValue(const T & key, TValue & value) const\n\t\t\t{\n\t\t\t\tif (bucketSizeMinusOne == -1)\n\t\t\t\t\treturn false;\n\t\t\t\tauto pos = FindPosition(key);\n\t\t\t\tif (pos.ObjectPosition != -1)\n\t\t\t\t{\n\t\t\t\t\tvalue = hashMap[pos.ObjectPosition]->Value.Value;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tclass ItemProxy\n\t\t\t{\n\t\t\tprivate:\n\t\t\t\tconst EnumerableDictionary<TKey, TValue> * dict;\n\t\t\t\tTKey key;\n\t\t\tpublic:\n\t\t\t\tItemProxy(const TKey & _key, const EnumerableDictionary<TKey, TValue> * _dict)\n\t\t\t\t{\n\t\t\t\t\tthis->dict = _dict;\n\t\t\t\t\tthis->key = _key;\n\t\t\t\t}\n\t\t\t\tItemProxy(TKey && _key, const EnumerableDictionary<TKey, TValue> * _dict)\n\t\t\t\t{\n\t\t\t\t\tthis->dict = _dict;\n\t\t\t\t\tthis->key = _Move(_key);\n\t\t\t\t}\n\t\t\t\tTValue & GetValue() const\n\t\t\t\t{\n\t\t\t\t\tauto pos = dict->FindPosition(key);\n\t\t\t\t\tif (pos.ObjectPosition != -1)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn dict->hashMap[pos.ObjectPosition]->Value.Value;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow KeyNotFoundException(\"The key does not exists in dictionary.\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tinline TValue & operator()() const\n\t\t\t\t{\n\t\t\t\t\treturn GetValue();\n\t\t\t\t}\n\t\t\t\toperator TValue&() const\n\t\t\t\t{\n\t\t\t\t\treturn GetValue();\n\t\t\t\t}\n\t\t\t\tTValue & operator = (const TValue & val)\n\t\t\t\t{\n\t\t\t\t\treturn ((EnumerableDictionary<TKey, TValue>*)dict)->Set(KeyValuePair<TKey, TValue>(_Move(key), val));\n\t\t\t\t}\n\t\t\t\tTValue & operator = (TValue && val)\n\t\t\t\t{\n\t\t\t\t\treturn ((EnumerableDictionary<TKey, TValue>*)dict)->Set(KeyValuePair<TKey, TValue>(_Move(key), _Move(val)));\n\t\t\t\t}\n\t\t\t};\n\t\t\tItemProxy operator [](const TKey & key) const\n\t\t\t{\n\t\t\t\treturn ItemProxy(key, this);\n\t\t\t}\n\t\t\tItemProxy operator [](TKey && key) const\n\t\t\t{\n\t\t\t\treturn ItemProxy(_Move(key), this);\n\t\t\t}\n\t\t\tint Count() const\n\t\t\t{\n\t\t\t\treturn _count;\n\t\t\t}\n\t\t\tKeyValuePair<TKey, TValue> & First() const\n\t\t\t{\n\t\t\t\treturn kvPairs.First();\n\t\t\t}\n\t\t\tKeyValuePair<TKey, TValue> & Last() const\n\t\t\t{\n\t\t\t\treturn kvPairs.Last();\n\t\t\t}\n\t\tprivate:\n\t\t\ttemplate<typename... Args>\n\t\t\tvoid Init(const KeyValuePair<TKey, TValue> & kvPair, Args... args)\n\t\t\t{\n\t\t\t\tAdd(kvPair);\n\t\t\t\tInit(args...);\n\t\t\t}\n\t\tpublic:\n\t\t\tEnumerableDictionary()\n\t\t\t{\n\t\t\t\tbucketSizeMinusOne = -1;\n\t\t\t\tshiftBits = 32;\n\t\t\t\t_count = 0;\n\t\t\t\thashMap = 0;\n\t\t\t}\n\t\t\ttemplate<typename Arg, typename... Args>\n\t\t\tEnumerableDictionary(Arg arg, Args... args)\n\t\t\t{\n\t\t\t\tInit(arg, args...);\n\t\t\t}\n\t\t\tEnumerableDictionary(const EnumerableDictionary<TKey, TValue> & other)\n\t\t\t\t: bucketSizeMinusOne(-1), _count(0), hashMap(0)\n\t\t\t{\n\t\t\t\t*this = other;\n\t\t\t}\n\t\t\tEnumerableDictionary(EnumerableDictionary<TKey, TValue> && other)\n\t\t\t\t: bucketSizeMinusOne(-1), _count(0), hashMap(0)\n\t\t\t{\n\t\t\t\t*this = (_Move(other));\n\t\t\t}\n\t\t\tEnumerableDictionary<TKey, TValue> & operator = (const EnumerableDictionary<TKey, TValue> & other)\n\t\t\t{\n\t\t\t\tif (this == &other)\n\t\t\t\t\treturn *this;\n\t\t\t\tClear();\n\t\t\t\tfor (auto & item : other)\n\t\t\t\t\tAdd(item.Key, item.Value);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tEnumerableDictionary<TKey, TValue> & operator = (EnumerableDictionary<TKey, TValue> && other)\n\t\t\t{\n\t\t\t\tif (this == &other)\n\t\t\t\t\treturn *this;\n\t\t\t\tFree();\n\t\t\t\tbucketSizeMinusOne = other.bucketSizeMinusOne;\n\t\t\t\t_count = other._count;\n\t\t\t\thashMap = other.hashMap;\n\t\t\t\tshiftBits = other.shiftBits;\n\t\t\t\tmarks = _Move(other.marks);\n\t\t\t\tother.hashMap = 0;\n\t\t\t\tother._count = 0;\n\t\t\t\tother.bucketSizeMinusOne = -1;\n\t\t\t\tkvPairs = _Move(other.kvPairs);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t~EnumerableDictionary()\n\t\t\t{\n\t\t\t\tFree();\n\t\t\t}\n\t\t};\n\n\t\tclass _DummyClass\n\t\t{};\n\n\t\ttemplate<typename T, typename DictionaryType>\n\t\tclass HashSetBase\n\t\t{\n\t\tprotected:\n\t\t\tDictionaryType dict;\n\t\tprivate:\n\t\t\ttemplate<typename... Args>\n\t\t\tvoid Init(const T & v, Args... args)\n\t\t\t{\n\t\t\t\tAdd(v);\n\t\t\t\tInit(args...);\n\t\t\t}\n\t\tpublic:\n\t\t\tHashSetBase()\n\t\t\t{}\n\t\t\ttemplate<typename Arg, typename... Args>\n\t\t\tHashSetBase(Arg arg, Args... args)\n\t\t\t{\n\t\t\t\tInit(arg, args...);\n\t\t\t}\n\t\t\tHashSetBase(const HashSetBase & set)\n\t\t\t{\n\t\t\t\toperator=(set);\n\t\t\t}\n\t\t\tHashSetBase(HashSetBase && set)\n\t\t\t{\n\t\t\t\toperator=(_Move(set));\n\t\t\t}\n\t\t\tHashSetBase & operator = (const HashSetBase & set)\n\t\t\t{\n\t\t\t\tdict = set.dict;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tHashSetBase & operator = (HashSetBase && set)\n\t\t\t{\n\t\t\t\tdict = _Move(set.dict);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\tpublic:\n\t\t\tclass Iterator\n\t\t\t{\n\t\t\tprivate:\n\t\t\t\ttypename DictionaryType::Iterator iter;\n\t\t\tpublic:\n\t\t\t\tIterator() = default;\n\t\t\t\tT & operator *() const\n\t\t\t\t{\n\t\t\t\t\treturn (*iter).Key;\n\t\t\t\t}\n\t\t\t\tT * operator ->() const\n\t\t\t\t{\n\t\t\t\t\treturn &(*iter).Key;\n\t\t\t\t}\n\t\t\t\tIterator & operator ++()\n\t\t\t\t{\n\t\t\t\t\t++iter;\n\t\t\t\t\treturn *this;\n\t\t\t\t}\n\t\t\t\tIterator operator ++(int)\n\t\t\t\t{\n\t\t\t\t\tIterator rs = *this;\n\t\t\t\t\toperator++();\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tbool operator != (const Iterator & _that) const\n\t\t\t\t{\n\t\t\t\t\treturn iter != _that.iter;\n\t\t\t\t}\n\t\t\t\tbool operator == (const Iterator & _that) const\n\t\t\t\t{\n\t\t\t\t\treturn iter == _that.iter;\n\t\t\t\t}\n\t\t\t\tIterator(const typename DictionaryType::Iterator & _iter)\n\t\t\t\t{\n\t\t\t\t\tthis->iter = _iter;\n\t\t\t\t}\n\t\t\t};\n\t\t\tIterator begin() const\n\t\t\t{\n\t\t\t\treturn Iterator(dict.begin());\n\t\t\t}\n\t\t\tIterator end() const\n\t\t\t{\n\t\t\t\treturn Iterator(dict.end());\n\t\t\t}\n\t\tpublic:\n\t\t\tint Count() const\n\t\t\t{\n\t\t\t\treturn dict.Count();\n\t\t\t}\n\t\t\tvoid Clear()\n\t\t\t{\n\t\t\t\tdict.Clear();\n\t\t\t}\n\t\t\tbool Add(const T& obj)\n\t\t\t{\n\t\t\t\treturn dict.AddIfNotExists(obj, _DummyClass());\n\t\t\t}\n\t\t\tbool Add(T && obj)\n\t\t\t{\n\t\t\t\treturn dict.AddIfNotExists(_Move(obj), _DummyClass());\n\t\t\t}\n\t\t\tvoid Remove(const T & obj)\n\t\t\t{\n\t\t\t\tdict.Remove(obj);\n\t\t\t}\n\t\t\tbool Contains(const T & obj) const\n\t\t\t{\n\t\t\t\treturn dict.ContainsKey(obj);\n\t\t\t}\n\t\t};\n\t\ttemplate <typename T>\n\t\tclass HashSet : public HashSetBase<T, Dictionary<T, _DummyClass>>\n\t\t{};\n\n\t\ttemplate <typename T>\n\t\tclass EnumerableHashSet : public HashSetBase<T, EnumerableDictionary<T, _DummyClass>>\n\t\t{\n\t\tpublic:\n\t\t\tT & First() const\n\t\t\t{\n\t\t\t\treturn this->dict.First().Key;\n\t\t\t}\n\t\t\tT & Last() const\n\t\t\t{\n\t\t\t\treturn this->dict.Last().Key;\n\t\t\t}\n\t\t};\n\t}\n}\n\n#endif\n"
  },
  {
    "path": "Source/CoreLib/Exception.h",
    "content": "#ifndef CORE_LIB_EXCEPTION_H\n#define CORE_LIB_EXCEPTION_H\n\n#include \"Common.h\"\n#include \"LibString.h\"\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\tclass Exception : public Object\n\t\t{\n\t\tpublic:\n\t\t\tString Message;\n\t\t\tException()\n\t\t\t{}\n\t\t\tException(const String & message)\n\t\t\t\t: Message(message)\n\t\t\t{\n\t\t\t}\n\t\t};\n\n\t\tclass IndexOutofRangeException : public Exception\n\t\t{\n\t\tpublic:\n\t\t\tIndexOutofRangeException()\n\t\t\t{}\n\t\t\tIndexOutofRangeException(const String & message)\n\t\t\t\t: Exception(message)\n\t\t\t{\n\t\t\t}\n\n\t\t};\n\n\t\tclass InvalidOperationException : public Exception\n\t\t{\n\t\tpublic:\n\t\t\tInvalidOperationException()\n\t\t\t{}\n\t\t\tInvalidOperationException(const String & message)\n\t\t\t\t: Exception(message)\n\t\t\t{\n\t\t\t}\n\n\t\t};\n\t\t\n\t\tclass ArgumentException : public Exception\n\t\t{\n\t\tpublic:\n\t\t\tArgumentException()\n\t\t\t{}\n\t\t\tArgumentException(const String & message)\n\t\t\t\t: Exception(message)\n\t\t\t{\n\t\t\t}\n\n\t\t};\n\n\t\tclass KeyNotFoundException : public Exception\n\t\t{\n\t\tpublic:\n\t\t\tKeyNotFoundException()\n\t\t\t{}\n\t\t\tKeyNotFoundException(const String & message)\n\t\t\t\t: Exception(message)\n\t\t\t{\n\t\t\t}\n\t\t};\n\t\tclass KeyExistsException : public Exception\n\t\t{\n\t\tpublic:\n\t\t\tKeyExistsException()\n\t\t\t{}\n\t\t\tKeyExistsException(const String & message)\n\t\t\t\t: Exception(message)\n\t\t\t{\n\t\t\t}\n\t\t};\n\n\t\tclass NotSupportedException : public Exception\n\t\t{\n\t\tpublic:\n\t\t\tNotSupportedException()\n\t\t\t{}\n\t\t\tNotSupportedException(const String & message)\n\t\t\t\t: Exception(message)\n\t\t\t{\n\t\t\t}\n\t\t};\n\n\t\tclass NotImplementedException : public Exception\n\t\t{\n\t\tpublic:\n\t\t\tNotImplementedException()\n\t\t\t{}\n\t\t\tNotImplementedException(const String & message)\n\t\t\t\t: Exception(message)\n\t\t\t{\n\t\t\t}\n\t\t};\n\n\t\tclass InvalidProgramException : public Exception\n\t\t{\n\t\tpublic:\n\t\t\tInvalidProgramException()\n\t\t\t{}\n\t\t\tInvalidProgramException(const String & message)\n\t\t\t\t: Exception(message)\n\t\t\t{\n\t\t\t}\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/CoreLib/Func.h",
    "content": "#ifndef CORELIB_FUNC_H\n#define CORELIB_FUNC_H\n\n#include \"SmartPointer.h\"\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\ttemplate<typename TResult, typename... Arguments>\n\t\tclass FuncPtr\n\t\t{\n\t\tpublic:\n\t\t\tvirtual TResult operator()(Arguments...) = 0;\n\t\t\tvirtual bool operator == (const FuncPtr<TResult, Arguments...> *)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvirtual ~FuncPtr() {}\n\t\t};\n\n\t\ttemplate<typename TResult, typename... Arguments>\n\t\tclass CdeclFuncPtr : public FuncPtr<TResult, Arguments...>\n\t\t{\n\t\tpublic:\n\t\t\ttypedef TResult (*FuncType)(Arguments...);\n\t\tprivate:\n\t\t\tFuncType funcPtr;\n\t\tpublic:\n\t\t\tCdeclFuncPtr(FuncType func)\n\t\t\t\t:funcPtr(func)\n\t\t\t{\n\t\t\t}\n\n\t\t\tvirtual TResult operator()(Arguments... params) override\n\t\t\t{\n\t\t\t\treturn funcPtr(params...);\n\t\t\t}\n\n\t\t\tvirtual bool operator == (const FuncPtr<TResult, Arguments...> * ptr) override\n\t\t\t{\n\t\t\t\tauto cptr = dynamic_cast<const CdeclFuncPtr<TResult, Arguments...>*>(ptr);\n\t\t\t\tif (cptr)\n\t\t\t\t\treturn funcPtr == cptr->funcPtr;\n\t\t\t\telse\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename Class, typename TResult, typename... Arguments>\n\t\tclass MemberFuncPtr : public FuncPtr<TResult, Arguments...>\n\t\t{\n\t\tpublic:\n\t\t\ttypedef TResult (Class::*FuncType)(Arguments...);\n\t\tprivate:\n\t\t\tFuncType funcPtr;\n\t\t\tClass * object;\n\t\tpublic:\n\t\t\tMemberFuncPtr(Class * obj, FuncType func)\n\t\t\t\t: funcPtr(func), object(obj)\n\t\t\t{\n\t\t\t}\n\n\t\t\tvirtual TResult operator()(Arguments... params) override\n\t\t\t{\n\t\t\t\treturn (object->*funcPtr)(params...);\n\t\t\t}\n\n\t\t\tvirtual bool operator == (const FuncPtr<TResult, Arguments...> * ptr) override\n\t\t\t{\n\t\t\t\tauto cptr = dynamic_cast<const MemberFuncPtr<Class, TResult, Arguments...>*>(ptr);\n\t\t\t\tif (cptr)\n\t\t\t\t\treturn funcPtr == cptr->funcPtr && object == cptr->object;\n\t\t\t\telse\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename F, typename TResult, typename... Arguments>\n\t\tclass LambdaFuncPtr : public FuncPtr<TResult, Arguments...>\n\t\t{\n\t\tprivate:\n\t\t\tF func;\n\t\tpublic:\n\t\t\tLambdaFuncPtr(const F & _func)\n\t\t\t\t: func(_func)\n\t\t\t{}\n\t\t\tvirtual TResult operator()(Arguments... params) override\n\t\t\t{\n\t\t\t\treturn func(params...);\n\t\t\t}\n\t\t\tvirtual bool operator == (const FuncPtr<TResult, Arguments...> * /*ptr*/) override\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename TResult, typename... Arguments>\n\t\tclass Func\n\t\t{\n\t\tprivate:\n\t\t\tRefPtr<FuncPtr<TResult, Arguments...>> funcPtr;\n\t\tpublic:\n\t\t\tFunc(){}\n\t\t\tFunc(typename CdeclFuncPtr<TResult, Arguments...>::FuncType func)\n\t\t\t{\n\t\t\t\tfuncPtr = new CdeclFuncPtr<TResult, Arguments...>(func);\n\t\t\t}\n\t\t\ttemplate<typename Class>\n\t\t\tFunc(Class * object, typename MemberFuncPtr<Class, TResult, Arguments...>::FuncType func)\n\t\t\t{\n\t\t\t\tfuncPtr = new MemberFuncPtr<Class, TResult, Arguments...>(object, func);\n\t\t\t}\n\t\t\ttemplate<typename TFuncObj>\n\t\t\tFunc(const TFuncObj & func)\n\t\t\t{\n\t\t\t\tfuncPtr = new LambdaFuncPtr<TFuncObj, TResult, Arguments...>(func);\n\t\t\t}\n\t\t\tFunc & operator = (typename CdeclFuncPtr<TResult, Arguments...>::FuncType func)\n\t\t\t{\n\t\t\t\tfuncPtr = new CdeclFuncPtr<TResult, Arguments...>(func);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\ttemplate<typename Class>\n\t\t\tFunc & operator = (const MemberFuncPtr<Class, TResult, Arguments...> & func)\n\t\t\t{\n\t\t\t\tfuncPtr = new MemberFuncPtr<Class, TResult, Arguments...>(func);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\ttemplate<typename TFuncObj>\n\t\t\tFunc & operator = (const TFuncObj & func)\n\t\t\t{\n\t\t\t\tfuncPtr = new LambdaFuncPtr<TFuncObj, TResult, Arguments...>(func);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tbool operator == (const Func & f)\n\t\t\t{\n\t\t\t\treturn *funcPtr == f.funcPtr.Ptr();\n\t\t\t}\n\t\t\tbool operator != (const Func & f)\n\t\t\t{\n\t\t\t\treturn !(*this == f);\n\t\t\t}\n\t\t\tTResult operator()(Arguments... params)\n\t\t\t{\n\t\t\t\treturn (*funcPtr)(params...);\n\t\t\t}\n\t\t};\n\n\t\t// template<typename... Arguments>\n\t\t// using Procedure = Func<void, Arguments...>;\n\n\t\ttemplate<typename... Arguments>\n\t\tclass Procedure : public Func<void, Arguments...>\n\t\t{\n\t\tprivate:\n\t\t\tRefPtr<FuncPtr<void, Arguments...>> funcPtr;\n\t\tpublic:\n\t\t\tProcedure(){}\n\t\t\tProcedure(const Procedure & proc)\n\t\t\t{\n\t\t\t\tfuncPtr = proc.funcPtr;\n\t\t\t}\n\t\t\tProcedure(typename CdeclFuncPtr<void, Arguments...>::FuncType func)\n\t\t\t{\n\t\t\t\tfuncPtr = new CdeclFuncPtr<void, Arguments...>(func);\n\t\t\t}\n\t\t\ttemplate<typename Class>\n\t\t\tProcedure(Class * object, typename MemberFuncPtr<Class, void, Arguments...>::FuncType func)\n\t\t\t{\n\t\t\t\tfuncPtr = new MemberFuncPtr<Class, void, Arguments...>(object, func);\n\t\t\t}\n\t\t\ttemplate<typename TFuncObj>\n\t\t\tProcedure(const TFuncObj & func)\n\t\t\t{\n\t\t\t\tfuncPtr = new LambdaFuncPtr<TFuncObj, void, Arguments...>(func);\n\t\t\t}\n\t\t\tProcedure & operator = (typename CdeclFuncPtr<void, Arguments...>::FuncType func)\n\t\t\t{\n\t\t\t\tfuncPtr = new CdeclFuncPtr<void, Arguments...>(func);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\ttemplate<typename Class>\n\t\t\tProcedure & operator = (const MemberFuncPtr<Class, void, Arguments...> & func)\n\t\t\t{\n\t\t\t\tfuncPtr = new MemberFuncPtr<Class, void, Arguments...>(func);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\ttemplate<typename TFuncObj>\n\t\t\tProcedure & operator = (const TFuncObj & func)\n\t\t\t{\n\t\t\t\tfuncPtr = new LambdaFuncPtr<TFuncObj, void, Arguments...>(func);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tProcedure & operator = (const Procedure & proc)\n\t\t\t{\n\t\t\t\tfuncPtr = proc.funcPtr;\n\t\t\t}\n\t\t\tvoid Clear()\n\t\t\t{\n\t\t\t\tfuncPtr = nullptr;\n\t\t\t}\n\t\t\tvoid operator()(Arguments... params)\n\t\t\t{\n\t\t\t\tif (funcPtr)\n\t\t\t\t\t(*funcPtr)(params...);\n\t\t\t}\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/CoreLib/Hash.h",
    "content": "#ifndef CORELIB_HASH_H\n#define CORELIB_HASH_H\n\n#include \"LibMath.h\"\n#include <string.h>\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\n\t\tinline int GetHashCode(double key)\n\t\t{\n\t\t\treturn FloatAsInt((float)key);\n\t\t}\n\t\tinline int GetHashCode(float key)\n\t\t{\n\t\t\treturn FloatAsInt(key);\n\t\t}\n\t\tinline int GetHashCode(const char * buffer)\n\t\t{\n\t\t\tif (!buffer)\n\t\t\t\treturn 0;\n\t\t\tint hash = 0;\n\t\t\tint c;\n\t\t\tauto str = buffer;\n\t\t\tc = *str++;\n\t\t\twhile (c)\n\t\t\t{\n\t\t\t\thash = c + (hash << 6) + (hash << 16) - hash;\n\t\t\t\tc = *str++;\n\t\t\t}\n\t\t\treturn hash;\n\t\t}\n\t\tinline int GetHashCode(char * buffer)\n\t\t{\n\t\t\treturn GetHashCode(const_cast<const char *>(buffer));\n\t\t}\n\n\t\ttemplate<int IsInt>\n\t\tclass Hash\n\t\t{\n\t\tpublic:\n\t\t};\n\t\ttemplate<>\n\t\tclass Hash<1>\n\t\t{\n\t\tpublic:\n\t\t\ttemplate<typename TKey>\n\t\t\tstatic int GetHashCode(TKey & key)\n\t\t\t{\n\t\t\t\treturn (int)key;\n\t\t\t}\n\t\t};\n\t\ttemplate<>\n\t\tclass Hash<0>\n\t\t{\n\t\tpublic:\n\t\t\ttemplate<typename TKey>\n\t\t\tstatic int GetHashCode(TKey & key)\n\t\t\t{\n\t\t\t\treturn key.GetHashCode();\n\t\t\t}\n\t\t};\n\t\ttemplate<int IsPointer>\n\t\tclass PointerHash\n\t\t{};\n\t\ttemplate<>\n\t\tclass PointerHash<1>\n\t\t{\n\t\tpublic:\n\t\t\ttemplate<typename TKey>\n\t\t\tstatic int GetHashCode(TKey & key)\n\t\t\t{\n\t\t\t\treturn (int)((CoreLib::PtrInt)key) / sizeof(typename std::remove_pointer<TKey>::type);\n\t\t\t}\n\t\t};\n\t\ttemplate<>\n\t\tclass PointerHash<0>\n\t\t{\n\t\tpublic:\n\t\t\ttemplate<typename TKey>\n\t\t\tstatic int GetHashCode(TKey & key)\n\t\t\t{\n\t\t\t\treturn Hash<std::is_integral<TKey>::value || std::is_enum<TKey>::value>::GetHashCode(key);\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename TKey>\n\t\tint GetHashCode(const TKey & key)\n\t\t{\n\t\t\treturn PointerHash<std::is_pointer<TKey>::value>::GetHashCode(key);\n\t\t}\n\n\t\ttemplate<typename TKey>\n\t\tint GetHashCode(TKey & key)\n\t\t{\n\t\t\treturn PointerHash<std::is_pointer<TKey>::value>::GetHashCode(key);\n\t\t}\n\n\t\t\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/CoreLib/IntSet.h",
    "content": "#ifndef BIT_VECTOR_INT_SET_H\n#define BIT_VECTOR_INT_SET_H\n\n#include <memory.h>\n#include \"List.h\"\n#include \"LibMath.h\"\n#include \"Common.h\"\n#include \"Exception.h\"\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\tclass IntSet\n\t\t{\n\t\tprivate:\n\t\t\tList<int> buffer;\n\t\tpublic:\n\t\t\tIntSet()\n\t\t\t{}\n\t\t\tIntSet(const IntSet & other)\n\t\t\t{\n\t\t\t\tbuffer = other.buffer;\n\t\t\t}\n\t\t\tIntSet(IntSet && other)\n\t\t\t{\n\t\t\t\t*this = (_Move(other));\n\t\t\t}\n\t\t\tIntSet & operator = (IntSet && other)\n\t\t\t{\n\t\t\t\tbuffer = _Move(other.buffer);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tIntSet & operator = (const IntSet & other)\n\t\t\t{\n\t\t\t\tbuffer = other.buffer;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tint GetHashCode()\n\t\t\t{\n\t\t\t\tint rs = 0;\n\t\t\t\tfor (auto val : buffer)\n\t\t\t\t\trs ^= val;\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tIntSet(int maxVal)\n\t\t\t{\n\t\t\t\tSetMax(maxVal);\n\t\t\t}\n\t\t\tint Size() const\n\t\t\t{\n\t\t\t\treturn buffer.Count()*32;\n\t\t\t}\n\t\t\tvoid SetMax(int val)\n\t\t\t{\n\t\t\t\tResize(val);\n\t\t\t\tClear();\n\t\t\t}\n\t\t\tvoid SetAll()\n\t\t\t{\n\t\t\t\tfor (int i = 0; i<buffer.Count(); i++)\n\t\t\t\t\tbuffer[i] = 0xFFFFFFFF;\n\t\t\t}\n\t\t\tvoid Resize(int size)\n\t\t\t{\n\t\t\t\tint oldBufferSize = buffer.Count();\n\t\t\t\tbuffer.SetSize((size+31)>>5);\n\t\t\t\tif (buffer.Count() > oldBufferSize)\n\t\t\t\t\tmemset(buffer.Buffer()+oldBufferSize, 0, (buffer.Count()-oldBufferSize) * sizeof(int));\n\t\t\t}\n\t\t\tvoid Clear()\n\t\t\t{\n\t\t\t\tfor (int i = 0; i<buffer.Count(); i++)\n\t\t\t\t\tbuffer[i] = 0;\n\t\t\t}\n\t\t\tvoid Add(int val)\n\t\t\t{\n\t\t\t\tint id = val>>5;\n\t\t\t\tif (id < buffer.Count())\n\t\t\t\t\tbuffer[id] |= (1<<(val&31));\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tint oldSize = buffer.Count();\n\t\t\t\t\tbuffer.SetSize(id+1);\n\t\t\t\t\tmemset(buffer.Buffer() + oldSize, 0, (buffer.Count()-oldSize)*sizeof(int));\n\t\t\t\t\tbuffer[id] |= (1<<(val&31));\n\t\t\t\t}\n\t\t\t}\n\t\t\tvoid Remove(int val)\n\t\t\t{\n\t\t\t\tif ((val>>5) < buffer.Count())\n\t\t\t\t\tbuffer[(val>>5)] &= ~(1<<(val&31));\n\t\t\t}\n\t\t\tbool Contains(int val) const\n\t\t\t{\n\t\t\t\tif ((val>>5) >= buffer.Count())\n\t\t\t\t\treturn false;\n\t\t\t\treturn (buffer[(val>>5)] & (1<<(val&31))) != 0;\n\t\t\t}\n\t\t\tvoid UnionWith(const IntSet & set)\n\t\t\t{\n\t\t\t\tfor (int i = 0; i<Math::Min(set.buffer.Count(), buffer.Count()); i++)\n\t\t\t\t{\n\t\t\t\t\tbuffer[i] |= set.buffer[i];\n\t\t\t\t}\n\t\t\t\tif (set.buffer.Count() > buffer.Count())\n\t\t\t\t\tbuffer.AddRange(set.buffer.Buffer()+buffer.Count(), set.buffer.Count()-buffer.Count());\n\t\t\t}\n\t\t\tbool operator == (const IntSet & set)\n\t\t\t{\n\t\t\t\tif (buffer.Count() != set.buffer.Count())\n\t\t\t\t\treturn false;\n\t\t\t\tfor (int i = 0; i<buffer.Count(); i++)\n\t\t\t\t\tif (buffer[i] != set.buffer[i])\n\t\t\t\t\t\treturn false;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tbool operator != (const IntSet & set)\n\t\t\t{\n\t\t\t\treturn !(*this == set);\n\t\t\t}\n\t\t\tvoid IntersectWith(const IntSet & set)\n\t\t\t{\n\t\t\t\tif (set.buffer.Count() < buffer.Count())\n\t\t\t\t\tmemset(buffer.Buffer() + set.buffer.Count(), 0, (buffer.Count()-set.buffer.Count())*sizeof(int));\n\t\t\t\tfor (int i = 0; i<Math::Min(set.buffer.Count(), buffer.Count()); i++)\n\t\t\t\t{\n\t\t\t\t\tbuffer[i] &= set.buffer[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\tstatic void Union(IntSet & rs, const IntSet & set1, const IntSet & set2)\n\t\t\t{\n\t\t\t\trs.buffer.SetSize(Math::Max(set1.buffer.Count(), set2.buffer.Count()));\n\t\t\t\trs.Clear();\n\t\t\t\tfor (int i = 0; i<set1.buffer.Count(); i++)\n\t\t\t\t\trs.buffer[i] |= set1.buffer[i];\n\t\t\t\tfor (int i = 0; i<set2.buffer.Count(); i++)\n\t\t\t\t\trs.buffer[i] |= set2.buffer[i];\n\t\t\t}\n\t\t\tstatic void Intersect(IntSet & rs, const IntSet & set1, const IntSet & set2)\n\t\t\t{\n\t\t\t\trs.buffer.SetSize(Math::Min(set1.buffer.Count(), set2.buffer.Count()));\n\t\t\t\tfor (int i = 0; i<rs.buffer.Count(); i++)\n\t\t\t\t\trs.buffer[i] = set1.buffer[i] & set2.buffer[i];\n\t\t\t}\n\t\t\tstatic void Subtract(IntSet & rs, const IntSet & set1, const IntSet & set2)\n\t\t\t{\n\t\t\t\trs.buffer.SetSize(set1.buffer.Count());\n\t\t\t\tfor (int i = 0; i<Math::Min(set1.buffer.Count(), set2.buffer.Count()); i++)\n\t\t\t\t\trs.buffer[i] = set1.buffer[i] & (~set2.buffer[i]);\n\t\t\t}\n\t\t\tstatic bool HasIntersection(const IntSet & set1, const IntSet & set2)\n\t\t\t{\n\t\t\t\tfor (int i = 0; i<Math::Min(set1.buffer.Count(), set2.buffer.Count()); i++)\n\t\t\t\t{\n\t\t\t\t\tif (set1.buffer[i] & set2.buffer[i])\n\t\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/CoreLib/LibIO.cpp",
    "content": "#include \"LibIO.h\"\n#include \"Exception.h\"\n#ifndef __STDC__\n#define __STDC__ 1\n#endif\n#include <sys/stat.h>\n#ifdef _WIN32\n#include <direct.h>\n#endif\nnamespace CoreLib\n{\n\tnamespace IO\n\t{\n\t\tusing namespace CoreLib::Basic;\n\n\t\tCommandLineWriter * currentCommandWriter = nullptr;\n\n\t\tvoid SetCommandLineWriter(CommandLineWriter * writer)\n\t\t{\n\t\t\tcurrentCommandWriter = writer;\n\t\t}\n\n\t\tbool File::Exists(const String & fileName)\n\t\t{\n#ifdef _WIN32\n\t\t\tstruct _stat32 statVar;\n\t\t\treturn ::_wstat32(((String)fileName).ToWString(), &statVar) != -1;\n#else\n\t\t\tstruct stat statVar;\n\t\t\treturn ::stat(fileName.Buffer(), &statVar) == 0;\n#endif\n\t\t}\n\n\t\tString Path::TruncateExt(const String & path)\n\t\t{\n\t\t\tint dotPos = path.LastIndexOf('.');\n\t\t\tif (dotPos != -1)\n\t\t\t\treturn path.SubString(0, dotPos);\n\t\t\telse\n\t\t\t\treturn path;\n\t\t}\n\t\tString Path::ReplaceExt(const String & path, const char * newExt)\n\t\t{\n\t\t\tStringBuilder sb(path.Length()+10);\n\t\t\tint dotPos = path.LastIndexOf('.');\n\t\t\tif (dotPos == -1)\n\t\t\t\tdotPos = path.Length();\n\t\t\tsb.Append(path.Buffer(), dotPos);\n\t\t\tsb.Append('.');\n\t\t\tsb.Append(newExt);\n\t\t\treturn sb.ProduceString();\n\t\t}\n\t\tString Path::GetFileName(const String & path)\n\t\t{\n\t\t\tint pos = path.LastIndexOf('/');\n\t\t\tpos = Math::Max(path.LastIndexOf('\\\\'), pos) + 1;\n\t\t\treturn path.SubString(pos, path.Length()-pos);\n\t\t}\n\t\tString Path::GetFileNameWithoutEXT(const String & path)\n\t\t{\n\t\t\tint pos = path.LastIndexOf('/');\n\t\t\tpos = Math::Max(path.LastIndexOf('\\\\'), pos) + 1;\n\t\t\tint dotPos = path.LastIndexOf('.');\n\t\t\tif (dotPos <= pos)\n\t\t\t\tdotPos = path.Length();\n\t\t\treturn path.SubString(pos, dotPos - pos);\n\t\t}\n\t\tString Path::GetFileExt(const String & path)\n\t\t{\n\t\t\tint dotPos = path.LastIndexOf('.');\n\t\t\tif (dotPos != -1)\n\t\t\t\treturn path.SubString(dotPos+1, path.Length()-dotPos-1);\n\t\t\telse\n\t\t\t\treturn \"\";\n\t\t}\n\t\tString Path::GetDirectoryName(const String & path)\n\t\t{\n\t\t\tint pos = path.LastIndexOf('/');\n\t\t\tpos = Math::Max(path.LastIndexOf('\\\\'), pos);\n\t\t\tif (pos != -1)\n\t\t\t\treturn path.SubString(0, pos);\n\t\t\telse\n\t\t\t\treturn \"\";\n\t\t}\n\t\tString Path::Combine(const String & path1, const String & path2)\n\t\t{\n\t\t\tif (path1.Length() == 0) return path2;\n\t\t\tStringBuilder sb(path1.Length()+path2.Length()+2);\n\t\t\tsb.Append(path1);\n\t\t\tif (!path1.EndsWith('\\\\') && !path1.EndsWith('/'))\n\t\t\t\tsb.Append(PathDelimiter);\n\t\t\tsb.Append(path2);\n\t\t\treturn sb.ProduceString();\n\t\t}\n\t\tString Path::Combine(const String & path1, const String & path2, const String & path3)\n\t\t{\n\t\t\tStringBuilder sb(path1.Length()+path2.Length()+path3.Length()+3);\n\t\t\tsb.Append(path1);\n\t\t\tif (!path1.EndsWith('\\\\') && !path1.EndsWith('/'))\n\t\t\t\tsb.Append(PathDelimiter);\n\t\t\tsb.Append(path2);\n\t\t\tif (!path2.EndsWith('\\\\') && !path2.EndsWith('/'))\n\t\t\t\tsb.Append(PathDelimiter);\n\t\t\tsb.Append(path3);\n\t\t\treturn sb.ProduceString();\n\t\t}\n\n\t\tbool Path::CreateDir(const String & path)\n\t\t{\n#if defined(_WIN32)\n\t\t\treturn _wmkdir(path.ToWString()) == 0;\n#else \n\t\t\treturn mkdir(path.Buffer(), 0777) == 0;\n#endif\n\t\t}\n\n\t\tCoreLib::Basic::String File::ReadAllText(const CoreLib::Basic::String & fileName)\n\t\t{\n\t\t\tStreamReader reader(new FileStream(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));\n\t\t\treturn reader.ReadToEnd();\n\t\t}\n\n\t\tCoreLib::Basic::List<unsigned char> File::ReadAllBytes(const CoreLib::Basic::String & fileName)\n\t\t{\n\t\t\tRefPtr<FileStream> fs = new FileStream(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite);\n\t\t\tList<unsigned char> buffer;\n\t\t\twhile (!fs->IsEnd())\n\t\t\t{\n\t\t\t\tunsigned char ch;\n\t\t\t\tint read = (int)fs->Read(&ch, 1);\n\t\t\t\tif (read)\n\t\t\t\t\tbuffer.Add(ch);\n\t\t\t\telse\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\treturn _Move(buffer);\n\t\t}\n\n\t\tvoid File::WriteAllText(const CoreLib::Basic::String & fileName, const CoreLib::Basic::String & text)\n\t\t{\n\t\t\tStreamWriter writer(new FileStream(fileName, FileMode::Create));\n\t\t\twriter.Write(text);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/CoreLib/LibIO.h",
    "content": "#ifndef CORE_LIB_IO_H\n#define CORE_LIB_IO_H\n\n#include \"LibString.h\"\n#include \"Stream.h\"\n#include \"TextIO.h\"\n#include \"SecureCRT.h\"\n\nnamespace CoreLib\n{\n\tnamespace IO\n\t{\n\t\tclass File\n\t\t{\n\t\tpublic:\n\t\t\tstatic bool Exists(const CoreLib::Basic::String & fileName);\n\t\t\tstatic CoreLib::Basic::String ReadAllText(const CoreLib::Basic::String & fileName);\n\t\t\tstatic CoreLib::Basic::List<unsigned char> ReadAllBytes(const CoreLib::Basic::String & fileName);\n\t\t\tstatic void WriteAllText(const CoreLib::Basic::String & fileName, const CoreLib::Basic::String & text);\n\t\t};\n\n\t\tclass Path\n\t\t{\n\t\tpublic:\n#ifdef _WIN32\n\t\t\tstatic const char PathDelimiter = '\\\\';\n#else\n\t\t\tstatic const char PathDelimiter = '/';\n#endif\n\t\t\tstatic String TruncateExt(const String & path);\n\t\t\tstatic String ReplaceExt(const String & path, const char * newExt);\n\t\t\tstatic String GetFileName(const String & path);\n\t\t\tstatic String GetFileNameWithoutEXT(const String & path);\n\t\t\tstatic String GetFileExt(const String & path);\n\t\t\tstatic String GetDirectoryName(const String & path);\n\t\t\tstatic String Combine(const String & path1, const String & path2);\n\t\t\tstatic String Combine(const String & path1, const String & path2, const String & path3);\n\t\t\tstatic bool CreateDir(const String & path);\n\t\t};\n\n\t\tclass CommandLineWriter : public Object\n\t\t{\n\t\tpublic:\n\t\t\tvirtual void Write(const String & text) = 0;\n\t\t};\n\n\t\tvoid SetCommandLineWriter(CommandLineWriter * writer);\n\n\t\textern CommandLineWriter * currentCommandWriter;\n\t\ttemplate<typename ...Args>\n\t\tvoid uiprintf(const wchar_t * format, Args... args)\n\t\t{\n\t\t\tif (currentCommandWriter)\n\t\t\t{\n\t\t\t\tchar buffer[1024];\n\t\t\t\tsnprintf(buffer, 1024, format, args...);\n\t\t\t\tcurrentCommandWriter->Write(buffer);\n\t\t\t}\n\t\t}\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/CoreLib/LibMath.cpp",
    "content": "#include \"LibMath.h\"\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\tconst float Math::Pi = 3.141592654f;\n\t}\n}"
  },
  {
    "path": "Source/CoreLib/LibMath.h",
    "content": "#ifndef CORE_LIB_MATH_H\n#define CORE_LIB_MATH_H\n\n#include <math.h>\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\tclass Math\n\t\t{\n\t\tpublic:\n\t\t\tstatic const float Pi;\n\t\t\ttemplate<typename T>\n\t\t\tstatic T Min(const T& v1, const T&v2)\n\t\t\t{\n\t\t\t\treturn v1<v2?v1:v2;\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tstatic T Max(const T& v1, const T&v2)\n\t\t\t{\n\t\t\t\treturn v1>v2?v1:v2;\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tstatic T Min(const T& v1, const T&v2, const T&v3)\n\t\t\t{\n\t\t\t\treturn Min(v1, Min(v2, v3));\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tstatic T Max(const T& v1, const T&v2, const T&v3)\n\t\t\t{\n\t\t\t\treturn Max(v1, Max(v2, v3));\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tstatic T Clamp(const T& val, const T& vmin, const T&vmax)\n\t\t\t{\n\t\t\t\tif (val < vmin) return vmin;\n\t\t\t\telse if (val > vmax) return vmax;\n\t\t\t\telse return val;\n\t\t\t}\n\n\t\t\tstatic inline int FastFloor(float x)\n\t\t\t{\n\t\t\t\tint i = (int)x;\n\t\t\t\treturn i - (i > x);\n\t\t\t}\n\n\t\t\tstatic inline int FastFloor(double x)\n\t\t\t{\n\t\t\t\tint i = (int)x;\n\t\t\t\treturn i - (i > x);\n\t\t\t}\n\n\t\t\tstatic inline int IsNaN(float x)\n\t\t\t{\n#ifdef _M_X64\n\t\t\t\treturn _isnanf(x);\n#else\n\t\t\t\treturn isnan(x);\n#endif\n\t\t\t}\n\n\t\t\tstatic inline int IsInf(float x)\n\t\t\t{\n\t\t\t\treturn isinf(x);\n\t\t\t}\n\n\t\t\tstatic inline unsigned int Ones32(register unsigned int x)\n\t\t\t{\n\t\t\t\t/* 32-bit recursive reduction using SWAR...\n\t\t\t\t\tbut first step is mapping 2-bit values\n\t\t\t\t\tinto sum of 2 1-bit values in sneaky way\n\t\t\t\t*/\n\t\t\t\tx -= ((x >> 1) & 0x55555555);\n\t\t\t\tx = (((x >> 2) & 0x33333333) + (x & 0x33333333));\n\t\t\t\tx = (((x >> 4) + x) & 0x0f0f0f0f);\n\t\t\t\tx += (x >> 8);\n\t\t\t\tx += (x >> 16);\n\t\t\t\treturn(x & 0x0000003f);\n\t\t\t}\n\n\t\t\tstatic inline unsigned int Log2Floor(register unsigned int x)\n\t\t\t{\n\t\t\t\tx |= (x >> 1);\n\t\t\t\tx |= (x >> 2);\n\t\t\t\tx |= (x >> 4);\n\t\t\t\tx |= (x >> 8);\n\t\t\t\tx |= (x >> 16);\n\t\t\t\treturn(Ones32(x >> 1));\n\t\t\t}\n\n\t\t\tstatic inline unsigned int Log2Ceil(register unsigned int x)\n\t\t\t{\n\t\t\t\tint y = (x & (x - 1));\n\t\t\t\ty |= -y;\n\t\t\t\ty >>= (32 - 1);\n\t\t\t\tx |= (x >> 1);\n\t\t\t\tx |= (x >> 2);\n\t\t\t\tx |= (x >> 4);\n\t\t\t\tx |= (x >> 8);\n\t\t\t\tx |= (x >> 16);\n\t\t\t\treturn(Ones32(x >> 1) - y);\n\t\t\t}\n\t\t\t/*\n\t\t\tstatic inline int Log2(float x)\n\t\t\t{\n\t\t\t\tunsigned int ix = (unsigned int&)x;\n\t\t\t\tunsigned int exp = (ix >> 23) & 0xFF;\n\t\t\t\tint log2 = (unsigned int)(exp) - 127;\n\n\t\t\t\treturn log2;\n\t\t\t}\n\t\t\t*/\n\t\t};\n\t\tinline int FloatAsInt(float val)\n\t\t{\n\t\t\tunion InterCast\n\t\t\t{\n\t\t\t\tfloat fvalue;\n\t\t\t\tint ivalue;\n\t\t\t} cast;\n\t\t\tcast.fvalue = val;\n\t\t\treturn cast.ivalue;\n\t\t}\n\t\tinline float IntAsFloat(int val)\n\t\t{\n\t\t\tunion InterCast\n\t\t\t{\n\t\t\t\tfloat fvalue;\n\t\t\t\tint ivalue;\n\t\t\t} cast;\n\t\t\tcast.ivalue = val;\n\t\t\treturn cast.fvalue;\n\t\t}\n\n\t\tinline unsigned short FloatToHalf(float val)\n\t\t{\n\t\t\tint x = *(int*)&val;\n\t\t\tunsigned short bits = (x >> 16) & 0x8000;\n\t\t\tunsigned short m = (x >> 12) & 0x07ff;\n\t\t\tunsigned int e = (x >> 23) & 0xff;\n\t\t\tif (e < 103)\n\t\t\t\treturn bits;\n\t\t\tif (e > 142)\n\t\t\t{\n\t\t\t\tbits |= 0x7c00u;\n\t\t\t\tbits |= e == 255 && (x & 0x007fffffu);\n\t\t\t\treturn bits;\n\t\t\t}\n\t\t\tif (e < 113)\n\t\t\t{\n\t\t\t\tm |= 0x0800u;\n\t\t\t\tbits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);\n\t\t\t\treturn bits;\n\t\t\t}\n\t\t\tbits |= ((e - 112) << 10) | (m >> 1);\n\t\t\tbits += m & 1;\n\t\t\treturn bits;\n\t\t}\n\n\t\tinline float HalfToFloat(unsigned short input)\n\t\t{\n\t\t\tunion InterCast\n\t\t\t{\n\t\t\t\tfloat fvalue;\n\t\t\t\tint ivalue;\n\t\t\t\tInterCast() = default;\n\t\t\t\tInterCast(int ival)\n\t\t\t\t{\n\t\t\t\t\tivalue = ival;\n\t\t\t\t}\n\t\t\t};\n\t\t\tstatic const InterCast magic = InterCast((127 + (127 - 15)) << 23);\n\t\t\tstatic const InterCast was_infnan = InterCast((127 + 16) << 23);\n\t\t\tInterCast o;\n\t\t\to.ivalue = (input & 0x7fff) << 13;     // exponent/mantissa bits\n\t\t\to.fvalue *= magic.fvalue;                 // exponent adjust\n\t\t\tif (o.fvalue >= was_infnan.fvalue)        // make sure Inf/NaN survive\n\t\t\t\to.ivalue |= 255 << 23;\n\t\t\to.ivalue |= (input & 0x8000) << 16;    // sign bit\n\t\t\treturn o.fvalue;\n\t\t}\n\n\t\tclass Random\n\t\t{\n\t\tprivate:\n\t\t\tunsigned int seed;\n\t\tpublic:\n\t\t\tRandom(int seed)\n\t\t\t{\n\t\t\t\tthis->seed = seed;\n\t\t\t}\n\t\t\tint Next() // random between 0 and RandMax (currently 0x7fff)\n\t\t\t{\n\t\t\t\treturn (((seed = seed * 214013L + 2531011L) >> 16) & 0x7fff);\n\t\t\t}\n\t\t\tint Next(int min, int max) // inclusive min, exclusive max\n\t\t\t{\n\t\t\t\tunsigned int a = ((seed = seed * 214013L + 2531011L) & 0xFFFF0000);\n\t\t\t\tunsigned int b = ((seed = seed * 214013L + 2531011L) >> 16);\n\t\t\t\tunsigned int r = a + b;\n\t\t\t\treturn min + r % (max - min);\n\t\t\t}\n\t\t\tfloat NextFloat()\n\t\t\t{\n\t\t\t\treturn ((Next() << 15) + Next()) / ((float)(1 << 30));\n\t\t\t}\n\t\t\tfloat NextFloat(float valMin, float valMax)\n\t\t\t{\n\t\t\t\treturn valMin + (valMax - valMin) * NextFloat();\n\t\t\t}\n\t\t\tstatic int RandMax()\n\t\t\t{\n\t\t\t\treturn 0x7fff;\n\t\t\t}\n\t\t};\n\t}\n}\n\n#endif \n"
  },
  {
    "path": "Source/CoreLib/LibString.cpp",
    "content": "#include \"LibString.h\"\n#include \"TextIO.h\"\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\t_EndLine EndLine;\n\t\tString StringConcat(const char * lhs, int leftLen, const char * rhs, int rightLen)\n\t\t{\n\t\t\tString res;\n\t\t\tres.length = leftLen + rightLen;\n\t\t\tres.buffer = new char[res.length + 1];\n\t\t\tstrcpy_s(res.buffer.Ptr(), res.length + 1, lhs);\n\t\t\tstrcpy_s(res.buffer + leftLen, res.length + 1 - leftLen, rhs);\n\t\t\treturn res;\n\t\t}\n\t\tString operator+(const char * op1, const String & op2)\n\t\t{\n\t\t\tif(!op2.buffer)\t\t// no string 2 - return first\n\t\t\t\treturn String(op1);\n\n            if (!op1)\t\t\t// no base string?!  return the second string\n                return op2;\n\n\t\t\treturn StringConcat(op1, (int)strlen(op1), op2.buffer.Ptr(), op2.length);\n\t\t}\n\n\t\tString operator+(const String & op1, const char * op2)\n\t\t{\n\t\t\tif(!op1.buffer)\n\t\t\t\treturn String(op2);\n\n\t\t\treturn StringConcat(op1.buffer.Ptr(), op1.length, op2, (int)strlen(op2));\n\t\t}\n\n\t\tString operator+(const String & op1, const String & op2)\n\t\t{\n\t\t\tif(!op1.buffer && !op2.buffer)\n\t\t\t\treturn String();\n\t\t\telse if(!op1.buffer)\n\t\t\t\treturn String(op2);\n\t\t\telse if(!op2.buffer)\n\t\t\t\treturn String(op1);\n\n\t\t\treturn StringConcat(op1.buffer.Ptr(), op1.length, op2.buffer.Ptr(), op2.length);\n\t\t}\n\n\t\tint StringToInt(const String & str, int radix)\n\t\t{\n\t\t\tif (str.StartsWith(\"0x\"))\n\t\t\t\treturn (int)strtoll(str.Buffer(), NULL, 16);\n\t\t\telse\n\t\t\t\treturn (int)strtoll(str.Buffer(), NULL, radix);\n\t\t}\n\t\tunsigned int StringToUInt(const String & str, int radix)\n\t\t{\n\t\t\tif (str.StartsWith(\"0x\"))\n\t\t\t\treturn (unsigned int)strtoull(str.Buffer(), NULL, 16);\n\t\t\telse\n\t\t\t\treturn (unsigned int)strtoull(str.Buffer(), NULL, radix);\n\t\t}\n\t\tdouble StringToDouble(const String & str)\n\t\t{\n\t\t\treturn (double)strtod(str.Buffer(), NULL);\n\t\t}\n\t\tfloat StringToFloat(const String & str)\n\t\t{\n\t\t\treturn strtof(str.Buffer(), NULL);\n\t\t}\n\n\t\tString String::ReplaceAll(String src, String dst) const\n\t\t{\n\t\t\tString rs = *this;\n\t\t\tint index = 0;\n\t\t\tint srcLen = src.length;\n\t\t\tint len = rs.length;\n\t\t\twhile ((index = rs.IndexOf(src, index)) != -1)\n\t\t\t{\n\t\t\t\trs = rs.SubString(0, index) + dst + rs.SubString(index + srcLen, len - index - srcLen);\n\t\t\t\tlen = rs.length;\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\n\t\tString String::FromWString(const wchar_t * wstr)\n\t\t{\n#ifdef _WIN32\n\t\t\treturn CoreLib::IO::Encoding::UTF16->ToString((const char*)wstr, (int)(wcslen(wstr) * sizeof(wchar_t)));\n#else\n\t\t\treturn CoreLib::IO::Encoding::UTF32->ToString((const char*)wstr, (int)(wcslen(wstr) * sizeof(wchar_t)));\n#endif\n\t\t}\n\n\t\tString String::FromWChar(const wchar_t ch)\n\t\t{\n#ifdef _WIN32\n\t\t\treturn CoreLib::IO::Encoding::UTF16->ToString((const char*)&ch, (int)(sizeof(wchar_t)));\n#else\n\t\t\treturn CoreLib::IO::Encoding::UTF32->ToString((const char*)&ch, (int)(sizeof(wchar_t)));\n#endif\n\t\t}\n\n\t\tString String::FromUnicodePoint(unsigned int codePoint)\n\t\t{\n\t\t\tchar buf[6];\n\t\t\tint len = CoreLib::IO::EncodeUnicodePointToUTF8(buf, (int)codePoint);\n\t\t\tbuf[len] = 0;\n\t\t\treturn String(buf);\n\t\t}\n\n\t\tconst wchar_t * String::ToWString(int * len) const\n\t\t{\n\t\t\tif (!buffer)\n\t\t\t{\n\t\t\t\tif (len)\n\t\t\t\t\t*len = 0;\n\t\t\t\treturn L\"\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (wcharBuffer)\n\t\t\t\t{\n\t\t\t\t\tif (len)\n\t\t\t\t\t\t*len = (int)wcslen(wcharBuffer);\n\t\t\t\t\treturn wcharBuffer;\n\t\t\t\t}\n\t\t\t\tList<char> buf;\n\t\t\t\tCoreLib::IO::Encoding::UTF16->GetBytes(buf, *this);\n\t\t\t\tif (len)\n\t\t\t\t\t*len = buf.Count() / sizeof(wchar_t);\n\t\t\t\tbuf.Add(0);\n\t\t\t\tbuf.Add(0);\n\t\t\t\tconst_cast<String*>(this)->wcharBuffer = (wchar_t*)buf.Buffer();\n\t\t\t\tbuf.ReleaseBuffer();\n\t\t\t\treturn wcharBuffer;\n\t\t\t}\n\t\t}\n\n\t\tString String::PadLeft(char ch, int pLen)\n\t\t{\n\t\t\tStringBuilder sb;\n\t\t\tfor (int i = 0; i < pLen - this->length; i++)\n\t\t\t\tsb << ch;\n\t\t\tfor (int i = 0; i < this->length; i++)\n\t\t\t\tsb << buffer[i];\n\t\t\treturn sb.ProduceString();\n\t\t}\n\n\t\tString String::PadRight(char ch, int pLen)\n\t\t{\n\t\t\tStringBuilder sb;\n\t\t\tfor (int i = 0; i < this->length; i++)\n\t\t\t\tsb << buffer[i];\n\t\t\tfor (int i = 0; i < pLen - this->length; i++)\n\t\t\t\tsb << ch;\n\t\t\treturn sb.ProduceString();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Source/CoreLib/LibString.h",
    "content": "#ifndef FUNDAMENTAL_LIB_STRING_H\n#define FUNDAMENTAL_LIB_STRING_H\n#include <string.h>\n#include <cstdlib>\n#include <stdio.h>\n#include \"SmartPointer.h\"\n#include \"Common.h\"\n#include \"Hash.h\"\n#include \"SecureCRT.h\"\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\tclass _EndLine\n\t\t{};\n\t\textern _EndLine EndLine;\n\n\t\t// in-place reversion, works only for ascii string\n\t\tinline void ReverseInternalAscii(char * buffer, int length)\n\t\t{\n\t\t\tint i, j;\n\t\t\tchar c;\n\t\t\tfor (i = 0, j = length - 1; i<j; i++, j--)\n\t\t\t{\n\t\t\t\tc = buffer[i];\n\t\t\t\tbuffer[i] = buffer[j];\n\t\t\t\tbuffer[j] = c;\n\t\t\t}\n\t\t}\n\t\ttemplate<typename IntType>\n\t\tinline int IntToAscii(char * buffer, IntType val, int radix)\n\t\t{\n\t\t\tint i = 0;\n\t\t\tIntType sign;\n\t\t\tsign = val;\n\t\t\tif (sign < 0)\n\t\t\t\tval = (IntType)(0 - val);\n\t\t\tdo\n\t\t\t{\n\t\t\t\tint digit = (val % radix);\n\t\t\t\tif (digit <= 9)\n\t\t\t\t\tbuffer[i++] = (char)(digit + '0');\n\t\t\t\telse\n\t\t\t\t\tbuffer[i++] = (char)(digit - 10 + 'A');\n\t\t\t} while ((val /= radix) > 0);\n\t\t\tif (sign < 0)\n\t\t\t\tbuffer[i++] = '-';\n\t\t\tbuffer[i] = '\\0';\n\t\t\treturn i;\n\t\t}\n\n\t\tinline bool IsUtf8LeadingByte(char ch)\n\t\t{\n\t\t\treturn (((unsigned char)ch) & 0xC0) == 0xC0;\n\t\t}\n\n\t\tinline bool IsUtf8ContinuationByte(char ch)\n\t\t{\n\t\t\treturn (((unsigned char)ch) & 0xC0) == 0x80;\n\t\t}\n\n\t\t/*!\n\t\t@brief Represents a UTF-8 encoded string.\n\t\t*/\n\n\t\tclass String\n\t\t{\n\t\t\tfriend class StringBuilder;\n\t\tprivate:\n\t\t\tRefPtr<char, RefPtrArrayDestructor> buffer;\n\t\t\twchar_t * wcharBuffer = nullptr;\n\t\t\tint length = 0;\n\t\t\tvoid Free()\n\t\t\t{\n\t\t\t\tif (buffer)\n\t\t\t\t\tbuffer = 0;\n\t\t\t\tif (wcharBuffer)\n\t\t\t\t\tdelete[] wcharBuffer;\n\t\t\t\tbuffer = 0;\n\t\t\t\twcharBuffer = 0;\n\t\t\t\tlength = 0;\n\t\t\t}\n\t\tpublic:\n\t\t\tstatic String FromBuffer(RefPtr<char, RefPtrArrayDestructor> buffer, int len)\n\t\t\t{\n\t\t\t\tString rs;\n\t\t\t\trs.buffer = buffer;\n\t\t\t\trs.length = len;\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tstatic String FromWString(const wchar_t * wstr);\n\t\t\tstatic String FromWChar(const wchar_t ch);\n\t\t\tstatic String FromUnicodePoint(unsigned int codePoint);\n\t\t\tString()\n\t\t\t{\n\t\t\t}\n\t\t\tconst char * begin() const\n\t\t\t{\n\t\t\t\treturn buffer.Ptr();\n\t\t\t}\n\t\t\tconst char * end() const\n\t\t\t{\n\t\t\t\treturn buffer.Ptr() + length;\n\t\t\t}\n\t\t\tString(int val, int radix = 10)\n\t\t\t{\n\t\t\t\tbuffer = new char[33];\n\t\t\t\tlength = IntToAscii(buffer.Ptr(), val, radix);\n\t\t\t\tReverseInternalAscii(buffer.Ptr(), length);\n\t\t\t}\n\t\t\tString(unsigned int val, int radix = 10)\n\t\t\t{\n\t\t\t\tbuffer = new char[33];\n\t\t\t\tlength = IntToAscii(buffer.Ptr(), val, radix);\n\t\t\t\tReverseInternalAscii(buffer.Ptr(), length);\n\t\t\t}\n\t\t\tString(long long val, int radix = 10)\n\t\t\t{\n\t\t\t\tbuffer = new char[65];\n\t\t\t\tlength = IntToAscii(buffer.Ptr(), val, radix);\n\t\t\t\tReverseInternalAscii(buffer.Ptr(), length);\n\t\t\t}\n\t\t\tString(float val, const char * format = \"%g\")\n\t\t\t{\n\t\t\t\tbuffer = new char[128];\n\t\t\t\tsprintf_s(buffer.Ptr(), 128, format, val);\n\t\t\t\tlength = (int)strnlen_s(buffer.Ptr(), 128);\n\t\t\t}\n\t\t\tString(double val, const char * format = \"%g\")\n\t\t\t{\n\t\t\t\tbuffer = new char[128];\n\t\t\t\tsprintf_s(buffer.Ptr(), 128, format, val);\n\t\t\t\tlength = (int)strnlen_s(buffer.Ptr(), 128);\n\t\t\t}\n\t\t\tString(const char * str)\n\t\t\t{\n\t\t\t\tif (str)\n\t\t\t\t{\n\t\t\t\t\tlength = (int)strlen(str);\n\t\t\t\t\tbuffer = new char[length + 1];\n\t\t\t\t\tmemcpy(buffer.Ptr(), str, length + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\tString(char chr)\n\t\t\t{\n\t\t\t\tif (chr)\n\t\t\t\t{\n\t\t\t\t\tlength = 1;\n\t\t\t\t\tbuffer = new char[2];\n\t\t\t\t\tbuffer[0] = chr;\n\t\t\t\t\tbuffer[1] = '\\0';\n\t\t\t\t}\n\t\t\t}\n\t\t\tString(const String & str)\n\t\t\t{\n\t\t\t\tthis->operator=(str);\n\t\t\t}\n\t\t\tString(String&& other)\n\t\t\t{\n\t\t\t\tthis->operator=(static_cast<String&&>(other));\n\t\t\t}\n\t\t\t~String()\n\t\t\t{\n\t\t\t\tFree();\n\t\t\t}\n\t\t\tString & operator=(const String & str)\n\t\t\t{\n\t\t\t\tif (str.buffer == buffer)\n\t\t\t\t\treturn *this;\n\t\t\t\tFree();\n\t\t\t\tif (str.buffer)\n\t\t\t\t{\n\t\t\t\t\tlength = str.length;\n\t\t\t\t\tbuffer = str.buffer;\n\t\t\t\t\twcharBuffer = 0;\n\t\t\t\t}\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tString & operator=(String&& other)\n\t\t\t{\n\t\t\t\tif (this != &other)\n\t\t\t\t{\n\t\t\t\t\tFree();\n\t\t\t\t\tbuffer = _Move(other.buffer);\n\t\t\t\t\tlength = other.length;\n\t\t\t\t\twcharBuffer = other.wcharBuffer;\n\t\t\t\t\tother.buffer = 0;\n\t\t\t\t\tother.length = 0;\n\t\t\t\t\tother.wcharBuffer = 0;\n\t\t\t\t}\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tchar operator[](int id) const\n\t\t\t{\n#if _DEBUG\n\t\t\t\tif (id < 0 || id >= length)\n\t\t\t\t\tthrow \"Operator[]: index out of range.\";\n#endif\n\t\t\t\treturn buffer.Ptr()[id];\n\t\t\t}\n\n\t\t\tfriend String StringConcat(const char * lhs, int leftLen, const char * rhs, int rightLen);\n\t\t\tfriend String operator+(const char*op1, const String & op2);\n\t\t\tfriend String operator+(const String & op1, const char * op2);\n\t\t\tfriend String operator+(const String & op1, const String & op2);\n\n\t\t\tString TrimStart() const\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn *this;\n\t\t\t\tint startIndex = 0;\n\t\t\t\twhile (startIndex < length &&\n\t\t\t\t\t(buffer[startIndex] == ' ' || buffer[startIndex] == '\\t' || buffer[startIndex] == '\\r' || buffer[startIndex] == '\\n'))\n\t\t\t\t\tstartIndex++;\n\t\t\t\treturn String(buffer + startIndex);\n\t\t\t}\n\n\t\t\tString TrimEnd() const\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn *this;\n\n\t\t\t\tint endIndex = length - 1;\n\t\t\t\twhile (endIndex >= 0 &&\n\t\t\t\t\t(buffer[endIndex] == ' ' || buffer[endIndex] == '\\t' || buffer[endIndex] == '\\r' || buffer[endIndex] == '\\n'))\n\t\t\t\t\tendIndex--;\n\t\t\t\tString res;\n\t\t\t\tres.length = endIndex + 1;\n\t\t\t\tres.buffer = new char[endIndex + 2];\n\t\t\t\tstrncpy_s(res.buffer.Ptr(), endIndex + 2, buffer.Ptr(), endIndex + 1);\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\tString Trim() const\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn *this;\n\n\t\t\t\tint startIndex = 0;\n\t\t\t\twhile (startIndex < length &&\n\t\t\t\t\t(buffer[startIndex] == ' ' || buffer[startIndex] == '\\t'))\n\t\t\t\t\tstartIndex++;\n\t\t\t\tint endIndex = length - 1;\n\t\t\t\twhile (endIndex >= startIndex &&\n\t\t\t\t\t(buffer[endIndex] == ' ' || buffer[endIndex] == '\\t'))\n\t\t\t\t\tendIndex--;\n\n\t\t\t\tString res;\n\t\t\t\tres.length = endIndex - startIndex + 1;\n\t\t\t\tres.buffer = new char[res.length + 1];\n\t\t\t\tmemcpy(res.buffer.Ptr(), buffer + startIndex, res.length);\n\t\t\t\tres.buffer[res.length] = '\\0';\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\tString SubString(int id, int len) const\n\t\t\t{\n\t\t\t\tif (len == 0)\n\t\t\t\t\treturn \"\";\n\t\t\t\tif (id + len > length)\n\t\t\t\t\tlen = length - id;\n#if _DEBUG\n\t\t\t\tif (id < 0 || id >= length || (id + len) > length)\n\t\t\t\t\tthrow \"SubString: index out of range.\";\n\t\t\t\tif (len < 0)\n\t\t\t\t\tthrow \"SubString: length less than zero.\";\n#endif\n\t\t\t\tString res;\n\t\t\t\tres.buffer = new char[len + 1];\n\t\t\t\tres.length = len;\n\t\t\t\tstrncpy_s(res.buffer.Ptr(), len + 1, buffer + id, len);\n\t\t\t\tres.buffer[len] = 0;\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\tconst char * Buffer() const\n\t\t\t{\n\t\t\t\tif (buffer)\n\t\t\t\t\treturn buffer.Ptr();\n\t\t\t\telse\n\t\t\t\t\treturn \"\";\n\t\t\t}\n\n\t\t\tconst wchar_t * ToWString(int * len = 0) const;\n\n\t\t\tbool Equals(const String & str, bool caseSensitive = true)\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn (str.buffer == 0);\n\t\t\t\tif (caseSensitive)\n\t\t\t\t\treturn (strcmp(buffer.Ptr(), str.buffer.Ptr()) == 0);\n\t\t\t\telse\n\t\t\t\t{\n#ifdef _MSC_VER\n\t\t\t\t\treturn (_stricmp(buffer.Ptr(), str.buffer.Ptr()) == 0);\n#else\n\t\t\t\t\treturn (strcasecmp(buffer.Ptr(), str.buffer.Ptr()) == 0);\n#endif\n\t\t\t\t}\n\t\t\t}\n\t\t\tbool operator==(const char * strbuffer) const\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn (strbuffer == 0 || strcmp(strbuffer, \"\") == 0);\n\t\t\t\tif (!strbuffer)\n\t\t\t\t\treturn buffer == nullptr || strcmp(buffer.Ptr(), \"\") == 0;\n\t\t\t\treturn (strcmp(buffer.Ptr(), strbuffer) == 0);\n\t\t\t}\n\n\t\t\tbool operator==(const String & str) const\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn (str.buffer == 0 || strcmp(str.buffer.Ptr(), \"\") == 0);\n\t\t\t\tif (!str.buffer)\n\t\t\t\t\treturn buffer == nullptr || strcmp(buffer.Ptr(), \"\") == 0;\n\t\t\t\treturn (strcmp(buffer.Ptr(), str.buffer.Ptr()) == 0);\n\t\t\t}\n\t\t\tbool operator!=(const char * strbuffer) const\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn (strbuffer != 0 && strcmp(strbuffer, \"\") != 0);\n\t\t\t\tif (strbuffer == 0)\n\t\t\t\t\treturn length != 0;\n\t\t\t\treturn (strcmp(buffer.Ptr(), strbuffer) != 0);\n\t\t\t}\n\t\t\tbool operator!=(const String & str) const\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn (str.buffer != 0 && strcmp(str.buffer.Ptr(), \"\") != 0);\n\t\t\t\tif (str.buffer.Ptr() == 0)\n\t\t\t\t\treturn length != 0;\n\t\t\t\treturn (strcmp(buffer.Ptr(), str.buffer.Ptr()) != 0);\n\t\t\t}\n\t\t\tbool operator>(const String & str) const\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn false;\n\t\t\t\tif (!str.buffer)\n\t\t\t\t\treturn buffer.Ptr() != nullptr && length != 0;\n\t\t\t\treturn (strcmp(buffer.Ptr(), str.buffer.Ptr()) > 0);\n\t\t\t}\n\t\t\tbool operator<(const String & str) const\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn (str.buffer != 0);\n\t\t\t\tif (!str.buffer)\n\t\t\t\t\treturn false;\n\t\t\t\treturn (strcmp(buffer.Ptr(), str.buffer.Ptr()) < 0);\n\t\t\t}\n\t\t\tbool operator>=(const String & str) const\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn (str.buffer == 0);\n\t\t\t\tif (!str.buffer)\n\t\t\t\t\treturn length == 0;\n\t\t\t\tint res = strcmp(buffer.Ptr(), str.buffer.Ptr());\n\t\t\t\treturn (res > 0 || res == 0);\n\t\t\t}\n\t\t\tbool operator<=(const String & str) const\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn true;\n\t\t\t\tif (!str.buffer)\n\t\t\t\t\treturn length > 0;\n\t\t\t\tint res = strcmp(buffer.Ptr(), str.buffer.Ptr());\n\t\t\t\treturn (res < 0 || res == 0);\n\t\t\t}\n\n\t\t\tString ToUpper() const\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn *this;\n\t\t\t\tString res;\n\t\t\t\tres.length = length;\n\t\t\t\tres.buffer = new char[length + 1];\n\t\t\t\tfor (int i = 0; i <= length; i++)\n\t\t\t\t\tres.buffer[i] = (buffer[i] >= 'a' && buffer[i] <= 'z') ?\n\t\t\t\t\t(buffer[i] - 'a' + 'A') : buffer[i];\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\tString ToLower() const\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn *this;\n\t\t\t\tString res;\n\t\t\t\tres.length = length;\n\t\t\t\tres.buffer = new char[length + 1];\n\t\t\t\tfor (int i = 0; i <= length; i++)\n\t\t\t\t\tres.buffer[i] = (buffer[i] >= 'A' && buffer[i] <= 'Z') ?\n\t\t\t\t\t(buffer[i] - 'A' + 'a') : buffer[i];\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\tint Length() const\n\t\t\t{\n\t\t\t\treturn length;\n\t\t\t}\n\n\t\t\tint IndexOf(const char * str, int id) const // String str\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn -1;\n\t\t\t\tif (id < 0 || id >= length)\n\t\t\t\t\treturn -1;\n\t\t\t\tauto findRs = strstr(buffer + id, str);\n\t\t\t\tint res = findRs ? (int)(findRs - buffer.Ptr()) : -1;\n\t\t\t\tif (res >= 0)\n\t\t\t\t\treturn res;\n\t\t\t\telse\n\t\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tint IndexOf(const String & str, int id) const\n\t\t\t{\n\t\t\t\treturn IndexOf(str.buffer.Ptr(), id);\n\t\t\t}\n\n\t\t\tint IndexOf(const char * str) const\n\t\t\t{\n\t\t\t\treturn IndexOf(str, 0);\n\t\t\t}\n\n\t\t\tint IndexOf(const String & str) const\n\t\t\t{\n\t\t\t\treturn IndexOf(str.buffer.Ptr(), 0);\n\t\t\t}\n\n\t\t\tint IndexOf(char ch, int id) const\n\t\t\t{\n#if _DEBUG\n\t\t\t\tif (id < 0 || id >= length)\n\t\t\t\t\tthrow \"SubString: index out of range.\";\n#endif\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn -1;\n\t\t\t\tfor (int i = id; i < length; i++)\n\t\t\t\t\tif (buffer[i] == ch)\n\t\t\t\t\t\treturn i;\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tint IndexOf(char ch) const\n\t\t\t{\n\t\t\t\treturn IndexOf(ch, 0);\n\t\t\t}\n\n\t\t\tint LastIndexOf(char ch) const\n\t\t\t{\n\t\t\t\tfor (int i = length - 1; i >= 0; i--)\n\t\t\t\t\tif (buffer[i] == ch)\n\t\t\t\t\t\treturn i;\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tbool StartsWith(const char * str) const // String str\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn false;\n\t\t\t\tint strLen = (int)strlen(str);\n\t\t\t\tif (strLen > length)\n\t\t\t\t\treturn false;\n\t\t\t\tfor (int i = 0; i < strLen; i++)\n\t\t\t\t\tif (str[i] != buffer[i])\n\t\t\t\t\t\treturn false;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool StartsWith(const String & str) const\n\t\t\t{\n\t\t\t\treturn StartsWith(str.buffer.Ptr());\n\t\t\t}\n\n\t\t\tbool EndsWith(char * str)  const // String str\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn false;\n\t\t\t\tint strLen = (int)strlen(str);\n\t\t\t\tif (strLen > length)\n\t\t\t\t\treturn false;\n\t\t\t\tfor (int i = strLen - 1; i >= 0; i--)\n\t\t\t\t\tif (str[i] != buffer[length - strLen + i])\n\t\t\t\t\t\treturn false;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool EndsWith(const String & str) const\n\t\t\t{\n\t\t\t\treturn EndsWith(str.buffer.Ptr());\n\t\t\t}\n\n\t\t\tbool Contains(const char * str) const // String str\n\t\t\t{\n\t\t\t\tif (!buffer)\n\t\t\t\t\treturn false;\n\t\t\t\treturn (IndexOf(str) >= 0) ? true : false;\n\t\t\t}\n\n\t\t\tbool Contains(const String & str) const\n\t\t\t{\n\t\t\t\treturn Contains(str.buffer.Ptr());\n\t\t\t}\n\n\t\t\tint GetHashCode() const\n\t\t\t{\n\t\t\t\treturn CoreLib::Basic::GetHashCode((const char*)buffer.Ptr());\n\t\t\t}\n\t\t\tString PadLeft(char ch, int length);\n\t\t\tString PadRight(char ch, int length);\n\t\t\tString ReplaceAll(String src, String dst) const;\n\t\t};\n\n\t\tclass StringBuilder\n\t\t{\n\t\tprivate:\n\t\t\tchar * buffer;\n\t\t\tint length;\n\t\t\tint bufferSize;\n\t\t\tstatic const int InitialSize = 512;\n\t\tpublic:\n\t\t\tStringBuilder(int bufferSize = 1024)\n\t\t\t\t:buffer(0), length(0), bufferSize(0)\n\t\t\t{\n\t\t\t\tbuffer = new char[InitialSize]; // new a larger buffer \n\t\t\t\tbuffer[0] = '\\0';\n\t\t\t\tlength = 0;\n\t\t\t\tbufferSize = InitialSize;\n\t\t\t}\n\t\t\t~StringBuilder()\n\t\t\t{\n\t\t\t\tif (buffer)\n\t\t\t\t\tdelete[] buffer;\n\t\t\t}\n\t\t\tvoid EnsureCapacity(int size)\n\t\t\t{\n\t\t\t\tif (bufferSize < size)\n\t\t\t\t{\n\t\t\t\t\tchar * newBuffer = new char[size + 1];\n\t\t\t\t\tif (buffer)\n\t\t\t\t\t{\n\t\t\t\t\t\tstrcpy_s(newBuffer, size + 1, buffer);\n\t\t\t\t\t\tdelete[] buffer;\n\t\t\t\t\t}\n\t\t\t\t\tbuffer = newBuffer;\n\t\t\t\t\tbufferSize = size;\n\t\t\t\t}\n\t\t\t}\n\t\t\tStringBuilder & operator << (char ch)\n\t\t\t{\n\t\t\t\tAppend(&ch, 1);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tStringBuilder & operator << (int val)\n\t\t\t{\n\t\t\t\tAppend(val);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tStringBuilder & operator << (unsigned int val)\n\t\t\t{\n\t\t\t\tAppend(val);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tStringBuilder & operator << (long long val)\n\t\t\t{\n\t\t\t\tAppend(val);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tStringBuilder & operator << (float val)\n\t\t\t{\n\t\t\t\tAppend(val);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tStringBuilder & operator << (double val)\n\t\t\t{\n\t\t\t\tAppend(val);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tStringBuilder & operator << (const char * str)\n\t\t\t{\n\t\t\t\tAppend(str, (int)strlen(str));\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tStringBuilder & operator << (const String & str)\n\t\t\t{\n\t\t\t\tAppend(str);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tStringBuilder & operator << (const _EndLine)\n\t\t\t{\n\t\t\t\tAppend('\\n');\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tvoid Append(char ch)\n\t\t\t{\n\t\t\t\tAppend(&ch, 1);\n\t\t\t}\n\t\t\tvoid Append(float val)\n\t\t\t{\n\t\t\t\tchar buf[128];\n\t\t\t\tsprintf_s(buf, 128, \"%g\", val);\n\t\t\t\tint len = (int)strnlen_s(buf, 128);\n\t\t\t\tAppend(buf, len);\n\t\t\t}\n\t\t\tvoid Append(double val)\n\t\t\t{\n\t\t\t\tchar buf[128];\n\t\t\t\tsprintf_s(buf, 128, \"%g\", val);\n\t\t\t\tint len = (int)strnlen_s(buf, 128);\n\t\t\t\tAppend(buf, len);\n\t\t\t}\n\t\t\tvoid Append(unsigned int value, int radix = 10)\n\t\t\t{\n\t\t\t\tchar vBuffer[33];\n\t\t\t\tint len = IntToAscii(vBuffer, value, radix);\n\t\t\t\tReverseInternalAscii(vBuffer, len);\n\t\t\t\tAppend(vBuffer);\n\t\t\t}\n\t\t\tvoid Append(int value, int radix = 10)\n\t\t\t{\n\t\t\t\tchar vBuffer[33];\n\t\t\t\tint len = IntToAscii(vBuffer, value, radix);\n\t\t\t\tReverseInternalAscii(vBuffer, len);\n\t\t\t\tAppend(vBuffer);\n\t\t\t}\n\t\t\tvoid Append(long long value, int radix = 10)\n\t\t\t{\n\t\t\t\tchar vBuffer[65];\n\t\t\t\tint len = IntToAscii(vBuffer, value, radix);\n\t\t\t\tReverseInternalAscii(vBuffer, len);\n\t\t\t\tAppend(vBuffer);\n\t\t\t}\n\t\t\tvoid Append(const String & str)\n\t\t\t{\n\t\t\t\tAppend(str.Buffer(), str.Length());\n\t\t\t}\n\t\t\tvoid Append(const char * str)\n\t\t\t{\n\t\t\t\tAppend(str, (int)strlen(str));\n\t\t\t}\n\t\t\tvoid Append(const char * str, int strLen)\n\t\t\t{\n\t\t\t\tint newLength = length + strLen;\n\t\t\t\tif (bufferSize < newLength + 1)\n\t\t\t\t{\n\t\t\t\t\tint newBufferSize = InitialSize;\n\t\t\t\t\twhile (newBufferSize < newLength + 1)\n\t\t\t\t\t\tnewBufferSize <<= 1;\n\t\t\t\t\tchar * newBuffer = new char[newBufferSize];\n\t\t\t\t\tif (buffer)\n\t\t\t\t\t{\n\t\t\t\t\t\tmemcpy(newBuffer, buffer, length);\n\t\t\t\t\t\tdelete[] buffer;\n\t\t\t\t\t}\n\t\t\t\t\tmemcpy(newBuffer + length, str, strLen);\n\t\t\t\t\tnewBuffer[newLength] = '\\0';\n\t\t\t\t\tbuffer = newBuffer;\n\t\t\t\t\tbufferSize = newBufferSize;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tmemcpy(buffer + length, str, strLen);\n\t\t\t\t\tbuffer[newLength] = '\\0';\n\t\t\t\t}\n\t\t\t\tlength = newLength;\n\t\t\t}\n\n\t\t\tint Capacity()\n\t\t\t{\n\t\t\t\treturn bufferSize;\n\t\t\t}\n\n\t\t\tchar * Buffer()\n\t\t\t{\n\t\t\t\treturn buffer;\n\t\t\t}\n\n\t\t\tint Length()\n\t\t\t{\n\t\t\t\treturn length;\n\t\t\t}\n\n\t\t\tString ToString()\n\t\t\t{\n\t\t\t\treturn String(buffer);\n\t\t\t}\n\n\t\t\tString ProduceString()\n\t\t\t{\n\t\t\t\tString rs;\n\t\t\t\trs.buffer = buffer;\n\t\t\t\trs.length = length;\n\t\t\t\tbuffer = 0;\n\t\t\t\tbufferSize = 0;\n\t\t\t\tlength = 0;\n\t\t\t\treturn rs;\n\n\t\t\t}\n\n\t\t\tString GetSubString(int start, int count)\n\t\t\t{\n\t\t\t\tString rs;\n\t\t\t\trs.buffer = new char[count + 1];\n\t\t\t\trs.length = count;\n\t\t\t\tstrncpy_s(rs.buffer.Ptr(), count + 1, buffer + start, count);\n\t\t\t\trs.buffer[count] = 0;\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tvoid Remove(int id, int len)\n\t\t\t{\n#if _DEBUG\n\t\t\t\tif (id >= length || id < 0)\n\t\t\t\t\tthrow \"Remove: Index out of range.\";\n\t\t\t\tif (len < 0)\n\t\t\t\t\tthrow \"Remove: remove length smaller than zero.\";\n#endif\n\t\t\t\tint actualDelLength = ((id + len) >= length) ? (length - id) : len;\n\t\t\t\tfor (int i = id + actualDelLength; i <= length; i++)\n\t\t\t\t\tbuffer[i - actualDelLength] = buffer[i];\n\t\t\t\tlength -= actualDelLength;\n\t\t\t}\n\n\t\t\tvoid Clear()\n\t\t\t{\n\t\t\t\tlength = 0;\n\t\t\t\tif (buffer)\n\t\t\t\t\tbuffer[0] = 0;\n\t\t\t}\n\t\t};\n\n\t\tint StringToInt(const String & str, int radix = 10);\n\t\tunsigned int StringToUInt(const String & str, int radix = 10);\n\t\tdouble StringToDouble(const String & str);\n\t\tfloat StringToFloat(const String & str);\n\t}\n}\n\n#endif\n"
  },
  {
    "path": "Source/CoreLib/Link.h",
    "content": "#ifndef CORE_LIB_LINK_H\n#define CORE_LIB_LINK_H\n\n#include \"Common.h\"\n#include \"Exception.h\"\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\ttemplate<typename T>\n\t\tclass LinkedList;\n\n\t\ttemplate<typename T>\n\t\tclass LinkedNode\n\t\t{\n\t\t\ttemplate<typename T1>\n\t\t\tfriend class LinkedList;\n\t\tprivate:\n\t\t\tLinkedNode<T> *pPrev, *pNext;\n\t\t\tLinkedList<T> * FLink;\n\t\tpublic:\n\t\t\tT Value;\n\t\t\tLinkedNode (LinkedList<T> * lnk):FLink(lnk)\n\t\t\t{\n\t\t\t\tpPrev = pNext = 0;\n\t\t\t};\n\t\t\tLinkedNode<T> * GetPrevious()\n\t\t\t{\n\t\t\t\treturn pPrev;\n\t\t\t};\n\t\t\tLinkedNode<T> * GetNext()\n\t\t\t{\n\t\t\t\treturn pNext;\n\t\t\t};\n\t\t\tLinkedNode<T> * InsertAfter(const T & nData)\n\t\t\t{\n\t\t\t\tLinkedNode<T> * n = new LinkedNode<T>(FLink);\n\t\t\t\tn->Value = nData;\n\t\t\t\tn->pPrev = this;\n\t\t\t\tn->pNext = this->pNext;\n\t\t\t\tLinkedNode<T> *npp = n->pNext;\n\t\t\t\tif (npp)\n\t\t\t\t{\n\t\t\t\t\tnpp->pPrev = n;\n\t\t\t\t}\n\t\t\t\tpNext = n;\n\t\t\t\tif (!n->pNext)\n\t\t\t\t\tFLink->FTail = n;\n\t\t\t\tFLink->FCount ++;\n\t\t\t\treturn n;\n\t\t\t};\n\t\t\tLinkedNode<T> * InsertBefore(const T & nData)\n\t\t\t{\n\t\t\t\tLinkedNode<T> * n = new LinkedNode<T>(FLink);\n\t\t\t\tn->Value = nData;\n\t\t\t\tn->pPrev = pPrev;\n\t\t\t\tn->pNext = this;\n\t\t\t\tpPrev = n;\n\t\t\t\tLinkedNode<T> *npp = n->pPrev;\n\t\t\t\tif (npp)\n\t\t\t\t\tnpp->pNext = n;\n\t\t\t\tif (!n->pPrev)\n\t\t\t\t\tFLink->FHead = n;\n\t\t\t\tFLink->FCount ++;\n\t\t\t\treturn n;\n\t\t\t};\n\t\t\tvoid Delete()\n\t\t\t{\n\t\t\t\tif (pPrev)\n\t\t\t\t\tpPrev->pNext = pNext;\n\t\t\t\tif (pNext)\n\t\t\t\t\tpNext->pPrev = pPrev;\n\t\t\t\tFLink->FCount --;\n\t\t\t\tif (FLink->FHead == this)\n\t\t\t\t{\n\t\t\t\t\tFLink->FHead = pNext;\n\t\t\t\t}\n\t\t\t\tif (FLink->FTail == this)\n\t\t\t\t{\n\t\t\t\t\tFLink->FTail = pPrev;\n\t\t\t\t}\n\t\t\t\tdelete this;\n\t\t\t}\n\t\t};\n\t\ttemplate<typename T>\n\t\tclass LinkedList\n\t\t{\n\t\t\ttemplate<typename T1>\n\t\t\tfriend class LinkedNode;\n\t\tprivate:\n\t\t\tLinkedNode<T> * FHead, *FTail;\n\t\t\tint FCount;\n\t\tpublic:\n\t\t\tclass Iterator\n\t\t\t{\n\t\t\tpublic:\n\t\t\t\tLinkedNode<T> * Current, *Next;\n\t\t\t\tvoid SetCurrent(LinkedNode<T> * cur)\n\t\t\t\t{\n\t\t\t\t\tCurrent = cur;\n\t\t\t\t\tif (Current)\n\t\t\t\t\t\tNext = Current->GetNext();\n\t\t\t\t\telse\n\t\t\t\t\t\tNext = 0;\n\t\t\t\t}\n\t\t\t\tIterator()\n\t\t\t\t{\n\t\t\t\t\tCurrent = Next = 0;\n\t\t\t\t}\n\t\t\t\tIterator(LinkedNode<T> * cur)\n\t\t\t\t{\n\t\t\t\t\tSetCurrent(cur);\n\t\t\t\t}\n\t\t\t\tT & operator *() const\n\t\t\t\t{\n\t\t\t\t\treturn Current->Value;\n\t\t\t\t}\n\t\t\t\tIterator& operator ++()\n\t\t\t\t{\n\t\t\t\t\tSetCurrent(Next);\n\t\t\t\t\treturn *this;\n\t\t\t\t}\n\t\t\t\tIterator operator ++(int)\n\t\t\t\t{\n\t\t\t\t\tIterator rs = *this;\n\t\t\t\t\tSetCurrent(Next);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tbool operator != (const Iterator & iter) const\n\t\t\t\t{\n\t\t\t\t\treturn Current != iter.Current;\n\t\t\t\t}\n\t\t\t\tbool operator == (const Iterator & iter) const\n\t\t\t\t{\n\t\t\t\t\treturn Current == iter.Current;\n\t\t\t\t}\n\t\t\t};\n\t\t\tIterator begin() const\n\t\t\t{\n\t\t\t\treturn Iterator(FHead);\n\t\t\t}\n\t\t\tIterator end() const\n\t\t\t{\n\t\t\t\treturn Iterator(0);\n\t\t\t}\n\t\tpublic:\n\t\t\tLinkedList() : FHead(0), FTail(0), FCount(0)\n\t\t\t{\n\t\t\t}\n\t\t\t~LinkedList()\n\t\t\t{\n\t\t\t\tClear();\n\t\t\t}\n\t\t\tLinkedList(const LinkedList<T> & link) : FHead(0), FTail(0), FCount(0)\n\t\t\t{\n\t\t\t\tthis->operator=(link);\n\t\t\t}\n\t\t\tLinkedList(LinkedList<T> && link) : FHead(0), FTail(0), FCount(0)\n\t\t\t{\n\t\t\t\tthis->operator=(_Move(link));\n\t\t\t}\n\t\t\tLinkedList<T> & operator = (LinkedList<T> && link)\n\t\t\t{\n\t\t\t\tif (FHead != 0)\n\t\t\t\t\tClear();\n\t\t\t\tFHead = link.FHead;\n\t\t\t\tFTail = link.FTail;\n\t\t\t\tFCount = link.FCount;\n\t\t\t\tlink.FHead = 0;\n\t\t\t\tlink.FTail = 0;\n\t\t\t\tlink.FCount = 0;\n\t\t\t\tfor (auto node = FHead; node; node = node->GetNext())\n\t\t\t\t\tnode->FLink = this;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tLinkedList<T> & operator = (const LinkedList<T> & link)\n\t\t\t{\n\t\t\t\tif (FHead != 0)\n\t\t\t\t\tClear();\n\t\t\t\tauto p = link.FHead;\n\t\t\t\twhile (p)\n\t\t\t\t{\n\t\t\t\t\tAddLast(p->Value);\n\t\t\t\t\tp = p->GetNext();\n\t\t\t\t}\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\ttemplate<typename IteratorFunc>\n\t\t\tvoid ForEach(const IteratorFunc & f)\n\t\t\t{\n\t\t\t\tauto p = FHead;\n\t\t\t\twhile (p)\n\t\t\t\t{\n\t\t\t\t\tf(p->Value);\n\t\t\t\t\tp = p->GetNext();\n\t\t\t\t}\n\t\t\t}\n\t\t\tLinkedNode<T> * GetNode(int x)\n\t\t\t{\n\t\t\t\tLinkedNode<T> *pCur = FHead;\n\t\t\t\tfor (int i=0;i<x;i++)\n\t\t\t\t{\n\t\t\t\t\tif (pCur)\n\t\t\t\t\t\tpCur = pCur->pNext;\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow \"Index out of range\";\n\t\t\t\t}\n\t\t\t\treturn pCur;\n\t\t\t};\n\t\t\tLinkedNode<T> * Find(const T& fData)\n\t\t\t{\n\t\t\t\tfor (LinkedNode<T> * pCur = FHead; pCur; pCur = pCur->pNext)\n\t\t\t\t{\n\t\t\t\t\tif (pCur->Value == fData)\n\t\t\t\t\t\treturn pCur;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t};\n\t\t\tLinkedNode<T> * FirstNode() const\n\t\t\t{\n\t\t\t\treturn FHead;\n\t\t\t};\n\t\t\tT & First() const\n\t\t\t{\n\t\t\t\tif (!FHead)\n\t\t\t\t\tthrow IndexOutofRangeException(\"LinkedList: index out of range.\");\n\t\t\t\treturn FHead->Value;\n\t\t\t}\n\t\t\tT & Last() const\n\t\t\t{\n\t\t\t\tif (!FTail)\n\t\t\t\t\tthrow IndexOutofRangeException(\"LinkedList: index out of range.\");\n\t\t\t\treturn FTail->Value;\n\t\t\t}\n\t\t\tLinkedNode<T> * LastNode() const\n\t\t\t{\n\t\t\t\treturn FTail;\n\t\t\t};\n\t\t\tLinkedNode<T> * AddLast(const T & nData)\n\t\t\t{\n\t\t\t\tLinkedNode<T> * n = new LinkedNode<T>(this);\n\t\t\t\tn->Value = nData;\n\t\t\t\tn->pPrev = FTail;\n\t\t\t\tif (FTail)\n\t\t\t\t\tFTail->pNext = n;\n\t\t\t\tn->pNext = 0;\n\t\t\t\tFTail = n;\n\t\t\t\tif (!FHead)\n\t\t\t\t\tFHead = n;\n\t\t\t\tFCount ++;\n\t\t\t\treturn n;\n\t\t\t};\n\t\t\t// Insert a blank node\n\t\t\tLinkedNode<T> * AddLast()\n\t\t\t{\n\t\t\t\tLinkedNode<T> * n = new LinkedNode<T>(this);\n\t\t\t\tn->pPrev = FTail;\n\t\t\t\tif (FTail)\n\t\t\t\t\tFTail->pNext = n;\n\t\t\t\tn->pNext = 0;\n\t\t\t\tFTail = n;\n\t\t\t\tif (!FHead)\n\t\t\t\t\tFHead = n;\n\t\t\t\tFCount ++;\n\t\t\t\treturn n;\n\t\t\t};\n\t\t\tLinkedNode<T> * AddFirst(const T& nData)\n\t\t\t{\n\t\t\t\tLinkedNode<T> *n = new LinkedNode<T>(this);\n\t\t\t\tn->Value = nData;\n\t\t\t\tn->pPrev = 0;\n\t\t\t\tn->pNext = FHead;\n\t\t\t\tif (FHead)\n\t\t\t\t\tFHead->pPrev = n;\n\t\t\t\tFHead = n;\n\t\t\t\tif (!FTail)\n\t\t\t\t\tFTail = n;\n\t\t\t\tFCount ++;\n\t\t\t\treturn n;\n\t\t\t};\n\t\t\tvoid Delete(LinkedNode<T>*n, int Count = 1)\n\t\t\t{\n\t\t\t\tLinkedNode<T> *n1,*n2 = 0, *tn;\n\t\t\t\tn1 = n->pPrev;\n\t\t\t\ttn = n;\n\t\t\t\tint numDeleted = 0;\n\t\t\t\tfor (int i=0; i<Count; i++)\n\t\t\t\t{\n\t\t\t\t\tn2 = tn->pNext;\n\t\t\t\t\tdelete tn;\n\t\t\t\t\ttn = n2;\n\t\t\t\t\tnumDeleted++;\n\t\t\t\t\tif (tn == 0)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (n1)\n\t\t\t\t\tn1->pNext = n2;\n\t\t\t\telse\n\t\t\t\t\tFHead = n2;\n\t\t\t\tif (n2)\n\t\t\t\t\tn2->pPrev = n1;\n\t\t\t\telse\n\t\t\t\t\tFTail = n1;\n\t\t\t\tFCount -= numDeleted;\n\t\t\t}\n\t\t\tvoid Clear()\n\t\t\t{\n\t\t\t\tfor (LinkedNode<T> *n = FHead; n; )\n\t\t\t\t{\n\t\t\t\t\tLinkedNode<T> * tmp = n->pNext;\n\t\t\t\t\tdelete n;\n\t\t\t\t\tn = tmp;\n\t\t\t\t}\n\t\t\t\tFHead = 0;\n\t\t\t\tFTail = 0;\n\t\t\t\tFCount = 0;\n\t\t\t}\n\t\t\tList<T> ToList() const\n\t\t\t{\n\t\t\t\tList<T> rs;\n\t\t\t\trs.Reserve(FCount);\n\t\t\t\tfor (auto & item : *this)\n\t\t\t\t{\n\t\t\t\t\trs.Add(item);\n\t\t\t\t}\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tint Count()\n\t\t\t{\n\t\t\t\treturn FCount;\n\t\t\t}\n\t\t};\n\t}\n}\n#endif\n"
  },
  {
    "path": "Source/CoreLib/Linq.h",
    "content": "#ifndef FUNDAMENTAL_LIB_LINQ_H\n#define FUNDAMENTAL_LIB_LINQ_H\n\n#include \"List.h\"\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\n\t\ttemplate <typename T>\n\t\tT ConstructT();\n\n\t\ttemplate <typename T>\n\t\tclass RemoveReference\n\t\t{\n\t\tpublic:\n\t\t\ttypedef T Type;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tclass RemoveReference<T&>\n\t\t{\n\t\tpublic:\n\t\t\ttypedef T Type;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tclass RemoveReference<T&&>\n\t\t{\n\t\tpublic:\n\t\t\ttypedef T Type;\n\t\t};\n\n\t\ttemplate<typename T>\n\t\tstruct RemovePointer\n\t\t{\n\t\t\ttypedef T Type;\n\t\t};\n\n\t\ttemplate<typename T>\n\t\tstruct RemovePointer<T*>\n\t\t{\n\t\t\ttypedef T Type;\n\t\t};\n\n\t\ttemplate <typename TQueryable1, typename TEnumerator1, typename TQueryable2, typename TEnumerator2, typename T>\n\t\tclass ConcatQuery\n\t\t{\n\t\tprivate:\n\t\t\tTQueryable1 items1;\n\t\t\tTQueryable2 items2;\n\t\tpublic:\n\t\t\tConcatQuery(const TQueryable1 & queryable1, const TQueryable2 & queryable2)\n\t\t\t\t: items1(queryable1), items2(queryable2)\n\t\t\t{}\n\t\t\tclass Enumerator\n\t\t\t{\n\t\t\tprivate:\n\t\t\t\tTEnumerator1 ptr1;\n\t\t\t\tTEnumerator1 end1;\n\t\t\t\tTEnumerator2 ptr2;\n\t\t\t\tTEnumerator2 end2;\n\t\t\tpublic:\n\t\t\t\tEnumerator(const Enumerator &) = default;\n\t\t\t\tEnumerator(TEnumerator1 pptr, TEnumerator1 pend, TEnumerator2 pptr2, TEnumerator2 pend2)\n\t\t\t\t\t: ptr1(pptr), end1(pend), ptr2(pptr2), end2(pend2)\n\t\t\t\t{}\n\t\t\t\tT operator *() const\n\t\t\t\t{\n\t\t\t\t\tif (ptr1 != end1)\n\t\t\t\t\t\treturn *(ptr1);\n\t\t\t\t\telse\n\t\t\t\t\t\treturn *(ptr2);\n\t\t\t\t}\n\t\t\t\tEnumerator& operator ++()\n\t\t\t\t{\n\t\t\t\t\tif (ptr1 != end1)\n\t\t\t\t\t\t++ptr1;\n\t\t\t\t\telse\n\t\t\t\t\t\t++ptr2;\n\t\t\t\t\treturn *this;\n\t\t\t\t}\n\t\t\t\tEnumerator operator ++(int)\n\t\t\t\t{\n\t\t\t\t\tEnumerator rs = *this;\n\t\t\t\t\t++rs;\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tbool operator != (const Enumerator & iter) const\n\t\t\t\t{\n\t\t\t\t\treturn ptr1 != iter.ptr1 || ptr2 != iter.ptr2;\n\t\t\t\t}\n\t\t\t\tbool operator == (const Enumerator & iter) const\n\t\t\t\t{\n\t\t\t\t\treturn ptr1 == iter.ptr1 && ptr2 == iter.ptr2;\n\t\t\t\t}\n\t\t\t};\n\t\t\tEnumerator begin() const\n\t\t\t{\n\t\t\t\treturn Enumerator(items1.begin(), items1.end(), items2.begin(), items2.end());\n\t\t\t}\n\t\t\tEnumerator end() const\n\t\t\t{\n\t\t\t\treturn Enumerator(items1.end(), items1.end(), items2.end(), items2.end());\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename TQueryable, typename TEnumerator, typename T, typename TFunc>\n\t\tclass WhereQuery\n\t\t{\n\t\tprivate:\n\t\t\tTQueryable items;\n\t\t\tTFunc func;\n\t\tpublic:\n\t\t\tWhereQuery(const TQueryable & queryable, const TFunc & f)\n\t\t\t\t: items(queryable), func(f)\n\t\t\t{}\n\t\t\tclass Enumerator\n\t\t\t{\n\t\t\tprivate:\n\t\t\t\tTEnumerator ptr;\n\t\t\t\tTEnumerator end;\n\t\t\t\tconst TFunc * func;\n\t\t\tpublic:\n\t\t\t\tEnumerator(const Enumerator &) = default;\n\t\t\t\tEnumerator(TEnumerator ptr, TEnumerator end, const TFunc & f)\n\t\t\t\t\t: ptr(ptr), end(end), func(&f)\n\t\t\t\t{}\n\t\t\t\tT operator *() const\n\t\t\t\t{\n\t\t\t\t\treturn *(ptr);\n\t\t\t\t}\n\t\t\t\tEnumerator& operator ++()\n\t\t\t\t{\n\t\t\t\t\t++ptr;\n\t\t\t\t\twhile (ptr != end)\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((*func)(*ptr))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t++ptr;\n\t\t\t\t\t}\n\t\t\t\t\treturn *this;\n\t\t\t\t}\n\t\t\t\tEnumerator operator ++(int)\n\t\t\t\t{\n\t\t\t\t\tEnumerator rs = *this;\n\t\t\t\t\twhile (rs.ptr != end)\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((*func)(*rs.ptr))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t++rs.ptr;\n\t\t\t\t\t}\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tbool operator != (const Enumerator & iter) const\n\t\t\t\t{\n\t\t\t\t\treturn ptr != iter.ptr;\n\t\t\t\t}\n\t\t\t\tbool operator == (const Enumerator & iter) const\n\t\t\t\t{\n\t\t\t\t\treturn ptr == iter.ptr;\n\t\t\t\t}\n\t\t\t};\n\t\t\tEnumerator begin() const\n\t\t\t{\n\t\t\t\tauto ptr = items.begin();\n\t\t\t\tauto end = items.end();\n\t\t\t\twhile (ptr != end)\n\t\t\t\t{\n\t\t\t\t\tif (func(*ptr))\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t++ptr;\n\t\t\t\t}\n\t\t\t\treturn Enumerator(ptr, end, func);\n\t\t\t}\n\t\t\tEnumerator end() const\n\t\t\t{\n\t\t\t\treturn Enumerator(items.end(), items.end(), func);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename TQueryable, typename TEnumerator, typename T>\n\t\tclass SkipQuery\n\t\t{\n\t\tprivate:\n\t\t\tTQueryable items;\n\t\t\tint count = 0;\n\t\tpublic:\n\t\t\tSkipQuery(const TQueryable & queryable, int pCount)\n\t\t\t\t: items(queryable), count(pCount)\n\t\t\t{}\n\t\t\tclass Enumerator\n\t\t\t{\n\t\t\tprivate:\n\t\t\t\tTEnumerator ptr;\n\t\t\t\tTEnumerator end;\n\t\t\tpublic:\n\t\t\t\tEnumerator(const Enumerator &) = default;\n\t\t\t\tEnumerator(TEnumerator pptr, TEnumerator pend)\n\t\t\t\t\t: ptr(pptr), end(pend)\n\t\t\t\t{\n\t\t\t\t}\n\t\t\t\tT operator *() const\n\t\t\t\t{\n\t\t\t\t\treturn *(ptr);\n\t\t\t\t}\n\t\t\t\tEnumerator& operator ++()\n\t\t\t\t{\n\t\t\t\t\t++ptr;\n\t\t\t\t\treturn *this;\n\t\t\t\t}\n\t\t\t\tEnumerator operator ++(int)\n\t\t\t\t{\n\t\t\t\t\tEnumerator rs = *this;\n\t\t\t\t\t++ptr;\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tbool operator != (const Enumerator & iter) const\n\t\t\t\t{\n\t\t\t\t\treturn ptr != iter.ptr;\n\t\t\t\t}\n\t\t\t\tbool operator == (const Enumerator & iter) const\n\t\t\t\t{\n\t\t\t\t\treturn ptr == iter.ptr;\n\t\t\t\t}\n\t\t\t};\n\t\t\tEnumerator begin() const\n\t\t\t{\n\t\t\t\tauto ptr = items.begin();\n\t\t\t\tauto end = items.end();\n\t\t\t\tfor (int i = 0; i < count; i++)\n\t\t\t\t\tif (ptr != end)\n\t\t\t\t\t\t++ptr;\n\t\t\t\treturn Enumerator(ptr, end);\n\t\t\t}\n\t\t\tEnumerator end() const\n\t\t\t{\n\t\t\t\treturn Enumerator(items.end(), items.end());\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename TQueryable, typename TEnumerator, typename T, typename TFunc>\n\t\tclass SelectQuery\n\t\t{\n\t\tprivate:\n\t\t\tTQueryable items;\n\t\t\tTFunc func;\n\t\tpublic:\n\t\t\tSelectQuery(const TQueryable & queryable, const TFunc & f)\n\t\t\t\t: items(queryable), func(f)\n\t\t\t{}\n\t\t\tclass Enumerator\n\t\t\t{\n\t\t\tprivate:\n\t\t\t\tTEnumerator ptr;\n\t\t\t\tTEnumerator end;\n\t\t\t\tconst TFunc * func;\n\t\t\tpublic:\n\t\t\t\tEnumerator(const Enumerator &) = default;\n\t\t\t\tEnumerator(TEnumerator ptr, TEnumerator end, const TFunc & f)\n\t\t\t\t\t: ptr(ptr), end(end), func(&f)\n\t\t\t\t{}\n\t\t\t\tauto operator *() const -> decltype((*func)(*ptr))\n\t\t\t\t{\n\t\t\t\t\treturn (*func)(*ptr);\n\t\t\t\t}\n\t\t\t\tEnumerator& operator ++()\n\t\t\t\t{\n\t\t\t\t\t++ptr;\n\t\t\t\t\treturn *this;\n\t\t\t\t}\n\t\t\t\tEnumerator operator ++(int)\n\t\t\t\t{\n\t\t\t\t\tEnumerator rs = *this;\n\t\t\t\t\t++rs;\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tbool operator != (const Enumerator & iter) const\n\t\t\t\t{\n\t\t\t\t\treturn !(ptr == iter.ptr);\n\t\t\t\t}\n\t\t\t\tbool operator == (const Enumerator & iter) const\n\t\t\t\t{\n\t\t\t\t\treturn ptr == iter.ptr;\n\t\t\t\t}\n\t\t\t};\n\t\t\tEnumerator begin() const\n\t\t\t{\n\t\t\t\treturn Enumerator(items.begin(), items.end(), func);\n\t\t\t}\n\t\t\tEnumerator end() const\n\t\t\t{\n\t\t\t\treturn Enumerator(items.end(), items.end(), func);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename TQueryable, typename TEnumerator, typename T, typename TFunc>\n\t\tclass SelectManyQuery\n\t\t{\n\t\tprivate:\n\t\t\tTQueryable items;\n\t\t\tTFunc func;\n\t\t\tSelectManyQuery()\n\t\t\t{}\n\t\tpublic:\n\t\t\tSelectManyQuery(const TQueryable & queryable, const TFunc & f)\n\t\t\t\t: items(queryable), func(f)\n\t\t\t{}\n\t\t\ttemplate<typename TItems, typename TItemPtr>\n\t\t\tclass Enumerator\n\t\t\t{\n\t\t\tprivate:\n\t\t\t\tTEnumerator ptr;\n\t\t\t\tTEnumerator end;\n\t\t\t\tconst TFunc * func;\n\t\t\t\tTItems items;\n\t\t\t\tTItemPtr subPtr;\n\t\t\tpublic:\n\t\t\t\tEnumerator(const Enumerator &) = default;\n\t\t\t\tEnumerator(TEnumerator ptr, TEnumerator end, const TFunc & f)\n\t\t\t\t\t: ptr(ptr), end(end), func(&f)\n\t\t\t\t{\n\t\t\t\t\tif (ptr != end)\n\t\t\t\t\t{\n\t\t\t\t\t\titems = f(*ptr);\n\t\t\t\t\t\tsubPtr = items.begin();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tauto operator *() const -> decltype(*subPtr)\n\t\t\t\t{\n\t\t\t\t\treturn *subPtr;\n\t\t\t\t}\n\t\t\t\tEnumerator& operator ++()\n\t\t\t\t{\n\t\t\t\t\t++subPtr;\n\t\t\t\t\twhile (subPtr == items.end() && ptr != end)\n\t\t\t\t\t{\n\t\t\t\t\t\t++ptr;\n\t\t\t\t\t\tif (ptr != end)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\titems = (*func)(*ptr);\n\t\t\t\t\t\t\tsubPtr = items.begin();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn *this;\n\t\t\t\t}\n\t\t\t\tEnumerator operator ++(int)\n\t\t\t\t{\n\t\t\t\t\tEnumerator rs = *this;\n\t\t\t\t\t++rs;\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tbool operator != (const Enumerator & iter) const\n\t\t\t\t{\n\t\t\t\t\treturn !operator==(iter);\n\t\t\t\t}\n\t\t\t\tbool operator == (const Enumerator & iter) const\n\t\t\t\t{\n\t\t\t\t\tif (ptr == iter.ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ptr == end)\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn subPtr == iter.subPtr;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t};\n\t\t\tauto begin() const ->Enumerator<decltype(func(ConstructT<T>())), decltype(func(ConstructT<T>()).begin())>\n\t\t\t{\n\t\t\t\treturn Enumerator<decltype(func(ConstructT<T>())), decltype(func(ConstructT<T>()).begin())>(items.begin(), items.end(), func);\n\t\t\t}\n\t\t\tauto end() const ->Enumerator<decltype(func(ConstructT<T>())), decltype(func(ConstructT<T>()).begin())>\n\t\t\t{\n\t\t\t\treturn Enumerator<decltype(func(ConstructT<T>())), decltype(func(ConstructT<T>()).begin())>(items.end(), items.end(), func);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct EnumeratorType\n\t\t{\n\t\t\ttypedef decltype(ConstructT<T>().begin()) Type;\n\t\t};\n\n\t\ttemplate <typename TFunc, typename TArg>\n\t\tclass ExtractReturnType\n\t\t{\n\t\tpublic:\n\t\t\tstatic TFunc * f;\n\t\t\tstatic TArg ConstructArg() {};\n\t\t\ttypedef decltype((*f)(ConstructArg())) ReturnType;\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tclass ExtractItemType\n\t\t{\n\t\tpublic:\n\t\t\ttypedef typename RemovePointer<decltype(ConstructT<T>().begin())>::Type Type;\n\t\t};\n\n\t\ttemplate <typename TQueryable, typename TEnumerator, typename T>\n\t\tclass Queryable\n\t\t{\n\t\tprivate:\n\t\t\tTQueryable items;\n\t\tpublic:\n\t\t\tauto begin() const -> decltype(items.begin())\n\t\t\t{\n\t\t\t\treturn items.begin();\n\t\t\t}\n\t\t\tauto end() const -> decltype(items.end())\n\t\t\t{\n\t\t\t\treturn items.end();\n\t\t\t}\n\t\tpublic:\n\t\t\tconst TQueryable & GetItems() const\n\t\t\t{\n\t\t\t\treturn items;\n\t\t\t}\n\t\t\tQueryable(const TQueryable & items)\n\t\t\t\t: items(items)\n\t\t\t{}\n\n\t\t\tQueryable<SkipQuery<TQueryable, TEnumerator, T>, typename SkipQuery<TQueryable, TEnumerator, T>::Enumerator, T> Skip(int count) const\n\t\t\t{\n\t\t\t\treturn Queryable<SkipQuery<TQueryable, TEnumerator, T>, typename SkipQuery<TQueryable, TEnumerator, T>::Enumerator, T>(SkipQuery<TQueryable, TEnumerator, T>(items, count));\n\t\t\t}\n\n\t\t\ttemplate<typename TQueryable2, typename TEnumerator2>\n\t\t\tQueryable<ConcatQuery<TQueryable, TEnumerator, TQueryable2, TEnumerator2, T>, typename ConcatQuery<TQueryable, TEnumerator, TQueryable2, TEnumerator2, T>::Enumerator, T> Concat(const Queryable<TQueryable2, TEnumerator2, T> & other) const\n\t\t\t{\n\t\t\t\treturn Queryable<ConcatQuery<TQueryable, TEnumerator, TQueryable2, TEnumerator2, T>, typename ConcatQuery<TQueryable, TEnumerator, TQueryable2, TEnumerator2, T>::Enumerator, T>(ConcatQuery<TQueryable, TEnumerator, TQueryable2, TEnumerator2, T>(this->items, other.GetItems()));\n\t\t\t}\n\n\t\t\ttemplate<typename TFunc>\n\t\t\tQueryable<WhereQuery<TQueryable, TEnumerator, T, TFunc>, typename WhereQuery<TQueryable, TEnumerator, T, TFunc>::Enumerator, T> Where(const TFunc & f) const\n\t\t\t{\n\t\t\t\treturn Queryable<WhereQuery<TQueryable, TEnumerator, T, TFunc>, typename WhereQuery<TQueryable, TEnumerator, T, TFunc>::Enumerator, T>(WhereQuery<TQueryable, TEnumerator, T, TFunc>(items, f));\n\t\t\t}\n\n\t\t\ttemplate<typename TFunc>\n\t\t\tQueryable<SelectQuery<TQueryable, TEnumerator, T, TFunc>, typename SelectQuery<TQueryable, TEnumerator, T, TFunc>::Enumerator, typename RemoveReference<typename ExtractReturnType<TFunc, T>::ReturnType>::Type> Select(const TFunc & f) const\n\t\t\t{\n\t\t\t\treturn Queryable<SelectQuery<TQueryable, TEnumerator, T, TFunc>, typename SelectQuery<TQueryable, TEnumerator, T, TFunc>::Enumerator, typename RemoveReference<typename ExtractReturnType<TFunc, T>::ReturnType>::Type>(SelectQuery<TQueryable, TEnumerator, T, TFunc>(items, f));\n\t\t\t}\n\n\t\t\ttemplate<typename TFunc>\n\t\t\tauto SelectMany(const TFunc & f) const ->Queryable<SelectManyQuery<TQueryable, TEnumerator, T, TFunc>, typename EnumeratorType<SelectManyQuery<TQueryable, TEnumerator, T, TFunc>>::Type, typename ExtractItemType<decltype(f(ConstructT<T>()))>::Type>\n\t\t\t{\n\t\t\t\treturn Queryable<SelectManyQuery<TQueryable, TEnumerator, T, TFunc>, typename EnumeratorType<SelectManyQuery<TQueryable, TEnumerator, T, TFunc>>::Type, typename ExtractItemType<decltype(f(ConstructT<T>()))>::Type>(SelectManyQuery<TQueryable, TEnumerator, T, TFunc>(items, f));\n\t\t\t}\n\n\t\t\ttemplate<typename TAggregateResult, typename TFunc>\n\t\t\tauto Aggregate(const TAggregateResult & initial, const TFunc & f) const -> decltype(f(initial, *items.begin()))\n\t\t\t{\n\t\t\t\tTAggregateResult rs = initial;\n\t\t\t\tfor (auto && x : items)\n\t\t\t\t\trs = f(rs, x);\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\ttemplate<typename TFunc>\n\t\t\tbool Any(const TFunc & condition) const\n\t\t\t{\n\t\t\t\tfor (auto && x : items)\n\t\t\t\t\tif (condition(x))\n\t\t\t\t\t\treturn true;\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttemplate<typename TFunc>\n\t\t\tT & First(const TFunc & condition) const\n\t\t\t{\n\t\t\t\tfor (auto && x : items)\n\t\t\t\t\tif (condition(x))\n\t\t\t\t\t\treturn x;\n\t\t\t}\n\n\t\t\ttemplate <typename TFunc>\n\t\t\tT Max(const TFunc & selector) const\n\t\t\t{\n\t\t\t\treturn Aggregate(*items.begin(), [&](const T & v0, const T & v1)\n\t\t\t\t{\n\t\t\t\t\treturn selector(v0) > selector(v1) ? v0 : v1;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\ttemplate <typename TFunc>\n\t\t\tT Min(const TFunc & selector) const\n\t\t\t{\n\t\t\t\treturn Aggregate(*items.begin(), [&](const T & v0, const T & v1)\n\t\t\t\t{\n\t\t\t\t\treturn selector(v0) < selector(v1) ? v0 : v1;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\ttemplate <typename TFunc>\n\t\t\tauto Sum(const TFunc & selector) const -> decltype(selector(ConstructT<T>()))\n\t\t\t{\n\t\t\t\tdecltype(selector(ConstructT<T>())) rs(0);\n\t\t\t\tfor (auto && x : items)\n\t\t\t\t\trs = rs + selector(x);\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tT Max() const\n\t\t\t{\n\t\t\t\treturn Aggregate(*items.begin(), [](const T & v0, const T & v1) {return v0 > v1 ? v0 : v1; });\n\t\t\t}\n\n\t\t\tT Min() const\n\t\t\t{\n\t\t\t\treturn Aggregate(*items.begin(), [](const T & v0, const T & v1) {return v0 < v1 ? v0 : v1; });\n\t\t\t}\n\n\t\t\tT Sum() const\n\t\t\t{\n\t\t\t\tT rs = T(0);\n\t\t\t\tfor (auto && x : items)\n\t\t\t\t\trs = rs + x;\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tT Avg() const\n\t\t\t{\n\t\t\t\tT rs = T(0);\n\t\t\t\tint count = 0;\n\t\t\t\tfor (auto && x : items)\n\t\t\t\t{\n\t\t\t\t\trs = rs + x;\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t\treturn rs / count;\n\t\t\t}\n\n\t\t\tint Count() const\n\t\t\t{\n\t\t\t\tint rs = 0;\n\t\t\t\tfor (auto && x : items)\n\t\t\t\t\trs++;\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tList<T> ToList() const\n\t\t\t{\n\t\t\t\tList<T> rs;\n\t\t\t\tfor (auto && val : items)\n\t\t\t\t\trs.Add(val);\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t};\n\n\n\t\ttemplate<typename T, typename TAllocator>\n\t\tinline Queryable<ArrayView<T>, T*, T> From(const List<T, TAllocator> & list)\n\t\t{\n\t\t\treturn Queryable<ArrayView<T>, T*, T>(list.GetArrayView());\n\t\t}\n\n\t\ttemplate<typename T, typename TAllocator>\n\t\tinline Queryable<List<T, TAllocator>, T*, T> From(List<T, TAllocator> && list)\n\t\t{\n\t\t\treturn Queryable<List<T, TAllocator>, T*, T>(_Move(list));\n\t\t}\n\n\t\ttemplate<typename T>\n\t\tinline Queryable<ArrayView<T>, T*, T> From(const ArrayView<T> & list)\n\t\t{\n\t\t\treturn Queryable<ArrayView<T>, T*, T>(list);\n\t\t}\n\n\t\ttemplate<typename T, int count>\n\t\tinline Queryable<Array<T, count>, T*, T> From(const Array<T, count> & list)\n\t\t{\n\t\t\treturn Queryable<Array<T, count>, T*, T>(list);\n\t\t}\n\n\t\ttemplate<typename T>\n\t\tinline auto From(const T & list) -> Queryable<T, decltype(list.begin()), decltype(*list.begin())>\n\t\t{\n\t\t\treturn Queryable<T, decltype(list.begin()), decltype(*list.begin())>(list);\n\t\t}\n\n\t\ttemplate<typename T>\n\t\tinline Queryable<Array<T, 1>, T*, T> FromSingle(const T & obj)\n\t\t{\n\t\t\tArray<T, 1> arr;\n\t\t\tarr.Add(obj);\n\t\t\treturn From(arr);\n\t\t}\n\n\t\ttemplate<typename T>\n\t\tstruct LinkedListView\n\t\t{\n\t\t\ttypename LinkedList<T>::Iterator start, last;\n\t\t\ttypename LinkedList<T>::Iterator begin() const\n\t\t\t{\n\t\t\t\treturn start;\n\t\t\t}\n\t\t\ttypename LinkedList<T>::Iterator end() const\n\t\t\t{\n\t\t\t\treturn last;\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename T>\n\t\tinline Queryable<LinkedListView<T>, LinkedNode<T>, T> From(const LinkedList<T> & list)\n\t\t{\n\t\t\tLinkedListView<T> view;\n\t\t\tview.start = list.begin();\n\t\t\tview.last = list.end();\n\t\t\treturn Queryable<LinkedListView<T>, LinkedNode<T>, T>(view);\n\t\t}\n\n\t\ttemplate<typename TKey, typename TValue>\n\t\tstruct EnumerableDictView\n\t\t{\n\t\t\ttypename EnumerableDictionary<TKey, TValue>::Iterator start, last;\n\t\t\ttypename EnumerableDictionary<TKey, TValue>::Iterator begin() const\n\t\t\t{\n\t\t\t\treturn start;\n\t\t\t}\n\t\t\ttypename EnumerableDictionary<TKey, TValue>::Iterator end() const\n\t\t\t{\n\t\t\t\treturn last;\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename TKey, typename TValue>\n\t\tinline Queryable<EnumerableDictView<TKey, TValue>, typename EnumerableDictionary<TKey, TValue>::Iterator, KeyValuePair<TKey, TValue>> From(const EnumerableDictionary<TKey, TValue> & dict)\n\t\t{\n\t\t\tEnumerableDictView<TKey, TValue> view;\n\t\t\tview.start = dict.begin();\n\t\t\tview.last = dict.end();\n\t\t\treturn Queryable<EnumerableDictView<TKey, TValue>, typename EnumerableDictionary<TKey, TValue>::Iterator, KeyValuePair<TKey, TValue>>(view);\n\t\t}\n\n\t\ttemplate<typename TKey>\n\t\tstruct EnumerableHashSetView\n\t\t{\n\t\t\ttypename HashSetBase<TKey, EnumerableDictionary<TKey, _DummyClass>>::Iterator start, last;\n\t\t\ttypename EnumerableHashSet<TKey>::Iterator begin() const\n\t\t\t{\n\t\t\t\treturn start;\n\t\t\t}\n\t\t\ttypename EnumerableHashSet<TKey>::Iterator end() const\n\t\t\t{\n\t\t\t\treturn last;\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename TKey>\n\t\tinline Queryable<EnumerableHashSetView<TKey>, typename HashSetBase<TKey, EnumerableDictionary<TKey, _DummyClass>>::Iterator, TKey> From(const EnumerableHashSet<TKey> & dict)\n\t\t{\n\t\t\tEnumerableHashSetView<TKey> view;\n\t\t\tview.start = dict.begin();\n\t\t\tview.last = dict.end();\n\t\t\treturn Queryable<EnumerableHashSetView<TKey>, typename HashSetBase<TKey, EnumerableDictionary<TKey, _DummyClass>>::Iterator, TKey>(view);\n\t\t}\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/CoreLib/List.h",
    "content": "#ifndef FUNDAMENTAL_LIB_LIST_H\n#define FUNDAMENTAL_LIB_LIST_H\n\n#include \"Allocator.h\"\n#include <type_traits>\n#include \"LibMath.h\"\n#include <new>\n#include \"ArrayView.h\"\n#include <algorithm>\n\nconst int MIN_QSORT_SIZE = 32;\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\ttemplate<typename T, int isPOD>\n\t\tclass Initializer\n\t\t{\n\n\t\t};\n\n\t\ttemplate<typename T>\n\t\tclass Initializer<T, 0>\n\t\t{\n\t\tpublic:\n\t\t\tstatic void Initialize(T * buffer, int size)\n\t\t\t{\n\t\t\t\tfor (int i = 0; i<size; i++)\n\t\t\t\t\tnew (buffer + i) T();\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename T, typename TAllocator>\n\t\tclass AllocateMethod\n\t\t{\n\t\tpublic:\n\t\t\tstatic inline T* Alloc(int size)\n\t\t\t{\n\t\t\t\tTAllocator allocator;\n\t\t\t\tT * rs = (T*)allocator.Alloc(size*sizeof(T));\n\t\t\t\tInitializer<T, std::is_pod<T>::value>::Initialize(rs, size);\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tstatic inline void Free(T * ptr, int bufferSize)\n\t\t\t{\n\t\t\t\tTAllocator allocator;\n\t\t\t\tif (!std::is_trivially_destructible<T>::value)\n\t\t\t\t{\n\t\t\t\t\tfor (int i = 0; i<bufferSize; i++)\n\t\t\t\t\t\tptr[i].~T();\n\t\t\t\t}\n\t\t\t\tallocator.Free(ptr);\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename T>\n\t\tclass AllocateMethod<T, StandardAllocator>\n\t\t{\n\t\tpublic:\n\t\t\tstatic inline T* Alloc(int size)\n\t\t\t{\n\t\t\t\treturn new T[size];\n\t\t\t}\n\t\t\tstatic inline void Free(T* ptr, int /*bufferSize*/)\n\t\t\t{\n\t\t\t\tdelete [] ptr;\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename T>\n\t\tclass Initializer<T, 1>\n\t\t{\n\t\tpublic:\n\t\t\tstatic void Initialize(T * buffer, int size)\n\t\t\t{\n\t\t\t\tfor (int i = 0; i<size; i++)\n\t\t\t\t\tnew (buffer + i) T;\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename T, typename TAllocator = StandardAllocator>\n\t\tclass List\n\t\t{\n\t\tprivate:\n\n\t\t\tinline T * Allocate(int size)\n\t\t\t{\n\t\t\t\treturn AllocateMethod<T, TAllocator>::Alloc(size);\n\t\t\t\t\n\t\t\t}\n\t\tprivate:\n\t\t\tstatic const int InitialSize = 16;\n\t\t\tTAllocator allocator;\n\t\tprivate:\n\t\t\tT * buffer;\n\t\t\tint _count;\n\t\t\tint bufferSize;\n\t\t\tvoid FreeBuffer()\n\t\t\t{\n\t\t\t\tAllocateMethod<T, TAllocator>::Free(buffer, bufferSize);\n\t\t\t\tbuffer = 0;\n\t\t\t}\n\t\t\tvoid Free()\n\t\t\t{\n\t\t\t\tif (buffer)\n\t\t\t\t{\n\t\t\t\t\tFreeBuffer();\n\t\t\t\t}\n\t\t\t\tbuffer = 0;\n\t\t\t\t_count = bufferSize = 0;\n\t\t\t}\n\t\tpublic:\n\t\t\tT* begin() const\n\t\t\t{\n\t\t\t\treturn buffer;\n\t\t\t}\n\t\t\tT* end() const\n\t\t\t{\n\t\t\t\treturn buffer+_count;\n\t\t\t}\n\t\tprivate:\n\t\t\ttemplate<typename... Args>\n\t\t\tvoid Init(const T & val, Args... args)\n\t\t\t{\n\t\t\t\tAdd(val);\n\t\t\t\tInit(args...);\n\t\t\t}\n\t\tpublic:\n\t\t\tList()\n\t\t\t\t: buffer(0), _count(0), bufferSize(0)\n\t\t\t{\n\t\t\t}\n\t\t\ttemplate<typename... Args>\n\t\t\tList(const T & val, Args... args)\n\t\t\t{\n\t\t\t\tInit(val, args...);\n\t\t\t}\n\t\t\tList(const List<T> & list)\n\t\t\t\t: buffer(0), _count(0), bufferSize(0)\n\t\t\t{\n\t\t\t\tthis->operator=(list);\n\t\t\t}\n\t\t\tList(List<T> && list)\n\t\t\t\t: buffer(0), _count(0), bufferSize(0)\n\t\t\t{\n\t\t\t\tthis->operator=(static_cast<List<T>&&>(list));\n\t\t\t}\n\t\t\tstatic List<T> Create(const T & val, int count)\n\t\t\t{\n\t\t\t\tList<T> rs;\n\t\t\t\trs.SetSize(count);\n\t\t\t\tfor (int i = 0; i < count; i++)\n\t\t\t\t\trs[i] = val;\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\t~List()\n\t\t\t{\n\t\t\t\tFree();\n\t\t\t}\n\t\t\tList<T> & operator=(const List<T> & list)\n\t\t\t{\n\t\t\t\tFree();\n\t\t\t\tAddRange(list);\n\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tList<T> & operator=(List<T> && list)\n\t\t\t{\n\t\t\t\tFree();\n\t\t\t\t_count = list._count;\n\t\t\t\tbufferSize = list.bufferSize;\n\t\t\t\tbuffer = list.buffer;\n\n\t\t\t\tlist.buffer = 0;\n\t\t\t\tlist._count = 0;\n\t\t\t\tlist.bufferSize = 0;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tT & First() const\n\t\t\t{\n#ifdef _DEBUG\n\t\t\t\tif (_count == 0)\n\t\t\t\t\tthrow \"Index out of range.\";\n#endif\n\t\t\t\treturn buffer[0];\n\t\t\t}\n\n\t\t\tT & Last() const\n\t\t\t{\n#ifdef _DEBUG\n\t\t\t\tif (_count == 0)\n\t\t\t\t\tthrow \"Index out of range.\";\n#endif\n\t\t\t\treturn buffer[_count-1];\n\t\t\t}\n\n\t\t\tinline void SwapWith(List<T, TAllocator> & other)\n\t\t\t{\n\t\t\t\tT* tmpBuffer = this->buffer;\n\t\t\t\tthis->buffer = other.buffer;\n\t\t\t\tother.buffer = tmpBuffer;\n\t\t\t\tint tmpBufferSize = this->bufferSize;\n\t\t\t\tthis->bufferSize = other.bufferSize;\n\t\t\t\tother.bufferSize = tmpBufferSize;\n\t\t\t\tint tmpCount = this->_count;\n\t\t\t\tthis->_count = other._count;\n\t\t\t\tother._count = tmpCount;\n\t\t\t\tTAllocator tmpAlloc = _Move(this->allocator);\n\t\t\t\tthis->allocator = _Move(other.allocator);\n\t\t\t\tother.allocator = _Move(tmpAlloc);\n\t\t\t}\n\n\t\t\tT* ReleaseBuffer()\n\t\t\t{\n\t\t\t\tT* rs = buffer;\n\t\t\t\tbuffer = nullptr;\n\t\t\t\t_count = 0;\n\t\t\t\tbufferSize = 0;\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tinline ArrayView<T> GetArrayView() const\n\t\t\t{\n\t\t\t\treturn ArrayView<T>(buffer, _count);\n\t\t\t}\n\n\t\t\tinline ArrayView<T> GetArrayView(int start, int count) const\n\t\t\t{\n#ifdef _DEBUG\n\t\t\t\tif (start + count > _count || start < 0 || count < 0)\n\t\t\t\t\tthrow \"Index out of range.\";\n#endif\n\t\t\t\treturn ArrayView<T>(buffer + start, count);\n\t\t\t}\n\n\t\t\tvoid Add(T && obj)\n\t\t\t{\n\t\t\t\tif (bufferSize < _count + 1)\n\t\t\t\t{\n\t\t\t\t\tint newBufferSize = InitialSize;\n\t\t\t\t\tif (bufferSize)\n\t\t\t\t\t\tnewBufferSize = (bufferSize << 1);\n\n\t\t\t\t\tReserve(newBufferSize);\n\t\t\t\t}\n\t\t\t\tbuffer[_count++] = static_cast<T&&>(obj);\n\t\t\t}\n\n\t\t\tvoid Add(const T & obj)\n\t\t\t{\n\t\t\t\tif (bufferSize < _count + 1)\n\t\t\t\t{\n\t\t\t\t\tint newBufferSize = InitialSize;\n\t\t\t\t\tif (bufferSize)\n\t\t\t\t\t\tnewBufferSize = (bufferSize << 1);\n\n\t\t\t\t\tReserve(newBufferSize);\n\t\t\t\t}\n\t\t\t\tbuffer[_count++] = obj;\n\n\t\t\t}\n\n\t\t\tint Count() const\n\t\t\t{\n\t\t\t\treturn _count;\n\t\t\t}\n\n\t\t\tT * Buffer() const\n\t\t\t{\n\t\t\t\treturn buffer;\n\t\t\t}\n\n\t\t\tint Capacity() const\n\t\t\t{\n\t\t\t\treturn bufferSize;\n\t\t\t}\n\n\t\t\tvoid Insert(int id, const T & val)\n\t\t\t{\n\t\t\t\tInsertRange(id, &val, 1);\n\t\t\t}\n\n\t\t\tvoid InsertRange(int id, const T * vals, int n)\n\t\t\t{\n\t\t\t\tif (bufferSize < _count + n)\n\t\t\t\t{\n\t\t\t\t\tint newBufferSize = InitialSize;\n\t\t\t\t\twhile (newBufferSize < _count + n)\n\t\t\t\t\t\tnewBufferSize = newBufferSize << 1;\n\n\t\t\t\t\tT * newBuffer = Allocate(newBufferSize);\n\t\t\t\t\tif (bufferSize)\n\t\t\t\t\t{\n\t\t\t\t\t\t/*if (std::has_trivial_copy_assign<T>::value && std::has_trivial_destructor<T>::value)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmemcpy(newBuffer, buffer, sizeof(T) * id);\n\t\t\t\t\t\t\tmemcpy(newBuffer + id + n, buffer + id, sizeof(T) * (_count - id));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse*/\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (int i = 0; i < id; i++)\n\t\t\t\t\t\t\t\tnewBuffer[i] = buffer[i];\n\t\t\t\t\t\t\tfor (int i = id; i < _count; i++)\n\t\t\t\t\t\t\t\tnewBuffer[i + n] = T(static_cast<T&&>(buffer[i]));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tFreeBuffer();\n\t\t\t\t\t}\n\t\t\t\t\tbuffer = newBuffer;\n\t\t\t\t\tbufferSize = newBufferSize;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t/*if (std::has_trivial_copy_assign<T>::value && std::has_trivial_destructor<T>::value)\n\t\t\t\t\t\tmemmove(buffer + id + n, buffer + id, sizeof(T) * (_count - id));\n\t\t\t\t\telse*/\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int i = _count - 1; i >= id; i--)\n\t\t\t\t\t\t\tbuffer[i + n] = static_cast<T&&>(buffer[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t/*if (std::has_trivial_copy_assign<T>::value && std::has_trivial_destructor<T>::value)\n\t\t\t\t\tmemcpy(buffer + id, vals, sizeof(T) * n);\n\t\t\t\telse*/\n\t\t\t\t\tfor (int i = 0; i < n; i++)\n\t\t\t\t\t\tbuffer[id + i] = vals[i];\n\n\t\t\t\t_count += n;\n\t\t\t}\n\n\t\t\t//slower than original edition\n\t\t\t//void Add(const T & val)\n\t\t\t//{\n\t\t\t//\tInsertRange(_count, &val, 1);\n\t\t\t//}\n\n\t\t\tvoid InsertRange(int id, const List<T> & list)\n\t\t\t{\n\t\t\t\tInsertRange(id, list.buffer, list._count);\n\t\t\t}\n\n\t\t\tvoid AddRange(ArrayView<T> list)\n\t\t\t{\n\t\t\t\tInsertRange(_count, list.Buffer(), list.Count());\n\t\t\t}\n\n\t\t\tvoid AddRange(const T * vals, int n)\n\t\t\t{\n\t\t\t\tInsertRange(_count, vals, n);\n\t\t\t}\n\n\t\t\tvoid AddRange(const List<T> & list)\n\t\t\t{\n\t\t\t\tInsertRange(_count, list.buffer, list._count);\n\t\t\t}\n\n\t\t\tvoid RemoveRange(int id, int deleteCount)\n\t\t\t{\n#if _DEBUG\n\t\t\t\tif (id >= _count || id < 0)\n\t\t\t\t\tthrow \"Remove: Index out of range.\";\n\t\t\t\tif(deleteCount < 0)\n\t\t\t\t\tthrow \"Remove: deleteCount smaller than zero.\";\n#endif\n\t\t\t\tint actualDeleteCount = ((id + deleteCount) >= _count)? (_count - id) : deleteCount;\n\t\t\t\tfor (int i = id + actualDeleteCount; i < _count; i++)\n\t\t\t\t\tbuffer[i - actualDeleteCount] = static_cast<T&&>(buffer[i]);\n\t\t\t\t_count -= actualDeleteCount;\n\t\t\t}\n\n\t\t\tvoid RemoveAt(int id)\n\t\t\t{\n\t\t\t\tRemoveRange(id, 1);\n\t\t\t}\n\n\t\t\tvoid Remove(const T & val)\n\t\t\t{\n\t\t\t\tint idx = IndexOf(val);\n\t\t\t\tif (idx != -1)\n\t\t\t\t\tRemoveAt(idx);\n\t\t\t}\n\n\t\t\tvoid Reverse()\n\t\t\t{\n\t\t\t\tfor (int i = 0; i < (_count >> 1); i++)\n\t\t\t\t{\n\t\t\t\t\tSwap(buffer, i, _count - i - 1);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid FastRemove(const T & val)\n\t\t\t{\n\t\t\t\tint idx = IndexOf(val);\n\t\t\t\tFastRemoveAt(idx);\n\t\t\t}\n\n\t\t\tvoid FastRemoveAt(int idx)\n\t\t\t{\n\t\t\t\tif (idx != -1 && _count - 1 != idx)\n\t\t\t\t{\n\t\t\t\t\tbuffer[idx] = _Move(buffer[_count - 1]);\n\t\t\t\t}\n\t\t\t\t_count--;\n\t\t\t}\n\n\t\t\tvoid Clear()\n\t\t\t{\n\t\t\t\t_count = 0;\n\t\t\t}\n\n\t\t\tvoid Reserve(int size)\n\t\t\t{\n\t\t\t\tif(size > bufferSize)\n\t\t\t\t{\n\t\t\t\t\tT * newBuffer = Allocate(size);\n\t\t\t\t\tif (bufferSize)\n\t\t\t\t\t{\n\t\t\t\t\t\t/*if (std::has_trivial_copy_assign<T>::value && std::has_trivial_destructor<T>::value)\n\t\t\t\t\t\t\tmemcpy(newBuffer, buffer, _count * sizeof(T));\n\t\t\t\t\t\telse*/\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (int i = 0; i < _count; i++)\n\t\t\t\t\t\t\t\tnewBuffer[i] = static_cast<T&&>(buffer[i]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tFreeBuffer();\n\t\t\t\t\t}\n\t\t\t\t\tbuffer = newBuffer;\n\t\t\t\t\tbufferSize = size;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid GrowToSize(int size)\n\t\t\t{\n\t\t\t\tint newBufferSize = 1<<Math::Log2Ceil(size);\n\t\t\t\tif (bufferSize < newBufferSize)\n\t\t\t\t{\n\t\t\t\t\tReserve(newBufferSize);\n\t\t\t\t}\n\t\t\t\tthis->_count = size;\n\t\t\t}\n\n\t\t\tvoid SetSize(int size)\n\t\t\t{\n\t\t\t\tReserve(size);\n\t\t\t\t_count = size;\n\t\t\t}\n\n\t\t\tvoid UnsafeShrinkToSize(int size)\n\t\t\t{\n\t\t\t\t_count = size;\n\t\t\t}\n\n\t\t\tvoid Compress()\n\t\t\t{\n\t\t\t\tif (bufferSize > _count && _count > 0)\n\t\t\t\t{\n\t\t\t\t\tT * newBuffer = Allocate(_count);\n\t\t\t\t\tfor (int i = 0; i < _count; i++)\n\t\t\t\t\t\tnewBuffer[i] = static_cast<T&&>(buffer[i]);\n\t\t\t\t\tFreeBuffer();\n\t\t\t\t\tbuffer = newBuffer;\n\t\t\t\t\tbufferSize = _count;\n\t\t\t\t}\n\t\t\t}\n\n#ifndef FORCE_INLINE\n#ifdef _MSC_VER\n#define FORCE_INLINE __forceinline\n#else\n#define FORCE_INLINE inline\n#endif\n#endif\n\n\t\t\tFORCE_INLINE T & operator [](int id) const\n\t\t\t{\n#if _DEBUG\n\t\t\t\tif(id >= _count || id < 0)\n\t\t\t\t\tthrow IndexOutofRangeException(\"Operator[]: Index out of Range.\");\n#endif\n\t\t\t\treturn buffer[id];\n\t\t\t}\n\n\t\t\ttemplate<typename Func>\n\t\t\tint FindFirst(const Func & predicate) const\n\t\t\t{\n\t\t\t\tfor (int i = 0; i < _count; i++)\n\t\t\t\t{\n\t\t\t\t\tif (predicate(buffer[i]))\n\t\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\ttemplate<typename Func>\n\t\t\tint FindLast(const Func & predicate) const\n\t\t\t{\n\t\t\t\tfor (int i = _count - 1; i >= 0; i--)\n\t\t\t\t{\n\t\t\t\t\tif (predicate(buffer[i]))\n\t\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\ttemplate<typename T2>\n\t\t\tint IndexOf(const T2 & val) const\n\t\t\t{\n\t\t\t\tfor (int i = 0; i < _count; i++)\n\t\t\t\t{\n\t\t\t\t\tif (buffer[i] == val)\n\t\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\ttemplate<typename T2>\n\t\t\tint LastIndexOf(const T2 & val) const\n\t\t\t{\n\t\t\t\tfor (int i = _count - 1; i >= 0; i--)\n\t\t\t\t{\n\t\t\t\t\tif(buffer[i] == val)\n\t\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tvoid Sort()\n\t\t\t{\n\t\t\t\tSort([](T& t1, T& t2){return t1<t2;});\n\t\t\t}\n\n\t\t\tbool Contains(const T & val)\n\t\t\t{\n\t\t\t\tfor (int i = 0; i<_count; i++)\n\t\t\t\t\tif (buffer[i] == val)\n\t\t\t\t\t\treturn true;\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttemplate<typename Comparer>\n\t\t\tvoid Sort(Comparer compare)\n\t\t\t{\n\t\t\t\t//InsertionSort(buffer, 0, _count - 1);\n\t\t\t\t//QuickSort(buffer, 0, _count - 1, compare);\n\t\t\t\tstd::sort(buffer, buffer + _count, compare);\n\t\t\t}\n\n\t\t\ttemplate <typename IterateFunc>\n\t\t\tvoid ForEach(IterateFunc f) const\n\t\t\t{\n\t\t\t\tfor (int i = 0; i<_count; i++)\n\t\t\t\t\tf(buffer[i]);\n\t\t\t}\n\n\t\t\ttemplate<typename Comparer>\n\t\t\tvoid QuickSort(T * vals, int startIndex, int endIndex, Comparer comparer)\n\t\t\t{\n\t\t\t\tif(startIndex < endIndex)\n\t\t\t\t{\n\t\t\t\t\tif (endIndex - startIndex < MIN_QSORT_SIZE)\n\t\t\t\t\t\tInsertionSort(vals, startIndex, endIndex, comparer);\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tint pivotIndex = (startIndex + endIndex) >> 1;\n\t\t\t\t\t\tint pivotNewIndex = Partition(vals, startIndex, endIndex, pivotIndex, comparer);\n\t\t\t\t\t\tQuickSort(vals, startIndex, pivotNewIndex - 1, comparer);\n\t\t\t\t\t\tQuickSort(vals, pivotNewIndex + 1, endIndex, comparer);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t\ttemplate<typename Comparer>\n\t\t\tint Partition(T * vals, int left, int right, int pivotIndex, Comparer comparer)\n\t\t\t{\n\t\t\t\tT pivotValue = vals[pivotIndex];\n\t\t\t\tSwap(vals, right, pivotIndex);\n\t\t\t\tint storeIndex = left;\n\t\t\t\tfor (int i = left; i < right; i++)\n\t\t\t\t{\n\t\t\t\t\tif (comparer(vals[i], pivotValue))\n\t\t\t\t\t{\n\t\t\t\t\t\tSwap(vals, i, storeIndex);\n\t\t\t\t\t\tstoreIndex++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tSwap(vals, storeIndex, right);\n\t\t\t\treturn storeIndex;\n\t\t\t}\n\t\t\ttemplate<typename Comparer>\n\t\t\tvoid InsertionSort(T * vals, int startIndex, int endIndex, Comparer comparer)\n\t\t\t{\n\t\t\t\tfor (int i = startIndex  + 1; i <= endIndex; i++)\n\t\t\t\t{\n\t\t\t\t\tT insertValue = static_cast<T&&>(vals[i]);\n\t\t\t\t\tint insertIndex = i - 1;\n\t\t\t\t\twhile (insertIndex >= startIndex && comparer(insertValue, vals[insertIndex]))\n\t\t\t\t\t{\n\t\t\t\t\t\tvals[insertIndex + 1] = static_cast<T&&>(vals[insertIndex]);\n\t\t\t\t\t\tinsertIndex--;\n\t\t\t\t\t}\n\t\t\t\t\tvals[insertIndex + 1] = static_cast<T&&>(insertValue);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tinline void Swap(T * vals, int index1, int index2)\n\t\t\t{\n\t\t\t\tif (index1 != index2)\n\t\t\t\t{\n\t\t\t\t\tT tmp = static_cast<T&&>(vals[index1]);\n\t\t\t\t\tvals[index1] = static_cast<T&&>(vals[index2]);\n\t\t\t\t\tvals[index2] = static_cast<T&&>(tmp);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate<typename T2, typename Comparer>\n\t\t\tint BinarySearch(const T2 & obj, Comparer comparer)\n\t\t\t{\n\t\t\t\tint imin = 0, imax = _count - 1;\n\t\t\t\twhile (imax >= imin)\n\t\t\t\t{\n\t\t\t\t\tint imid = (imin + imax) >> 1;\n\t\t\t\t\tint compareResult = comparer(buffer[imid], obj);\n\t\t\t\t\tif (compareResult == 0)\n\t\t\t\t\t\treturn imid;\n\t\t\t\t\telse if (compareResult < 0)\n\t\t\t\t\t\timin = imid + 1;\n\t\t\t\t\telse\n\t\t\t\t\t\timax = imid - 1;\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\ttemplate<typename T2>\n\t\t\tint BinarySearch(const T2 & obj)\n\t\t\t{\n\t\t\t\treturn BinarySearch(obj, \n\t\t\t\t\t[](T & curObj, const T2 & thatObj)->int\n\t\t\t\t\t{\n\t\t\t\t\t\tif (curObj < thatObj)\n\t\t\t\t\t\t\treturn -1;\n\t\t\t\t\t\telse if (curObj == thatObj)\n\t\t\t\t\t\t\treturn 0;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn 1;\n\t\t\t\t\t});\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename T>\n\t\tT Min(const List<T> & list)\n\t\t{\n\t\t\tT minVal = list.First();\n\t\t\tfor (int i = 1; i<list.Count(); i++)\n\t\t\t\tif (list[i] < minVal)\n\t\t\t\t\tminVal = list[i];\n\t\t\treturn minVal;\n\t\t}\n\n\t\ttemplate<typename T>\n\t\tT Max(const List<T> & list)\n\t\t{\n\t\t\tT maxVal = list.First();\n\t\t\tfor (int i = 1; i<list.Count(); i++)\n\t\t\t\tif (list[i] > maxVal)\n\t\t\t\t\tmaxVal = list[i];\n\t\t\treturn maxVal;\n\t\t}\n\t}\n}\n\n#endif\n"
  },
  {
    "path": "Source/CoreLib/MemoryPool.cpp",
    "content": "#include \"MemoryPool.h\"\n#include <cassert>\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\tMemoryPool::MemoryPool(unsigned char * pBuffer, int pLog2BlockSize, int numBlocks)\n\t\t{\n\t\t\tInit(pBuffer, pLog2BlockSize, numBlocks);\n\t\t}\n\t\tvoid MemoryPool::Init(unsigned char * pBuffer, int pLog2BlockSize, int numBlocks)\n\t\t{\n\t\t\tassert(pLog2BlockSize >= 1 && pLog2BlockSize <= 30);\n\t\t\tassert(numBlocks >= 4);\n\t\t\tbuffer = pBuffer;\n\t\t\tblockSize = 1 << pLog2BlockSize;\n\t\t\tlog2BlockSize = pLog2BlockSize;\n\t\t\tnumLevels = Math::Log2Floor(numBlocks);\n\t\t\tfreeList[0] = (FreeListNode*)buffer;\n\t\t\tfreeList[0]->NextPtr = nullptr;\n\t\t\tfreeList[0]->PrevPtr = nullptr;\n\t\t\tused.SetMax(1 << (numLevels));\n\t\t\tfor (int i = 1; i < MaxLevels; i++)\n\t\t\t{\n\t\t\t\tfreeList[i] = nullptr;\n\t\t\t}\n\t\t}\n\t\tint MemoryPool::AllocBlock(int level)\n\t\t{\n\t\t\tif (level < 0)\n\t\t\t\treturn -1;\n\t\t\tif (freeList[level] == nullptr)\n\t\t\t{\n\t\t\t\tauto largeBlockAddr = AllocBlock(level - 1);\n\t\t\t\tif (largeBlockAddr != -1)\n\t\t\t\t{\n\t\t\t\t\tauto block1 = (FreeListNode*)(buffer + ((largeBlockAddr ^ (1 << (numLevels - level))) << log2BlockSize));\n\t\t\t\t\tblock1->NextPtr = nullptr;\n\t\t\t\t\tblock1->PrevPtr = nullptr;\n\t\t\t\t\tfreeList[level] = block1;\n\n\t\t\t\t\tint blockIndex = (1 << level) + (largeBlockAddr >> (numLevels-level)) - 1;\n\t\t\t\t\tused.Add(blockIndex);\n\t\t\t\t\treturn largeBlockAddr;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\treturn -1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tauto node = freeList[level];\n\t\t\t\tif (node->NextPtr)\n\t\t\t\t{\n\t\t\t\t\tnode->NextPtr->PrevPtr = node->PrevPtr;\n\t\t\t\t}\n\t\t\t\tfreeList[level] = freeList[level]->NextPtr;\n\t\t\t\tint rs = (int)((unsigned char *)node - buffer) >> log2BlockSize;\n\t\t\t\tint blockIndex = (1 << level) + (rs >> (numLevels - level)) - 1;\n\t\t\t\tused.Add(blockIndex);\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t}\n\t\tunsigned char * MemoryPool::Alloc(int size)\n\t\t{\n\t\t\tif (size == 0)\n\t\t\t\treturn nullptr;\n\t\t\tint originalSize = size;\n\t\t\tif (size < blockSize)\n\t\t\t\tsize = blockSize;\n\t\t\tint order = numLevels - (Math::Log2Ceil(size) - log2BlockSize);\n\t\t\tassert(order >= 0 && order < MaxLevels);\n\n\t\t\tbytesAllocated += (1 << ((numLevels-order) + log2BlockSize));\n\t\t\tbytesWasted += (1 << ((numLevels - order) + log2BlockSize)) - originalSize;\n\n\t\t\tint blockId = AllocBlock(order);\n\t\t\tif (blockId != -1)\n\t\t\t\treturn buffer + (blockId << log2BlockSize);\n\t\t\telse\n\t\t\t\treturn nullptr;\n\t\t}\n\t\tvoid MemoryPool::FreeBlock(unsigned char * ptr, int level)\n\t\t{\n\t\t\tint indexInLevel = (int)(ptr - buffer) >> (numLevels - level + log2BlockSize);\n\t\t\tint blockIndex = (1 << level) + indexInLevel - 1;\n\t\t\tassert(used.Contains(blockIndex));\n\t\t\tint buddyIndex = (blockIndex & 1) ? blockIndex + 1 : blockIndex - 1;\n\t\t\tused.Remove(blockIndex);\n\t\t\tif (level > 0 && !used.Contains(buddyIndex))\n\t\t\t{\n\t\t\t\tauto buddyPtr = (FreeListNode *)(buffer + ((((int)(ptr - buffer) >> log2BlockSize) ^ (1 << (numLevels - level))) << log2BlockSize));\n\t\t\t\tif (buddyPtr->PrevPtr)\n\t\t\t\t{\n\t\t\t\t\tbuddyPtr->PrevPtr->NextPtr = buddyPtr->NextPtr;\n\t\t\t\t}\n\t\t\t\tif (buddyPtr->NextPtr)\n\t\t\t\t{\n\t\t\t\t\tbuddyPtr->NextPtr->PrevPtr = buddyPtr->PrevPtr;\n\t\t\t\t}\n\t\t\t\tif (freeList[level] == buddyPtr)\n\t\t\t\t{\n\t\t\t\t\tfreeList[level] = buddyPtr->NextPtr;\n\t\t\t\t}\n\t\t\t\t// recursively free parent blocks\n\t\t\t\tauto parentPtr = Math::Min(buddyPtr, (FreeListNode*)ptr);\n\t\t\t\tif (level > 0)\n\t\t\t\t\tFreeBlock((unsigned char*)parentPtr, level - 1);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// insert to freelist\n\t\t\t\tauto freeNode = (FreeListNode *)ptr;\n\t\t\t\tfreeNode->NextPtr = freeList[level];\n\t\t\t\tfreeNode->PrevPtr = nullptr;\n\t\t\t\tif (freeList[level])\n\t\t\t\t\tfreeList[level]->PrevPtr = freeNode;\n\t\t\t\tfreeList[level] = freeNode;\n\t\t\t}\n\t\t}\n\t\tvoid MemoryPool::Free(unsigned char * ptr, int size)\n\t\t{\n\t\t\tif (size == 0)\n\t\t\t\treturn;\n\t\t\tint originalSize = size;\n\t\t\tif (size < blockSize)\n\t\t\t\tsize = blockSize;\n\t\t\tint level = numLevels - (Math::Log2Ceil(size) - log2BlockSize);\n\t\t\tbytesAllocated -= (1 << ((numLevels-level) + log2BlockSize));\n\t\t\tbytesWasted -= (1 << ((numLevels - level) + log2BlockSize)) - originalSize;\n\t\t\tFreeBlock(ptr, level);\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "Source/CoreLib/MemoryPool.h",
    "content": "#ifndef CORE_LIB_MEMORY_POOL_H\n#define CORE_LIB_MEMORY_POOL_H\n\n#include \"Basic.h\"\n#include \"IntSet.h\"\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\tstruct MemoryBlockFields\n\t\t{\n\t\t\tunsigned int Occupied : 1;\n\t\t\tunsigned int Order : 31;\n\t\t};\n\t\tstruct FreeListNode\n\t\t{\n\t\t\tFreeListNode * PrevPtr = nullptr, *NextPtr = nullptr;\n\t\t};\n\t\tclass MemoryPool\n\t\t{\n\t\tprivate:\n\t\t\tstatic const int MaxLevels = 32;\n\t\t\tint blockSize = 0, log2BlockSize = 0;\n\t\t\tint numLevels = 0;\n\t\t\tint bytesAllocated = 0;\n\t\t\tint bytesWasted = 0;\n\t\t\tunsigned char * buffer = nullptr;\n\t\t\tFreeListNode * freeList[MaxLevels];\n\t\t\tIntSet used;\n\t\t\tint AllocBlock(int level);\n\t\t\tvoid FreeBlock(unsigned char * ptr, int level);\n\t\tpublic:\n\t\t\tMemoryPool(unsigned char * buffer, int log2BlockSize, int numBlocks);\n\t\t\tMemoryPool() = default;\n\t\t\tvoid Init(unsigned char * buffer, int log2BlockSize, int numBlocks);\n\t\t\tunsigned char * Alloc(int size);\n\t\t\tvoid Free(unsigned char * ptr, int size);\n\t\t};\n\n\t\tclass OutofPoolMemoryException : public Exception\n\t\t{};\n\n\t\ttemplate<typename T, int PoolSize>\n\t\tclass ObjectPool\n\t\t{\n\t\t\tstatic const int ObjectSize = sizeof(T) < 8 ? 8 : sizeof(T);\n\t\tprivate:\n\t\t\tstruct FreeList\n\t\t\t{\n\t\t\t\tFreeList* Next;\n\t\t\t};\n\t\t\tFreeList * freeList = nullptr;\n\t\t\tint allocPtr = 0;\n\t\t\tint poolSize = 0;\n\t\t\tvoid * buffer = 0;\n\t\t\tT * GetFreeObject()\n\t\t\t{\n\t\t\t\tif (freeList)\n\t\t\t\t{\n\t\t\t\t\tauto rs = (T*)freeList;\n\t\t\t\t\tfreeList = freeList->Next;\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\tpublic:\n\t\t\tObjectPool() \n\t\t\t{\n\t\t\t\tfreeList = nullptr;\n\t\t\t\tallocPtr = 0;\n\t\t\t\tbuffer = malloc(PoolSize * ObjectSize);\n\t\t\t}\n\n\t\t\tvoid Close()\n\t\t\t{\n\t\t\t\tfree(buffer);\n\t\t\t}\n\t\t\t\n\t\t\tvoid Free(T * obj)\n\t\t\t{\n\t\t\t\tauto newList = (FreeList*)obj;\n\t\t\t\tnewList->Next = freeList;\n\t\t\t\tfreeList = newList;\n\t\t\t}\n\n\t\t\tvoid * Buffer()\n\t\t\t{\n\t\t\t\treturn buffer;\n\t\t\t}\n\t\t\t\n\t\t\tT * Alloc()\n\t\t\t{\n\t\t\t\tauto rs = GetFreeObject();\n\t\t\t\tif (!rs)\n\t\t\t\t{\n\t\t\t\t\tif (allocPtr < PoolSize)\n\t\t\t\t\t{\n\t\t\t\t\t\trs = (T*)buffer + allocPtr;\n\t\t\t\t\t\tallocPtr++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!rs)\n\t\t\t\t{\n\t\t\t\t\tthrow OutofPoolMemoryException();\n\t\t\t\t}\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t};\n\t};\n\n#define USE_POOL_ALLOCATOR(T, PoolSize) \\\n\tprivate:\\\n\t\tstatic CoreLib::ObjectPool<T, PoolSize> _pool;\\\n\tpublic:\\\n\t\tvoid * operator new(std::size_t) { return _pool.Alloc(); } \\\n\t\tvoid operator delete(void * ptr) {_pool.Free((T*)ptr); }\\\n\t\tint GetObjectId() { return (int)(this -  (T*)_pool.Buffer()); }\\\n\t\tstatic void ClosePool(); \n#define IMPL_POOL_ALLOCATOR(T, PoolSize) \\\n\tCoreLib::ObjectPool<T, PoolSize> T::_pool;\\\n\tvoid T::ClosePool() { _pool.Close(); }\n\t\t\n}\n\n#endif"
  },
  {
    "path": "Source/CoreLib/SecureCRT.h",
    "content": "#ifndef _MSC_VER\n#ifndef CORE_LIB_SECURE_CRT_H\n#define CORE_LIB_SECURE_CRT_H\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <wchar.h>\n\ninline void memcpy_s(void *dest, size_t numberOfElements, const void * src, size_t count)\n{\n\tmemcpy(dest, src, count);\n}\n\n#define _TRUNCATE ((size_t)-1)\n#define _stricmp strcasecmp\n\ninline void fopen_s(FILE**f, const char * fileName, const char * mode)\n{\n\t*f = fopen(fileName, mode);\n}\n\ninline size_t fread_s(void * buffer, size_t bufferSize, size_t elementSize, size_t count, FILE * stream)\n{\n\treturn fread(buffer, elementSize, count, stream);\n}\n\ninline size_t wcsnlen_s(const wchar_t * str, size_t /*numberofElements*/)\n{\n\treturn wcslen(str);\n}\n\ninline size_t strnlen_s(const char * str, size_t numberofElements)\n{\n\treturn strnlen(str, numberofElements);\n}\n\ninline int sprintf_s(char * buffer, size_t sizeOfBuffer, const char * format, ...)\n{\n\tva_list argptr;\n\tva_start(argptr, format);\n\tint rs = snprintf(buffer, sizeOfBuffer, format, argptr);\n\tva_end(argptr);\n\treturn rs;\n}\n\ninline int swprintf_s(wchar_t * buffer, size_t sizeOfBuffer, const wchar_t * format, ...)\n{\n\tva_list argptr;\n\tva_start(argptr, format);\n\tint rs = swprintf(buffer, sizeOfBuffer, format, argptr);\n\tva_end(argptr);\n\treturn rs;\n}\n\ninline void wcscpy_s(wchar_t * strDestination, size_t /*numberOfElements*/, const wchar_t * strSource)\n{\n\twcscpy(strDestination, strSource);\n}\ninline void strcpy_s(char * strDestination, size_t /*numberOfElements*/, const char * strSource)\n{\n\tstrcpy(strDestination, strSource);\n}\n\ninline void wcsncpy_s(wchar_t * strDestination, size_t /*numberOfElements*/, const wchar_t * strSource, size_t count)\n{\n\twcscpy(strDestination, strSource);\n\t//wcsncpy(strDestination, strSource, count);\n}\ninline void strncpy_s(char * strDestination, size_t /*numberOfElements*/, const char * strSource, size_t count)\n{\n\tstrncpy(strDestination, strSource, count);\n\t//wcsncpy(strDestination, strSource, count);\n}\n#endif\n#endif\n"
  },
  {
    "path": "Source/CoreLib/SmartPointer.h",
    "content": "#ifndef FUNDAMENTAL_LIB_SMART_POINTER_H\n#define FUNDAMENTAL_LIB_SMART_POINTER_H\n\n#include \"TypeTraits.h\"\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\tclass RefPtrDefaultDestructor\n\t\t{\n\t\tpublic:\n\t\t\ttemplate<typename T>\n\t\t\tvoid operator ()(T * ptr)\n\t\t\t{\n\t\t\t\tdelete ptr;\n\t\t\t}\n\t\t};\n\n\t\tclass RefPtrArrayDestructor\n\t\t{\n\t\tpublic:\n\t\t\ttemplate<typename T>\n\t\t\tvoid operator() (T * ptr)\n\t\t\t{\n\t\t\t\tdelete [] ptr;\n\t\t\t}\n\t\t};\n\n\t\tclass ReferenceCounted\n\t\t{\n\t\t\ttemplate<typename T, bool b, typename Destructor>\n\t\t\tfriend class RefPtrImpl;\n\t\tprivate:\n\t\t\tint _refCount = 0;\n\t\tpublic:\n\t\t\tReferenceCounted() {}\n\t\t\tReferenceCounted(const ReferenceCounted &)\n\t\t\t{\n\t\t\t\t_refCount = 0;\n\t\t\t}\n\t\t};\n\n\n\t\tclass RefObject : public ReferenceCounted\n\t\t{\n\t\tpublic:\n\t\t\tvirtual ~RefObject()\n\t\t\t{}\n\t\t};\n\n\t\ttemplate<typename T, bool HasBuiltInCounter, typename Destructor>\n\t\tclass RefPtrImpl\n\t\t{\n\t\t};\n\n\t\ttemplate<typename T, typename Destructor = RefPtrDefaultDestructor>\n\t\tusing RefPtr = RefPtrImpl<T, IsBaseOf<ReferenceCounted, T>::Value, Destructor>;\n\n\t\ttemplate<typename T, typename Destructor>\n\t\tclass RefPtrImpl<T, 0, Destructor>\n\t\t{\n\t\t\ttemplate<typename T1, bool b, typename Destructor1>\n\t\t\tfriend class RefPtrImpl;\n\t\tprivate:\n\t\t\tT * pointer;\n\t\t\tint * refCount;\n\t\t\t\n\t\tpublic:\n\t\t\tRefPtrImpl()\n\t\t\t{\n\t\t\t\tpointer = 0;\n\t\t\t\trefCount = 0;\n\t\t\t}\n\t\t\tRefPtrImpl(T * ptr)\n\t\t\t\t: pointer(0), refCount(0)\n\t\t\t{\n\t\t\t\tthis->operator=(ptr);\n\t\t\t}\n\t\t\tRefPtrImpl(const RefPtrImpl<T, 0, Destructor> & ptr)\n\t\t\t\t: pointer(0), refCount(0)\n\t\t\t{\n\t\t\t\tthis->operator=(ptr);\n\t\t\t}\n\t\t\tRefPtrImpl(RefPtrImpl<T, 0, Destructor> && str)\n\t\t\t\t: pointer(0), refCount(0)\n\t\t\t{\n\t\t\t\tthis->operator=(static_cast<RefPtrImpl<T, 0, Destructor> &&>(str));\n\t\t\t}\n\n\t\t\ttemplate <typename U>\n\t\t\tRefPtrImpl(const RefPtrImpl<U, 0, Destructor>& ptr,\n\t\t\t\ttypename EnableIf<IsConvertible<T*, U*>::Value, void>::type * = 0)\n\t\t\t\t: pointer(0), refCount(0)\n\t\t\t{\n\t\t\t\tpointer = ptr.pointer;\n\t\t\t\tif (ptr)\n\t\t\t\t{\n\t\t\t\t\trefCount = ptr.refCount;\n\t\t\t\t\t(*refCount)++;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\trefCount = 0;\n\t\t\t}\n\n\t\t\ttemplate <typename U>\n\t\t\ttypename EnableIf<IsConvertible<T*, U*>::value, RefPtrImpl<T, 0, Destructor>>::type&\n\t\t\t\toperator=(const RefPtrImpl<U,0,Destructor> & ptr)\n\t\t\t{\n\t\t\t\tUnreference();\n\n\t\t\t\tpointer = ptr;\n\t\t\t\tif (ptr)\n\t\t\t\t{\n\t\t\t\t\trefCount = ptr.refCount;\n\t\t\t\t\t(*refCount)++;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\trefCount = 0;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tRefPtrImpl<T, 0, Destructor>& operator=(const RefPtrImpl<T, 0, Destructor> & ptr)\n\t\t\t{\n\t\t\t\tUnreference();\n\t\t\t\tpointer = ptr.pointer;\n\t\t\t\tif (ptr)\n\t\t\t\t{\n\t\t\t\t\trefCount = ptr.refCount;\n\t\t\t\t\t(*refCount)++;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\trefCount = 0;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tRefPtrImpl<T, 0, Destructor>& operator=(T * ptr)\n\t\t\t{\n\t\t\t\tif (ptr != pointer)\n\t\t\t\t{\n\t\t\t\t\tUnreference();\n\n\t\t\t\t\tpointer = ptr;\n\t\t\t\t\tif (ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\trefCount = new int;\n\t\t\t\t\t\t(*refCount) = 1;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\trefCount = 0;\n\t\t\t\t}\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tint GetHashCode()\n\t\t\t{\n\t\t\t\treturn (int)(long long)(void*)pointer;\n\t\t\t}\n\t\t\tbool operator == (const T * ptr) const\n\t\t\t{\n\t\t\t\treturn pointer == ptr;\n\t\t\t}\n\t\t\tbool operator != (const T * ptr) const\n\t\t\t{\n\t\t\t\treturn pointer != ptr;\n\t\t\t}\n\t\t\ttemplate<typename U>\n\t\t\tbool operator == (const RefPtr<U, Destructor> & ptr) const\n\t\t\t{\n\t\t\t\treturn pointer == ptr.pointer;\n\t\t\t}\n\t\t\ttemplate<typename U>\n\t\t\tbool operator != (const RefPtr<U, Destructor> & ptr) const\n\t\t\t{\n\t\t\t\treturn pointer != ptr.pointer;\n\t\t\t}\n\t\t\ttemplate<typename U>\n\t\t\tRefPtrImpl<U, 0, Destructor> As() const\n\t\t\t{\n\t\t\t\tRefPtrImpl<U, 0, Destructor> result;\n\t\t\t\tif (pointer)\n\t\t\t\t{\n\t\t\t\t\tresult.pointer = dynamic_cast<U*>(pointer);\n\t\t\t\t\tif (result.pointer)\n\t\t\t\t\t{\n\t\t\t\t\t\tresult.refCount = refCount;\n\t\t\t\t\t\t(*refCount)++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tT* operator +(int offset) const\n\t\t\t{\n\t\t\t\treturn pointer+offset;\n\t\t\t}\n\t\t\tT& operator [](int idx) const\n\t\t\t{\n\t\t\t\treturn *(pointer + idx);\n\t\t\t}\n\t\t\tRefPtrImpl<T, 0, Destructor>& operator=(RefPtrImpl<T, 0, Destructor> && ptr)\n\t\t\t{\n\t\t\t\tif(ptr.pointer != pointer)\n\t\t\t\t{\n\t\t\t\t\tUnreference();\n\t\t\t\t\tpointer = ptr.pointer;\n\t\t\t\t\trefCount = ptr.refCount;\n\t\t\t\t\tptr.pointer = 0;\n\t\t\t\t\tptr.refCount = 0;\n\t\t\t\t}\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tT* Release()\n\t\t\t{\n\t\t\t\tif(pointer)\n\t\t\t\t{\n\t\t\t\t\tif((*refCount) > 1)\n\t\t\t\t\t{\n\t\t\t\t\t\t(*refCount)--;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tdelete refCount;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tauto rs = pointer;\n\t\t\t\trefCount = 0;\n\t\t\t\tpointer = 0;\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\t~RefPtrImpl()\n\t\t\t{\n\t\t\t\tUnreference();\n\t\t\t}\n\n\t\t\tvoid Unreference()\n\t\t\t{\n\t\t\t\tif(pointer)\n\t\t\t\t{\n\t\t\t\t\tif((*refCount) > 1)\n\t\t\t\t\t{\n\t\t\t\t\t\t(*refCount)--;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tDestructor destructor;\n\t\t\t\t\t\tdestructor(pointer);\n\t\t\t\t\t\tdelete refCount;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tT & operator *() const\n\t\t\t{\n\t\t\t\treturn *pointer;\n\t\t\t}\n\t\t\tT * operator->() const\n\t\t\t{\n\t\t\t\treturn pointer;\n\t\t\t}\n\t\t\tT * Ptr() const\n\t\t\t{\n\t\t\t\treturn pointer;\n\t\t\t}\n\t\tpublic:\n\t\t\texplicit operator bool() const \n\t\t\t{\n\t\t\t\tif (pointer)\n\t\t\t\t\treturn true;\n\t\t\t\telse\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\n\n\t\ttemplate<typename T, typename Destructor>\n\t\tclass RefPtrImpl<T, 1, Destructor>\n\t\t{\n\t\t\ttemplate<typename T1, bool b, typename Destructor1>\n\t\t\tfriend class RefPtrImpl;\n\t\t\t\n\t\tprivate:\n\t\t\tT * pointer;\n\t\tpublic:\n\t\t\tRefPtrImpl()\n\t\t\t{\n\t\t\t\tpointer = 0;\n\t\t\t}\n\t\t\tRefPtrImpl(T * ptr)\n\t\t\t\t: pointer(0)\n\t\t\t{\n\t\t\t\tthis->operator=(ptr);\n\t\t\t}\n\t\t\tRefPtrImpl(const RefPtrImpl<T, 1, Destructor> & ptr)\n\t\t\t\t: pointer(0)\n\t\t\t{\n\t\t\t\tthis->operator=(ptr);\n\t\t\t}\n\t\t\tRefPtrImpl(RefPtrImpl<T, 1, Destructor> && str)\n\t\t\t\t: pointer(0)\n\t\t\t{\n\t\t\t\tthis->operator=(static_cast<RefPtrImpl<T, 1, Destructor> &&>(str));\n\t\t\t}\n\t\t\ttemplate <typename U>\n\t\t\t\tRefPtrImpl(const RefPtrImpl<U, 1, Destructor>& ptr,\n\t\t\t\t\ttypename EnableIf<IsConvertible<T*, U*>::Value, void>::type * = 0)\n\t\t\t\t: pointer(0)\n\t\t\t{\n\t\t\t\tpointer = ptr.pointer;\n\t\t\t\tif (ptr)\n\t\t\t\t{\n\t\t\t\t\tptr->_refCount++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttemplate <typename U>\n\t\t\ttypename EnableIf<IsConvertible<T*, U*>::value, RefPtrImpl<T, 1, Destructor>&>::type\n\t\t\t\toperator=(const RefPtrImpl<U, 1, Destructor> & ptr)\n\t\t\t{\n\t\t\t\tUnreference();\n\n\t\t\t\tpointer = ptr.pointer;\n\t\t\t\tif (ptr)\n\t\t\t\t{\n\t\t\t\t\tptr->_refCount++;\n\t\t\t\t}\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tRefPtrImpl<T, 1, Destructor>& operator=(T * ptr)\n\t\t\t{\n\t\t\t\tif (ptr != pointer)\n\t\t\t\t{\n\t\t\t\t\tUnreference();\n\n\t\t\t\t\tpointer = ptr;\n\t\t\t\t\tif (ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tptr->_refCount++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tRefPtrImpl<T, 1, Destructor>& operator=(const RefPtrImpl<T, 1, Destructor> & ptr)\n\t\t\t{\n\t\t\t\tif (ptr.pointer != pointer)\n\t\t\t\t{\n\t\t\t\t\tUnreference();\n\t\t\t\t\tpointer = ptr.pointer;\n\t\t\t\t\tif (pointer)\n\t\t\t\t\t\tpointer->_refCount++;\n\t\t\t\t}\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tint GetHashCode()\n\t\t\t{\n\t\t\t\treturn (int)(long long)(void*)pointer;\n\t\t\t}\n\t\t\tbool operator == (const T * ptr) const\n\t\t\t{\n\t\t\t\treturn pointer == ptr;\n\t\t\t}\n\t\t\tbool operator != (const T * ptr) const\n\t\t\t{\n\t\t\t\treturn pointer != ptr;\n\t\t\t}\n\t\t\ttemplate<typename U>\n\t\t\tbool operator == (const RefPtr<U, Destructor> & ptr) const\n\t\t\t{\n\t\t\t\treturn pointer == ptr.pointer;\n\t\t\t}\n\t\t\ttemplate<typename U>\n\t\t\tbool operator != (const RefPtr<U, Destructor> & ptr) const\n\t\t\t{\n\t\t\t\treturn pointer != ptr.pointer;\n\t\t\t}\n\t\t\ttemplate<typename U>\n\t\t\tRefPtrImpl<U, 1, Destructor> As() const\n\t\t\t{\n\t\t\t\tRefPtrImpl<U, 1, Destructor> result;\n\t\t\t\tif (pointer)\n\t\t\t\t{\n\t\t\t\t\tresult.pointer = dynamic_cast<U*>(pointer);\n\t\t\t\t\tif (result.pointer)\n\t\t\t\t\t{\n\t\t\t\t\t\tresult.pointer->_refCount++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tT* operator +(int offset) const\n\t\t\t{\n\t\t\t\treturn pointer + offset;\n\t\t\t}\n\t\t\tT& operator [](int idx) const\n\t\t\t{\n\t\t\t\treturn *(pointer + idx);\n\t\t\t}\n\t\t\tRefPtrImpl<T, 1, Destructor>& operator=(RefPtrImpl<T, 1, Destructor> && ptr)\n\t\t\t{\n\t\t\t\tif (ptr.pointer != pointer)\n\t\t\t\t{\n\t\t\t\t\tUnreference();\n\t\t\t\t\tpointer = ptr.pointer;\n\t\t\t\t\tptr.pointer = nullptr;\n\t\t\t\t}\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tT* Release()\n\t\t\t{\n\t\t\t\tif (pointer)\n\t\t\t\t{\n\t\t\t\t\tpointer->_refCount--;\n\t\t\t\t}\n\t\t\t\tauto rs = pointer;\n\t\t\t\tpointer = 0;\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\t~RefPtrImpl()\n\t\t\t{\n\t\t\t\tUnreference();\n\t\t\t}\n\n\t\t\tvoid Unreference()\n\t\t\t{\n\t\t\t\tif (pointer)\n\t\t\t\t{\n\t\t\t\t\tif (pointer->_refCount > 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tpointer->_refCount--;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tDestructor destructor;\n\t\t\t\t\t\tdestructor(pointer);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tT & operator *() const\n\t\t\t{\n\t\t\t\treturn *pointer;\n\t\t\t}\n\t\t\tT * operator->() const\n\t\t\t{\n\t\t\t\treturn pointer;\n\t\t\t}\n\t\t\tT * Ptr() const\n\t\t\t{\n\t\t\t\treturn pointer;\n\t\t\t}\n\t\tpublic:\n\t\t\texplicit operator bool() const\n\t\t\t{\n\t\t\t\tif (pointer)\n\t\t\t\t\treturn true;\n\t\t\t\telse\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/CoreLib/Stream.cpp",
    "content": "#include \"Stream.h\"\n#ifdef _WIN32\n#include <share.h>\n#endif\n#include \"LibIO.h\"\n\nnamespace CoreLib\n{\n\tnamespace IO\n\t{\n\t\tusing namespace CoreLib::Basic;\n\t\tFileStream::FileStream(const CoreLib::Basic::String & fileName, FileMode fileMode)\n\t\t{\n\t\t\tInit(fileName, fileMode, fileMode==FileMode::Open?FileAccess::Read:FileAccess::Write, FileShare::None);\n\t\t}\n\t\tFileStream::FileStream(const CoreLib::Basic::String & fileName, FileMode fileMode, FileAccess access, FileShare share)\n\t\t{\n\t\t\tInit(fileName, fileMode, access, share);\n\t\t}\n\t\tvoid FileStream::Init(const CoreLib::Basic::String & fileName, FileMode fileMode, FileAccess access, FileShare share)\n\t\t{\n\t\t\tconst wchar_t * mode = L\"rt\";\n\t\t\tconst char* modeMBCS = \"rt\";\n\t\t\tswitch (fileMode)\n\t\t\t{\n\t\t\tcase CoreLib::IO::FileMode::Create:\n\t\t\t\tif (access == FileAccess::Read)\n\t\t\t\t\tthrow ArgumentException(\"Read-only access is incompatible with Create mode.\");\n\t\t\t\telse if (access == FileAccess::ReadWrite)\n\t\t\t\t{\n\t\t\t\t\tmode = L\"w+b\";\n\t\t\t\t\tmodeMBCS = \"w+b\";\n\t\t\t\t\tthis->fileAccess = FileAccess::ReadWrite;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tmode = L\"wb\";\n\t\t\t\t\tmodeMBCS = \"wb\";\n\t\t\t\t\tthis->fileAccess = FileAccess::Write;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase CoreLib::IO::FileMode::Open:\n\t\t\t\tif (access == FileAccess::Read)\n\t\t\t\t{\n\t\t\t\t\tmode = L\"rb\";\n\t\t\t\t\tmodeMBCS = \"rb\";\n\t\t\t\t\tthis->fileAccess = FileAccess::Read;\n\t\t\t\t}\n\t\t\t\telse if (access == FileAccess::ReadWrite)\n\t\t\t\t{\n\t\t\t\t\tmode = L\"r+b\";\n\t\t\t\t\tmodeMBCS = \"r+b\";\n\t\t\t\t\tthis->fileAccess = FileAccess::ReadWrite;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tmode = L\"wb\";\n\t\t\t\t\tmodeMBCS = \"wb\";\n\t\t\t\t\tthis->fileAccess = FileAccess::Write;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase CoreLib::IO::FileMode::CreateNew:\n\t\t\t\tif (File::Exists(fileName))\n\t\t\t\t{\n\t\t\t\t\tthrow IOException(\"Failed opening '\" + fileName + \"', file already exists.\");\n\t\t\t\t}\n\t\t\t\tif (access == FileAccess::Read)\n\t\t\t\t\tthrow ArgumentException(\"Read-only access is incompatible with Create mode.\");\n\t\t\t\telse if (access == FileAccess::ReadWrite)\n\t\t\t\t{\n\t\t\t\t\tmode = L\"w+b\";\n\t\t\t\t\tthis->fileAccess = FileAccess::ReadWrite;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tmode = L\"wb\";\n\t\t\t\t\tthis->fileAccess = FileAccess::Write;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase CoreLib::IO::FileMode::Append:\n\t\t\t\tif (access == FileAccess::Read)\n\t\t\t\t\tthrow ArgumentException(\"Read-only access is incompatible with Append mode.\");\n\t\t\t\telse if (access == FileAccess::ReadWrite)\n\t\t\t\t{\n\t\t\t\t\tmode = L\"a+b\";\n\t\t\t\t\tthis->fileAccess = FileAccess::ReadWrite;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tmode = L\"ab\";\n\t\t\t\t\tthis->fileAccess = FileAccess::Write;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tint shFlag;\n#ifdef _WIN32\n\t\t\tswitch (share)\n\t\t\t{\n\t\t\tcase CoreLib::IO::FileShare::None:\n\t\t\t\tshFlag = _SH_DENYRW;\n\t\t\t\tbreak;\n\t\t\tcase CoreLib::IO::FileShare::ReadOnly:\n\t\t\t\tshFlag = _SH_DENYWR;\n\t\t\t\tbreak;\n\t\t\tcase CoreLib::IO::FileShare::WriteOnly:\n\t\t\t\tshFlag = _SH_DENYRD;\n\t\t\t\tbreak;\n\t\t\tcase CoreLib::IO::FileShare::ReadWrite:\n\t\t\t\tshFlag = _SH_DENYNO;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow ArgumentException(\"Invalid file share mode.\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\thandle = _wfsopen(fileName.ToWString(), mode, shFlag);\n#else\n\t\t\thandle = fopen(fileName.Buffer(), modeMBCS);\n#endif\n\t\t\tif (!handle)\n\t\t\t{\n\t\t\t\tthrow IOException(\"Cannot open file '\" + fileName + \"'\");\n\t\t\t}\n\t\t}\n\t\tFileStream::~FileStream()\n\t\t{\n\t\t\tClose();\n\t\t}\n\t\tInt64 FileStream::GetPosition()\n\t\t{\n#ifdef _WIN32\n\t\t\tfpos_t pos;\n\t\t\tfgetpos(handle, &pos);\n\t\t\treturn pos;\n#else\n\t\t\tfpos64_t pos;\n\t\t\tfgetpos64(handle, &pos);\n\t\t\treturn *(Int64*)(&pos);\n#endif\n\t\t}\n\t\tvoid FileStream::Seek(SeekOrigin origin, Int64 offset)\n\t\t{\n\t\t\tint _origin;\n\t\t\tswitch (origin)\n\t\t\t{\n\t\t\tcase CoreLib::IO::SeekOrigin::Start:\n\t\t\t\t_origin = SEEK_SET;\n\t\t\t\tendReached = false;\n\t\t\t\tbreak;\n\t\t\tcase CoreLib::IO::SeekOrigin::End:\n\t\t\t\t_origin = SEEK_END;\n\t\t\t\tendReached = true;\n\t\t\t\tbreak;\n\t\t\tcase CoreLib::IO::SeekOrigin::Current:\n\t\t\t\t_origin = SEEK_CUR;\n\t\t\t\tendReached = false;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow NotSupportedException(\"Unsupported seek origin.\");\n\t\t\t\tbreak;\n\t\t\t}\n#ifdef _WIN32\n\t\t\tint rs = _fseeki64(handle, offset, _origin);\n#else\n\t\t\tint rs = fseek(handle, (int)offset, _origin);\n#endif\n\t\t\tif (rs != 0)\n\t\t\t{\n\t\t\t\tthrow IOException(\"FileStream seek failed.\");\n\t\t\t}\n\t\t}\n\t\tInt64 FileStream::Read(void * buffer, Int64 length)\n\t\t{\n\t\t\tauto bytes = fread_s(buffer, (size_t)length, 1, (size_t)length, handle);\n\t\t\tif (bytes == 0 && length > 0)\n\t\t\t{\n\t\t\t\tif (!feof(handle))\n\t\t\t\t\tthrow IOException(\"FileStream read failed.\");\n\t\t\t\telse if (endReached)\n\t\t\t\t\tthrow EndOfStreamException(\"End of file is reached.\");\n\t\t\t\tendReached = true;\n\t\t\t}\n\t\t\treturn (int)bytes;\n\t\t}\n\t\tInt64 FileStream::Write(const void * buffer, Int64 length)\n\t\t{\n\t\t\tauto bytes = (Int64)fwrite(buffer, 1, (size_t)length, handle);\n\t\t\tif (bytes < length)\n\t\t\t{\n\t\t\t\tthrow IOException(\"FileStream write failed.\");\n\t\t\t}\n\t\t\treturn bytes;\n\t\t}\n\t\tbool FileStream::CanRead()\n\t\t{\n\t\t\treturn ((int)fileAccess & (int)FileAccess::Read) != 0;\n\t\t}\n\t\tbool FileStream::CanWrite()\n\t\t{\n\t\t\treturn ((int)fileAccess & (int)FileAccess::Write) != 0;\n\t\t}\n\t\tvoid FileStream::Close()\n\t\t{\n\t\t\tif (handle)\n\t\t\t{\n\t\t\t\tfclose(handle);\n\t\t\t\thandle = 0;\n\t\t\t}\n\t\t}\n\t\tbool FileStream::IsEnd()\n\t\t{\n\t\t\treturn endReached;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Source/CoreLib/Stream.h",
    "content": "#ifndef CORE_LIB_STREAM_H\n#define CORE_LIB_STREAM_H\n\n#include \"Basic.h\"\n\nnamespace CoreLib\n{\n\tnamespace IO\n\t{\n\t\tusing CoreLib::Basic::Exception;\n\t\tusing CoreLib::Basic::String;\n\t\tusing CoreLib::Basic::RefPtr;\n\n\t\tclass IOException : public Exception\n\t\t{\n\t\tpublic:\n\t\t\tIOException()\n\t\t\t{}\n\t\t\tIOException(const String & message)\n\t\t\t\t: CoreLib::Basic::Exception(message)\n\t\t\t{\n\t\t\t}\n\t\t};\n\n\t\tclass EndOfStreamException : public IOException\n\t\t{\n\t\tpublic:\n\t\t\tEndOfStreamException()\n\t\t\t{}\n\t\t\tEndOfStreamException(const String & message)\n\t\t\t\t: IOException(message)\n\t\t\t{\n\t\t\t}\n\t\t};\n\n\t\tenum class SeekOrigin\n\t\t{\n\t\t\tStart, End, Current\n\t\t};\n\n\t\tclass Stream : public CoreLib::Basic::Object\n\t\t{\n\t\tpublic:\n\t\t\tvirtual Int64 GetPosition()=0;\n\t\t\tvirtual void Seek(SeekOrigin origin, Int64 offset)=0;\n\t\t\tvirtual Int64 Read(void * buffer, Int64 length) = 0;\n\t\t\tvirtual Int64 Write(const void * buffer, Int64 length) = 0;\n\t\t\tvirtual bool IsEnd() = 0;\n\t\t\tvirtual bool CanRead() = 0;\n\t\t\tvirtual bool CanWrite() = 0;\n\t\t\tvirtual void Close() = 0;\n\t\t};\n\n\t\tclass BinaryReader\n\t\t{\n\t\tprivate:\n\t\t\tRefPtr<Stream> stream;\n\t\t\tinline void Throw(Int64 val)\n\t\t\t{\n\t\t\t\tif (val == 0)\n\t\t\t\t\tthrow IOException(\"read operation failed.\");\n\t\t\t}\n\t\tpublic:\n\t\t\tBinaryReader(RefPtr<Stream> stream)\n\t\t\t{\n\t\t\t\tthis->stream = stream;\n\t\t\t}\n\t\t\tStream * GetStream()\n\t\t\t{\n\t\t\t\treturn stream.Ptr();\n\t\t\t}\n\t\t\tvoid ReleaseStream()\n\t\t\t{\n\t\t\t\tstream.Release();\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tvoid Read(T * buffer, int count)\n\t\t\t{\n\t\t\t\tstream->Read(buffer, sizeof(T)*(Int64)count);\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tvoid Read(T & buffer)\n\t\t\t{\n\t\t\t\tThrow(stream->Read(&buffer, sizeof(T)));\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tvoid Read(List<T> & buffer)\n\t\t\t{\n\t\t\t\tint count = ReadInt32();\n\t\t\t\tbuffer.SetSize(count);\n\t\t\t\tRead(buffer.Buffer(), count);\n\t\t\t}\n\t\t\tvoid Read(String & buffer)\n\t\t\t{\n\t\t\t\tbuffer = ReadString();\n\t\t\t}\n\t\t\tint ReadInt32()\n\t\t\t{\n\t\t\t\tint rs;\n\t\t\t\tThrow(stream->Read(&rs, sizeof(int)));\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tshort ReadInt16()\n\t\t\t{\n\t\t\t\tshort rs;\n\t\t\t\tThrow(stream->Read(&rs, sizeof(short)));\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tInt64 ReadInt64()\n\t\t\t{\n\t\t\t\tInt64 rs;\n\t\t\t\tThrow(stream->Read(&rs, sizeof(Int64)));\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tfloat ReadFloat()\n\t\t\t{\n\t\t\t\tfloat rs;\n\t\t\t\tThrow(stream->Read(&rs, sizeof(float)));\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tdouble ReadDouble()\n\t\t\t{\n\t\t\t\tdouble rs;\n\t\t\t\tThrow(stream->Read(&rs, sizeof(double)));\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tchar ReadChar()\n\t\t\t{\n\t\t\t\tchar rs;\n\t\t\t\tThrow(stream->Read(&rs, sizeof(char)));\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tString ReadString()\n\t\t\t{\n\t\t\t\tint len = ReadInt32();\n\t\t\t\tchar * buffer = new char[len+1];\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tThrow(stream->Read(buffer, len));\n\t\t\t\t}\n\t\t\t\tcatch(IOException & e)\n\t\t\t\t{\n\t\t\t\t\tdelete [] buffer;\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t\tbuffer[len] = 0;\n\t\t\t\treturn String::FromBuffer(buffer, len);\n\t\t\t}\n\t\t};\n\n\t\tclass BinaryWriter\n\t\t{\n\t\tprivate:\n\t\t\tRefPtr<Stream> stream;\n\t\tpublic:\n\t\t\tBinaryWriter(RefPtr<Stream> stream)\n\t\t\t{\n\t\t\t\tthis->stream = stream;\n\t\t\t}\n\t\t\tStream * GetStream()\n\t\t\t{\n\t\t\t\treturn stream.Ptr();\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tvoid Write(const T& val)\n\t\t\t{\n\t\t\t\tstream->Write(&val, sizeof(T));\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tvoid Write(T * buffer, int count)\n\t\t\t{\n\t\t\t\tstream->Write(buffer, sizeof(T)*(Int64)count);\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tvoid Write(const List<T> & list)\n\t\t\t{\n\t\t\t\tWrite(list.Count());\n\t\t\t\tstream->Write(list.Buffer(), sizeof(T)*list.Count());\n\t\t\t}\n\t\t\tvoid Write(const String & str)\n\t\t\t{\n\t\t\t\tWrite(str.Length());\n\t\t\t\tWrite(str.Buffer(), str.Length());\n\t\t\t}\n\t\t\tvoid ReleaseStream()\n\t\t\t{\n\t\t\t\tstream.Release();\n\t\t\t}\n\t\t\tvoid Close()\n\t\t\t{\n\t\t\t\tstream->Close();\n\t\t\t}\n\t\t};\n\n\t\tenum class FileMode\n\t\t{\n\t\t\tCreate, Open, CreateNew, Append\n\t\t};\n\n\t\tenum class FileAccess\n\t\t{\n\t\t\tRead = 1, Write = 2, ReadWrite = 3\n\t\t};\n\n\t\tenum class FileShare\n\t\t{\n\t\t\tNone, ReadOnly, WriteOnly, ReadWrite\n\t\t};\n\n\t\tclass FileStream : public Stream\n\t\t{\n\t\tprivate:\n\t\t\tFILE * handle;\n\t\t\tFileAccess fileAccess;\n\t\t\tbool endReached = false;\n\t\t\tvoid Init(const CoreLib::Basic::String & fileName, FileMode fileMode, FileAccess access, FileShare share);\n\t\tpublic:\n\t\t\tFileStream(const CoreLib::Basic::String & fileName, FileMode fileMode = FileMode::Open);\n\t\t\tFileStream(const CoreLib::Basic::String & fileName, FileMode fileMode, FileAccess access, FileShare share);\n\t\t\t~FileStream();\n\t\tpublic:\n\t\t\tvirtual Int64 GetPosition();\n\t\t\tvirtual void Seek(SeekOrigin origin, Int64 offset);\n\t\t\tvirtual Int64 Read(void * buffer, Int64 length);\n\t\t\tvirtual Int64 Write(const void * buffer, Int64 length);\n\t\t\tvirtual bool CanRead();\n\t\t\tvirtual bool CanWrite();\n\t\t\tvirtual void Close();\n\t\t\tvirtual bool IsEnd();\n\t\t};\n\n\t\tclass MemoryStream : public Stream\n\t\t{\n\t\tprivate:\n\t\t\tCoreLib::List<unsigned char> writeBuffer;\n\t\t\tCoreLib::ArrayView<unsigned char> readBuffer;\n\t\t\tint ptr = 0;\n\t\t\tbool isReadStream;\n\t\tpublic:\n\t\t\tMemoryStream()\n\t\t\t{\n\t\t\t\tisReadStream = false;\n\t\t\t}\n\t\t\tMemoryStream(unsigned char * mem, int length)\n\t\t\t{\n\t\t\t\tisReadStream = true;\n\t\t\t\treadBuffer = MakeArrayView(mem, length);\n\t\t\t}\n\t\t\tMemoryStream(CoreLib::ArrayView<unsigned char> source)\n\t\t\t{\n\t\t\t\tisReadStream = true;\n\t\t\t\treadBuffer = source;\n\t\t\t}\n\t\t\tvirtual Int64 GetPosition()\n\t\t\t{\n\t\t\t\treturn ptr;\n\t\t\t}\n\t\t\tvirtual void Seek(SeekOrigin origin, Int64 offset)\n\t\t\t{\n\t\t\t\tif (origin == SeekOrigin::Start)\n\t\t\t\t\tptr = (int)offset;\n\t\t\t\telse if (origin == SeekOrigin::End)\n\t\t\t\t{\n\t\t\t\t\tif (isReadStream)\n\t\t\t\t\t\tptr = readBuffer.Count() + (int)offset;\n\t\t\t\t\telse\n\t\t\t\t\t\tptr = writeBuffer.Count() + (int)offset;\n\t\t\t\t}\n\t\t\t}\n\t\t\tvirtual Int64 Read(void * pbuffer, Int64 length)\n\t\t\t{\n\t\t\t\tInt64 i;\n\t\t\t\tfor (i = 0; i < length; i++)\n\t\t\t\t{\n\t\t\t\t\tif (ptr + i < readBuffer.Count())\n\t\t\t\t\t{\n\t\t\t\t\t\t((unsigned char*)pbuffer)[i] = readBuffer[(int)(ptr + i)];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\treturn i;\n\t\t\t}\n\t\t\tvirtual Int64 Write(const void * pbuffer, Int64 length)\n\t\t\t{\n\t\t\t\twriteBuffer.SetSize(ptr);\n\t\t\t\tif (pbuffer)\n\t\t\t\t\twriteBuffer.AddRange((unsigned char *)pbuffer, (int)length);\n\t\t\t\telse\n\t\t\t\t\tfor (auto i = 0; i < length; i++)\n\t\t\t\t\t\twriteBuffer.Add(0);\n\t\t\t\tptr = writeBuffer.Count();\n\t\t\t\treturn length;\n\t\t\t}\n\t\t\tvirtual bool CanRead()\n\t\t\t{\n\t\t\t\treturn isReadStream;\n\t\t\t}\n\t\t\tvirtual bool CanWrite()\n\t\t\t{\n\t\t\t\treturn !isReadStream;\n\t\t\t}\n\t\t\tvirtual void Close()\n\t\t\t{\n\t\t\t\twriteBuffer.SetSize(0);\n\t\t\t\twriteBuffer.Compress();\n\t\t\t}\n\t\t\tvirtual bool IsEnd()\n\t\t\t{\n\t\t\t\tif (isReadStream)\n\t\t\t\t\treturn ptr >= readBuffer.Count();\n\t\t\t\telse\n\t\t\t\t\treturn ptr == writeBuffer.Count();\n\t\t\t}\n\t\t\tvoid * GetBuffer()\n\t\t\t{\n\t\t\t\tif (isReadStream)\n\t\t\t\t\treturn readBuffer.Buffer();\n\t\t\t\telse\n\t\t\t\t\treturn writeBuffer.Buffer();\n\t\t\t}\n\t\t\tint GetBufferSize()\n\t\t\t{\n\t\t\t\tif (isReadStream)\n\t\t\t\t\treturn readBuffer.Count();\n\t\t\t\telse\n\t\t\t\t\treturn writeBuffer.Count();\n\t\t\t}\n\t\t};\n\t}\n}\n\n#endif\n"
  },
  {
    "path": "Source/CoreLib/TextIO.cpp",
    "content": "#include \"TextIO.h\"\n#ifdef _WIN32\n#include <Windows.h>\n#define CONVERT_END_OF_LINE\n#endif\n\nnamespace CoreLib\n{\n\tnamespace IO\n\t{\n\t\tusing namespace CoreLib::Basic;\n\n\t\tclass Utf8Encoding : public Encoding \n\t\t{\n\t\tpublic:\n\t\t\tvirtual void GetBytes(List<char> & result, const String & str) override\n\t\t\t{\n\t\t\t\tresult.AddRange(str.Buffer(), str.Length());\n\t\t\t}\n\t\t\tvirtual String ToString(const char * bytes, int /*length*/) override\n\t\t\t{\n\t\t\t\treturn String(bytes);\n\t\t\t}\n\t\t};\n\n\t\tclass Utf32Encoding : public Encoding\n\t\t{\n\t\tpublic:\n\t\t\tvirtual void GetBytes(List<char> & result, const String & str) override\n\t\t\t{\n\t\t\t\tint ptr = 0;\n\t\t\t\twhile (ptr < str.Length())\n\t\t\t\t{\n\t\t\t\t\tint codePoint = GetUnicodePointFromUTF8([&](int)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ptr < str.Length())\n\t\t\t\t\t\t\treturn str[ptr++];\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn '\\0';\n\t\t\t\t\t});\n\t\t\t\t\tresult.AddRange((char*)&codePoint, 4);\n\t\t\t\t}\n\t\t\t}\n\t\t\tvirtual String ToString(const char * bytes, int length) override\n\t\t\t{\n\t\t\t\tStringBuilder sb;\n\t\t\t\tint * content = (int*)bytes;\n\t\t\t\tfor (int i = 0; i < (length >> 2); i++)\n\t\t\t\t{\n\t\t\t\t\tchar buf[5];\n\t\t\t\t\tint count = EncodeUnicodePointToUTF8(buf, content[i]);\n\t\t\t\t\tfor (int j = 0; j < count; j++)\n\t\t\t\t\t\tsb.Append(buf[j]);\n\t\t\t\t}\n\t\t\t\treturn sb.ProduceString();\n\t\t\t}\n\t\t};\n\n\t\tclass Utf16Encoding : public Encoding //UTF16\n\t\t{\n\t\tprivate:\n\t\t\tbool reverseOrder = false;\n\t\tpublic:\n\t\t\tUtf16Encoding(bool pReverseOrder)\n\t\t\t\t: reverseOrder(pReverseOrder)\n\t\t\t{}\n\t\t\tvirtual void GetBytes(List<char> & result, const String & str) override\n\t\t\t{\n\t\t\t\tint ptr = 0;\n\t\t\t\twhile (ptr < str.Length())\n\t\t\t\t{\n\t\t\t\t\tint codePoint = GetUnicodePointFromUTF8([&](int)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ptr < str.Length())\n\t\t\t\t\t\t\treturn str[ptr++];\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn '\\0';\n\t\t\t\t\t});\n\t\t\t\t\tunsigned short buffer[2];\n\t\t\t\t\tint count;\n\t\t\t\t\tif (!reverseOrder)\n\t\t\t\t\t\tcount = EncodeUnicodePointToUTF16(buffer, codePoint);\n\t\t\t\t\telse\n\t\t\t\t\t\tcount = EncodeUnicodePointToUTF16Reversed(buffer, codePoint);\n\t\t\t\t\tresult.AddRange((char*)buffer, count * 2);\n\t\t\t\t}\n\t\t\t}\n\t\t\tvirtual String ToString(const char * bytes, int length) override\n\t\t\t{\n\t\t\t\tint ptr = 0;\n\t\t\t\tStringBuilder sb;\n\t\t\t\twhile (ptr < length)\n\t\t\t\t{\n\t\t\t\t\tint codePoint = GetUnicodePointFromUTF16([&](int)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ptr < length)\n\t\t\t\t\t\t\treturn bytes[ptr++];\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn '\\0';\n\t\t\t\t\t});\n\t\t\t\t\tchar buf[5];\n\t\t\t\t\tint count = EncodeUnicodePointToUTF8(buf, codePoint);\n\t\t\t\t\tfor (int i = 0; i < count; i++)\n\t\t\t\t\t\tsb.Append(buf[i]);\n\t\t\t\t}\n\t\t\t\treturn sb.ProduceString();\n\t\t\t}\n\t\t};\n\n\t\tUtf8Encoding __utf8Encoding;\n\t\tUtf16Encoding __utf16Encoding(false);\n\t\tUtf16Encoding __utf16EncodingReversed(true);\n\t\tUtf32Encoding __utf32Encoding;\n\n\t\tEncoding * Encoding::UTF8 = &__utf8Encoding;\n\t\tEncoding * Encoding::UTF16 = &__utf16Encoding;\n\t\tEncoding * Encoding::UTF16Reversed = &__utf16EncodingReversed;\n\t\tEncoding * Encoding::UTF32 = &__utf32Encoding;\n\n\t\tconst unsigned short Utf16Header = 0xFEFF;\n\t\tconst unsigned short Utf16ReversedHeader = 0xFFFE;\n\n\t\tStreamWriter::StreamWriter(const String & path, Encoding * encoding)\n\t\t{\n\t\t\tthis->stream = new FileStream(path, FileMode::Create);\n\t\t\tthis->encoding = encoding;\n\t\t\tif (encoding == Encoding::UTF16)\n\t\t\t{\n\t\t\t\tthis->stream->Write(&Utf16Header, 2);\n\t\t\t}\n\t\t\telse if (encoding == Encoding::UTF16Reversed)\n\t\t\t{\n\t\t\t\tthis->stream->Write(&Utf16ReversedHeader, 2);\n\t\t\t}\n\t\t}\n\t\tStreamWriter::StreamWriter(RefPtr<Stream> stream, Encoding * encoding)\n\t\t{\n\t\t\tthis->stream = stream;\n\t\t\tthis->encoding = encoding;\n\t\t\tif (encoding == Encoding::UTF16)\n\t\t\t{\n\t\t\t\tthis->stream->Write(&Utf16Header, 2);\n\t\t\t}\n\t\t\telse if (encoding == Encoding::UTF16Reversed)\n\t\t\t{\n\t\t\t\tthis->stream->Write(&Utf16ReversedHeader, 2);\n\t\t\t}\n\t\t}\n\t\tvoid StreamWriter::Write(const String & str)\n\t\t{\n\t\t\tencodingBuffer.Clear();\n\t\t\tStringBuilder sb;\n\t\t\tString newLine;\n#ifdef _WIN32\n\t\t\tnewLine = \"\\r\\n\";\n#else\n\t\t\tnewLine = \"\\n\";\n#endif\n\t\t\tfor (int i = 0; i < str.Length(); i++)\n\t\t\t{\n\t\t\t\tif (str[i] == '\\r')\n\t\t\t\t\tsb << newLine;\n\t\t\t\telse if (str[i] == '\\n')\n\t\t\t\t{\n\t\t\t\t\tif (i > 0 && str[i - 1] != '\\r')\n\t\t\t\t\t\tsb << newLine;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tsb << str[i];\n\t\t\t}\n\t\t\tencoding->GetBytes(encodingBuffer, sb.ProduceString());\n\t\t\tstream->Write(encodingBuffer.Buffer(), encodingBuffer.Count());\n\t\t}\n\t\tvoid StreamWriter::Write(const char * str)\n\t\t{\n\t\t\tWrite(String(str));\n\t\t}\n\n\t\tStreamReader::StreamReader(const String & path)\n\t\t{\n\t\t\tstream = new FileStream(path, FileMode::Open);\n\t\t\tReadBuffer();\n\t\t\tencoding = DetermineEncoding();\n\t\t\tif (encoding == 0)\n\t\t\t\tencoding = Encoding::UTF8;\n\t\t}\n\t\tStreamReader::StreamReader(RefPtr<Stream> stream, Encoding * encoding)\n\t\t{\n\t\t\tthis->stream = stream;\n\t\t\tthis->encoding = encoding;\n\t\t\tReadBuffer();\n\t\t\tauto determinedEncoding = DetermineEncoding();\n\t\t\tif (this->encoding == nullptr)\n\t\t\t\tthis->encoding = determinedEncoding;\n\t\t}\n\n\t\tEncoding * StreamReader::DetermineEncoding()\n\t\t{\n\t\t\tif (buffer.Count() >= 3 && (unsigned char)(buffer[0]) == 0xEF && (unsigned char)(buffer[1]) == 0xBB && (unsigned char)(buffer[2]) == 0xBF)\n\t\t\t{\n\t\t\t\tptr += 3;\n\t\t\t\treturn Encoding::UTF8;\n\t\t\t}\n\t\t\telse if (*((unsigned short*)(buffer.Buffer())) == 0xFEFF)\n\t\t\t{\n\t\t\t\tptr += 2;\n\t\t\t\treturn Encoding::UTF16;\n\t\t\t}\n\t\t\telse if (*((unsigned short*)(buffer.Buffer())) == 0xFFFE)\n\t\t\t{\n\t\t\t\tptr += 2;\n\t\t\t\treturn Encoding::UTF16Reversed;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n#ifdef _WIN32\n\t\t\t\tint flag = IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_REVERSE_SIGNATURE | IS_TEXT_UNICODE_STATISTICS | IS_TEXT_UNICODE_ASCII16;\n\t\t\t\tint rs = IsTextUnicode(buffer.Buffer(), buffer.Count(), &flag);\n\t\t\t\tif (rs)\n\t\t\t\t{\n\t\t\t\t\tif (flag & (IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_STATISTICS))\n\t\t\t\t\t\treturn Encoding::UTF16;\n\t\t\t\t\telse if (flag & (IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_STATISTICS))\n\t\t\t\t\t\treturn Encoding::UTF16Reversed;\n\t\t\t\t\telse if (flag & IS_TEXT_UNICODE_ASCII16)\n\t\t\t\t\t\treturn Encoding::UTF8;\n\t\t\t\t}\n#endif \n\t\t\t\treturn Encoding::UTF8;\n\t\t\t}\n\t\t}\n\t\t\n\t\tvoid StreamReader::ReadBuffer()\n\t\t{\n\t\t\tbuffer.SetSize(4096);\n\t\t\tauto len = stream->Read(buffer.Buffer(), buffer.Count());\n\t\t\tbuffer.SetSize((int)len);\n\t\t\tptr = 0;\n\t\t}\n\n\t\tchar StreamReader::ReadBufferChar()\n\t\t{\n\t\t\tif (ptr<buffer.Count())\n\t\t\t{\n\t\t\t\treturn buffer[ptr++];\n\t\t\t}\n\t\t\tif (!stream->IsEnd())\n\t\t\t\tReadBuffer();\n\t\t\tif (ptr<buffer.Count())\n\t\t\t{\n\t\t\t\treturn buffer[ptr++];\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\t\tint TextReader::Read(char * destBuffer, int length)\n\t\t{\n\t\t\tint i = 0;\n\t\t\tfor (i = 0; i<length; i++)\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tauto ch = Read();\n\t\t\t\t\tif (IsEnd())\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tif (ch == '\\r')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (Peak() == '\\n')\n\t\t\t\t\t\t\tRead();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (ch == '\\n')\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tdestBuffer[i] = ch;\n\t\t\t\t}\n\t\t\t\tcatch (EndOfStreamException)\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn i;\n\t\t}\n\t\tString StreamReader::ReadLine()\n\t\t{\n\t\t\tStringBuilder sb(256);\n\t\t\twhile (!IsEnd())\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tauto ch = Read();\n\t\t\t\t\tif (IsEnd())\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tif (ch == '\\r')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (Peak() == '\\n')\n\t\t\t\t\t\t\tRead();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (ch == '\\n')\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tsb.Append(ch);\n\t\t\t\t}\n\t\t\t\tcatch (EndOfStreamException)\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn sb.ProduceString();\n\t\t}\n\t\tString StreamReader::ReadToEnd()\n\t\t{\n\t\t\tStringBuilder sb(16384);\n\t\t\twhile (!IsEnd())\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tauto ch = Read();\n\t\t\t\t\tif (IsEnd())\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tif (ch == '\\r')\n\t\t\t\t\t{\n\t\t\t\t\t\tsb.Append('\\n');\n\t\t\t\t\t\tif (Peak() == '\\n')\n\t\t\t\t\t\t\tRead();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tsb.Append(ch);\n\t\t\t\t}\n\t\t\t\tcatch (EndOfStreamException)\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn sb.ProduceString();\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/CoreLib/TextIO.h",
    "content": "#ifndef CORE_LIB_TEXT_IO_H\n#define CORE_LIB_TEXT_IO_H\n\n#include \"SecureCRT.h\"\n#include \"Stream.h\"\n\nnamespace CoreLib\n{\n\tnamespace IO\n\t{\n\t\tusing CoreLib::Basic::List;\n\t\tusing CoreLib::Basic::_EndLine;\n\n\t\tclass TextReader : public CoreLib::Basic::Object\n\t\t{\n\t\tprotected:\n\t\t\tchar decodedChar[5];\n\t\t\tint decodedCharPtr = 0, decodedCharSize = 0;\n\t\t\tvirtual void ReadChar() = 0;\n\t\tpublic:\n\t\t\t~TextReader()\n\t\t\t{\n\t\t\t\tClose();\n\t\t\t}\n\t\t\tvirtual void Close(){}\n\t\t\tvirtual String ReadLine()=0;\n\t\t\tvirtual String ReadToEnd()=0;\n\t\t\tvirtual bool IsEnd() = 0;\n\t\t\tint Read(char * buffer, int count);\n\t\t\tchar Read()\n\t\t\t{\n\t\t\t\tif (decodedCharPtr == decodedCharSize)\n\t\t\t\t\tReadChar();\n\t\t\t\tif (decodedCharPtr < decodedCharSize)\n\t\t\t\t\treturn decodedChar[decodedCharPtr++];\n\t\t\t\telse\n\t\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tchar Peak()\n\t\t\t{\n\t\t\t\tif (decodedCharPtr == decodedCharSize)\n\t\t\t\t\tReadChar();\n\t\t\t\tif (decodedCharPtr < decodedCharSize)\n\t\t\t\t\treturn decodedChar[decodedCharPtr];\n\t\t\t\telse\n\t\t\t\t\treturn 0;\n\t\t\t}\n\t\t};\n\n\t\tclass TextWriter : public CoreLib::Basic::Object\n\t\t{\n\t\tpublic:\n\t\t\t~TextWriter()\n\t\t\t{\n\t\t\t\tClose();\n\t\t\t}\n\t\t\tvirtual void Write(const String & str)=0;\n\t\t\tvirtual void Write(const char * str)=0;\n\t\t\tvirtual void Close(){}\n\t\t\ttemplate<typename T>\n\t\t\tTextWriter & operator << (const T& val)\n\t\t\t{\n\t\t\t\tWrite(val.ToString());\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tTextWriter & operator << (int value)\n\t\t\t{\n\t\t\t\tWrite(String(value));\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tTextWriter & operator << (float value)\n\t\t\t{\n\t\t\t\tWrite(String(value));\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tTextWriter & operator << (double value)\n\t\t\t{\n\t\t\t\tWrite(String(value));\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tTextWriter & operator << (const char* value)\n\t\t\t{\n\t\t\t\tWrite(value);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tTextWriter & operator << (const String & val)\n\t\t\t{\n\t\t\t\tWrite(val);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tTextWriter & operator << (const _EndLine &)\n\t\t\t{\n#ifdef _WIN32\n\t\t\t\tWrite(\"\\r\\n\");\n#else\n\t\t\t\tWrite(\"\\n\");\n#endif\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename ReadCharFunc>\n\t\tint GetUnicodePointFromUTF8(const ReadCharFunc & get)\n\t\t{\n\t\t\tint codePoint = 0;\n\t\t\tint leading = get(0);\n\t\t\tint mask = 0x80;\n\t\t\tint count = 0;\n\t\t\twhile (leading & mask)\n\t\t\t{\n\t\t\t\tcount++;\n\t\t\t\tmask >>= 1;\n\t\t\t}\n\t\t\tcodePoint = (leading & (mask - 1));\n\t\t\tfor (int i = 1; i <= count - 1; i++)\n\t\t\t{\n\t\t\t\tcodePoint <<= 6;\n\t\t\t\tcodePoint += (get(i) & 0x3F);\n\t\t\t}\n\t\t\treturn codePoint;\n\t\t}\n\n\t\ttemplate <typename ReadCharFunc>\n\t\tint GetUnicodePointFromUTF16(const ReadCharFunc & get)\n\t\t{\n\t\t\tint byte0 = (unsigned char)get(0);\n\t\t\tint byte1 = (unsigned char)get(1);\n\t\t\tint word0 = byte0 + (byte1 << 8);\n\t\t\tif (word0 >= 0xD800 && word0 <= 0xDFFF)\n\t\t\t{\n\t\t\t\tint byte2 = (unsigned char)get(2);\n\t\t\t\tint byte3 = (unsigned char)get(3);\n\t\t\t\tint word1 = byte2 + (byte3 << 8);\n\t\t\t\treturn ((word0 & 0x3FF) << 10) + (word1 & 0x3FF) + 0x10000;\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn word0;\n\t\t}\n\n\t\ttemplate <typename ReadCharFunc>\n\t\tint GetUnicodePointFromUTF16Reversed(const ReadCharFunc & get)\n\t\t{\n\t\t\tint byte0 = (unsigned char)get(0);\n\t\t\tint byte1 = (unsigned char)get(1);\n\t\t\tint word0 = (byte0 << 8) + byte1;\n\t\t\tif (word0 >= 0xD800 && word0 <= 0xDFFF)\n\t\t\t{\n\t\t\t\tint byte2 = (unsigned char)get(2);\n\t\t\t\tint byte3 = (unsigned char)get(3);\n\t\t\t\tint word1 = (byte2 << 8) + byte3;\n\t\t\t\treturn ((word0 & 0x3FF) << 10) + (word1 & 0x3FF);\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn word0;\n\t\t}\n\n\t\ttemplate <typename ReadCharFunc>\n\t\tint GetUnicodePointFromUTF32(const ReadCharFunc & get)\n\t\t{\n\t\t\tint byte0 = (unsigned char)get(0);\n\t\t\tint byte1 = (unsigned char)get(1);\n\t\t\tint byte2 = (unsigned char)get(2);\n\t\t\tint byte3 = (unsigned char)get(3);\n\t\t\treturn byte0 + (byte1 << 8) + (byte2 << 16) + (byte3 << 24);\n\t\t}\n\n\t\tinline int EncodeUnicodePointToUTF8(char * buffer, int codePoint)\n\t\t{\n\t\t\tint count = 0;\n\t\t\tif (codePoint <= 0x7F)\n\t\t\t\tbuffer[count++] = ((char)codePoint);\n\t\t\telse if (codePoint <= 0x7FF)\n\t\t\t{\n\t\t\t\tunsigned char byte = (unsigned char)(0xC0 + (codePoint >> 6));\n\t\t\t\tbuffer[count++] = ((char)byte);\n\t\t\t\tbyte = 0x80 + (codePoint & 0x3F);\n\t\t\t\tbuffer[count++] = ((char)byte);\n\t\t\t}\n\t\t\telse if (codePoint <= 0xFFFF)\n\t\t\t{\n\t\t\t\tunsigned char byte = (unsigned char)(0xE0 + (codePoint >> 12));\n\t\t\t\tbuffer[count++] = ((char)byte);\n\t\t\t\tbyte = (unsigned char)(0x80 + ((codePoint >> 6) & (0x3F)));\n\t\t\t\tbuffer[count++] = ((char)byte);\n\t\t\t\tbyte = (unsigned char)(0x80 + (codePoint & 0x3F));\n\t\t\t\tbuffer[count++] = ((char)byte);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tunsigned char byte = (unsigned char)(0xF0 + (codePoint >> 18));\n\t\t\t\tbuffer[count++] = ((char)byte);\n\t\t\t\tbyte = (unsigned char)(0x80 + ((codePoint >> 12) & 0x3F));\n\t\t\t\tbuffer[count++] = ((char)byte);\n\t\t\t\tbyte = (unsigned char)(0x80 + ((codePoint >> 6) & 0x3F));\n\t\t\t\tbuffer[count++] = ((char)byte);\n\t\t\t\tbyte = (unsigned char)(0x80 + (codePoint & 0x3F));\n\t\t\t\tbuffer[count++] = ((char)byte);\n\t\t\t}\n\t\t\treturn count;\n\t\t}\n\n\t\tinline int EncodeUnicodePointToUTF16(unsigned short * buffer, int codePoint)\n\t\t{\n\t\t\tint count = 0;\n\t\t\tif (codePoint <= 0xD7FF || (codePoint >= 0xE000 && codePoint <= 0xFFFF))\n\t\t\t\tbuffer[count++] = (unsigned short)codePoint;\n\t\t\telse\n\t\t\t{\n\t\t\t\tint sub = codePoint - 0x10000;\n\t\t\t\tint high = (sub >> 10) + 0xD800;\n\t\t\t\tint low = (sub & 0x3FF) + 0xDC00;\n\t\t\t\tbuffer[count++] = (unsigned short)high;\n\t\t\t\tbuffer[count++] = (unsigned short)low;\n\t\t\t}\n\t\t\treturn count;\n\t\t}\n\n\t\tinline unsigned short ReverseBitOrder(unsigned short val)\n\t\t{\n\t\t\tint byte0 = val & 0xFF;\n\t\t\tint byte1 = val >> 8;\n\t\t\treturn (unsigned short)(byte1 + (byte0 << 8));\n\t\t}\n\n\t\tinline int EncodeUnicodePointToUTF16Reversed(unsigned short * buffer, int codePoint)\n\t\t{\n\t\t\tint count = 0;\n\t\t\tif (codePoint <= 0xD7FF || (codePoint >= 0xE000 && codePoint <= 0xFFFF))\n\t\t\t\tbuffer[count++] = ReverseBitOrder((unsigned short)codePoint);\n\t\t\telse\n\t\t\t{\n\t\t\t\tint sub = codePoint - 0x10000;\n\t\t\t\tint high = (sub >> 10) + 0xD800;\n\t\t\t\tint low = (sub & 0x3FF) + 0xDC00;\n\t\t\t\tbuffer[count++] = ReverseBitOrder((unsigned short)high);\n\t\t\t\tbuffer[count++] = ReverseBitOrder((unsigned short)low);\n\t\t\t}\n\t\t\treturn count;\n\t\t}\n\n\t\tclass Encoding\n\t\t{\n\t\tpublic:\n\t\t\tstatic Encoding * UTF8, * UTF16, *UTF16Reversed, * UTF32;\n\t\t\tvirtual void GetBytes(List<char>& buffer, const String & str) = 0;\n\t\t\tvirtual String ToString(const char * buffer, int length) = 0;\n\t\t\tvirtual ~Encoding()\n\t\t\t{}\n\t\t};\n\n\t\tclass StreamWriter : public TextWriter\n\t\t{\n\t\tprivate:\n\t\t\tList<char> encodingBuffer;\n\t\t\tRefPtr<Stream> stream;\n\t\t\tEncoding * encoding;\n\t\tpublic:\n\t\t\tStreamWriter(const String & path, Encoding * encoding = Encoding::UTF8);\n\t\t\tStreamWriter(RefPtr<Stream> stream, Encoding * encoding = Encoding::UTF8);\n\t\t\tvirtual void Write(const String & str);\n\t\t\tvirtual void Write(const char * str);\n\t\t\tvirtual void Close()\n\t\t\t{\n\t\t\t\tstream->Close();\n\t\t\t}\n            void ReleaseStream()\n            {\n                stream.Release();\n            }\n\t\t};\n\n\t\tclass StreamReader : public TextReader\n\t\t{\n\t\tprivate:\n\t\t\tRefPtr<Stream> stream;\n\t\t\tList<char> buffer;\n\t\t\tEncoding * encoding;\n\t\t\tint ptr;\n\t\t\tchar ReadBufferChar();\n\t\t\tvoid ReadBuffer();\n\t\t\t\n\t\t\tEncoding * DetermineEncoding();\n\t\tprotected:\n\t\t\tvirtual void ReadChar()\n\t\t\t{\n\t\t\t\tdecodedCharPtr = 0;\n\t\t\t\tint codePoint = 0;\n\t\t\t\tif (encoding == Encoding::UTF8)\n\t\t\t\t\tcodePoint = GetUnicodePointFromUTF8([&](int) {return ReadBufferChar(); });\n\t\t\t\telse if (encoding == Encoding::UTF16)\n\t\t\t\t\tcodePoint = GetUnicodePointFromUTF16([&](int) {return ReadBufferChar(); });\n\t\t\t\telse if (encoding == Encoding::UTF16Reversed)\n\t\t\t\t\tcodePoint = GetUnicodePointFromUTF16Reversed([&](int) {return ReadBufferChar(); });\n\t\t\t\telse if (encoding == Encoding::UTF32)\n\t\t\t\t\tcodePoint = GetUnicodePointFromUTF32([&](int) {return ReadBufferChar(); });\n\t\t\t\tdecodedCharSize = EncodeUnicodePointToUTF8(decodedChar, codePoint);\n\t\t\t}\n\t\tpublic:\n\t\t\tStreamReader(const String & path);\n\t\t\tStreamReader(RefPtr<Stream> stream, Encoding * encoding = nullptr);\n\t\t\tvirtual String ReadLine();\n\t\t\tvirtual String ReadToEnd();\n\t\t\tvirtual bool IsEnd()\n\t\t\t{\n\t\t\t\treturn ptr == buffer.Count() && stream->IsEnd();\n\t\t\t}\n\t\t\tvirtual void Close()\n\t\t\t{\n\t\t\t\tstream->Close();\n\t\t\t}\n            void ReleaseStream()\n            {\n                stream.Release();\n            }\n\t\t};\n\n\t}\n}\n\n#endif\n"
  },
  {
    "path": "Source/CoreLib/Tokenizer.cpp",
    "content": "#include \"Tokenizer.h\"\n\nusing namespace CoreLib::Basic;\n\nnamespace CoreLib\n{\n\tnamespace Text\n\t{\n\t\tTokenReader::TokenReader(String text)\n\t\t{\n\t\t\tthis->tokens = TokenizeText(\"\", text, [&](TokenizeErrorType, CodePosition) {legal = false; });\n\t\t\ttokenPtr = 0;\n\t\t}\n\n\t\tenum class State\n\t\t{\n\t\t\tStart, Identifier, Operator, Int, Hex, Fixed, Double, Char, String, MultiComment, SingleComment\n\t\t};\n\n\t\tenum class LexDerivative\n\t\t{\n\t\t\tNone, Line, File\n\t\t};\n\n\t\tvoid ParseOperators(const String & str, List<Token> & tokens, TokenFlags& tokenFlags, int line, int col, int startPos, String fileName)\n\t\t{\n\t\t\tint pos = 0;\n\t\t\twhile (pos < str.Length())\n\t\t\t{\n\t\t\t\twchar_t curChar = str[pos];\n\t\t\t\twchar_t nextChar = (pos < str.Length() - 1) ? str[pos + 1] : '\\0';\n\t\t\t\twchar_t nextNextChar = (pos < str.Length() - 2) ? str[pos + 2] : '\\0';\n\t\t\t\tauto InsertToken = [&](TokenType type, const String & ct)\n\t\t\t\t{\n\t\t\t\t\ttokens.Add(Token(type, ct, line, col + pos, pos + startPos, fileName, tokenFlags));\n                    tokenFlags = 0;\n\t\t\t\t};\n\t\t\t\tswitch (curChar)\n\t\t\t\t{\n\t\t\t\tcase '+':\n\t\t\t\t\tif (nextChar == '+')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpInc, \"++\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse if (nextChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpAddAssign, \"+=\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpAdd, \"+\");\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '-':\n\t\t\t\t\tif (nextChar == '-')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpDec, \"--\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse if (nextChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpSubAssign, \"-=\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse if (nextChar == '>')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::RightArrow, \"->\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpSub, \"-\");\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '*':\n\t\t\t\t\tif (nextChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpMulAssign, \"*=\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpMul, \"*\");\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '/':\n\t\t\t\t\tif (nextChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpDivAssign, \"/=\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpDiv, \"/\");\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '%':\n\t\t\t\t\tif (nextChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpModAssign, \"%=\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpMod, \"%\");\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '|':\n\t\t\t\t\tif (nextChar == '|')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpOr, \"||\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse if (nextChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpOrAssign, \"|=\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpBitOr, \"|\");\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '&':\n\t\t\t\t\tif (nextChar == '&')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpAnd, \"&&\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse if (nextChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpAndAssign, \"&=\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpBitAnd, \"&\");\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '^':\n\t\t\t\t\tif (nextChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpXorAssign, \"^=\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpBitXor, \"^\");\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '>':\n\t\t\t\t\tif (nextChar == '>')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (nextNextChar == '=')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tInsertToken(TokenType::OpShrAssign, \">>=\");\n\t\t\t\t\t\t\tpos += 3;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tInsertToken(TokenType::OpRsh, \">>\");\n\t\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (nextChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpGeq, \">=\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpGreater, \">\");\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '<':\n\t\t\t\t\tif (nextChar == '<')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (nextNextChar == '=')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tInsertToken(TokenType::OpShlAssign, \"<<=\");\n\t\t\t\t\t\t\tpos += 3;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tInsertToken(TokenType::OpLsh, \"<<\");\n\t\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (nextChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpLeq, \"<=\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpLess, \"<\");\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '=':\n\t\t\t\t\tif (nextChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpEql, \"==\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpAssign, \"=\");\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '!':\n\t\t\t\t\tif (nextChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpNeq, \"!=\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::OpNot, \"!\");\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase '?':\n\t\t\t\t\tInsertToken(TokenType::QuestionMark, \"?\");\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase '@':\n\t\t\t\t\tInsertToken(TokenType::At, \"@\");\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n                case '#':\n                    if (nextChar == '#')\n\t\t\t\t\t{\n                        InsertToken(TokenType::PoundPound, \"##\");\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n                        InsertToken(TokenType::Pound, \"#\");\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ':':\n\t\t\t\t\tInsertToken(TokenType::Colon, \":\");\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase '~':\n\t\t\t\t\tInsertToken(TokenType::OpBitNot, \"~\");\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ';':\n\t\t\t\t\tInsertToken(TokenType::Semicolon, \";\");\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ',':\n\t\t\t\t\tInsertToken(TokenType::Comma, \",\");\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase '.':\n\t\t\t\t\tInsertToken(TokenType::Dot, \".\");\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase '{':\n\t\t\t\t\tInsertToken(TokenType::LBrace, \"{\");\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase '}':\n\t\t\t\t\tInsertToken(TokenType::RBrace, \"}\");\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase '[':\n\t\t\t\t\tInsertToken(TokenType::LBracket, \"[\");\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ']':\n\t\t\t\t\tInsertToken(TokenType::RBracket, \"]\");\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase '(':\n\t\t\t\t\tInsertToken(TokenType::LParent, \"(\");\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ')':\n\t\t\t\t\tInsertToken(TokenType::RParent, \")\");\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tList<Token> TokenizeText(const String & fileName, const String & text, Procedure<TokenizeErrorType, CodePosition> errorHandler)\n\t\t{\n\t\t\tint lastPos = 0, pos = 0;\n\t\t\tint line = 1, col = 0;\n\t\t\tString file = fileName;\n\t\t\tState state = State::Start;\n\t\t\tStringBuilder tokenBuilder;\n\t\t\tint tokenLine, tokenCol;\n\t\t\tList<Token> tokenList;\n\t\t\tLexDerivative derivative = LexDerivative::None;\n            TokenFlags tokenFlags = TokenFlag::AtStartOfLine;\n\t\t\tauto InsertToken = [&](TokenType type)\n\t\t\t{\n\t\t\t\tderivative = LexDerivative::None;\n\t\t\t\ttokenList.Add(Token(type, tokenBuilder.ToString(), tokenLine, tokenCol, pos, file, tokenFlags));\n                tokenFlags = 0;\n\t\t\t\ttokenBuilder.Clear();\n\t\t\t};\n\t\t\tauto ProcessTransferChar = [&](char nextChar)\n\t\t\t{\n\t\t\t\tswitch (nextChar)\n\t\t\t\t{\n\t\t\t\tcase '\\\\':\n\t\t\t\tcase '\\\"':\n\t\t\t\tcase '\\'':\n\t\t\t\t\ttokenBuilder.Append(nextChar);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 't':\n\t\t\t\t\ttokenBuilder.Append('\\t');\n\t\t\t\t\tbreak;\n\t\t\t\tcase 's':\n\t\t\t\t\ttokenBuilder.Append(' ');\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'n':\n\t\t\t\t\ttokenBuilder.Append('\\n');\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'r':\n\t\t\t\t\ttokenBuilder.Append('\\r');\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'b':\n\t\t\t\t\ttokenBuilder.Append('\\b');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t};\n\t\t\twhile (pos <= text.Length())\n\t\t\t{\n\t\t\t\tchar curChar = (pos < text.Length() ? text[pos] : ' ');\n\t\t\t\tchar nextChar = (pos < text.Length() - 1) ? text[pos + 1] : '\\0';\n\t\t\t\tif (lastPos != pos)\n\t\t\t\t{\n\t\t\t\t\tif (curChar == '\\n')\n\t\t\t\t\t{\n\t\t\t\t\t\tline++;\n\t\t\t\t\t\tcol = 0;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tcol++;\n\t\t\t\t\tlastPos = pos;\n\t\t\t\t}\n\n\t\t\t\tswitch (state)\n\t\t\t\t{\n\t\t\t\tcase State::Start:\n\t\t\t\t\tif (IsLetter(curChar))\n\t\t\t\t\t{\n\t\t\t\t\t\tstate = State::Identifier;\n\t\t\t\t\t\ttokenLine = line;\n\t\t\t\t\t\ttokenCol = col;\n\t\t\t\t\t}\n\t\t\t\t\telse if (IsDigit(curChar))\n\t\t\t\t\t{\n\t\t\t\t\t\tstate = State::Int;\n\t\t\t\t\t\ttokenLine = line;\n\t\t\t\t\t\ttokenCol = col;\n\t\t\t\t\t}\n\t\t\t\t\telse if (curChar == '\\'')\n\t\t\t\t\t{\n\t\t\t\t\t\tstate = State::Char;\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t\ttokenLine = line;\n\t\t\t\t\t\ttokenCol = col;\n\t\t\t\t\t}\n\t\t\t\t\telse if (curChar == '\"')\n\t\t\t\t\t{\n\t\t\t\t\t\tstate = State::String;\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t\ttokenLine = line;\n\t\t\t\t\t\ttokenCol = col;\n\t\t\t\t\t}\n                    else if (curChar == '\\r' || curChar == '\\n')\n                    {\n                        tokenFlags |= TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace;\n                        pos++;\n                    }\n\t\t\t\t\telse if (curChar == ' ' || curChar == '\\t' || curChar == -62 || curChar== -96) // -62/-96:non-break space\n                    {\n                        tokenFlags |= TokenFlag::AfterWhitespace;\n\t\t\t\t\t\tpos++;\n                    }\n\t\t\t\t\telse if (curChar == '/' && nextChar == '/')\n\t\t\t\t\t{\n\t\t\t\t\t\tstate = State::SingleComment;\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse if (curChar == '/' && nextChar == '*')\n\t\t\t\t\t{\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t\tstate = State::MultiComment;\n\t\t\t\t\t}\n\t\t\t\t\telse if (curChar == '.' && IsDigit(nextChar))\n\t\t\t\t\t{\n\t\t\t\t\t\ttokenBuilder.Append(\"0.\");\n\t\t\t\t\t\tstate = State::Fixed;\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\telse if (IsPunctuation(curChar))\n\t\t\t\t\t{\n\t\t\t\t\t\tstate = State::Operator;\n\t\t\t\t\t\ttokenLine = line;\n\t\t\t\t\t\ttokenCol = col;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\terrorHandler(TokenizeErrorType::InvalidCharacter, CodePosition(line, col, pos, file));\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase State::Identifier:\n\t\t\t\t\tif (IsLetter(curChar) || IsDigit(curChar))\n\t\t\t\t\t{\n\t\t\t\t\t\ttokenBuilder.Append(curChar);\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tauto tokenStr = tokenBuilder.ToString();\n#if 0\n\t\t\t\t\t\tif (tokenStr == \"#line_reset#\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tline = 0;\n\t\t\t\t\t\t\tcol = 0;\n\t\t\t\t\t\t\ttokenBuilder.Clear();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (tokenStr == \"#line\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tderivative = LexDerivative::Line;\n\t\t\t\t\t\t\ttokenBuilder.Clear();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (tokenStr == \"#file\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tderivative = LexDerivative::File;\n\t\t\t\t\t\t\ttokenBuilder.Clear();\n\t\t\t\t\t\t\tline = 0;\n\t\t\t\t\t\t\tcol = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n#endif\n\t\t\t\t\t\t\tInsertToken(TokenType::Identifier);\n\t\t\t\t\t\tstate = State::Start;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase State::Operator:\n\t\t\t\t\tif (IsPunctuation(curChar) && !((curChar == '/' && nextChar == '/') || (curChar == '/' && nextChar == '*')))\n\t\t\t\t\t{\n\t\t\t\t\t\ttokenBuilder.Append(curChar);\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t//do token analyze\n\t\t\t\t\t\tParseOperators(tokenBuilder.ToString(), tokenList, tokenFlags, tokenLine, tokenCol, pos - tokenBuilder.Length(), file);\n\t\t\t\t\t\ttokenBuilder.Clear();\n\t\t\t\t\t\tstate = State::Start;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase State::Int:\n\t\t\t\t\tif (IsDigit(curChar))\n\t\t\t\t\t{\n\t\t\t\t\t\ttokenBuilder.Append(curChar);\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\telse if (curChar == '.')\n\t\t\t\t\t{\n\t\t\t\t\t\tstate = State::Fixed;\n\t\t\t\t\t\ttokenBuilder.Append(curChar);\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\telse if (curChar == 'e' || curChar == 'E')\n\t\t\t\t\t{\n\t\t\t\t\t\tstate = State::Double;\n\t\t\t\t\t\ttokenBuilder.Append(curChar);\n\t\t\t\t\t\tif (nextChar == '-' || nextChar == '+')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttokenBuilder.Append(nextChar);\n\t\t\t\t\t\t\tpos++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\telse if (curChar == 'x')\n\t\t\t\t\t{\n\t\t\t\t\t\tstate = State::Hex;\n\t\t\t\t\t\ttokenBuilder.Append(curChar);\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\telse if (curChar == 'u')\n\t\t\t\t\t{\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t\ttokenBuilder.Append(curChar);\n\t\t\t\t\t\tInsertToken(TokenType::IntLiterial);\n\t\t\t\t\t\tstate = State::Start;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (derivative == LexDerivative::Line)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tderivative = LexDerivative::None;\n\t\t\t\t\t\t\tline = StringToInt(tokenBuilder.ToString()) - 1;\n\t\t\t\t\t\t\tcol = 0;\n\t\t\t\t\t\t\ttokenBuilder.Clear();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tInsertToken(TokenType::IntLiterial);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstate = State::Start;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase State::Hex:\n\t\t\t\t\tif (IsDigit(curChar) || (curChar>='a' && curChar <= 'f') || (curChar >= 'A' && curChar <= 'F'))\n\t\t\t\t\t{\n\t\t\t\t\t\ttokenBuilder.Append(curChar);\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tInsertToken(TokenType::IntLiterial);\n\t\t\t\t\t\tstate = State::Start;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase State::Fixed:\n\t\t\t\t\tif (IsDigit(curChar))\n\t\t\t\t\t{\n\t\t\t\t\t\ttokenBuilder.Append(curChar);\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\telse if (curChar == 'e' || curChar == 'E')\n\t\t\t\t\t{\n\t\t\t\t\t\tstate = State::Double;\n\t\t\t\t\t\ttokenBuilder.Append(curChar);\n\t\t\t\t\t\tif (nextChar == '-' || nextChar == '+')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttokenBuilder.Append(nextChar);\n\t\t\t\t\t\t\tpos++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (curChar == 'f')\n\t\t\t\t\t\t\tpos++;\n\t\t\t\t\t\tInsertToken(TokenType::DoubleLiterial);\n\t\t\t\t\t\tstate = State::Start;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase State::Double:\n\t\t\t\t\tif (IsDigit(curChar))\n\t\t\t\t\t{\n\t\t\t\t\t\ttokenBuilder.Append(curChar);\n\t\t\t\t\t\tpos++;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (curChar == 'f')\n\t\t\t\t\t\t\tpos++;\n\t\t\t\t\t\tInsertToken(TokenType::DoubleLiterial);\n\t\t\t\t\t\tstate = State::Start;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase State::String:\n\t\t\t\t\tif (curChar != '\"')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (curChar == '\\\\')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tProcessTransferChar(nextChar);\n\t\t\t\t\t\t\tpos++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\ttokenBuilder.Append(curChar);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (derivative == LexDerivative::File)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tderivative = LexDerivative::None;\n\t\t\t\t\t\t\tfile = tokenBuilder.ToString();\n\t\t\t\t\t\t\ttokenBuilder.Clear();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tInsertToken(TokenType::StringLiterial);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstate = State::Start;\n\t\t\t\t\t}\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase State::Char:\n\t\t\t\t\tif (curChar != '\\'')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (curChar == '\\\\')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tProcessTransferChar(nextChar);\n\t\t\t\t\t\t\tpos++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\ttokenBuilder.Append(curChar);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (tokenBuilder.Length() > 1)\n\t\t\t\t\t\t\terrorHandler(TokenizeErrorType::InvalidEscapeSequence, CodePosition(line, col - tokenBuilder.Length(), pos, file));\n\n\t\t\t\t\t\tInsertToken(TokenType::CharLiterial);\n\t\t\t\t\t\tstate = State::Start;\n\t\t\t\t\t}\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase State::SingleComment:\n\t\t\t\t\tif( curChar == '\\n' )\n\t\t\t\t\t{\n\t\t\t\t\t\tstate = State::Start;\n\t\t\t\t\t\ttokenFlags |= TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace;\n\t\t\t\t\t}\n\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase State::MultiComment:\n\t\t\t\t\tif (curChar == '*' && nextChar == '/')\n\t\t\t\t\t{\n\t\t\t\t\t\tstate = State::Start;\n\t\t\t\t\t\ttokenFlags |= TokenFlag::AfterWhitespace;\n\t\t\t\t\t\tpos += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tpos++;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn tokenList;\n\t\t}\n\t\tList<Token> TokenizeText(const String & fileName, const String & text)\n\t\t{\n\t\t\treturn TokenizeText(fileName, text, [](TokenizeErrorType, CodePosition) {});\n\t\t}\n\t\tList<Token> TokenizeText(const String & text)\n\t\t{\n\t\t\treturn TokenizeText(\"\", text, [](TokenizeErrorType, CodePosition) {});\n\t\t}\n\n\t\tString EscapeStringLiteral(String str)\n\t\t{\n\t\t\tStringBuilder sb;\n\t\t\tsb << \"\\\"\";\n\t\t\tfor (int i = 0; i < str.Length(); i++)\n\t\t\t{\n\t\t\t\tswitch (str[i])\n\t\t\t\t{\n\t\t\t\tcase ' ':\n\t\t\t\t\tsb << \"\\\\s\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase '\\n':\n\t\t\t\t\tsb << \"\\\\n\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase '\\r':\n\t\t\t\t\tsb << \"\\\\r\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase '\\t':\n\t\t\t\t\tsb << \"\\\\t\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase '\\v':\n\t\t\t\t\tsb << \"\\\\v\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase '\\'':\n\t\t\t\t\tsb << \"\\\\\\'\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase '\\\"':\n\t\t\t\t\tsb << \"\\\\\\\"\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase '\\\\':\n\t\t\t\t\tsb << \"\\\\\\\\\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tsb << str[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tsb << \"\\\"\";\n\t\t\treturn sb.ProduceString();\n\t\t}\n\n\t\tString UnescapeStringLiteral(String str)\n\t\t{\n\t\t\tStringBuilder sb;\n\t\t\tfor (int i = 0; i < str.Length(); i++)\n\t\t\t{\n\t\t\t\tif (str[i] == '\\\\' && i < str.Length() - 1)\n\t\t\t\t{\n\t\t\t\t\tswitch (str[i + 1])\n\t\t\t\t\t{\n\t\t\t\t\tcase 's':\n\t\t\t\t\t\tsb << \" \";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 't':\n\t\t\t\t\t\tsb << '\\t';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'n':\n\t\t\t\t\t\tsb << '\\n';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'r':\n\t\t\t\t\t\tsb << '\\r';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'v':\n\t\t\t\t\t\tsb << '\\v';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '\\'':\n\t\t\t\t\t\tsb << '\\'';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '\\\"':\n\t\t\t\t\t\tsb << \"\\\"\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\tsb << \"\\\\\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\ti = i - 1;\n\t\t\t\t\t\tsb << str[i];\n\t\t\t\t\t}\n\t\t\t\t\ti++;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tsb << str[i];\n\t\t\t}\n\t\t\treturn sb.ProduceString();\n\t\t}\n\n\n\t\tString TokenTypeToString(TokenType type)\n\t\t{\n\t\t\tswitch (type)\n\t\t\t{\n\t\t\tcase TokenType::EndOfFile:\n\t\t\t\treturn \"end of file\";\n\t\t\tcase TokenType::Unknown:\n\t\t\t\treturn \"UnknownToken\";\n\t\t\tcase TokenType::Identifier:\n\t\t\t\treturn \"identifier\";\n\t\t\tcase TokenType::IntLiterial:\n\t\t\t\treturn \"integer literal\";\n\t\t\tcase TokenType::DoubleLiterial:\n\t\t\t\treturn \"floating-point literal\";\n\t\t\tcase TokenType::StringLiterial:\n\t\t\t\treturn \"string literal\";\n\t\t\tcase TokenType::CharLiterial:\n\t\t\t\treturn \"character literal\";\n\t\t\tcase TokenType::QuestionMark:\n\t\t\t\treturn \"'?'\";\n\t\t\tcase TokenType::Colon:\n\t\t\t\treturn \"':'\";\n\t\t\tcase TokenType::Semicolon:\n\t\t\t\treturn \"';'\";\n\t\t\tcase TokenType::Comma:\n\t\t\t\treturn \"','\";\n\t\t\tcase TokenType::LBrace:\n\t\t\t\treturn \"'{'\";\n\t\t\tcase TokenType::RBrace:\n\t\t\t\treturn \"'}'\";\n\t\t\tcase TokenType::LBracket:\n\t\t\t\treturn \"'['\";\n\t\t\tcase TokenType::RBracket:\n\t\t\t\treturn \"']'\";\n\t\t\tcase TokenType::LParent:\n\t\t\t\treturn \"'('\";\n\t\t\tcase TokenType::RParent:\n\t\t\t\treturn \"')'\";\n\t\t\tcase TokenType::At:\n\t\t\t\treturn \"'@'\";\n\t\t\tcase TokenType::OpAssign:\n\t\t\t\treturn \"'='\";\n\t\t\tcase TokenType::OpAdd:\n\t\t\t\treturn \"'+'\";\n\t\t\tcase TokenType::OpSub:\n\t\t\t\treturn \"'-'\";\n\t\t\tcase TokenType::OpMul:\n\t\t\t\treturn \"'*'\";\n\t\t\tcase TokenType::OpDiv:\n\t\t\t\treturn \"'/'\";\n\t\t\tcase TokenType::OpMod:\n\t\t\t\treturn \"'%'\";\n\t\t\tcase TokenType::OpNot:\n\t\t\t\treturn \"'!'\";\n\t\t\tcase TokenType::OpLsh:\n\t\t\t\treturn \"'<<'\";\n\t\t\tcase TokenType::OpRsh:\n\t\t\t\treturn \"'>>'\";\n\t\t\tcase TokenType::OpAddAssign:\n\t\t\t\treturn \"'+='\";\n\t\t\tcase TokenType::OpSubAssign:\n\t\t\t\treturn \"'-='\";\n\t\t\tcase TokenType::OpMulAssign:\n\t\t\t\treturn \"'*='\";\n\t\t\tcase TokenType::OpDivAssign:\n\t\t\t\treturn \"'/='\";\n\t\t\tcase TokenType::OpModAssign:\n\t\t\t\treturn \"'%='\";\n\t\t\tcase TokenType::OpEql:\n\t\t\t\treturn \"'=='\";\n\t\t\tcase TokenType::OpNeq:\n\t\t\t\treturn \"'!='\";\n\t\t\tcase TokenType::OpGreater:\n\t\t\t\treturn \"'>'\";\n\t\t\tcase TokenType::OpLess:\n\t\t\t\treturn \"'<'\";\n\t\t\tcase TokenType::OpGeq:\n\t\t\t\treturn \"'>='\";\n\t\t\tcase TokenType::OpLeq:\n\t\t\t\treturn \"'<='\";\n\t\t\tcase TokenType::OpAnd:\n\t\t\t\treturn \"'&&'\";\n\t\t\tcase TokenType::OpOr:\n\t\t\t\treturn \"'||'\";\n\t\t\tcase TokenType::OpBitXor:\n\t\t\t\treturn \"'^'\";\n\t\t\tcase TokenType::OpBitAnd:\n\t\t\t\treturn \"'&'\";\n\t\t\tcase TokenType::OpBitOr:\n\t\t\t\treturn \"'|'\";\n\t\t\tcase TokenType::OpInc:\n\t\t\t\treturn \"'++'\";\n\t\t\tcase TokenType::OpDec:\n\t\t\t\treturn \"'--'\";\n\t\t\tcase TokenType::Pound:\n\t\t\t\treturn \"'#'\";\n\t\t\tcase TokenType::PoundPound:\n\t\t\t\treturn \"'##'\";\n\t\t\tdefault:\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t}\n\n\t\tList<String> Split(String text, char c)\n\t\t{\n\t\t\tList<String> result;\n\t\t\tStringBuilder sb;\n\t\t\tfor (int i = 0; i < text.Length(); i++)\n\t\t\t{\n\t\t\t\tif (text[i] == c)\n\t\t\t\t{\n\t\t\t\t\tauto str = sb.ToString();\n\t\t\t\t\tif (str.Length() != 0)\n\t\t\t\t\t\tresult.Add(str);\n\t\t\t\t\tsb.Clear();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tsb << text[i];\n\t\t\t}\n\t\t\tauto lastStr = sb.ToString();\n\t\t\tif (lastStr.Length())\n\t\t\t\tresult.Add(lastStr);\n\t\t\treturn result;\n\t\t}\n\n\t}\n}"
  },
  {
    "path": "Source/CoreLib/Tokenizer.h",
    "content": "#ifndef CORELIB_TEXT_PARSER_H\n#define CORELIB_TEXT_PARSER_H\n\n#include \"Basic.h\"\n\nnamespace CoreLib\n{\n\tnamespace Text\n\t{\n\t\tclass TextFormatException : public Exception\n\t\t{\n\t\tpublic:\n\t\t\tTextFormatException(String message)\n\t\t\t\t: Exception(message)\n\t\t\t{}\n\t\t};\n\n\t\tinline bool IsLetter(char ch)\n\t\t{\n\t\t\treturn ((ch >= 'a' && ch <= 'z') ||\n\t\t\t\t(ch >= 'A' && ch <= 'Z') || ch == '_');\n\t\t}\n\n\t\tinline bool IsDigit(char ch)\n\t\t{\n\t\t\treturn ch >= '0' && ch <= '9';\n\t\t}\n\n\t\tinline bool IsPunctuation(char ch)\n\t\t{\n\t\t\treturn  ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' ||\n\t\t\t\tch == '!' || ch == '^' || ch == '&' || ch == '(' || ch == ')' ||\n\t\t\t\tch == '=' || ch == '{' || ch == '}' || ch == '[' || ch == ']' ||\n\t\t\t\tch == '|' || ch == ';' || ch == ',' || ch == '.' || ch == '<' ||\n                ch == '>' || ch == '~' || ch == '@' || ch == ':' || ch == '?' || ch == '#';\n\t\t}\n\n\t\tinline bool IsWhiteSpace(char ch)\n\t\t{\n\t\t\treturn (ch == ' ' || ch == '\\t' || ch == '\\n' || ch == '\\r' || ch == '\\v');\n\t\t}\n\n\t\tclass CodePosition\n\t\t{\n\t\tpublic:\n\t\t\tint Line = -1, Col = -1, Pos = -1;\n\t\t\tString FileName;\n\t\t\tString ToString()\n\t\t\t{\n\t\t\t\tStringBuilder sb(100);\n\t\t\t\tsb << FileName;\n\t\t\t\tif (Line != -1)\n\t\t\t\t\tsb << \"(\" << Line << \")\";\n\t\t\t\treturn sb.ProduceString();\n\t\t\t}\n\t\t\tCodePosition() = default;\n\t\t\tCodePosition(int line, int col, int pos, String fileName)\n\t\t\t{\n\t\t\t\tLine = line;\n\t\t\t\tCol = col;\n\t\t\t\tPos = pos;\n\t\t\t\tthis->FileName = fileName;\n\t\t\t}\n\t\t\tbool operator < (const CodePosition & pos) const\n\t\t\t{\n\t\t\t\treturn FileName < pos.FileName || (FileName == pos.FileName && Line < pos.Line) ||\n\t\t\t\t\t(FileName == pos.FileName && Line == pos.Line && Col < pos.Col);\n\t\t\t}\n\t\t\tbool operator == (const CodePosition & pos) const\n\t\t\t{\n\t\t\t\treturn FileName == pos.FileName && Line == pos.Line && Col == pos.Col;\n\t\t\t}\n\t\t};\n\n\t\tenum class TokenType\n\t\t{\n            EndOfFile = -1,\n\t\t\t// illegal\n\t\t\tUnknown,\n\t\t\t// identifier\n\t\t\tIdentifier,\n\t\t\t// constant\n\t\t\tIntLiterial, DoubleLiterial, StringLiterial, CharLiterial,\n\t\t\t// operators\n\t\t\tSemicolon, Comma, Dot, LBrace, RBrace, LBracket, RBracket, LParent, RParent,\n\t\t\tOpAssign, OpAdd, OpSub, OpMul, OpDiv, OpMod, OpNot, OpBitNot, OpLsh, OpRsh,\n\t\t\tOpEql, OpNeq, OpGreater, OpLess, OpGeq, OpLeq,\n\t\t\tOpAnd, OpOr, OpBitXor, OpBitAnd, OpBitOr,\n\t\t\tOpInc, OpDec, OpAddAssign, OpSubAssign, OpMulAssign, OpDivAssign, OpModAssign,\n\t\t\tOpShlAssign, OpShrAssign, OpOrAssign, OpAndAssign, OpXorAssign,\n\n\t\t\tQuestionMark, Colon, RightArrow, At, Pound, PoundPound,\n\t\t};\n\n\t\tString TokenTypeToString(TokenType type);\n\n        enum TokenFlag : unsigned int\n        {\n            AtStartOfLine   = 1 << 0,\n            AfterWhitespace = 1 << 1,\n        };\n        typedef unsigned int TokenFlags;\n\n\t\tclass Token\n\t\t{\n\t\tpublic:\n\t\t\tTokenType Type = TokenType::Unknown;\n\t\t\tString Content;\n\t\t\tCodePosition Position;\n            TokenFlags flags = 0;\n\t\t\tToken() = default;\n\t\t\tToken(TokenType type, const String & content, int line, int col, int pos, String fileName, TokenFlags flags = 0)\n                : flags(flags)\n\t\t\t{\n\t\t\t\tType = type;\n\t\t\t\tContent = content;\n\t\t\t\tPosition = CodePosition(line, col, pos, fileName);\n\t\t\t}\n\t\t};\n\n\t\tenum class TokenizeErrorType\n\t\t{\n\t\t\tInvalidCharacter, InvalidEscapeSequence\n\t\t};\n\n\t\tList<Token> TokenizeText(const String & fileName, const String & text, Procedure<TokenizeErrorType, CodePosition> errorHandler);\n\t\tList<Token> TokenizeText(const String & fileName, const String & text);\n\t\tList<Token> TokenizeText(const String & text);\n\t\t\n\t\tString EscapeStringLiteral(String str);\n\t\tString UnescapeStringLiteral(String str);\n\n\t\tclass TokenReader\n\t\t{\n\t\tprivate:\n\t\t\tbool legal;\n\t\t\tList<Token> tokens;\n\t\t\tint tokenPtr;\n\t\tpublic:\n\t\t\tTokenReader(Basic::String text);\n\t\t\tint ReadInt()\n\t\t\t{\n\t\t\t\tauto token = ReadToken();\n\t\t\t\tbool neg = false;\n\t\t\t\tif (token.Content == '-')\n\t\t\t\t{\n\t\t\t\t\tneg = true;\n\t\t\t\t\ttoken = ReadToken();\n\t\t\t\t}\n\t\t\t\tif (token.Type == TokenType::IntLiterial)\n\t\t\t\t{\n\t\t\t\t\tif (neg)\n\t\t\t\t\t\treturn -StringToInt(token.Content);\n\t\t\t\t\telse\n\t\t\t\t\t\treturn StringToInt(token.Content);\n\t\t\t\t}\n\t\t\t\tthrow TextFormatException(\"Text parsing error: int expected.\");\n\t\t\t}\n\t\t\tunsigned int ReadUInt()\n\t\t\t{\n\t\t\t\tauto token = ReadToken();\n\t\t\t\tif (token.Type == TokenType::IntLiterial)\n\t\t\t\t{\n\t\t\t\t\treturn StringToUInt(token.Content);\n\t\t\t\t}\n\t\t\t\tthrow TextFormatException(\"Text parsing error: int expected.\");\n\t\t\t}\n\t\t\tdouble ReadDouble()\n\t\t\t{\n\t\t\t\tauto token = ReadToken();\n\t\t\t\tbool neg = false;\n\t\t\t\tif (token.Content == '-')\n\t\t\t\t{\n\t\t\t\t\tneg = true;\n\t\t\t\t\ttoken = ReadToken();\n\t\t\t\t}\n\t\t\t\tif (token.Type == TokenType::DoubleLiterial || token.Type == TokenType::IntLiterial)\n\t\t\t\t{\n\t\t\t\t\tif (neg)\n\t\t\t\t\t\treturn -StringToDouble(token.Content);\n\t\t\t\t\telse\n\t\t\t\t\t\treturn StringToDouble(token.Content);\n\t\t\t\t}\n\t\t\t\tthrow TextFormatException(\"Text parsing error: floating point value expected.\");\n\t\t\t}\n\t\t\tfloat ReadFloat()\n\t\t\t{\n\t\t\t\treturn (float)ReadDouble();\n\t\t\t}\n\t\t\tString ReadWord()\n\t\t\t{\n\t\t\t\tauto token = ReadToken();\n\t\t\t\tif (token.Type == TokenType::Identifier)\n\t\t\t\t{\n\t\t\t\t\treturn token.Content;\n\t\t\t\t}\n\t\t\t\tthrow TextFormatException(\"Text parsing error: identifier expected.\");\n\t\t\t}\n\t\t\tString Read(const char * expectedStr)\n\t\t\t{\n\t\t\t\tauto token = ReadToken();\n\t\t\t\tif (token.Content == expectedStr)\n\t\t\t\t{\n\t\t\t\t\treturn token.Content;\n\t\t\t\t}\n\t\t\t\tthrow TextFormatException(\"Text parsing error: \\'\" + String(expectedStr) + \"\\' expected.\");\n\t\t\t}\n\t\t\tString Read(String expectedStr)\n\t\t\t{\n\t\t\t\tauto token = ReadToken();\n\t\t\t\tif (token.Content == expectedStr)\n\t\t\t\t{\n\t\t\t\t\treturn token.Content;\n\t\t\t\t}\n\t\t\t\tthrow TextFormatException(\"Text parsing error: \\'\" + expectedStr + \"\\' expected.\");\n\t\t\t}\n\t\t\t\n\t\t\tString ReadStringLiteral()\n\t\t\t{\n\t\t\t\tauto token = ReadToken();\n\t\t\t\tif (token.Type == TokenType::StringLiterial)\n\t\t\t\t{\n\t\t\t\t\treturn token.Content;\n\t\t\t\t}\n\t\t\t\tthrow TextFormatException(\"Text parsing error: string literal expected.\");\n\t\t\t}\n\t\t\tvoid Back(int count)\n\t\t\t{\n\t\t\t\ttokenPtr -= count;\n\t\t\t}\n\t\t\tToken ReadToken()\n\t\t\t{\n\t\t\t\tif (tokenPtr < tokens.Count())\n\t\t\t\t{\n\t\t\t\t\tauto &rs = tokens[tokenPtr];\n\t\t\t\t\ttokenPtr++;\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tthrow TextFormatException(\"Unexpected ending.\");\n\t\t\t}\n\t\t\tToken NextToken(int offset = 0)\n\t\t\t{\n\t\t\t\tif (tokenPtr + offset < tokens.Count())\n\t\t\t\t\treturn tokens[tokenPtr + offset];\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tToken rs;\n\t\t\t\t\trs.Type = TokenType::Unknown;\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbool LookAhead(String token)\n\t\t\t{\n\t\t\t\tif (tokenPtr < tokens.Count())\n\t\t\t\t{\n\t\t\t\t\tauto next = NextToken();\n\t\t\t\t\treturn next.Content == token;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbool IsEnd()\n\t\t\t{\n\t\t\t\treturn tokenPtr == tokens.Count();\n\t\t\t}\n\t\tpublic:\n\t\t\tbool IsLegalText()\n\t\t\t{\n\t\t\t\treturn legal;\n\t\t\t}\n\t\t};\n\n\t\tList<String> Split(String str, char c);\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/CoreLib/TypeTraits.h",
    "content": "#ifndef CORELIB_TYPETRAITS_H\n#define CORELIB_TYPETRAITS_H\n\nnamespace CoreLib\n{\n\tnamespace Basic\n\t{\n\t\tstruct TraitResultYes\n\t\t{\n\t\t\tchar x;\n\t\t};\n\t\tstruct TraitResultNo\n\t\t{\n\t\t\tchar x[2];\n\t\t};\n\n\t\ttemplate <typename B, typename D>\n\t\tstruct IsBaseOfTraitHost\n\t\t{\n\t\t\toperator B*() const { return nullptr; }\n\t\t\toperator D*() { return nullptr; }\n\t\t};\n\n\t\ttemplate <typename B, typename D>\n\t\tstruct IsBaseOf\n\t\t{\n\t\t\ttemplate <typename T>\n\t\t\tstatic TraitResultYes Check(D*, T) { return TraitResultYes(); }\n\t\t\tstatic TraitResultNo Check(B*, int) { return TraitResultNo(); }\n\t\t\tenum { Value = sizeof(Check(IsBaseOfTraitHost<B, D>(), int())) == sizeof(TraitResultYes) };\n\t\t};\n\n\t\ttemplate<bool B, class T = void>\n\t\tstruct EnableIf {};\n\n\t\ttemplate<class T>\n\t\tstruct EnableIf<true, T> { typedef T type; };\n\n\t\ttemplate <typename B, typename D>\n\t\tstruct IsConvertible\n\t\t{\n\t\t\tstatic TraitResultYes Use(B) {};\n\t\t\tstatic TraitResultNo Use(...) {};\n\t\t\tenum { Value = sizeof(Use(*(D*)(nullptr))) == sizeof(TraitResultYes) };\n\t\t};\n\t}\n}\n\n#endif\n"
  },
  {
    "path": "Source/CoreLib/VectorMath.cpp",
    "content": "#include \"VectorMath.h\"\n\nnamespace VectorMath\n{\n\tconst __m128 Matrix4_M128::VecOne = _mm_set_ps1(1.0f);\n\tvoid Matrix4::Rotation(Matrix4 & rs, const Vec3 & axis, float angle)\n\t{\n\t\tfloat c = cosf(angle);\n\t\tfloat s = sinf(angle);\n\t\tfloat t = 1.0f - c;\n\n\t\tVec3 nAxis;\n\t\tVec3::Normalize(nAxis, axis);\n\t\tfloat x = nAxis.x;\n\t\tfloat y = nAxis.y;\n\t\tfloat z = nAxis.z;\n\n\t\trs.m[0][0] = 1 + t*(x*x-1);\n\t\trs.m[1][0] = z*s+t*x*y;\n\t\trs.m[2][0] = -y*s+t*x*z;\n\t\trs.m[3][0] = 0.0f;\n\n\t\trs.m[0][1] = -z*s+t*x*y;\n\t\trs.m[1][1] = 1+t*(y*y-1);\n\t\trs.m[2][1] = x*s+t*y*z;\n\t\trs.m[3][1] = 0.0f;\n\n\t\trs.m[0][2] = y*s+t*x*z;\n\t\trs.m[1][2] = -x*s+t*y*z;\n\t\trs.m[2][2] = 1+t*(z*z-1);\n\t\trs.m[3][2] = 0.0f;\n\n\t\trs.m[0][3] = 0.0f;\n\t\trs.m[1][3] = 0.0f;\n\t\trs.m[2][3] = 0.0f;\n\t\trs.m[3][3] = 1.0f;\n\t}\n\tvoid Matrix4::Rotation(Matrix4 & rs, float yaw, float pitch, float roll)\n\t{\n\t\tMatrix4 mat;\n\t\tMatrix4::RotationY(rs, yaw);\n\t\tMatrix4::RotationX(mat, pitch);\n\t\tMatrix4::Multiply(rs, rs, mat);\n\t\tMatrix4::RotationZ(mat, roll);\n\t\tMatrix4::Multiply(rs, rs, mat);\n\t}\n\n\tvoid Matrix4::GetNormalMatrix(Matrix4 & mOut) const\n\t{\n\t\tfloat fDet = (mi._11 * (mi._22 * mi._33 - mi._23 * mi._32) -\n\t\t\tmi._12 * (mi._21 * mi._33 - mi._23 * mi._31) +\n\t\t\tmi._13 * (mi._21 * mi._32 - mi._22 * mi._31));\n\t\tfloat fDetInv = 1.0f / fDet;\n\n\t\tmOut.mi._11 = fDetInv * (mi._22 * mi._33 - mi._23 * mi._32);\n\t\tmOut.mi._21 = -fDetInv * (mi._12 * mi._33 - mi._13 * mi._32);\n\t\tmOut.mi._31 = fDetInv * (mi._12 * mi._23 - mi._13 * mi._22);\n\n\t\tmOut.mi._12 = -fDetInv * (mi._21 * mi._33 - mi._23 * mi._31);\n\t\tmOut.mi._22 = fDetInv * (mi._11 * mi._33 - mi._13 * mi._31);\n\t\tmOut.mi._32 = -fDetInv * (mi._11 * mi._23 - mi._13 * mi._21);\n\n\t\tmOut.mi._13 = fDetInv * (mi._21 * mi._32 - mi._22 * mi._31);\n\t\tmOut.mi._23 = -fDetInv * (mi._11 * mi._32 - mi._12 * mi._31);\n\t\tmOut.mi._33 = fDetInv * (mi._11 * mi._22 - mi._12 * mi._21);\n\n\t\tmOut.mi._14 = 0.0f;\n\t\tmOut.mi._24 = 0.0f;\n\t\tmOut.mi._34 = 0.0f;\n\t\tmOut.mi._41 = 0.0f;\n\t\tmOut.mi._42 = 0.0f;\n\t\tmOut.mi._43 = 0.0f;\n\t\tmOut.mi._44 = 1.0f;\n\t}\n\t\n\tfloat Matrix4::Inverse3D(Matrix4 & mOut_d) const\n\t{\n\t\tif(fabs(mi._44 - 1.0f) > 0.001f)\n\t\t\treturn 0.0f;\n\t\tif(fabs(mi._14)>0.001f || fabs(mi._24)>0.001f || fabs(mi._34)>0.001f)\n\t\t\treturn 0.0f;\n\n\t\tfloat fDet = (mi._11 * (mi._22 * mi._33 - mi._23 * mi._32) - \n\t\tmi._12 * (mi._21 * mi._33 - mi._23 * mi._31) +\n\t\tmi._13 * (mi._21 * mi._32 - mi._22 * mi._31));\n\t\tfloat fDetInv = 1.0f / fDet;\n\n\t\tmOut_d.mi._11 = fDetInv * (mi._22 * mi._33 - mi._23 * mi._32);\n\t\tmOut_d.mi._12 = -fDetInv * (mi._12 * mi._33 - mi._13 * mi._32);\n\t\tmOut_d.mi._13 = fDetInv * (mi._12 * mi._23 - mi._13 * mi._22);\n\t\tmOut_d.mi._14 = 0.0f;\n\n\t\tmOut_d.mi._21 = -fDetInv * (mi._21 * mi._33 - mi._23 * mi._31);\n\t\tmOut_d.mi._22 = fDetInv * (mi._11 * mi._33 - mi._13 * mi._31);\n\t\tmOut_d.mi._23 = -fDetInv * (mi._11 * mi._23 - mi._13 * mi._21);\n\t\tmOut_d.mi._24 = 0.0f;\n\n\t\tmOut_d.mi._31 = fDetInv * (mi._21 * mi._32 - mi._22 * mi._31);\n\t\tmOut_d.mi._32 = -fDetInv * (mi._11 * mi._32 - mi._12 * mi._31);\n\t\tmOut_d.mi._33 = fDetInv * (mi._11 * mi._22 - mi._12 * mi._21);\n\t\tmOut_d.mi._34 = 0.0f;\n\n\t\tmOut_d.mi._41 = -(mi._41 * mOut_d.mi._11 + mi._42 * mOut_d.mi._21 + mi._43 * mOut_d.mi._31);\n\t\tmOut_d.mi._42 = -(mi._41 * mOut_d.mi._12 + mi._42 * mOut_d.mi._22 + mi._43 * mOut_d.mi._32);\n\t\tmOut_d.mi._43 = -(mi._41 * mOut_d.mi._13 + mi._42 * mOut_d.mi._23 + mi._43 * mOut_d.mi._33);\n\t\tmOut_d.mi._44 = 1.0f;\n\n\t\treturn fDet;\n\t}\n\t\t\n\tfloat Matrix4::InverseFPU(Matrix4 &mOut_d) const\n\t{\n\t\tfloat succ = Inverse3D(mOut_d);\n\t\tif (succ != 0.0f)\n\t\t\treturn succ;\n\t\tdouble Result[4][4];\n\t\tdouble tmp[12];\n\t\tdouble src[16];\n\t\tdouble det;\n\t\tfor (int i = 0; i < 4; i++)\n\t\t{\n\t\t\tsrc[i+0] = m[i][0];\n\t\t\tsrc[i+4] = m[i][1];\n\t\t\tsrc[i+8] = m[i][2];\n\t\t\tsrc[i+12] = m[i][3];\n\t\t}\n\t\ttmp[0] = src[10] * src[15];\n\t\ttmp[1] = src[11] * src[14];\n\t\ttmp[2] = src[9] * src[15];\n\t\ttmp[3] = src[11] * src[13];\n\t\ttmp[4] = src[9] * src[14];\n\t\ttmp[5] = src[10] * src[13];\n\t\ttmp[6] = src[8] * src[15];\n\t\ttmp[7] = src[11] * src[12];\n\t\ttmp[8] = src[8] * src[14];\n\t\ttmp[9] = src[10] * src[12];\n\t\ttmp[10] = src[8] * src[13];\n\t\ttmp[11] = src[9] * src[12];\n\t\tResult[0][0] = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7];\n\t\tResult[0][0] -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7];\n\t\tResult[0][1] = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7];\n\t\tResult[0][1] -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7];\n\t\tResult[0][2] = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7];\n\t\tResult[0][2] -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7];\n\t\tResult[0][3] = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6];\n\t\tResult[0][3] -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6];\n\t\tResult[1][0] = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3];\n\t\tResult[1][0] -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3];\n\t\tResult[1][1] = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3];\n\t\tResult[1][1] -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3];\n\t\tResult[1][2] = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3];\n\t\tResult[1][2] -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3];\n\t\tResult[1][3] = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2];\n\t\tResult[1][3] -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2];\n\t\ttmp[0] = src[2]*src[7];\n\t\ttmp[1] = src[3]*src[6];\n\t\ttmp[2] = src[1]*src[7];\n\t\ttmp[3] = src[3]*src[5];\n\t\ttmp[4] = src[1]*src[6];\n\t\ttmp[5] = src[2]*src[5];\n\t\ttmp[6] = src[0]*src[7];\n\t\ttmp[7] = src[3]*src[4];\n\t\ttmp[8] = src[0]*src[6];\n\t\ttmp[9] = src[2]*src[4];\n\t\ttmp[10] = src[0]*src[5];\n\t\ttmp[11] = src[1]*src[4];\n\t\tResult[2][0] = tmp[0]*src[13] + tmp[3]*src[14] + tmp[4]*src[15];\n\t\tResult[2][0] -= tmp[1]*src[13] + tmp[2]*src[14] + tmp[5]*src[15];\n\t\tResult[2][1] = tmp[1]*src[12] + tmp[6]*src[14] + tmp[9]*src[15];\n\t\tResult[2][1] -= tmp[0]*src[12] + tmp[7]*src[14] + tmp[8]*src[15];\n\t\tResult[2][2] = tmp[2]*src[12] + tmp[7]*src[13] + tmp[10]*src[15];\n\t\tResult[2][2] -= tmp[3]*src[12] + tmp[6]*src[13] + tmp[11]*src[15];\n\t\tResult[2][3] = tmp[5]*src[12] + tmp[8]*src[13] + tmp[11]*src[14];\n\t\tResult[2][3] -= tmp[4]*src[12] + tmp[9]*src[13] + tmp[10]*src[14];\n\t\tResult[3][0] = tmp[2]*src[10] + tmp[5]*src[11] + tmp[1]*src[9];\n\t\tResult[3][0] -= tmp[4]*src[11] + tmp[0]*src[9] + tmp[3]*src[10];\n\t\tResult[3][1] = tmp[8]*src[11] + tmp[0]*src[8] + tmp[7]*src[10];\n\t\tResult[3][1] -= tmp[6]*src[10] + tmp[9]*src[11] + tmp[1]*src[8];\n\t\tResult[3][2] = tmp[6]*src[9] + tmp[11]*src[11] + tmp[3]*src[8];\n\t\tResult[3][2] -= tmp[10]*src[11] + tmp[2]*src[8] + tmp[7]*src[9];\n\t\tResult[3][3] = tmp[10]*src[10] + tmp[4]*src[8] + tmp[9]*src[9];\n\t\tResult[3][3] -= tmp[8]*src[9] + tmp[11]*src[10] + tmp[5]*src[8];\n\t\tdet=src[0]*Result[0][0]+src[1]*Result[0][1]+src[2]*Result[0][2]+src[3]*Result[0][3];\n\t\tdet = 1.0f / det;\n\t\tfor (int i = 0; i < 4; i++)\n\t\t{\n\t\t\tfor (int j = 0; j < 4; j++)\n\t\t\t{\n\t\t\t\tmOut_d.m[i][j] = (float)(Result[i][j] * det);\n\t\t\t}\n\t\t}\n\t\treturn (float)det;\n\t}\n\t\n\tvoid Matrix4::LookAt(Matrix4 & rs, const Vec3 & pos, const Vec3 & center, const Vec3 & up)\n\t{\n\t\tVec3 xAxis, yAxis, zAxis;\n\t\tVec3::Subtract(zAxis, pos, center);\n\t\tVec3::Normalize(zAxis, zAxis);\n\t\tVec3::Cross(xAxis, up, zAxis);\n\t\tVec3::Normalize(xAxis, xAxis);\n\t\tVec3::Cross(yAxis, zAxis, xAxis);\n\t\tVec3::Normalize(yAxis, yAxis);\n\n\t\trs.m[0][0] = xAxis.x;\n\t\trs.m[0][1] = yAxis.x;\n\t\trs.m[0][2] = zAxis.x;\n\t\trs.m[0][3] = 0.0f;\n\n\t\trs.m[1][0] = xAxis.y;\n\t\trs.m[1][1] = yAxis.y;\n\t\trs.m[1][2] = zAxis.y;\n\t\trs.m[1][3] = 0.0f;\n\n\t\trs.m[2][0] = xAxis.z;\n\t\trs.m[2][1] = yAxis.z;\n\t\trs.m[2][2] = zAxis.z;\n\t\trs.m[2][3] = 0.0f;\n\n\t\trs.m[3][0] = -Vec3::Dot(xAxis, pos);\n\t\trs.m[3][1] = -Vec3::Dot(yAxis, pos);\n\t\trs.m[3][2] = -Vec3::Dot(zAxis, pos);\n\t\trs.m[3][3] = 1.0f;\n\t}\n\t\n\tfloat Matrix4_M128::Inverse(Matrix4_M128 &mOut) const\n\t{\n\t\t__m128 Fac0;\n\t\t{\n\t\t\t__m128 Swp0a = _mm_shuffle_ps(C4, C3, _MM_SHUFFLE(3, 3, 3, 3));\n\t\t\t__m128 Swp0b = _mm_shuffle_ps(C4, C3, _MM_SHUFFLE(2, 2, 2, 2));\n\n\t\t\t__m128 Swp00 = _mm_shuffle_ps(C3, C2, _MM_SHUFFLE(2, 2, 2, 2));\n\t\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t\t__m128 Swp03 = _mm_shuffle_ps(C3, C2, _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\t\tFac0 = _mm_sub_ps(Mul00, Mul01);\n\t\t}\n\n\t\t__m128 Fac1;\n\t\t{\n\t\t\t__m128 Swp0a = _mm_shuffle_ps(C4, C3, _MM_SHUFFLE(3, 3, 3, 3));\n\t\t\t__m128 Swp0b = _mm_shuffle_ps(C4, C3, _MM_SHUFFLE(1, 1, 1, 1));\n\n\t\t\t__m128 Swp00 = _mm_shuffle_ps(C3, C2, _MM_SHUFFLE(1, 1, 1, 1));\n\t\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t\t__m128 Swp03 = _mm_shuffle_ps(C3, C2, _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\t\tFac1 = _mm_sub_ps(Mul00, Mul01);\n\t\t}\n\n\t\t__m128 Fac2;\n\t\t{\n\t\t\t__m128 Swp0a = _mm_shuffle_ps(C4, C3, _MM_SHUFFLE(2, 2, 2, 2));\n\t\t\t__m128 Swp0b = _mm_shuffle_ps(C4, C3, _MM_SHUFFLE(1, 1, 1, 1));\n\n\t\t\t__m128 Swp00 = _mm_shuffle_ps(C3, C2, _MM_SHUFFLE(1, 1, 1, 1));\n\t\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t\t__m128 Swp03 = _mm_shuffle_ps(C3, C2, _MM_SHUFFLE(2, 2, 2, 2));\n\n\t\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\t\tFac2 = _mm_sub_ps(Mul00, Mul01);\n\t\t}\n\n\t\t__m128 Fac3;\n\t\t{\n\t\t\t__m128 Swp0a = _mm_shuffle_ps(C4, C3, _MM_SHUFFLE(3, 3, 3, 3));\n\t\t\t__m128 Swp0b = _mm_shuffle_ps(C4, C3, _MM_SHUFFLE(0, 0, 0, 0));\n\n\t\t\t__m128 Swp00 = _mm_shuffle_ps(C3, C2, _MM_SHUFFLE(0, 0, 0, 0));\n\t\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t\t__m128 Swp03 = _mm_shuffle_ps(C3, C2, _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\t\tFac3 = _mm_sub_ps(Mul00, Mul01);\n\t\t}\n\n\t\t__m128 Fac4;\n\t\t{\n\t\t\t__m128 Swp0a = _mm_shuffle_ps(C4, C3, _MM_SHUFFLE(2, 2, 2, 2));\n\t\t\t__m128 Swp0b = _mm_shuffle_ps(C4, C3, _MM_SHUFFLE(0, 0, 0, 0));\n\n\t\t\t__m128 Swp00 = _mm_shuffle_ps(C3, C2, _MM_SHUFFLE(0, 0, 0, 0));\n\t\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t\t__m128 Swp03 = _mm_shuffle_ps(C3, C2, _MM_SHUFFLE(2, 2, 2, 2));\n\n\t\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\t\tFac4 = _mm_sub_ps(Mul00, Mul01);\n\t\t}\n\n\t\t__m128 Fac5;\n\t\t{\n\t\t\t__m128 Swp0a = _mm_shuffle_ps(C4, C3, _MM_SHUFFLE(1, 1, 1, 1));\n\t\t\t__m128 Swp0b = _mm_shuffle_ps(C4, C3, _MM_SHUFFLE(0, 0, 0, 0));\n\n\t\t\t__m128 Swp00 = _mm_shuffle_ps(C3, C2, _MM_SHUFFLE(0, 0, 0, 0));\n\t\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t\t__m128 Swp03 = _mm_shuffle_ps(C3, C2, _MM_SHUFFLE(1, 1, 1, 1));\n\n\t\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\t\tFac5 = _mm_sub_ps(Mul00, Mul01);\n\t\t}\n\n\t\t__m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f);\n\t\t__m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f);\n\n\t\t__m128 Temp0 = _mm_shuffle_ps(C2, C1, _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t\t__m128 Temp1 = _mm_shuffle_ps(C2, C1, _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t\t__m128 Temp2 = _mm_shuffle_ps(C2, C1, _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t\t__m128 Temp3 = _mm_shuffle_ps(C2, C1, _MM_SHUFFLE(3, 3, 3, 3));\n\t\t__m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Vec1, Fac0);\n\t\t__m128 Mul01 = _mm_mul_ps(Vec2, Fac1);\n\t\t__m128 Mul02 = _mm_mul_ps(Vec3, Fac2);\n\t\t__m128 Sub00 = _mm_sub_ps(Mul00, Mul01);\n\t\t__m128 Add00 = _mm_add_ps(Sub00, Mul02);\n\t\t__m128 Inv0 = _mm_mul_ps(SignB, Add00);\n\n\t\t__m128 Mul03 = _mm_mul_ps(Vec0, Fac0);\n\t\t__m128 Mul04 = _mm_mul_ps(Vec2, Fac3);\n\t\t__m128 Mul05 = _mm_mul_ps(Vec3, Fac4);\n\t\t__m128 Sub01 = _mm_sub_ps(Mul03, Mul04);\n\t\t__m128 Add01 = _mm_add_ps(Sub01, Mul05);\n\t\t__m128 Inv1 = _mm_mul_ps(SignA, Add01);\n\n\t\t__m128 Mul06 = _mm_mul_ps(Vec0, Fac1);\n\t\t__m128 Mul07 = _mm_mul_ps(Vec1, Fac3);\n\t\t__m128 Mul08 = _mm_mul_ps(Vec3, Fac5);\n\t\t__m128 Sub02 = _mm_sub_ps(Mul06, Mul07);\n\t\t__m128 Add02 = _mm_add_ps(Sub02, Mul08);\n\t\t__m128 Inv2 = _mm_mul_ps(SignB, Add02);\n\n\t\t__m128 Mul09 = _mm_mul_ps(Vec0, Fac2);\n\t\t__m128 Mul10 = _mm_mul_ps(Vec1, Fac4);\n\t\t__m128 Mul11 = _mm_mul_ps(Vec2, Fac5);\n\t\t__m128 Sub03 = _mm_sub_ps(Mul09, Mul10);\n\t\t__m128 Add03 = _mm_add_ps(Sub03, Mul11);\n\t\t__m128 Inv3 = _mm_mul_ps(SignA, Add03);\n\n\t\t__m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0));\n\n\t\t// Det0 = dot(C1, Row2)\n\t\t__m128 mul0 = _mm_mul_ps(C1, Row2);\n\t\t__m128 swp0 = _mm_shuffle_ps(mul0, mul0, _MM_SHUFFLE(2, 3, 0, 1));\n\t\t__m128 add0 = _mm_add_ps(mul0, swp0);\n\t\t__m128 swp1 = _mm_shuffle_ps(add0, add0, _MM_SHUFFLE(0, 1, 2, 3));\n\t\t__m128 Det0 = _mm_add_ps(add0, swp1);\n\n\t\t__m128 Rcp0 = _mm_div_ps(VecOne, Det0);\n\n\t\tmOut.C1 = _mm_mul_ps(Inv0, Rcp0);\n\t\tmOut.C2 = _mm_mul_ps(Inv1, Rcp0);\n\t\tmOut.C3 = _mm_mul_ps(Inv2, Rcp0);\n\t\tmOut.C4 = _mm_mul_ps(Inv3, Rcp0);\n\n\t\tfloat retVal;\n\t\t_mm_store_ss(&retVal, Det0);\n\t\treturn retVal;\n\t}\n\n}\n"
  },
  {
    "path": "Source/CoreLib/VectorMath.h",
    "content": "#ifndef VECTOR_MATH_H\n#define VECTOR_MATH_H\n#include <memory.h>\n#include <random>\n#include <cmath>\n#include <xmmintrin.h>\n#include \"LibMath.h\"\n#ifdef _M_X64\n#define NO_SIMD_ASM\n#endif\n#if !defined(_MSC_VER) || defined(__clang__)\n#define NO_SIMD_ASM\n#endif\n#ifndef NO_VECTOR_CONSTRUCTORS\n#define NO_VECTOR_CONSTRUCTORS\n#endif\nnamespace VectorMath\n{\n\tusing namespace CoreLib::Basic;\n\tconst float PI = 3.1415926535f;\n\tconst float Epsilon = 1e-4f;\n\tconst int DefaultFloatUlps = 1024;\n\tinline float Clamp(float val, float vmin, float vmax)\n\t{\n\t\treturn val>vmax ? vmax : val<vmin ? vmin : val;\n\t}\n\tinline bool FloatEquals(float A, float B, int maxUlps = DefaultFloatUlps)\n\t{\n\t\tint aInt = *(int*)&A;\n\t\t// Make aInt lexicographically ordered as a twos-complement int\n\t\tif (aInt < 0)\n\t\t\taInt = 0x80000000 - aInt;\n\t\t// Make bInt lexicographically ordered as a twos-complement int\n\t\tint bInt = *(int*)&B;\n\t\tif (bInt < 0)\n\t\t\tbInt = 0x80000000 - bInt;\n\t\tint intDiff = abs(aInt - bInt);\n\t\tif (intDiff <= maxUlps)\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\tinline bool FloatLarger(float A, float B, int maxUlps = DefaultFloatUlps)\n\t{\n\t\treturn A>B && !FloatEquals(A, B, maxUlps);\n\t}\n\tinline bool FloatSmaller(float A, float B, int maxUlps = DefaultFloatUlps)\n\t{\n\t\treturn A<B && !FloatEquals(A, B, maxUlps);\n\t}\n\tinline bool FloatSmallerOrEquals(float A, float B, int maxUlps = DefaultFloatUlps)\n\t{\n\t\treturn A<B || FloatEquals(A, B, maxUlps);\n\t}\n\tinline bool FloatLargerOrEquals(float A, float B, int maxUlps = DefaultFloatUlps)\n\t{\n\t\treturn A>B || FloatEquals(A, B, maxUlps);\n\t}\n\n\ttemplate<typename T>\n\tinline T Max(T v1, T v2)\n\t{\n\t\tif (v1>v2) return v1; else return v2;\n\t}\n\ttemplate<typename T>\n\tinline T Min(T v1, T v2)\n\t{\n\t\tif (v1<v2) return v1; else return v2;\n\t}\n\n\tclass Vec4;\n\tclass Vec2\n\t{\n\tpublic:\n\t\tfloat x, y;\n#ifndef NO_VECTOR_CONSTRUCTORS\n\t\tVec2() = default;\n\t\tVec2(const Vec2 & v) = default;\n\t\tVec2(float vx, float vy)\n\t\t{\n\t\t\tx = vx; y = vy;\n\t\t}\n#endif\n\t\tstatic Vec2 Create(float f)\n\t\t{\n\t\t\tVec2 rs;\n\t\t\trs.x = rs.y = f;\n\t\t\treturn rs;\n\t\t}\n\t\tstatic Vec2 Create(float vx, float vy)\n\t\t{\n\t\t\tVec2 rs;\n\t\t\trs.x = vx;\trs.y = vy;\n\t\t\treturn rs;\n\t\t}\n\t\tinline void SetZero()\n\t\t{\n\t\t\tx = y = 0.0f;\n\t\t}\n\t\tstatic inline float Dot(const Vec2 & v0, const Vec2 & v1)\n\t\t{\n\t\t\treturn v0.x * v1.x + v0.y * v1.y;\n\t\t}\n\t\tinline float & operator [] (int i)\n\t\t{\n\t\t\treturn ((float*)this)[i];\n\t\t}\n\t\tinline Vec2 operator * (float s) const\n\t\t{\n\t\t\tVec2 rs;\n\t\t\trs.x = x * s;\n\t\t\trs.y = y * s;\n\t\t\treturn rs;\n\t\t}\n\t\tinline Vec2 operator * (const Vec2 &vin) const\n\t\t{\n\t\t\tVec2 rs;\n\t\t\trs.x = x * vin.x;\n\t\t\trs.y = y * vin.y;\n\t\t\treturn rs;\n\t\t}\n\t\tinline Vec2 operator + (const Vec2 &vin) const\n\t\t{\n\t\t\tVec2 rs;\n\t\t\trs.x = x + vin.x;\n\t\t\trs.y = y + vin.y;\n\t\t\treturn rs;\n\t\t}\n\t\tinline Vec2 operator - (const Vec2 &vin) const\n\t\t{\n\t\t\tVec2 rs;\n\t\t\trs.x = x - vin.x;\n\t\t\trs.y = y - vin.y;\n\t\t\treturn rs;\n\t\t}\n\t\tinline Vec2 & operator += (const Vec2 & vin)\n\t\t{\n\t\t\tx += vin.x;\n\t\t\ty += vin.y;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec2 & operator -= (const Vec2 & vin)\n\t\t{\n\t\t\tx -= vin.x;\n\t\t\ty -= vin.y;\n\t\t\treturn *this;\n\t\t}\n\t\tVec2 & operator = (float v)\n\t\t{\n\t\t\tx = y = v;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec2 & operator *= (float s)\n\t\t{\n\t\t\tx *= s;\n\t\t\ty *= s;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec2 & operator *= (const Vec2 & vin)\n\t\t{\n\t\t\tx *= vin.x;\n\t\t\ty *= vin.y;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec2 Normalize()\n\t\t{\n\t\t\tfloat len = sqrt(x*x + y*y);\n\t\t\tfloat invLen = 1.0f / len;\n\t\t\tVec2 rs;\n\t\t\trs.x = x * invLen;\n\t\t\trs.y = y * invLen;\n\t\t\treturn rs;\n\t\t}\n\t\tinline float Length()\n\t\t{\n\t\t\treturn sqrt(x*x + y*y);\n\t\t}\n\t};\n\n\tclass Vec3\n\t{\n\tpublic:\n\t\tfloat x, y, z;\n#ifndef NO_VECTOR_CONSTRUCTORS\n\t\tinline Vec3() = default;\n\t\tinline Vec3(float f)\n\t\t{\n\t\t\tx = y = z = f;\n\t\t}\n\t\tinline Vec3(float vx, float vy, float vz)\n\t\t{\n\t\t\tx = vx;\ty = vy;\tz = vz;\n\t\t}\n\t\tinline Vec3(const Vec3 & v) = default;\n#endif\n\t\tstatic inline Vec3 Create(float f)\n\t\t{\n\t\t\tVec3 rs;\n\t\t\trs.x = rs.y = rs.z = f;\n\t\t\treturn rs;\n\t\t}\n\t\tstatic inline Vec3 Create(float vx, float vy, float vz)\n\t\t{\n\t\t\tVec3 rs;\n\t\t\trs.x = vx;\trs.y = vy;\trs.z = vz;\n\t\t\treturn rs;\n\t\t}\n\t\tstatic inline Vec3 Lerp(const Vec3 & v0, const Vec3 & v1, float t)\n\t\t{\n\t\t\treturn v0 * (1.0f - t) + v1 * t;\n\t\t}\n\t\tstatic inline Vec3 FromHomogeneous(const Vec4 & v);\n\t\tinline void SetZero()\n\t\t{\n\t\t\tx = y = z = 0.0f;\n\t\t}\n\t\tinline float& operator [] (int i) const\n\t\t{\n\t\t\treturn ((float*)this)[i];\n\t\t}\n\t\tinline Vec3 operator + (const Vec3 &vin) const\n\t\t{\n\t\t\tVec3 rs;\n\t\t\trs.x = x + vin.x;\n\t\t\trs.y = y + vin.y;\n\t\t\trs.z = z + vin.z;\n\t\t\treturn rs;\n\t\t}\n\t\tinline Vec3 operator - (const Vec3 &vin) const\n\t\t{\n\t\t\tVec3 rs;\n\t\t\trs.x = x - vin.x;\n\t\t\trs.y = y - vin.y;\n\t\t\trs.z = z - vin.z;\n\t\t\treturn rs;\n\t\t}\n\t\tinline Vec3 operator - () const\n\t\t{\n\t\t\tVec3 rs;\n\t\t\trs.x = -x;\n\t\t\trs.y = -y;\n\t\t\trs.z = -z;\n\t\t\treturn rs;\n\t\t}\n\t\tinline Vec3 operator * (float scale) const\n\t\t{\n\t\t\tVec3 rs;\n\t\t\trs.x = x * scale;\n\t\t\trs.y = y * scale;\n\t\t\trs.z = z * scale;\n\t\t\treturn rs;\n\t\t}\n\t\tinline Vec3 & operator += (const Vec3 & vin)\n\t\t{\n\t\t\tx += vin.x; y += vin.y; z += vin.z;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec3 & operator -= (const Vec3 & vin)\n\t\t{\n\t\t\tx -= vin.x; y -= vin.y; z -= vin.z;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec3 & operator *= (const Vec3 & vin)\n\t\t{\n\t\t\tx *= vin.x; y *= vin.y; z *= vin.z;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec3 & operator *= (float s)\n\t\t{\n\t\t\tx *= s; y *= s; z *= s;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec3 & operator /= (const Vec3 & vin)\n\t\t{\n\t\t\tx /= vin.x; y /= vin.y; z /= vin.z;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec3 & operator /= (float s)\n\t\t{\n\t\t\tfloat inv = 1.0f / s;\n\t\t\treturn (*this) *= inv;\n\t\t}\n\t\tinline bool operator == (const Vec3 & vin)\n\t\t{\n\t\t\treturn x == vin.x && y == vin.y && z == vin.z;\n\t\t}\n\t\tinline bool operator != (const Vec3 & vin)\n\t\t{\n\t\t\treturn x != vin.x || y != vin.y || z != vin.z;\n\t\t}\n\t\tinline int GetHashCode()\n\t\t{\n\t\t\treturn FloatAsInt(x) ^ FloatAsInt(y) ^ FloatAsInt(z);\n\t\t}\n\t\tinline static float Dot(const Vec3 & v1, const Vec3 & v2)\n\t\t{\n\t\t\treturn v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;\n\t\t}\n\t\tinline static void Cross(Vec3 & rs_d, const Vec3 & v1, const Vec3 & v2)\n\t\t{\n\t\t\trs_d.x = v1.y*v2.z - v1.z * v2.y;\n\t\t\trs_d.y = v1.z*v2.x - v1.x * v2.z;\n\t\t\trs_d.z = v1.x*v2.y - v1.y * v2.x;\n\t\t}\n\t\tinline static Vec3 Cross(const Vec3 & v1, const Vec3 & v2)\n\t\t{\n\t\t\tVec3 rs_d;\n\t\t\trs_d.x = v1.y*v2.z - v1.z * v2.y;\n\t\t\trs_d.y = v1.z*v2.x - v1.x * v2.z;\n\t\t\trs_d.z = v1.x*v2.y - v1.y * v2.x;\n\t\t\treturn rs_d;\n\t\t}\n\t\tinline static void Scale(Vec3 & rs, const Vec3 & v1, float s)\n\t\t{\n\t\t\trs.x = v1.x*s;\trs.y = v1.y*s;\trs.z = v1.z*s;\n\t\t}\n\t\tinline static void Add(Vec3 & rs, const Vec3 & v1, const Vec3 & v2)\n\t\t{\n\t\t\trs.x = v1.x + v2.x;\n\t\t\trs.y = v1.y + v2.y;\n\t\t\trs.z = v1.z + v2.z;\n\t\t}\n\t\tinline static void Subtract(Vec3 & rs, const Vec3 & v1, const Vec3 & v2)\n\t\t{\n\t\t\trs.x = v1.x - v2.x;\n\t\t\trs.y = v1.y - v2.y;\n\t\t\trs.z = v1.z - v2.z;\n\t\t}\n\t\tinline static void Multiply(Vec3 & rs, const Vec3 & v1, const Vec3 & v2)\n\t\t{\n\t\t\trs.x = v1.x * v2.x;\n\t\t\trs.y = v1.y * v2.y;\n\t\t\trs.z = v1.z * v2.z;\n\t\t}\n\t\tinline float LengthFPU() const\n\t\t{\n\t\t\treturn sqrt(x*x + y*y + z*z);\n\t\t}\n\t\tinline float Length2() const\n\t\t{\n\t\t\treturn x*x + y*y + z*z;\n\t\t}\n\t\tstatic inline void NormalizeFPU(Vec3 & rs, const Vec3 & vin)\n\t\t{\n\t\t\tfloat invLen = 1.0f / vin.LengthFPU();\n\t\t\tScale(rs, vin, invLen);\n\t\t}\n\t\tinline float Length() const;\n\t\tstatic inline void Normalize(Vec3 & rs, const Vec3 & vin);\n\t\tinline Vec3 Normalize() const\n\t\t{\n\t\t\tVec3 rs;\n\t\t\tNormalize(rs, *this);\n\t\t\treturn rs;\n\t\t}\n\t};\n\n\tclass Vec4\n\t{\n\tpublic:\n\t\tfloat x, y, z, w;\n#ifndef NO_VECTOR_CONSTRUCTORS\n\t\tinline Vec4() = default;\n\t\tinline Vec4(const Vec4_Struct & v)\n\t\t{\n\t\t\tx = v.x;\n\t\t\ty = v.y;\n\t\t\tz = v.z;\n\t\t\tw = v.w;\n\t\t}\n\t\tinline Vec4(float f)\n\t\t{\n\t\t\tx = y = z = w = f;\n\t\t}\n\t\tinline Vec4(float vx, float vy, float vz, float vw)\n\t\t{\n\t\t\tx = vx;\ty = vy;\tz = vz;\tw = vw;\n\t\t}\n\t\tinline Vec4(const Vec3 & v)\n\t\t{\n\t\t\tx = v.x; y = v.y; z = v.z; w = 0.0f;\n\t\t}\n\t\tinline Vec4(const Vec3 & v, float vw)\n\t\t{\n\t\t\tx = v.x; y = v.y; z = v.z; w = vw;\n\t\t}\n\t\tinline Vec4(const Vec4 & v) = default;\n#endif\n\t\tstatic inline Vec4 Create(float f)\n\t\t{\n\t\t\tVec4 rs;\n\t\t\trs.x = rs.y = rs.z = rs.w = f;\n\t\t\treturn rs;\n\t\t}\n\t\tstatic inline Vec4 Create(float vx, float vy, float vz, float vw)\n\t\t{\n\t\t\tVec4 rs;\n\t\t\trs.x = vx;\trs.y = vy;\trs.z = vz; rs.w = vw;\n\t\t\treturn rs;\n\t\t}\n\t\tstatic inline Vec4 Create(const Vec3 & v, float vw)\n\t\t{\n\t\t\tVec4 rs;\n\t\t\trs.x = v.x; rs.y = v.y; rs.z = v.z; rs.w = vw;\n\t\t\treturn rs;\n\t\t}\n\t\tinline void SetZero()\n\t\t{\n\t\t\tx = y = z = w = 0.0f;\n\t\t}\n\t\tinline void xyz(Vec3 & v) const\n\t\t{\n\t\t\tv.x = x;\n\t\t\tv.y = y;\n\t\t\tv.z = z;\n\t\t}\n\t\tinline Vec3 xyz() const\n\t\t{\n\t\t\tVec3 rs;\n\t\t\trs.x = x;\n\t\t\trs.y = y;\n\t\t\trs.z = z;\n\t\t\treturn rs;\n\t\t}\n\t\tinline float& operator [] (int i) const\n\t\t{\n\t\t\treturn ((float*)this)[i];\n\t\t}\n\t\tinline Vec4 operator + (const Vec4 &vin)\n\t\t{\n\t\t\tVec4 rs;\n\t\t\trs.x = x + vin.x;\n\t\t\trs.y = y + vin.y;\n\t\t\trs.z = z + vin.z;\n\t\t\trs.w = w + vin.w;\n\t\t\treturn rs;\n\t\t}\n\t\tinline Vec4 operator - (const Vec4 &vin)\n\t\t{\n\t\t\tVec4 rs;\n\t\t\trs.x = x - vin.x;\n\t\t\trs.y = y - vin.y;\n\t\t\trs.z = z - vin.z;\n\t\t\trs.w = w - vin.w;\n\t\t\treturn rs;\n\t\t}\n\t\tinline Vec4 operator - ()\n\t\t{\n\t\t\tVec4 rs;\n\t\t\trs.x = -x;\n\t\t\trs.y = -y;\n\t\t\trs.z = -z;\n\t\t\trs.w = -w;\n\t\t\treturn rs;\n\t\t}\n\t\tinline Vec4 operator * (float scale) const\n\t\t{\n\t\t\tVec4 rs;\n\t\t\trs.x = x * scale;\n\t\t\trs.y = y * scale;\n\t\t\trs.z = z * scale;\n\t\t\trs.w = w * scale;\n\t\t\treturn rs;\n\t\t}\n\t\tinline Vec4 & operator += (const Vec4 & vin)\n\t\t{\n\t\t\tx += vin.x; y += vin.y; z += vin.z; w += vin.w;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec4 & operator -= (const Vec4 & vin)\n\t\t{\n\t\t\tx -= vin.x; y -= vin.y; z -= vin.z; w -= vin.w;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec4 & operator *= (const Vec4 & vin)\n\t\t{\n\t\t\tx *= vin.x; y *= vin.y; z *= vin.z; w *= vin.w;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec4 & operator *= (float s)\n\t\t{\n\t\t\tx *= s; y *= s; z *= s; w *= s;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec4 & operator /= (const Vec4 & vin)\n\t\t{\n\t\t\tx /= vin.x; y /= vin.y; z /= vin.z; w /= vin.w;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Vec4 & operator /= (float s)\n\t\t{\n\t\t\tfloat inv = 1.0f / s;\n\t\t\treturn (*this) *= inv;\n\t\t}\n\t\tinline bool operator == (const Vec4 & vin)\n\t\t{\n\t\t\treturn vin.x == x && vin.y == y && vin.z == z && vin.w == w;\n\t\t}\n\t\tinline bool operator != (const Vec4 & vin)\n\t\t{\n\t\t\treturn vin.x != x || vin.y != y || vin.z != z || vin.w != w;\n\t\t}\n\t\tinline int GetHashCode()\n\t\t{\n\t\t\treturn FloatAsInt(x) ^ FloatAsInt(y) ^ FloatAsInt(z) ^ FloatAsInt(w);\n\t\t}\n\t\tstatic inline void Add(Vec4 & rs, const Vec4 & v1, const Vec4 & v2);\n\t\tstatic inline void Subtract(Vec4 & rs, const Vec4 & v1, const Vec4 & v2);\n\t\tstatic inline void Multiply(Vec4 & rs, const Vec4 & v1, const Vec4 & v2);\n\t\tstatic inline void MultiplyScale(Vec4 & rs, const Vec4 & v1, const Vec4 & v2);\n\t\tstatic inline void Scale(Vec4 & rs, const Vec4 & v1, float s);\n\t\tstatic inline float Dot(const Vec4 & v1, const Vec4 & v2);\n\t\tstatic inline void Cross(Vec4 & rs_d, const Vec4 & v1, const Vec4 & v2);\n\t\tinline float LengthFPU() const;\n\t\tinline float Length() const;\n\t\tstatic inline void NormalizeFPU(Vec4& vout, const Vec4& vin);\n\t\tstatic inline void Normalize(Vec4 &vout, const Vec4 &vin);\n\t\tinline Vec4 Normalize()\n\t\t{\n\t\t\tVec4 rs;\n\t\t\tNormalize(rs, *this);\n\t\t\treturn rs;\n\t\t}\n\t};\n\n\tclass Vec4_M128\n\t{\n\tpublic:\n\t\t__m128 vec;\n\t\tVec4_M128()\n\t\t{}\n\t\tVec4_M128(__m128 v)\n\t\t{\n\t\t\tvec = v;\n\t\t}\n\t\tVec4_M128(float a, float b, float c, float d)\n\t\t{\n\t\t\tvec = _mm_set_ps(a, b, c, d);\n\t\t}\n\t\tVec4_M128(const Vec4 & v)\n\t\t{\n\t\t\tvec = _mm_load_ps((const float*)&v);\n\t\t}\n\t\tinline void Zero()\n\t\t{\n\t\t\tvec = _mm_setzero_ps();\n\t\t}\n\t\tinline void ToVec4(Vec4 & v) const\n\t\t{\n\t\t\t_mm_store_ps((float*)&v, vec);\n\t\t}\n\t};\n\n\tclass Matrix3\n\t{\n\tpublic:\n\t\tunion\n\t\t{\n\t\t\tfloat values[9];\n\t\t\tfloat m[3][3];\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tfloat _11, _12, _13,\n\t\t\t\t\t_21, _22, _23,\n\t\t\t\t\t_31, _32, _33;\n\t\t\t} mi;\n\t\t};\n\t\tinline Vec3 Transform(const Vec3& vIn) const\n\t\t{\n\t\t\tVec3 rs;\n\t\t\trs.x = m[0][0] * vIn.x + m[1][0] * vIn.y + m[2][0] * vIn.z;\n\t\t\trs.y = m[0][1] * vIn.x + m[1][1] * vIn.y + m[2][1] * vIn.z;\n\t\t\trs.z = m[0][2] * vIn.x + m[1][2] * vIn.y + m[2][2] * vIn.z;\n\t\t\treturn rs;\n\t\t}\n\t\tinline Vec3 TransformTransposed(const Vec3& vIn) const\n\t\t{\n\t\t\tVec3 rs;\n\t\t\trs.x = m[0][0] * vIn.x + m[0][1] * vIn.y + m[0][2] * vIn.z;\n\t\t\trs.y = m[1][0] * vIn.x + m[1][1] * vIn.y + m[1][2] * vIn.z;\n\t\t\trs.z = m[2][0] * vIn.x + m[2][1] * vIn.y + m[2][2] * vIn.z;\n\t\t\treturn rs;\n\t\t}\n\t\tstatic inline void Multiply(Matrix3 & rs, Matrix3 & m1, Matrix3 & m2)\n\t\t{\n\t\t\tfor (int i = 0; i < 3; i++)\n\t\t\t\tfor (int j = 0; j < 3; j++)\n\t\t\t\t{\n\t\t\t\t\tfloat dot = 0.0f;\n\t\t\t\t\tfor (int k = 0; k < 3; k++)\n\t\t\t\t\t\tdot += m1.m[k][j] * m2.m[i][k];\n\t\t\t\t\trs.m[i][j] = dot;\n\t\t\t\t}\n\t\t}\n\t};\n\n\tenum class ClipSpaceType\n\t{\n\t\tNegativeOneToOne, ZeroToOne\n\t};\n\n\tclass Matrix4\n\t{\n\tpublic:\n\t\tunion\n\t\t{\n\t\t\tfloat values[16];\n\t\t\tfloat m[4][4];\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tfloat _11, _12, _13, _14,\n\t\t\t\t\t_21, _22, _23, _24,\n\t\t\t\t\t_31, _32, _33, _34,\n\t\t\t\t\t_41, _42, _43, _44;\n\t\t\t} mi;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tfloat _11, _12, _13, _14,\n\t\t\t\t\t_21, _22, _23, _24,\n\t\t\t\t\t_31, _32, _33, _34,\n\t\t\t\t\t_41, _42, _43, _44;\n\t\t\t} mr;\n\t\t};\n\t\tMatrix4()\n\t\t{}\n\t\tMatrix4(float v)\n\t\t{\n\t\t\tfor (int i = 0; i<16; i++)\n\t\t\t\tvalues[i] = v;\n\t\t}\n\t\tMatrix4(const Vec4 & c1, const Vec4 & c2, const Vec4 & c3, const Vec4 &c4)\n\t\t{\n\t\t\tmemcpy(m[0], &c1, sizeof(Vec4));\n\t\t\tmemcpy(m[1], &c2, sizeof(Vec4));\n\t\t\tmemcpy(m[2], &c3, sizeof(Vec4));\n\t\t\tmemcpy(m[3], &c4, sizeof(Vec4));\n\t\t}\n\t\tinline Matrix4 & operator += (const Matrix4 & v)\n\t\t{\n\t\t\tfor (int i = 0; i < 16; i++)\n\t\t\t\tvalues[i] += v.values[i];\n\t\t\treturn *this;\n\t\t}\n\t\tinline Matrix3 GetMatrix3()\n\t\t{\n\t\t\tMatrix3 rs;\n\t\t\tfor (int i = 0; i < 3; i++)\n\t\t\t\tfor (int j = 0; j < 3; j++)\n\t\t\t\t\trs.m[i][j] = m[i][j];\n\t\t\treturn rs;\n\t\t}\n\t\tinline Matrix4 & operator *= (const float & val)\n\t\t{\n\t\t\tfor (int i = 0; i < 16; i++)\n\t\t\t\tvalues[i] *= val;\n\t\t\treturn *this;\n\t\t}\n\t\tinline Matrix4 & operator *= (const Matrix4 & matrix)\n\t\t{\n\t\t\tMultiply(*this, *this, matrix);\n\t\t\treturn *this;\n\t\t}\n\t\tinline Matrix4 operator * (const Matrix4 & matrix)\n\t\t{\n\t\t\tMatrix4 rs;\n\t\t\tMultiply(rs, *this, matrix);\n\t\t\treturn rs;\n\t\t}\n\t\tinline Matrix4 & LeftMultiply(const Matrix4 & matrix)\n\t\t{\n\t\t\tMultiply(*this, matrix, *this);\n\t\t\treturn *this;\n\t\t}\n\t\tinline void Transpose()\n\t\t{\n\t\t\tfloat tmp;\n\t\t\tfor (int i = 1; i<4; i++)\n\t\t\t\tfor (int j = 0; j < i; j++)\n\t\t\t\t{\n\t\t\t\t\ttmp = m[i][j];\n\t\t\t\t\tm[i][j] = m[j][i];\n\t\t\t\t\tm[j][i] = tmp;\n\t\t\t\t}\n\t\t}\n\t\tstatic inline void CreateIdentityMatrix(Matrix4 & mOut);\n\t\tstatic inline void CreateRandomMatrix(Matrix4 & mOut);\n\t\tstatic inline void CreateOrthoMatrix(Matrix4 & mOut, float left, float right, float top, float bottom, float zNear, float zFar, ClipSpaceType clipSpace = ClipSpaceType::NegativeOneToOne);\n\t\tstatic inline void CreatePerspectiveMatrixFromViewAngle(Matrix4 &mOut, float fovY, float aspect, float zNear, float zFar, ClipSpaceType clipSpace = ClipSpaceType::NegativeOneToOne);\n\t\tstatic inline void CreatePerspectiveMatrixFromViewAngleTiled(Matrix4 &mOut, float fovY, float aspect, float zNear, float zFar, float x0, float y0, float x1, float y1);\n\t\tstatic inline void CreatePerspectiveMatrix(Matrix4 &mOut, float left, float right, float bottom, float top, float zNear, float zFar, ClipSpaceType clipSpace = ClipSpaceType::NegativeOneToOne);\n\t\tstatic void LookAt(Matrix4 & rs, const Vec3 & pos, const Vec3 & center, const Vec3 & up);\n\t\tstatic inline void RotationX(Matrix4 & rs, float angle);\n\t\tstatic inline void RotationY(Matrix4 & rs, float angle);\n\t\tstatic inline void RotationZ(Matrix4 & rs, float angle);\n\t\tstatic void Rotation(Matrix4 & rs, const Vec3 & axis, float angle);\n\t\tstatic void Rotation(Matrix4 & rs, float yaw, float pitch, float roll);\n\t\tstatic inline void Scale(Matrix4 & rs, float sx, float sy, float sz);\n\t\tstatic inline void Translation(Matrix4 & rs, float tx, float ty, float tz);\n\t\tinline void Transform(Vec3 & rs_d, const Vec3& vIn) const;\n\t\tinline void Transform(Vec4 & rs_d, const Vec4& vIn) const;\n\t\tinline Vec4 Transform(const Vec4& vIn) const;\n\t\tinline Vec3 TransformNormal(const Vec3& vIn) const;\n\n\t\tinline void TransformNormal(Vec3 & rs, const Vec3& vIn) const;\n\t\tinline void TransposeTransformNormal(Vec3 & rs, const Vec3 & vIn) const;\n\t\tinline void TransposeTransform(Vec3 & rs, const Vec3 & vIn) const;\n\t\tinline void TransposeTransform(Vec4 & rs_d, const Vec4& vIn) const;\n\t\tinline Vec3 TransformHomogeneous(const Vec3 & vIn) const;\n\t\tinline void TransformHomogeneous(Vec3 & rs, const Vec3 & vIn) const;\n\t\tinline void TransformHomogeneous2D(Vec2 & rs, const Vec3 & vIn) const;\n\t\tstatic inline void MultiplyFPU(Matrix4 &mOut, const Matrix4& M1, const Matrix4& M2);\n\t\tstatic inline void Multiply(Matrix4 &mOut, const Matrix4& M1, const Matrix4& M2);\n\t\tfloat Inverse3D(Matrix4 & mOut_d) const;\n\t\tfloat InverseFPU(Matrix4 &mOut_d) const;\n\t\tvoid GetNormalMatrix(Matrix4 & mOut) const;\n\t\tinline float Inverse(Matrix4 &mOut_d) const;\n\t};\n\n\t//__declspec(align(16))\n\tclass Matrix4_M128\n\t{\n\tprivate:\n\t\tstatic const __m128 VecOne;\n\tpublic:\n\t\t__m128 C1, C2, C3, C4;\n\t\tMatrix4_M128()\n\t\t{}\n\t\tMatrix4_M128(const Matrix4 & m)\n\t\t{\n\t\t\tC1 = _mm_loadu_ps(m.values);\n\t\t\tC2 = _mm_loadu_ps(m.values + 4);\n\t\t\tC3 = _mm_loadu_ps(m.values + 8);\n\t\t\tC4 = _mm_loadu_ps(m.values + 12);\n\t\t}\n\t\tinline void ToMatrix4(Matrix4 & mOut) const;\n\t\tinline void Transform(Vec4_M128 & rs, const Vec4& vIn) const;\n\t\tinline void Transform(Vec4 & rs, const Vec4& vIn) const;\n\t\tinline void Transform(Vec4_M128 & rs, const Vec3& vIn) const;\n\t\tinline void Transform(Vec3 & rs, const Vec3& vIn) const;\n\t\tinline void Transform(Vec4_M128 & rs, const Vec4_M128& vIn) const;\n\t\tinline void TransformNormal(Vec4_M128 & rs, const Vec4& vIn) const;\n\t\tinline void TransformNormal(Vec4 & rs, const Vec4& vIn) const;\n\t\tinline void TransformNormal(Vec4_M128 & rs, const Vec3& vIn) const;\n\t\tinline void TransformNormal(Vec3 & rs, const Vec3& vIn) const;\n\t\tinline void Multiply(Matrix4_M128 & rs, const Matrix4 & mB) const;\n\t\tinline void Multiply(Matrix4_M128 & rs, const Matrix4_M128 & mB) const;\n\t\tfloat Inverse(Matrix4_M128 &mOut) const;\n\t};\n\n\t//***********************************************************************\n\t/**************************** Implementation ****************************/\n\t//***********************************************************************\n\t//inline int FloatAsInt(float val)\n\t//{\n\t//\tunion InterCast\n\t//\t{\n\t//\t\tfloat fvalue;\n\t//\t\tint ivalue;\n\t//\t} cast;\n\t//\tcast.fvalue = val;\n\t//\treturn cast.ivalue;\n\t//}\n\t//inline float IntAsFloat(int val)\n\t//{\n\t//\tunion InterCast\n\t//\t{\n\t//\t\tfloat fvalue;\n\t//\t\tint ivalue;\n\t//\t} cast;\n\t//\tcast.ivalue = val;\n\t//\treturn cast.fvalue;\n\t//}\n\tinline Vec3 Vec3::FromHomogeneous(const Vec4 & v)\n\t{\n\t\tfloat invW = 1.0f / v.w;\n\t\treturn v.xyz()*invW;\n\t}\n\t// Vec3\n\tinline float Vec3::Length() const\n\t{\n\t\treturn Vec4::Create(*this, 0.0f).Length();\n\t}\n\tinline void Vec3::Normalize(Vec3 & rs, const Vec3 & vin)\n\t{\n\t\tVec3::NormalizeFPU(rs, vin);\n\t}\n\t// Vec4\n\tinline void Vec4::Add(Vec4 & rs, const Vec4 & v1, const Vec4 & v2)\n\t{\n\t\trs.x = v1.x + v2.x;\n\t\trs.y = v1.y + v2.y;\n\t\trs.z = v1.z + v2.z;\n\t\trs.w = v1.w + v2.w;\n\t}\n\tinline void Vec4::Subtract(Vec4 & rs, const Vec4 & v1, const Vec4 & v2)\n\t{\n\t\trs.x = v1.x - v2.x;\n\t\trs.y = v1.y - v2.y;\n\t\trs.z = v1.z - v2.z;\n\t\trs.w = v1.w - v2.w;\n\t}\n\tinline void Vec4::Multiply(Vec4 & rs, const Vec4 & v1, const Vec4 & v2)\n\t{\n\t\trs.x = v1.x * v2.x;\n\t\trs.y = v1.y * v2.y;\n\t\trs.z = v1.z * v2.z;\n\t\trs.w = v1.w * v2.w;\n\t}\n\tinline void Vec4::MultiplyScale(Vec4 & rs, const Vec4 & v1, const Vec4 & v2)\n\t{\n\t\trs.x = v1.x * v2.x;\n\t\trs.y = v1.y * v2.y;\n\t\trs.z = v1.z * v2.z;\n\t\trs.w = v1.w * v2.w;\n\t}\n\tinline void Vec4::Scale(Vec4 & rs, const Vec4 & v1, float s)\n\t{\n\t\trs.x = v1.x * s;\n\t\trs.y = v1.y * s;\n\t\trs.z = v1.z * s;\n\t\trs.w = v1.w * s;\n\t}\n\tinline float Vec4::Dot(const Vec4 & v1, const Vec4 & v2)\n\t{\n\t\treturn v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w;\n\t}\n\tinline void Vec4::Cross(Vec4 & rs_d, const Vec4 & v1, const Vec4 & v2)\n\t{\n\t\trs_d.x = v1.y*v2.z - v1.z * v2.y;\n\t\trs_d.y = v1.z*v2.x - v1.x * v2.z;\n\t\trs_d.z = v1.x*v2.y - v1.y * v2.x;\n\t\trs_d.w = 0.0f;\n\t}\n\tinline float Vec4::LengthFPU() const\n\t{\n\t\treturn sqrt(Dot(*this, *this));\n\t}\n\tinline float Vec4::Length() const\n\t{\n#ifdef NO_SIMD_ASM\n\t\treturn LengthFPU();\n#else\n\t\tfloat f;\n\t\t_asm\n\t\t{\n\t\t\tlea\tecx, f;\n\t\t\tmov\teax, this;\n\n\t\t\tmovups\txmm0, [eax];\n\t\t\tmulps\txmm0, xmm0;\n\t\t\tmovaps\txmm1, xmm0;\n\t\t\tshufps\txmm1, xmm1, 4Eh;\n\t\t\taddps\txmm0, xmm1;\n\t\t\tmovaps\txmm1, xmm0;\n\t\t\tshufps\txmm1, xmm1, 11h;\n\t\t\taddss\txmm0, xmm1;\n\n\t\t\tsqrtss\txmm0, xmm0;\n\t\t\tmovss\tdword ptr[ecx], xmm0;\n\t\t}\n\t\treturn f;\n#endif\n\t}\n\tinline void Vec4::NormalizeFPU(Vec4& vout, const Vec4& vin)\n\t{\n\t\tfloat len = 1.0f / vin.Length();\n\t\tScale(vout, vin, len);\n\t}\n\tinline void Vec4::Normalize(Vec4 &vout, const Vec4 &vin)\n\t{\n#ifdef NO_SIMD_ASM\n\t\tNormalizeFPU(vout, vin);\n#else\n\t\t__m128 xmm0 = _mm_loadu_ps((float*)&vin);\n\t\t__m128 xmm2 = xmm0;\n\t\txmm0 = _mm_mul_ps(xmm0, xmm0);\n\t\t__m128 xmm1 = xmm0;\n\t\txmm1 = _mm_shuffle_ps(xmm1, xmm1, 0x4E);\n\t\txmm0 = _mm_add_ps(xmm0, xmm1);\n\t\txmm1 = xmm0;\n\t\txmm1 = _mm_shuffle_ps(xmm1, xmm1, 0x11);\n\t\txmm0 = _mm_add_ps(xmm0, xmm1);\n\t\txmm0 = _mm_rsqrt_ps(xmm0);\n\t\txmm2 = _mm_mul_ps(xmm2, xmm0);\n\t\t_mm_storeu_ps((float*)&vout, xmm2);\n#endif\n\t}\n\n\t// Matrix4\n\tinline void Matrix4::CreateIdentityMatrix(Matrix4 & mOut)\n\t{\n\t\tmemset(&mOut, 0, sizeof(Matrix4));\n\t\tmOut.m[0][0] = mOut.m[1][1] = mOut.m[2][2] = mOut.m[3][3] = 1.0f;\n\t}\n\n\tinline void Matrix4::CreateOrthoMatrix(Matrix4 & mOut, float left, float right, float top, float bottom, float zNear, float zFar, ClipSpaceType clipSpace)\n\t{\n\t\tmemset(&mOut, 0, sizeof(Matrix4));\n\t\tmOut.m[0][0] = 2.0f / (right - left);\n\t\tmOut.m[1][1] = 2.0f / (top - bottom);\n\t\tmOut.m[3][0] = -(right + left) / (right - left);\n\t\tmOut.m[3][1] = -(top + bottom) / (top - bottom);\n\t\tif (clipSpace == ClipSpaceType::NegativeOneToOne)\n\t\t{\n\t\t\tmOut.m[2][2] = -2.0f / (zFar - zNear);\n\t\t\tmOut.m[3][2] = -(zFar + zNear) / (zFar - zNear);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmOut.m[2][2] = -1.0f / (zFar - zNear);\n\t\t\tmOut.m[3][2] = 0.5f - 0.5f * (zFar + zNear) / (zFar - zNear);\n\t\t}\n\t\tmOut.m[3][3] = 1.0f;\n\t}\n\n\tinline void Matrix4::CreatePerspectiveMatrix(Matrix4 &mOut, float left, float right, float bottom, float top, float znear, float zfar, ClipSpaceType /*clipSpace*/)\n\t{\n\t\tmemset(&mOut, 0, sizeof(Matrix4));\n\t\tmOut.m[0][0] = (znear*2.0f) / (right - left);\n\t\tmOut.m[1][1] = (2.0f*znear) / (top - bottom);\n\t\tmOut.m[2][0] = (right + left) / (right - left);\n\t\tmOut.m[2][1] = (top + bottom) / (top - bottom);\n\t\tmOut.m[2][3] = -1.0f;\n\t\t\n\t\tmOut.m[2][2] = (zfar + znear) / (znear - zfar);\n\t\tmOut.m[3][2] = 2.0f*zfar*znear / (znear - zfar);\n\t\t\n\t}\n\n\tinline void Matrix4::CreatePerspectiveMatrixFromViewAngle(Matrix4 &mOut, float fovY, float aspect, float zNear, float zFar, ClipSpaceType clipSpace)\n\t{\n\t\tfloat xmin, xmax, ymin, ymax;\n\t\tymax = zNear * tan(fovY * CoreLib::Basic::Math::Pi / 360.0f);\n\t\tymin = -ymax;\n\t\txmin = ymin * aspect;\n\t\txmax = ymax * aspect;\n\t\tMatrix4::CreatePerspectiveMatrix(mOut, xmin, xmax, ymin, ymax, zNear, zFar, clipSpace);\n\t}\n\n\tinline void Matrix4::CreatePerspectiveMatrixFromViewAngleTiled(Matrix4 &mOut, float fovY, float aspect, float zNear, float zFar, float x0, float y0, float x1, float y1)\n\t{\n\t\tfloat xmin, xmax, ymin, ymax;\n\t\tymax = zNear * tan(fovY * CoreLib::Basic::Math::Pi / 360.0f);\n\t\tymin = -ymax;\n\t\txmin = ymin * aspect;\n\t\txmax = ymax * aspect;\n\t\tx0 *= (xmax - xmin);  x0 += xmin;\n\t\ty0 *= (ymax - ymin); y0 += ymin;\n\t\tx1 *= (xmax - xmin);  x1 += xmin;\n\t\ty1 *= (ymax - ymin); y1 += ymin;\n\t\tMatrix4::CreatePerspectiveMatrix(mOut, x0, x1, y0, y1, zNear, zFar);\n\t}\n\n\tinline void Matrix4::CreateRandomMatrix(Matrix4 & mOut)\n\t{\n\t\tfor (int i = 0; i<16; i++)\n\t\t{\n\t\t\tmOut.values[i] = rand() / (float)RAND_MAX;\n\t\t}\n\t}\n\tinline void Matrix4::RotationX(Matrix4 & rs, float angle)\n\t{\n\t\tfloat c = cosf(angle);\n\t\tfloat s = sinf(angle);\n\n\t\tMatrix4::CreateIdentityMatrix(rs);\n\t\trs.m[1][1] = c;\n\t\trs.m[2][1] = -s;\n\t\trs.m[1][2] = s;\n\t\trs.m[2][2] = c;\n\t}\n\tinline void Matrix4::RotationY(Matrix4 & rs, float angle)\n\t{\n\t\tfloat c = cosf(angle);\n\t\tfloat s = sinf(angle);\n\n\t\tMatrix4::CreateIdentityMatrix(rs);\n\t\trs.m[0][0] = c;\n\t\trs.m[2][0] = s;\n\t\trs.m[0][2] = -s;\n\t\trs.m[2][2] = c;\n\t}\n\tinline void Matrix4::RotationZ(Matrix4 & rs, float angle)\n\t{\n\t\tfloat c = cosf(angle);\n\t\tfloat s = sinf(angle);\n\n\t\tMatrix4::CreateIdentityMatrix(rs);\n\t\trs.m[0][0] = c;\n\t\trs.m[1][0] = -s;\n\t\trs.m[0][1] = s;\n\t\trs.m[1][1] = c;\n\t}\n\n\tinline void Matrix4::Scale(Matrix4 & rs, float sx, float sy, float sz)\n\t{\n\t\tMatrix4::CreateIdentityMatrix(rs);\n\t\trs.m[0][0] = sx;\n\t\trs.m[1][1] = sy;\n\t\trs.m[2][2] = sz;\n\t}\n\tinline void Matrix4::Translation(Matrix4 & rs, float tx, float ty, float tz)\n\t{\n\t\tMatrix4::CreateIdentityMatrix(rs);\n\t\trs.values[12] = tx;\n\t\trs.values[13] = ty;\n\t\trs.values[14] = tz;\n\t}\n\tinline void Matrix4::TransposeTransformNormal(Vec3 & rs, const Vec3 & vIn) const\n\t{\n\t\trs.x = m[0][0] * vIn.x + m[0][1] * vIn.y + m[0][2] * vIn.z;\n\t\trs.y = m[1][0] * vIn.x + m[1][1] * vIn.y + m[1][2] * vIn.z;\n\t\trs.z = m[2][0] * vIn.x + m[2][1] * vIn.y + m[2][2] * vIn.z;\n\t}\n\tinline void Matrix4::TransposeTransform(Vec3 & rs, const Vec3 & vIn) const\n\t{\n\t\trs.x = m[0][0] * vIn.x + m[0][1] * vIn.y + m[0][2] * vIn.z + m[0][3];\n\t\trs.y = m[1][0] * vIn.x + m[1][1] * vIn.y + m[1][2] * vIn.z + m[1][3];\n\t\trs.z = m[2][0] * vIn.x + m[2][1] * vIn.y + m[2][2] * vIn.z + m[2][3];\n\t}\n\tinline void Matrix4::TransposeTransform(Vec4 & rs, const Vec4 & vIn) const\n\t{\n\t\trs.x = m[0][0] * vIn.x + m[0][1] * vIn.y + m[0][2] * vIn.z + m[0][3] * vIn.w;\n\t\trs.y = m[1][0] * vIn.x + m[1][1] * vIn.y + m[1][2] * vIn.z + m[1][3] * vIn.w;\n\t\trs.z = m[2][0] * vIn.x + m[2][1] * vIn.y + m[2][2] * vIn.z + m[2][3] * vIn.w;\n\t\trs.w = m[3][0] * vIn.x + m[3][1] * vIn.y + m[3][2] * vIn.z + m[3][3] * vIn.w;\n\t}\n\tinline void Matrix4::Transform(Vec3 & rs, const Vec3& vIn) const\n\t{\n\t\trs.x = m[0][0] * vIn.x + m[1][0] * vIn.y + m[2][0] * vIn.z + m[3][0];\n\t\trs.y = m[0][1] * vIn.x + m[1][1] * vIn.y + m[2][1] * vIn.z + m[3][1];\n\t\trs.z = m[0][2] * vIn.x + m[1][2] * vIn.y + m[2][2] * vIn.z + m[3][2];\n\t}\n\tinline Vec3 Matrix4::TransformHomogeneous(const Vec3 & vIn) const\n\t{\n\t\tVec3 rs;\n\t\trs.x = m[0][0] * vIn.x + m[1][0] * vIn.y + m[2][0] * vIn.z + m[3][0];\n\t\trs.y = m[0][1] * vIn.x + m[1][1] * vIn.y + m[2][1] * vIn.z + m[3][1];\n\t\trs.z = m[0][2] * vIn.x + m[1][2] * vIn.y + m[2][2] * vIn.z + m[3][2];\n\t\tfloat w = 1.0f / (m[0][3] * vIn.x + m[1][3] * vIn.y + m[2][3] * vIn.z + m[3][3]);\n\t\trs.x *= w;\n\t\trs.y *= w;\n\t\trs.z *= w;\n\t\treturn rs;\n\t}\n\tinline void Matrix4::TransformHomogeneous(Vec3 & rs, const Vec3 & vIn) const\n\t{\n\t\trs.x = m[0][0] * vIn.x + m[1][0] * vIn.y + m[2][0] * vIn.z + m[3][0];\n\t\trs.y = m[0][1] * vIn.x + m[1][1] * vIn.y + m[2][1] * vIn.z + m[3][1];\n\t\trs.z = m[0][2] * vIn.x + m[1][2] * vIn.y + m[2][2] * vIn.z + m[3][2];\n\t\tfloat w = 1.0f / (m[0][3] * vIn.x + m[1][3] * vIn.y + m[2][3] * vIn.z + m[3][3]);\n\t\trs.x *= w;\n\t\trs.y *= w;\n\t\trs.z *= w;\n\t}\n\tinline void Matrix4::TransformHomogeneous2D(Vec2 & rs, const Vec3 & vIn) const\n\t{\n\t\trs.x = m[0][0] * vIn.x + m[1][0] * vIn.y + m[2][0] * vIn.z + m[3][0];\n\t\trs.y = m[0][1] * vIn.x + m[1][1] * vIn.y + m[2][1] * vIn.z + m[3][1];\n\t\tfloat w = 1.0f / (m[0][3] * vIn.x + m[1][3] * vIn.y + m[2][3] * vIn.z + m[3][3]);\n\t\trs.x *= w;\n\t\trs.y *= w;\n\t}\n\tinline void Matrix4::TransformNormal(Vec3 & rs, const Vec3& vIn) const\n\t{\n\t\trs.x = m[0][0] * vIn.x + m[1][0] * vIn.y + m[2][0] * vIn.z;\n\t\trs.y = m[0][1] * vIn.x + m[1][1] * vIn.y + m[2][1] * vIn.z;\n\t\trs.z = m[0][2] * vIn.x + m[1][2] * vIn.y + m[2][2] * vIn.z;\n\t}\n\tinline void Matrix4::Transform(Vec4 & rs, const Vec4& vIn) const\n\t{\n\t\trs.x = m[0][0] * vIn.x + m[1][0] * vIn.y + m[2][0] * vIn.z + m[3][0] * vIn.w;\n\t\trs.y = m[0][1] * vIn.x + m[1][1] * vIn.y + m[2][1] * vIn.z + m[3][1] * vIn.w;\n\t\trs.z = m[0][2] * vIn.x + m[1][2] * vIn.y + m[2][2] * vIn.z + m[3][2] * vIn.w;\n\t\trs.w = m[0][3] * vIn.x + m[1][3] * vIn.y + m[2][3] * vIn.z + m[3][3] * vIn.w;\n\t}\n\tinline Vec3 Matrix4::TransformNormal(const Vec3& vIn) const\n\t{\n\t\tVec3 rs;\n\t\trs.x = m[0][0] * vIn.x + m[1][0] * vIn.y + m[2][0] * vIn.z;\n\t\trs.y = m[0][1] * vIn.x + m[1][1] * vIn.y + m[2][1] * vIn.z;\n\t\trs.z = m[0][2] * vIn.x + m[1][2] * vIn.y + m[2][2] * vIn.z;\n\t\treturn rs;\n\t}\n\tinline Vec4 Matrix4::Transform(const Vec4& vIn) const\n\t{\n\t\tVec4 rs;\n\t\trs.x = m[0][0] * vIn.x + m[1][0] * vIn.y + m[2][0] * vIn.z + m[3][0] * vIn.w;\n\t\trs.y = m[0][1] * vIn.x + m[1][1] * vIn.y + m[2][1] * vIn.z + m[3][1] * vIn.w;\n\t\trs.z = m[0][2] * vIn.x + m[1][2] * vIn.y + m[2][2] * vIn.z + m[3][2] * vIn.w;\n\t\trs.w = m[0][3] * vIn.x + m[1][3] * vIn.y + m[2][3] * vIn.z + m[3][3] * vIn.w;\n\t\treturn rs;\n\t}\n\tinline void Matrix4::MultiplyFPU(Matrix4 &mOut, const Matrix4& M1, const Matrix4& M2)\n\t{\n\t\tMatrix4 TempMat;\n\t\tfor (int i = 0; i<4; i++) //col\n\t\t{\n\t\t\tfor (int j = 0; j<4; j++) // row\n\t\t\t{\n\t\t\t\tTempMat.m[i][j] = M1.m[0][j] * M2.m[i][0] + M1.m[1][j] * M2.m[i][1] + M1.m[2][j] * M2.m[i][2] + M1.m[3][j] * M2.m[i][3];\n\t\t\t}\n\t\t}\n\t\tmemcpy(&mOut, &TempMat, sizeof(Matrix4));\n\t}\n\n\tinline void Matrix4::Multiply(Matrix4 &mOut, const Matrix4 &M1, const Matrix4 &M2)\n\t{\n\t\tMatrix4 rs;\n\t\tMatrix4_M128 TempMat;\n\t\tMatrix4_M128 mA(M1);\n\t\tmA.Multiply(TempMat, M2);\n\t\tTempMat.ToMatrix4(rs);\n\t\tmOut = rs;\n\t}\n\tinline float Matrix4::Inverse(Matrix4 &mOut_d) const\n\t{\n\t\tMatrix4 mat;\n\t\tMatrix4_M128 m_m(*this);\n\t\tMatrix4_M128 tmr;\n\t\tfloat rs = m_m.Inverse(tmr);\n\t\ttmr.ToMatrix4(mat);\n\t\tmOut_d = mat;\n\t\treturn rs;\n\t}\n\n\t// Matrix4_M128\n\n\tinline void Matrix4_M128::ToMatrix4(Matrix4 & mOut) const\n\t{\n\t\t_mm_storeu_ps(mOut.values, C1);\n\t\t_mm_storeu_ps(mOut.values + 4, C2);\n\t\t_mm_storeu_ps(mOut.values + 8, C3);\n\t\t_mm_storeu_ps(mOut.values + 12, C4);\n\t}\n\tinline void Matrix4_M128::Transform(Vec4_M128 & rs, const Vec4& vIn) const\n\t{\n\t\t__m128 r;\n\t\tr = _mm_mul_ps(C1, _mm_set_ps1(vIn.x));\n\t\tr = _mm_add_ps(r, _mm_mul_ps(C2, _mm_set_ps1(vIn.y)));\n\t\tr = _mm_add_ps(r, _mm_mul_ps(C3, _mm_set_ps1(vIn.z)));\n\t\tr = _mm_add_ps(r, _mm_mul_ps(C4, _mm_set_ps1(vIn.w)));\n\t\trs.vec = r;\n\t}\n\tinline void Matrix4_M128::Transform(Vec4 & rs, const Vec4& vIn) const\n\t{\n\t\tVec4_M128 r;\n\t\tTransform(r, vIn);\n\t\t_mm_store_ps((float*)&rs, r.vec);\n\t}\n\tinline void Matrix4_M128::Transform(Vec4_M128 & rs, const Vec3& vIn) const\n\t{\n\t\t__m128 r;\n\t\tr = _mm_mul_ps(C1, _mm_set_ps1(vIn.x));\n\t\tr = _mm_add_ps(r, _mm_mul_ps(C2, _mm_set_ps1(vIn.y)));\n\t\tr = _mm_add_ps(r, _mm_mul_ps(C3, _mm_set_ps1(vIn.z)));\n\t\trs.vec = r;\n\t}\n\tinline void Matrix4_M128::Transform(Vec3 & rs, const Vec3& vIn) const\n\t{\n\t\tVec4_M128 r;\n\t\tTransform(r, vIn);\n\t\tVec4 tmp;\n\t\t_mm_store_ps((float*)&tmp, r.vec);\n\t\trs.x = tmp.x;\n\t\trs.y = tmp.y;\n\t\trs.z = tmp.z;\n\t}\n\tinline void Matrix4_M128::Transform(Vec4_M128 & rs, const Vec4_M128& vIn) const\n\t{\n\t\t__m128 r;\n\t\t__m128 x, y, z, w;\n\t\tx = _mm_shuffle_ps(vIn.vec, vIn.vec, _MM_SHUFFLE(0, 0, 0, 0));\n\t\tr = _mm_mul_ps(C1, x);\n\t\ty = _mm_shuffle_ps(vIn.vec, vIn.vec, _MM_SHUFFLE(1, 1, 1, 1));\n\t\tr = _mm_add_ps(r, _mm_mul_ps(C2, y));\n\t\tz = _mm_shuffle_ps(vIn.vec, vIn.vec, _MM_SHUFFLE(2, 2, 2, 2));\n\t\tr = _mm_add_ps(r, _mm_mul_ps(C3, z));\n\t\tw = _mm_shuffle_ps(vIn.vec, vIn.vec, _MM_SHUFFLE(3, 3, 3, 3));\n\t\tr = _mm_add_ps(r, _mm_mul_ps(C4, w));\n\t\trs.vec = r;\n\t}\n\tinline void Matrix4_M128::TransformNormal(Vec4_M128 & rs, const Vec4& vIn) const\n\t{\n\t\t__m128 r;\n\t\tr = _mm_mul_ps(C1, _mm_set_ps1(vIn.x));\n\t\tr = _mm_add_ps(r, _mm_mul_ps(C2, _mm_set_ps1(vIn.y)));\n\t\tr = _mm_add_ps(r, _mm_mul_ps(C3, _mm_set_ps1(vIn.z)));\n\t\trs.vec = r;\n\t}\n\tinline void Matrix4_M128::TransformNormal(Vec4 & rs, const Vec4& vIn) const\n\t{\n\t\tVec4_M128 r;\n\t\tTransformNormal(r, vIn);\n\t\t_mm_store_ps((float*)&rs, r.vec);\n\t\trs.w = 0.0f;\n\t}\n\tinline void Matrix4_M128::TransformNormal(Vec4_M128 & rs, const Vec3& vIn) const\n\t{\n\t\t__m128 r;\n\t\tr = _mm_mul_ps(C1, _mm_set_ps1(vIn.x));\n\t\tr = _mm_add_ps(r, _mm_mul_ps(C2, _mm_set_ps1(vIn.y)));\n\t\tr = _mm_add_ps(r, _mm_mul_ps(C3, _mm_set_ps1(vIn.z)));\n\t\trs.vec = r;\n\t}\n\tinline void Matrix4_M128::TransformNormal(Vec3 & rs, const Vec3& vIn) const\n\t{\n\t\tVec4_M128 r;\n\t\tTransformNormal(r, vIn);\n\t\tVec4 tmp;\n\t\t_mm_store_ps((float*)&tmp, r.vec);\n\t\trs = tmp.xyz();\n\t}\n\tinline void Matrix4_M128::Multiply(Matrix4_M128 & rs, const Matrix4 & mB) const\n\t{\n\t\t__m128 T0, T1, T2, T3, R0, R1, R2, R3;\n\t\tT0 = _mm_set_ps1(mB.values[0]);\n\t\tT1 = _mm_set_ps1(mB.values[1]);\n\t\tT2 = _mm_set_ps1(mB.values[2]);\n\t\tT3 = _mm_set_ps1(mB.values[3]);\n\t\tR0 = _mm_mul_ps(C1, T0);\n\t\tT0 = _mm_set_ps1(mB.values[4]);\n\t\tR1 = _mm_mul_ps(C2, T1);\n\t\tR1 = _mm_add_ps(R1, R0);\n\t\tR2 = _mm_mul_ps(C3, T2);\n\t\tT1 = _mm_set_ps1(mB.values[5]);\n\t\tR3 = _mm_mul_ps(C4, T3);\n\t\tR2 = _mm_add_ps(R2, R1);\n\t\tT2 = _mm_set_ps1(mB.values[6]);\n\t\trs.C1 = _mm_add_ps(R3, R2);\n\t\tR0 = _mm_mul_ps(C1, T0);\n\t\tT3 = _mm_set_ps1(mB.values[7]);\n\t\tR1 = _mm_mul_ps(C2, T1);\n\t\tT0 = _mm_set_ps1(mB.values[8]);\n\t\tR2 = _mm_mul_ps(C3, T2);\n\t\tR1 = _mm_add_ps(R1, R0);\n\t\tT1 = _mm_set_ps1(mB.values[9]);\n\t\tR3 = _mm_mul_ps(C4, T3);\n\t\tR2 = _mm_add_ps(R2, R1);\n\t\trs.C2 = _mm_add_ps(R3, R2);\n\t\tT2 = _mm_set_ps1(mB.values[10]);\n\t\tR0 = _mm_mul_ps(C1, T0);\n\t\tT3 = _mm_set_ps1(mB.values[11]);\n\t\tR1 = _mm_mul_ps(C2, T1);\n\t\tT0 = _mm_set_ps1(mB.values[12]);\n\t\tR2 = _mm_mul_ps(C3, T2);\n\t\tR1 = _mm_add_ps(R1, R0);\n\t\tT2 = _mm_set_ps1(mB.values[14]);\n\t\tR3 = _mm_mul_ps(C4, T3);\n\t\tR2 = _mm_add_ps(R2, R1);\n\t\tT1 = _mm_set_ps1(mB.values[13]);\n\t\trs.C3 = _mm_add_ps(R3, R2);\n\t\tR0 = _mm_mul_ps(C1, T0);\n\t\tR1 = _mm_mul_ps(C2, T1);\n\t\tT3 = _mm_set_ps1(mB.values[15]);\n\t\tR2 = _mm_mul_ps(C3, T2);\n\t\tR1 = _mm_add_ps(R1, R0);\n\t\tR3 = _mm_mul_ps(C4, T3);\n\t\tR2 = _mm_add_ps(R2, R1);\n\t\trs.C4 = _mm_add_ps(R3, R2);\n\t}\n\tinline void Matrix4_M128::Multiply(Matrix4_M128 & rs, const Matrix4_M128 & mB) const\n\t{\n\t\t__m128 T0, T1, T2, T3, R0, R1, R2, R3;\n\t\tT0 = _mm_shuffle_ps(mB.C1, mB.C1, _MM_SHUFFLE(0, 0, 0, 0));\n\t\tT1 = _mm_shuffle_ps(mB.C1, mB.C1, _MM_SHUFFLE(1, 1, 1, 1));\n\t\tT2 = _mm_shuffle_ps(mB.C1, mB.C1, _MM_SHUFFLE(2, 2, 2, 2));\n\t\tT3 = _mm_shuffle_ps(mB.C1, mB.C1, _MM_SHUFFLE(3, 3, 3, 3));\n\t\tR0 = _mm_mul_ps(C1, T0);\n\t\tR1 = _mm_mul_ps(C2, T1);\n\t\tR2 = _mm_mul_ps(C3, T2);\n\t\tR3 = _mm_mul_ps(C4, T3);\n\t\tR1 = _mm_add_ps(R1, R0);\n\t\tR2 = _mm_add_ps(R2, R1);\n\t\trs.C1 = _mm_add_ps(R3, R2);\n\n\t\tT0 = _mm_shuffle_ps(mB.C2, mB.C2, _MM_SHUFFLE(0, 0, 0, 0));\n\t\tT1 = _mm_shuffle_ps(mB.C2, mB.C2, _MM_SHUFFLE(1, 1, 1, 1));\n\t\tT2 = _mm_shuffle_ps(mB.C2, mB.C2, _MM_SHUFFLE(2, 2, 2, 2));\n\t\tT3 = _mm_shuffle_ps(mB.C2, mB.C2, _MM_SHUFFLE(3, 3, 3, 3));\n\t\tR0 = _mm_mul_ps(C1, T0);\n\t\tR1 = _mm_mul_ps(C2, T1);\n\t\tR2 = _mm_mul_ps(C3, T2);\n\t\tR3 = _mm_mul_ps(C4, T3);\n\t\tR1 = _mm_add_ps(R1, R0);\n\t\tR2 = _mm_add_ps(R2, R1);\n\t\trs.C2 = _mm_add_ps(R3, R2);\n\n\t\tT0 = _mm_shuffle_ps(mB.C3, mB.C3, _MM_SHUFFLE(0, 0, 0, 0));\n\t\tT1 = _mm_shuffle_ps(mB.C3, mB.C3, _MM_SHUFFLE(1, 1, 1, 1));\n\t\tT2 = _mm_shuffle_ps(mB.C3, mB.C3, _MM_SHUFFLE(2, 2, 2, 2));\n\t\tT3 = _mm_shuffle_ps(mB.C3, mB.C3, _MM_SHUFFLE(3, 3, 3, 3));\n\t\tR0 = _mm_mul_ps(C1, T0);\n\t\tR1 = _mm_mul_ps(C2, T1);\n\t\tR2 = _mm_mul_ps(C3, T2);\n\t\tR3 = _mm_mul_ps(C4, T3);\n\t\tR1 = _mm_add_ps(R1, R0);\n\t\tR2 = _mm_add_ps(R2, R1);\n\t\trs.C3 = _mm_add_ps(R3, R2);\n\n\t\tT0 = _mm_shuffle_ps(mB.C4, mB.C4, _MM_SHUFFLE(0, 0, 0, 0));\n\t\tT1 = _mm_shuffle_ps(mB.C4, mB.C4, _MM_SHUFFLE(1, 1, 1, 1));\n\t\tT2 = _mm_shuffle_ps(mB.C4, mB.C4, _MM_SHUFFLE(2, 2, 2, 2));\n\t\tT3 = _mm_shuffle_ps(mB.C4, mB.C4, _MM_SHUFFLE(3, 3, 3, 3));\n\t\tR0 = _mm_mul_ps(C1, T0);\n\t\tR1 = _mm_mul_ps(C2, T1);\n\t\tR2 = _mm_mul_ps(C3, T2);\n\t\tR3 = _mm_mul_ps(C4, T3);\n\t\tR1 = _mm_add_ps(R1, R0);\n\t\tR2 = _mm_add_ps(R2, R1);\n\t\trs.C4 = _mm_add_ps(R3, R2);\n\t}\n\n\tinline void CartesianToSphere(const Vec3 & dir, float & u, float & v)\n\t{\n\t\tconst float inv2Pi = 0.5f / PI;\n\t\tv = acos(dir.y);\n\t\tu = atan2(dir.z, dir.x);\n\t\tif (u<0.0f)\n\t\t\tu += PI * 2.0f;\n\t\tu *= inv2Pi;\n\t\tv *= 1.0f / PI;\n\t}\n\n\tinline void SphereToCartesian(Vec3 & dir, float u, float v)\n\t{\n\t\tdir.y = cos(v);\n\t\tfloat s = sin(v);\n\t\tdir.x = cos(u) * s;\n\t\tdir.z = sin(u) * s;\n\t}\n\n\tinline void GetOrthoVec(Vec3 & vout, const Vec3 & vin)\n\t{\n\t\tVec3 absV = Vec3::Create(abs(vin.x), abs(vin.y), abs(vin.z));\n\t\tif (absV.x <= absV.y && absV.x <= absV.z)\n\t\t\tVec3::Cross(vout, vin, Vec3::Create(1.0f, 0.0f, 0.0f));\n\t\telse if (absV.y <= absV.x && absV.y <= absV.z)\n\t\t\tVec3::Cross(vout, vin, Vec3::Create(0.0f, 1.0f, 0.0f));\n\t\telse\n\t\t\tVec3::Cross(vout, vin, Vec3::Create(0.0f, 0.0f, 1.0f));\n\t}\n\n\ttemplate<typename T>\n\tinline T CatmullInterpolate(const T & p0, const T & p1, const T & p2, const T & p3, float t)\n\t{\n\t\tfloat t2 = t * t;\n\t\tfloat t3 = t2 * t;\n\t\treturn (p1 * 2.0f + (-p0 + p2) * t +\n\t\t\t(p0 * 2.0f - p1 * 5.0f + p2 * 4.0f - p3) * t2 +\n\t\t\t(-p0 + p1 * 3.0f - p2 * 3.0f + p3) * t3) * 0.5f;\n\t}\n#ifdef _MSC_VER\n#ifndef __clang__\n#ifndef M128_OPERATOR_OVERLOADS\n#define M128_OPERATOR_OVERLOADS\n\tinline __m128 & operator += (__m128 & v0, const __m128 &v1)\n\t{\n\t\tv0 = _mm_add_ps(v0, v1);\n\t\treturn v0;\n\t}\n\tinline __m128 & operator -= (__m128 & v0, const __m128 &v1)\n\t{\n\t\tv0 = _mm_sub_ps(v0, v1);\n\t\treturn v0;\n\t}\n\tinline __m128 & operator *= (__m128 & v0, const __m128 &v1)\n\t{\n\t\tv0 = _mm_mul_ps(v0, v1);\n\t\treturn v0;\n\t}\n\tinline __m128 & operator /= (__m128 & v0, const __m128 &v1)\n\t{\n\t\tv0 = _mm_div_ps(v0, v1);\n\t\treturn v0;\n\t}\n\tinline __m128 operator + (const __m128 & v0, const __m128 & v1)\n\t{\n\t\treturn _mm_add_ps(v0, v1);\n\t}\n\tinline __m128 operator - (const __m128 & v0, const __m128 & v1)\n\t{\n\t\treturn _mm_sub_ps(v0, v1);\n\t}\n\tinline __m128 operator * (const __m128 & v0, const __m128 & v1)\n\t{\n\t\treturn _mm_mul_ps(v0, v1);\n\t}\n\tinline __m128 operator / (const __m128 & v0, const __m128 & v1)\n\t{\n\t\treturn _mm_div_ps(v0, v1);\n\t}\n\tinline __m128 operator - (const __m128 & v0)\n\t{\n\t\tstatic const __m128 SIGNMASK =\n\t\t\t_mm_castsi128_ps(_mm_set1_epi32(0x80000000));\n\t\treturn _mm_xor_ps(v0, SIGNMASK);\n\t}\n\n\tinline __m128i & operator += (__m128i & v0, const __m128i &v1)\n\t{\n\t\tv0 = _mm_add_epi32(v0, v1);\n\t\treturn v0;\n\t}\n\tinline __m128i & operator -= (__m128i & v0, const __m128i &v1)\n\t{\n\t\tv0 = _mm_sub_epi32(v0, v1);\n\t\treturn v0;\n\t}\n\tinline __m128i & operator *= (__m128i & v0, const __m128i &v1)\n\t{\n\t\tv0 = _mm_mul_epi32(v0, v1);\n\t\treturn v0;\n\t}\n\tinline __m128i operator + (const __m128i & v0, const __m128i & v1)\n\t{\n\t\treturn _mm_add_epi32(v0, v1);\n\t}\n\tinline __m128i operator - (const __m128i & v0, const __m128i & v1)\n\t{\n\t\treturn _mm_sub_epi32(v0, v1);\n\t}\n\tinline __m128i operator * (const __m128i & v0, const __m128i & v1)\n\t{\n\t\treturn _mm_mullo_epi32(v0, v1);\n\t}\n\tinline __m128i operator - (const __m128i & v0)\n\t{\n\t\treturn _mm_xor_si128(v0, _mm_set1_epi32(0xFFFFFFFF));\n\t}\n#endif\n#endif\n\t_declspec(align(16))\n\t\tclass SSEVec3\n\t{\n\tpublic:\n\t\t__m128 x, y, z;\n\t\tSSEVec3()\n\t\t{};\n\t\tSSEVec3(__m128 x, __m128 y, __m128 z)\n\t\t\t:x(x), y(y), z(z)\n\t\t{\n\t\t}\n\t\tSSEVec3(const Vec3 &v)\n\t\t{\n\t\t\tthis->x = _mm_set_ps1(v.x);\n\t\t\tthis->y = _mm_set_ps1(v.y);\n\t\t\tthis->z = _mm_set_ps1(v.z);\n\t\t}\n\t\tSSEVec3(float x, float y, float z)\n\t\t{\n\t\t\tthis->x = _mm_set_ps1(x);\n\t\t\tthis->y = _mm_set_ps1(y);\n\t\t\tthis->z = _mm_set_ps1(z);\n\t\t}\n\t\tinline __m128 Length()\n\t\t{\n\t\t\treturn _mm_sqrt_ps(x*x + y*y + z*z);\n\t\t}\n\t\tinline void Normalize(__m128 one)\n\t\t{\n\t\t\tauto s = one / Length();\n\t\t\tx *= s;\n\t\t\ty *= s;\n\t\t\tz *= s;\n\t\t}\n\t\tinline SSEVec3 operator + (const SSEVec3 &vin)\n\t\t{\n\t\t\tSSEVec3 rs;\n\t\t\trs.x = x + vin.x;\n\t\t\trs.y = y + vin.y;\n\t\t\trs.z = z + vin.z;\n\t\t\treturn rs;\n\t\t}\n\t\tinline SSEVec3 operator - (const SSEVec3 &vin)\n\t\t{\n\t\t\tSSEVec3 rs;\n\t\t\trs.x = x - vin.x;\n\t\t\trs.y = y - vin.y;\n\t\t\trs.z = z - vin.z;\n\t\t\treturn rs;\n\t\t}\n\t\tinline SSEVec3 operator - ()\n\t\t{\n\t\t\tSSEVec3 rs;\n\t\t\trs.x = -x;\n\t\t\trs.y = -y;\n\t\t\trs.z = -z;\n\t\t\treturn rs;\n\t\t}\n\t\tinline SSEVec3 operator * (__m128 scale)\n\t\t{\n\t\t\tSSEVec3 rs;\n\t\t\trs.x = x * scale;\n\t\t\trs.y = y * scale;\n\t\t\trs.z = z * scale;\n\t\t\treturn rs;\n\t\t}\n\t\tinline SSEVec3 & operator += (const SSEVec3 & vin)\n\t\t{\n\t\t\tx += vin.x; y += vin.y; z += vin.z;\n\t\t\treturn *this;\n\t\t}\n\t\tinline SSEVec3 & operator -= (const SSEVec3 & vin)\n\t\t{\n\t\t\tx -= vin.x; y -= vin.y; z -= vin.z;\n\t\t\treturn *this;\n\t\t}\n\t\tinline SSEVec3 & operator *= (const SSEVec3 & vin)\n\t\t{\n\t\t\tx *= vin.x; y *= vin.y; z *= vin.z;\n\t\t\treturn *this;\n\t\t}\n\t\tinline SSEVec3 & operator *= (__m128 s)\n\t\t{\n\t\t\tx *= s; y *= s; z *= s;\n\t\t\treturn *this;\n\t\t}\n\t\tinline SSEVec3 & operator /= (const SSEVec3 & vin)\n\t\t{\n\t\t\tx /= vin.x; y /= vin.y; z /= vin.z;\n\t\t\treturn *this;\n\t\t}\n\t\tinline SSEVec3 & operator /= (float s)\n\t\t{\n\t\t\tfloat inv = 1.0f / s;\n\t\t\treturn (*this) *= _mm_set_ps1(inv);\n\t\t}\n\n\t\tinline static __m128 Dot(const SSEVec3 & v1, const SSEVec3 & v2)\n\t\t{\n\t\t\treturn v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;\n\t\t}\n\t\tinline static void Cross(SSEVec3 & rs_d, const SSEVec3 & v1, const SSEVec3 & v2)\n\t\t{\n\t\t\trs_d.x = v1.y*v2.z - v1.z * v2.y;\n\t\t\trs_d.y = v1.z*v2.x - v1.x * v2.z;\n\t\t\trs_d.z = v1.x*v2.y - v1.y * v2.x;\n\t\t}\n\t};\n\n\t_declspec(align(16))\n\t\tclass SSEVec4\n\t{\n\tpublic:\n\t\t__m128 x, y, z, w;\n\t\tSSEVec4()\n\t\t{};\n\t\tSSEVec4(const __m128 & x, const __m128 & y, const __m128 & z, const __m128 & w)\n\t\t\t:x(x), y(y), z(z), w(w)\n\t\t{\n\t\t}\n\t\tSSEVec4(const Vec4 &v)\n\t\t{\n\t\t\tthis->x = _mm_set_ps1(v.x);\n\t\t\tthis->y = _mm_set_ps1(v.y);\n\t\t\tthis->z = _mm_set_ps1(v.z);\n\t\t\tthis->w = _mm_set_ps1(v.w);\n\t\t}\n\t\tSSEVec4(float x, float y, float z, float w)\n\t\t{\n\t\t\tthis->x = _mm_set_ps1(x);\n\t\t\tthis->y = _mm_set_ps1(y);\n\t\t\tthis->z = _mm_set_ps1(z);\n\t\t\tthis->w = _mm_set_ps1(w);\n\t\t}\n\t\tinline __m128 Length()\n\t\t{\n\t\t\treturn _mm_sqrt_ps(x*x + y*y + z*z + w*w);\n\t\t}\n\t\tinline void Normalize(__m128 one)\n\t\t{\n\t\t\tauto s = one / Length();\n\t\t\tx *= s;\n\t\t\ty *= s;\n\t\t\tz *= s;\n\t\t\tw *= s;\n\t\t}\n\t\tinline SSEVec4 operator + (const SSEVec4 &vin)\n\t\t{\n\t\t\tSSEVec4 rs;\n\t\t\trs.x = x + vin.x;\n\t\t\trs.y = y + vin.y;\n\t\t\trs.z = z + vin.z;\n\t\t\trs.w = w + vin.w;\n\t\t\treturn rs;\n\t\t}\n\t\tinline SSEVec4 operator - (const SSEVec4 &vin)\n\t\t{\n\t\t\tSSEVec4 rs;\n\t\t\trs.x = x - vin.x;\n\t\t\trs.y = y - vin.y;\n\t\t\trs.z = z - vin.z;\n\t\t\trs.w = w - vin.w;\n\t\t\treturn rs;\n\t\t}\n\t\tinline SSEVec4 operator - ()\n\t\t{\n\t\t\tSSEVec4 rs;\n\t\t\trs.x = -x;\n\t\t\trs.y = -y;\n\t\t\trs.z = -z;\n\t\t\trs.w = -w;\n\t\t\treturn rs;\n\t\t}\n\t\tinline SSEVec4 operator * (__m128 scale)\n\t\t{\n\t\t\tSSEVec4 rs;\n\t\t\trs.x = x * scale;\n\t\t\trs.y = y * scale;\n\t\t\trs.z = z * scale;\n\t\t\trs.w = w * scale;\n\t\t\treturn rs;\n\t\t}\n\t\tinline SSEVec4 & operator += (const SSEVec4 & vin)\n\t\t{\n\t\t\tx += vin.x; y += vin.y; z += vin.z; w += vin.w;\n\t\t\treturn *this;\n\t\t}\n\t\tinline SSEVec4 & operator -= (const SSEVec4 & vin)\n\t\t{\n\t\t\tx -= vin.x; y -= vin.y; z -= vin.z; w -= vin.w;\n\t\t\treturn *this;\n\t\t}\n\t\tinline SSEVec4 & operator *= (const SSEVec4 & vin)\n\t\t{\n\t\t\tx *= vin.x; y *= vin.y; z *= vin.z; w *= vin.w;\n\t\t\treturn *this;\n\t\t}\n\t\tinline SSEVec4 & operator *= (__m128 s)\n\t\t{\n\t\t\tx *= s; y *= s; z *= s; w *= s;\n\t\t\treturn *this;\n\t\t}\n\t\tinline SSEVec4 & operator /= (const SSEVec4 & vin)\n\t\t{\n\t\t\tx /= vin.x; y /= vin.y; z /= vin.z; w /= vin.w;\n\t\t\treturn *this;\n\t\t}\n\t\tinline SSEVec4 & operator /= (float s)\n\t\t{\n\t\t\tfloat inv = 1.0f / s;\n\t\t\treturn (*this) *= _mm_set_ps1(inv);\n\t\t}\n\n\t\tinline static __m128 Dot(const SSEVec4 & v1, const SSEVec4 & v2)\n\t\t{\n\t\t\treturn v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w;\n\t\t}\n\t};\n\n\t_declspec(align(16))\n\t\tclass SSEMatrix4\n\t{\n\tpublic:\n\t\t__m128 values[16];\n\t\tSSEMatrix4()\n\t\t{}\n\t\tSSEMatrix4(const Matrix4 & mat)\n\t\t{\n\t\t\tfor (int i = 0; i<16; i++)\n\t\t\t\tvalues[i] = _mm_set_ps1(mat.values[i]);\n\t\t}\n\t\tinline SSEVec3 Transform(SSEVec3 & v)\n\t\t{\n\t\t\tSSEVec3 rs;\n\t\t\trs.x = values[0] * v.x + values[4] * v.y + values[8] * v.z + values[12];\n\t\t\trs.y = values[1] * v.x + values[5] * v.y + values[9] * v.z + values[13];\n\t\t\trs.z = values[2] * v.x + values[6] * v.y + values[10] * v.z + values[14];\n\t\t\tauto w = values[3] * v.x + values[7] * v.y + values[11] * v.z + values[15];\n\t\t\tw = _mm_set_ps1(1.0f) / w;\n\t\t\trs.x *= w;\n\t\t\trs.y *= w;\n\t\t\trs.z *= w;\n\t\t\treturn rs;\n\t\t}\n\t\tinline SSEVec3 TransformNonPerspective(SSEVec3 & v)\n\t\t{\n\t\t\tSSEVec3 rs;\n\t\t\trs.x = values[0] * v.x + values[4] * v.y + values[8] * v.z + values[12];\n\t\t\trs.y = values[1] * v.x + values[5] * v.y + values[9] * v.z + values[13];\n\t\t\trs.z = values[2] * v.x + values[6] * v.y + values[10] * v.z + values[14];\n\t\t\treturn rs;\n\t\t}\n\t};\n#endif\n\n\tclass Vec2i\n\t{\n\tpublic:\n\t\tint x, y;\n\t\tstatic Vec2i Create(int px, int py)\n\t\t{\n\t\t\tVec2i rs;\n\t\t\trs.x = px;\n\t\t\trs.y = py;\n\t\t\treturn rs;\n\t\t}\n\t};\n\n\tclass Vec3i\n\t{\n\tpublic:\n\t\tint x, y, z;\n\t\tstatic Vec3i Create(int px, int py, int pz)\n\t\t{\n\t\t\tVec3i rs;\n\t\t\trs.x = px;\n\t\t\trs.y = py;\n\t\t\trs.z = pz;\n\t\t\treturn rs;\n\t\t}\n\t};\n\n\tclass Vec4i\n\t{\n\tpublic:\n\t\tint x, y, z, w;\n\t\tstatic Vec4i Create(int px, int py, int pz, int pw)\n\t\t{\n\t\t\tVec4i rs;\n\t\t\trs.x = px;\n\t\t\trs.y = py;\n\t\t\trs.z = pz;\n\t\t\trs.w = pw;\n\t\t\treturn rs;\n\t\t}\n\t};\n\n\tclass Quaternion\n\t{\n\tpublic:\n\t\tfloat x, y, z, w;\n\t\tQuaternion() = default;\n\t\tQuaternion(float px, float py, float pz, float pw)\n\t\t{\n\t\t\tx = px; y = py; z = pz; w = pw;\n\t\t}\n\t\tQuaternion(const Vec4& v)\n\t\t{\n\t\t\tx = v.x; y = v.y; z = v.z; w = v.w;\n\t\t}\n\t\tVec4 ToVec4() const\n\t\t{\n\t\t\treturn Vec4::Create(x, y, z, w);\n\t\t}\n\t\tQuaternion operator * (const Quaternion & q) const\n\t\t{\n\t\t\tQuaternion rs;\n\t\t\trs.x = w*q.x + x*q.w + y*q.z - z*q.y;\n\t\t\trs.y = w*q.y + y*q.w + z*q.x - x*q.z;\n\t\t\trs.z = w*q.z + z*q.w + x*q.y - y*q.x;\n\t\t\trs.w = w*q.w - x*q.x - y*q.y - z*q.z;\n\t\t\treturn rs;\n\t\t}\n\t\tQuaternion operator + (const Quaternion & q) const\n\t\t{\n\t\t\tQuaternion rs;\n\t\t\trs.x = x + q.x;\n\t\t\trs.y = y + q.y;\n\t\t\trs.z = z + q.z;\n\t\t\trs.w = w + q.w;\n\t\t\treturn rs;\n\t\t}\n\t\tQuaternion operator * (float s) const\n\t\t{\n\t\t\tQuaternion rs;\n\t\t\trs.x = x * s;\n\t\t\trs.y = y * s;\n\t\t\trs.z = z * s;\n\t\t\trs.w = w * s;\n\t\t\treturn rs;\n\t\t}\n\t\tQuaternion operator *= (float s)\n\t\t{\n\t\t\tx = x * s;\n\t\t\ty = y * s;\n\t\t\tz = z * s;\n\t\t\tw = w * s;\n\t\t\treturn *this;\n\t\t}\n\t\tQuaternion operator -() const\n\t\t{\n\t\t\treturn Quaternion(-x, -y, -z, -w);\n\t\t}\n\t\tQuaternion Conjugate() const\n\t\t{\n\t\t\treturn Quaternion(-x, -y, -z, w);\n\t\t}\n\t\tfloat Length() const\n\t\t{\n\t\t\treturn sqrt(x*x + y*y + z*z + w*w);\n\t\t}\n\t\tfloat LengthSquared() const\n\t\t{\n\t\t\treturn x*x + y*y + z*z + w*w;\n\t\t}\n\t\tQuaternion Inverse() const\n\t\t{\n\t\t\tauto rs = Conjugate();\n\t\t\trs *= (1.0f / LengthSquared());\n\t\t\treturn rs;\n\t\t}\n\t\tVec3 Transform(const Vec3 &v) const\n\t\t{\n\t\t\tQuaternion V(v.x, v.y, v.z, 0.0f);\n\t\t\tauto rs = *this * V * Conjugate();\n\t\t\treturn Vec3::Create(rs.x, rs.y, rs.z);\n\t\t}\n\t\tVec4 ToAxisAngle() const\n\t\t{\n\t\t\tfloat theta = acos(w);\n\t\t\tfloat invSinTheta = 1.0f / sin(theta);\n\n\t\t\tVec4 rs;\n\t\t\trs.x = x * invSinTheta;\n\t\t\trs.y = y * invSinTheta;\n\t\t\trs.z = z * invSinTheta;\n\t\t\trs.w = theta * 2.0f;\n\t\t\treturn rs;\n\t\t}\n\t\tMatrix3 ToMatrix3() const\n\t\t{\n\t\t\tMatrix3 rs;\n\t\t\trs.values[0] = 1.0f - 2.0f * (y*y + z*z);\n\t\t\trs.values[1] = 2.0f * (x*y + w*z);\n\t\t\trs.values[2] = 2.0f * (x*z - w*y);\n\n\t\t\trs.values[3] = 2.0f * (x*y - w*z);\n\t\t\trs.values[4] = 1.0f - 2.0f * (x*x + z*z);\n\t\t\trs.values[5] = 2.0f * (y*z + w*x);\n\n\t\t\trs.values[6] = 2.0f * (x*z + w*y);\n\t\t\trs.values[7] = 2.0f * (y*z - w*x);\n\t\t\trs.values[8] = 1.0f - 2.0f * (x*x + y*y);\n\t\t\treturn rs;\n\t\t}\n\t\tMatrix4 ToMatrix4() const\n\t\t{\n\t\t\tMatrix4 rs;\n\t\t\trs.values[0] = 1.0f - 2.0f * (y*y + z*z);\n\t\t\trs.values[1] = 2.0f * (x*y + w*z);\n\t\t\trs.values[2] = 2.0f * (x*z - w*y);\n\t\t\trs.values[3] = 0.0f;\n\n\t\t\trs.values[4] = 2.0f * (x*y - w*z);\n\t\t\trs.values[5] = 1.0f - 2.0f * (x*x + z*z);\n\t\t\trs.values[6] = 2.0f * (y*z + w*x);\n\t\t\trs.values[7] = 0.0f;\n\n\t\t\trs.values[8] = 2.0f * (x*z + w*y);\n\t\t\trs.values[9] = 2.0f * (y*z - w*x);\n\t\t\trs.values[10] = 1.0f - 2.0f * (x*x + y*y);\n\t\t\trs.values[11] = 0.0f;\n\n\t\t\trs.values[12] = 0.0f;\n\t\t\trs.values[13] = 0.0f;\n\t\t\trs.values[14] = 0.0f;\n\t\t\trs.values[15] = 1.0f;\n\n\t\t\treturn rs;\n\t\t}\n\t\tstatic inline Quaternion FromMatrix(const Matrix3 & a)\n\t\t{\n\t\t\tQuaternion q;\n\t\t\tfloat trace = a.m[0][0] + a.m[1][1] + a.m[2][2]; // I removed + 1.0f; see discussion with Ethan\n\t\t\tif (trace > 0)\n\t\t\t{\n\t\t\t\tfloat s = 0.5f / sqrtf(trace + 1.0f);\n\t\t\t\tq.w = 0.25f / s;\n\t\t\t\tq.x = (a.m[1][2] - a.m[2][1]) * s;\n\t\t\t\tq.y = (a.m[2][0] - a.m[0][2]) * s;\n\t\t\t\tq.z = (a.m[0][1] - a.m[1][0]) * s;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (a.m[0][0] > a.m[1][1] && a.m[0][0] > a.m[2][2])\n\t\t\t\t{\n\t\t\t\t\tfloat s = 2.0f * sqrtf(1.0f + a.m[0][0] - a.m[1][1] - a.m[2][2]);\n\t\t\t\t\tq.w = (a.m[1][2] - a.m[2][1]) / s;\n\t\t\t\t\tq.x = 0.25f * s;\n\t\t\t\t\tq.y = (a.m[0][1] + a.m[1][0]) / s;\n\t\t\t\t\tq.z = (a.m[0][2] + a.m[2][0]) / s;\n\t\t\t\t}\n\t\t\t\telse if (a.m[1][1] > a.m[2][2])\n\t\t\t\t{\n\t\t\t\t\tfloat s = 2.0f * sqrtf(1.0f + a.m[1][1] - a.m[0][0] - a.m[2][2]);\n\t\t\t\t\tq.w = (a.m[2][0] - a.m[0][2]) / s;\n\t\t\t\t\tq.x = (a.m[0][1] + a.m[1][0]) / s;\n\t\t\t\t\tq.y = 0.25f * s;\n\t\t\t\t\tq.z = (a.m[1][2] + a.m[2][1]) / s;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfloat s = 2.0f * sqrtf(1.0f + a.m[2][2] - a.m[0][0] - a.m[1][1]);\n\t\t\t\t\tq.w = (a.m[0][1] - a.m[1][0]) / s;\n\t\t\t\t\tq.x = (a.m[0][2] + a.m[2][0]) / s;\n\t\t\t\t\tq.y = (a.m[1][2] + a.m[2][1]) / s;\n\t\t\t\t\tq.z = 0.25f * s;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn q * (1.0f / q.Length());\n\t\t}\n\t\t// equivalent to mat(colX, colY, colZ)\n\t\tstatic inline Quaternion FromCoordinates(const Vec3 & axisX, const Vec3 & axisY, const Vec3 & axisZ)\n\t\t{\n\t\t\tMatrix3 a;\n\t\t\ta.values[0] = axisX.x; a.values[1] = axisX.y; a.values[2] = axisX.z;\n\t\t\ta.values[3] = axisY.x; a.values[4] = axisY.y; a.values[5] = axisY.z;\n\t\t\ta.values[6] = axisZ.x; a.values[7] = axisZ.y; a.values[8] = axisZ.z;\n\n\t\t\treturn FromMatrix(a);\n\t\t}\n\t\tstatic inline Quaternion FromAxisAngle(const Vec3 & axis, float angle)\n\t\t{\n\t\t\tfloat cosAng = cos(angle * 0.5f);\n\t\t\tfloat sinAng = sin(angle * 0.5f);\n\t\t\treturn Quaternion(axis.x *  sinAng, axis.y * sinAng, axis.z * sinAng, cosAng);\n\t\t}\n\t\tstatic inline float Dot(const Quaternion & q1, const Quaternion & q2)\n\t\t{\n\t\t\treturn q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;\n\t\t}\n\t\tstatic inline Quaternion Lerp(const Quaternion & q1, const Quaternion & q2, float t)\n\t\t{\n\t\t\tfloat invT = 1.0f - t;\n\t\t\treturn Quaternion(q1.x * invT + q2.x * t,\n\t\t\t\tq1.y * invT + q2.y * t,\n\t\t\t\tq1.z * invT + q2.z * t,\n\t\t\t\tq1.w * invT + q2.w * t);\n\t\t}\n\t\tstatic inline Quaternion Slerp(const Quaternion & q1, const Quaternion & q2, float t)\n\t\t{\n\t\t\tQuaternion q3;\n\t\t\tfloat dot = Quaternion::Dot(q1, q2);\n\t\t\tif (dot < 0)\n\t\t\t{\n\t\t\t\tdot = -dot;\n\t\t\t\tq3 = -q2;\n\t\t\t}\n\t\t\telse\n\t\t\t\tq3 = q2;\n\t\t\tif (dot < 0.95f)\n\t\t\t{\n\t\t\t\tfloat angle = acos(dot);\n\t\t\t\treturn (q1*sin(angle*(1 - t)) + q3*sin(angle*t)) * (1.0f / sin(angle));\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn Lerp(q1, q3, t);\n\t\t}\n\n        static inline void SetYawAngle(Quaternion & q, float yaw)\n        {\n            Matrix4 roty;\n            Matrix4::RotationY(roty, yaw);\n            Matrix4 original = q.ToMatrix4();\n            Matrix4::Multiply(original, roty, original);\n            q = Quaternion::FromMatrix(original.GetMatrix3());\n        }\n\t};\n}\n\n#endif\n"
  },
  {
    "path": "Source/CoreLib/corelib.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n\n<Type Name=\"CoreLib::Basic::String\">\n    <DisplayString>{buffer.pointer,s}</DisplayString>\n\t<StringView>buffer.pointer,s</StringView>\n</Type>\n\n<Type Name=\"CoreLib::Basic::ArrayView&lt;*&gt;\">\n  <DisplayString>{{ size={_count} }}</DisplayString>\n  <Expand>\n    <Item Name=\"[size]\">_count</Item>\n    <ArrayItems>\n      <Size>_count</Size>\n      <ValuePointer>_buffer</ValuePointer>\n    </ArrayItems>\n  </Expand>\n</Type>\n\n<Type Name=\"CoreLib::Basic::List&lt;*&gt;\">\n    <DisplayString>{{ size={_count} }}</DisplayString>\n    <Expand>\n        <Item Name=\"[size]\">_count</Item>\n        <Item Name=\"[capacity]\">bufferSize</Item>\n        <ArrayItems>\n            <Size>_count</Size>\n            <ValuePointer>buffer</ValuePointer>\n        </ArrayItems>\n    </Expand>\n</Type>\n\n\n<Type Name=\"CoreLib::Basic::Array&lt;*,*&gt;\">\n  <DisplayString>{{ size={_count} }}</DisplayString>\n  <Expand>\n    <Item Name=\"[size]\">_count</Item>\n    <ArrayItems>\n      <Size>_count</Size>\n      <ValuePointer>_buffer</ValuePointer>\n    </ArrayItems>\n  </Expand>\n</Type>\n  \n<Type Name=\"CoreLib::Basic::LinkedList&lt;*&gt;\">\n    <DisplayString>{{ size={FCount} }}</DisplayString>\n    <Expand>\n        <LinkedListItems>\n            <Size>FCount</Size>\n            <HeadPointer>FHead</HeadPointer>\n            <NextPointer>pNext</NextPointer>\n            <ValueNode>Value</ValueNode>\n        </LinkedListItems>\n    </Expand>\n</Type>\n\n<Type Name=\"CoreLib::Basic::Dictionary&lt;*,*&gt;\">\n    <DisplayString>{{ size={_count} }}</DisplayString>\n    <Expand>\n        <Item Name=\"[size]\">_count</Item>\n        <Item Name=\"[capacity]\">bucketSizeMinusOne + 1</Item>\n        <ArrayItems>\n           <Size>bucketSizeMinusOne + 1</Size>\n           <ValuePointer>hashMap</ValuePointer>\n        </ArrayItems>\n    </Expand>\n</Type>\n\n<Type Name=\"CoreLib::Basic::EnumerableDictionary&lt;*,*&gt;\">\n    <DisplayString>{{ size={_count} }}</DisplayString>\n    <Expand>\n        <Item Name=\"[size]\">_count</Item>\n        <Item Name=\"[capacity]\">bucketSizeMinusOne + 1</Item>\n        <LinkedListItems>\n            <Size>kvPairs.FCount</Size>\n            <HeadPointer>kvPairs.FHead</HeadPointer>\n            <NextPointer>pNext</NextPointer>\n            <ValueNode>Value</ValueNode>\n        </LinkedListItems>\n    </Expand>\n</Type>\n\n<Type Name=\"CoreLib::Basic::EnumerableHashSet&lt;*,*&gt;\">\n    <DisplayString>{{ size={dict._count} }}</DisplayString>\n    <Expand>\n        <Item Name=\"[size]\">dict._count</Item>\n        <Item Name=\"[capacity]\">dict.bucketSizeMinusOne + 1</Item>\n        <LinkedListItems>\n            <Size>dict.kvPairs.FCount</Size>\n            <HeadPointer>dict.kvPairs.FHead</HeadPointer>\n            <NextPointer>pNext</NextPointer>\n            <ValueNode>Value</ValueNode>\n        </LinkedListItems>\n    </Expand>\n</Type>\n\n<Type Name=\"CoreLib::Basic::RefPtrImpl&lt;*,*,*&gt;\">\n    <SmartPointer Usage=\"Minimal\">pointer</SmartPointer>\n    <DisplayString Condition=\"pointer == 0\">empty</DisplayString>\n    <DisplayString Condition=\"pointer != 0\">RefPtr {*pointer}</DisplayString>\n    <Expand>\n      <ExpandedItem>pointer</ExpandedItem>\n    </Expand>\n</Type>\n</AutoVisualizer>\n"
  },
  {
    "path": "Source/Spire.sln",
    "content": "Microsoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 14\nVisualStudioVersion = 14.0.25123.0\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"SpireLib\", \"SpireLib\\SpireLib.vcxproj\", \"{1168C449-66A5-4D23-80E2-2C1A07E58F83}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"SpireCore\", \"SpireCore\\SpireCore.vcxproj\", \"{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"SpireCompiler\", \"SpireCompiler\\SpireCompiler.vcxproj\", \"{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Spire\", \"Spire\", \"{362538E0-CA8A-4F9A-AC99-15CC9A715A43}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"SharedLib\", \"SharedLib\", \"{F37C8C78-754B-4E58-AE7E-B31C8F1C7003}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"CoreLibBasic\", \"CoreLib\\CoreLibBasic.vcxproj\", \"{F9BE7957-8399-899E-0C49-E714FDDD4B65}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"SpireTestTool\", \"..\\Tests\\SpireTestTool\\SpireTestTool.vcxproj\", \"{0C768A18-1D25-4000-9F37-DA5FE99E3B64}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Examples\", \"Examples\", \"{B625E3E2-3B0B-4A01-9D10-957F84092E10}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"hello\", \"..\\Examples\\hello\\hello.vcxproj\", \"{E6385042-1649-4803-9EBD-168F8B7EF131}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug_VS2013|Any CPU = Debug_VS2013|Any CPU\n\t\tDebug_VS2013|ARM = Debug_VS2013|ARM\n\t\tDebug_VS2013|Win32 = Debug_VS2013|Win32\n\t\tDebug_VS2013|x64 = Debug_VS2013|x64\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|ARM = Debug|ARM\n\t\tDebug|Win32 = Debug|Win32\n\t\tDebug|x64 = Debug|x64\n\t\tDebugClang|Any CPU = DebugClang|Any CPU\n\t\tDebugClang|ARM = DebugClang|ARM\n\t\tDebugClang|Win32 = DebugClang|Win32\n\t\tDebugClang|x64 = DebugClang|x64\n\t\tRelease_VS2013|Any CPU = Release_VS2013|Any CPU\n\t\tRelease_VS2013|ARM = Release_VS2013|ARM\n\t\tRelease_VS2013|Win32 = Release_VS2013|Win32\n\t\tRelease_VS2013|x64 = Release_VS2013|x64\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|ARM = Release|ARM\n\t\tRelease|Win32 = Release|Win32\n\t\tRelease|x64 = Release|x64\n\t\tTracingDebug|Any CPU = TracingDebug|Any CPU\n\t\tTracingDebug|ARM = TracingDebug|ARM\n\t\tTracingDebug|Win32 = TracingDebug|Win32\n\t\tTracingDebug|x64 = TracingDebug|x64\n\t\tTracingRelease|Any CPU = TracingRelease|Any CPU\n\t\tTracingRelease|ARM = TracingRelease|ARM\n\t\tTracingRelease|Win32 = TracingRelease|Win32\n\t\tTracingRelease|x64 = TracingRelease|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Debug_VS2013|Any CPU.ActiveCfg = Debug_VS2013|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Debug_VS2013|ARM.ActiveCfg = Debug_VS2013|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Debug_VS2013|Win32.ActiveCfg = Debug_VS2013|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Debug_VS2013|Win32.Build.0 = Debug_VS2013|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Debug_VS2013|x64.ActiveCfg = Debug_VS2013|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Debug_VS2013|x64.Build.0 = Debug_VS2013|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Debug|Any CPU.ActiveCfg = Debug|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Debug|ARM.ActiveCfg = Debug|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Debug|x64.Build.0 = Debug|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.DebugClang|Any CPU.ActiveCfg = DebugClang|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.DebugClang|ARM.ActiveCfg = DebugClang|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.DebugClang|Win32.ActiveCfg = DebugClang|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.DebugClang|Win32.Build.0 = DebugClang|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.DebugClang|x64.ActiveCfg = DebugClang|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.DebugClang|x64.Build.0 = DebugClang|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Release_VS2013|Any CPU.ActiveCfg = Release_VS2013|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Release_VS2013|ARM.ActiveCfg = Release_VS2013|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Release_VS2013|Win32.ActiveCfg = Release_VS2013|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Release_VS2013|Win32.Build.0 = Release_VS2013|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Release_VS2013|x64.ActiveCfg = Release_VS2013|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Release_VS2013|x64.Build.0 = Release_VS2013|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Release|Any CPU.ActiveCfg = Release|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Release|ARM.ActiveCfg = Release|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Release|Win32.Build.0 = Release|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Release|x64.ActiveCfg = Release|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.Release|x64.Build.0 = Release|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingDebug|Any CPU.ActiveCfg = Release|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingDebug|Any CPU.Build.0 = Release|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingDebug|ARM.ActiveCfg = Release|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingDebug|ARM.Build.0 = Release|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingDebug|Win32.ActiveCfg = Debug|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingDebug|Win32.Build.0 = Debug|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingDebug|x64.ActiveCfg = Debug|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingDebug|x64.Build.0 = Debug|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingRelease|Any CPU.ActiveCfg = Release|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingRelease|Any CPU.Build.0 = Release|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingRelease|ARM.ActiveCfg = Release|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingRelease|ARM.Build.0 = Release|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingRelease|Win32.ActiveCfg = Release|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingRelease|Win32.Build.0 = Release|Win32\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingRelease|x64.ActiveCfg = Release|x64\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83}.TracingRelease|x64.Build.0 = Release|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Debug_VS2013|Any CPU.ActiveCfg = Debug_VS2013|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Debug_VS2013|ARM.ActiveCfg = Debug_VS2013|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Debug_VS2013|Win32.ActiveCfg = Debug_VS2013|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Debug_VS2013|Win32.Build.0 = Debug_VS2013|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Debug_VS2013|x64.ActiveCfg = Debug_VS2013|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Debug_VS2013|x64.Build.0 = Debug_VS2013|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Debug|Any CPU.ActiveCfg = Debug|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Debug|ARM.ActiveCfg = Debug|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Debug|x64.Build.0 = Debug|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.DebugClang|Any CPU.ActiveCfg = DebugClang|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.DebugClang|ARM.ActiveCfg = DebugClang|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.DebugClang|Win32.ActiveCfg = DebugClang|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.DebugClang|Win32.Build.0 = DebugClang|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.DebugClang|x64.ActiveCfg = DebugClang|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.DebugClang|x64.Build.0 = DebugClang|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Release_VS2013|Any CPU.ActiveCfg = Release_VS2013|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Release_VS2013|ARM.ActiveCfg = Release_VS2013|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Release_VS2013|Win32.ActiveCfg = Release_VS2013|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Release_VS2013|Win32.Build.0 = Release_VS2013|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Release_VS2013|x64.ActiveCfg = Release_VS2013|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Release_VS2013|x64.Build.0 = Release_VS2013|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Release|Any CPU.ActiveCfg = Release|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Release|ARM.ActiveCfg = Release|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Release|Win32.Build.0 = Release|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Release|x64.ActiveCfg = Release|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.Release|x64.Build.0 = Release|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingDebug|Any CPU.ActiveCfg = Release|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingDebug|Any CPU.Build.0 = Release|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingDebug|ARM.ActiveCfg = Release|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingDebug|ARM.Build.0 = Release|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingDebug|Win32.ActiveCfg = Debug|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingDebug|Win32.Build.0 = Debug|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingDebug|x64.ActiveCfg = Debug|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingDebug|x64.Build.0 = Debug|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingRelease|Any CPU.ActiveCfg = Release|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingRelease|Any CPU.Build.0 = Release|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingRelease|ARM.ActiveCfg = Release|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingRelease|ARM.Build.0 = Release|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingRelease|Win32.ActiveCfg = Release|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingRelease|Win32.Build.0 = Release|Win32\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingRelease|x64.ActiveCfg = Release|x64\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}.TracingRelease|x64.Build.0 = Release|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Debug_VS2013|Any CPU.ActiveCfg = Debug_VS2013|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Debug_VS2013|ARM.ActiveCfg = Debug_VS2013|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Debug_VS2013|Win32.ActiveCfg = Debug_VS2013|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Debug_VS2013|Win32.Build.0 = Debug_VS2013|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Debug_VS2013|x64.ActiveCfg = Debug_VS2013|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Debug_VS2013|x64.Build.0 = Debug_VS2013|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Debug|Any CPU.ActiveCfg = Debug|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Debug|ARM.ActiveCfg = Debug|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Debug|x64.Build.0 = Debug|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.DebugClang|Any CPU.ActiveCfg = DebugClang|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.DebugClang|ARM.ActiveCfg = DebugClang|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.DebugClang|Win32.ActiveCfg = DebugClang|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.DebugClang|Win32.Build.0 = DebugClang|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.DebugClang|x64.ActiveCfg = DebugClang|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.DebugClang|x64.Build.0 = DebugClang|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Release_VS2013|Any CPU.ActiveCfg = Release_VS2013|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Release_VS2013|ARM.ActiveCfg = Release_VS2013|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Release_VS2013|Win32.ActiveCfg = Release_VS2013|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Release_VS2013|Win32.Build.0 = Release_VS2013|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Release_VS2013|x64.ActiveCfg = Release_VS2013|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Release_VS2013|x64.Build.0 = Release_VS2013|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Release|Any CPU.ActiveCfg = Release|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Release|ARM.ActiveCfg = Release|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Release|Win32.Build.0 = Release|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Release|x64.ActiveCfg = Release|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.Release|x64.Build.0 = Release|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingDebug|Any CPU.ActiveCfg = Release|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingDebug|Any CPU.Build.0 = Release|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingDebug|ARM.ActiveCfg = Release|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingDebug|ARM.Build.0 = Release|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingDebug|Win32.ActiveCfg = Debug|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingDebug|Win32.Build.0 = Debug|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingDebug|x64.ActiveCfg = Debug|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingDebug|x64.Build.0 = Debug|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingRelease|Any CPU.ActiveCfg = Release|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingRelease|Any CPU.Build.0 = Release|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingRelease|ARM.ActiveCfg = Release|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingRelease|ARM.Build.0 = Release|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingRelease|Win32.ActiveCfg = Release|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingRelease|Win32.Build.0 = Release|Win32\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingRelease|x64.ActiveCfg = Release|x64\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}.TracingRelease|x64.Build.0 = Release|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug_VS2013|Any CPU.ActiveCfg = Debug_VS2013|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug_VS2013|ARM.ActiveCfg = Debug_VS2013|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug_VS2013|ARM.Build.0 = Debug_VS2013|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug_VS2013|Win32.ActiveCfg = Debug_VS2013|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug_VS2013|Win32.Build.0 = Debug_VS2013|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug_VS2013|x64.ActiveCfg = Debug_VS2013|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug_VS2013|x64.Build.0 = Debug_VS2013|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug|Any CPU.ActiveCfg = Debug|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug|ARM.ActiveCfg = Debug|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug|ARM.Build.0 = Debug|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Debug|x64.Build.0 = Debug|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.DebugClang|Any CPU.ActiveCfg = DebugClang|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.DebugClang|ARM.ActiveCfg = DebugClang|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.DebugClang|ARM.Build.0 = DebugClang|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.DebugClang|Win32.ActiveCfg = DebugClang|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.DebugClang|Win32.Build.0 = DebugClang|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.DebugClang|x64.ActiveCfg = DebugClang|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.DebugClang|x64.Build.0 = DebugClang|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release_VS2013|Any CPU.ActiveCfg = Release_VS2013|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release_VS2013|ARM.ActiveCfg = Release_VS2013|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release_VS2013|ARM.Build.0 = Release_VS2013|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release_VS2013|Win32.ActiveCfg = Release_VS2013|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release_VS2013|Win32.Build.0 = Release_VS2013|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release_VS2013|x64.ActiveCfg = Release_VS2013|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release_VS2013|x64.Build.0 = Release_VS2013|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release|Any CPU.ActiveCfg = Release|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release|ARM.ActiveCfg = Release|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release|ARM.Build.0 = Release|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release|Win32.Build.0 = Release|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release|x64.ActiveCfg = Release|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release|x64.Build.0 = Release|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingDebug|Any CPU.ActiveCfg = TracingDebug|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingDebug|ARM.ActiveCfg = TracingDebug|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingDebug|ARM.Build.0 = TracingDebug|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingDebug|Win32.ActiveCfg = TracingDebug|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingDebug|Win32.Build.0 = TracingDebug|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingDebug|x64.ActiveCfg = TracingDebug|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingDebug|x64.Build.0 = TracingDebug|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingRelease|Any CPU.ActiveCfg = TracingRelease|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingRelease|ARM.ActiveCfg = TracingRelease|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingRelease|ARM.Build.0 = TracingRelease|ARM\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingRelease|Win32.ActiveCfg = TracingRelease|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingRelease|Win32.Build.0 = TracingRelease|Win32\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingRelease|x64.ActiveCfg = TracingRelease|x64\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65}.TracingRelease|x64.Build.0 = TracingRelease|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug_VS2013|Any CPU.ActiveCfg = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug_VS2013|Any CPU.Build.0 = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug_VS2013|ARM.ActiveCfg = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug_VS2013|ARM.Build.0 = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug_VS2013|Win32.ActiveCfg = Debug|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug_VS2013|Win32.Build.0 = Debug|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug_VS2013|x64.ActiveCfg = Debug_VS2013|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug_VS2013|x64.Build.0 = Debug_VS2013|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug|Any CPU.ActiveCfg = Debug|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug|ARM.ActiveCfg = Debug|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Debug|x64.Build.0 = Debug|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.DebugClang|Any CPU.ActiveCfg = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.DebugClang|Any CPU.Build.0 = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.DebugClang|ARM.ActiveCfg = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.DebugClang|ARM.Build.0 = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.DebugClang|Win32.ActiveCfg = Debug|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.DebugClang|Win32.Build.0 = Debug|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.DebugClang|x64.ActiveCfg = Debug|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.DebugClang|x64.Build.0 = Debug|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release_VS2013|Any CPU.ActiveCfg = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release_VS2013|Any CPU.Build.0 = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release_VS2013|ARM.ActiveCfg = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release_VS2013|ARM.Build.0 = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release_VS2013|Win32.ActiveCfg = Release|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release_VS2013|Win32.Build.0 = Release|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release_VS2013|x64.ActiveCfg = Release_VS2013|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release_VS2013|x64.Build.0 = Release_VS2013|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release|Any CPU.ActiveCfg = Release|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release|ARM.ActiveCfg = Release|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release|Win32.Build.0 = Release|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release|x64.ActiveCfg = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.Release|x64.Build.0 = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingDebug|Any CPU.ActiveCfg = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingDebug|Any CPU.Build.0 = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingDebug|ARM.ActiveCfg = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingDebug|ARM.Build.0 = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingDebug|Win32.ActiveCfg = Debug|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingDebug|Win32.Build.0 = Debug|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingDebug|x64.ActiveCfg = Debug|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingDebug|x64.Build.0 = Debug|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingRelease|Any CPU.ActiveCfg = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingRelease|Any CPU.Build.0 = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingRelease|ARM.ActiveCfg = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingRelease|ARM.Build.0 = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingRelease|Win32.ActiveCfg = Release|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingRelease|Win32.Build.0 = Release|Win32\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingRelease|x64.ActiveCfg = Release|x64\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64}.TracingRelease|x64.Build.0 = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug_VS2013|Any CPU.ActiveCfg = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug_VS2013|Any CPU.Build.0 = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug_VS2013|ARM.ActiveCfg = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug_VS2013|ARM.Build.0 = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug_VS2013|Win32.ActiveCfg = Debug|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug_VS2013|Win32.Build.0 = Debug|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug_VS2013|x64.ActiveCfg = Debug_VS2013|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug_VS2013|x64.Build.0 = Debug_VS2013|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|Any CPU.ActiveCfg = Debug|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|ARM.ActiveCfg = Debug|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|x64.Build.0 = Debug|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.DebugClang|Any CPU.ActiveCfg = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.DebugClang|Any CPU.Build.0 = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.DebugClang|ARM.ActiveCfg = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.DebugClang|ARM.Build.0 = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.DebugClang|Win32.ActiveCfg = Debug|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.DebugClang|Win32.Build.0 = Debug|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.DebugClang|x64.ActiveCfg = Debug|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.DebugClang|x64.Build.0 = Debug|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release_VS2013|Any CPU.ActiveCfg = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release_VS2013|Any CPU.Build.0 = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release_VS2013|ARM.ActiveCfg = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release_VS2013|ARM.Build.0 = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release_VS2013|Win32.ActiveCfg = Release|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release_VS2013|Win32.Build.0 = Release|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release_VS2013|x64.ActiveCfg = Release_VS2013|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release_VS2013|x64.Build.0 = Release_VS2013|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release|Any CPU.ActiveCfg = Release|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release|ARM.ActiveCfg = Release|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release|Win32.Build.0 = Release|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release|x64.ActiveCfg = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.Release|x64.Build.0 = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingDebug|Any CPU.ActiveCfg = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingDebug|Any CPU.Build.0 = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingDebug|ARM.ActiveCfg = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingDebug|ARM.Build.0 = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingDebug|Win32.ActiveCfg = Debug|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingDebug|Win32.Build.0 = Debug|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingDebug|x64.ActiveCfg = Debug|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingDebug|x64.Build.0 = Debug|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingRelease|Any CPU.ActiveCfg = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingRelease|Any CPU.Build.0 = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingRelease|ARM.ActiveCfg = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingRelease|ARM.Build.0 = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingRelease|Win32.ActiveCfg = Release|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingRelease|Win32.Build.0 = Release|Win32\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingRelease|x64.ActiveCfg = Release|x64\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131}.TracingRelease|x64.Build.0 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{1168C449-66A5-4D23-80E2-2C1A07E58F83} = {362538E0-CA8A-4F9A-AC99-15CC9A715A43}\n\t\t{DB00DA62-0533-4AFD-B59F-A67D5B3A0808} = {362538E0-CA8A-4F9A-AC99-15CC9A715A43}\n\t\t{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7} = {362538E0-CA8A-4F9A-AC99-15CC9A715A43}\n\t\t{F9BE7957-8399-899E-0C49-E714FDDD4B65} = {F37C8C78-754B-4E58-AE7E-B31C8F1C7003}\n\t\t{0C768A18-1D25-4000-9F37-DA5FE99E3B64} = {362538E0-CA8A-4F9A-AC99-15CC9A715A43}\n\t\t{E6385042-1649-4803-9EBD-168F8B7EF131} = {B625E3E2-3B0B-4A01-9D10-957F84092E10}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "Source/SpireCompiler/D3DCompiler.cpp",
    "content": "﻿#include \"D3DCompiler.h\"\n#ifdef _WIN32\n\n#include <d3dcompiler.h>\n\nusing namespace CoreLib::Basic;\n\ntypedef HRESULT (WINAPI *D3DCompile2Func)(\n\tLPCVOID pSrcData,\n\tSIZE_T SrcDataSize,\n\tLPCSTR pSourceName,\n\tD3D_SHADER_MACRO * pDefines,\n\tID3DInclude * pInclude,\n\tLPCSTR pEntrypoint,\n\tLPCSTR pTarget,\n\tUINT Flags1,\n\tUINT Flags2,\n\tUINT SecondaryDataFlags,\n\tLPCVOID pSecondaryData,\n\tSIZE_T SecondaryDataSize,\n\tID3DBlob **ppCode,\n\tID3DBlob **ppErrorMsgs\n);\ntypedef HRESULT (WINAPI *D3DCreateBlobFunc)(\n\tSIZE_T Size,\n\tID3DBlob **ppBlob\n);\n\n\nclass D3DCompilerImpl : public D3DCompiler\n{\npublic:\n\tD3DCompile2Func D3DCompile2;\n\tD3DCreateBlobFunc D3DCreateBlob;\n\tHMODULE Lib;\n\tvirtual bool Compile(CoreLib::String input, CoreLib::String stageName, CoreLib::String & errMsg) override\n\t{\n\t\tauto entryPoint = \"main\";\n\t\tchar * profile = \"ps_5_0\";\n\t\tif (stageName == \"vs\")\n\t\t\tprofile = \"vs_5_0\";\n\t\telse if (stageName == \"tes\")\n\t\t\tprofile = \"hs_5_0\";\n\t\telse if (stageName == \"tcs\")\n\t\t\tprofile = \"ds_5_0\";\n\t\tID3DBlob *code, *err = nullptr;\n\t\tD3DCompile2(input.Buffer(), input.Length(), \"\", nullptr, nullptr, entryPoint, profile, 0, 0, 0, 0, 0, &code, &err);\n\t\tif (err != nullptr)\n\t\t{\n\t\t\terrMsg = (char*)err->GetBufferPointer();\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n};\n\nD3DCompiler * LoadD3DCompiler()\n{\n\tauto d3dLib = LoadLibraryW(L\"D3DCompiler_47.dll\");\n\tif (d3dLib)\n\t{\n\t\tauto compileFunc = (D3DCompile2Func)GetProcAddress(d3dLib, \"D3DCompile2\");\n\t\tauto createBlobFunc = (D3DCreateBlobFunc)GetProcAddress(d3dLib, \"D3DCreateBlob\");\n\t\tif (compileFunc && createBlobFunc)\n\t\t{\n\t\t\tD3DCompilerImpl* result = new D3DCompilerImpl();\n\t\t\tresult->D3DCompile2 = compileFunc;\n\t\t\tresult->D3DCreateBlob = createBlobFunc;\n\t\t\tresult->Lib = d3dLib;\n\t\t\treturn result;\n\t\t}\n\t\telse\n\t\t\tFreeLibrary(d3dLib);\n\t}\n\treturn nullptr;\n}\n\n#else\n\nD3DCompiler * LoadD3DCompiler()\n{\n\treturn nullptr;\n}\n\n#endif\n"
  },
  {
    "path": "Source/SpireCompiler/D3DCompiler.h",
    "content": "#ifndef SPIRE_D3D_COMPILER_H\n#define SPIRE_D3D_COMPILER_H\n\n#include \"CoreLib/Basic.h\"\n\nclass D3DCompiler : public CoreLib::Object\n{\npublic:\n\tvirtual bool Compile(CoreLib::String input, CoreLib::String stageName, CoreLib::String & errMsg) = 0;\n};\n\nD3DCompiler * LoadD3DCompiler();\n\n#endif"
  },
  {
    "path": "Source/SpireCompiler/ShaderCompilerShell.cpp",
    "content": "﻿#include \"CoreLib/LibIO.h\"\n#include \"SpireLib.h\"\n#include \"D3DCompiler.h\"\n\nusing namespace CoreLib::Basic;\nusing namespace CoreLib::IO;\nusing namespace Spire::Compiler;\n\n// Try to read an argument for a command-line option.\nString tryReadCommandLineArgument(wchar_t const* option, wchar_t***ioCursor, wchar_t**end)\n{\n\twchar_t**& cursor = *ioCursor;\n\tif (cursor == end)\n\t{\n\t\tfprintf(stderr, \"expected an argument for command-line option '%S'\", option);\n\t\texit(1);\n\t}\n\telse\n\t{\n\t\treturn String::FromWString(*cursor++);\n\t}\n}\n\nint wmain(int argc, wchar_t* argv[])\n{\n\tint returnValue = -1;\n\t{\n\t\t// We need to parse any command-line arguments.\n\t\tString outputDir;\n\t\tCompileOptions options;\n\n\t\t// As we parse the command line, we will rewrite the\n\t\t// entries in `argv` to collect any \"ordinary\" arguments.\n\t\twchar_t const** inputPaths = (wchar_t const**)&argv[1];\n\t\twchar_t const** inputPathCursor = inputPaths;\n\n\t\twchar_t** argCursor = &argv[1];\n\t\twchar_t** argEnd = &argv[argc];\n\t\twhile (argCursor != argEnd)\n\t\t{\n\t\t\twchar_t const* arg = *argCursor++;\n\t\t\tif (arg[0] == '-')\n\t\t\t{\n\t\t\t\tString argStr = String::FromWString(arg);\n\n\t\t\t\t// The argument looks like an option, so try to parse it.\n\t\t\t\tif (argStr == \"-out\")\n\t\t\t\t\toutputDir = tryReadCommandLineArgument(arg, &argCursor, argEnd);\n\t\t\t\telse if (argStr == \"-symbo\")\n\t\t\t\t\toptions.SymbolToCompile = tryReadCommandLineArgument(arg, &argCursor, argEnd);\n\t\t\t\telse if (argStr == \"-schedule\")\n\t\t\t\t\toptions.ScheduleFileName = tryReadCommandLineArgument(arg, &argCursor, argEnd);\n\t\t\t\telse if (argStr == \"-backend\")\n\t\t\t\t{\n\t\t\t\t\tString name = tryReadCommandLineArgument(arg, &argCursor, argEnd);\n\t\t\t\t\tif (name == \"glsl\")\n\t\t\t\t\t{\n\t\t\t\t\t\toptions.Target = CodeGenTarget::GLSL;\n\t\t\t\t\t}\n\t\t\t\t\telse if (name == \"glsl_vk\")\n\t\t\t\t\t{\n\t\t\t\t\t\toptions.Target = CodeGenTarget::GLSL_Vulkan;\n\t\t\t\t\t}\n\t\t\t\t\telse if (name == \"glsl_vk_onedesc\")\n\t\t\t\t\t{\n\t\t\t\t\t\toptions.Target = CodeGenTarget::GLSL_Vulkan_OneDesc;\n\t\t\t\t\t}\n\t\t\t\t\telse if (name == \"hlsl\")\n\t\t\t\t\t{\n\t\t\t\t\t\toptions.Target = CodeGenTarget::HLSL;\n\t\t\t\t\t}\n\t\t\t\t\telse if (name == \"spriv\")\n\t\t\t\t\t{\n\t\t\t\t\t\toptions.Target = CodeGenTarget::SPIRV;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfprintf(stderr, \"unknown code generation target '%S'\\n\", name.ToWString());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (argStr == \"-genchoice\")\n\t\t\t\t\toptions.Mode = CompilerMode::GenerateChoice;\n\t\t\t\telse if (argStr == \"--\")\n\t\t\t\t{\n\t\t\t\t\t// The `--` option causes us to stop trying to parse options,\n\t\t\t\t\t// and treat the rest of the command line as input file names:\n\t\t\t\t\twhile (argCursor != argEnd)\n\t\t\t\t\t{\n\t\t\t\t\t\t*inputPathCursor++ = *argCursor++;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfprintf(stderr, \"unknown command-line option '%S'\\n\", argStr.ToWString());\n\t\t\t\t\t// TODO: print a usage message\n\t\t\t\t\texit(1);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t*inputPathCursor++ = arg;\n\t\t\t}\n\t\t}\n\n\t\tint inputPathCount = (int)(inputPathCursor - inputPaths);\n\t\tif (inputPathCount == 0)\n\t\t{\n\t\t\tfprintf(stderr, \"error: no input file specified\\n\");\n\t\t\texit(1);\n\t\t}\n\t\telse if (inputPathCount > 1)\n\t\t{\n\t\t\tfprintf(stderr, \"error: multiple input files specified\\n\");\n\t\t\texit(1);\n\t\t}\n\n\t\tString fileName = String::FromWString(inputPaths[0]);\n\n\t\t// Output directory defaults to the path of the input file\n\t\tif (outputDir.Length() == 0)\n\t\t{\n\t\t\toutputDir = Path::GetDirectoryName(fileName);\n\t\t}\n\n\t\tauto sourceDir = Path::GetDirectoryName(fileName);\n\t\tString schedule;\n\t\tif (options.ScheduleFileName.Length())\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tschedule = File::ReadAllText(options.ScheduleFileName);\n\t\t\t\toptions.ScheduleSource = schedule;\n\t\t\t}\n\t\t\tcatch (IOException)\n\t\t\t{\n\t\t\t\tprintf(\"Cannot open schedule file '%S'.\\n\", options.ScheduleFileName.ToWString());\n\t\t\t\tgoto end;\n\t\t\t}\n\t\t}\n\t\tCompileResult result;\n\t\ttry\n\t\t{\n\t\t\tauto files = SpireLib::CompileShaderSourceFromFile(result, fileName, options);\n\t\t\tfor (auto & f : files)\n\t\t\t{\n\t\t\t\t\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tf.SaveToFile(Path::Combine(outputDir, f.MetaData.ShaderName + \".cse\"));\n\t\t\t\t}\n\t\t\t\tcatch (Exception &)\n\t\t\t\t{\n\t\t\t\t\tresult.GetErrorWriter()->diagnose(CodePosition(0, 0, 0, \"\"), Diagnostics::cannotWriteOutputFile, Path::Combine(outputDir, f.MetaData.ShaderName + \".cse\"));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options.Target == CodeGenTarget::HLSL)\n\t\t\t{\n\t\t\t\t// verify shader using D3DCompileShaderFromFile\n\t\t\t\tRefPtr<D3DCompiler> d3dCompiler = LoadD3DCompiler();\n\t\t\t\tif (d3dCompiler)\n\t\t\t\t{\n\t\t\t\t\tfor (auto & f : files)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto & stage : f.Sources)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tString errMsg;\n\t\t\t\t\t\t\td3dCompiler->Compile(stage.Value.MainCode, stage.Key, errMsg);\n\t\t\t\t\t\t\tif (errMsg.Length())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tauto dumpFileName = f.MetaData.ShaderName + \".\" + stage.Key + \".hlsl\";\n\t\t\t\t\t\t\t\tresult.GetErrorWriter()->diagnose(CodePosition(0, 0, 0, dumpFileName), Diagnostics::d3dCompileInfo, errMsg);\n\t\t\t\t\t\t\t\tFile::WriteAllText(Path::Combine(Path::GetDirectoryName(fileName), dumpFileName), stage.Value.MainCode);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tprintf(\"failed to load d3d compiler for verification.\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (Exception & e)\n\t\t{\n\t\t\tprintf(\"internal compiler error: %S\\n\", e.Message.ToWString());\n\t\t}\n\t\tresult.PrintDiagnostics();\n\t\tif (result.GetErrorCount() == 0)\n\t\t\treturnValue = 0;\n\t\t\n\t}\nend:;\n#ifdef _MSC_VER\n\t_CrtDumpMemoryLeaks();\n#endif\n\treturn returnValue;\n}"
  },
  {
    "path": "Source/SpireCompiler/SpireCompiler.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugClang|Win32\">\n      <Configuration>DebugClang</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugClang|x64\">\n      <Configuration>DebugClang</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug_VS2013|Win32\">\n      <Configuration>Debug_VS2013</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug_VS2013|x64\">\n      <Configuration>Debug_VS2013</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release_VS2013|Win32\">\n      <Configuration>Release_VS2013</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release_VS2013|x64\">\n      <Configuration>Release_VS2013</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{D56CBCEB-1EB5-4CA8-AEC4-48EA35ED61C7}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>SpireCompiler</RootNamespace>\n    <ProjectName>SpireCompiler</ProjectName>\n    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140_clang_3_7</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140_Clang_3_7</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;../SpireLib</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;../SpireLib</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>EnableAllWarnings</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;../SpireLib</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n      <RuntimeTypeInfo>true</RuntimeTypeInfo>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;../SpireLib</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;../SpireLib</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;../SpireLib</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;../SpireLib</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;../SpireLib</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;../SpireLib</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;../SpireLib</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"D3DCompiler.cpp\" />\n    <ClCompile Include=\"ShaderCompilerShell.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\CoreLib\\CoreLibBasic.vcxproj\">\n      <Project>{f9be7957-8399-899e-0c49-e714fddd4b65}</Project>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\SpireCore\\SpireCore.vcxproj\">\n      <Project>{db00da62-0533-4afd-b59f-a67d5b3a0808}</Project>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\SpireLib\\SpireLib.vcxproj\">\n      <Project>{1168c449-66a5-4d23-80e2-2c1a07e58f83}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"D3DCompiler.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "Source/SpireCompiler/SpireCompiler.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"ShaderCompilerShell.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"D3DCompiler.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"D3DCompiler.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Source/SpireCore/CLikeCodeGen.cpp",
    "content": "#include \"CLikeCodeGen.h\"\n#include \"../CoreLib/Tokenizer.h\"\n#include \"Syntax.h\"\n#include \"Naming.h\"\n\nusing namespace CoreLib::Basic;\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tILRecordType * ExtractRecordType(ILType * type)\n\t\t{\n\t\t\tif (auto recType = dynamic_cast<ILRecordType*>(type))\n\t\t\t\treturn recType;\n\t\t\telse if (auto arrType = dynamic_cast<ILArrayType*>(type))\n\t\t\t\treturn ExtractRecordType(arrType->BaseType.Ptr());\n\t\t\telse if (auto genType = dynamic_cast<ILGenericType*>(type))\n\t\t\t\treturn ExtractRecordType(genType->BaseType.Ptr());\n\t\t\telse\n\t\t\t\treturn nullptr;\n\t\t}\n\n\t\tString AddWorldNameSuffix(String name, String suffix)\n\t\t{\n\t\t\tif (name.EndsWith(suffix))\n\t\t\t\treturn name;\n\t\t\telse\n\t\t\t\treturn EscapeCodeName(name + \"_\" + suffix);\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintType(StringBuilder & sbCode, ILType* type)\n\t\t{\n\t\t\tif (auto arrType = dynamic_cast<ILArrayType*>(type))\n\t\t\t{\n\t\t\t\tPrintType(sbCode, arrType->BaseType.Ptr());\n\t\t\t\tif (arrType->ArrayLength > 0)\n\t\t\t\t\tsbCode << \"[\" << arrType->ArrayLength << \"]\";\n\t\t\t\telse\n\t\t\t\t\tsbCode << \"[]\";\n\t\t\t}\n\t\t\telse\n\t\t\t\tPrintTypeName(sbCode, type);\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintDef(StringBuilder & sbCode, ILType* type, const String & name)\n\t\t{\n\t\t\tif (auto arrType = dynamic_cast<ILArrayType*>(type))\n\t\t\t{\n\t\t\t\tPrintDef(sbCode, arrType->BaseType.Ptr(), name);\n\t\t\t\tif (arrType->ArrayLength > 0)\n\t\t\t\t\tsbCode << \"[\" << arrType->ArrayLength << \"]\";\n\t\t\t\telse\n\t\t\t\t\tsbCode << \"[]\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tPrintType(sbCode, type);\n\t\t\t\tsbCode << \" \";\n\t\t\t\tsbCode << name;\n\t\t\t\tif (name.Length() == 0)\n\t\t\t\t\tthrow InvalidProgramException(\"unnamed instruction.\");\n\t\t\t}\n\t\t}\n\t\t\n\t\tString CLikeCodeGen::GetFuncOriginalName(const String & name)\n\t\t{\n\t\t\tString originalName;\n\t\t\tint splitPos = name.IndexOf('@');\n\t\t\tif (splitPos == 0)\n\t\t\t\treturn name;\n\t\t\tif (splitPos != -1)\n\t\t\t\toriginalName = name.SubString(0, splitPos);\n\t\t\telse\n\t\t\t\toriginalName = name;\n\t\t\treturn originalName;\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintOp(CodeGenContext & ctx, ILOperand * op, bool forceExpression)\n\t\t{\n\t\t\tauto makeFloat = [](float v)\n\t\t\t{\n\t\t\t\tString rs(v, \"%.12e\");\n\t\t\t\tif (!rs.Contains('.') && !rs.Contains('e') && !rs.Contains('E'))\n\t\t\t\t\trs = rs + \".0\";\n\t\t\t\tif (rs.StartsWith(\"-\"))\n\t\t\t\t\trs = \"(\" + rs + \")\";\n\t\t\t\treturn rs;\n\t\t\t};\n\t\t\t\n\t\t\tif (auto c = dynamic_cast<ILConstOperand*>(op))\n\t\t\t{\n\t\t\t\tauto type = c->Type.Ptr();\n\t\t\t\tif (type->IsFloat())\n\t\t\t\t\tctx.Body << makeFloat(c->FloatValues[0]);\n\t\t\t\telse if (type->IsInt())\n\t\t\t\t\tctx.Body << (c->IntValues[0]);\n\t\t\t\telse if (type->IsUInt())\n\t\t\t\t\tctx.Body << (unsigned int)(c->IntValues[0]) << \"u\";\n\t\t\t\telse if (type->IsBool())\n\t\t\t\t\tctx.Body << ((c->IntValues[0] != 0) ? \"true\" : \"false\");\n\t\t\t\telse if (auto baseType = dynamic_cast<ILBasicType*>(type))\n\t\t\t\t{\n\t\t\t\t\tPrintType(ctx.Body, baseType);\n\t\t\t\t\tctx.Body << \"(\";\n\n\t\t\t\t\tif (baseType->Type == ILBaseType::Float2)\n\t\t\t\t\t\tctx.Body << makeFloat(c->FloatValues[0]) << \", \" << makeFloat(c->FloatValues[1]);\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Float3)\n\t\t\t\t\t\tctx.Body << makeFloat(c->FloatValues[0]) << \", \" << makeFloat(c->FloatValues[1]) << \", \" << makeFloat(c->FloatValues[2]);\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Float4)\n\t\t\t\t\t\tctx.Body << makeFloat(c->FloatValues[0]) << \", \" << makeFloat(c->FloatValues[1]) << \", \" << makeFloat(c->FloatValues[2]) << \", \" << makeFloat(c->FloatValues[3]);\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Float3x3)\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.Body << \"mat3(\";\n\t\t\t\t\t\tfor (int i = 0; i < 9; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tctx.Body << makeFloat(c->FloatValues[i]);\n\t\t\t\t\t\t\tif (i != 8)\n\t\t\t\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tctx.Body;\n\t\t\t\t\t}\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Float4x4)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int i = 0; i < 16; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tctx.Body << makeFloat(c->FloatValues[i]);\n\t\t\t\t\t\t\tif (i != 15)\n\t\t\t\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Int2)\n\t\t\t\t\t\tctx.Body << c->IntValues[0] << \", \" << c->IntValues[1];\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Int3)\n\t\t\t\t\t\tctx.Body << c->IntValues[0] << \", \" << c->IntValues[1] << \", \" << c->IntValues[2];\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Int4)\n\t\t\t\t\t\tctx.Body << c->IntValues[0] << \", \" << c->IntValues[1] << \", \" << c->IntValues[2] << \", \" << c->IntValues[3];\n\n\t\t\t\t\tctx.Body << \")\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"Illegal constant.\");\n\t\t\t}\n\t\t\telse if (auto instr = dynamic_cast<ILInstruction*>(op))\n\t\t\t{\n\t\t\t\tif (AppearAsExpression(*instr, forceExpression))\n\t\t\t\t{\n\t\t\t\t\tPrintInstrExpr(ctx, *instr);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (forceExpression)\n\t\t\t\t\t\tthrow InvalidProgramException(\"cannot generate code block as an expression.\");\n\t\t\t\t\tString substituteName;\n\t\t\t\t\tif (ctx.SubstituteNames.TryGetValue(instr->Name, substituteName))\n\t\t\t\t\t\tctx.Body << substituteName;\n\t\t\t\t\telse\n\t\t\t\t\t\tctx.Body << instr->Name;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (auto param = dynamic_cast<ILModuleParameterInstance*>(op))\n\t\t\t{\n\t\t\t\tPrintParameterReference(ctx.Body, param);\n\t\t\t}\n\t\t\telse\n\t\t\t\tthrow InvalidOperationException(\"Unsupported operand type.\");\n\t\t}\n\n\t\tstatic bool IsMatrix(ILOperand* operand)\n\t\t{\n\t\t\tauto type = operand->Type;\n\t\t\t// TODO(tfoley): This needs to be expanded once other matrix types are supported\n\t\t\treturn type->IsFloatMatrix();\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintMatrixMulInstrExpr(CodeGenContext & ctx, ILOperand* op0, ILOperand* op1)\n\t\t{\n\t\t\tctx.Body << \"(\";\n\t\t\tPrintOp(ctx, op0);\n\t\t\tctx.Body << \" * \";\n\t\t\tPrintOp(ctx, op1);\n\t\t\tctx.Body << \")\";\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintBinaryInstrExpr(CodeGenContext & ctx, BinaryInstruction * instr)\n\t\t{\n\t\t\tif (instr->Is<StoreInstruction>())\n\t\t\t{\n\t\t\t\tauto op0 = instr->Operands[0].Ptr();\n\t\t\t\tauto op1 = instr->Operands[1].Ptr();\n\t\t\t\tctx.Body << \"(\";\n\t\t\t\tPrintOp(ctx, op0);\n\t\t\t\tctx.Body << \" = \";\n\t\t\t\tPrintOp(ctx, op1);\n\t\t\t\tctx.Body << \")\";\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tauto op0 = instr->Operands[0].Ptr();\n\t\t\tauto op1 = instr->Operands[1].Ptr();\n\t\t\tif (instr->Is<StoreInstruction>())\n\t\t\t{\n\t\t\t\tthrow InvalidOperationException(\"store instruction cannot appear as expression.\");\n\t\t\t}\n\t\t\tif (instr->Is<MemberLoadInstruction>())\n\t\t\t{\n\t\t\t\tPrintOp(ctx, op0);\n\t\t\t\tbool printDefault = true;\n\t\t\t\tif (op0->Type->GetVectorSize() <= 4 && op0->Type->IsVector())\n\t\t\t\t{\n\t\t\t\t\tif (auto c = dynamic_cast<ILConstOperand*>(op1))\n\t\t\t\t\t{\n\t\t\t\t\t\tswitch (c->IntValues[0])\n\t\t\t\t\t\t{\n\t\t\t\t\t\tcase 0:\n\t\t\t\t\t\t\tctx.Body << \".x\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 1:\n\t\t\t\t\t\t\tctx.Body << \".y\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 2:\n\t\t\t\t\t\t\tctx.Body << \".z\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 3:\n\t\t\t\t\t\t\tctx.Body << \".w\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow InvalidOperationException(\"Invalid member access.\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tprintDefault = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (auto structType = dynamic_cast<ILStructType*>(op0->Type.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tif (auto c = dynamic_cast<ILConstOperand*>(op1))\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.Body << \".\" << structType->Members[c->IntValues[0]].FieldName;\n\t\t\t\t\t}\n\t\t\t\t\tprintDefault = false;\n\t\t\t\t}\n\t\t\t\tif (printDefault)\n\t\t\t\t{\n\t\t\t\t\tctx.Body << \"[\";\n\t\t\t\t\tPrintOp(ctx, op1);\n\t\t\t\t\tctx.Body << \"]\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst char * op = \"\";\n\t\t\tif (instr->Is<AddInstruction>())\n\t\t\t{\n\t\t\t\top = \"+\";\n\t\t\t}\n\t\t\telse if (instr->Is<SubInstruction>())\n\t\t\t{\n\t\t\t\top = \"-\";\n\t\t\t}\n\t\t\telse if (instr->Is<MulInstruction>())\n\t\t\t{\n\t\t\t\t// For matrix-matrix, matrix-vector, and vector-matrix `*`,\n\t\t\t\t// GLSL performs a linear-algebraic inner product, while HLSL\n\t\t\t\t// always does element-wise product. We need to give the\n\t\t\t\t// codegen backend a change to handle this case.\n\t\t\t\tif(IsMatrix(op0) || IsMatrix(op1))\n\t\t\t\t{\n\t\t\t\t\tPrintMatrixMulInstrExpr(ctx, op0, op1);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\top = \"*\";\n\t\t\t}\n\t\t\telse if (instr->Is<DivInstruction>())\n\t\t\t{\n\t\t\t\top = \"/\";\n\t\t\t}\n\t\t\telse if (instr->Is<ModInstruction>())\n\t\t\t{\n\t\t\t\top = \"%\";\n\t\t\t}\n\t\t\telse if (instr->Is<ShlInstruction>())\n\t\t\t{\n\t\t\t\top = \"<<\";\n\t\t\t}\n\t\t\telse if (instr->Is<ShrInstruction>())\n\t\t\t{\n\t\t\t\top = \">>\";\n\t\t\t}\n\t\t\telse if (instr->Is<CmpeqlInstruction>())\n\t\t\t{\n\t\t\t\top = \"==\";\n\t\t\t\t//ctx.Body << \"int\";\n\t\t\t}\n\t\t\telse if (instr->Is<CmpgeInstruction>())\n\t\t\t{\n\t\t\t\top = \">=\";\n\t\t\t\t//ctx.Body << \"int\";\n\t\t\t}\n\t\t\telse if (instr->Is<CmpgtInstruction>())\n\t\t\t{\n\t\t\t\top = \">\";\n\t\t\t\t//ctx.Body << \"int\";\n\t\t\t}\n\t\t\telse if (instr->Is<CmpleInstruction>())\n\t\t\t{\n\t\t\t\top = \"<=\";\n\t\t\t\t//ctx.Body << \"int\";\n\t\t\t}\n\t\t\telse if (instr->Is<CmpltInstruction>())\n\t\t\t{\n\t\t\t\top = \"<\";\n\t\t\t\t//ctx.Body << \"int\";\n\t\t\t}\n\t\t\telse if (instr->Is<CmpneqInstruction>())\n\t\t\t{\n\t\t\t\top = \"!=\";\n\t\t\t\t//ctx.Body << \"int\";\n\t\t\t}\n\t\t\telse if (instr->Is<AndInstruction>())\n\t\t\t{\n\t\t\t\top = \"&&\";\n\t\t\t}\n\t\t\telse if (instr->Is<OrInstruction>())\n\t\t\t{\n\t\t\t\top = \"||\";\n\t\t\t}\n\t\t\telse if (instr->Is<BitXorInstruction>())\n\t\t\t{\n\t\t\t\top = \"^\";\n\t\t\t}\n\t\t\telse if (instr->Is<BitAndInstruction>())\n\t\t\t{\n\t\t\t\top = \"&\";\n\t\t\t}\n\t\t\telse if (instr->Is<BitOrInstruction>())\n\t\t\t{\n\t\t\t\top = \"|\";\n\t\t\t}\n\t\t\telse\n\t\t\t\tthrow InvalidProgramException(\"unsupported binary instruction.\");\n\t\t\tctx.Body << \"(\";\n\t\t\tPrintOp(ctx, op0);\n\t\t\tctx.Body << \" \" << op << \" \";\n\t\t\tPrintOp(ctx, op1);\n\t\t\tctx.Body << \")\";\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintBinaryInstr(CodeGenContext & ctx, BinaryInstruction * instr)\n\t\t{\n\t\t\tauto op0 = instr->Operands[0].Ptr();\n\t\t\tauto op1 = instr->Operands[1].Ptr();\n\t\t\tif (instr->Is<StoreInstruction>())\n\t\t\t{\n\t\t\t\tPrintOp(ctx, op0);\n\t\t\t\tctx.Body << \" = \";\n\t\t\t\tPrintOp(ctx, op1);\n\t\t\t\tctx.Body << \";\\n\";\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tauto varName = ctx.DefineVariable(instr);\n\t\t\tif (instr->Is<MemberLoadInstruction>())\n\t\t\t{\n\t\t\t\tctx.Body << varName << \" = \";\n\t\t\t\tPrintBinaryInstrExpr(ctx, instr);\n\t\t\t\tctx.Body << \";\\n\";\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tctx.Body << varName << \" = \";\n\t\t\tPrintBinaryInstrExpr(ctx, instr);\n\t\t\tctx.Body << \";\\n\";\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintUnaryInstrExpr(CodeGenContext & ctx, UnaryInstruction * instr)\n\t\t{\n\t\t\tauto op0 = instr->Operand.Ptr();\n\t\t\tif (instr->Is<LoadInstruction>())\n\t\t\t{\n\t\t\t\tPrintOp(ctx, op0);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if (instr->Is<SwizzleInstruction>())\n\t\t\t{\n\t\t\t\tPrintSwizzleInstrExpr(ctx, instr->As<SwizzleInstruction>());\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst char * op = \"\";\n\t\t\tif (instr->Is<BitNotInstruction>())\n\t\t\t\top = \"~\";\n\t\t\telse if (instr->Is<Float2IntInstruction>())\n\t\t\t\top = \"(int)\";\n\t\t\telse if (instr->Is<Int2FloatInstruction>())\n\t\t\t\top = \"(float)\";\n\t\t\telse if (instr->Is<CopyInstruction>())\n\t\t\t\top = \"\";\n\t\t\telse if (instr->Is<NegInstruction>())\n\t\t\t\top = \"-\";\n\t\t\telse if (instr->Is<NotInstruction>())\n\t\t\t\top = \"!\";\n\t\t\telse\n\t\t\t\tthrow InvalidProgramException(\"unsupported unary instruction.\");\n\t\t\tctx.Body << \"(\" << op;\n\t\t\tPrintOp(ctx, op0);\n\t\t\tctx.Body << \")\";\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintUnaryInstr(CodeGenContext & ctx, UnaryInstruction * instr)\n\t\t{\n\t\t\tauto varName = ctx.DefineVariable(instr);\n\t\t\tctx.Body << varName << \" = \";\n\t\t\tPrintUnaryInstrExpr(ctx, instr);\n\t\t\tctx.Body << \";\\n\";\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintAllocVarInstrExpr(CodeGenContext & ctx, AllocVarInstruction * instr)\n\t\t{\n\t\t\tctx.Body << instr->Name;\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintAllocVarInstr(CodeGenContext & ctx, AllocVarInstruction * instr)\n\t\t{\n\t\t\tif (dynamic_cast<ILConstOperand*>(instr->Size.Ptr()))\n\t\t\t{\n\t\t\t\tctx.DefineVariable(instr);\n\t\t\t}\n\t\t\telse\n\t\t\t\tthrow InvalidProgramException(\"size operand of allocVar instr is not an intermediate.\");\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintFetchArgInstrExpr(CodeGenContext & ctx, FetchArgInstruction * instr)\n\t\t{\n\t\t\tctx.Body << instr->Name;\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintFetchArgInstr(CodeGenContext & ctx, FetchArgInstruction * instr)\n\t\t{\n\t\t\tif (instr->ArgId == 0)\n\t\t\t{\n\t\t\t\tctx.ReturnVarName = ctx.DefineVariable(instr);\n\t\t\t}\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintSelectInstrExpr(CodeGenContext & ctx, SelectInstruction * instr)\n\t\t{\n\t\t\tctx.Body << \"(\";\n\t\t\tPrintOp(ctx, instr->Operands[0].Ptr());\n\t\t\tctx.Body << \"?\";\n\t\t\tPrintOp(ctx, instr->Operands[1].Ptr());\n\t\t\tctx.Body << \":\";\n\t\t\tPrintOp(ctx, instr->Operands[2].Ptr());\n\t\t\tctx.Body << \")\";\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintSelectInstr(CodeGenContext & ctx, SelectInstruction * instr)\n\t\t{\n\t\t\tauto varName = ctx.DefineVariable(instr);\n\t\t\tctx.Body << varName << \" = \";\n\t\t\tPrintSelectInstrExpr(ctx, instr);\n\t\t\tctx.Body << \";\\n\";\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintCallInstrExprForTarget(CodeGenContext & ctx, CallInstruction * instr, String const& name)\n\t\t{\n\t\t\tPrintDefaultCallInstrExpr(ctx, instr, name);\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintDefaultCallInstrArgs(CodeGenContext & ctx, CallInstruction * instr)\n\t\t{\n\t\t\tctx.Body << \"(\";\n\t\t\tint id = 0;\n\t\t\tfor (auto & arg : instr->Arguments)\n\t\t\t{\n\t\t\t\tPrintOp(ctx, arg.Ptr());\n\t\t\t\tif (id != instr->Arguments.Count() - 1)\n\t\t\t\t\tctx.Body << \", \";\n\t\t\t\tid++;\n\t\t\t}\n\t\t\tctx.Body << \")\";\n\t\t}\n\n\n\t\tvoid CLikeCodeGen::PrintDefaultCallInstrExpr(CodeGenContext & ctx, CallInstruction * instr, String const& callName)\n\t\t{\n\t\t\tctx.Body << callName;\n\t\t\tPrintDefaultCallInstrArgs(ctx, instr);\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintCallInstrExpr(CodeGenContext & ctx, CallInstruction * instr)\n\t\t{\n\t\t\tif (instr->Arguments.Count() > 0 && instr->Arguments.First()->Type->IsTexture() && intrinsicTextureFunctions.Contains(instr->Function))\n\t\t\t{\n\t\t\t\tPrintTextureCall(ctx, instr);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tString callName;\n\t\t\tcallName = GetFuncOriginalName(instr->Function);\n\t\t\tPrintCallInstrExprForTarget(ctx, instr, callName);\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintCallInstr(CodeGenContext & ctx, CallInstruction * instr)\n\t\t{\n\t\t\tif (!instr->Type->IsVoid())\n\t\t\t{\n\t\t\t\tauto varName = ctx.DefineVariable(instr);\n\t\t\t\tctx.Body << varName;\n\t\t\t\tctx.Body << \" = \";\n\t\t\t}\n\t\t\tPrintCallInstrExpr(ctx, instr);\n\t\t\tctx.Body << \";\\n\";\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintCastF2IInstrExpr(CodeGenContext & ctx, Float2IntInstruction * instr)\n\t\t{\n\t\t\tctx.Body << \"((int)(\";\n\t\t\tPrintOp(ctx, instr->Operand.Ptr());\n\t\t\tctx.Body << \"))\";\n\t\t}\n\t\tvoid CLikeCodeGen::PrintCastF2IInstr(CodeGenContext & ctx, Float2IntInstruction * instr)\n\t\t{\n\t\t\tauto varName = ctx.DefineVariable(instr);\n\t\t\tctx.Body << varName;\n\t\t\tctx.Body << \" = \";\n\t\t\tPrintCastF2IInstrExpr(ctx, instr);\n\t\t\tctx.Body << \";\\n\";\n\t\t}\n\t\tvoid CLikeCodeGen::PrintCastI2FInstrExpr(CodeGenContext & ctx, Int2FloatInstruction * instr)\n\t\t{\n\t\t\tctx.Body << \"((float)(\";\n\t\t\tPrintOp(ctx, instr->Operand.Ptr());\n\t\t\tctx.Body << \"))\";\n\t\t}\n\t\tvoid CLikeCodeGen::PrintCastI2FInstr(CodeGenContext & ctx, Int2FloatInstruction * instr)\n\t\t{\n\t\t\tauto varName = ctx.DefineVariable(instr);\n\t\t\tctx.Body << varName;\n\t\t\tctx.Body << \" = \";\n\t\t\tPrintCastI2FInstrExpr(ctx, instr);\n\t\t\tctx.Body << \";\\n\";\n\t\t}\n\n\t\tbool CLikeCodeGen::AppearAsExpression(ILInstruction & instr, bool force)\n\t\t{\n\t\t\tif (instr.Is<LoadInputInstruction>() || instr.Is<ProjectInstruction>() || instr.Is<MemberLoadInstruction>())\n\t\t\t\treturn true;\n\t\t\tif (auto arg = instr.As<FetchArgInstruction>())\n\t\t\t{\n\t\t\t\tif (arg->ArgId == 0)\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (auto import = instr.As<ImportInstruction>())\n\t\t\t{\n\t\t\t\tif ((!useBindlessTexture && import->Type->IsTexture()) \n\t\t\t\t\t|| import->Type.As<ILArrayType>() \n\t\t\t\t\t|| import->Type->IsSamplerState()\n\t\t\t\t\t|| import->Type.As<ILGenericType>())\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t\tfor (auto &&usr : instr.Users)\n\t\t\t{\n\t\t\t\tif (auto update = dynamic_cast<MemberUpdateInstruction*>(usr))\n\t\t\t\t{\n\t\t\t\t\tif (&instr == update->Operands[0].Ptr())\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\telse if (dynamic_cast<MemberLoadInstruction*>(usr))\n\t\t\t\t\treturn false;\n\t\t\t\telse if (dynamic_cast<ExportInstruction*>(usr))\n\t\t\t\t\treturn false;\n\t\t\t\telse if (dynamic_cast<ImportInstruction*>(usr))\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (instr.Is<StoreInstruction>() && force)\n\t\t\t\treturn true;\n\n\t\t\treturn (instr.Users.Count() <= 1 && !instr.HasSideEffect() && !instr.Is<MemberUpdateInstruction>()\n\t\t\t\t&& !instr.Is<AllocVarInstruction>() && !instr.Is<ImportInstruction>())\n\t\t\t\t|| instr.Is<FetchArgInstruction>();\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintExportInstr(CodeGenContext &ctx, ExportInstruction * exportInstr)\n\t\t{\n\t\t\toutputStrategy->ProcessExportInstruction(ctx, exportInstr);\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintUpdateInstr(CodeGenContext & ctx, MemberUpdateInstruction * instr)\n\t\t{\n\t\t\tauto genCode = [&](String varName, ILType * srcType, ILOperand * op1, ILOperand * op2)\n\t\t\t{\n\t\t\t\tctx.Body << varName;\n\t\t\t\tif (auto structType = dynamic_cast<ILStructType*>(srcType))\n\t\t\t\t{\n\t\t\t\t\tctx.Body << \".\";\n\t\t\t\t\tctx.Body << structType->Members[dynamic_cast<ILConstOperand*>(op1)->IntValues[0]].FieldName;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tctx.Body << \"[\";\n\t\t\t\t\tPrintOp(ctx, op1);\n\t\t\t\t\tctx.Body << \"]\";\n\t\t\t\t}\n\t\t\t\tctx.Body << \" = \";\n\t\t\t\tPrintOp(ctx, op2);\n\t\t\t\tctx.Body << \";\\n\";\n\t\t\t};\n\t\t\tif (auto srcInstr = dynamic_cast<ILInstruction*>(instr->Operands[0].Ptr()))\n\t\t\t{\n\t\t\t\tif (srcInstr->Users.Count() == 1)\n\t\t\t\t{\n\t\t\t\t\tauto srcName = srcInstr->Name;\n\t\t\t\t\twhile (ctx.SubstituteNames.TryGetValue(srcName, srcName));\n\t\t\t\t\tgenCode(srcName, srcInstr->Type.Ptr(), instr->Operands[1].Ptr(), instr->Operands[2].Ptr());\n\t\t\t\t\tctx.SubstituteNames[instr->Name] = srcName;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tgenCode(instr->Operands[0]->Name, instr->Operands[0]->Type.Ptr(), instr->Operands[1].Ptr(), instr->Operands[2].Ptr());\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintSwizzleInstrExpr(CodeGenContext & ctx, SwizzleInstruction * swizzle)\n\t\t{\n\t\t\tPrintOp(ctx, swizzle->Operand.Ptr());\n\t\t\tctx.Body << \".\" << swizzle->SwizzleString;\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintImportInstr(CodeGenContext & ctx, ImportInstruction * importInstr)\n\t\t{\n\t\t\tcurrentImportInstr = importInstr;\n\t\t\t\t\n\t\t\tctx.DefineVariable(importInstr);\n\t\t\tGenerateCode(ctx, importInstr->ImportOperator.Ptr());\n\t\t\t\t\n\t\t\tcurrentImportInstr = nullptr;\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintImportInstrExpr(CodeGenContext & ctx, ImportInstruction * importInstr)\n\t\t{\n\t\t\tcurrentImportInstr = importInstr;\n\t\t\tPrintOp(ctx, importInstr->ImportOperator->GetLastInstruction()->As<ReturnInstruction>()->Operand.Ptr());\n\t\t\tcurrentImportInstr = nullptr;\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintInstrExpr(CodeGenContext & ctx, ILInstruction & instr)\n\t\t{\n\t\t\tif (auto projInstr = instr.As<ProjectInstruction>())\n\t\t\t\tPrintProjectInstrExpr(ctx, projInstr);\n\t\t\telse if (auto binInstr = instr.As<BinaryInstruction>())\n\t\t\t\tPrintBinaryInstrExpr(ctx, binInstr);\n\t\t\telse if (auto unaryInstr = instr.As<UnaryInstruction>())\n\t\t\t\tPrintUnaryInstrExpr(ctx, unaryInstr);\n\t\t\telse if (auto allocVar = instr.As<AllocVarInstruction>())\n\t\t\t\tPrintAllocVarInstrExpr(ctx, allocVar);\n\t\t\telse if (auto fetchArg = instr.As<FetchArgInstruction>())\n\t\t\t\tPrintFetchArgInstrExpr(ctx, fetchArg);\n\t\t\telse if (auto select = instr.As<SelectInstruction>())\n\t\t\t\tPrintSelectInstrExpr(ctx, select);\n\t\t\telse if (auto call = instr.As<CallInstruction>())\n\t\t\t\tPrintCallInstrExpr(ctx, call);\n\t\t\telse if (auto castf2i = instr.As<Float2IntInstruction>())\n\t\t\t\tPrintCastF2IInstrExpr(ctx, castf2i);\n\t\t\telse if (auto casti2f = instr.As<Int2FloatInstruction>())\n\t\t\t\tPrintCastI2FInstrExpr(ctx, casti2f);\n\t\t\telse if (auto ldInput = instr.As<LoadInputInstruction>())\n\t\t\t\tPrintLoadInputInstrExpr(ctx, ldInput);\n\t\t\telse if (auto import = instr.As<ImportInstruction>())\n\t\t\t\tPrintImportInstrExpr(ctx, import);\n\t\t\telse if (instr.As<MemberUpdateInstruction>())\n\t\t\t\tthrow InvalidOperationException(\"member update instruction cannot appear as expression.\");\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintInstr(CodeGenContext & ctx, ILInstruction & instr)\n\t\t{\n\t\t\t// ctx.Body << \"// \" << instr.ToString() << \";\\n\";\n\t\t\tif (!AppearAsExpression(instr, false))\n\t\t\t{\n\t\t\t\tif (auto binInstr = instr.As<BinaryInstruction>())\n\t\t\t\t\tPrintBinaryInstr(ctx, binInstr);\n\t\t\t\telse if (auto exportInstr = instr.As<ExportInstruction>())\n\t\t\t\t\tPrintExportInstr(ctx, exportInstr);\n\t\t\t\telse if (auto unaryInstr = instr.As<UnaryInstruction>())\n\t\t\t\t\tPrintUnaryInstr(ctx, unaryInstr);\n\t\t\t\telse if (auto allocVar = instr.As<AllocVarInstruction>())\n\t\t\t\t\tPrintAllocVarInstr(ctx, allocVar);\n\t\t\t\telse if (auto fetchArg = instr.As<FetchArgInstruction>())\n\t\t\t\t\tPrintFetchArgInstr(ctx, fetchArg);\n\t\t\t\telse if (auto select = instr.As<SelectInstruction>())\n\t\t\t\t\tPrintSelectInstr(ctx, select);\n\t\t\t\telse if (auto call = instr.As<CallInstruction>())\n\t\t\t\t\tPrintCallInstr(ctx, call);\n\t\t\t\telse if (auto castf2i = instr.As<Float2IntInstruction>())\n\t\t\t\t\tPrintCastF2IInstr(ctx, castf2i);\n\t\t\t\telse if (auto casti2f = instr.As<Int2FloatInstruction>())\n\t\t\t\t\tPrintCastI2FInstr(ctx, casti2f);\n\t\t\t\telse if (auto update = instr.As<MemberUpdateInstruction>())\n\t\t\t\t\tPrintUpdateInstr(ctx, update);\n\t\t\t\telse if (auto importInstr = instr.As<ImportInstruction>())\n\t\t\t\t\tPrintImportInstr(ctx, importInstr);\n\t\t\t\t\t\n\t\t\t}\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintLoadInputInstrExpr(CodeGenContext & ctx, LoadInputInstruction * instr)\n\t\t{\n\t\t\tPrintInputReference(ctx, ctx.Body, instr->InputName);\n\t\t}\n\n\t\tvoid CLikeCodeGen::GenerateCode(CodeGenContext & context, CFGNode * code)\n\t\t{\n\t\t\tfor (auto & instr : *code)\n\t\t\t{\n\t\t\t\tif (auto ifInstr = instr.As<IfInstruction>())\n\t\t\t\t{\n\t\t\t\t\tcontext.Body << \"if (bool(\";\n\t\t\t\t\tPrintOp(context, ifInstr->Operand.Ptr());\n\t\t\t\t\tcontext.Body << \"))\\n{\\n\";\n\t\t\t\t\tGenerateCode(context, ifInstr->TrueCode.Ptr());\n\t\t\t\t\tcontext.Body << \"}\\n\";\n\t\t\t\t\tif (ifInstr->FalseCode)\n\t\t\t\t\t{\n\t\t\t\t\t\tcontext.Body << \"else\\n{\\n\";\n\t\t\t\t\t\tGenerateCode(context, ifInstr->FalseCode.Ptr());\n\t\t\t\t\t\tcontext.Body << \"}\\n\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (auto forInstr = instr.As<ForInstruction>())\n\t\t\t\t{\n\t\t\t\t\tcontext.Body << \"for (\";\n\t\t\t\t\tif (forInstr->InitialCode)\n\t\t\t\t\t\tPrintOp(context, forInstr->InitialCode->GetLastInstruction(), true);\n\t\t\t\t\tcontext.Body << \"; \";\n\t\t\t\t\tif (forInstr->ConditionCode)\n\t\t\t\t\t\tPrintOp(context, forInstr->ConditionCode->GetLastInstruction(), true);\n\t\t\t\t\tcontext.Body << \"; \";\n\t\t\t\t\tif (forInstr->SideEffectCode)\n\t\t\t\t\t\tPrintOp(context, forInstr->SideEffectCode->GetLastInstruction(), true);\n\t\t\t\t\tcontext.Body << \")\\n{\\n\";\n\t\t\t\t\tGenerateCode(context, forInstr->BodyCode.Ptr());\n\t\t\t\t\tcontext.Body << \"}\\n\";\n\t\t\t\t}\n\t\t\t\telse if (auto doInstr = instr.As<DoInstruction>())\n\t\t\t\t{\n\t\t\t\t\tcontext.Body << \"do\\n{\\n\";\n\t\t\t\t\tGenerateCode(context, doInstr->BodyCode.Ptr());\n\t\t\t\t\tcontext.Body << \"} while (bool(\";\n\t\t\t\t\tPrintOp(context, doInstr->ConditionCode->GetLastInstruction()->As<ReturnInstruction>()->Operand.Ptr());\n\t\t\t\t\tcontext.Body << \"));\\n\";\n\t\t\t\t}\n\t\t\t\telse if (auto whileInstr = instr.As<WhileInstruction>())\n\t\t\t\t{\n\t\t\t\t\tcontext.Body << \"while (bool(\";\n\t\t\t\t\tPrintOp(context, whileInstr->ConditionCode->GetLastInstruction()->As<ReturnInstruction>()->Operand.Ptr());\n\t\t\t\t\tcontext.Body << \"))\\n{\\n\";\n\t\t\t\t\tGenerateCode(context, whileInstr->BodyCode.Ptr());\n\t\t\t\t\tcontext.Body << \"}\\n\";\n\t\t\t\t}\n\t\t\t\telse if (auto ret = instr.As<ReturnInstruction>())\n\t\t\t\t{\n\t\t\t\t\tif (currentImportInstr) \n\t\t\t\t\t{\n\t\t\t\t\t\tcontext.Body << currentImportInstr->Name << \" = \";\n\t\t\t\t\t\tPrintOp(context, ret->Operand.Ptr());\n\t\t\t\t\t\tcontext.Body << \";\\n\";\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tcontext.Body << \"return \";\n\t\t\t\t\t\tPrintOp(context, ret->Operand.Ptr());\n\t\t\t\t\t\tcontext.Body << \";\\n\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (instr.Is<BreakInstruction>())\n\t\t\t\t{\n\t\t\t\t\tcontext.Body << \"break;\\n\";\n\t\t\t\t}\n\t\t\t\telse if (instr.Is<ContinueInstruction>())\n\t\t\t\t{\n\t\t\t\t\tcontext.Body << \"continue;\\n\";\n\t\t\t\t}\n\t\t\t\telse if (instr.Is<DiscardInstruction>())\n\t\t\t\t{\n\t\t\t\t\tcontext.Body << \"discard;\\n\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tPrintInstr(context, instr);\n\t\t\t}\n\t\t}\n\n\t\tCLikeCodeGen::CLikeCodeGen()\n\t\t{\n\t\t\tintrinsicTextureFunctions.Add(\"Sample\");\n\t\t\tintrinsicTextureFunctions.Add(\"SampleBias\");\n\t\t\tintrinsicTextureFunctions.Add(\"SampleGrad\");\n\t\t\tintrinsicTextureFunctions.Add(\"SampleLevel\");\n\t\t\tintrinsicTextureFunctions.Add(\"SampleCmp\");\n\t\t\tintrinsicTextureFunctions.Add(\"Load\");\n\t\t}\n\n\t\tvoid CLikeCodeGen::GenerateShaderMetaData(ShaderMetaData & result, ILProgram* /*program*/, ILShader * shader, DiagnosticSink * /*err*/)\n\t\t{\n\t\t\tresult.ShaderName = shader->Name;\n\t\t\tresult.ParameterSets = shader->ModuleParamSets;\n\t\t}\n\n\t\tCompiledShaderSource CLikeCodeGen::GenerateShader(CompileResult & result, SymbolTable *, ILShader * shader, DiagnosticSink * err)\n\t\t{\n\t\t\tthis->errWriter = err;\n\n\t\t\tCompiledShaderSource rs;\n\n\t\t\tfor (auto & stage : shader->Stages)\n\t\t\t{\n\t\t\t\tStageSource src;\n\t\t\t\tif (stage.Value->StageType == \"VertexShader\" || stage.Value->StageType == \"FragmentShader\" || stage.Value->StageType == \"DomainShader\")\n\t\t\t\t\tsrc = GenerateVertexFragmentDomainShader(result.Program.Ptr(), shader, stage.Value.Ptr());\n\t\t\t\telse if (stage.Value->StageType == \"ComputeShader\")\n\t\t\t\t\tsrc = GenerateComputeShader(result.Program.Ptr(), shader, stage.Value.Ptr());\n\t\t\t\telse if (stage.Value->StageType == \"HullShader\")\n\t\t\t\t\tsrc = GenerateHullShader(result.Program.Ptr(), shader, stage.Value.Ptr());\n\t\t\t\telse\n                    errWriter->diagnose(stage.Value->Position, Diagnostics::unknownStageType, stage.Value->StageType);\n\t\t\t\trs.Stages[stage.Key] = src;\n\t\t\t}\n\t\t\t\t\n\t\t\tGenerateShaderMetaData(rs.MetaData, result.Program.Ptr(), shader, err);\n\t\t\t\t\n\t\t\treturn rs;\n\t\t}\n\n\t\tvoid CLikeCodeGen::GenerateStructs(StringBuilder & sb, ILProgram * program)\n\t\t{\n\t\t\tfor (auto & st : program->Structs)\n\t\t\t{\n\t\t\t\tif (!st->IsIntrinsic)\n\t\t\t\t{\n\t\t\t\t\tsb << \"struct \" << st->TypeName << \"\\n{\\n\";\n\t\t\t\t\tfor (auto & f : st->Members)\n\t\t\t\t\t{\n\t\t\t\t\t\tPrintDef(sb, f.Type.Ptr(), f.FieldName);\n\t\t\t\t\t\tsb << \";\\n\";\n\t\t\t\t\t}\n\t\t\t\t\tsb << \"};\\n\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid CLikeCodeGen::GenerateReferencedFunctions(StringBuilder & sb, ILProgram * program, ArrayView<ILWorld*> worlds)\n\t\t{\n\t\t\tEnumerableHashSet<String> refFuncs;\n\t\t\tfor (auto & world : worlds)\n\t\t\t\tfor (auto & func : world->ReferencedFunctions)\n\t\t\t\t\trefFuncs.Add(func);\n\t\t\tfor (auto & func : program->Functions)\n\t\t\t{\n\t\t\t\tif (refFuncs.Contains(func.Value->Name))\n\t\t\t\t{\n\t\t\t\t\tGenerateFunctionDeclaration(sb, func.Value.Ptr());\n\t\t\t\t\tsb << \";\\n\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (auto & func : program->Functions)\n\t\t\t{\n\t\t\t\tif (refFuncs.Contains(func.Value->Name))\n\t\t\t\t\tsb << GenerateFunction(func.Value.Ptr());\n\t\t\t}\n\t\t}\n\n\t\tExternComponentCodeGenInfo CLikeCodeGen::ExtractExternComponentInfo(const ILObjectDefinition & input)\n\t\t{\n\t\t\tauto type = input.Type.Ptr();\n\t\t\tauto recType = ExtractRecordType(type);\n\t\t\tExternComponentCodeGenInfo info;\n\t\t\tinfo.Type = type;\n\t\t\tToken bindingVal;\n\t\t\tif (input.Attributes.TryGetValue(\"Binding\", bindingVal))\n\t\t\t\tinfo.Binding = StringToInt(bindingVal.Content);\n\t\t\tif (recType)\n\t\t\t{\n\t\t\t\tif (auto genType = dynamic_cast<ILGenericType*>(type))\n\t\t\t\t{\n\t\t\t\t\tif (genType->GenericTypeName == \"Patch\")\n\t\t\t\t\t{\n\t\t\t\t\t\ttype = genType->BaseType.Ptr();\n\t\t\t\t\t\tinfo.DataStructure = ExternComponentCodeGenInfo::DataStructureType::Patch;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (auto arrType = dynamic_cast<ILArrayType*>(type))\n\t\t\t\t{\n                    if (info.DataStructure != ExternComponentCodeGenInfo::DataStructureType::StandardInput &&\n                        info.DataStructure != ExternComponentCodeGenInfo::DataStructureType::Patch)\n                    {\n                        errWriter->diagnose(input.Position, Diagnostics::cannotGenerateCodeForExternComponentType, type);\n                    }\n\t\t\t\t\ttype = arrType->BaseType.Ptr();\n\t\t\t\t\tinfo.IsArray = true;\n\t\t\t\t\tinfo.ArrayLength = arrType->ArrayLength;\n\t\t\t\t}\n\t\t\t\tif (type != recType)\n\t\t\t\t{\n                    errWriter->diagnose(input.Position, Diagnostics::cannotGenerateCodeForExternComponentType, type);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// check for attributes \n\t\t\t\tif (input.Attributes.ContainsKey(\"TessCoord\"))\n\t\t\t\t{\n\t\t\t\t\tinfo.SystemVar = ExternComponentCodeGenInfo::SystemVarType::TessCoord;\n\t\t\t\t\tif (!(input.Type->IsFloatVector() && input.Type->GetVectorSize() <= 3))\n                        getSink()->diagnose(input.Position, Diagnostics::invalidTessCoordType);\n\t\t\t\t}\n\t\t\t\telse if (input.Attributes.ContainsKey(\"FragCoord\"))\n\t\t\t\t{\n\t\t\t\t\tinfo.SystemVar = ExternComponentCodeGenInfo::SystemVarType::FragCoord;\n\t\t\t\t\tif (!(input.Type->IsFloatVector() && input.Type->GetVectorSize() == 4))\n                        getSink()->diagnose(input.Position, Diagnostics::invalidFragCoordType);\n\t\t\t\t}\n\t\t\t\telse if (input.Attributes.ContainsKey(\"InvocationId\"))\n\t\t\t\t{\n\t\t\t\t\tinfo.SystemVar = ExternComponentCodeGenInfo::SystemVarType::InvocationId;\n\t\t\t\t\tif (!input.Type->IsInt())\n                        getSink()->diagnose(input.Position, Diagnostics::invalidInvocationIdType);\n\t\t\t\t}\n\t\t\t\telse if (input.Attributes.ContainsKey(\"ThreadId\"))\n\t\t\t\t{\n\t\t\t\t\tinfo.SystemVar = ExternComponentCodeGenInfo::SystemVarType::InvocationId;\n\t\t\t\t\tif (!input.Type->IsInt())\n                        getSink()->diagnose(input.Position, Diagnostics::invalidThreadIdType);\n\t\t\t\t}\n\t\t\t\telse if (input.Attributes.ContainsKey(\"PrimitiveId\"))\n\t\t\t\t{\n\t\t\t\t\tinfo.SystemVar = ExternComponentCodeGenInfo::SystemVarType::PrimitiveId;\n\t\t\t\t\tif (!input.Type->IsInt())\n                        getSink()->diagnose(input.Position, Diagnostics::invalidPrimitiveIdType);\n\t\t\t\t}\n\t\t\t\telse if (input.Attributes.ContainsKey(\"PatchVertexCount\"))\n\t\t\t\t{\n\t\t\t\t\tinfo.SystemVar = ExternComponentCodeGenInfo::SystemVarType::PatchVertexCount;\n\t\t\t\t\tif (!input.Type->IsInt())\n                        getSink()->diagnose(input.Position, Diagnostics::invalidPatchVertexCountType);\n\t\t\t\t}\n\t\t\t\telse if (input.Attributes.ContainsKey(\"InstanceId\"))\n\t\t\t\t{\n\t\t\t\t\tinfo.SystemVar = ExternComponentCodeGenInfo::SystemVarType::InstanceId;\n\t\t\t\t\tif (!input.Type->IsInt())\n                        getSink()->diagnose(input.Position, Diagnostics::invalidTypeForSystemVar, \"InstanceId\", input.Type);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn info;\n\t\t}\n\n\t\tvoid CLikeCodeGen::PrintInputReference(CodeGenContext & ctx, StringBuilder & sb, String input)\n\t\t{\n\t\t\tauto info = extCompInfo[input]();\n\n\t\t\t// TODO(tfoley): Is there any reason why this isn't just a `switch`?\n\t\t\tif (auto recType = ExtractRecordType(info.Type.Ptr()))\n\t\t\t{\n\t\t\t\t// TODO(tfoley): hoist this logic up to the top-level if chain?\n\t\t\t\tif(info.DataStructure == ExternComponentCodeGenInfo::DataStructureType::StandardInput)\n\t\t\t\t{\n\t\t\t\t\tif(info.IsArray)\n\t\t\t\t\t{\n\t\t\t\t\t\tPrintStandardArrayInputReference(sb, recType, input, currentImportInstr->ComponentName);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tPrintStandardInputReference(sb, recType, input, currentImportInstr->ComponentName);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if(info.DataStructure == ExternComponentCodeGenInfo::DataStructureType::Patch)\n\t\t\t\t{\n\t\t\t\t\tPrintPatchInputReference(sb, recType, input, currentImportInstr->ComponentName);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// TODO(tfoley): Does this case ever actually trigger?\n\t\t\t\t\tPrintDefaultInputReference(sb, recType, input, currentImportInstr->ComponentName);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tPrintSystemVarReference(ctx, sb, input, info.SystemVar);\n\t\t\t}\n\t\t}\n\n\t\tvoid CLikeCodeGen::DeclareInput(CodeGenContext & sb, const ILObjectDefinition & input, bool isVertexShader)\n\t\t{\n\t\t\tauto info = ExtractExternComponentInfo(input);\n\t\t\textCompInfo[input.Name] = info;\n\t\t\tauto recType = ExtractRecordType(input.Type.Ptr());\n\t\t\tif (recType)\n\t\t\t{\n\t\t\t\tswitch(info.DataStructure)\n\t\t\t\t{\n\t\t\t\tcase ExternComponentCodeGenInfo::DataStructureType::StandardInput:\n\t\t\t\t\tDeclareStandardInputRecord(sb, input, isVertexShader);\n\t\t\t\t\treturn;\n\n\t\t\t\tcase ExternComponentCodeGenInfo::DataStructureType::Patch:\n\t\t\t\t\tDeclarePatchInputRecord(sb, input, isVertexShader);\n\t\t\t\t\treturn;\n\n\t\t\t\tdefault:\n                    SPIRE_INTERNAL_ERROR(getSink(), input.Position);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid CLikeCodeGen::GenerateVertexShaderEpilog(CodeGenContext & ctx, ILWorld * world, ILStage * stage)\n\t\t{\n\t\t\tStageAttribute positionVar;\n\t\t\tif (stage->Attributes.TryGetValue(\"Position\", positionVar))\n\t\t\t{\n\t\t\t\tILOperand * operand;\n\t\t\t\tif (world->Components.TryGetValue(positionVar.Value, operand))\n\t\t\t\t{\n                    if (operand->Type->IsFloatVector() && operand->Type->GetVectorSize() == 4)\n                    {\n                        PrintRasterPositionOutputWrite(ctx, operand);\n                    }\n                    else\n                        errWriter->diagnose(positionVar.Position, Diagnostics::componentHasInvalidTypeForPositionOutput, positionVar.Value);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\terrWriter->diagnose(positionVar.Position, Diagnostics::componentNotDefined, positionVar.Value);\n\t\t\t}\n\t\t}\n\n\t\tStageSource CLikeCodeGen::GenerateVertexFragmentDomainShader(ILProgram * program, ILShader * shader, ILStage * stage)\n\t\t{\n\t\t\tRefPtr<ILWorld> world = nullptr;\n\t\t\tStageAttribute worldName;\n\t\t\tif (stage->Attributes.TryGetValue(\"World\", worldName))\n\t\t\t{\n\t\t\t\tif (!shader->Worlds.TryGetValue(worldName.Value, world))\n\t\t\t\t\terrWriter->diagnose(worldName.Position, Diagnostics::worldIsNotDefined, worldName.Value);\n\t\t\t}\n\t\t\toutputStrategy = CreateStandardOutputStrategy(world.Ptr(), \"\");\n\t\t\treturn GenerateSingleWorldShader(program, shader, stage);\n\t\t}\n\n\t\tStageSource CLikeCodeGen::GenerateComputeShader(ILProgram * program, ILShader * shader, ILStage * stage)\n\t\t{\n\t\t\tRefPtr<ILWorld> world = nullptr;\n\t\t\tStageAttribute worldName;\n\t\t\tif (stage->Attributes.TryGetValue(\"World\", worldName))\n\t\t\t{\n\t\t\t\tif (!shader->Worlds.TryGetValue(worldName.Value, world))\n\t\t\t\t\terrWriter->diagnose(worldName.Position, Diagnostics::worldIsNotDefined, worldName);\n\t\t\t}\n\t\t\toutputStrategy = CreatePackedBufferOutputStrategy(world.Ptr());\n\t\t\treturn GenerateSingleWorldShader(program, shader, stage);\n\t\t}\n\n\t\tvoid CLikeCodeGen::GenerateFunctionDeclaration(StringBuilder & sbCode, ILFunction * function)\n\t\t{\n\t\t\tfunction->Code->NameAllInstructions();\n\t\t\tauto retType = function->ReturnType.Ptr();\n\t\t\tif (retType)\n\t\t\t\tPrintType(sbCode, retType);\n\t\t\telse\n\t\t\t\tsbCode << \"void\";\n\t\t\tsbCode << \" \" << GetFuncOriginalName(function->Name) << \"(\";\n\t\t\tint id = 0;\n\t\t\tauto paramIter = function->Parameters.begin();\n\t\t\tfor (auto & instr : *function->Code)\n\t\t\t{\n\t\t\t\tif (auto arg = instr.As<FetchArgInstruction>())\n\t\t\t\t{\n\t\t\t\t\tif (arg->ArgId != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (id > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsbCode << \", \";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tauto qualifier = (*paramIter).Value.Qualifier;\n\t\t\t\t\t\tif (qualifier == ParameterQualifier::InOut)\n\t\t\t\t\t\t\tsbCode << \"inout \";\n\t\t\t\t\t\telse if (qualifier == ParameterQualifier::Out)\n\t\t\t\t\t\t\tsbCode << \"out \";\n\t\t\t\t\t\telse if (qualifier == ParameterQualifier::Uniform)\n\t\t\t\t\t\t\tsbCode << \"uniform \";\n\t\t\t\t\t\tPrintDef(sbCode, arg->Type.Ptr(), arg->Name);\n\t\t\t\t\t\tid++;\n\t\t\t\t\t}\n\t\t\t\t\t++paramIter;\n\t\t\t\t}\n\t\t\t}\n\t\t\tsbCode << \")\";\n\t\t}\n\t\tString CLikeCodeGen::GenerateFunction(ILFunction * function)\n\t\t{\n\t\t\tStringBuilder sbCode;\n\t\t\tCodeGenContext ctx;\n\t\t\tctx.codeGen = this;\n\t\t\tctx.UsedVarNames.Clear();\n\t\t\tctx.Body.Clear();\n\t\t\tctx.Header.Clear();\n\t\t\tctx.Arguments.Clear();\n\t\t\tctx.ReturnVarName = \"\";\n\t\t\tctx.VarName.Clear();\n\t\t\t\t\n\t\t\tfunction->Code->NameAllInstructions();\n\t\t\tGenerateFunctionDeclaration(sbCode, function);\n\t\t\tsbCode << \"\\n{\\n\";\n\t\t\tGenerateCode(ctx, function->Code.Ptr());\n\t\t\tsbCode << ctx.Header.ToString() << ctx.Body.ToString();\n\t\t\tif (ctx.ReturnVarName.Length())\n\t\t\t\tsbCode << \"return \" << ctx.ReturnVarName << \";\\n\";\n\t\t\tsbCode << \"}\\n\";\n\t\t\treturn sbCode.ProduceString();\n\t\t}\n\n\t\tString CodeGenContext::DefineVariable(ILOperand * op)\n\t\t{\n\t\t\tString rs;\n\t\t\tif (VarName.TryGetValue(op, rs))\n\t\t\t{\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tauto name = GenerateCodeName(op->Name, \"\");\n\t\t\t\tcodeGen->PrintDef(Header, op->Type.Ptr(), name);\n\t\t\t\tif (op->Type->IsInt() || op->Type->IsUInt())\n\t\t\t\t{\n\t\t\t\t\tHeader << \" = 0\";\n\t\t\t\t}\n\t\t\t\tHeader << \";\\n\";\n\t\t\t\tVarName.Add(op, name);\n\t\t\t\top->Name = name;\n\t\t\t\treturn op->Name;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/CLikeCodeGen.h",
    "content": "// CLikeCodeGen.h\n#ifndef SPIRE_C_LIKE_CODE_GEN_H\n#define SPIRE_C_LIKE_CODE_GEN_H\n\n//\n// This file implements the shared logic for code generation in C-like\n// languages, such as GLSL and HLSL.\n//\n\n#include \"CodeGenBackend.h\"\n#include \"../CoreLib/Tokenizer.h\"\n#include \"Syntax.h\"\n#include \"Naming.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tusing namespace CoreLib::Basic;\n\n\t\tILRecordType * ExtractRecordType(ILType * type);\n\t\tString AddWorldNameSuffix(String name, String suffix);\n\n\t\tclass CLikeCodeGen;\n\n\t\tclass ExternComponentCodeGenInfo\n\t\t{\n\t\tpublic:\n\t\t\tenum class DataStructureType\n\t\t\t{\n\t\t\t\tStandardInput, Patch\n\t\t\t};\n\t\t\tenum class SystemVarType\n\t\t\t{\n\t\t\t\tNone, TessCoord, InvocationId, ThreadId, FragCoord, PatchVertexCount, PrimitiveId, InstanceId,\n\t\t\t};\n\t\t\tDataStructureType DataStructure = DataStructureType::StandardInput;\n\t\t\tRefPtr<ILType> Type;\n\t\t\tSystemVarType SystemVar = SystemVarType::None;\n\t\t\tbool IsArray = false;\n\t\t\tint ArrayLength = 0;\n\t\t\tint Binding = -1;\n\t\t};\n\n\t\tclass CodeGenContext\n\t\t{\n\t\tpublic:\n\t\t\tCLikeCodeGen * codeGen;\n\t\t\tHashSet<String> GeneratedDefinitions;\n\t\t\tDictionary<String, String> SubstituteNames;\n\t\t\tDictionary<ILOperand*, String> VarName;\n\t\t\tCompileResult * Result = nullptr;\n\t\t\tHashSet<String> UsedVarNames;\n\t\t\tint BufferAllocator = 0;\n\t\t\tStringBuilder Body, Header, GlobalHeader;\n\t\t\tList<ILType*> Arguments;\n\t\t\tString ReturnVarName;\n\t\t\tHashSet<ExternComponentCodeGenInfo::SystemVarType> UsedSystemInputs;\n\n\t\t\tString GenerateCodeName(String name, String prefix)\n\t\t\t{\n\t\t\t\tStringBuilder nameBuilder;\n\t\t\t\tint startPos = 0;\n\t\t\t\tif (name.StartsWith(\"_sys_\"))\n\t\t\t\t\tstartPos = name.IndexOf('_', 5) + 1;\n\t\t\t\tnameBuilder << prefix;\n\t\t\t\tfor (int i = startPos; i < name.Length(); i++)\n\t\t\t\t{\n\t\t\t\t\tif ((name[i] >= 'a' && name[i] <= 'z') || \n\t\t\t\t\t\t(name[i] >= 'A' && name[i] <= 'Z') ||\n\t\t\t\t\t\tname[i] == '_' || \n\t\t\t\t\t\t(name[i] >= '0' && name[i] <= '9'))\n\t\t\t\t\t{\n\t\t\t\t\t\tnameBuilder << name[i];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tnameBuilder << '_';\n\t\t\t\t}\n\t\t\t\tauto rs = nameBuilder.ToString();\n\t\t\t\tint i = 0;\n\t\t\t\twhile (UsedVarNames.Contains(rs))\n\t\t\t\t{\n\t\t\t\t\ti++;\n\t\t\t\t\trs = nameBuilder.ToString() + String(i);\n\t\t\t\t}\n\t\t\t\tUsedVarNames.Add(rs);\n\n\t\t\t\treturn rs;\n\t\t\t}\n\n\n\t\t\tString DefineVariable(ILOperand * op);\n\t\t};\n\n\t\tclass OutputStrategy : public Object\n\t\t{\n\t\tprotected:\n\t\t\tCLikeCodeGen * codeGen = nullptr;\n\t\t\tILWorld * world = nullptr;\n\t\tpublic:\n\t\t\tOutputStrategy(CLikeCodeGen * pCodeGen, ILWorld * pWorld)\n\t\t\t{\n\t\t\t\tcodeGen = pCodeGen;\n\t\t\t\tworld = pWorld;\n\t\t\t}\n\n\t\t\tvirtual void DeclareOutput(CodeGenContext & ctx, ILStage * stage) = 0;\n\t\t\tvirtual void ProcessExportInstruction(CodeGenContext & ctx, ExportInstruction * instr) = 0;\n\t\t};\n\n\t\tclass CLikeCodeGen : public CodeGenBackend\n\t\t{\n\t\tprotected:\n\t\t\t//ILWorld * currentWorld = nullptr;\n\t\t\t//ILRecordType * currentRecordType = nullptr;\n\t\t\t//bool exportWriteToPackedBuffer = false;\n\t\t\tRefPtr<OutputStrategy> outputStrategy;\n\t\t\tDictionary<String, ExternComponentCodeGenInfo> extCompInfo;\n\t\t\tHashSet<String> intrinsicTextureFunctions;\n\t\t\tImportInstruction * currentImportInstr = nullptr;\n\t\t\tbool useBindlessTexture = false;\n\t\t\tDiagnosticSink * errWriter;\n\n\t\t\tvirtual OutputStrategy * CreateStandardOutputStrategy(ILWorld * world, String layoutPrefix) = 0;\n\t\t\tvirtual OutputStrategy * CreatePackedBufferOutputStrategy(ILWorld * world) = 0;\n\t\t\tvirtual OutputStrategy * CreateArrayOutputStrategy(ILWorld * world, bool pIsPatch, int pArraySize, String arrayIndex) = 0;\n\n\t\t\t// Hooks for declaring an input record based on the storage mode used (uniform, SSBO, etc.)\n\t\t\tvirtual void DeclareStandardInputRecord(CodeGenContext & sb, const ILObjectDefinition & input, bool isVertexShader) = 0;\n\t\t\tvirtual void DeclarePatchInputRecord(CodeGenContext & sb, const ILObjectDefinition & input, bool isVertexShader) = 0;\n\n\t\t\t// Hooks for generating per-stage kernels\n\t\t\tvirtual StageSource GenerateSingleWorldShader(ILProgram * program, ILShader * shader, ILStage * stage) = 0;\n\t\t\tvirtual StageSource GenerateHullShader(ILProgram * program, ILShader * shader, ILStage * stage) = 0;\n\n\t\t\tvirtual void PrintParameterReference(StringBuilder& sb, ILModuleParameterInstance * param) = 0;\n\n\t\t\t// Print a reference to some entity that is input to a kernel\n\t\t\tvirtual void PrintStandardInputReference(StringBuilder& sb, ILRecordType* recType, String inputName, String componentName) = 0;\n\t\t\tvirtual void PrintStandardArrayInputReference(StringBuilder& sb, ILRecordType* recType, String inputName, String componentName) = 0;\n\t\t\tvirtual void PrintPatchInputReference(StringBuilder& sb, ILRecordType* recType, String inputName, String componentName) = 0;\n\t\t\tvirtual void PrintDefaultInputReference(StringBuilder& sb, ILRecordType* recType, String inputName, String componentName) = 0;\n\t\t\tvirtual void PrintSystemVarReference(CodeGenContext & ctx, StringBuilder& sb, String inputName, ExternComponentCodeGenInfo::SystemVarType systemVar) = 0;\n\n\t\t\t//\n\t\t\tvirtual void PrintTypeName(StringBuilder& sb, ILType* type) = 0;\n\t\t\tvirtual void PrintCallInstrExprForTarget(CodeGenContext & ctx, CallInstruction * instr, String const& name);\n\t\t\tvirtual void PrintMatrixMulInstrExpr(CodeGenContext & ctx, ILOperand* op0, ILOperand* op1);\n\t\t\tvirtual void PrintRasterPositionOutputWrite(CodeGenContext & ctx, ILOperand * operand) = 0;\n\t\t\tvirtual void PrintTextureCall(CodeGenContext & ctx, CallInstruction * instr) = 0;\n\t\t\tvirtual void PrintProjectInstrExpr(CodeGenContext & ctx, ProjectInstruction * instr) = 0;\n\n\t\t\t// Helpers for printing call instructions\n\t\t\tvoid PrintDefaultCallInstrArgs(CodeGenContext & ctx, CallInstruction * instr);\n\t\t\tvoid PrintDefaultCallInstrExpr(CodeGenContext & ctx, CallInstruction * instr, String const& name);\n\n\t\tpublic:\n            DiagnosticSink* getSink() { return this->errWriter; }\n\t\t\tvoid PrintType(StringBuilder & sbCode, ILType* type);\n\n\t\t\tvoid PrintDef(StringBuilder & sbCode, ILType* type, const String & name);\n\n\t\t\tString GetFuncOriginalName(const String & name);\n\n\t\t\tvirtual void PrintOp(CodeGenContext & ctx, ILOperand * op, bool forceExpression = false);\n\t\t\tvoid PrintBinaryInstrExpr(CodeGenContext & ctx, BinaryInstruction * instr);\n\t\t\tvoid PrintBinaryInstr(CodeGenContext & ctx, BinaryInstruction * instr);\n\t\t\tvoid PrintUnaryInstrExpr(CodeGenContext & ctx, UnaryInstruction * instr);\n\t\t\tvoid PrintUnaryInstr(CodeGenContext & ctx, UnaryInstruction * instr);\n\t\t\tvoid PrintAllocVarInstrExpr(CodeGenContext & ctx, AllocVarInstruction * instr);\n\t\t\tvoid PrintAllocVarInstr(CodeGenContext & ctx, AllocVarInstruction * instr);\n\t\t\tvoid PrintFetchArgInstrExpr(CodeGenContext & ctx, FetchArgInstruction * instr);\n\t\t\tvoid PrintFetchArgInstr(CodeGenContext & ctx, FetchArgInstruction * instr);\n\t\t\tvoid PrintSelectInstrExpr(CodeGenContext & ctx, SelectInstruction * instr);\n\t\t\tvoid PrintSelectInstr(CodeGenContext & ctx, SelectInstruction * instr);\n\t\t\tvoid PrintCallInstrExpr(CodeGenContext & ctx, CallInstruction * instr);\n\t\t\tvoid PrintCallInstr(CodeGenContext & ctx, CallInstruction * instr);\n\t\t\tvoid PrintCastF2IInstrExpr(CodeGenContext & ctx, Float2IntInstruction * instr);\n\t\t\tvoid PrintCastF2IInstr(CodeGenContext & ctx, Float2IntInstruction * instr);\n\t\t\tvoid PrintCastI2FInstrExpr(CodeGenContext & ctx, Int2FloatInstruction * instr);\n\t\t\tvoid PrintCastI2FInstr(CodeGenContext & ctx, Int2FloatInstruction * instr);\n\t\t\tbool AppearAsExpression(ILInstruction & instr, bool force);\n\t\t\tvoid PrintExportInstr(CodeGenContext &ctx, ExportInstruction * exportInstr);\n\t\t\tvoid PrintUpdateInstr(CodeGenContext & ctx, MemberUpdateInstruction * instr);\n\t\t\tvoid PrintSwizzleInstrExpr(CodeGenContext & ctx, SwizzleInstruction * swizzle);\n\t\t\tvoid PrintImportInstr(CodeGenContext & ctx, ImportInstruction * importInstr);\n\t\t\tvoid PrintImportInstrExpr(CodeGenContext & ctx, ImportInstruction * importInstr);\n\t\t\tvoid PrintInstrExpr(CodeGenContext & ctx, ILInstruction & instr);\n\t\t\tvoid PrintInstr(CodeGenContext & ctx, ILInstruction & instr);\n\t\t\tvoid PrintLoadInputInstrExpr(CodeGenContext & ctx, LoadInputInstruction * instr);\n\t\t\tvoid GenerateCode(CodeGenContext & context, CFGNode * code);\n\n\t\tpublic:\n\t\t\tCLikeCodeGen();\n\t\t\tvirtual void GenerateShaderMetaData(ShaderMetaData & result, ILProgram* program, ILShader * shader, DiagnosticSink * err);\n\t\t\tvirtual CompiledShaderSource GenerateShader(CompileResult & result, SymbolTable *, ILShader * shader, DiagnosticSink * err) override;\n\t\t\tvoid GenerateStructs(StringBuilder & sb, ILProgram * program);\n\t\t\tvoid GenerateReferencedFunctions(StringBuilder & sb, ILProgram * program, ArrayView<ILWorld*> worlds);\n\t\t\tExternComponentCodeGenInfo ExtractExternComponentInfo(const ILObjectDefinition & input);\n\t\t\tvoid PrintInputReference(CodeGenContext & ctx, StringBuilder & sb, String input);\n\t\t\tvoid DeclareInput(CodeGenContext & sb, const ILObjectDefinition & input, bool isVertexShader);\n\n\t\t\tvoid GenerateVertexShaderEpilog(CodeGenContext & ctx, ILWorld * world, ILStage * stage);\n\n\t\t\tStageSource GenerateVertexFragmentDomainShader(ILProgram * program, ILShader * shader, ILStage * stage);\n\t\t\tStageSource GenerateComputeShader(ILProgram * program, ILShader * shader, ILStage * stage);\n\t\t\tvoid GenerateFunctionDeclaration(StringBuilder & sbCode, ILFunction * function);\n\t\t\tString GenerateFunction(ILFunction * function);\n\t\t};\n\t}\n}\n\n#endif // SPIRE_C_LIKE_CODE_GEN_H\n"
  },
  {
    "path": "Source/SpireCore/Closure.cpp",
    "content": "#include \"Closure.h\"\n#include \"StringObject.h\"\n#include \"Naming.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tvoid CheckComponentRedefinition(DiagnosticSink * err, ShaderClosure * parent, ShaderClosure * child)\n\t\t{\n\t\t\tfor (auto & comp : child->Components)\n\t\t\t{\n\t\t\t\tRefPtr<ShaderComponentSymbol> ccomp;\n\t\t\t\tRefPtr<ShaderClosure> su;\n\t\t\t\tif ((comp.Value->Implementations.First()->SyntaxNode->IsPublic() ||\n\t\t\t\t\tcomp.Value->Implementations.First()->SyntaxNode->IsOutput()))\n\t\t\t\t{\n                    if (parent->Components.TryGetValue(comp.Key, ccomp))\n                    {\n\t\t\t\t\t\terr->diagnose(comp.Value->Implementations.First()->SyntaxNode, Diagnostics::nameAlreadyDefinedInCurrentScope, comp.Key);\n                        err->diagnose(ccomp->Implementations.First()->SyntaxNode, Diagnostics::seePreviousDefinition);\n                    }\n                    else if (parent->SubClosures.TryGetValue(comp.Key, su))\n                    {\n\t\t\t\t\t\terr->diagnose(comp.Value->Implementations.First()->SyntaxNode->Position, Diagnostics::nameAlreadyDefinedInCurrentScope, comp.Key);\n                        err->diagnose(su->UsingPosition, Diagnostics::seePreviousDefinition);\n                    }\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (auto & c : child->SubClosures)\n\t\t\t{\n\t\t\t\tif (c.Value->IsInPlace)\n\t\t\t\t{\n\t\t\t\t\tRefPtr<ShaderComponentSymbol> ccomp;\n\t\t\t\t\tRefPtr<ShaderClosure> su;\n                    if (parent->Components.TryGetValue(c.Key, ccomp))\n                    {\n                        err->diagnose(c.Value->UsingPosition, Diagnostics::nameAlreadyDefinedInCurrentScope, c.Key);\n                        err->diagnose(ccomp->Implementations.First()->SyntaxNode, Diagnostics::seePreviousDefinition);\n                    }\n                    else if (parent->SubClosures.TryGetValue(c.Key, su))\n                    {\n                        err->diagnose(c.Value->UsingPosition, Diagnostics::nameAlreadyDefinedInCurrentScope, c.Key);\n                        err->diagnose(su->UsingPosition, Diagnostics::seePreviousDefinition);\n                    }\n\t\t\t\t\tfor (auto & sc : c.Value->SubClosures)\n\t\t\t\t\t\tif (sc.Value->IsInPlace)\n\t\t\t\t\t\t\tCheckComponentRedefinition(err, parent, sc.Value.Ptr());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tRefPtr<ShaderClosure> CreateShaderClosure(DiagnosticSink * err, SymbolTable * symTable, ShaderSymbol * shader, CodePosition usingPos, \n\t\t\tShaderClosure * rootShader,\n\t\t\tconst EnumerableDictionary<String, RefPtr<ShaderComponentSymbol>>& pRefMap)\n\t\t{\n\t\t\tRefPtr<ShaderClosure> rs = new ShaderClosure();\n\t\t\tif (rootShader == nullptr)\n\t\t\t{\n\t\t\t\trootShader = rs.Ptr();\n\t\t\t\trootShader->Pipeline = shader->ParentPipeline;\n\t\t\t}\n\t\t\trs->ModuleSyntaxNode = shader->SyntaxNode.Ptr();\n\t\t\trs->Name = shader->SyntaxNode->Name.Content;\n\t\t\trs->RefMap = pRefMap;\n\t\t\tif (shader->ParentPipeline && rootShader->Pipeline)\n\t\t\t{\n\t\t\t\tif (shader->ParentPipeline->IsChildOf(rootShader->Pipeline))\n\t\t\t\t\trootShader->Pipeline = shader->ParentPipeline;\n\t\t\t\telse if (!rootShader->Pipeline->IsChildOf(shader->ParentPipeline))\n\t\t\t\t{\n                    err->diagnose(shader->SyntaxNode->Position, Diagnostics::pipelineOfModuleIncompatibleWithPipelineOfShader,\n                        shader->ParentPipeline->SyntaxNode->Name,\n                        shader->SyntaxNode->Name.Content,\n                        rootShader->Pipeline->SyntaxNode->Name.Content,\n                        rootShader->Name);\n                    err->diagnose(shader->SyntaxNode->Position, Diagnostics::seeDefinitionOfShader, shader->SyntaxNode->Name);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\trs->Pipeline = rootShader->Pipeline;\n\t\t\trs->UsingPosition = usingPos;\n\t\t\trs->Position = shader->SyntaxNode->Position;\n\t\t\tfor (auto & mbr : shader->SyntaxNode->Members)\n\t\t\t{\n\t\t\t\tif (auto import = dynamic_cast<ImportSyntaxNode*>(mbr.Ptr()))\n\t\t\t\t{\n\t\t\t\t\t// create component for each argument\n\t\t\t\t\tEnumerableDictionary<String, RefPtr<ShaderComponentSymbol>> refMap;\n\t\t\t\t\tfor (auto & arg : import->Arguments)\n\t\t\t\t\t{\n\t\t\t\t\t\tRefPtr<ShaderComponentSymbol> ccomp = new ShaderComponentSymbol();\n\t\t\t\t\t\tauto compName = \"arg\" + String(rs->Components.Count()) + \"_\" + \n\t\t\t\t\t\t\t(import->ObjectName.Content.Length()==0?import->ShaderName.Content:import->ObjectName.Content) + arg->ArgumentName.Content;\n\t\t\t\t\t\tauto impl = new ShaderComponentImplSymbol();\n\t\t\t\t\t\tauto compSyntax = new ComponentSyntaxNode();\n\t\t\t\t\t\tcompSyntax->Position = arg->Expression->Position;\n\t\t\t\t\t\tcompSyntax->Name.Content = compName;\n\t\t\t\t\t\tCloneContext cloneCtx;\n\t\t\t\t\t\tcompSyntax->Expression = arg->Expression->Clone(cloneCtx);\n\t\t\t\t\t\tcompSyntax->TypeNode = new BasicTypeSyntaxNode();\n\t\t\t\t\t\tcompSyntax->TypeNode->Position = compSyntax->Position;\n\t\t\t\t\t\timpl->SyntaxNode = compSyntax;\n\t\t\t\t\t\tccomp->Name = compName;\n\t\t\t\t\t\tccomp->Type = new Type();\n\t\t\t\t\t\tccomp->Type->DataType = arg->Expression->Type;\n\t\t\t\t\t\tccomp->Implementations.Add(impl);\n\t\t\t\t\t\trs->Components[compName] = ccomp;\n\t\t\t\t\t\trefMap[arg->ArgumentName.Content] = ccomp;\n\t\t\t\t\t}\n\t\t\t\t\tRefPtr<ShaderSymbol> shaderSym;\n\t\t\t\t\tif (symTable->Shaders.TryGetValue(import->ShaderName.Content, shaderSym))\n\t\t\t\t\t{\n\t\t\t\t\t\t// fill in automatic arguments\n\t\t\t\t\t\tfor (auto & param : shaderSym->Components)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (param.Value->IsRequire() && !refMap.ContainsKey(param.Key))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tauto arg = rs->FindComponent(param.Key);\n\t\t\t\t\t\t\t\tif (arg && arg->Type->DataType->Equals(param.Value->Type->DataType.Ptr()))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\trefMap[param.Key] = arg;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tauto refClosure = CreateShaderClosure(err, symTable, shaderSym.Ptr(), import->Position, rootShader, refMap);\n\t\t\t\t\t\trefClosure->IsPublic = import->IsPublic();\n\t\t\t\t\t\trefClosure->Parent = rs.Ptr();\n\t\t\t\t\t\tToken bindingVal;\n\t\t\t\t\t\tif (import->FindSimpleAttribute(\"Binding\", bindingVal))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\trefClosure->BindingIndex = StringToInt(bindingVal.Content);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (import->IsInplace)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\trefClosure->IsInPlace = true;\n\t\t\t\t\t\t\tCheckComponentRedefinition(err, rs.Ptr(), refClosure.Ptr());\n\t\t\t\t\t\t\trs->SubClosures[\"annonymousObj\" + String(UniqueIdGenerator::Next())] = refClosure;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\trefClosure->Name = import->ObjectName.Content;\n\t\t\t\t\t\t\trs->SubClosures[import->ObjectName.Content] = refClosure;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (auto compt = dynamic_cast<ComponentSyntaxNode*>(mbr.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tRefPtr<ShaderComponentSymbol> comp;\n\t\t\t\t\tif (shader->Components.TryGetValue(compt->Name.Content, comp) &&\n\t\t\t\t\t\t!rs->Components.ContainsKey(compt->Name.Content))\n\t\t\t\t\t{\n\t\t\t\t\t\tRefPtr<ShaderComponentSymbol> ccomp = new ShaderComponentSymbol(*comp);\n\t\t\t\t\t\trs->Components.Add(comp->Name, ccomp);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// check for unassigned arguments\n\t\t\tfor (auto & comp : shader->Components)\n\t\t\t{\n\t\t\t\tif (comp.Value->Implementations.First()->SyntaxNode->IsRequire() &&\n\t\t\t\t\t!pRefMap.ContainsKey(comp.Key))\n\t\t\t\t{\n                    err->diagnose(rs->UsingPosition, Diagnostics::parameterOfModuleIsUnassigned, comp.Key, shader->SyntaxNode->Name);\n\t\t\t\t\t// try to provide more info on why it is unassigned\n\t\t\t\t\tauto arg = rootShader->FindComponent(comp.Key, true, false);\n                    if (!arg)\n                        err->diagnose(rootShader, Diagnostics::implicitParameterMatchingFailedBecauseShaderDoesNotDefineComponent,\n                            rootShader->Name,\n                            comp.Key);\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (comp.Value->Type->DataType->Equals(arg->Type->DataType.Ptr()))\n\t\t\t\t\t\t{\n                            err->diagnose(rs->UsingPosition, Diagnostics::implicitParameterMatchingFailedBecauseNameNotAccessible, shader->SyntaxNode->Name);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n                            err->diagnose(rs->UsingPosition, Diagnostics::implicitParameterMatchingFailedBecauseTypeMismatch, comp.Value->Type->DataType);\n\t\t\t\t\t\t}\n                        err->diagnose(comp.Value->Implementations.First()->SyntaxNode, Diagnostics::seeRequirementDeclaration);\n                        err->diagnose(arg->Implementations.First()->SyntaxNode, Diagnostics::seePotentialDefinitionOfComponent, comp.Key);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\n\t\tRefPtr<ShaderClosure> CreateShaderClosure(DiagnosticSink * err, SymbolTable * symTable, ShaderSymbol * shader)\n\t\t{\n\t\t\treturn CreateShaderClosure(err, symTable, shader, shader->SyntaxNode->Position, nullptr, EnumerableDictionary<String, RefPtr<ShaderComponentSymbol>>());\n\t\t}\n\n\t\tclass ReplaceReferenceVisitor : public SyntaxVisitor\n\t\t{\n\t\tprivate:\n\t\t\tShaderClosure * shaderClosure = nullptr;\n\t\t\tShaderComponentSymbol * currentComponent = nullptr;\n\t\t\tImportExpressionSyntaxNode * currentImport = nullptr;\n\t\t\tvoid ReplaceReference(RefPtr<StringObject> refComp)\n\t\t\t{\n\t\t\t\tString targetComp;\n\t\t\t\tif ((*replacements).TryGetValue(refComp->Content, targetComp))\n\t\t\t\t{\n\t\t\t\t\tauto oldComp = shaderClosure->AllComponents[refComp->Content]().Symbol;\n\t\t\t\t\tauto newComp = shaderClosure->AllComponents[targetComp]().Symbol;\n\t\t\t\t\tif (auto * importOps = currentComponent->DependentComponents.TryGetValue(newComp))\n\t\t\t\t\t\timportOps->Add(currentImport);\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tEnumerableHashSet<RefPtr<ImportExpressionSyntaxNode>> op;\n\t\t\t\t\t\top.Add(currentImport);\n\t\t\t\t\t\tcurrentComponent->DependentComponents.Add(newComp, op);\n\t\t\t\t\t}\n\t\t\t\t\tcurrentComponent->DependentComponents.Remove(oldComp);\n\t\t\t\t\tif (auto * importOps = currentImpl->DependentComponents.TryGetValue(newComp))\n\t\t\t\t\t\timportOps->Add(currentImport);\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tEnumerableHashSet<RefPtr<ImportExpressionSyntaxNode>> op;\n\t\t\t\t\t\top.Add(currentImport);\n\t\t\t\t\t\tcurrentImpl->DependentComponents.Add(newComp, op);\n\t\t\t\t\t}\n\t\t\t\t\tcurrentImpl->DependentComponents.Remove(oldComp);\n\t\t\t\t\tcurrentImpl->ComponentReferencePositions[newComp] = currentImpl->ComponentReferencePositions[oldComp]();\n\t\t\t\t\trefComp->Content = newComp->UniqueName;\n\t\t\t\t}\n\t\t\t}\n\t\tpublic:\n\t\t\tShaderComponentImplSymbol * currentImpl = nullptr;\n\t\t\tEnumerableDictionary<String, String> * replacements;\n\t\t\tReplaceReferenceVisitor(ShaderClosure * closure, ShaderComponentSymbol * comp, EnumerableDictionary<String, String> &pReplacements)\n\t\t\t\t: SyntaxVisitor(nullptr), shaderClosure(closure), currentComponent(comp), replacements(&pReplacements)\n\t\t\t{}\n\n\t\t\tRefPtr<ExpressionSyntaxNode> VisitImportExpression(ImportExpressionSyntaxNode * import) override\n\t\t\t{\n\t\t\t\tcurrentImport = import;\n\t\t\t\timport->Component->Accept(this);\n\t\t\t\tif (import->Component->Tags.ContainsKey(\"ComponentReference\"))\n\t\t\t\t{\n\t\t\t\t\timport->ComponentUniqueName = import->Component->Tags[\"ComponentReference\"]().As<StringObject>()->Content;\n\t\t\t\t}\n\t\t\t\tcurrentImport = nullptr;\n\t\t\t\tfor (auto & arg : import->Arguments)\n\t\t\t\t\targ->Accept(this);\n\t\t\t\treturn import;\n\t\t\t}\n\n\t\t\tRefPtr<ExpressionSyntaxNode> VisitVarExpression(VarExpressionSyntaxNode * var) override\n\t\t\t{\n\t\t\t\tRefPtr<Object> compRef;\n\t\t\t\tif (var->Tags.TryGetValue(\"ComponentReference\", compRef))\n\t\t\t\t{\n\t\t\t\t\tReplaceReference(compRef.As<StringObject>());\n\t\t\t\t}\n\t\t\t\treturn var;\n\t\t\t}\n\n\t\t\tRefPtr<ExpressionSyntaxNode> VisitMemberExpression(MemberExpressionSyntaxNode * member) override\n\t\t\t{\n\t\t\t\tmember->BaseExpression->Accept(this);\n\t\t\t\tRefPtr<Object> compRef;\n\t\t\t\tif (member->Tags.TryGetValue(\"ComponentReference\", compRef))\n\t\t\t\t{\n\t\t\t\t\tReplaceReference(compRef.As<StringObject>());\n\t\t\t\t}\n\t\t\t\treturn member;\n\t\t\t}\n\t\t};\n\n\t\tclass ResolveDependencyVisitor : public SyntaxVisitor\n\t\t{\n\t\tprivate:\n\t\t\tShaderClosure * shaderClosure = nullptr, *rootShader = nullptr;\n\t\t\tShaderComponentSymbol * currentComponent = nullptr;\n\t\t\tImportExpressionSyntaxNode * currentImport = nullptr;\n\t\t\tvoid AddReference(ShaderComponentSymbol * referee, ImportExpressionSyntaxNode * importOp, CodePosition pos)\n\t\t\t{\n\t\t\t\tComponentInstance referedCompInst;\n\t\t\t\tif (rootShader->AllComponents.TryGetValue(referee->UniqueName, referedCompInst))\n\t\t\t\t\treferee = referedCompInst.Symbol;\n\t\t\t\tif (auto * importOps = currentComponent->DependentComponents.TryGetValue(referee))\n\t\t\t\t\timportOps->Add(importOp);\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tEnumerableHashSet<RefPtr<ImportExpressionSyntaxNode>> op;\n\t\t\t\t\top.Add(importOp);\n\t\t\t\t\tcurrentComponent->DependentComponents.Add(referee, op);\n\t\t\t\t}\n\n\t\t\t\tif (auto * importOps = currentImpl->DependentComponents.TryGetValue(referee))\n\t\t\t\t\timportOps->Add(importOp);\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tEnumerableHashSet<RefPtr<ImportExpressionSyntaxNode>> op;\n\t\t\t\t\top.Add(importOp);\n\t\t\t\t\tcurrentImpl->DependentComponents.Add(referee, op);\n\t\t\t\t}\n\t\t\t\tcurrentImpl->ComponentReferencePositions[referee] = pos;\n\t\t\t}\n\t\tpublic:\n\t\t\tShaderComponentImplSymbol * currentImpl = nullptr;\n\n\t\t\tResolveDependencyVisitor(DiagnosticSink * err, ShaderClosure * pRootShader, ShaderClosure * closure, ShaderComponentSymbol * comp)\n\t\t\t\t: SyntaxVisitor(err), shaderClosure(closure), rootShader(pRootShader), currentComponent(comp)\n\t\t\t{}\n\n\t\t\tRefPtr<ExpressionSyntaxNode> VisitImportExpression(ImportExpressionSyntaxNode * import) override\n\t\t\t{\n\t\t\t\tcurrentImport = import;\n\t\t\t\timport->Component->Accept(this);\n\t\t\t\tif (!import->Component->Tags.ContainsKey(\"ComponentReference\"))\n\t\t\t\t{\n\t\t\t\t\tgetSink()->diagnose(import->Component.Ptr(), Diagnostics::firstArgumentToImportNotComponent);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\timport->ComponentUniqueName = import->Component->Tags[\"ComponentReference\"]().As<StringObject>()->Content;\n\t\t\t\t}\n\t\t\t\tcurrentImport = nullptr;\n\t\t\t\tfor (auto & arg : import->Arguments)\n\t\t\t\t\targ->Accept(this);\n\t\t\t\timport->ImportOperatorDef->Accept(this);\n\t\t\t\treturn import;\n\t\t\t}\n\n\t\t\tRefPtr<ExpressionSyntaxNode> VisitVarExpression(VarExpressionSyntaxNode * var) override\n\t\t\t{\n                if (auto decl = var->Scope->LookUp(var->Variable))\n                {\n                    // TODO(tfoley): wire up the variable to the declaration\n\t\t\t\t\tif (dynamic_cast<VarDeclBase*>(decl)) // make sure this is a ordinary variable (currently ComponentSyntaxNode is not VarDeclBase)\n\t\t\t\t\t\treturn var;\n                }\n                // Otherwise look in other places...\n\t\t\t\tif (var->Type->AsBasicType() && var->Type->AsBasicType()->Component)\n\t\t\t\t{\n\t\t\t\t\tif (auto comp = shaderClosure->FindComponent(var->Type->AsBasicType()->Component->Name))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (comp->Implementations.First()->SyntaxNode->IsRequire())\n\t\t\t\t\t\t\tshaderClosure->RefMap.TryGetValue(comp->Name, comp);\n\t\t\t\t\t\tvar->Tags[\"ComponentReference\"] = new StringObject(comp->UniqueName);\n\t\t\t\t\t\tAddReference(comp.Ptr(), currentImport, var->Position);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow InvalidProgramException(\"cannot resolve reference.\");\n\t\t\t\t}\n\t\t\t\tif (auto comp = shaderClosure->FindComponent(var->Variable))\n\t\t\t\t{\n\t\t\t\t\tif (comp->Implementations.First()->SyntaxNode->IsRequire())\n\t\t\t\t\t\tshaderClosure->RefMap.TryGetValue(var->Variable, comp);\n\t\t\t\t\tvar->Tags[\"ComponentReference\"] = new StringObject(comp->UniqueName);\n\n\t\t\t\t\tAddReference(comp.Ptr(), currentImport, var->Position);\n\t\t\t\t}\n\t\t\t\telse if (auto closure = shaderClosure->FindClosure(var->Variable))\n\t\t\t\t{\n\t\t\t\t\tShaderSymbol * originalShader = nullptr;\n\t\t\t\t\tif (var->Type->AsBasicType())\n\t\t\t\t\t\toriginalShader = var->Type->AsBasicType()->Shader;\n\t\t\t\t\tvar->Type = new BasicExpressionType(originalShader, closure.Ptr());\n\t\t\t\t}\n\t\t\t\telse if (!(var->Type->AsBasicType() && var->Type->AsBasicType()->BaseType == BaseType::Function))\n\t\t\t\t\tthrow InvalidProgramException(\"cannot resolve reference.\");\n\t\t\t\treturn var;\n\t\t\t}\n\n\t\t\tRefPtr<ExpressionSyntaxNode> VisitMemberExpression(MemberExpressionSyntaxNode * member) override\n\t\t\t{\n\t\t\t\tmember->BaseExpression->Accept(this);\n\t\t\t\tif (member->BaseExpression->Type->AsBasicType() && member->BaseExpression->Type->AsBasicType()->ShaderClosure)\n\t\t\t\t{\n\t\t\t\t\tString memberName = member->MemberName;\n                    // HACK(tfoley): Is this a valid fix?\n                    if(member->Type->AsBasicType())\n\t\t\t\t\tif (auto refComp = member->Type->AsBasicType()->Component)\n\t\t\t\t\t{\n\t\t\t\t\t\tmemberName = refComp->Name;\n\t\t\t\t\t}\n\t\t\t\t\tif (auto comp = member->BaseExpression->Type->AsBasicType()->ShaderClosure->FindComponent(memberName))\n\t\t\t\t\t{\n\t\t\t\t\t\tmember->Tags[\"ComponentReference\"] = new StringObject(comp->UniqueName);\n\t\t\t\t\t\tAddReference(comp.Ptr(), currentImport, member->Position);\n\t\t\t\t\t}\n\t\t\t\t\telse if (auto shader = member->BaseExpression->Type->AsBasicType()->ShaderClosure->FindClosure(memberName))\n\t\t\t\t\t{\n\t\t\t\t\t\tShaderSymbol * originalShader = nullptr;\n\t\t\t\t\t\tif (member->Type->AsBasicType())\n\t\t\t\t\t\t\toriginalShader = member->Type->AsBasicType()->Shader;\n\t\t\t\t\t\tmember->Type = new BasicExpressionType(originalShader, shader.Ptr());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (member->Type->AsBasicType() && member->Type->AsBasicType()->Component)\n\t\t\t\t{\n\t\t\t\t\tif (auto comp = shaderClosure->FindComponent(member->Type->AsBasicType()->Component->Name))\n\t\t\t\t\t{\n\t\t\t\t\t\tmember->Tags[\"ComponentReference\"] = new StringObject(comp->UniqueName);\n\t\t\t\t\t\tAddReference(comp.Ptr(), currentImport, member->Position);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow InvalidProgramException(\"cannot resolve reference.\");\n\t\t\t\t}\n\t\t\t\treturn member;\n\t\t\t}\n\t\t};\n\n\t\tvoid ResolveReference(DiagnosticSink * err, ShaderClosure * rootShader, ShaderClosure* shader)\n\t\t{\n\t\t\tfor (auto & comp : shader->Components)\n\t\t\t{\n\t\t\t\tResolveDependencyVisitor depVisitor(err, rootShader, shader, comp.Value.Ptr());\n\t\t\t\tfor (auto & impl : comp.Value->Implementations)\n\t\t\t\t{\n\t\t\t\t\tdepVisitor.currentImpl = impl.Ptr();\n\t\t\t\t\timpl->SyntaxNode->Accept(&depVisitor);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (auto & subClosure : shader->SubClosures)\n\t\t\t\tResolveReference(err, rootShader, subClosure.Value.Ptr());\n\t\t}\n\n\t\tvoid ReplaceRefMapReference(ShaderClosure * root, ShaderClosure * shader, EnumerableDictionary<String, String> & replacements)\n\t\t{\n\t\t\tfor (auto & map : shader->RefMap)\n\t\t\t{\n\t\t\t\tString newName = map.Value->UniqueName;\n\t\t\t\twhile (replacements.TryGetValue(newName, newName))\n\t\t\t\t{\n\t\t\t\t}\n\t\t\t\tif (newName != map.Value->UniqueName)\n\t\t\t\t\tmap.Value = root->AllComponents[newName]().Symbol;\n\t\t\t}\n\t\t\tfor (auto & subclosure : shader->SubClosures)\n\t\t\t\tReplaceRefMapReference(root, subclosure.Value.Ptr(), replacements);\n\t\t}\n\n\n\t\tvoid ReplaceReference(ShaderClosure * shader, EnumerableDictionary<String, String> & replacements)\n\t\t{\n\t\t\tReplaceRefMapReference(shader, shader, replacements);\n\t\t\tfor (auto & comp : shader->AllComponents)\n\t\t\t{\n\t\t\t\tReplaceReferenceVisitor replaceVisitor(shader, comp.Value.Symbol, replacements);\n\t\t\t\tfor (auto & impl : comp.Value.Symbol->Implementations)\n\t\t\t\t{\n\t\t\t\t\treplaceVisitor.currentImpl = impl.Ptr();\n\t\t\t\t\timpl->SyntaxNode->Accept(&replaceVisitor);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbool IsInAbstractWorld(PipelineSymbol * pipeline, ShaderComponentSymbol* comp)\n\t\t{\n\t\t\treturn comp->Implementations.First()->Worlds.Count() && !comp->Implementations.First()->SyntaxNode->IsRequire() &&\n\t\t\t\tpipeline->IsAbstractWorld(comp->Implementations.First()->Worlds.First());\n\t\t}\n\n\t\tvoid AssignUniqueNames(ShaderClosure * shader, String namePrefix, String publicNamePrefix)\n\t\t{\n\t\t\tfor (auto & comp : shader->Components)\n\t\t\t{\n\t\t\t\tif (IsInAbstractWorld(shader->Pipeline, comp.Value.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tcomp.Value->UniqueKey = comp.Value->UniqueName = comp.Value->Name;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tString uniqueChoiceName;\n\t\t\t\t\tif (comp.Value->Implementations.First()->SyntaxNode->IsPublic())\n\t\t\t\t\t\tuniqueChoiceName = publicNamePrefix + comp.Key;\n\t\t\t\t\telse\n\t\t\t\t\t\tuniqueChoiceName = namePrefix + comp.Key;\n\t\t\t\t\tcomp.Value->ChoiceNames.Add(uniqueChoiceName);\n\t\t\t\t\tcomp.Value->UniqueKey = uniqueChoiceName;\n\t\t\t\t\tcomp.Value->UniqueName = EscapeCodeName(uniqueChoiceName);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (auto & subClosure : shader->SubClosures)\n\t\t\t{\n\t\t\t\tif (subClosure.Value->IsInPlace)\n\t\t\t\t\tAssignUniqueNames(subClosure.Value.Ptr(), namePrefix + subClosure.Value->Name + \".\", publicNamePrefix);\n\t\t\t\telse\n\t\t\t\t\tAssignUniqueNames(subClosure.Value.Ptr(), namePrefix + subClosure.Key + \".\", publicNamePrefix + subClosure.Key + \".\");\n\t\t\t}\n\t\t}\n\n\t\tbool IsConsistentGlobalComponentDefinition(ShaderComponentSymbol * comp0, ShaderComponentSymbol * comp1)\n\t\t{\n\t\t\tif (comp0->Type->DataType != comp1->Type->DataType)\n\t\t\t\treturn false;\n\t\t\tif (comp0->Implementations.First()->Worlds.Count() != comp1->Implementations.First()->Worlds.Count())\n\t\t\t\treturn false;\n\t\t\tfor (auto w : comp0->Implementations.First()->Worlds)\n\t\t\t\tif (!comp1->Implementations.First()->Worlds.Contains(w))\n\t\t\t\t\treturn false;\n\t\t\treturn true;\n\t\t}\n\n\t\tvoid GatherComponents(DiagnosticSink * err, ShaderClosure * closure, ShaderClosure * subClosure)\n\t\t{\n\t\t\tfor (auto & comp : subClosure->Components)\n\t\t\t{\n\t\t\t\tShaderComponentSymbol* existingComp = nullptr;\n\t\t\t\tif (comp.Value->IsRequire())\n\t\t\t\t\tcontinue;\n\t\t\t\tComponentInstance existingCompInst;\n\t\t\t\tif (closure->AllComponents.TryGetValue(comp.Value->UniqueName, existingCompInst))\n\t\t\t\t{\n\t\t\t\t\texistingComp = existingCompInst.Symbol;\n\t\t\t\t\tif (IsInAbstractWorld(closure->Pipeline, comp.Value.Ptr()) &&\n\t\t\t\t\t\tIsInAbstractWorld(closure->Pipeline, existingComp))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!IsConsistentGlobalComponentDefinition(comp.Value.Ptr(), existingComp))\n\t\t\t\t\t\t{\n                            err->diagnose(comp.Value->Implementations.First()->SyntaxNode, Diagnostics::globalComponentConflictWithPreviousDeclaration, existingComp->Name);\n                            err->diagnose(existingComp->Implementations.First()->SyntaxNode, Diagnostics::seePreviousDefinition);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n    \t\t\t\t\t\t// silently ignore consistently defined global components (components in abstract worlds)\n\t\t\t\t\t\t\terr->diagnose(comp.Value->Implementations.First()->SyntaxNode, Diagnostics::componentIsAlreadyDefinedUseRequire, existingComp->Name, closure->Name);\n                            err->diagnose(existingComp->Implementations.First()->SyntaxNode, Diagnostics::seePreviousDefinition);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (!comp.Value->Implementations.First()->SyntaxNode->IsComponentFunction())\n\t\t\t\t\t{\n\t\t\t\t\t\terr->diagnose(comp.Value->Implementations.First()->SyntaxNode, Diagnostics::componentAlreadyDefinedWhenCompiling, comp.Value->UniqueKey, closure->Name);\n\t\t\t\t\t\tauto currentClosure = subClosure;\n\t\t\t\t\t\twhile (currentClosure != nullptr && currentClosure != closure)\n\t\t\t\t\t\t{\n                            err->diagnose(currentClosure->UsingPosition, Diagnostics::seeInclusionOf, currentClosure->Name);\n\t\t\t\t\t\t\tcurrentClosure = currentClosure->Parent;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tclosure->AllComponents[comp.Value->UniqueName] = ComponentInstance(subClosure, comp.Value.Ptr());\n\t\t\t}\n\t\t\tfor (auto & sc : subClosure->SubClosures)\n\t\t\t\tGatherComponents(err, closure, sc.Value.Ptr());\n\t\t}\n\n\t\tbool IsWorldFeasible(SymbolTable * symTable, PipelineSymbol * pipeline, ShaderComponentImplSymbol * impl, String world, ShaderComponentSymbol*& unaccessibleComp)\n\t\t{\n\t\t\t// shader parameter (uniform values) are available to all worlds\n\t\t\tif (impl->SyntaxNode->IsParam())\n\t\t\t\treturn true;\n\t\t\tbool isWFeasible = true;\n\t\t\tfor (auto & dcomp : impl->DependentComponents)\n\t\t\t{\n\t\t\t\tif (dcomp.Value.Contains(nullptr))\n\t\t\t\t{\n\t\t\t\t\tbool reachable = false;\n\t\t\t\t\tfor (auto & dw : dcomp.Key->Type->FeasibleWorlds)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (symTable->IsWorldImplicitlyReachable(pipeline, dw, world, dcomp.Key->Type->DataType))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treachable = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!reachable)\n\t\t\t\t\t{\n\t\t\t\t\t\tunaccessibleComp = dcomp.Key;\n\t\t\t\t\t\tisWFeasible = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn isWFeasible;\n\t\t}\n\n\t\tvoid SolveWorldConstraints(DiagnosticSink * err, SymbolTable * symTable, ShaderClosure * shader)\n\t\t{\n\t\t\tEnumerableHashSet<String> allWorlds;\n\t\t\tfor (auto w : shader->Pipeline->Worlds)\n\t\t\t\tif (!shader->Pipeline->IsAbstractWorld(w.Key))\n\t\t\t\t\tallWorlds.Add(w.Key);\n\t\t\tauto depOrder = shader->GetDependencyOrder();\n\t\t\tfor (auto & comp : depOrder)\n\t\t\t{\n\t\t\t\tcomp->Type->FeasibleWorlds.Clear();\n\t\t\t\tfor (auto & impl : comp->Implementations)\n\t\t\t\t{\n\t\t\t\t\tauto autoWorld = allWorlds;\n\t\t\t\t\tfor (auto & w : impl->Worlds)\n\t\t\t\t\t{\n\t\t\t\t\t\tShaderComponentSymbol* unaccessibleComp = nullptr;\n\t\t\t\t\t\tif (!IsWorldFeasible(symTable, shader->Pipeline, impl.Ptr(), w, unaccessibleComp))\n\t\t\t\t\t\t{\n                            err->diagnose(impl->ComponentReferencePositions[unaccessibleComp](), Diagnostics::componentCantBeComputedAtWorldBecauseDependentNotAvailable,\n                                comp->Name,\n                                w,\n                                unaccessibleComp->Name);\n                            err->diagnose(unaccessibleComp->Implementations.First()->SyntaxNode, Diagnostics::seeDefinitionOf, unaccessibleComp->Name);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// if a world is explicitly stated in any of the component defintions, remove it from autoWorld\n\t\t\t\t\t\tautoWorld.Remove(w);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (auto & impl : comp->Implementations)\n\t\t\t\t{\n\t\t\t\t\tif (impl->Worlds.Count() == 0) // if this component definition is not qualified with a world\n\t\t\t\t\t{\n\t\t\t\t\t\tEnumerableHashSet<String> deducedWorlds = allWorlds;\n\t\t\t\t\t\tEnumerableHashSet<String> feasibleWorlds;\n\t\t\t\t\t\t// the auto-deduced world for this definition is all feasible worlds in autoWorld.\n\t\t\t\t\t\tfor (auto & w : deducedWorlds)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tShaderComponentSymbol* unaccessibleComp = nullptr;\n\t\t\t\t\t\t\tbool isWFeasible = IsWorldFeasible(symTable, shader->Pipeline, impl.Ptr(), w, unaccessibleComp);\n\t\t\t\t\t\t\tif (isWFeasible)\n\t\t\t\t\t\t\t\tfeasibleWorlds.Add(w);\n\t\t\t\t\t\t}\n\t\t\t\t\t\timpl->Worlds = feasibleWorlds;\n\t\t\t\t\t}\n\t\t\t\t\tfor (auto & w : impl->Worlds)\n\t\t\t\t\t\tcomp->Type->FeasibleWorlds.Add(w);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (auto & comp : depOrder)\n\t\t\t{\n\t\t\t\tcomp->Type->ConstrainedWorlds = comp->Type->FeasibleWorlds;\n\t\t\t}\n\t\t\tauto useInWorld = [&](String comp, String world)\n\t\t\t{\n\t\t\t\t// comp is used in world, restrict comp.ContainedWorlds to guarantee\n\t\t\t\t// all candidate definitions can reach world\n\t\t\t\tRefPtr<ShaderComponentSymbol> compSym;\n\t\t\t\tif (shader->Components.TryGetValue(comp, compSym))\n\t\t\t\t{\n\t\t\t\t\tEnumerableHashSet<String> newWorlds;\n\t\t\t\t\tfor (auto & w : compSym->Type->ConstrainedWorlds)\n\t\t\t\t\t\tif (symTable->IsWorldReachable(shader->Pipeline, w, world, compSym->Type->DataType))\n\t\t\t\t\t\t\tnewWorlds.Add(w);\n\t\t\t\t\tcompSym->Type->ConstrainedWorlds = _Move(newWorlds);\n\t\t\t\t}\n\t\t\t};\n\t\t\tfor (auto impOp : shader->Pipeline->SyntaxNode->GetImportOperators())\n\t\t\t{\n\t\t\t\tfor (auto comp : impOp->Usings)\n\t\t\t\t{\n\t\t\t\t\tuseInWorld(comp, impOp->DestWorld.Content);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbool CheckCircularReference(DiagnosticSink * err, ShaderClosure * shader)\n\t\t{\n\t\t\tbool rs = false;\n\t\t\tfor (auto & comp : shader->AllComponents)\n\t\t\t{\n\t\t\t\tfor (auto & impl : comp.Value.Symbol->Implementations)\n\t\t\t\t{\n\t\t\t\t\t// check circular references\n\t\t\t\t\tHashSet<ShaderComponentSymbol*> set;\n\t\t\t\t\tList<ShaderComponentSymbol*> referredComponents;\n\t\t\t\t\treferredComponents.Add(comp.Value.Symbol);\n\t\t\t\t\tfor (int i = 0; i < referredComponents.Count(); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto xcomp = referredComponents[i];\n\t\t\t\t\t\tfor (auto & xcompImpl : xcomp->Implementations)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto & rcomp : xcompImpl->DependentComponents)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (set.Add(rcomp.Key))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\treferredComponents.Add(rcomp.Key);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (rcomp.Key == comp.Value.Symbol)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\terr->diagnose(impl->SyntaxNode->Position, Diagnostics::circularReferenceNotAllowed, rcomp.Key->Name);\n\t\t\t\t\t\t\t\t\trs = true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\n\t\tvoid PropagateArgumentConstraints(ShaderComponentSymbol * requirement, ShaderComponentSymbol * arg)\n\t\t{\n\t\t\tfor (auto w : requirement->Implementations.First()->ExportWorlds)\n\t\t\t{\n\t\t\t\tfor (auto impl : arg->Implementations)\n\t\t\t\t{\n\t\t\t\t\tif (impl->Worlds.Contains(w))\n\t\t\t\t\t\timpl->ExportWorlds.Add(w);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (auto w : requirement->Implementations.First()->SrcPinnedWorlds)\n\t\t\t{\n\t\t\t\tfor (auto impl : arg->Implementations)\n\t\t\t\t{\n\t\t\t\t\tif (impl->Worlds.Contains(w))\n\t\t\t\t\t\timpl->SrcPinnedWorlds.Add(w);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid VerifyAndPropagateArgumentConstraints(DiagnosticSink * err, SymbolTable * symTable, ShaderClosure * shader)\n\t\t{\n\t\t\tfor (auto & map : shader->RefMap)\n\t\t\t{\n\t\t\t\tauto & arg = map.Value;\n\t\t\t\tRefPtr<ShaderComponentSymbol> requirement;\n\t\t\t\tif (shader->Components.TryGetValue(map.Key, requirement) && requirement->IsRequire())\n\t\t\t\t{\n\t\t\t\t\tif (requirement->Implementations.First()->SyntaxNode->Rate)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto w : requirement->Implementations.First()->Worlds)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!symTable->IsWorldImplicitlyReachable(shader->Pipeline, arg->Type->FeasibleWorlds, w, requirement->Type->DataType))\n\t\t\t\t\t\t\t{\n                                err->diagnose(arg->Implementations.First()->SyntaxNode->Position, Diagnostics::argumentNotAvilableInWorld,\n                                    arg->Name,\n                                    w,\n                                    shader->Name);\n                                err->diagnose(requirement->Implementations.First()->SyntaxNode->Position, Diagnostics::seeRequirementDeclaration);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tPropagateArgumentConstraints(requirement.Ptr(), arg.Ptr());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (auto & subClosure : shader->SubClosures)\n\t\t\t\tVerifyAndPropagateArgumentConstraints(err, symTable, subClosure.Value.Ptr());\n\t\t}\n\n\t\tvoid AddPipelineComponents(ShaderClosure * shader)\n\t\t{\n\t\t\tfor (auto & comp : shader->Pipeline->Components)\n\t\t\t{\n\t\t\t\tif (!comp.Value->IsRequire())\n\t\t\t\t\tshader->Components.AddIfNotExists(comp.Key, new ShaderComponentSymbol(*comp.Value));\n\t\t\t}\n\t\t}\n\n\t\tvoid GatherArgumentMappings(EnumerableDictionary<String, String> & result, ShaderClosure* shader)\n\t\t{\n\t\t\tfor (auto & map : shader->RefMap)\n\t\t\t{\n\t\t\t\tresult[shader->Components[map.Key]()->UniqueName] = map.Value->UniqueName;\n\t\t\t}\n\t\t\tfor (auto & subShader : shader->SubClosures)\n\t\t\t\tGatherArgumentMappings(result, subShader.Value.Ptr());\n\t\t}\n\n\t\tvoid RemoveTrivialComponents(ShaderClosure * shader)\n\t\t{\n\t\t\t// remove trivial components, e.g. if A = B, replace all references to A with B.\n\t\t\t// this is not just an optimization, it is also critical for CodeGen because \n\t\t\t// code gen does not support components that returns another function component or sampler2D etc.\n\t\t\t// i.e. function/sampler2D components must be referenced directly.\n\t\t\tEnumerableDictionary<String, String> compSub;\n\t\t\tfor (auto & comp : shader->AllComponents)\n\t\t\t{\n\t\t\t\t// if this component is required by pipeline (e.g. gl_Position), do not attempt to remove it\n\t\t\t\tif (shader->Pipeline->Components.ContainsKey(comp.Key))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (comp.Value.Symbol->Implementations.Count() == 1 &&\n\t\t\t\t\tcomp.Value.Symbol->Implementations.First()->SyntaxNode->Expression &&\n\t\t\t\t\t!comp.Value.Symbol->Implementations.First()->SyntaxNode->IsOutput())\n\t\t\t\t{\n\t\t\t\t\tRefPtr<Object> compRef;\n\t\t\t\t\tif (comp.Value.Symbol->Implementations.First()->SyntaxNode->Expression->Tags.TryGetValue(\"ComponentReference\", compRef))\n\t\t\t\t\t{\n\t\t\t\t\t\tcompSub[comp.Key] = compRef.As<StringObject>()->Content;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// gather argument mappings\n\t\t\tEnumerableDictionary<String, String> arguments;\n\t\t\tGatherArgumentMappings(arguments, shader);\n\t\t\tEnumerableDictionary<String, String> replacements;\n\t\t\tfor (auto & replace : compSub)\n\t\t\t{\n\t\t\t\t// search transitively for replaceDest;\n\t\t\t\tString replaceDest = replace.Key;\n\t\t\t\twhile (compSub.ContainsKey(replaceDest))\n\t\t\t\t{\n\t\t\t\t\treplaceDest = compSub[replaceDest]();\n\t\t\t\t\targuments.TryGetValue(replaceDest, replaceDest);\n\t\t\t\t}\n\t\t\t\tif (replace.Key != replaceDest)\n\t\t\t\t\treplacements[replace.Key] = replaceDest;\n\t\t\t}\n\t\t\tReplaceReference(shader, replacements);\n\t\t\tfor (auto & r : replacements)\n\t\t\t\tshader->AllComponents.Remove(r.Key);\n\t\t}\n\n\t\tvoid PropagatePipelineRequirements(DiagnosticSink * err, ShaderClosure * shader)\n\t\t{\n\t\t\tfor (auto & req : shader->Pipeline->Components)\n\t\t\t{\n\t\t\t\tif (req.Value->IsRequire())\n\t\t\t\t{\n\t\t\t\t\tComponentInstance comp;\n\t\t\t\t\t\n\t\t\t\t\tStringBuilder errMsg;\n\t\t\t\t\tif (shader->AllComponents.TryGetValue(req.Key, comp))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!comp.Symbol->Type->DataType->Equals(req.Value->Type->DataType.Ptr()))\n\t\t\t\t\t\t{\n                            err->diagnose(comp.Symbol->Implementations.First()->SyntaxNode, Diagnostics::componentTypeNotWhatPipelineRequires,\n                                req.Key,\n\t\t\t\t\t\t\t\tcomp.Symbol->Type->DataType,\n                                shader->Pipeline->SyntaxNode->Name.Content,\n                                req.Value->Type->DataType);\n                            err->diagnose(req.Value->Implementations.First()->SyntaxNode, Diagnostics::seePipelineRequirementDefinition);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n                        err->diagnose(shader->Position, Diagnostics::shaderDoesNotDefineComponentAsRequiredByPipeline,\n                            shader->Name,\n                            req.Key,\n                            shader->Pipeline->SyntaxNode->Name);\n                        err->diagnose(req.Value->Implementations.First()->SyntaxNode, Diagnostics::seePipelineRequirementDefinition);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid diagnoseModuleUsingStack(DiagnosticSink* sink, ShaderClosure * shader)\n\t\t{\n\t\t\tif (shader->Parent)\n\t\t\t{\n                sink->diagnose(shader, Diagnostics::seeModuleBeingUsedIn, shader->Name, shader->Parent->Name);\n\t\t\t\tdiagnoseModuleUsingStack(sink, shader->Parent);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n                sink->diagnose(shader, Diagnostics::noteShaderIsTargetingPipeine, shader->Name, shader->Pipeline->SyntaxNode->Name);\n                sink->diagnose(shader->Pipeline->SyntaxNode, Diagnostics::alsoSeePipelineDefinition);\n\t\t\t}\n\t\t}\n\t\n\t\tvoid CheckPipelineShaderConsistency(DiagnosticSink * err, ShaderClosure * shader)\n\t\t{\n\t\t\tfor (auto & comp : shader->Components)\n\t\t\t{\n\t\t\t\tfor (auto & impl : comp.Value->Implementations)\n\t\t\t\t{\n\t\t\t\t\tbool inAbstractWorld = false;\n\t\t\t\t\tif (impl->SyntaxNode->Rate)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto & userSpecifiedWorlds = impl->SyntaxNode->Rate->Worlds;\n\t\t\t\t\t\tfor (auto & world : userSpecifiedWorlds)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t{\n                                if (!shader->Pipeline->WorldDependency.ContainsKey(world.World.Content))\n                                {\n\t\t\t\t\t\t\t\t\terr->diagnose(world.World.Position, Diagnostics::worldIsNotDefinedInPipeline, world.World, shader->Pipeline->SyntaxNode->Name);\n    \t\t\t\t\t\t\t\tdiagnoseModuleUsingStack(err, shader);\n                                }\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tWorldSyntaxNode* worldDecl;\n\t\t\t\t\t\t\tif (shader->Pipeline->Worlds.TryGetValue(world.World.Content, worldDecl))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (worldDecl->IsAbstract())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tinAbstractWorld = true;\n\t\t\t\t\t\t\t\t\tif (userSpecifiedWorlds.Count() > 1)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\terr->diagnose(world.World.Position, Diagnostics::abstractWorldCannotAppearWithOthers);\n\t\t\t\t\t\t\t\t\t\tdiagnoseModuleUsingStack(err, shader);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!inAbstractWorld && !impl->SyntaxNode->IsRequire() && !impl->SyntaxNode->IsInput() && !impl->SyntaxNode->IsParam()\n\t\t\t\t\t\t&& !impl->SyntaxNode->Expression && !impl->SyntaxNode->BlockStatement)\n\t\t\t\t\t{\n\t\t\t\t\t\terr->diagnose(impl->SyntaxNode->Position, Diagnostics::nonAbstractComponentMustHaveImplementation);\n\t\t\t\t\t}\n\n\t\t\t\t\tbool isDefinedInAbstractWorld = false, isDefinedInNonAbstractWorld = false;\n\t\t\t\t\tif (impl->SyntaxNode->Rate)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto & w : impl->SyntaxNode->Rate->Worlds)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto world = shader->Pipeline->Worlds.TryGetValue(w.World.Content);\n\t\t\t\t\t\t\tif (world)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif ((*world)->IsAbstract())\n\t\t\t\t\t\t\t\t\tisDefinedInAbstractWorld = true;\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tisDefinedInNonAbstractWorld = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tisDefinedInNonAbstractWorld = true;\n\t\t\t\t\tif (impl->SyntaxNode->Expression || impl->SyntaxNode->BlockStatement)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (isDefinedInAbstractWorld)\n\t\t\t\t\t\t\terr->diagnose(impl->SyntaxNode->Position, Diagnostics::componentInInputWorldCantHaveCode, impl->SyntaxNode->Name);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (auto & subShader : shader->SubClosures)\n\t\t\t\tCheckPipelineShaderConsistency(err, subShader.Value.Ptr());\n\t\t}\n\n\t\tvoid FlattenShaderClosure(DiagnosticSink * err, SymbolTable * symTable, ShaderClosure * shader)\n\t\t{\n\t\t\t// add input(extern) components from pipeline\n\t\t\tAddPipelineComponents(shader);\n\t\t\tCheckPipelineShaderConsistency(err, shader);\n\t\t\t// assign choice names\n\t\t\tAssignUniqueNames(shader, \"\", \"\");\n\t\t\t// traverse closures to get component list\n\t\t\tGatherComponents(err, shader, shader);\n\t\t\tPropagatePipelineRequirements(err, shader);\n\t\t\tResolveReference(err, shader, shader);\n\t\t\t// propagate world constraints\n\t\t\tif (CheckCircularReference(err, shader))\n\t\t\t\treturn;\n\t\t\tif (err->GetErrorCount())\n\t\t\t\treturn;\n\t\t\tRemoveTrivialComponents(shader);\n\t\t\tSolveWorldConstraints(err, symTable, shader);\n\t\t\t// check pipeline constraints\n\t\t\tfor (auto & requirement : shader->Pipeline->Components)\n\t\t\t{\n\t\t\t\tif (!requirement.Value->IsRequire())\n\t\t\t\t\tcontinue;\n\t\t\t\tauto comp = shader->FindComponent(requirement.Key);\n\t\t\t\tif (!comp)\n\t\t\t\t{\n                    err->diagnose(shader->Position, Diagnostics::shaderDoesProvideRequirement,\n                        shader->Name,\n                        requirement.Key,\n                        shader->Pipeline->SyntaxNode->Name.Content);\n                    err->diagnose(requirement.Value->Implementations.First()->SyntaxNode, Diagnostics::seeRequirementDeclaration);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor (auto & impl : requirement.Value->Implementations)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto w : impl->Worlds)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!symTable->IsWorldImplicitlyReachable(shader->Pipeline, comp->Type->FeasibleWorlds, w, requirement.Value->Type->DataType))\n\t\t\t\t\t\t\t{\n                                err->diagnose(comp->Implementations.First()->SyntaxNode, Diagnostics::componentNotAvilableInWorld,\n                                    comp->Name,\n                                    w,\n                                    shader->Pipeline->SyntaxNode->Name);\n                                err->diagnose(requirement.Value->Implementations.First()->SyntaxNode, Diagnostics::seeRequirementDeclaration);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tPropagateArgumentConstraints(requirement.Value.Ptr(), comp.Ptr());\n\t\t\t\t}\n\t\t\t}\n\t\t\t// check argument constraints\n\t\t\tVerifyAndPropagateArgumentConstraints(err, symTable, shader);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/Closure.h",
    "content": "#ifndef BAKERSL_SHADER_CLOSURE_H\n#define BAKERSL_SHADER_CLOSURE_H\n#include \"SymbolTable.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tRefPtr<ShaderClosure> CreateShaderClosure(DiagnosticSink * sink, SymbolTable * symTable, ShaderSymbol * shader);\n\t\tvoid FlattenShaderClosure(DiagnosticSink * sink, SymbolTable * symTable, ShaderClosure * shader);\n\t\tvoid InsertImplicitImportOperators(DiagnosticSink * sink, ShaderIR * shader);\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/CodeGenBackend.h",
    "content": "#ifndef CODE_GEN_BACKEND_H\n#define CODE_GEN_BACKEND_H\n\n#include \"../CoreLib/Basic.h\"\n#include \"CompiledProgram.h\"\n#include \"SymbolTable.h\"\n#include \"TypeLayout.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\t\t\n\t\tclass CodeGenBackend : public CoreLib::Basic::Object\n\t\t{\n\t\tpublic:\n\t\t\tvirtual CompiledShaderSource GenerateShader(CompileResult & result, SymbolTable * symbols, ILShader * shader, DiagnosticSink * err) = 0;\n            virtual LayoutRule GetDefaultLayoutRule() = 0;\n\t\t};\n\n\t\tCodeGenBackend * CreateGLSLCodeGen();\n\t\tCodeGenBackend * CreateGLSL_VulkanCodeGen();\n\t\tCodeGenBackend * CreateGLSL_VulkanOneDescCodeGen();\n\t\tCodeGenBackend * CreateHLSLCodeGen();\n\t\tCodeGenBackend * CreateSpirVCodeGen();\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/CodeGenerator.cpp",
    "content": "#include \"SyntaxVisitors.h\"\n#include \"ScopeDictionary.h\"\n#include \"CodeWriter.h\"\n#include \"StringObject.h\"\n#include \"Naming.h\"\n#include \"TypeLayout.h\"\n#include \"../CoreLib/Tokenizer.h\"\n#include <assert.h>\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tconst int MaxBindingValue = 128;\n\n\t\ttemplate<typename Func>\n\t\tclass ImportNodeVisitor : public SyntaxVisitor\n\t\t{\n\t\tpublic:\n\t\t\tconst Func * func;\n\t\t\tImportNodeVisitor(const Func & f)\n\t\t\t\t: SyntaxVisitor(nullptr), func(&f)\n\t\t\t{}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitImportExpression(ImportExpressionSyntaxNode * expr) override\n\t\t\t{\n\t\t\t\t(*func)(expr);\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename Func>\n\t\tvoid EnumerateImportExpressions(SyntaxNode * node, const Func & f)\n\t\t{\n\t\t\tImportNodeVisitor<Func> visitor(f);\n\t\t\tnode->Accept(&visitor);\n\t\t}\n\n\t\tclass CodeGenerator : public ICodeGenerator\n\t\t{\n\t\tprivate:\n\t\t\tSymbolTable * symTable;\n\t\t\tILWorld * currentWorld = nullptr;\n\t\t\tComponentDefinitionIR * currentComponent = nullptr;\n\t\t\tFunctionSymbol * currentFunc = nullptr;\n\t\t\tILOperand * returnRegister = nullptr;\n\t\t\tImportExpressionSyntaxNode * currentImport = nullptr;\n\t\t\tShaderIR * currentShader = nullptr;\n\t\t\tRefPtr<ILShader> compiledShader;\n\t\t\tCompileResult & result;\n\t\t\tList<ILOperand*> exprStack;\n\t\t\tCodeWriter codeWriter;\n\t\t\tScopeDictionary<String, ILOperand*> variables;\n\t\t\tDictionary<String, RefPtr<ILType>> genericTypeMappings;\n\t\t\tDictionary<StructSyntaxNode*, RefPtr<ILStructType>> structTypes;\n            LayoutRule defaultLayoutRule;\n\n\t\t\tvoid PushStack(ILOperand * op)\n\t\t\t{\n\t\t\t\texprStack.Add(op);\n\t\t\t}\n\t\t\tILOperand * PopStack()\n\t\t\t{\n\t\t\t\tauto rs = exprStack.Last();\n\t\t\t\texprStack.SetSize(exprStack.Count() - 1);\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tAllocVarInstruction * AllocVar(ExpressionType * etype)\n\t\t\t{\n\t\t\t\tAllocVarInstruction * varOp = 0;\n\t\t\t\tRefPtr<ILType> type = TranslateExpressionType(etype);\n\t\t\t\tauto arrType = dynamic_cast<ILArrayType*>(type.Ptr());\n\n\t\t\t\tif (arrType)\n\t\t\t\t{\n\t\t\t\t\tvarOp = codeWriter.AllocVar(arrType->BaseType, result.Program->ConstantPool->CreateConstant(arrType->ArrayLength));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tassert(type);\n\t\t\t\t\tvarOp = codeWriter.AllocVar(type, result.Program->ConstantPool->CreateConstant(0));\n\t\t\t\t}\n\t\t\t\treturn varOp;\n\t\t\t}\n\t\t\tFetchArgInstruction * FetchArg(ExpressionType * etype, int argId)\n\t\t\t{\n\t\t\t\tauto type = TranslateExpressionType(etype);\n\t\t\t\tauto arrType = dynamic_cast<ILArrayType*>(type.Ptr());\n\t\t\t\tFetchArgInstruction * varOp = 0;\n\t\t\t\tif (arrType)\n\t\t\t\t{\n\t\t\t\t\tauto baseType = arrType->BaseType.Release();\n\t\t\t\t\tvarOp = codeWriter.FetchArg(baseType, argId);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tvarOp = codeWriter.FetchArg(type, argId);\n\t\t\t\t}\n\t\t\t\treturn varOp;\n\t\t\t}\n\t\t\tvoid TranslateStages(PipelineSyntaxNode * pipeline)\n\t\t\t{\n\t\t\t\tfor (auto & stage : pipeline->GetStages())\n\t\t\t\t{\n\t\t\t\t\tRefPtr<ILStage> ilStage = new ILStage();\n\t\t\t\t\tilStage->Position = stage->Position;\n\t\t\t\t\tilStage->Name = stage->Name.Content;\n\t\t\t\t\tilStage->StageType = stage->StageType.Content;\n\t\t\t\t\tfor (auto & attrib : stage->Attributes)\n\t\t\t\t\t{\n\t\t\t\t\t\tStageAttribute sattrib;\n\t\t\t\t\t\tsattrib.Name = attrib.Key;\n\t\t\t\t\t\tsattrib.Position = attrib.Value.Position;\n\t\t\t\t\t\tsattrib.Value = attrib.Value.Content;\n\t\t\t\t\t\tilStage->Attributes[attrib.Key] = sattrib;\n\t\t\t\t\t}\n\t\t\t\t\tcompiledShader->Stages[stage->Name.Content] = ilStage;\n\t\t\t\t}\n\t\t\t}\n\t\t\tString GetComponentFunctionName(ComponentSyntaxNode * comp)\n\t\t\t{\n\t\t\t\tStringBuilder nameSb;\n\t\t\t\tnameSb << comp->ParentDecl->Name.Content << \".\" << comp->Name.Content;\n\t\t\t\treturn EscapeCodeName(nameSb.ProduceString());\n\t\t\t}\n\t\tpublic:\n\t\t\tvirtual RefPtr<StructSyntaxNode> VisitStruct(StructSyntaxNode * st) override\n\t\t\t{\n\t\t\t\tRefPtr<ILStructType> structType = TranslateStructType(st);\n\t\t\t\tresult.Program->Structs.Add(structType);\n\t\t\t\treturn st;\n\t\t\t}\n\t\t\tvirtual void ProcessFunction(FunctionSyntaxNode * func) override\n\t\t\t{\n\t\t\t\tVisitFunction(func);\n\t\t\t}\n\t\t\tvirtual void ProcessStruct(StructSyntaxNode * st) override\n\t\t\t{\n\t\t\t\tVisitStruct(st);\n\t\t\t}\n\t\t\tvoid SetSubModuleDescriptorSetId(ILModuleParameterSet * moduleParam, int id)\n\t\t\t{\n\t\t\t\tmoduleParam->DescriptorSetId = id;\n\t\t\t\tfor (auto & submodule : moduleParam->SubModules)\n\t\t\t\t\tSetSubModuleDescriptorSetId(submodule.Ptr(), id);\n\t\t\t}\n            LayoutRule GetDefaultLayoutRule()\n            {\n                return defaultLayoutRule;\n            }\n\t\t\tvoid GenerateParameterBindingInfo(ShaderIR * shader)\n\t\t\t{\n\t\t\t\tDictionary<int, ModuleInstanceIR*> usedDescriptorSetBindings;\n\t\t\t\t// initialize module parameter layouts for all module instances in this shader\n\t\t\t\tfor (auto module : shader->ModuleInstances)\n\t\t\t\t{\n\t\t\t\t\tif (module->BindingIndex != -1 && module->IsTopLevel)\n\t\t\t\t\t{\n\t\t\t\t\t\tModuleInstanceIR * existingModule;\n\t\t\t\t\t\tif (usedDescriptorSetBindings.TryGetValue(module->BindingIndex, existingModule))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgetSink()->diagnose(module->UsingPosition, Diagnostics::bindingAlreadyOccupiedByModule, module->BindingIndex, existingModule->BindingName);\n\t\t\t\t\t\t\tgetSink()->diagnose(existingModule->UsingPosition, Diagnostics::seeUsingOf, existingModule->SyntaxNode->Name.Content);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tusedDescriptorSetBindings[module->BindingIndex] = module.Ptr();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// report error if shader uses a top-level module without specifying its binding\n\t\t\t\tfor (auto & module : shader->ModuleInstances)\n\t\t\t\t{\n\t\t\t\t\tif (module->BindingIndex == -1 && module->IsTopLevel)\n\t\t\t\t\t{\n\t\t\t\t\t\tbool hasParam = false;\n\t\t\t\t\t\tfor (auto & comp : module->SyntaxNode->GetMembersOfType<ComponentSyntaxNode>())\n\t\t\t\t\t\t\tif (comp->IsParam())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\thasParam = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\tif (hasParam)\n\t\t\t\t\t\t\tgetSink()->diagnose(module->UsingPosition, Diagnostics::topLevelModuleUsedWithoutSpecifyingBinding, module->SyntaxNode->Name);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tshader->ModuleInstances.Sort([](RefPtr<ModuleInstanceIR> & x, RefPtr<ModuleInstanceIR> & y) {return x->BindingIndex < y->BindingIndex; });\n\t\t\t\tfor (auto module : shader->ModuleInstances)\n\t\t\t\t{\n\t\t\t\t\tauto set = new ILModuleParameterSet();\n\t\t\t\t\tset->BindingName = module->BindingName;\n\t\t\t\t\tset->DescriptorSetId = module->BindingIndex;\n\t\t\t\t\tset->UniformBufferLegacyBindingPoint = set->DescriptorSetId;\n\t\t\t\t\tset->IsTopLevel = module->IsTopLevel;\n\t\t\t\t\tcompiledShader->ModuleParamSets[module->BindingName] = set;\n\t\t\t\t}\n\t\t\t\tfor (auto module : shader->ModuleInstances)\n\t\t\t\t{\n\t\t\t\t\tauto ilModule = compiledShader->ModuleParamSets[module->BindingName]();\n\t\t\t\t\tfor (auto subModule : module->SubModuleInstances)\n\t\t\t\t\t\tilModule->SubModules.Add(compiledShader->ModuleParamSets[subModule->BindingName]());\n\t\t\t\t}\n\t\t\t\tfor (auto module : compiledShader->ModuleParamSets)\n\t\t\t\t{\n\t\t\t\t\tif (module.Value->IsTopLevel && module.Value->DescriptorSetId != -1 && module.Key != compiledShader->Name)\n\t\t\t\t\t\tfor (auto submodule : module.Value->SubModules)\n\t\t\t\t\t\t\tSetSubModuleDescriptorSetId(submodule.Ptr(), module.Value->DescriptorSetId);\n\t\t\t\t}\n\t\t\t\t// allocate binding slots for shader resources (textures, buffers, samplers etc.), as required by legacy APIs\n\t\t\t\tDictionary<int, ComponentDefinitionIR*> usedTextureBindings, usedBufferBindings, usedSamplerBindings, usedStorageBufferBindings;\n\t\t\t\tint textureBindingAllcator = 0, samplerBindingAllocator = 0, storageBufferBindingAllocator = 0, bufferBindingAllocator = 0;\n\t\t\t\t// first pass: add components to module layout definition, and assign them user-defined binding slots (if any).\n\t\t\t\tfor (auto def : shader->Definitions)\n\t\t\t\t{\n\t\t\t\t\tif (def->SyntaxNode->IsParam())\n\t\t\t\t\t{\n\t\t\t\t\t\tauto module = compiledShader->ModuleParamSets[def->ModuleInstance->BindingName]().Ptr();\n\t\t\t\t\t\tRefPtr<ILModuleParameterInstance> param = new ILModuleParameterInstance();\n\t\t\t\t\t\tparam->Module = module;\n\t\t\t\t\t\tparam->Name = def->OriginalName;\n\t\t\t\t\t\tparam->Type = TranslateExpressionType(def->SyntaxNode->Type);\n\t\t\t\t\t\tauto resType = param->Type->GetBindableResourceType();\n\t\t\t\t\t\t// if this parameter is ordinary-value typed, assign it a buffer range\n\t\t\t\t\t\tif (resType == BindableResourceType::NonBindable)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tparam->BindingPoints.Clear();\n\t\t\t\t\t\t\tparam->BufferOffset = (int)RoundToAlignment(module->BufferSize, (int)GetTypeAlignment(param->Type.Ptr(), defaultLayoutRule));\n\t\t\t\t\t\t\tmodule->BufferSize = param->BufferOffset + (int)GetTypeSize(param->Type.Ptr(), defaultLayoutRule);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// otherwise, check for binding slot collision if the user assigns a binding slot explicitly\n\t\t\t\t\t\t\tparam->BufferOffset = -1;\n\t\t\t\t\t\t\tDictionary<int, ComponentDefinitionIR*> * bindingRegistry = nullptr;\n\t\t\t\t\t\t\tswitch (resType)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase BindableResourceType::Texture:\n\t\t\t\t\t\t\t\tbindingRegistry = &usedTextureBindings;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase BindableResourceType::Sampler:\n\t\t\t\t\t\t\t\tbindingRegistry = &usedSamplerBindings;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase BindableResourceType::Buffer:\n\t\t\t\t\t\t\t\tbindingRegistry = &usedBufferBindings;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase BindableResourceType::StorageBuffer:\n\t\t\t\t\t\t\t\tbindingRegistry = &usedStorageBufferBindings;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tToken bindingValStr;\n\t\t\t\t\t\t\tif (def->SyntaxNode->FindSimpleAttribute(\"Binding\", bindingValStr))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tint bindingVal = StringToInt(bindingValStr.Content);\n\n\t\t\t\t\t\t\t\tComponentDefinitionIR * otherComp = nullptr;\n\t\t\t\t\t\t\t\tif (bindingRegistry->TryGetValue(bindingVal, otherComp))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tgetSink()->diagnose(def->SyntaxNode->Position, Diagnostics::bindingAlreadyOccupiedByComponent, bindingVal, otherComp->OriginalName);\n\t\t\t\t\t\t\t\t\tgetSink()->diagnose(otherComp->SyntaxNode->Position, Diagnostics::seeDefinitionOf, otherComp->OriginalName);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (bindingVal < 0 || bindingVal >= MaxBindingValue)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tgetSink()->diagnose(def->SyntaxNode->Position, Diagnostics::invalidBindingValue, bindingVal);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t(*bindingRegistry)[bindingVal] = def.Ptr();\n\t\t\t\t\t\t\t\tparam->BindingPoints.Clear();\n\t\t\t\t\t\t\t\tparam->BindingPoints.Add(bindingVal);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmodule->Parameters.Add(def->OriginalName, param);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// second pass: assign binding slots for rest of resource components whose binding is not explicitly specified by user\n\t\t\t\tfor (auto def : shader->Definitions)\n\t\t\t\t{\n\t\t\t\t\tif (def->SyntaxNode->IsParam())\n\t\t\t\t\t{\n\t\t\t\t\t\tauto module = compiledShader->ModuleParamSets[def->ModuleInstance->BindingName]().Ptr();\n\t\t\t\t\t\tauto & param = **module->Parameters.TryGetValue(def->OriginalName);\n\t\t\t\t\t\tauto bindableResType = param.Type->GetBindableResourceType();\n\t\t\t\t\t\tif (bindableResType != BindableResourceType::NonBindable)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDictionary<int, ComponentDefinitionIR*> * bindingRegistry = nullptr;\n\t\t\t\t\t\t\tif (param.BindingPoints.Count())\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\tint * bindingAllocator = nullptr;\n\t\t\t\t\t\t\tswitch (bindableResType)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase BindableResourceType::Texture:\n\t\t\t\t\t\t\t\tbindingRegistry = &usedTextureBindings;\n\t\t\t\t\t\t\t\tbindingAllocator = &textureBindingAllcator;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase BindableResourceType::Sampler:\n\t\t\t\t\t\t\t\tbindingRegistry = &usedSamplerBindings;\n\t\t\t\t\t\t\t\tbindingAllocator = &samplerBindingAllocator;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase BindableResourceType::Buffer:\n\t\t\t\t\t\t\t\tbindingRegistry = &usedBufferBindings;\n\t\t\t\t\t\t\t\tbindingAllocator = &bufferBindingAllocator;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase BindableResourceType::StorageBuffer:\n\t\t\t\t\t\t\t\tbindingRegistry = &usedStorageBufferBindings;\n\t\t\t\t\t\t\t\tbindingAllocator = &storageBufferBindingAllocator;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\twhile (bindingRegistry->ContainsKey(*bindingAllocator))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t(*bindingAllocator)++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tparam.BindingPoints.Add(*bindingAllocator);\n\t\t\t\t\t\t\tint maxBinding = GetMaxResourceBindings(bindableResType);\n\t\t\t\t\t\t\tif (*bindingAllocator > maxBinding)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tgetSink()->diagnose(def->SyntaxNode->Position, Diagnostics::bindingExceedsLimit, *bindingAllocator, def->SyntaxNode->Name);\n\t\t\t\t\t\t\t\tgetSink()->diagnose(def->SyntaxNode->Position, Diagnostics::seeModuleBeingUsedIn, def->ModuleInstance->SyntaxNode->Name, def->ModuleInstance->BindingName);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t(*bindingAllocator)++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\n            ParameterQualifier GetParamQualifier(ParameterSyntaxNode* paramDecl)\n            {\n                if ((paramDecl->modifiers.flags & ModifierFlag::InOut) == ModifierFlag::InOut)\n                    return ParameterQualifier::InOut;\n                else if (paramDecl->modifiers.flags & ModifierFlag::Out)\n                    return ParameterQualifier::Out;\n                else\n                    return ParameterQualifier::In;\n            }\n\n            EnumerableDictionary<String, Token> CopyLayoutAttributes(Decl* decl)\n            {\n                EnumerableDictionary<String, Token> attrs;\n                for (auto attr : decl->GetLayoutAttributes())\n                {\n                    attrs[attr->Key] = attr->Value;\n                }\n                return attrs;\n            }\n\n\t\t\tvirtual void ProcessShader(ShaderIR * shader) override\n\t\t\t{\n\t\t\t\tcurrentShader = shader;\n\t\t\t\tauto pipeline = shader->Shader->Pipeline;\n\t\t\t\tcompiledShader = new ILShader();\n\t\t\t\tcompiledShader->Name = EscapeCodeName(shader->Shader->Name);\n\t\t\t\tcompiledShader->Position = shader->Shader->Position;\n\n\t\t\t\tGenerateParameterBindingInfo(shader);\n\n\t\t\t\tTranslateStages(pipeline->SyntaxNode);\n\t\t\t\tresult.Program->Shaders.Add(compiledShader);\n\n\t\t\t\tgenericTypeMappings.Clear();\n\n\t\t\t\t// pass 1: iterating all worlds\n\t\t\t\t// create ILWorld and ILRecordType objects for all worlds\n\n\t\t\t\tfor (auto & world : pipeline->Worlds)\n\t\t\t\t{\n\t\t\t\t\tauto w = new ILWorld();\n\t\t\t\t\tauto recordType = new ILRecordType();\n\t\t\t\t\trecordType->TypeName = world.Key;\n\t\t\t\t\tgenericTypeMappings[world.Key] = recordType;\n\t\t\t\t\tw->Name = world.Key;\n\t\t\t\t\tw->OutputType = recordType;\n\t\t\t\t\tw->Attributes = CopyLayoutAttributes(world.Value);\n\t\t\t\t\tw->Shader = compiledShader.Ptr();\n\t\t\t\t\tw->IsAbstract = world.Value->IsAbstract();\n\t\t\t\t\tauto impOps = pipeline->GetImportOperatorsFromSourceWorld(world.Key);\n\t\t\t\t\tw->Position = world.Value->Position;\n\t\t\t\t\tcompiledShader->Worlds[world.Key] = w;\n\t\t\t\t}\n\n\t\t\t\t// pass 2: iterating all worlds:\n\t\t\t\t// 1) Gather list of components for each world, and store it in worldComps dictionary.\n\t\t\t\t// 2) For each abstract world, add its components to record type\n\n\t\t\t\tDictionary<String, List<ComponentDefinitionIR*>> worldComps;\n\t\t\t\tauto worlds = From(pipeline->Worlds).Select([](KeyValuePair<String, WorldSyntaxNode*> kv) {return kv.Key; }).Concat(FromSingle(String(\"<uniform>\")));\n\t\t\t\t//worlds.Add(\"<uniform>\");\n\t\t\t\tfor (auto world : worlds)\n\t\t\t\t{\n\t\t\t\t\t// gather list of components\n\t\t\t\t\tList<ComponentDefinitionIR*> components;\n\t\t\t\t\tfor (auto & compDef : shader->Definitions)\n\t\t\t\t\t\tif (compDef->World == world)\n\t\t\t\t\t\t\tcomponents.Add(compDef.Ptr());\n\t\t\t\t\t// for abstract world, fill in record type now\n\t\t\t\t\tif (world != \"<uniform>\" && pipeline->Worlds[world]()->IsAbstract())\n\t\t\t\t\t{\n\t\t\t\t\t\tauto compiledWorld = compiledShader->Worlds[world]();\n\t\t\t\t\t\tfor (auto & comp : components)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tILObjectDefinition compDef;\n\t\t\t\t\t\t\tcompDef.Attributes = CopyLayoutAttributes(comp->SyntaxNode.Ptr());\n\t\t\t\t\t\t\tcompDef.Name = comp->UniqueName;\n\t\t\t\t\t\t\tcompDef.Type = TranslateExpressionType(comp->Type.Ptr());\n\t\t\t\t\t\t\tcompDef.Position = comp->SyntaxNode->Position;\n\t\t\t\t\t\t\tcompDef.Binding = -1;\n\n\t\t\t\t\t\t\tcompiledWorld->OutputType->Members.AddIfNotExists(compDef.Name, compDef);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// put the list in worldComps\n\t\t\t\t\tworldComps[world] = components;\n\t\t\t\t}\n\n\t\t\t\t// now we need to deal with import operators\n\t\t\t\t// create world input declarations base on input components\n\t\t\t\tfor (auto & world : compiledShader->Worlds)\n\t\t\t\t{\n\t\t\t\t\tauto &components = worldComps[world.Key]();\n\t\t\t\t\tfor (auto & comp : components)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (comp->SyntaxNode->IsInput())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tILObjectDefinition def;\n\t\t\t\t\t\t\tdef.Name = comp->UniqueName;\n\t\t\t\t\t\t\tdef.Type = TranslateExpressionType(comp->Type.Ptr());\n\t\t\t\t\t\t\tdef.Position = comp->SyntaxNode->Position;\n\t\t\t\t\t\t\tdef.Attributes = CopyLayoutAttributes(comp->SyntaxNode.Ptr());\n\t\t\t\t\t\t\tworld.Value->Inputs.Add(def);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// fill in record types\n\t\t\t\tfor (auto & comps : worldComps)\n\t\t\t\t{\n\t\t\t\t\tfor (auto & comp : comps.Value)\n\t\t\t\t\t{\n\t\t\t\t\t\t// for each import operator call \"import[w0->w1](x)\", add x to w0's record type\n\t\t\t\t\t\tEnumerateImportExpressions(comp->SyntaxNode.Ptr(), [&](ImportExpressionSyntaxNode * importExpr)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto recType = genericTypeMappings[importExpr->ImportOperatorDef->SourceWorld.Content]().As<ILRecordType>();\n\t\t\t\t\t\t\tILObjectDefinition entryDef;\n\t\t\t\t\t\t\tentryDef.Attributes = CopyLayoutAttributes(comp->SyntaxNode.Ptr());\n\t\t\t\t\t\t\tentryDef.Name = importExpr->ComponentUniqueName;\n\t\t\t\t\t\t\tentryDef.Type = TranslateExpressionType(importExpr->Type.Ptr());\n\t\t\t\t\t\t\tentryDef.Position = importExpr->Position;\n\t\t\t\t\t\t\trecType->Members.AddIfNotExists(importExpr->ComponentUniqueName, entryDef);\n\t\t\t\t\t\t});\n\t\t\t\t\t\t// if comp is output, add comp to its world's record type\n\t\t\t\t\t\tif (comp->SyntaxNode->IsOutput())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto recType = genericTypeMappings[comp->World]().As<ILRecordType>();\n\t\t\t\t\t\t\tILObjectDefinition entryDef;\n\t\t\t\t\t\t\tentryDef.Attributes = CopyLayoutAttributes(comp->SyntaxNode.Ptr());\n\t\t\t\t\t\t\tentryDef.Name = comp->UniqueName;\n\t\t\t\t\t\t\tentryDef.Type = TranslateExpressionType(comp->Type.Ptr());\n\t\t\t\t\t\t\tentryDef.Position = comp->SyntaxNode->Position;\n\t\t\t\t\t\t\trecType->Members.AddIfNotExists(comp->UniqueName, entryDef);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// sort components by dependency\n\t\t\t\tfor (auto & world : compiledShader->Worlds)\n\t\t\t\t{\n\t\t\t\t\tauto &components = worldComps[world.Key]();\n\t\t\t\t\tDependencySort(components, [](ComponentDefinitionIR * def)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn def->Dependency;\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// generate component functions\n\t\t\t\tfor (auto & comp : shader->Definitions)\n\t\t\t\t{\n\t\t\t\t\tcurrentComponent = comp.Ptr();\n\t\t\t\t\tif (comp->SyntaxNode->IsComponentFunction())\n\t\t\t\t\t{\n\t\t\t\t\t\tauto funcName = GetComponentFunctionName(comp->SyntaxNode.Ptr());\n\t\t\t\t\t\t\n\t\t\t\t\t\t// BUG FIX: The following line must be commented out.\n\t\t\t\t\t\t/* we cannot really cached IL for previously generated component functions\n\t\t\t\t\t\t  because the actual component function is dependent on component composition.\n\t\t\t\t\t\t  example: module A, module B, module C. module A has requires void f(int) that can be\n\t\t\t\t\t\t    provided by either B::f or C::f. because B::f and C::f may capture different environment,\n\t\t\t\t\t\t\ttheir actual parameter list can be different, therefore if module A has a method g that calls f,\n\t\t\t\t\t\t\tthe implementation of g will differ based on wheither it is calling B::f or C::f.\n\t\t\t\t\t\t\tsimply caching an IL for A::g using function name as key is therefore not sufficient.\n\t\t\t\t\t\t  the real bug fix should factor this into the function name, but for now just disable caching.\n\t\t\t\t\t    */\n\t\t\t\t\t\t/*if (result.Program->Functions.ContainsKey(funcName))\n\t\t\t\t\t\t\tcontinue;*/\n\t\t\t\t\t\tRefPtr<ILFunction> func = new ILFunction();\n\t\t\t\t\t\tRefPtr<FunctionSymbol> funcSym = new FunctionSymbol();\n\t\t\t\t\t\tfunc->Name = funcName;\n\t\t\t\t\t\tfunc->ReturnType = TranslateExpressionType(comp->Type);\n\t\t\t\t\t\tsymTable->Functions[funcName] = funcSym;\n\t\t\t\t\t\tresult.Program->Functions[funcName] = func;\n\t\t\t\t\t\tcurrentFunc = funcSym.Ptr();\n\t\t\t\t\t\tfor (auto dep : comp->GetComponentFunctionDependencyClosure())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (dep->SyntaxNode->IsComponentFunction())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfuncSym->ReferencedFunctions.Add(GetComponentFunctionName(dep->SyntaxNode.Ptr()));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tint id = 0;\n\t\t\t\t\t\tDictionary<String, ILOperand*> refComponents;\n\t\t\t\t\t\tvariables.PushScope();\n\t\t\t\t\t\tcodeWriter.PushNode();\n\t\t\t\t\t\tfor (auto & dep : comp->GetComponentFunctionDependencyClosure())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!dep->SyntaxNode->IsComponentFunction())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tauto paramType = TranslateExpressionType(dep->Type);\n\t\t\t\t\t\t\t\tString paramName = EscapeCodeName(\"p\" + String(id) + \"_\" + dep->OriginalName);\n\t\t\t\t\t\t\t\tfunc->Parameters.Add(paramName, ILParameter(paramType));\n\t\t\t\t\t\t\t\tauto argInstr = codeWriter.FetchArg(paramType, id + 1);\n\t\t\t\t\t\t\t\targInstr->Name = paramName;\n\t\t\t\t\t\t\t\tvariables.Add(dep->UniqueName, argInstr);\n\t\t\t\t\t\t\t\tid++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (auto & param : comp->SyntaxNode->GetParameters())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto paramType = TranslateExpressionType(param->Type);\n\t\t\t\t\t\t\tString paramName = EscapeCodeName(\"p\" + String(id) + \"_\" + param->Name.Content);\n\t\t\t\t\t\t\tfunc->Parameters.Add(paramName, ILParameter(paramType, GetParamQualifier(param.Ptr())));\n\t\t\t\t\t\t\tauto argInstr = codeWriter.FetchArg(paramType, id + 1);\n\t\t\t\t\t\t\targInstr->Name = paramName;\n\t\t\t\t\t\t\tvariables.Add(param->Name.Content, argInstr);\n\t\t\t\t\t\t\tid++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (comp->SyntaxNode->Expression)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcomp->SyntaxNode->Expression->Accept(this);\n\t\t\t\t\t\t\tcodeWriter.Insert(new ReturnInstruction(PopStack()));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcomp->SyntaxNode->BlockStatement->Accept(this);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcurrentFunc = nullptr;\n\t\t\t\t\t\tvariables.PopScope();\n\t\t\t\t\t\tfunc->Code = codeWriter.PopNode();\n\t\t\t\t\t}\n\t\t\t\t\tcurrentComponent = nullptr;\n\t\t\t\t}\n\t\t\t\tvariables.PushScope();\n\t\t\t\t// push parameter components to variables table\n\t\t\t\tif (auto paramComps = worldComps.TryGetValue(\"<uniform>\"))\n\t\t\t\t{\n\t\t\t\t\tfor (auto & comp : *paramComps)\n\t\t\t\t\t{\n\t\t\t\t\t\tvariables.Add(comp->UniqueName, compiledShader->ModuleParamSets[comp->ModuleInstance->BindingName]()->Parameters[comp->OriginalName]().Ptr());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (auto & world : pipeline->Worlds)\n\t\t\t\t{\n\t\t\t\t\tif (world.Value->IsAbstract())\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tNamingCounter = 0;\n\n\t\t\t\t\tauto & components = worldComps[world.Key].GetValue();\n\t\t\t\t\tauto compiledWorld = compiledShader->Worlds[world.Key].GetValue().Ptr();\n\t\t\t\t\tcurrentWorld = compiledWorld;\n\t\t\t\t\tcodeWriter.PushNode();\n\t\t\t\t\tvariables.PushScope();\n\t\t\t\t\tHashSet<String> localComponents;\n\t\t\t\t\tfor (auto & comp : components)\n\t\t\t\t\t\tlocalComponents.Add(comp->UniqueName);\n\n\t\t\t\t\tDependencySort(components, [](ComponentDefinitionIR * def)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn def->Dependency;\n\t\t\t\t\t});\n\n\t\t\t\t\tfor (auto & comp : components)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!comp->SyntaxNode->IsComponentFunction())\n\t\t\t\t\t\t\tVisitComponent(comp);\n\t\t\t\t\t}\n\n\t\t\t\t\tvariables.PopScope();\n\t\t\t\t\tcompiledWorld->Code = codeWriter.PopNode();\n\t\t\t\t\tEvalReferencedFunctionClosure(compiledWorld);\n\t\t\t\t\tcurrentWorld = nullptr;\n\t\t\t\t}\n\t\t\t\tvariables.PopScope();\n\t\t\t\tcurrentShader = nullptr;\n\t\t\t}\n\n\t\t\tvoid EvalReferencedFunctionClosure(ILWorld * world)\n\t\t\t{\n\t\t\t\tList<String> workList;\n\t\t\t\tfor (auto & rfunc : world->ReferencedFunctions)\n\t\t\t\t\tworkList.Add(rfunc);\n\t\t\t\tfor (int i = 0; i < workList.Count(); i++)\n\t\t\t\t{\n\t\t\t\t\tauto rfunc = workList[i];\n\t\t\t\t\tRefPtr<FunctionSymbol> funcSym;\n\t\t\t\t\tif (symTable->Functions.TryGetValue(rfunc, funcSym))\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto & rrfunc : funcSym->ReferencedFunctions)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tworld->ReferencedFunctions.Add(rrfunc);\n\t\t\t\t\t\t\tworkList.Add(rrfunc);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tvirtual RefPtr<ComponentSyntaxNode> VisitComponent(ComponentSyntaxNode *) override\n\t\t\t{\n\t\t\t\tthrow NotImplementedException();\n\t\t\t}\n\t\t\tvoid VisitComponent(ComponentDefinitionIR * comp)\n\t\t\t{\n\t\t\t\tcurrentComponent = comp;\n\t\t\t\tString varName = EscapeCodeName(currentComponent->OriginalName);\n\t\t\t\tRefPtr<ILType> type = TranslateExpressionType(currentComponent->Type);\n\n\t\t\t\tif (comp->SyntaxNode->IsInput())\n\t\t\t\t{\n\t\t\t\t\tauto loadInput = new LoadInputInstruction(type.Ptr(), comp->UniqueName);\n\t\t\t\t\tcodeWriter.Insert(loadInput);\n\t\t\t\t\tvariables.Add(currentComponent->UniqueName, loadInput);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\telse if (comp->SyntaxNode->IsParam())\n\t\t\t\t{\n\t\t\t\t\tauto moduleInst = compiledShader->ModuleParamSets[comp->ModuleInstance->BindingName]();\n\t\t\t\t\tauto param = moduleInst->Parameters[comp->UniqueName]().Ptr();\n\t\t\t\t\tvariables.Add(currentComponent->UniqueName, param);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tILOperand * componentVar = nullptr;\n\n\t\t\t\tif (currentComponent->SyntaxNode->Expression)\n\t\t\t\t{\n\t\t\t\t\tcurrentComponent->SyntaxNode->Expression->Accept(this);\n\t\t\t\t\tcomponentVar = exprStack.Last();\n\t\t\t\t\texprStack.Clear();\n\t\t\t\t}\n\t\t\t\telse if (currentComponent->SyntaxNode->BlockStatement)\n\t\t\t\t{\n\t\t\t\t\treturnRegister = nullptr;\n\t\t\t\t\tcurrentComponent->SyntaxNode->BlockStatement->Accept(this);\n\t\t\t\t\tcomponentVar = returnRegister;\n\t\t\t\t}\n\n\t\t\t\tif (currentWorld->OutputType->Members.ContainsKey(currentComponent->UniqueName))\n\t\t\t\t{\n\t\t\t\t\tauto exp = new ExportInstruction(currentComponent->UniqueName, currentWorld, componentVar);\n\t\t\t\t\tcodeWriter.Insert(exp);\n\t\t\t\t}\n\n\t\t\t\t/*if (!currentComponent->Type->IsTexture() && !currentComponent->Type->IsArray())\n\t\t\t\t{\n\t\t\t\tauto vartype = TranslateExpressionType(currentComponent->Type.Ptr(), &recordTypes);\n\t\t\t\tauto var = codeWriter.AllocVar(vartype, result.Program->ConstantPool->CreateConstant(1));\n\t\t\t\tvar->Name = varName;\n\t\t\t\tcodeWriter.Store(var, componentVar);\n\t\t\t\tcomponentVar = var;\n\t\t\t\t}\n\t\t\t\telse*/\n\t\t\t\tcomponentVar->Name = varName;\n\t\t\t\tcurrentWorld->Components[currentComponent->UniqueName] = componentVar;\n\t\t\t\tvariables.Add(currentComponent->UniqueName, componentVar);\n\t\t\t\tcurrentComponent = nullptr;\n\t\t\t}\n\t\t\tvirtual RefPtr<FunctionSyntaxNode> VisitFunction(FunctionSyntaxNode* function) override\n\t\t\t{\n\t\t\t\tif (function->IsExtern())\n\t\t\t\t\treturn function;\n\t\t\t\tRefPtr<ILFunction> func = new ILFunction();\n\t\t\t\tresult.Program->Functions.Add(function->InternalName, func);\n\t\t\t\tfunc->Name = function->InternalName;\n\t\t\t\tfunc->ReturnType = TranslateExpressionType(function->ReturnType);\n\t\t\t\tvariables.PushScope();\n\t\t\t\tcodeWriter.PushNode();\n\t\t\t\tint id = 0;\n\t\t\t\tfor (auto &param : function->GetParameters())\n\t\t\t\t{\n\t\t\t\t\tfunc->Parameters.Add(param->Name.Content, ILParameter(TranslateExpressionType(param->Type), GetParamQualifier(param.Ptr())));\n\t\t\t\t\tauto op = FetchArg(param->Type.Ptr(), ++id);\n\t\t\t\t\top->Name = EscapeCodeName(String(\"p_\") + param->Name.Content);\n\t\t\t\t\tvariables.Add(param->Name.Content, op);\n\t\t\t\t}\n\t\t\t\tfunction->Body->Accept(this);\n\t\t\t\tfunc->Code = codeWriter.PopNode();\n\t\t\t\tvariables.PopScope();\n\t\t\t\treturn function;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitBlockStatement(BlockStatementSyntaxNode* stmt) override\n\t\t\t{\n\t\t\t\tvariables.PushScope();\n\t\t\t\tfor (auto & subStmt : stmt->Statements)\n\t\t\t\t\tsubStmt->Accept(this);\n\t\t\t\tvariables.PopScope();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitWhileStatement(WhileStatementSyntaxNode* stmt) override\n\t\t\t{\n\t\t\t\tRefPtr<WhileInstruction> instr = new WhileInstruction();\n\t\t\t\tvariables.PushScope();\n\t\t\t\tcodeWriter.PushNode();\n\t\t\t\tstmt->Predicate->Accept(this);\n\t\t\t\tcodeWriter.Insert(new ReturnInstruction(PopStack()));\n\t\t\t\tinstr->ConditionCode = codeWriter.PopNode();\n\t\t\t\tcodeWriter.PushNode();\n\t\t\t\tstmt->Statement->Accept(this);\n\t\t\t\tinstr->BodyCode = codeWriter.PopNode();\n\t\t\t\tcodeWriter.Insert(instr.Release());\n\t\t\t\tvariables.PopScope();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitDoWhileStatement(DoWhileStatementSyntaxNode* stmt) override\n\t\t\t{\n\t\t\t\tRefPtr<DoInstruction> instr = new DoInstruction();\n\t\t\t\tvariables.PushScope();\n\t\t\t\tcodeWriter.PushNode();\n\t\t\t\tstmt->Predicate->Accept(this);\n\t\t\t\tcodeWriter.Insert(new ReturnInstruction(PopStack()));\n\t\t\t\tinstr->ConditionCode = codeWriter.PopNode();\n\t\t\t\tcodeWriter.PushNode();\n\t\t\t\tstmt->Statement->Accept(this);\n\t\t\t\tinstr->BodyCode = codeWriter.PopNode();\n\t\t\t\tcodeWriter.Insert(instr.Release());\n\t\t\t\tvariables.PopScope();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitForStatement(ForStatementSyntaxNode* stmt) override\n\t\t\t{\n\t\t\t\tRefPtr<ForInstruction> instr = new ForInstruction();\n\t\t\t\tvariables.PushScope();\n\t\t\t\tif (auto initStmt = stmt->InitialStatement.Ptr())\n\t\t\t\t{\n\t\t\t\t\t// TODO(tfoley): any of this push-pop malarky needed here?\n\t\t\t\t\tinitStmt->Accept(this);\n\t\t\t\t}\n\t\t\t\tif (stmt->PredicateExpression)\n\t\t\t\t{\n\t\t\t\t\tcodeWriter.PushNode();\n\t\t\t\t\tstmt->PredicateExpression->Accept(this);\n\t\t\t\t\tPopStack();\n\t\t\t\t\tinstr->ConditionCode = codeWriter.PopNode();\n\t\t\t\t}\n\n\t\t\t\tif (stmt->SideEffectExpression)\n\t\t\t\t{\n\t\t\t\t\tcodeWriter.PushNode();\n\t\t\t\t\tstmt->SideEffectExpression->Accept(this);\n\t\t\t\t\tPopStack();\n\t\t\t\t\tinstr->SideEffectCode = codeWriter.PopNode();\n\t\t\t\t}\n\n\t\t\t\tcodeWriter.PushNode();\n\t\t\t\tstmt->Statement->Accept(this);\n\t\t\t\tinstr->BodyCode = codeWriter.PopNode();\n\t\t\t\tcodeWriter.Insert(instr.Release());\n\t\t\t\tvariables.PopScope();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitIfStatement(IfStatementSyntaxNode* stmt) override\n\t\t\t{\n\t\t\t\tRefPtr<IfInstruction> instr = new IfInstruction();\n\t\t\t\tvariables.PushScope();\n\t\t\t\tstmt->Predicate->Accept(this);\n\t\t\t\tinstr->Operand = PopStack();\n\t\t\t\tcodeWriter.PushNode();\n\t\t\t\tstmt->PositiveStatement->Accept(this);\n\t\t\t\tinstr->TrueCode = codeWriter.PopNode();\n\t\t\t\tif (stmt->NegativeStatement)\n\t\t\t\t{\n\t\t\t\t\tcodeWriter.PushNode();\n\t\t\t\t\tstmt->NegativeStatement->Accept(this);\n\t\t\t\t\tinstr->FalseCode = codeWriter.PopNode();\n\t\t\t\t}\n\t\t\t\tcodeWriter.Insert(instr.Release());\n\t\t\t\tvariables.PopScope();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitReturnStatement(ReturnStatementSyntaxNode* stmt) override\n\t\t\t{\n\t\t\t\treturnRegister = nullptr;\n\t\t\t\tif (currentWorld != nullptr && currentComponent != nullptr && !currentImport)\n\t\t\t\t{\n\t\t\t\t\tif (stmt->Expression)\n\t\t\t\t\t{\n\t\t\t\t\t\tstmt->Expression->Accept(this);\n\t\t\t\t\t\treturnRegister = PopStack();\n\t\t\t\t\t\tif (!currentComponent->SyntaxNode->IsComponentFunction())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (currentWorld->OutputType->Members.ContainsKey(currentComponent->UniqueName))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tauto exp = new ExportInstruction(currentComponent->UniqueName, currentWorld, returnRegister);\n\t\t\t\t\t\t\t\tcodeWriter.Insert(exp);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcodeWriter.Insert(new ReturnInstruction(returnRegister));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (stmt->Expression)\n\t\t\t\t\t{\n\t\t\t\t\t\tstmt->Expression->Accept(this);\n\t\t\t\t\t\treturnRegister = PopStack();\n\t\t\t\t\t}\n\t\t\t\t\tcodeWriter.Insert(new ReturnInstruction(returnRegister));\n\t\t\t\t}\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitBreakStatement(BreakStatementSyntaxNode* stmt) override\n\t\t\t{\n\t\t\t\tcodeWriter.Insert(new BreakInstruction());\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitContinueStatement(ContinueStatementSyntaxNode* stmt) override\n\t\t\t{\n\t\t\t\tcodeWriter.Insert(new ContinueInstruction());\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitSelectExpression(SelectExpressionSyntaxNode * expr) override\n\t\t\t{\n\t\t\t\texpr->SelectorExpr->Accept(this);\n\t\t\t\tauto predOp = PopStack();\n\t\t\t\texpr->Expr0->Accept(this);\n\t\t\t\tauto v0 = PopStack();\n\t\t\t\texpr->Expr1->Accept(this);\n\t\t\t\tauto v1 = PopStack();\n\t\t\t\tPushStack(codeWriter.Select(predOp, v0, v1));\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tILOperand * EnsureBoolType(ILOperand * op, RefPtr<ExpressionType> type)\n\t\t\t{\n\t\t\t\tif (!type->Equals(ExpressionType::Bool.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tauto cmpeq = new CmpneqInstruction();\n\t\t\t\t\tcmpeq->Operands[0] = op;\n\t\t\t\t\tcmpeq->Operands[1] = result.Program->ConstantPool->CreateConstant(0);\n\t\t\t\t\tcmpeq->Type = new ILBasicType(ILBaseType::Int);\n\t\t\t\t\tcodeWriter.Insert(cmpeq);\n\t\t\t\t\treturn cmpeq;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\treturn op;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitDiscardStatement(DiscardStatementSyntaxNode * stmt) override\n\t\t\t{\n\t\t\t\tcodeWriter.Discard();\n\t\t\t\treturn stmt;\n\t\t\t}\n\n\t\t\tRefPtr<Variable> VisitDeclrVariable(Variable* varDecl)\n\t\t\t{\n\t\t\t\tAllocVarInstruction * varOp = AllocVar(varDecl->Type.Ptr());\n\t\t\t\tvarOp->Name = EscapeCodeName(varDecl->Name.Content);\n\t\t\t\tvariables.Add(varDecl->Name.Content, varOp);\n\t\t\t\tif (varDecl->Expr)\n\t\t\t\t{\n\t\t\t\t\tvarDecl->Expr->Accept(this);\n\t\t\t\t\tAssign(varOp, PopStack());\n\t\t\t\t}\n\t\t\t\treturn varDecl;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitExpressionStatement(ExpressionStatementSyntaxNode* stmt) override\n\t\t\t{\n\t\t\t\tstmt->Expression->Accept(this);\n\t\t\t\tPopStack();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvoid Assign(ILOperand * left, ILOperand * right)\n\t\t\t{\n\t\t\t\tif (auto swizzle = dynamic_cast<SwizzleInstruction*>(left))\n\t\t\t\t{\n\t\t\t\t\tauto baseOp = swizzle->Operand.Ptr();\n\t\t\t\t\tint index = 0;\n\t\t\t\t\tfor (int i = 0; i < swizzle->SwizzleString.Length(); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tswitch (swizzle->SwizzleString[i])\n\t\t\t\t\t\t{\n\t\t\t\t\t\tcase 'r':\n\t\t\t\t\t\tcase 'x':\n\t\t\t\t\t\t\tindex = 0;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'g':\n\t\t\t\t\t\tcase 'y':\n\t\t\t\t\t\t\tindex = 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'b':\n\t\t\t\t\t\tcase 'z':\n\t\t\t\t\t\t\tindex = 2;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'a':\n\t\t\t\t\t\tcase 'w':\n\t\t\t\t\t\t\tindex = 3;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcodeWriter.Update(baseOp, result.Program->ConstantPool->CreateConstant(index),\n\t\t\t\t\t\t\tcodeWriter.Retrieve(right, result.Program->ConstantPool->CreateConstant(i)));\n\t\t\t\t\t}\n\t\t\t\t\tswizzle->Erase();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tcodeWriter.Store(left, right);\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitBinaryExpression(BinaryExpressionSyntaxNode* expr) override\n\t\t\t{\n\t\t\t\texpr->RightExpression->Accept(this);\n\t\t\t\tauto right = PopStack();\n\t\t\t\tif (expr->Operator == Operator::Assign)\n\t\t\t\t{\n\t\t\t\t\texpr->LeftExpression->Access = ExpressionAccess::Write;\n\t\t\t\t\texpr->LeftExpression->Accept(this);\n\t\t\t\t\tauto left = PopStack();\n\t\t\t\t\tAssign(left, right);\n\t\t\t\t\tPushStack(left);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\texpr->LeftExpression->Access = ExpressionAccess::Read;\n\t\t\t\t\texpr->LeftExpression->Accept(this);\n\t\t\t\t\tauto left = PopStack();\n\t\t\t\t\tBinaryInstruction * rs = 0;\n\t\t\t\t\tswitch (expr->Operator)\n\t\t\t\t\t{\n\t\t\t\t\tcase Operator::Add:\n\t\t\t\t\tcase Operator::AddAssign:\n\t\t\t\t\t\trs = new AddInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::Sub:\n\t\t\t\t\tcase Operator::SubAssign:\n\t\t\t\t\t\trs = new SubInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::Mul:\n\t\t\t\t\tcase Operator::MulAssign:\n\t\t\t\t\t\trs = new MulInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::Mod:\n\t\t\t\t\tcase Operator::ModAssign:\n\t\t\t\t\t\trs = new ModInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::Div:\n\t\t\t\t\tcase Operator::DivAssign:\n\t\t\t\t\t\trs = new DivInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::And:\n\t\t\t\t\t\trs = new AndInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::Or:\n\t\t\t\t\t\trs = new OrInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::BitAnd:\n\t\t\t\t\tcase Operator::AndAssign:\n\t\t\t\t\t\trs = new BitAndInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::BitOr:\n\t\t\t\t\tcase Operator::OrAssign:\n\t\t\t\t\t\trs = new BitOrInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::BitXor:\n\t\t\t\t\tcase Operator::XorAssign:\n\t\t\t\t\t\trs = new BitXorInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::Lsh:\n\t\t\t\t\tcase Operator::LshAssign:\n\t\t\t\t\t\trs = new ShlInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::Rsh:\n\t\t\t\t\tcase Operator::RshAssign:\n\t\t\t\t\t\trs = new ShrInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::Eql:\n\t\t\t\t\t\trs = new CmpeqlInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::Neq:\n\t\t\t\t\t\trs = new CmpneqInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::Greater:\n\t\t\t\t\t\trs = new CmpgtInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::Geq:\n\t\t\t\t\t\trs = new CmpgeInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::Leq:\n\t\t\t\t\t\trs = new CmpleInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Operator::Less:\n\t\t\t\t\t\trs = new CmpltInstruction();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow NotImplementedException(\"Code gen not implemented for this operator.\");\n\t\t\t\t\t}\n\t\t\t\t\trs->Operands.SetSize(2);\n\t\t\t\t\trs->Operands[0] = left;\n\t\t\t\t\trs->Operands[1] = right;\n\t\t\t\t\trs->Type = TranslateExpressionType(expr->Type);\n\t\t\t\t\tcodeWriter.Insert(rs);\n\t\t\t\t\tswitch (expr->Operator)\n\t\t\t\t\t{\n\t\t\t\t\tcase Operator::AddAssign:\n\t\t\t\t\tcase Operator::SubAssign:\n\t\t\t\t\tcase Operator::MulAssign:\n\t\t\t\t\tcase Operator::DivAssign:\n\t\t\t\t\tcase Operator::ModAssign:\n\t\t\t\t\tcase Operator::LshAssign:\n\t\t\t\t\tcase Operator::RshAssign:\n\t\t\t\t\tcase Operator::AndAssign:\n\t\t\t\t\tcase Operator::OrAssign:\n\t\t\t\t\tcase Operator::XorAssign:\n\t\t\t\t\t{\n\t\t\t\t\t\texpr->LeftExpression->Access = ExpressionAccess::Write;\n\t\t\t\t\t\texpr->LeftExpression->Accept(this);\n\t\t\t\t\t\tauto target = PopStack();\n\t\t\t\t\t\tAssign(target, rs);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tPushStack(rs);\n\t\t\t\t}\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitProject(ProjectExpressionSyntaxNode * project) override\n\t\t\t{\n\t\t\t\tproject->BaseExpression->Accept(this);\n\t\t\t\tauto rs = PopStack();\n\t\t\t\tauto proj = new ProjectInstruction();\n\t\t\t\tproj->ComponentName = currentImport->ComponentUniqueName;\n\t\t\t\tproj->Operand = rs;\n\t\t\t\tcodeWriter.Insert(proj);\n\t\t\t\tPushStack(proj);\n\t\t\t\treturn project;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitConstantExpression(ConstantExpressionSyntaxNode* expr) override\n\t\t\t{\n\t\t\t\tILConstOperand * op;\n\t\t\t\tif (expr->ConstType == ConstantExpressionSyntaxNode::ConstantType::Float)\n\t\t\t\t{\n\t\t\t\t\top = result.Program->ConstantPool->CreateConstant(expr->FloatValue);\n\t\t\t\t}\n\t\t\t\telse if (expr->ConstType == ConstantExpressionSyntaxNode::ConstantType::Bool)\n\t\t\t\t{\n\t\t\t\t\top = result.Program->ConstantPool->CreateConstant(expr->IntValue != 0);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (expr->Type->Equals(ExpressionType::UInt))\n\t\t\t\t\t\top = result.Program->ConstantPool->CreateConstantU((unsigned int)(expr->IntValue));\n\t\t\t\t\telse\n\t\t\t\t\t\top = result.Program->ConstantPool->CreateConstant(expr->IntValue);\n\t\t\t\t}\n\t\t\t\tPushStack(op);\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvoid GenerateIndexExpression(ILOperand * base, ILOperand * idx)\n\t\t\t{\n\t\t\t\tauto ldInstr = codeWriter.Retrieve(base, idx);\n\t\t\t\tldInstr->Attribute = base->Attribute;\n\t\t\t\tPushStack(ldInstr);\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitImportExpression(ImportExpressionSyntaxNode * expr) override\n\t\t\t{\n\t\t\t\tvariables.PushScope();\n\t\t\t\tList<ILOperand*> arguments;\n\t\t\t\tint argIndex = 0;\n\t\t\t\tfor (auto param : expr->ImportOperatorDef->GetParameters())\n\t\t\t\t{\n\t\t\t\t\texpr->Arguments[argIndex]->Accept(this);\n\t\t\t\t\tauto argOp = PopStack();\n\t\t\t\t\targuments.Add(argOp);\n\t\t\t\t\tvariables.Add(param->Name.Content, argOp);\n\t\t\t\t\targIndex++;\n\t\t\t\t}\n\t\t\t\tcurrentImport = expr;\n\t\t\t\tauto oldTypeMapping = genericTypeMappings.TryGetValue(expr->ImportOperatorDef->TypeName.Content);\n\t\t\t\tauto componentType = TranslateExpressionType(expr->Type);\n\t\t\t\tgenericTypeMappings[expr->ImportOperatorDef->TypeName.Content] = componentType;\n\t\t\t\tcodeWriter.PushNode();\n\t\t\t\texpr->ImportOperatorDef->Body->Accept(this);\n\t\t\t\tcurrentImport = nullptr;\n\t\t\t\tauto impInstr = new ImportInstruction(expr->Arguments.Count());\n\t\t\t\tfor (int i = 0; i < expr->Arguments.Count(); i++)\n\t\t\t\t\timpInstr->Arguments[i] = arguments[i];\n\t\t\t\timpInstr->ImportOperator = codeWriter.PopNode();\n\t\t\t\tvariables.PopScope();\n\t\t\t\tif (oldTypeMapping)\n\t\t\t\t\tgenericTypeMappings[expr->ImportOperatorDef->TypeName.Content] = *oldTypeMapping;\n\t\t\t\telse\n\t\t\t\t\tgenericTypeMappings.Remove(expr->ImportOperatorDef->TypeName.Content);\n\t\t\t\timpInstr->ComponentName = expr->ComponentUniqueName;\n\t\t\t\timpInstr->Type = TranslateExpressionType(expr->Type);\n\t\t\t\tcodeWriter.Insert(impInstr);\n\t\t\t\tPushStack(impInstr);\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitIndexExpression(IndexExpressionSyntaxNode* expr) override\n\t\t\t{\n\t\t\t\texpr->BaseExpression->Access = expr->Access;\n\t\t\t\texpr->BaseExpression->Accept(this);\n\t\t\t\tauto base = PopStack();\n\t\t\t\texpr->IndexExpression->Access = ExpressionAccess::Read;\n\t\t\t\texpr->IndexExpression->Accept(this);\n\t\t\t\tauto idx = PopStack();\n\t\t\t\tGenerateIndexExpression(base, idx);\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitMemberExpression(MemberExpressionSyntaxNode * expr) override\n\t\t\t{\n\t\t\t\tRefPtr<Object> refObj;\n\t\t\t\tif (expr->Tags.TryGetValue(\"ComponentReference\", refObj))\n\t\t\t\t{\n\t\t\t\t\tif (auto refComp = refObj.As<StringObject>())\n\t\t\t\t\t{\n\t\t\t\t\t\tILOperand * op;\n\t\t\t\t\t\tif (variables.TryGetValue(refComp->Content, op))\n\t\t\t\t\t\t\tPushStack(op);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tthrow InvalidProgramException(\"referencing undefined component/variable. probable cause: unchecked circular reference.\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\texpr->BaseExpression->Access = expr->Access;\n\t\t\t\t\texpr->BaseExpression->Accept(this);\n\t\t\t\t\tauto base = PopStack();\n\t\t\t\t\tauto generateSingleMember = [&](char memberName)\n\t\t\t\t\t{\n\t\t\t\t\t\tint idx = 0;\n\t\t\t\t\t\tif (memberName == 'y' || memberName == 'g')\n\t\t\t\t\t\t\tidx = 1;\n\t\t\t\t\t\telse if (memberName == 'z' || memberName == 'b')\n\t\t\t\t\t\t\tidx = 2;\n\t\t\t\t\t\telse if (memberName == 'w' || memberName == 'a')\n\t\t\t\t\t\t\tidx = 3;\n\n\t\t\t\t\t\tGenerateIndexExpression(base, result.Program->ConstantPool->CreateConstant(idx));\n\t\t\t\t\t};\n\t\t\t\t\tif (expr->BaseExpression->Type->IsVectorType())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (expr->MemberName.Length() == 1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgenerateSingleMember(expr->MemberName[0]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto rs = new SwizzleInstruction();\n\t\t\t\t\t\t\trs->Type = TranslateExpressionType(expr->Type.Ptr());\n\t\t\t\t\t\t\trs->SwizzleString = expr->MemberName;\n\t\t\t\t\t\t\trs->Operand = base;\n\t\t\t\t\t\t\tcodeWriter.Insert(rs);\n\t\t\t\t\t\t\tPushStack(rs);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (expr->BaseExpression->Type->IsStruct())\n\t\t\t\t\t{\n\t\t\t\t\t\tint id = expr->BaseExpression->Type->AsBasicType()->structDecl->FindFieldIndex(expr->MemberName);\n\t\t\t\t\t\tGenerateIndexExpression(base, result.Program->ConstantPool->CreateConstant(id));\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow NotImplementedException(\"member expression codegen\");\n\t\t\t\t}\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitInvokeExpression(InvokeExpressionSyntaxNode* expr) override\n\t\t\t{\n\t\t\t\tList<ILOperand*> args;\n\t\t\t\tString funcName;\n\t\t\t\tbool hasSideEffect = false;\n\t\t\t\tif (auto basicType = expr->FunctionExpr->Type->AsBasicType())\n\t\t\t\t{\n\t\t\t\t\tif (basicType->Func)\n\t\t\t\t\t{\n\t\t\t\t\t\tfuncName = basicType->Func->SyntaxNode->IsExtern() ? basicType->Func->SyntaxNode->Name.Content : basicType->Func->SyntaxNode->InternalName;\n\t\t\t\t\t\tfor (auto & param : basicType->Func->SyntaxNode->GetParameters())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (param->HasModifier(ModifierFlag::Out))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\thasSideEffect = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (basicType->Component)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto funcCompName = expr->FunctionExpr->Tags[\"ComponentReference\"]().As<StringObject>()->Content;\n\t\t\t\t\t\tauto funcComp = *(currentShader->DefinitionsByComponent[funcCompName]().TryGetValue(currentComponent->World));\n\t\t\t\t\t\tfuncName = GetComponentFunctionName(funcComp->SyntaxNode.Ptr());\n\t\t\t\t\t\tfor (auto & param : funcComp->SyntaxNode->GetParameters())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (param->HasModifier(ModifierFlag::Out))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\thasSideEffect = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// push additional arguments\n\t\t\t\t\t\tfor (auto & dep : funcComp->GetComponentFunctionDependencyClosure())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!dep->SyntaxNode->IsComponentFunction())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tILOperand * op = nullptr;\n\t\t\t\t\t\t\t\tif (variables.TryGetValue(dep->UniqueName, op))\n\t\t\t\t\t\t\t\t\targs.Add(op);\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tthrow InvalidProgramException(\"cannot resolve reference for implicit component function argument.\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (currentWorld)\n\t\t\t\t{\n\t\t\t\t\tcurrentWorld->ReferencedFunctions.Add(funcName);\n\t\t\t\t}\n\t\t\t\tif (currentFunc)\n\t\t\t\t\tcurrentFunc->ReferencedFunctions.Add(funcName);\n\t\t\t\tfor (auto arg : expr->Arguments)\n\t\t\t\t{\n\t\t\t\t\targ->Accept(this);\n\t\t\t\t\targs.Add(PopStack());\n\t\t\t\t}\n\t\t\t\tauto instr = new CallInstruction(args.Count());\n\t\t\t\tinstr->SideEffect = hasSideEffect;\n\t\t\t\tinstr->Function = funcName;\n\t\t\t\tfor (int i = 0; i < args.Count(); i++)\n\t\t\t\t\tinstr->Arguments[i] = args[i];\n\t\t\t\tinstr->Type = TranslateExpressionType(expr->Type);\n\t\t\t\tcodeWriter.Insert(instr);\n\t\t\t\tPushStack(instr);\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitTypeCastExpression(TypeCastExpressionSyntaxNode * expr) override\n\t\t\t{\n\t\t\t\texpr->Expression->Accept(this);\n\t\t\t\tauto base = PopStack();\n\t\t\t\tif (expr->Expression->Type == expr->Type)\n\t\t\t\t{\n\t\t\t\t\tPushStack(base);\n\t\t\t\t}\n\t\t\t\telse if (expr->Expression->Type == ExpressionType::Float &&\n\t\t\t\t\texpr->Type == ExpressionType::Int)\n\t\t\t\t{\n\t\t\t\t\tauto instr = new Float2IntInstruction(base);\n\t\t\t\t\tcodeWriter.Insert(instr);\n\t\t\t\t\tPushStack(instr);\n\t\t\t\t}\n\t\t\t\telse if (expr->Expression->Type == ExpressionType::Int &&\n\t\t\t\t\texpr->Type == ExpressionType::Float)\n\t\t\t\t{\n\t\t\t\t\tauto instr = new Int2FloatInstruction(base);\n\t\t\t\t\tcodeWriter.Insert(instr);\n\t\t\t\t\tPushStack(instr);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::invalidTypeCast, expr->Expression->Type, expr->Type);\n\t\t\t\t}\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitUnaryExpression(UnaryExpressionSyntaxNode* expr) override\n\t\t\t{\n\t\t\t\tif (expr->Operator == Operator::PostDec || expr->Operator == Operator::PostInc\n\t\t\t\t\t|| expr->Operator == Operator::PreDec || expr->Operator == Operator::PreInc)\n\t\t\t\t{\n\t\t\t\t\texpr->Expression->Access = ExpressionAccess::Read;\n\t\t\t\t\texpr->Expression->Accept(this);\n\t\t\t\t\tauto base = PopStack();\n\t\t\t\t\tBinaryInstruction * instr;\n\t\t\t\t\tif (expr->Operator == Operator::PostDec)\n\t\t\t\t\t\tinstr = new SubInstruction();\n\t\t\t\t\telse\n\t\t\t\t\t\tinstr = new AddInstruction();\n\t\t\t\t\tinstr->Operands.SetSize(2);\n\t\t\t\t\tinstr->Operands[0] = base;\n\t\t\t\t\tif (expr->Type == ExpressionType::Float)\n\t\t\t\t\t\tinstr->Operands[1] = result.Program->ConstantPool->CreateConstant(1.0f);\n\t\t\t\t\telse\n\t\t\t\t\t\tinstr->Operands[1] = result.Program->ConstantPool->CreateConstant(1);\n\t\t\t\t\tinstr->Type = TranslateExpressionType(expr->Type);\n\t\t\t\t\tcodeWriter.Insert(instr);\n\n\t\t\t\t\texpr->Expression->Access = ExpressionAccess::Write;\n\t\t\t\t\texpr->Expression->Accept(this);\n\t\t\t\t\tauto dest = PopStack();\n\t\t\t\t\tauto store = new StoreInstruction(dest, instr);\n\t\t\t\t\tcodeWriter.Insert(store);\n\t\t\t\t\tPushStack(base);\n\t\t\t\t}\n\t\t\t\telse if (expr->Operator == Operator::PreDec || expr->Operator == Operator::PreInc)\n\t\t\t\t{\n\t\t\t\t\texpr->Expression->Access = ExpressionAccess::Read;\n\t\t\t\t\texpr->Expression->Accept(this);\n\t\t\t\t\tauto base = PopStack();\n\t\t\t\t\tBinaryInstruction * instr;\n\t\t\t\t\tif (expr->Operator == Operator::PostDec)\n\t\t\t\t\t\tinstr = new SubInstruction();\n\t\t\t\t\telse\n\t\t\t\t\t\tinstr = new AddInstruction();\n\t\t\t\t\tinstr->Operands.SetSize(2);\n\t\t\t\t\tinstr->Operands[0] = base;\n\t\t\t\t\tif (expr->Type == ExpressionType::Float)\n\t\t\t\t\t\tinstr->Operands[1] = result.Program->ConstantPool->CreateConstant(1.0f);\n\t\t\t\t\telse\n\t\t\t\t\t\tinstr->Operands[1] = result.Program->ConstantPool->CreateConstant(1);\n\t\t\t\t\tinstr->Type = TranslateExpressionType(expr->Type);\n\t\t\t\t\tcodeWriter.Insert(instr);\n\n\t\t\t\t\texpr->Expression->Access = ExpressionAccess::Write;\n\t\t\t\t\texpr->Expression->Accept(this);\n\t\t\t\t\tauto dest = PopStack();\n\t\t\t\t\tauto store = new StoreInstruction(dest, instr);\n\t\t\t\t\tcodeWriter.Insert(store);\n\t\t\t\t\tPushStack(instr);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\texpr->Expression->Accept(this);\n\t\t\t\t\tauto base = PopStack();\n\t\t\t\t\tauto genUnaryInstr = [&](ILOperand * input)\n\t\t\t\t\t{\n\t\t\t\t\t\tUnaryInstruction * rs = 0;\n\t\t\t\t\t\tswitch (expr->Operator)\n\t\t\t\t\t\t{\n\t\t\t\t\t\tcase Operator::Not:\n\t\t\t\t\t\t\tinput = EnsureBoolType(input, expr->Expression->Type);\n\t\t\t\t\t\t\trs = new NotInstruction();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase Operator::Neg:\n\t\t\t\t\t\t\trs = new NegInstruction();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase Operator::BitNot:\n\t\t\t\t\t\t\trs = new BitNotInstruction();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow NotImplementedException(\"Code gen is not implemented for this operator.\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\trs->Operand = input;\n\t\t\t\t\t\trs->Type = input->Type;\n\t\t\t\t\t\tcodeWriter.Insert(rs);\n\t\t\t\t\t\treturn rs;\n\t\t\t\t\t};\n\t\t\t\t\tPushStack(genUnaryInstr(base));\n\t\t\t\t}\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tbool GenerateVarRef(String name, ExpressionAccess access)\n\t\t\t{\n\t\t\t\tILOperand * var = 0;\n\t\t\t\tString srcName = name;\n\t\t\t\tif (!variables.TryGetValue(srcName, var))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif (access == ExpressionAccess::Read)\n\t\t\t\t{\n\t\t\t\t\tPushStack(var);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tPushStack(var);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitVarExpression(VarExpressionSyntaxNode* expr) override\n\t\t\t{\n\t\t\t\tRefPtr<Object> refObj;\n\t\t\t\tif (expr->Tags.TryGetValue(\"ComponentReference\", refObj))\n\t\t\t\t{\n\t\t\t\t\tif (auto refComp = refObj.As<StringObject>())\n\t\t\t\t\t{\n\t\t\t\t\t\tILOperand * op;\n\t\t\t\t\t\tif (variables.TryGetValue(refComp->Content, op))\n\t\t\t\t\t\t\tPushStack(op);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tthrow InvalidProgramException(String(\"referencing undefined component/variable '\") + refComp->Content + \"'. probable cause: unchecked circular reference.\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (!GenerateVarRef(expr->Variable, expr->Access))\n\t\t\t\t{\n\t\t\t\t\tthrow InvalidProgramException(\"identifier is neither a variable nor a recognized component.\");\n\t\t\t\t}\n\t\t\t\treturn expr;\n\t\t\t}\n\t\tprivate:\n\t\t\tCodeGenerator & operator = (const CodeGenerator & other) = delete;\n\t\tpublic:\n\t\t\tCodeGenerator(SymbolTable * symbols, DiagnosticSink * pErr, CompileResult & _result, LayoutRule defaultLayoutRule)\n\t\t\t\t: ICodeGenerator(pErr), symTable(symbols), result(_result), defaultLayoutRule(defaultLayoutRule)\n\t\t\t{\n\t\t\t\tresult.Program = new ILProgram();\n\t\t\t\tcodeWriter.SetConstantPool(result.Program->ConstantPool.Ptr());\n\t\t\t}\n\n\t\tprivate:\n\t\t\tRefPtr<ILStructType> TranslateStructType(StructSyntaxNode* structDecl)\n\t\t\t{\n\t\t\t\tRefPtr<ILStructType> ilStructType;\n\n\t\t\t\tif (structTypes.TryGetValue(structDecl, ilStructType))\n\t\t\t\t{\n\t\t\t\t\treturn ilStructType;\n\t\t\t\t}\n\n\t\t\t\tilStructType = new ILStructType();\n\t\t\t\tilStructType->TypeName = structDecl->Name.Content;\n\t\t\t\tilStructType->IsIntrinsic = structDecl->IsIntrinsic;\n\n\n\t\t\t\tfor (auto field : structDecl->GetFields())\n\t\t\t\t{\n\t\t\t\t\tILStructType::ILStructField ilField;\n\t\t\t\t\tilField.FieldName = field->Name.Content;\n\t\t\t\t\tilField.Type = TranslateExpressionType(field->Type.Ptr());\n\t\t\t\t\tilStructType->Members.Add(ilField);\n\t\t\t\t}\n\n\t\t\t\tstructTypes.Add(structDecl, ilStructType);\n\t\t\t\treturn ilStructType;\n\t\t\t}\n\n\t\t\tRefPtr<ILType> TranslateExpressionType(ExpressionType * type)\n\t\t\t{\n\t\t\t\tRefPtr<ILType> resultType = 0;\n\t\t\t\tif (auto basicType = type->AsBasicType())\n\t\t\t\t{\n\t\t\t\t\tif (basicType->BaseType == BaseType::Struct)\n\t\t\t\t\t{\n\t\t\t\t\t\tresultType = TranslateStructType(basicType->structDecl);\n\t\t\t\t\t}\n\t\t\t\t\telse if (basicType->BaseType == BaseType::Record)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn genericTypeMappings[basicType->RecordTypeName]();\n\t\t\t\t\t}\n\t\t\t\t\telse if (basicType->BaseType == BaseType::Generic)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn genericTypeMappings[basicType->GenericTypeVar]();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tauto base = new ILBasicType();\n\t\t\t\t\t\tbase->Type = (ILBaseType)basicType->BaseType;\n\t\t\t\t\t\tresultType = base;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (auto arrType = type->AsArrayType())\n\t\t\t\t{\n\t\t\t\t\tauto nArrType = new ILArrayType();\n\t\t\t\t\tnArrType->BaseType = TranslateExpressionType(arrType->BaseType.Ptr());\n\t\t\t\t\tnArrType->ArrayLength = arrType->ArrayLength;\n\t\t\t\t\tresultType = nArrType;\n\t\t\t\t}\n\t\t\t\telse if (auto genType = type->AsGenericType())\n\t\t\t\t{\n\t\t\t\t\tauto gType = new ILGenericType();\n\t\t\t\t\tgType->GenericTypeName = genType->GenericTypeName;\n\t\t\t\t\tgType->BaseType = TranslateExpressionType(genType->BaseType.Ptr());\n\t\t\t\t\tresultType = gType;\n\t\t\t\t}\n\t\t\t\treturn resultType;\n\t\t\t}\n\n\t\t\tRefPtr<ILType> TranslateExpressionType(const RefPtr<ExpressionType> & type)\n\t\t\t{\n\t\t\t\treturn TranslateExpressionType(type.Ptr());\n\t\t\t}\n\n\t\t};\n\n\t\tICodeGenerator * CreateCodeGenerator(SymbolTable * symbols, CompileResult & result, CodeGenBackend* backend)\n\t\t{\n\t\t\treturn new CodeGenerator(symbols, result.GetErrorWriter(), result, backend->GetDefaultLayoutRule());\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Source/SpireCore/CodeWriter.h",
    "content": "#ifndef IL_CODE_WRITER_H\n#define IL_CODE_WRITER_H\n\n#include \"IL.h\"\n#include \"ShaderCompiler.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tclass CodeWriter\n\t\t{\n\t\tprivate:\n\t\t\tList<RefPtr<CFGNode>> cfgNode;\n\t\t\tConstantPool * constantPool = nullptr;\n\t\tpublic:\n\t\t\tvoid SetConstantPool(ConstantPool * pool)\n\t\t\t{\n\t\t\t\tconstantPool = pool;\n\t\t\t}\n\t\t\tCFGNode * GetCurrentNode()\n\t\t\t{\n\t\t\t\treturn cfgNode.Last().Ptr();\n\t\t\t}\n\t\t\tvoid PushNode()\n\t\t\t{\n\t\t\t\tRefPtr<CFGNode> n = new CFGNode();\n\t\t\t\tcfgNode.Add(n);\n\t\t\t}\n\t\t\tRefPtr<CFGNode> PopNode()\n\t\t\t{\n\t\t\t\tauto rs = cfgNode.Last();\n\t\t\t\tcfgNode.SetSize(cfgNode.Count() - 1);\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tvoid Assign(ILType * type, ILOperand * dest, ILOperand * src) // handles base type and ILArrayType assignment\n\t\t\t{\n\t\t\t\tauto arrType = dynamic_cast<ILArrayType*>(type);\n\t\t\t\tif (arrType)\n\t\t\t\t{\n\t\t\t\t\tfor (int i = 0; i < arrType->ArrayLength; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto srcAddr = Add(src, i);\n\t\t\t\t\t\tauto destAddr = Add(dest, i);\n\t\t\t\t\t\tStore(destAddr, Load(srcAddr));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tStore(dest, Load(src));\n\t\t\t}\n\t\t\tILOperand * Select(ILOperand * cond, ILOperand * v0, ILOperand * v1)\n\t\t\t{\n\t\t\t\tauto rs = new SelectInstruction(cond, v0, v1);\n\t\t\t\tcfgNode.Last()->InsertTail(rs);\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tILOperand * BitAnd(ILOperand * v0, ILOperand * v1)\n\t\t\t{\n\t\t\t\tauto instr = new BitAndInstruction(v0, v1);\n\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\treturn instr;\n\t\t\t}\n\t\t\tILOperand * BitAnd(ILOperand * v0, int c)\n\t\t\t{\n\t\t\t\tauto instr = new BitAndInstruction(v0, constantPool->CreateConstant(c));\n\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\treturn instr;\n\t\t\t}\n\t\t\tILOperand * Add(ILOperand * v0, ILOperand * v1)\n\t\t\t{\n\t\t\t\tauto instr = new AddInstruction(v0, v1);\n\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\treturn instr;\n\t\t\t}\n\t\t\tILOperand * Add(ILOperand * v0, int v1)\n\t\t\t{\n\t\t\t\tauto instr = new AddInstruction(v0, constantPool->CreateConstant(v1));\n\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\treturn instr;\n\t\t\t}\n\t\t\tILOperand * Mul(ILOperand * v0, ILOperand * v1)\n\t\t\t{\n\t\t\t\tauto instr = new MulInstruction(v0, v1);\n\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\treturn instr;\n\t\t\t}\n\t\t\tILOperand * Copy(ILOperand * src)\n\t\t\t{\n\t\t\t\tauto rs = new CopyInstruction(src);\n\t\t\t\tcfgNode.Last()->InsertTail(rs);\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tILOperand * Load(ILOperand * src, int offset)\n\t\t\t{\n\t\t\t\tif (offset == 0)\n\t\t\t\t{\n\t\t\t\t\tauto instr = new LoadInstruction(src);\n\t\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\t\treturn instr;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto dest = new AddInstruction(src, constantPool->CreateConstant(offset));\n\t\t\t\t\tcfgNode.Last()->InsertTail(dest);\n\t\t\t\t\tauto instr = new LoadInstruction(dest);\n\t\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\t\treturn instr;\n\t\t\t\t}\n\t\t\t}\n\t\t\tILOperand * Load(ILOperand * src)\n\t\t\t{\n\t\t\t\tauto instr = new LoadInstruction(src);\n\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\treturn instr;\n\t\t\t}\n\t\t\tILOperand * Load(ILOperand * src, ILOperand * offset)\n\t\t\t{\n\t\t\t\tauto dest = new AddInstruction(src, offset);\n\t\t\t\tcfgNode.Last()->InsertTail(dest);\n\t\t\t\treturn Load(dest);\n\t\t\t}\n\t\t\tStoreInstruction * Store(ILOperand * dest, ILOperand * value)\n\t\t\t{\n\t\t\t\tauto instr = new StoreInstruction(dest, value);\n\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\treturn instr;\n\t\t\t}\n\t\t\tDiscardInstruction * Discard()\n\t\t\t{\n\t\t\t\tauto instr = new DiscardInstruction();\n\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\treturn instr;\n\t\t\t}\n\t\t\tMemberUpdateInstruction * Update(ILOperand * dest, ILOperand * offset, ILOperand * value)\n\t\t\t{\n\t\t\t\tauto instr = new MemberUpdateInstruction(dest, offset, value);\n\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\treturn instr;\n\t\t\t}\n\t\t\tMemberLoadInstruction * Retrieve(ILOperand * dest, ILOperand * offset)\n\t\t\t{\n\t\t\t\tauto instr = new MemberLoadInstruction(dest, offset);\n\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\treturn instr;\n\t\t\t}\n\t\t\t//AllocVarInstruction * AllocVar(ILType * type, ILOperand * size)\n\t\t\t//{\n\t\t\t//\tauto arrType = dynamic_cast<ILArrayType*>(type);\n\t\t\t//\tif (arrType)\n\t\t\t//\t{\n\t\t\t//\t\t// check: size must be constant 1. Do not support array of array in IL level.\n\t\t\t//\t\tauto s = dynamic_cast<ILConstOperand*>(size);\n\t\t\t//\t\tif (!s || s->IntValues[0] != 1)\n\t\t\t//\t\t\tthrow ArgumentException(\"AllocVar(arrayType, size): size must be constant 1.\");\n\t\t\t//\t\tauto instr = new AllocVarInstruction(arrType->BaseType, program.CreateConstant(arrType->ArrayLength));\n\t\t\t//\t\tcfgNode->InsertTail(instr);\n\t\t\t//\t\treturn instr;\n\t\t\t//\t}\n\t\t\t//\telse\n\t\t\t//\t{\n\t\t\t//\t\tauto instr = new AllocVarInstruction(type, size);\n\t\t\t//\t\tcfgNode->InsertTail(instr);\n\t\t\t//\t\treturn instr;\n\t\t\t//\t}\n\t\t\t//}\n\t\t\tAllocVarInstruction * AllocVar(RefPtr<ILType> & type, ILOperand * size)\n\t\t\t{\n\t\t\t\tauto arrType = dynamic_cast<ILArrayType*>(type.Ptr());\n\t\t\t\tif (arrType)\n\t\t\t\t{\n\t\t\t\t\t// check: size must be constant 1. Do not support array of array in IL level.\n\t\t\t\t\tauto s = dynamic_cast<ILConstOperand*>(size);\n\t\t\t\t\tif (!s || s->IntValues[0] != 1)\n\t\t\t\t\t\tthrow ArgumentException(\"AllocVar(arrayType, size): size must be constant 1.\");\n\t\t\t\t\tauto instr = new AllocVarInstruction(arrType->BaseType, constantPool->CreateConstant(arrType->ArrayLength));\n\t\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\t\treturn instr;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto instr = new AllocVarInstruction(type, size);\n\t\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\t\treturn instr;\n\t\t\t\t}\n\t\t\t}\n\t\t\t/*GLeaInstruction * GLea(ILType * type, const String & name)\n\t\t\t{\n\t\t\t\tauto arrType = dynamic_cast<ILArrayType*>(type);\n\t\t\t\tauto instr = new GLeaInstruction();\n\t\t\t\tif (arrType)\n\t\t\t\t\tinstr->Type = new ILPointerType(arrType->BaseType);\n\t\t\t\telse\n\t\t\t\t\tinstr->Type = new ILPointerType(type);\n\t\t\t\tinstr->Name = name;\n\t\t\t\tinstr->VariableName = name;\n\t\t\t\tcfgNode->InsertTail(instr);\n\t\t\t\treturn instr;\n\t\t\t}*/\n\t\t\tFetchArgInstruction * FetchArg(RefPtr<ILType> type, int argId)\n\t\t\t{\n\t\t\t\tauto instr = new FetchArgInstruction(type);\n\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t\tinstr->ArgId = argId;\n\t\t\t\treturn instr;\n\t\t\t}\n\t\t\t\n\t\t\tvoid Insert(ILInstruction * instr)\n\t\t\t{\n\t\t\t\tcfgNode.Last()->InsertTail(instr);\n\t\t\t}\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/CompiledProgram.cpp",
    "content": "#include \"CompiledProgram.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tvoid IndentString(StringBuilder & sb, String src)\n\t\t{\n\t\t\tint indent = 0;\n\t\t\tbool beginTrim = true;\n\t\t\tfor (int c = 0; c < src.Length(); c++)\n\t\t\t{\n\t\t\t\tauto ch = src[c];\n\t\t\t\tif (ch == '\\n')\n\t\t\t\t{\n\t\t\t\t\tsb << \"\\n\";\n\n\t\t\t\t\tbeginTrim = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (beginTrim)\n\t\t\t\t\t{\n\t\t\t\t\t\twhile (c < src.Length() - 1 && (src[c] == '\\t' || src[c] == '\\n' || src[c] == '\\r' || src[c] == ' '))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tc++;\n\t\t\t\t\t\t\tch = src[c];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (int i = 0; i < indent - 1; i++)\n\t\t\t\t\t\t\tsb << '\\t';\n\t\t\t\t\t\tif (ch != '}' && indent > 0)\n\t\t\t\t\t\t\tsb << '\\t';\n\t\t\t\t\t\tbeginTrim = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (ch == '{')\n\t\t\t\t\t\tindent++;\n\t\t\t\t\telse if (ch == '}')\n\t\t\t\t\t\tindent--;\n\t\t\t\t\tif (indent < 0)\n\t\t\t\t\t\tindent = 0;\n\n\t\t\t\t\tsb << ch;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tShaderChoiceValue ShaderChoiceValue::Parse(String str)\n\t\t{\n\t\t\treturn ShaderChoiceValue(str);\n\t\t}\n\t\t\n}\n}"
  },
  {
    "path": "Source/SpireCore/CompiledProgram.h",
    "content": "#ifndef BAKER_SL_COMPILED_PROGRAM_H\n#define BAKER_SL_COMPILED_PROGRAM_H\n\n#include \"../CoreLib/Basic.h\"\n#include \"Diagnostics.h\"\n#include \"IL.h\"\n#include \"Syntax.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tclass ConstantPoolImpl;\n\n\t\tclass ConstantPool\n\t\t{\n\t\tprivate:\n\t\t\tConstantPoolImpl * impl;\n\t\tpublic:\n\t\t\tILConstOperand * CreateConstant(ILConstOperand * c);\n\t\t\tILConstOperand * CreateConstantIntVec(int val0, int val1);\n\t\t\tILConstOperand * CreateConstantIntVec(int val0, int val1, int val2);\n\t\t\tILConstOperand * CreateConstantIntVec(int val0, int val1, int val3, int val4);\n\t\t\tILConstOperand * CreateConstant(int val, int vectorSize = 0);\n\t\t\tILConstOperand * CreateConstant(float val, int vectorSize = 0);\n\t\t\tILConstOperand * CreateConstant(float val, float val1);\n\t\t\tILConstOperand * CreateConstant(float val, float val1, float val2);\n\t\t\tILConstOperand * CreateConstant(float val, float val1, float val2, float val3);\n\t\t\tILConstOperand * CreateConstant(bool b);\n\t\t\tILConstOperand * CreateConstantU(unsigned int u);\n\n\t\t\tILOperand * CreateDefaultValue(ILType * type);\n\t\t\tILUndefinedOperand * GetUndefinedOperand();\n\t\t\tConstantPool();\n\t\t\t~ConstantPool();\n\t\t};\n\n\t\tclass ILShader;\n\n\t\tclass ILWorld : public Object\n\t\t{\n\t\tpublic:\n\t\t\tString Name;\n\t\t\tCodePosition Position;\n\t\t\tRefPtr<ILRecordType> OutputType;\n\t\t\tList<ILObjectDefinition> Inputs;\n\t\t\tRefPtr<CFGNode> Code;\n\t\t\tEnumerableDictionary<String, ILOperand*> Components;\n\t\t\tbool IsAbstract = false;\n\t\t\tEnumerableDictionary<String, Token> Attributes;\n\t\t\tEnumerableHashSet<String> ReferencedFunctions; // internal names of referenced functions\n\t\t\tILShader * Shader = nullptr;\n\t\t};\n\n\t\tclass StageAttribute\n\t\t{\n\t\tpublic:\n\t\t\tString Name;\n\t\t\tString Value;\n\t\t\tCodePosition Position;\n\t\t};\n\n\t\tclass ILStage : public Object\n\t\t{\n\t\tpublic:\n\t\t\tCodePosition Position;\n\t\t\tString Name;\n\t\t\tString StageType;\n\t\t\tEnumerableDictionary<String, StageAttribute> Attributes;\n\t\t};\n\n\t\tclass ILModuleParameterSet;\n\n\t\tclass ILModuleParameterInstance : public ILOperand\n\t\t{\n\t\tpublic:\n\t\t\tILModuleParameterSet * Module = nullptr;\n\t\t\tint BufferOffset = -1;\n\t\t\tint Size = 0;\n\t\t\tList<int> BindingPoints; // for legacy API, usually one item. Samplers may have multiple binding points in OpenGL.\n\t\t\tvirtual String ToString()\n\t\t\t{\n\t\t\t\treturn \"moduleParam<\" + Name + \">\";\n\t\t\t}\n\t\t};\n\n\t\tclass ILModuleParameterSet : public RefObject\n\t\t{\n\t\tpublic:\n\t\t\tint BufferSize = 0;\n\t\t\tString BindingName;\n\t\t\tint DescriptorSetId = -1;\n\t\t\tint UniformBufferLegacyBindingPoint = -1;\n\t\t\tbool IsTopLevel = false;\n\t\t\t\n\t\t\t// for sub parameter sets: these are starting indices for each type of resource (for vk they should be the same)\n\t\t\tint TextureBindingStartIndex = 0, SamplerBindingStartIndex = 0, StorageBufferBindingStartIndex = 0, UniformBindingStartIndex = 0;\n\t\t\t\n\t\t\t// for sub parameter sets: this is the offset into parent's uniform buffer where fields of this parameter set started.\n\t\t\tint UniformBufferOffset = 0;\n\t\t\tEnumerableDictionary<String, RefPtr<ILModuleParameterInstance>> Parameters;\n\t\t\tList<RefPtr<ILModuleParameterSet>> SubModules;\n\t\t};\n\n\t\tclass ILShader\n\t\t{\n\t\tpublic:\n\t\t\tCodePosition Position;\n\t\t\tString Name;\n\t\t\tEnumerableDictionary<String, RefPtr<ILModuleParameterSet>> ModuleParamSets;\n\t\t\tEnumerableDictionary<String, RefPtr<ILWorld>> Worlds;\n\t\t\tEnumerableDictionary<String, RefPtr<ILStage>> Stages;\n\t\t};\n\n\t\tclass ILParameter\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ILType> Type;\n\t\t\tParameterQualifier Qualifier;\n\t\t\tILParameter() = default;\n\t\t\tILParameter(RefPtr<ILType> type, ParameterQualifier qualifier = ParameterQualifier::In)\n\t\t\t\t: Type(type), Qualifier(qualifier)\n\t\t\t{}\n\t\t};\n\n\t\tclass ILFunction\n\t\t{\n\t\tpublic:\n\t\t\tEnumerableDictionary<String, ILParameter> Parameters;\n\t\t\tRefPtr<ILType> ReturnType;\n\t\t\tRefPtr<CFGNode> Code;\n\t\t\tString Name;\n\t\t};\n\n\t\tclass ILProgram\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ConstantPool> ConstantPool = new Compiler::ConstantPool();\n\t\t\tList<RefPtr<ILShader>> Shaders;\n\t\t\tEnumerableDictionary<String, RefPtr<ILFunction>> Functions;\n\t\t\tList<RefPtr<ILStructType>> Structs;\n\t\t};\n\n\t\tclass ShaderChoiceValue\n\t\t{\n\t\tpublic:\n\t\t\tString WorldName;\n\t\t\tShaderChoiceValue() = default;\n\t\t\tShaderChoiceValue(String world)\n\t\t\t{\n\t\t\t\tWorldName = world;\n\t\t\t}\n\t\t\tstatic ShaderChoiceValue Parse(String str);\n\t\t\tString ToString()\n\t\t\t{\n\t\t\t\treturn WorldName;\n\t\t\t}\n\t\t\tbool operator == (const ShaderChoiceValue & val)\n\t\t\t{\n\t\t\t\treturn WorldName == val.WorldName;\n\t\t\t}\n\t\t\tbool operator != (const ShaderChoiceValue & val)\n\t\t\t{\n\t\t\t\treturn WorldName != val.WorldName;\n\t\t\t}\n\t\t\tint GetHashCode()\n\t\t\t{\n\t\t\t\treturn WorldName.GetHashCode();\n\t\t\t}\n\t\t};\n\n\t\tclass ShaderChoice\n\t\t{\n\t\tpublic:\n\t\t\tString ChoiceName;\n\t\t\tString DefaultValue;\n\t\t\tList<ShaderChoiceValue> Options;\n\t\t};\n\n\t\tclass ShaderMetaData\n\t\t{\n\t\tpublic:\n\t\t\tCoreLib::String ShaderName;\n\t\t\tCoreLib::EnumerableDictionary<CoreLib::String, CoreLib::RefPtr<ILModuleParameterSet>> ParameterSets; // bindingName->DescSet\n\t\t};\n\n\t\tclass StageSource\n\t\t{\n\t\tpublic:\n\t\t\tString MainCode;\n\t\t\tList<unsigned char> BinaryCode;\n\t\t};\n\n\t\tclass CompiledShaderSource\n\t\t{\n\t\tpublic:\n\t\t\tEnumerableDictionary<String, StageSource> Stages;\n\t\t\tShaderMetaData MetaData;\n\t\t};\n\n\t\tvoid IndentString(StringBuilder & sb, String src);\n\n\t\tclass CompileResult\n\t\t{\n\t\tpublic:\n\t\t\tDiagnosticSink sink;\n\t\t\tString ScheduleFile;\n\t\t\tRefPtr<ILProgram> Program;\n\t\t\tList<ShaderChoice> Choices;\n\t\t\tEnumerableDictionary<String, CompiledShaderSource> CompiledSource; // shader -> stage -> code\n\t\t\tvoid PrintDiagnostics()\n\t\t\t{\n\t\t\t\tfor (int i = 0; i < sink.diagnostics.Count(); i++)\n\t\t\t\t{\n\t\t\t\t\tfprintf(stderr, \"%S(%d): %s %d: %S\\n\",\n                        sink.diagnostics[i].Position.FileName.ToWString(),\n                        sink.diagnostics[i].Position.Line,\n                        getSeverityName(sink.diagnostics[i].severity),\n\t\t\t\t\t\tsink.diagnostics[i].ErrorID,\n                        sink.diagnostics[i].Message.ToWString());\n\t\t\t\t}\n\t\t\t}\n\t\t\tCompileResult()\n\t\t\t{}\n\t\t\tDiagnosticSink * GetErrorWriter()\n\t\t\t{\n\t\t\t\treturn &sink;\n\t\t\t}\n            int GetErrorCount()\n            {\n                return sink.GetErrorCount();\n            }\n\t\t};\n\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/ConstantPool.cpp",
    "content": "#ifndef CONSTANT_POOL_H\n#define CONSTANT_POOL_H\n\n#include \"ShaderCompiler.h\"\n#include \"IL.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tclass ConstantPoolImpl\n\t\t{\n\t\tprivate:\n\t\t\tILUndefinedOperand undefOperand;\n\t\t\tDictionary<ConstKey<int>, ILConstOperand*> intConsts;\n\t\t\tDictionary<ConstKey<unsigned int>, ILConstOperand*> uintConsts;\n\t\t\tDictionary<ConstKey<float>, ILConstOperand*> floatConsts;\n\t\t\tList<RefPtr<ILConstOperand>> constants;\n\t\t\tRefPtr<ILConstOperand> trueConst, falseConst;\n\t\tpublic:\n\t\t\tILUndefinedOperand * GetUndefinedOperand()\n\t\t\t{\n\t\t\t\treturn &undefOperand;\n\t\t\t}\n\t\t\tILOperand * CreateDefaultValue(ILType * type)\n\t\t\t{\n\t\t\t\tILOperand * value = 0;\n\t\t\t\tif (type->IsFloat())\n\t\t\t\t\tvalue = CreateConstant(0.0f);\n\t\t\t\telse if (type->IsInt())\n\t\t\t\t\tvalue = CreateConstant(0);\n\t\t\t\telse if (auto baseType = dynamic_cast<ILBasicType*>(type))\n\t\t\t\t{\n\t\t\t\t\tif (baseType->Type == ILBaseType::Int2)\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue = CreateConstant(0, 2);\n\t\t\t\t\t}\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Int3)\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue = CreateConstant(0, 3);\n\t\t\t\t\t}\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Int4)\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue = CreateConstant(0, 4);\n\t\t\t\t\t}\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Float2)\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue = CreateConstant(0.0f, 2);\n\t\t\t\t\t}\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Float3)\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue = CreateConstant(0.0f, 3);\n\t\t\t\t\t}\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Float4)\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue = CreateConstant(0.0f, 4);\n\t\t\t\t\t}\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Float3x3)\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue = CreateConstant(0.0f, 9);\n\t\t\t\t\t}\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Float4x4)\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue = CreateConstant(0.0f, 16);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow NotImplementedException(\"default value for this type is not implemented.\");\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow NotImplementedException(\"default value for this type is not implemented.\");\n\t\t\t\treturn value;\n\t\t\t}\n\t\t\tILConstOperand * CreateConstantIntVec(int val, int val2)\n\t\t\t{\n\t\t\t\tILConstOperand * rs = 0;\n\t\t\t\tauto key = ConstKey<int>::FromValues(val, val2);\n\t\t\t\tif (intConsts.TryGetValue(key, rs))\n\t\t\t\t\treturn rs;\n\t\t\t\trs = new ILConstOperand();\n\t\t\t\trs->Type = new ILBasicType(ILBaseType::Int2);\n\t\t\t\trs->IntValues[0] = val;\n\t\t\t\trs->IntValues[1] = val2;\n\t\t\t\tintConsts[key] = rs;\n\t\t\t\trs->Name = rs->ToString();\n\t\t\t\tconstants.Add(rs);\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tILConstOperand * CreateConstantIntVec(int val, int val2, int val3)\n\t\t\t{\n\t\t\t\tILConstOperand * rs = 0;\n\t\t\t\tauto key = ConstKey<int>::FromValues(val, val2, val3);\n\t\t\t\tif (intConsts.TryGetValue(key, rs))\n\t\t\t\t\treturn rs;\n\t\t\t\trs = new ILConstOperand();\n\t\t\t\trs->Type = new ILBasicType(ILBaseType::Int3);\n\t\t\t\trs->IntValues[0] = val;\n\t\t\t\trs->IntValues[1] = val2;\n\t\t\t\trs->IntValues[2] = val3;\n\n\t\t\t\tintConsts[key] = rs;\n\t\t\t\trs->Name = rs->ToString();\n\t\t\t\tconstants.Add(rs);\n\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tILConstOperand * CreateConstantIntVec(int val, int val2, int val3, int val4)\n\t\t\t{\n\t\t\t\tILConstOperand * rs = 0;\n\t\t\t\tauto key = ConstKey<int>::FromValues(val, val2, val3, val4);\n\t\t\t\tif (intConsts.TryGetValue(key, rs))\n\t\t\t\t\treturn rs;\n\t\t\t\trs = new ILConstOperand();\n\t\t\t\trs->Type = new ILBasicType(ILBaseType::Int4);\n\t\t\t\trs->IntValues[0] = val;\n\t\t\t\trs->IntValues[1] = val2;\n\t\t\t\trs->IntValues[2] = val3;\n\t\t\t\trs->IntValues[3] = val4;\n\t\t\t\tintConsts[key] = rs;\n\t\t\t\trs->Name = rs->ToString();\n\t\t\t\tconstants.Add(rs);\n\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tILConstOperand * CreateConstant(ILConstOperand * c)\n\t\t\t{\n\t\t\t\tauto baseType = dynamic_cast<ILBasicType*>(c->Type.Ptr())->Type;\n\t\t\t\tswitch (baseType)\n\t\t\t\t{\n\t\t\t\tcase ILBaseType::Float:\n\t\t\t\t\treturn CreateConstant(c->FloatValues[0]);\n\t\t\t\tcase ILBaseType::Float2:\n\t\t\t\t\treturn CreateConstant(c->FloatValues[0], c->FloatValues[1]);\n\t\t\t\tcase ILBaseType::Float3:\n\t\t\t\t\treturn CreateConstant(c->FloatValues[0], c->FloatValues[1], c->FloatValues[2]);\n\t\t\t\tcase ILBaseType::Float4:\n\t\t\t\t\treturn CreateConstant(c->FloatValues[0], c->FloatValues[1], c->FloatValues[2], c->FloatValues[3]);\n\t\t\t\tcase ILBaseType::Int:\n\t\t\t\t\treturn CreateConstant(c->IntValues[0]);\n\t\t\t\tcase ILBaseType::Int2:\n\t\t\t\t\treturn CreateConstantIntVec(c->IntValues[0], c->IntValues[1]);\n\t\t\t\tcase ILBaseType::Int3:\n\t\t\t\t\treturn CreateConstantIntVec(c->IntValues[0], c->IntValues[1], c->IntValues[2]);\n\t\t\t\tcase ILBaseType::Int4:\n\t\t\t\t\treturn CreateConstantIntVec(c->IntValues[0], c->IntValues[1], c->IntValues[2], c->IntValues[3]);\n\t\t\t\tdefault:\n\t\t\t\t\tif (constants.IndexOf(c) != -1)\n\t\t\t\t\t\treturn c;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tauto rs = new ILConstOperand(*c);\n\t\t\t\t\t\tconstants.Add(rs);\n\t\t\t\t\t\treturn rs;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tILConstOperand * CreateConstantU(unsigned int val)\n\t\t\t{\n\t\t\t\tILConstOperand * rs = 0;\n\t\t\t\tif (uintConsts.TryGetValue(ConstKey<unsigned int>(val, 1), rs))\n\t\t\t\t\treturn rs;\n\t\t\t\trs = new ILConstOperand();\n\t\t\t\tILBaseType baseType;\n\t\t\t\tbaseType = ILBaseType::UInt;\n\t\t\t\trs->Type = new ILBasicType(baseType);\n\t\t\t\trs->IntValues[0] = val;\n\t\t\t\tuintConsts[ConstKey<unsigned int>(val, 1)] = rs;\n\t\t\t\trs->Name = rs->ToString();\n\t\t\t\tconstants.Add(rs);\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tILConstOperand * CreateConstant(bool b)\n\t\t\t{\n\t\t\t\tif (b) \n\t\t\t\t\treturn trueConst.Ptr();\n\t\t\t\telse\n\t\t\t\t\treturn falseConst.Ptr();\n\t\t\t}\n\n\t\t\tILConstOperand * CreateConstant(int val, int size = 0)\n\t\t\t{\n\t\t\t\tILConstOperand * rs = 0;\n\t\t\t\tif (intConsts.TryGetValue(ConstKey<int>(val, size), rs))\n\t\t\t\t\treturn rs;\n\t\t\t\trs = new ILConstOperand();\n\t\t\t\tILBaseType baseType;\n\t\t\t\tswitch (size)\n\t\t\t\t{\n\t\t\t\tcase 0:\n\t\t\t\tcase 1:\n\t\t\t\t\tbaseType = ILBaseType::Int;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tbaseType = ILBaseType::Int2;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tbaseType = ILBaseType::Int3;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tbaseType = ILBaseType::Int4;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow InvalidOperationException(\"Invalid vector size.\");\n\t\t\t\t}\n\t\t\t\trs->Type = new ILBasicType(baseType);\n\t\t\t\trs->IntValues[0] = val;\n\t\t\t\tintConsts[ConstKey<int>(val, size)] = rs;\n\t\t\t\trs->Name = rs->ToString();\n\t\t\t\tconstants.Add(rs);\n\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tILConstOperand * CreateConstant(float val, int size = 0)\n\t\t\t{\n\t\t\t\tILConstOperand * rs = 0;\n\t\t\t\tif (floatConsts.TryGetValue(ConstKey<float>(val, size), rs))\n\t\t\t\t\treturn rs;\n\t\t\t\tif (Math::IsNaN(val) || Math::IsInf(val))\n\t\t\t\t{\n\t\t\t\t\tthrow InvalidOperationException(\"Attempting to create NAN constant.\");\n\t\t\t\t}\n\t\t\t\trs = new ILConstOperand();\n\t\t\t\tILBaseType baseType;\n\t\t\t\tswitch (size)\n\t\t\t\t{\n\t\t\t\tcase 0:\n\t\t\t\tcase 1:\n\t\t\t\t\tbaseType = ILBaseType::Float;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tbaseType = ILBaseType::Float2;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tbaseType = ILBaseType::Float3;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tbaseType = ILBaseType::Float4;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 9:\n\t\t\t\t\tbaseType = ILBaseType::Float3x3;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 16:\n\t\t\t\t\tbaseType = ILBaseType::Float4x4;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow InvalidOperationException(\"Invalid vector size.\");\n\t\t\t\t}\n\t\t\t\trs->Type = new ILBasicType(baseType);\n\t\t\t\tfor (int i = 0; i < 16; i++)\n\t\t\t\t\trs->FloatValues[i] = val;\n\t\t\t\tfloatConsts[ConstKey<float>(val, size)] = rs;\n\t\t\t\trs->Name = rs->ToString();\n\t\t\t\tconstants.Add(rs);\n\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tILConstOperand * CreateConstant(float val, float val2)\n\t\t\t{\n\t\t\t\tILConstOperand * rs = 0;\n\t\t\t\tif (Math::IsNaN(val) || Math::IsInf(val) || Math::IsNaN(val2) || Math::IsInf(val2))\n\t\t\t\t{\n\t\t\t\t\tthrow InvalidOperationException(\"Attempting to create NAN constant.\");\n\t\t\t\t}\n\t\t\t\tauto key = ConstKey<float>::FromValues(val, val2);\n\t\t\t\tif (floatConsts.TryGetValue(key, rs))\n\t\t\t\t\treturn rs;\n\t\t\t\trs = new ILConstOperand();\n\t\t\t\trs->Type = new ILBasicType(ILBaseType::Float2);\n\t\t\t\trs->FloatValues[0] = val;\n\t\t\t\trs->FloatValues[1] = val2;\n\t\t\t\tfloatConsts[key] = rs;\n\t\t\t\trs->Name = rs->ToString();\n\t\t\t\tconstants.Add(rs);\n\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tILConstOperand * CreateConstant(float val, float val2, float val3)\n\t\t\t{\n\t\t\t\tILConstOperand * rs = 0;\n\t\t\t\tif (Math::IsNaN(val) || Math::IsInf(val) || Math::IsNaN(val2) || Math::IsInf(val2) || Math::IsNaN(val3) || Math::IsInf(val3))\n\t\t\t\t{\n\t\t\t\t\tthrow InvalidOperationException(\"Attempting to create NAN constant.\");\n\t\t\t\t}\n\t\t\t\tauto key = ConstKey<float>::FromValues(val, val2, val3);\n\t\t\t\tif (floatConsts.TryGetValue(key, rs))\n\t\t\t\t\treturn rs;\n\t\t\t\trs = new ILConstOperand();\n\t\t\t\trs->Type = new ILBasicType(ILBaseType::Float3);\n\t\t\t\trs->FloatValues[0] = val;\n\t\t\t\trs->FloatValues[1] = val2;\n\t\t\t\trs->FloatValues[2] = val3;\n\n\t\t\t\tfloatConsts[key] = rs;\n\t\t\t\trs->Name = rs->ToString();\n\t\t\t\tconstants.Add(rs);\n\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tILConstOperand * CreateConstant(float val, float val2, float val3, float val4)\n\t\t\t{\n\t\t\t\tif (Math::IsNaN(val) || Math::IsInf(val) || Math::IsNaN(val2) || Math::IsInf(val2) || Math::IsNaN(val3) || Math::IsInf(val3) || Math::IsNaN(val4) || Math::IsInf(val4))\n\t\t\t\t{\n\t\t\t\t\tthrow InvalidOperationException(\"Attempting to create NAN constant.\");\n\t\t\t\t}\n\t\t\t\tILConstOperand * rs = 0;\n\t\t\t\tauto key = ConstKey<float>::FromValues(val, val2, val3, val4);\n\t\t\t\tif (floatConsts.TryGetValue(key, rs))\n\t\t\t\t\treturn rs;\n\t\t\t\trs = new ILConstOperand();\n\t\t\t\trs->Type = new ILBasicType(ILBaseType::Float4);\n\t\t\t\trs->FloatValues[0] = val;\n\t\t\t\trs->FloatValues[1] = val2;\n\t\t\t\trs->FloatValues[2] = val3;\n\t\t\t\trs->FloatValues[3] = val4;\n\n\t\t\t\tfloatConsts[key] = rs;\n\t\t\t\trs->Name = rs->ToString();\n\t\t\t\tconstants.Add(rs);\n\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tConstantPoolImpl()\n\t\t\t{\n\t\t\t\ttrueConst = new ILConstOperand();\n\t\t\t\ttrueConst->Type = new ILBasicType(ILBaseType::Bool);\n\t\t\t\ttrueConst->IntValues[0] = trueConst->IntValues[1] = trueConst->IntValues[2] = trueConst->IntValues[3] = 1;\n\t\t\t\ttrueConst->Name = \"true\";\n\n\t\t\t\tfalseConst = new ILConstOperand();\n\t\t\t\tfalseConst->Type = new ILBasicType(ILBaseType::Bool);\n\t\t\t\tfalseConst->IntValues[0] = falseConst->IntValues[1] = falseConst->IntValues[2] = falseConst->IntValues[3] = 0;\n\t\t\t\ttrueConst->Name = \"false\";\n\n\t\t\t}\n\t\t};\n\n\t\tConstantPool::ConstantPool()\n\t\t{\n\t\t\timpl = new ConstantPoolImpl();\n\t\t}\n\t\tConstantPool::~ConstantPool()\n\t\t{\n\t\t\tdelete impl;\n\t\t}\n\t\tILUndefinedOperand * ConstantPool::GetUndefinedOperand()\n\t\t{\n\t\t\treturn impl->GetUndefinedOperand();\n\t\t}\n\t\tILConstOperand * ConstantPool::CreateConstant(ILConstOperand * c)\n\t\t{\n\t\t\treturn impl->CreateConstant(c);\n\t\t}\n\t\tILConstOperand * ConstantPool::CreateConstantIntVec(int val0, int val1)\n\t\t{\n\t\t\treturn impl->CreateConstantIntVec(val0, val1);\n\n\t\t}\n\t\tILConstOperand * ConstantPool::CreateConstantIntVec(int val0, int val1, int val2)\n\t\t{\n\t\t\treturn impl->CreateConstantIntVec(val0, val1, val2);\n\t\t}\n\t\tILConstOperand * ConstantPool::CreateConstantIntVec(int val0, int val1, int val3, int val4)\n\t\t{\n\t\t\treturn impl->CreateConstantIntVec(val0, val1, val3, val4);\n\t\t}\n\t\tILConstOperand * ConstantPool::CreateConstant(bool b)\n\t\t{\n\t\t\treturn impl->CreateConstant(b);\n\t\t}\n\t\tILConstOperand * ConstantPool::CreateConstantU(unsigned int u)\n\t\t{\n\t\t\treturn impl->CreateConstantU(u);\n\t\t}\n\t\tILConstOperand * ConstantPool::CreateConstant(int val, int vectorSize)\n\t\t{\n\t\t\treturn impl->CreateConstant(val, vectorSize);\n\t\t}\n\t\tILConstOperand * ConstantPool::CreateConstant(float val, int vectorSize)\n\t\t{\n\t\t\treturn impl->CreateConstant(val, vectorSize);\n\t\t}\n\t\tILConstOperand * ConstantPool::CreateConstant(float val, float val1)\n\t\t{\n\t\t\treturn impl->CreateConstant(val, val1);\n\t\t}\n\t\tILConstOperand * ConstantPool::CreateConstant(float val, float val1, float val2)\n\t\t{\n\t\t\treturn impl->CreateConstant(val, val1, val2);\n\t\t}\n\t\tILConstOperand * ConstantPool::CreateConstant(float val, float val1, float val2, float val3)\n\t\t{\n\t\t\treturn impl->CreateConstant(val, val1, val2, val3);\n\t\t}\n\t\tILOperand * ConstantPool::CreateDefaultValue(ILType * type)\n\t\t{\n\t\t\treturn impl->CreateDefaultValue(type);\n\t\t}\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/DiagnosticDefs.h",
    "content": "//\n\n// The file is meant to be included multiple times, to produce different\n// pieces of declaration/definition code related to diagnostic messages\n//\n// Each diagnostic is declared here with:\n//\n//     DIAGNOSTIC(id, severity, name, messageFormat)\n//\n// Where `id` is the unique diagnostic ID, `severity` is the default\n// severity (from the `Severity` enum), `name` is a name used to refer\n// to this diagnostic from code, and `messageFormat` is the default\n// (non-localized) message for the diagnostic, with placeholders\n// for any arguments.\n\n#ifndef DIAGNOSTIC\n#error Need to #define DIAGNOSTIC(...) before including \"DiagnosticDefs.h\"\n#define DIAGNOSTIC(id, severity, name, messageFormat) /* */\n#endif\n\n//\n// -1 - Notes that decorate another diagnostic.\n//\n\nDIAGNOSTIC(-1, Note, alsoSeePipelineDefinition, \"also see pipeline definition\");\nDIAGNOSTIC(-1, Note, implicitParameterMatchingFailedBecauseNameNotAccessible, \"implicit parameter matching failed because the component of the same name is not accessible from '$0'.\\ncheck if you have declared necessary requirements and properly used the 'public' qualifier.\")\nDIAGNOSTIC(-1, Note, implicitParameterMatchingFailedBecauseShaderDoesNotDefineComponent, \"implicit parameter matching failed because shader '$0' does not define component '$1'.\")\nDIAGNOSTIC(-1, Note, implicitParameterMatchingFailedBecauseTypeMismatch, \"implicit parameter matching failed because the component of the same name does not match parameter type '$0'.\")\nDIAGNOSTIC(-1, Note, noteShaderIsTargetingPipeine, \"shader '$0' is targeting pipeline '$1'\")\nDIAGNOSTIC(-1, Note, seeDefinitionOf, \"see definition of '$0'\")\nDIAGNOSTIC(-1, Note, seeInterfaceDefinitionOf, \"see interface definition of '$0'\")\nDIAGNOSTIC(-1, Note, seeUsingOf, \"see using of '$0'\")\nDIAGNOSTIC(-1, Note, seeDefinitionOfShader, \"see definition of shader '$0'\")\nDIAGNOSTIC(-1, Note, seeInclusionOf, \"see inclusion of '$0'\")\nDIAGNOSTIC(-1, Note, seeModuleBeingUsedIn, \"see module '$0' being used in '$1'\")\nDIAGNOSTIC(-1, Note, seePipelineRequirementDefinition, \"see pipeline requirement definition\")\nDIAGNOSTIC(-1, Note, seePotentialDefinitionOfComponent, \"see potential definition of component '$0'\")\nDIAGNOSTIC(-1, Note, seePreviousDefinition, \"see previous definition\")\nDIAGNOSTIC(-1, Note, seePreviousDefinitionOf, \"see previous definition of '$0'\")\nDIAGNOSTIC(-1, Note, seeRequirementDeclaration, \"see requirement declaration\")\nDIAGNOSTIC(-1, Note, doYouForgetToMakeComponentAccessible, \"do you forget to make component '$0' acessible from '$1' (missing public qualifier)?\")\n//\n// 0xxxx -  Command line and interaction with host platform APIs.\n//\n\nDIAGNOSTIC(    1, Error, cannotOpenFile, \"cannot open file '$0'.\")\nDIAGNOSTIC(    2, Error, cannotFindFile, \"cannot find file '$0'.\")\nDIAGNOSTIC(    2, Error, unsupportedCompilerMode, \"unsupported compiler mode.\")\nDIAGNOSTIC(    4, Error, cannotWriteOutputFile, \"cannot write output file '$0'.\")\nDIAGNOSTIC(    5, Note, d3dCompileInfo, \"$0\")\n\n//\n// 1xxxx - Lexical anaylsis\n//\n\nDIAGNOSTIC(10000, Error, illegalCharacter, \"Illegal character '\\\\x$0'\");\nDIAGNOSTIC(10001, Error, illegalCharacterLiteral, \"Illegal character literial.\");\n\n//\n// 15xxx - Preprocessing\n//\n\n// 150xx - conditionals\nDIAGNOSTIC(15000, Error, endOfFileInPreprocessorConditional, \"end of file encountered during preprocessor conditional\")\nDIAGNOSTIC(15001, Error, directiveWithoutIf, \"'$0' directive without '#if'\")\nDIAGNOSTIC(15002, Error, directiveAfterElse , \"'$0' directive without '#if'\")\nDIAGNOSTIC(-1, Note, seeDirective, \"see '$0' directive\")\n\n// 151xx - directive parsing\nDIAGNOSTIC(15100, Error, expectedPreprocessorDirectiveName, \"expected preprocessor directive name\")\nDIAGNOSTIC(15101, Error, unknownPreprocessorDirective, \"unknown preprocessor directive '$0'\")\nDIAGNOSTIC(15102, Error, expectedTokenInPreprocessorDirective, \"expected '$0' in '$1' directive\")\nDIAGNOSTIC(15102, Error, expected2TokensInPreprocessorDirective, \"expected '$0' or '$1' in '$2' directive\")\nDIAGNOSTIC(15103, Error, unexpectedTokensAfterDirective, \"unexpected tokens following '$0' directive\")\n\n\n// 152xx - preprocessor expressions\nDIAGNOSTIC(15200, Error, expectedTokenInPreprocessorExpression, \"expected '$0' in preprocessor expression\");\nDIAGNOSTIC(15201, Error, syntaxErrorInPreprocessorExpression, \"syntax error in preprocessor expression\");\nDIAGNOSTIC(15202, Error, divideByZeroInPreprocessorExpression, \"division by zero in preprocessor expression\");\nDIAGNOSTIC(15203, Error, expectedTokenInDefinedExpression, \"expected '$0' in 'defined' expression\");\nDIAGNOSTIC(-1, Note, seeOpeningToken, \"see opening '$0'\")\n\n// 153xx - #include\nDIAGNOSTIC(15300, Error, includeFailed, \"failed to find include file '$0'\")\nDIAGNOSTIC(-1, Error, noIncludeHandlerSpecified, \"no `#include` handler was specified\")\n\n// 154xx - macro definition\nDIAGNOSTIC(15400, Warning, macroRedefinition, \"redefinition of macro '$0'\")\nDIAGNOSTIC(15401, Warning, macroNotDefined, \"macro '$0' is not defined\")\nDIAGNOSTIC(15403, Error, expectedTokenInMacroParameters, \"expected '$0' in macro parameters\")\n\n// 155xx - macro expansion\nDIAGNOSTIC(15500, Warning, expectedTokenInMacroArguments, \"expected '$0' in macro invocation\")\n\n// 159xx - user-defined error/warning\nDIAGNOSTIC(15900, Error,    userDefinedError,   \"#error: $0\")\nDIAGNOSTIC(15901, Warning,  userDefinedWarning, \"#warning: $0\")\n\n//\n// 2xxxx - Parsing\n//\n\nDIAGNOSTIC(20003, Error, unexpectedToken, \"unexpected $0\");\nDIAGNOSTIC(20001, Error, unexpectedTokenExpectedTokenType, \"unexpected $0, expected $1\");\nDIAGNOSTIC(20001, Error, unexpectedTokenExpectedTokenName, \"unexpected $0, expected '$1'\");\n\nDIAGNOSTIC(0, Error, tokenNameExpectedButEOF, \"\\\"$0\\\" expected but end of file encountered.\");\nDIAGNOSTIC(0, Error, tokenTypeExpectedButEOF, \"$0 expected but end of file encountered.\");\nDIAGNOSTIC(20001, Error, tokenNameExpected, \"\\\"$0\\\" expected\");\nDIAGNOSTIC(20001, Error, tokenNameExpectedButEOF2, \"\\\"$0\\\" expected but end of file encountered.\");\nDIAGNOSTIC(20001, Error, tokenTypeExpected, \"$0 expected\");\nDIAGNOSTIC(20001, Error, tokenTypeExpectedButEOF2, \"$0 expected but end of file encountered.\");\nDIAGNOSTIC(20001, Error, typeNameExpectedBut, \"unexpected $0, expected type name\");\nDIAGNOSTIC(20001, Error, typeNameExpectedButEOF, \"type name expected but end of file encountered.\");\nDIAGNOSTIC(20001, Error, unexpectedEOF, \" Unexpected end of file.\");\nDIAGNOSTIC(20002, Error, syntaxError, \"syntax error.\");\nDIAGNOSTIC(20004, Error, unexpectedTokenExpectedComponentDefinition, \"unexpected token '$0', only component definitions are allowed in a shader scope.\")\nDIAGNOSTIC(20008, Error, invalidOperator, \"invalid operator '$0'.\");\nDIAGNOSTIC(20011, Error, unexpectedColon, \"unexpected ':'.\")\n\n//\n// 3xxxx - Semantic analysis\n//\n\nDIAGNOSTIC(30001, Error, functionRedefinitionWithArgList, \"'$0$1': function redefinition.\")\nDIAGNOSTIC(30002, Error, parameterAlreadyDefined, \"parameter '$0' already defined.\")\nDIAGNOSTIC(30003, Error, breakOutsideLoop, \"'break' must appear inside loop constructs.\")\nDIAGNOSTIC(30004, Error, continueOutsideLoop, \"'continue' must appear inside loop constructs.\")\nDIAGNOSTIC(30005, Error, whilePredicateTypeError, \"'while': expression must evaluate to int.\")\nDIAGNOSTIC(30006, Error, ifPredicateTypeError,  \"'if': expression must evaluate to int.\")\nDIAGNOSTIC(30006, Error, returnNeedsExpression, \"'return' should have an expression.\")\nDIAGNOSTIC(30007, Error, componentReturnTypeMismatch, \"expression type '$0' does not match component's type '$1'\")\nDIAGNOSTIC(30007, Error, functionReturnTypeMismatch, \"expression type '$0' does not match function's return type '$1'\")\nDIAGNOSTIC(30008, Error, variableNameAlreadyDefined, \"variable $0 already defined.\")\nDIAGNOSTIC(30009, Error, invalidTypeVoid, \"invalid type 'void'.\")\nDIAGNOSTIC(30010, Error, whilePredicateTypeError2, \"'while': expression must evaluate to int.\")\nDIAGNOSTIC(30011, Error, assignNonLValue, \"left of '=' is not an l-value.\")\nDIAGNOSTIC(30012, Error, noApplicationUnaryOperator, \"no overload found for operator $0 ($1).\")\nDIAGNOSTIC(30012, Error, noOverloadFoundForBinOperatorOnTypes, \"no overload found for operator $0  ($1, $2).\")\nDIAGNOSTIC(30013, Error, subscriptNonArray, \"'[]' can only index on arrays.\")\nDIAGNOSTIC(30014, Error, subscriptIndexNonInteger, \"index expression must evaluate to int.\")\nDIAGNOSTIC(30015, Error, undefinedIdentifier, \"'$0': undefined identifier.\")\nDIAGNOSTIC(30015, Error, undefinedIdentifier2, \"undefined identifier '$0'.\")\nDIAGNOSTIC(30016, Error, parameterCannotBeVoid, \"'void' can not be parameter type.\")\nDIAGNOSTIC(30017, Error, componentNotAccessibleFromShader, \"component '$0' is not accessible from shader '$1'.\")\nDIAGNOSTIC(30019, Error, typeMismatch, \"type mismatch '$0' and '$1'\")\nDIAGNOSTIC(30020, Error, importOperatorReturnTypeMismatch, \"import operator should return '$1', but the expression has type '$0''. do you forget 'project'?\")\nDIAGNOSTIC(30021, Error, noApplicationFunction, \"$0: no overload takes arguments ($1)\")\nDIAGNOSTIC(30022, Error, invalidTypeCast, \"invalid type cast between \\\"$0\\\" and \\\"$1\\\".\")\nDIAGNOSTIC(30023, Error, typeHasNoPublicMemberOfName, \"\\\"$0\\\" does not have public member \\\"$1\\\".\");\nDIAGNOSTIC(30025, Error, invalidArraySize, \"array size must be larger than zero.\")\nDIAGNOSTIC(30026, Error, returnInComponentMustComeLast, \"'return' can only appear as the last statement in component definition.\")\nDIAGNOSTIC(30027, Error, noMemberOfNameInType, \"'$0' is not a member of '$1'.\");\nDIAGNOSTIC(30028, Error, forPredicateTypeError, \"'for': predicate expression must evaluate to bool.\")\nDIAGNOSTIC(30030, Error, projectionOutsideImportOperator, \"'project': invalid use outside import operator.\")\nDIAGNOSTIC(30031, Error, projectTypeMismatch, \"'project': expression must evaluate to record type '$0'.\")\nDIAGNOSTIC(30033, Error, invalidTypeForLocalVariable, \"cannot declare a local variable of this type.\")\nDIAGNOSTIC(30035, Error, componentOverloadTypeMismatch, \"'$0': type of overloaded component mismatches previous definition.\")\nDIAGNOSTIC(30041, Error, bitOperationNonIntegral, \"bit operation: operand must be integral type.\")\nDIAGNOSTIC(30047, Error, argumentExpectedLValue, \"argument passed to parameter '$0' must be l-value.\")\nDIAGNOSTIC(30051, Error, invalidValueForArgument, \"invalid value for argument '$0'\")\nDIAGNOSTIC(30052, Error, ordinaryFunctionAsModuleArgument, \"ordinary functions not allowed as argument to function-typed module parameter.\")\nDIAGNOSTIC(30079, Error, selectPrdicateTypeMismatch, \"selector must evaluate to bool.\");\nDIAGNOSTIC(30080, Error, selectValuesTypeMismatch, \"the two value expressions in a select clause must have same type.\");\nDIAGNOSTIC(31040, Error, undefinedTypeName, \"undefined type name: '$0'.\")\nDIAGNOSTIC(32013, Error, circularReferenceNotAllowed, \"'$0': circular reference is not allowed.\");\nDIAGNOSTIC(32014, Error, shaderDoesProvideRequirement, \"shader '$0' does not provide '$1' as required by '$2'.\")\nDIAGNOSTIC(32015, Error, argumentNotAvilableInWorld, \"argument '$0' is not available in world '$1' as required by '$2'.\")\nDIAGNOSTIC(32015, Error, componentNotAvilableInWorld, \"component '$0' is not available in world '$1' as required by '$2'.\")\nDIAGNOSTIC(32047, Error, firstArgumentToImportNotComponent, \"first argument of an import operator call does not resolve to a component.\");\nDIAGNOSTIC(32051, Error, componentTypeNotWhatPipelineRequires, \"component '$0' has type '$1', but pipeline '$2' requires it to be '$3'.\")\nDIAGNOSTIC(32052, Error, shaderDoesNotDefineComponentAsRequiredByPipeline, \"shader '$0' does not define '$1' as required by pipeline '$2''.\")\nDIAGNOSTIC(33001, Error, worldNameAlreadyDefined, \"world '$0' is already defined.\")\nDIAGNOSTIC(33002, Error, explicitPipelineSpecificationRequiredForShader, \"explicit pipeline specification required for shader '$0' because multiple pipelines are defined in current context.\")\nDIAGNOSTIC(33003, Error, cannotDefineComponentsInAPipeline, \"cannot define components in a pipeline.\")\nDIAGNOSTIC(33004, Error, undefinedWorldName, \"undefined world name '$0'.\")\nDIAGNOSTIC(33005, Error, abstractWorldAsTargetOfImport, \"abstract world cannot appear as target as an import operator.\")\n\n// Note(tfoley): This is a duplicate of 33004 above.\nDIAGNOSTIC(33006, Error, undefinedWorldName2, \"undefined world name '$0'.\")\n\nDIAGNOSTIC(33007, Error, importOperatorCircularity, \"import operator '$0' creates a circular dependency between world '$1' and '$2'\")\nDIAGNOSTIC(33009, Error, parametersOnlyAllowedInModules, \"parameters can only be defined in modules.\")\nDIAGNOSTIC(33010, Error, undefinedPipelineName, \"pipeline '$0' is undefined.\")\nDIAGNOSTIC(33011, Error, shaderCircularity, \"shader '$0' involves circular reference.\")\nDIAGNOSTIC(33012, Error, worldIsNotDefinedInPipeline, \"'$0' is not a defined world in '$1'.\")\nDIAGNOSTIC(33013, Error, abstractWorldCannotAppearWithOthers, \"abstract world cannot appear with other worlds.\")\nDIAGNOSTIC(33014, Error, nonAbstractComponentMustHaveImplementation, \"non-abstract component must have an implementation.\")\nDIAGNOSTIC(33016, Error, usingInComponentDefinition, \"'using': importing not allowed in component definition.\")\nDIAGNOSTIC(33018, Error, nameAlreadyDefined, \"'$0' is already defined.\")\nDIAGNOSTIC(33018, Error, shaderAlreadyDefined, \"shader '$0' has already been defined.\")\nDIAGNOSTIC(33019, Error, componentMarkedExportMustHaveWorld, \"component '$0': definition marked as 'export' must have an explicitly specified world.\")\nDIAGNOSTIC(33020, Error, componentIsAlreadyDefined, \"'$0' is already defined.\")\nDIAGNOSTIC(33020, Error, componentIsAlreadyDefinedInThatWorld, \"'$0' is already defined at '$1'.\")\nDIAGNOSTIC(33021, Error, inconsistentSignatureForComponent, \"'$0': inconsistent signature.\")\nDIAGNOSTIC(33022, Error, nameAlreadyDefinedInCurrentScope, \"'$0' is already defined in current scope.\")\nDIAGNOSTIC(33022, Error, parameterNameConflictsWithExistingDefinition, \"'$0': parameter name conflicts with existing definition.\")\nDIAGNOSTIC(33023, Error, parameterOfModuleIsUnassigned, \"parameter '$0' of module '$1' is unassigned.\")\nDIAGNOSTIC(33027, Error, argumentTypeDoesNotMatchParameterType, \"argument type ($0) does not match parameter type ($1)\")\nDIAGNOSTIC(33028, Error, nameIsNotAParameterOfCallee, \"'$0' is not a parameter of '$1'.\")\nDIAGNOSTIC(33029, Error, requirementsClashWithPreviousDef, \"'$0': requirement clash with previous definition.\")\nDIAGNOSTIC(33030, Error, positionArgumentAfterNamed, \"positional argument cannot appear after a named argument.\")\nDIAGNOSTIC(33031, Error, tooManyArguments, \"too many arguments.\")\nDIAGNOSTIC(33032, Error, functionRedefinition, \"'$0': function redefinition.\")\nDIAGNOSTIC(33034, Error, recordTypeVariableInImportOperator, \"cannot declare a record-typed variable in an import operator.\")\nDIAGNOSTIC(33037, Error, componetMarkedExportCannotHaveParameters, \"component '$0': definition marked as 'export' cannot have parameters.\")\nDIAGNOSTIC(33039, Error, componentInInputWorldCantHaveCode, \"'$0': no code allowed for component defined in input world.\")\nDIAGNOSTIC(33040, Error, requireWithComputation, \"'require': cannot define computation on component requirements.\")\nDIAGNOSTIC(33042, Error, paramWithComputation, \"'param': cannot define computation on parameters.\")\nDIAGNOSTIC(33041, Error, pipelineOfModuleIncompatibleWithPipelineOfShader, \"pipeline '$0' targeted by module '$1' is incompatible with pipeline '$2' targeted by shader '$3'.\")\nDIAGNOSTIC(33070, Error, expectedFunction, \"expression preceding parenthesis of apparent call must have function type.\")\nDIAGNOSTIC(33071, Error, importOperatorCalledFromAutoPlacedComponent, \"cannot call an import operator from an auto-placed component '$0'. try qualify the component with explicit worlds.\")\nDIAGNOSTIC(33072, Error, noApplicableImportOperator, \"'$0' is an import operator defined in pipeline '$1', but none of the import operator overloads converting to world '$2' matches argument list ($3).\")\nDIAGNOSTIC(33073, Error, importOperatorCalledFromMultiWorldComponent, \"cannot call an import operator from a multi-world component definition. consider qualify the component with only one explicit world.\")\nDIAGNOSTIC(33080, Error, componentTypeDoesNotMatchInterface, \"'$0': component type does not match definition in interface '$1'.\")\nDIAGNOSTIC(33081, Error, shaderDidNotDefineComponentFunction, \"shader '$0' did not define component function $1 as required by interface '$2'.\")\nDIAGNOSTIC(33082, Error, shaderDidNotDefineComponent, \"shader '$0' did not define component '$1' as required by interface '$2'.\")\nDIAGNOSTIC(33083, Error, interfaceImplMustBePublic, \"'$0': component fulfilling interface '$1' must be declared as 'public'.\")\nDIAGNOSTIC(33084, Error, defaultParamNotAllowedInInterface, \"'$0': default parameter value not allowed in interface definition.\")\n\nDIAGNOSTIC(33100, Error, componentCantBeComputedAtWorldBecauseDependentNotAvailable, \"'$0' cannot be computed at '$1' because the dependent component '$2' is not accessible.\")\nDIAGNOSTIC(33101, Warning, worldIsNotAValidChoiceForKey, \"'$0' is not a valid choice for '$1'.\")\nDIAGNOSTIC(33102, Error, componentDefinitionCircularity, \"component definition '$0' involves circular reference.\")\nDIAGNOSTIC(34024, Error, componentAlreadyDefinedWhenCompiling, \"component named '$0' is already defined when compiling '$1'.\")\nDIAGNOSTIC(34025, Error, globalComponentConflictWithPreviousDeclaration, \"'$0': global component conflicts with previous declaration.\")\nDIAGNOSTIC(34026, Warning, componentIsAlreadyDefinedUseRequire, \"'$0': component is already defined when compiling shader '$1'. use 'require' to declare it as a parameter.\")\nDIAGNOSTIC(34062, Error, cylicReference, \"cyclic reference: $0\");\nDIAGNOSTIC(34064, Error, noApplicableImplicitImportOperator, \"cannot find import operator to import component '$0' to world '$1' when compiling '$2'.\")\nDIAGNOSTIC(34065, Error, resourceTypeMustBeParamOrRequire, \"'$0': resource typed component must be declared as 'param' or 'require'.\");\nDIAGNOSTIC(34066, Error, cannotDefineComputationOnResourceType, \"'$0': cannot define computation on resource typed component.\");\n\nDIAGNOSTIC(35001, Error, fragDepthAttributeCanOnlyApplyToOutput, \"FragDepth attribute can only apply to an output component.\");\nDIAGNOSTIC(35002, Error, fragDepthAttributeCanOnlyApplyToFloatComponent, \"FragDepth attribute can only apply to a float component.\");\n\n\nDIAGNOSTIC(36001, Error, insufficientTemplateShaderArguments, \"instantiating template shader '$0': insufficient arguments.\");\nDIAGNOSTIC(36002, Error, tooManyTemplateShaderArguments, \"instantiating template shader '$0': too many arguments.\");\nDIAGNOSTIC(36003, Error, templateShaderArgumentIsNotDefined, \"'$0' provided as template shader argument to '$1' is not a defined module.\");\nDIAGNOSTIC(36004, Error, templateShaderArgumentDidNotImplementRequiredInterface, \"module '$0' provided as template shader argument to '$1' did not implement required interface '$2'.\");\nDIAGNOSTIC(36010, Error, specializeCanOnlyBeUsedOnParam, \"'specialize' modifier can only be used on module parameters.\");\nDIAGNOSTIC(36011, Error, specializedParameterMustBeInt, \"specialized parameters must be a int, uint or bool.\");\nDIAGNOSTIC(36012, Error, specializationValuesMustBeConstantLiterial, \"specialization candidate values can only be constant literials.\");\n//\n// 4xxxx - IL code generation.\n//\nDIAGNOSTIC(40001, Error, bindingAlreadyOccupiedByComponent, \"resource binding location '$0' is already occupied by component '$1'.\")\nDIAGNOSTIC(40002, Error, invalidBindingValue, \"binding location '$0' is out of valid range.\")\nDIAGNOSTIC(40003, Error, bindingExceedsLimit, \"binding location '$0' assigned to component '$1' exceeds maximum limit.\")\nDIAGNOSTIC(40004, Error, bindingAlreadyOccupiedByModule, \"DescriptorSet ID '$0' is already occupied by module instance '$1'.\")\nDIAGNOSTIC(40005, Error, topLevelModuleUsedWithoutSpecifyingBinding, \"top level module '$0' is being used without specifying binding location. Use [Binding: \\\"index\\\"] attribute to provide a binding location.\")\n//\n// 5xxxx - Target code generation.\n//\n\nDIAGNOSTIC(50020, Error, unknownStageType,              \"Unknown stage type '$0'.\")\nDIAGNOSTIC(50020, Error, invalidTessCoordType,          \"TessCoord must have vec2 or vec3 type.\")\nDIAGNOSTIC(50020, Error, invalidFragCoordType,          \"FragCoord must be a vec4.\")\nDIAGNOSTIC(50020, Error, invalidInvocationIdType,       \"InvocationId must have int type.\")\nDIAGNOSTIC(50020, Error, invalidThreadIdType,           \"ThreadId must have int type.\")\nDIAGNOSTIC(50020, Error, invalidPrimitiveIdType,        \"PrimitiveId must have int type.\")\nDIAGNOSTIC(50020, Error, invalidPatchVertexCountType,    \"PatchVertexCount must have int type.\")\nDIAGNOSTIC(50020, Error, invalidTypeForSystemVar,    \"Invalid type for system value '$0'.\")\n\nDIAGNOSTIC(50022, Error, worldIsNotDefined, \"world '$0' is not defined.\");\nDIAGNOSTIC(50023, Error, stageShouldProvideWorldAttribute, \"'$0' should provide 'World' attribute.\");\nDIAGNOSTIC(50040, Error, componentHasInvalidTypeForPositionOutput, \"'$0': component used as 'Position' output must be of vec4 type.\")\nDIAGNOSTIC(50041, Error, componentNotDefined, \"'$0': component not defined.\")\n\nDIAGNOSTIC(50052, Error, domainShaderRequiresControlPointCount, \"'DomainShader' requires attribute 'ControlPointCount'.\");\nDIAGNOSTIC(50052, Error, hullShaderRequiresControlPointCount, \"'HullShader' requires attribute 'ControlPointCount'.\")\nDIAGNOSTIC(50052, Error, hullShaderRequiresControlPointWorld, \"'HullShader' requires attribute 'ControlPointWorld'.\");\nDIAGNOSTIC(50052, Error, hullShaderRequiresCornerPointWorld, \"'HullShader' requires attribute 'CornerPointWorld'.\");\nDIAGNOSTIC(50052, Error, hullShaderRequiresDomain, \"'HullShader' requires attribute 'Domain'.\");\nDIAGNOSTIC(50052, Error, hullShaderRequiresInputControlPointCount, \"'HullShader' requires attribute 'InputControlPointCount'.\")\nDIAGNOSTIC(50052, Error, hullShaderRequiresOutputTopology, \"'HullShader' requires attribute 'OutputTopology'.\")\nDIAGNOSTIC(50052, Error, hullShaderRequiresPartitioning, \"'HullShader' requires attribute 'Partitioning'.\")\nDIAGNOSTIC(50052, Error, hullShaderRequiresPatchWorld, \"'HullShader' requires attribute 'PatchWorld'.\");\nDIAGNOSTIC(50052, Error, hullShaderRequiresTessLevelInner, \"'HullShader' requires attribute 'TessLevelInner'.\")\nDIAGNOSTIC(50052, Error, hullShaderRequiresTessLevelOuter, \"'HullShader' requires attribute 'TessLevelOuter'.\")\n\nDIAGNOSTIC(50053, Error, invalidTessellationDomian, \"'Domain' should be either 'triangles' or 'quads'.\");\nDIAGNOSTIC(50053, Error, invalidTessellationOutputTopology, \"'OutputTopology' must be one of: 'point', 'line', 'triangle_cw', or 'triangle_ccw'.\");\nDIAGNOSTIC(50053, Error, invalidTessellationPartitioning, \"'Partitioning' must be one of: 'integer', 'pow2', 'fractional_even', or 'fractional_odd'.\")\nDIAGNOSTIC(50053, Error, invalidTessellationDomain,     \"'Domain' should be either 'triangles' or 'quads'.\")\n\nDIAGNOSTIC(50082, Error, importingFromPackedBufferUnsupported, \"importing type '$0' from PackedBuffer is not supported by the GLSL backend.\")\nDIAGNOSTIC(51090, Error, cannotGenerateCodeForExternComponentType, \"cannot generate code for extern component type '$0'.\")\nDIAGNOSTIC(51091, Error, typeCannotBePlacedInATexture, \"type '$0' cannot be placed in a texture.\")\nDIAGNOSTIC(51092, Error, stageDoesntHaveInputWorld, \"'$0' doesn't appear to have any input world\");\n\n\n// 99999 - Internal compiler errors, and not-yet-classified diagnostics.\n\nDIAGNOSTIC(99999, Internal, internalCompilerError, \"internal compiler error\")\nDIAGNOSTIC(99999, Internal, unimplemented, \"unimplemented feature: $0\")\n\n#undef DIAGNOSTIC\n"
  },
  {
    "path": "Source/SpireCore/Diagnostics.cpp",
    "content": "// Diagnostics.cpp\n#include \"Diagnostics.h\"\n\n#include \"CompiledProgram.h\"\n#include \"SymbolTable.h\"\n#include \"Syntax.h\"\n\n#include <assert.h>\n\nnamespace Spire {\nnamespace Compiler {\n\nvoid printDiagnosticArg(StringBuilder& sb, char const* str)\n{\n    sb << str;\n}\n\nvoid printDiagnosticArg(StringBuilder& sb, int str)\n{\n\tsb << str;\n}\n\nvoid printDiagnosticArg(StringBuilder& sb, CoreLib::Basic::String const& str)\n{\n    sb << str;\n}\n\nvoid printDiagnosticArg(StringBuilder& sb, Decl* decl)\n{\n    sb << decl->Name.Content;\n}\n\nvoid printDiagnosticArg(StringBuilder& sb, Type* type)\n{\n    sb << type->DataType->ToString();\n}\n\nvoid printDiagnosticArg(StringBuilder& sb, ExpressionType* type)\n{\n    sb << type->ToString();\n}\n\nvoid printDiagnosticArg(StringBuilder& sb, ILType* type)\n{\n    sb << type->ToString();\n}\n\nvoid printDiagnosticArg(StringBuilder& sb, CoreLib::Text::TokenType tokenType)\n{\n    sb << TokenTypeToString(tokenType);\n}\n\nvoid printDiagnosticArg(StringBuilder& sb, Token const& token)\n{\n    sb << token.Content;\n}\n\nvoid printDiagnosticArg(StringBuilder& sb, StageAttribute const& attr)\n{\n    sb << attr.Value;\n}\n\nCodePosition const& getDiagnosticPos(SyntaxNode const* syntax)\n{\n    return syntax->Position;\n}\n\nCodePosition const& getDiagnosticPos(CoreLib::Text::Token const& token)\n{\n    return token.Position;\n}\n\nCodePosition const& getDiagnosticPos(ShaderClosure* shader)\n{\n    return shader->Position;\n}\n\n// Take the format string for a diagnostic message, along with its arguments, and turn it into a\nstatic void formatDiagnosticMessage(StringBuilder& sb, char const* format, int argCount, DiagnosticArg const* const* args)\n{\n    char const* spanBegin = format;\n    for(;;)\n    {\n        char const* spanEnd = spanBegin;\n        while (int c = *spanEnd)\n        {\n            if (c == '$')\n                break;\n            spanEnd++;\n        }\n\n        sb.Append(spanBegin, int(spanEnd - spanBegin));\n        if (!*spanEnd)\n            return;\n\n        assert(*spanEnd == '$');\n        spanEnd++;\n        int d = *spanEnd++;\n        switch (d)\n        {\n        // A double dollar sign `$$` is used to emit a single `$` \n        case '$':\n            sb.Append('$');\n            break;\n\n        // A single digit means to emit the corresponding argument.\n        // TODO: support more than 10 arguments, and add options\n        // to control formatting, etc.\n        case '0': case '1': case '2': case '3': case '4':\n        case '5': case '6': case '7': case '8': case '9':\n            {\n                int index = d - '0';\n                if (index >= argCount)\n                {\n                    // TODO(tfoley): figure out what a good policy will be for \"panic\" situations like this\n                    throw InvalidOperationException(\"too few arguments for diagnostic message\");\n                }\n                else\n                {\n                    DiagnosticArg const* arg = args[index];\n                    arg->printFunc(sb, arg->data);\n                }\n            }\n            break;\n\n        default:\n            throw InvalidOperationException(\"invalid diagnostic message format\");\n            break;\n        }\n\n        spanBegin = spanEnd;\n    }\n}\n\nvoid DiagnosticSink::diagnoseImpl(CodePosition const& pos, DiagnosticInfo const& info, int argCount, DiagnosticArg const* const* args)\n{\n    StringBuilder sb;\n    formatDiagnosticMessage(sb, info.messageFormat, argCount, args);\n\n    Diagnostic diagnostic;\n    diagnostic.ErrorID = info.id;\n    diagnostic.Message = sb.ProduceString();\n    diagnostic.Position = pos;\n    diagnostic.severity = info.severity;\n\n    diagnostics.Add(diagnostic);\n    if (diagnostic.severity >= Severity::Error)\n    {\n        errorCount++;\n    }\n    if (diagnostic.severity >= Severity::Fatal)\n    {\n        // TODO: figure out a better policy for aborting compilation\n        throw InvalidOperationException();\n    }\n}\n\nnamespace Diagnostics\n{\n#define DIAGNOSTIC(id, severity, name, messageFormat) const DiagnosticInfo name = { id, Severity::severity, messageFormat };\n#include \"DiagnosticDefs.h\"\n}\n\n\n}} // namespace Spire::Compiler\n"
  },
  {
    "path": "Source/SpireCore/Diagnostics.h",
    "content": "#ifndef RASTER_RENDERER_COMPILE_ERROR_H\n#define RASTER_RENDERER_COMPILE_ERROR_H\n\n#include \"../CoreLib/Basic.h\"\n#include \"../CoreLib/Tokenizer.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tusing namespace CoreLib::Basic;\n\t\tusing namespace CoreLib::Text;\n\n        enum class Severity\n        {\n            Note,\n            Warning,\n            Error,\n            Fatal,\n            Internal,\n        };\n\n        // TODO(tfoley): move this into a source file...\n        inline const char* getSeverityName(Severity severity)\n        {\n            switch (severity)\n            {\n            case Severity::Note:        return \"note\";\n            case Severity::Warning:     return \"warning\";\n            case Severity::Error:       return \"error\";\n            case Severity::Fatal:       return \"fatal error\";\n            case Severity::Internal:    return \"internal error\";\n            default:                    return \"unknown error\";\n            }\n        }\n\n        // A structure to be used in static data describing different\n        // diagnostic messages.\n        struct DiagnosticInfo\n        {\n            int id;\n            Severity severity;\n            char const* messageFormat;\n        };\n\n\t\tclass Diagnostic\n\t\t{\n\t\tpublic:\n\t\t\tString Message;\n\t\t\tCodePosition Position;\n\t\t\tint ErrorID;\n            Severity severity;\n\n\t\t\tDiagnostic()\n\t\t\t{\n\t\t\t\tErrorID = -1;\n\t\t\t}\n\t\t\tDiagnostic(\n                const String & msg,\n                int id,\n\t\t\t\tconst CodePosition & pos,\n                Severity severity)\n                : severity(severity)\n\t\t\t{\n\t\t\t\tMessage = msg;\n\t\t\t\tErrorID = id;\n\t\t\t\tPosition = pos;\n\t\t\t}\n\t\t};\n\n        class Decl;\n        class Type;\n        class ExpressionType;\n        class ILType;\n        class StageAttribute;\n\n        void printDiagnosticArg(StringBuilder& sb, char const* str);\n\t\tvoid printDiagnosticArg(StringBuilder& sb, int val);\n        void printDiagnosticArg(StringBuilder& sb, CoreLib::Basic::String const& str);\n        void printDiagnosticArg(StringBuilder& sb, Decl* decl);\n        void printDiagnosticArg(StringBuilder& sb, Type* type);\n        void printDiagnosticArg(StringBuilder& sb, ExpressionType* type);\n        void printDiagnosticArg(StringBuilder& sb, ILType* type);\n        void printDiagnosticArg(StringBuilder& sb, CoreLib::Text::TokenType tokenType);\n        void printDiagnosticArg(StringBuilder& sb, Token const& token);\n        void printDiagnosticArg(StringBuilder& sb, StageAttribute const& attr);\n\n        template<typename T>\n        void printDiagnosticArg(StringBuilder& sb, RefPtr<T> ptr)\n        {\n            printDiagnosticArg(sb, ptr.Ptr());\n        }\n\n        inline CodePosition const& getDiagnosticPos(CodePosition const& pos) { return pos;  }\n\n        class SyntaxNode;\n        class ShaderClosure;\n        CodePosition const& getDiagnosticPos(SyntaxNode const* syntax);\n        CodePosition const& getDiagnosticPos(CoreLib::Text::Token const& token);\n        CodePosition const& getDiagnosticPos(ShaderClosure* shader);\n\n        template<typename T>\n        CodePosition getDiagnosticPos(RefPtr<T> const& ptr)\n        {\n            return getDiagnosticPos(ptr.Ptr());\n        }\n\n        struct DiagnosticArg\n        {\n            void* data;\n            void (*printFunc)(StringBuilder&, void*);\n\n            template<typename T>\n            struct Helper\n            {\n                static void printFunc(StringBuilder& sb, void* data) { printDiagnosticArg(sb, *(T*)data); }\n            };\n\n            template<typename T>\n            DiagnosticArg(T const& arg)\n                : data((void*)&arg)\n                , printFunc(&Helper<T>::printFunc)\n            {}\n        };\n\n        class DiagnosticSink\n        {\n        public:\n            List<Diagnostic> diagnostics;\n            int errorCount = 0;\n/*\n\t\t\tvoid Error(int id, const String & msg, const CodePosition & pos)\n\t\t\t{\n\t\t\t\tdiagnostics.Add(Diagnostic(msg, id, pos, Severity::Error));\n                errorCount++;\n\t\t\t}\n\n\t\t\tvoid Warning(int id, const String & msg, const CodePosition & pos)\n\t\t\t{\n\t\t\t\tdiagnostics.Add(Diagnostic(msg, id, pos, Severity::Warning));\n\t\t\t}\n*/\n            int GetErrorCount() { return errorCount; }\n\n            void diagnoseDispatch(CodePosition const& pos, DiagnosticInfo const& info)\n            {\n                diagnoseImpl(pos, info, 0, NULL);\n            }\n\n            void diagnoseDispatch(CodePosition const& pos, DiagnosticInfo const& info, DiagnosticArg const& arg0)\n            {\n                DiagnosticArg const* args[] = { &arg0 };\n                diagnoseImpl(pos, info, 1, args);\n            }\n\n            void diagnoseDispatch(CodePosition const& pos, DiagnosticInfo const& info, DiagnosticArg const& arg0, DiagnosticArg const& arg1)\n            {\n                DiagnosticArg const* args[] = { &arg0, &arg1 };\n                diagnoseImpl(pos, info, 2, args);\n            }\n\n            void diagnoseDispatch(CodePosition const& pos, DiagnosticInfo const& info, DiagnosticArg const& arg0, DiagnosticArg const& arg1, DiagnosticArg const& arg2)\n            {\n                DiagnosticArg const* args[] = { &arg0, &arg1, &arg2 };\n                diagnoseImpl(pos, info, 3, args);\n            }\n\n            void diagnoseDispatch(CodePosition const& pos, DiagnosticInfo const& info, DiagnosticArg const& arg0, DiagnosticArg const& arg1, DiagnosticArg const& arg2, DiagnosticArg const& arg3)\n            {\n                DiagnosticArg const* args[] = { &arg0, &arg1, &arg2, &arg3 };\n                diagnoseImpl(pos, info, 4, args);\n            }\n\n            template<typename P, typename... Args>\n            void diagnose(P const& pos, DiagnosticInfo const& info, Args const&... args )\n            {\n                diagnoseDispatch(getDiagnosticPos(pos), info, args...);\n            }\n\n            void diagnoseImpl(CodePosition const& pos, DiagnosticInfo const& info, int argCount, DiagnosticArg const* const* args);\n\n            // A stored state for the sink, which can be used to restore it later.\n            struct State\n            {\n                int diagnosticCount;\n                int errorCount;\n            };\n\n            // Save the state of the sink so that it can be restored later.\n            State saveState()\n            {\n                State state;\n                state.diagnosticCount = diagnostics.Count();\n                state.errorCount = errorCount;\n                return state;\n            }\n\n            // Restore the state of the sink to a saved state.\n            void restoreState(State state)\n            {\n                errorCount = state.errorCount;\n                diagnostics.SetSize(state.diagnosticCount);\n            }\n        };\n\n        namespace Diagnostics\n        {\n#define DIAGNOSTIC(id, severity, name, messageFormat) extern const DiagnosticInfo name;\n#include \"DiagnosticDefs.h\"\n        }\n\t}\n}\n\n#ifdef _DEBUG\n#define SPIRE_INTERNAL_ERROR(sink, pos) \\\n    (sink)->diagnose(Spire::Compiler::CodePosition(__LINE__, 0, 0, __FILE__), Spire::Compiler::Diagnostics::internalCompilerError)\n#define SPIRE_UNIMPLEMENTED(sink, pos, what) \\\n    (sink)->diagnose(Spire::Compiler::CodePosition(__LINE__, 0, 0, __FILE__), Spire::Compiler::Diagnostics::unimplemented, what)\n#else\n#define SPIRE_INTERNAL_ERROR(sink, pos) \\\n    (sink)->diagnose(pos, Spire::Compiler::Diagnostics::internalCompilerError)\n#define SPIRE_UNIMPLEMENTED(sink, pos, what) \\\n    (sink)->diagnose(pos, Spire::Compiler::Diagnostics::unimplemented, what)\n#endif\n\n#endif"
  },
  {
    "path": "Source/SpireCore/GLSLCodeGen.cpp",
    "content": "#include \"CLikeCodeGen.h\"\n#include \"../CoreLib/Tokenizer.h\"\n#include \"Syntax.h\"\n#include \"Naming.h\"\n#include \"SamplerUsageAnalysis.h\"\n#include <cassert>\n\nusing namespace CoreLib::Basic;\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tclass GLSLCodeGen : public CLikeCodeGen\n\t\t{\n\t\tpublic:\n\t\t\tbool useVulkanBinding = false;\n\t\t\tbool useSingleDescSet = false;\n\t\tprotected:\n\t\t\tOutputStrategy * CreateStandardOutputStrategy(ILWorld * world, String layoutPrefix) override;\n\t\t\tOutputStrategy * CreatePackedBufferOutputStrategy(ILWorld * world) override;\n\t\t\tOutputStrategy * CreateArrayOutputStrategy(ILWorld * world, bool pIsPatch, int pArraySize, String arrayIndex) override;\n\n            LayoutRule GetDefaultLayoutRule() override\n            {\n                return LayoutRule::Std140;\n            }\n\n\t\t\tvoid PrintOp(CodeGenContext & ctx, ILOperand * op, bool forceExpression = false) override\n\t\t\t{\n\t\t\t\tif (!useVulkanBinding && op->Type->IsSamplerState())\n\t\t\t\t{\n\t\t\t\t\t// GLSL does not have sampler type, print 0 as placeholder\n\t\t\t\t\tctx.Body << \"0\";\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tCLikeCodeGen::PrintOp(ctx, op, forceExpression);\n\t\t\t}\n\n\t\t\tvoid PrintRasterPositionOutputWrite(CodeGenContext & ctx, ILOperand * operand) override\n\t\t\t{\n\t\t\t\tctx.Body << \"gl_Position = \";\n\t\t\t\tPrintOp(ctx, operand);\n\t\t\t\tctx.Body << \";\\n\";\n\t\t\t}\n\t\t\t\n\t\t\tvoid PrintStandardInputReference(StringBuilder& sb, ILRecordType* recType, String inputName, String componentName) override\n\t\t\t{\n\t\t\t\tString declName = componentName;\n\t\t\t\tdeclName = AddWorldNameSuffix(declName, recType->ToString());\n\t\t\t\tsb << declName;\n\t\t\t}\n\n\t\t\tvoid PrintStandardArrayInputReference(StringBuilder& sb, ILRecordType* recType, String inputName, String componentName) override\n\t\t\t{\n\t\t\t\tPrintStandardInputReference(sb, recType, inputName, componentName);\n\t\t\t}\n\n\t\t\tvoid PrintPatchInputReference(StringBuilder& sb, ILRecordType* recType, String inputName, String componentName) override\n\t\t\t{\n\t\t\t\tString declName = componentName;\n\t\t\t\tdeclName = AddWorldNameSuffix(declName, recType->ToString());\n\t\t\t\tsb << declName;\n\t\t\t}\n\n\t\t\tvoid PrintDefaultInputReference(StringBuilder& sb, ILRecordType* /*recType*/, String inputName, String componentName) override\n\t\t\t{\n\t\t\t\tString declName = componentName;\n\t\t\t\tsb << declName;\n\t\t\t}\n\n\t\t\tvoid PrintSystemVarReference(CodeGenContext & /*ctx*/, StringBuilder& sb, String inputName, ExternComponentCodeGenInfo::SystemVarType systemVar) override\n\t\t\t{\n\t\t\t\tswitch(systemVar)\n\t\t\t\t{\n\t\t\t\tcase ExternComponentCodeGenInfo::SystemVarType::FragCoord:\n\t\t\t\t\tsb << \"gl_FragCoord\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExternComponentCodeGenInfo::SystemVarType::TessCoord:\n\t\t\t\t\tsb << \"gl_TessCoord\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExternComponentCodeGenInfo::SystemVarType::InvocationId:\n\t\t\t\t\tsb << \"gl_InvocationID\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExternComponentCodeGenInfo::SystemVarType::ThreadId:\n\t\t\t\t\tsb << \"gl_GlobalInvocationID.x\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExternComponentCodeGenInfo::SystemVarType::PatchVertexCount:\n\t\t\t\t\tsb << \"gl_PatchVerticesIn\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExternComponentCodeGenInfo::SystemVarType::PrimitiveId:\n\t\t\t\t\tsb << \"gl_PrimitiveID\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tsb << inputName;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid PrintProjectInstrExpr(CodeGenContext & ctx, ProjectInstruction * proj)\n\t\t\t{\n\t\t\t\tif (auto memberLoadInstr = dynamic_cast<MemberLoadInstruction*>(proj->Operand.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tbool overrideBaseMemberLoad = false;\n\t\t\t\t\tauto genType = dynamic_cast<ILGenericType*>(memberLoadInstr->Operands[0]->Type.Ptr());\n\t\t\t\t\tif (genType && genType->GenericTypeName == \"PackedBuffer\")\n\t\t\t\t\t{\n\t\t\t\t\t\t// load record type from packed buffer\n\t\t\t\t\t\tString conversionFunction;\n\t\t\t\t\t\tint size = 0;\n\t\t\t\t\t\tif (memberLoadInstr->Type->ToString() == \"int\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"floatBitsToInt\";\n\t\t\t\t\t\t\tsize = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (memberLoadInstr->Type->ToString() == \"ivec2\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"floatBitsToInt\";\n\t\t\t\t\t\t\tsize = 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (memberLoadInstr->Type->ToString() == \"ivec3\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"floatBitsToInt\";\n\t\t\t\t\t\t\tsize = 3;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (memberLoadInstr->Type->ToString() == \"ivec4\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"floatBitsToInt\";\n\t\t\t\t\t\t\tsize = 4;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (memberLoadInstr->Type->ToString() == \"uint\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"floatBitsToUint\";\n\t\t\t\t\t\t\tsize = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (memberLoadInstr->Type->ToString() == \"uvec2\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"floatBitsToUint\";\n\t\t\t\t\t\t\tsize = 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (memberLoadInstr->Type->ToString() == \"uvec3\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"floatBitsToUint\";\n\t\t\t\t\t\t\tsize = 3;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (memberLoadInstr->Type->ToString() == \"uvec4\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"floatBitsToUint\";\n\t\t\t\t\t\t\tsize = 4;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (memberLoadInstr->Type->ToString() == \"float\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\t\t\tsize = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (memberLoadInstr->Type->ToString() == \"vec2\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\t\t\tsize = 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (memberLoadInstr->Type->ToString() == \"vec3\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\t\t\tsize = 3;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (memberLoadInstr->Type->ToString() == \"vec4\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\t\t\tsize = 4;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (memberLoadInstr->Type->ToString() == \"mat3\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\t\t\tsize = 9;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (memberLoadInstr->Type->ToString() == \"mat4\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\t\t\tsize = 16;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terrWriter->diagnose(CodePosition(), Diagnostics::importingFromPackedBufferUnsupported, memberLoadInstr->Type);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tctx.Body << memberLoadInstr->Type->ToString() << \"(\";\n\t\t\t\t\t\tauto recType = dynamic_cast<ILRecordType*>(genType->BaseType.Ptr());\n\t\t\t\t\t\tint recTypeSize = 0;\n\t\t\t\t\t\tEnumerableDictionary<String, int> memberOffsets;\n\t\t\t\t\t\tfor (auto & member : recType->Members)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmemberOffsets[member.Key] = recTypeSize;\n\t\t\t\t\t\t\trecTypeSize += member.Value.Type->GetVectorSize();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (int i = 0; i < size; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tctx.Body << conversionFunction << \"(\";\n\t\t\t\t\t\t\tPrintOp(ctx, memberLoadInstr->Operands[0].Ptr());\n\t\t\t\t\t\t\tctx.Body << \"[(\";\n\t\t\t\t\t\t\tPrintOp(ctx, memberLoadInstr->Operands[1].Ptr());\n\t\t\t\t\t\t\tctx.Body << \") * \" << recTypeSize << \" + \" << memberOffsets[proj->ComponentName]() << \"])\";\n\t\t\t\t\t\t\tif (i != size - 1)\n\t\t\t\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tctx.Body << \")\";\n\t\t\t\t\t\toverrideBaseMemberLoad = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (!overrideBaseMemberLoad)\n\t\t\t\t\t\tPrintOp(ctx, memberLoadInstr, true);\n\t\t\t\t\tif (genType)\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((genType->GenericTypeName == \"StructuredBuffer\" || genType->GenericTypeName == \"RWStructuredBuffer\")\n\t\t\t\t\t\t\t&& dynamic_cast<ILRecordType*>(genType->BaseType.Ptr()))\n\t\t\t\t\t\t\tctx.Body << \".\" << proj->ComponentName;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tPrintOp(ctx, proj->Operand.Ptr(), true);\n\t\t\t}\n\n\t\t\tconst char * GetTextureType(ILType * textureType)\n\t\t\t{\n\t\t\t\tauto baseType = dynamic_cast<ILBasicType*>(textureType)->Type;\n\t\t\t\tconst char * textureName = nullptr;\n\t\t\t\tswitch (baseType)\n\t\t\t\t{\n\t\t\t\tcase ILBaseType::Texture2D:\n\t\t\t\t\ttextureName = \"texture2D\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::Texture2DArray:\n\t\t\t\t\ttextureName = \"texture2DArray\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::Texture2DArrayShadow:\n\t\t\t\t\ttextureName = \"texture2DArray\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::TextureCube:\n\t\t\t\t\ttextureName = \"textureCube\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::TextureCubeShadow:\n\t\t\t\t\ttextureName = \"textureCube\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::Texture3D:\n\t\t\t\t\ttextureName = \"texture3D\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::TextureCubeArray:\n\t\t\t\t\ttextureName = \"textureCubeArray\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::TextureCubeShadowArray:\n\t\t\t\t\ttextureName = \"textureCubeArray\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow NotImplementedException();\n\t\t\t\t}\n\t\t\t\treturn textureName;\n\t\t\t}\n\n\t\t\tconst char * GetSamplerType(ILType * textureType)\n\t\t\t{\n\t\t\t\tauto baseType = dynamic_cast<ILBasicType*>(textureType)->Type;\n\t\t\t\tconst char * samplerName = nullptr;\n\t\t\t\tswitch (baseType)\n\t\t\t\t{\n\t\t\t\tcase ILBaseType::Texture2D:\n\t\t\t\t\tsamplerName = \"sampler2D\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::Texture2DArray:\n\t\t\t\t\tsamplerName = \"sampler2DArray\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::Texture2DArrayShadow:\n\t\t\t\t\tsamplerName = \"sampler2DArrayShadow\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::TextureCube:\n\t\t\t\t\tsamplerName = \"samplerCube\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::TextureCubeShadow:\n\t\t\t\t\tsamplerName = \"samplerCubeShadow\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::Texture3D:\n\t\t\t\t\tsamplerName = \"sampler3D\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::TextureCubeArray:\n\t\t\t\t\tsamplerName = \"samplerCubeArray\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ILBaseType::TextureCubeShadowArray:\n\t\t\t\t\tsamplerName = \"samplerCubeArrayShadow\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow NotImplementedException();\n\t\t\t\t}\n\t\t\t\treturn samplerName;\n\t\t\t}\n\n\t\t\tvoid PrintTypeName(StringBuilder& sb, ILType* type) override\n\t\t\t{\n\t\t\t\t// Currently, all types are internally named based on their GLSL equivalent, so\n\t\t\t\t// outputting a type for GLSL is trivial.\n\n\t\t\t\t// GLSL does not have sampler type, use int as placeholder\n\t\t\t\tif (type->IsSamplerState())\n\t\t\t\t{\n\t\t\t\t\tif (useVulkanBinding)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (dynamic_cast<ILBasicType*>(type)->Type == ILBaseType::SamplerComparisonState)\n\t\t\t\t\t\t\tsb << \"samplerShadow\";\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tsb << \"sampler\";\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tsb << \"int\";\n\t\t\t\t}\n\t\t\t\telse if (type->IsTexture())\n\t\t\t\t{\n\t\t\t\t\tif (useVulkanBinding)\n\t\t\t\t\t\tsb << GetTextureType(type);\n\t\t\t\t\telse\n\t\t\t\t\t\tsb << GetSamplerType(type);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tsb << type->ToString();\n\t\t\t}\n\n\t\t\tvoid PrintTextureCall(CodeGenContext & ctx, CallInstruction * instr)\n\t\t\t{\n\t\t\t\tauto printSamplerArgument = [&](ILOperand * texture, ILOperand * sampler)\n\t\t\t\t{\n\t\t\t\t\tif (useVulkanBinding)\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.Body << GetSamplerType(texture->Type.Ptr()) << \"(\";\n\t\t\t\t\t\tPrintOp(ctx, texture);\n\t\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t\t\tPrintOp(ctx, sampler);\n\t\t\t\t\t\tctx.Body << \")\";\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tPrintOp(ctx, texture);\n\t\t\t\t\t}\n\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t};\n\t\t\t\tif (instr->Function == \"Sample\")\n\t\t\t\t{\n\t\t\t\t\tif (instr->Arguments.Count() == 4)\n\t\t\t\t\t\tctx.Body << \"textureOffset\";\n\t\t\t\t\telse\n\t\t\t\t\t\tctx.Body << \"texture\";\n\t\t\t\t\tctx.Body << \"(\";\n\t\t\t\t\tprintSamplerArgument(instr->Arguments[0].Ptr(), instr->Arguments[1].Ptr());\n\t\t\t\t\tfor (int i = 2; i < instr->Arguments.Count(); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tPrintOp(ctx, instr->Arguments[i].Ptr());\n\t\t\t\t\t\tif (i < instr->Arguments.Count() - 1)\n\t\t\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t\t}\n\t\t\t\t\tctx.Body << \")\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Function == \"SampleLevel\")\n\t\t\t\t{\n\t\t\t\t\tctx.Body << \"textureLod\";\n\t\t\t\t\tctx.Body << \"(\";\n\t\t\t\t\tprintSamplerArgument(instr->Arguments[0].Ptr(), instr->Arguments[1].Ptr());\n\t\t\t\t\tfor (int i = 2; i < instr->Arguments.Count(); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tPrintOp(ctx, instr->Arguments[i].Ptr());\n\t\t\t\t\t\tif (i < instr->Arguments.Count() - 1)\n\t\t\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t\t}\n\t\t\t\t\tctx.Body << \")\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Function == \"SampleGrad\")\n\t\t\t\t{\n\t\t\t\t\tif (instr->Arguments.Count() == 6)\n\t\t\t\t\t\tctx.Body << \"textureGradOffset\";\n\t\t\t\t\telse\n\t\t\t\t\t\tctx.Body << \"textureGrad\";\n\t\t\t\t\tctx.Body << \"(\";\n\t\t\t\t\tprintSamplerArgument(instr->Arguments[0].Ptr(), instr->Arguments[1].Ptr());\n\t\t\t\t\tfor (int i = 2; i < instr->Arguments.Count(); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tPrintOp(ctx, instr->Arguments[i].Ptr());\n\t\t\t\t\t\tif (i < instr->Arguments.Count() - 1)\n\t\t\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t\t}\n\t\t\t\t\tctx.Body << \")\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Function == \"SampleBias\")\n\t\t\t\t{\n\t\t\t\t\tif (instr->Arguments.Count() == 5) // loc, bias, offset\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.Body << \"textureOffset(\";\n\t\t\t\t\t\tprintSamplerArgument(instr->Arguments[0].Ptr(), instr->Arguments[1].Ptr());\n\t\t\t\t\t\tPrintOp(ctx, instr->Arguments[2].Ptr());\n\t\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t\t\tPrintOp(ctx, instr->Arguments[4].Ptr());\n\t\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t\t\tPrintOp(ctx, instr->Arguments[3].Ptr());\n\t\t\t\t\t\tctx.Body << \")\";\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.Body << \"texture(\";\n\t\t\t\t\t\tprintSamplerArgument(instr->Arguments[0].Ptr(), instr->Arguments[1].Ptr());\n\t\t\t\t\t\tPrintOp(ctx, instr->Arguments[2].Ptr());\n\t\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t\t\tPrintOp(ctx, instr->Arguments[3].Ptr());\n\t\t\t\t\t\tctx.Body << \")\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (instr->Function == \"SampleCmp\")\n\t\t\t\t{\n\t\t\t\t\tif (instr->Arguments.Count() == 5)\n\t\t\t\t\t\tctx.Body << \"textureOffset(\";\n\t\t\t\t\telse\n\t\t\t\t\t\tctx.Body << \"texture(\";\n\t\t\t\t\tprintSamplerArgument(instr->Arguments[0].Ptr(), instr->Arguments[1].Ptr());\n\t\t\t\t\tauto baseType = dynamic_cast<ILBasicType*>(instr->Arguments[0]->Type.Ptr());\n\t\t\t\t\tif (baseType)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (baseType->Type == ILBaseType::Texture2DShadow)\n\t\t\t\t\t\t\tctx.Body << \"vec3(\";\n\t\t\t\t\t\telse if (baseType->Type == ILBaseType::TextureCubeShadow || baseType->Type == ILBaseType::Texture2DArrayShadow)\n\t\t\t\t\t\t\tctx.Body << \"vec4(\";\n\t\t\t\t\t\tPrintOp(ctx, instr->Arguments[2].Ptr());\n\t\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t\t\tPrintOp(ctx, instr->Arguments[3].Ptr());\n\t\t\t\t\t\tctx.Body << \")\";\n\t\t\t\t\t\tif (instr->Arguments.Count() == 5)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t\t\t\tPrintOp(ctx, instr->Arguments[4].Ptr());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tctx.Body << \")\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow NotImplementedException(\"CodeGen for texture function '\" + instr->Function + \"' is not implemented.\");\n\t\t\t}\n\n\t\t\tvoid DeclareStandardInputRecord(CodeGenContext & sb, const ILObjectDefinition & input, bool isVertexShader) override\n\t\t\t{\n\t\t\t\tauto info = ExtractExternComponentInfo(input);\n\t\t\t\tauto recType = ExtractRecordType(input.Type.Ptr());\n\t\t\t\tassert(recType);\n\t\t\t\tassert(info.DataStructure == ExternComponentCodeGenInfo::DataStructureType::StandardInput);\n\n\t\t\t\tint itemsDeclaredInBlock = 0;\n\n\t\t\t\tint index = 0;\n\t\t\t\tfor (auto & field : recType->Members)\n\t\t\t\t{\n\t\t\t\t\tif (!useVulkanBinding && field.Value.Type->IsSamplerState())\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t//if (input.Attributes.ContainsKey(\"VertexInput\"))\n\t\t\t\t\tif (useVulkanBinding || input.Attributes.ContainsKey(\"VertexInput\"))\n\t\t\t\t\t\tsb.GlobalHeader << \"layout(location = \" << index << \") \";\n\t\t\t\t\tif (!isVertexShader && (input.Attributes.ContainsKey(\"Flat\") || field.Value.Type->IsIntegral()))\n\t\t\t\t\t\tsb.GlobalHeader << \"flat \";\n\t\t\t\t\tsb.GlobalHeader << \"in \";\n\n\t\t\t\t\tString declName = field.Key;\n\t\t\t\t\tdeclName = AddWorldNameSuffix(declName, recType->ToString());\n\n\t\t\t\t\tPrintDef(sb.GlobalHeader, field.Value.Type.Ptr(), declName);\n\t\t\t\t\titemsDeclaredInBlock++;\n\t\t\t\t\tif (info.IsArray)\n\t\t\t\t\t{\n\t\t\t\t\t\tsb.GlobalHeader << \"[\";\n\t\t\t\t\t\tif (info.ArrayLength)\n\t\t\t\t\t\t\tsb.GlobalHeader << String(info.ArrayLength);\n\t\t\t\t\t\tsb.GlobalHeader << \"]\";\n\t\t\t\t\t}\n\t\t\t\t\tsb.GlobalHeader << \";\\n\";\n\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid DeclarePatchInputRecord(CodeGenContext & sb, const ILObjectDefinition & input, bool isVertexShader) override\n\t\t\t{\n\t\t\t\tauto info = ExtractExternComponentInfo(input);\n\t\t\t\tauto recType = ExtractRecordType(input.Type.Ptr());\n\t\t\t\tassert(recType);\n\t\t\t\tassert(info.DataStructure == ExternComponentCodeGenInfo::DataStructureType::Patch);\n\n\n\t\t\t\tint itemsDeclaredInBlock = 0;\n\n\t\t\t\tint index = 0;\n\t\t\t\tfor (auto & field : recType->Members)\n\t\t\t\t{\n\t\t\t\t\tif (!useVulkanBinding && field.Value.Type->IsSamplerState())\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (!isVertexShader && (input.Attributes.ContainsKey(\"Flat\")))\n\t\t\t\t\t\tsb.GlobalHeader << \"flat \";\n\t\t\t\t\tsb.GlobalHeader << \"patch in \";\n\n\t\t\t\t\tString declName = field.Key;\n\t\t\t\t\tdeclName = AddWorldNameSuffix(declName, recType->ToString());\n\n\t\t\t\t\tPrintDef(sb.GlobalHeader, field.Value.Type.Ptr(), declName);\n\t\t\t\t\titemsDeclaredInBlock++;\n\t\t\t\t\tif (info.IsArray)\n\t\t\t\t\t{\n\t\t\t\t\t\tsb.GlobalHeader << \"[\";\n\t\t\t\t\t\tif (info.ArrayLength)\n\t\t\t\t\t\t\tsb.GlobalHeader << String(info.ArrayLength);\n\t\t\t\t\t\tsb.GlobalHeader << \"]\";\n\t\t\t\t\t}\n\t\t\t\t\tsb.GlobalHeader << \";\\n\";\n\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid GenerateHeader(StringBuilder & sb, ILStage * stage)\n\t\t\t{\n\t\t\t\tsb << \"#version 440\\n\";\n\t\t\t\tif (stage->Attributes.ContainsKey(\"BindlessTexture\"))\n\t\t\t\t\tsb << \"#extension GL_ARB_bindless_texture: require\\n#extension GL_NV_gpu_shader5 : require\\n\";\n\t\t\t\tif (stage->Attributes.ContainsKey(\"NV_CommandList\"))\n\t\t\t\t\tsb << \"#extension GL_NV_command_list: require\\n\";\n\t\t\t}\n\n\t\t\tvoid GenerateDomainShaderProlog(CodeGenContext & ctx, ILStage * stage)\n\t\t\t{\n\t\t\t\tctx.GlobalHeader << \"layout(\";\n\t\t\t\tStageAttribute val;\n\t\t\t\tif (stage->Attributes.TryGetValue(\"Domain\", val))\n\t\t\t\t\tctx.GlobalHeader << ((val.Value == \"quads\") ? \"quads\" : \"triangles\");\n\t\t\t\telse\n\t\t\t\t\tctx.GlobalHeader << \"triangles\";\n                if (val.Value != \"triangles\" && val.Value != \"quads\")\n                    getSink()->diagnose(val.Position, Diagnostics::invalidTessellationDomain);\n\t\t\t\tif (stage->Attributes.TryGetValue(\"Winding\", val))\n\t\t\t\t{\n\t\t\t\t\tif (val.Value == \"cw\")\n\t\t\t\t\t\tctx.GlobalHeader << \", cw\";\n\t\t\t\t\telse\n\t\t\t\t\t\tctx.GlobalHeader << \", ccw\";\n\t\t\t\t}\n\t\t\t\tif (stage->Attributes.TryGetValue(\"EqualSpacing\", val))\n\t\t\t\t{\n\t\t\t\t\tif (val.Value == \"1\" || val.Value == \"true\")\n\t\t\t\t\t\tctx.GlobalHeader << \", equal_spacing\";\n\t\t\t\t}\n\t\t\t\tctx.GlobalHeader << \") in;\\n\";\n\t\t\t}\n\t\t\tvirtual void PrintParameterReference(StringBuilder& sb, ILModuleParameterInstance * param) override\n\t\t\t{\n\t\t\t\tif (param->Type->GetBindableResourceType() == BindableResourceType::NonBindable)\n\t\t\t\t{\n\t\t\t\t\tauto bufferName = EscapeCodeName(param->Module->BindingName);\n\t\t\t\t\tsb << bufferName << \".\" << param->Name;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tsb << EscapeCodeName(param->Module->BindingName + \"_\" + param->Name);\n\t\t\t\t}\n\t\t\t}\n\t\t\tvoid GenerateShaderParameterDefinition(CodeGenContext & ctx, ILShader * shader)\n\t\t\t{\n\t\t\t\tint oneDescBindingLoc = 0;\n\t\t\t\tfor (auto module : shader->ModuleParamSets)\n\t\t\t\t{\n\t\t\t\t\t// generate uniform buffer declaration\n\t\t\t\t\tauto bufferName = EscapeCodeName(module.Value->BindingName);\n\t\t\t\t\tbool containsOrdinaryParams = false;\n\t\t\t\t\tfor (auto param : module.Value->Parameters)\n\t\t\t\t\t\tif (param.Value->BufferOffset != -1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcontainsOrdinaryParams = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\tif (containsOrdinaryParams)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (useVulkanBinding)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!useSingleDescSet)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tctx.GlobalHeader << \"layout(std140, set = \" << module.Value->DescriptorSetId << \", binding = 0) \";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tctx.GlobalHeader << \"layout(std140, set = 0, binding =\" << oneDescBindingLoc << \") \";\n\t\t\t\t\t\t\t\tmodule.Value->UniformBufferLegacyBindingPoint = oneDescBindingLoc;\n\t\t\t\t\t\t\t\toneDescBindingLoc++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tctx.GlobalHeader << \"layout(binding = \" << module.Value->DescriptorSetId << \", std140) \";\n\t\t\t\t\t\tctx.GlobalHeader << \"uniform buf\" << bufferName << \"\\n{\\n\";\n\t\t\t\t\t\tfor (auto param : module.Value->Parameters)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (param.Value->BufferOffset != -1)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tPrintType(ctx.GlobalHeader, param.Value->Type.Ptr());\n\t\t\t\t\t\t\t\tctx.GlobalHeader << \" \" << param.Value->Name << \";\\n\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tctx.GlobalHeader << \"} \" << bufferName << \";\\n\";\n\t\t\t\t\t}\n\t\t\t\t\tint slotId = containsOrdinaryParams ? 1 : 0;\n\t\t\t\t\tfor (auto param : module.Value->Parameters)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto bindableType = param.Value->Type->GetBindableResourceType();\n\t\t\t\t\t\tif (bindableType != BindableResourceType::NonBindable)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tswitch (bindableType)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase BindableResourceType::StorageBuffer:\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tauto genType = param.Value->Type.As<ILGenericType>();\n\t\t\t\t\t\t\t\tif (!genType)\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\tString bufName = EscapeCodeName(module.Value->BindingName + \"_\" + param.Value->Name);\n\t\t\t\t\t\t\t\tif (useVulkanBinding)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (!useSingleDescSet)\n\t\t\t\t\t\t\t\t\t\tctx.GlobalHeader << \"layout(std430, set = \" << module.Value->DescriptorSetId << \", binding = \" << slotId << \") \";\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tctx.GlobalHeader << \"layout(std430, set = 0, binding = \" << oneDescBindingLoc << \") \";\n\t\t\t\t\t\t\t\t\t\tparam.Value->BindingPoints.Clear();\n\t\t\t\t\t\t\t\t\t\tparam.Value->BindingPoints.Add(oneDescBindingLoc);\n\t\t\t\t\t\t\t\t\t\toneDescBindingLoc++;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tctx.GlobalHeader << \"layout(std430, binding = \" << param.Value->BindingPoints.First() << \") \";\n\t\t\t\t\t\t\t\tctx.GlobalHeader << \"buffer buf\" << bufName << \"\\n{\\n\";\n\t\t\t\t\t\t\t\tPrintType(ctx.GlobalHeader, genType->BaseType.Ptr());\n\t\t\t\t\t\t\t\tctx.GlobalHeader << \" \" << bufName << \"[];\\n};\\n\";\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcase BindableResourceType::Texture:\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (useVulkanBinding)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (!useSingleDescSet)\n\t\t\t\t\t\t\t\t\t\tctx.GlobalHeader << \"layout(set = \" << module.Value->DescriptorSetId << \", binding = \" << slotId << \")\";\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tctx.GlobalHeader << \"layout(set = 0, binding = \" << oneDescBindingLoc << \")\";\n\t\t\t\t\t\t\t\t\t\tparam.Value->BindingPoints.Clear();\n\t\t\t\t\t\t\t\t\t\tparam.Value->BindingPoints.Add(oneDescBindingLoc);\n\t\t\t\t\t\t\t\t\t\toneDescBindingLoc++;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tctx.GlobalHeader << \"layout(binding = \" << param.Value->BindingPoints.First() << \")\";\n\t\t\t\t\t\t\t\tctx.GlobalHeader << \" uniform \";\n\t\t\t\t\t\t\t\tPrintType(ctx.GlobalHeader, param.Value->Type.Ptr());\n\t\t\t\t\t\t\t\tctx.GlobalHeader << \" \" << EscapeCodeName(module.Value->BindingName + \"_\" + param.Value->Name) << \";\\n\";\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcase BindableResourceType::Sampler:\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (useVulkanBinding)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (!useSingleDescSet)\n\t\t\t\t\t\t\t\t\t\tctx.GlobalHeader << \"layout(set = \" << module.Value->DescriptorSetId << \", binding = \" << slotId << \")\";\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tctx.GlobalHeader << \"layout(set = 0, binding = \" << oneDescBindingLoc << \")\";\n\t\t\t\t\t\t\t\t\t\tparam.Value->BindingPoints.Clear();\n\t\t\t\t\t\t\t\t\t\tparam.Value->BindingPoints.Add(oneDescBindingLoc);\n\t\t\t\t\t\t\t\t\t\toneDescBindingLoc++;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tctx.GlobalHeader << \" uniform \";\n\t\t\t\t\t\t\t\t\tPrintType(ctx.GlobalHeader, param.Value->Type.Ptr());\n\t\t\t\t\t\t\t\t\tctx.GlobalHeader << \" \" << EscapeCodeName(module.Value->BindingName + \"_\" + param.Value->Name) << \";\\n\";\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tslotId++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvirtual void GenerateShaderMetaData(ShaderMetaData & result, ILProgram* program, ILShader* shader, DiagnosticSink* err) override\n\t\t\t{\n\t\t\t\tEnumerableDictionary<ILModuleParameterInstance*, List<ILModuleParameterInstance*>> samplerTextures;\n\t\t\t\tfor (auto & w : shader->Worlds)\n\t\t\t\t{\n\t\t\t\t\tif (w.Value->Code)\n\t\t\t\t\t\tAnalyzeSamplerUsage(samplerTextures, program, w.Value->Code.Ptr(), err);\n\t\t\t\t}\n\t\t\t\tif (!useVulkanBinding)\n\t\t\t\t{\n\t\t\t\t\tfor (auto & s : program->Shaders)\n\t\t\t\t\t\tfor (auto & pset : s->ModuleParamSets)\n\t\t\t\t\t\t\tfor (auto & p : pset.Value->Parameters)\n\t\t\t\t\t\t\t\tif (p.Value->Type->IsSamplerState())\n\t\t\t\t\t\t\t\t\tp.Value->BindingPoints.Clear();\n\t\t\t\t\tfor (auto & sampler : samplerTextures)\n\t\t\t\t\t{\n\t\t\t\t\t\tsampler.Key->BindingPoints.Clear();\n\t\t\t\t\t\tfor (auto & tex : sampler.Value)\n\t\t\t\t\t\t\tsampler.Key->BindingPoints.AddRange(tex->BindingPoints);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tCLikeCodeGen::GenerateShaderMetaData(result, program, shader, err);\n\t\t\t}\n\n\t\t\tStageSource GenerateSingleWorldShader(ILProgram * program, ILShader * shader, ILStage * stage) override\n\t\t\t{\n\t\t\t\tuseBindlessTexture = stage->Attributes.ContainsKey(\"BindlessTexture\");\n\t\t\t\tStageSource rs;\n\t\t\t\tCodeGenContext ctx;\n\t\t\t\tGenerateHeader(ctx.GlobalHeader, stage);\n\n\t\t\t\tif (stage->StageType == \"DomainShader\")\n\t\t\t\t\tGenerateDomainShaderProlog(ctx, stage);\n\n\t\t\t\tGenerateStructs(ctx.GlobalHeader, program);\n\t\t\t\tGenerateShaderParameterDefinition(ctx, shader);\n\n\t\t\t\tStageAttribute worldName;\n\t\t\t\tRefPtr<ILWorld> world = nullptr;\n\t\t\t\tif (stage->Attributes.TryGetValue(\"World\", worldName))\n\t\t\t\t{\n\t\t\t\t\tif (!shader->Worlds.TryGetValue(worldName.Value, world))\n\t\t\t\t\t\terrWriter->diagnose(worldName.Position, Diagnostics::worldIsNotDefined, worldName.Value);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::stageShouldProvideWorldAttribute, stage->StageType);\n\t\t\t\tif (!world)\n\t\t\t\t\treturn rs;\n\t\t\t\tGenerateReferencedFunctions(ctx.GlobalHeader, program, MakeArrayView(world.Ptr()));\n\t\t\t\textCompInfo.Clear();\n\t\t\t\tfor (auto & input : world->Inputs)\n\t\t\t\t{\n\t\t\t\t\tDeclareInput(ctx, input, stage->StageType == \"VertexShader\");\n\t\t\t\t}\n\t\t\n\t\t\t\toutputStrategy->DeclareOutput(ctx, stage);\n\t\t\t\tctx.codeGen = this;\n\t\t\t\tworld->Code->NameAllInstructions();\n\t\t\t\tGenerateCode(ctx, world->Code.Ptr());\n\t\t\t\tif (stage->StageType == \"VertexShader\" || stage->StageType == \"DomainShader\")\n\t\t\t\t\tGenerateVertexShaderEpilog(ctx, world.Ptr(), stage);\n\n\t\t\t\tStringBuilder sb;\n\t\t\t\tsb << ctx.GlobalHeader.ProduceString();\n\t\t\t\tsb << \"void main()\\n{\\n\";\n\t\t\t\tsb << ctx.Header.ProduceString() << ctx.Body.ProduceString();\n\t\t\t\tsb << \"}\";\n\t\t\t\trs.MainCode = sb.ProduceString();\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tStageSource GenerateHullShader(ILProgram * program, ILShader * shader, ILStage * stage) override\n\t\t\t{\n\t\t\t\tuseBindlessTexture = stage->Attributes.ContainsKey(\"BindlessTexture\");\n\n\t\t\t\tStageSource rs;\n\t\t\t\tStageAttribute patchWorldName, controlPointWorldName, cornerPointWorldName, domain, innerLevel, outerLevel, numControlPoints;\n\t\t\t\tRefPtr<ILWorld> patchWorld, controlPointWorld, cornerPointWorld;\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"PatchWorld\", patchWorldName))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresPatchWorld);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (!shader->Worlds.TryGetValue(patchWorldName.Value, patchWorld))\n\t\t\t\t\terrWriter->diagnose(patchWorldName.Position, Diagnostics::worldIsNotDefined, patchWorldName.Value);\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"ControlPointWorld\", controlPointWorldName))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresControlPointWorld); \n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (!shader->Worlds.TryGetValue(controlPointWorldName.Value, controlPointWorld))\n\t\t\t\t\terrWriter->diagnose(controlPointWorldName.Position, Diagnostics::worldIsNotDefined, controlPointWorldName.Value);\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"CornerPointWorld\", cornerPointWorldName))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresCornerPointWorld);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (!shader->Worlds.TryGetValue(cornerPointWorldName.Value, cornerPointWorld))\n\t\t\t\t\terrWriter->diagnose(cornerPointWorldName.Position, Diagnostics::worldIsNotDefined, cornerPointWorldName.Value);\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"Domain\", domain))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresDomain);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (domain.Value != \"triangles\" && domain.Value != \"quads\")\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(domain.Position, Diagnostics::invalidTessellationDomain);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"TessLevelOuter\", outerLevel))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresTessLevelOuter);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"TessLevelInner\", innerLevel))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresTessLevelInner);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"ControlPointCount\", numControlPoints))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresControlPointCount);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tCodeGenContext ctx;\n\t\t\t\tctx.codeGen = this;\n\t\t\t\tList<ILWorld*> worlds;\n\t\t\t\tworlds.Add(patchWorld.Ptr());\n\t\t\t\tworlds.Add(controlPointWorld.Ptr());\n\t\t\t\tworlds.Add(cornerPointWorld.Ptr());\n\t\t\t\tGenerateHeader(ctx.GlobalHeader, stage);\n\t\t\t\tctx.GlobalHeader << \"layout(vertices = \" << numControlPoints.Value << \") out;\\n\";\n\t\t\t\tGenerateStructs(ctx.GlobalHeader, program);\n\t\t\t\tGenerateShaderParameterDefinition(ctx, shader);\n\t\t\t\tGenerateReferencedFunctions(ctx.GlobalHeader, program, worlds.GetArrayView());\n\t\t\t\textCompInfo.Clear();\n\n\t\t\t\tHashSet<String> declaredInputs;\n\n\t\t\t\tpatchWorld->Code->NameAllInstructions();\n\t\t\t\toutputStrategy = CreateStandardOutputStrategy(patchWorld.Ptr(), \"patch\");\n\t\t\t\tfor (auto & input : patchWorld->Inputs)\n\t\t\t\t{\n\t\t\t\t\tif (declaredInputs.Add(input.Name))\n\t\t\t\t\t\tDeclareInput(ctx, input, false);\n\t\t\t\t}\n\t\t\t\toutputStrategy->DeclareOutput(ctx, stage);\n\t\t\t\tGenerateCode(ctx, patchWorld->Code.Ptr());\n\n\t\t\t\tcontrolPointWorld->Code->NameAllInstructions();\n\t\t\t\toutputStrategy = CreateArrayOutputStrategy(controlPointWorld.Ptr(), false, 0, \"gl_InvocationID\");\n\t\t\t\tfor (auto & input : controlPointWorld->Inputs)\n\t\t\t\t{\n\t\t\t\t\tif (declaredInputs.Add(input.Name))\n\t\t\t\t\t\tDeclareInput(ctx, input, false);\n\t\t\t\t}\n\t\t\t\toutputStrategy->DeclareOutput(ctx, stage);\n\t\t\t\tGenerateCode(ctx, controlPointWorld->Code.Ptr());\n\n\t\t\t\tcornerPointWorld->Code->NameAllInstructions();\n\t\t\t\toutputStrategy = CreateArrayOutputStrategy(cornerPointWorld.Ptr(), true, (domain.Value == \"triangles\" ? 3 : 4), \"sysLocalIterator\");\n\t\t\t\tfor (auto & input : cornerPointWorld->Inputs)\n\t\t\t\t{\n\t\t\t\t\tif (declaredInputs.Add(input.Name))\n\t\t\t\t\t\tDeclareInput(ctx, input, false);\n\t\t\t\t}\n\t\t\t\toutputStrategy->DeclareOutput(ctx, stage);\n\t\t\t\tctx.Body << \"for (int sysLocalIterator = 0; sysLocalIterator < gl_PatchVerticesIn; sysLocalIterator++)\\n{\\n\";\n\t\t\t\tGenerateCode(ctx, cornerPointWorld->Code.Ptr());\n\t\t\t\tauto debugStr = cornerPointWorld->Code->ToString();\n\t\t\t\tctx.Body << \"}\\n\";\n\n\t\t\t\t// generate epilog\n\t\t\t\tbool found = false;\n\t\t\t\tfor (auto & world : worlds)\n\t\t\t\t{\n\t\t\t\t\tILOperand * operand;\n\t\t\t\t\tif (world->Components.TryGetValue(innerLevel.Value, operand))\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int i = 0; i < 2; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tctx.Body << \"gl_TessLevelInner[\" << i << \"] = \";\n\t\t\t\t\t\t\tPrintOp(ctx, operand);\n\t\t\t\t\t\t\tctx.Body << \"[\" << i << \"];\\n\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!found)\n\t\t\t\t\terrWriter->diagnose(innerLevel.Position, Diagnostics::componentNotDefined, innerLevel.Value);\n\n\t\t\t\tfound = false;\n\t\t\t\tfor (auto & world : worlds)\n\t\t\t\t{\n\t\t\t\t\tILOperand * operand;\n\t\t\t\t\tif (world->Components.TryGetValue(outerLevel.Value, operand))\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int i = 0; i < 4; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tctx.Body << \"gl_TessLevelOuter[\" << i << \"] = \";\n\t\t\t\t\t\t\tPrintOp(ctx, operand);\n\t\t\t\t\t\t\tctx.Body << \"[\" << i << \"];\\n\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\tif (!found)\n\t\t\t\t\terrWriter->diagnose(outerLevel.Position, Diagnostics::componentNotDefined, outerLevel.Value);\n\n\t\t\t\tStringBuilder sb;\n\t\t\t\tsb << ctx.GlobalHeader.ProduceString();\n\t\t\t\tsb << \"void main()\\n{\\n\" << ctx.Header.ProduceString() << ctx.Body.ProduceString() << \"}\";\n\t\t\t\trs.MainCode = sb.ProduceString();\n\t\t\t\treturn rs;\n\t\t\t}\n\t\tpublic:\n\t\t\tGLSLCodeGen(bool vulkanBinding, bool pUseSingleDescSet)\n\t\t\t{\n\t\t\t\tuseVulkanBinding = vulkanBinding;\n\t\t\t\tuseSingleDescSet = pUseSingleDescSet;\n\t\t\t}\n\t\t};\n\n\n\t\tclass StandardOutputStrategy : public OutputStrategy\n\t\t{\n\t\tprivate:\n\t\t\tString declPrefix;\n\t\t\tbool isVulkan;\n\t\tpublic:\n\t\t\tStandardOutputStrategy(GLSLCodeGen * pCodeGen, ILWorld * world, String prefix)\n\t\t\t\t: OutputStrategy(pCodeGen, world), declPrefix(prefix)\n\t\t\t{\n\t\t\t\tisVulkan = pCodeGen->useVulkanBinding;\n\t\t\t}\n\t\t\tvirtual void DeclareOutput(CodeGenContext & ctx, ILStage * stage) override\n\t\t\t{\n\t\t\t\tint location = 0;\n\t\t\t\tfor (auto & field : world->OutputType->Members)\n\t\t\t\t{\n\t\t\t\t\tif (field.Value.Attributes.ContainsKey(\"FragDepth\"))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (isVulkan || stage->StageType == \"FragmentShader\")\n\t\t\t\t\t\tctx.GlobalHeader << \"layout(location = \" << location << \") \";\n\t\t\t\t\tif (declPrefix.Length())\n\t\t\t\t\t\tctx.GlobalHeader << declPrefix << \" \";\n\t\t\t\t\tif (field.Value.Type->IsIntegral())\n\t\t\t\t\t\tctx.GlobalHeader << \"flat \";\n\t\t\t\t\tctx.GlobalHeader << \"out \";\n\t\t\t\t\tString declName = field.Key;\n\t\t\t\t\tcodeGen->PrintDef(ctx.GlobalHeader, field.Value.Type.Ptr(), AddWorldNameSuffix(declName, world->OutputType->TypeName));\n\t\t\t\t\tctx.GlobalHeader << \";\\n\";\n\t\t\t\t\tlocation++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tvirtual void ProcessExportInstruction(CodeGenContext & ctx, ExportInstruction * instr) override\n\t\t\t{\n\t\t\t\tif (world->OutputType->Members[instr->ComponentName]().Attributes.ContainsKey(\"FragDepth\"))\n\t\t\t\t\tctx.Body << \"gl_FragDepth = \";\n\t\t\t\telse\n\t\t\t\t\tctx.Body << AddWorldNameSuffix(instr->ComponentName, world->OutputType->TypeName) << \" = \";\n\t\t\t\tcodeGen->PrintOp(ctx, instr->Operand.Ptr());\n\t\t\t\tctx.Body << \";\\n\";\n\t\t\t}\n\t\t};\n\n\t\tclass ArrayOutputStrategy : public OutputStrategy\n\t\t{\n\t\tprotected:\n\t\t\tbool isPatch = false;\n\t\t\tint arraySize = 0;\n\t\tpublic:\n\t\t\tString outputIndex;\n\t\t\tArrayOutputStrategy(GLSLCodeGen * pCodeGen, ILWorld * world, bool pIsPatch, int pArraySize, String pOutputIndex)\n\t\t\t\t: OutputStrategy(pCodeGen, world)\n\t\t\t{\n\t\t\t\tisPatch = pIsPatch;\n\t\t\t\tarraySize = pArraySize;\n\t\t\t\toutputIndex = pOutputIndex;\n\t\t\t}\n\t\t\tvirtual void DeclareOutput(CodeGenContext & ctx, ILStage *) override\n\t\t\t{\n\t\t\t\tfor (auto & field : world->OutputType->Members)\n\t\t\t\t{\n\t\t\t\t\tif (isPatch)\n\t\t\t\t\t\tctx.GlobalHeader << \"patch \";\n\t\t\t\t\tctx.GlobalHeader << \"out \";\n\t\t\t\t\tcodeGen->PrintDef(ctx.GlobalHeader, field.Value.Type.Ptr(), AddWorldNameSuffix(field.Key, world->Name));\n\t\t\t\t\tctx.GlobalHeader << \"[\";\n\t\t\t\t\tif (arraySize != 0)\n\t\t\t\t\t\tctx.GlobalHeader << arraySize;\n\t\t\t\t\tctx.GlobalHeader<<\"]; \\n\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tvirtual void ProcessExportInstruction(CodeGenContext & ctx, ExportInstruction * instr) override\n\t\t\t{\n\t\t\t\tctx.Body << AddWorldNameSuffix(instr->ComponentName, world->Name) << \"[\" << outputIndex << \"] = \";\n\t\t\t\tcodeGen->PrintOp(ctx, instr->Operand.Ptr());\n\t\t\t\tctx.Body << \";\\n\";\n\t\t\t}\n\t\t};\n\n\t\tclass PackedBufferOutputStrategy : public OutputStrategy\n\t\t{\n\t\tpublic:\n\t\t\tPackedBufferOutputStrategy(GLSLCodeGen * pCodeGen, ILWorld * world)\n\t\t\t\t: OutputStrategy(pCodeGen, world)\n\t\t\t{}\n\t\t\tvirtual void DeclareOutput(CodeGenContext & ctx, ILStage *) override\n\t\t\t{\n\t\t\t\tfor (auto & field : world->OutputType->Members)\n\t\t\t\t{\n\t\t\t\t\tctx.GlobalHeader << \"out \";\n\t\t\t\t\tcodeGen->PrintDef(ctx.GlobalHeader, field.Value.Type.Ptr(), field.Key);\n\t\t\t\t\tctx.GlobalHeader << \";\\n\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tvirtual void ProcessExportInstruction(CodeGenContext & ctx, ExportInstruction * exportInstr) override\n\t\t\t{\n\t\t\t\tString conversionFunction;\n\t\t\t\tint size = 0;\n\t\t\t\tString typeName = exportInstr->Type->ToString();\n\t\t\t\tif (typeName == \"int\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"intBitsToFloat\";\n\t\t\t\t\tsize = 1;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"ivec2\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"intBitsToFloat\";\n\t\t\t\t\tsize = 2;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"ivec3\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"intBitsToFloat\";\n\t\t\t\t\tsize = 3;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"ivec4\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"intBitsToFloat\";\n\t\t\t\t\tsize = 4;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"uint\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"uintBitsToFloat\";\n\t\t\t\t\tsize = 1;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"uvec2\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"uintBitsToFloat\";\n\t\t\t\t\tsize = 2;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"uvec3\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"uintBitsToFloat\";\n\t\t\t\t\tsize = 3;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"uvec4\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"uintBitsToFloat\";\n\t\t\t\t\tsize = 4;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"float\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\tsize = 1;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"vec2\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\tsize = 2;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"vec3\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\tsize = 3;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"vec4\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\tsize = 4;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"mat3\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\tsize = 9;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"mat4\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\tsize = 16;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n                    codeGen->getSink()->diagnose(CodePosition(), Diagnostics::importingFromPackedBufferUnsupported, typeName);\n\t\t\t\t}\n\t\t\t\tauto recType = world->OutputType.Ptr();\n\t\t\t\tint recTypeSize = 0;\n\t\t\t\tEnumerableDictionary<String, int> memberOffsets;\n\t\t\t\tfor (auto & member : recType->Members)\n\t\t\t\t{\n\t\t\t\t\tmemberOffsets[member.Key] = recTypeSize;\n\t\t\t\t\trecTypeSize += member.Value.Type->GetVectorSize();\n\t\t\t\t}\n\t\t\t\tfor (int i = 0; i < size; i++)\n\t\t\t\t{\n\t\t\t\t\tctx.Body << \"sysOutputBuffer.content[gl_InvocationId.x * \" << recTypeSize << \" + \" + memberOffsets[exportInstr->ComponentName]()\n\t\t\t\t\t\t<< \"] = \" << conversionFunction << \"(\";\n\t\t\t\t\tcodeGen->PrintOp(ctx, exportInstr->Operand.Ptr());\n\t\t\t\t\tif (size <= 4)\n\t\t\t\t\t\tctx.Body << \"[\" << i << \"]\";\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tint width = size == 9 ? 3 : 4;\n\t\t\t\t\t\tctx.Body << \"[\" << i / width << \"][\" << i % width << \"]\";\n\t\t\t\t\t}\n\t\t\t\t\tctx.Body << \");\\n\";\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tOutputStrategy * GLSLCodeGen::CreateStandardOutputStrategy(ILWorld * world, String layoutPrefix)\n\t\t{\n\t\t\treturn new StandardOutputStrategy(this, world, layoutPrefix);\n\t\t}\n\t\tOutputStrategy * GLSLCodeGen::CreatePackedBufferOutputStrategy(ILWorld * world)\n\t\t{\n\t\t\treturn new PackedBufferOutputStrategy(this, world);\n\t\t}\n\t\tOutputStrategy * GLSLCodeGen::CreateArrayOutputStrategy(ILWorld * world, bool pIsPatch, int pArraySize, String arrayIndex)\n\t\t{\n\t\t\treturn new ArrayOutputStrategy(this, world, pIsPatch, pArraySize, arrayIndex);\n\t\t}\n\n\t\tCodeGenBackend * CreateGLSLCodeGen()\n\t\t{\n\t\t\treturn new GLSLCodeGen(false, false);\n\t\t}\n\t\tCodeGenBackend * CreateGLSL_VulkanCodeGen()\n\t\t{\n\t\t\treturn new GLSLCodeGen(true, false);\n\t\t}\n\t\tCodeGenBackend * CreateGLSL_VulkanOneDescCodeGen()\n\t\t{\n\t\t\treturn new GLSLCodeGen(true, true);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/GetDependencyVisitor.cpp",
    "content": "#include \"GetDependencyVisitor.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tEnumerableHashSet<ComponentDependency> GetDependentComponents(SyntaxNode * tree)\n\t\t{\n\t\t\tGetDependencyVisitor visitor;\n\t\t\ttree->Accept(&visitor);\n\t\t\treturn visitor.Result;\n\t\t}\n\n\t\tRefPtr<ExpressionSyntaxNode> GetDependencyVisitor::VisitImportExpression(ImportExpressionSyntaxNode * syntax)\n\t\t{\n\t\t\tfor (auto & comp : syntax->ImportOperatorDef->Usings)\n\t\t\t\tResult.Add(ComponentDependency(comp, nullptr));\n\t\t\tResult.Add(ComponentDependency(syntax->ComponentUniqueName, syntax->ImportOperatorDef.Ptr()));\n\t\t\treturn SyntaxVisitor::VisitImportExpression(syntax);\n\t\t}\n\t\tRefPtr<ExpressionSyntaxNode> GetDependencyVisitor::VisitMemberExpression(MemberExpressionSyntaxNode * member)\n\t\t{\n\t\t\tRefPtr<Object> refCompObj;\n\t\t\tif (member->Tags.TryGetValue(\"ComponentReference\", refCompObj))\n\t\t\t{\n\t\t\t\tauto refComp = refCompObj.As<StringObject>().Ptr();\n\t\t\t\tResult.Add(ComponentDependency(refComp->Content, nullptr));\n\t\t\t}\n\t\t\telse\n\t\t\t\tmember->BaseExpression->Accept(this);\n\t\t\treturn member;\n\t\t}\n\t\tRefPtr<ExpressionSyntaxNode> GetDependencyVisitor::VisitVarExpression(VarExpressionSyntaxNode * var)\n\t\t{\n\t\t\tRefPtr<Object> refCompObj;\n\t\t\tif (var->Tags.TryGetValue(\"ComponentReference\", refCompObj))\n\t\t\t{\n\t\t\t\tauto refComp = refCompObj.As<StringObject>().Ptr();\n\t\t\t\tResult.Add(ComponentDependency(refComp->Content, nullptr));\n\t\t\t}\n\t\t\treturn var;\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "Source/SpireCore/GetDependencyVisitor.h",
    "content": "#ifndef GET_DEPENDENCY_VISITOR_H\n#define GET_DEPENDENCY_VISITOR_H\n\n#include \"VariantIR.h\"\n#include \"Closure.h\"\n#include \"StringObject.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tclass ComponentDependency\n\t\t{\n\t\tpublic:\n\t\t\tString ReferencedComponent;\n\t\t\tImportOperatorDefSyntaxNode * ImportOperator = nullptr;\n\t\t\tComponentDependency() = default;\n\t\t\tComponentDependency(String compName, ImportOperatorDefSyntaxNode * impOp)\n\t\t\t\t: ReferencedComponent(compName), ImportOperator(impOp)\n\t\t\t{}\n\t\t\tint GetHashCode()\n\t\t\t{\n\t\t\t\treturn ReferencedComponent.GetHashCode() ^ (int)(CoreLib::PtrInt)(void*)(ImportOperator);\n\t\t\t}\n\t\t\tbool operator == (const ComponentDependency & other)\n\t\t\t{\n\t\t\t\treturn ReferencedComponent == other.ReferencedComponent && ImportOperator == other.ImportOperator;\n\t\t\t}\n\t\t};\n\n\t\tclass GetDependencyVisitor : public SyntaxVisitor\n\t\t{\n\t\tpublic:\n\t\t\tEnumerableHashSet<ComponentDependency> Result;\n\t\t\tGetDependencyVisitor()\n\t\t\t\t: SyntaxVisitor(nullptr)\n\t\t\t{}\n\n\t\t\tRefPtr<ExpressionSyntaxNode> VisitVarExpression(VarExpressionSyntaxNode * var) override;\n\n\t\t\tRefPtr<ExpressionSyntaxNode> VisitMemberExpression(MemberExpressionSyntaxNode * member) override;\n\n\t\t\tRefPtr<ExpressionSyntaxNode> VisitImportExpression(ImportExpressionSyntaxNode * syntax) override;\n\t\t};\n\n\t\tEnumerableHashSet<ComponentDependency> GetDependentComponents(SyntaxNode * tree);\n\t}\n}\n#endif"
  },
  {
    "path": "Source/SpireCore/HLSLCodeGen.cpp",
    "content": "#include \"CLikeCodeGen.h\"\n#include \"../CoreLib/Tokenizer.h\"\n#include \"Syntax.h\"\n#include \"Naming.h\"\n#include \"TypeLayout.h\"\n#include <cassert>\n\nusing namespace CoreLib::Basic;\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tclass HLSLCodeGen : public CLikeCodeGen\n\t\t{\n\t\tprivate:\n\t\t\tbool useD3D12Registers = false;\n\t\tprotected:\n\t\t\tOutputStrategy * CreateStandardOutputStrategy(ILWorld * world, String layoutPrefix) override;\n\t\t\tOutputStrategy * CreatePackedBufferOutputStrategy(ILWorld * world) override;\n\t\t\tOutputStrategy * CreateArrayOutputStrategy(ILWorld * world, bool pIsPatch, int pArraySize, String arrayIndex) override;\n\n            LayoutRule GetDefaultLayoutRule() override\n            {\n                return LayoutRule::HLSL;\n            }\n\n\t\t\tvoid PrintRasterPositionOutputWrite(CodeGenContext & ctx, ILOperand * operand) override\n\t\t\t{\n\t\t\t\tctx.Body << \"stage_output.sv_position = \";\n\t\t\t\tPrintOp(ctx, operand);\n\t\t\t\tctx.Body << \";\\n\";\n\t\t\t}\n\n\t\t\tvoid PrintMatrixMulInstrExpr(CodeGenContext & ctx, ILOperand* op0, ILOperand* op1) override\n\t\t\t{\n\t\t\t\t// The matrix-vector, vector-matrix, and matrix-matrix product\n\t\t\t\t// operation is written with the `*` operator in GLSL, but\n\t\t\t\t// is handled by the built-in function `mul()` in HLSL.\n\t\t\t\t//\n\t\t\t\t// This function is called by the code generator for that op\n\t\t\t\t// and allows us to print it appropriately.\n\n\t\t\t\tctx.Body << \"mul(\";\n\t\t\t\tPrintOp(ctx, op1);\n\t\t\t\tctx.Body << \", \";\n\t\t\t\tPrintOp(ctx, op0);\n\t\t\t\tctx.Body << \")\";\n\t\t\t}\n\t\t\t\n\t\t\tvoid PrintStandardInputReference(StringBuilder& sb, ILRecordType* /*recType*/, String inputName, String componentName) override\n\t\t\t{\n\t\t\t\tsb << \"stage_input/*standard*/\";\n\t\t\t}\n\n\t\t\tvoid PrintStandardArrayInputReference(StringBuilder& sb, ILRecordType* /*recType*/, String inputName, String componentName) override\n\t\t\t{\n\t\t\t\tsb << \"stage_input/*array*/\";\n\t\t\t}\n\n\t\t\tvoid PrintPatchInputReference(StringBuilder& sb, ILRecordType* /*recType*/, String inputName, String componentName) override\n\t\t\t{\n\t\t\t\tsb << \"stage_input_patch/*patch*/.\" << inputName;\n\t\t\t}\n\n\t\t\tvoid PrintDefaultInputReference(StringBuilder& sb, ILRecordType* /*recType*/, String inputName, String componentName) override\n\t\t\t{\n\t\t\t\tString declName = componentName;\n\t\t\t\tsb << declName;\n\t\t\t}\n\n\t\t\tvoid PrintSystemVarReference(CodeGenContext & ctx, StringBuilder& sb, String inputName, ExternComponentCodeGenInfo::SystemVarType systemVar) override\n\t\t\t{\n\t\t\t\tctx.UsedSystemInputs.Add(systemVar);\n\t\t\t\tswitch(systemVar)\n\t\t\t\t{\n\t\t\t\tcase ExternComponentCodeGenInfo::SystemVarType::FragCoord:\n\t\t\t\t\tsb << \"sv_FragPosition\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExternComponentCodeGenInfo::SystemVarType::TessCoord:\n\t\t\t\t\tsb << \"sv_DomainLocation\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExternComponentCodeGenInfo::SystemVarType::InvocationId:\n\t\t\t\t\tsb << \"sv_ThreadID\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExternComponentCodeGenInfo::SystemVarType::ThreadId:\n\t\t\t\t\tsb << \"sv_GlobalThreadID.x\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExternComponentCodeGenInfo::SystemVarType::PatchVertexCount:\n\t\t\t\t\t// TODO(tfoley): there is no equivalent of this in HLSL\n\t\t\t\t\tsb << \"sv_InputControlPointCount\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExternComponentCodeGenInfo::SystemVarType::PrimitiveId:\n\t\t\t\t\tsb << \"sv_PrimitiveID\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase ExternComponentCodeGenInfo::SystemVarType::InstanceId:\n\t\t\t\t\tsb << \"sv_InstanceID\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tsb << inputName;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid PrintCallInstrExprForTarget(CodeGenContext & ctx, CallInstruction * instr, String const& name) override\n\t\t\t{\n\t\t\t\t// Currently, all types are internally named based on their GLSL equivalent, so\n\t\t\t\t// for HLSL output we go ahead and maintain a big table to remap the names.\n\t\t\t\t//\n\t\t\t\t// Note: for right now, this is just a linear array, with no particular sorting.\n\t\t\t\t// Eventually it should be turned into a hash table for performance, or at least\n\t\t\t\t// just be kept sorted so that we can use a binary search.\n\t\t\t\t//\n\t\t\t\t// Note 2: Well, actually, the Right Answer is for the type representation to\n\t\t\t\t// be better than just a string, so that we don't have to do this string->string map.\n\t\t\t\tstatic const struct {\n\t\t\t\t\tchar const* glslName;\n\t\t\t\t\tchar const* hlslName;\n\t\t\t\t} kNameRemaps[] =\n\t\t\t\t{\n\t\t\t\t\t{ \"vec2\", \"*float2\" },\n\t\t\t\t\t{ \"vec3\", \"*float3\" },\n\t\t\t\t\t{ \"vec4\", \"*float4\" },\n\n\t\t\t\t\t{ \"ivec2\", \"*int2\" },\n\t\t\t\t\t{ \"ivec3\", \"*int3\" },\n\t\t\t\t\t{ \"ivec4\", \"*int4\" },\n\n\t\t\t\t\t{ \"uvec2\", \"*uint2\" },\n\t\t\t\t\t{ \"uvec3\", \"*uint3\" },\n\t\t\t\t\t{ \"uvec4\", \"*uint4\" },\n\n\t\t\t\t\t{ \"mat3\", \"float3x3\" },\n\t\t\t\t\t{ \"mat4\", \"float4x4\" },\n\n\t\t\t\t\t{ \"sampler2D\", \"Texture2D\" },\n\t\t\t\t\t{ \"sampler2DArray\", \"Texture2DArray\" },\n\t\t\t\t\t{ \"samplerCube\", \"TextureCube\" },\n\t\t\t\t\t{ \"sampler2DShadow\", \"Texture2D\" },\n\t\t\t\t\t{ \"sampler2DArrayShadow\", \"Texture2DArray\" },\n\t\t\t\t\t{ \"samplerCubeShadow\", \"TextureCube\" },\n\t\t\t\t};\n\n\t\t\t\tfor(auto remap : kNameRemaps)\n\t\t\t\t{\n\t\t\t\t\tif(strcmp(name.Buffer(), remap.glslName) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tchar const* hlslName = remap.hlslName;\n\t\t\t\t\t\tif(*hlslName == '*')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thlslName++;\n\n\t\t\t\t\t\t\t// Note(tfoley): The specific case we are dealing with right\n\t\t\t\t\t\t\t// now is that constructing a vector from a scalar value\n\t\t\t\t\t\t\t// *must* be expressed as a cast in HLSL, while in GLSL\n\t\t\t\t\t\t\t// it *must* be expressed as a constructor call. We\n\t\t\t\t\t\t\t// intercept the call to a constructor here in the\n\t\t\t\t\t\t\t// specific case where it has one argument, and print\n\t\t\t\t\t\t\t// it differently\n\t\t\t\t\t\t\tif(instr->Arguments.Count() == 1)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tctx.Body << \"((\" << hlslName << \") \";\n\t\t\t\t\t\t\t\tPrintOp(ctx, instr->Arguments[0].Ptr());\n\t\t\t\t\t\t\t\tctx.Body << \")\";\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tPrintDefaultCallInstrExpr(ctx, instr, hlslName);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tPrintDefaultCallInstrExpr(ctx, instr, name);\n\t\t\t}\n\n\t\t\tvoid PrintTextureCall(CodeGenContext & ctx, CallInstruction * instr)\n\t\t\t{\n\t\t\t\t// texture functions are defined based on HLSL, so this is trivial\n\t\t\t\t// internally, texObj.Sample(sampler_obj, uv, ..) is represented as Sample(texObj, sampler_obj, uv, ...)\n\t\t\t\t// so we need to lift first argument to the front\n\t\t\t\tPrintOp(ctx, instr->Arguments[0].Ptr(), true);\n\t\t\t\tctx.Body << \".\" << instr->Function;\n\t\t\t\tctx.Body << \"(\";\n\t\t\t\tfor (int i = 1; i < instr->Arguments.Count(); i++)\n\t\t\t\t{\n\t\t\t\t\tPrintOp(ctx, instr->Arguments[i].Ptr());\n\t\t\t\t\tif (i < instr->Arguments.Count() - 1)\n\t\t\t\t\t\tctx.Body << \", \";\n\t\t\t\t}\n\t\t\t\tctx.Body << \")\";\n\t\t\t}\n\n\t\t\tvoid PrintProjectInstrExpr(CodeGenContext & ctx, ProjectInstruction * proj) override\n\t\t\t{\n\t\t\t\t// project component out of record type. \n\t\t\t\tPrintOp(ctx, proj->Operand.Ptr());\n\t\t\t\tctx.Body << \".\" << proj->ComponentName;\n\t\t\t}\n\n\t\t\tvoid PrintTypeName(StringBuilder& sb, ILType* type) override\n\t\t\t{\n\t\t\t\t// Currently, all types are internally named based on their GLSL equivalent, so\n\t\t\t\t// for HLSL output we go ahead and maintain a big table to remap the names.\n\t\t\t\t//\n\t\t\t\t// Note: for right now, this is just a linear array, with no particular sorting.\n\t\t\t\t// Eventually it should be turned into a hash table for performance, or at least\n\t\t\t\t// just be kept sorted so that we can use a binary search.\n\t\t\t\t//\n\t\t\t\t// Note 2: Well, actually, the Right Answer is for the type representation to\n\t\t\t\t// be better than just a string, so that we don't have to do this string->string map.\n\t\t\t\tstatic const struct {\n\t\t\t\t\tchar const* glslName;\n\t\t\t\t\tchar const* hlslName;\n\t\t\t\t} kNameRemaps[] =\n\t\t\t\t{\n\t\t\t\t\t{ \"vec2\", \"float2\" },\n\t\t\t\t\t{ \"vec3\", \"float3\" },\n\t\t\t\t\t{ \"vec4\", \"float4\" },\n\n\t\t\t\t\t{ \"ivec2\", \"int2\" },\n\t\t\t\t\t{ \"ivec3\", \"int3\" },\n\t\t\t\t\t{ \"ivec4\", \"int4\" },\n\n\t\t\t\t\t{ \"uvec2\", \"uint2\" },\n\t\t\t\t\t{ \"uvec3\", \"uint3\" },\n\t\t\t\t\t{ \"uvec4\", \"uint4\" },\n\n\t\t\t\t\t{ \"mat3\", \"float3x3\" },\n\t\t\t\t\t{ \"mat4\", \"float4x4\" },\n\n\t\t\t\t\t{ \"sampler2D\", \"Texture2D\" },\n\t\t\t\t\t{ \"sampler2DArray\", \"Texture2DArray\" },\n\t\t\t\t\t{ \"samplerCube\", \"TextureCube\" },\n\t\t\t\t\t{ \"sampler2DShadow\", \"Texture2D\" },\n\t\t\t\t\t{ \"sampler2DArrayShadow\", \"Texture2DArray\" },\n\t\t\t\t\t{ \"samplerCubeShadow\", \"TextureCube\" },\n\t\t\t\t\t{ \"samplerCubeArray\", \"TextureCubeArray\" },\n\t\t\t\t\t{ \"samplerCubeArrayShadow\", \"TextureCubeArray\" },\n\t\t\t\t\t{ \"sampler3D\", \"Texture3D\" }\n\t\t\t\t};\n\n\t\t\t\tString typeName = type->ToString();\n\t\t\t\tfor(auto remap : kNameRemaps)\n\t\t\t\t{\n\t\t\t\t\tif(strcmp(typeName.Buffer(), remap.glslName) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tsb << remap.hlslName;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If we don't find the type in our map, then that either means we missed a case,\n\t\t\t\t// or this is a user-defined type. I don't see an obvious way to check which of\n\t\t\t\t// those cases we are in, so we will just fall back to outputting the \"GLSL name\" here.\n\t\t\t\tsb << type->ToString();\n\t\t\t}\n\n\t\t\tString GetLastSegment(String accessName)\n\t\t\t{\n\t\t\t\tint idx = accessName.LastIndexOf('.');\n\t\t\t\tif (idx == -1)\n\t\t\t\t\treturn accessName;\n\t\t\t\treturn accessName.SubString(idx + 1, accessName.Length() - idx - 1);\n\t\t\t}\n\n\t\t\tvoid DefineCBufferParameterFields(CodeGenContext & sb, ILModuleParameterSet * module, int & itemsDeclaredInBlock)\n\t\t\t{\n\t\t\t\t// We declare an inline struct inside the `cbuffer` to ensure that\n\t\t\t\t// the members have an appropriate prefix on their name.\n\t\t\t\tsb.GlobalHeader << \"struct {\\n\";\n\n\t\t\t\tint index = 0;\n\t\t\t\tfor (auto & field : module->Parameters)\n\t\t\t\t{\n\t\t\t\t\tauto bindableResType = field.Value->Type->GetBindableResourceType();\n\t\t\t\t\tif (bindableResType != BindableResourceType::NonBindable)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tString declName = field.Key;\n\t\t\t\t\tPrintDef(sb.GlobalHeader, field.Value->Type.Ptr(), declName);\n\t\t\t\t\titemsDeclaredInBlock++;\n\t\t\t\t\tsb.GlobalHeader << \";\\n\";\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\n\t\t\t\t// define sub parameter fields\n\t\t\t\tfor (auto & subParam : module->SubModules)\n\t\t\t\t{\n\t\t\t\t\tint subItemsDeclaredInBlock = 0;\n\t\t\t\t\tint declarationStart = sb.GlobalHeader.Length();\n\t\t\t\t\tDefineCBufferParameterFields(sb, subParam.Ptr(), subItemsDeclaredInBlock);\n\t\t\t\t\tif (subItemsDeclaredInBlock == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tsb.GlobalHeader.Remove(declarationStart, sb.GlobalHeader.Length() - declarationStart);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tsb.GlobalHeader << \"} \" << GetLastSegment(module->BindingName) << \";\\n\";\n\t\t\t}\n\t\t\tvoid DefineBindableParameterFields(CodeGenContext & sb, ILModuleParameterSet * module, int descSetId, int & tCount, int & sCount, int & uCount, int & cCount)\n\t\t\t{\n\t\t\t\tmodule->TextureBindingStartIndex = tCount;\n\t\t\t\tmodule->SamplerBindingStartIndex = sCount;\n\t\t\t\tmodule->StorageBufferBindingStartIndex = uCount;\n\t\t\t\tmodule->UniformBindingStartIndex = cCount;\n\t\t\t\tfor (auto & field : module->Parameters)\n\t\t\t\t{\n\t\t\t\t\tauto bindableResType = field.Value->Type->GetBindableResourceType();\n\t\t\t\t\tif (bindableResType == BindableResourceType::NonBindable)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tPrintDef(sb.GlobalHeader, field.Value->Type.Ptr(), EscapeCodeName(module->BindingName + \"_\" + field.Key));\n\t\t\t\t\tif (field.Value->BindingPoints.Count())\n\t\t\t\t\t{\n\t\t\t\t\t\tsb.GlobalHeader << \": register(\";\n\t\t\t\t\t\tswitch (bindableResType)\n\t\t\t\t\t\t{\n\t\t\t\t\t\tcase BindableResourceType::Texture:\n\t\t\t\t\t\t\tsb.GlobalHeader << \"t\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase BindableResourceType::Sampler:\n\t\t\t\t\t\t\tsb.GlobalHeader << \"s\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase BindableResourceType::StorageBuffer:\n\t\t\t\t\t\t\tsb.GlobalHeader << \"u\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase BindableResourceType::Buffer:\n\t\t\t\t\t\t\tsb.GlobalHeader << \"c\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow NotImplementedException();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (useD3D12Registers)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tswitch (bindableResType)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase BindableResourceType::Texture:\n\t\t\t\t\t\t\t\tsb.GlobalHeader << tCount;\n\t\t\t\t\t\t\t\ttCount++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase BindableResourceType::Sampler:\n\t\t\t\t\t\t\t\tsb.GlobalHeader << sCount;\n\t\t\t\t\t\t\t\tsCount++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase BindableResourceType::StorageBuffer:\n\t\t\t\t\t\t\t\tsb.GlobalHeader << uCount;\n\t\t\t\t\t\t\t\tuCount++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase BindableResourceType::Buffer:\n\t\t\t\t\t\t\t\tsb.GlobalHeader << cCount;\n\t\t\t\t\t\t\t\tcCount++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsb.GlobalHeader << \", space\" << descSetId;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsb.GlobalHeader << field.Value->BindingPoints.First();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsb.GlobalHeader << \")\";\n\t\t\t\t\t}\n\t\t\t\t\tsb.GlobalHeader << \";\\n\";\n\t\t\t\t}\n\t\t\t\tfor (auto & subModule : module->SubModules)\n\t\t\t\t\tDefineBindableParameterFields(sb, subModule.Ptr(), descSetId, tCount, sCount, uCount, cCount);\n\t\t\t}\n\t\t\tbool DetermineParameterFieldOffset(ILModuleParameterSet * module, int & ptr)\n\t\t\t{\n\t\t\t\tbool firstFieldEncountered = false;\n\t\t\t\tmodule->UniformBufferOffset = ptr;\n\t\t\t\tauto layout = GetLayoutRulesImpl(LayoutRule::HLSL);\n\t\t\t\tauto structInfo = layout->BeginStructLayout();\n\t\t\t\tfor (auto & field : module->Parameters)\n\t\t\t\t{\n\t\t\t\t\tif (field.Value->Type->GetBindableResourceType() == BindableResourceType::NonBindable)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto flayout = GetLayout(field.Value->Type.Ptr(), LayoutRule::HLSL);\n\t\t\t\t\t\tfield.Value->BufferOffset = (int)(layout->AddStructField(&structInfo, flayout));\n\t\t\t\t\t\tfield.Value->Size = (int)flayout.size;\n\t\t\t\t\t\tif (!firstFieldEncountered)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmodule->UniformBufferOffset = field.Value->BufferOffset;\n\t\t\t\t\t\t\tfirstFieldEncountered = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfor (auto & subModule : module->SubModules)\n\t\t\t\t\t\tfirstFieldEncountered = DetermineParameterFieldOffset(subModule.Ptr(), ptr) | firstFieldEncountered;\n\t\t\t\t}\n\t\t\t\tlayout->EndStructLayout(&structInfo);\n\t\t\t\tmodule->BufferSize = (int)structInfo.size;\n\t\t\t\treturn firstFieldEncountered;\n\t\t\t}\n\t\t\tvoid GenerateShaderParameterDefinition(CodeGenContext & sb, ILShader * shader)\n\t\t\t{\n\t\t\t\t// first pass: figure out buffer offsets and alignments\n\t\t\t\tfor (auto module : shader->ModuleParamSets)\n\t\t\t\t{\n\t\t\t\t\tif (!module.Value->IsTopLevel)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tint ptr = 0;\n\t\t\t\t\tDetermineParameterFieldOffset(module.Value.Ptr(), ptr);\n\t\t\t\t}\n\t\t\t\tfor (auto module : shader->ModuleParamSets)\n\t\t\t\t{\n\t\t\t\t\tif (!module.Value->IsTopLevel)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t// TODO: this generates D3D11 style binding, should update to generate D3D12 root signature declaration\n\t\t\t\t\tauto moduleName = EscapeCodeName(module.Value->BindingName);\n\t\t\t\t\t\n\t\t\t\t\tint declarationStart = sb.GlobalHeader.Length();\n\t\t\t\t\tint itemsDeclaredInBlock = 0;\n\n\t\t\t\t\tsb.GlobalHeader << \"cbuffer buf\" << moduleName;\n\t\t\t\t\tif (module.Value->DescriptorSetId != -1)\n\t\t\t\t\t\tsb.GlobalHeader << \" : register(b\" << module.Value->DescriptorSetId << \")\";\n\t\t\t\t\tsb.GlobalHeader << \"\\n{\\n\";\n\t\t\t\t\tDefineCBufferParameterFields(sb, module.Value.Ptr(), itemsDeclaredInBlock);\n\t\t\t\t\tsb.GlobalHeader << \"};\\n\";\n\n\t\t\t\t\tif (itemsDeclaredInBlock == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tsb.GlobalHeader.Remove(declarationStart, sb.GlobalHeader.Length() - declarationStart);\n\t\t\t\t\t}\n\t\t\t\t\tint textureReg = 0; \n\t\t\t\t\tint samplerReg = 0;\n\t\t\t\t\tint uReg = 0;\n\t\t\t\t\tint cReg = 0;\n\t\t\t\t\tDefineBindableParameterFields(sb, module.Value.Ptr(), module.Value->DescriptorSetId, textureReg, samplerReg, uReg, cReg);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t}\n\n\t\t\tvirtual void PrintParameterReference(StringBuilder& sb, ILModuleParameterInstance * param) override\n\t\t\t{\n\t\t\t\tif (param->Type->GetBindableResourceType() == BindableResourceType::NonBindable)\n\t\t\t\t{\n\t\t\t\t\tsb << param->Module->BindingName << \".\" << param->Name;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tsb << EscapeCodeName(param->Module->BindingName + \"_\" + param->Name);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid DeclareStandardInputRecord(CodeGenContext & sb, const ILObjectDefinition & input, bool /*isVertexShader*/) override\n\t\t\t{\n\t\t\t\tauto info = ExtractExternComponentInfo(input);\n\t\t\t\textCompInfo[input.Name] = info;\n\t\t\t\tauto recType = ExtractRecordType(input.Type.Ptr());\n\t\t\t\tassert(recType);\n\n\t\t\t\tDeclareRecordTypeStruct(sb, recType);\n\t\t\t}\n\n\t\t\tvoid DeclarePatchInputRecord(CodeGenContext & sb, const ILObjectDefinition & input, bool isVertexShader) override\n\t\t\t{\n\t\t\t\t// In HLSL, both standard input/output and per-patch input/output are passed as ordinary `struct` types.\n\t\t\t\tDeclareStandardInputRecord(sb, input, isVertexShader);\n\t\t\t}\n\n\t\t\tvoid GenerateDomainShaderAttributes(StringBuilder & sb, ILStage * stage)\n\t\t\t{\n\t\t\t\tStageAttribute val;\n\t\t\t\tif (stage->Attributes.TryGetValue(\"Domain\", val))\n\t\t\t\t\tsb << \"[domain(\\\"\" << ((val.Value == \"quads\") ? \"quad\" : \"tri\") << \"\\\")]\\n\";\n\t\t\t\telse\n\t\t\t\t\tsb << \"[domain(\\\"tri\\\")]\\n\";\n                if (val.Value != \"triangles\" && val.Value != \"quads\")\n                    getSink()->diagnose(val.Position, Diagnostics::invalidTessellationDomain);\n\t\t\t}\n\n\t\t\tvoid PrintHeaderBoilerplate(CodeGenContext& ctx)\n\t\t\t{\n\t\t\t\t// The way that we assign semantics may generate a warning,\n\t\t\t\t// and rather than clear it up with more complicated codegen,\n\t\t\t\t// we choose to just disable it (since we control all the\n\t\t\t\t// semantics anyway).\n\t\t\t\tctx.GlobalHeader << \"#pragma warning(disable: 3576)\\n\";\n\n\t\t\t\t// In order to be a portable shading language, Spire needs\n\t\t\t\t// to make some basic decisions about the semantics of\n\t\t\t\t// matrix operations so they are consistent between APIs.\n\t\t\t\t//\n\t\t\t\t// The default interpretation in each language is:\n\t\t\t\t//   GLSL: column-major storage, column-major semantics\n\t\t\t\t//   HLSL: column-major storage, row-major semantics\n\t\t\t\t//\n\t\t\t\t// We can't change the semantics, but we *can* change\n\t\t\t\t// the storage layout, and making it be row-major in\n\t\t\t\t// HLSL ensures that the actual behavior of a shader\n\t\t\t\t// is consistent between APIs.\n\t\t\t\tctx.GlobalHeader << \"#pragma pack_matrix( row_major )\\n\";\n\t\t\t}\n\n\t\t\tStageSource GenerateSingleWorldShader(ILProgram * program, ILShader * shader, ILStage * stage) override\n\t\t\t{\n\t\t\t\t// This entry point is used to generate a Vertex, Fragment,\n\t\t\t\t// Domain, or Compute Shader, since they all amount to\n\t\t\t\t// a single world.\n\t\t\t\t//\n\t\t\t\t// TODO(tfoley): This code actually doesn't work for compute,\n\t\t\t\t// since it currently assumes there is always going to be\n\t\t\t\t// \"varying\" stage input/output.\n\t\t\t\t//\n\t\t\t\t// TODO(tfoley): Honestly, there is almost zero value in trying\n\t\t\t\t// to share this code, and what little sharing there is could\n\t\t\t\t// be expressed just as well by having a differentry codegen\n\t\t\t\t// entry point per stage type, with lower-level shared routines\n\t\t\t\t// they can call into.\n\n\t\t\t\t// TODO(tfoley): Ther are no bindles textures in HLSL, so I'm\n\t\t\t\t// not sure what to do with this flag.\n\t\t\t\tuseBindlessTexture = stage->Attributes.ContainsKey(\"BindlessTexture\");\n\n\t\t\t\tStageSource rs;\n\t\t\t\tCodeGenContext ctx;\n\n\t\t\t\tPrintHeaderBoilerplate(ctx);\n\n\t\t\t\tGenerateStructs(ctx.GlobalHeader, program);\n\t\t\t\tGenerateShaderParameterDefinition(ctx, shader);\n\n\t\t\t\tStageAttribute worldName;\n\t\t\t\tRefPtr<ILWorld> world = nullptr;\n\t\t\t\tif (stage->Attributes.TryGetValue(\"World\", worldName))\n\t\t\t\t{\n\t\t\t\t\tif (!shader->Worlds.TryGetValue(worldName.Value, world))\n\t\t\t\t\t\terrWriter->diagnose(worldName.Position, Diagnostics::worldIsNotDefined, worldName.Value);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::stageShouldProvideWorldAttribute, stage->StageType);\n\t\t\t\tif (!world)\n\t\t\t\t\treturn rs;\n\t\t\t\tGenerateReferencedFunctions(ctx.GlobalHeader, program, MakeArrayView(world.Ptr()));\n\t\t\t\textCompInfo.Clear();\n\t\t\t\tILRecordType* stageInputType = nullptr;\n\t\t\t\tILRecordType* dsCornerPointType = nullptr;\n\t\t\t\tint dsCornerPointCount = 0;\n\t\t\t\tILRecordType* dsPatchType = nullptr;\n\n\t\t\t\tILObjectDefinition* dsCornerPointInput = nullptr;\n\t\t\t\tILObjectDefinition* dsPatchInput = nullptr;\n\n\t\t\t\t// We start by emitting whatever declarations the input worlds\n\t\t\t\t// need, and along the way we try to capture the components/\n\t\t\t\t// records being used as input, so that we can refer to them\n\t\t\t\t// appropriately.\n\t\t\t\t//\n\t\t\t\t// Note(tfoley): It seems awkward to find these worlds/records\n\t\t\t\t// that we need by search, whereas the \"primary\" world for the\n\t\t\t\t// shader is passed to us more explicitly.\n\t\t\t\tfor (auto & input : world->Inputs)\n\t\t\t\t{\n\t\t\t\t\tDeclareInput(ctx, input, stage->StageType == \"VertexShader\");\n\n\t\t\t\t\t// We need to detect the world that represents the ordinary stage input...\n\t\t\t\t\t// TODO(tfoley): It seems like this is logically part of the stage definition.\n\t\t\t\t\tauto info = ExtractExternComponentInfo(input);\n\t\t\t\t\tif(info.DataStructure == ExternComponentCodeGenInfo::DataStructureType::StandardInput)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto recType = ExtractRecordType(input.Type.Ptr());\n\t\t\t\t\t\tif(recType)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstageInputType = recType;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if(info.DataStructure == ExternComponentCodeGenInfo::DataStructureType::Patch)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto recType = ExtractRecordType(input.Type.Ptr());\n\t\t\t\t\t\tif(recType)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(info.IsArray)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdsCornerPointInput = &input;\n\t\t\t\t\t\t\t\tdsCornerPointType = recType;\n\t\t\t\t\t\t\t\tdsCornerPointCount = info.ArrayLength;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdsPatchInput = &input;\n\t\t\t\t\t\t\t\tdsPatchType = recType;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(!stageInputType)\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::stageDoesntHaveInputWorld, stage->StageType);\n\t\t\t\t}\n\t\t\n\t\t\t\t// For a domain shader, we need to know how many corners the\n\t\t\t\t// domain has (triangle or quadrilateral), so that we can\n\t\t\t\t// declare an output array of appropriate size.\n\t\t\t\tStageAttribute controlPointCount;\n\t\t\t\tint cornerCount = 3;\n\t\t\t\tif(stage->StageType == \"DomainShader\")\n\t\t\t\t{\n\t\t\t\t\tif (!stage->Attributes.TryGetValue(\"ControlPointCount\", controlPointCount))\n\t\t\t\t\t{\n\t\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::domainShaderRequiresControlPointCount);\n\t\t\t\t\t}\n\t\t\t\t\tStageAttribute val;\n\t\t\t\t\tif(stage->Attributes.TryGetValue(\"Domain\", val))\n\t\t\t\t\t{\n\t\t\t\t\t\tif(val.Value == \"quads\")\t\t\tcornerCount = 4;\n\t\t\t\t\t\telse if(val.Value == \"triangles\")\tcornerCount = 3;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\toutputStrategy->DeclareOutput(ctx, stage);\n\t\t\t\tctx.codeGen = this;\n\t\t\t\tworld->Code->NameAllInstructions();\n\t\t\t\tGenerateCode(ctx, world->Code.Ptr());\n\n\t\t\t\t// For shader types that might output the special `SV_Position`\n\t\t\t\t// output, we check if the stage in the pipeline actually\n\t\t\t\t// declares this output, and emit the logic as needed.\n\t\t\t\tif (stage->StageType == \"VertexShader\" || stage->StageType == \"DomainShader\")\n\t\t\t\t\tGenerateVertexShaderEpilog(ctx, world.Ptr(), stage);\n\n\t\t\t\tStringBuilder sb;\n\t\t\t\tsb << ctx.GlobalHeader.ProduceString();\n\n\t\t\t\t// We always declare our shader entry point as outputting a\n\t\t\t\t// single `struct` value, for simplicity. To make this\n\t\t\t\t// work, we generate a combined `struct` that comprises\n\t\t\t\t// the user-declared outputs (in a nested `struct`) along\n\t\t\t\t// with any system-interpreted outputs we need.\n\t\t\t\tsb << \"struct T\" << world->OutputType->TypeName << \"Ext\\n{\\n\";\n\t\t\t\tsb << \"T\" << world->OutputType->TypeName << \" user\";\n\n\t\t\t\t// The fragment shader needs to use the specific output\n\t\t\t\t// semantic `SV_Target` as expected by the HLSL compiler.\n\t\t\t\t// Because the `user` field is a `struct` this semantic\n\t\t\t\t// will recursively propagate to all of its fields.\n\t\t\t\t//\n\t\t\t\t// All other stage types will just use the default semantics\n\t\t\t\t// already applied to the fields of the output `struct`.\n\t\t\t\tif(stage->StageType == \"FragmentShader\")\n\t\t\t\t{\n\t\t\t\t\tsb << \" : SV_Target\";\n\t\t\t\t}\n\t\t\t\tsb << \";\\n\";\n\n\t\t\t\t// We emit any required system-output semantics here.\n\t\t\t\t// For now we are just handling `SV_Position`, but\n\t\t\t\t// values like fragment shader depth output, etc.\n\t\t\t\t// would also go here.\n\t\t\t\tif(stage->Attributes.TryGetValue(\"Position\"))\n\t\t\t\t{\n\t\t\t\t\tsb << \"float4 sv_position : SV_Position;\\n\";\n\t\t\t\t}\n\t\t\t\tsb << \"};\\n\";\n\n\t\t\t\tif(dsPatchType || dsCornerPointType)\n\t\t\t\t{\n\t\t\t\t\t// A domain shader receives two kinds of input: per-patch\n\t\t\t\t\t// and per-control-point. The per-control-point input\n\t\t\t\t\t// appears as the ordinary input, from the perspective\n\t\t\t\t\t// of the Spire front-end, so we need to declare the\n\t\t\t\t\t// per-patch input more explicitly.\n\t\t\t\t\t//\n\t\t\t\t\t// Similar to what we do with the `*Ext` contrivance\n\t\t\t\t\t// above, we are going to output a single `struct`\n\t\t\t\t\t// that combines user-defined and system inputs.\n\n\t\t\t\t\tsb << \"struct TStageInputPatch\\n{\\n\";\n\t\t\t\t\tif(dsPatchType)\n\t\t\t\t\t{\n\t\t\t\t\t\t// In order to ensure consistent semantics, we apply\n\t\t\t\t\t\t// a blanket `P` semantic here to the per-patch input.\n\t\t\t\t\t\t// This semantic will override any per-field semantics\n\t\t\t\t\t\t// that got emitted for the record type itself.\n\t\t\t\t\t\tsb << \"T\" << dsPatchType->TypeName << \" \"\n\t\t\t\t\t\t\t<< dsPatchInput->Name << \" : P;\\n\";\n\t\t\t\t\t}\n\t\t\t\t\tif(dsCornerPointType)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Similar to the per-patch case, we declare an array\n\t\t\t\t\t\t// of records for the per-corner-point data, and\n\t\t\t\t\t\t// apply a single blanket semantic that will go and\n\t\t\t\t\t\t// recursively enumerate unique semantics for all\n\t\t\t\t\t\t// the array elements and fields.\n\t\t\t\t\t\tsb << \"T\" << dsCornerPointType->TypeName << \" \"\n\t\t\t\t\t\t\t<< dsCornerPointInput->Name\n\t\t\t\t\t\t\t<< \"[\" << cornerCount << \"] : C;\\n\";\n\t\t\t\t\t}\n\n\t\t\t\t\t// Note: HLSL requires tessellation level to be declared\n\t\t\t\t\t// as an input to the Domain Shader, even if it is unused\n\n\t\t\t\t\t// TODO(tfoley): This repeated matching on the `Domain`\n\t\t\t\t\t// attribute by string comparison is dangerous, and needs\n\t\t\t\t\t// to be handled more centrally and robustly.\n\t\t\t\t\tStageAttribute val;\n\t\t\t\t\tif(stage->Attributes.TryGetValue(\"Domain\", val) && (val.Value == \"quads\"))\n\t\t\t\t\t{\n\t\t\t\t\t\tsb << \"    float sv_TessFactors[4] : SV_TessFactor;\\n\";\n\t\t\t\t\t\tsb << \"    float sv_InsideTessFactors[2] : SV_InsideTessFactor;\\n\";\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tsb << \"    float sv_TessFactors[3] : SV_TessFactor;\\n\";\n\t\t\t\t\t\tsb << \"    float sv_InsideTessFactors[1] : SV_InsideTessFactor;\\n\";\n\t\t\t\t\t}\n\n\t\t\t\t\tsb << \"};\\n\";\n\t\t\t\t}\n\n\t\t\t\t// The domain shader has a few required attributes that need\n\t\t\t\t// to be emitted in front of the declaration of `main()`.\n\t\t\t\tif(stage->StageType == \"DomainShader\")\n\t\t\t\t{\n\t\t\t\t\tGenerateDomainShaderAttributes(sb, stage);\n\t\t\t\t}\n\n\t\t\t\tsb << \"T\" << world->OutputType->TypeName << \"Ext main(\";\n\n\t\t\t\tif(stageInputType)\n\t\t\t\t{\n\t\t\t\t\t// We need to declare our inputs a bit differently,\n\t\t\t\t\t// depending on the stage we are emitting:\n\n\t\t\t\t\t// TODO(tfoley): All this string-based matching on stage type seems wrong\n\t\t\t\t\tif(stage->StageType == \"DomainShader\")\n\t\t\t\t\t{\n\t\t\t\t\t\t// A domain shader needs to declare an array of input\n\t\t\t\t\t\t// control points, using the special-purpose generic type\n\t\t\t\t\t\t// provided by HLSL.\n\t\t\t\t\t\tsb << \"OutputPatch<T\" << stageInputType->TypeName << \", \" << controlPointCount.Value << \"> stage_input\";\n\t\t\t\t\t}\n                    /* FALCOR Don't treat vertex shader specially...\n\t\t\t\t\telse if (stage->StageType == \"VertexShader\")\n\t\t\t\t\t{\n\t\t\t\t\t\t// A vertex shader can declare its input as normal, but\n\t\t\t\t\t\t// to make matching over vertex attributes with host\n\t\t\t\t\t\t// code simpler, we apply a blanket `A` semantic here,\n\t\t\t\t\t\t// so that the individual vertex elements in the input\n\t\t\t\t\t\t// layout will all get the semantic \"A\" with sequential\n\t\t\t\t\t\t// indices starting at zero.\n\t\t\t\t\t\tsb << \"\\n    T\" << stageInputType->TypeName << \" stage_input : A\";\n\t\t\t\t\t}\n                    FALCOR */\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Finally, the default case just uses the semantics\n\t\t\t\t\t\t// that were automatically assigned to the fields\n\t\t\t\t\t\t// of the input record type.\n\t\t\t\t\t\tsb << \"\\n    T\" << stageInputType->TypeName << \" stage_input\";\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif(dsPatchType || dsCornerPointType)\n\t\t\t\t{\n\t\t\t\t\t// For a domain shader, we also need to declare\n\t\t\t\t\t// the per-patch (and per-corner point) input.\n\t\t\t\t\tsb << \",\\n    TStageInputPatch stage_input_patch\";\n\t\t\t\t}\n\n\t\t\t\t// Next we declare any addition system inputs that ended up\n\t\t\t\t// being used during code generation.\n\t\t\t\tif(ctx.UsedSystemInputs.Contains(ExternComponentCodeGenInfo::SystemVarType::TessCoord))\n\t\t\t\t{\n\t\t\t\t\tsb << \",\\n    \";\n\n\t\t\t\t\tStageAttribute val;\n\t\t\t\t\tif(stage->Attributes.TryGetValue(\"Domain\", val))\n\t\t\t\t\t\tsb << ((val.Value == \"quads\") ? \"float2\" : \"float3\");\n\t\t\t\t\telse\n\t\t\t\t\t\tsb << \"float3\";\n\n\t\t\t\t\tsb << \" sv_DomainLocation : SV_DomainLocation\";\n\t\t\t\t}\n\t\t\t\tif(ctx.UsedSystemInputs.Contains(ExternComponentCodeGenInfo::SystemVarType::FragCoord))\n\t\t\t\t{\n\t\t\t\t\tsb << \",\\n    float4 sv_FragPosition : SV_Position\";\n\t\t\t\t}\n\t\t\t\tif(ctx.UsedSystemInputs.Contains(ExternComponentCodeGenInfo::SystemVarType::InstanceId))\n\t\t\t\t{\n\t\t\t\t\tsb << \",\\n    uint sv_InstanceID : SV_InstanceID\";\n\t\t\t\t}\n\n\t\t\t\tsb << \")\\n{ \\n\";\n\t\t\t\tsb << \"T\" << world->OutputType->TypeName << \"Ext stage_output;\\n\";\n\t\t\t\tsb << ctx.Header.ProduceString() << ctx.Body.ProduceString();\n\t\t\t\tsb << \"return stage_output;\\n\";\n\t\t\t\tsb << \"}\";\n\t\t\t\trs.MainCode = sb.ProduceString();\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tvoid DeclareRecordTypeStruct(CodeGenContext& ctx, ILRecordType* recType)\n\t\t\t{\n\t\t\t\t// By convention, the name of the generated `struct` is\n\t\t\t\t// \"T\" prefixed onto the name of the record type.\n\t\t\t\tctx.GlobalHeader << \"struct T\" << recType->TypeName << \"\\n{\\n\";\n\n\t\t\t\tint index = 0;\n\t\t\t\tfor (auto & field : recType->Members)\n\t\t\t\t{\n\t\t\t\t\t// As a catch-all, we apply the `nointerpolation`\n\t\t\t\t\t// modifier to all integral types, even though\n\t\t\t\t\t// this really only affects records that flow\n\t\t\t\t\t// through rasterization/setup/interpolation.\n\t\t\t\t\tif (field.Value.Type->IsIntegral())\n\t\t\t\t\t\tctx.GlobalHeader << \"nointerpolation \";\n\n\t\t\t\t\t// Declare the field as a `struct` member\n\t\t\t\t\tString declName = field.Key;\n\t\t\t\t\tPrintDef(ctx.GlobalHeader, field.Value.Type.Ptr(), declName);\n\n\t\t\t\t\t// We automatically synthesize a semantic for every\n\t\t\t\t\t// field. This will need to match any equivalent\n\t\t\t\t\t// declaration on the input side.\n\t\t\t\t\t//\n\t\t\t\t\t// The semantic must be unique across fields.\n\t\t\t\t\t// We can't simply use a convention like \"A0\", \"A1\", ...\n\t\t\t\t\t// because these semantics with a numeric suffix\n\t\t\t\t\t// will not interact nicely with fields of `struct`\n\t\t\t\t\t// or array type.\n\t\t\t\t\t//\n\t\t\t\t\t// We could use the field name to generate a unique\n\t\t\t\t\t// semantic, but this might be long and ugly, and we'd\n\t\t\t\t\t// need to decorate it to avoid accidentally having a\n\t\t\t\t\t// numeric suffix, or an \"SV_\" prefix.\n\t\t\t\t\t//\n\t\t\t\t\t// Ultimately, the easiest thing to do is to take the\n\t\t\t\t\t// simple \"A0\", \"A1\", ... idea and simply add another\n\t\t\t\t\t// \"A\" onto the end, so that it isn't techically a\n\t\t\t\t\t// numeric suffix. So: \"A0A\", \"A1A\", \"A2A\", ...\n\t\t\t\t\t//\n\t\t\t\t\t// In the case where the field is a `struct` or array\n\t\t\t\t\t// type, the HLSL compiler will then automatically\n\t\t\t\t\t// generate per-field/-element semantics based on\n\t\t\t\t\t// the prefix we gave it, e.g.: \"A0A0\", \"A0A1\", ...\n//FALCOR\t\t\t\t\tctx.GlobalHeader << \" : A\" << index << \"A\";\n\n                    // FALCOR: just use the name instead...\n                    ctx.GlobalHeader << \" : \" << declName;\n\n\t\t\t\t\tctx.GlobalHeader << \";\\n\";\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\n\t\t\t\tctx.GlobalHeader << \"};\\n\";\n\t\t\t}\n\n\t\t\t// Most of our generated HLSL code can use a single simple output\n\t\t\t// strategy, which simply declares the output as a `struct` type\n\t\t\t// (to be used in the declaration of `main()`, and then output\n\t\t\t// writes so that they reference the fields of that type with\n\t\t\t// a simple prefix.\n\t\t\tstruct SimpleOutputStrategy : OutputStrategy\n\t\t\t{\n\t\t\t\tHLSLCodeGen* hlslCodeGen;\n\t\t\t\tString prefix;\n\n\t\t\t\tSimpleOutputStrategy(HLSLCodeGen* hlslCodeGen, ILWorld* world, String const& prefix)\n\t\t\t\t\t: OutputStrategy(hlslCodeGen, world)\n\t\t\t\t\t, hlslCodeGen(hlslCodeGen)\n\t\t\t\t\t, prefix(prefix)\n\t\t\t\t{}\n\n\t\t\t\tvirtual void DeclareOutput(CodeGenContext & ctx, ILStage * /*stage*/) override\n\t\t\t\t{\n\t\t\t\t\thlslCodeGen->DeclareRecordTypeStruct(ctx, world->OutputType.Ptr());\n\t\t\t\t}\n\n\t\t\t\tvirtual void ProcessExportInstruction(CodeGenContext & ctx, ExportInstruction * instr) override\n\t\t\t\t{\n\t\t\t\t\tctx.Body << prefix << \".\" << instr->ComponentName << \" = \";\n\t\t\t\t\tcodeGen->PrintOp(ctx, instr->Operand.Ptr());\n\t\t\t\t\tctx.Body << \";\\n\";\n\t\t\t\t}\n\t\t\t};\n\n\n\t\t\tStageSource GenerateHullShader(ILProgram * program, ILShader * shader, ILStage * stage) override\n\t\t\t{\n\t\t\t\t// As a first step, we validate the various attributes required\n\t\t\t\t// on a `HullShader` stage declaration.\n\t\t\t\t//\n\t\t\t\t// Note(tfoley): This logic is mostly copy-pasted from the GLSL\n\t\t\t\t// case, and there is a reasonable case to be made that it\n\t\t\t\t// should be unified.\n\t\t\t\t//\n\t\t\t\tStageSource rs;\n\t\t\t\tStageAttribute patchWorldName, controlPointWorldName, cornerPointWorldName, domain, innerLevel, outerLevel, numControlPoints;\n\t\t\t\tStageAttribute inputControlPointCount;\n\t\t\t\tRefPtr<ILWorld> patchWorld, controlPointWorld, cornerPointWorld;\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"PatchWorld\", patchWorldName))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresPatchWorld);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (!shader->Worlds.TryGetValue(patchWorldName.Value, patchWorld))\n\t\t\t\t\terrWriter->diagnose(patchWorldName.Position, Diagnostics::worldIsNotDefined, patchWorldName.Value);\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"ControlPointWorld\", controlPointWorldName))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresControlPointWorld); \n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (!shader->Worlds.TryGetValue(controlPointWorldName.Value, controlPointWorld))\n\t\t\t\t\terrWriter->diagnose(controlPointWorldName.Position, Diagnostics::worldIsNotDefined, controlPointWorldName.Value);\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"CornerPointWorld\", cornerPointWorldName))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresCornerPointWorld);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (!shader->Worlds.TryGetValue(cornerPointWorldName.Value, cornerPointWorld))\n\t\t\t\t\terrWriter->diagnose(cornerPointWorldName.Position, Diagnostics::worldIsNotDefined, cornerPointWorldName.Value);\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"Domain\", domain))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresDomain);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (domain.Value != \"triangles\" && domain.Value != \"quads\")\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(domain.Position, Diagnostics::invalidTessellationDomian);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"TessLevelOuter\", outerLevel))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresTessLevelOuter);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"TessLevelInner\", innerLevel))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresTessLevelInner);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"InputControlPointCount\", inputControlPointCount))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresInputControlPointCount);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tif (!stage->Attributes.TryGetValue(\"ControlPointCount\", numControlPoints))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresControlPointCount);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\n\t\t\t\t// Note(tfoley): The needs of HLSL codegen forced me to add\n\t\t\t\t// a few more required attributes, and we probably need to\n\t\t\t\t// decide whether to always require these (for portability)\n\t\t\t\t// or only require them when generating HLSL.\n\t\t\t\t//\n\t\t\t\tStageAttribute partitioning;\n\t\t\t\tif(!stage->Attributes.TryGetValue(\"Partitioning\", partitioning))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresPartitioning);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tStageAttribute outputTopology;\n\t\t\t\tif(!stage->Attributes.TryGetValue(\"OutputTopology\", outputTopology))\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(stage->Position, Diagnostics::hullShaderRequiresOutputTopology);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\t// TODO(tfoley): Any reason to include an optional\n\t\t\t\t// `maxtessfactor` attribute?\n\n\t\t\t\tCodeGenContext ctx;\n\t\t\t\tctx.codeGen = this;\n\t\t\t\tList<ILWorld*> worlds;\n\t\t\t\tworlds.Add(patchWorld.Ptr());\n\t\t\t\tworlds.Add(controlPointWorld.Ptr());\n\t\t\t\tworlds.Add(cornerPointWorld.Ptr());\n\n\t\t\t\tPrintHeaderBoilerplate(ctx);\n\n\t\t\t\tint cornerCount = 3;\n\t\t\t\tif(domain.Value == \"triangles\")\n\t\t\t\t\tcornerCount = 3;\n\t\t\t\telse if(domain.Value == \"quads\")\n\t\t\t\t\tcornerCount = 4;\n\n\n\t\t\t\tGenerateStructs(ctx.GlobalHeader, program);\n\t\t\t\tGenerateShaderParameterDefinition(ctx, shader);\n\t\t\t\tGenerateReferencedFunctions(ctx.GlobalHeader, program, worlds.GetArrayView());\n\n\t\t\t\t// As in the single-world case, we need to emit declarations\n\t\t\t\t// for any inputs to the stage, but unlike that case we have\n\t\t\t\t// multiple worlds to deal with.\n\t\t\t\t//\n\t\t\t\t// We maintain a set of inputs encountered so far, so that\n\t\t\t\t// don't re-declare any given input.\n\t\t\t\tHashSet<String> declaredInputs;\n\n\t\t\t\t// Similar to the single-world case, we try to capture\n\t\t\t\t// some information about inputs so that we can use it\n\t\t\t\t// to inform code generation later.\n\t\t\t\tString perCornerIteratorInputName = \"perCornerIterator\";\n\t\t\t\tILRecordType* coarseVertexType = nullptr;\n\t\t\t\t//\n\t\t\t\tfor (auto & input : controlPointWorld->Inputs)\n\t\t\t\t{\n\t\t\t\t\tif(declaredInputs.Add(input.Name))\n\t\t\t\t\t{\n\t\t\t\t\t\tDeclareInput(ctx, input, false);\n\n\t\t\t\t\t\tauto info = ExtractExternComponentInfo(input);\n\t\t\t\t\t\tif(info.DataStructure == ExternComponentCodeGenInfo::DataStructureType::StandardInput)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto recType = ExtractRecordType(input.Type.Ptr());\n\t\t\t\t\t\t\tif(recType)\n\t\t\t\t\t\t\t\tcoarseVertexType = recType;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (auto & input : patchWorld->Inputs)\n\t\t\t\t{\n\t\t\t\t\tif (declaredInputs.Add(input.Name))\n\t\t\t\t\t\tDeclareInput(ctx, input, false);\n\t\t\t\t}\n\t\t\t\tfor (auto & input : cornerPointWorld->Inputs)\n\t\t\t\t{\n\t\t\t\t\tif(declaredInputs.Add(input.Name))\n\t\t\t\t\t{\n\t\t\t\t\t\tDeclareInput(ctx, input, false);\n\n\t\t\t\t\t\tif(input.Attributes.ContainsKey(\"PerCornerIterator\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tperCornerIteratorInputName = input.Name;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\n\t\t\t\t// HLSL requires two entry points for the Hull Shader: a\n\t\t\t\t// \"patch-constant\" function and the ordinary `main()`\n\t\t\t\t// entry point (which runs per-control-point).\n\t\t\t\t//\n\t\t\t\t// We start code generation with the \"patch-constant\"\n\t\t\t\t// function, which we use for per-patch and per-corner\n\t\t\t\t// computation.\n\n\n\t\t\t\t// Perform per-corner computation\n\t\t\t\tcornerPointWorld->Code->NameAllInstructions();\n\n\t\t\t\tStringBuilder cornerPointOutputPrefix;\n\t\t\t\tcornerPointOutputPrefix << \"stage_output.corners[\" << perCornerIteratorInputName << \"]\";\n\n\t\t\t\toutputStrategy = new SimpleOutputStrategy(this, cornerPointWorld.Ptr(), cornerPointOutputPrefix.ProduceString());\n\t\t\t\toutputStrategy->DeclareOutput(ctx, stage);\n\n\t\t\t\t// Note(tfoley): We use the `[unroll]` attribute here, because\n\t\t\t\t// the HLSL compiler will end up unrolling this loop anyway,\n\t\t\t\t// and we'd rather not get their warning about it.\n\t\t\t\tctx.Body << \"[unroll] for (uint \" << perCornerIteratorInputName << \" = 0; \"\n\t\t\t\t\t<< perCornerIteratorInputName << \" < \" << cornerCount << \"; \"\n\t\t\t\t\t<< perCornerIteratorInputName << \"++)\\n{\\n\";\n\t\t\t\tGenerateCode(ctx, cornerPointWorld->Code.Ptr());\n\t\t\t\tauto debugStr = cornerPointWorld->Code->ToString();\n\t\t\t\tctx.Body << \"}\\n\";\n\t\t\t\toutputStrategy = NULL;\n\n\t\t\t\t// Perform per-patch computation\n\t\t\t\tpatchWorld->Code->NameAllInstructions();\n\t\t\t\toutputStrategy = CreateStandardOutputStrategy(patchWorld.Ptr(), \"patch\");\n\t\t\t\toutputStrategy->DeclareOutput(ctx, stage);\n\t\t\t\tGenerateCode(ctx, patchWorld->Code.Ptr());\n\n\t\t\t\t// Compute the number of edges and interior axes we need to deal with.\n\t\t\t\tStageAttribute val;\n\t\t\t\tint tessFactorCount = 3;\n\t\t\t\tint insideFactorCount = 1;\n\t\t\t\tif(stage->Attributes.TryGetValue(\"Domain\", val) && (val.Value == \"quads\"))\n\t\t\t\t{\n\t\t\t\t\ttessFactorCount = 4;\n\t\t\t\t\tinsideFactorCount = 2;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttessFactorCount = 3;\n\t\t\t\t\tinsideFactorCount = 1;\n\t\t\t\t}\n\n\t\t\t\t// Generate code to set tessellation factors.\n\t\t\t\t//\n\t\t\t\t// TODO(tfoley): This is written as a search over worlds,\n\t\t\t\t// whereas I would have expected the tess factors to\n\t\t\t\t// be expected in a fixed world (e.g., @PatchEdge,\n\t\t\t\t// and then @PatchInterior). This should probalby get\n\t\t\t\t// cleaned up.\n\t\t\t\t//\n\t\t\t\t// Note(tfoley): I swapped the order from what the GLSL\n\t\t\t\t// case does, so that we output the edge factors before\n\t\t\t\t// the interior one(s). This doesn't matter right now,\n\t\t\t\t// but in practice many adaptive schemes will want to\n\t\t\t\t// compute the interior factor(s) from the edge ones,\n\t\t\t\t// so this ordering would in theory be conducive to that.\n\t\t\t\tbool found = false;\n\t\t\t\tfor (auto & world : worlds)\n\t\t\t\t{\n\t\t\t\t\tILOperand * operand;\n\t\t\t\t\tif (world->Components.TryGetValue(outerLevel.Value, operand))\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int i = 0; i < tessFactorCount; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// TODO(tfoley): is this needlessly re-computing the operand multiple times?\n\n\t\t\t\t\t\t\tctx.Body << \"stage_output.sv_TessFactors[\" << i << \"] = \";\n\t\t\t\t\t\t\tPrintOp(ctx, operand);\n\t\t\t\t\t\t\tctx.Body << \"[\" << i << \"];\\n\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\tif (!found)\n\t\t\t\t\terrWriter->diagnose(outerLevel.Position, Diagnostics::componentNotDefined, outerLevel.Value);\n\n\n\t\t\t\tfound = false;\n\t\t\t\tfor (auto & world : worlds)\n\t\t\t\t{\n\t\t\t\t\tILOperand * operand;\n\t\t\t\t\tif (world->Components.TryGetValue(innerLevel.Value, operand))\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int i = 0; i < insideFactorCount; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tctx.Body << \"stage_output.sv_InsideTessFactors[\" << i << \"] = \";\n\t\t\t\t\t\t\tPrintOp(ctx, operand);\n\t\t\t\t\t\t\tctx.Body << \"[\" << i << \"];\\n\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!found)\n\t\t\t\t\terrWriter->diagnose(innerLevel.Position, Diagnostics::componentNotDefined, innerLevel.Value);\n\n\t\t\t\t// Now surround the code with the boilerplate needed to\n\t\t\t\t// make a real Hull Shader \"patch constant function\"\n\n\t\t\t\tStringBuilder patchMain;\n\n\t\t\t\tpatchMain << \"struct SPIRE_PatchOutput\\n{\\n\";\n\t\t\t\tpatchMain << \"T\" << patchWorld->OutputType->TypeName << \" user : P;\\n\";\n\t\t\t\tpatchMain << \"T\" << cornerPointWorld->OutputType->TypeName << \" corners[\" << cornerCount << \"] : C;\\n\";\n\n\t\t\t\tpatchMain << \"    float sv_TessFactors[\" << tessFactorCount << \"] : SV_TessFactor;\\n\";\n\t\t\t\tpatchMain << \"    float sv_InsideTessFactors[\" << insideFactorCount << \"] : SV_InsideTessFactor;\\n\";\n\n\t\t\t\tpatchMain << \"};\\n\";\n\n\n\t\t\t\tpatchMain << \"SPIRE_PatchOutput SPIRE_patchOutput(\";\n\n\t\t\t\tif (coarseVertexType)\n\t\t\t\t{\n\t\t\t\t\tpatchMain << \"    InputPatch<T\" << coarseVertexType->TypeName << \", \" << inputControlPointCount.Value << \"> stage_input\\n\";\n\t\t\t\t}\n\t\t\t\t// TODO(tfoley): provide other input shere like SV_PrimitiveID\n\n\n\t\t\t\tpatchMain << \")\\n{\\n\";\n\t\t\t\tpatchMain << \"SPIRE_PatchOutput stage_output;\\n\";\n\t\t\t\tpatchMain << ctx.Header.ProduceString() << ctx.Body.ProduceString();\n\t\t\t\tpatchMain << \"return stage_output;\\n\";\n\t\t\t\tpatchMain << \"}\\n\";\n\n\t\t\t\t// After we are done outputting the per-patch entry point,\n\t\t\t\t// we move on to the per-control-point one.\n\t\t\t\t//\n\t\t\t\t// Note that calling `ProduceString()` on the `Header` and\n\t\t\t\t// `Body` builders above has cleared them out for us.\n\n\t\t\t\tcontrolPointWorld->Code->NameAllInstructions();\n\t\t\t\toutputStrategy = new SimpleOutputStrategy(this, controlPointWorld.Ptr(), \"stage_output\");\n\t\t\t\toutputStrategy->DeclareOutput(ctx, stage);\n\t\t\t\tGenerateCode(ctx, controlPointWorld->Code.Ptr());\n\n\n\t\t\t\tStringBuilder controlPointMain;\n\n\t\t\t\t// HLSL requires a bunch of attributres in front of the\n\t\t\t\t// Hull Shader `main()` (the per-control-point function)\n\t\t\t\t// These are effectively binding the state of the\n\t\t\t\t// fixed-function tessellator (rather than have a bunch of API\n\t\t\t\t// state for it).\n\n\t\t\t\t// Name of the entry point to use for the patch-constant phase\n\t\t\t\tcontrolPointMain << \"[patchconstantfunc(\\\"SPIRE_patchOutput\\\")]\\n\";\n\n\t\t\t\t// Domain for tessellation.\n\t\t\t\tcontrolPointMain << \"[domain(\\\"\";\n\t\t\t\tif(domain.Value == \"quads\")\n\t\t\t\t{\n\t\t\t\t\tcontrolPointMain << \"quad\";\n\t\t\t\t}\n\t\t\t\telse if(domain.Value == \"triangles\")\n\t\t\t\t{\n\t\t\t\t\tcontrolPointMain << \"tri\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(domain.Position, Diagnostics::invalidTessellationDomain);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tcontrolPointMain << \"\\\")]\\n\";\n\n\t\t\t\t// Parititoning mode (integer, fractional, etc.)\n\t\t\t\tcontrolPointMain << \"[partitioning(\\\"\";\n\t\t\t\tif(partitioning.Value == \"integer\")\n\t\t\t\t{\n\t\t\t\t\tcontrolPointMain << \"integer\";\n\t\t\t\t}\n\t\t\t\telse if(partitioning.Value == \"pow2\")\n\t\t\t\t{\n\t\t\t\t\tcontrolPointMain << \"pow2\";\n\t\t\t\t}\n\t\t\t\telse if(partitioning.Value == \"fractional_even\")\n\t\t\t\t{\n\t\t\t\t\tcontrolPointMain << \"fractional_even\";\n\t\t\t\t}\n\t\t\t\telse if(partitioning.Value == \"fractional_odd\")\n\t\t\t\t{\n\t\t\t\t\tcontrolPointMain << \"fractional_odd\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(partitioning.Position, Diagnostics::invalidTessellationPartitioning);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tcontrolPointMain << \"\\\")]\\n\";\n\n\t\t\t\t// Desired output topology, including winding order\n\t\t\t\t// for triangles.\n\t\t\t\tcontrolPointMain << \"[outputtopology(\\\"\";\n\t\t\t\tif(outputTopology.Value == \"point\")\n\t\t\t\t{\n\t\t\t\t\tcontrolPointMain << \"point\";\n\t\t\t\t}\n\t\t\t\telse if(outputTopology.Value == \"line\")\n\t\t\t\t{\n\t\t\t\t\tcontrolPointMain << \"line\";\n\t\t\t\t}\n\t\t\t\telse if(outputTopology.Value == \"triangle_cw\")\n\t\t\t\t{\n\t\t\t\t\tcontrolPointMain << \"triangle_cw\";\n\t\t\t\t}\n\t\t\t\telse if(outputTopology.Value == \"triangle_ccw\")\n\t\t\t\t{\n\t\t\t\t\tcontrolPointMain << \"triangle_ccw\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\terrWriter->diagnose(partitioning.Position, Diagnostics::invalidTessellationOutputTopology);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tcontrolPointMain << \"\\\")]\\n\";\n\n\t\t\t\t// Number of output control points\n\t\t\t\tcontrolPointMain << \"[outputcontrolpoints(\" << numControlPoints.Value << \")]\\n\";\n\n\t\t\t\t// With all the attributes dealt with, we can emit the actual `main()` routine\n\n\t\t\t\tcontrolPointMain << \"T\" << controlPointWorld->OutputType->TypeName << \" main(\";\n\n\t\t\t\tcontrolPointMain << \"    InputPatch<T\" << coarseVertexType->TypeName << \", \" << inputControlPointCount.Value << \"> stage_input\";\n\t\t\t\tcontrolPointMain << \",\\n    uint sv_ControlPointID : SV_OutputControlPointID\";\n\n\t\t\t\tcontrolPointMain << \")\\n{\\n\";\n\t\t\t\tcontrolPointMain << \"T\" << controlPointWorld->OutputType->TypeName << \" stage_output;\\n\";\n\t\t\t\tcontrolPointMain << ctx.Header.ProduceString() << ctx.Body.ProduceString();\n\t\t\t\tcontrolPointMain << \"return stage_output;\\n\";\n\t\t\t\tcontrolPointMain << \"}\\n\";\n\n\t\t\t\tStringBuilder sb;\n\t\t\t\tsb << ctx.GlobalHeader.ProduceString();\n\t\t\t\tsb << patchMain.ProduceString();\n\t\t\t\tsb << controlPointMain.ProduceString();\n\t\t\t\trs.MainCode = sb.ProduceString();\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t};\n\n\t\t// TODO(tfoley): This code has not been ported or tested.\n\t\tclass HLSLArrayOutputStrategy : public OutputStrategy\n\t\t{\n\t\tprotected:\n\t\t\tbool isPatch = false;\n\t\t\tint arraySize = 0;\n\t\tpublic:\n\t\t\tString outputIndex;\n\t\t\tHLSLArrayOutputStrategy(HLSLCodeGen * pCodeGen, ILWorld * world, bool pIsPatch, int pArraySize, String pOutputIndex)\n\t\t\t\t: OutputStrategy(pCodeGen, world)\n\t\t\t{\n\t\t\t\tisPatch = pIsPatch;\n\t\t\t\tarraySize = pArraySize;\n\t\t\t\toutputIndex = pOutputIndex;\n\t\t\t}\n\t\t\tvirtual void DeclareOutput(CodeGenContext & ctx, ILStage *) override\n\t\t\t{\n\t\t\t\tctx.GlobalHeader << \"struct T\" << world->OutputType->TypeName << \"\\n{\\n\";\n\n\t\t\t\tfor (auto & field : world->OutputType->Members)\n\t\t\t\t{\n\t\t\t\t\tcodeGen->PrintDef(ctx.GlobalHeader, field.Value.Type.Ptr(), field.Key);\n\t\t\t\t\tctx.GlobalHeader << \";\\n\";\n\t\t\t\t}\n\n\t\t\t\tctx.GlobalHeader << \"};\\n\";\n\t\t\t}\n\t\t\tvirtual void ProcessExportInstruction(CodeGenContext & ctx, ExportInstruction * instr) override\n\t\t\t{\n\t\t\t\tctx.Body << AddWorldNameSuffix(instr->ComponentName, world->Name) << \"[\" << outputIndex << \"] = \";\n\t\t\t\tcodeGen->PrintOp(ctx, instr->Operand.Ptr());\n\t\t\t\tctx.Body << \";\\n\";\n\t\t\t}\n\t\t};\n\n\t\t// TODO(tfoley): This code has not been ported or tested.\n\t\tclass HLSLPackedBufferOutputStrategy : public OutputStrategy\n\t\t{\n\t\tpublic:\n\t\t\tHLSLPackedBufferOutputStrategy(HLSLCodeGen * pCodeGen, ILWorld * world)\n\t\t\t\t: OutputStrategy(pCodeGen, world)\n\t\t\t{}\n\t\t\tvirtual void DeclareOutput(CodeGenContext & ctx, ILStage *) override\n\t\t\t{\n\t\t\t\tfor (auto & field : world->OutputType->Members)\n\t\t\t\t{\n\t\t\t\t\tctx.GlobalHeader << \"out \";\n\t\t\t\t\tcodeGen->PrintDef(ctx.GlobalHeader, field.Value.Type.Ptr(), field.Key);\n\t\t\t\t\tctx.GlobalHeader << \";\\n\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tvirtual void ProcessExportInstruction(CodeGenContext & ctx, ExportInstruction * exportInstr) override\n\t\t\t{\n\t\t\t\tString conversionFunction;\n\t\t\t\tint size = 0;\n\t\t\t\tString typeName = exportInstr->Type->ToString();\n\t\t\t\tif (typeName == \"int\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"intBitsToFloat\";\n\t\t\t\t\tsize = 1;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"ivec2\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"intBitsToFloat\";\n\t\t\t\t\tsize = 2;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"ivec3\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"intBitsToFloat\";\n\t\t\t\t\tsize = 3;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"ivec4\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"intBitsToFloat\";\n\t\t\t\t\tsize = 4;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"uint\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"uintBitsToFloat\";\n\t\t\t\t\tsize = 1;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"uvec2\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"uintBitsToFloat\";\n\t\t\t\t\tsize = 2;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"uvec3\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"uintBitsToFloat\";\n\t\t\t\t\tsize = 3;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"uvec4\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"uintBitsToFloat\";\n\t\t\t\t\tsize = 4;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"float\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\tsize = 1;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"vec2\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\tsize = 2;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"vec3\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\tsize = 3;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"vec4\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\tsize = 4;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"mat3\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\tsize = 9;\n\t\t\t\t}\n\t\t\t\telse if (typeName == \"mat4\")\n\t\t\t\t{\n\t\t\t\t\tconversionFunction = \"\";\n\t\t\t\t\tsize = 16;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n                    codeGen->getSink()->diagnose(CodePosition(), Diagnostics::importingFromPackedBufferUnsupported, typeName);\n\t\t\t\t}\n\t\t\t\tauto recType = world->OutputType.Ptr();\n\t\t\t\tint recTypeSize = 0;\n\t\t\t\tEnumerableDictionary<String, int> memberOffsets;\n\t\t\t\tfor (auto & member : recType->Members)\n\t\t\t\t{\n\t\t\t\t\tmemberOffsets[member.Key] = recTypeSize;\n\t\t\t\t\trecTypeSize += member.Value.Type->GetVectorSize();\n\t\t\t\t}\n\t\t\t\tfor (int i = 0; i < size; i++)\n\t\t\t\t{\n\t\t\t\t\tctx.Body << \"sysOutputBuffer.content[gl_InvocationId.x * \" << recTypeSize << \" + \" + memberOffsets[exportInstr->ComponentName]()\n\t\t\t\t\t\t<< \"] = \" << conversionFunction << \"(\";\n\t\t\t\t\tcodeGen->PrintOp(ctx, exportInstr->Operand.Ptr());\n\t\t\t\t\tif (size <= 4)\n\t\t\t\t\t\tctx.Body << \"[\" << i << \"]\";\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tint width = size == 9 ? 3 : 4;\n\t\t\t\t\t\tctx.Body << \"[\" << i / width << \"][\" << i % width << \"]\";\n\t\t\t\t\t}\n\t\t\t\t\tctx.Body << \");\\n\";\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tOutputStrategy * HLSLCodeGen::CreateStandardOutputStrategy(ILWorld * world, String layoutPrefix)\n\t\t{\n\t\t\treturn new HLSLCodeGen::SimpleOutputStrategy(this, world, \"stage_output.user\");\n\t\t}\n\n\t\tOutputStrategy * HLSLCodeGen::CreatePackedBufferOutputStrategy(ILWorld * world)\n\t\t{\n\t\t\treturn new HLSLPackedBufferOutputStrategy(this, world);\n\t\t}\n\t\tOutputStrategy * HLSLCodeGen::CreateArrayOutputStrategy(ILWorld * world, bool pIsPatch, int pArraySize, String arrayIndex)\n\t\t{\n\t\t\treturn new HLSLArrayOutputStrategy(this, world, pIsPatch, pArraySize, arrayIndex);\n\t\t}\n\n\t\tCodeGenBackend * CreateHLSLCodeGen()\n\t\t{\n\t\t\treturn new HLSLCodeGen();\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/IL.cpp",
    "content": "#include \"IL.h\"\n#include \"../CoreLib/LibIO.h\"\n#include \"Syntax.h\"\n#include \"CompiledProgram.h\"\n#include \"../CoreLib/Tokenizer.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tusing namespace CoreLib::IO;\n\n\t\tRefPtr<ILType> BaseTypeFromString(CoreLib::Text::TokenReader & parser)\n\t\t{\n\t\t\tif (parser.LookAhead(\"int\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Int);\n\t\t\telse if (parser.LookAhead(\"uint\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::UInt);\n\t\t\telse if (parser.LookAhead(\"uvec2\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::UInt2);\n\t\t\telse if (parser.LookAhead(\"uvec3\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::UInt3);\n\t\t\telse if (parser.LookAhead(\"uvec4\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::UInt4);\n\t\t\tif (parser.LookAhead(\"float\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Float);\n\t\t\tif (parser.LookAhead(\"vec2\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Float2);\n\t\t\tif (parser.LookAhead(\"vec3\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Float3);\n\t\t\tif (parser.LookAhead(\"vec4\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Float4);\n\t\t\tif (parser.LookAhead(\"ivec2\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Int2);\n\t\t\tif (parser.LookAhead(\"mat3\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Float3x3);\n\t\t\tif (parser.LookAhead(\"mat4\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Float4x4);\n\t\t\tif (parser.LookAhead(\"ivec3\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Int3);\n\t\t\tif (parser.LookAhead(\"ivec4\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Int4);\n\t\t\tif (parser.LookAhead(\"sampler2D\") || parser.LookAhead(\"Texture2D\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Texture2D);\n\t\t\tif (parser.LookAhead(\"samplerCube\") || parser.LookAhead(\"TextureCube\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::TextureCube);\n\t\t\tif (parser.LookAhead(\"sampler2DArray\") || parser.LookAhead(\"Texture2DArray\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Texture2DArray);\n\t\t\tif (parser.LookAhead(\"sampler2DShadow\") || parser.LookAhead(\"Texture2DShadow\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Texture2DShadow);\n\t\t\tif (parser.LookAhead(\"samplerCubeShadow\") || parser.LookAhead(\"TextureCubeShadow\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::TextureCubeShadow);\n\t\t\tif (parser.LookAhead(\"sampler2DArrayShadow\") || parser.LookAhead(\"Texture2DArrayShadow\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Texture2DArrayShadow);\n\t\t\tif (parser.LookAhead(\"sampler3D\") || parser.LookAhead(\"Texture3D\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Texture3D);\n\t\t\tif (parser.LookAhead(\"samplerCubeArray\") || parser.LookAhead(\"TextureCubeArray\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::TextureCubeArray);\n\t\t\tif (parser.LookAhead(\"samplerCubeArrayShadow\") || parser.LookAhead(\"TextureCubeShadowArray\") || parser.LookAhead(\"TextureCubeArrayShadow\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::TextureCubeShadowArray);\n\t\t\tif (parser.LookAhead(\"bool\"))\n\t\t\t\treturn new ILBasicType(ILBaseType::Bool);\n\t\t\treturn nullptr;\n\t\t}\n\n\t\tint RoundToAlignment(int offset, int alignment)\n\t\t{\n\t\t\tint remainder = offset % alignment;\n\t\t\tif (remainder == 0)\n\t\t\t\treturn offset;\n\t\t\telse\n\t\t\t\treturn offset + (alignment - remainder);\n\t\t}\n\n\t\tint GetMaxResourceBindings(BindableResourceType type)\n\t\t{\n\t\t\tswitch (type)\n\t\t\t{\n\t\t\tcase BindableResourceType::Texture:\n\t\t\t\treturn 32;\n\t\t\tcase BindableResourceType::Sampler:\n\t\t\t\treturn 32;\n\t\t\tcase BindableResourceType::Buffer:\n\t\t\t\treturn 16;\n\t\t\tcase BindableResourceType::StorageBuffer:\n\t\t\t\treturn 16;\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\n\t\tint SizeofBaseType(ILBaseType type)\n\t\t{\n\t\t\tif (type == ILBaseType::Int)\n\t\t\t\treturn 4;\n\t\t\tif (type == ILBaseType::UInt)\n\t\t\t\treturn 4;\n\t\t\tif (type == ILBaseType::UInt2)\n\t\t\t\treturn 8;\n\t\t\tif (type == ILBaseType::UInt3)\n\t\t\t\treturn 12;\n\t\t\tif (type == ILBaseType::UInt4)\n\t\t\t\treturn 16;\n\t\t\telse if (type == ILBaseType::Int2)\n\t\t\t\treturn 8;\n\t\t\telse if (type == ILBaseType::Int3)\n\t\t\t\treturn 12;\n\t\t\telse if (type == ILBaseType::Int4)\n\t\t\t\treturn 16;\n\t\t\telse if (type == ILBaseType::Float)\n\t\t\t\treturn 4;\n\t\t\telse if (type == ILBaseType::Float2)\n\t\t\t\treturn 8;\n\t\t\telse if (type == ILBaseType::Float3)\n\t\t\t\treturn 12;\n\t\t\telse if (type == ILBaseType::Float4)\n\t\t\t\treturn 16;\n\t\t\telse if (type == ILBaseType::Float3x3)\n\t\t\t\treturn 48;\n\t\t\telse if (type == ILBaseType::Float4x4)\n\t\t\t\treturn 64;\n\t\t\telse if (type == ILBaseType::Texture2D)\n\t\t\t\treturn 8;\n\t\t\telse if (type == ILBaseType::TextureCube)\n\t\t\t\treturn 8;\n\t\t\telse if (type == ILBaseType::Texture2DArray)\n\t\t\t\treturn 8;\n\t\t\telse if (type == ILBaseType::Texture2DShadow)\n\t\t\t\treturn 8;\n\t\t\telse if (type == ILBaseType::TextureCubeShadow)\n\t\t\t\treturn 8;\n\t\t\telse if (type == ILBaseType::Texture2DArrayShadow)\n\t\t\t\treturn 8;\n\t\t\telse if (type == ILBaseType::TextureCubeArray)\n\t\t\t\treturn 8; \n\t\t\telse if (type == ILBaseType::TextureCubeShadowArray)\n\t\t\t\treturn 8;\n\t\t\telse if (type == ILBaseType::Bool)\n\t\t\t\treturn 4;\n\t\t\telse\n\t\t\t\treturn 0;\n\t\t}\n\n\t\tbool ILType::IsBool()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::Bool;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool ILType::IsInt()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::Int;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool ILType::IsUInt()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::UInt;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool ILType::IsIntegral()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::Int || basicType->Type == ILBaseType::Int2 || basicType->Type == ILBaseType::Int3 || basicType->Type == ILBaseType::Int4\n\t\t\t\t|| basicType->Type == ILBaseType::UInt || basicType->Type == ILBaseType::UInt2 || basicType->Type == ILBaseType::UInt3 || basicType->Type == ILBaseType::UInt4 ||\n\t\t\t\tbasicType->Type == ILBaseType::Bool;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool ILType::IsVoid()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::Void;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool ILType::IsFloat()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::Float;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool ILType::IsBoolVector()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::Bool2 || basicType->Type == ILBaseType::Bool3 || basicType->Type == ILBaseType::Bool4;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool ILType::IsIntVector()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::Int2 || basicType->Type == ILBaseType::Int3 || basicType->Type == ILBaseType::Int4;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool ILType::IsUIntVector()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::UInt2 || basicType->Type == ILBaseType::UInt3 || basicType->Type == ILBaseType::UInt4;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool ILType::IsFloatVector()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::Float2 || basicType->Type == ILBaseType::Float3 || basicType->Type == ILBaseType::Float4 ||\n\t\t\t\tbasicType->Type == ILBaseType::Float3x3 || basicType->Type == ILBaseType::Float4x4;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool ILType::IsFloatMatrix()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::Float3x3 || basicType->Type == ILBaseType::Float4x4;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool ILType::IsNonShadowTexture()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::Texture2D || basicType->Type == ILBaseType::TextureCube || basicType->Type == ILBaseType::Texture2DArray ||\n\t\t\t\tbasicType->Type == ILBaseType::Texture3D || basicType->Type == ILBaseType::TextureCubeArray;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool ILType::IsTexture()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::Texture2D || basicType->Type == ILBaseType::TextureCube || basicType->Type == ILBaseType::Texture2DArray ||\n\t\t\t\tbasicType->Type == ILBaseType::Texture2DShadow || basicType->Type == ILBaseType::TextureCubeShadow || basicType->Type == ILBaseType::Texture2DArrayShadow ||\n\t\t\t\tbasicType->Type == ILBaseType::Texture3D || basicType->Type == ILBaseType::TextureCubeShadowArray || basicType->Type == ILBaseType::TextureCubeArray;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool ILType::IsSamplerState()\n\t\t{\n\t\t\tauto basicType = dynamic_cast<ILBasicType*>(this);\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Type == ILBaseType::SamplerState || basicType->Type == ILBaseType::SamplerComparisonState;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tint ILType::GetVectorSize()\n\t\t{\n\t\t\tif (auto basicType = dynamic_cast<ILBasicType*>(this))\n\t\t\t{\n\t\t\t\tswitch (basicType->Type)\n\t\t\t\t{\n\t\t\t\tcase ILBaseType::Int2:\n\t\t\t\tcase ILBaseType::Float2:\n\t\t\t\tcase ILBaseType::UInt2:\n\t\t\t\t\treturn 2;\n\t\t\t\tcase ILBaseType::Int3:\n\t\t\t\tcase ILBaseType::Float3:\n\t\t\t\tcase ILBaseType::UInt3:\n\t\t\t\t\treturn 3;\n\t\t\t\tcase ILBaseType::Int4:\n\t\t\t\tcase ILBaseType::Float4:\n\t\t\t\tcase ILBaseType::UInt4:\n\t\t\t\t\treturn 4;\n\t\t\t\tcase ILBaseType::Float3x3:\n\t\t\t\t\treturn 9;\n\t\t\t\tcase ILBaseType::Float4x4:\n\t\t\t\t\treturn 16;\n\t\t\t\tdefault:\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn 1;\n\t\t}\n\n\t\tRefPtr<ILType> DeserializeBasicType(CoreLib::Text::TokenReader & reader)\n\t\t{\n\t\t\treader.Read(\"basic\");\n\t\t\tauto rs = BaseTypeFromString(reader);\n\t\t\treader.ReadWord();\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<ILType> DeserializeStructType(CoreLib::Text::TokenReader & reader)\n\t\t{\n\t\t\treader.Read(\"struct\");\n\t\t\tRefPtr<ILStructType> rs = new ILStructType();\n\t\t\trs->TypeName = reader.ReadToken().Content;\n\t\t\treader.Read(\"(\");\n\t\t\twhile (reader.LookAhead(\")\"))\n\t\t\t{\n\t\t\t\tILStructType::ILStructField field;\n\t\t\t\tfield.FieldName = reader.ReadToken().Content;\n\t\t\t\treader.Read(\":\");\n\t\t\t\tfield.Type = ILType::Deserialize(reader);\n\t\t\t\treader.Read(\";\");\n\t\t\t}\n\t\t\treader.Read(\")\");\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<ILType> DeserializeArrayType(CoreLib::Text::TokenReader & reader)\n\t\t{\n\t\t\treader.Read(\"array\");\n\t\t\treader.Read(\"(\");\n\t\t\tRefPtr<ILArrayType> rs = new ILArrayType();\n\t\t\trs->BaseType = ILType::Deserialize(reader);\n\t\t\treader.Read(\",\");\n\t\t\trs->ArrayLength = reader.ReadInt();\n\t\t\treader.Read(\")\");\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<ILType> DeserializeGenericType(CoreLib::Text::TokenReader & reader)\n\t\t{\n\t\t\treader.Read(\"generic\");\n\t\t\tRefPtr<ILGenericType> rs = new ILGenericType();\n\t\t\trs->GenericTypeName = reader.ReadWord();\n\t\t\treader.Read(\"(\");\n\t\t\trs->BaseType = ILType::Deserialize(reader);\n\t\t\treader.Read(\")\");\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<ILType> DeserializeRecordType(CoreLib::Text::TokenReader & reader)\n\t\t{\n\t\t\treader.Read(\"record\");\n\t\t\tRefPtr<ILRecordType> rs = new ILRecordType();\n\t\t\trs->TypeName = reader.ReadWord();\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<ILType> ILType::Deserialize(CoreLib::Text::TokenReader & reader)\n\t\t{\n\t\t\tif (reader.LookAhead(\"basic\"))\n\t\t\t\treturn DeserializeBasicType(reader);\n\t\t\telse if (reader.LookAhead(\"struct\"))\n\t\t\t\treturn DeserializeStructType(reader);\n\t\t\telse if (reader.LookAhead(\"array\"))\n\t\t\t\treturn DeserializeArrayType(reader);\n\t\t\telse if (reader.LookAhead(\"generic\"))\n\t\t\t\treturn DeserializeGenericType(reader);\n\t\t\telse if (reader.LookAhead(\"record\"))\n\t\t\t\treturn DeserializeRecordType(reader);\n\t\t\treturn nullptr;\n\t\t}\n\n\t\tbool CFGNode::HasPhiInstruction()\n\t\t{\n\t\t\treturn headInstr && headInstr->GetNext() && headInstr->GetNext()->Is<PhiInstruction>();\n\t\t}\n\n\t\tILInstruction * CFGNode::GetFirstNonPhiInstruction()\n\t\t{\n\t\t\tfor (auto & instr : *this)\n\t\t\t{\n\t\t\t\tif (!instr.Is<PhiInstruction>())\n\t\t\t\t\treturn &instr;\n\t\t\t}\n\t\t\treturn tailInstr;\n\t\t}\n\n\t\tint NamingCounter = 0;\n\n\t\tvoid CFGNode::NameAllInstructions()\n\t\t{\n\t\t\t// name all operands\n\t\t\tStringBuilder numBuilder;\n\t\t\tfor (auto & instr : GetAllInstructions())\n\t\t\t{\n\t\t\t\tnumBuilder.Clear();\n\t\t\t\tfor (auto & c : instr.Name)\n\t\t\t\t{\n\t\t\t\t\tif (c >= '0' && c <= '9')\n\t\t\t\t\t\tnumBuilder.Append(c);\n\t\t\t\t\telse\n\t\t\t\t\t\tnumBuilder.Clear();\n\t\t\t\t}\n\t\t\t\tauto num = numBuilder.ToString();\n\t\t\t\tif (num.Length())\n\t\t\t\t{\n\t\t\t\t\tint id = StringToInt(num);\n\t\t\t\t\tNamingCounter = Math::Max(NamingCounter, id + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\tHashSet<String> existingNames;\n\t\t\tfor (auto & instr : GetAllInstructions())\n\t\t\t{\n\t\t\t\tif (instr.Name.Length() == 0)\n\t\t\t\t\tinstr.Name = String(\"t\") + String(NamingCounter++, 16);\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tint counter = 1;\n\t\t\t\t\tString newName = instr.Name;\n\t\t\t\t\twhile (existingNames.Contains(newName))\n\t\t\t\t\t{\n\t\t\t\t\t\tnewName = instr.Name + String(counter);\n\t\t\t\t\t\tcounter++;\n\t\t\t\t\t}\n\t\t\t\t\tinstr.Name = newName;\n\t\t\t\t}\n\t\t\t\texistingNames.Add(instr.Name);\n\t\t\t}\n\t\t}\n\n\t\tvoid CFGNode::DebugPrint()\n\t\t{\n\t\t\tprintf(\"===========\\n\");\n\t\t\tfor (auto& instr : *this)\n\t\t\t{\n\t\t\t\tprintf(\"%S\\n\", instr.ToString().ToWString());\n\t\t\t}\n\t\t\tprintf(\"===========\\n\");\n\t\t}\n\n\t\tLoadInstruction::LoadInstruction(ILOperand * dest)\n\t\t{\n\t\t\tDeterministic = false;\n\t\t\tOperand = dest;\n\t\t\tType = dest->Type->Clone();\n\t\t\tif (!Spire::Compiler::Is<AllocVarInstruction>(dest) && !Spire::Compiler::Is<FetchArgInstruction>(dest))\n\t\t\t\tthrow \"invalid address operand\";\n\t\t}\n\t\tvoid MemberUpdateInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitMemberUpdateInstruction(this);\n\t\t}\n\t\tvoid SubInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitSubInstruction(this);\n\t\t}\n\t\tvoid MulInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitMulInstruction(this);\n\t\t}\n\t\tvoid DivInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitDivInstruction(this);\n\t\t}\n\t\tvoid ModInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitModInstruction(this);\n\t\t}\n\t\tvoid AndInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitAndInstruction(this);\n\t\t}\n\t\tvoid OrInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitOrInstruction(this);\n\t\t}\n\t\tvoid BitAndInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitBitAndInstruction(this);\n\t\t}\n\t\tvoid BitOrInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitBitOrInstruction(this);\n\t\t}\n\t\tvoid BitXorInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitBitXorInstruction(this);\n\t\t}\n\t\tvoid ShlInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitShlInstruction(this);\n\t\t}\n\t\tvoid ShrInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitShrInstruction(this);\n\t\t}\n\t\tvoid CmpgtInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitCmpgtInstruction(this);\n\t\t}\n\t\tvoid CmpgeInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitCmpgeInstruction(this);\n\t\t}\n\t\tvoid CmpltInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitCmpltInstruction(this);\n\t\t}\n\t\tvoid CmpleInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitCmpleInstruction(this);\n\t\t}\n\t\tvoid CmpeqlInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitCmpeqlInstruction(this);\n\t\t}\n\t\tvoid CmpneqInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitCmpneqInstruction(this);\n\t\t}\n\t\tvoid Float2IntInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitFloat2IntInstruction(this);\n\t\t}\n\t\tvoid Int2FloatInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitInt2FloatInstruction(this);\n\t\t}\n\t\tvoid CopyInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitCopyInstruction(this);\n\t\t}\n\t\tvoid LoadInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitLoadInstruction(this);\n\t\t}\n\t\tvoid StoreInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitStoreInstruction(this);\n\t\t}\n\t\tvoid AllocVarInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitAllocVarInstruction(this);\n\t\t}\n\t\tvoid FetchArgInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitFetchArgInstruction(this);\n\t\t}\n\t\tvoid PhiInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitPhiInstruction(this);\n\t\t}\n\t\tvoid SelectInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitSelectInstruction(this);\n\t\t}\n\t\tvoid CallInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitCallInstruction(this);\n\t\t}\n\t\tvoid SwitchInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitSwitchInstruction(this);\n\t\t}\n\t\tvoid NotInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitNotInstruction(this);\n\t\t}\n\t\tvoid NegInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitNegInstruction(this);\n\t\t}\n\t\tvoid BitNotInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitBitNotInstruction(this);\n\t\t}\n\t\tvoid AddInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitAddInstruction(this);\n\t\t}\n\t\tvoid MemberLoadInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitMemberLoadInstruction(this);\n\t\t}\n\t\tAllInstructionsIterator & AllInstructionsIterator::operator++()\n\t\t{\n\t\t\tif (subBlockPtr < curInstr->GetSubBlockCount())\n\t\t\t{\n\t\t\t\tStackItem item;\n\t\t\t\titem.instr = curInstr;\n\t\t\t\titem.subBlockPtr = subBlockPtr + 1;\n\t\t\t\tstack.Add(item);\n\t\t\t\tcurInstr = curInstr->GetSubBlock(subBlockPtr)->begin().Current;\n\t\t\t\tsubBlockPtr = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t\tcurInstr = curInstr->GetNext();\n\t\t\twhile (curInstr->GetNext() == nullptr && stack.Count() > 0)\n\t\t\t{\n\t\t\t\tauto item = stack.Last();\n\t\t\t\tstack.RemoveAt(stack.Count() - 1);\n\t\t\t\tcurInstr = item.instr;\n\t\t\t\tsubBlockPtr = item.subBlockPtr;\n\t\t\t\tif (subBlockPtr >= curInstr->GetSubBlockCount())\n\t\t\t\t{\n\t\t\t\t\tsubBlockPtr = 0;\n\t\t\t\t\tcurInstr = curInstr->GetNext();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn *this;\n\t\t}\n\t\tAllInstructionsIterator AllInstructionsCollection::begin()\n\t\t{\n\t\t\treturn AllInstructionsIterator(node->begin().Current);\n\t\t}\n\t\tAllInstructionsIterator AllInstructionsCollection::end()\n\t\t{\n\t\t\treturn AllInstructionsIterator(node->end().Current);\n\t\t}\n\t\tString ImportInstruction::ToString()\n\t\t{\n\t\t\tStringBuilder rs;\n\t\t\trs << Name << \" = import [\" << ComponentName << \"](\";\n\t\t\tfor (auto & arg : Arguments)\n\t\t\t{\n\t\t\t\trs << arg->ToString() << \", \";\n\t\t\t}\n\t\t\trs << \")\";\n\t\t\trs << \"\\n{\";\n\t\t\trs << ImportOperator->ToString() << \"}\\n\";\n\t\t\treturn rs.ProduceString();\n\t\t}\n\t\tString ImportInstruction::GetOperatorString()\n\t\t{\n\t\t\treturn \"import\";\n\t\t}\n\t\tvoid ImportInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitImportInstruction(this);\n\t\t}\n\t\tvoid ExportInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitExportInstruction(this);\n\t\t}\n\t\tILType * ILStructType::Clone()\n\t\t{\n\t\t\tauto rs = new ILStructType(*this);\n\t\t\trs->Members.Clear();\n\t\t\tfor (auto & m : Members)\n\t\t\t{\n\t\t\t\tILStructField f;\n\t\t\t\tf.FieldName = m.FieldName;\n\t\t\t\tf.Type = m.Type->Clone();\n\t\t\t\trs->Members.Add(f);\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\t\tString ILStructType::ToString()\n\t\t{\n\t\t\treturn TypeName;\n\t\t}\n\t\tbool ILStructType::Equals(ILType * type)\n\t\t{\n\t\t\tauto st = dynamic_cast<ILStructType*>(type);\n\t\t\tif (st && st->TypeName == this->TypeName)\n\t\t\t\treturn true;\n\t\t\treturn false;\n\t\t}\n\t\tILType * ILRecordType::Clone()\n\t\t{\n\t\t\tauto rs = new ILRecordType(*this);\n\t\t\trs->Members.Clear();\n\t\t\tfor (auto & m : Members)\n\t\t\t{\n\t\t\t\tILObjectDefinition f;\n\t\t\t\tf.Type = m.Value.Type->Clone();\n\t\t\t\tf.Name = m.Value.Name;\n\t\t\t\tf.Attributes = m.Value.Attributes;\n\t\t\t\trs->Members.Add(m.Key, f);\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\t\tString ILRecordType::ToString()\n\t\t{\n\t\t\treturn TypeName;\n\t\t}\n\t\tbool ILRecordType::Equals(ILType * type)\n\t\t{\n\t\t\tauto recType = dynamic_cast<ILRecordType*>(type);\n\t\t\tif (recType)\n\t\t\t\treturn TypeName == recType->TypeName;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\t\tvoid DiscardInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitDiscardInstruction(this);\n\t\t}\n\t\tvoid LoadInputInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitLoadInputInstruction(this);\n\t\t}\n\t\tvoid SwizzleInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitSwizzleInstruction(this);\n\t\t}\n\t\tvoid ProjectInstruction::Accept(InstructionVisitor * visitor)\n\t\t{\n\t\t\tvisitor->VisitProjectInstruction(this);\n\t\t}\n}\n}"
  },
  {
    "path": "Source/SpireCore/IL.h",
    "content": "#ifndef RASTER_RENDERER_IL_H\n#define RASTER_RENDERER_IL_H\n\n#include \"../CoreLib/Basic.h\"\n#include \"../CoreLib/Tokenizer.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tusing CoreLib::Text::CodePosition;\n\n\t\tusing namespace CoreLib::Basic;\n\t\tenum ILBaseType\n\t\t{\n\t\t\tVoid = 0,\n\t\t\tInt = 16, Int2 = 17, Int3 = 18, Int4 = 19,\n\t\t\tFloat = 32, Float2 = 33, Float3 = 34, Float4 = 35,\n\t\t\tFloat3x3 = 40, Float4x4 = 47,\n\t\t\tTexture2D = 48,\n\t\t\tTextureCube = 49,\n\t\t\tTexture2DArray = 50,\n\t\t\tTexture2DShadow = 51,\n\t\t\tTextureCubeShadow = 52,\n\t\t\tTexture2DArrayShadow = 53,\n\t\t\tTexture3D = 54,\n\t\t\tTextureCubeArray = 55,\n\t\t\tTextureCubeShadowArray = 56,\n\t\t\tBool = 128, Bool2 = 129, Bool3 = 130, Bool4 = 131,\n\t\t\tUInt = 512, UInt2 = 513, UInt3 = 514, UInt4 = 515,\n\t\t\tSamplerState = 4096, SamplerComparisonState = 4097\n\t\t};\n\t\tint SizeofBaseType(ILBaseType type);\n\t\tint RoundToAlignment(int offset, int alignment);\n\t\textern int NamingCounter;\n\n\t\tenum class BindableResourceType\n\t\t{\n\t\t\tNonBindable, Texture, Sampler, Buffer, StorageBuffer\n\t\t};\n\t\tint GetMaxResourceBindings(BindableResourceType type);\n\n\t\tclass ILType : public RefObject\n\t\t{\n\t\tpublic:\n\t\t\tbool IsBool();\n\t\t\tbool IsInt();\n\t\t\tbool IsUInt();\n\t\t\tbool IsIntegral();\n\t\t\tbool IsFloat();\n\t\t\tbool IsVoid();\n\t\t\tbool IsScalar()\n\t\t\t{\n\t\t\t\treturn IsInt() || IsUInt() || IsFloat() || IsBool();\n\t\t\t}\n\t\t\tbool IsBoolVector(); \n\t\t\tbool IsIntVector();\n\t\t\tbool IsUIntVector();\n\t\t\tbool IsFloatVector();\n\t\t\tbool IsFloatMatrix();\n\t\t\tbool IsVector()\n\t\t\t{\n\t\t\t\treturn IsIntVector() || IsUIntVector() || IsFloatVector() || IsBoolVector();\n\t\t\t}\n\t\t\tbool IsTexture();\n\t\t\tbool IsSamplerState();\n\t\t\tbool IsNonShadowTexture();\n\t\t\tint GetVectorSize();\n\t\t\tvirtual BindableResourceType GetBindableResourceType() = 0;\n\t\t\tvirtual ILType * Clone() = 0;\n\t\t\tvirtual String ToString() = 0;\n\t\t\tvirtual bool Equals(ILType* type) = 0;\n\t\t\tvirtual void Serialize(StringBuilder & sb) = 0;\n\t\t\tstatic RefPtr<ILType> Deserialize(CoreLib::Text::TokenReader & reader);\n\t\t};\n\n\t\tclass ILObjectDefinition\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ILType> Type;\n\t\t\tString Name;\n\t\t\tEnumerableDictionary<String, CoreLib::Text::Token> Attributes;\n\t\t\tCodePosition Position;\n\t\t\tint Binding = -1;\n\t\t};\n\n\t\tclass ILRecordType : public ILType\n\t\t{\n\t\tpublic:\n\t\t\tString TypeName;\n\t\t\tEnumerableDictionary<String, ILObjectDefinition> Members;\n\t\t\tvirtual ILType * Clone() override;\n\t\t\tvirtual String ToString() override;\n\t\t\tvirtual bool Equals(ILType* type) override;\n\t\t\tvirtual void Serialize(StringBuilder & sb) override\n\t\t\t{\n\t\t\t\tsb << \"record \" << TypeName;\n\t\t\t}\n\t\t\tvirtual BindableResourceType GetBindableResourceType() override\n\t\t\t{\n\t\t\t\treturn BindableResourceType::NonBindable;\n\t\t\t}\n\t\t};\n\n\t\tclass ILBasicType : public ILType\n\t\t{\n\t\tpublic:\n\t\t\tILBaseType Type;\n\t\t\tILBasicType()\n\t\t\t{\n\t\t\t\tType = ILBaseType::Int;\n\t\t\t}\n\t\t\tILBasicType(ILBaseType t)\n\t\t\t{\n\t\t\t\tType = t;\n\t\t\t}\n\t\t\tvirtual bool Equals(ILType* type) override\n\t\t\t{\n\t\t\t\tauto btype = dynamic_cast<ILBasicType*>(type);\n\t\t\t\tif (!btype)\n\t\t\t\t\treturn false;\n\t\t\t\treturn Type == btype->Type;\n\t\t\t}\n\n\t\t\tvirtual BindableResourceType GetBindableResourceType() override\n\t\t\t{\n\t\t\t\tswitch (Type)\n\t\t\t\t{\n\t\t\t\tcase ILBaseType::Texture2D:\n\t\t\t\tcase ILBaseType::TextureCube:\n\t\t\t\tcase ILBaseType::Texture2DArray:\n\t\t\t\tcase ILBaseType::Texture2DShadow:\n\t\t\t\tcase ILBaseType::TextureCubeShadow:\n\t\t\t\tcase ILBaseType::Texture2DArrayShadow:\n\t\t\t\tcase ILBaseType::TextureCubeArray:\n\t\t\t\tcase ILBaseType::TextureCubeShadowArray:\n\t\t\t\tcase ILBaseType::Texture3D:\n\t\t\t\t\treturn BindableResourceType::Texture;\n\t\t\t\tcase ILBaseType::SamplerState:\n\t\t\t\tcase ILBaseType::SamplerComparisonState:\n\t\t\t\t\treturn BindableResourceType::Sampler;\n\t\t\t\tdefault:\n\t\t\t\t\treturn BindableResourceType::NonBindable;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvirtual ILType * Clone() override\n\t\t\t{\n\t\t\t\tauto rs = new ILBasicType();\n\t\t\t\trs->Type = Type;\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tvirtual void Serialize(StringBuilder & sb) override\n\t\t\t{\n\t\t\t\tsb << \"basic \" << ToString();\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\tif (Type == ILBaseType::Int)\n\t\t\t\t\treturn \"int\";\n\t\t\t\telse if (Type == ILBaseType::UInt)\n\t\t\t\t\treturn \"uint\";\n\t\t\t\telse if (Type == ILBaseType::UInt2)\n\t\t\t\t\treturn \"uvec2\";\n\t\t\t\telse if (Type == ILBaseType::UInt3)\n\t\t\t\t\treturn \"uvec3\";\n\t\t\t\telse if (Type == ILBaseType::UInt4)\n\t\t\t\t\treturn \"uvec4\";\n\t\t\t\telse if (Type == ILBaseType::Int2)\n\t\t\t\t\treturn \"ivec2\";\n\t\t\t\telse if (Type == ILBaseType::Int3)\n\t\t\t\t\treturn \"ivec3\";\n\t\t\t\telse if (Type == ILBaseType::Int4)\n\t\t\t\t\treturn \"ivec4\";\n\t\t\t\telse if (Type == ILBaseType::Float)\n\t\t\t\t\treturn \"float\";\n\t\t\t\telse if (Type == ILBaseType::Float2)\n\t\t\t\t\treturn \"vec2\";\n\t\t\t\telse if (Type == ILBaseType::Float3)\n\t\t\t\t\treturn \"vec3\";\n\t\t\t\telse if (Type == ILBaseType::Float4)\n\t\t\t\t\treturn \"vec4\";\n\t\t\t\telse if (Type == ILBaseType::Float3x3)\n\t\t\t\t\treturn \"mat3\";\n\t\t\t\telse if (Type == ILBaseType::Float4x4)\n\t\t\t\t\treturn \"mat4\";\n\t\t\t\telse if (Type == ILBaseType::Texture2D)\n\t\t\t\t\treturn \"sampler2D\";\n\t\t\t\telse if (Type == ILBaseType::TextureCube)\n\t\t\t\t\treturn \"samplerCube\";\n\t\t\t\telse if (Type == ILBaseType::Texture2DArray)\n\t\t\t\t\treturn \"sampler2DArray\";\n\t\t\t\telse if (Type == ILBaseType::Texture2DShadow)\n\t\t\t\t\treturn \"sampler2DShadow\";\n\t\t\t\telse if (Type == ILBaseType::TextureCubeShadow)\n\t\t\t\t\treturn \"samplerCubeShadow\";\n\t\t\t\telse if (Type == ILBaseType::Texture2DArrayShadow)\n\t\t\t\t\treturn \"sampler2DArrayShadow\";\n\t\t\t\telse if (Type == ILBaseType::Texture3D)\n\t\t\t\t\treturn \"sampler3D\";\n\t\t\t\telse if (Type == ILBaseType::TextureCubeArray)\n\t\t\t\t\treturn \"samplerCubeArray\";\n\t\t\t\telse if (Type == ILBaseType::TextureCubeShadowArray)\n\t\t\t\t\treturn \"samplerCubeArrayShadow\";\n\t\t\t\telse if (Type == ILBaseType::Bool)\n\t\t\t\t\treturn \"bool\";\n\t\t\t\telse if (Type == ILBaseType::Bool2)\n\t\t\t\t\treturn \"bvec2\";\n\t\t\t\telse if (Type == ILBaseType::Bool3)\n\t\t\t\t\treturn \"bvec3\";\n\t\t\t\telse if (Type == ILBaseType::Bool4)\n\t\t\t\t\treturn \"bvec4\";\n\t\t\t\telse if (Type == ILBaseType::SamplerState)\n\t\t\t\t\treturn \"SamplerState\";\n\t\t\t\telse if (Type == ILBaseType::SamplerComparisonState)\n\t\t\t\t\treturn \"SamplerComparisonState\";\n\t\t\t\telse if (Type == ILBaseType::Void)\n\t\t\t\t\treturn \"void\";\n\t\t\t\telse\n\t\t\t\t\treturn \"?unknown\";\n\t\t\t}\n\t\t};\n\n\t\tclass ILArrayType : public ILType\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ILType> BaseType;\n\t\t\tint ArrayLength;\n\t\t\tvirtual bool Equals(ILType* type) override\n\t\t\t{\n\t\t\t\tauto btype = dynamic_cast<ILArrayType*>(type);\n\t\t\t\tif (!btype)\n\t\t\t\t\treturn false;\n\t\t\t\treturn BaseType->Equals(btype->BaseType.Ptr());;\n\t\t\t}\n\t\t\tvirtual ILType * Clone() override\n\t\t\t{\n\t\t\t\tauto rs = new ILArrayType();\n\t\t\t\trs->BaseType = BaseType->Clone();\n\t\t\t\trs->ArrayLength = ArrayLength;\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tvirtual void Serialize(StringBuilder & sb) override\n\t\t\t{\n\t\t\t\tsb << \"array(\";\n\t\t\t\tBaseType->Serialize(sb);\n\t\t\t\tsb << \", \" << ArrayLength << \")\";\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\tif (ArrayLength > 0)\n\t\t\t\t\treturn BaseType->ToString() + \"[\" + String(ArrayLength) + \"]\";\n\t\t\t\telse\n\t\t\t\t\treturn BaseType->ToString() + \"[]\";\n\t\t\t}\n\t\t\tvirtual BindableResourceType GetBindableResourceType() override\n\t\t\t{\n\t\t\t\treturn BindableResourceType::NonBindable;\n\t\t\t}\n\t\t};\n\n\t\tclass ILGenericType : public ILType\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ILType> BaseType;\n\t\t\tString GenericTypeName;\n\t\t\tvirtual bool Equals(ILType* type) override\n\t\t\t{\n\t\t\t\tauto btype = dynamic_cast<ILArrayType*>(type);\n\t\t\t\tif (!btype)\n\t\t\t\t\treturn false;\n\t\t\t\treturn BaseType->Equals(btype->BaseType.Ptr());;\n\t\t\t}\n\t\t\tvirtual ILType * Clone() override\n\t\t\t{\n\t\t\t\tauto rs = new ILGenericType();\n\t\t\t\trs->BaseType = BaseType->Clone();\n\t\t\t\trs->GenericTypeName = GenericTypeName;\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn GenericTypeName + \"<\" + BaseType->ToString() + \">\";\n\t\t\t}\n\t\t\tvirtual void Serialize(StringBuilder & sb) override\n\t\t\t{\n\t\t\t\tsb << \"generic \" << GenericTypeName << \"(\";\n\t\t\t\tBaseType->Serialize(sb);\n\t\t\t\tsb << \")\";\n\t\t\t}\n\t\t\tvirtual BindableResourceType GetBindableResourceType() override\n\t\t\t{\n\t\t\t\tif (GenericTypeName == \"StructuredBuffer\" || GenericTypeName == \"RWStructuredBuffer\")\n\t\t\t\t\treturn BindableResourceType::StorageBuffer;\n\t\t\t\telse if (GenericTypeName == \"Buffer\" || GenericTypeName == \"RWBuffer\" || GenericTypeName == \"ByteAddressBuffer\" ||\n\t\t\t\t\tGenericTypeName == \"RWByteAddressBuffer\")\n\t\t\t\t\treturn BindableResourceType::Buffer;\n\t\t\t\treturn BindableResourceType::NonBindable;\n\t\t\t}\n\t\t};\n\n\t\tclass ILStructType : public ILType\n\t\t{\n\t\tpublic:\n\t\t\tString TypeName;\n\t\t\tbool IsIntrinsic = false;\n\t\t\tclass ILStructField\n\t\t\t{\n\t\t\tpublic:\n\t\t\t\tRefPtr<ILType> Type;\n\t\t\t\tString FieldName;\n\t\t\t};\n\t\t\tList<ILStructField> Members;\n\t\t\tvirtual ILType * Clone() override;\n\t\t\tvirtual String ToString() override;\n\t\t\tvirtual bool Equals(ILType * type) override;\n\t\t\tvirtual void Serialize(StringBuilder & sb) override\n\t\t\t{\n\t\t\t\tsb << \"struct \" << TypeName << \"(\";\n\t\t\t\tfor (auto & member : Members)\n\t\t\t\t{\n\t\t\t\t\tsb << member.FieldName << \":\";\n\t\t\t\t\tmember.Type->Serialize(sb);\n\t\t\t\t\tsb << \"; \";\n\t\t\t\t}\n\t\t\t\tsb << \")\";\n\t\t\t}\n\t\t\tvirtual BindableResourceType GetBindableResourceType() override\n\t\t\t{\n\t\t\t\treturn BindableResourceType::NonBindable;\n\t\t\t}\n\t\t};\n\n\t\tclass ILOperand;\n\n\t\tclass UserReferenceSet\n\t\t{\n\t\tprivate:\n\t\t\tEnumerableDictionary<ILOperand*, int> userRefCounts;\n\t\t\tint count;\n\t\tpublic:\n\t\t\tUserReferenceSet()\n\t\t\t{\n\t\t\t\tcount = 0;\n\t\t\t}\n\t\t\tint Count()\n\t\t\t{\n\t\t\t\treturn count;\n\t\t\t}\n\t\t\tint GetUseCount(ILOperand * op)\n\t\t\t{\n\t\t\t\tint rs = -1;\n\t\t\t\tuserRefCounts.TryGetValue(op, rs);\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tvoid Add(ILOperand * user)\n\t\t\t{\n\t\t\t\tthis->count++;\n\t\t\t\tint ncount = 0;\n\t\t\t\tif (userRefCounts.TryGetValue(user, ncount))\n\t\t\t\t{\n\t\t\t\t\tncount++;\n\t\t\t\t\tuserRefCounts[user] = ncount;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tuserRefCounts.Add(user, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\tvoid Remove(ILOperand * user)\n\t\t\t{\n\t\t\t\tint ncount = 0;\n\t\t\t\tif (userRefCounts.TryGetValue(user, ncount))\n\t\t\t\t{\n\t\t\t\t\tthis->count--;\n\t\t\t\t\tncount--;\n\t\t\t\t\tif (ncount)\n\t\t\t\t\t\tuserRefCounts[user] = ncount;\n\t\t\t\t\telse\n\t\t\t\t\t\tuserRefCounts.Remove(user);\n\t\t\t\t}\n\t\t\t}\n\t\t\tvoid RemoveAll(ILOperand * user)\n\t\t\t{\n\t\t\t\tint ncount = 0;\n\t\t\t\tif (userRefCounts.TryGetValue(user, ncount))\n\t\t\t\t{\n\t\t\t\t\tthis->count -= ncount;\n\t\t\t\t\tuserRefCounts.Remove(user);\n\t\t\t\t}\n\t\t\t}\n\t\t\tclass UserIterator\n\t\t\t{\n\t\t\tprivate:\n\t\t\t\tEnumerableDictionary<ILOperand*, int>::Iterator iter;\n\t\t\tpublic:\n\t\t\t\tILOperand * operator *()\n\t\t\t\t{\n\t\t\t\t\treturn iter.Current->Value.Key;\n\t\t\t\t}\n\t\t\t\tILOperand ** operator ->()\n\t\t\t\t{\n\t\t\t\t\treturn &iter.Current->Value.Key;\n\t\t\t\t}\n\t\t\t\tUserIterator & operator ++()\n\t\t\t\t{\n\t\t\t\t\titer++;\n\t\t\t\t\treturn *this;\n\t\t\t\t}\n\t\t\t\tUserIterator operator ++(int)\n\t\t\t\t{\n\t\t\t\t\tUserIterator rs = *this;\n\t\t\t\t\toperator++();\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tbool operator != (const UserIterator & _that)\n\t\t\t\t{\n\t\t\t\t\treturn iter != _that.iter;\n\t\t\t\t}\n\t\t\t\tbool operator == (const UserIterator & _that)\n\t\t\t\t{\n\t\t\t\t\treturn iter == _that.iter;\n\t\t\t\t}\n\t\t\t\tUserIterator(const EnumerableDictionary<ILOperand*, int>::Iterator & iter)\n\t\t\t\t{\n\t\t\t\t\tthis->iter = iter;\n\t\t\t\t}\n\t\t\t\tUserIterator()\n\t\t\t\t{\n\t\t\t\t}\n\t\t\t};\n\t\t\tUserIterator begin()\n\t\t\t{\n\t\t\t\treturn UserIterator(userRefCounts.begin());\n\t\t\t}\n\t\t\tUserIterator end()\n\t\t\t{\n\t\t\t\treturn UserIterator(userRefCounts.end());\n\t\t\t}\n\t\t};\n\n\t\tclass ILOperand : public Object\n\t\t{\n\t\tpublic:\n\t\t\tString Name;\n\t\t\tRefPtr<ILType> Type;\n\t\t\tUserReferenceSet Users;\n\t\t\tString Attribute;\n\t\t\tvoid * Tag;\n\t\t\tCodePosition Position;\n\t\t\tunion VMFields\n\t\t\t{\n\t\t\t\tvoid * VMData;\n\t\t\t\tstruct Fields\n\t\t\t\t{\n\t\t\t\t\tint VMDataWords[2];\n\t\t\t\t} Fields;\n\t\t\t} VMFields;\n\t\t\tProcedure<ILOperand*> OnDelete;\n\t\t\tILOperand()\n\t\t\t{\n\t\t\t\tTag = nullptr;\n\t\t\t}\n\t\t\tILOperand(const ILOperand & op)\n\t\t\t{\n\t\t\t\tTag = op.Tag;\n\t\t\t\tName = op.Name;\n\t\t\t\tAttribute = op.Attribute;\n\t\t\t\tif (op.Type)\n\t\t\t\t\tType = op.Type->Clone();\n\t\t\t\t//Users = op.Users;\n\t\t\t}\n\t\t\tvirtual ~ILOperand()\n\t\t\t{\n\t\t\t\tOnDelete(this);\n\t\t\t}\n\t\t\tvirtual String ToString()\n\t\t\t{\n\t\t\t\treturn \"<operand>\";\n\t\t\t}\n\t\t\tvirtual bool IsUndefined()\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\n\t\tclass ILUndefinedOperand : public ILOperand\n\t\t{\n\t\tpublic:\n\t\t\tILUndefinedOperand()\n\t\t\t{\n\t\t\t\tName = \"<undef>\";\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn \"<undef>\";\n\t\t\t}\n\t\t\tvirtual bool IsUndefined() override\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t};\n\n\t\tclass UseReference\n\t\t{\n\t\tprivate:\n\t\t\tILOperand * user;\n\t\t\tILOperand * reference;\n\t\tpublic:\n\t\t\tUseReference()\n\t\t\t\t: user(0), reference(0)\n\t\t\t{}\n\t\t\tUseReference(const UseReference &)\n\t\t\t{\n\t\t\t\tuser = 0;\n\t\t\t\treference = 0;\n\t\t\t}\n\t\t\tUseReference(ILOperand * user)\n\t\t\t\t: user(user), reference(0)\n\t\t\t{}\n\t\t\tUseReference(ILOperand * user, ILOperand * ref)\n\t\t\t{\n\t\t\t\tthis->user = user;\n\t\t\t\tthis->reference = ref;\n\t\t\t}\n\t\t\t~UseReference()\n\t\t\t{\n\t\t\t\tif (reference)\n\t\t\t\t\treference->Users.Remove(user);\n\t\t\t}\n\t\t\tvoid SetUser(ILOperand * _user)\n\t\t\t{\n\t\t\t\tthis->user = _user;\n\t\t\t}\n\t\t\tvoid operator = (const UseReference & ref)\n\t\t\t{\n\t\t\t\tif (reference)\n\t\t\t\t\treference->Users.Remove(user);\n\t\t\t\treference = ref.Ptr();\n\t\t\t\tif (ref.Ptr())\n\t\t\t\t{\n\t\t\t\t\tif (!user)\n\t\t\t\t\t\tthrow InvalidOperationException(\"user not initialized.\");\n\t\t\t\t\tref.Ptr()->Users.Add(user);\n\t\t\t\t}\n\t\t\t}\n\t\t\tvoid operator = (ILOperand * newRef)\n\t\t\t{\n\t\t\t\tif (reference)\n\t\t\t\t\treference->Users.Remove(user);\n\t\t\t\treference = newRef;\n\t\t\t\tif (newRef)\n\t\t\t\t{\n\t\t\t\t\tif (!user)\n\t\t\t\t\t\tthrow InvalidOperationException(\"user not initialized.\");\n\t\t\t\t\tnewRef->Users.Add(user);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbool operator != (const UseReference & _that)\n\t\t\t{\n\t\t\t\treturn reference != _that.reference || user != _that.user;\n\t\t\t}\n\t\t\tbool operator == (const UseReference & _that)\n\t\t\t{\n\t\t\t\treturn reference == _that.reference && user == _that.user;\n\t\t\t}\n\t\t\tILOperand * Ptr() const\n\t\t\t{\n\t\t\t\treturn reference;\n\t\t\t}\n\t\t\tILOperand * operator->()\n\t\t\t{\n\t\t\t\treturn reference;\n\t\t\t}\n\t\t\tILOperand & operator*()\n\t\t\t{\n\t\t\t\treturn *reference;\n\t\t\t}\n\t\t\texplicit operator bool()\n\t\t\t{\n\t\t\t\treturn (reference != 0);\n\t\t\t}\n\t\t\tString ToString()\n\t\t\t{\n\t\t\t\tif (reference)\n\t\t\t\t\treturn reference->Name;\n\t\t\t\telse\n\t\t\t\t\treturn \"<null>\";\n\t\t\t}\n\t\t};\n\n\t\tclass OperandIterator\n\t\t{\n\t\tprivate:\n\t\t\tUseReference * use;\n\t\tpublic:\n\t\t\tOperandIterator()\n\t\t\t{\n\t\t\t\tuse = 0;\n\t\t\t}\n\t\t\tOperandIterator(UseReference * use)\n\t\t\t\t: use(use)\n\t\t\t{}\n\t\t\tILOperand & operator *()\n\t\t\t{\n\t\t\t\treturn use->operator*();\n\t\t\t}\n\t\t\tILOperand * operator ->()\n\t\t\t{\n\t\t\t\treturn use->operator->();\n\t\t\t}\n\t\t\tvoid Set(ILOperand * user, ILOperand * op)\n\t\t\t{\n\t\t\t\t(*use).SetUser(user);\n\t\t\t\t(*use) = op;\n\t\t\t}\n\t\t\tvoid Set(ILOperand * op)\n\t\t\t{\n\t\t\t\t(*use) = op; \n\t\t\t}\n\t\t\tOperandIterator & operator ++()\n\t\t\t{\n\t\t\t\tuse++;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tOperandIterator operator ++(int)\n\t\t\t{\n\t\t\t\tOperandIterator rs = *this;\n\t\t\t\toperator++();\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tbool operator != (const OperandIterator & _that)\n\t\t\t{\n\t\t\t\treturn use != _that.use;\n\t\t\t}\n\t\t\tbool operator == (const OperandIterator & _that)\n\t\t\t{\n\t\t\t\treturn use == _that.use;\n\t\t\t}\n\t\t\tbool operator == (const ILOperand * op)\n\t\t\t{\n\t\t\t\treturn use->Ptr() == op;\n\t\t\t}\n\t\t\tbool operator != (const ILOperand * op)\n\t\t\t{\n\t\t\t\treturn use->Ptr() != op;\n\t\t\t}\n\t\t};\n\n\t\tclass ILConstOperand : public ILOperand\n\t\t{\n\t\tpublic:\n\t\t\tunion\n\t\t\t{\n\t\t\t\tint IntValues[16];\n\t\t\t\tfloat FloatValues[16];\n\t\t\t};\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\tif (Type->IsFloat())\n\t\t\t\t\treturn String(FloatValues[0]) + \"f\";\n\t\t\t\telse if (Type->IsInt())\n\t\t\t\t\treturn String(IntValues[0]);\n\t\t\t\telse if (auto baseType = dynamic_cast<ILBasicType*>(Type.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tStringBuilder sb(256);\n\t\t\t\t\tif (baseType->Type == ILBaseType::Float2)\n\t\t\t\t\t\tsb << \"vec2(\" << FloatValues[0] << \"f, \" << FloatValues[1] << \"f)\";\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Float3)\n\t\t\t\t\t\tsb << \"vec3(\" << FloatValues[0] << \"f, \" << FloatValues[1] << \"f, \" << FloatValues[2] << \"f)\";\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Float4)\n\t\t\t\t\t\tsb << \"vec4(\" << FloatValues[0] << \"f, \" << FloatValues[1] << \"f, \" << FloatValues[2] << \"f, \" << FloatValues[3] << \"f)\";\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Float3x3)\n\t\t\t\t\t\tsb << \"mat3(...)\";\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Float4x4)\n\t\t\t\t\t\tsb << \"mat4(...)\";\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Int2)\n\t\t\t\t\t\tsb << \"ivec2(\" << IntValues[0] << \", \" << IntValues[1] << \")\";\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Int3)\n\t\t\t\t\t\tsb << \"ivec3(\" << IntValues[0] << \", \" << IntValues[1] << \", \" << IntValues[2] << \")\";\n\t\t\t\t\telse if (baseType->Type == ILBaseType::Int4)\n\t\t\t\t\t\tsb << \"ivec4(\" << IntValues[0] << \", \" << IntValues[1] << \", \" << IntValues[2] << \", \" << IntValues[3] << \")\";\n\t\t\t\t\telse if (baseType->Type == ILBaseType::UInt2)\n\t\t\t\t\t\tsb << \"uvec2(\" << IntValues[0] << \", \" << IntValues[1] << \")\";\n\t\t\t\t\telse if (baseType->Type == ILBaseType::UInt3)\n\t\t\t\t\t\tsb << \"uvec3(\" << IntValues[0] << \", \" << IntValues[1] << \", \" << IntValues[2] << \")\";\n\t\t\t\t\telse if (baseType->Type == ILBaseType::UInt4)\n\t\t\t\t\t\tsb << \"uvec4(\" << IntValues[0] << \", \" << IntValues[1] << \", \" << IntValues[2] << \", \" << IntValues[3] << \")\";\n\t\t\t\t\treturn sb.ToString();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"Illegal constant.\");\n\t\t\t}\n\t\t};\n\n\t\tclass InstructionVisitor;\n\n\t\tclass CFGNode;\n\n\t\tclass ILInstruction : public ILOperand\n\t\t{\n\t\tprivate:\n\t\t\tILInstruction *next, *prev;\n\t\tpublic:\n\t\t\tCFGNode * Parent;\n\t\t\tILInstruction()\n\t\t\t{\n\t\t\t\tnext = 0;\n\t\t\t\tprev = 0;\n\t\t\t\tParent = 0;\n\t\t\t}\n\t\t\tILInstruction(const ILInstruction & instr)\n\t\t\t\t: ILOperand(instr)\n\t\t\t{\n\t\t\t\tnext = 0;\n\t\t\t\tprev = 0;\n\t\t\t\tParent = 0;\n\t\t\t}\n\t\t\t~ILInstruction()\n\t\t\t{\n\t\t\t\t\n\t\t\t}\n\t\t\tvirtual ILInstruction * Clone()\n\t\t\t{\n\t\t\t\treturn new ILInstruction(*this);\n\t\t\t}\n\n\t\t\tvirtual String GetOperatorString()\n\t\t\t{\n\t\t\t\treturn \"<instruction>\";\n\t\t\t}\n\t\t\tvirtual bool HasSideEffect()\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvirtual bool IsDeterministic()\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor *)\n\t\t\t{\n\t\t\t}\n\t\t\tvoid InsertBefore(ILInstruction * instr)\n\t\t\t{\n\t\t\t\tinstr->Parent = Parent;\n\t\t\t\tinstr->prev = prev;\n\t\t\t\tinstr->next = this;\n\t\t\t\tprev = instr;\n\t\t\t\tauto *npp = instr->prev;\n\t\t\t\tif (npp)\n\t\t\t\t\tnpp->next = instr;\n\t\t\t}\n\t\t\tvoid InsertAfter(ILInstruction * instr)\n\t\t\t{\n\t\t\t\tinstr->Parent = Parent;\n\t\t\t\tinstr->prev = this;\n\t\t\t\tinstr->next = this->next;\n\t\t\t\tnext = instr;\n\t\t\t\tauto *npp = instr->next;\n\t\t\t\tif (npp)\n\t\t\t\t\tnpp->prev = instr;\n\t\t\t}\n\t\t\tILInstruction * GetNext()\n\t\t\t{\n\t\t\t\treturn next;\n\t\t\t}\n\t\t\tILInstruction * GetPrevious()\n\t\t\t{\n\t\t\t\treturn prev;\n\t\t\t}\n\t\t\tvoid Remove()\n\t\t\t{\n\t\t\t\tif (prev)\n\t\t\t\t\tprev->next = next;\n\t\t\t\tif (next)\n\t\t\t\t\tnext->prev = prev;\n\t\t\t}\n\t\t\tvoid Erase()\n\t\t\t{\n\t\t\t\tRemove();\n\t\t\t\tif (Users.Count())\n\t\t\t\t{\n\t\t\t\t\tthrow InvalidOperationException(\"All uses must be removed before removing this instruction\");\n\t\t\t\t}\n\t\t\t\tdelete this;\n\t\t\t}\n\t\t\tvirtual OperandIterator begin()\n\t\t\t{\n\t\t\t\treturn OperandIterator();\n\t\t\t}\n\t\t\tvirtual OperandIterator end()\n\t\t\t{\n\t\t\t\treturn OperandIterator();\n\t\t\t}\n\t\t\tvirtual int GetSubBlockCount()\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tvirtual CFGNode * GetSubBlock(int)\n\t\t\t{\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tT * As()\n\t\t\t{\n\t\t\t\treturn dynamic_cast<T*>(this);\n\t\t\t}\n\t\t\ttemplate<typename T>\n\t\t\tbool Is()\n\t\t\t{\n\t\t\t\treturn dynamic_cast<T*>(this) != 0;\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, typename TOperand>\n\t\tbool Is(TOperand * op)\n\t\t{\n\t\t\tauto ptr = dynamic_cast<T*>(op);\n\t\t\tif (ptr)\n\t\t\t\treturn true;\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tclass SwitchInstruction : public ILInstruction\n\t\t{\n\t\tpublic:\n\t\t\tList<UseReference> Candidates;\n\t\t\tvirtual OperandIterator begin() override\n\t\t\t{\n\t\t\t\treturn Candidates.begin();\n\t\t\t}\n\t\t\tvirtual OperandIterator end() override\n\t\t\t{\n\t\t\t\treturn Candidates.end();\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\tStringBuilder sb(256);\n\t\t\t\tsb << Name;\n\t\t\t\tsb << \" = switch \";\n\t\t\t\tfor (auto & op : Candidates)\n\t\t\t\t{\n\t\t\t\t\tsb << op.ToString();\n\t\t\t\t\tif (op != Candidates.Last())\n\t\t\t\t\t\tsb << \", \";\n\t\t\t\t}\n\t\t\t\treturn sb.ProduceString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"switch\";\n\t\t\t}\n\t\t\tvirtual bool HasSideEffect() override\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tSwitchInstruction(int argSize)\n\t\t\t{\n\t\t\t\tCandidates.SetSize(argSize);\n\t\t\t\tfor (auto & use : Candidates)\n\t\t\t\t\tuse.SetUser(this);\n\t\t\t}\n\t\t\tSwitchInstruction(const SwitchInstruction & other)\n\t\t\t\t: ILInstruction(other)\n\t\t\t{\n\t\t\t\tCandidates.SetSize(other.Candidates.Count());\n\t\t\t\tfor (int i = 0; i < other.Candidates.Count(); i++)\n\t\t\t\t{\n\t\t\t\t\tCandidates[i].SetUser(this);\n\t\t\t\t\tCandidates[i] = other.Candidates[i].Ptr();\n\t\t\t\t}\n\n\t\t\t}\n\t\t\tvirtual SwitchInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new SwitchInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass LeaInstruction : public ILInstruction\n\t\t{};\n\t\tclass ILWorld;\n\t\tclass ImportInstruction : public LeaInstruction\n\t\t{\n\t\tpublic:\n\t\t\tString ComponentName;\n\t\t\tRefPtr<CFGNode> ImportOperator;\n\n\t\t\tList<UseReference> Arguments;\n\t\t\tvirtual OperandIterator begin() override\n\t\t\t{\n\t\t\t\treturn Arguments.begin();\n\t\t\t}\n\t\t\tvirtual OperandIterator end() override\n\t\t\t{\n\t\t\t\treturn Arguments.end();\n\t\t\t}\n\t\t\tvirtual int GetSubBlockCount() override\n\t\t\t{\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tvirtual CFGNode * GetSubBlock(int i) override\n\t\t\t{\n\t\t\t\tif (i == 0)\n\t\t\t\t\treturn ImportOperator.Ptr();\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\tImportInstruction(int argSize = 0)\n\t\t\t\t: LeaInstruction()\n\t\t\t{\n\t\t\t\tArguments.SetSize(argSize);\n\t\t\t\tfor (auto & use : Arguments)\n\t\t\t\t\tuse.SetUser(this);\n\t\t\t}\n\t\t\tImportInstruction(const ImportInstruction & other)\n\t\t\t\t: LeaInstruction(other)\n\t\t\t{\n\t\t\t\tArguments.SetSize(other.Arguments.Count());\n\t\t\t\tfor (int i = 0; i < other.Arguments.Count(); i++)\n\t\t\t\t{\n\t\t\t\t\tArguments[i].SetUser(this);\n\t\t\t\t\tArguments[i] = other.Arguments[i].Ptr();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImportInstruction(int argSize, String compName, RefPtr<CFGNode> importOp, RefPtr<ILType> type)\n\t\t\t\t:ImportInstruction(argSize)\n\t\t\t{\n\t\t\t\tthis->ComponentName = compName;\n\t\t\t\tthis->ImportOperator = importOp;\n\t\t\t\tthis->Type = type;\n\t\t\t}\n\t\t\tvirtual String ToString() override;\n\t\t\tvirtual String GetOperatorString() override;\n\t\t\tvirtual ImportInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new ImportInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass LoadInputInstruction : public LeaInstruction\n\t\t{\n\t\tpublic:\n\t\t\tString InputName;\n\t\t\tLoadInputInstruction(RefPtr<ILType> type, String name)\n\t\t\t\t: InputName(name)\n\t\t\t{\n\t\t\t\tthis->Type = type;\n\t\t\t}\n\t\t\tLoadInputInstruction(const LoadInputInstruction & other)\n\t\t\t\t:LeaInstruction(other), InputName(other.InputName)\n\t\t\t{\n\t\t\t}\n\t\t\tvirtual bool IsDeterministic() override\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = INPUT \" + InputName;\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"input\";\n\t\t\t}\n\t\t\tvirtual LoadInputInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new LoadInputInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass AllocVarInstruction : public LeaInstruction\n\t\t{\n\t\tpublic:\n\t\t\tUseReference Size;\n\t\t\tAllocVarInstruction(ILType * type, ILOperand * count)\n\t\t\t\t: Size(this)\n\t\t\t{\n\t\t\t\tthis->Type = type;\n\t\t\t\tthis->Size = count;\n\t\t\t}\n\t\t\tAllocVarInstruction(RefPtr<ILType> & type, ILOperand * count)\n\t\t\t\t: Size(this)\n\t\t\t{\n\t\t\t\tauto ptrType = type->Clone();\n\t\t\t\tif (!type)\n\t\t\t\t\tthrow ArgumentException(\"type cannot be null.\");\n\t\t\t\tthis->Type = ptrType;\n\t\t\t\tthis->Size = count;\n\t\t\t}\n\t\t\tAllocVarInstruction(const AllocVarInstruction & other)\n\t\t\t\t:LeaInstruction(other), Size(this)\n\t\t\t{\n\t\t\t\tSize = other.Size.Ptr();\n\t\t\t}\n\t\t\tvirtual bool IsDeterministic() override\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = VAR \" + Type->ToString() + \", \" + Size.ToString();\n\t\t\t}\n\t\t\tvirtual OperandIterator begin() override\n\t\t\t{\n\t\t\t\treturn &Size;\n\t\t\t}\n\t\t\tvirtual OperandIterator end() override\n\t\t\t{\n\t\t\t\treturn &Size + 1;\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"avar\";\n\t\t\t}\n\t\t\tvirtual AllocVarInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new AllocVarInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass FetchArgInstruction : public LeaInstruction\n\t\t{\n\t\tpublic:\n\t\t\tint ArgId;\n\t\t\tFetchArgInstruction(RefPtr<ILType> type)\n\t\t\t{\n\t\t\t\tthis->Type = type;\n\t\t\t\tArgId = 0;\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = ARG \" + Type->ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"arg \" + String(ArgId);\n\t\t\t}\n\t\t\tvirtual bool IsDeterministic() override\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvirtual FetchArgInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new FetchArgInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass CFGNode;\n\n\t\tclass AllInstructionsIterator\n\t\t{\n\t\tprivate:\n\t\t\tstruct StackItem\n\t\t\t{\n\t\t\t\tILInstruction* instr;\n\t\t\t\tint subBlockPtr;\n\t\t\t};\n\t\t\tList<StackItem> stack;\n\t\t\tILInstruction * curInstr = nullptr;\n\t\t\tint subBlockPtr = 0;\n\t\tpublic:\n\t\t\tAllInstructionsIterator(ILInstruction * instr)\n\t\t\t{\n\t\t\t\tcurInstr = instr;\n\t\t\t}\n\t\t\tAllInstructionsIterator & operator ++();\n\t\t\t\n\t\t\tAllInstructionsIterator operator ++(int)\n\t\t\t{\n\t\t\t\tAllInstructionsIterator rs = *this;\n\t\t\t\toperator++();\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tbool operator != (const AllInstructionsIterator & _that)\n\t\t\t{\n\t\t\t\treturn curInstr != _that.curInstr || subBlockPtr != _that.subBlockPtr;\n\t\t\t}\n\t\t\tbool operator == (const AllInstructionsIterator & _that)\n\t\t\t{\n\t\t\t\treturn curInstr == _that.curInstr && subBlockPtr == _that.subBlockPtr;\n\t\t\t}\n\t\t\tILOperand & operator *()\n\t\t\t{\n\t\t\t\treturn *curInstr;\n\t\t\t}\n\t\t\tILOperand * operator ->()\n\t\t\t{\n\t\t\t\treturn curInstr;\n\t\t\t}\n\t\t};\n\n\t\tclass AllInstructionsCollection\n\t\t{\n\t\tprivate:\n\t\t\tCFGNode * node;\n\t\tpublic:\n\t\t\tAllInstructionsCollection(CFGNode * _node)\n\t\t\t\t: node(_node)\n\t\t\t{}\n\t\t\tAllInstructionsIterator begin();\n\t\t\tAllInstructionsIterator end();\n\t\t};\n\t\t\n\t\tclass CFGNode : public Object\n\t\t{\n\t\tprivate:\n\t\t\tILInstruction *headInstr, *tailInstr;\n\t\tpublic:\n\t\t\tclass Iterator\n\t\t\t{\n\t\t\tpublic:\n\t\t\t\tILInstruction * Current, *Next;\n\t\t\t\tvoid SetCurrent(ILInstruction * cur)\n\t\t\t\t{\n\t\t\t\t\tCurrent = cur;\n\t\t\t\t\tif (Current)\n\t\t\t\t\t\tNext = Current->GetNext();\n\t\t\t\t\telse\n\t\t\t\t\t\tNext = 0;\n\t\t\t\t}\n\t\t\t\tIterator(ILInstruction * cur)\n\t\t\t\t{\n\t\t\t\t\tSetCurrent(cur);\n\t\t\t\t}\n\t\t\t\tILInstruction & operator *() const\n\t\t\t\t{\n\t\t\t\t\treturn *Current;\n\t\t\t\t}\n\t\t\t\tIterator& operator ++()\n\t\t\t\t{\n\t\t\t\t\tSetCurrent(Next);\n\t\t\t\t\treturn *this;\n\t\t\t\t}\n\t\t\t\tIterator operator ++(int)\n\t\t\t\t{\n\t\t\t\t\tIterator rs = *this;\n\t\t\t\t\tSetCurrent(Next);\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t\tbool operator != (const Iterator & iter) const\n\t\t\t\t{\n\t\t\t\t\treturn Current != iter.Current;\n\t\t\t\t}\n\t\t\t\tbool operator == (const Iterator & iter) const\n\t\t\t\t{\n\t\t\t\t\treturn Current == iter.Current;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tString ToString() {\n\t\t\t\tStringBuilder sb;\n\t\t\t\tbool first = true;\n\t\t\t\tauto pintr = begin();\n\t\t\t\twhile (pintr != end()) {\n\t\t\t\t\tif (!first)\n\t\t\t\t\t\tsb << EndLine;\n\t\t\t\t\tfirst = false;\n\t\t\t\t\tsb << pintr.Current->ToString();\n\t\t\t\t\tpintr++;\n\t\t\t\t}\n\t\t\t\treturn sb.ToString();\n\t\t\t}\n\n\t\t\tIterator begin() const\n\t\t\t{\n\t\t\t\treturn Iterator(headInstr->GetNext());\n\t\t\t}\n\n\t\t\tIterator end() const\n\t\t\t{\n\t\t\t\treturn Iterator(tailInstr);\n\t\t\t}\n\n\t\t\tAllInstructionsCollection GetAllInstructions()\n\t\t\t{\n\t\t\t\treturn AllInstructionsCollection(this);\n\t\t\t}\n\t\t\t\n\t\t\tILInstruction * GetFirstNonPhiInstruction();\n\t\t\tbool HasPhiInstruction();\n\n\t\t\tILInstruction * GetLastInstruction()\n\t\t\t{\n\t\t\t\treturn (tailInstr->GetPrevious());\n\t\t\t}\n\n\t\t\tString Name;\n\n\t\t\tCFGNode()\n\t\t\t{\n\t\t\t\theadInstr = new ILInstruction();\n\t\t\t\ttailInstr = new ILInstruction();\n\t\t\t\theadInstr->Parent = this;\n\t\t\t\theadInstr->InsertAfter(tailInstr);\n\t\t\t}\n\t\t\t~CFGNode()\n\t\t\t{\n\t\t\t\tILInstruction * instr = headInstr;\n\t\t\t\twhile (instr)\n\t\t\t\t{\n\t\t\t\t\tfor (auto user : instr->Users)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto userInstr = dynamic_cast<ILInstruction*>(user);\n\t\t\t\t\t\tif (userInstr)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto iter = userInstr->begin(); iter != userInstr->end(); ++iter)\n\t\t\t\t\t\t\tif (iter == instr)\n\t\t\t\t\t\t\t\titer.Set(0);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\tauto next = instr->GetNext();\n\t\t\t\t\tdelete instr;\n\t\t\t\t\tinstr = next;\n\t\t\t\t}\n\t\t\t}\n\t\t\tvoid InsertHead(ILInstruction * instr)\n\t\t\t{\n\t\t\t\theadInstr->InsertAfter(instr);\n\t\t\t}\n\t\t\tvoid InsertTail(ILInstruction * instr)\n\t\t\t{\n\t\t\t\ttailInstr->InsertBefore(instr);\n\t\t\t}\n\t\t\tvoid NameAllInstructions();\n\t\t\tvoid DebugPrint();\n\t\t};\n\n\t\ttemplate<typename T>\n\t\tstruct ConstKey\n\t\t{\n\t\t\tArray<T, 16> Value;\n\t\t\tint Size;\n\t\t\tConstKey()\n\t\t\t{\n\t\t\t\tValue.SetSize(Value.GetCapacity());\n\t\t\t}\n\t\t\tConstKey(T value, int size)\n\t\t\t{\n\t\t\t\tif (size == 0)\n\t\t\t\t\tsize = 1;\n\t\t\t\tValue.SetSize(Value.GetCapacity());\n\t\t\t\tfor (int i = 0; i < size; i++)\n\t\t\t\t\tValue[i] = value;\n\t\t\t\tSize = size;\n\t\t\t}\n\t\t\tstatic ConstKey<T> FromValues(T value, T value1)\n\t\t\t{\n\t\t\t\tConstKey<T> result;\n\t\t\t\tresult.Value.SetSize(result.Value.GetCapacity());\n\t\t\t\tresult.Size = 2;\n\t\t\t\tresult.Value[0] = value;\n\t\t\t\tresult.Value[1] = value1;\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tstatic ConstKey<T> FromValues(T value, T value1, T value2)\n\t\t\t{\n\t\t\t\tConstKey<T> result;\n\t\t\t\tresult.Value.SetSize(result.Value.GetCapacity());\n\t\t\t\tresult.Size = 3;\n\t\t\t\tresult.Value[0] = value;\n\t\t\t\tresult.Value[1] = value1;\n\t\t\t\tresult.Value[2] = value2;\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tstatic ConstKey<T> FromValues(T value, T value1, T value2, T value3)\n\t\t\t{\n\t\t\t\tConstKey<T> result;\n\t\t\t\tresult.Value.SetSize(result.Value.GetCapacity());\n\t\t\t\tresult.Size = 4;\n\t\t\t\tresult.Value[0] = value;\n\t\t\t\tresult.Value[1] = value1;\n\t\t\t\tresult.Value[2] = value2;\n\t\t\t\tresult.Value[3] = value3;\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tint GetHashCode()\n\t\t\t{\n\t\t\t\tint result = Size;\n\t\t\t\tfor (int i = 0; i < Size; i++)\n\t\t\t\t\tresult ^= ((*(int*)&Value) << 5);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tbool operator == (const ConstKey<T> & other)\n\t\t\t{\n\t\t\t\tif (Size != other.Size)\n\t\t\t\t\treturn false;\n\t\t\t\tfor (int i = 0; i < Size; i++)\n\t\t\t\t\tif (Value[i] != other.Value[i])\n\t\t\t\t\t\treturn false;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t};\n\n\n\t\tclass PhiInstruction : public ILInstruction\n\t\t{\n\t\tpublic:\n\t\t\tList<UseReference> Operands; // Use as fixed array, no insert or resize\n\t\tpublic:\n\t\t\tPhiInstruction(int opCount)\n\t\t\t{\n\t\t\t\tOperands.SetSize(opCount);\n\t\t\t\tfor (int i = 0; i < opCount; i++)\n\t\t\t\t\tOperands[i].SetUser(this);\n\t\t\t}\n\t\t\tPhiInstruction(const PhiInstruction & other)\n\t\t\t\t: ILInstruction(other)\n\t\t\t{\n\t\t\t\tOperands.SetSize(other.Operands.Count());\n\t\t\t\tfor (int i = 0; i < Operands.Count(); i++)\n\t\t\t\t{\n\t\t\t\t\tOperands[i].SetUser(this);\n\t\t\t\t\tOperands[i] = other.Operands[i].Ptr();\n\t\t\t\t}\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"phi\";\n\t\t\t}\n\t\t\tvirtual OperandIterator begin() override\n\t\t\t{\n\t\t\t\treturn Operands.begin();\n\t\t\t}\n\t\t\tvirtual OperandIterator end() override\n\t\t\t{\n\t\t\t\treturn Operands.end();\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\tStringBuilder sb;\n\t\t\t\tsb << Name << \" = phi \";\n\t\t\t\tfor (auto & op : Operands)\n\t\t\t\t{\n\t\t\t\t\tif (op)\n\t\t\t\t\t{\n\t\t\t\t\t\tsb << op.ToString();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tsb << \"<?>\";\n\t\t\t\t\tsb << \", \";\n\t\t\t\t}\n\t\t\t\treturn sb.ProduceString();\n\t\t\t}\n\t\t\tvirtual PhiInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new PhiInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass UnaryInstruction : public ILInstruction\n\t\t{\n\t\tpublic:\n\t\t\tUseReference Operand;\n\t\t\tUnaryInstruction()\n\t\t\t\t: Operand(this)\n\t\t\t{}\n\t\t\tUnaryInstruction(const UnaryInstruction & other)\n\t\t\t\t: ILInstruction(other), Operand(this)\n\t\t\t{\n\t\t\t\tOperand = other.Operand.Ptr();\n\t\t\t}\n\t\t\tvirtual OperandIterator begin() override\n\t\t\t{\n\t\t\t\treturn &Operand;\n\t\t\t}\n\t\t\tvirtual OperandIterator end() override\n\t\t\t{\n\t\t\t\treturn &Operand + 1;\n\t\t\t}\n\t\t};\n\n\t\tclass MakeRecordInstruction : public ILInstruction\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ILRecordType> RecordType;\n\t\t\tList<UseReference> Arguments;\n\t\t};\n\n\t\tclass ProjectInstruction : public UnaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tString ComponentName;\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\tStringBuilder sb;\n\t\t\t\tsb << Name << \" = project \";\n\t\t\t\tsb << Operand.ToString();\n\t\t\t\tsb << \", \" << ComponentName;\n\t\t\t\treturn sb.ProduceString();\n\t\t\t}\n\t\t\tvirtual ProjectInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new ProjectInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass ExportInstruction : public UnaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tString ComponentName;\n\t\t\tILWorld * World;\n\n\t\t\tExportInstruction() = default;\n\t\t\tExportInstruction(const ExportInstruction &) = default;\n\n\t\t\tExportInstruction(String compName, ILWorld * srcWorld, ILOperand * value)\n\t\t\t\t: UnaryInstruction()\n\t\t\t{\n\t\t\t\tthis->Operand = value;\n\t\t\t\tthis->ComponentName = compName;\n\t\t\t\tthis->World = srcWorld;\n\t\t\t\tthis->Type = value->Type;\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn \"export [\" + ComponentName + \"], \" + Operand.ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"export [\" + ComponentName + \"]\";\n\t\t\t}\n\t\t\tvirtual ExportInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new ExportInstruction(*this);\n\t\t\t}\n\t\t\tvirtual bool HasSideEffect() override\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass BinaryInstruction : public ILInstruction\n\t\t{\n\t\tpublic:\n\t\t\tArray<UseReference, 2> Operands;\n\t\t\tBinaryInstruction()\n\t\t\t{\n\t\t\t\tOperands.SetSize(2);\n\t\t\t\tOperands[0].SetUser(this);\n\t\t\t\tOperands[1].SetUser(this);\n\t\t\t}\n\t\t\tBinaryInstruction(const BinaryInstruction & other)\n\t\t\t\t: ILInstruction(other)\n\t\t\t{\n\t\t\t\tOperands.SetSize(2);\n\t\t\t\tOperands[0].SetUser(this);\n\t\t\t\tOperands[1].SetUser(this);\n\t\t\t\tOperands[0] = other.Operands[0].Ptr();\n\t\t\t\tOperands[1] = other.Operands[1].Ptr();\n\t\t\t}\n\t\t\tvirtual OperandIterator begin() override\n\t\t\t{\n\t\t\t\treturn Operands.begin();\n\t\t\t}\n\t\t\tvirtual OperandIterator end() override\n\t\t\t{\n\t\t\t\treturn Operands.end();\n\t\t\t}\n\t\t};\n\n\t\tclass SelectInstruction : public ILInstruction\n\t\t{\n\t\tpublic:\n\t\t\tUseReference Operands[3];\n\t\t\tSelectInstruction()\n\t\t\t{\n\t\t\t\tOperands[0].SetUser(this);\n\t\t\t\tOperands[1].SetUser(this);\n\t\t\t\tOperands[2].SetUser(this);\n\t\t\t}\n\t\t\tSelectInstruction(const SelectInstruction & other)\n\t\t\t\t: ILInstruction(other)\n\t\t\t{\n\t\t\t\tOperands[0].SetUser(this);\n\t\t\t\tOperands[1].SetUser(this);\n\t\t\t\tOperands[2].SetUser(this);\n\t\t\t\tOperands[0] = other.Operands[0].Ptr();\n\t\t\t\tOperands[1] = other.Operands[1].Ptr();\n\t\t\t\tOperands[2] = other.Operands[2].Ptr();\n\t\t\t}\n\t\t\tSelectInstruction(ILOperand * mask, ILOperand * val0, ILOperand * val1)\n\t\t\t{\n\t\t\t\tOperands[0].SetUser(this);\n\t\t\t\tOperands[1].SetUser(this);\n\t\t\t\tOperands[2].SetUser(this);\n\t\t\t\tOperands[0] = mask;\n\t\t\t\tOperands[1] = val0;\n\t\t\t\tOperands[2] = val1;\n\t\t\t\tType = val0->Type->Clone();\n\t\t\t}\n\t\t\tvirtual OperandIterator begin() override\n\t\t\t{\n\t\t\t\treturn Operands;\n\t\t\t}\n\t\t\tvirtual OperandIterator end() override\n\t\t\t{\n\t\t\t\treturn Operands + 3;\n\t\t\t}\n\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = select \" + Operands[0].ToString() + \": \" + Operands[1].ToString() + \", \" + Operands[2].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"select\";\n\t\t\t}\n\t\t\tvirtual SelectInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new SelectInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass CallInstruction : public ILInstruction\n\t\t{\n\t\tpublic:\n\t\t\tString Function;\n\t\t\tList<UseReference> Arguments;\n\t\t\tbool SideEffect = false;\n\t\t\tvirtual OperandIterator begin() override\n\t\t\t{\n\t\t\t\treturn Arguments.begin();\n\t\t\t}\n\t\t\tvirtual OperandIterator end() override\n\t\t\t{\n\t\t\t\treturn Arguments.end();\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\tStringBuilder sb(256);\n\t\t\t\tsb << Name;\n\t\t\t\tsb << \" = call \" << Function << \"(\";\n\t\t\t\tfor (auto & op : Arguments)\n\t\t\t\t{\n\t\t\t\t\tsb << op.ToString();\n\t\t\t\t\tif (op != Arguments.Last())\n\t\t\t\t\t\tsb << \", \";\n\t\t\t\t}\n\t\t\t\tsb << \")\";\n\t\t\t\treturn sb.ProduceString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"call \" + Function;\n\t\t\t}\n\t\t\tvirtual bool HasSideEffect() override\n\t\t\t{\n\t\t\t\treturn SideEffect;\n\t\t\t}\n\t\t\tCallInstruction(int argSize)\n\t\t\t{\n\t\t\t\tArguments.SetSize(argSize);\n\t\t\t\tfor (auto & use : Arguments)\n\t\t\t\t\tuse.SetUser(this);\n\t\t\t}\n\t\t\tCallInstruction(const CallInstruction & other)\n\t\t\t\t: ILInstruction(other)\n\t\t\t{\n\t\t\t\tFunction = other.Function;\n\t\t\t\tSideEffect = other.SideEffect;\n\t\t\t\tArguments.SetSize(other.Arguments.Count());\n\t\t\t\tfor (int i = 0; i < other.Arguments.Count(); i++)\n\t\t\t\t{\n\t\t\t\t\tArguments[i].SetUser(this);\n\t\t\t\t\tArguments[i] = other.Arguments[i].Ptr();\n\t\t\t\t}\n\n\t\t\t}\n\t\t\tvirtual CallInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new CallInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass NotInstruction : public UnaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn  Name + \" = not \" + Operand.ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"not\";\n\t\t\t}\n\t\t\tvirtual NotInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new NotInstruction(*this);\n\t\t\t}\n\t\t\tNotInstruction() = default;\n\t\t\tNotInstruction(const NotInstruction & other) = default;\n\n\t\t\tNotInstruction(ILOperand * op)\n\t\t\t{\n\t\t\t\tOperand = op;\n\t\t\t\tType = op->Type->Clone();\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass NegInstruction : public UnaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn  Name + \" = neg \" + Operand.ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"neg\";\n\t\t\t}\n\t\t\tvirtual NegInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new NegInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\n\t\tclass SwizzleInstruction : public UnaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tString SwizzleString;\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn  Name + \" = \" + Operand.ToString() + \".\" + SwizzleString;\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"swizzle\";\n\t\t\t}\n\t\t\tvirtual SwizzleInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new SwizzleInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass BitNotInstruction : public UnaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn  Name + \" = bnot \" + Operand.ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"bnot\";\n\t\t\t}\n\t\t\tvirtual BitNotInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new BitNotInstruction(*this);\n\t\t\t}\n\t\t\tBitNotInstruction() = default;\n\t\t\tBitNotInstruction(const BitNotInstruction & instr) = default;\n\n\t\t\tBitNotInstruction(ILOperand * op)\n\t\t\t{\n\t\t\t\tOperand = op;\n\t\t\t\tType = op->Type->Clone();\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass AddInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tAddInstruction() = default;\n\t\t\tAddInstruction(const AddInstruction & instr) = default;\n\t\t\tAddInstruction(ILOperand * v0, ILOperand * v1)\n\t\t\t{\n\t\t\t\tOperands[0] = v0;\n\t\t\t\tOperands[1] = v1;\n\t\t\t\tType = v0->Type->Clone();\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = add \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"add\";\n\t\t\t}\n\t\t\tvirtual AddInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new AddInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass MemberLoadInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tMemberLoadInstruction() = default;\n\t\t\tMemberLoadInstruction(const MemberLoadInstruction &) = default;\n\t\t\tMemberLoadInstruction(ILOperand * v0, ILOperand * v1)\n\t\t\t{\n\t\t\t\tOperands[0] = v0;\n\t\t\t\tOperands[1] = v1;\n\t\t\t\tif (auto arrType = dynamic_cast<ILArrayType *>(v0->Type.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tType = arrType->BaseType->Clone();\n\t\t\t\t}\n\t\t\t\telse if (auto genType = dynamic_cast<ILGenericType*>(v0->Type.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tType = genType->BaseType->Clone();\n\t\t\t\t}\n\t\t\t\telse if (auto baseType = dynamic_cast<ILBasicType *>(v0->Type.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tswitch (baseType->Type)\n\t\t\t\t\t{\n\t\t\t\t\tcase ILBaseType::Float2:\n\t\t\t\t\tcase ILBaseType::Float3:\n\t\t\t\t\tcase ILBaseType::Float4:\n\t\t\t\t\t\tType = new ILBasicType(ILBaseType::Float);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ILBaseType::Float3x3:\n\t\t\t\t\t\tType = new ILBasicType(ILBaseType::Float3);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ILBaseType::Float4x4:\n\t\t\t\t\t\tType = new ILBasicType(ILBaseType::Float4);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ILBaseType::Int2:\n\t\t\t\t\tcase ILBaseType::Int3:\n\t\t\t\t\tcase ILBaseType::Int4:\n\t\t\t\t\t\tType = new ILBasicType(ILBaseType::Int);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ILBaseType::UInt2:\n\t\t\t\t\tcase ILBaseType::UInt3:\n\t\t\t\t\tcase ILBaseType::UInt4:\n\t\t\t\t\t\tType = new ILBasicType(ILBaseType::UInt);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow InvalidOperationException(\"Unsupported aggregate type.\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (auto structType = dynamic_cast<ILStructType*>(v0->Type.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tauto cv1 = dynamic_cast<ILConstOperand*>(v1);\n\t\t\t\t\tif (!cv1)\n\t\t\t\t\t\tthrow InvalidProgramException(\"member field access offset is not constant.\");\n\t\t\t\t\tif (cv1->IntValues[0] < 0 || cv1->IntValues[0] >= structType->Members.Count())\n\t\t\t\t\t\tthrow InvalidProgramException(\"member field access offset out of bounds.\");\n\t\t\t\t\tType = structType->Members[cv1->IntValues[0]].Type;\n\t\t\t\t}\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = retrieve \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"retrieve\";\n\t\t\t}\n\t\t\tvirtual MemberLoadInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new MemberLoadInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass SubInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = sub \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"sub\";\n\t\t\t}\n\t\t\tvirtual SubInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new SubInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass MulInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tMulInstruction(){}\n\t\t\tMulInstruction(ILOperand * v0, ILOperand * v1)\n\t\t\t{\n\t\t\t\tOperands[0] = v0;\n\t\t\t\tOperands[1] = v1;\n\t\t\t\tType = v0->Type->Clone();\n\t\t\t}\n\t\t\tMulInstruction(const MulInstruction &) = default;\n\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = mul \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"mu\";\n\t\t\t}\n\t\t\tvirtual MulInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new MulInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass DivInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = div \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"div\";\n\t\t\t}\n\t\t\tvirtual DivInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new DivInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\t\tclass ModInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = mod \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"mod\";\n\t\t\t}\n\t\t\tvirtual ModInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new ModInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\t\tclass AndInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = and \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"and\";\n\t\t\t}\n\t\t\tvirtual AndInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new AndInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass OrInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = or \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"or\";\n\t\t\t}\n\t\t\tvirtual OrInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new OrInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass BitAndInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tBitAndInstruction(){}\n\t\t\tBitAndInstruction(ILOperand * v0, ILOperand * v1)\n\t\t\t{\n\t\t\t\tOperands[0] = v0;\n\t\t\t\tOperands[1] = v1;\n\t\t\t\tType = v0->Type->Clone();\n\t\t\t}\n\t\t\tBitAndInstruction(const BitAndInstruction &) = default;\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = band \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"band\";\n\t\t\t}\n\t\t\tvirtual BitAndInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new BitAndInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass BitOrInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = bor \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"bor\";\n\t\t\t}\n\t\t\tvirtual BitOrInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new BitOrInstruction(*this);\n\t\t\t}\n\t\t\tBitOrInstruction(){}\n\t\t\tBitOrInstruction(const BitOrInstruction &) = default;\n\t\t\tBitOrInstruction(ILOperand * v0, ILOperand * v1)\n\t\t\t{\n\t\t\t\tOperands[0] = v0;\n\t\t\t\tOperands[1] = v1;\n\t\t\t\tType = v0->Type->Clone();\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass BitXorInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = bxor \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"bxor\";\n\t\t\t}\n\t\t\tvirtual BitXorInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new BitXorInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass ShlInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = shl \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"sh\";\n\t\t\t}\n\t\t\tvirtual ShlInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new ShlInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\t\tclass ShrInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = shr \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"shr\";\n\t\t\t}\n\t\t\tvirtual ShrInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new ShrInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\t\tclass CompareInstruction : public BinaryInstruction\n\t\t{};\n\t\tclass CmpgtInstruction : public CompareInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = gt \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"gt\";\n\t\t\t}\n\t\t\tvirtual CmpgtInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new CmpgtInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\t\tclass CmpgeInstruction : public CompareInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = ge \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"ge\";\n\t\t\t}\n\t\t\tvirtual CmpgeInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new CmpgeInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\t\tclass CmpltInstruction : public CompareInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = lt \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"lt\";\n\t\t\t}\n\t\t\tvirtual CmpltInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new CmpltInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\t\tclass CmpleInstruction : public CompareInstruction\n\t\t{\n\t\tpublic:\n\t\t\tCmpleInstruction() = default;\n\t\t\tCmpleInstruction(const CmpleInstruction &) = default;\n\t\t\tCmpleInstruction(ILOperand * v0, ILOperand * v1)\n\t\t\t{\n\t\t\t\tOperands[0] = v0;\n\t\t\t\tOperands[1] = v1;\n\t\t\t\tType = v0->Type->Clone();\n\t\t\t}\n\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = le \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"le\";\n\t\t\t}\n\t\t\tvirtual CmpleInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new CmpleInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\t\tclass CmpeqlInstruction : public CompareInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = eql \" + Operands[0].ToString()\n\t\t\t\t\t+ \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"eq\";\n\t\t\t}\n\t\t\tvirtual CmpeqlInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new CmpeqlInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\t\tclass CmpneqInstruction : public CompareInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = neq \" + Operands[0].ToString() + \", \" + Operands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"neq\";\n\t\t\t}\n\t\t\tvirtual CmpneqInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new CmpneqInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass CastInstruction : public UnaryInstruction\n\t\t{};\n\n\t\tclass Float2IntInstruction : public CastInstruction\n\t\t{\n\t\tpublic:\n\t\t\tFloat2IntInstruction(){}\n\t\t\tFloat2IntInstruction(const Float2IntInstruction &) = default;\n\n\t\t\tFloat2IntInstruction(ILOperand * op)\n\t\t\t{\n\t\t\t\tOperand = op;\n\t\t\t\tType = new ILBasicType(ILBaseType::Int);\n\t\t\t}\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = f2i \" + Operand.ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"f2i\";\n\t\t\t}\n\t\t\tvirtual Float2IntInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new Float2IntInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass Int2FloatInstruction : public CastInstruction\n\t\t{\n\t\tpublic:\n\t\t\tInt2FloatInstruction(){}\n\t\t\tInt2FloatInstruction(ILOperand * op)\n\t\t\t{\n\t\t\t\tOperand = op;\n\t\t\t\tType = new ILBasicType(ILBaseType::Float);\n\t\t\t}\n\t\t\tInt2FloatInstruction(const Int2FloatInstruction &) = default;\n\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = i2f \" + Operand.ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"i2f\";\n\t\t\t}\n\t\t\tvirtual Int2FloatInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new Int2FloatInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass CopyInstruction : public UnaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tCopyInstruction(){}\n\t\t\tCopyInstruction(const CopyInstruction &) = default;\n\n\t\t\tCopyInstruction(ILOperand * dest)\n\t\t\t{\n\t\t\t\tOperand = dest;\n\t\t\t\tType = dest->Type->Clone();\n\t\t\t}\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = \" + Operand.ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"copy\";\n\t\t\t}\n\t\t\tvirtual CopyInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new CopyInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\t\t// load(src)\n\t\tclass LoadInstruction : public UnaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tbool Deterministic;\n\t\t\tLoadInstruction()\n\t\t\t{\n\t\t\t\tDeterministic = false;\n\t\t\t}\n\t\t\tLoadInstruction(const LoadInstruction & other)\n\t\t\t\t: UnaryInstruction(other)\n\t\t\t{\n\t\t\t\tDeterministic = other.Deterministic;\n\t\t\t}\n\t\t\tLoadInstruction(ILOperand * dest);\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = load \" + Operand.ToString();\n\t\t\t}\n\t\t\tvirtual bool IsDeterministic() override\n\t\t\t{\n\t\t\t\treturn Deterministic;\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"ld\";\n\t\t\t}\n\t\t\tvirtual LoadInstruction * Clone() override\n\t\t\t{\n\t\t\t\tauto rs = new LoadInstruction(*this);\n\t\t\t\tif (!rs->Type)\n\t\t\t\t\tprintf(\"shit\");\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass DiscardInstruction : public ILInstruction\n\t\t{\n\t\tpublic:\n\t\t\tvirtual bool IsDeterministic() override\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tvirtual bool HasSideEffect() override\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn  \"discard\";\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"discard\";\n\t\t\t}\n\t\t\tvirtual DiscardInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new DiscardInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\t// store(dest, value)\n\t\tclass StoreInstruction : public BinaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tStoreInstruction(){}\n\t\t\tStoreInstruction(const StoreInstruction &) = default;\n\n\t\t\tStoreInstruction(ILOperand * dest, ILOperand * value)\n\t\t\t{\n\t\t\t\tOperands.SetSize(2);\n\t\t\t\tOperands[0] = dest;\n\t\t\t\tOperands[1] = value;\n\t\t\t}\n\t\tpublic:\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn \"store \" + Operands[0].ToString() + \", \" +\n\t\t\t\t\tOperands[1].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"st\";\n\t\t\t}\n\t\t\tvirtual bool HasSideEffect() override\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tvirtual StoreInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new StoreInstruction(*this);\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\t\tclass MemberUpdateInstruction : public ILInstruction\n\t\t{\n\t\tpublic:\n\t\t\tUseReference Operands[3];\n\t\t\tMemberUpdateInstruction()\n\t\t\t{\n\t\t\t\tOperands[0].SetUser(this);\n\t\t\t\tOperands[1].SetUser(this);\n\t\t\t\tOperands[2].SetUser(this);\n\t\t\t}\n\t\t\tMemberUpdateInstruction(const MemberUpdateInstruction & other)\n\t\t\t\t: ILInstruction(other)\n\t\t\t{\n\t\t\t\tOperands[0].SetUser(this);\n\t\t\t\tOperands[1].SetUser(this);\n\t\t\t\tOperands[2].SetUser(this);\n\t\t\t\tOperands[0] = other.Operands[0].Ptr();\n\t\t\t\tOperands[1] = other.Operands[1].Ptr();\n\t\t\t\tOperands[2] = other.Operands[2].Ptr();\n\t\t\t}\n\t\t\tMemberUpdateInstruction(ILOperand * var, ILOperand * offset, ILOperand * value)\n\t\t\t{\n\t\t\t\tOperands[0].SetUser(this);\n\t\t\t\tOperands[1].SetUser(this);\n\t\t\t\tOperands[2].SetUser(this);\n\t\t\t\tOperands[0] = var;\n\t\t\t\tOperands[1] = offset;\n\t\t\t\tOperands[2] = value;\n\t\t\t\tType = var->Type->Clone();\n\t\t\t}\n\t\t\tvirtual OperandIterator begin() override\n\t\t\t{\n\t\t\t\treturn Operands;\n\t\t\t}\n\t\t\tvirtual OperandIterator end() override\n\t\t\t{\n\t\t\t\treturn Operands + 3;\n\t\t\t}\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn Name + \" = update \" + Operands[0].ToString() + \", \" + Operands[1].ToString() + \",\" + Operands[2].ToString();\n\t\t\t}\n\t\t\tvirtual String GetOperatorString() override\n\t\t\t{\n\t\t\t\treturn \"update\";\n\t\t\t}\n\t\t\tvirtual MemberUpdateInstruction * Clone() override\n\t\t\t{\n\t\t\t\treturn new MemberUpdateInstruction(*this);\n\t\t\t}\n\t\t\tvirtual bool HasSideEffect() override\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tvirtual void Accept(InstructionVisitor * visitor) override;\n\t\t};\n\n\n\t\tclass InstructionVisitor : public Object\n\t\t{\n\t\tpublic:\n\t\t\tvirtual void VisitAddInstruction(AddInstruction *){}\n\t\t\tvirtual void VisitSubInstruction(SubInstruction *){}\n\t\t\tvirtual void VisitDivInstruction(DivInstruction *){}\n\t\t\tvirtual void VisitMulInstruction(MulInstruction *){}\n\t\t\tvirtual void VisitModInstruction(ModInstruction *){}\n\t\t\tvirtual void VisitNegInstruction(NegInstruction *){}\n\t\t\tvirtual void VisitAndInstruction(AndInstruction *){}\n\t\t\tvirtual void VisitOrInstruction(OrInstruction *){}\n\t\t\tvirtual void VisitBitAndInstruction(BitAndInstruction *){}\n\t\t\tvirtual void VisitBitOrInstruction(BitOrInstruction *){}\n\t\t\tvirtual void VisitBitXorInstruction(BitXorInstruction *){}\n\t\t\tvirtual void VisitShlInstruction(ShlInstruction *){}\n\t\t\tvirtual void VisitShrInstruction(ShrInstruction *){}\n\t\t\tvirtual void VisitBitNotInstruction(BitNotInstruction *){}\n\t\t\tvirtual void VisitNotInstruction(NotInstruction *){}\n\t\t\tvirtual void VisitCmpeqlInstruction(CmpeqlInstruction *){}\n\t\t\tvirtual void VisitCmpneqInstruction(CmpneqInstruction *){}\n\t\t\tvirtual void VisitCmpltInstruction(CmpltInstruction *){}\n\t\t\tvirtual void VisitCmpleInstruction(CmpleInstruction *){}\n\t\t\tvirtual void VisitCmpgtInstruction(CmpgtInstruction *){}\n\t\t\tvirtual void VisitCmpgeInstruction(CmpgeInstruction *){}\n\n\t\t\tvirtual void VisitLoadInstruction(LoadInstruction *){}\n\t\t\tvirtual void VisitStoreInstruction(StoreInstruction *){}\n\t\t\tvirtual void VisitCopyInstruction(CopyInstruction *){}\n\n\t\t\tvirtual void VisitAllocVarInstruction(AllocVarInstruction *){}\n\t\t\tvirtual void VisitFetchArgInstruction(FetchArgInstruction *){}\n\t\t\tvirtual void VisitCastInstruction(CastInstruction *){}\n\t\t\tvirtual void VisitInt2FloatInstruction(Int2FloatInstruction *){}\n\t\t\tvirtual void VisitFloat2IntInstruction(Float2IntInstruction *){}\n\t\t\tvirtual void VisitMemberLoadInstruction(MemberLoadInstruction *){}\n\t\t\tvirtual void VisitMemberUpdateInstruction(MemberUpdateInstruction *) {}\n\t\t\tvirtual void VisitImportInstruction(ImportInstruction*) {}\n\t\t\tvirtual void VisitExportInstruction(ExportInstruction*) {}\n\t\t\tvirtual void VisitSelectInstruction(SelectInstruction *){}\n\t\t\tvirtual void VisitCallInstruction(CallInstruction *){}\n\t\t\tvirtual void VisitSwitchInstruction(SwitchInstruction *){}\n\t\t\tvirtual void VisitDiscardInstruction(DiscardInstruction *) {}\n\t\t\tvirtual void VisitLoadInputInstruction(LoadInputInstruction *) {}\n\t\t\tvirtual void VisitPhiInstruction(PhiInstruction *){}\n\t\t\tvirtual void VisitSwizzleInstruction(SwizzleInstruction*) {}\n\t\t\tvirtual void VisitProjectInstruction(ProjectInstruction*) {}\n\t\t};\n\n\t\tclass ForInstruction : public ILInstruction\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<CFGNode> InitialCode, ConditionCode, SideEffectCode, BodyCode;\n\t\t\tvirtual int GetSubBlockCount() override\n\t\t\t{\n\t\t\t\tint count = 0;\n\t\t\t\tif (InitialCode)\n\t\t\t\t\tcount++;\n\t\t\t\tif (ConditionCode)\n\t\t\t\t\tcount++;\n\t\t\t\tif (SideEffectCode)\n\t\t\t\t\tcount++;\n\t\t\t\tif (BodyCode)\n\t\t\t\t\tcount++;\n\t\t\t\treturn count;\n\t\t\t}\n\t\t\tvirtual CFGNode * GetSubBlock(int i) override\n\t\t\t{\n\t\t\t\tint id = 0;\n\t\t\t\tif (InitialCode)\n\t\t\t\t{\n\t\t\t\t\tif (id == i) return InitialCode.Ptr();\n\t\t\t\t\tid++;\n\t\t\t\t}\n\t\t\t\tif (ConditionCode)\n\t\t\t\t{\n\t\t\t\t\tif (id == i) return ConditionCode.Ptr();\n\t\t\t\t\tid++;\n\t\t\t\t}\n\t\t\t\tif (SideEffectCode)\n\t\t\t\t{\n\t\t\t\t\tif (id == i) return SideEffectCode.Ptr();\n\t\t\t\t\tid++;\n\t\t\t\t}\n\t\t\t\tif (BodyCode)\n\t\t\t\t{\n\t\t\t\t\tif (id == i) return BodyCode.Ptr();\n\t\t\t\t}\n\t\t\t\treturn nullptr;\n\t\t\t}\n\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\tStringBuilder sb;\n\t\t\t\tsb << \"for (\";\n\t\t\t\tif (InitialCode)\n\t\t\t\t\tsb << InitialCode->ToString();\n\t\t\t\tsb << \"; \";\n\t\t\t\tif (ConditionCode)\n\t\t\t\t\tsb << ConditionCode->ToString();\n\t\t\t\tsb << \"; \";\n\t\t\t\tif (SideEffectCode)\n\t\t\t\t\tsb << SideEffectCode->ToString();\n\t\t\t\tsb << \")\" << EndLine;\n\t\t\t\tsb << \"{\" << EndLine;\n\t\t\t\tsb << BodyCode->ToString() << EndLine;\n\t\t\t\tsb << \"}\" << EndLine;\n\t\t\t\treturn sb.ProduceString();\n\t\t\t}\n\t\t};\n\t\tclass IfInstruction : public UnaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<CFGNode> TrueCode, FalseCode;\n\t\t\tvirtual int GetSubBlockCount() override\n\t\t\t{\n\t\t\t\tif (FalseCode)\n\t\t\t\t\treturn 2;\n\t\t\t\telse\n\t\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tvirtual CFGNode * GetSubBlock(int i) override\n\t\t\t{\n\t\t\t\tif (i == 0)\n\t\t\t\t\treturn TrueCode.Ptr();\n\t\t\t\telse if (i == 1)\n\t\t\t\t\treturn FalseCode.Ptr();\n\t\t\t\treturn nullptr;\n\t\t\t}\n\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\tStringBuilder sb;\n\t\t\t\tsb << \"if (\" << Operand->ToString() << \")\" << EndLine;\n\t\t\t\tsb << \"{\" << EndLine;\n\t\t\t\tsb << TrueCode->ToString() << EndLine;\n\t\t\t\tsb << \"}\" << EndLine;\n\t\t\t\tif (FalseCode)\n\t\t\t\t{\n\t\t\t\t\tsb << \"else\" << EndLine;\n\t\t\t\t\tsb << \"{\" << EndLine;\n\t\t\t\t\tsb << FalseCode->ToString() << EndLine;\n\t\t\t\t\tsb << \"}\" << EndLine;\n\t\t\t\t}\n\t\t\t\treturn sb.ProduceString();\n\t\t\t}\n\t\t};\n\t\tclass WhileInstruction : public ILInstruction\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<CFGNode> ConditionCode, BodyCode;\n\t\t\tvirtual int GetSubBlockCount() override\n\t\t\t{\n\t\t\t\treturn 2;\n\t\t\t}\n\t\t\tvirtual CFGNode * GetSubBlock(int i) override\n\t\t\t{\n\t\t\t\tif (i == 0)\n\t\t\t\t\treturn ConditionCode.Ptr();\n\t\t\t\telse if (i == 1)\n\t\t\t\t\treturn BodyCode.Ptr();\n\t\t\t\treturn nullptr;\n\t\t\t}\n\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\tStringBuilder sb;\n\t\t\t\tsb << \"while (\" << ConditionCode->ToString() << \")\" << EndLine;\n\t\t\t\tsb << \"{\" << EndLine;\n\t\t\t\tsb << BodyCode->ToString();\n\t\t\t\tsb << \"}\" << EndLine;\n\t\t\t\treturn sb.ProduceString();\n\t\t\t}\n\t\t};\n\t\tclass DoInstruction : public ILInstruction\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<CFGNode> ConditionCode, BodyCode;\n\t\t\tvirtual int GetSubBlockCount() override\n\t\t\t{\n\t\t\t\treturn 2;\n\t\t\t}\n\t\t\tvirtual CFGNode * GetSubBlock(int i) override\n\t\t\t{\n\t\t\t\tif (i == 1)\n\t\t\t\t\treturn ConditionCode.Ptr();\n\t\t\t\telse if (i == 0)\n\t\t\t\t\treturn BodyCode.Ptr();\n\t\t\t\treturn nullptr;\n\t\t\t}\n\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\tStringBuilder sb;\n\t\t\t\tsb << \"{\" << EndLine;\n\t\t\t\tsb << BodyCode->ToString();\n\t\t\t\tsb << \"}\" << EndLine;\n\t\t\t\tsb << \"while (\" << ConditionCode->ToString() << \")\" << EndLine;\n\t\t\t\treturn sb.ProduceString();\n\t\t\t}\n\t\t};\n\t\tclass ReturnInstruction : public UnaryInstruction\n\t\t{\n\t\tpublic:\n\t\t\tReturnInstruction(ILOperand * op)\n\t\t\t\t:UnaryInstruction()\n\t\t\t{\n\t\t\t\tOperand = op;\n\t\t\t}\n\n\t\t\tvirtual String ToString() override\n\t\t\t{\n\t\t\t\treturn \"return \" + Operand->ToString() + \";\";\n\t\t\t}\n\t\t};\n\t\tclass BreakInstruction : public ILInstruction\n\t\t{};\n\t\tclass ContinueInstruction : public ILInstruction\n\t\t{};\n\n\t\tclass KeyHoleNode\n\t\t{\n\t\tpublic:\n\t\t\tString NodeType;\n\t\t\tint CaptureId = -1;\n\t\t\tList<RefPtr<KeyHoleNode>> Children;\n\t\t\tbool Match(List<ILOperand*> & matchResult, ILOperand * instr);\n\t\t\tstatic RefPtr<KeyHoleNode> Parse(String format);\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/InsertImplicitImportOperator.cpp",
    "content": "#include \"Closure.h\"\n#include \"VariantIR.h\"\n#include \"StringObject.h\"\n#include \"Naming.h\"\n#include \"GetDependencyVisitor.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tclass InsertImplicitImportOperatorVisitor : public SyntaxVisitor\n\t\t{\n\t\tprivate:\n\t\t\tShaderIR * shaderIR;\n\t\t\tGetDependencyVisitor depVisitor;\n\t\tpublic:\n\t\t\tComponentDefinitionIR * currentCompDef = nullptr;\n\t\t\tEnumerableDictionary<String, RefPtr<ComponentDefinitionIR>> passThroughComponents;\n\t\tpublic:\n\t\t\tInsertImplicitImportOperatorVisitor(ShaderIR * ir, DiagnosticSink* err)\n\t\t\t\t: SyntaxVisitor(err), shaderIR(ir)\n\t\t\t{}\n\n\t\t\tComponentDefinitionIR * MakeComponentAvailableAtWorld(String componentUniqueName, String world)\n\t\t\t{\n\t\t\t\tHashSet<String> visitedComponents;\n\t\t\t\treturn MakeComponentAvailableAtWorldInternal(visitedComponents, componentUniqueName, world);\n\t\t\t}\n\n\t\t\tComponentDefinitionIR * MakeComponentAvailableAtWorldInternal(HashSet<String> & visitedComponents, String componentUniqueName, String world)\n\t\t\t{\n\t\t\t\tRefPtr<ComponentDefinitionIR> refDef;\n\t\t\t\tif (passThroughComponents.TryGetValue(EscapeCodeName(componentUniqueName + \"_\" + world), refDef))\n\t\t\t\t\treturn refDef.Ptr();\n\t\t\t\tif (visitedComponents.Contains(componentUniqueName + \"@\" + world))\n\t\t\t\t{\n\t\t\t\t\tStringBuilder refs;\n\t\t\t\t\tint count = 0;\n\t\t\t\t\tfor (auto & comp : visitedComponents)\n\t\t\t\t\t{\n\t\t\t\t\t\trefs << comp;\n\t\t\t\t\t\tif (count != visitedComponents.Count() - 1)\n\t\t\t\t\t\t\trefs << \", \";\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t}\n\t\t\t\t\tgetSink()->diagnose(currentCompDef->SyntaxNode, Diagnostics::cylicReference, refs.ProduceString());\n\t\t\t\t\treturn nullptr;\n\t\t\t\t}\n\t\t\t\tvisitedComponents.Add(componentUniqueName);\n\t\t\t\tImportPath importPath;\n\t\t\t\tint currentPathLength = 1 << 30;\n\t\t\t\tComponentDefinitionIR * referencedDef = nullptr;\n\t\t\t\tfor (auto & compDef : shaderIR->DefinitionsByComponent[componentUniqueName]())\n\t\t\t\t{\n\t\t\t\t\tif (compDef.Value->World == world || compDef.Value->World == \"<uniform>\")\n\t\t\t\t\t\treturn compDef.Value;\n\t\t\t\t}\n\t\t\t\tfor (auto & compDef : shaderIR->DefinitionsByComponent[componentUniqueName]())\n\t\t\t\t{\n\t\t\t\t\tauto path = shaderIR->SymbolTable->FindImplicitImportOperatorChain(shaderIR->Shader->Pipeline, compDef.Value->World, world, compDef.Value->Type);\n\t\t\t\t\tif (path.Count() && path.First().Nodes.Count() < currentPathLength)\n\t\t\t\t\t{\n\t\t\t\t\t\timportPath = path.First();\n\t\t\t\t\t\tcurrentPathLength = importPath.Nodes.Count();\n\t\t\t\t\t\treferencedDef = compDef.Value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (referencedDef)\n\t\t\t\t{\n\t\t\t\t\tauto & node = importPath.Nodes.Last();\n\t\t\t\t\tRefPtr<ComponentDefinitionIR> thruDef;\n\t\t\t\t\tauto thruDefName = EscapeCodeName(componentUniqueName + \"_\" + node.TargetWorld);\n\t\t\t\t\tif (!passThroughComponents.TryGetValue(thruDefName, thruDef))\n\t\t\t\t\t{\n\t\t\t\t\t\tauto srcDef = MakeComponentAvailableAtWorldInternal(visitedComponents, componentUniqueName, node.ImportOperator->SourceWorld.Content);\n\t\t\t\t\t\tthruDef = new ComponentDefinitionIR();\n\t\t\t\t\t\tthruDef->World = world;\n\t\t\t\t\t\tthruDef->Dependency.Add(srcDef);\n\t\t\t\t\t\tsrcDef->Users.Add(thruDef.Ptr());\n\t\t\t\t\t\tthruDef->OriginalName = referencedDef->OriginalName;\n\t\t\t\t\t\tthruDef->UniqueName = thruDefName;\n\t\t\t\t\t\tthruDef->UniqueKey = referencedDef->UniqueKey + \"@\" + node.TargetWorld;\n\t\t\t\t\t\tthruDef->IsEntryPoint = false;\n\t\t\t\t\t\tthruDef->SyntaxNode = new ComponentSyntaxNode();\n\t\t\t\t\t\tthruDef->SyntaxNode->Type = thruDef->Type = srcDef->SyntaxNode->Type;\n\t\t\t\t\t\tthruDef->SyntaxNode->Rate = new RateSyntaxNode();\n\t\t\t\t\t\tthruDef->SyntaxNode->Rate->Worlds.Add(RateWorld(node.TargetWorld));\n\t\t\t\t\t\tthruDef->SyntaxNode->Name.Content = thruDefName;\n\t\t\t\t\t\tCloneContext cloneCtx;\n\t\t\t\t\t\tthruDef->SyntaxNode->TypeNode = srcDef->SyntaxNode->TypeNode->Clone(cloneCtx);\n\t\t\t\t\t\tauto importExpr = new ImportExpressionSyntaxNode();\n\t\t\t\t\t\timportExpr->Type = thruDef->Type;\n\t\t\t\t\t\timportExpr->ImportOperatorDef = node.ImportOperator->Clone(cloneCtx);\n\t\t\t\t\t\timportExpr->ImportOperatorDef->Scope->Parent = thruDef->SyntaxNode->Scope.Ptr();\n\t\t\t\t\t\timportExpr->ComponentUniqueName = srcDef->UniqueName;\n\t\t\t\t\t\tfor (auto & arg : importExpr->Arguments)\n\t\t\t\t\t\t\targ->Accept(this);\n\t\t\t\t\t\timportExpr->ImportOperatorDef->Body->Accept(this);\n\t\t\t\t\t\tthruDef->SyntaxNode->Expression = importExpr;\n\t\t\t\t\t\tpassThroughComponents[thruDefName] = thruDef;\n\t\t\t\t\t}\n\t\t\t\t\tvisitedComponents.Remove(componentUniqueName + \"@\" + world);\n\t\t\t\t\treturn thruDef.Ptr();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto targetComp = shaderIR->Shader->AllComponents[componentUniqueName]();\n                    getSink()->diagnose(currentCompDef->SyntaxNode, Diagnostics::noApplicableImplicitImportOperator, targetComp.Symbol->Name, world, currentCompDef->OriginalName);\n                    getSink()->diagnose(targetComp.Symbol->Implementations.First()->SyntaxNode, Diagnostics::seeDefinitionOf, targetComp.Symbol->Name);\n\t\t\t\t\treturn currentCompDef;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tRefPtr<ExpressionSyntaxNode> ProcessComponentReference(String componentUniqueName)\n\t\t\t{\n\t\t\t\tauto refDef = MakeComponentAvailableAtWorld(componentUniqueName, currentCompDef->World);\n\t\t\t\tauto refNode = new VarExpressionSyntaxNode();\n\t\t\t\tif (refDef)\n\t\t\t\t{\n\t\t\t\t\trefNode->Variable = refDef->UniqueName;\n\t\t\t\t\trefNode->Type = refDef->Type;\n\t\t\t\t\trefNode->Tags[\"ComponentReference\"] = new StringObject(refDef->UniqueName);\n\t\t\t\t\tcurrentCompDef->Dependency.Add(refDef);\n\t\t\t\t\trefDef->Users.Add(currentCompDef);\n\t\t\t\t}\n\t\t\t\treturn refNode;\n\t\t\t}\n\t\t\tRefPtr<ExpressionSyntaxNode> VisitVarExpression(VarExpressionSyntaxNode * var) override\n\t\t\t{\n\t\t\t\tRefPtr<Object> refCompObj;\n\t\t\t\tif (var->Tags.TryGetValue(\"ComponentReference\", refCompObj))\n\t\t\t\t{\n\t\t\t\t\tauto refComp = refCompObj.As<StringObject>().Ptr();\n\t\t\t\t\treturn ProcessComponentReference(refComp->Content);\n\t\t\t\t}\n\t\t\t\treturn var;\n\t\t\t}\n\n\t\t\tRefPtr<ExpressionSyntaxNode> VisitMemberExpression(MemberExpressionSyntaxNode * member) override\n\t\t\t{\n\t\t\t\tRefPtr<Object> refCompObj;\n\t\t\t\tif (member->Tags.TryGetValue(\"ComponentReference\", refCompObj))\n\t\t\t\t{\n\t\t\t\t\tauto refComp = refCompObj.As<StringObject>().Ptr();\n\t\t\t\t\treturn ProcessComponentReference(refComp->Content);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tmember->BaseExpression = member->BaseExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn member;\n\t\t\t}\n\t\t\tRefPtr<ExpressionSyntaxNode> VisitImportExpression(ImportExpressionSyntaxNode * import) override\n\t\t\t{\n\t\t\t\tauto refDef = MakeComponentAvailableAtWorld(import->ComponentUniqueName, import->ImportOperatorDef->SourceWorld.Content);\n\t\t\t\tif (refDef)\n\t\t\t\t\timport->ComponentUniqueName = refDef->UniqueName;\n\t\t\t\tdepVisitor.Result.Clear();\n\t\t\t\timport->ImportOperatorDef->Accept(&depVisitor);\n\t\t\t\tfor (auto & x : depVisitor.Result)\n\t\t\t\t{\n\t\t\t\t\tProcessComponentReference(x.ReferencedComponent);\n\t\t\t\t}\n\t\t\t\treturn import;\n\t\t\t}\n\t\t};\n\t\tvoid InsertImplicitImportOperators(DiagnosticSink * err, ShaderIR * shader)\n\t\t{\n\t\t\tInsertImplicitImportOperatorVisitor visitor(shader, err);\n\t\t\tfor (auto & comp : shader->Definitions)\n\t\t\t{\n\t\t\t\tfor (auto & dep : comp->Dependency)\n\t\t\t\t\tdep->Users.Remove(comp.Ptr());\n\t\t\t\tcomp->ClearDependency();\n\t\t\t}\n\t\t\tfor (auto & comp : shader->Definitions)\n\t\t\t{\n\t\t\t\tvisitor.currentCompDef = comp.Ptr();\n\t\t\t\tcomp->SyntaxNode->Accept(&visitor);\n\t\t\t}\n\t\t\tfor (auto & comp : visitor.passThroughComponents)\n\t\t\t{\n\t\t\t\tshader->Definitions.Add(comp.Value);\n\t\t\t\tEnumerableDictionary<String, ComponentDefinitionIR*> defs;\n\t\t\t\tdefs[comp.Value->World] = comp.Value.Ptr();\n\t\t\t\tshader->DefinitionsByComponent[comp.Key] = defs;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/KeyHoleMatching.cpp",
    "content": "#include \"IL.h\"\n#include \"../CoreLib/Tokenizer.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tRefPtr<KeyHoleNode> ParseInternal(CoreLib::Text::TokenReader & parser)\n\t\t{\n\t\t\tRefPtr<KeyHoleNode> result = new KeyHoleNode();\n\t\t\tresult->NodeType = parser.ReadWord();\n\t\t\tif (parser.LookAhead(\"<\"))\n\t\t\t{\n\t\t\t\tparser.ReadToken();\n\t\t\t\tresult->CaptureId = parser.ReadInt();\n\t\t\t\tparser.ReadToken();\n\t\t\t}\n\t\t\tif (parser.LookAhead(\"(\"))\n\t\t\t{\n\t\t\t\twhile (!parser.LookAhead(\")\"))\n\t\t\t\t{\n\t\t\t\t\tresult->Children.Add(ParseInternal(parser));\n\t\t\t\t\tif (parser.LookAhead(\",\"))\n\t\t\t\t\t\tparser.ReadToken();\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tparser.Read(\")\");\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tRefPtr<KeyHoleNode> KeyHoleNode::Parse(String format)\n\t\t{\n\t\t\tCoreLib::Text::TokenReader parser(format);\n\t\t\treturn ParseInternal(parser);\n\t\t}\n\n\t\tbool KeyHoleNode::Match(List<ILOperand*> & matchResult, ILOperand * instr)\n\t\t{\n\t\t\tbool matches = false;\n\t\t\tif (NodeType == \"store\")\n\t\t\t\tmatches = dynamic_cast<StoreInstruction*>(instr) != nullptr;\n\t\t\telse if (NodeType == \"op\")\n\t\t\t\tmatches = true;\n\t\t\telse if (NodeType == \"load\")\n\t\t\t\tmatches = dynamic_cast<LoadInstruction*>(instr) != nullptr;\n\t\t\telse if (NodeType == \"add\")\n\t\t\t\tmatches = dynamic_cast<AddInstruction*>(instr) != nullptr;\n\t\t\telse if (NodeType == \"mu\")\n\t\t\t\tmatches = dynamic_cast<MulInstruction*>(instr) != nullptr;\n\t\t\telse if (NodeType == \"sub\")\n\t\t\t\tmatches = dynamic_cast<SubInstruction*>(instr) != nullptr;\n\t\t\telse if (NodeType == \"cal\")\n\t\t\t\tmatches = dynamic_cast<CallInstruction*>(instr) != nullptr;\n\t\t\telse if (NodeType == \"switch\")\n\t\t\t\tmatches = dynamic_cast<SwitchInstruction*>(instr) != nullptr;\n\t\t\tif (matches)\n\t\t\t{\n\t\t\t\tif (Children.Count() > 0)\n\t\t\t\t{\n\t\t\t\t\tILInstruction * cinstr = dynamic_cast<ILInstruction*>(instr);\n\t\t\t\t\tif (cinstr != nullptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tint opId = 0;\n\t\t\t\t\t\tfor (auto & op : *cinstr)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (opId >= Children.Count())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmatches = false;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tmatches = matches && Children[opId]->Match(matchResult, &op);\n\t\t\t\t\t\t\topId++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (opId != Children.Count())\n\t\t\t\t\t\t\tmatches = false;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tmatches = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (matches && CaptureId != -1)\n\t\t\t{\n\t\t\t\tmatchResult.SetSize(Math::Max(matchResult.Count(), CaptureId + 1));\n\t\t\t\tmatchResult[CaptureId] = instr;\n\t\t\t}\n\t\t\treturn matches;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/Lexer.cpp",
    "content": "#include \"Lexer.h\"\n#include \"../CoreLib/Tokenizer.h\"\n\n#include <assert.h>\n\nusing namespace CoreLib::Text;\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n        static Token GetEndOfFileToken()\n        {\n            return Token(TokenType::EndOfFile, \"\", 0, 0, 0, \"\");\n        }\n\n        Token* TokenList::begin() const\n        {\n            assert(mTokens.Count());\n            return &mTokens[0];\n        }\n\n        Token* TokenList::end() const\n        {\n            assert(mTokens.Count());\n            assert(mTokens[mTokens.Count()-1].Type == TokenType::EndOfFile);\n            return &mTokens[mTokens.Count() - 1];\n        }\n\n        TokenSpan::TokenSpan()\n            : mBegin(NULL)\n            , mEnd  (NULL)\n        {}\n\n        TokenReader::TokenReader()\n            : mCursor(NULL)\n            , mEnd   (NULL)\n        {}\n\n\n        Token TokenReader::PeekToken() const\n        {\n            if (!mCursor)\n                return GetEndOfFileToken();\n\n            Token token = *mCursor;\n            if (mCursor == mEnd)\n                token.Type = TokenType::EndOfFile;\n            return token;\n        }\n\n        CoreLib::Text::TokenType TokenReader::PeekTokenType() const\n        {\n            if (mCursor == mEnd)\n                return TokenType::EndOfFile;\n            assert(mCursor);\n            return mCursor->Type;\n        }\n\n        CodePosition TokenReader::PeekLoc() const\n        {\n            if (!mCursor)\n                return CodePosition();\n            assert(mCursor);\n            return mCursor->Position;\n        }\n\n        Token TokenReader::AdvanceToken()\n        {\n            if (!mCursor)\n                return GetEndOfFileToken();\n\n            Token token = *mCursor;\n            if (mCursor == mEnd)\n                token.Type = TokenType::EndOfFile;\n            else\n                mCursor++;\n            return token;\n        }\n\n\n\t\tTokenList Lexer::Parse(const String & fileName, const String & str, DiagnosticSink * sink)\n\t\t{\n            TokenList tokenList;\n\t\t\ttokenList.mTokens = CoreLib::Text::TokenizeText(fileName, str, [&](CoreLib::Text::TokenizeErrorType errType, CoreLib::Text::CodePosition pos)\n\t\t\t{\n\t\t\t\tauto curChar = str[pos.Pos];\n\t\t\t\tswitch (errType)\n\t\t\t\t{\n\t\t\t\tcase CoreLib::Text::TokenizeErrorType::InvalidCharacter:\n\t\t\t\t\tsink->diagnose(pos, Diagnostics::illegalCharacter, String((unsigned char)curChar, 16));\n\t\t\t\t\tbreak;\n\t\t\t\tcase CoreLib::Text::TokenizeErrorType::InvalidEscapeSequence:\n\t\t\t\t\tsink->diagnose(pos, Diagnostics::illegalCharacterLiteral);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t});\n\n            // Add an end-of-file token so that we can reference it in diagnostic messages\n            tokenList.mTokens.Add(Token(TokenType::EndOfFile, \"\", 0, 0, 0, fileName, TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace));\n\n            return tokenList;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/Lexer.h",
    "content": "#ifndef RASTER_RENDERER_LEXER_H\n#define RASTER_RENDERER_LEXER_H\n\n#include \"../CoreLib/Basic.h\"\n#include \"Diagnostics.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tusing namespace CoreLib::Basic;\n\n        struct TokenList\n        {\n            Token* begin() const;\n            Token* end() const;\n\n            List<Token> mTokens;\n        };\n\n        struct TokenSpan\n        {\n            TokenSpan();\n            TokenSpan(\n                TokenList const& tokenList)\n                : mBegin(tokenList.begin())\n                , mEnd  (tokenList.end  ())\n            {}\n\n            Token* begin() const { return mBegin; }\n            Token* end  () const { return mEnd  ; }\n\n            int GetCount() { return (int)(mEnd - mBegin); }\n\n            Token* mBegin;\n            Token* mEnd;\n        };\n\n        struct TokenReader\n        {\n            TokenReader();\n            explicit TokenReader(TokenSpan const& tokens)\n                : mCursor(tokens.begin())\n                , mEnd   (tokens.end  ())\n            {}\n            explicit TokenReader(TokenList const& tokens)\n                : mCursor(tokens.begin())\n                , mEnd   (tokens.end  ())\n            {}\n\n            bool IsAtEnd() const { return mCursor == mEnd; }\n            Token PeekToken() const;\n            CoreLib::Text::TokenType PeekTokenType() const;\n            CodePosition PeekLoc() const;\n\n            Token AdvanceToken();\n\n            int GetCount() { return (int)(mEnd - mCursor); }\n\n            Token* mCursor;\n            Token* mEnd;\n        };\n\n\t\t\n\t\tclass Lexer\n\t\t{\n\t\tpublic:\n\t\t\tTokenList Parse(const String & fileName, const String & str, DiagnosticSink * sink);\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/Naming.cpp",
    "content": "#include \"Naming.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tusing namespace CoreLib;\n\n\t\tCoreLib::String EscapeCodeName(CoreLib::String str)\n\t\t{\n\t\t\tStringBuilder sb;\n\t\t\tbool isUnderScore = false;\n\t\t\tfor (auto ch : str)\n\t\t\t{\n\t\t\t\tif (ch == '_' || !((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')))\n\t\t\t\t{\n\t\t\t\t\tif (isUnderScore)\n\t\t\t\t\t\tsb << \"I_\";\n\t\t\t\t\telse\n\t\t\t\t\t\tsb << \"_\";\n\t\t\t\t\tisUnderScore = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tisUnderScore = false;\n\t\t\t\t\tsb << ch;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (isUnderScore)\n\t\t\t\tsb << \"I\";\n\t\t\treturn sb.ProduceString();\n\t\t}\n\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/Naming.h",
    "content": "#ifndef SPIRE_NAMING_H\n#define SPIRE_NAMING_H\n\n#include \"../CoreLib/Basic.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tCoreLib::String EscapeCodeName(CoreLib::String str);\n\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/NatvisFile.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?> \n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n  <Type Name=\"Spire::Compiler::CFGNode\">\n    <DisplayString>{{CFG Basic Block}}</DisplayString>\n    <Expand>\n      <LinkedListItems>\n        <Size>kvPairs.FCount</Size>\n        <HeadPointer>kvPairs.FHead</HeadPointer>\n        <NextPointer>pNext</NextPointer>\n        <ValueNode>Value</ValueNode>\n      </LinkedListItems>\n    </Expand>\n  </Type>\n</AutoVisualizer>"
  },
  {
    "path": "Source/SpireCore/NewSpirVCodeGen.cpp",
    "content": "#include \"CodeGenBackend.h\"\n#include \"../CoreLib/Tokenizer.h\"\n#include \"IL.h\"\n#include \"Syntax.h\"\n#include <vector>\n#include <fstream>\n#include \"../CoreLib/TextIO.h\"\n#include \"../CoreLib/LibIO.h\"\n\nusing namespace CoreLib::Basic;\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tvoid PrintILShader(ILShader * shader)\n\t\t{\n\t\t\tprintf(\"%S\\n\", shader->Name.ToWString());\n\t\t\tprintf(\"%S\\n\", shader->Position.ToString().ToWString());\n\t\t\tprintf(\"\\n---\\n\\n\");\n\n\t\t\tfor (auto& stage : shader->Stages)\n\t\t\t{\n\t\t\t\tprintf(\"Stage: %S\\n\", stage.Key.ToWString());\n\t\t\t\tauto& stageIL = stage.Value;\n\n\t\t\t\tint maxAttrNameLength = 0;\n\t\t\t\tint maxAttrValueLength = 0;\n\t\t\t\tfor (auto& attr : stageIL->Attributes)\n\t\t\t\t{\n\t\t\t\t\tif (attr.Value.Name.Length() > maxAttrNameLength)\n\t\t\t\t\t\tmaxAttrNameLength = attr.Value.Name.Length();\n\n\t\t\t\t\tif (attr.Value.Value.Length() > maxAttrValueLength)\n\t\t\t\t\t\tmaxAttrValueLength = attr.Value.Value.Length();\n\t\t\t\t}\n\n\t\t\t\tfor (auto& attr : stageIL->Attributes)\n\t\t\t\t{\n\t\t\t\t\tprintf(\"\\t%-*S = %-*S (%S)\\n\",\n\t\t\t\t\t\tmaxAttrNameLength, attr.Value.Name.ToWString(),\n\t\t\t\t\t\tmaxAttrValueLength, attr.Value.Value.ToWString(),\n\t\t\t\t\t\tattr.Value.Position.ToString().ToWString());\n\t\t\t\t}\n\n\t\t\t\tprintf(\"\\n\");\n\t\t\t}\n\n\t\t\tprintf(\"\\n---\\n\\n\");\n\n\t\t\tfor (auto& world : shader->Worlds)\n\t\t\t{\n\t\t\t\tprintf(\"World: %S\\n\", world.Key.ToWString());\n\t\t\t\t//auto& worldIL = world.Value;\n\t\t\t}\n\t\t}\n\n\t\tclass SpirVCodeGen : public CodeGenBackend\n\t\t{\n\t\tpublic:\n\t\t\tvirtual CompiledShaderSource GenerateShader(CompileResult & /*result*/, SymbolTable * /*symbols*/, ILShader * shader, DiagnosticSink * /*err*/) override\n\t\t\t{\n\t\t\t\tPrintILShader(shader);\n\t\t\t\tsystem(\"pause\");\n\t\t\t\treturn CompiledShaderSource();\n\t\t\t}\n\n            LayoutRule GetDefaultLayoutRule() override\n            {\n                return LayoutRule::Std140;\n            }\n\n    };\n\n\t\tCodeGenBackend * CreateSpirVCodeGen()\n\t\t{\n\t\t\treturn new SpirVCodeGen();\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/Parser.cpp",
    "content": "#include \"Parser.h\"\n\n#include <assert.h>\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tconst int MaxExprLevel = 12;\n\n\t\t// TODO: implement two pass parsing for file reference and struct type recognition\n\n\t\tclass Parser\n\t\t{\n        public:\n\t\t\tint anonymousParamCounter = 0;\n\t\t\tRefPtr<Scope> currentScope;\n            TokenReader tokenReader;\n            DiagnosticSink * sink;\n\t\t\tString fileName;\n\t\t\tHashSet<String> typeNames;\n\t\t\tHashSet<String> classNames;\n\t\t\tbool isInImportOperator = false;\n\n            // Is the parser in a \"recovering\" state?\n            // During recovery we don't emit additional errors, until we find\n            // a token that we expected, when we exit recovery.\n            bool isRecovering = false;\n\n\t\t\tvoid FillPosition(SyntaxNode * node)\n\t\t\t{\n\t\t\t\tnode->Position = tokenReader.PeekLoc();\n\t\t\t\tnode->Scope = currentScope;\n\t\t\t}\n\t\t\tvoid PushScope(ContainerDecl* containerDecl)\n\t\t\t{\n\t\t\t\tcurrentScope = new Scope(currentScope, containerDecl);\n\t\t\t}\n\t\t\tvoid PopScope()\n\t\t\t{\n\t\t\t\tcurrentScope = currentScope->Parent;\n\t\t\t}\n\t\t\tParser(TokenSpan const& _tokens, DiagnosticSink * sink, String _fileName)\n\t\t\t\t: tokenReader(_tokens), sink(sink), fileName(_fileName)\n\t\t\t{\n\t\t\t\ttypeNames.Add(\"int\");\n\t\t\t\ttypeNames.Add(\"uint\");\n\t\t\t\ttypeNames.Add(\"bool\");\n\t\t\t\ttypeNames.Add(\"float\");\n\t\t\t\ttypeNames.Add(\"half\");\n\t\t\t\ttypeNames.Add(\"void\");\n\t\t\t\ttypeNames.Add(\"ivec2\");\n\t\t\t\ttypeNames.Add(\"ivec3\");\n\t\t\t\ttypeNames.Add(\"ivec4\");\n\t\t\t\ttypeNames.Add(\"uvec2\");\n\t\t\t\ttypeNames.Add(\"uvec3\");\n\t\t\t\ttypeNames.Add(\"uvec4\");\n\t\t\t\ttypeNames.Add(\"vec2\");\n\t\t\t\ttypeNames.Add(\"vec3\");\n\t\t\t\ttypeNames.Add(\"vec4\");\n\t\t\t\ttypeNames.Add(\"mat3\");\n\t\t\t\ttypeNames.Add(\"mat4\");\n\t\t\t\ttypeNames.Add(\"mat4x4\");\n\t\t\t\ttypeNames.Add(\"mat3x3\");\n\t\t\t\ttypeNames.Add(\"int2\");\n\t\t\t\ttypeNames.Add(\"int3\");\n\t\t\t\ttypeNames.Add(\"int4\");\n\t\t\t\ttypeNames.Add(\"uint2\");\n\t\t\t\ttypeNames.Add(\"uint3\");\n\t\t\t\ttypeNames.Add(\"uint4\");\n\t\t\t\ttypeNames.Add(\"float2\");\n\t\t\t\ttypeNames.Add(\"float3\");\n\t\t\t\ttypeNames.Add(\"float4\");\n\t\t\t\ttypeNames.Add(\"half2\");\n\t\t\t\ttypeNames.Add(\"half3\");\n\t\t\t\ttypeNames.Add(\"half4\");\n\t\t\t\ttypeNames.Add(\"float3x3\");\n\t\t\t\ttypeNames.Add(\"float4x4\");\n\t\t\t\ttypeNames.Add(\"half3x3\");\n\t\t\t\ttypeNames.Add(\"half4x4\");\n\t\t\t\ttypeNames.Add(\"Texture1D\");\n\t\t\t\ttypeNames.Add(\"Texture2D\");\n\t\t\t\ttypeNames.Add(\"Texture2DArray\");\n\t\t\t\ttypeNames.Add(\"Texture2DArrayShadow\");\n\t\t\t\ttypeNames.Add(\"TextureCube\");\n\t\t\t\ttypeNames.Add(\"TextureCubeShadow\");\n\t\t\t\ttypeNames.Add(\"TextureCubeArray\");\n\t\t\t\ttypeNames.Add(\"TextureCubeShadowArray\");\n\t\t\t\ttypeNames.Add(\"TextureCubeArrayShadow\");\n\t\t\t\ttypeNames.Add(\"Texture3D\");\n\t\t\t\ttypeNames.Add(\"texture\");\n\t\t\t\ttypeNames.Add(\"Texture\");\n\t\t\t\ttypeNames.Add(\"sampler\");\n\t\t\t\ttypeNames.Add(\"SamplerState\");\n\t\t\t\ttypeNames.Add(\"SamplerComparisonState\");\n\t\t\t\ttypeNames.Add(\"sampler_state\");\n\t\t\t\ttypeNames.Add(\"Uniform\");\n\t\t\t\ttypeNames.Add(\"StructuredBuffer\");\n\t\t\t\ttypeNames.Add(\"RWStructuredBuffer\");\n\t\t\t\ttypeNames.Add(\"PackedBuffer\");\n\t\t\t\ttypeNames.Add(\"StorageBuffer\");\n\t\t\t\ttypeNames.Add(\"Patch\");\n\t\t\t}\n\t\t\tRefPtr<ProgramSyntaxNode> Parse();\n\n\t\t\tToken ReadToken();\n\t\t\tToken ReadToken(CoreLib::Text::TokenType type);\n\t\t\tToken ReadToken(const char * string);\n\t\t\tbool LookAheadToken(CoreLib::Text::TokenType type, int offset = 0);\n\t\t\tbool LookAheadToken(const char * string, int offset = 0);\n\t\t\tToken ReadTypeKeyword();\n\t\t\tbool IsTypeKeyword();\n\t\t\tRefPtr<ProgramSyntaxNode>\t\t\t\t\tParseProgram();\n\t\t\tRefPtr<ShaderSyntaxNode>\t\t\t\t\tParseShader();\n\t\t\tRefPtr<TemplateShaderSyntaxNode>\t\t\tParseTemplateShader();\n\t\t\tRefPtr<TemplateShaderParameterSyntaxNode>\tParseTemplateShaderParameter();\n\t\t\tRefPtr<InterfaceSyntaxNode>\t\t\t\t\tParseInterface();\n\t\t\tRefPtr<PipelineSyntaxNode>\t\t\t\t\tParsePipeline();\n\t\t\tRefPtr<StageSyntaxNode>\t\t\t\t\t\tParseStage();\n\t\t\tRefPtr<WorldSyntaxNode>\t\t\t\t\t\tParseWorld();\n\t\t\tRefPtr<RateSyntaxNode>\t\t\t\t\t\tParseRate();\n\t\t\tRefPtr<ImportSyntaxNode>\t\t\t\t\tParseImportInner();\n\t\t\tRefPtr<ImportStatementSyntaxNode>\t\t\tParseImportStatement();\n\t\t\tRefPtr<ImportOperatorDefSyntaxNode>\t\t\tParseImportOperator();\n\t\t\tRefPtr<FunctionSyntaxNode>\t\t\t\t\tParseFunction(bool parseBody = true);\n\t\t\tRefPtr<StructSyntaxNode>\t\t\t\t\tParseStruct();\n\t\t\tRefPtr<StatementSyntaxNode>\t\t\t\t\tParseStatement();\n\t\t\tRefPtr<BlockStatementSyntaxNode>\t\t\tParseBlockStatement();\n\t\t\tRefPtr<VarDeclrStatementSyntaxNode>\t\t\tParseVarDeclrStatement();\n\t\t\tRefPtr<IfStatementSyntaxNode>\t\t\t\tParseIfStatement();\n\t\t\tRefPtr<ForStatementSyntaxNode>\t\t\t\tParseForStatement();\n\t\t\tRefPtr<WhileStatementSyntaxNode>\t\t\tParseWhileStatement();\n\t\t\tRefPtr<DoWhileStatementSyntaxNode>\t\t\tParseDoWhileStatement();\n\t\t\tRefPtr<BreakStatementSyntaxNode>\t\t\tParseBreakStatement();\n\t\t\tRefPtr<ContinueStatementSyntaxNode>\t\t\tParseContinueStatement();\n\t\t\tRefPtr<ReturnStatementSyntaxNode>\t\t\tParseReturnStatement();\n\t\t\tRefPtr<ExpressionStatementSyntaxNode>\t\tParseExpressionStatement();\n\t\t\tRefPtr<ExpressionSyntaxNode>\t\t\t\tParseExpression(int level = 0);\n\t\t\tRefPtr<ExpressionSyntaxNode>\t\t\t\tParseLeafExpression();\n\t\t\tRefPtr<ParameterSyntaxNode>\t\t\t\t\tParseParameter();\n\t\t\tRefPtr<TypeSyntaxNode>\t\t\t\t\t\tParseType();\n\n\t\t\tParser & operator = (const Parser &) = delete;\n\t\t};\n\n        static void Unexpected(\n            Parser*     parser)\n        {\n            // Don't emit \"unexpected token\" errors if we are in recovering mode\n            if (!parser->isRecovering)\n            {\n                parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::unexpectedToken,\n                    parser->tokenReader.PeekTokenType());\n\n                // Switch into recovery mode, to suppress additional errors\n                parser->isRecovering = true;\n            }\n        }\n\n        static void Unexpected(\n            Parser*     parser,\n            char const* expected)\n        {\n            // Don't emit \"unexpected token\" errors if we are in recovering mode\n            if (!parser->isRecovering)\n            {\n                parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::unexpectedTokenExpectedTokenName,\n                    parser->tokenReader.PeekTokenType(),\n                    expected);\n\n                // Switch into recovery mode, to suppress additional errors\n                parser->isRecovering = true;\n            }\n        }\n\n        static void Unexpected(\n            Parser*                     parser,\n            CoreLib::Text::TokenType    expected)\n        {\n            // Don't emit \"unexpected token\" errors if we are in recovering mode\n            if (!parser->isRecovering)\n            {\n                parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::unexpectedTokenExpectedTokenType,\n                    parser->tokenReader.PeekTokenType(),\n                    expected);\n\n                // Switch into recovery mode, to suppress additional errors\n                parser->isRecovering = true;\n            }\n        }\n\n        static CoreLib::Text::TokenType SkipToMatchingToken(TokenReader* reader, CoreLib::Text::TokenType tokenType);\n\n        // Skip a singel balanced token, which is either a single token in\n        // the common case, or a matched pair of tokens for `()`, `[]`, and `{}`\n        static CoreLib::Text::TokenType SkipBalancedToken(\n            TokenReader* reader)\n        {\n            CoreLib::Text::TokenType tokenType = reader->AdvanceToken().Type;\n            switch (tokenType)\n            {\n            default:\n                break;\n\n            case TokenType::LParent:    tokenType = SkipToMatchingToken(reader, TokenType::RParent);    break;\n            case TokenType::LBrace:     tokenType = SkipToMatchingToken(reader, TokenType::RBrace);     break;\n            case TokenType::LBracket:   tokenType = SkipToMatchingToken(reader, TokenType::RBracket);   break;\n            }\n            return tokenType;\n        }\n\n        // Skip balanced \n        static CoreLib::Text::TokenType SkipToMatchingToken(\n            TokenReader*                reader,\n            CoreLib::Text::TokenType    tokenType)\n        {\n            for (;;)\n            {\n                if (reader->IsAtEnd()) return TokenType::EndOfFile;\n                if (reader->PeekTokenType() == tokenType)\n                {\n                    reader->AdvanceToken();\n                    return tokenType;\n                }\n                SkipBalancedToken(reader);\n            }\n        }\n\n        // Is the given token type one that is used to \"close\" a\n        // balanced construct.\n        static bool IsClosingToken(CoreLib::Text::TokenType tokenType)\n        {\n            switch (tokenType)\n            {\n            case TokenType::EndOfFile:\n            case TokenType::RBracket:\n            case TokenType::RParent:\n            case TokenType::RBrace:\n                return true;\n\n            default:\n                return false;\n            }\n        }\n\n\n        // Expect an identifier token with the given content, and consume it.\n\t\tToken Parser::ReadToken(const char* expected)\n\t\t{\n            if (tokenReader.PeekTokenType() == TokenType::Identifier\n                    && tokenReader.PeekToken().Content == expected)\n            {\n                isRecovering = false;\n                return tokenReader.AdvanceToken();\n            }\n\n            if (!isRecovering)\n            {\n                Unexpected(this, expected);\n                return tokenReader.PeekToken();\n            }\n            else\n            {\n                // Try to find a place to recover\n                for (;;)\n                {\n                    // The token we expected?\n                    // Then exit recovery mode and pretend like all is well.\n                    if (tokenReader.PeekTokenType() == TokenType::Identifier\n                        && tokenReader.PeekToken().Content == expected)\n                    {\n                        isRecovering = false;\n                        return tokenReader.AdvanceToken();\n                    }\n\n\n                    // Don't skip past any \"closing\" tokens.\n                    if (IsClosingToken(tokenReader.PeekTokenType()))\n                    {\n                        return tokenReader.PeekToken();\n                    }\n\n                    // Skip balanced tokens and try again.\n                    SkipBalancedToken(&tokenReader);\n                }\n            }\n\t\t}\n\n\t\tToken Parser::ReadToken()\n\t\t{\n\t\t\treturn tokenReader.AdvanceToken();\n\t\t}\n\n        static bool TryRecover(\n            Parser*                         parser,\n            CoreLib::Text::TokenType const* recoverBefore,\n            int                             recoverBeforeCount,\n            CoreLib::Text::TokenType const* recoverAfter,\n            int                             recoverAfterCount)\n        {\n            if (!parser->isRecovering)\n                return true;\n\n            // Determine if we are looking for a closing token at all...\n            bool lookingForClose = false;\n            for (int ii = 0; ii < recoverBeforeCount; ++ii)\n            {\n                if (IsClosingToken(recoverBefore[ii]))\n                    lookingForClose = true;\n            }\n            for (int ii = 0; ii < recoverAfterCount; ++ii)\n            {\n                if (IsClosingToken(recoverAfter[ii]))\n                    lookingForClose = true;\n            }\n\n            TokenReader* tokenReader = &parser->tokenReader;\n            for (;;)\n            {\n                CoreLib::Text::TokenType peek = tokenReader->PeekTokenType();\n\n                // Is the next token in our recover-before set?\n                // If so, then we have recovered successfully!\n                for (int ii = 0; ii < recoverBeforeCount; ++ii)\n                {\n                    if (peek == recoverBefore[ii])\n                    {\n                        parser->isRecovering = false;\n                        return true;\n                    }\n                }\n\n                // If we are looking at a token in our recover-after set,\n                // then consume it and recover\n                for (int ii = 0; ii < recoverAfterCount; ++ii)\n                {\n                    if (peek == recoverAfter[ii])\n                    {\n                        tokenReader->AdvanceToken();\n                        parser->isRecovering = false;\n                        return true;\n                    }\n                }\n\n                // Don't try to skip past end of file\n                if (peek == TokenType::EndOfFile)\n                    return false;\n\n                switch (peek)\n                {\n                // Don't skip past simple \"closing\" tokens, *unless*\n                // we are looking for a closing token\n                case TokenType::RParent:\n                case TokenType::RBracket:\n                    if (!lookingForClose)\n                        return false;\n                    break;\n\n                // never skip a `}`, to avoid spurious errors\n                case TokenType::RBrace:\n                    return false;\n                }\n\n                // Skip balanced tokens and try again.\n                CoreLib::Text::TokenType skipped = SkipBalancedToken(tokenReader);\n                \n                // If we happened to find a matched pair of tokens, and\n                // the end of it was a token we were looking for,\n                // then recover here\n                for (int ii = 0; ii < recoverAfterCount; ++ii)\n                {\n                    if (skipped == recoverAfter[ii])\n                    {\n                        parser->isRecovering = false;\n                        return true;\n                    }\n                }\n            }\n        }\n\n        static bool TryRecoverBefore(\n            Parser*                     parser,\n            CoreLib::Text::TokenType    before0)\n        {\n            CoreLib::Text::TokenType recoverBefore[] = { before0 };\n            return TryRecover(parser, recoverBefore, 1, nullptr, 0);\n        }\n\n        // Default recovery strategy, to use inside `{}`-delimeted blocks.\n        static bool TryRecover(\n            Parser*                     parser)\n        {\n            CoreLib::Text::TokenType recoverBefore[] = { TokenType::RBrace };\n            CoreLib::Text::TokenType recoverAfter[] = { TokenType::Semicolon };\n            return TryRecover(parser, recoverBefore, 1, recoverAfter, 1);\n        }\n\n\t\tToken Parser::ReadToken(CoreLib::Text::TokenType expected)\n\t\t{\n            if (tokenReader.PeekTokenType() == expected)\n            {\n                isRecovering = false;\n                return tokenReader.AdvanceToken();\n            }\n\n            if (!isRecovering)\n            {\n                Unexpected(this, expected);\n                return tokenReader.PeekToken();\n            }\n            else\n            {\n                // Try to find a place to recover\n                if (TryRecoverBefore(this, expected))\n                {\n                    isRecovering = false;\n                    return tokenReader.AdvanceToken();\n                }\n\n                return tokenReader.PeekToken();\n            }\n\t\t}\n\n\t\tbool Parser::LookAheadToken(const char * string, int offset)\n\t\t{\n            TokenReader r = tokenReader;\n            for (int ii = 0; ii < offset; ++ii)\n                r.AdvanceToken();\n\n            return r.PeekTokenType() == TokenType::Identifier\n                && r.PeekToken().Content == string;\n\t}\n\n\t\tbool Parser::LookAheadToken(CoreLib::Text::TokenType type, int offset)\n\t\t{\n            TokenReader r = tokenReader;\n            for (int ii = 0; ii < offset; ++ii)\n                r.AdvanceToken();\n\n            return r.PeekTokenType() == type;\n\t\t}\n\n        // Consume a token and return true it if matches, otherwise false\n        bool AdvanceIf(Parser* parser, CoreLib::Text::TokenType tokenType)\n        {\n            if (parser->LookAheadToken(tokenType))\n            {\n                parser->ReadToken();\n                return true;\n            }\n            return false;\n        }\n\n        // Consume a token and return true it if matches, otherwise false\n        bool AdvanceIf(Parser* parser, char const* text)\n        {\n            if (parser->LookAheadToken(text))\n            {\n                parser->ReadToken();\n                return true;\n            }\n            return false;\n        }\n\n        // Consume a token and return true if it matches, otherwise check\n        // for end-of-file and expect that token (potentially producing\n        // an error) and return true to maintain forward progress.\n        // Otherwise return false.\n        bool AdvanceIfMatch(Parser* parser, CoreLib::Text::TokenType tokenType)\n        {\n            // If we've run into a syntax error, but haven't recovered inside\n            // the block, then try to recover here.\n            if (parser->isRecovering)\n            {\n                TryRecoverBefore(parser, tokenType);\n            }\n            if (AdvanceIf(parser, tokenType))\n                return true;\n            if (parser->tokenReader.PeekTokenType() == TokenType::EndOfFile)\n            {\n                parser->ReadToken(tokenType);\n                return true;\n            }\n            return false;\n        }\n\n\t\tToken Parser::ReadTypeKeyword()\n\t\t{\n\t\t\tif(!IsTypeKeyword())\n\t\t\t{\n                if (!isRecovering)\n                {\n    \t\t\t\tsink->diagnose(tokenReader.PeekLoc(), Diagnostics::typeNameExpectedBut, tokenReader.PeekTokenType());\n                }\n                return tokenReader.PeekToken();\n\t\t\t}\n\t\t\treturn tokenReader.AdvanceToken();\n\t\t}\n\n\t\tbool Parser::IsTypeKeyword()\n\t\t{\n\t\t\treturn tokenReader.PeekTokenType() == TokenType::Identifier\n                && typeNames.Contains(tokenReader.PeekToken().Content);\n\t\t}\n\n\t\tRefPtr<ProgramSyntaxNode> Parser::Parse()\n\t\t{\n\t\t\treturn ParseProgram();\n\t\t}\n\n        RefPtr<TypeDefDecl> ParseTypeDef(Parser* parser)\n        {\n            // Consume the `typedef` keyword\n            parser->ReadToken(\"typedef\");\n\n            // TODO(tfoley): parse an actual declarator\n            auto type = parser->ParseType();\n\n            auto nameToken = parser->ReadToken(TokenType::Identifier);\n\n            RefPtr<TypeDefDecl> typeDefDecl = new TypeDefDecl();\n            typeDefDecl->Name = nameToken;\n            typeDefDecl->TypeNode = type;\n\n\t\t\tparser->typeNames.Add(nameToken.Content);\n\n            return typeDefDecl;\n        }\n\n        static Modifiers ParseModifiers(Parser* parser)\n        {\n            Modifiers modifiers;\n            RefPtr<Modifier>* modifierLink = &modifiers.first;\n            for (;;)\n            {\n                if (AdvanceIf(parser, \"in\"))\n                {\n                    modifiers.flags |= ModifierFlag::In;\n                }\n\t\t\t\telse if (AdvanceIf(parser, \"inout\"))\n\t\t\t\t{\n\t\t\t\t\tmodifiers.flags |= ModifierFlag::InOut;\n\t\t\t\t}\n                else if (AdvanceIf(parser, \"input\"))\n                {\n                    modifiers.flags |= ModifierFlag::Input;\n                }\n                else if (AdvanceIf(parser, \"out\"))\n                {\n                    modifiers.flags |= ModifierFlag::Out;\n                }\n                else if (AdvanceIf(parser, \"uniform\"))\n                {\n                    modifiers.flags |= ModifierFlag::Uniform;\n                }\n                else if (AdvanceIf(parser, \"const\"))\n                {\n                    modifiers.flags |= ModifierFlag::Const;\n                }\n                else if (AdvanceIf(parser, \"instance\"))\n                {\n                    modifiers.flags |= ModifierFlag::Instance;\n                }\n                else if (AdvanceIf(parser, \"__builtin\"))\n                {\n                    modifiers.flags |= ModifierFlag::Builtin;\n                }\n                else if (AdvanceIf(parser, \"layout\"))\n\t\t\t\t{\n\t\t\t\t\tparser->ReadToken(TokenType::LParent);\n\t\t\t\t\tStringBuilder layoutSB;\n\t\t\t\t\twhile (!AdvanceIfMatch(parser, TokenType::RParent))\n\t\t\t\t\t{\n\t\t\t\t\t\tlayoutSB.Append(parser->ReadToken(TokenType::Identifier).Content);\n\t\t\t\t\t\tif (parser->LookAheadToken(TokenType::OpAssign))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlayoutSB.Append(parser->ReadToken(TokenType::OpAssign).Content);\n\t\t\t\t\t\t\tlayoutSB.Append(parser->ReadToken(TokenType::IntLiterial).Content);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (AdvanceIf(parser, TokenType::RParent))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tparser->ReadToken(TokenType::Comma);\n\t\t\t\t\t\tlayoutSB.Append(\", \");\n\t\t\t\t\t}\n\n                    RefPtr<LayoutModifier> modifier = new LayoutModifier();\n                    modifier->LayoutString = layoutSB.ProduceString();\n\n                    *modifierLink = modifier;\n                    modifierLink = &modifier->next;\n\t\t\t\t}\n\t\t\t\telse if (AdvanceIf(parser, \"specialize\"))\n\t\t\t\t{\n\t\t\t\t\tRefPtr<SpecializeModifier> modifier = new SpecializeModifier();\n\t\t\t\t\tif (AdvanceIf(parser, TokenType::LParent))\n\t\t\t\t\t{\n\t\t\t\t\t\twhile (!AdvanceIfMatch(parser, TokenType::RParent))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto expr = parser->ParseExpression();\n\t\t\t\t\t\t\tmodifier->Values.Add(expr);\n\t\t\t\t\t\t\tif (AdvanceIf(parser, TokenType::RParent))\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tparser->ReadToken(TokenType::Comma);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t*modifierLink = modifier;\n\t\t\t\t\tmodifierLink = &modifier->next;\n\t\t\t\t}\n                else if (AdvanceIf(parser, \"inline\"))\n\t\t\t\t{\n\t\t\t\t\tmodifiers.flags |= ModifierFlag::Inline;\n\t\t\t\t}\n\t\t\t\telse if (AdvanceIf(parser, \"public\"))\n\t\t\t\t{\n\t\t\t\t\tmodifiers.flags |= ModifierFlag::Public;\n\t\t\t\t}\n\t\t\t\telse if (AdvanceIf(parser, \"require\"))\n\t\t\t\t{\n\t\t\t\t\tmodifiers.flags |= ModifierFlag::Require;\n\t\t\t\t}\n\t\t\t\telse if (AdvanceIf(parser, \"param\"))\n\t\t\t\t{\n\t\t\t\t\tmodifiers.flags |= ModifierFlag::Param;\n\t\t\t\t}\n\t\t\t\telse if (AdvanceIf(parser, \"extern\"))\n\t\t\t\t{\n\t\t\t\t\tmodifiers.flags |= ModifierFlag::Extern;\n\t\t\t\t}\n                else if (AdvanceIf(parser, TokenType::LBracket))\n                {\n                    auto name = parser->ReadToken(TokenType::Identifier).Content;\n                    Token valueToken;\n                    if (AdvanceIf(parser, TokenType::Colon))\n                    {\n                        valueToken = parser->ReadToken(TokenType::StringLiterial);\n                    }\n                    parser->ReadToken(TokenType::RBracket);\n\n                    RefPtr<SimpleAttribute> modifier = new SimpleAttribute();\n                    modifier->Key = name;\n                    modifier->Value = valueToken;\n\n                    *modifierLink = modifier;\n                    modifierLink = &modifier->next;\n                }\n                else if (AdvanceIf(parser, \"__intrinsic\"))\n                {\n                    modifiers.flags |= ModifierFlag::Intrinsic;\n                }\n                else\n                {\n                    // Done with modifier list\n                    return modifiers;\n                }\n            }\n        }\n\n        static RefPtr<Decl> ParseUsing(\n            Parser* parser)\n        {\n            parser->ReadToken(\"using\");\n            if (parser->tokenReader.PeekTokenType() == TokenType::StringLiterial)\n            {\n                auto usingDecl = new UsingFileDecl();\n                usingDecl->fileName = parser->ReadToken(TokenType::StringLiterial);\n                parser->ReadToken(TokenType::Semicolon);\n                return usingDecl;\n            }\n            else\n            {\n                // This is an import decl\n                return parser->ParseImportInner();\n            }\n        }\n\n        static Token ParseDeclName(\n            Parser* parser)\n        {\n            Token name;\n            if (AdvanceIf(parser, \"operator\"))\n\t\t\t{\n\t\t\t\tname = parser->ReadToken();\n\t\t\t\tswitch (name.Type)\n\t\t\t\t{\n\t\t\t\tcase TokenType::OpAdd: case TokenType::OpSub: case TokenType::OpMul: case TokenType::OpDiv:\n\t\t\t\tcase TokenType::OpMod: case TokenType::OpNot: case TokenType::OpBitNot: case TokenType::OpLsh: case TokenType::OpRsh:\n\t\t\t\tcase TokenType::OpEql: case TokenType::OpNeq: case TokenType::OpGreater: case TokenType::OpLess: case TokenType::OpGeq:\n\t\t\t\tcase TokenType::OpLeq: case TokenType::OpAnd: case TokenType::OpOr: case TokenType::OpBitXor: case TokenType::OpBitAnd:\n\t\t\t\tcase TokenType::OpBitOr: case TokenType::OpInc: case TokenType::OpDec:\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tparser->sink->diagnose(name.Position, Diagnostics::invalidOperator, name.Content);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tname = parser->ReadToken(TokenType::Identifier);\n\t\t\t}\n            return name;\n        }\n\n        struct DeclaratorInfo\n        {\n            RefPtr<RateSyntaxNode>  rate;\n            RefPtr<TypeSyntaxNode>  typeSpec;\n            Token                   nameToken;\n        };\n\n        static void ParseFuncDeclHeader(\n            Parser*                     parser,\n            DeclaratorInfo const&       declaratorInfo,\n            RefPtr<FunctionSyntaxNode>  decl)\n        {\n            parser->PushScope(decl.Ptr());\n\n            parser->anonymousParamCounter = 0;\n            parser->FillPosition(decl.Ptr());\n            decl->Position = declaratorInfo.nameToken.Position;\n\n            decl->Name = declaratorInfo.nameToken;\n            decl->ReturnTypeNode = declaratorInfo.typeSpec;\n            parser->ReadToken(TokenType::LParent);\n            while (!AdvanceIfMatch(parser, TokenType::RParent))\n            {\n                decl->Members.Add(parser->ParseParameter());\n                if (AdvanceIf(parser, TokenType::RParent))\n                    break;\n                parser->ReadToken(TokenType::Comma);\n            }\n        }\n\n        static void ParseFuncDeclHeader(\n            Parser*                     parser,\n            DeclaratorInfo const&       declaratorInfo,\n            RefPtr<ComponentSyntaxNode> decl)\n        {\n            parser->PushScope(decl.Ptr());\n\n            parser->anonymousParamCounter = 0;\n            parser->FillPosition(decl.Ptr());\n            decl->Position = declaratorInfo.nameToken.Position;\n\n            decl->Name = declaratorInfo.nameToken;\n            decl->TypeNode = declaratorInfo.typeSpec;\n            parser->ReadToken(TokenType::LParent);\n            while (!AdvanceIfMatch(parser, TokenType::RParent))\n            {\n                decl->Members.Add(parser->ParseParameter());\n                if (AdvanceIf(parser, TokenType::RParent))\n                    break;\n                parser->ReadToken(TokenType::Comma);\n            }\n        }\n\n        static RefPtr<Decl> ParseFuncDecl(\n            Parser*                 parser,\n            ContainerDecl*          containerDecl,\n            DeclaratorInfo const&   declaratorInfo)\n        {\n            if (dynamic_cast<ShaderDeclBase*>(containerDecl))\n            {\n                // inside a shader, we create a component decl\n                RefPtr<ComponentSyntaxNode> decl = new ComponentSyntaxNode();\n                ParseFuncDeclHeader(parser, declaratorInfo, decl);\n\n                //\n                decl->Rate = declaratorInfo.rate;\n                //\n\n                if (AdvanceIf(parser, TokenType::Semicolon))\n                {\n                    // empty body\n                }\n                else\n                {\n                    decl->BlockStatement = parser->ParseBlockStatement();\n                }\n\n                parser->PopScope();\n                return decl;\n            }\n            else\n            {\n                // everywhere else, we create an ordinary `FunctionSyntaxNode`\n\n                RefPtr<FunctionSyntaxNode> decl = new FunctionSyntaxNode();\n                ParseFuncDeclHeader(parser, declaratorInfo, decl);\n\n                if (AdvanceIf(parser, TokenType::Semicolon))\n                {\n                    // empty body\n                }\n                else\n                {\n                    decl->Body = parser->ParseBlockStatement();\n                }\n\n                parser->PopScope();\n                return decl;\n            }\n        }\n\n        static RefPtr<VarDeclBase> CreateVarDeclForContext(\n            ContainerDecl*  containerDecl )\n        {\n            if (dynamic_cast<StructSyntaxNode*>(containerDecl))\n            {\n                return new StructField();\n            }\n            else if (dynamic_cast<FunctionDeclBase*>(containerDecl))\n            {\n                return new ParameterSyntaxNode();\n            }\n            else\n            {\n                return new Variable();\n            }\n        }\n\n        static RefPtr<Decl> ParseVarDecl(\n            Parser*                 parser,\n            ContainerDecl*          containerDecl,\n            DeclaratorInfo const&   declaratorInfo)\n        {\n            if (dynamic_cast<ShaderDeclBase*>(containerDecl))\n            {\n                // inside a shader, we create a component decl\n                RefPtr<ComponentSyntaxNode> decl = new ComponentSyntaxNode();\n                parser->FillPosition(decl.Ptr());\n                decl->Position = declaratorInfo.nameToken.Position;\n\n                //\n                decl->Rate = declaratorInfo.rate;\n                //\n\n                decl->Name = declaratorInfo.nameToken;\n                decl->TypeNode = declaratorInfo.typeSpec;\n\n                // Note(tfoley): this case is the one place where a component\n                // declaration differents in any meaningful way from an\n                // ordinary variable declaration.\n                if (parser->tokenReader.PeekTokenType() == TokenType::LBrace)\n                {\n                    decl->BlockStatement = parser->ParseBlockStatement();\n                }\n                else\n                {\n                    if (AdvanceIf(parser, TokenType::OpAssign))\n                    {\n                        decl->Expression = parser->ParseExpression();\n                    }\n                    // TODO(tfoley): support the block case here\n                    parser->ReadToken(TokenType::Semicolon);\n                }\n\n                return decl;\n            }\n            else\n            {\n                // everywhere else, we create an ordinary `VarDeclBase`\n                RefPtr<VarDeclBase> decl = CreateVarDeclForContext(containerDecl);\n                parser->FillPosition(decl.Ptr());\n                decl->Position = declaratorInfo.nameToken.Position;\n\n                decl->Name = declaratorInfo.nameToken;\n                decl->TypeNode = declaratorInfo.typeSpec;\n\n                if (AdvanceIf(parser, TokenType::OpAssign))\n                {\n                    decl->Expr = parser->ParseExpression();\n                }\n                parser->ReadToken(TokenType::Semicolon);\n\n                return decl;\n            }\n        }\n\n        static RefPtr<Decl> ParseDeclaratorDecl(\n            Parser*         parser,\n            ContainerDecl*  containerDecl)\n        {\n            DeclaratorInfo declaratorInfo;\n\n            // For now we just parse <type-spec> <decl-name>\n            //\n            // TODO(tfoley): Actual C-style declarator-based parsed.\n            //\n            if (parser->tokenReader.PeekTokenType() == TokenType::At)\n            {\n                declaratorInfo.rate = parser->ParseRate();\n            }\n            declaratorInfo.typeSpec = parser->ParseType();\n            declaratorInfo.nameToken = ParseDeclName(parser);\n\n            // TODO(tfoley): handle array-ness here...\n\n            // Look at the token after the name to disambiguate\n            switch (parser->tokenReader.PeekTokenType())\n            {\n            case TokenType::LParent:\n                // It must be a function\n                return ParseFuncDecl(parser, containerDecl, declaratorInfo);\n\n            default:\n                // Assume it is a variable-like declaration\n                return ParseVarDecl(parser, containerDecl, declaratorInfo);\n            }\n        }\n\n        static RefPtr<Decl> ParseDeclWithModifiers(\n            Parser*             parser,\n            ContainerDecl*      containerDecl,\n            Modifiers const&    modifiers )\n        {\n            RefPtr<Decl> decl;\n\n            // TODO: actual dispatch!\n\t\t\tif (parser->LookAheadToken(\"shader\") || parser->LookAheadToken(\"module\"))\n\t\t\t\tdecl = parser->ParseShader();\n\t\t\telse if (parser->LookAheadToken(\"template\"))\n\t\t\t\tdecl = parser->ParseTemplateShader();\n\t\t\telse if (parser->LookAheadToken(\"pipeline\"))\n\t\t\t\tdecl = parser->ParsePipeline();\n\t\t\telse if (parser->LookAheadToken(\"struct\"))\n\t\t\t\tdecl = parser->ParseStruct();\n\t\t\telse if (parser->LookAheadToken(\"typedef\"))\n\t\t\t\tdecl = ParseTypeDef(parser);\n\t\t\telse if (parser->LookAheadToken(\"using\"))\n\t\t\t\tdecl = ParseUsing(parser);\n\t\t\telse if (parser->LookAheadToken(\"world\"))\n\t\t\t\tdecl = parser->ParseWorld();\n\t\t\telse if (parser->LookAheadToken(\"import\"))\n\t\t\t\tdecl = parser->ParseImportOperator();\n\t\t\telse if (parser->LookAheadToken(\"stage\"))\n\t\t\t\tdecl = parser->ParseStage();\n\t\t\telse if (parser->LookAheadToken(\"interface\"))\n\t\t\t\tdecl = parser->ParseInterface();\n            else if (AdvanceIf(parser, TokenType::Semicolon))\n            {\n                // empty declaration\n            }\n            else\n                decl = ParseDeclaratorDecl(parser, containerDecl);\n\n            if (decl)\n            {\n                decl->modifiers = modifiers;\n                if (containerDecl)\n                {\n                    containerDecl->Members.Add(decl);\n                }\n            }\n            return decl;\n        }\n\n        static RefPtr<Decl> ParseDecl(\n            Parser*         parser,\n            ContainerDecl*  containerDecl)\n        {\n            Modifiers modifiers = ParseModifiers(parser);\n            return ParseDeclWithModifiers(parser, containerDecl, modifiers);\n        }\n\n        // Parse a body consisting of declarations\n        static void ParseDeclBody(\n            Parser*         parser,\n            ContainerDecl*  containerDecl,\n            CoreLib::Text::TokenType       closingToken)\n        {\n            while(!AdvanceIfMatch(parser, closingToken))\n            {\n                RefPtr<Decl> decl = ParseDecl(parser, containerDecl);\n                if (decl)\n                {\n                    decl->ParentDecl = containerDecl;\n                    //containerDecl->Members.Add(decl);\n                }\n                TryRecover(parser);\n            }\n        }\n\n\t\tRefPtr<ProgramSyntaxNode> Parser::ParseProgram()\n\t\t{\n\t\t\tRefPtr<ProgramSyntaxNode> program = new ProgramSyntaxNode();\n\t\t\tPushScope(program.Ptr());\n\t\t\tprogram->Position = CodePosition(0, 0, 0, fileName);\n\t\t\tprogram->Scope = currentScope;\n            ParseDeclBody(this, program.Ptr(), TokenType::EndOfFile);\n\t\t\tPopScope();\n\t\t\tassert(!currentScope.Ptr());\n\t\t\tcurrentScope = nullptr;\n\t\t\treturn program;\n\t\t}\n\n\t\tRefPtr<InterfaceSyntaxNode> Parser::ParseInterface()\n\t\t{\n\t\t\tRefPtr<InterfaceSyntaxNode> node = new InterfaceSyntaxNode();\n\t\t\tReadToken(\"interface\");\n\t\t\tPushScope(node.Ptr());\n\t\t\tFillPosition(node.Ptr());\n\t\t\tnode->Name = ReadToken(TokenType::Identifier);\n\t\t\tReadToken(TokenType::LBrace);\n\t\t\tParseDeclBody(this, node.Ptr(), TokenType::RBrace);\n\t\t\tPopScope();\n\t\t\treturn node;\n\t\t}\n\n\t\tRefPtr<ShaderSyntaxNode> Parser::ParseShader()\n\t\t{\n\t\t\tRefPtr<ShaderSyntaxNode> shader = new ShaderSyntaxNode();\n\t\t\tif (AdvanceIf(this, \"module\"))\n\t\t\t{\n\t\t\t\tshader->IsModule = true;\n\t\t\t}\n\t\t\telse\n\t\t\t\tReadToken(\"shader\");\n\t\t\tPushScope(shader.Ptr());\n\t\t\tFillPosition(shader.Ptr());\n\t\t\tshader->Name = ReadToken(TokenType::Identifier);\n\t\t\twhile (LookAheadToken(\"targets\") || LookAheadToken(\"implements\"))\n\t\t\t{\n\t\t\t\tif (AdvanceIf(this, \"targets\"))\n\t\t\t\t{\n\t\t\t\t\tshader->ParentPipelineName = ReadToken(TokenType::Identifier);\n\t\t\t\t}\n\t\t\t\tif (AdvanceIf(this, \"implements\"))\n\t\t\t\t{\n\t\t\t\t\twhile (!LookAheadToken(\"implements\") && !LookAheadToken(\"targets\") && !LookAheadToken(TokenType::LBrace))\n\t\t\t\t\t{\n\t\t\t\t\t\tshader->InterfaceNames.Add(ReadToken(TokenType::Identifier));\n\t\t\t\t\t\tif (!AdvanceIf(this, TokenType::Comma))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tReadToken(TokenType::LBrace);\n            ParseDeclBody(this, shader.Ptr(), TokenType::RBrace);\n\t\t\tPopScope();\n\t\t\treturn shader;\n\t\t}\n\n\t\tRefPtr<TemplateShaderSyntaxNode> Parser::ParseTemplateShader()\n\t\t{\n\t\t\tRefPtr<TemplateShaderSyntaxNode> shader = new TemplateShaderSyntaxNode();\n\t\t\tReadToken(\"template\");\n\t\t\tReadToken(\"shader\");\n\t\t\tPushScope(shader.Ptr());\n\t\t\tFillPosition(shader.Ptr());\n\t\t\tshader->Name = ReadToken(TokenType::Identifier);\n\t\t\tReadToken(TokenType::LParent);\n\t\t\twhile (!AdvanceIf(this, TokenType::RParent))\n\t\t\t{\n\t\t\t\tshader->Parameters.Add(ParseTemplateShaderParameter());\n\t\t\t\tif (!AdvanceIf(this, TokenType::Comma))\n\t\t\t\t{\n\t\t\t\t\tReadToken(TokenType::RParent);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (AdvanceIf(this, \"targets\"))\n\t\t\t\tshader->ParentPipelineName = ReadToken(TokenType::Identifier);\n\t\t\tReadToken(TokenType::LBrace);\n\t\t\tParseDeclBody(this, shader.Ptr(), TokenType::RBrace);\n\t\t\tPopScope();\n\t\t\treturn shader;\n\t\t}\n\n\t\tRefPtr<TemplateShaderParameterSyntaxNode> Parser::ParseTemplateShaderParameter()\n\t\t{\n\t\t\tRefPtr<TemplateShaderParameterSyntaxNode> param = new TemplateShaderParameterSyntaxNode();\n\t\t\tFillPosition(param.Ptr());\n\t\t\tparam->ModuleName = ReadToken(TokenType::Identifier);\n\t\t\tif (AdvanceIf(this, TokenType::Colon))\n\t\t\t\tparam->InterfaceName = ReadToken(TokenType::Identifier);\n\t\t\treturn param;\n\t\t}\n\n\t\tRefPtr<PipelineSyntaxNode> Parser::ParsePipeline()\n\t\t{\n\t\t\tRefPtr<PipelineSyntaxNode> pipeline = new PipelineSyntaxNode();\n\t\t\tReadToken(\"pipeline\");\n\t\t\tPushScope(pipeline.Ptr());\n\t\t\tFillPosition(pipeline.Ptr());\n\t\t\tpipeline->Name = ReadToken(TokenType::Identifier);\n\t\t\tif (AdvanceIf(this, TokenType::Colon))\n\t\t\t{\n\t\t\t\tpipeline->ParentPipelineName = ReadToken(TokenType::Identifier);\n\t\t\t}\n\t\t\tReadToken(TokenType::LBrace);\n            ParseDeclBody(this, pipeline.Ptr(), TokenType::RBrace);\n\t\t\tPopScope();\n\t\t\treturn pipeline;\n\t\t}\n\n\t\tRefPtr<StageSyntaxNode> Parser::ParseStage()\n\t\t{\n\t\t\tRefPtr<StageSyntaxNode> stage = new StageSyntaxNode();\n\t\t\tReadToken(\"stage\");\n\t\t\tstage->Name = ReadToken(TokenType::Identifier);\n\t\t\tFillPosition(stage.Ptr());\n\t\t\tReadToken(TokenType::Colon);\n\t\t\tstage->StageType = ReadToken(TokenType::Identifier);\n\t\t\tReadToken(TokenType::LBrace);\n\t\t\twhile (!AdvanceIfMatch(this, TokenType::RBrace))\n\t\t\t{\n\t\t\t\tauto attribName = ReadToken(TokenType::Identifier);\n\t\t\t\tReadToken(TokenType::Colon);\n\t\t\t\tToken attribValue;\n\t\t\t\tif (LookAheadToken(TokenType::StringLiterial) || LookAheadToken(TokenType::DoubleLiterial) || LookAheadToken(TokenType::IntLiterial))\n\t\t\t\t\tattribValue = ReadToken();\n\t\t\t\telse\n\t\t\t\t\tattribValue = ReadToken(TokenType::Identifier);\n\t\t\t\tstage->Attributes[attribName.Content] = attribValue;\n\t\t\t\tReadToken(TokenType::Semicolon);\n\t\t\t}\n\t\t\treturn stage;\n\t\t}\n\n\t\tRefPtr<WorldSyntaxNode> Parser::ParseWorld()\n\t\t{\n\t\t\tRefPtr<WorldSyntaxNode> world = new WorldSyntaxNode();\n            world->modifiers = ParseModifiers(this);\n\t\t\tReadToken(\"world\");\n\t\t\tFillPosition(world.Ptr());\n\t\t\tworld->Name = ReadToken(TokenType::Identifier);\n\t\t\tReadToken(TokenType::Semicolon);\n\t\t\treturn world;\n\t\t}\n\n\t\tRefPtr<RateSyntaxNode> Parser::ParseRate()\n\t\t{\n\t\t\tRefPtr<RateSyntaxNode> rate = new RateSyntaxNode();\n\t\t\tFillPosition(rate.Ptr());\n\t\t\tReadToken(TokenType::At);\n\t\t\tauto readWorldRate = [this]()\n\t\t\t{\n\t\t\t\tRateWorld rw;\n\t\t\t\trw.World = ReadToken(TokenType::Identifier);\n\t\t\t\tif (AdvanceIf(this, TokenType::OpMul))\n\t\t\t\t{\n\t\t\t\t\trw.Pinned = true;\n\t\t\t\t}\n\t\t\t\treturn rw;\n\t\t\t};\n\t\t\tif (AdvanceIf(this, TokenType::LParent))\n\t\t\t{\n\t\t\t\twhile (!AdvanceIfMatch(this, TokenType::RParent))\n\t\t\t\t{\n\t\t\t\t\tRateWorld rw = readWorldRate();\n\t\t\t\t\trate->Worlds.Add(rw);\n                    if (AdvanceIf(this, TokenType::RParent))\n                        break;\n                    ReadToken(TokenType::Comma);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\trate->Worlds.Add(readWorldRate());\n\t\t\treturn rate;\n\t\t}\n\n\t\tRefPtr<ImportSyntaxNode> Parser::ParseImportInner()\n\t\t{\n\t\t\tRefPtr<ImportSyntaxNode> rs = new ImportSyntaxNode();\n\t\t\trs->IsInplace = !LookAheadToken(TokenType::OpAssign, 1);\n\t\t\tif (!rs->IsInplace)\n\t\t\t{\n\t\t\t\trs->ObjectName = ReadToken(TokenType::Identifier);\n\t\t\t\tReadToken(TokenType::OpAssign);\n\t\t\t}\n\t\t\tFillPosition(rs.Ptr());\n\t\t\trs->ShaderName = ReadToken(TokenType::Identifier);\n\t\t\tif (LookAheadToken(TokenType::Semicolon))\n\t\t\t\tReadToken(TokenType::Semicolon);\n\t\t\telse\n\t\t\t{\n\t\t\t\tReadToken(TokenType::LParent);\n\t\t\t\twhile (!AdvanceIfMatch(this, TokenType::RParent))\n\t\t\t\t{\n\t\t\t\t\tRefPtr<ImportArgumentSyntaxNode> arg = new ImportArgumentSyntaxNode();\n\t\t\t\t\tFillPosition(arg.Ptr());\n\t\t\t\t\tauto expr = ParseExpression();\n\t\t\t\t\tif (LookAheadToken(TokenType::Colon))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (auto varExpr = dynamic_cast<VarExpressionSyntaxNode*>(expr.Ptr()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\targ->ArgumentName.Content = varExpr->Variable;\n\t\t\t\t\t\t\targ->ArgumentName.Position = varExpr->Position;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tsink->diagnose(tokenReader.PeekLoc(), Diagnostics::unexpectedColon);\n\t\t\t\t\t\tReadToken(TokenType::Colon);\n\t\t\t\t\t\targ->Expression = ParseExpression();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\targ->Expression = expr;\n\t\t\t\t\trs->Arguments.Add(arg);\n\t\t\t\t\tif (AdvanceIf(this, TokenType::RParent))\n\t\t\t\t\t\tbreak;\n                    ReadToken(TokenType::Comma);\n\t\t\t\t}\n\t\t\t\tReadToken(TokenType::Semicolon);\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\n\t\tRefPtr<ImportStatementSyntaxNode> Parser::ParseImportStatement()\n\t\t{\n\t\t\tRefPtr<ImportStatementSyntaxNode> rs = new ImportStatementSyntaxNode();\n\t\t\tFillPosition(rs.Ptr());\n            ReadToken(\"import\");\n\t\t\trs->Import = ParseImportInner();\n\t\t\treturn rs;\n\t\t}\n\n\t\tRefPtr<ImportOperatorDefSyntaxNode> Parser::ParseImportOperator()\n\t\t{\n\t\t\tRefPtr<ImportOperatorDefSyntaxNode> op = new ImportOperatorDefSyntaxNode();\n\t\t\tPushScope(op.Ptr());\n\t\t\tFillPosition(op.Ptr());\n\t\t\tReadToken(\"import\");\n\t\t\tReadToken(TokenType::LParent);\n\t\t\top->SourceWorld = ReadToken(TokenType::Identifier);\n\t\t\tReadToken(TokenType::RightArrow);\n\t\t\top->DestWorld = ReadToken(TokenType::Identifier);\n\t\t\tReadToken(TokenType::RParent);\n\t\t\tFillPosition(op.Ptr());\n\t\t\top->Name = ReadToken(TokenType::Identifier);\n\t\t\tif (LookAheadToken(TokenType::OpLess))\n\t\t\t{\n\t\t\t\tReadToken(TokenType::OpLess);\n\t\t\t\top->TypeName = ReadToken(TokenType::Identifier);\n\t\t\t\tReadToken(TokenType::OpGreater);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\top->TypeName.Position = op->Name.Position;\n\t\t\t\top->TypeName.Content = \"TComponentType\";\n\t\t\t}\n\t\t\tReadToken(TokenType::LParent);\n\t\t\twhile (!AdvanceIf(this, TokenType::RParent))\n\t\t\t{\n\t\t\t\top->Members.Add(ParseParameter());\n\t\t\t\tif (AdvanceIf(this, TokenType::RParent))\n\t\t\t\t\tbreak;\n                ReadToken(TokenType::Comma);\n\t\t\t}\n\t\t\twhile (LookAheadToken(\"require\"))\n\t\t\t{\n\t\t\t\tReadToken(\"require\");\n\t\t\t\top->Requirements.Add(ParseFunction(false));\n\t\t\t}\n\t\t\tisInImportOperator = true;\n\t\t\top->Body = ParseBlockStatement();\n\t\t\tisInImportOperator = false;\n\t\t\tPopScope();\n\t\t\treturn op;\n\t\t}\n\n        // TODO(tfoley): this definition is now largely redundant (only\n        // used to parse requirements for import operators)\n\t\tRefPtr<FunctionSyntaxNode> Parser::ParseFunction(bool parseBody)\n\t\t{\n\t\t\tanonymousParamCounter = 0;\n\t\t\tRefPtr<FunctionSyntaxNode> function = new FunctionSyntaxNode();\n            function->modifiers = ParseModifiers(this);\n\t\t\t\n\t\t\tPushScope(function.Ptr());\n\t\t\tfunction->ReturnTypeNode = ParseType();\n\t\t\tFillPosition(function.Ptr());\n\t\t\tToken name;\n\t\t\tif (LookAheadToken(\"operator\"))\n\t\t\t{\n\t\t\t\tReadToken();\n\t\t\t\tname = ReadToken();\n\t\t\t\tswitch (name.Type)\n\t\t\t\t{\n\t\t\t\tcase TokenType::OpAdd: case TokenType::OpSub: case TokenType::OpMul: case TokenType::OpDiv:\n\t\t\t\tcase TokenType::OpMod: case TokenType::OpNot: case TokenType::OpBitNot: case TokenType::OpLsh: case TokenType::OpRsh:\n\t\t\t\tcase TokenType::OpEql: case TokenType::OpNeq: case TokenType::OpGreater: case TokenType::OpLess: case TokenType::OpGeq:\n\t\t\t\tcase TokenType::OpLeq: case TokenType::OpAnd: case TokenType::OpOr: case TokenType::OpBitXor: case TokenType::OpBitAnd:\n\t\t\t\tcase TokenType::OpBitOr: case TokenType::OpInc: case TokenType::OpDec:\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tsink->diagnose(name.Position, Diagnostics::invalidOperator, name.Content);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tname = ReadToken(TokenType::Identifier);\n\t\t\t}\n\t\t\tfunction->Name = name;\n\t\t\tReadToken(TokenType::LParent);\n\t\t\twhile(!AdvanceIfMatch(this, TokenType::RParent))\n\t\t\t{\n\t\t\t\tfunction->Members.Add(ParseParameter());\n\t\t\t\tif (AdvanceIf(this, TokenType::RParent))\n\t\t\t\t\tbreak;\n\t\t\t\tReadToken(TokenType::Comma);\n\t\t\t}\n\t\t\tif (parseBody)\n\t\t\t{\n\t\t\t\tif (!function->IsExtern())\n\t\t\t\t\tfunction->Body = ParseBlockStatement();\n\t\t\t\telse\n\t\t\t\t\tReadToken(TokenType::Semicolon);\n\t\t\t}\n\t\t\tPopScope();\n\t\t\treturn function;\n\t\t}\n\n\t\tRefPtr<StructSyntaxNode> Parser::ParseStruct()\n\t\t{\n\t\t\tRefPtr<StructSyntaxNode> rs = new StructSyntaxNode();\n\t\t\tFillPosition(rs.Ptr());\n\t\t\tReadToken(\"struct\");\n\t\t\trs->Name = ReadToken(TokenType::Identifier);\n\t\t\tif (LookAheadToken(\"__intrinsic\"))\n\t\t\t{\n\t\t\t\tReadToken();\n\t\t\t\trs->IsIntrinsic = true;\n\t\t\t}\n\t\t\ttypeNames.Add(rs->Name.Content);\n\t\t\tReadToken(TokenType::LBrace);\n            ParseDeclBody(this, rs.Ptr(), TokenType::RBrace);\n\t\t\treturn rs;\n\t\t}\n\n\t\tRefPtr<StatementSyntaxNode> Parser::ParseStatement()\n\t\t{\n\t\t\tRefPtr<StatementSyntaxNode> statement;\n\t\t\tif (LookAheadToken(TokenType::LBrace))\n\t\t\t\tstatement = ParseBlockStatement();\n\t\t\telse if (IsTypeKeyword() || LookAheadToken(\"const\"))\n\t\t\t\tstatement = ParseVarDeclrStatement();\n\t\t\telse if (LookAheadToken(\"if\"))\n\t\t\t\tstatement = ParseIfStatement();\n\t\t\telse if (LookAheadToken(\"for\"))\n\t\t\t\tstatement = ParseForStatement();\n\t\t\telse if (LookAheadToken(\"while\"))\n\t\t\t\tstatement = ParseWhileStatement();\n\t\t\telse if (LookAheadToken(\"do\"))\n\t\t\t\tstatement = ParseDoWhileStatement();\n\t\t\telse if (LookAheadToken(\"break\"))\n\t\t\t\tstatement = ParseBreakStatement();\n\t\t\telse if (LookAheadToken(\"continue\"))\n\t\t\t\tstatement = ParseContinueStatement();\n\t\t\telse if (LookAheadToken(\"return\"))\n\t\t\t\tstatement = ParseReturnStatement();\n\t\t\telse if (LookAheadToken(\"using\") || (LookAheadToken(\"public\") && LookAheadToken(\"using\", 1)))\n\t\t\t\tstatement = ParseImportStatement();\n\t\t\telse if (LookAheadToken(\"discard\"))\n\t\t\t{\n\t\t\t\tstatement = new DiscardStatementSyntaxNode();\n\t\t\t\tFillPosition(statement.Ptr());\n\t\t\t\tReadToken(\"discard\");\n\t\t\t\tReadToken(TokenType::Semicolon);\n\t\t\t}\n\t\t\telse if (LookAheadToken(TokenType::Identifier))\n\t\t\t{\n\t\t\t\tToken* startPos = tokenReader.mCursor;\n\t\t\t\tbool isVarDeclr = false;\n\t\t\t\tRefPtr<TypeSyntaxNode> type = ParseType();\n\t\t\t\tif (LookAheadToken(TokenType::Identifier))\n\t\t\t\t{\n\t\t\t\t\ttype = nullptr;\n\t\t\t\t\ttokenReader.mCursor = startPos;\n\t\t\t\t\tstatement = ParseVarDeclrStatement();\n\t\t\t\t\tisVarDeclr = true;\n\t\t\t\t}\n\t\t\t\tif (!isVarDeclr)\n\t\t\t\t{\n                    tokenReader.mCursor = startPos;\n\t\t\t\t\tstatement = ParseExpressionStatement();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (LookAheadToken(TokenType::Semicolon))\n\t\t\t{\n\t\t\t\tstatement = new EmptyStatementSyntaxNode();\n\t\t\t\tFillPosition(statement.Ptr());\n\t\t\t\tReadToken(TokenType::Semicolon);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n                Unexpected(this);\n\t\t\t}\n\t\t\treturn statement;\n\t\t}\n\n\t\tRefPtr<BlockStatementSyntaxNode> Parser::ParseBlockStatement()\n\t\t{\n\t\t\tRefPtr<ScopeDecl> scopeDecl = new ScopeDecl();\n\t\t\tRefPtr<BlockStatementSyntaxNode> blockStatement = new BlockStatementSyntaxNode();\n            blockStatement->scopeDecl = scopeDecl;\n\t\t\tPushScope(scopeDecl.Ptr());\n\t\t\tReadToken(TokenType::LBrace);\n\t\t\tif(!tokenReader.IsAtEnd())\n\t\t\t{\n\t\t\t\tFillPosition(blockStatement.Ptr());\n\t\t\t}\n\t\t\twhile (!AdvanceIfMatch(this, TokenType::RBrace))\n\t\t\t{\n                auto stmt = ParseStatement();\n                if(stmt)\n                {\n    \t\t\t\tblockStatement->Statements.Add(stmt);\n\t\t\t\t}\n                TryRecover(this);\n\t\t\t}\n\t\t\tPopScope();\n\t\t\treturn blockStatement;\n\t\t}\n\n\t\tRefPtr<VarDeclrStatementSyntaxNode> Parser::ParseVarDeclrStatement()\n\t\t{\n\t\t\tRefPtr<VarDeclrStatementSyntaxNode>varDeclrStatement = new VarDeclrStatementSyntaxNode();\n\t\t\n\t\t\tFillPosition(varDeclrStatement.Ptr());\n            auto decl = ParseDecl(this, currentScope->containerDecl);\n            varDeclrStatement->decl = decl;\n\t\t\treturn varDeclrStatement;\n\t\t}\n\n\t\tRefPtr<IfStatementSyntaxNode> Parser::ParseIfStatement()\n\t\t{\n\t\t\tRefPtr<IfStatementSyntaxNode> ifStatement = new IfStatementSyntaxNode();\n\t\t\tFillPosition(ifStatement.Ptr());\n\t\t\tReadToken(\"if\");\n\t\t\tReadToken(TokenType::LParent);\n\t\t\tifStatement->Predicate = ParseExpression();\n\t\t\tReadToken(TokenType::RParent);\n\t\t\tifStatement->PositiveStatement = ParseStatement();\n\t\t\tif (LookAheadToken(\"else\"))\n\t\t\t{\n\t\t\t\tReadToken(\"else\");\n\t\t\t\tifStatement->NegativeStatement = ParseStatement();\n\t\t\t}\n\t\t\treturn ifStatement;\n\t\t}\n\n\t\tRefPtr<ForStatementSyntaxNode> Parser::ParseForStatement()\n\t\t{\n\t\t\tRefPtr<ScopeDecl> scopeDecl = new ScopeDecl();\n\t\t\tRefPtr<ForStatementSyntaxNode> stmt = new ForStatementSyntaxNode();\n            stmt->scopeDecl = scopeDecl;\n\t\t\tPushScope(scopeDecl.Ptr());\n\t\t\tFillPosition(stmt.Ptr());\n\t\t\tReadToken(\"for\");\n\t\t\tReadToken(TokenType::LParent);\n\t\t\tif (IsTypeKeyword())\n\t\t\t{\n                stmt->InitialStatement = ParseVarDeclrStatement();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n                if (!LookAheadToken(TokenType::Semicolon))\n                {\n\t\t\t\t\tstmt->InitialStatement = ParseExpressionStatement();\n                }\n                else\n                {\n\t\t\t        ReadToken(TokenType::Semicolon);\n                }\n\t\t\t}\n\t\t\tif (!LookAheadToken(TokenType::Semicolon))\n\t\t\t\tstmt->PredicateExpression = ParseExpression();\n\t\t\tReadToken(TokenType::Semicolon);\n\t\t\tif (!LookAheadToken(TokenType::RParent))\n\t\t\t\tstmt->SideEffectExpression = ParseExpression();\n\t\t\tReadToken(TokenType::RParent);\n\t\t\tstmt->Statement = ParseStatement();\n\t\t\tPopScope();\n\t\t\treturn stmt;\n\t\t}\n\n\t\tRefPtr<WhileStatementSyntaxNode> Parser::ParseWhileStatement()\n\t\t{\n\t\t\tRefPtr<WhileStatementSyntaxNode> whileStatement = new WhileStatementSyntaxNode();\n\t\t\tFillPosition(whileStatement.Ptr());\n\t\t\tReadToken(\"while\");\n\t\t\tReadToken(TokenType::LParent);\n\t\t\twhileStatement->Predicate = ParseExpression();\n\t\t\tReadToken(TokenType::RParent);\n\t\t\twhileStatement->Statement = ParseStatement();\n\t\t\treturn whileStatement;\n\t\t}\n\n\t\tRefPtr<DoWhileStatementSyntaxNode> Parser::ParseDoWhileStatement()\n\t\t{\n\t\t\tRefPtr<DoWhileStatementSyntaxNode> doWhileStatement = new DoWhileStatementSyntaxNode();\n\t\t\tFillPosition(doWhileStatement.Ptr());\n\t\t\tReadToken(\"do\");\n\t\t\tdoWhileStatement->Statement = ParseStatement();\n\t\t\tReadToken(\"while\");\n\t\t\tReadToken(TokenType::LParent);\n\t\t\tdoWhileStatement->Predicate = ParseExpression();\n\t\t\tReadToken(TokenType::RParent);\n\t\t\tReadToken(TokenType::Semicolon);\n\t\t\treturn doWhileStatement;\n\t\t}\n\n\t\tRefPtr<BreakStatementSyntaxNode> Parser::ParseBreakStatement()\n\t\t{\n\t\t\tRefPtr<BreakStatementSyntaxNode> breakStatement = new BreakStatementSyntaxNode();\n\t\t\tFillPosition(breakStatement.Ptr());\n\t\t\tReadToken(\"break\");\n\t\t\tReadToken(TokenType::Semicolon);\n\t\t\treturn breakStatement;\n\t\t}\n\n\t\tRefPtr<ContinueStatementSyntaxNode>\tParser::ParseContinueStatement()\n\t\t{\n\t\t\tRefPtr<ContinueStatementSyntaxNode> continueStatement = new ContinueStatementSyntaxNode();\n\t\t\tFillPosition(continueStatement.Ptr());\n\t\t\tReadToken(\"continue\");\n\t\t\tReadToken(TokenType::Semicolon);\n\t\t\treturn continueStatement;\n\t\t}\n\n\t\tRefPtr<ReturnStatementSyntaxNode> Parser::ParseReturnStatement()\n\t\t{\n\t\t\tRefPtr<ReturnStatementSyntaxNode> returnStatement = new ReturnStatementSyntaxNode();\n\t\t\tFillPosition(returnStatement.Ptr());\n\t\t\tReadToken(\"return\");\n\t\t\tif (!LookAheadToken(TokenType::Semicolon))\n\t\t\t\treturnStatement->Expression = ParseExpression();\n\t\t\tReadToken(TokenType::Semicolon);\n\t\t\treturn returnStatement;\n\t\t}\n\n\t\tRefPtr<ExpressionStatementSyntaxNode> Parser::ParseExpressionStatement()\n\t\t{\n\t\t\tRefPtr<ExpressionStatementSyntaxNode> statement = new ExpressionStatementSyntaxNode();\n\t\t\t\n\t\t\tFillPosition(statement.Ptr());\n\t\t\tstatement->Expression = ParseExpression();\n\t\t\t\n\t\t\tReadToken(TokenType::Semicolon);\n\t\t\treturn statement;\n\t\t}\n\n\t\tRefPtr<ParameterSyntaxNode> Parser::ParseParameter()\n\t\t{\n\t\t\tRefPtr<ParameterSyntaxNode> parameter = new ParameterSyntaxNode();\n            parameter->modifiers = ParseModifiers(this);\n\t\t\tparameter->TypeNode = ParseType();\n\t\t\tif (LookAheadToken(TokenType::Identifier))\n\t\t\t{\n\t\t\t\tToken name = ReadToken(TokenType::Identifier);\n\t\t\t\tparameter->Name = name;\n\t\t\t}\n\t\t\telse\n\t\t\t\tparameter->Name.Content = \"_anonymousParam\" + String(anonymousParamCounter++);\n\t\t\tFillPosition(parameter.Ptr());\n\t\t\treturn parameter;\n\t\t}\n\n\t\tRefPtr<TypeSyntaxNode> Parser::ParseType()\n\t\t{\n\t\t\tToken typeName;\n\t\t\tif (LookAheadToken(TokenType::Identifier))\n\t\t\t\ttypeName = ReadToken(TokenType::Identifier);\n\t\t\telse\n\t\t\t\ttypeName = ReadTypeKeyword();\n\t\t\tRefPtr<TypeSyntaxNode> rs;\n\t\t\tif (LookAheadToken(TokenType::OpLess))\n\t\t\t{\n\t\t\t\tRefPtr<GenericTypeSyntaxNode> gtype = new GenericTypeSyntaxNode();\n\t\t\t\tgtype->Position = typeName.Position;\n\t\t\t\tgtype->GenericTypeName = typeName.Content;\n\t\t\t\tReadToken(TokenType::OpLess);\n\t\t\t\tgtype->BaseType = ParseType();\n\t\t\t\tReadToken(TokenType::OpGreater);\n\t\t\t\trs = gtype;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tauto basicType = new BasicTypeSyntaxNode();\n\t\t\t\tbasicType->Position = typeName.Position;\n\t\t\t\tbasicType->TypeName = typeName.Content;\n\t\t\t\trs = basicType;\n\t\t\t}\n\t\t\twhile (LookAheadToken(TokenType::LBracket))\n\t\t\t{\n\t\t\t\tRefPtr<ArrayTypeSyntaxNode> arrType = new ArrayTypeSyntaxNode();\n\t\t\t\tarrType->Position = rs->Position;\n\t\t\t\tarrType->BaseType = rs;\n\t\t\t\tReadToken(TokenType::LBracket);\n\t\t\t\tif (LookAheadToken(TokenType::IntLiterial))\n\t\t\t\t\tarrType->ArrayLength = StringToInt(ReadToken(TokenType::IntLiterial).Content);\n\t\t\t\telse\n\t\t\t\t\tarrType->ArrayLength = 0;\n\t\t\t\tReadToken(TokenType::RBracket);\n\t\t\t\trs = arrType;\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\n\t\tenum class Associativity\n\t\t{\n\t\t\tLeft, Right\n\t\t};\n\n\t\tAssociativity GetAssociativityFromLevel(int level)\n\t\t{\n\t\t\tif (level == 0)\n\t\t\t\treturn Associativity::Right;\n\t\t\telse\n\t\t\t\treturn Associativity::Left;\n\t\t}\n\n\t\tint GetOpLevel(CoreLib::Text::TokenType type)\n\t\t{\n\t\t\tswitch(type)\n\t\t\t{\n\t\t\tcase TokenType::OpAssign:\n\t\t\tcase TokenType::OpMulAssign:\n\t\t\tcase TokenType::OpDivAssign:\n\t\t\tcase TokenType::OpAddAssign:\n\t\t\tcase TokenType::OpSubAssign:\n\t\t\tcase TokenType::OpModAssign:\n\t\t\tcase TokenType::OpShlAssign:\n\t\t\tcase TokenType::OpShrAssign:\n\t\t\tcase TokenType::OpOrAssign:\n\t\t\tcase TokenType::OpAndAssign:\n\t\t\tcase TokenType::OpXorAssign:\n\t\t\t\treturn 0;\n\t\t\tcase TokenType::OpOr:\n\t\t\t\treturn 2;\n\t\t\tcase TokenType::OpAnd:\n\t\t\t\treturn 3;\n\t\t\tcase TokenType::OpBitOr:\n\t\t\t\treturn 4;\n\t\t\tcase TokenType::OpBitXor:\n\t\t\t\treturn 5;\n\t\t\tcase TokenType::OpBitAnd:\n\t\t\t\treturn 6;\n\t\t\tcase TokenType::OpEql:\n\t\t\tcase TokenType::OpNeq:\n\t\t\t\treturn 7;\n\t\t\tcase TokenType::OpGeq:\n\t\t\tcase TokenType::OpLeq:\n\t\t\tcase TokenType::OpGreater:\n\t\t\tcase TokenType::OpLess:\n\t\t\t\treturn 8;\n\t\t\tcase TokenType::OpLsh:\n\t\t\tcase TokenType::OpRsh:\n\t\t\t\treturn 9;\n\t\t\tcase TokenType::OpAdd:\n\t\t\tcase TokenType::OpSub:\n\t\t\t\treturn 10;\n\t\t\tcase TokenType::OpMul:\n\t\t\tcase TokenType::OpDiv:\n\t\t\tcase TokenType::OpMod:\n\t\t\t\treturn 11;\n\t\t\tdefault:\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\n\t\tOperator GetOpFromToken(Token & token)\n\t\t{\n\t\t\tswitch(token.Type)\n\t\t\t{\n\t\t\tcase TokenType::OpAssign:\n\t\t\t\treturn Operator::Assign;\n\t\t\tcase TokenType::OpAddAssign:\n\t\t\t\treturn Operator::AddAssign;\n\t\t\tcase TokenType::OpSubAssign:\n\t\t\t\treturn Operator::SubAssign;\n\t\t\tcase TokenType::OpMulAssign:\n\t\t\t\treturn Operator::MulAssign;\n\t\t\tcase TokenType::OpDivAssign:\n\t\t\t\treturn Operator::DivAssign;\n\t\t\tcase TokenType::OpModAssign:\n\t\t\t\treturn Operator::ModAssign;\n\t\t\tcase TokenType::OpShlAssign:\n\t\t\t\treturn Operator::LshAssign;\n\t\t\tcase TokenType::OpShrAssign:\n\t\t\t\treturn Operator::RshAssign;\n\t\t\tcase TokenType::OpOrAssign:\n\t\t\t\treturn Operator::OrAssign;\n\t\t\tcase TokenType::OpAndAssign:\n\t\t\t\treturn Operator::AddAssign;\n\t\t\tcase TokenType::OpXorAssign:\n\t\t\t\treturn Operator::XorAssign;\n\t\t\tcase TokenType::OpOr:\n\t\t\t\treturn Operator::Or;\n\t\t\tcase TokenType::OpAnd:\n\t\t\t\treturn Operator::And;\n\t\t\tcase TokenType::OpBitOr:\n\t\t\t\treturn Operator::BitOr;\n\t\t\tcase TokenType::OpBitXor:\n\t\t\t\treturn Operator::BitXor;\n\t\t\tcase TokenType::OpBitAnd:\n\t\t\t\treturn Operator::BitAnd;\n\t\t\tcase TokenType::OpEql:\n\t\t\t\treturn Operator::Eql;\n\t\t\tcase TokenType::OpNeq:\n\t\t\t\treturn Operator::Neq;\n\t\t\tcase TokenType::OpGeq:\n\t\t\t\treturn Operator::Geq;\n\t\t\tcase TokenType::OpLeq:\n\t\t\t\treturn Operator::Leq;\n\t\t\tcase TokenType::OpGreater:\n\t\t\t\treturn Operator::Greater;\n\t\t\tcase TokenType::OpLess:\n\t\t\t\treturn Operator::Less;\n\t\t\tcase TokenType::OpLsh:\n\t\t\t\treturn Operator::Lsh;\n\t\t\tcase TokenType::OpRsh:\n\t\t\t\treturn Operator::Rsh;\n\t\t\tcase TokenType::OpAdd:\n\t\t\t\treturn Operator::Add;\n\t\t\tcase TokenType::OpSub:\n\t\t\t\treturn Operator::Sub;\n\t\t\tcase TokenType::OpMul:\n\t\t\t\treturn Operator::Mul;\n\t\t\tcase TokenType::OpDiv:\n\t\t\t\treturn Operator::Div;\n\t\t\tcase TokenType::OpMod:\n\t\t\t\treturn Operator::Mod;\n\t\t\tcase TokenType::OpInc:\n\t\t\t\treturn Operator::PostInc;\n\t\t\tcase TokenType::OpDec:\n\t\t\t\treturn Operator::PostDec;\n\t\t\tcase TokenType::OpNot:\n\t\t\t\treturn Operator::Not;\n\t\t\tcase TokenType::OpBitNot:\n\t\t\t\treturn Operator::BitNot;\n\t\t\tdefault:\n\t\t\t\tthrow \"Illegal TokenType.\";\n\t\t\t}\n\t\t}\n\n\t\tRefPtr<ExpressionSyntaxNode> Parser::ParseExpression(int level)\n\t\t{\n\t\t\tif (level == MaxExprLevel)\n\t\t\t\treturn ParseLeafExpression();\n\t\t\tif (level == 1)\n\t\t\t{\n\t\t\t\t// parse select clause\n\t\t\t\tauto condition = ParseExpression(level + 1);\n\t\t\t\tif (LookAheadToken(TokenType::QuestionMark))\n\t\t\t\t{\n\t\t\t\t\tRefPtr<SelectExpressionSyntaxNode> select = new SelectExpressionSyntaxNode();\n\t\t\t\t\tFillPosition(select.Ptr());\n\t\t\t\t\tReadToken(TokenType::QuestionMark);\n\t\t\t\t\tselect->SelectorExpr = condition;\n\t\t\t\t\tselect->Expr0 = ParseExpression(level);\n\t\t\t\t\tReadToken(TokenType::Colon);\n\t\t\t\t\tselect->Expr1 = ParseExpression(level);\n\t\t\t\t\treturn select;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\treturn condition;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (GetAssociativityFromLevel(level) == Associativity::Left)\n\t\t\t\t{\n\t\t\t\t\tauto left = ParseExpression(level + 1);\n\t\t\t\t\twhile (GetOpLevel(tokenReader.PeekTokenType()) == level)\n\t\t\t\t\t{\n\t\t\t\t\t\tRefPtr<BinaryExpressionSyntaxNode> tmp = new BinaryExpressionSyntaxNode();\n\t\t\t\t\t\ttmp->LeftExpression = left;\n\t\t\t\t\t\tFillPosition(tmp.Ptr());\n\t\t\t\t\t\tToken opToken = tokenReader.AdvanceToken();\n\t\t\t\t\t\ttmp->Operator = GetOpFromToken(opToken);\n\t\t\t\t\t\ttmp->RightExpression = ParseExpression(level + 1);\n\t\t\t\t\t\tleft = tmp;\n\t\t\t\t\t}\n\t\t\t\t\treturn left;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto left = ParseExpression(level + 1);\n\t\t\t\t\tif (GetOpLevel(tokenReader.PeekTokenType()) == level)\n\t\t\t\t\t{\n\t\t\t\t\t\tRefPtr<BinaryExpressionSyntaxNode> tmp = new BinaryExpressionSyntaxNode();\n\t\t\t\t\t\ttmp->LeftExpression = left;\n\t\t\t\t\t\tFillPosition(tmp.Ptr());\n\t\t\t\t\t\tToken opToken = tokenReader.AdvanceToken();\n\t\t\t\t\t\ttmp->Operator = GetOpFromToken(opToken);\n\t\t\t\t\t\ttmp->RightExpression = ParseExpression(level);\n\t\t\t\t\t\tleft = tmp;\n\t\t\t\t\t}\n\t\t\t\t\treturn left;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRefPtr<ExpressionSyntaxNode> Parser::ParseLeafExpression()\n\t\t{\n\t\t\tRefPtr<ExpressionSyntaxNode> rs;\n\t\t\tif (LookAheadToken(\"project\"))\n\t\t\t{\n\t\t\t\tRefPtr<ProjectExpressionSyntaxNode> project = new ProjectExpressionSyntaxNode();\n\t\t\t\tFillPosition(project.Ptr());\n\t\t\t\tReadToken(\"project\");\n\t\t\t\tReadToken(TokenType::LParent);\n\t\t\t\tproject->BaseExpression = ParseExpression();\n\t\t\t\tReadToken(TokenType::RParent);\n\t\t\t\treturn project;\n\t\t\t}\n\t\t\tif (LookAheadToken(TokenType::OpInc) ||\n\t\t\t\tLookAheadToken(TokenType::OpDec) ||\n\t\t\t\tLookAheadToken(TokenType::OpNot) ||\n\t\t\t\tLookAheadToken(TokenType::OpBitNot) ||\n\t\t\t\tLookAheadToken(TokenType::OpSub))\n\t\t\t{\n\t\t\t\tRefPtr<UnaryExpressionSyntaxNode> unaryExpr = new UnaryExpressionSyntaxNode();\n\t\t\t\tToken token = tokenReader.AdvanceToken();\n\t\t\t\tFillPosition(unaryExpr.Ptr());\n\t\t\t\tunaryExpr->Operator = GetOpFromToken(token);\n\t\t\t\tif (unaryExpr->Operator == Operator::PostInc)\n\t\t\t\t\tunaryExpr->Operator = Operator::PreInc;\n\t\t\t\telse if (unaryExpr->Operator == Operator::PostDec)\n\t\t\t\t\tunaryExpr->Operator = Operator::PreDec;\n\t\t\t\telse if (unaryExpr->Operator == Operator::Sub)\n\t\t\t\t\tunaryExpr->Operator = Operator::Neg;\n\n\t\t\t\tunaryExpr->Expression = ParseLeafExpression();\n\t\t\t\trs = unaryExpr;\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tif (LookAheadToken(TokenType::LParent))\n\t\t\t{\n\t\t\t\tReadToken(TokenType::LParent);\n\t\t\t\tRefPtr<ExpressionSyntaxNode> expr;\n\t\t\t\tif (IsTypeKeyword() && LookAheadToken(TokenType::RParent, 1))\n\t\t\t\t{\n\t\t\t\t\tRefPtr<TypeCastExpressionSyntaxNode> tcexpr = new TypeCastExpressionSyntaxNode();\n\t\t\t\t\tFillPosition(tcexpr.Ptr());\n\t\t\t\t\ttcexpr->TargetType = ParseType();\n\t\t\t\t\tReadToken(TokenType::RParent);\n\t\t\t\t\ttcexpr->Expression = ParseExpression();\n\t\t\t\t\texpr = tcexpr;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\texpr = ParseExpression();\n\t\t\t\t\tReadToken(TokenType::RParent);\n\t\t\t\t}\n\t\t\t\trs = expr;\n\t\t\t}\n\t\t\telse if (LookAheadToken(TokenType::IntLiterial) ||\n\t\t\t\tLookAheadToken(TokenType::DoubleLiterial))\n\t\t\t{\n\t\t\t\tRefPtr<ConstantExpressionSyntaxNode> constExpr = new ConstantExpressionSyntaxNode();\n\t\t\t\tauto token = tokenReader.AdvanceToken();\n\t\t\t\tFillPosition(constExpr.Ptr());\n\t\t\t\tif (token.Type == TokenType::IntLiterial)\n\t\t\t\t{\n\t\t\t\t\tif (token.Content.EndsWith(\"u\") || token.Content.EndsWith(\"U\"))\n\t\t\t\t\t{\n\t\t\t\t\t\tconstExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::UInt;\n\t\t\t\t\t\tconstExpr->IntValue = StringToUInt(token.Content);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tconstExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Int;\n\t\t\t\t\t\tconstExpr->IntValue = StringToInt(token.Content);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (token.Type == TokenType::DoubleLiterial)\n\t\t\t\t{\n\t\t\t\t\tconstExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Float;\n\t\t\t\t\tconstExpr->FloatValue = (float)StringToDouble(token.Content);\n\t\t\t\t}\n\t\t\t\trs = constExpr;\n\t\t\t}\n\t\t\telse if (LookAheadToken(\"true\") || LookAheadToken(\"false\"))\n\t\t\t{\n\t\t\t\tRefPtr<ConstantExpressionSyntaxNode> constExpr = new ConstantExpressionSyntaxNode();\n\t\t\t\tauto token = tokenReader.AdvanceToken();\n\t\t\t\tFillPosition(constExpr.Ptr());\n\t\t\t\tconstExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Bool;\n\t\t\t\tconstExpr->IntValue = token.Content == \"true\" ? 1 : 0;\n\t\t\t\trs = constExpr;\n\t\t\t}\n\t\t\telse if (LookAheadToken(TokenType::Identifier))\n\t\t\t{\n\t\t\t\tRefPtr<VarExpressionSyntaxNode> varExpr = new VarExpressionSyntaxNode();\n\t\t\t\tFillPosition(varExpr.Ptr());\n\t\t\t\tauto token = ReadToken(TokenType::Identifier);\n\t\t\t\tvarExpr->Variable = token.Content;\n\t\t\t\trs = varExpr;\n\t\t\t}\n\n\t\t\twhile (!tokenReader.IsAtEnd() &&\n\t\t\t\t(LookAheadToken(TokenType::OpInc) ||\n\t\t\t\tLookAheadToken(TokenType::OpDec) ||\n\t\t\t\tLookAheadToken(TokenType::Dot) ||\n\t\t\t\tLookAheadToken(TokenType::LBracket) ||\n\t\t\t\tLookAheadToken(TokenType::LParent)))\n\t\t\t{\n\t\t\t\tif (LookAheadToken(TokenType::OpInc))\n\t\t\t\t{\n\t\t\t\t\tRefPtr<UnaryExpressionSyntaxNode> unaryExpr = new UnaryExpressionSyntaxNode();\n\t\t\t\t\tFillPosition(unaryExpr.Ptr());\n\t\t\t\t\tReadToken(TokenType::OpInc);\n\t\t\t\t\tunaryExpr->Operator = Operator::PostInc;\n\t\t\t\t\tunaryExpr->Expression = rs;\n\t\t\t\t\trs = unaryExpr;\n\t\t\t\t}\n\t\t\t\telse if (LookAheadToken(TokenType::OpDec))\n\t\t\t\t{\n\t\t\t\t\tRefPtr<UnaryExpressionSyntaxNode> unaryExpr = new UnaryExpressionSyntaxNode();\n\t\t\t\t\tFillPosition(unaryExpr.Ptr());\n\t\t\t\t\tReadToken(TokenType::OpDec);\n\t\t\t\t\tunaryExpr->Operator = Operator::PostDec;\n\t\t\t\t\tunaryExpr->Expression = rs;\n\t\t\t\t\trs = unaryExpr;\n\t\t\t\t}\n\t\t\t\telse if (LookAheadToken(TokenType::LBracket))\n\t\t\t\t{\n\t\t\t\t\tRefPtr<IndexExpressionSyntaxNode> indexExpr = new IndexExpressionSyntaxNode();\n\t\t\t\t\tindexExpr->BaseExpression = rs;\n\t\t\t\t\tFillPosition(indexExpr.Ptr());\n\t\t\t\t\tReadToken(TokenType::LBracket);\n\t\t\t\t\tindexExpr->IndexExpression = ParseExpression();\n\t\t\t\t\tReadToken(TokenType::RBracket);\n\t\t\t\t\trs = indexExpr;\n\t\t\t\t}\n\t\t\t\telse if (LookAheadToken(TokenType::LParent))\n\t\t\t\t{\n\t\t\t\t\tRefPtr<InvokeExpressionSyntaxNode> invokeExpr = new InvokeExpressionSyntaxNode();\n\t\t\t\t\tinvokeExpr->FunctionExpr = rs;\n\t\t\t\t\tFillPosition(invokeExpr.Ptr());\n\t\t\t\t\tReadToken(TokenType::LParent);\n\t\t\t\t\twhile (!tokenReader.IsAtEnd())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!LookAheadToken(TokenType::RParent))\n\t\t\t\t\t\t\tinvokeExpr->Arguments.Add(ParseExpression());\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!LookAheadToken(TokenType::Comma))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tReadToken(TokenType::Comma);\n\t\t\t\t\t}\n\t\t\t\t\tReadToken(TokenType::RParent);\n\t\t\t\t\trs = invokeExpr;\n\t\t\t\t}\n\t\t\t\telse if (LookAheadToken(TokenType::Dot))\n\t\t\t\t{\n\t\t\t\t\tRefPtr<MemberExpressionSyntaxNode> memberExpr = new MemberExpressionSyntaxNode();\n\t\t\t\t\tFillPosition(memberExpr.Ptr());\n\t\t\t\t\tmemberExpr->BaseExpression = rs;\n\t\t\t\t\tReadToken(TokenType::Dot); \n\t\t\t\t\tmemberExpr->MemberName = ReadToken(TokenType::Identifier).Content;\n\t\t\t\t\trs = memberExpr;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!rs)\n\t\t\t{\n\t\t\t\tsink->diagnose(tokenReader.PeekLoc(), Diagnostics::syntaxError);\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\n        RefPtr<ProgramSyntaxNode> ParseProgram(\n            TokenSpan const&    tokens,\n            DiagnosticSink*     sink,\n            String const&       fileName)\n        {\n            Parser parser(tokens, sink, fileName);\n            return parser.Parse();\n        }\n\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/Parser.h",
    "content": "#ifndef RASTER_RENDERER_PARSER_H\n#define RASTER_RENDERER_PARSER_H\n\n#include \"Lexer.h\"\n#include \"Syntax.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n        RefPtr<ProgramSyntaxNode> ParseProgram(\n            TokenSpan const&    tokens,\n            DiagnosticSink*     sink,\n            String const&       fileName);\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/Preprocessor.cpp",
    "content": "// Preprocessor.cpp\n#include \"Preprocessor.h\"\n\n#include \"Diagnostics.h\"\n#include \"Lexer.h\"\n\n#include <assert.h>\n\nusing namespace CoreLib;\nusing namespace CoreLib::Text;\n\n\n// This file provides an implementation of a simple C-style preprocessor.\n// It does not aim for 100% compatibility with any particular preprocessor\n// specification, but the goal is to have it accept the most common\n// idioms for using the preprocessor, found in shader code in the wild.\n\n\nnamespace Spire{ namespace Compiler {\n\n// State of a preprocessor conditional, which can change when\n// we encounter directives like `#elif` or `#endif`\nenum class PreprocessorConditionalState\n{\n    Before, // We have not yet seen a branch with a `true` condition.\n    During, // We are inside the branch with a `true` condition.\n    After,  // We have already seen the branch with a `true` condition.\n};\n\n// Represents a preprocessor conditional that we are currently\n// nested inside.\nstruct PreprocessorConditional\n{\n    // The next outer conditional in the current file/stream, or NULL.\n    PreprocessorConditional*        parent;\n\n    // The directive token that started the conditional (an `#if` or `#ifdef`)\n    Token                           ifToken;\n\n    // The `#else` directive token, if one has been seen (otherwise `TokenType::Unknown`)\n    Token                           elseToken;\n\n    // The state of the conditional\n    PreprocessorConditionalState    state;\n};\n\nstruct PreprocessorMacro;\n\nstruct PreprocessorEnvironment\n{\n    // The \"outer\" environment, to be used if lookup in this env fails\n    PreprocessorEnvironment*                parent = NULL;\n\n    // Macros defined in this environment\n    Dictionary<String, PreprocessorMacro*>  macros;\n\n    ~PreprocessorEnvironment();\n};\n\n// Input tokens can either come from source text, or from macro expansion.\n// In general, input streams can be nested, so we have to keep a conceptual\n// stack of input.\n\n// A stream of input tokens to be consumed\nstruct PreprocessorInputStream\n{\n    // The next input stream up the stack, if any.\n    PreprocessorInputStream*        parent;\n\n    // The deepest preprocessor conditional active for this stream.\n    PreprocessorConditional*        conditional;\n\n    // Environment to use when looking up macros\n    PreprocessorEnvironment*        environment;\n\n    // Reader for pre-tokenized input\n    TokenReader                     tokenReader;\n\n    // Destructor is virtual so that we can clean up\n    // after concrete subtypes.\n    virtual ~PreprocessorInputStream() = default;\n};\n\nstruct SourceTextInputStream : PreprocessorInputStream\n{\n    // The pre-tokenized input\n    TokenList           lexedTokens;\n};\n\nstruct MacroExpansion : PreprocessorInputStream\n{\n    // The macro we will expand\n    PreprocessorMacro*  macro;\n};\n\nstruct ObjectLikeMacroExpansion : MacroExpansion\n{\n};\n\nstruct FunctionLikeMacroExpansion : MacroExpansion\n{\n    // Environment for macro arguments\n    PreprocessorEnvironment     argumentEnvironment;\n};\n\n// An enumeration for the diferent types of macros\nenum class PreprocessorMacroFlavor\n{\n    ObjectLike,\n    FunctionArg,\n    FunctionLike,\n};\n\n// In the current design (which we may want to re-consider),\n// a macro is a specialized flavor of input stream, that\n// captures the token list in its expansion, and then\n// can be \"played back.\"\nstruct PreprocessorMacro\n{\n    // The name under which the macro was `#define`d\n    Token                       nameToken;\n\n    // Parameters of the macro, in case of a function-like macro\n    List<Token>                 params;\n\n    // The tokens that make up the macro body\n    TokenList                   tokens;\n\n    // The flavor of macro\n    PreprocessorMacroFlavor     flavor;\n\n    // The environment in which this macro needs to be expanded.\n    // For ordinary macros this will be the global environment,\n    // while for function-like macro arguments, it will be\n    // the environment of the macro invocation.\n    PreprocessorEnvironment*    environment;\n};\n\n// State of the preprocessor\nstruct Preprocessor\n{\n    // diagnostics sink to use when writing messages\n    DiagnosticSink*                         sink;\n\n    // An external callback interface to use when looking\n    // for files in a `#include` directive\n    IncludeHandler*                         includeHandler;\n\n    // Current input stream (top of the stack of input)\n    PreprocessorInputStream*                inputStream;\n\n    // Currently-defined macros\n    PreprocessorEnvironment                 globalEnv;\n\n    // A pre-allocated token that can be returned to\n    // represent end-of-input situations.\n    Token                                   endOfFileToken;\n};\n\n// Convenience routine to access the diagnostic sink\nstatic DiagnosticSink* GetSink(Preprocessor* preprocessor)\n{\n    return preprocessor->sink;\n}\n\n//\n// Forward declarations\n//\n\nstatic void DestroyConditional(PreprocessorConditional* conditional);\nstatic void DestroyMacro(Preprocessor* preprocessor, PreprocessorMacro* macro);\n\n//\n// Basic Input Handling\n//\n\n// Create a fresh input stream\nstatic void  InitializeInputStream(Preprocessor* preprocessor, PreprocessorInputStream* inputStream)\n{\n    inputStream->parent = NULL;\n    inputStream->conditional = NULL;\n    inputStream->environment = &preprocessor->globalEnv;\n}\n\n// Destroy an input stream\nstatic void DestroyInputStream(Preprocessor* /*preprocessor*/, PreprocessorInputStream* inputStream)\n{\n    delete inputStream;\n}\n\n// Create an input stream to represent a pre-tokenized input file.\n// TODO(tfoley): pre-tokenizing files isn't going to work in the long run.\nstatic PreprocessorInputStream* CreateInputStreamForSource(Preprocessor* preprocessor, CoreLib::String const& source, CoreLib::String const& fileName)\n{\n    SourceTextInputStream* inputStream = new SourceTextInputStream();\n    InitializeInputStream(preprocessor, inputStream);\n\n    // Use existing `Lexer` to generate a token stream.\n    Lexer lexer;\n    inputStream->lexedTokens = lexer.Parse(fileName, source, GetSink(preprocessor));\n    inputStream->tokenReader = TokenReader(inputStream->lexedTokens);\n\n    return inputStream;\n}\n\n\n\nstatic void PushInputStream(Preprocessor* preprocessor, PreprocessorInputStream* inputStream)\n{\n    inputStream->parent = preprocessor->inputStream;\n    preprocessor->inputStream = inputStream;\n}\n\n// Called when we reach the end of an input stream.\n// Performs some validation and then destroys the input stream if required.\nstatic void EndInputStream(Preprocessor* preprocessor, PreprocessorInputStream* inputStream)\n{\n    // If there are any conditionals that weren't completed, then it is an error\n    if (inputStream->conditional)\n    {\n        PreprocessorConditional* conditional = inputStream->conditional;\n\n        GetSink(preprocessor)->diagnose(conditional->ifToken.Position, Diagnostics::endOfFileInPreprocessorConditional);\n\n        while (conditional)\n        {\n            PreprocessorConditional* parent = conditional->parent;\n            DestroyConditional(conditional);\n            conditional = parent;\n        }\n    }\n\n    DestroyInputStream(preprocessor, inputStream);\n}\n\n// Consume one token from an input stream\nstatic Token AdvanceRawToken(PreprocessorInputStream* inputStream)\n{\n    return inputStream->tokenReader.AdvanceToken();\n}\n\n// Peek one token from an input stream\nstatic Token PeekRawToken(PreprocessorInputStream* inputStream)\n{\n    return inputStream->tokenReader.PeekToken();\n}\n\n// Peek one token type from an input stream\nstatic CoreLib::Text::TokenType PeekRawTokenType(PreprocessorInputStream* inputStream)\n{\n    return inputStream->tokenReader.PeekTokenType();\n}\n\n\n// Read one token in \"raw\" mode (meaning don't expand macros)\nstatic Token AdvanceRawToken(Preprocessor* preprocessor)\n{\n    for (;;)\n    {\n        // Look at the input stream on top of the stack\n        PreprocessorInputStream* inputStream = preprocessor->inputStream;\n\n        // If there isn't one, then there is no more input left to read.\n        if (!inputStream)\n        {\n            return preprocessor->endOfFileToken;\n        }\n\n        // The top-most input stream may be at its end\n        if (PeekRawTokenType(inputStream) == TokenType::EndOfFile)\n        {\n            // If there is another stream remaining, switch to it\n            if (inputStream->parent)\n            {\n                preprocessor->inputStream = inputStream->parent;\n                EndInputStream(preprocessor, inputStream);\n                continue;\n            }\n        }\n\n        // Everything worked, so read a token from the top-most stream\n        return AdvanceRawToken(inputStream);\n    }\n}\n\n// Return the next token in \"raw\" mode, but don't advance the\n// current token state.\nstatic Token PeekRawToken(Preprocessor* preprocessor)\n{\n    // We need to find the strema that `advanceRawToken` would read from.\n    PreprocessorInputStream* inputStream = preprocessor->inputStream;\n    for (;;)\n    {\n        if (!inputStream)\n        {\n            // No more input streams left to read\n            return preprocessor->endOfFileToken;\n        }\n\n        // The top-most input stream may be at its end, so\n        // look one entry up the stack (don't actually pop\n        // here, since we are just peeking)\n        if (PeekRawTokenType(inputStream) == TokenType::EndOfFile)\n        {\n            if (inputStream->parent)\n            {\n                inputStream = inputStream->parent;\n                continue;\n            }\n        }\n\n        // Everything worked, so the token we just peeked is fine.\n        return PeekRawToken(inputStream);\n    }\n}\n\n// Without advancing preprocessor state, look *two* raw tokens ahead\n// (This is only needed in order to determine when we are possibly\n// expanding a function-style macro)\nCoreLib::Text::TokenType PeekSecondRawTokenType(Preprocessor* preprocessor)\n{\n    // We need to find the strema that `advanceRawToken` would read from.\n    PreprocessorInputStream* inputStream = preprocessor->inputStream;\n    int count = 1;\n    for (;;)\n    {\n        if (!inputStream)\n        {\n            // No more input streams left to read\n            return TokenType::EndOfFile;\n        }\n\n        // The top-most input stream may be at its end, so\n        // look one entry up the stack (don't actually pop\n        // here, since we are just peeking)\n\n        TokenReader reader = inputStream->tokenReader;\n        if (reader.PeekTokenType() == TokenType::EndOfFile)\n        {\n            inputStream = inputStream->parent;\n            continue;\n        }\n\n        if (count)\n        {\n            count--;\n\n            // Note: we are advancing our temporary\n            // copy of the token reader\n            reader.AdvanceToken();\n            if (reader.PeekTokenType() == TokenType::EndOfFile)\n            {\n                inputStream = inputStream->parent;\n                continue;\n            }\n        }\n\n        // Everything worked, so peek a token from the top-most stream\n        return reader.PeekTokenType();\n    }\n}\n\n\n// Get the location of the current (raw) token\nstatic CodePosition PeekLoc(Preprocessor* preprocessor)\n{\n    return PeekRawToken(preprocessor).Position;\n}\n\n// Get the `TokenType` of the current (raw) token\nstatic CoreLib::Text::TokenType PeekRawTokenType(Preprocessor* preprocessor)\n{\n    return PeekRawToken(preprocessor).Type;\n}\n\n//\n// Macros\n//\n\n// Create a macro\nstatic PreprocessorMacro* CreateMacro(Preprocessor* preprocessor)\n{\n    // TODO(tfoley): Allocate these more intelligently.\n    // For example, consider pooling them on the preprocessor.\n\n    PreprocessorMacro* macro = new PreprocessorMacro();\n    macro->flavor = PreprocessorMacroFlavor::ObjectLike;\n    macro->environment = &preprocessor->globalEnv;\n    return macro;\n}\n\n// Destroy a macro\nstatic void DestroyMacro(Preprocessor* /*preprocessor*/, PreprocessorMacro* macro)\n{\n    delete macro;\n}\n\n\n// Find the currently-defined macro of the given name, or return NULL\nstatic PreprocessorMacro* LookupMacro(PreprocessorEnvironment* environment, String const& name)\n{\n    for(PreprocessorEnvironment* e = environment; e; e = e->parent)\n    {\n        PreprocessorMacro* macro = NULL;\n        if (e->macros.TryGetValue(name, macro))\n            return macro;\n    }\n\n    return NULL;\n}\n\nstatic PreprocessorEnvironment* GetCurrentEnvironment(Preprocessor* preprocessor)\n{\n    PreprocessorInputStream* inputStream = preprocessor->inputStream;\n    return inputStream ? inputStream->environment : &preprocessor->globalEnv;\n}\n\nstatic PreprocessorMacro* LookupMacro(Preprocessor* preprocessor, String const& name)\n{\n    return LookupMacro(GetCurrentEnvironment(preprocessor), name);\n}\n\n// A macro is \"busy\" if it is currently being used for expansion.\n// A macro cannot be expanded again while busy, to avoid infinite recursion.\nstatic bool IsMacroBusy(PreprocessorMacro* /*macro*/)\n{\n    // TODO: need to implement this correctly\n    //\n    // The challenge here is that we are implementing expansion\n    // for argumenst to function-like macros in a \"lazy\" fashion.\n    //\n    // The letter of the spec is that we should macro expand\n    // each argument *before* substitution, and then go and\n    // macro-expand the substituted body. This means that we\n    // can invoke a macro as part of an argument to an\n    // invocation of the same macro:\n    //\n    //     FOO( 1, FOO(22), 333 );\n    //\n    // In our implementation, the \"inner\" invocation of `FOO`\n    // gets expanded at the point where it gets referenced\n    // in the body of the \"outer\" invocation of `FOO`.\n    // Doing things this way leads to greatly simplified\n    // code for handling expansion.\n    //\n    // A proper implementation of `IsMacroBusy` needs to\n    // take context into account, so that it bans recursive\n    // use of a macro when it occurs (indirectly) through\n    // the *body* of the expansion, but not when it occcurs\n    // only through an *argument*.\n    return false;\n}\n\n//\n// Reading Tokens With Expansion\n//\n\nstatic void InitializeMacroExpansion(\n    Preprocessor*       preprocessor,\n    MacroExpansion*     expansion,\n    PreprocessorMacro*  macro)\n{\n    InitializeInputStream(preprocessor, expansion);\n    expansion->environment = macro->environment;\n    expansion->macro = macro;\n    expansion->tokenReader = TokenReader(macro->tokens);\n}\n\nstatic void PushMacroExpansion(\n    Preprocessor*   preprocessor,\n    MacroExpansion* expansion)\n{\n    PushInputStream(preprocessor, expansion);\n}\n\nstatic void AddEndOfStreamToken(\n    Preprocessor*       preprocessor,\n    PreprocessorMacro*  macro)\n{\n    Token token = PeekRawToken(preprocessor);\n    token.Type = TokenType::EndOfFile;\n    macro->tokens.mTokens.Add(token);\n}\n\n// Check whether the current token on the given input stream should be\n// treated as a macro invocation, and if so set up state for expanding\n// that macro.\nstatic void MaybeBeginMacroExpansion(\n    Preprocessor*               preprocessor )\n{\n    // We iterate because the first token in the expansion of one\n    // macro may be another macro invocation.\n    for (;;)\n    {\n        // Look at the next token ahead of us\n        Token const& token = PeekRawToken(preprocessor);\n\n        // Not an identifier? Can't be a macro.\n        if (token.Type != TokenType::Identifier)\n            return;\n\n        // Look for a macro with the given name.\n        String name = token.Content;\n        PreprocessorMacro* macro = LookupMacro(preprocessor, name);\n\n        // Not a macro? Can't be an invocation.\n        if (!macro)\n            return;\n\n        // If the macro is busy (already being expanded),\n        // don't try to trigger recursive expansion\n        if (IsMacroBusy(macro))\n            return;\n\n        // A function-style macro invocation should only match\n        // if the token *after* the identifier is `(`. This\n        // requires more lookahead than we usually have/need\n        if (macro->flavor == PreprocessorMacroFlavor::FunctionLike)\n        {\n            if(PeekSecondRawTokenType(preprocessor) != TokenType::LParent)\n                return;\n\n            // Consume the token that triggered macro expansion\n            AdvanceRawToken(preprocessor);\n\n            // Consume the opening `(`\n            Token leftParen = AdvanceRawToken(preprocessor);\n\n            FunctionLikeMacroExpansion* expansion = new FunctionLikeMacroExpansion();\n            InitializeMacroExpansion(preprocessor, expansion, macro);\n            expansion->argumentEnvironment.parent = &preprocessor->globalEnv;\n            expansion->environment = &expansion->argumentEnvironment;\n\n            // Try to read any arguments present.\n            int paramCount = macro->params.Count();\n            int argIndex = 0;\n\n            switch (PeekRawTokenType(preprocessor))\n            {\n            case TokenType::EndOfFile:\n            case TokenType::RParent:\n                // No arguments.\n                break;\n\n            default:\n                // At least one argument\n                while(argIndex < paramCount)\n                {\n                    // Read an argument\n\n                    // Create the argument, represented as a special flavor of macro\n                    PreprocessorMacro* arg = CreateMacro(preprocessor);\n                    arg->flavor = PreprocessorMacroFlavor::FunctionArg;\n                    arg->environment = GetCurrentEnvironment(preprocessor);\n\n                    // Associate the new macro with its parameter name\n                    Token paramToken = macro->params[argIndex];\n                    String const& paramName = paramToken.Content;\n                    arg->nameToken = paramToken;\n                    expansion->argumentEnvironment.macros[paramName] = arg;\n                    argIndex++;\n\n                    // Read tokens for the argument\n\n                    // We track the nesting depth, since we don't break\n                    // arguments on a `,` nested in balanced parentheses\n                    //\n                    int nesting = 0;\n                    for (;;)\n                    {\n                        switch (PeekRawTokenType(preprocessor))\n                        {\n                        case TokenType::EndOfFile:\n                            // if we reach the end of the file,\n                            // then we have an error, and need to\n                            // bail out\n                            AddEndOfStreamToken(preprocessor, arg);\n                            goto doneWithAllArguments;\n\n                        case TokenType::RParent:\n                            // If we see a right paren when we aren't nested\n                            // then we are at the end of an argument\n                            if (nesting == 0)\n                            {\n                                AddEndOfStreamToken(preprocessor, arg);\n                                goto doneWithAllArguments;\n                            }\n                            // Otherwise we decrease our nesting depth, add\n                            // the token, and keep going\n                            nesting--;\n                            break;\n\n                        case TokenType::Comma:\n                            // If we see a comma when we aren't nested\n                            // then we are at the end of an argument\n                            if (nesting == 0)\n                            {\n                                AddEndOfStreamToken(preprocessor, arg);\n                                AdvanceRawToken(preprocessor);\n                                goto doneWithArgument;\n                            }\n                            // Otherwise we add it as a normal token\n                            break;\n\n                        case TokenType::LParent:\n                            // If we see a left paren then we need to\n                            // increase our tracking of nesting\n                            nesting++;\n                            break;\n\n                        default:\n                            break;\n                        }\n\n                        // Add the token and continue parsing.\n                        arg->tokens.mTokens.Add(AdvanceRawToken(preprocessor));\n                    }\n                doneWithArgument: {}\n                    // We've parsed an argument and should move onto\n                    // the next one.\n                }\n                break;\n            }\n        doneWithAllArguments:\n            // TODO: handle possible varargs\n\n            // Expect closing right paren\n            if (PeekRawTokenType(preprocessor) == TokenType::RParent)\n            {\n                AdvanceRawToken(preprocessor);\n            }\n            else\n            {\n                GetSink(preprocessor)->diagnose(PeekLoc(preprocessor), Diagnostics::expectedTokenInMacroArguments, TokenType::RParent, PeekRawTokenType(preprocessor));\n            }\n\n            int argCount = argIndex;\n            if (argCount != paramCount)\n            {\n                // TODO: diagnose\n                throw 99;\n            }\n\n            // We are ready to expand.\n            PushMacroExpansion(preprocessor, expansion);\n        }\n        else\n        {\n            // Consume the token that triggered macro expansion\n            AdvanceRawToken(preprocessor);\n\n            // Object-like macros are the easy case.\n            ObjectLikeMacroExpansion* expansion = new ObjectLikeMacroExpansion();\n            InitializeMacroExpansion(preprocessor, expansion, macro);\n            PushMacroExpansion(preprocessor, expansion);\n        }\n    }\n}\n\n// Read one token with macro-expansion enabled.\nstatic Token AdvanceToken(Preprocessor* preprocessor)\n{\ntop:\n    // Check whether we need to macro expand at the cursor.\n    MaybeBeginMacroExpansion(preprocessor);\n\n    // Read a raw token (now that expansion has been triggered)\n    Token token = AdvanceRawToken(preprocessor);\n\n    // Check if we need to perform token pasting\n    if (PeekRawTokenType(preprocessor) != TokenType::PoundPound)\n    {\n        // If we aren't token pasting, then we are done\n        return token;\n    }\n    else\n    {\n        // We are pasting tokens, which could get messy\n\n        StringBuilder sb;\n        sb << token.Content;\n\n        while (PeekRawTokenType(preprocessor) == TokenType::PoundPound)\n        {\n            // Consume the `##`\n            AdvanceRawToken(preprocessor);\n\n            // Possibly macro-expand the next token\n            MaybeBeginMacroExpansion(preprocessor);\n\n            // Read the next raw token (now that expansion has been triggered)\n            Token nextToken = AdvanceRawToken(preprocessor);\n\n            sb << nextToken.Content;\n        }\n\n        // Now re-lex the input\n        PreprocessorInputStream* inputStream = CreateInputStreamForSource(preprocessor, sb.ProduceString(), \"token paste\");\n        if (inputStream->tokenReader.GetCount() != 1)\n        {\n            // We expect a token paste to produce a single token\n            // TODO(tfoley): emit a diagnostic here\n        }\n\n        PushInputStream(preprocessor, inputStream);\n        goto top;\n    }\n}\n\n// Read one token with macro-expansion enabled.\n//\n// Note that because triggering macro expansion may\n// involve changing the input-stream state, this\n// operation *can* have side effects.\nstatic Token PeekToken(Preprocessor* preprocessor)\n{\n    // Check whether we need to macro expand at the cursor.\n    MaybeBeginMacroExpansion(preprocessor);\n\n    // Peek a raw token (now that expansion has been triggered)\n    return PeekRawToken(preprocessor);\n\n    // TODO: need a plan for how to handle token pasting\n    // here without it being onerous. Would be nice if we\n    // didn't have to re-do pasting on a \"peek\"...\n}\n\n// Peek the type of the next token, including macro expansion.\nstatic CoreLib::Text::TokenType PeekTokenType(Preprocessor* preprocessor)\n{\n    return PeekToken(preprocessor).Type;\n}\n\n//\n// Preprocessor Directives\n//\n\n// When reading a preprocessor directive, we use a context\n// to wrap the direct preprocessor routines defines so far.\n//\n// One of the most important things the directive context\n// does is give us a convenient way to read tokens with\n// a guarantee that we won't read past the end of a line.\nstruct PreprocessorDirectiveContext\n{\n    // The preprocessor that is parsing the directive.\n    Preprocessor*   preprocessor;\n\n    // The directive token (e.g., the `if` in `#if`).\n    // Useful for reference in diagnostic messages.\n    Token           directiveToken;\n\n    // Has any kind of parse error been encountered in\n    // the directive so far?\n    bool            parseError;\n};\n\n// Get the token for  the preprocessor directive being parsed.\ninline Token const& GetDirective(PreprocessorDirectiveContext* context)\n{\n    return context->directiveToken;\n}\n\n// Get the name of the directive being parsed.\ninline String const& GetDirectiveName(PreprocessorDirectiveContext* context)\n{\n    return context->directiveToken.Content;\n}\n\n// Get the location of the directive being parsed.\ninline CodePosition const& GetDirectiveLoc(PreprocessorDirectiveContext* context)\n{\n    return context->directiveToken.Position;\n}\n\n// Wrapper to get the diagnostic sink in the context of a directive.\nstatic inline DiagnosticSink* GetSink(PreprocessorDirectiveContext* context)\n{\n    return GetSink(context->preprocessor);\n}\n\n// Wrapper to get a \"current\" location when parsing a directive\nstatic CodePosition PeekLoc(PreprocessorDirectiveContext* context)\n{\n    return PeekLoc(context->preprocessor);\n}\n\n// Wrapper to look up a macro in the context of a directive.\nstatic PreprocessorMacro* LookupMacro(PreprocessorDirectiveContext* context, String const& name)\n{\n    return LookupMacro(context->preprocessor, name);\n}\n\n// Determine if we have read everthing on the directive's line.\nstatic bool IsEndOfLine(PreprocessorDirectiveContext* context)\n{\n    // Is the next token at the start of its own line?\n    // If so, we have read to the end of the directive.\n    return (PeekRawToken(context->preprocessor).flags & TokenFlag::AtStartOfLine) != 0;\n}\n\n// Read one raw token in a directive, without going past the end of the line.\nstatic Token AdvanceRawToken(PreprocessorDirectiveContext* context)\n{\n    if (IsEndOfLine(context))\n        return context->preprocessor->endOfFileToken;\n    return AdvanceRawToken(context->preprocessor);\n}\n\n// Peek one raw token in a directive, without going past the end of the line.\nstatic Token PeekRawToken(PreprocessorDirectiveContext* context)\n{\n    if (IsEndOfLine(context))\n        return context->preprocessor->endOfFileToken;\n    return PeekRawToken(context->preprocessor);\n}\n\n// Peek next raw token type, without going past the end of the line.\nstatic CoreLib::Text::TokenType PeekRawTokenType(PreprocessorDirectiveContext* context)\n{\n    if (IsEndOfLine(context))\n        return TokenType::EndOfFile;\n    return PeekRawTokenType(context->preprocessor);\n}\n\n// Read one token, with macro-expansion, without going past the end of the line.\nstatic Token AdvanceToken(PreprocessorDirectiveContext* context)\n{\n    if (IsEndOfLine(context))\n        context->preprocessor->endOfFileToken;\n    return AdvanceToken(context->preprocessor);\n}\n\n// Peek one token, with macro-expansion, without going past the end of the line.\nstatic Token PeekToken(PreprocessorDirectiveContext* context)\n{\n    if (IsEndOfLine(context))\n        context->preprocessor->endOfFileToken;\n    return PeekToken(context->preprocessor);\n}\n\n// Peek next token type, with macro-expansion, without going past the end of the line.\nstatic CoreLib::Text::TokenType PeekTokenType(PreprocessorDirectiveContext* context)\n{\n    if (IsEndOfLine(context))\n        return TokenType::EndOfFile;\n    return PeekTokenType(context->preprocessor);\n}\n\n// Skip to the end of the line (useful for recovering from errors in a directive)\nstatic void SkipToEndOfLine(PreprocessorDirectiveContext* context)\n{\n    while(!IsEndOfLine(context))\n    {\n        AdvanceRawToken(context);\n    }\n}\n\nstatic bool ExpectRaw(PreprocessorDirectiveContext* context, CoreLib::Text::TokenType tokenType, DiagnosticInfo const& diagnostic, Token* outToken = NULL)\n{\n    if (PeekRawTokenType(context) != tokenType)\n    {\n        // Only report the first parse error within a directive\n        if (!context->parseError)\n        {\n            GetSink(context)->diagnose(PeekLoc(context), diagnostic, tokenType, GetDirectiveName(context));\n        }\n        context->parseError = true;\n        return false;\n    }\n    Token const& token = AdvanceRawToken(context);\n    if (outToken)\n        *outToken = token;\n    return true;\n}\n\nstatic bool Expect(PreprocessorDirectiveContext* context, CoreLib::Text::TokenType tokenType, DiagnosticInfo const& diagnostic, Token* outToken = NULL)\n{\n    if (PeekTokenType(context) != tokenType)\n    {\n        // Only report the first parse error within a directive\n        if (!context->parseError)\n        {\n            GetSink(context)->diagnose(PeekLoc(context), diagnostic, tokenType, GetDirectiveName(context));\n            context->parseError = true;\n        }\n        return false;\n    }\n    Token const& token = AdvanceToken(context);\n    if (outToken)\n        *outToken = token;\n    return true;\n}\n\n\n\n//\n// Preprocessor Conditionals\n//\n\n// Determine whether the current preprocessor state means we\n// should be skipping tokens.\nstatic bool IsSkipping(Preprocessor* preprocessor)\n{\n    PreprocessorInputStream* inputStream = preprocessor->inputStream;\n    if (!inputStream) return false;\n\n    // If we are not inside a preprocessor conditional, then don't skip\n    PreprocessorConditional* conditional = inputStream->conditional;\n    if (!conditional) return false;\n\n    // skip tokens unless the conditional is inside its `true` case\n    return conditional->state != PreprocessorConditionalState::During;\n}\n\n// Wrapper for use inside directives\nstatic inline bool IsSkipping(PreprocessorDirectiveContext* context)\n{\n    return IsSkipping(context->preprocessor);\n}\n\n// Create a preprocessor conditional\nstatic PreprocessorConditional* CreateConditional(Preprocessor* /*preprocessor*/)\n{\n    // TODO(tfoley): allocate these more intelligently (for example,\n    // pool them on the `Preprocessor`.\n    return new PreprocessorConditional();\n}\n\n// Destroy a preprocessor conditional.\nstatic void DestroyConditional(PreprocessorConditional* conditional)\n{\n    delete conditional;\n}\n\n// Start a preprocessor conditional, with an initial enable/disable state.\nstatic void BeginConditional(PreprocessorDirectiveContext* context, bool enable)\n{\n    Preprocessor* preprocessor = context->preprocessor;\n    PreprocessorInputStream* inputStream = preprocessor->inputStream;\n    assert(inputStream);\n\n    PreprocessorConditional* conditional = CreateConditional(preprocessor);\n\n    conditional->ifToken = context->directiveToken;\n\n    // Set state of this condition appropriately.\n    //\n    // Default to the \"haven't yet seen a `true` branch\" state.\n    PreprocessorConditionalState state = PreprocessorConditionalState::Before;\n    //\n    // If we are nested inside a `false` branch of another condition, then\n    // we never want to enable, so we act as if we already *saw* the `true` branch.\n    //\n    if (IsSkipping(preprocessor)) state = PreprocessorConditionalState::After;\n    //\n    // Similarly, if we ran into any parse errors when dealing with the\n    // opening directive, then things are probably screwy and we should just\n    // skip all the branches.\n    if (IsSkipping(preprocessor)) state = PreprocessorConditionalState::After;\n    //\n    // Otherwise, if our condition was true, then set us to be inside the `true` branch\n    else if (enable) state = PreprocessorConditionalState::During;\n\n    conditional->state = state;\n\n    // Push conditional onto the stack\n    conditional->parent = inputStream->conditional;\n    inputStream->conditional = conditional;\n}\n\n//\n// Preprocessor Conditional Expressions\n//\n\n// Conditional expressions are always of type `int`\ntypedef int PreprocessorExpressionValue;\n\n// Forward-declaretion\nstatic PreprocessorExpressionValue ParseAndEvaluateExpression(PreprocessorDirectiveContext* context);\n\n// Parse a unary (prefix) expression inside of a preprocessor directive.\nstatic PreprocessorExpressionValue ParseAndEvaluateUnaryExpression(PreprocessorDirectiveContext* context)\n{\n    switch (PeekTokenType(context))\n    {\n    // handle prefix unary ops\n    case TokenType::OpSub:\n        AdvanceToken(context);\n        return -ParseAndEvaluateUnaryExpression(context);\n    case TokenType::OpNot:\n        AdvanceToken(context);\n        return !ParseAndEvaluateUnaryExpression(context);\n    case TokenType::OpBitNot:\n        AdvanceToken(context);\n        return ~ParseAndEvaluateUnaryExpression(context);\n\n    // handle parenthized sub-expression\n    case TokenType::LParent:\n        {\n            Token leftParen = AdvanceToken(context);\n            PreprocessorExpressionValue value = ParseAndEvaluateExpression(context);\n            if (!Expect(context, TokenType::RParent, Diagnostics::expectedTokenInPreprocessorExpression))\n            {\n                GetSink(context)->diagnose(leftParen.Position, Diagnostics::seeOpeningToken, leftParen);\n            }\n            return value;\n        }\n\n    case TokenType::IntLiterial:\n        return StringToInt(AdvanceToken(context).Content);\n\n    case TokenType::Identifier:\n        {\n            Token token = AdvanceToken(context);\n            if (token.Content == \"defined\")\n            {\n                // handle `defined(someName)`\n\n                // Possibly parse a `(`\n                Token leftParen;\n                if (PeekRawTokenType(context) == TokenType::LParent)\n                {\n                    leftParen = AdvanceRawToken(context);\n                }\n\n                // Expect an identifier\n                Token nameToken;\n                if (!ExpectRaw(context, TokenType::Identifier, Diagnostics::expectedTokenInDefinedExpression, &nameToken))\n                {\n                    return 0;\n                }\n                String name = nameToken.Content;\n\n                // If we saw an opening `(`, then expect one to close\n                if (leftParen.Type != TokenType::Unknown)\n                {\n                    if(!ExpectRaw(context, TokenType::RParent, Diagnostics::expectedTokenInDefinedExpression))\n                    {\n                        GetSink(context)->diagnose(leftParen.Position, Diagnostics::seeOpeningToken, leftParen);\n                        return 0;\n                    }\n                }\n\n                return LookupMacro(context, name) != NULL;\n            }\n\n            // An identifier here means it was not defined as a macro (or\n            // it is defined, but as a function-like macro. These should\n            // just evaluate to zero (possibly with a warning)\n            return 0;\n        }\n\n    default:\n        GetSink(context)->diagnose(PeekLoc(context), Diagnostics::syntaxErrorInPreprocessorExpression);\n        return 0;\n    }\n}\n\n// Determine the precedence level of an infix operator\n// for use in parsing preprocessor conditionals.\nstatic int GetInfixOpPrecedence(Token const& opToken)\n{\n    // If token is on another line, it is not part of the\n    // expression\n    if (opToken.flags & TokenFlag::AtStartOfLine)\n        return -1;\n\n    // otherwise we look at the token type to figure\n    // out what precednece it should be parse with\n    switch (opToken.Type)\n    {\n    default:\n        // tokens that aren't infix operators should\n        // cause us to stop parsing an expression\n        return -1;\n\n    case TokenType::OpMul:     return 10;\n    case TokenType::OpDiv:     return 10;\n    case TokenType::OpMod:     return 10;\n\n    case TokenType::OpAdd:     return 9;\n    case TokenType::OpSub:     return 9;\n\n    case TokenType::OpLsh:     return 8;\n    case TokenType::OpRsh:     return 8;\n\n    case TokenType::OpLess:    return 7;\n    case TokenType::OpGreater: return 7;\n    case TokenType::OpLeq:     return 7;\n    case TokenType::OpGeq:     return 7;\n\n    case TokenType::OpEql:     return 6;\n    case TokenType::OpNeq:     return 6;\n\n    case TokenType::OpBitAnd:  return 5;\n    case TokenType::OpBitOr:   return 4;\n    case TokenType::OpBitXor:  return 3;\n    case TokenType::OpAnd:     return 2;\n    case TokenType::OpOr:      return 1;\n    }\n};\n\n// Evaluate one infix operation in a preprocessor\n// conditional expression\nstatic PreprocessorExpressionValue EvaluateInfixOp(\n    PreprocessorDirectiveContext*   context,\n    Token const&                    opToken,\n    PreprocessorExpressionValue     left,\n    PreprocessorExpressionValue     right)\n{\n    switch (opToken.Type)\n    {\n    default:\n//        SPIRE_INTERNAL_ERROR(getSink(preprocessor), opToken);\n        return 0;\n        break;\n\n    case TokenType::OpMul:     return left * right;\n    case TokenType::OpDiv:\n    {\n        if (right == 0)\n        {\n            if (!context->parseError)\n            {\n                GetSink(context)->diagnose(opToken.Position, Diagnostics::divideByZeroInPreprocessorExpression);\n            }\n            return 0;\n        }\n        return left / right;\n    }\n    case TokenType::OpMod:\n    {\n        if (right == 0)\n        {\n            if (!context->parseError)\n            {\n                GetSink(context)->diagnose(opToken.Position, Diagnostics::divideByZeroInPreprocessorExpression);\n            }\n            return 0;\n        }\n        return left % right;\n    }\n    case TokenType::OpAdd:      return left +  right;\n    case TokenType::OpSub:      return left -  right;\n    case TokenType::OpLsh:      return left << right;\n    case TokenType::OpRsh:      return left >> right;\n    case TokenType::OpLess:     return left <  right ? 1 : 0;\n    case TokenType::OpGreater:  return left >  right ? 1 : 0;\n    case TokenType::OpLeq:      return left <= right ? 1 : 0;\n    case TokenType::OpGeq:      return left <= right ? 1 : 0;\n    case TokenType::OpEql:      return left == right ? 1 : 0;\n    case TokenType::OpNeq:      return left != right ? 1 : 0;\n    case TokenType::OpBitAnd:   return left & right;\n    case TokenType::OpBitOr:    return left | right;\n    case TokenType::OpBitXor:   return left ^ right;\n    case TokenType::OpAnd:      return left && right;\n    case TokenType::OpOr:       return left || right;\n    }\n}\n\n// Parse the rest of an infix preprocessor expression with\n// precedence greater than or equal to the given `precedence` argument.\n// The value of the left-hand-side expression is provided as\n// an argument.\n// This is used to form a simple recursive-descent expression parser.\nstatic PreprocessorExpressionValue ParseAndEvaluateInfixExpressionWithPrecedence(\n    PreprocessorDirectiveContext* context,\n    PreprocessorExpressionValue left,\n    int precedence)\n{\n    for (;;)\n    {\n        // Look at the next token, and see if it is an operator of\n        // high enough precedence to be included in our expression\n        Token opToken = PeekToken(context);\n        int opPrecedence = GetInfixOpPrecedence(opToken);\n\n        // If it isn't an operator of high enough precendece, we are done.\n        if(opPrecedence < precedence)\n            break;\n\n        // Otherwise we need to consume the operator token.\n        AdvanceToken(context);\n\n        // Next we parse a right-hand-side expression by starting with\n        // a unary expression and absorbing and many infix operators\n        // as possible with strictly higher precedence than the operator\n        // we found above.\n        PreprocessorExpressionValue right = ParseAndEvaluateUnaryExpression(context);\n        for (;;)\n        {\n            // Look for an operator token\n            Token rightOpToken = PeekToken(context);\n            int rightOpPrecedence = GetInfixOpPrecedence(rightOpToken);\n\n            // If no operator was found, or the operator wasn't high\n            // enough precedence to fold into the right-hand-side,\n            // exit this loop.\n            if (rightOpPrecedence <= opPrecedence)\n                break;\n\n            // Now invoke the parser recursively, passing in our\n            // existing right-hand side to form an even larger one.\n            right = ParseAndEvaluateInfixExpressionWithPrecedence(\n                context,\n                right,\n                rightOpPrecedence);\n        }\n\n        // Now combine the left- and right-hand sides using\n        // the operator we found above.\n        left = EvaluateInfixOp(context, opToken, left, right);\n    }\n    return left;\n}\n\n// Parse a complete (infix) preprocessor expression, and return its value\nstatic PreprocessorExpressionValue ParseAndEvaluateExpression(PreprocessorDirectiveContext* context)\n{\n    // First read in the left-hand side (or the whole expression in the unary case)\n    PreprocessorExpressionValue value = ParseAndEvaluateUnaryExpression(context);\n\n    // Try to read in trailing infix operators with correct precedence\n    return ParseAndEvaluateInfixExpressionWithPrecedence(context, value, 0);\n}\n\n// Handle a `#if` directive\nstatic void HandleIfDirective(PreprocessorDirectiveContext* context)\n{\n    // Parse a preprocessor expression.\n    PreprocessorExpressionValue value = ParseAndEvaluateExpression(context);\n\n    // Begin a preprocessor block, enabled based on the expression.\n    BeginConditional(context, value != 0);\n}\n\n// Handle a `#ifdef` directive\nstatic void HandleIfDefDirective(PreprocessorDirectiveContext* context)\n{\n    // Expect a raw identifier, so we can check if it is defined\n    Token nameToken;\n    if(!ExpectRaw(context, TokenType::Identifier, Diagnostics::expectedTokenInPreprocessorDirective, &nameToken))\n        return;\n    String name = nameToken.Content;\n\n    // Check if the name is defined.\n    BeginConditional(context, LookupMacro(context, name) != NULL);\n}\n\n// Handle a `#ifndef` directive\nstatic void HandleIfNDefDirective(PreprocessorDirectiveContext* context)\n{\n    // Expect a raw identifier, so we can check if it is defined\n    Token nameToken;\n    if(!ExpectRaw(context, TokenType::Identifier, Diagnostics::expectedTokenInPreprocessorDirective, &nameToken))\n        return;\n    String name = nameToken.Content;\n\n    // Check if the name is defined.\n    BeginConditional(context, LookupMacro(context, name) == NULL);\n}\n\n// Handle a `#else` directive\nstatic void HandleElseDirective(PreprocessorDirectiveContext* context)\n{\n    PreprocessorInputStream* inputStream = context->preprocessor->inputStream;\n    assert(inputStream);\n\n    // if we aren't inside a conditional, then error\n    PreprocessorConditional* conditional = inputStream->conditional;\n    if (!conditional)\n    {\n        GetSink(context)->diagnose(GetDirectiveLoc(context), Diagnostics::directiveWithoutIf, GetDirectiveName(context));\n        return;\n    }\n\n    // if we've already seen a `#else`, then it is an error\n    if (conditional->elseToken.Type != TokenType::Unknown)\n    {\n        GetSink(context)->diagnose(GetDirectiveLoc(context), Diagnostics::directiveAfterElse, GetDirectiveName(context));\n        GetSink(context)->diagnose(conditional->elseToken.Position, Diagnostics::seeDirective);\n        return;\n    }\n    conditional->elseToken = context->directiveToken;\n\n    switch (conditional->state)\n    {\n    case PreprocessorConditionalState::Before:\n        conditional->state = PreprocessorConditionalState::During;\n        break;\n\n    case PreprocessorConditionalState::During:\n        conditional->state = PreprocessorConditionalState::After;\n        break;\n\n    default:\n        break;\n    }\n}\n\n// Handle a `#elif` directive\nstatic void HandleElifDirective(PreprocessorDirectiveContext* context)\n{\n    PreprocessorExpressionValue value = ParseAndEvaluateExpression(context);\n\n    PreprocessorInputStream* inputStream = context->preprocessor->inputStream;\n    assert(inputStream);\n\n    // if we aren't inside a conditional, then error\n    PreprocessorConditional* conditional = inputStream->conditional;\n    if (!conditional)\n    {\n        GetSink(context)->diagnose(GetDirectiveLoc(context), Diagnostics::directiveWithoutIf, GetDirectiveName(context));\n        return;\n    }\n\n    // if we've already seen a `#else`, then it is an error\n    if (conditional->elseToken.Type != TokenType::Unknown)\n    {\n        GetSink(context)->diagnose(GetDirectiveLoc(context), Diagnostics::directiveAfterElse, GetDirectiveName(context));\n        GetSink(context)->diagnose(conditional->elseToken.Position, Diagnostics::seeDirective);\n        return;\n    }\n\n    switch (conditional->state)\n    {\n    case PreprocessorConditionalState::Before:\n        if(value)\n            conditional->state = PreprocessorConditionalState::During;\n        break;\n\n    case PreprocessorConditionalState::During:\n        conditional->state = PreprocessorConditionalState::After;\n        break;\n\n    default:\n        break;\n    }\n}\n\n// Handle a `#endif` directive\nstatic void HandleEndIfDirective(PreprocessorDirectiveContext* context)\n{\n    PreprocessorInputStream* inputStream = context->preprocessor->inputStream;\n    assert(inputStream);\n\n    // if we aren't inside a conditional, then error\n    PreprocessorConditional* conditional = inputStream->conditional;\n    if (!conditional)\n    {\n        GetSink(context)->diagnose(GetDirectiveLoc(context), Diagnostics::directiveWithoutIf, GetDirectiveName(context));\n        return;\n    }\n\n    inputStream->conditional = conditional->parent;\n    DestroyConditional(conditional);\n}\n\n// Handle a `#include` directive\nstatic void HandleIncludeDirective(PreprocessorDirectiveContext* context)\n{\n    Token pathToken;\n    if(!Expect(context, TokenType::StringLiterial, Diagnostics::expectedTokenInPreprocessorDirective, &pathToken))\n        return;\n    String path = pathToken.Content;\n\n    // TODO(tfoley): make this robust in presence of `#line`\n    String pathIncludedFrom = GetDirectiveLoc(context).FileName;\n    String foundPath;\n    String foundSource;\n\n\n    IncludeHandler* includeHandler = context->preprocessor->includeHandler;\n    if (!includeHandler)\n    {\n        GetSink(context)->diagnose(pathToken.Position, Diagnostics::includeFailed, path);\n        GetSink(context)->diagnose(pathToken.Position, Diagnostics::noIncludeHandlerSpecified);\n        return;\n    }\n    if (!includeHandler->TryToFindIncludeFile(path, pathIncludedFrom, &foundPath, &foundSource))\n    {\n        GetSink(context)->diagnose(pathToken.Position, Diagnostics::includeFailed, path);\n        return;\n    }\n\n    // Push the new file onto our stack of input streams\n    // TODO(tfoley): check if we have made our include stack too deep\n    PreprocessorInputStream* inputStream = CreateInputStreamForSource(context->preprocessor, foundSource, foundPath);\n    inputStream->parent = context->preprocessor->inputStream;\n    context->preprocessor->inputStream = inputStream;\n}\n\n// Handle a `#define` directive\nstatic void HandleDefineDirective(PreprocessorDirectiveContext* context)\n{\n    Token nameToken;\n    if (!Expect(context, TokenType::Identifier, Diagnostics::expectedTokenInPreprocessorDirective, &nameToken))\n        return;\n    String name = nameToken.Content;\n\n    PreprocessorMacro* macro = CreateMacro(context->preprocessor);\n    macro->nameToken = nameToken;\n\n    PreprocessorMacro* oldMacro = LookupMacro(&context->preprocessor->globalEnv, name);\n    if (oldMacro)\n    {\n        GetSink(context)->diagnose(nameToken.Position, Diagnostics::macroRedefinition, name);\n        GetSink(context)->diagnose(oldMacro->nameToken.Position, Diagnostics::seePreviousDefinitionOf, name);\n\n        DestroyMacro(context->preprocessor, oldMacro);\n    }\n    context->preprocessor->globalEnv.macros[name] = macro;\n\n    // If macro name is immediately followed (with no space) by `(`,\n    // then we have a function-like macro\n    if (PeekRawTokenType(context) == TokenType::LParent)\n    {\n        if (!(PeekRawToken(context).flags & TokenFlag::AfterWhitespace))\n        {\n            // This is a function-like macro, so we need to remember that\n            // and start capturing parameters\n            macro->flavor = PreprocessorMacroFlavor::FunctionLike;\n\n            AdvanceRawToken(context);\n\n            // If there are any parameters, parse them\n            if (PeekRawTokenType(context) != TokenType::RParent)\n            {\n                for (;;)\n                {\n                    // TODO: handle elipsis (`...`) for varags\n\n                    // A macro parameter name should be a raw identifier\n                    Token paramToken;\n                    if (!ExpectRaw(context, TokenType::Identifier, Diagnostics::expectedTokenInMacroParameters, &paramToken))\n                        break;\n\n                    // TODO(tfoley): some validation on parameter name.\n                    // Certain names (e.g., `defined` and `__VA_ARGS__`\n                    // are not allowed to be used as macros or parameters).\n\n                    // Add the parameter to the macro being deifned\n                    macro->params.Add(paramToken);\n\n                    // If we see `)` then we are done with arguments\n                    if (PeekRawTokenType(context) == TokenType::RParent)\n                        break;\n\n                    ExpectRaw(context, TokenType::Comma, Diagnostics::expectedTokenInMacroParameters);\n                }\n            }\n\n            ExpectRaw(context, TokenType::RParent, Diagnostics::expectedTokenInMacroParameters);\n        }\n    }\n\n    // consume tokens until end-of-line\n    for(;;)\n    {\n        Token token = AdvanceRawToken(context);\n        macro->tokens.mTokens.Add(token);\n        if (token.Type == TokenType::EndOfFile)\n            break;\n    }\n}\n\n// Handle a `#undef` directive\nstatic void HandleUndefDirective(PreprocessorDirectiveContext* context)\n{\n    Token nameToken;\n    if (!Expect(context, TokenType::Identifier, Diagnostics::expectedTokenInPreprocessorDirective, &nameToken))\n        return;\n    String name = nameToken.Content;\n\n    PreprocessorEnvironment* env = &context->preprocessor->globalEnv;\n    PreprocessorMacro* macro = LookupMacro(env, name);\n    if (macro != NULL)\n    {\n        // name was defined, so remove it\n        env->macros.Remove(name);\n\n        DestroyMacro(context->preprocessor, macro);\n    }\n    else\n    {\n        // name wasn't defined\n        GetSink(context)->diagnose(nameToken.Position, Diagnostics::macroNotDefined, name);\n    }\n}\n\n// Handle a `#warning` directive\nstatic void HandleWarningDirective(PreprocessorDirectiveContext* context)\n{\n    // TODO: read rest of line without actual tokenization\n    GetSink(context)->diagnose(GetDirectiveLoc(context), Diagnostics::userDefinedWarning, \"user-defined warning\");\n    SkipToEndOfLine(context);\n}\n\n// Handle a `#error` directive\nstatic void HandleErrorDirective(PreprocessorDirectiveContext* context)\n{\n    // TODO: read rest of line without actual tokenization\n    GetSink(context)->diagnose(GetDirectiveLoc(context), Diagnostics::userDefinedError, \"user-defined warning\");\n    SkipToEndOfLine(context);\n}\n\n// Handle a `#line` directive\nstatic void HandleLineDirective(PreprocessorDirectiveContext* context)\n{\n    int line = 0;\n    if (PeekTokenType(context) == TokenType::IntLiterial)\n    {\n        line = StringToInt(AdvanceToken(context).Content);\n    }\n    else if (PeekTokenType(context) == TokenType::Identifier\n        && PeekToken(context).Content == \"default\")\n    {\n        AdvanceToken(context);\n\n        // TODO(tfoley): reset line numbering here\n        return;\n    }\n    else\n    {\n        GetSink(context)->diagnose(PeekLoc(context), Diagnostics::expected2TokensInPreprocessorDirective,\n            TokenType::IntLiterial,\n            \"default\",\n            GetDirectiveName(context));\n        context->parseError = true;\n        return;\n    }\n\n    if (PeekTokenType(context) == TokenType::EndOfFile)\n    {\n        // TODO(tfoley): set line number, but not file\n        return;\n    }\n\n    String file;\n    if (PeekTokenType(context) == TokenType::StringLiterial)\n    {\n        file = AdvanceToken(context).Content;\n    }\n    else if (PeekTokenType(context) == TokenType::IntLiterial)\n    {\n        // Note(tfoley): GLSL allows the \"source string\" to be indicated by an integer\n        // TODO(tfoley): Figure out a better way to handle this, if it matters\n        file = AdvanceToken(context).Content;\n    }\n    else\n    {\n        Expect(context, TokenType::StringLiterial, Diagnostics::expectedTokenInPreprocessorDirective);\n        return;\n    }\n\n    // TODO(tfoley): set line number and file here\n}\n\n// Handle a `#pragma` directive\nstatic void HandlePragmaDirective(PreprocessorDirectiveContext* context)\n{\n    // TODO(tfoley): figure out which pragmas to parse,\n    // and which to pass along\n    SkipToEndOfLine(context);\n}\n\n// Handle a `#version` directive\nstatic void HandleVersionDirective(PreprocessorDirectiveContext* context)\n{\n    // TODO(tfoley): parse enough of this to spit it out again later?\n    SkipToEndOfLine(context);\n}\n\n\n// Callback interface used by preprocessor directives\ntypedef void (*PreprocessorDirectiveCallback)(PreprocessorDirectiveContext* context);\n\nenum PreprocessorDirectiveFlag : unsigned int\n{\n    // Should this directive be handled even when skipping disbaled code?\n    ProcessWhenSkipping = 1 << 0,\n};\n\n// Information about a specific directive\nstruct PreprocessorDirective\n{\n    // Name of the directive\n    char const*                     name;\n\n    // Callback to handle the directive\n    PreprocessorDirectiveCallback   callback;\n\n    unsigned int                    flags;\n};\n\n// A simple array of all the directives we know how to handle.\n// TODO(tfoley): considering making this into a real hash map,\n// and then make it easy-ish for users of the codebase to add\n// their own directives as desired.\nstatic const PreprocessorDirective kDirectives[] =\n{\n    { \"if\",         &HandleIfDirective,         ProcessWhenSkipping },\n    { \"ifdef\",      &HandleIfDefDirective,      ProcessWhenSkipping },\n    { \"ifndef\",     &HandleIfNDefDirective,     ProcessWhenSkipping },\n    { \"else\",       &HandleElseDirective,       ProcessWhenSkipping },\n    { \"elif\",       &HandleElifDirective,       ProcessWhenSkipping },\n    { \"endif\",      &HandleEndIfDirective,      ProcessWhenSkipping },\n\n    { \"include\",    &HandleIncludeDirective,    0 },\n    { \"define\",     &HandleDefineDirective,     0 },\n    { \"undef\",      &HandleUndefDirective,      0 },\n    { \"warning\",    &HandleWarningDirective,    0 },\n    { \"error\",      &HandleErrorDirective,      0 },\n    { \"line\",       &HandleLineDirective,       0 },\n    { \"pragma\",     &HandlePragmaDirective,     0 },\n    { \"version\",    &HandleVersionDirective,    0 },\n    { NULL, NULL },\n};\n\n// Look up the directive with the given name.\nstatic PreprocessorDirective const* FindDirective(String const& name)\n{\n    char const* nameStr = name.Buffer();\n    for (int ii = 0; kDirectives[ii].name; ++ii)\n    {\n        if (strcmp(kDirectives[ii].name, nameStr) != 0)\n            continue;\n\n        return &kDirectives[ii];\n    }\n\n    return NULL;\n}\n\n// Process a directive, where the preprocessor has already consumed the\n// `#` token that started the directive line.\nstatic void HandleDirective(PreprocessorDirectiveContext* context)\n{\n    // Try to read the directive name.\n    context->directiveToken = PeekRawToken(context);\n\n    CoreLib::Text::TokenType directiveTokenType = GetDirective(context).Type;\n\n    // An empty directive is allowed, and ignored.\n    if (directiveTokenType == TokenType::EndOfFile)\n    {\n        return;\n    }\n    // Otherwise the directive name had better be an identifier\n    else if (directiveTokenType != TokenType::Identifier)\n    {\n        GetSink(context)->diagnose(GetDirectiveLoc(context), Diagnostics::expectedPreprocessorDirectiveName);\n        SkipToEndOfLine(context);\n        return;\n    }\n\n    // Consume the directive name token.\n    AdvanceRawToken(context);\n\n    // Look up the handler for the directive.\n    PreprocessorDirective const* directive = FindDirective(GetDirectiveName(context));\n    if (!directive)\n    {\n        GetSink(context)->diagnose(GetDirectiveLoc(context), Diagnostics::unknownPreprocessorDirective, GetDirectiveName(context));\n        SkipToEndOfLine(context);\n        return;\n    }\n\n    // If we are skipping disabled code, and the directive is not one\n    // of the small number that need to run even in that case, skip it.\n    if (IsSkipping(context) && !(directive->flags & PreprocessorDirectiveFlag::ProcessWhenSkipping))\n    {\n        SkipToEndOfLine(context);\n        return;\n    }\n\n    // Apply the directive-specific callback\n    (directive->callback)(context);\n\n    // We expect the directive to consume the entire line, so if\n    // it hasn't that is a parse error.\n    if (!IsEndOfLine(context))\n    {\n        // If we already saw a previous parse error, then don't\n        // emit another one for the same directive.\n        if (!context->parseError)\n        {\n            GetSink(context)->diagnose(PeekLoc(context), Diagnostics::unexpectedTokensAfterDirective, GetDirectiveName(context));\n        }\n        SkipToEndOfLine(context);\n    }\n}\n\n// Read one token using the full preprocessor, with all its behaviors.\nstatic Token ReadToken(Preprocessor* preprocessor)\n{\n    for (;;)\n    {\n        // Look at the next raw token in the input.\n        Token const& token = PeekRawToken(preprocessor);\n\n        // If we have a directive (`#` at start of line) then handle it\n        if ((token.Type == TokenType::Pound) && (token.flags & TokenFlag::AtStartOfLine))\n        {\n            // Skip the `#`\n            AdvanceRawToken(preprocessor);\n\n            // Create a context for parsing the directive\n            PreprocessorDirectiveContext directiveContext;\n            directiveContext.preprocessor = preprocessor;\n            directiveContext.parseError = false;\n\n            // Parse and handle the directive\n            HandleDirective(&directiveContext);\n            continue;\n        }\n\n        // otherwise, if we are currently in a skipping mode, then skip tokens\n        if (IsSkipping(preprocessor))\n        {\n            if( token.Type == TokenType::EndOfFile )\n            {\n                GetSink(preprocessor)->diagnose(PeekLoc(preprocessor), Diagnostics::endOfFileInPreprocessorConditional);\n                return token;\n            }\n\n            AdvanceRawToken(preprocessor);\n            continue;\n        }\n\n        // otherwise read a token, which may involve macro expansion\n        return AdvanceToken(preprocessor);\n    }\n}\n\n// intialize a preprocessor context, using the given sink for errros\nstatic void InitializePreprocessor(\n    Preprocessor*   preprocessor,\n    DiagnosticSink* sink)\n{\n    preprocessor->sink = sink;\n    preprocessor->includeHandler = NULL;\n    preprocessor->endOfFileToken.Type = TokenType::EndOfFile;\n    preprocessor->endOfFileToken.flags = TokenFlag::AtStartOfLine;\n}\n\n// clean up after an environment\nPreprocessorEnvironment::~PreprocessorEnvironment()\n{\n    for (auto pair : this->macros)\n    {\n        DestroyMacro(NULL, pair.Value);\n    }\n}\n\n// finalize a preprocessor and free any memory still in use\nstatic void FinalizePreprocessor(\n    Preprocessor*   preprocessor)\n{\n    // Clear out any waiting input streams\n    PreprocessorInputStream* input = preprocessor->inputStream;\n    while (input)\n    {\n        PreprocessorInputStream* parent = input->parent;\n        DestroyInputStream(preprocessor, input);\n        input = parent;\n    }\n\n#if 0\n    // clean up any macros that were allocated\n    for (auto pair : preprocessor->globalEnv.macros)\n    {\n        DestroyMacro(preprocessor, pair.Value);\n    }\n#endif\n}\n\n// Add a simple macro definition from a string (e.g., for a\n// `-D` option passed on the command line\nstatic void DefineMacro(\n    Preprocessor*   preprocessor,\n    String const&   key,\n    String const&   value)\n{\n    String fileName = \"command line\";\n    PreprocessorMacro* macro = CreateMacro(preprocessor);\n\n    // Use existing `Lexer` to generate a token stream.\n    Lexer lexer;\n    macro->tokens = lexer.Parse(fileName, value, GetSink(preprocessor));\n    macro->nameToken = Token(TokenType::Identifier, key, 0, 0, 0, fileName);\n\n    PreprocessorMacro* oldMacro = NULL;\n    if (preprocessor->globalEnv.macros.TryGetValue(key, oldMacro))\n    {\n        DestroyMacro(preprocessor, oldMacro);\n    }\n\n    preprocessor->globalEnv.macros[key] = macro;\n}\n\n// read the entire input into tokens\nstatic TokenList ReadAllTokens(\n    Preprocessor*   preprocessor)\n{\n    TokenList tokens;\n    for (;;)\n    {\n        Token token = ReadToken(preprocessor);\n\n        tokens.mTokens.Add(token);\n\n        // Note: we include the EOF token in the list,\n        // since that is expected by the `TokenList` type.\n        if (token.Type == TokenType::EndOfFile)\n            break;\n    }\n    return tokens;\n}\n\n\n// Take a string of source code and preprocess it into a list of tokens.\nTokenList PreprocessSource(\n    CoreLib::String const& source,\n    CoreLib::String const& fileName,\n    DiagnosticSink* sink,\n    IncludeHandler* includeHandler)\n{\n    Preprocessor preprocessor;\n    InitializePreprocessor(&preprocessor, sink);\n\n    preprocessor.includeHandler = includeHandler;\n\n    // create an initial input stream based on the provided buffer\n    preprocessor.inputStream = CreateInputStreamForSource(&preprocessor, source, fileName);\n\n    TokenList tokens = ReadAllTokens(&preprocessor);\n\n    FinalizePreprocessor(&preprocessor);\n\n    return tokens;\n}\n\nTokenList PreprocessSource(\n    CoreLib::String const& source,\n    CoreLib::String const& fileName,\n    DiagnosticSink* sink,\n    IncludeHandler* includeHandler,\n    CoreLib::Dictionary<CoreLib::String, CoreLib::String>  defines)\n{\n    Preprocessor preprocessor;\n    InitializePreprocessor(&preprocessor, sink);\n\n    preprocessor.includeHandler = includeHandler;\n    for (auto p : defines)\n    {\n        DefineMacro(&preprocessor, p.Key, p.Value);\n    }\n\n    // create an initial input stream based on the provided buffer\n    preprocessor.inputStream = CreateInputStreamForSource(&preprocessor, source, fileName);\n\n    TokenList tokens = ReadAllTokens(&preprocessor);\n\n    FinalizePreprocessor(&preprocessor);\n\n    // debugging: build the pre-processed source back together\n#if 0\n    StringBuilder sb;\n    for (auto t : tokens)\n    {\n        if (t.flags & TokenFlag::AtStartOfLine)\n        {\n            sb << \"\\n\";\n        }\n        else if (t.flags & TokenFlag::AfterWhitespace)\n        {\n            sb << \" \";\n        }\n        \n        sb << t.Content;\n    }\n\n    String s = sb.ProduceString();\n#endif\n\n    return tokens;\n}\n\n}}\n"
  },
  {
    "path": "Source/SpireCore/Preprocessor.h",
    "content": "// Preprocessor.h\n#ifndef SPIRE_PREPROCESSOR_H_INCLUDED\n#define SPIRE_PREPROCESSOR_H_INCLUDED\n\n#include \"../CoreLib/Basic.h\"\n#include \"../CoreLib/Tokenizer.h\"\n#include \"../SpireCore/Lexer.h\"\n\nnamespace Spire{ namespace Compiler {\n\nclass DiagnosticSink;\n\n// Callback interface for the preprocessor to use when looking\n// for files in `#include` directives.\nstruct IncludeHandler\n{\n    virtual bool TryToFindIncludeFile(\n        CoreLib::String const& pathToInclude,\n        CoreLib::String const& pathIncludedFrom,\n        CoreLib::String* outFoundPath,\n        CoreLib::String* outFoundSource) = 0;\n};\n\n// Take a string of source code and preprocess it into a list of tokens.\nTokenList PreprocessSource(\n    CoreLib::String const& source,\n    CoreLib::String const& fileName,\n    DiagnosticSink* sink,\n    IncludeHandler* includeHandler);\n\nTokenList PreprocessSource(\n    CoreLib::String const& source,\n    CoreLib::String const& fileName,\n    DiagnosticSink* sink,\n    IncludeHandler* includeHandler,\n    CoreLib::Dictionary<CoreLib::String, CoreLib::String>  defines);\n\n}}\n\n#endif\n"
  },
  {
    "path": "Source/SpireCore/SamplerUsageAnalysis.cpp",
    "content": "#include \"SamplerUsageAnalysis.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tusing namespace CoreLib;\n\n\t\tvoid AnalyzeSamplerUsageImpl(EnumerableDictionary<ILModuleParameterInstance*, List<ILModuleParameterInstance*>> & samplerTextures,\n\t\t\tILProgram * program,\n\t\t\tCFGNode * code,\n\t\t\tDiagnosticSink * sink,\n\t\t\tHashSet<ILFunction*> & processedFunctions,\n\t\t\tDictionary<int, ILModuleParameterInstance*> & paramValues)\n\t\t{\n\t\t\tfor (auto & instr : code->GetAllInstructions())\n\t\t\t{\n\t\t\t\tauto call = dynamic_cast<CallInstruction*>(&instr);\n\t\t\t\tif (call)\n\t\t\t\t{\n\t\t\t\t\tif (call->Function.StartsWith(\"Sample\") && !program->Functions.ContainsKey(call->Function))\n\t\t\t\t\t{\n\t\t\t\t\t\tauto textureOp = call->Arguments[0].Ptr();\n\t\t\t\t\t\tauto samplerOp = call->Arguments[1].Ptr();\n\t\t\t\t\t\tILModuleParameterInstance * textureInstance = nullptr;\n\t\t\t\t\t\tILModuleParameterInstance * samplerInstance = nullptr;\n\t\t\t\t\t\tif (auto texArg = dynamic_cast<FetchArgInstruction*>(textureOp))\n\t\t\t\t\t\t\tparamValues.TryGetValue(texArg->ArgId, textureInstance);\n\t\t\t\t\t\telse if (auto texArg1 = dynamic_cast<ILModuleParameterInstance*>(textureOp))\n\t\t\t\t\t\t\ttextureInstance = texArg1;\n\t\t\t\t\t\tif (auto samplerArg = dynamic_cast<FetchArgInstruction*>(samplerOp))\n\t\t\t\t\t\t\tparamValues.TryGetValue(samplerArg->ArgId, samplerInstance);\n\t\t\t\t\t\telse if (auto samplerArg1 = dynamic_cast<ILModuleParameterInstance*>(samplerOp))\n\t\t\t\t\t\t\tsamplerInstance = samplerArg1;\n\t\t\t\t\t\tif (textureInstance && samplerInstance)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto list = samplerTextures.TryGetValue(samplerInstance);\n\t\t\t\t\t\t\tif (!list)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tsamplerTextures.Add(samplerInstance, List<ILModuleParameterInstance*>());\n\t\t\t\t\t\t\t\tlist = samplerTextures.TryGetValue(samplerInstance);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlist->Add(textureInstance);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSPIRE_INTERNAL_ERROR(sink, instr.Position);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tRefPtr<ILFunction> func = nullptr;\n\t\t\t\t\t\tif (program->Functions.TryGetValue(call->Function, func))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!processedFunctions.Contains(func.Ptr()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// trace into the function call\n\t\t\t\t\t\t\t\tDictionary<int, ILModuleParameterInstance*> args;\n\t\t\t\t\t\t\t\tfor (int i = 0; i < call->Arguments.Count(); i++)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (auto arg = dynamic_cast<FetchArgInstruction*>(call->Arguments[i].Ptr()))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tILModuleParameterInstance * argValue = nullptr;\n\t\t\t\t\t\t\t\t\t\tif (paramValues.TryGetValue(arg->ArgId, argValue))\n\t\t\t\t\t\t\t\t\t\t\targs[i + 1] = argValue;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse if (auto argValue = dynamic_cast<ILModuleParameterInstance*>(call->Arguments[i].Ptr()))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\targs[i + 1] = argValue;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (func->Code)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tprocessedFunctions.Add(func.Ptr());\n\t\t\t\t\t\t\t\t\tAnalyzeSamplerUsageImpl(samplerTextures, program, func->Code.Ptr(), sink,\n\t\t\t\t\t\t\t\t\t\tprocessedFunctions, args);\n\t\t\t\t\t\t\t\t\tprocessedFunctions.Remove(func.Ptr());\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid AnalyzeSamplerUsage(EnumerableDictionary<ILModuleParameterInstance*, List<ILModuleParameterInstance*>> & samplerTextures, \n\t\t\tILProgram * program, CFGNode * code, DiagnosticSink * sink)\n\t\t{\n\t\t\tDictionary<int, ILModuleParameterInstance*> params;\n\t\t\tHashSet<ILFunction*> processedFuncs;\n\t\t\tAnalyzeSamplerUsageImpl(samplerTextures, program, code, sink, processedFuncs, params);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/SamplerUsageAnalysis.h",
    "content": "#include \"IL.h\"\n#include \"CompiledProgram.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tvoid AnalyzeSamplerUsage(CoreLib::EnumerableDictionary<ILModuleParameterInstance*, CoreLib::List<ILModuleParameterInstance*>> & samplerTextures,\n\t\t\tILProgram * program, CFGNode * code, DiagnosticSink * sink);\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/Schedule.cpp",
    "content": "#include \"Schedule.h\"\n#include \"Lexer.h\"\nusing namespace CoreLib::Basic;\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tclass ScheduleParser\n\t\t{\n\t\tprivate:\n            DiagnosticSink * sink;\n\t\t\tTokenList tokens;\n            TokenReader reader;\n            String fileName;\n\t\t\tToken ReadToken(const char * string)\n\t\t\t{\n\t\t\t\tif (reader.PeekTokenType() == TokenType::EndOfFile)\n\t\t\t\t{\n\t\t\t\t\tsink->diagnose(reader.PeekLoc(), Diagnostics::tokenNameExpectedButEOF, string);\n\t\t\t\t\tthrow 0;\n\t\t\t\t}\n\t\t\t\telse if (reader.PeekToken().Content != string)\n\t\t\t\t{\n\t\t\t\t\tsink->diagnose(reader.PeekLoc(), Diagnostics::tokenNameExpected, string);\n\t\t\t\t\tthrow 20001;\n\t\t\t\t}\n\t\t\t\treturn reader.AdvanceToken();\n\t\t\t}\n\n\t\t\tToken ReadToken(CoreLib::Text::TokenType type)\n\t\t\t{\n\t\t\t\tif (reader.PeekTokenType() == TokenType::EndOfFile)\n\t\t\t\t{\n\t\t\t\t\tsink->diagnose(reader.PeekLoc(), Diagnostics::tokenTypeExpectedButEOF, type);\n\t\t\t\t\tthrow 0;\n\t\t\t\t}\n\t\t\t\telse if (reader.PeekTokenType() != type)\n\t\t\t\t{\n\t\t\t\t\tsink->diagnose(reader.PeekLoc(), Diagnostics::tokenTypeExpected, type);\n\t\t\t\t\tthrow 20001;\n\t\t\t\t}\n\t\t\t\treturn reader.AdvanceToken();\n\t\t\t}\n\n\t\t\tbool LookAheadToken(const char * string)\n\t\t\t{\n\t\t\t\tif (reader.PeekTokenType() == TokenType::EndOfFile)\n\t\t\t\t{\n                    // TODO(tfoley): this error condition seems wrong\n                    // it shouldn't be an error to see EOF as out *lookahead*\n\t\t\t\t\tsink->diagnose(reader.PeekLoc(), Diagnostics::tokenNameExpectedButEOF);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (reader.PeekToken().Content == string)\n\t\t\t\t\t\treturn true;\n\t\t\t\t\telse\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\tpublic:\n\t\t\tScheduleParser(DiagnosticSink * sink)\n\t\t\t\t: sink(sink)\n\t\t\t{}\n\t\t\tSchedule Parse(String source, String _fileName)\n\t\t\t{\n\t\t\t\tthis->fileName = _fileName;\n\t\t\t\tSchedule schedule;\n\t\t\t\tLexer lex;\n\t\t\t\ttokens = lex.Parse(fileName, source, sink);\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\twhile (reader.PeekTokenType() != TokenType::EndOfFile)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (LookAheadToken(\"attrib\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEnumerableDictionary<String, String> additionalAttributes;\n\t\t\t\t\t\t\tReadToken(\"attrib\");\n\t\t\t\t\t\t\tString choiceName = ReadToken(TokenType::Identifier).Content;\n\t\t\t\t\t\t\twhile (LookAheadToken(\".\"))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tchoiceName = choiceName + \".\";\n\t\t\t\t\t\t\t\tReadToken(TokenType::Dot);\n\t\t\t\t\t\t\t\tchoiceName = choiceName + ReadToken(TokenType::Identifier).Content;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tReadToken(TokenType::OpAssign);\n\n\t\t\t\t\t\t\twhile (reader.PeekTokenType() != TokenType::EndOfFile)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tauto name = ReadToken(TokenType::Identifier).Content;\n\t\t\t\t\t\t\t\tString value;\n\t\t\t\t\t\t\t\tif (LookAheadToken(\":\"))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tReadToken(\":\");\n\t\t\t\t\t\t\t\t\tvalue = ReadToken(TokenType::StringLiterial).Content;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tadditionalAttributes[name] = value;\n\t\t\t\t\t\t\t\tif (LookAheadToken(\",\"))\n\t\t\t\t\t\t\t\t\tReadToken(TokenType::Comma);\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tschedule.AddtionalAttributes[choiceName] = additionalAttributes;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tString choiceName = ReadToken(TokenType::Identifier).Content;\n\t\t\t\t\t\t\twhile (LookAheadToken(\".\"))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tchoiceName = choiceName + \".\";\n\t\t\t\t\t\t\t\tReadToken(TokenType::Dot);\n\t\t\t\t\t\t\t\tchoiceName = choiceName + ReadToken(TokenType::Identifier).Content;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tReadToken(TokenType::OpAssign);\n\t\t\t\t\t\t\tList<RefPtr<ChoiceValueSyntaxNode>> worlds;\n\t\t\t\t\t\t\twhile (reader.PeekTokenType() != TokenType::EndOfFile)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tauto token = ReadToken(TokenType::StringLiterial);\n\t\t\t\t\t\t\t\tRefPtr<ChoiceValueSyntaxNode> choiceValue = new ChoiceValueSyntaxNode();\n\t\t\t\t\t\t\t\tchoiceValue->Position = token.Position;\n\t\t\t\t\t\t\t\tchoiceValue->WorldName = token.Content;\n\t\t\t\t\t\t\t\tworlds.Add(choiceValue);\n\t\t\t\t\t\t\t\tif (LookAheadToken(\",\"))\n\t\t\t\t\t\t\t\t\tReadToken(TokenType::Comma);\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tschedule.Choices[choiceName] = worlds;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tReadToken(TokenType::Semicolon);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (...)\n\t\t\t\t{\n\t\t\t\t}\n\t\t\t\treturn schedule;\n\t\t\t}\n\t\t};\n\t\n\t\tSchedule Schedule::Parse(String source, String fileName, DiagnosticSink * sink)\n\t\t{\n\t\t\treturn ScheduleParser(sink).Parse(source, fileName);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/Schedule.h",
    "content": "#ifndef BAKER_SL_SCHEDULE_H\n#define BAKER_SL_SCHEDULE_H\n\n#include \"../CoreLib/Basic.h\"\n#include \"Diagnostics.h\"\n#include \"Syntax.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tclass Schedule\n\t\t{\n\t\tpublic:\n\t\t\tCoreLib::EnumerableDictionary<CoreLib::String, CoreLib::List<RefPtr<ChoiceValueSyntaxNode>>> Choices;\n\t\t\tCoreLib::EnumerableDictionary<CoreLib::String, CoreLib::EnumerableDictionary<CoreLib::String, CoreLib::String>> AddtionalAttributes;\n\t\t\tstatic Schedule Parse(CoreLib::String source, CoreLib::String fileName, DiagnosticSink * sink);\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/ScopeDictionary.h",
    "content": "#ifndef RASTER_RENDERER_SCOPE_DICTIONARY_H\n#define RASTER_RENDERER_SCOPE_DICTIONARY_H\n\n#include \"../CoreLib/Basic.h\"\n\nusing namespace CoreLib::Basic;\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\ttemplate <typename TKey, typename TValue>\n\t\tclass ScopeDictionary\n\t\t{\n\t\tpublic:\n\t\t\tLinkedList<Dictionary<TKey, TValue>> dicts;\n\t\tpublic:\n\t\t\tvoid PushScope()\n\t\t\t{\n\t\t\t\tdicts.AddLast();\n\t\t\t}\n\t\t\tvoid PopScope()\n\t\t\t{\n\t\t\t\tdicts.Delete(dicts.LastNode());\n\t\t\t}\n\t\t\tbool TryGetValue(const TKey & key, TValue & value)\n\t\t\t{\n\t\t\t\tfor (auto iter = dicts.LastNode(); iter; iter = iter->GetPrevious())\n\t\t\t\t{\n\t\t\t\t\tbool rs = iter->Value.TryGetValue(key, value);\n\t\t\t\t\tif (rs)\n\t\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tbool TryGetValueInCurrentScope(const TKey & key, TValue & value)\n\t\t\t{\n\t\t\t\treturn dicts.Last().TryGetValue(key, value);\n\t\t\t}\n\t\t\tvoid Add(const TKey & key, const TValue & value)\n\t\t\t{\n\t\t\t\tdicts.Last().Add(key, value);\n\t\t\t}\n\t\t\tvoid Set(const TKey & key, const TValue & value)\n\t\t\t{\n\t\t\t\tdicts.Last()[key] = value;\n\t\t\t}\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/SemanticsVisitor.cpp",
    "content": "#include \"SyntaxVisitors.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tbool IsNumeric(BaseType t)\n\t\t{\n\t\t\treturn t == BaseType::Int || t == BaseType::Float || t == BaseType::UInt;\n\t\t}\n\n\t\tString GetFullComponentName(ComponentSyntaxNode * comp)\n\t\t{\n\t\t\tStringBuilder sb;\n\t\t\tsb << comp->Name.Content;\n\t\t\tfor (auto & param : comp->GetParameters())\n\t\t\t{\n\t\t\t\tsb << \"@\" << param->Type->ToString();\n\t\t\t}\n\t\t\treturn sb.ProduceString();\n\t\t}\n\n\t\tString TranslateHLSLTypeNames(String name)\n\t\t{\n\t\t\tif (name == \"float2\" || name == \"half2\")\n\t\t\t\treturn \"vec2\";\n\t\t\telse if (name == \"float3\" || name == \"half3\")\n\t\t\t\treturn \"vec3\";\n\t\t\telse if (name == \"float4\" || name == \"half4\")\n\t\t\t\treturn \"vec4\";\n\t\t\telse if (name == \"half\")\n\t\t\t\treturn \"float\";\n\t\t\telse if (name == \"int2\")\n\t\t\t\treturn \"ivec2\";\n\t\t\telse if (name == \"int3\")\n\t\t\t\treturn \"ivec3\";\n\t\t\telse if (name == \"int4\")\n\t\t\t\treturn \"ivec4\";\n\t\t\telse if (name == \"uint2\")\n\t\t\t\treturn \"uvec2\";\n\t\t\telse if (name == \"uint3\")\n\t\t\t\treturn \"uvec3\";\n\t\t\telse if (name == \"uint4\")\n\t\t\t\treturn \"uvec4\";\n\t\t\telse if (name == \"float3x3\" || name == \"half3x3\")\n\t\t\t\treturn \"mat3\";\n\t\t\telse if (name == \"float4x4\" || name == \"half4x4\")\n\t\t\t\treturn \"mat4\";\n\t\t\telse\n\t\t\t\treturn name;\n\t\t}\n\n\t\tclass SemanticsVisitor : public SyntaxVisitor\n\t\t{\n\t\t\tProgramSyntaxNode * program = nullptr;\n\t\t\tFunctionSyntaxNode * function = nullptr;\n\t\t\tFunctionSymbol * currentFunc = nullptr;\n\t\t\tShaderSymbol * currentShader = nullptr;\n\t\t\tPipelineSymbol * currentPipeline = nullptr;\n\t\t\tImportOperatorDefSyntaxNode * currentImportOperator = nullptr;\n\t\t\tShaderComponentSymbol * currentComp = nullptr;\n\t\t\tComponentSyntaxNode * currentCompNode = nullptr;\n\t\t\tList<SyntaxNode *> loops;\n\t\t\tSymbolTable * symbolTable;\n\t\tpublic:\n\t\t\tSemanticsVisitor(SymbolTable * symbols, DiagnosticSink * pErr)\n\t\t\t\t:SyntaxVisitor(pErr), symbolTable(symbols)\n\t\t\t{\n\t\t\t}\n\t\t\t// return true if world0 depends on world1 (there exists a series of import operators that converts world1 variables to world0)\n\t\t\tbool IsWorldDependent(PipelineSymbol * pipeline, String world0, String world1)\n\t\t\t{\n\t\t\t\tHashSet<String> depWorldsSet;\n\t\t\t\tList<String> depWorlds;\n\t\t\t\tdepWorlds.Add(world0);\n\t\t\t\tfor (int i = 0; i < depWorlds.Count(); i++)\n\t\t\t\t{\n\t\t\t\t\tauto & dep = pipeline->WorldDependency[world0].GetValue();\n\t\t\t\t\tif (dep.Contains(world1))\n\t\t\t\t\t\treturn true;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto w : dep)\n\t\t\t\t\t\t\tif (depWorldsSet.Add(w))\n\t\t\t\t\t\t\t\tdepWorlds.Add(w);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\tpublic:\n\t\t\t// Translate Types\n\t\t\tRefPtr<ExpressionType> typeResult;\n\t\t\tRefPtr<ExpressionType> TranslateTypeNode(const RefPtr<TypeSyntaxNode> & node)\n\t\t\t{\n\t\t\t\tnode->Accept(this);\n\t\t\t\treturn typeResult;\n\t\t\t}\n\t\t\tRefPtr<TypeSyntaxNode> VisitBasicType(BasicTypeSyntaxNode * typeNode) override\n\t\t\t{\n\t\t\t\tRefPtr<BasicExpressionType> expType = new BasicExpressionType();\n\t\t\t\tif (typeNode->TypeName == \"int\")\n\t\t\t\t\texpType->BaseType = BaseType::Int;\n\t\t\t\telse if (typeNode->TypeName == \"uint\")\n\t\t\t\t\texpType->BaseType = BaseType::UInt;\n\t\t\t\telse if (typeNode->TypeName == \"float\" || typeNode->TypeName == \"half\")\n\t\t\t\t\texpType->BaseType = BaseType::Float;\n\t\t\t\telse if (typeNode->TypeName == \"ivec2\" || typeNode->TypeName == \"int2\")\n\t\t\t\t\texpType->BaseType = BaseType::Int2;\n\t\t\t\telse if (typeNode->TypeName == \"ivec3\" || typeNode->TypeName == \"int3\")\n\t\t\t\t\texpType->BaseType = BaseType::Int3;\n\t\t\t\telse if (typeNode->TypeName == \"ivec4\" || typeNode->TypeName == \"int4\")\n\t\t\t\t\texpType->BaseType = BaseType::Int4;\n\t\t\t\telse if (typeNode->TypeName == \"uvec2\" || typeNode->TypeName == \"uint2\")\n\t\t\t\t\texpType->BaseType = BaseType::UInt2;\n\t\t\t\telse if (typeNode->TypeName == \"uvec3\" || typeNode->TypeName == \"uint3\")\n\t\t\t\t\texpType->BaseType = BaseType::UInt3;\n\t\t\t\telse if (typeNode->TypeName == \"uvec4\" || typeNode->TypeName == \"uint4\")\n\t\t\t\t\texpType->BaseType = BaseType::UInt4;\n\t\t\t\telse if (typeNode->TypeName == \"vec2\" || typeNode->TypeName == \"float2\" || typeNode->TypeName == \"half2\")\n\t\t\t\t\texpType->BaseType = BaseType::Float2;\n\t\t\t\telse if (typeNode->TypeName == \"vec3\" || typeNode->TypeName == \"float3\" || typeNode->TypeName == \"half3\")\n\t\t\t\t\texpType->BaseType = BaseType::Float3;\n\t\t\t\telse if (typeNode->TypeName == \"vec4\" || typeNode->TypeName == \"float4\" || typeNode->TypeName == \"half4\")\n\t\t\t\t\texpType->BaseType = BaseType::Float4;\n\t\t\t\telse if (typeNode->TypeName == \"mat3\" || typeNode->TypeName == \"mat3x3\" || typeNode->TypeName == \"float3x3\" || typeNode->TypeName == \"half3x3\")\n\t\t\t\t\texpType->BaseType = BaseType::Float3x3;\n\t\t\t\telse if (typeNode->TypeName == \"mat4\" || typeNode->TypeName == \"mat4x4\" || typeNode->TypeName == \"float4x4\" || typeNode->TypeName == \"half4x4\")\n\t\t\t\t\texpType->BaseType = BaseType::Float4x4;\n\t\t\t\telse if (typeNode->TypeName == \"texture\" || typeNode->TypeName == \"Texture\" || typeNode->TypeName == \"Texture2D\")\n\t\t\t\t\texpType->BaseType = BaseType::Texture2D;\n\t\t\t\telse if (typeNode->TypeName == \"TextureCUBE\" || typeNode->TypeName == \"TextureCube\")\n\t\t\t\t\texpType->BaseType = BaseType::TextureCube;\n\t\t\t\telse if (typeNode->TypeName == \"TextureCubeArray\")\n\t\t\t\t\texpType->BaseType = BaseType::TextureCubeArray;\n\t\t\t\telse if (typeNode->TypeName == \"TextureCubeShadowArray\" || typeNode->TypeName == \"TextureCubeArrayShadow\")\n\t\t\t\t\texpType->BaseType = BaseType::TextureCubeShadowArray;\n\t\t\t\telse if (typeNode->TypeName == \"Texture2DArray\")\n\t\t\t\t\texpType->BaseType = BaseType::Texture2DArray;\n\t\t\t\telse if (typeNode->TypeName == \"Texture2DArrayShadow\")\n\t\t\t\t\texpType->BaseType = BaseType::Texture2DArrayShadow;\n\t\t\t\telse if (typeNode->TypeName == \"Texture2DShadow\")\n\t\t\t\t\texpType->BaseType = BaseType::Texture2DShadow;\n\t\t\t\telse if (typeNode->TypeName == \"TextureCubeShadow\")\n\t\t\t\t\texpType->BaseType = BaseType::TextureCubeShadow;\n\t\t\t\telse if (typeNode->TypeName == \"Texture3D\")\n\t\t\t\t\texpType->BaseType = BaseType::Texture3D;\n\t\t\t\telse if (typeNode->TypeName == \"SamplerState\" || typeNode->TypeName == \"sampler\" || typeNode->TypeName == \"sampler_state\")\n\t\t\t\t\texpType->BaseType = BaseType::SamplerState;\n\t\t\t\telse if (typeNode->TypeName == \"SamplerComparisonState\")\n\t\t\t\t\texpType->BaseType = BaseType::SamplerComparisonState;\n\t\t\t\telse if (typeNode->TypeName == \"void\")\n\t\t\t\t\texpType->BaseType = BaseType::Void;\n\t\t\t\telse if (typeNode->TypeName == \"bool\")\n\t\t\t\t\texpType->BaseType = BaseType::Bool;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\texpType->BaseType = BaseType::Struct;\n\t\t\t\t\tif (auto decl = symbolTable->LookUp(typeNode->TypeName))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (auto structDecl = dynamic_cast<StructSyntaxNode*>(decl))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\texpType->structDecl = structDecl;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (auto typeDefDecl = dynamic_cast<TypeDefDecl*>(decl))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tRefPtr<NamedExpressionType> namedType = new NamedExpressionType();\n\t\t\t\t\t\t\tnamedType->decl = typeDefDecl;\n\n\t\t\t\t\t\t\ttypeResult = namedType;\n\t\t\t\t\t\t\treturn typeNode;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgetSink()->diagnose(typeNode, Diagnostics::undefinedTypeName, typeNode->TypeName);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (currentPipeline || currentShader)\n\t\t\t\t\t{\n\t\t\t\t\t\tPipelineSymbol * pipe = currentPipeline ? currentPipeline : currentShader->ParentPipeline;\n\t\t\t\t\t\tbool matched = false;\n\t\t\t\t\t\tif (pipe)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (pipe->Worlds.ContainsKey(typeNode->TypeName))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\texpType->BaseType = BaseType::Record;\n\t\t\t\t\t\t\t\texpType->RecordTypeName = typeNode->TypeName;\n\t\t\t\t\t\t\t\tmatched = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (currentImportOperator)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (typeNode->TypeName == currentImportOperator->TypeName.Content)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\texpType->BaseType = BaseType::Generic;\n\t\t\t\t\t\t\t\texpType->GenericTypeVar = typeNode->TypeName;\n\t\t\t\t\t\t\t\tmatched = true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!matched)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgetSink()->diagnose(typeNode, Diagnostics::undefinedTypeName, typeNode->TypeName);\n\t\t\t\t\t\t\ttypeResult = ExpressionType::Error;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tgetSink()->diagnose(typeNode, Diagnostics::undefinedTypeName, typeNode->TypeName);\n\t\t\t\t\t\ttypeResult = ExpressionType::Error;\n\t\t\t\t\t\treturn typeNode;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttypeResult = expType;\n\t\t\t\treturn typeNode;\n\t\t\t}\n\t\t\tRefPtr<TypeSyntaxNode> VisitArrayType(ArrayTypeSyntaxNode * typeNode) override\n\t\t\t{\n\t\t\t\tRefPtr<ArrayExpressionType> rs = new ArrayExpressionType();\n\t\t\t\trs->ArrayLength = typeNode->ArrayLength;\n\t\t\t\ttypeNode->BaseType->Accept(this);\n\t\t\t\trs->BaseType = typeResult;\n\t\t\t\ttypeResult = rs;\n\t\t\t\treturn typeNode;\n\t\t\t}\n\t\t\tRefPtr<TypeSyntaxNode> VisitGenericType(GenericTypeSyntaxNode * typeNode) override\n\t\t\t{\n\t\t\t\tRefPtr<GenericExpressionType> rs = new GenericExpressionType();\n\t\t\t\ttypeNode->BaseType->Accept(this);\n\t\t\t\trs->BaseType = typeResult;\n\t\t\t\trs->GenericTypeName = typeNode->GenericTypeName;\n\t\t\t\tif (rs->GenericTypeName != \"PackedBuffer\" &&\n\t\t\t\t\trs->GenericTypeName != \"StructuredBuffer\" &&\n\t\t\t\t\trs->GenericTypeName != \"RWStructuredBuffer\" &&\n\t\t\t\t\trs->GenericTypeName != \"Uniform\" &&\n\t\t\t\t\trs->GenericTypeName != \"Patch\" &&\n\t\t\t\t\trs->GenericTypeName != \"PackedBuffer\")\n\t\t\t\t{\n\t\t\t\t\tgetSink()->diagnose(typeNode, Diagnostics::undefinedIdentifier, rs->GenericTypeName);\n\t\t\t\t}\n\t\t\t\ttypeResult = rs;\n\t\t\t\treturn typeNode;\n\t\t\t}\n\t\tpublic:\n\t\t\tRefPtr<PipelineSyntaxNode> VisitPipeline(PipelineSyntaxNode * pipeline) override\n\t\t\t{\n\t\t\t\tRefPtr<PipelineSymbol> psymbol = new PipelineSymbol();\n\t\t\t\tpsymbol->SyntaxNode = pipeline;\n\t\t\t\tif (pipeline->ParentPipelineName.Content.Length())\n\t\t\t\t{\n\t\t\t\t\tRefPtr<PipelineSymbol> parentPipeline;\n\t\t\t\t\tif (symbolTable->Pipelines.TryGetValue(pipeline->ParentPipelineName.Content, parentPipeline))\n\t\t\t\t\t{\n\t\t\t\t\t\tpsymbol->ParentPipeline = parentPipeline.Ptr();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tgetSink()->diagnose(pipeline->ParentPipelineName, Diagnostics::undefinedPipelineName, pipeline->ParentPipelineName.Content);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcurrentPipeline = psymbol.Ptr();\n\t\t\t\tsymbolTable->Pipelines.Add(pipeline->Name.Content, psymbol);\n\t\t\t\tfor (auto world : pipeline->GetWorlds())\n\t\t\t\t{\n\t\t\t\t\tif (!psymbol->Worlds.ContainsKey(world->Name.Content))\n\t\t\t\t\t{\n\t\t\t\t\t\tpsymbol->Worlds.Add(world->Name.Content, world.Ptr());\n\t\t\t\t\t\tpsymbol->WorldDependency.Add(world->Name.Content, EnumerableHashSet<String>());\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tgetSink()->diagnose(world.Ptr(), Diagnostics::worldNameAlreadyDefined, world->Name.Content);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (auto comp : pipeline->GetAbstractComponents())\n\t\t\t\t{\n\t\t\t\t\tcomp->Type = TranslateTypeNode(comp->TypeNode);\n\t\t\t\t\tif (comp->IsRequire() || comp->IsInput() || (comp->Rate && comp->Rate->Worlds.Count() == 1\n\t\t\t\t\t\t&& psymbol->IsAbstractWorld(comp->Rate->Worlds.First().World.Content)))\n\t\t\t\t\t\tAddNewComponentSymbol(psymbol->Components, psymbol->FunctionComponents, comp);\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tgetSink()->diagnose(comp.Ptr(), Diagnostics::cannotDefineComponentsInAPipeline);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (auto & op : pipeline->GetImportOperators())\n\t\t\t\t{\n\t\t\t\t\tpsymbol->AddImportOperator(op);\n\t\t\t\t}\n\t\t\t\t// add initial world dependency edges\n\t\t\t\tfor (auto op : pipeline->GetImportOperators())\n\t\t\t\t{\n\t\t\t\t\tif (!psymbol->WorldDependency.ContainsKey(op->DestWorld.Content))\n\t\t\t\t\t\tgetSink()->diagnose(op->DestWorld, Diagnostics::undefinedWorldName, op->DestWorld.Content);\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (psymbol->Worlds[op->DestWorld.Content].GetValue()->IsAbstract())\n\t\t\t\t\t\t\tgetSink()->diagnose(op->DestWorld, Diagnostics::abstractWorldAsTargetOfImport);\n\t\t\t\t\t\telse if (!psymbol->WorldDependency.ContainsKey(op->SourceWorld.Content))\n\t\t\t\t\t\t\tgetSink()->diagnose(op->SourceWorld, Diagnostics::undefinedWorldName2, op->SourceWorld.Content);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (IsWorldDependent(psymbol.Ptr(), op->SourceWorld.Content, op->DestWorld.Content))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tgetSink()->diagnose(op->Name, Diagnostics::importOperatorCircularity, op->Name.Content, op->SourceWorld.Content, op->DestWorld.Content);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tpsymbol->WorldDependency[op->DestWorld.Content].GetValue().Add(op->SourceWorld.Content);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\t// propagate world dependency graph\n\t\t\t\tbool changed = true;\n\t\t\t\twhile (changed)\n\t\t\t\t{\n\t\t\t\t\tchanged = false;\n\t\t\t\t\tfor (auto world : pipeline->GetWorlds())\n\t\t\t\t\t{\n\t\t\t\t\t\tEnumerableHashSet<String> & dependentWorlds = psymbol->WorldDependency[world->Name.Content].GetValue();\n\t\t\t\t\t\tList<String> loopRange;\n\t\t\t\t\t\tfor (auto w : dependentWorlds)\n\t\t\t\t\t\t\tloopRange.Add(w);\n\t\t\t\t\t\tfor (auto w : loopRange)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEnumerableHashSet<String> & ddw = psymbol->WorldDependency[w].GetValue();\n\t\t\t\t\t\t\tfor (auto ww : ddw)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (!dependentWorlds.Contains(ww))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tdependentWorlds.Add(ww);\n\t\t\t\t\t\t\t\t\tchanged = true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (auto & op : pipeline->GetImportOperators())\n\t\t\t\t{\n\t\t\t\t\tcurrentImportOperator = op.Ptr();\n\t\t\t\t\tHashSet<String> paraNames;\n\t\t\t\t\tfor (auto & para : op->GetParameters())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (paraNames.Contains(para->Name.Content))\n\t\t\t\t\t\t\tgetSink()->diagnose(para.Ptr(), Diagnostics::parameterAlreadyDefined, para->Name);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tparaNames.Add(para->Name.Content);\n\t\t\t\t\t\tpara->Type = TranslateTypeNode(para->TypeNode);\n\t\t\t\t\t\tif (para->Type->Equals(ExpressionType::Void.Ptr()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgetSink()->diagnose(para.Ptr(), Diagnostics::parameterCannotBeVoid);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tauto oldSymFuncs = symbolTable->Functions;\n\t\t\t\t\tauto oldSymFuncOverloads = symbolTable->FunctionOverloads;\n\t\t\t\t\tfor (auto req : op->Requirements)\n\t\t\t\t\t{\n\t\t\t\t\t\tVisitFunctionDeclaration(req.Ptr());\n\t\t\t\t\t}\n\t\t\t\t\top->Body->Accept(this);\n\t\t\t\t\tsymbolTable->Functions = oldSymFuncs;\n\t\t\t\t\tsymbolTable->FunctionOverloads = oldSymFuncOverloads;\n\t\t\t\t\tcurrentImportOperator = nullptr;\n\t\t\t\t}\n\t\t\t\tcurrentPipeline = nullptr;\n\t\t\t\treturn pipeline;\n\t\t\t}\n\n\t\t\tvirtual CoreLib::RefPtr<InterfaceSyntaxNode> VisitInterface(InterfaceSyntaxNode * interfaceNode) override\n\t\t\t{\n\t\t\t\tfor (auto & comp : interfaceNode->GetComponents())\n\t\t\t\t{\n\t\t\t\t\tinterfaceNode->Scope->decls.AddIfNotExists(comp->Name.Content, comp.Ptr());\n\t\t\t\t\tfor (auto & param : comp->GetParameters())\n\t\t\t\t\t{\n\t\t\t\t\t\tparam->Type = TranslateTypeNode(param->TypeNode);\n\t\t\t\t\t\tif (param->Expr)\n\t\t\t\t\t\t\tgetSink()->diagnose(param->Expr->Position, Diagnostics::defaultParamNotAllowedInInterface, param->Name);\n\t\t\t\t\t}\n\t\t\t\t\tcomp->Type = TranslateTypeNode(comp->TypeNode);\n\t\t\t\t\tif (comp->Expression)\n\t\t\t\t\t\tcomp->Expression->Accept(this);\n\t\t\t\t\tif (comp->BlockStatement)\n\t\t\t\t\t\tcomp->BlockStatement->Accept(this);\n\t\t\t\t}\n\t\t\t\treturn interfaceNode;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<ImportSyntaxNode> VisitImport(ImportSyntaxNode * import) override\n\t\t\t{\n\t\t\t\tRefPtr<ShaderSymbol> refShader;\n\t\t\t\tsymbolTable->Shaders.TryGetValue(import->ShaderName.Content, refShader);\n\t\t\t\tif (refShader)\n\t\t\t\t{\n\t\t\t\t\t// type check\n\t\t\t\t\tList<ShaderComponentSymbol*> paramList;\n\t\t\t\t\tfor (auto & comp : refShader->Components)\n\t\t\t\t\t\tif (comp.Value->IsRequire())\n\t\t\t\t\t\t\tparamList.Add(comp.Value.Ptr());\n\t\t\t\t\tint position = 0;\n\t\t\t\t\tbool namedArgumentAppeared = false;\n\t\t\t\t\tfor (auto & arg : import->Arguments)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (arg->ArgumentName.Content.Length())\n\t\t\t\t\t\t\tnamedArgumentAppeared = true;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (namedArgumentAppeared)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tgetSink()->diagnose(arg->Expression.Ptr(), Diagnostics::positionArgumentAfterNamed);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (position >= paramList.Count())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tgetSink()->diagnose(arg->Expression.Ptr(), Diagnostics::tooManyArguments);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\targ->ArgumentName.Content = paramList[position]->Name;\n\t\t\t\t\t\t\targ->ArgumentName.Position = arg->Position;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tposition++;\n\t\t\t\t\t\tRefPtr<ShaderComponentSymbol> refComp, argComp;\n\t\t\t\t\t\tif (auto funcs = refShader->FunctionComponents.TryGetValue(arg->ArgumentName.Content))\n\t\t\t\t\t\t\tif (funcs->First()->IsRequire())\n\t\t\t\t\t\t\t\trefComp = funcs->First();\n\t\t\t\t\t\tif (!refComp)\n\t\t\t\t\t\t\trefShader->Components.TryGetValue(arg->ArgumentName.Content, refComp);\n\n\t\t\t\t\t\tif (refComp)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (refComp->Implementations.First()->SyntaxNode->IsComponentFunction()) // this is a function parameter\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\targ->ArgumentName.Content = refComp->Name;\n\t\t\t\t\t\t\t\t// construct an invocation node to resolve overloaded component function\n\t\t\t\t\t\t\t\tRefPtr<InvokeExpressionSyntaxNode> tempInvoke = new InvokeExpressionSyntaxNode();\n\t\t\t\t\t\t\t\ttempInvoke->Position = arg->Position;\n\t\t\t\t\t\t\t\ttempInvoke->Scope = arg->Scope;\n\t\t\t\t\t\t\t\ttempInvoke->FunctionExpr = arg->Expression;\n\t\t\t\t\t\t\t\tfor (auto & param : refComp->Implementations.First()->SyntaxNode->GetParameters())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tRefPtr<VarExpressionSyntaxNode> tempArg = new VarExpressionSyntaxNode();\n\t\t\t\t\t\t\t\t\ttempArg->Type = param->Type;\n\t\t\t\t\t\t\t\t\ttempInvoke->Arguments.Add(tempArg);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tauto resolvedExpr = ResolveInvoke(tempInvoke.Ptr());\n\t\t\t\t\t\t\t\tif (auto resolveInvoke = resolvedExpr.As<InvokeExpressionSyntaxNode>())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tauto funcType = resolveInvoke->FunctionExpr->Type->AsBasicType();\n\t\t\t\t\t\t\t\t\tif (funcType->Component)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// modify function name to resolved name\n\t\t\t\t\t\t\t\t\t\tif (auto memberExpr = arg->Expression.As<MemberExpressionSyntaxNode>())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tauto basicType = new BasicExpressionType(BaseType::Function);\n\t\t\t\t\t\t\t\t\t\t\tbasicType->Component = funcType->Component;\n\t\t\t\t\t\t\t\t\t\t\tmemberExpr->Type = basicType;\n\t\t\t\t\t\t\t\t\t\t\t//memberExpr->MemberName = funcType->Component->Name;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse if (auto varExpr = arg->Expression.As<VarExpressionSyntaxNode>())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tvarExpr->Type = funcType;\n\t\t\t\t\t\t\t\t\t\t\t//varExpr->Variable = funcType->Component->Name;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\tgetSink()->diagnose(arg.Ptr(), Diagnostics::ordinaryFunctionAsModuleArgument);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tgetSink()->diagnose(arg.Ptr(), Diagnostics::invalidValueForArgument, arg->ArgumentName.Content);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\targ->Accept(this);\n\t\t\t\t\t\t\t\tif (!refComp->Type->DataType->Equals(arg->Expression->Type.Ptr()))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tgetSink()->diagnose(arg->Expression.Ptr(), Diagnostics::argumentTypeDoesNotMatchParameterType, arg->Expression->Type, refComp->Type->DataType);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (!refComp->IsRequire())\n\t\t\t\t\t\t\t\t\tgetSink()->diagnose(arg->ArgumentName, Diagnostics::nameIsNotAParameterOfCallee, arg->ArgumentName.Content, import->ShaderName.Content);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tgetSink()->diagnose(arg->ArgumentName, Diagnostics::nameIsNotAParameterOfCallee, arg->ArgumentName.Content, import->ShaderName.Content);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn import;\n\t\t\t}\n\n\t\t\tclass ShaderImportVisitor : public SyntaxVisitor\n\t\t\t{\n\t\t\tprivate:\n\t\t\t\tSymbolTable * symbolTable = nullptr;\n\t\t\t\tShaderSymbol * currentShader = nullptr;\n\t\t\t\tShaderComponentSymbol * currentComp = nullptr;\n\t\t\tpublic:\n\t\t\t\tShaderImportVisitor(DiagnosticSink * writer, SymbolTable * symTable)\n\t\t\t\t\t: SyntaxVisitor(writer), symbolTable(symTable)\n\t\t\t\t{}\n\t\t\t\tvirtual RefPtr<ShaderSyntaxNode> VisitShader(ShaderSyntaxNode * shader) override\n\t\t\t\t{\n\t\t\t\t\tcurrentShader = symbolTable->Shaders[shader->Name.Content].GetValue().Ptr();\n\t\t\t\t\tSyntaxVisitor::VisitShader(shader);\n\t\t\t\t\tcurrentShader = nullptr;\n\t\t\t\t\treturn shader;\n\t\t\t\t}\n\t\t\t\tvirtual RefPtr<ComponentSyntaxNode> VisitComponent(ComponentSyntaxNode * comp) override\n\t\t\t\t{\n\t\t\t\t\tRefPtr<ShaderComponentSymbol> compSym;\n\n\t\t\t\t\tcurrentShader->Components.TryGetValue(comp->Name.Content, compSym);\n\t\t\t\t\tcurrentComp = compSym.Ptr();\n\t\t\t\t\tSyntaxVisitor::VisitComponent(comp);\n\t\t\t\t\tif (comp->Expression || comp->BlockStatement)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (comp->IsRequire())\n\t\t\t\t\t\t\tgetSink()->diagnose(comp, Diagnostics::requireWithComputation);\n\t\t\t\t\t\tif (comp->IsParam())\n\t\t\t\t\t\t\tgetSink()->diagnose(comp, Diagnostics::paramWithComputation);\n\t\t\t\t\t}\n\t\t\t\t\tif (compSym->Type->DataType->GetBindableResourceType() != BindableResourceType::NonBindable && !comp->IsParam()\n\t\t\t\t\t\t&& !comp->IsRequire() && !dynamic_cast<InterfaceSyntaxNode*>(comp->ParentDecl))\n\t\t\t\t\t\tgetSink()->diagnose(comp, Diagnostics::resourceTypeMustBeParamOrRequire, comp->Name);\n\t\t\t\t\tif (compSym->Type->DataType->GetBindableResourceType() != BindableResourceType::NonBindable &&\n\t\t\t\t\t\t(comp->Expression || comp->BlockStatement))\n\t\t\t\t\t\tgetSink()->diagnose(comp, Diagnostics::cannotDefineComputationOnResourceType, comp->Name);\n\n\t\t\t\t\tif (comp->HasSimpleAttribute(\"FragDepth\"))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!comp->IsOutput())\n\t\t\t\t\t\t\tgetSink()->diagnose(comp, Diagnostics::fragDepthAttributeCanOnlyApplyToOutput);\n\t\t\t\t\t\tif (!comp->Type->Equals(ExpressionType::Float))\n\t\t\t\t\t\t\tgetSink()->diagnose(comp, Diagnostics::fragDepthAttributeCanOnlyApplyToFloatComponent);\n\t\t\t\t\t}\n\t\t\t\t\tcurrentComp = nullptr;\n\t\t\t\t\treturn comp;\n\t\t\t\t}\n\t\t\t\tvirtual RefPtr<ImportSyntaxNode> VisitImport(ImportSyntaxNode * import) override\n\t\t\t\t{\n\t\t\t\t\tRefPtr<ShaderSymbol> refShader;\n\t\t\t\t\tsymbolTable->Shaders.TryGetValue(import->ShaderName.Content, refShader);\n\t\t\t\t\tif (!refShader)\n\t\t\t\t\t\tgetSink()->diagnose(import->ShaderName, Diagnostics::undefinedIdentifier, import->ShaderName.Content);\n\t\t\t\t\tcurrentShader->DependentShaders.Add(refShader.Ptr());\n\t\t\t\t\tif (!currentComp)\n\t\t\t\t\t{\n\t\t\t\t\t\tShaderUsing su;\n\t\t\t\t\t\tsu.Shader = refShader.Ptr();\n\t\t\t\t\t\tsu.IsPublic = import->IsPublic();\n\t\t\t\t\t\tif (import->IsInplace)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcurrentShader->ShaderUsings.Add(su);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (currentShader->ShaderObjects.ContainsKey(import->ObjectName.Content) ||\n\t\t\t\t\t\t\t\tcurrentShader->Components.ContainsKey(import->ObjectName.Content))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tgetSink()->diagnose(import->ShaderName, Diagnostics::nameAlreadyDefined, import->ShaderName);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcurrentShader->ShaderObjects[import->ObjectName.Content] = su;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (currentComp)\n\t\t\t\t\t\tgetSink()->diagnose(import->ShaderName, Diagnostics::usingInComponentDefinition);\n\t\t\t\t\treturn import;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tvoid CheckShaderInterfaceRequirements(ShaderSymbol * shaderSym)\n\t\t\t{\n\t\t\t\tfor (auto interfaceName : shaderSym->SyntaxNode->InterfaceNames)\n\t\t\t\t{\n\t\t\t\t\tauto interfaceNode = dynamic_cast<InterfaceSyntaxNode*>(symbolTable->LookUp(interfaceName.Content));\n\t\t\t\t\tif (!interfaceNode)\n\t\t\t\t\t{\n\t\t\t\t\t\tgetSink()->diagnose(interfaceName.Position, Diagnostics::undefinedIdentifier, interfaceName);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tfor (auto comp : interfaceNode->GetComponents())\n\t\t\t\t\t{\n\t\t\t\t\t\tauto compRef = shaderSym->ResolveComponentReference(GetFullComponentName(comp.Ptr()));\n\t\t\t\t\t\tif (compRef.IsAccessible)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!compRef.Component->Implementations.First()->SyntaxNode->IsPublic())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tgetSink()->diagnose(compRef.Component->Implementations.First()->SyntaxNode->Position, Diagnostics::interfaceImplMustBePublic, comp->Name.Content, interfaceName);\n\t\t\t\t\t\t\t\tgetSink()->diagnose(comp->Position, Diagnostics::seeInterfaceDefinitionOf, comp->Name);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!compRef.Component->Type->DataType->Equals(comp->Type.Ptr()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tgetSink()->diagnose(compRef.Component->Implementations.First()->SyntaxNode->Position, Diagnostics::componentTypeDoesNotMatchInterface, comp->Name, interfaceName);\n\t\t\t\t\t\t\t\tgetSink()->diagnose(comp->Position, Diagnostics::seeInterfaceDefinitionOf, comp->Name);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!comp->Expression && !comp->BlockStatement) // interface does not define default impl, and shader does not provide impl\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tgetSink()->diagnose(shaderSym->SyntaxNode->Position, Diagnostics::shaderDidNotDefineComponent, shaderSym->SyntaxNode->Name, comp->Name.Content, interfaceName);\n\t\t\t\t\t\t\t\tgetSink()->diagnose(comp->Position, Diagnostics::seeInterfaceDefinitionOf, comp->Name);\n\t\t\t\t\t\t\t\tif (compRef.Component)\n\t\t\t\t\t\t\t\t\tgetSink()->diagnose(compRef.Component->Implementations.First()->SyntaxNode->Position, Diagnostics::doYouForgetToMakeComponentAccessible, comp->Name,\n\t\t\t\t\t\t\t\t\t\tshaderSym->SyntaxNode->Name);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse // if interface provides default impl, add it to shader\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tCloneContext ctx;\n\t\t\t\t\t\t\t\tauto newComp = comp->Clone(ctx);\n\t\t\t\t\t\t\t\tshaderSym->SyntaxNode->Members.Add(newComp);\n\t\t\t\t\t\t\t\tnewComp->modifiers.flags |= Public;\n\t\t\t\t\t\t\t\tAddNewComponentSymbol(shaderSym->Components, shaderSym->FunctionComponents, newComp);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// pass 1: fill components in shader symbol table\n\t\t\tvoid VisitShaderPass1(ShaderSyntaxNode * shader)\n\t\t\t{\n\t\t\t\tHashSet<String> inheritanceSet;\n\t\t\t\tauto curShader = shader;\n\t\t\t\tinheritanceSet.Add(curShader->Name.Content);\n\t\t\t\tauto & shaderSymbol = symbolTable->Shaders[curShader->Name.Content].GetValue();\n\t\t\t\tthis->currentShader = shaderSymbol.Ptr();\n\n\t\t\t\tif (shader->ParentPipelineName.Content.Length() == 0) // implicit pipeline\n\t\t\t\t{\n\t\t\t\t\tif (program->GetPipelines().Count() == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tshader->ParentPipelineName = shader->Name; // get line and col from shader name\n\t\t\t\t\t\tshader->ParentPipelineName.Content = program->GetPipelines().First()->Name.Content;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!shader->IsModule)\n\t\t\t\t\t{\n\t\t\t\t\t\t// current compilation context has more than one pipeline defined,\n\t\t\t\t\t\t// in which case we do not allow implicit pipeline specification\n\t\t\t\t\t\tgetSink()->diagnose(curShader->Name, Diagnostics::explicitPipelineSpecificationRequiredForShader, shader->Name.Content);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tauto pipelineName = shader->ParentPipelineName.Content;\n\t\t\t\tif (pipelineName.Length())\n\t\t\t\t{\n\t\t\t\t\tauto pipeline = symbolTable->Pipelines.TryGetValue(pipelineName);\n\t\t\t\t\tif (pipeline)\n\t\t\t\t\t\tshaderSymbol->ParentPipeline = pipeline->Ptr();\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tgetSink()->diagnose(shader->ParentPipelineName, Diagnostics::undefinedPipelineName, pipelineName);\n\t\t\t\t\t\tthrow 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (shader->IsModule)\n\t\t\t\t\tshaderSymbol->IsAbstract = true;\n\t\t\t\t// add components to symbol table\n\t\t\t\tfor (auto & mbr : shader->Members)\n\t\t\t\t{\n\t\t\t\t\tif (auto comp = dynamic_cast<ComponentSyntaxNode*>(mbr.Ptr()))\n\t\t\t\t\t{\n\t\t\t\t\t\tcomp->Type = TranslateTypeNode(comp->TypeNode);\n\t\t\t\t\t\tif (comp->IsRequire())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tshaderSymbol->IsAbstract = true;\n\t\t\t\t\t\t\tif (!shaderSymbol->SyntaxNode->IsModule)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tgetSink()->diagnose(shaderSymbol->SyntaxNode, Diagnostics::parametersOnlyAllowedInModules);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (auto & param : comp->GetParameters())\n\t\t\t\t\t\t\tparam->Type = TranslateTypeNode(param->TypeNode);\n\t\t\t\t\t\tAddNewComponentSymbol(shaderSymbol->Components, shaderSymbol->FunctionComponents, comp);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// add shader objects to symbol table\n\t\t\t\tShaderImportVisitor importVisitor(sink, symbolTable);\n\t\t\t\tshader->Accept(&importVisitor);\n\n\t\t\t\tthis->currentShader = nullptr;\n\t\t\t}\n\t\t\t// pass 2: type checking component definitions\n\t\t\tvoid VisitShaderPass2(ShaderSyntaxNode * shaderNode)\n\t\t\t{\n\t\t\t\tRefPtr<ShaderSymbol> shaderSym;\n\t\t\t\tif (!symbolTable->Shaders.TryGetValue(shaderNode->Name.Content, shaderSym))\n\t\t\t\t\treturn;\n\t\t\t\tCheckShaderInterfaceRequirements(shaderSym.Ptr());\n\t\t\t\tthis->currentShader = shaderSym.Ptr();\n\t\t\t\tfor (auto & comp : shaderNode->Members)\n\t\t\t\t{\n\t\t\t\t\tcomp->Accept(this);\n\t\t\t\t}\n\t\t\t\tthis->currentShader = nullptr;\n\t\t\t}\n\n\t\t\tbool MatchType_GenericType(String typeName, ExpressionType * valueType)\n\t\t\t{\n\t\t\t\tif (auto basicType = valueType->AsBasicType())\n\t\t\t\t\treturn basicType->GenericTypeVar == typeName;\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tbool MatchType_ValueReceiver(ExpressionType * receiverType, ExpressionType * valueType)\n\t\t\t{\n\t\t\t\tif (receiverType->Equals(valueType))\n\t\t\t\t\treturn true;\n\t\t\t\tif (receiverType->IsIntegral() && valueType->Equals(ExpressionType::Int.Ptr()))\n\t\t\t\t\treturn true;\n\t\t\t\tif (receiverType->Equals(ExpressionType::Float.Ptr()) && valueType->IsIntegral())\n\t\t\t\t\treturn true;\n\t\t\t\tif (receiverType->IsVectorType() && valueType->IsVectorType())\n\t\t\t\t{\n\t\t\t\t\tauto recieverBasicType = receiverType->AsBasicType();\n\t\t\t\t\tauto valueBasicType = valueType->AsBasicType();\n\t\t\t\t\tif (GetVectorBaseType(recieverBasicType->BaseType) == BaseType::Float &&\n\t\t\t\t\t\tGetVectorSize(recieverBasicType->BaseType) == GetVectorSize(valueBasicType->BaseType))\n\t\t\t\t\t\treturn true;\n\t\t\t\t\tif (GetVectorBaseType(recieverBasicType->BaseType) == BaseType::UInt &&\n\t\t\t\t\t\tGetVectorBaseType(valueBasicType->BaseType) == BaseType::Int &&\n\t\t\t\t\t\tGetVectorSize(recieverBasicType->BaseType) == GetVectorSize(valueBasicType->BaseType))\n\t\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvirtual RefPtr<ComponentSyntaxNode> VisitComponent(ComponentSyntaxNode * comp) override\n\t\t\t{\n\t\t\t\tthis->currentCompNode = comp;\n\t\t\t\tRefPtr<ShaderComponentSymbol> compSym;\n\t\t\t\tcurrentShader->Components.TryGetValue(comp->Name.Content, compSym);\n\t\t\t\tthis->currentComp = compSym.Ptr();\n\t\t\t\tif (auto specialize = comp->FindSpecializeModifier())\n\t\t\t\t{\n\t\t\t\t\tif (!comp->IsParam())\n\t\t\t\t\t\tgetSink()->diagnose(comp->Position, Diagnostics::specializeCanOnlyBeUsedOnParam);\n\t\t\t\t\tif (!compSym->Type->DataType->Equals(ExpressionType::Int) && !compSym->Type->DataType->Equals(ExpressionType::Bool)\n\t\t\t\t\t\t&& !compSym->Type->DataType->Equals(ExpressionType::UInt))\n\t\t\t\t\t\tgetSink()->diagnose(comp->Position, Diagnostics::specializedParameterMustBeInt);\n\t\t\t\t\tfor (auto & val : specialize->Values)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!dynamic_cast<ConstantExpressionSyntaxNode*>(val.Ptr()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgetSink()->diagnose(val->Position, Diagnostics::specializationValuesMustBeConstantLiterial);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tval->Accept(this);\n\t\t\t\t\t\tif (!val->Type->Equals(compSym->Type->DataType))\n\t\t\t\t\t\t\tgetSink()->diagnose(val->Position, Diagnostics::typeMismatch, val->Type, currentComp->Type);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (auto & param : comp->GetParameters())\n\t\t\t\t{\n\t\t\t\t\tparam->Accept(this);\n\t\t\t\t}\n\t\t\t\tif (comp->Expression)\n\t\t\t\t{\n\t\t\t\t\tcomp->Expression = comp->Expression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\t\tif (!MatchType_ValueReceiver(compSym->Type->DataType.Ptr(), comp->Expression->Type.Ptr()) &&\n\t\t\t\t\t\t!comp->Expression->Type->Equals(ExpressionType::Error.Ptr()))\n\t\t\t\t\t\tgetSink()->diagnose(comp->Name, Diagnostics::typeMismatch, comp->Expression->Type, currentComp->Type);\n\t\t\t\t}\n\t\t\t\tif (comp->BlockStatement)\n\t\t\t\t\tcomp->BlockStatement->Accept(this);\n\n\t\t\t\tthis->currentComp = nullptr;\n\t\t\t\tthis->currentCompNode = nullptr;\n\t\t\t\treturn comp;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitImportStatement(ImportStatementSyntaxNode * importStmt) override\n\t\t\t{\n\t\t\t\timportStmt->Import->Accept(this);\n\t\t\t\treturn importStmt;\n\t\t\t}\n\t\t\tvoid AddNewComponentSymbol(EnumerableDictionary<String, RefPtr<ShaderComponentSymbol>> & components,\n\t\t\t\tEnumerableDictionary<String, List<RefPtr<ShaderComponentSymbol>>> & funcComponents,\n\t\t\t\tRefPtr<ComponentSyntaxNode> comp)\n\t\t\t{\n\t\t\t\tRefPtr<ShaderComponentSymbol> compSym;\n\t\t\t\tRefPtr<ShaderComponentImplSymbol> compImpl = new ShaderComponentImplSymbol();\n\t\t\t\tif (comp->Rate)\n\t\t\t\t\tfor (auto w : comp->Rate->Worlds)\n\t\t\t\t\t\tcompImpl->Worlds.Add(w.World.Content);\n\t\t\t\tcompImpl->SyntaxNode = comp;\n\t\t\t\tif (compImpl->SyntaxNode->Rate)\n\t\t\t\t{\n\t\t\t\t\tfor (auto & w : compImpl->SyntaxNode->Rate->Worlds)\n\t\t\t\t\t\tif (w.Pinned)\n\t\t\t\t\t\t\tcompImpl->SrcPinnedWorlds.Add(w.World.Content);\n\t\t\t\t}\n\t\t\t\tif (compImpl->SyntaxNode->IsOutput())\n\t\t\t\t{\n\t\t\t\t\tif (compImpl->SyntaxNode->Rate)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto & w : compImpl->SyntaxNode->Rate->Worlds)\n\t\t\t\t\t\t\tcompImpl->ExportWorlds.Add(w.World.Content);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tgetSink()->diagnose(compImpl->SyntaxNode.Ptr(), Diagnostics::componentMarkedExportMustHaveWorld, compImpl->SyntaxNode->Name);\n\t\t\t\t\t}\n\t\t\t\t\tif (compImpl->SyntaxNode->IsComponentFunction())\n\t\t\t\t\t\tgetSink()->diagnose(compImpl->SyntaxNode->Name, Diagnostics::componetMarkedExportCannotHaveParameters, compImpl->SyntaxNode->Name);\n\t\t\t\t}\n\t\t\t\tauto compName = GetFullComponentName(comp.Ptr());\n\t\t\t\tif (!components.TryGetValue(compName, compSym))\n\t\t\t\t{\n\t\t\t\t\tcompSym = new ShaderComponentSymbol();\n\t\t\t\t\tcompSym->Type = new Type();\n\t\t\t\t\tcompSym->Name = compName;\n\t\t\t\t\tcompSym->Type->DataType = comp->Type;\n\t\t\t\t\tcomponents.Add(compName, compSym);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (comp->IsRequire())\n\t\t\t\t\t\tgetSink()->diagnose(compImpl->SyntaxNode.Ptr(), Diagnostics::requirementsClashWithPreviousDef, compImpl->SyntaxNode->Name.Content);\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!compSym->Type->DataType->Equals(comp->Type.Ptr()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgetSink()->diagnose(comp->Name, Diagnostics::componentOverloadTypeMismatch, comp->Name.Content);\n\t\t\t\t\t\t\tgetSink()->diagnose(compSym->Implementations.First()->SyntaxNode, Diagnostics::seePreviousDefinition);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (compImpl->SyntaxNode->IsComponentFunction())\n\t\t\t\t\t{\n\t\t\t\t\t\tgetSink()->diagnose(compImpl->SyntaxNode.Ptr(), Diagnostics::functionRedefinition, compImpl->SyntaxNode->Name.Content);\n\t\t\t\t\t\tgetSink()->diagnose(compSym->Implementations.Last()->SyntaxNode, Diagnostics::seePreviousDefinition);\n\t\t\t\t\t}\n\t\t\t\t\tsymbolTable->CheckComponentImplementationConsistency(sink, compSym.Ptr(), compImpl.Ptr());\n\t\t\t\t}\n\t\t\t\tif (compImpl->SyntaxNode->IsComponentFunction())\n\t\t\t\t{\n\t\t\t\t\tauto list = funcComponents.TryGetValue(comp->Name.Content);\n\t\t\t\t\tif (!list)\n\t\t\t\t\t{\n\t\t\t\t\t\tfuncComponents[comp->Name.Content] = List<RefPtr<ShaderComponentSymbol>>();\n\t\t\t\t\t\tlist = funcComponents.TryGetValue(comp->Name.Content);\n\t\t\t\t\t}\n\t\t\t\t\tcomp->Name.Content = compName;\n\t\t\t\t\tlist->Add(compSym);\n\t\t\t\t}\n\t\t\t\tcompSym->Implementations.Add(compImpl);\n\t\t\t}\n\t\t\tvirtual RefPtr<ProgramSyntaxNode> VisitProgram(ProgramSyntaxNode * programNode) override\n\t\t\t{\n\t\t\t\tHashSet<String> funcNames;\n\t\t\t\tthis->program = programNode;\n\t\t\t\tthis->function = nullptr;\n\t\t\t\tfor (auto & s : program->Members)\n\t\t\t\t{\n\t\t\t\t\tsymbolTable->globalDecls.AddIfNotExists(s->Name.Content, s.Ptr());\n\t\t\t\t}\n\t\t\t\tfor (auto & s : program->GetTypeDefs())\n\t\t\t\t\tVisitTypeDefDecl(s.Ptr());\n\t\t\t\tfor (auto & s : program->GetStructs())\n\t\t\t\t{\n\t\t\t\t\tif (!s->SemanticallyChecked)\n\t\t\t\t\t{\n\t\t\t\t\t\tVisitStruct(s.Ptr());\n\t\t\t\t\t\ts->SemanticallyChecked = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (auto & func : program->GetFunctions())\n\t\t\t\t{\n\t\t\t\t\tif (!func->SemanticallyChecked)\n\t\t\t\t\t{\n\t\t\t\t\t\tVisitFunctionDeclaration(func.Ptr());\n\t\t\t\t\t\tif (funcNames.Contains(func->InternalName))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tStringBuilder argList;\n\t\t\t\t\t\t\targList << \"(\";\n\t\t\t\t\t\t\tbool first = true;\n\t\t\t\t\t\t\tfor (auto & param : func->GetParameters())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (!first)\n\t\t\t\t\t\t\t\t\targList << \", \";\n\t\t\t\t\t\t\t\targList << param->Type->ToString();\n\t\t\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\targList << \")\";\n\t\t\t\t\t\t\tgetSink()->diagnose(func, Diagnostics::functionRedefinitionWithArgList, func->Name, argList.ProduceString());\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tfuncNames.Add(func->InternalName);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (auto & func : program->GetFunctions())\n\t\t\t\t{\n\t\t\t\t\tif (!func->SemanticallyChecked)\n\t\t\t\t\t{\n\t\t\t\t\t\tfunc->Accept(this);\n\t\t\t\t\t\tfunc->SemanticallyChecked = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (auto & pipeline : program->GetPipelines())\n\t\t\t\t{\n\t\t\t\t\tVisitPipeline(pipeline.Ptr());\n\t\t\t\t}\n\t\t\t\tfor (auto & interfaceNode : program->GetInterfaces())\n\t\t\t\t{\n\t\t\t\t\tif (!interfaceNode->SemanticallyChecked)\n\t\t\t\t\t{\n\t\t\t\t\t\tVisitInterface(interfaceNode.Ptr());\n\t\t\t\t\t\tinterfaceNode->SemanticallyChecked = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// build initial symbol table for shaders\n\t\t\t\tfor (auto & shader : program->GetShaders())\n\t\t\t\t{\n\t\t\t\t\tif (!shader->SemanticallyChecked)\n\t\t\t\t\t{\n\t\t\t\t\t\tRefPtr<ShaderSymbol> shaderSym = new ShaderSymbol();\n\t\t\t\t\t\tshaderSym->SyntaxNode = shader.Ptr();\n\t\t\t\t\t\tif (symbolTable->Shaders.ContainsKey(shader->Name.Content))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgetSink()->diagnose(shader->Name, Diagnostics::shaderAlreadyDefined, shader->Name);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsymbolTable->Shaders[shader->Name.Content] = shaderSym;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (auto & shader : program->GetShaders())\n\t\t\t\t{\n\t\t\t\t\tif (!shader->SemanticallyChecked)\n\t\t\t\t\t{\n\t\t\t\t\t\tVisitShaderPass1(shader.Ptr());\n\t\t\t\t\t\tshader->SemanticallyChecked = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (sink->GetErrorCount() != 0)\n\t\t\t\t\treturn programNode;\n\t\t\t\t// shader dependency is discovered in pass 1, we can now sort the shaders\n\t\t\t\tif (!symbolTable->SortShaders())\n\t\t\t\t{\n\t\t\t\t\tHashSet<ShaderSymbol*> sortedShaders;\n\t\t\t\t\tfor (auto & shader : symbolTable->ShaderDependenceOrder)\n\t\t\t\t\t\tsortedShaders.Add(shader);\n\t\t\t\t\tfor (auto & shader : symbolTable->Shaders)\n\t\t\t\t\t\tif (!sortedShaders.Contains(shader.Value.Ptr()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgetSink()->diagnose(shader.Value->SyntaxNode->Name, Diagnostics::shaderCircularity, shader.Key);\n\t\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (auto & shader : symbolTable->ShaderDependenceOrder)\n\t\t\t\t{\n\t\t\t\t\tif (!shader->SemanticallyChecked)\n\t\t\t\t\t{\n\t\t\t\t\t\tVisitShaderPass2(shader->SyntaxNode.Ptr());\n\t\t\t\t\t\tshader->SemanticallyChecked = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn programNode;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<StructSyntaxNode> VisitStruct(StructSyntaxNode * structNode) override\n\t\t\t{\n\t\t\t\tfor (auto field : structNode->GetFields())\n\t\t\t\t{\n\t\t\t\t\tfield->Type = TranslateTypeNode(field->TypeNode);\n\t\t\t\t}\n\t\t\t\treturn structNode;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<TypeDefDecl> VisitTypeDefDecl(TypeDefDecl* decl) override\n\t\t\t{\n\t\t\t\tdecl->Type = TranslateTypeNode(decl->TypeNode);\n\t\t\t\treturn decl;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<FunctionSyntaxNode> VisitFunction(FunctionSyntaxNode *functionNode) override\n\t\t\t{\n\t\t\t\tif (!functionNode->IsExtern())\n\t\t\t\t{\n\t\t\t\t\tcurrentFunc = symbolTable->Functions.TryGetValue(functionNode->InternalName)->Ptr();\n\t\t\t\t\tthis->function = functionNode;\n\t\t\t\t\tfunctionNode->Body->Accept(this);\n\t\t\t\t\tthis->function = NULL;\n\t\t\t\t\tcurrentFunc = nullptr;\n\t\t\t\t}\n\t\t\t\treturn functionNode;\n\t\t\t}\n\n\t\t\tvoid VisitFunctionDeclaration(FunctionSyntaxNode *functionNode)\n\t\t\t{\n\t\t\t\tthis->function = functionNode;\n\t\t\t\tauto returnType = TranslateTypeNode(functionNode->ReturnTypeNode);\n\t\t\t\tfunctionNode->ReturnType = returnType;\n\t\t\t\tStringBuilder internalName;\n\t\t\t\tinternalName << functionNode->Name.Content;\n\t\t\t\tHashSet<String> paraNames;\n\t\t\t\tfor (auto & para : functionNode->GetParameters())\n\t\t\t\t{\n\t\t\t\t\tif (paraNames.Contains(para->Name.Content))\n\t\t\t\t\t\tgetSink()->diagnose(para, Diagnostics::parameterAlreadyDefined, para->Name);\n\t\t\t\t\telse\n\t\t\t\t\t\tparaNames.Add(para->Name.Content);\n\t\t\t\t\tpara->Type = TranslateTypeNode(para->TypeNode);\n\t\t\t\t\tif (para->Type->Equals(ExpressionType::Void.Ptr()))\n\t\t\t\t\t\tgetSink()->diagnose(para, Diagnostics::parameterCannotBeVoid);\n\t\t\t\t\tinternalName << \"@\" << para->Type->ToString();\n\t\t\t\t}\n\t\t\t\tfunctionNode->InternalName = internalName.ProduceString();\n\t\t\t\tRefPtr<FunctionSymbol> symbol = new FunctionSymbol();\n\t\t\t\tsymbol->SyntaxNode = functionNode;\n\t\t\t\tsymbolTable->Functions[functionNode->InternalName] = symbol;\n\t\t\t\tauto overloadList = symbolTable->FunctionOverloads.TryGetValue(functionNode->Name.Content);\n\t\t\t\tif (!overloadList)\n\t\t\t\t{\n\t\t\t\t\tsymbolTable->FunctionOverloads[functionNode->Name.Content] = List<RefPtr<FunctionSymbol>>();\n\t\t\t\t\toverloadList = symbolTable->FunctionOverloads.TryGetValue(functionNode->Name.Content);\n\t\t\t\t}\n\t\t\t\toverloadList->Add(symbol);\n\t\t\t\tthis->function = NULL;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitBlockStatement(BlockStatementSyntaxNode *stmt) override\n\t\t\t{\n\t\t\t\tfor (auto & node : stmt->Statements)\n\t\t\t\t{\n\t\t\t\t\tnode->Accept(this);\n\t\t\t\t}\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitBreakStatement(BreakStatementSyntaxNode *stmt) override\n\t\t\t{\n\t\t\t\tif (!loops.Count())\n\t\t\t\t\tgetSink()->diagnose(stmt, Diagnostics::breakOutsideLoop);\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitContinueStatement(ContinueStatementSyntaxNode *stmt) override\n\t\t\t{\n\t\t\t\tif (!loops.Count())\n\t\t\t\t\tgetSink()->diagnose(stmt, Diagnostics::continueOutsideLoop);\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitDoWhileStatement(DoWhileStatementSyntaxNode *stmt) override\n\t\t\t{\n\t\t\t\tloops.Add(stmt);\n\t\t\t\tif (stmt->Predicate != NULL)\n\t\t\t\t\tstmt->Predicate = stmt->Predicate->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (!stmt->Predicate->Type->Equals(ExpressionType::Error.Ptr()) &&\n\t\t\t\t\t!stmt->Predicate->Type->Equals(ExpressionType::Int.Ptr()) &&\n\t\t\t\t\t!stmt->Predicate->Type->Equals(ExpressionType::Bool.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tgetSink()->diagnose(stmt, Diagnostics::whilePredicateTypeError);\n\t\t\t\t}\n\t\t\t\tstmt->Statement->Accept(this);\n\n\t\t\t\tloops.RemoveAt(loops.Count() - 1);\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitForStatement(ForStatementSyntaxNode *stmt) override\n\t\t\t{\n\t\t\t\tloops.Add(stmt);\n\t\t\t\tif (stmt->InitialStatement)\n\t\t\t\t{\n\t\t\t\t\tstmt->InitialStatement = stmt->InitialStatement->Accept(this).As<StatementSyntaxNode>();\n\t\t\t\t}\n\t\t\t\tif (stmt->PredicateExpression)\n\t\t\t\t{\n\t\t\t\t\tstmt->PredicateExpression = stmt->PredicateExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\t\tif (!stmt->PredicateExpression->Type->Equals(ExpressionType::Bool.Ptr()) &&\n\t\t\t\t\t\t!stmt->PredicateExpression->Type->Equals(ExpressionType::Int.Ptr()) &&\n\t\t\t\t\t\t!stmt->PredicateExpression->Type->Equals(ExpressionType::UInt.Ptr()))\n\t\t\t\t\t{\n\t\t\t\t\t\tgetSink()->diagnose(stmt->PredicateExpression.Ptr(), Diagnostics::forPredicateTypeError);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (stmt->SideEffectExpression)\n\t\t\t\t{\n\t\t\t\t\tstmt->SideEffectExpression = stmt->SideEffectExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\t}\n\t\t\t\tstmt->Statement->Accept(this);\n\n\t\t\t\tloops.RemoveAt(loops.Count() - 1);\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitIfStatement(IfStatementSyntaxNode *stmt) override\n\t\t\t{\n\t\t\t\tif (stmt->Predicate != NULL)\n\t\t\t\t\tstmt->Predicate = stmt->Predicate->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (!stmt->Predicate->Type->Equals(ExpressionType::Error.Ptr())\n\t\t\t\t\t&& (!stmt->Predicate->Type->Equals(ExpressionType::Int.Ptr()) &&\n\t\t\t\t\t\t!stmt->Predicate->Type->Equals(ExpressionType::Bool.Ptr())))\n\t\t\t\t\tgetSink()->diagnose(stmt, Diagnostics::ifPredicateTypeError);\n\n\t\t\t\tif (stmt->PositiveStatement != NULL)\n\t\t\t\t\tstmt->PositiveStatement->Accept(this);\n\n\t\t\t\tif (stmt->NegativeStatement != NULL)\n\t\t\t\t\tstmt->NegativeStatement->Accept(this);\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitReturnStatement(ReturnStatementSyntaxNode *stmt) override\n\t\t\t{\n\t\t\t\tif (currentCompNode && currentCompNode->BlockStatement->Statements.Count() &&\n\t\t\t\t\tstmt != currentCompNode->BlockStatement->Statements.Last().Ptr())\n\t\t\t\t{\n\t\t\t\t\tgetSink()->diagnose(stmt, Diagnostics::returnInComponentMustComeLast);\n\t\t\t\t}\n\t\t\t\tif (!stmt->Expression)\n\t\t\t\t{\n\t\t\t\t\tif (function && !function->ReturnType->Equals(ExpressionType::Void.Ptr()))\n\t\t\t\t\t\tgetSink()->diagnose(stmt, Diagnostics::returnNeedsExpression);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstmt->Expression = stmt->Expression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\t\tif (!stmt->Expression->Type->Equals(ExpressionType::Error.Ptr()))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (function && !MatchType_ValueReceiver(function->ReturnType.Ptr(), stmt->Expression->Type.Ptr()))\n\t\t\t\t\t\t\tgetSink()->diagnose(stmt, Diagnostics::functionReturnTypeMismatch, stmt->Expression->Type, function->ReturnType);\n\t\t\t\t\t\tif (currentComp && !MatchType_ValueReceiver(currentComp->Type->DataType.Ptr(), stmt->Expression->Type.Ptr()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgetSink()->diagnose(stmt, Diagnostics::componentReturnTypeMismatch, stmt->Expression->Type, currentComp->Type->DataType);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (currentImportOperator && !MatchType_GenericType(currentImportOperator->TypeName.Content, stmt->Expression->Type.Ptr()))\n\t\t\t\t\t\t\tgetSink()->diagnose(stmt, Diagnostics::importOperatorReturnTypeMismatch, stmt->Expression->Type, currentImportOperator->TypeName);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn stmt;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<Variable> VisitDeclrVariable(Variable* varDecl)\n\t\t\t{\n\t\t\t\tRefPtr<ExpressionType> type = TranslateTypeNode(varDecl->TypeNode);\n\t\t\t\tif (type->IsTextureOrSampler() || type->AsGenericType())\n\t\t\t\t{\n\t\t\t\t\tgetSink()->diagnose(varDecl->TypeNode, Diagnostics::invalidTypeForLocalVariable);\n\t\t\t\t}\n\t\t\t\telse if (type->AsBasicType() && type->AsBasicType()->RecordTypeName.Length())\n\t\t\t\t{\n\t\t\t\t\tgetSink()->diagnose(varDecl->TypeNode, Diagnostics::recordTypeVariableInImportOperator);\n\t\t\t\t}\n\t\t\t\tvarDecl->Type = type;\n\t\t\t\tif (varDecl->Type->Equals(ExpressionType::Void.Ptr()))\n\t\t\t\t\tgetSink()->diagnose(varDecl, Diagnostics::invalidTypeVoid);\n\t\t\t\tif (varDecl->Type->IsArray() && varDecl->Type->AsArrayType()->ArrayLength <= 0)\n\t\t\t\t\tgetSink()->diagnose(varDecl, Diagnostics::invalidArraySize);\n\t\t\t\tif (varDecl->Expr != NULL)\n\t\t\t\t{\n\t\t\t\t\tvarDecl->Expr = varDecl->Expr->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\t\tif (!MatchType_ValueReceiver(varDecl->Type.Ptr(), varDecl->Expr->Type.Ptr())\n\t\t\t\t\t\t&& !varDecl->Expr->Type->Equals(ExpressionType::Error.Ptr()))\n\t\t\t\t\t{\n\t\t\t\t\t\tgetSink()->diagnose(varDecl, Diagnostics::typeMismatch, varDecl->Expr->Type, varDecl->Type);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn varDecl;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitWhileStatement(WhileStatementSyntaxNode *stmt) override\n\t\t\t{\n\t\t\t\tloops.Add(stmt);\n\t\t\t\tstmt->Predicate = stmt->Predicate->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (!stmt->Predicate->Type->Equals(ExpressionType::Error.Ptr()) &&\n\t\t\t\t\t!stmt->Predicate->Type->Equals(ExpressionType::Int.Ptr()) &&\n\t\t\t\t\t!stmt->Predicate->Type->Equals(ExpressionType::Bool.Ptr()))\n\t\t\t\t\tgetSink()->diagnose(stmt, Diagnostics::whilePredicateTypeError2);\n\n\t\t\t\tstmt->Statement->Accept(this);\n\t\t\t\tloops.RemoveAt(loops.Count() - 1);\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitExpressionStatement(ExpressionStatementSyntaxNode *stmt) override\n\t\t\t{\n\t\t\t\tstmt->Expression = stmt->Expression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitBinaryExpression(BinaryExpressionSyntaxNode *expr) override\n\t\t\t{\n\t\t\t\texpr->LeftExpression = expr->LeftExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\texpr->RightExpression = expr->RightExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tauto & leftType = expr->LeftExpression->Type;\n\t\t\t\tif (!leftType)\n\t\t\t\t\tprintf(\"Break\");\n\t\t\t\tauto & rightType = expr->RightExpression->Type;\n\t\t\t\tRefPtr<ExpressionType> matchedType;\n\t\t\t\tauto checkAssign = [&]()\n\t\t\t\t{\n\t\t\t\t\tif (!(leftType->AsBasicType() && leftType->AsBasicType()->IsLeftValue) &&\n\t\t\t\t\t\t!leftType->Equals(ExpressionType::Error.Ptr()))\n\t\t\t\t\t\tgetSink()->diagnose(expr->LeftExpression.Ptr(), Diagnostics::assignNonLValue);\n\t\t\t\t\tif (expr->Operator == Operator::AndAssign ||\n\t\t\t\t\t\texpr->Operator == Operator::OrAssign ||\n\t\t\t\t\t\texpr->Operator == Operator::XorAssign ||\n\t\t\t\t\t\texpr->Operator == Operator::LshAssign ||\n\t\t\t\t\t\texpr->Operator == Operator::RshAssign)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!(leftType->IsIntegral() && rightType->IsIntegral()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::bitOperationNonIntegral);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\texpr->LeftExpression->Access = ExpressionAccess::Write;\n\t\t\t\t\tif (MatchType_ValueReceiver(leftType.Ptr(), expr->Type.Ptr()))\n\t\t\t\t\t\texpr->Type = leftType;\n\t\t\t\t\telse\n\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t};\n\t\t\t\tif (expr->Operator == Operator::Assign)\n\t\t\t\t{\n\t\t\t\t\texpr->Type = rightType;\n\t\t\t\t\tcheckAssign();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tList<RefPtr<ExpressionType>> argTypes;\n\t\t\t\t\targTypes.Add(leftType);\n\t\t\t\t\targTypes.Add(rightType);\n\t\t\t\t\tList<RefPtr<FunctionSymbol>> * operatorOverloads = symbolTable->FunctionOverloads.TryGetValue(GetOperatorFunctionName(expr->Operator));\n\t\t\t\t\tauto overload = FindFunctionOverload(*operatorOverloads, [](RefPtr<FunctionSymbol> f)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn f->SyntaxNode->GetParameters();\n\t\t\t\t\t}, argTypes);\n\t\t\t\t\tif (!overload)\n\t\t\t\t\t{\n\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\t\tif (!leftType->Equals(ExpressionType::Error.Ptr()) && !rightType->Equals(ExpressionType::Error.Ptr()))\n\t\t\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::noOverloadFoundForBinOperatorOnTypes, OperatorToString(expr->Operator), leftType, rightType);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\texpr->Type = overload->SyntaxNode->ReturnType;\n\t\t\t\t\t}\n\t\t\t\t\tif (expr->Operator > Operator::Assign)\n\t\t\t\t\t\tcheckAssign();\n\t\t\t\t}\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitConstantExpression(ConstantExpressionSyntaxNode *expr) override\n\t\t\t{\n\t\t\t\tswitch (expr->ConstType)\n\t\t\t\t{\n\t\t\t\tcase ConstantExpressionSyntaxNode::ConstantType::Int:\n\t\t\t\t\texpr->Type = ExpressionType::Int;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ConstantExpressionSyntaxNode::ConstantType::UInt:\n\t\t\t\t\texpr->Type = ExpressionType::UInt;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ConstantExpressionSyntaxNode::ConstantType::Bool:\n\t\t\t\t\texpr->Type = ExpressionType::Bool;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ConstantExpressionSyntaxNode::ConstantType::Float:\n\t\t\t\t\texpr->Type = ExpressionType::Float;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\tthrow \"Invalid constant type.\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitIndexExpression(IndexExpressionSyntaxNode *expr) override\n\t\t\t{\n\t\t\t\texpr->BaseExpression = expr->BaseExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\texpr->IndexExpression = expr->IndexExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (expr->BaseExpression->Type->Equals(ExpressionType::Error.Ptr()))\n\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto & baseExprType = expr->BaseExpression->Type;\n\t\t\t\t\tbool isValid = baseExprType->AsGenericType() &&\n\t\t\t\t\t\t(baseExprType->AsGenericType()->GenericTypeName == \"StructuredBuffer\" ||\n\t\t\t\t\t\t\tbaseExprType->AsGenericType()->GenericTypeName == \"RWStructuredBuffer\" ||\n\t\t\t\t\t\t\tbaseExprType->AsGenericType()->GenericTypeName == \"PackedBuffer\");\n\t\t\t\t\tisValid = isValid || (baseExprType->AsBasicType() && GetVectorSize(baseExprType->AsBasicType()->BaseType) != 0);\n\t\t\t\t\tisValid = isValid || baseExprType->AsArrayType();\n\t\t\t\t\tif (!isValid)\n\t\t\t\t\t{\n\t\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::subscriptNonArray);\n\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\t}\n\t\t\t\t\tif (!expr->IndexExpression->Type->Equals(ExpressionType::Int.Ptr()) &&\n\t\t\t\t\t\t!expr->IndexExpression->Type->Equals(ExpressionType::UInt.Ptr()))\n\t\t\t\t\t{\n\t\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::subscriptIndexNonInteger);\n\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (expr->BaseExpression->Type->IsArray())\n\t\t\t\t{\n\t\t\t\t\texpr->Type = expr->BaseExpression->Type->AsArrayType()->BaseType;\n\t\t\t\t}\n\t\t\t\telse if (auto genType = expr->BaseExpression->Type->AsGenericType())\n\t\t\t\t{\n\t\t\t\t\texpr->Type = genType->BaseType;\n\t\t\t\t}\n\t\t\t\telse if (auto basicType = expr->BaseExpression->Type->AsBasicType())\n\t\t\t\t{\n\t\t\t\t\tif (basicType->BaseType == BaseType::Float3x3)\n\t\t\t\t\t\texpr->Type = ExpressionType::Float3;\n\t\t\t\t\telse if (basicType->BaseType == BaseType::Float4x4)\n\t\t\t\t\t\texpr->Type = ExpressionType::Float4;\n\t\t\t\t\telse\n\t\t\t\t\t\texpr->Type = new BasicExpressionType(GetVectorBaseType(basicType->BaseType));\n\t\t\t\t}\n\t\t\t\texpr->Type = expr->Type->Clone();\n\t\t\t\tif (auto basicType = expr->Type->AsBasicType())\n\t\t\t\t{\n\t\t\t\t\tbasicType->IsLeftValue = true;\n\t\t\t\t\tbasicType->IsReference = true;\n\t\t\t\t}\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tbool MatchArguments(FunctionSyntaxNode * functionNode, List <RefPtr<ExpressionSyntaxNode>> &args)\n\t\t\t{\n\t\t\t\tif (functionNode->GetParameters().Count() != args.Count())\n\t\t\t\t\treturn false;\n\t\t\t\tint i = 0;\n\t\t\t\tfor (auto param : functionNode->GetParameters())\n\t\t\t\t{\n\t\t\t\t\tif (!param->Type->Equals(args[i]->Type.Ptr()))\n\t\t\t\t\t\treturn false;\n\t\t\t\t\ti++;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\ttemplate<typename GetParamFunc, typename PFuncT>\n\t\t\tPFuncT FindFunctionOverload(const List<PFuncT> & funcs, const GetParamFunc & getParam, const List<RefPtr<ExpressionType>> & arguments)\n\t\t\t{\n\t\t\t\tint bestMatchConversions = 1 << 30;\n\t\t\t\tPFuncT func = nullptr;\n\t\t\t\tfor (auto & f : funcs)\n\t\t\t\t{\n\t\t\t\t\tauto params = getParam(f);\n\t\t\t\t\tif (params.Count() == arguments.Count())\n\t\t\t\t\t{\n\t\t\t\t\t\tint conversions = 0;\n\t\t\t\t\t\tbool match = true;\n\t\t\t\t\t\tint i = 0;\n\t\t\t\t\t\tfor (auto param : params)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto argType = arguments[i];\n\t\t\t\t\t\t\tauto paramType = param->Type;\n\t\t\t\t\t\t\tif (argType->Equals(paramType.Ptr()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (MatchType_ValueReceiver(paramType.Ptr(), argType.Ptr()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconversions++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmatch = false;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ti++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (match && conversions < bestMatchConversions)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfunc = f;\n\t\t\t\t\t\t\tbestMatchConversions = conversions;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn func;\n\t\t\t}\n\n\t\t\tShaderComponentSymbol * ResolveFunctionComponent(ShaderSymbol * shader, String name, const List<RefPtr<ExpressionType>> & args, bool topLevel = true)\n\t\t\t{\n\t\t\t\tauto list = shader->FunctionComponents.TryGetValue(name);\n\t\t\t\tif (list)\n\t\t\t\t{\n\t\t\t\t\tauto func = FindFunctionOverload(*list, [](RefPtr<ShaderComponentSymbol> & comp)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn comp->Implementations.First()->SyntaxNode->GetParameters();\n\t\t\t\t\t}, args);\n\t\t\t\t\tif (func)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn func.Ptr();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (auto & module : shader->ShaderUsings)\n\t\t\t\t{\n\t\t\t\t\tif (module.IsPublic || topLevel)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto func = ResolveFunctionComponent(module.Shader, name, args, false);\n\t\t\t\t\t\tif (func)\n\t\t\t\t\t\t\treturn func;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn nullptr;\n\t\t\t}\n\n\t\t\tShaderComponentSymbol * ResolveFunctionComponent(ShaderSymbol * shader, String name, const List<RefPtr<ExpressionSyntaxNode>> & args, bool topLevel = true)\n\t\t\t{\n\t\t\t\treturn ResolveFunctionComponent(shader, name, From(args).Select([](RefPtr<ExpressionSyntaxNode> x) {return x->Type; }).ToList(), topLevel);\n\t\t\t}\n\n\t\t\tRefPtr<ExpressionSyntaxNode> ResolveFunctionOverload(InvokeExpressionSyntaxNode * invoke, MemberExpressionSyntaxNode* memberExpr, List<RefPtr<ExpressionSyntaxNode>> & arguments)\n\t\t\t{\n\t\t\t\t// TODO(tfoley): Figure out why we even need to do this here...\n\t\t\t\tDiagnosticSink::State savedState = sink->saveState();\n\t\t\t\tmemberExpr->BaseExpression->Accept(this);\n\t\t\t\tsink->restoreState(savedState);\n\t\t\t\tif (memberExpr->BaseExpression->Type->IsShader())\n\t\t\t\t{\n\t\t\t\t\tauto basicType = memberExpr->BaseExpression->Type->AsBasicType();\n\t\t\t\t\tauto func = ResolveFunctionComponent(basicType->Shader, memberExpr->MemberName, arguments);\n\t\t\t\t\tif (func)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto funcType = new BasicExpressionType();\n\t\t\t\t\t\tfuncType->BaseType = BaseType::Function;\n\t\t\t\t\t\tfuncType->Component = func;\n\t\t\t\t\t\tmemberExpr->Type = funcType;\n\t\t\t\t\t\tinvoke->Type = func->Implementations.First()->SyntaxNode->Type;\n\t\t\t\t\t\treturn invoke;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tStringBuilder argList;\n\t\t\t\t\t\tfor (int i = 0; i < arguments.Count(); i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\targList << arguments[i]->Type->ToString();\n\t\t\t\t\t\t\tif (i != arguments.Count() - 1)\n\t\t\t\t\t\t\t\targList << \", \";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tgetSink()->diagnose(invoke, Diagnostics::noApplicationFunction, memberExpr->MemberName, argList.ProduceString());\n\t\t\t\t\t\tinvoke->Type = ExpressionType::Error;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tinvoke->Arguments.Insert(0, memberExpr->BaseExpression);\n\t\t\t\t\tauto funcExpr = new VarExpressionSyntaxNode();\n\t\t\t\t\tfuncExpr->Scope = invoke->Scope;\n\t\t\t\t\tfuncExpr->Position = invoke->Position;\n\t\t\t\t\tfuncExpr->Variable = memberExpr->MemberName;\n\t\t\t\t\tinvoke->FunctionExpr = funcExpr;\n\t\t\t\t\treturn ResolveFunctionOverload(invoke, funcExpr, invoke->Arguments);\n\t\t\t\t}\n\t\t\t\treturn invoke;\n\t\t\t}\n\n\t\t\tRefPtr<ExpressionSyntaxNode> ResolveFunctionOverload(InvokeExpressionSyntaxNode * invoke, VarExpressionSyntaxNode* varExpr, List<RefPtr<ExpressionSyntaxNode>> & arguments)\n\t\t\t{\n\t\t\t\tif (currentShader)\n\t\t\t\t{\n\t\t\t\t\tauto func = ResolveFunctionComponent(currentShader, varExpr->Variable, arguments);\n\t\t\t\t\tif (func)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto funcType = new BasicExpressionType();\n\t\t\t\t\t\tfuncType->BaseType = BaseType::Function;\n\t\t\t\t\t\tfuncType->Component = func;\n\t\t\t\t\t\tvarExpr->Type = funcType;\n\t\t\t\t\t\tinvoke->Type = func->Implementations.First()->SyntaxNode->Type;\n\t\t\t\t\t\treturn invoke;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// check if this is an import operator call\n\t\t\t\tif (currentShader && currentCompNode && arguments.Count() > 0 && currentShader->ParentPipeline)\n\t\t\t\t{\n\t\t\t\t\tif (auto impOpList = currentShader->ParentPipeline->ImportOperators.TryGetValue(varExpr->Variable))\n\t\t\t\t\t{\n\t\t\t\t\t\t// component with explicit import operator call must be qualified with explicit rate\n\t\t\t\t\t\tif (!currentCompNode->Rate)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgetSink()->diagnose(varExpr, Diagnostics::importOperatorCalledFromAutoPlacedComponent, currentCompNode->Name);\n\t\t\t\t\t\t\tinvoke->Type = ExpressionType::Error;\n\t\t\t\t\t\t\treturn invoke;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// for now we do not support calling import operator from a multi-world component definition\n\t\t\t\t\t\tif (currentCompNode->Rate->Worlds.Count() > 1)\n\t\t\t\t\t\t\tgetSink()->diagnose(varExpr, Diagnostics::importOperatorCalledFromMultiWorldComponent);\n\t\t\t\t\t\tauto validOverloads = From(*impOpList).Where([&](RefPtr<ImportOperatorDefSyntaxNode> imp) { return imp->DestWorld.Content == currentCompNode->Rate->Worlds.First().World.Content; }).ToList();\n\t\t\t\t\t\tauto func = FindFunctionOverload(validOverloads, [](RefPtr<ImportOperatorDefSyntaxNode> imp)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn imp->GetParameters();\n\t\t\t\t\t\t}, From(arguments).Skip(1).Select([](RefPtr<ExpressionSyntaxNode> x) {return x->Type; }).ToList());\n\t\t\t\t\t\tif (func)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tRefPtr<ImportExpressionSyntaxNode> importExpr = new ImportExpressionSyntaxNode();\n\t\t\t\t\t\t\timportExpr->Position = varExpr->Position;\n\t\t\t\t\t\t\timportExpr->Component = arguments[0];\n\t\t\t\t\t\t\tCloneContext cloneCtx;\n\t\t\t\t\t\t\timportExpr->ImportOperatorDef = func->Clone(cloneCtx);\n\t\t\t\t\t\t\timportExpr->ImportOperatorDef->Scope->Parent = varExpr->Scope->Parent;\n\t\t\t\t\t\t\timportExpr->Type = arguments[0]->Type->Clone();\n\t\t\t\t\t\t\timportExpr->Scope = varExpr->Scope;\n\t\t\t\t\t\t\timportExpr->Access = ExpressionAccess::Read;\n\t\t\t\t\t\t\tfor (int i = 1; i < arguments.Count(); i++)\n\t\t\t\t\t\t\t\timportExpr->Arguments.Add(arguments[i]);\n\t\t\t\t\t\t\treturn importExpr;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tStringBuilder argList;\n\t\t\t\t\t\t\tfor (int i = 1; i < arguments.Count(); i++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\targList << arguments[i]->Type->ToString();\n\t\t\t\t\t\t\t\tif (i != arguments.Count() - 1)\n\t\t\t\t\t\t\t\t\targList << \", \";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tgetSink()->diagnose(varExpr, Diagnostics::noApplicableImportOperator,\n\t\t\t\t\t\t\t\tvarExpr->Variable,\n\t\t\t\t\t\t\t\tcurrentShader->ParentPipeline->SyntaxNode->Name,\n\t\t\t\t\t\t\t\tcurrentCompNode->Rate->Worlds.First().World,\n\t\t\t\t\t\t\t\targList.ProduceString());\n\t\t\t\t\t\t\tinvoke->Type = ExpressionType::Error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn invoke;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// this is not an import operator call, resolve as function call\n\t\t\t\tbool found = false;\n\t\t\t\tbool functionNameFound = false;\n\t\t\t\tRefPtr<FunctionSymbol> func;\n\t\t\t\tvarExpr->Variable = TranslateHLSLTypeNames(varExpr->Variable);\n\n\t\t\t\tif (varExpr->Variable == \"texture\" && arguments.Count() > 0 &&\n\t\t\t\t\targuments[0]->Type->IsGenericType(\"Texture\"))\n\t\t\t\t{\n\t\t\t\t\tif (arguments.Count() != 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tinvoke->Type = ExpressionType::Error;\n\t\t\t\t\t\tfound = false;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (auto genType = arguments[0]->Type->AsGenericType())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tinvoke->Type = genType->BaseType;\n\t\t\t\t\t\t\tif (!arguments[1]->Type->Equals(ExpressionType::Float2.Ptr()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfound = false;\n\t\t\t\t\t\t\t\tinvoke->Type = ExpressionType::Error;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tinvoke->Type = ExpressionType::Error;\n\t\t\t\t\t\t\tfound = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tauto funcType = new BasicExpressionType(BaseType::Function);\n\t\t\t\t\tfuncType->Func = symbolTable->FunctionOverloads[\"texture\"]().First().Ptr();\n\t\t\t\t\tvarExpr->Type = funcType;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// find function overload with implicit argument type conversions\n\t\t\t\t\tauto namePrefix = varExpr->Variable + \"@\";\n\t\t\t\t\tList<RefPtr<FunctionSymbol>> * functionOverloads = symbolTable->FunctionOverloads.TryGetValue(varExpr->Variable);\n\t\t\t\t\tif (functionOverloads)\n\t\t\t\t\t{\n\t\t\t\t\t\tfunc = FindFunctionOverload(*functionOverloads, [](RefPtr<FunctionSymbol> f)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn f->SyntaxNode->GetParameters();\n\t\t\t\t\t\t}, From(arguments).Select([](RefPtr<ExpressionSyntaxNode> x) {return x->Type; }).ToList());\n\t\t\t\t\t\tfunctionNameFound = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (func)\n\t\t\t\t{\n\t\t\t\t\tif (!func->SyntaxNode->IsExtern())\n\t\t\t\t\t{\n\t\t\t\t\t\t//varExpr->Variable = func->SyntaxNode->InternalName;\n\t\t\t\t\t\tif (currentFunc)\n\t\t\t\t\t\t\tcurrentFunc->ReferencedFunctions.Add(func->SyntaxNode->InternalName);\n\t\t\t\t\t}\n\t\t\t\t\tinvoke->Type = func->SyntaxNode->ReturnType;\n\t\t\t\t\tauto funcType = new BasicExpressionType();\n\t\t\t\t\tfuncType->BaseType = BaseType::Function;\n\t\t\t\t\tfuncType->Func = func.Ptr();\n\t\t\t\t\tvarExpr->Type = funcType;\n\t\t\t\t\tfound = true;\n\t\t\t\t}\n\t\t\t\tif (!found)\n\t\t\t\t{\n\t\t\t\t\tinvoke->Type = ExpressionType::Error;\n\t\t\t\t\tStringBuilder argList;\n\t\t\t\t\tfor (int i = 0; i < arguments.Count(); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\targList << arguments[i]->Type->ToString();\n\t\t\t\t\t\tif (i != arguments.Count() - 1)\n\t\t\t\t\t\t\targList << \", \";\n\t\t\t\t\t}\n\t\t\t\t\tif (functionNameFound)\n\t\t\t\t\t\tgetSink()->diagnose(varExpr, Diagnostics::noApplicationFunction, varExpr->Variable, argList.ProduceString());\n\t\t\t\t\telse\n\t\t\t\t\t\tgetSink()->diagnose(varExpr, Diagnostics::undefinedIdentifier2, varExpr->Variable);\n\t\t\t\t}\n\t\t\t\treturn invoke;\n\t\t\t}\n\n\t\t\tRefPtr<ExpressionSyntaxNode> VisitProject(ProjectExpressionSyntaxNode * project) override\n\t\t\t{\n\t\t\t\tif (currentImportOperator == nullptr)\n\t\t\t\t{\n\t\t\t\t\tgetSink()->diagnose(project, Diagnostics::projectionOutsideImportOperator);\n\t\t\t\t\treturn project;\n\t\t\t\t}\n\t\t\t\tproject->BaseExpression->Accept(this);\n\t\t\t\tauto baseType = project->BaseExpression->Type->AsBasicType();\n\t\t\t\tif (!baseType || baseType->RecordTypeName != currentImportOperator->SourceWorld.Content)\n\t\t\t\t\tgetSink()->diagnose(project, Diagnostics::projectTypeMismatch, currentImportOperator->SourceWorld);\n\t\t\t\tauto rsType = new BasicExpressionType(BaseType::Generic);\n\t\t\t\tproject->Type = rsType;\n\t\t\t\trsType->GenericTypeVar = currentImportOperator->TypeName.Content;\n\t\t\t\treturn project;\n\t\t\t}\n\n\t\t\tRefPtr<ExpressionSyntaxNode> ResolveInvoke(InvokeExpressionSyntaxNode * expr)\n\t\t\t{\n\n\t\t\t\tif (auto varExpr = expr->FunctionExpr.As<VarExpressionSyntaxNode>())\n\t\t\t\t{\n\t\t\t\t\treturn ResolveFunctionOverload(expr, varExpr.Ptr(), expr->Arguments);\n\t\t\t\t}\n\t\t\t\telse if (auto memberExpr = expr->FunctionExpr.As<MemberExpressionSyntaxNode>())\n\t\t\t\t{\n\t\t\t\t\treturn ResolveFunctionOverload(expr, memberExpr.Ptr(), expr->Arguments);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tgetSink()->diagnose(expr->FunctionExpr, Diagnostics::expectedFunction);\n\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t}\n\t\t\t\treturn expr;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitInvokeExpression(InvokeExpressionSyntaxNode *expr) override\n\t\t\t{\n\t\t\t\tfor (auto & arg : expr->Arguments)\n\t\t\t\t\targ = arg->Accept(this).As<ExpressionSyntaxNode>();\n\n\t\t\t\tauto rs = ResolveInvoke(expr);\n\t\t\t\tif (auto invoke = dynamic_cast<InvokeExpressionSyntaxNode*>(rs.Ptr()))\n\t\t\t\t{\n\t\t\t\t\t// if this is still an invoke expression, test arguments passed to inout/out parameter are LValues\n\t\t\t\t\tif (auto basicType = dynamic_cast<BasicExpressionType*>(invoke->FunctionExpr->Type.Ptr()))\n\t\t\t\t\t{\n\t\t\t\t\t\tList<RefPtr<ParameterSyntaxNode>> paramsStorage;\n\t\t\t\t\t\tList<RefPtr<ParameterSyntaxNode>> * params = nullptr;\n\t\t\t\t\t\tif (basicType->Func)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tparamsStorage = basicType->Func->SyntaxNode->GetParameters().ToArray();\n\t\t\t\t\t\t\tparams = &paramsStorage;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (basicType->Component)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tparamsStorage = basicType->Component->Implementations.First()->SyntaxNode->GetParameters().ToArray();\n\t\t\t\t\t\t\tparams = &paramsStorage;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (params)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (int i = 0; i < (*params).Count(); i++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif ((*params)[i]->HasModifier(ModifierFlag::Out))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (i < expr->Arguments.Count() && expr->Arguments[i]->Type->AsBasicType() &&\n\t\t\t\t\t\t\t\t\t\t!expr->Arguments[i]->Type->AsBasicType()->IsLeftValue)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tgetSink()->diagnose(expr->Arguments[i], Diagnostics::argumentExpectedLValue, (*params)[i]->Name);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn rs;\n\t\t\t}\n\n\t\t\tString OperatorToString(Operator op)\n\t\t\t{\n\t\t\t\tswitch (op)\n\t\t\t\t{\n\t\t\t\tcase Spire::Compiler::Operator::Neg:\n\t\t\t\t\treturn \"-\";\n\t\t\t\tcase Spire::Compiler::Operator::Not:\n\t\t\t\t\treturn \"!\";\n\t\t\t\tcase Spire::Compiler::Operator::PreInc:\n\t\t\t\t\treturn \"++\";\n\t\t\t\tcase Spire::Compiler::Operator::PreDec:\n\t\t\t\t\treturn \"--\";\n\t\t\t\tcase Spire::Compiler::Operator::PostInc:\n\t\t\t\t\treturn \"++\";\n\t\t\t\tcase Spire::Compiler::Operator::PostDec:\n\t\t\t\t\treturn \"--\";\n\t\t\t\tcase Spire::Compiler::Operator::Mul:\n\t\t\t\tcase Spire::Compiler::Operator::MulAssign:\n\t\t\t\t\treturn \"*\";\n\t\t\t\tcase Spire::Compiler::Operator::Div:\n\t\t\t\tcase Spire::Compiler::Operator::DivAssign:\n\t\t\t\t\treturn \"/\";\n\t\t\t\tcase Spire::Compiler::Operator::Mod:\n\t\t\t\tcase Spire::Compiler::Operator::ModAssign:\n\t\t\t\t\treturn \"%\";\n\t\t\t\tcase Spire::Compiler::Operator::Add:\n\t\t\t\tcase Spire::Compiler::Operator::AddAssign:\n\t\t\t\t\treturn \"+\";\n\t\t\t\tcase Spire::Compiler::Operator::Sub:\n\t\t\t\tcase Spire::Compiler::Operator::SubAssign:\n\t\t\t\t\treturn \"-\";\n\t\t\t\tcase Spire::Compiler::Operator::Lsh:\n\t\t\t\tcase Spire::Compiler::Operator::LshAssign:\n\t\t\t\t\treturn \"<<\";\n\t\t\t\tcase Spire::Compiler::Operator::Rsh:\n\t\t\t\tcase Spire::Compiler::Operator::RshAssign:\n\t\t\t\t\treturn \">>\";\n\t\t\t\tcase Spire::Compiler::Operator::Eql:\n\t\t\t\t\treturn \"==\";\n\t\t\t\tcase Spire::Compiler::Operator::Neq:\n\t\t\t\t\treturn \"!=\";\n\t\t\t\tcase Spire::Compiler::Operator::Greater:\n\t\t\t\t\treturn \">\";\n\t\t\t\tcase Spire::Compiler::Operator::Less:\n\t\t\t\t\treturn \"<\";\n\t\t\t\tcase Spire::Compiler::Operator::Geq:\n\t\t\t\t\treturn \">=\";\n\t\t\t\tcase Spire::Compiler::Operator::Leq:\n\t\t\t\t\treturn \"<=\";\n\t\t\t\tcase Spire::Compiler::Operator::BitAnd:\n\t\t\t\tcase Spire::Compiler::Operator::AndAssign:\n\t\t\t\t\treturn \"&\";\n\t\t\t\tcase Spire::Compiler::Operator::BitXor:\n\t\t\t\tcase Spire::Compiler::Operator::XorAssign:\n\t\t\t\t\treturn \"^\";\n\t\t\t\tcase Spire::Compiler::Operator::BitOr:\n\t\t\t\tcase Spire::Compiler::Operator::OrAssign:\n\t\t\t\t\treturn \"|\";\n\t\t\t\tcase Spire::Compiler::Operator::And:\n\t\t\t\t\treturn \"&&\";\n\t\t\t\tcase Spire::Compiler::Operator::Or:\n\t\t\t\t\treturn \"||\";\n\t\t\t\tcase Spire::Compiler::Operator::Assign:\n\t\t\t\t\treturn \"=\";\n\t\t\t\tdefault:\n\t\t\t\t\treturn \"ERROR\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitUnaryExpression(UnaryExpressionSyntaxNode *expr) override\n\t\t\t{\n\t\t\t\texpr->Expression = expr->Expression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tList<RefPtr<ExpressionType>> argTypes;\n\t\t\t\targTypes.Add(expr->Expression->Type);\n\t\t\t\tList<RefPtr<FunctionSymbol>> * operatorOverloads = symbolTable->FunctionOverloads.TryGetValue(GetOperatorFunctionName(expr->Operator));\n\t\t\t\tauto overload = FindFunctionOverload(*operatorOverloads, [](RefPtr<FunctionSymbol> f)\n\t\t\t\t{\n\t\t\t\t\treturn f->SyntaxNode->GetParameters();\n\t\t\t\t}, argTypes);\n\t\t\t\tif (!overload)\n\t\t\t\t{\n\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\tif (!expr->Expression->Type->Equals(ExpressionType::Error.Ptr()))\n\t\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::noApplicationUnaryOperator, OperatorToString(expr->Operator), expr->Expression->Type);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\texpr->Type = overload->SyntaxNode->ReturnType;\n\t\t\t\t}\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitVarExpression(VarExpressionSyntaxNode *expr) override\n\t\t\t{\n\t\t\t\tShaderUsing shaderObj;\n\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\tauto decl = expr->Scope->LookUp(expr->Variable);\n\t\t\t\tauto varDecl = dynamic_cast<VarDeclBase*>(decl);\n\t\t\t\tif (varDecl)\n\t\t\t\t{\n\t\t\t\t\texpr->Type = varDecl->Type;\n\t\t\t\t\tif (auto basicType = expr->Type->AsBasicType())\n\t\t\t\t\t\tbasicType->IsLeftValue = !(dynamic_cast<ComponentSyntaxNode*>(varDecl));\n\t\t\t\t}\n\t\t\t\telse if (currentShader && currentShader->ShaderObjects.TryGetValue(expr->Variable, shaderObj))\n\t\t\t\t{\n\t\t\t\t\tauto basicType = new BasicExpressionType(BaseType::Shader);\n\t\t\t\t\tbasicType->Shader = shaderObj.Shader;\n\t\t\t\t\tbasicType->IsLeftValue = false;\n\t\t\t\t\texpr->Type = basicType;\n\t\t\t\t}\n\t\t\t\telse if (currentPipeline && currentImportOperator)\n\t\t\t\t{\n\t\t\t\t\tRefPtr<ShaderComponentSymbol> comp;\n\t\t\t\t\tif (currentPipeline->Components.TryGetValue(expr->Variable, comp))\n\t\t\t\t\t{\n\t\t\t\t\t\tcurrentImportOperator->Usings.Add(comp->Name);\n\t\t\t\t\t\texpr->Type = comp->Type->DataType;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::undefinedIdentifier2, expr->Variable);\n\t\t\t\t}\n\t\t\t\telse if (currentShader)\n\t\t\t\t{\n\t\t\t\t\tauto compRef = currentShader->ResolveComponentReference(expr->Variable);\n\t\t\t\t\tif (compRef.IsAccessible)\n\t\t\t\t\t{\n\t\t\t\t\t\texpr->Type = compRef.Component->Type->DataType->Clone();\n\t\t\t\t\t\tif (auto basicType = expr->Type->AsBasicType())\n\t\t\t\t\t\t\tbasicType->IsLeftValue = false;\n\t\t\t\t\t}\n\t\t\t\t\telse if (compRef.Component)\n\t\t\t\t\t{\n\t\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::componentNotAccessibleFromShader, expr->Variable, currentShader->SyntaxNode->Name);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::undefinedIdentifier2, expr->Variable);\n\t\t\t\t}\n\t\t\t\telse if (auto compDecl = dynamic_cast<ComponentSyntaxNode*>(decl)) // interface decl\n\t\t\t\t{\n\t\t\t\t\texpr->Type = compDecl->Type;\n\t\t\t\t\tif (auto basicType = expr->Type->AsBasicType())\n\t\t\t\t\t\tbasicType->IsLeftValue = false;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::undefinedIdentifier2, expr->Variable);\n\n\t\t\t\tif (expr->Type->IsGenericType(\"Uniform\") || expr->Type->IsGenericType(\"Patch\") || expr->Type->IsGenericType(\"StorageBuffer\"))\n\t\t\t\t\texpr->Type = expr->Type->AsGenericType()->BaseType;\n\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitTypeCastExpression(TypeCastExpressionSyntaxNode * expr) override\n\t\t\t{\n\t\t\t\texpr->Expression = expr->Expression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tauto targetType = TranslateTypeNode(expr->TargetType);\n\n\t\t\t\tif (!expr->Expression->Type->Equals(ExpressionType::Error.Ptr()) && targetType->AsBasicType())\n\t\t\t\t{\n\t\t\t\t\tif (!expr->Expression->Type->AsBasicType())\n\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\telse if (!IsNumeric(GetVectorBaseType(expr->Expression->Type->AsBasicType()->BaseType))\n\t\t\t\t\t\t|| !IsNumeric(GetVectorBaseType(targetType->AsBasicType()->BaseType)))\n\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\telse if (targetType->AsBasicType()->BaseType == BaseType::Void || expr->Expression->Type->AsBasicType()->BaseType == BaseType::Void)\n\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\telse\n\t\t\t\t\t\texpr->Type = targetType;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\tif (expr->Type->Equals(ExpressionType::Error.Ptr()) && !expr->Expression->Type->Equals(ExpressionType::Error.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::invalidTypeCast, expr->Expression->Type, targetType->ToString());\n\t\t\t\t}\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitSelectExpression(SelectExpressionSyntaxNode * expr) override\n\t\t\t{\n\t\t\t\texpr->SelectorExpr = expr->SelectorExpr->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (!expr->SelectorExpr->Type->Equals(ExpressionType::Int.Ptr()) && !expr->SelectorExpr->Type->Equals(ExpressionType::Bool.Ptr())\n\t\t\t\t\t&& !expr->SelectorExpr->Type->Equals(ExpressionType::Error.Ptr()))\n\t\t\t\t{\n\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::selectPrdicateTypeMismatch);\n\t\t\t\t}\n\t\t\t\texpr->Expr0 = expr->Expr0->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\texpr->Expr1 = expr->Expr1->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (!expr->Expr0->Type->Equals(expr->Expr1->Type.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::selectValuesTypeMismatch);\n\t\t\t\t}\n\t\t\t\texpr->Type = expr->Expr0->Type;\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitMemberExpression(MemberExpressionSyntaxNode * expr) override\n\t\t\t{\n\t\t\t\texpr->BaseExpression = expr->BaseExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tauto & baseType = expr->BaseExpression->Type;\n\t\t\t\tif (!baseType->AsBasicType())\n\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\telse if (IsVector(baseType->AsBasicType()->BaseType))\n\t\t\t\t{\n\t\t\t\t\tArray<int, 4> children;\n\t\t\t\t\tif (expr->MemberName.Length() > 4)\n\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tbool error = false;\n\n\t\t\t\t\t\tfor (int i = 0; i < expr->MemberName.Length(); i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto ch = expr->MemberName[i];\n\t\t\t\t\t\t\tswitch (ch)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase 'x':\n\t\t\t\t\t\t\tcase 'r':\n\t\t\t\t\t\t\t\tchildren.Add(0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 'y':\n\t\t\t\t\t\t\tcase 'g':\n\t\t\t\t\t\t\t\tchildren.Add(1);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 'z':\n\t\t\t\t\t\t\tcase 'b':\n\t\t\t\t\t\t\t\tchildren.Add(2);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 'w':\n\t\t\t\t\t\t\tcase 'a':\n\t\t\t\t\t\t\t\tchildren.Add(3);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\terror = true;\n\t\t\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tint vecLen = GetVectorSize(baseType->AsBasicType()->BaseType);\n\t\t\t\t\t\tfor (auto m : children)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (m >= vecLen)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\terror = true;\n\t\t\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ((vecLen == 9 || vecLen == 16) && children.Count() > 1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terror = true;\n\t\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!error)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (vecLen == 9)\n\t\t\t\t\t\t\t\texpr->Type = new BasicExpressionType((BaseType)((int)GetVectorBaseType(baseType->AsBasicType()->BaseType) + 2));\n\t\t\t\t\t\t\telse if (vecLen == 16)\n\t\t\t\t\t\t\t\texpr->Type = new BasicExpressionType((BaseType)((int)GetVectorBaseType(baseType->AsBasicType()->BaseType) + 3));\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\texpr->Type = new BasicExpressionType((BaseType)((int)GetVectorBaseType(baseType->AsBasicType()->BaseType) + children.Count() - 1));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\texpr->Type->AsBasicType()->IsMaskedVector = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (auto bt = expr->Type->AsBasicType())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbt->IsLeftValue = !baseType->AsBasicType()->IsMaskedVector;\n\t\t\t\t\t\t\tif (children.Count() > vecLen || children.Count() == 0)\n\t\t\t\t\t\t\t\tbt->IsLeftValue = false;\n\t\t\t\t\t\t\tint curMax = children[0];\n\t\t\t\t\t\t\tfor (int i = 0; i < children.Count(); i++)\n\t\t\t\t\t\t\t\tif (children[i] < curMax)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tbt->IsLeftValue = false;\n\t\t\t\t\t\t\t\t\tcurMax = children[i];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (baseType->AsBasicType()->BaseType == BaseType::Shader)\n\t\t\t\t{\n\t\t\t\t\tShaderUsing shaderObj;\n\t\t\t\t\tauto refComp = baseType->AsBasicType()->Shader->ResolveComponentReference(expr->MemberName);\n\t\t\t\t\tif (refComp.IsAccessible)\n\t\t\t\t\t\texpr->Type = refComp.Component->Type->DataType;\n\t\t\t\t\telse if (baseType->AsBasicType()->Shader->ShaderObjects.TryGetValue(expr->MemberName, shaderObj))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (shaderObj.IsPublic)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto shaderType = new BasicExpressionType(BaseType::Shader);\n\t\t\t\t\t\t\tshaderType->Shader = shaderObj.Shader;\n\t\t\t\t\t\t\texpr->Type = shaderType;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t}\n\t\t\t\telse if (baseType->IsStruct())\n\t\t\t\t{\n\t\t\t\t\tStructField* field = baseType->AsBasicType()->structDecl->FindField(expr->MemberName);\n\t\t\t\t\tif (!field)\n\t\t\t\t\t{\n\t\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::noMemberOfNameInType, expr->MemberName, baseType->AsBasicType()->structDecl);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\texpr->Type = field->Type;\n\t\t\t\t\tif (auto bt = expr->Type->AsBasicType())\n\t\t\t\t\t{\n\t\t\t\t\t\tbt->IsLeftValue = baseType->AsBasicType()->IsLeftValue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\texpr->Type = ExpressionType::Error;\n\t\t\t\tif (!baseType->Equals(ExpressionType::Error.Ptr()) &&\n\t\t\t\t\texpr->Type->Equals(ExpressionType::Error.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tgetSink()->diagnose(expr, Diagnostics::typeHasNoPublicMemberOfName, baseType, expr->MemberName);\n\t\t\t\t}\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tSemanticsVisitor & operator = (const SemanticsVisitor &) = delete;\n\t\t};\n\n\t\tSyntaxVisitor * CreateSemanticsVisitor(SymbolTable * symbols, DiagnosticSink * err)\n\t\t{\n\t\t\treturn new SemanticsVisitor(symbols, err);\n\t\t}\n\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/ShaderCompiler.cpp",
    "content": "// Compiler.cpp : Defines the entry point for the console application.\n//\n#include \"../CoreLib/Basic.h\"\n#include \"../CoreLib/LibIO.h\"\n#include \"ShaderCompiler.h\"\n#include \"Lexer.h\"\n#include \"Parser.h\"\n#include \"Preprocessor.h\"\n#include \"SyntaxVisitors.h\"\n#include \"StdInclude.h\"\n#include \"Schedule.h\"\n#include \"CodeGenBackend.h\"\n#include \"../CoreLib/Tokenizer.h\"\n#include \"Closure.h\"\n#include \"VariantIR.h\"\n#include \"Naming.h\"\n\n#ifdef CreateDirectory\n#undef CreateDirectory\n#endif\n\nusing namespace CoreLib::Basic;\nusing namespace CoreLib::IO;\nusing namespace Spire::Compiler;\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tint compilerInstances = 0;\n\n\t\tclass ShaderCompilerImpl : public ShaderCompiler\n\t\t{\n\t\tprivate:\n\t\t\tDictionary<String, RefPtr<CodeGenBackend>> backends;\n\n\t\t\tvoid ResolveAttributes(SymbolTable * symTable)\n\t\t\t{\n\t\t\t\tfor (auto & shader : symTable->ShaderDependenceOrder)\n\t\t\t\t{\n\t\t\t\t\tauto comps = shader->GetComponentDependencyOrder();\n\t\t\t\t\tfor (auto & comp : comps)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto & impl : comp->Implementations)\n\t\t\t\t\t\t\tfor (auto attrib : impl->SyntaxNode->GetLayoutAttributes())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttry\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (attrib->GetValue().StartsWith(\"%\"))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tCoreLib::Text::TokenReader parser(attrib->GetValue().SubString(1, attrib->GetValue().Length() - 1));\n\t\t\t\t\t\t\t\t\t\tauto compName = parser.ReadWord();\n\t\t\t\t\t\t\t\t\t\tparser.Read(\".\");\n\t\t\t\t\t\t\t\t\t\tauto compAttrib = parser.ReadWord();\n\t\t\t\t\t\t\t\t\t\tRefPtr<ShaderComponentSymbol> compSym;\n\t\t\t\t\t\t\t\t\t\tif (shader->Components.TryGetValue(compName, compSym))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tfor (auto & timpl : compSym->Implementations)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tToken attribValue;\n\t\t\t\t\t\t\t\t\t\t\t\tif (timpl->SyntaxNode->FindSimpleAttribute(compAttrib, attribValue))\n\t\t\t\t\t\t\t\t\t\t\t\t\tattrib->Value = attribValue;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tcatch (Exception)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Generate a shader variant by applying mechanic choice rules and the choice file.\n\t\t\t   The choice file provides \"preferred\" definitions, as represented in ShaderComponentSymbol::Type::PinnedWorlds\n\t\t       The process resolves the component references by picking a pinned definition if one is available, or a definition\n\t\t\t   with the preferred import path as defined by import operator ordering.\n\t\t\t   After all references are resolved, all unreferenced definitions (dead code) are eliminated, \n\t\t\t   resulting a shader variant ready for code generation.\n\t\t\t*/\n\t\t\tRefPtr<ShaderIR> GenerateShaderVariantIR(CompileResult & cresult, ShaderClosure * shader, Schedule & schedule, SymbolTable * symbolTable)\n\t\t\t{\n\t\t\t\tRefPtr<ShaderIR> result = new ShaderIR();\n\t\t\t\tresult->Shader = shader;\n\t\t\t\tresult->SymbolTable = symbolTable;\n\t\t\t\t// mark pinned worlds\n\t\t\t\tfor (auto & comp : shader->Components)\n\t\t\t\t{\n\t\t\t\t\tfor (auto & impl : comp.Value->Implementations)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto & w : impl->Worlds)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (impl->SrcPinnedWorlds.Contains(w) || impl->SyntaxNode->IsInline() || impl->ExportWorlds.Contains(w) || impl->SyntaxNode->IsInput())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcomp.Value->Type->PinnedWorlds.Add(w);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// apply choices\n\t\t\t\tDictionary<String, ShaderComponentSymbol*> choiceComps;\n\t\t\t\tfor (auto & comp : shader->AllComponents)\n\t\t\t\t{\n\t\t\t\t\tfor (auto & choiceName : comp.Value.Symbol->ChoiceNames)\n\t\t\t\t\t\tchoiceComps[choiceName] = comp.Value.Symbol;\n\t\t\t\t}\n\t\t\t\tHashSet<ShaderComponentImplSymbol*> pinnedImpl;\n\t\t\t\tfor (auto & choice : schedule.Choices)\n\t\t\t\t{\n\t\t\t\t\tShaderComponentSymbol * comp = nullptr;\n\t\t\t\t\tif (choiceComps.TryGetValue(choice.Key, comp))\n\t\t\t\t\t{\n\t\t\t\t\t\tcomp->Type->PinnedWorlds.Clear();\n\t\t\t\t\t\tfor (auto & selectedDef : choice.Value)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (comp->Type->ConstrainedWorlds.Contains(selectedDef->WorldName))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcomp->Type->PinnedWorlds.Add(selectedDef->WorldName);\n\t\t\t\t\t\t\t\t// find specified impl\n\t\t\t\t\t\t\t\tfor (auto & impl : comp->Implementations)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (impl->Worlds.Contains(selectedDef->WorldName))\n\t\t\t\t\t\t\t\t\t\tpinnedImpl.Add(impl.Ptr());\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n                                cresult.GetErrorWriter()->diagnose(selectedDef.Ptr()->Position, Diagnostics::worldIsNotAValidChoiceForKey, selectedDef->WorldName, choice.Key);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (auto & attribs : schedule.AddtionalAttributes)\n\t\t\t\t{\n\t\t\t\t\tShaderComponentSymbol * comp = nullptr;\n\t\t\t\t\tif (choiceComps.TryGetValue(attribs.Key, comp))\n\t\t\t\t\t{\n\t\t\t\t\t\t// apply attributes\n\t\t\t\t\t\tfor (auto & impl : comp->Implementations)\n\t\t\t\t\t\t{\n                            for (auto & attrib : attribs.Value)\n                            {\n                                auto modifier = new SimpleAttribute();\n                                modifier->Key = attrib.Key;\n                                modifier->Value.Content = attrib.Value;\n\n                                modifier->next = impl->SyntaxNode->modifiers.first;\n                                impl->SyntaxNode->modifiers.first = modifier;\n                            }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// generate definitions\n\t\t\t\tEnumerableDictionary<ShaderClosure*, ModuleInstanceIR*> moduleInstanceMap;\n\t\t\t\tauto createModuleInstance = [&](ShaderClosure * closure)\n\t\t\t\t{\n\t\t\t\t\tModuleInstanceIR * inst;\n\t\t\t\t\tif (moduleInstanceMap.TryGetValue(closure, inst))\n\t\t\t\t\t\treturn inst;\n\t\t\t\t\tList<String> namePath;\n\t\t\t\t\t\n\t\t\t\t\tauto parent = closure;\n\t\t\t\t\twhile (parent)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (parent->Name.Length())\n\t\t\t\t\t\t\tnamePath.Add(parent->Name);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tnamePath.Add(parent->ModuleSyntaxNode->Name.Content);\n\t\t\t\t\t\tparent = parent->Parent;\n\t\t\t\t\t}\n\t\t\t\t\tStringBuilder sbBindingName;\n\t\t\t\t\tfor (int i = namePath.Count() - 2; i >= 0; i--)\n\t\t\t\t\t{\n\t\t\t\t\t\tsbBindingName << namePath[i];\n\t\t\t\t\t\tif (i > 0)\n\t\t\t\t\t\t\tsbBindingName << \".\";\n\t\t\t\t\t}\n\t\t\t\t\t// if this is the root module, its binding name is module name.\n\t\t\t\t\tif (namePath.Count() == 1)\n\t\t\t\t\t\tsbBindingName << namePath[0];\n\t\t\t\t\tinst = new ModuleInstanceIR();\n\t\t\t\t\tinst->IsTopLevel = namePath.Count() <= 2;\n\t\t\t\t\tinst->SyntaxNode = closure->ModuleSyntaxNode;\n\t\t\t\t\tinst->BindingIndex = closure->BindingIndex;\n\t\t\t\t\tinst->UsingPosition = closure->UsingPosition;\n\t\t\t\t\tresult->ModuleInstances.Add(inst);\n\t\t\t\t\tinst->BindingName = sbBindingName.ProduceString();\n\t\t\t\t\tmoduleInstanceMap[closure] = inst;\n\t\t\t\t\treturn inst;\n\t\t\t\t};\n\t\t\t\tfor (auto & comp : shader->AllComponents)\n\t\t\t\t{\n\t\t\t\t\tEnumerableDictionary<String, ComponentDefinitionIR*> defs;\n\t\t\t\t\tDictionary<String, ShaderComponentImplSymbol*> impls;\n\t\t\t\t\tfor (auto & impl : comp.Value.Symbol->Implementations)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto createComponentDef = [&](const String & w)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tRefPtr<ComponentDefinitionIR> def = new ComponentDefinitionIR();\n\t\t\t\t\t\t\tdef->OriginalName = comp.Value.Symbol->Name;\n\t\t\t\t\t\t\tdef->UniqueKey = comp.Value.Symbol->UniqueKey;\n\t\t\t\t\t\t\tdef->UniqueName = comp.Value.Symbol->UniqueName;\n\t\t\t\t\t\t\tdef->Type = comp.Value.Symbol->Type->DataType;\n\t\t\t\t\t\t\tdef->IsEntryPoint = (impl->ExportWorlds.Contains(w) || impl->SyntaxNode->IsParam() ||\n\t\t\t\t\t\t\t\t(shader->Pipeline->IsAbstractWorld(w) &&\n\t\t\t\t\t\t\t\t(impl->SyntaxNode->HasSimpleAttribute(\"Pinned\") || shader->Pipeline->Worlds[w]()->HasSimpleAttribute(\"Pinned\"))));\n\t\t\t\t\t\t\tCloneContext cloneCtx;\n\t\t\t\t\t\t\tdef->SyntaxNode = impl->SyntaxNode->Clone(cloneCtx);\n\t\t\t\t\t\t\tdef->World = w;\n\t\t\t\t\t\t\tdef->ModuleInstance = createModuleInstance(comp.Value.Closure);\n\t\t\t\t\t\t\treturn def;\n\t\t\t\t\t\t};\n\t\t\t\t\t\t// parameter component will only have one defintion that is shared by all worlds\n\t\t\t\t\t\tif (impl->SyntaxNode->IsParam())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto def = createComponentDef(\"<uniform>\");\n\t\t\t\t\t\t\tresult->Definitions.Add(def);\n\t\t\t\t\t\t\tdefs[\"<uniform>\"] = def.Ptr();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto & w : impl->Worlds)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tauto def = createComponentDef(w);\n\t\t\t\t\t\t\t\tresult->Definitions.Add(def);\n\t\t\t\t\t\t\t\tbool existingDefIsPinned = false;\n\t\t\t\t\t\t\t\tif (defs.ContainsKey(w))\n\t\t\t\t\t\t\t\t\texistingDefIsPinned = pinnedImpl.Contains(impls[w]());\n\t\t\t\t\t\t\t\tif (!existingDefIsPinned)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tdefs[w] = def.Ptr();\n\t\t\t\t\t\t\t\t\timpls[w] = impl.Ptr();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tresult->DefinitionsByComponent[comp.Key] = defs;\n\t\t\t\t}\n\t\t\t\t// now that all module instances are generated, sort out sub module instances\n\t\t\t\tfor (auto & module : moduleInstanceMap)\n\t\t\t\t{\n\t\t\t\t\tauto closure = module.Key;\n\t\t\t\t\t// find first parent of this module, and add the module to the parent's children list\n\t\t\t\t\twhile (closure->Parent)\n\t\t\t\t\t{\n\t\t\t\t\t\tclosure = closure->Parent;\n\t\t\t\t\t\tModuleInstanceIR * parentModule;\n\t\t\t\t\t\tif (closure->Parent && moduleInstanceMap.TryGetValue(closure, parentModule))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tparentModule->SubModuleInstances.Add(module.Value);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbool changed = true;\n\t\t\t\twhile (changed)\n\t\t\t\t{\n\t\t\t\t\tchanged = false;\n\t\t\t\t\tresult->ResolveComponentReference();\n\t\t\t\t\tresult->EliminateDeadCode();\n\t\t\t\t\t// check circular references\n\t\t\t\t\tfor (auto & def : result->Definitions)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (def->Dependency.Contains(def.Ptr()))\n\t\t\t\t\t\t{\n                            cresult.GetErrorWriter()->diagnose(def->SyntaxNode->Position, Diagnostics::componentDefinitionCircularity, def->OriginalName);\n\t\t\t\t\t\t\treturn nullptr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t/*\n\t\t\t\t\t// eliminate redundant (downstream) definitions, one at a time\n\t\t\t\t\tauto comps = result->GetComponentDependencyOrder();\n\t\t\t\t\tfor (int i = comps.Count() - 1; i >= 0; i--)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto comp = comps[i];\n\t\t\t\t\t\tauto & defs = result->DefinitionsByComponent[comp->UniqueName]();\n\t\t\t\t\t\tEnumerableHashSet<ComponentDefinitionIR*> removedDefs;\n\t\t\t\t\t\tfor (auto & def : defs)\n\t\t\t\t\t\t\tif (!def.Value->IsEntryPoint && !comp->Type->PinnedWorlds.Contains(def.Value->World))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor (auto & otherDef : defs)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (otherDef.Value != def.Value && !removedDefs.Contains(otherDef.Value)\n\t\t\t\t\t\t\t\t\t\t&& shader->Pipeline->IsWorldReachable(otherDef.Value->World, def.Value->World))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tremovedDefs.Add(def.Value);\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\tif (removedDefs.Count())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tresult->RemoveDefinitions([&](ComponentDefinitionIR* def) {return removedDefs.Contains(def); });\n\t\t\t\t\t\t\tchanged = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t*/\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tShaderSyntaxNode * InstantiateShaderTemplate(DiagnosticSink* sink, SymbolTable* symTable, TemplateShaderSyntaxNode* ts, const List<String>& args)\n\t\t\t{\n\t\t\t\tif (ts->Parameters.Count() > args.Count())\n\t\t\t\t{\n\t\t\t\t\tsink->diagnose(ts->Position, Diagnostics::insufficientTemplateShaderArguments, ts->Name);\n\t\t\t\t\treturn nullptr;\n\t\t\t\t}\n\t\t\t\tif (ts->Parameters.Count() < args.Count())\n\t\t\t\t{\n\t\t\t\t\tsink->diagnose(ts->Position, Diagnostics::tooManyTemplateShaderArguments, ts->Name);\n\t\t\t\t\treturn nullptr;\n\t\t\t\t}\n\t\t\t\t// check semantics\n\t\t\t\tbool hasErrors = false;\n\t\t\t\tfor (int i = 0; i < args.Count(); i++)\n\t\t\t\t{\n\t\t\t\t\tauto name = args[i];\n\t\t\t\t\tif (auto module = symTable->Shaders.TryGetValue(name))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ts->Parameters[i]->InterfaceName.Content.Length())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ((*module)->SyntaxNode->Name.Content != ts->Parameters[i]->InterfaceName.Content &&\n\t\t\t\t\t\t\t\t(*module)->SyntaxNode->InterfaceNames.FindFirst([&](const Token & t) { return t.Content == ts->Parameters[i]->InterfaceName.Content; }) == -1)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\thasErrors = true;\n\t\t\t\t\t\t\t\tsink->diagnose(ts->Parameters[i]->Position, Diagnostics::templateShaderArgumentDidNotImplementRequiredInterface, name, ts->Parameters[i]->ModuleName, ts->Parameters[i]->InterfaceName);\n\t\t\t\t\t\t\t\tsink->diagnose((*module)->SyntaxNode->Position, Diagnostics::seeDefinitionOf, (*module)->SyntaxNode->Name);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\thasErrors = true;\n\t\t\t\t\t\tsink->diagnose(ts->Parameters[i]->Position, Diagnostics::templateShaderArgumentIsNotDefined, args[i], ts->Parameters[i]->ModuleName.Content);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (hasErrors)\n\t\t\t\t\treturn nullptr;\n\t\t\t\tShaderSyntaxNode * result = new ShaderSyntaxNode();\n\t\t\t\tresult->Name = ts->Name;\n\t\t\t\tStringBuilder nameBuilder;\n\t\t\t\tnameBuilder << ts->Name.Content << \"<\";\n\t\t\t\tfor (int i = 0; i < args.Count(); i++)\n\t\t\t\t{\n\t\t\t\t\tnameBuilder << args[i];\n\t\t\t\t\tif (i < args.Count()-1)\n\t\t\t\t\t\tnameBuilder << \",\";\n\t\t\t\t}\n\t\t\t\tnameBuilder << \">\";\n\t\t\t\tresult->Name.Content = nameBuilder.ProduceString();\n\t\t\t\tresult->ParentPipelineName = ts->ParentPipelineName;\n\t\t\t\tfor (auto & member : ts->Members)\n\t\t\t\t{\n\t\t\t\t\tif (auto import = member.As<ImportSyntaxNode>())\n\t\t\t\t\t{\n\t\t\t\t\t\tint index = ts->Parameters.FindFirst([&](RefPtr<TemplateShaderParameterSyntaxNode> p) { return p->ModuleName.Content == import->ShaderName.Content; });\n\t\t\t\t\t\tif (index != -1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tCloneContext cloneCtx;\n\t\t\t\t\t\t\tauto newImport = import->Clone(cloneCtx);\n\t\t\t\t\t\t\tauto attribModifier = new SimpleAttribute();\n\t\t\t\t\t\t\tattribModifier->Key = \"Binding\";\n\t\t\t\t\t\t\tattribModifier->Value.Content = String(index);\n\t\t\t\t\t\t\tnewImport->modifiers.first = attribModifier;\n\t\t\t\t\t\t\tnewImport->Scope->Parent = result->Scope;\n\t\t\t\t\t\t\tnewImport->ShaderName.Content = args[index];\n\t\t\t\t\t\t\tresult->Members.Add(newImport);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tresult->Members.Add(member);\n\t\t\t\t}\n\t\t\t\tresult->IsModule = false;\n\t\t\t\treturn result;\n\t\t\t}\n\t\tpublic:\n\t\t\tvirtual CompileUnit Parse(CompileResult & result, String source, String fileName, IncludeHandler* includeHandler, Dictionary<String,String> const& preprocesorDefinitions) override\n\t\t\t{\n                auto tokens = PreprocessSource(source, fileName, result.GetErrorWriter(), includeHandler, preprocesorDefinitions);\n\t\t\t\tCompileUnit rs;\n                rs.SyntaxNode = ParseProgram(tokens, result.GetErrorWriter(), fileName);\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\tvirtual void Compile(CompileResult & result, CompilationContext & context, List<CompileUnit> & units, const CompileOptions & options) override\n\t\t\t{\n\t\t\t\tRefPtr<ProgramSyntaxNode> programSyntaxNode = new ProgramSyntaxNode();\n\t\t\t\tfor (auto & unit : units)\n\t\t\t\t{\n\t\t\t\t\tprogramSyntaxNode->Include(unit.SyntaxNode.Ptr());\n\t\t\t\t}\n\n\t\t\t\tSymbolTable & symTable = context.Symbols;\n\t\t\t\tauto & shaderClosures = context.ShaderClosures;\n\t\t\t\t\n\t\t\t\tRefPtr<SyntaxVisitor> visitor = CreateSemanticsVisitor(&symTable, result.GetErrorWriter());\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tprogramSyntaxNode->Accept(visitor.Ptr());\n\t\t\t\t\tif (result.GetErrorCount() > 0)\n\t\t\t\t\t\treturn;\n\t\t\t\t\t// if user specified a template shader symbol, instantiate the template now\n\t\t\t\t\tString symbolToCompile = options.SymbolToCompile;\n\t\t\t\t\tif (symbolToCompile.Length())\n\t\t\t\t\t{\n\t\t\t\t\t\tauto templateShaders = programSyntaxNode->GetMembersOfType<TemplateShaderSyntaxNode>();\n\t\t\t\t\t\tfor (auto & ts : templateShaders)\n\t\t\t\t\t\t\tif (ts->Name.Content == symbolToCompile)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tauto shader = InstantiateShaderTemplate(result.GetErrorWriter(), &symTable, ts.Ptr(), options.TemplateShaderArguments);\n\t\t\t\t\t\t\t\tif (shader)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tprogramSyntaxNode->Members.Add(shader);\n\t\t\t\t\t\t\t\t\tsymbolToCompile = shader->Name.Content;\n\t\t\t\t\t\t\t\t\tprogramSyntaxNode->Accept(visitor.Ptr());\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tvisitor = nullptr;\n\t\t\t\t\tsymTable.EvalFunctionReferenceClosure();\n\t\t\t\t\tif (result.GetErrorCount() > 0)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\tfor (auto & shader : symTable.ShaderDependenceOrder)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (shader->IsAbstract)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tif (!shaderClosures.ContainsKey(shader->SyntaxNode->Name.Content))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto shaderClosure = CreateShaderClosure(result.GetErrorWriter(), &symTable, shader);\n\t\t\t\t\t\t\tFlattenShaderClosure(result.GetErrorWriter(), &symTable, shaderClosure.Ptr());\n\t\t\t\t\t\t\tshaderClosures.Add(shader->SyntaxNode->Name.Content, shaderClosure);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tResolveAttributes(&symTable);\n\n\t\t\t\t\tif (result.GetErrorCount() > 0)\n\t\t\t\t\t\treturn;\n\t\t\t\t\tCodeGenBackend * backend = nullptr;\n\t\t\t\t\tswitch(options.Target)\n\t\t\t\t\t{\n\t\t\t\t\tcase CodeGenTarget::SPIRV:\n\t\t\t\t\t\tbackend = backends[\"spirv\"]().Ptr();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CodeGenTarget::GLSL:\n\t\t\t\t\t\tbackend = backends[\"glsl\"]().Ptr();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CodeGenTarget::GLSL_Vulkan:\n\t\t\t\t\t\tbackend = backends[\"glsl_vk\"]().Ptr();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CodeGenTarget::GLSL_Vulkan_OneDesc:\n\t\t\t\t\t\tbackend = backends[\"glsl_vk_onedesc\"]().Ptr();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CodeGenTarget::HLSL:\n\t\t\t\t\t\tbackend = backends[\"hlsl\"]().Ptr();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\t// TODO: emit an appropriate diagnostic\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tSchedule schedule;\n\t\t\t\t\tif (options.ScheduleSource != \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\tschedule = Schedule::Parse(options.ScheduleSource, options.ScheduleFileName, result.GetErrorWriter());\n\t\t\t\t\t}\n\t\t\t\t\tfor (auto shader : shaderClosures)\n\t\t\t\t\t{\n\t\t\t\t\t\t// generate shader variant from schedule file, and also apply mechanic deduction rules\n\t\t\t\t\t\tif (!shader.Value->IR)\n\t\t\t\t\t\t\tshader.Value->IR = GenerateShaderVariantIR(result, shader.Value.Ptr(), schedule, &symTable);\n\t\t\t\t\t}\n\t\t\t\t\tif (options.Mode == CompilerMode::ProduceShader)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (result.GetErrorWriter()->GetErrorCount() > 0)\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t// generate IL code\n\t\t\t\t\t\t\n\t\t\t\t\t\tRefPtr<ICodeGenerator> codeGen = CreateCodeGenerator(&symTable, result, backend);\n\t\t\t\t\t\tif (context.Program)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tresult.Program->Functions = context.Program->Functions;\n\t\t\t\t\t\t\tresult.Program->Shaders = context.Program->Shaders;\n\t\t\t\t\t\t\tresult.Program->Structs = context.Program->Structs;\n\t\t\t\t\t\t\tresult.Program->ConstantPool = context.Program->ConstantPool;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (auto & s : programSyntaxNode->GetStructs())\n\t\t\t\t\t\t\tcodeGen->ProcessStruct(s.Ptr());\n\n\t\t\t\t\t\tfor (auto & func : programSyntaxNode->GetFunctions())\n\t\t\t\t\t\t\tcodeGen->ProcessFunction(func.Ptr());\n\t\t\t\t\t\tfor (auto & shader : shaderClosures)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tInsertImplicitImportOperators(result.GetErrorWriter(), shader.Value->IR.Ptr());\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (result.GetErrorCount() > 0)\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\tfor (auto & shader : shaderClosures)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcodeGen->ProcessShader(shader.Value->IR.Ptr());\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (result.GetErrorCount() > 0)\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t// emit target code\n\t\t\t\t\t\tEnumerableHashSet<String> symbolsToGen;\n\t\t\t\t\t\tfor (auto & unit : units)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto & shader : unit.SyntaxNode->GetShaders())\n\t\t\t\t\t\t\t\tif (!shader->IsModule)\n\t\t\t\t\t\t\t\t\tsymbolsToGen.Add(shader->Name.Content);\n\t\t\t\t\t\t\tfor (auto & func : unit.SyntaxNode->GetFunctions())\n\t\t\t\t\t\t\t\tsymbolsToGen.Add(func->Name.Content);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tauto IsSymbolToGen = [&](String & shaderName)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (symbolsToGen.Contains(shaderName))\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\tfor (auto & symbol : symbolsToGen)\n\t\t\t\t\t\t\t\tif (shaderName.StartsWith(symbol))\n\t\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t};\n\t\t\t\t\t\tfor (auto & shader : result.Program->Shaders)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ((symbolToCompile.Length() == 0 && IsSymbolToGen(shader->Name))\n\t\t\t\t\t\t\t\t|| EscapeCodeName(symbolToCompile) == shader->Name)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStringBuilder glslBuilder;\n\t\t\t\t\t\t\t\tDictionary<String, String> targetCode;\n\t\t\t\t\t\t\t\tresult.CompiledSource[shader->Name] = backend->GenerateShader(result, &symTable, shader.Ptr(), result.GetErrorWriter());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (options.Mode == CompilerMode::GenerateChoice)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto shader : shaderClosures)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (options.SymbolToCompile.Length() == 0 || shader.Value->Name == options.SymbolToCompile)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tauto &worldOrder = shader.Value->Pipeline->GetWorldTopologyOrder();\n\t\t\t\t\t\t\t\tfor (auto & comp : shader.Value->AllComponents)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tShaderChoice choice;\n\t\t\t\t\t\t\t\t\tif (comp.Value.Symbol->ChoiceNames.Count() == 0)\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\tif (comp.Value.Symbol->IsRequire())\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\tchoice.ChoiceName = comp.Value.Symbol->ChoiceNames.First();\n\t\t\t\t\t\t\t\t\tfor (auto & impl : comp.Value.Symbol->Implementations)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tfor (auto w : impl->Worlds)\n\t\t\t\t\t\t\t\t\t\t\tif (comp.Value.Symbol->Type->ConstrainedWorlds.Contains(w))\n\t\t\t\t\t\t\t\t\t\t\t\tchoice.Options.Add(ShaderChoiceValue(w));\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif (auto defs = shader.Value->IR->DefinitionsByComponent.TryGetValue(comp.Key))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tint latestWorldOrder = -1;\n\t\t\t\t\t\t\t\t\t\tfor (auto & def : *defs)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tint order = worldOrder.IndexOf(def.Key);\n\t\t\t\t\t\t\t\t\t\t\tif (latestWorldOrder < order)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tchoice.DefaultValue = def.Key;\n\t\t\t\t\t\t\t\t\t\t\t\tlatestWorldOrder = order;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tresult.Choices.Add(choice);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n                        result.GetErrorWriter()->diagnose(CodePosition(), Diagnostics::unsupportedCompilerMode);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcontext.Program = result.Program;\n\t\t\t\t}\n\t\t\t\tcatch (int)\n\t\t\t\t{\n\t\t\t\t}\n\t\t\t\tcatch (...)\n\t\t\t\t{\n\t\t\t\t\tthrow;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tShaderCompilerImpl()\n\t\t\t{\n\t\t\t\tif (compilerInstances == 0)\n\t\t\t\t{\n\t\t\t\t\tBasicExpressionType::Init();\n\t\t\t\t}\n\t\t\t\tcompilerInstances++;\n\t\t\t\tbackends.Add(\"glsl\", CreateGLSLCodeGen());\n\t\t\t\tbackends.Add(\"hlsl\", CreateHLSLCodeGen());\n\t\t\t\tbackends.Add(\"spirv\", CreateSpirVCodeGen());\n\t\t\t\tbackends.Add(\"glsl_vk\", CreateGLSL_VulkanCodeGen());\n\t\t\t\tbackends.Add(\"glsl_vk_onedesc\", CreateGLSL_VulkanOneDescCodeGen());\n\t\t\t}\n\n\t\t\t~ShaderCompilerImpl()\n\t\t\t{\n\t\t\t\tcompilerInstances--;\n\t\t\t\tif (compilerInstances == 0)\n\t\t\t\t{\n\t\t\t\t\tBasicExpressionType::Finalize();\n\t\t\t\t\tSpireStdLib::Finalize();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tShaderCompiler * CreateShaderCompiler()\n\t\t{\n\t\t\treturn new ShaderCompilerImpl();\n\t\t}\n\n\t\tvoid CompilationContext::MergeWith(CompilationContext * ctx)\n\t\t{\n\t\t\tSymbols.MergeWith(ctx->Symbols);\n\t\t\tif (ctx->Program != Program)\n\t\t\t{\n\t\t\t\tfor (auto & f : ctx->Program->Functions)\n\t\t\t\t\tProgram->Functions[f.Key] = f.Value;\n\t\t\t\tHashSet<ILStructType*> existingStructs;\n\t\t\t\tfor (auto & s : Program->Structs)\n\t\t\t\t\texistingStructs.Add(s.Ptr());\n\t\t\t\tfor (auto & s : ctx->Program->Structs)\n\t\t\t\t\tif (existingStructs.Add(s.Ptr()))\n\t\t\t\t\t\tProgram->Structs.Add(s);\n\t\t\t\tHashSet<ILShader*> existingShaders;\n\t\t\t\tfor (auto & s : Program->Shaders)\n\t\t\t\t\texistingShaders.Add(s.Ptr());\n\t\t\t\tfor (auto & s : ctx->Program->Shaders)\n\t\t\t\t\tif (existingShaders.Add(s.Ptr()))\n\t\t\t\t\t\tProgram->Shaders.Add(s);\n\t\t\t}\n\t\t\tfor (auto & s : ctx->ShaderClosures)\n\t\t\t\tShaderClosures[s.Key] = s.Value;\n\t\t}\n\n}\n}\n"
  },
  {
    "path": "Source/SpireCore/ShaderCompiler.h",
    "content": "#ifndef RASTER_SHADER_COMPILER_H\n#define RASTER_SHADER_COMPILER_H\n\n#include \"../CoreLib/Basic.h\"\n#include \"Diagnostics.h\"\n#include \"CompiledProgram.h\"\n#include \"Syntax.h\"\n#include \"CodeGenBackend.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tclass ILConstOperand;\n        struct IncludeHandler;\n\n\t\tenum class CompilerMode\n\t\t{\n\t\t\tProduceLibrary,\n\t\t\tProduceShader,\n\t\t\tGenerateChoice\n\t\t};\n\n\t\tenum class CodeGenTarget\n\t\t{\n\t\t\tGLSL, GLSL_Vulkan, GLSL_Vulkan_OneDesc, HLSL, SPIRV\n\t\t};\n\n\t\tclass CompileOptions\n\t\t{\n\t\tpublic:\n\t\t\tCompilerMode Mode = CompilerMode::ProduceShader;\n\t\t\tCodeGenTarget Target = CodeGenTarget::GLSL;\n\t\t\tEnumerableDictionary<String, String> BackendArguments;\n\t\t\tString ScheduleSource, ScheduleFileName;\n\t\t\tString SymbolToCompile;\n\t\t\tList<String> TemplateShaderArguments;\n\t\t\tList<String> SearchDirectories;\n            Dictionary<String, String> PreprocessorDefinitions;\n\t\t};\n\n\t\tclass CompileUnit\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ProgramSyntaxNode> SyntaxNode;\n\t\t};\n\n\t\tclass CompilationContext : public CoreLib::Basic::RefObject\n\t\t{\n\t\tpublic:\n\t\t\tSymbolTable Symbols;\n\t\t\tEnumerableDictionary<String, RefPtr<ShaderClosure>> ShaderClosures;\n\t\t\tRefPtr<ILProgram> Program;\n\t\t\tvoid MergeWith(CompilationContext * ctx);\n\t\t};\n\n\t\tclass ShaderCompiler : public CoreLib::Basic::Object\n\t\t{\n\t\tpublic:\n\t\t\tvirtual CompileUnit Parse(CompileResult & result, String source, String fileName, IncludeHandler* includeHandler, Dictionary<String,String> const& preprocessorDefinitions) = 0;\n\t\t\tvirtual void Compile(CompileResult & result, CompilationContext & context, List<CompileUnit> & units, const CompileOptions & options) = 0;\n\t\t\tvoid Compile(CompileResult & result, List<CompileUnit> & units, const CompileOptions & options)\n\t\t\t{\n\t\t\t\tCompilationContext context;\n\t\t\t\tCompile(result, context, units, options);\n\t\t\t}\n\t\t};\n\n\t\tShaderCompiler * CreateShaderCompiler();\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/SpirVCodeGen.cpp",
    "content": "#if 0\n#include \"CodeGenBackend.h\"\n#include \"../CoreLib/Tokenizer.h\"\n#include \"IL.h\"\n#include \"Syntax.h\"\n#include <vector>\n#include <fstream>\n#include \"../CoreLib/TextIO.h\"\n#include \"../CoreLib/LibIO.h\"\n\nusing namespace CoreLib::Basic;\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\n\t\tenum class ExecutionModel\n\t\t{\n\t\t\tInvalid = 777,\n\t\t\tVertex = 0,\n\t\t\tTessellationControl = 1,\n\t\t\tTessellationEvaluation = 2,\n\t\t\tGeometry = 3,\n\t\t\tFragment = 4,\n\t\t\tGLCompute = 5,\n\t\t\tKernel = 6\n\t\t};\n\n\t\tString ExecutionModelToString(ExecutionModel em)\n\t\t{\n\t\t\tswitch (em)\n\t\t\t{\n\t\t\tcase ExecutionModel::Invalid:\n\t\t\t\treturn \"invalid\";\n\t\t\tcase ExecutionModel::Vertex:\n\t\t\t\treturn \"Vertex\";\n\t\t\tcase ExecutionModel::TessellationControl:\n\t\t\t\treturn \"TessellationContro\";\n\t\t\tcase ExecutionModel::TessellationEvaluation:\n\t\t\t\treturn \"TessellationEvaluation\";\n\t\t\tcase ExecutionModel::Geometry:\n\t\t\t\treturn \"Geometry\";\n\t\t\tcase ExecutionModel::Fragment:\n\t\t\t\treturn \"Fragment\";\n\t\t\tcase ExecutionModel::GLCompute:\n\t\t\t\treturn \"GLCompute\";\n\t\t\tcase ExecutionModel::Kernel:\n\t\t\t\treturn \"Kerne\";\n\t\t\tdefault:\n\t\t\t\tthrow NotImplementedException(\"unknown ExecutionMode\");\n\t\t\t}\n\t\t}\n\n\t\tenum class ExecutionMode\n\t\t{\n\t\t\tInvalid = 777,\n\t\t\tInvocations = 0,\n\t\t\tPixelCenterInteger = 6,\n\t\t\tOriginUpperLeft = 7,\n\t\t\tOriginLowerLeft = 8,\n\t\t\tEarlyFragmentTests = 9,\n\t\t\tDepthReplacing = 12,\n\t\t\tDepthGreater = 14,\n\t\t\tDepthLess = 15,\n\t\t\tDepthUnchanged = 16,\n\t\t\tLocalSize = 17\n\t\t};\n\n\t\tString ExecutionModeToString(ExecutionMode em)\n\t\t{\n\t\t\tswitch (em)\n\t\t\t{\n\t\t\tcase ExecutionMode::Invalid:\n\t\t\t\treturn \"invalid\";\n\t\t\tcase ExecutionMode::Invocations:\n\t\t\t\treturn \"Invocations\";\n\t\t\tcase ExecutionMode::PixelCenterInteger:\n\t\t\t\treturn \"PixelCenterInteger\";\n\t\t\tcase ExecutionMode::OriginUpperLeft:\n\t\t\t\treturn \"OriginUpperLeft\";\n\t\t\tcase ExecutionMode::OriginLowerLeft:\n\t\t\t\treturn \"OriginLowerLeft\";\n\t\t\tcase ExecutionMode::EarlyFragmentTests:\n\t\t\t\treturn \"EarlyFragmentTests\";\n\t\t\tcase ExecutionMode::DepthReplacing:\n\t\t\t\treturn \"DepthReplacing\";\n\t\t\tcase ExecutionMode::DepthGreater:\n\t\t\t\treturn \"DepthGreater\";\n\t\t\tcase ExecutionMode::DepthLess:\n\t\t\t\treturn \"DepthLess\";\n\t\t\tcase ExecutionMode::DepthUnchanged:\n\t\t\t\treturn \"DepthUnchanged\";\n\t\t\tcase ExecutionMode::LocalSize:\n\t\t\t\treturn \"LocalSize\";\n\t\t\tdefault:\n\t\t\t\tthrow NotImplementedException(\"unknown ExecutionMode\");\n\t\t\t}\n\t\t}\n\n\t\tenum class StorageClass\n\t\t{\n\t\t\tInvalid = 777,\n\t\t\tUniformConstant = 0,\n\t\t\tInput = 1,\n\t\t\tUniform = 2,\n\t\t\tOutput = 3,\n\t\t\tWorkgroup = 4,\n\t\t\tCrossWorkGroup = 5,\n\t\t\tPrivate = 6,\n\t\t\tFunction = 7,\n\t\t\tGeneric = 8,\n\t\t\tPushConstant = 9,\n\t\t\tAtomicCounter = 10,\n\t\t\tImage = 11\n\t\t};\n\n\t\tString StorageClassToString(StorageClass store)\n\t\t{\n\t\t\tswitch (store)\n\t\t\t{\n\t\t\tcase StorageClass::UniformConstant:\n\t\t\t\treturn \"UniformConstant\";\n\t\t\tcase StorageClass::Input:\n\t\t\t\treturn \"Input\";\n\t\t\tcase StorageClass::Uniform:\n\t\t\t\treturn \"Uniform\";\n\t\t\tcase StorageClass::Output:\n\t\t\t\treturn \"Output\";\n\t\t\tcase StorageClass::Workgroup:\n\t\t\t\treturn \"Workgroup\";\n\t\t\tcase StorageClass::CrossWorkGroup:\n\t\t\t\treturn \"CrossWorkGroup\";\n\t\t\tcase StorageClass::Private:\n\t\t\t\treturn \"Private\";\n\t\t\tcase StorageClass::Function:\n\t\t\t\treturn \"Function\";\n\t\t\tcase StorageClass::Generic:\n\t\t\t\treturn \"Generic\";\n\t\t\tcase StorageClass::PushConstant:\n\t\t\t\treturn \"PushConstant\";\n\t\t\tcase StorageClass::AtomicCounter:\n\t\t\t\treturn \"AtomicCounter\";\n\t\t\tcase StorageClass::Image:\n\t\t\t\treturn \"Image\";\n\t\t\tdefault:\n\t\t\t\tthrow NotImplementedException(\"Unknown StorageClass: \");\n\t\t\t}\n\t\t}\n\n\t\tenum class MemoryAccess\n\t\t{\n\t\t\tNone = 0, //0x0\n\t\t\tVolatile = 1, //0x1\n\t\t\tAligned = 2, //0x2\n\t\t\tNontemporal = 4 //0x4\n\t\t};\n\n\t\tString MemoryAccessToString(MemoryAccess ma)\n\t\t{\n\t\t\tswitch (ma)\n\t\t\t{\n\t\t\tcase MemoryAccess::None:\n\t\t\t\treturn \"None\";\n\t\t\tcase MemoryAccess::Volatile:\n\t\t\t\treturn \"Volatile\";\n\t\t\tcase MemoryAccess::Aligned:\n\t\t\t\treturn \"Aligned\";\n\t\t\tcase MemoryAccess::Nontemporal:\n\t\t\t\treturn \"Nontempora\";\n\t\t\tdefault:\n\t\t\t\tthrow NotImplementedException(\"Unknown MemoryAccess\");\n\t\t\t}\n\t\t}\n\n\t\tenum class Decoration\n\t\t{\n\t\t\tInvalid = 777,\n\t\t\tBlock = 2,\n\t\t\tBufferBlock = 3,\n\t\t\tRowMajor = 4,\n\t\t\tColMajor = 5,\n\t\t\tArrayStride = 6,\n\t\t\tMatrixStride = 7,\n\t\t\tBuiltIn = 11,\n\t\t\tFlat = 14,\n\t\t\tConstant = 22,\n\t\t\tLocation = 30,\n\t\t\tComponent = 31,\n\t\t\tIndex = 32,\n\t\t\tBinding = 33,\n\t\t\tDescriptorSet = 34,\n\t\t\tOffset = 35\n\t\t};\n\n\t\tString DecorationToString(Decoration d)\n\t\t{\n\t\t\tswitch (d)\n\t\t\t{\n\t\t\tcase Decoration::Invalid:\n\t\t\t\treturn \"invalid\";\n\t\t\tcase Decoration::Block:\n\t\t\t\treturn \"Block\";\n\t\t\tcase Decoration::BufferBlock:\n\t\t\t\treturn \"BufferBlock\";\n\t\t\tcase Decoration::RowMajor:\n\t\t\t\treturn \"RowMajor\";\n\t\t\tcase Decoration::ColMajor:\n\t\t\t\treturn \"ColMajor\";\n\t\t\tcase Decoration::ArrayStride:\n\t\t\t\treturn \"ArrayStride\";\n\t\t\tcase Decoration::MatrixStride:\n\t\t\t\treturn \"MatrixStride\";\n\t\t\tcase Decoration::BuiltIn:\n\t\t\t\treturn \"BuiltIn\";\n\t\t\tcase Decoration::Flat:\n\t\t\t\treturn \"Flat\";\n\t\t\tcase Decoration::Constant:\n\t\t\t\treturn \"Constant\";\n\t\t\tcase Decoration::Location:\n\t\t\t\treturn \"Location\";\n\t\t\tcase Decoration::Component:\n\t\t\t\treturn \"Component\";\n\t\t\tcase Decoration::Index:\n\t\t\t\treturn \"Index\";\n\t\t\tcase Decoration::Binding:\n\t\t\t\treturn \"Binding\";\n\t\t\tcase Decoration::DescriptorSet:\n\t\t\t\treturn \"DescriptorSet\";\n\t\t\tcase Decoration::Offset:\n\t\t\t\treturn \"Offset\";\n\t\t\tdefault:\n\t\t\t\tthrow NotImplementedException(\"unknown Decoration\");\n\t\t\t}\n\t\t}\n\n\t\tenum class BuiltIn\n\t\t{\n\t\t\tInvalid = 777,\n\t\t\tPosition = 0,\n\t\t\tPointSize = 1,\n\t\t\tClipDistance = 3,\n\t\t\tCullDistance = 4,\n\t\t\tFragDepth = 22,\n\t\t\tWorkgroupSize = 25,\n\t\t\tGlobalInvocationId = 28\n\t\t};\n\n\t\tString BuiltinToString(BuiltIn b)\n\t\t{\n\t\t\tswitch (b)\n\t\t\t{\n\t\t\tcase BuiltIn::Invalid:\n\t\t\t\treturn \"invalid\";\n\t\t\tcase BuiltIn::Position:\n\t\t\t\treturn \"Position\";\n\t\t\tcase BuiltIn::PointSize:\n\t\t\t\treturn \"PointSize\";\n\t\t\tcase BuiltIn::ClipDistance:\n\t\t\t\treturn \"ClipDistance\";\n\t\t\tcase BuiltIn::CullDistance:\n\t\t\t\treturn \"CullDistance\";\n\t\t\tcase BuiltIn::FragDepth:\n\t\t\t\treturn \"FragDepth\";\n\t\t\tcase BuiltIn::WorkgroupSize:\n\t\t\t\treturn \"WorkgroupSize\";\n\t\t\tcase BuiltIn::GlobalInvocationId:\n\t\t\t\treturn \"GlobalInvocationId\";\n\t\t\tdefault:\n\t\t\t\tthrow NotImplementedException(\"unknown Builtin\");\n\t\t\t}\n\t\t}\n\n\t\tenum class Dim\n\t\t{\n\t\t\te1D = 0,\n\t\t\te2D = 1,\n\t\t\te3D = 2,\n\t\t\teCube = 3,\n\t\t\teRect = 4,\n\t\t\teBuffer = 5,\n\t\t\teSubpassData = 6\n\t\t};\n\n\t\tString DimToString(Dim b)\n\t\t{\n\t\t\tswitch (b)\n\t\t\t{\n\t\t\tcase Dim::e1D:\n\t\t\t\treturn \"1D\";\n\t\t\tcase Dim::e2D:\n\t\t\t\treturn \"2D\";\n\t\t\tcase Dim::e3D:\n\t\t\t\treturn \"3D\";\n\t\t\tcase Dim::eCube:\n\t\t\t\treturn \"Cube\";\n\t\t\tcase Dim::eRect:\n\t\t\t\treturn \"Rect\";\n\t\t\tcase Dim::eBuffer:\n\t\t\t\treturn \"Buffer\";\n\t\t\tcase Dim::eSubpassData:\n\t\t\t\treturn \"SubpassData\";\n\t\t\tdefault:\n\t\t\t\tthrow NotImplementedException(\"unknown Builtin\");\n\t\t\t}\n\t\t}\n\n\t\tenum class ImageOperands\n\t\t{\n\t\t\tNone = 0,\n\t\t\tBias = 0x1,\n\t\t\tLod = 0x2,\n\t\t\tGrad = 0x4,\n\t\t\tConstOffset = 0x8,\n\t\t\tOffset = 0x10,\n\t\t\tConstOffsets = 0x20,\n\t\t\tSample = 0x40,\n\t\t\tMinLod = 0x80\n\t\t};\n\n\t\tString ImageOperandsToString(ImageOperands io)\n\t\t{\n\t\t\tswitch (io)\n\t\t\t{\n\t\t\tcase ImageOperands::None:\n\t\t\t\treturn \"None\";\n\t\t\tcase ImageOperands::Bias:\n\t\t\t\treturn \"Bias\";\n\t\t\tcase ImageOperands::Lod:\n\t\t\t\treturn \"Lod\";\n\t\t\tcase ImageOperands::Grad:\n\t\t\t\treturn \"Grad\";\n\t\t\tcase ImageOperands::ConstOffset:\n\t\t\t\treturn \"ConstOffset\";\n\t\t\tcase ImageOperands::Offset:\n\t\t\t\treturn \"Offset\";\n\t\t\tcase ImageOperands::ConstOffsets:\n\t\t\t\treturn \"ConstOffsets\";\n\t\t\tcase ImageOperands::Sample:\n\t\t\t\treturn \"Sample\";\n\t\t\tcase ImageOperands::MinLod:\n\t\t\t\treturn \"MinLod\";\n\t\t\tdefault:\n\t\t\t\tthrow NotImplementedException(\"unknown Image Operands\");\n\t\t\t}\n\t\t}\n\n\t\tDictionary<String, int> GenGLSLstd450InstructionSet()\n\t\t\t//https://www.khronos.org/registry/spir-v/specs/1.0/GLSL.std.450.html\n\t\t{\n\t\t\tDictionary<String, int> ret;\n\n\t\t\tret[\"abs\"] = 4;\t//fabs, actually :(\n\t\t\tret[\"sign\"] = 6;\t//fsign, actually :(\n\t\t\tret[\"floor\"] = 8;\n\t\t\tret[\"cei\"] = 9;\n\t\t\tret[\"fract\"] = 10;\n\t\t\tret[\"sin\"] = 13;\n\t\t\tret[\"cos\"] = 14;\n\t\t\tret[\"tan\"] = 15;\n\t\t\tret[\"asin\"] = 16;\n\t\t\tret[\"acos\"] = 17;\n\t\t\tret[\"atan\"] = 18;\n\t\t\tret[\"atan2\"] = 25;\n\t\t\tret[\"pow\"] = 26;\n\t\t\tret[\"exp\"] = 27;\n\t\t\tret[\"log\"] = 28;\n\t\t\tret[\"exp2\"] = 29;\n\t\t\tret[\"log2\"] = 30;\n\n\t\t\tret[\"sqrt\"] = 31;\n\n\t\t\tret[\"min\"] = 37;\n\t\t\tret[\"max\"] = 40;\n\t\t\tret[\"clamp\"] = 43;\n\n\t\t\tret[\"mix\"] = 46;\n\n\t\t\tret[\"step\"] = 48;\n\t\t\tret[\"smoothstep\"] = 49;\n\n\t\t\tret[\"length\"] = 66;\n\n\t\t\tret[\"cross\"] = 68;\n\t\t\tret[\"normalize\"] = 69;\n\n\t\t\tret[\"reflect\"] = 71;\n\t\t\tret[\"refract\"] = 72;\n\n\t\t\treturn ret;\n\t\t}\n\n\t\tString GetFuncOriginalName(const String & name)\n\t\t{\n\t\t\tString originalName;\n\t\t\tint splitPos = name.IndexOf('@');\n\t\t\tif (splitPos == 0)\n\t\t\t\treturn name;\n\t\t\tif (splitPos != -1)\n\t\t\t\toriginalName = name.SubString(0, splitPos);\n\t\t\telse\n\t\t\t\toriginalName = name;\n\t\t\treturn originalName;\n\t\t}\n\n\t\tString SpirVFloatToString(float v)\n\t\t{\n\t\t\tString rs(v, \"%.12e\");\n\t\t\tif (!rs.Contains('.') && !rs.Contains('e') && !rs.Contains('E'))\n\t\t\t\trs = rs + \".0\";\n\t\t\treturn rs;\n\t\t};\n\n\t\tString SpirVUIntToString(unsigned int i)\n\t\t{\n\t\t\tString s;\n\t\t\tif (i >> 31)\n\t\t\t\ts = s + \"1\";\n\t\t\ts = s + int(i & 0x7fffffff);\n\t\t\treturn s;\n\t\t}\n\n\t\tRefPtr<ILType> GetTypeFromString(String s)\n\t\t{\n\t\t\tCoreLib::Text::Parser parser(s);\n\t\t\treturn TypeFromString(parser);\n\t\t}\n\n\t\t//UniformOrBuffer - 0: none; 1: uniform; 2: buffer \n\t\tint GetBaseAlignment(ILType* Type, int UniformOrBuffer)\n\t\t{\n\t\t\tauto RoundUpTo = [](int x, int r)\n\t\t\t{\n\t\t\t\tif (x%r)\n\t\t\t\t\tx += r - x%r;\n\t\t\t\treturn x;\n\t\t\t};\n\t\t\tif (auto basicType = dynamic_cast<ILBasicType*>(Type))\n\t\t\t{\n\t\t\t\treturn Type->GetAlignment();\n\t\t\t}\n\t\t\telse if (auto arrayType = dynamic_cast<ILArrayType*>(Type))\n\t\t\t{\n\t\t\t\tint elementAlignment = GetBaseAlignment(arrayType->BaseType.Ptr(), UniformOrBuffer);\n\t\t\t\tif (UniformOrBuffer == 1)\n\t\t\t\t\telementAlignment = RoundUpTo(elementAlignment, 16);\n\t\t\t\treturn elementAlignment;\n\t\t\t}\n\t\t\telse if (auto structType = dynamic_cast<ILStructType*>(Type))\n\t\t\t{\n\t\t\t\tint maxAlignment = -1;\n\t\t\t\tfor (auto &member : structType->Members)\n\t\t\t\t{\n\t\t\t\t\tint memberAlignment = GetBaseAlignment(member.Type.Ptr(), UniformOrBuffer);\n\t\t\t\t\tmaxAlignment = std::max(maxAlignment, memberAlignment);\n\t\t\t\t}\n\t\t\t\tif (UniformOrBuffer == 1)\n\t\t\t\t\tmaxAlignment = RoundUpTo(maxAlignment, 16);\n\t\t\t\treturn maxAlignment;\n\t\t\t}\n\t\t\treturn -1;\n\t\t}\n\n\t\tint GetSize(ILType* Type, int UniformOrBuffer)\n\t\t{\n\t\t\tauto RoundUpTo = [](int x, int r)\n\t\t\t{\n\t\t\t\tif (x%r)\n\t\t\t\t\tx += r - x%r;\n\t\t\t\treturn x;\n\t\t\t};\n\n\t\t\tif (auto basicType = dynamic_cast<ILBasicType*>(Type))\n\t\t\t{\n\t\t\t\treturn Type->GetSize();\n\t\t\t}\n\t\t\telse if (auto arrayType = dynamic_cast<ILArrayType*>(Type))\n\t\t\t{\n\t\t\t\treturn GetSize(arrayType->BaseType.Ptr(), UniformOrBuffer) * arrayType->ArrayLength;\n\t\t\t}\n\t\t\telse if (auto structType = dynamic_cast<ILStructType*>(Type))\n\t\t\t{\n\t\t\t\tint rs = 0;\n\t\t\t\tfor (auto &member : structType->Members)\n\t\t\t\t{\n\t\t\t\t\tint memberAlignment = GetBaseAlignment(member.Type.Ptr(), UniformOrBuffer);\n\t\t\t\t\trs = RoundUpTo(rs, memberAlignment);\n\t\t\t\t\trs += GetSize(member.Type.Ptr(), UniformOrBuffer);\n\t\t\t\t}\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\n\t\tenum class IDClass\n\t\t{\n\t\t\tNone,\n\t\t\tTypeofValue,\n\t\t\tTypeofPointer,\n\t\t\tPointer,\n\t\t\tValue,\n\t\t\tFunction\n\t\t};\n\n\t\tclass IDInfo\n\t\t{\n\t\tprivate:\n\t\t\tbool available;\n\t\t\tIDClass idClass;\n\t\t\tint ID;\n\t\t\tString variableName; // only available for Class:Pointer\n\t\t\tString typeName;\n\t\t\tint typeID;\n\t\t\tint baseTypeID;\n\t\t\tRefPtr<ILType> typeIL;\n\t\t\tStorageClass store;\n\t\t\tCompiledFunction * func = nullptr;\n\t\t\tILOperand *op;\n\t\tpublic:\n\t\t\tIDInfo()\n\t\t\t\t:available(false)\n\t\t\t{\n\t\t\t}\n\n\t\t\t//\n\t\t\tstatic IDInfo CreateIDInfoForTypeofValue(int ID, RefPtr<ILType> typeIL, int UniformOrBuffer = 0)\n\t\t\t{\n\t\t\t\tIDInfo ret;\n\t\t\t\tret.available = true;\n\t\t\t\tret.idClass = IDClass::TypeofValue;\n\t\t\t\tret.ID = ID;\n\t\t\t\tret.typeName = \"\";\n\t\t\t\tif (typeIL) \n\t\t\t\t{\n\t\t\t\t\tret.typeName = typeIL->ToString();\n\t\t\t\t\tif (UniformOrBuffer)\n\t\t\t\t\t\tret.typeName = ret.typeName + \"#\" + UniformOrBuffer;\n\t\t\t\t}\n\t\t\t\tret.typeID = ID;\n\t\t\t\tret.typeIL = typeIL;\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\tstatic IDInfo CreateIDInfoForValue(int ID, RefPtr<ILType> typeIL, ILOperand *op, int typeID)\n\t\t\t{\n\t\t\t\tIDInfo ret;\n\t\t\t\tret.available = true;\n\t\t\t\tret.idClass = IDClass::Value;\n\t\t\t\tret.ID = ID;\n\t\t\t\tif (op)\n\t\t\t\t\tret.variableName = op->Name;\n\t\t\t\telse\n\t\t\t\t\tret.variableName = \"\";\n\t\t\t\tret.op = op;\n\t\t\t\tret.typeName = typeIL->ToString();\n\t\t\t\tret.typeID = typeID;\n\t\t\t\tret.typeIL = typeIL;\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\tstatic IDInfo CreateIDInfoForPointer(int ID, ILOperand *op, int typeID, RefPtr<ILType> basetypeIL, int basetypeID, StorageClass store)\n\t\t\t{\n\t\t\t\tIDInfo ret;\n\t\t\t\tret.available = true;\n\t\t\t\tret.idClass = IDClass::Pointer;\n\t\t\t\tret.ID = ID;\n\t\t\t\tret.op = op;\n\t\t\t\tif (op)\n\t\t\t\t\tret.variableName = op->Name;\n\t\t\t\telse\n\t\t\t\t\tret.variableName = \"\";\n\t\t\t\tret.typeName = basetypeIL->ToString();\n\t\t\t\tret.typeID = typeID;\n\t\t\t\tret.baseTypeID = basetypeID;\n\t\t\t\tret.typeIL = basetypeIL;\n\t\t\t\tret.store = store;\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\tstatic IDInfo CreateIDInfoForTypeofPointer(int ID, RefPtr<ILType> baseTypeIL, int baseTypeID, StorageClass store)\n\t\t\t{\n\t\t\t\tIDInfo ret;\n\t\t\t\tret.available = true;\n\t\t\t\tret.idClass = IDClass::TypeofPointer;\n\t\t\t\tret.ID = ID;\n\t\t\t\tret.typeName = baseTypeIL->ToString();\n\t\t\t\tret.typeID = ID;\n\t\t\t\tret.baseTypeID = baseTypeID;\n\t\t\t\tret.typeIL = baseTypeIL;\n\t\t\t\tret.store = store;\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\tstatic IDInfo CreateIDInfoForFunction(int ID, CompiledFunction * func)\n\t\t\t{\n\t\t\t\tIDInfo ret;\n\t\t\t\tret.available = true;\n\t\t\t\tret.idClass = IDClass::Function;\n\t\t\t\tret.ID = ID;\n\t\t\t\tret.func = func;\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\tbool IsAvailable()\n\t\t\t{\n\t\t\t\treturn available;\n\t\t\t}\n\t\t\tint GetID()\n\t\t\t{\n\t\t\t\tif (!available) return -1;\n\t\t\t\treturn ID;\n\t\t\t}\n\t\t\tIDClass GetClass()\n\t\t\t{\n\t\t\t\tif (!available) return IDClass::None;\n\t\t\t\treturn idClass;\n\t\t\t}\n\t\t\tbool IsTypeofValue()\n\t\t\t{\n\t\t\t\tif (!available) return false;\n\t\t\t\treturn idClass == IDClass::TypeofValue;\n\t\t\t}\n\t\t\tbool IsValue()\n\t\t\t{\n\t\t\t\tif (!available) return false;\n\t\t\t\treturn idClass == IDClass::Value;\n\t\t\t}\n\t\t\tbool IsPointer()\n\t\t\t{\n\t\t\t\tif (!available) return false;\n\t\t\t\treturn idClass == IDClass::Pointer;\n\t\t\t}\n\t\t\tbool IsTypeofPointer()\n\t\t\t{\n\t\t\t\tif (!available) return false;\n\t\t\t\treturn idClass == IDClass::TypeofPointer;\n\t\t\t}\n\t\t\tbool IsFunction()\n\t\t\t{\n\t\t\t\tif (!available) return false;\n\t\t\t\treturn idClass == IDClass::Function;\n\t\t\t}\n\t\t\tString GetVariableName()\n\t\t\t{\n\t\t\t\tif (!available) return \"\";\n\t\t\t\treturn variableName;\n\t\t\t}\n\t\t\tString GetTypeName()\n\t\t\t{\n\t\t\t\tif (!available) return \"\";\n\t\t\t\treturn typeName;\n\t\t\t}\n\t\t\tint GetTypeID()\n\t\t\t{\n\t\t\t\tif (!available) return -1;\n\t\t\t\treturn typeID;\n\t\t\t}\n\t\t\tint GetBaseTypeID()\n\t\t\t{\n\t\t\t\tif (!available) return -1;\n\t\t\t\treturn baseTypeID;\n\t\t\t}\n\t\t\tRefPtr<ILType> GetILType()\n\t\t\t{\n\t\t\t\tif (!available) return nullptr;\n\t\t\t\treturn typeIL;\n\t\t\t}\n\t\t\tStorageClass GetStorageClass()\n\t\t\t{\n\t\t\t\tif (!available) return StorageClass::Invalid;\n\t\t\t\treturn store;\n\t\t\t}\n\t\t\tCompiledFunction * GetFunc()\n\t\t\t{\n\t\t\t\tif (!available || idClass != IDClass::Function)\n\t\t\t\t\treturn nullptr;\n\t\t\t\treturn func;\n\t\t\t}\n\t\t\tILOperand* GetOp()\n\t\t\t{\n\t\t\t\tif (!available)\n\t\t\t\t\treturn nullptr;\n\t\t\t\treturn op;\n\t\t\t}\n\t\t};\n\n\t\tclass SpirVCodeBuilder\n\t\t{\n\t\t\tList<unsigned int> streamHeader;\n\t\t\tList<unsigned int> streamDebug;\n\t\t\tList<unsigned int> streamAnnotation;\n\t\t\tList<unsigned int> streamTypeDefinition;\n\t\t\tList<unsigned int> streamFunctionHeader;\n\t\t\tList<unsigned int> streamFunctionVariable;\n\t\t\tList<unsigned int> streamFunctionBody;\n\t\t\tList<unsigned int> streamProcessedFunctions;\n\t\t\tStringBuilder sbTextHeader;\n\t\t\t//OpCapability, OpExtension, OpExtInstImport, OpMemoryModel, OpEntryPoint, OpExecutionMode\n\t\t\tStringBuilder sbDebug;\n\t\t\t//OpName, OpMemberName\n\t\t\tStringBuilder sbTextAnnotation;\n\t\t\t//OpDecorate, OpMemberDecorate, OpGroupDecorate, OpGroupMemberDecorate, OpDecoration Group\n\t\t\tStringBuilder sbTextTypeDefinition;\n\t\t\t//OpTypeXXXX, OpConstant, global variable declarations(all OpVariable instructions whose storage class is not Function)\n\t\t\tStringBuilder sbTextFunctionDefinitions;\n\t\t\tStringBuilder sbTextFunctionHeader;\n\t\t\tStringBuilder sbTextFunctionVariable;\n\t\t\tStringBuilder sbTextFunctionBody;\n\n\t\tpublic:\n\t\t\tvoid Clear()\n\t\t\t{\n\t\t\t\tstreamHeader.Clear();\n\t\t\t\tstreamDebug.Clear();\n\t\t\t\tstreamAnnotation.Clear();\n\t\t\t\tstreamTypeDefinition.Clear();\n\t\t\t\tstreamFunctionHeader.Clear();\n\t\t\t\tstreamFunctionVariable.Clear();\n\t\t\t\tstreamFunctionBody.Clear();\n\t\t\t\tstreamProcessedFunctions.Clear();\n\t\t\t\t\n\t\t\t\tsbTextHeader.Clear();\n\t\t\t\tsbDebug.Clear();\n\t\t\t\tsbTextAnnotation.Clear();\n\t\t\t\tsbTextTypeDefinition.Clear();\n\t\t\t\tsbTextFunctionDefinitions.Clear();\n\t\t\t\tsbTextFunctionHeader.Clear();\n\t\t\t\tsbTextFunctionVariable.Clear();\n\t\t\t\tsbTextFunctionBody.Clear();\n\t\t\t}\n\t\t\tvoid Initiate()\n\t\t\t{\n\t\t\t\tClear();\n\n\t\t\t\tstreamHeader.Add(0x07230203); // magic number\n\t\t\t\tstreamHeader.Add(0x00010000); // version \n\t\t\t\tstreamHeader.Add(0x00080001); // register number\n\t\t\t\tstreamHeader.Add(0x0000ffff); // ID bound\n\t\t\t\tstreamHeader.Add(0x00000000); // reserved\n\t\t\t}\n\t\t\tvoid ProduceFunction()\n\t\t\t{\n\t\t\t\t//---------------- for binary code ----------------\n\t\t\t\tstreamProcessedFunctions.AddRange(streamFunctionHeader);\n\t\t\t\tstreamFunctionHeader.Clear();\n\n\t\t\t\tstreamProcessedFunctions.AddRange(streamFunctionVariable);\n\t\t\t\tstreamFunctionVariable.Clear();\n\n\t\t\t\tstreamProcessedFunctions.AddRange(streamFunctionBody);\n\t\t\t\tstreamFunctionBody.Clear();\n\n\t\t\t\t//---------------- for text code ----------------\n\t\t\t\tsbTextFunctionDefinitions\n\t\t\t\t\t<< sbTextFunctionHeader.ToString()\n\t\t\t\t\t<< sbTextFunctionVariable.ToString()\n\t\t\t\t\t<< sbTextFunctionBody.ToString();\n\t\t\t\tsbTextFunctionHeader.Clear();\n\t\t\t\tsbTextFunctionVariable.Clear();\n\t\t\t\tsbTextFunctionBody.Clear();\n\t\t\t}\n\t\t\tList<unsigned int> ProduceWordStream(int IDBound)\n\t\t\t{\n\t\t\t\tstreamHeader[3] = IDBound + 5;\n\t\t\t\tList<unsigned int> ret;\n\t\t\t\tret.AddRange(streamHeader);\n\t\t\t\tret.AddRange(streamDebug);\n\t\t\t\tret.AddRange(streamAnnotation);\n\t\t\t\tret.AddRange(streamTypeDefinition);\n\t\t\t\tret.AddRange(streamProcessedFunctions);\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t\tString ProduceTextCode()\n\t\t\t{\n\t\t\t\tString ret;\n\t\t\t\tret = ret + sbTextHeader.ToString();\n\t\t\t\tret = ret + sbDebug.ToString();\n\t\t\t\tret = ret + sbTextAnnotation.ToString();\n\t\t\t\tret = ret + sbTextTypeDefinition.ToString();\n\t\t\t\tret = ret + sbTextFunctionDefinitions.ToString();\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t\tvoid ProgramHeader()\n\t\t\t{\n\t\t\t\tsbTextHeader << LR\"(OpCapability Shader)\" << EndLine;\n\t\t\t\tsbTextHeader << LR\"(%1 = OpExtInstImport \"GLSL.std.450\")\" << EndLine;\n\t\t\t\tsbTextHeader << LR\"(OpMemoryModel Logical GLSL450)\" << EndLine;\n\n\t\t\t\tstreamHeader.Add(17 + (2 << 16));\t//wordCount and opCode\n\t\t\t\tstreamHeader.Add(1);\t//Shader\n\n\t\t\t\t\t\t\t\t\t\t//hardcoded\n\t\t\t\tstreamHeader.Add(0x0006000B);\n\t\t\t\tstreamHeader.Add(0x00000001);\n\t\t\t\tstreamHeader.Add(0x4c534c47);\n\t\t\t\tstreamHeader.Add(0x6474732E);\n\t\t\t\tstreamHeader.Add(0x3035342E);\n\t\t\t\tstreamHeader.Add(0);\n\n\t\t\t\tstreamHeader.Add(14 + (3 << 16));\n\t\t\t\tstreamHeader.Add(0);\n\t\t\t\tstreamHeader.Add(1);\n\t\t\t}\n\t\t\tvoid OpFunction(const int funcID, const int returnTypeID, const int functionTypeID)\n\t\t\t{\n\n\t\t\t\tsbTextFunctionHeader << LR\"(%)\" << funcID << LR\"( = OpFunction )\";\n\t\t\t\tsbTextFunctionHeader << LR\"(%)\" << returnTypeID;\n\t\t\t\tsbTextFunctionHeader << LR\"( None)\";\n\t\t\t\tsbTextFunctionHeader << LR\"( %)\" << functionTypeID;\n\t\t\t\tsbTextFunctionHeader << EndLine;\n\n\t\t\t\tstreamFunctionHeader.Add(54 + (5 << 16));\n\t\t\t\tstreamFunctionHeader.Add(returnTypeID);\n\t\t\t\tstreamFunctionHeader.Add(funcID);\n\t\t\t\tstreamFunctionHeader.Add(0);\t// function control - 0\n\t\t\t\tstreamFunctionHeader.Add(functionTypeID);\n\t\t\t}\n\t\t\tvoid OpFunctionParameter(const int paramID, const int typeID)\n\t\t\t{\n\t\t\t\tsbTextFunctionHeader << LR\"(%)\" << paramID << LR\"( = OpFunctionParameter %)\" << typeID << EndLine;\n\n\t\t\t\tstreamFunctionHeader.Add(55 + (3 << 16));\n\t\t\t\tstreamFunctionHeader.Add(typeID);\n\t\t\t\tstreamFunctionHeader.Add(paramID);\n\t\t\t}\n\t\t\tvoid OpTypeFunction(const int functionTypeID, const int returnTypeID, const List<int> &argIDList)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << functionTypeID << LR\"( = OpTypeFunction %)\" << returnTypeID;\n\t\t\t\tfor (auto & arg : argIDList)\n\t\t\t\t\tsbTextTypeDefinition << LR\"( %)\" << arg;\n\t\t\t\tsbTextTypeDefinition << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(33 + ((3 + argIDList.Count()) << 16));\n\t\t\t\tstreamTypeDefinition.Add(functionTypeID);\n\t\t\t\tstreamTypeDefinition.Add(returnTypeID);\n\t\t\t\tfor (auto & arg : argIDList)\n\t\t\t\t\tstreamTypeDefinition.Add(arg);\n\t\t\t}\n\t\t\tvoid OpLabel_AtFunctionHeader(const int label)\n\t\t\t{\n\t\t\t\tsbTextFunctionHeader << LR\"(%)\" << label << LR\"( = OpLabel)\" << EndLine;\n\n\t\t\t\tstreamFunctionHeader.Add(248 + (2 << 16));\n\t\t\t\tstreamFunctionHeader.Add(label);\n\t\t\t}\n\t\t\tvoid OpLabel_AtFunctionBody(const int label)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << label << LR\"( = OpLabel)\" << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(248 + (2 << 16));\n\t\t\t\tstreamFunctionBody.Add(label);\n\t\t\t}\n\t\t\tvoid OpBranch(const int ID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(OpBranch %)\" << ID << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(249 + (2 << 16));\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t}\n\t\t\tvoid OpBranchConditional(const int cond, const int tb, const int fb)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(OpBranchConditional %)\" << cond << LR\"( %)\" << tb << LR\"( %)\" << fb << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(250 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(cond);\n\t\t\t\tstreamFunctionBody.Add(tb);\n\t\t\t\tstreamFunctionBody.Add(fb);\n\t\t\t}\n\t\t\tvoid OpLoopMerge(const int merge, const int cont)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(OpLoopMerge %)\" << merge << LR\"( %)\" << cont << LR\"( None)\" << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(246 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(merge);\n\t\t\t\tstreamFunctionBody.Add(cont);\n\t\t\t\tstreamFunctionBody.Add(0);\t//loop control: none\n\t\t\t}\n\t\t\tvoid OpSelectionMerge(const int merge)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(OpSelectionMerge %)\" << merge << LR\"( None)\" << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(247 + (3 << 16));\n\t\t\t\tstreamFunctionBody.Add(merge);\n\t\t\t\tstreamFunctionBody.Add(0);\t//selection control: none\n\t\t\t}\n\t\t\tvoid OpPhi(const int ID, const int typeID, const List<int> branches)\n\t\t\t{\n\t\t\t\t//<branches>: (variable1, parent branch1), (variable2, parent branch2), ...\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpPhi %)\" << typeID;\n\t\t\t\tfor (const auto & x : branches)\n\t\t\t\t\tsbTextFunctionBody << LR\"( %)\" << x;\n\t\t\t\tsbTextFunctionBody << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(245 + ((3 + branches.Count()) << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tfor (const auto & x : branches)\n\t\t\t\t\tstreamFunctionBody.Add(x);\n\t\t\t}\n\t\t\tvoid OpFunctionCall(const int ID, const int typeID, const int funcID, const List<int> &args)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpFunctionCall %)\" << typeID << LR\"( %)\" << funcID;\n\t\t\t\tfor (auto & arg : args)\n\t\t\t\t\tsbTextFunctionBody << LR\"( %)\" << arg;\n\t\t\t\tsbTextFunctionBody << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(57 + ((4 + args.Count()) << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(funcID);\n\t\t\t\tfor (auto & arg : args)\n\t\t\t\t\tstreamFunctionBody.Add(arg);\n\t\t\t}\n\t\t\tvoid OpKill()\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(OpKill)\" << EndLine;\n\t\t\t\t\n\t\t\t\tstreamFunctionBody.Add(252 + (1<<16));\n\t\t\t}\n\t\t\tvoid OpReturn()\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(OpReturn)\" << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(253 + (1 << 16));\n\t\t\t}\n\t\t\tvoid OpReturnValue(const int ID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(OpReturnValue %)\" << ID << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(254 + (2 << 16));\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t}\n\t\t\tvoid OpFunctionEnd()\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(OpFunctionEnd)\" << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(56 + (1 << 16));\n\t\t\t}\n\t\t\tint EncodeString(List<unsigned int> & stream, String S)\n\t\t\t{\n\t\t\t\tauto encoder = CoreLib::IO::Encoding::UTF8;\n\t\t\t\tList<char> bytes;\n\t\t\t\tencoder->GetBytes(bytes, S);\n\t\t\t\tint padding = (4 - (bytes.Count() & 3)) & 3;\n\t\t\t\tfor (int i = 0; i < padding; i++)\n\t\t\t\t\tbytes.Add(0);\n\t\t\t\tint oldSize = stream.Count();\n\t\t\t\tstream.SetSize(oldSize + (bytes.Count() >> 2));\n\t\t\t\tmemcpy(stream.Buffer() + oldSize, bytes.Buffer(), bytes.Count());\n\t\t\t\tif (padding==0)\n\t\t\t\t\tstream.Add(0);\n\t\t\t\treturn stream.Count() - oldSize;\n\t\t\t}\n\t\t\tvoid OpEntryPoint(const ExecutionModel currentExecutionModel, const int entryID, const List<int> &interfaceIDs)\n\t\t\t{\n\t\t\t\tsbTextHeader << LR\"(OpEntryPoint )\";\n\t\t\t\tsbTextHeader << ExecutionModelToString(currentExecutionModel) << LR\"( )\";\n\t\t\t\tsbTextHeader << LR\"(%)\" << entryID << LR\"( \"main\" )\";\n\t\t\t\tfor (auto & id : interfaceIDs)\n\t\t\t\t\tsbTextHeader << LR\"( %)\" << id;\n\t\t\t\tsbTextHeader << EndLine;\n\n\t\t\t\tint len_i = streamHeader.Count();\n\t\t\t\tstreamHeader.Add(0);\n\t\t\t\tstreamHeader.Add((int)currentExecutionModel);\n\t\t\t\tstreamHeader.Add(entryID);\n\t\t\t\tint NameLen = EncodeString(streamHeader, \"main\");\n\t\t\t\tfor (auto & id : interfaceIDs)\n\t\t\t\t\tstreamHeader.Add(id);\n\t\t\t\tstreamHeader[len_i] = (15) + ((1 + 1 + NameLen + 1 + interfaceIDs.Count()) << 16);\n\t\t\t}\n\t\t\tvoid OpExecutionMode(const int entryID, const ExecutionMode mode, const int op1, const int op2, const int op3)\n\t\t\t{\n\t\t\t\tbool LocalSize = false;\n\t\t\t\tif (mode == ExecutionMode::LocalSize)\n\t\t\t\t\tLocalSize = true;\n\n\t\t\t\tsbTextHeader << LR\"(OpExecutionMode %)\" << entryID << LR\"( )\" << ExecutionModeToString(mode);\n\t\t\t\tif (LocalSize)\n\t\t\t\t\tsbTextHeader << op1 << op2 << op3;\n\t\t\t\tsbTextHeader << EndLine;\n\n\t\t\t\tint len = 3;\n\t\t\t\tif (LocalSize)\n\t\t\t\t\tlen += 3;\n\t\t\t\tstreamHeader.Add(16 + (len << 16));\n\t\t\t\tstreamHeader.Add(entryID);\n\t\t\t\tstreamHeader.Add((int)mode);\n\t\t\t\tif (LocalSize) {\n\t\t\t\t\tstreamHeader.Add(op1);\n\t\t\t\t\tstreamHeader.Add(op2);\n\t\t\t\t\tstreamHeader.Add(op3);\n\t\t\t\t}\n\t\t\t}\n\t\t\tint Decorate(const Decoration deco, int op1 = 0)\n\t\t\t{\n\t\t\t\tint len = 0;\n\t\t\t\tsbTextAnnotation << \" \" << DecorationToString(deco);\n\t\t\t\tstreamAnnotation.Add((int)deco);\n\t\t\t\tlen++;\n\t\t\t\tif (deco == Decoration::Location ||\n\t\t\t\t\tdeco == Decoration::Offset ||\n\t\t\t\t\tdeco == Decoration::MatrixStride ||\n\t\t\t\t\tdeco == Decoration::ArrayStride ||\n\t\t\t\t\tdeco == Decoration::DescriptorSet ||\n\t\t\t\t\tdeco == Decoration::Binding)\n\t\t\t\t{\n\t\t\t\t\tsbTextAnnotation << LR\"( )\" << op1;\n\t\t\t\t\tstreamAnnotation.Add(op1);\n\t\t\t\t\tlen++;\n\t\t\t\t}\n\t\t\t\tif (deco == Decoration::BuiltIn)\n\t\t\t\t{\n\t\t\t\t\tBuiltIn builtin = static_cast<BuiltIn>(op1);\n\t\t\t\t\tsbTextAnnotation << LR\"( )\" << BuiltinToString(builtin);\n\t\t\t\t\tstreamAnnotation.Add(op1);\n\t\t\t\t\tlen++;\n\t\t\t\t}\n\t\t\t\treturn len;\n\t\t\t}\n\t\t\tvoid OpDecorate(const int ID, const Decoration deco, int op1 = 0)\n\t\t\t{\n\t\t\t\tsbTextAnnotation << LR\"(OpDecorate %)\" << ID;\n\n\t\t\t\tint len_i = streamAnnotation.Count();\n\t\t\t\tstreamAnnotation.Add(0);\n\t\t\t\tstreamAnnotation.Add(ID);\n\t\t\t\tint deco_len = Decorate(deco, op1);\n\t\t\t\tstreamAnnotation[len_i] = 71 + ((2 + deco_len) << 16);\n\n\t\t\t\tsbTextAnnotation << EndLine;\n\t\t\t}\n\t\t\tvoid OpMemberDecorate(const int ID, const int memberIndex, const Decoration deco, int op1 = 0)\n\t\t\t{\n\t\t\t\tsbTextAnnotation << LR\"(OpMemberDecorate %)\" << ID << LR\"( )\" << memberIndex;\n\n\t\t\t\tint len_i = streamAnnotation.Count();\n\t\t\t\tstreamAnnotation.Add(0);\n\t\t\t\tstreamAnnotation.Add(ID);\n\t\t\t\tstreamAnnotation.Add(memberIndex);\n\t\t\t\tint deco_len = Decorate(deco, op1);\n\t\t\t\tstreamAnnotation[len_i] = 72 + ((3 + deco_len) << 16);\n\n\t\t\t\tsbTextAnnotation << EndLine;\n\t\t\t}\n\t\t\tvoid OpSNegate(const int ID, const int typeID, const int valueID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpSNegate %)\" << typeID << LR\"( %)\" << valueID << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(126 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(valueID);\n\t\t\t}\n\t\t\tvoid OpFNegate(const int ID, const int typeID, const int valueID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpFNegate %)\" << typeID << LR\"( %)\" << valueID << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(127 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(valueID);\n\t\t\t}\n\t\t\tvoid OpFAdd(const int ID, const int typeID, const int op1, const int op2)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpFAdd %)\" << typeID << LR\"( %)\" << op1 << LR\"( %)\" << op2 << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(129 + (5 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(op1);\n\t\t\t\tstreamFunctionBody.Add(op2);\n\t\t\t}\n\t\t\tvoid OpFMul(const int ID, const int typeID, const int op1, const int op2)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpFMul %)\" << typeID << LR\"( %)\" << op1 << LR\"( %)\" << op2 << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(133 + (5 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(op1);\n\t\t\t\tstreamFunctionBody.Add(op2);\n\t\t\t}\n\t\t\tvoid OpINotEqual(const int ID, const int typeID, const int id0, const int id1)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpINotEqual %)\" << typeID << LR\"( %)\" << id0 << LR\"( %)\" << id1 << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(171 + (5 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(id0);\n\t\t\t\tstreamFunctionBody.Add(id1);\n\t\t\t}\n\t\t\tvoid OpNot(const int ID, const int typeID, const int valueID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpNot %)\" << typeID << LR\"( %)\" << valueID << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(200 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(valueID);\n\t\t\t}\n\t\t\tvoid OpLogicalNot(const int ID, const int typeID, const int valueID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpLogicalNot %)\" << typeID << LR\"( %)\" << valueID << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(168 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(valueID);\n\t\t\t}\n\t\t\tvoid OpBinaryInstr(const int ID, String opStr, const int typeID, const int ID0, const int ID1)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = )\";\n\t\t\t\tsbTextFunctionBody << opStr;\n\t\t\t\tsbTextFunctionBody << LR\"( %)\" << typeID << LR\"( %)\" << ID0 << LR\"( %)\" << ID1 << EndLine;\n\n\t\t\t\tint opCode = -1;\n\t\t\t\tString opStr_prefix = opStr.SubString(0, 2);\n\t\t\t\topStr = opStr.SubString(2, opStr.Length() - 2);\n\t\t\t\tif (opStr == \"FMu\")\n\t\t\t\t\topCode = 133;\n\t\t\t\telse if (opStr == \"IMu\")\n\t\t\t\t\topCode = 132;\n\t\t\t\telse if (opStr == \"FAdd\")\n\t\t\t\t\topCode = 129;\n\t\t\t\telse if (opStr == \"IAdd\")\n\t\t\t\t\topCode = 128;\n\t\t\t\telse if (opStr == \"UDiv\")\n\t\t\t\t\topCode = 134;\n\t\t\t\telse if (opStr == \"SDiv\")\n\t\t\t\t\topCode = 135;\n\t\t\t\telse if (opStr == \"FDiv\")\n\t\t\t\t\topCode = 136;\n\t\t\t\telse if (opStr == \"FSub\")\n\t\t\t\t\topCode = 131;\n\t\t\t\telse if (opStr == \"ISub\")\n\t\t\t\t\topCode = 130;\n\t\t\t\telse if (opStr == \"UMod\")\n\t\t\t\t\topCode = 137;\n\t\t\t\telse if (opStr == \"SMod\")\n\t\t\t\t\topCode = 139;\n\t\t\t\telse if (opStr == \"FMod\")\n\t\t\t\t\topCode = 141;\n\t\t\t\telse if (opStr == \"ShiftLeftLogica\")\n\t\t\t\t\topCode = 196;\n\t\t\t\telse if (opStr == \"ShiftRightArithmetic\")\n\t\t\t\t\topCode = 195;\n\t\t\t\telse if (opStr == \"ShiftRightLogica\")\n\t\t\t\t\topCode = 194;\n\t\t\t\telse if (opStr == \"BitwiseXor\")\n\t\t\t\t\topCode = 198;\n\t\t\t\telse if (opStr == \"BitwiseAnd\")\n\t\t\t\t\topCode = 199;\n\t\t\t\telse if (opStr == \"BitwiseOr\")\n\t\t\t\t\topCode = 197;\n\t\t\t\telse if (opStr == \"LogicalAnd\")\n\t\t\t\t\topCode = 167;\n\t\t\t\telse if (opStr == \"LogicalOr\")\n\t\t\t\t\topCode = 166;\n\t\t\t\telse if (opStr == \"INotEqua\")\n\t\t\t\t\topCode = 171;\n\t\t\t\telse if (opStr == \"FOrdNotEqua\")\n\t\t\t\t\topCode = 182;\n\t\t\t\telse if (opStr == \"IEqua\")\n\t\t\t\t\topCode = 170;\n\t\t\t\telse if (opStr == \"FOrdEqua\")\n\t\t\t\t\topCode = 180;\n\t\t\t\telse if (opStr == \"SGreaterThanEqua\")\n\t\t\t\t\topCode = 175;\n\t\t\t\telse if (opStr == \"FOrdGreaterThanEqua\")\n\t\t\t\t\topCode = 190;\n\t\t\t\telse if (opStr == \"SGreaterThan\")\n\t\t\t\t\topCode = 173;\n\t\t\t\telse if (opStr == \"FOrdGreaterThan\")\n\t\t\t\t\topCode = 186;\n\t\t\t\telse if (opStr == \"SLessThanEqua\")\n\t\t\t\t\topCode = 179;\n\t\t\t\telse if (opStr == \"FOrdLessThanEqua\")\n\t\t\t\t\topCode = 188;\n\t\t\t\telse if (opStr == \"SLessThan\")\n\t\t\t\t\topCode = 177;\n\t\t\t\telse if (opStr == \"FOrdLessThan\")\n\t\t\t\t\topCode = 184;\n\t\t\t\telse if (opStr == \"UGreaterThan\")\n\t\t\t\t\topCode = 172;\n\t\t\t\telse if (opStr == \"UGreaterThanEqua\")\n\t\t\t\t\topCode = 174;\n\t\t\t\telse if (opStr == \"ULessThan\")\n\t\t\t\t\topCode = 176;\n\t\t\t\telse if (opStr == \"ULessThanEqua\")\n\t\t\t\t\topCode = 178;\n\t\t\t\tif (opCode == -1)\n\t\t\t\t\tthrow InvalidOperationException(\"unrecognized op string in CodeGenerator::OpBinaryInstr(): \" + opStr);\n\n\t\t\t\tstreamFunctionBody.Add(opCode + (5 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(ID0);\n\t\t\t\tstreamFunctionBody.Add(ID1);\n\t\t\t}\n\t\t\tvoid OpMatrixTimesScalar(const int ID, const int typeID, const int ID0, const int ID1)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpMatrixTimesScalar %)\" << typeID << LR\"( %)\" << ID0 << LR\"( %)\" << ID1 << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(143 + (5 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(ID0);\n\t\t\t\tstreamFunctionBody.Add(ID1);\n\t\t\t}\n\t\t\tvoid OpVectorTimesMatrix(const int ID, const int typeID, const int ID0, const int ID1)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpVectorTimesMatrix %)\" << typeID << LR\"( %)\" << ID0 << LR\"( %)\" << ID1 << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(144 + (5 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(ID0);\n\t\t\t\tstreamFunctionBody.Add(ID1);\n\t\t\t}\n\t\t\tvoid OpMatrixTimesVector(const int ID, const int typeID, const int ID0, const int ID1)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpMatrixTimesVector %)\" << typeID << LR\"( %)\" << ID0 << LR\"( %)\" << ID1 << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(145 + (5 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(ID0);\n\t\t\t\tstreamFunctionBody.Add(ID1);\n\t\t\t}\n\t\t\tvoid OpMatrixTimesMatrix(const int ID, const int typeID, const int ID0, const int ID1)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpMatrixTimesMatrix %)\" << typeID << LR\"( %)\" << ID0 << LR\"( %)\" << ID1 << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(146 + (5 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(ID0);\n\t\t\t\tstreamFunctionBody.Add(ID1);\n\t\t\t}\n\t\t\tvoid OpConstantBool(const int typeID, const int ID, const bool b)\n\t\t\t{\n\t\t\t\tif (b)\n\t\t\t\t{\n\t\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpConstantTrue%)\" << EndLine;\n\n\t\t\t\t\tstreamTypeDefinition.Add(41 + (3 << 16));\n\t\t\t\t\tstreamTypeDefinition.Add(typeID);\n\t\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpConstantFalse%)\" << EndLine;\n\n\t\t\t\t\tstreamTypeDefinition.Add(42 + (3 << 16));\n\t\t\t\t\tstreamTypeDefinition.Add(typeID);\n\t\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\t}\n\t\t\t}\n\t\t\tvoid OpConstantFloat(const int ID, const int typeID, float f)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpConstant %)\" << typeID << LR\"( )\" << SpirVFloatToString(f) << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(43 + (4 << 16));\n\t\t\t\tstreamTypeDefinition.Add(typeID);\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tstreamTypeDefinition.Add(*reinterpret_cast<unsigned int*>(&f));\n\t\t\t\t//printf(\"%.8f -> %x\\n\", f, streamTypeDefinition[streamTypeDefinition.Count() - 1]);\n\t\t\t}\n\t\t\tvoid OpConstantInt(const int ID, const int typeID, int i)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpConstant %)\" << typeID << LR\"( )\" << i << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(43 + (4 << 16));\n\t\t\t\tstreamTypeDefinition.Add(typeID);\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tstreamTypeDefinition.Add(*reinterpret_cast<unsigned int*>(&i));\n\t\t\t}\n\t\t\tvoid OpConstantUInt(const int ID, const int typeID, const unsigned int i)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpConstant %)\" << typeID << LR\"( )\";\n\t\t\t\tsbTextTypeDefinition << SpirVUIntToString(i);\n\t\t\t\tsbTextTypeDefinition << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(43 + (4 << 16));\n\t\t\t\tstreamTypeDefinition.Add(typeID);\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tstreamTypeDefinition.Add(i);\n\t\t\t}\n\t\t\tvoid OpConstantComposite(const int ID, const int typeID, const List<int> &args)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpConstantComposite %)\" << typeID;\n\t\t\t\tfor (auto & id : args)\n\t\t\t\t\tsbTextTypeDefinition << LR\"( %)\" << id;\n\t\t\t\tsbTextTypeDefinition << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(44 + ((3 + args.Count()) << 16));\n\t\t\t\tstreamTypeDefinition.Add(typeID);\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tfor (auto & id : args)\n\t\t\t\t\tstreamTypeDefinition.Add(id);\n\t\t\t}\n\t\t\tvoid OpCompositeConstruct(const int ID, const int typeID, const List<int> &args)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpCompositeConstruct %)\" << typeID;\n\t\t\t\tfor (auto & id : args)\n\t\t\t\t\tsbTextFunctionBody << LR\"( %)\" << id;\n\t\t\t\tsbTextFunctionBody << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(80 + ((3 + args.Count()) << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tfor (auto & id : args)\n\t\t\t\t\tstreamFunctionBody.Add(id);\n\t\t\t}\n\t\t\tvoid OpCompositeExtract(const int ID, const int baseTypeID, const int compositeID, const int index)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpCompositeExtract %)\" << baseTypeID << LR\"( %)\" << compositeID\n\t\t\t\t\t<< LR\"( )\" << index << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(81 + (5 << 16));\n\t\t\t\tstreamFunctionBody.Add(baseTypeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(compositeID);\n\t\t\t\tstreamFunctionBody.Add(index);\n\t\t\t}\n\t\t\tvoid OpCompositeInsert(const int ID, const int typeID, const int objectID, const int compositeID, const int index)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpCompositeInsert %)\"\n\t\t\t\t\t<< typeID << LR\"( %)\" << objectID << LR\"( %)\" << compositeID << LR\"( )\" << index << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(82 + (6 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(objectID);\n\t\t\t\tstreamFunctionBody.Add(compositeID);\n\t\t\t\tstreamFunctionBody.Add(index);\n\t\t\t}\n\t\t\tvoid OpExtInst(const int ID, const int typeID, const int instrNumber, const List<int> &Arguments)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpExtInst %)\" << typeID << LR\"( %1 )\";\n\t\t\t\tsbTextFunctionBody << instrNumber;\n\t\t\t\tfor (auto & arg : Arguments)\n\t\t\t\t\tsbTextFunctionBody << LR\"( %)\" << arg;\n\t\t\t\tsbTextFunctionBody << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(12 + ((5 + Arguments.Count()) << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(1);\t//instruction set **<ID>**\n\t\t\t\tstreamFunctionBody.Add(instrNumber);\n\t\t\t\tfor (auto & arg : Arguments)\n\t\t\t\t\tstreamFunctionBody.Add(arg);\n\t\t\t}\n\t\t\tvoid OpStore(const int op0, const int op1)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(OpStore %)\" << op0 << LR\"( %)\" << op1 << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(62 + (3 << 16));\n\t\t\t\tstreamFunctionBody.Add(op0);\n\t\t\t\tstreamFunctionBody.Add(op1);\n\t\t\t}\n\t\t\tvoid OpLoad(const int ID, const int typeID, const int variableID, const MemoryAccess ma)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpLoad %)\" << typeID << LR\"( %)\"\n\t\t\t\t\t<< variableID << LR\"( )\" << MemoryAccessToString(ma) << EndLine;\n\n\t\t\t\tif (ma != MemoryAccess::None)\n\t\t\t\t\tthrow NotImplementedException(\"not support memory access in CodeGenerator::OpLoad(): \" + MemoryAccessToString(ma));\n\n\t\t\t\tstreamFunctionBody.Add(61 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(variableID);\n\t\t\t}\n\t\t\tvoid OpVariable(const int ID, const int typeID, StorageClass store)\n\t\t\t{\n\t\t\t\tStringBuilder instrBuilder;\n\t\t\t\tinstrBuilder << LR\"(%)\" << ID << LR\"( = OpVariable %)\" << typeID << LR\"( )\" << StorageClassToString(store) << EndLine;\n\t\t\t\tif (store == StorageClass::Function)\n\t\t\t\t\tsbTextFunctionVariable << instrBuilder.ProduceString() << EndLine;\n\t\t\t\telse\n\t\t\t\t\tsbTextTypeDefinition << instrBuilder.ProduceString() << EndLine;\n\n\t\t\t\tif (store == StorageClass::Function)\n\t\t\t\t{\n\t\t\t\t\tstreamFunctionVariable.Add(59 + (4 << 16));\n\t\t\t\t\tstreamFunctionVariable.Add(typeID);\n\t\t\t\t\tstreamFunctionVariable.Add(ID);\n\t\t\t\t\tstreamFunctionVariable.Add((int)store);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstreamTypeDefinition.Add(59 + (4 << 16));\n\t\t\t\t\tstreamTypeDefinition.Add(typeID);\n\t\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\t\tstreamTypeDefinition.Add((int)store);\n\t\t\t\t}\n\t\t\t}\n\t\t\tvoid OpAccessChain(const int ID, const int typeID, const int structID, const int indexID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpAccessChain %)\" << typeID\n\t\t\t\t\t<< LR\"( %)\" << structID << LR\"( %)\" << indexID << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(65 + (5 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(structID);\n\t\t\t\tstreamFunctionBody.Add(indexID);\n\t\t\t}\n\t\t\tvoid OpImageSampleImplicitLod(\n\t\t\t\tconst int ID, \n\t\t\t\tconst int typeID, \n\t\t\t\tconst int textureID, \n\t\t\t\tconst int coordinateID,\n\t\t\t\tconst int Bias = -1)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpImageSampleImplicitLod %)\"\n\t\t\t\t\t<< typeID << LR\"( %)\" << textureID << LR\"( %)\" << coordinateID;\n\t\t\t\tif (Bias != -1)\n\t\t\t\t\tsbTextFunctionBody << LR\"( Bias %)\" << Bias;\n\t\t\t\tsbTextFunctionBody << EndLine;\n\n\t\t\t\tint len = 5;\n\t\t\t\tint IO = 0;\n\t\t\t\tif (Bias != -1)\n\t\t\t\t{\n\t\t\t\t\tlen++;\n\t\t\t\t\tIO |= (int)ImageOperands::Bias;\n\t\t\t\t}\n\t\t\t\tif (IO)\n\t\t\t\t\tlen++;\n\t\t\t\tstreamFunctionBody.Add(87 + (len << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(textureID);\n\t\t\t\tstreamFunctionBody.Add(coordinateID);\n\t\t\t\tif (IO)\n\t\t\t\t\tstreamFunctionBody.Add(IO);\n\t\t\t\tif (Bias != -1)\n\t\t\t\t\tstreamFunctionBody.Add(Bias);\n\t\t\t}\n\t\t\tvoid OpImageSampleExplicitLod(\n\t\t\t\tconst int ID, \n\t\t\t\tconst int typeID, \n\t\t\t\tconst int textureID, \n\t\t\t\tconst int coordinateID, \n\t\t\t\tconst int LodID,\n\t\t\t\tconst int Bias = -1,\n\t\t\t\tconst int GradX = -1, \n\t\t\t\tconst int GradY = -1)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpImageSampleExplicitLod %)\"\n\t\t\t\t\t<< typeID << LR\"( %)\" << textureID << LR\"( %)\" << coordinateID;\n\t\t\t\tif (Bias != -1)\n\t\t\t\t\tsbTextFunctionBody << LR\"( Bias %)\" << Bias;\n\t\t\t\tif (GradX != -1)\n\t\t\t\t\tsbTextFunctionBody << LR\"( Grad %)\" << GradX << LR\"( %)\" << GradY;\n\t\t\t\telse\n\t\t\t\t\tsbTextFunctionBody << LR\"( Lod %)\" << LodID;\n\t\t\t\tsbTextFunctionBody << EndLine;\n\n\t\t\t\tint IO = 0;\n\t\t\t\tint len = 5;\n\t\t\t\tif (Bias != -1)\n\t\t\t\t{\n\t\t\t\t\tIO |= (int)ImageOperands::Bias;\n\t\t\t\t\tlen++;\n\t\t\t\t}\n\t\t\t\tif (GradX != -1) {\n\t\t\t\t\tIO |= (int)ImageOperands::Grad;\n\t\t\t\t\tlen += 2;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tIO |= (int)ImageOperands::Lod;\n\t\t\t\t\tlen++;\n\t\t\t\t}\n\t\t\t\tif (IO)\n\t\t\t\t\tlen++;\n\t\t\t\tstreamFunctionBody.Add(88 + (len << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(textureID);\n\t\t\t\tstreamFunctionBody.Add(coordinateID);\n\t\t\t\tif (IO)\n\t\t\t\t\tstreamFunctionBody.Add(IO);\n\t\t\t\tif (Bias != -1)\n\t\t\t\t\tstreamFunctionBody.Add(Bias);\n\t\t\t\tif (GradX != -1)\n\t\t\t\t{\n\t\t\t\t\tstreamFunctionBody.Add(GradX);\n\t\t\t\t\tstreamFunctionBody.Add(GradY);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tstreamFunctionBody.Add(LodID);\n\t\t\t}\n\t\t\tvoid OpImageSampleDrefImplicitLod(\n\t\t\t\tconst int ID,\n\t\t\t\tconst int typeID,\n\t\t\t\tconst int textureID,\n\t\t\t\tconst int coordinateID,\n\t\t\t\tconst int DrefID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpImageSampleDrefImplicitLod %)\"\n\t\t\t\t\t<< typeID << LR\"( %)\" << textureID << LR\"( %)\" << coordinateID << LR\"( %)\" << DrefID;\n\t\t\t\tsbTextFunctionBody << EndLine;\n\n\t\t\t\tint len = 6;\n\t\t\t\tstreamFunctionBody.Add(89 + (len << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(textureID);\n\t\t\t\tstreamFunctionBody.Add(coordinateID);\n\t\t\t\tstreamFunctionBody.Add(DrefID);\n\t\t\t}\n\t\t\tvoid OpImageSampleDrefExplicitLod(\n\t\t\t\tconst int ID,\n\t\t\t\tconst int typeID,\n\t\t\t\tconst int textureID,\n\t\t\t\tconst int coordinateID, \n\t\t\t\tconst int DrefID,\n\t\t\t\tconst int LodID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpImageSampleDrefExplicitLod %)\"\n\t\t\t\t\t<< typeID << LR\"( %)\" << textureID << LR\"( %)\" << coordinateID << LR\"( %)\" << DrefID;\n\t\t\t\tsbTextFunctionBody << LR\"( Lod %)\" << LodID;\n\t\t\t\tsbTextFunctionBody << EndLine;\n\n\t\t\t\tint len = 8;\n\t\t\t\tstreamFunctionBody.Add(90 + (len << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(textureID);\n\t\t\t\tstreamFunctionBody.Add(coordinateID);\n\t\t\t\tstreamFunctionBody.Add(DrefID);\n\t\t\t\tstreamFunctionBody.Add((int)ImageOperands::Lod);\n\t\t\t\tstreamFunctionBody.Add(LodID);\n\t\t\t}\n\t\t\tvoid OpImageSampleProjDrefImplicitLod(\n\t\t\t\tconst int ID,\n\t\t\t\tconst int typeID,\n\t\t\t\tconst int textureID,\n\t\t\t\tconst int coordinateID,\n\t\t\t\tconst int DrefID) \n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpImageSampleProjDrefImplicitLod %)\"\n\t\t\t\t\t<< typeID << LR\"( %)\" << textureID << LR\"( %)\" << coordinateID << LR\"( %)\" << DrefID;\n\t\t\t\tsbTextFunctionBody << EndLine;\n\n\t\t\t\tint len = 6;\n\t\t\t\tstreamFunctionBody.Add(93 + (len << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(textureID);\n\t\t\t\tstreamFunctionBody.Add(coordinateID);\n\t\t\t\tstreamFunctionBody.Add(DrefID);\n\t\t\t}\n\t\t\tvoid OpImageSampleProjDrefExplicitLod(\n\t\t\t\tconst int ID,\n\t\t\t\tconst int typeID,\n\t\t\t\tconst int textureID,\n\t\t\t\tconst int coordinateID,\n\t\t\t\tconst int DrefID,\n\t\t\t\tconst int LodID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpImageSampleProjDrefExplicitLod %)\"\n\t\t\t\t\t<< typeID << LR\"( %)\" << textureID << LR\"( %)\" << coordinateID << LR\"( %)\" << DrefID;\n\t\t\t\tsbTextFunctionBody << LR\"( Lod %)\" << LodID;\n\t\t\t\tsbTextFunctionBody << EndLine;\n\n\t\t\t\tint len = 8;\n\t\t\t\tstreamFunctionBody.Add(94 + (len << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(textureID);\n\t\t\t\tstreamFunctionBody.Add(coordinateID);\n\t\t\t\tstreamFunctionBody.Add(DrefID);\n\t\t\t\tstreamFunctionBody.Add((int)ImageOperands::Lod);\n\t\t\t\tstreamFunctionBody.Add(LodID);\n\t\t\t}\n\t\t\tvoid OpConvertSToF(const int ID, const int typeID, const int operandID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpConvertSToF %)\" << typeID << LR\"( %)\" << operandID << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(111 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(operandID);\n\t\t\t}\n\t\t\tvoid OpConvertFToS(const int ID, const int typeID, const int operandID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpConvertFToS %)\" << typeID << LR\"( %)\" << operandID << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(110 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(operandID);\n\t\t\t}\n\t\t\tvoid OpConvertFToU(const int ID, const int typeID, const int operandID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpConvertFToU %)\" << typeID << LR\"( %)\" << operandID << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(109 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(operandID);\n\t\t\t}\n\t\t\tvoid OpConvertUToF(const int ID, const int typeID, const int operandID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpConvertUToF %)\" << typeID << LR\"( %)\" << operandID << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(112 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(operandID);\n\t\t\t}\n\t\t\tvoid OpBitCast(const int ID, const int typeID, const int operandID)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpBitcast %)\" << typeID << LR\"( %)\" << operandID << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(124 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(operandID);\n\t\t\t}\n\t\t\tvoid OpTypeVoid(const int ID)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpTypeVoid)\" << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(19 + (2 << 16));\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t}\n\t\t\tvoid OpTypeBool(const int ID)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpTypeBool)\" << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(20 + (2 << 16));\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t}\n\t\t\tvoid OpTypeInt(const int ID, const int width, const int signedness)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpTypeInt )\" << width << LR\"( )\" << signedness << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(21 + (4 << 16));\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tstreamTypeDefinition.Add(width);\n\t\t\t\tstreamTypeDefinition.Add(signedness);\n\t\t\t}\n\t\t\tvoid OpTypeFloat(const int ID, const int width)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpTypeFloat )\" << width << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(22 + (3 << 16));\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tstreamTypeDefinition.Add(width);\n\t\t\t}\n\t\t\tvoid OpTypeVector(const int ID, const int eleTypeID, const int vecLen)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpTypeVector %)\" << eleTypeID << LR\"( )\" << vecLen << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(23 + (4 << 16));\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tstreamTypeDefinition.Add(eleTypeID);\n\t\t\t\tstreamTypeDefinition.Add(vecLen);\n\t\t\t}\n\t\t\tvoid OpTypeMatrix(const int ID, const int colTypeID, const int Dim)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpTypeMatrix %)\" << colTypeID << LR\"( )\" << Dim << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(24 + (4 << 16));\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tstreamTypeDefinition.Add(colTypeID);\n\t\t\t\tstreamTypeDefinition.Add(Dim);\n\t\t\t}\n\t\t\tvoid OpTypeImage(const int ID, const int sampledTypeID, const Dim d, const int depth)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpTypeImage %)\" << sampledTypeID\n\t\t\t\t\t<< LR\"( )\" << DimToString(d) << LR\"( )\" << depth << LR\"( 0 0 1 Unknown)\" << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(25 + (9 << 16));\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tstreamTypeDefinition.Add(sampledTypeID);\n\t\t\t\tstreamTypeDefinition.Add((int)d);\t\t\t//Dim\n\t\t\t\tstreamTypeDefinition.Add(depth);\t\t\t//depth\n\t\t\t\tstreamTypeDefinition.Add(0);\t\t\t\t//arrayed\n\t\t\t\tstreamTypeDefinition.Add(0);\t\t\t\t//MS\n\t\t\t\tstreamTypeDefinition.Add(1);\t\t\t\t//sampled: will be used with sampler\n\t\t\t\tstreamTypeDefinition.Add(0);\t\t\t\t//image format: Unknown\n\t\t\t}\n\t\t\tvoid OpTypeSampledImage(const int ID, const int imageTypeID)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpTypeSampledImage %)\" << imageTypeID << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(27 + (3 << 16));\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tstreamTypeDefinition.Add(imageTypeID);\n\t\t\t}\n\t\t\tvoid OpTypePointer(const int ID, const StorageClass store, const int baseTypeID)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpTypePointer )\" << StorageClassToString(store)\n\t\t\t\t\t<< LR\"( %)\" << baseTypeID << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(32 + (4 << 16));\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tstreamTypeDefinition.Add((int)store);\n\t\t\t\tstreamTypeDefinition.Add(baseTypeID);\n\t\t\t}\n\t\t\tvoid OpTypeArray(const int ID, const int elementTypeID, const int lengthID)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpTypeArray %)\" << elementTypeID << LR\"( %)\" << lengthID << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(28 + (4 << 16));\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tstreamTypeDefinition.Add(elementTypeID);\n\t\t\t\tstreamTypeDefinition.Add(lengthID);\n\t\t\t}\n\t\t\tvoid OpTypeRuntimeArray(const int ID, const int elementTypeID)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpTypeRuntimeArray %)\" << elementTypeID << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(29 + (3 << 16));\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tstreamTypeDefinition.Add(elementTypeID);\n\t\t\t}\n\t\t\tvoid OpTypeStruct(const int ID, const List<int> & memberIDList)\n\t\t\t{\n\t\t\t\tsbTextTypeDefinition << LR\"(%)\" << ID << LR\"( = OpTypeStruct)\";\n\t\t\t\tfor (auto & member : memberIDList)\n\t\t\t\t\tsbTextTypeDefinition << LR\"( %)\" << member;\n\t\t\t\tsbTextTypeDefinition << EndLine;\n\n\t\t\t\tstreamTypeDefinition.Add(30 + ((2 + memberIDList.Count()) << 16));\n\t\t\t\tstreamTypeDefinition.Add(ID);\n\t\t\t\tfor (auto & member : memberIDList)\n\t\t\t\t\tstreamTypeDefinition.Add(member);\n\t\t\t}\n\n\t\t\tvoid OpDot(const int ID, const int typeID, const int ID0, const int ID1)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpDot %)\" << typeID << LR\"( %)\" << ID0 << LR\"( %)\" << ID1 << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(148 + (5 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(ID0);\n\t\t\t\tstreamFunctionBody.Add(ID1);\n\t\t\t}\n\n\t\t\tvoid OpTranspose(const int ID, const int typeID, const int Op0)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpTranspose %)\" << typeID << LR\"( %)\" << Op0 << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(84 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(Op0);\n\t\t\t}\n\n\t\t\tvoid OpDPdx(const int ID, const int typeID, const int Op0)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpDPdx %)\" << typeID << LR\"( %)\" << Op0 << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(207 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(Op0);\n\t\t\t}\n\n\t\t\tvoid OpDPdy(const int ID, const int typeID, const int Op0)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpDPdy %)\" << typeID << LR\"( %)\" << Op0 << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(208 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(Op0);\n\t\t\t}\n\n\t\t\tvoid OpFwidth(const int ID, const int typeID, const int Op0)\n\t\t\t{\n\t\t\t\tsbTextFunctionBody << LR\"(%)\" << ID << LR\"( = OpFwidth %)\" << typeID << LR\"( %)\" << Op0 << EndLine;\n\n\t\t\t\tstreamFunctionBody.Add(209 + (4 << 16));\n\t\t\t\tstreamFunctionBody.Add(typeID);\n\t\t\t\tstreamFunctionBody.Add(ID);\n\t\t\t\tstreamFunctionBody.Add(Op0);\n\t\t\t}\n\n\t\t\tvoid OpName(int ID, String Name)\n\t\t\t{\n\t\t\t\tsbDebug << LR\"(OpName %)\" << ID << LR\"( \")\" << Name << LR\"(\")\" << EndLine;\n\n\t\t\t\tint len_i = streamDebug.Count();\n\t\t\t\tstreamDebug.Add(0);\n\t\t\t\tstreamDebug.Add(ID);\n\t\t\t\tint len = EncodeString(streamDebug, Name);\n\t\t\t\tstreamDebug[len_i] = 5 + ((2 + len) << 16);\n\t\t\t}\n\n\t\t\tvoid OpMemberName(int ID, int index, String Name)\n\t\t\t{\n\t\t\t\tsbDebug << LR\"(OpMemberName %)\" << ID << LR\"( )\" << index << LR\"( \")\" << Name << LR\"(\")\" << EndLine;\n\n\t\t\t\tint len_i = streamDebug.Count();\n\t\t\t\tstreamDebug.Add(0);\n\t\t\t\tstreamDebug.Add(ID);\n\t\t\t\tstreamDebug.Add(index);\n\t\t\t\tint len = EncodeString(streamDebug, Name);\n\t\t\t\tstreamDebug[len_i] = 6 + ((3 + len) << 16);\n\t\t\t}\n\t\t};\n\n\t\tclass SpirVCodeGenContext\n\t\t{\n\t\tpublic:\n\t\t\tCompileResult * Result = nullptr;\n\n\t\t\tint CurrentID = 0;\n\t\t\tint MainFunctionID = 0;\n\t\t\tint MainFunctionReturnTypeID = 0;\n\t\t\tint MainFunctionTypeID = 0;\n\t\t\tint ReturnID = -1;\n\t\t\tDictionary<String, int> TypeNameToID;\t\t\t\t\t// 'int' - 1, 'vec4' - 2\n\t\t\tDictionary<String, int> TypeStorageToTypePointerID;\t\t// 'uint Function' - 5, 'mat3 Uniform' - 6\n\t\t\tDictionary<String, int> FunctionNameToFunctionTypeID;\n\t\t\tDictionary<String, int> FunctionNameToFunctionID;\n\t\t\tDictionary<ILOperand*, int> ParameterNameToID;\n\n\t\t\tList<Dictionary<ILOperand*, int>> StackVariableNameToStorageID;\n\t\t\tList<Dictionary<ILOperand*, int>> StackVariableNameToValueID;\n\t\t\tDictionary<String, int> InterfaceNameToID;\n\n\t\t\tDictionary<int, int> Dictionary_ConstantIntToID;\n\t\t\tDictionary<unsigned int, int> Dictionary_ConstantUIntToID;\n\t\t\tDictionary<int, int> Dictionary_ConstantBoolToID;\n\n\t\t\tDictionary<int, IDInfo> IDInfos;\n\n\t\t\tList<int> StackMergeBlock;\n\t\t\tList<int> StackContinueBlock;\n\n\t\t\tSpirVCodeBuilder CodeGen;\n\n\t\t\tvoid Clear()\n\t\t\t{\n\t\t\t\tResult = nullptr;\n\t\t\t\tCurrentID = 0;\n\t\t\t\tMainFunctionID = 0;\n\t\t\t\tMainFunctionReturnTypeID = 0;\n\t\t\t\tMainFunctionTypeID = 0;\n\t\t\t\tReturnID = -1;\n\t\t\t\tStackVariableNameToStorageID.Clear();\n\t\t\t\tStackVariableNameToValueID.Clear();\n\t\t\t\tTypeNameToID.Clear();\n\t\t\t\tTypeStorageToTypePointerID.Clear();\n\t\t\t\tFunctionNameToFunctionTypeID.Clear();\n\t\t\t\tFunctionNameToFunctionID.Clear();\n\t\t\t\tParameterNameToID.Clear();\n\t\t\t\tDictionary_ConstantIntToID.Clear();\n\t\t\t\tDictionary_ConstantUIntToID.Clear();\n\t\t\t\tDictionary_ConstantBoolToID.Clear();\n\t\t\t\tIDInfos.Clear();\n\t\t\t\tStackMergeBlock.Clear();\n\t\t\t\tStackContinueBlock.Clear();\n\t\t\t\tCodeGen.Clear();\n\t\t\t\tInterfaceNameToID.Clear();\n\t\t\t}\n\n\t\t\tvoid ClearBuffer()\n\t\t\t{\n\t\t\t\tStackVariableNameToStorageID.Clear();\n\t\t\t\tStackVariableNameToValueID.Clear();\n\t\t\t\tParameterNameToID.Clear();\n\t\t\t\tReturnID = -1;\n\t\t\t}\n\n\t\t\tvoid PushScope()\n\t\t\t{\n\t\t\t\tStackVariableNameToStorageID.Add(Dictionary<ILOperand*, int>());\n\t\t\t\tStackVariableNameToValueID.Add(Dictionary<ILOperand*, int>());\n\t\t\t}\n\n\t\t\tvoid PopScope()\n\t\t\t{\n\t\t\t\tStackVariableNameToStorageID.RemoveAt(StackVariableNameToStorageID.Count() - 1);\n\t\t\t\tStackVariableNameToValueID.RemoveAt(StackVariableNameToValueID.Count() - 1); \n\t\t\t}\n\n\t\t\tvoid UpdateVariable(ILOperand* op, int id)\n\t\t\t{\n\t\t\t\tif (op == nullptr)\n\t\t\t\t\treturn;\n\t\t\t\tStackVariableNameToStorageID.Last()[op] = id;\n\t\t\t}\n\n\t\t\tint FindVariableID(ILOperand* op)\n\t\t\t{\n\t\t\t\tauto it = StackVariableNameToStorageID.end();\n\t\t\t\twhile (it != StackVariableNameToStorageID.begin())\n\t\t\t\t{\n\t\t\t\t\tit--;\n\t\t\t\t\tif (it->ContainsKey(op))\n\t\t\t\t\t\treturn (*it)[op];\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\t// ***NOTICE***: \n\t\t\t//   There is no relation between VariableNameToStorageID and ValueIDToVariableNames.\n\n\t\t\tvoid UpdateValue(ILOperand *op, int id)\n\t\t\t{\n\t\t\t\tif (op == nullptr)\n\t\t\t\t\treturn;\n\t\t\t\tStackVariableNameToValueID.Last()[op] = id;\n\t\t\t}\n\n\t\t\tint FindValueID(ILOperand *op)\n\t\t\t{\n\t\t\t\tauto it = StackVariableNameToValueID.end();\n\t\t\t\twhile (it != StackVariableNameToValueID.begin())\n\t\t\t\t{\n\t\t\t\t\tit--;\n\t\t\t\t\tif (it->ContainsKey(op))\n\t\t\t\t\t\treturn (*it)[op];\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tvoid InvalidateValue(ILOperand *op)\n\t\t\t{\n\t\t\t\tif (StackVariableNameToValueID.Last().ContainsKey(op))\n\t\t\t\t\tStackVariableNameToValueID.Last()[op] = -1;\n\t\t\t}\n\n\t\t\tint DefineBasicType(RefPtr<ILType> Type)\n\t\t\t{\n\t\t\t\tString typeName = Type->ToString();\n\t\t\t\tif (TypeNameToID.ContainsKey(typeName))\n\t\t\t\t\treturn TypeNameToID[typeName];\n\t\t\t\tTypeNameToID[typeName] = -1; //marked as visited\n\n\t\t\t\tif (typeName == \"int\" || typeName.StartsWith(\"ivec\"))\n\t\t\t\t{\n\t\t\t\t\tDefineBasicType(new ILBasicType(ILBaseType::Int));\n\n\t\t\t\t\tif (typeName == \"int\")\n\t\t\t\t\t{\n\t\t\t\t\t\t++CurrentID;\n\t\t\t\t\t\tCodeGen.OpTypeInt(CurrentID, 32, 1);\n\t\t\t\t\t\tTypeNameToID[typeName] = CurrentID;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeName.StartsWith(\"ivec\"))\n\t\t\t\t\t{\n\t\t\t\t\t\t++CurrentID;\n\t\t\t\t\t\tCodeGen.OpTypeVector(CurrentID, TypeNameToID[\"int\"](), StringToInt(typeName[4]));\n\t\t\t\t\t\tTypeNameToID[typeName] = CurrentID;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (typeName == \"uint\" || typeName.StartsWith(\"uvec\"))\n\t\t\t\t{\n\t\t\t\t\tDefineBasicType(new ILBasicType(ILBaseType::UInt));\n\n\t\t\t\t\tif (typeName == \"uint\") {\n\t\t\t\t\t\t++CurrentID;\n\t\t\t\t\t\tCodeGen.OpTypeInt(CurrentID, 32, 0);\n\t\t\t\t\t\tTypeNameToID[typeName] = CurrentID;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeName.StartsWith(\"uvec\"))\n\t\t\t\t\t{\n\t\t\t\t\t\t++CurrentID;\n\t\t\t\t\t\tCodeGen.OpTypeVector(CurrentID, TypeNameToID[\"uint\"](), StringToInt(typeName[4]));\n\t\t\t\t\t\tTypeNameToID[typeName] = CurrentID;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (typeName == \"float\" || typeName.StartsWith(\"vec\") || typeName.StartsWith(\"mat\"))\n\t\t\t\t{\n\t\t\t\t\tDefineBasicType(new ILBasicType(ILBaseType::Float));\n\n\t\t\t\t\tif (typeName == \"float\")\n\t\t\t\t\t{\n\t\t\t\t\t\t++CurrentID;\n\t\t\t\t\t\tCodeGen.OpTypeFloat(CurrentID, 32);\n\t\t\t\t\t\tTypeNameToID[typeName] = CurrentID;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeName.StartsWith(\"vec\"))\n\t\t\t\t\t{\n\t\t\t\t\t\t++CurrentID;\n\t\t\t\t\t\tCodeGen.OpTypeVector(CurrentID, TypeNameToID[\"float\"](), StringToInt(typeName[3]));\n\t\t\t\t\t\tTypeNameToID[typeName] = CurrentID;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeName == \"mat3\")\n\t\t\t\t\t{\n\t\t\t\t\t\tDefineBasicType(new ILBasicType(ILBaseType::Float3));\n\t\t\t\t\t\t++CurrentID;\n\t\t\t\t\t\tCodeGen.OpTypeMatrix(CurrentID, TypeNameToID[\"vec3\"](), 3);\n\t\t\t\t\t\tTypeNameToID[typeName] = CurrentID;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeName == \"mat4\")\n\t\t\t\t\t{\n\t\t\t\t\t\tDefineBasicType(new ILBasicType(ILBaseType::Float4));\n\t\t\t\t\t\t++CurrentID;\n\t\t\t\t\t\tCodeGen.OpTypeMatrix(CurrentID, TypeNameToID[\"vec4\"](), 4);\n\t\t\t\t\t\tTypeNameToID[typeName] = CurrentID;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (typeName == \"sampler2D\")\n\t\t\t\t{\n\t\t\t\t\t//according to vulkan specification\n\t\t\t\t\t//\tResource Descriptors, Descriptor Types, Sampled Image\n\t\t\t\t\tDefineBasicType(new ILBasicType(ILBaseType::Float));\n\n\t\t\t\t\t++CurrentID;\n\t\t\t\t\tCodeGen.OpTypeImage(CurrentID, TypeNameToID[\"float\"](), Dim::e2D, 0);\n\t\t\t\t\tint tmp = CurrentID;\n\n\t\t\t\t\t++CurrentID;\n\t\t\t\t\tCodeGen.OpTypeSampledImage(CurrentID, tmp);\n\t\t\t\t\tTypeNameToID[typeName] = CurrentID;\n\t\t\t\t}\n\n\t\t\t\tif (typeName == \"samplerCube\")\n\t\t\t\t{\n\t\t\t\t\tDefineBasicType(new ILBasicType(ILBaseType::Float));\n\n\t\t\t\t\t++CurrentID;\n\t\t\t\t\tCodeGen.OpTypeImage(CurrentID, TypeNameToID[\"float\"](), Dim::eCube, 0);\n\t\t\t\t\tint tmp = CurrentID;\n\n\t\t\t\t\t++CurrentID;\n\t\t\t\t\tCodeGen.OpTypeSampledImage(CurrentID, tmp);\n\t\t\t\t\tTypeNameToID[typeName] = CurrentID;\n\t\t\t\t}\n\n\t\t\t\tif (typeName == \"samplerCubeShadow\")\n\t\t\t\t{\n\t\t\t\t\tDefineBasicType(new ILBasicType(ILBaseType::Float));\n\n\t\t\t\t\t++CurrentID;\n\t\t\t\t\tCodeGen.OpTypeImage(CurrentID, TypeNameToID[\"float\"](), Dim::eCube, 1);\n\t\t\t\t\tint tmp = CurrentID;\n\n\t\t\t\t\t++CurrentID;\n\t\t\t\t\tCodeGen.OpTypeSampledImage(CurrentID, tmp);\n\t\t\t\t\tTypeNameToID[typeName] = CurrentID;\n\t\t\t\t}\n\n\t\t\t\tif (typeName == \"sampler2DShadow\")\n\t\t\t\t{\n\t\t\t\t\tDefineBasicType(new ILBasicType(ILBaseType::Float));\n\n\t\t\t\t\t++CurrentID;\n\t\t\t\t\tCodeGen.OpTypeImage(CurrentID, TypeNameToID[\"float\"](), Dim::e2D, 1);\n\t\t\t\t\tint tmp = CurrentID;\n\n\t\t\t\t\t++CurrentID;\n\t\t\t\t\tCodeGen.OpTypeSampledImage(CurrentID, tmp);\n\t\t\t\t\tTypeNameToID[typeName] = CurrentID;\n\t\t\t\t}\n\n\t\t\t\tif (typeName == \"bool\")\n\t\t\t\t{\n\t\t\t\t\t++CurrentID;\n\t\t\t\t\tCodeGen.OpTypeBool(CurrentID);\n\t\t\t\t\tTypeNameToID[typeName] = CurrentID;\n\t\t\t\t}\n\n\t\t\t\tif (TypeNameToID[typeName] == -1)\n\t\t\t\t{\n\t\t\t\t\tthrow InvalidProgramException(\"fail to generate type definition for: \" + typeName);\n\t\t\t\t}\n\n\t\t\t\tint id = TypeNameToID[typeName];\n\t\t\t\tIDInfos[id] = IDInfo::CreateIDInfoForTypeofValue(id, Type);\n\n\t\t\t\treturn id;\n\t\t\t}\n\n\t\t\t//UniformOrBuffer - 0: none; 1: uniform; 2: buffer \n\t\t\tint DefineType(RefPtr<ILType> Type, int UniformOrBuffer = 0)\n\t\t\t{\n\t\t\t\tif (!Type)\n\t\t\t\t{\n\t\t\t\t\tif (TypeNameToID.ContainsKey(\"void\"))\n\t\t\t\t\t\treturn TypeNameToID[\"void\"];\n\t\t\t\t\t++CurrentID;\n\t\t\t\t\t//TypeDefinition << LR\"(%)\" <<  << LR\"( = OpTypeVoid)\" << EndLine;\n\t\t\t\t\tCodeGen.OpTypeVoid(CurrentID);\n\t\t\t\t\tTypeNameToID[\"void\"] = CurrentID;\n\t\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForTypeofValue(CurrentID, nullptr);\n\t\t\t\t\treturn CurrentID;\n\t\t\t\t}\n\t\t\t\tint RetID = -1;\n\t\t\t\tif (auto ArrayType = dynamic_cast<ILArrayType*>(Type.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tString IndexName = Type->ToString();\n\t\t\t\t\tif (UniformOrBuffer != 0)\n\t\t\t\t\t\tIndexName = IndexName + \"#\" + UniformOrBuffer;\n\t\t\t\t\tif (TypeNameToID.ContainsKey(IndexName))\n\t\t\t\t\t\treturn TypeNameToID[IndexName];\n\n\t\t\t\t\tif (ArrayType->ArrayLength != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t//normal constant-length array\n\t\t\t\t\t\tint lengthID = AddInstrConstantInt(ArrayType->ArrayLength);\n\n\t\t\t\t\t\tint elementTypeID = DefineType(ArrayType->BaseType, UniformOrBuffer);\n\t\t\t\t\t\t++CurrentID;\n\t\t\t\t\t\tCodeGen.OpTypeArray(CurrentID, elementTypeID, lengthID);\n\t\t\t\t\t\tTypeNameToID[IndexName] = CurrentID;\n\t\t\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForTypeofValue(CurrentID, Type, UniformOrBuffer);\n\t\t\t\t\t\tRetID = CurrentID;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t//dynamic array\n\t\t\t\t\t\tint elementTypeID = DefineType(ArrayType->BaseType, UniformOrBuffer);\n\t\t\t\t\t\t++CurrentID;\n\t\t\t\t\t\tCodeGen.OpTypeRuntimeArray(CurrentID, elementTypeID);\n\t\t\t\t\t\tTypeNameToID[IndexName] = CurrentID;\n\t\t\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForTypeofValue(CurrentID, Type, UniformOrBuffer);\n\t\t\t\t\t\tRetID = CurrentID;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (UniformOrBuffer != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tint Stride = GetSize(ArrayType->BaseType.Ptr(), UniformOrBuffer);\n\t\t\t\t\t\tCodeGen.OpDecorate(RetID, Decoration::ArrayStride, Stride);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (auto StructType = dynamic_cast<ILStructType*>(Type.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tString IndexName = Type->ToString();\n\t\t\t\t\tif (UniformOrBuffer != 0)\n\t\t\t\t\t\tIndexName = IndexName + \"#\" + UniformOrBuffer;\n\t\t\t\t\tif (TypeNameToID.ContainsKey(IndexName))\n\t\t\t\t\t\treturn TypeNameToID[IndexName];\n\n\t\t\t\t\tList<int> memberIDList;\n\t\t\t\t\tfor (auto & member : StructType->Members)\n\t\t\t\t\t\tmemberIDList.Add(DefineType(member.Type, UniformOrBuffer));\n\t\t\t\t\t++CurrentID;\n\t\t\t\t\tCodeGen.OpTypeStruct(CurrentID, memberIDList);\n\t\t\t\t\tTypeNameToID[IndexName] = CurrentID;\n\t\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForTypeofValue(CurrentID, Type, UniformOrBuffer);\n\t\t\t\t\tRetID = CurrentID;\n\n\t\t\t\t\t//generate decoration for struct layout\n\t\t\t\t\tif (UniformOrBuffer != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tint Offset = 0;\n\t\t\t\t\t\tint Index = 0;\n\t\t\t\t\t\tfor (auto & MemberTypeID : memberIDList)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tRefPtr<ILType> MemberType = IDInfos[MemberTypeID]().GetILType();\n\n\t\t\t\t\t\t\tint BaseAlignment = GetBaseAlignment(MemberType.Ptr(), UniformOrBuffer);\n\n\t\t\t\t\t\t\t//round up to baseAlignment\n\t\t\t\t\t\t\tif (Offset % BaseAlignment)\n\t\t\t\t\t\t\t\tOffset += BaseAlignment - Offset % BaseAlignment;\n\n\t\t\t\t\t\t\tAddInstrMemberDecorate(RetID, Index, Decoration::Offset, Offset);\n\n\t\t\t\t\t\t\tif (MemberType->IsFloatMatrix())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAddInstrMemberDecorate(RetID, Index, Decoration::ColMajor);\n\t\t\t\t\t\t\t\tAddInstrMemberDecorate(RetID, Index, Decoration::MatrixStride, 16);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tOffset += GetSize(MemberType.Ptr(), UniformOrBuffer);\n\t\t\t\t\t\t\tIndex++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t//generate debug information\n\t\t\t\t\tCodeGen.OpName(RetID, Type->ToString());\n\t\t\t\t\tint index = 0;\n\t\t\t\t\tfor (auto &member : StructType->Members)\n\t\t\t\t\t{\n\t\t\t\t\t\tCodeGen.OpMemberName(RetID, index, member.FieldName);\n\t\t\t\t\t\tindex++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (auto BasicType = dynamic_cast<ILBasicType*>(Type.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tif (TypeNameToID.ContainsKey(Type->ToString()))\n\t\t\t\t\t\treturn TypeNameToID[Type->ToString()];\n\t\t\t\t\tRetID = DefineBasicType(Type);\n\t\t\t\t}\n\t\t\t\treturn RetID;\n\t\t\t}\n\n\t\t\tint DefineTypePointer(RefPtr<ILType> Type, StorageClass store, int UniformOrBuffer = 0)\n\t\t\t{\n\t\t\t\tString PointerName = Type->ToString() + \"$\" + StorageClassToString(store) + \"#\" + UniformOrBuffer;\n\t\t\t\tif (TypeStorageToTypePointerID.ContainsKey(PointerName))\n\t\t\t\t\treturn TypeStorageToTypePointerID[PointerName]();\n\n\t\t\t\tint basetypeID = DefineType(Type, UniformOrBuffer);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpTypePointer(CurrentID, store, basetypeID);\n\t\t\t\tTypeStorageToTypePointerID[PointerName] = CurrentID;\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForTypeofPointer(CurrentID, Type, basetypeID, store);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrTypeFunction(CompiledFunction * func, const List<RefPtr<ILType>> & argTypes, RefPtr<ILType> returnType)\n\t\t\t{\n\t\t\t\tint returnTypeID = DefineType(returnType);\n\t\t\t\tfor (auto & arg : argTypes)\n\t\t\t\t\tDefineTypePointer(arg, StorageClass::Function);\n\t\t\t\tint functionTypeID = ++CurrentID;\n\t\t\t\tList<int> argIDList;\n\t\t\t\tfor (auto & arg : argTypes)\n\t\t\t\t\targIDList.Add(DefineTypePointer(arg, StorageClass::Function));\n\t\t\t\tCodeGen.OpTypeFunction(functionTypeID, returnTypeID, argIDList);\n\t\t\t\tIDInfos[functionTypeID] = IDInfo::CreateIDInfoForFunction(functionTypeID, func);\n\t\t\t\tif (func)\n\t\t\t\t\tFunctionNameToFunctionTypeID[func->Name] = functionTypeID;\n\t\t\t\telse\n\t\t\t\t\tFunctionNameToFunctionTypeID[\"main\"] = functionTypeID;\n\t\t\t\treturn functionTypeID;\n\t\t\t}\n\n\t\t\tint AddInstrConstantBool(int value)\n\t\t\t{\n\t\t\t\tif (Dictionary_ConstantBoolToID.ContainsKey(value != 0))\n\t\t\t\t\treturn Dictionary_ConstantBoolToID[value != 0].GetValue();\n\n\t\t\t\tauto Type = GetTypeFromString(\"bool\");\n\t\t\t\tint typeID = DefineType(Type);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpConstantBool(typeID, CurrentID, value != 0);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, Type, 0, typeID);\n\t\t\t\tDictionary_ConstantBoolToID[value != 0] = CurrentID;\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrConstantFloat(float f)\n\t\t\t{\n\t\t\t\tauto Type = GetTypeFromString(\"float\");\n\t\t\t\tint typeID = DefineType(Type);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpConstantFloat(CurrentID, typeID, f);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, Type, 0, typeID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrConstantInt(int i)\n\t\t\t{\n\t\t\t\tauto Type = GetTypeFromString(\"int\");\n\t\t\t\tif (Dictionary_ConstantIntToID.ContainsKey(i))\n\t\t\t\t\treturn Dictionary_ConstantIntToID[i].GetValue();\n\n\t\t\t\tint typeID = DefineType(Type);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpConstantInt(CurrentID, typeID, i);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, Type, 0, typeID);\n\t\t\t\tDictionary_ConstantIntToID[i] = CurrentID;\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrConstantUInt(unsigned int i)\n\t\t\t{\n\t\t\t\tauto Type = GetTypeFromString(\"uint\");\n\t\t\t\tif (Dictionary_ConstantUIntToID.ContainsKey(i))\n\t\t\t\t\treturn Dictionary_ConstantUIntToID[i].GetValue();\n\n\t\t\t\tint typeID = DefineType(Type);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpConstantUInt(CurrentID, typeID, i);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, Type, 0, typeID);\n\t\t\t\tDictionary_ConstantUIntToID[i] = CurrentID;\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrConstantCompositeFloat(float *f, int len)\n\t\t\t{\n\t\t\t\tRefPtr<ILType> Type;\n\t\t\t\tif (len == 2)\n\t\t\t\t\tType = GetTypeFromString(\"vec2\");\n\t\t\t\telse if (len == 3)\n\t\t\t\t\tType = GetTypeFromString(\"vec3\");\n\t\t\t\telse if (len == 4)\n\t\t\t\t\tType = GetTypeFromString(\"vec4\");\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"Invalid type in AddInstrConstantCompositeFloat(): vec\"+len);\n\t\t\t\tint typeID = DefineType(Type);\n\n\t\t\t\tList<int> elementIDs;\n\t\t\t\tfor (int i = 0; i < len; i++)\n\t\t\t\t\telementIDs.Add(AddInstrConstantFloat(f[i]));\n\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpConstantComposite(CurrentID, typeID, elementIDs);\n\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, Type, 0, typeID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrConstantCompositeInt(int *v, int len)\n\t\t\t{\n\t\t\t\tRefPtr<ILType> Type;\n\t\t\t\tif (len == 2)\n\t\t\t\t\tType = GetTypeFromString(\"ivec2\");\n\t\t\t\telse if (len == 3)\n\t\t\t\t\tType = GetTypeFromString(\"ivec3\");\n\t\t\t\telse if (len == 4)\n\t\t\t\t\tType = GetTypeFromString(\"ivec4\");\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"Invalid type in AddInstrConstantCompositeInt(): ivec\" + len);\n\t\t\t\tint typeID = DefineType(Type);\n\n\t\t\t\tList<int> elementIDs;\n\t\t\t\tfor (int i = 0; i < len; i++)\n\t\t\t\t\telementIDs.Add(AddInstrConstantInt(v[i]));\n\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpConstantComposite(CurrentID, typeID, elementIDs);\n\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, Type, 0, typeID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrConstantCompositeUInt(unsigned int *v, int len)\n\t\t\t{\n\t\t\t\tRefPtr<ILType> Type;\n\t\t\t\tif (len == 2)\n\t\t\t\t\tType = GetTypeFromString(\"uvec2\");\n\t\t\t\telse if (len == 3)\n\t\t\t\t\tType = GetTypeFromString(\"uvec3\");\n\t\t\t\telse if (len == 4)\n\t\t\t\t\tType = GetTypeFromString(\"uvec4\");\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"Invalid type in AddInstrConstantCompositeUInt(): uvec\" + len);\n\t\t\t\tint typeID = DefineType(Type);\n\n\t\t\t\tList<int> elementIDs;\n\t\t\t\tfor (int i = 0; i < len; i++)\n\t\t\t\t\telementIDs.Add(AddInstrConstantUInt(*(v + i)));\n\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpConstantComposite(CurrentID, typeID, elementIDs);\n\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, Type, 0, typeID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrConstantMatrix(float *f, int n)\n\t\t\t{\n\t\t\t\tRefPtr<ILType> Type;\n\t\t\t\tif (n == 3)\n\t\t\t\t\tType = GetTypeFromString(\"mat3\");\n\t\t\t\telse if (n == 4)\n\t\t\t\t\tType = GetTypeFromString(\"mat4\");\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"Invalid type in AddInstrConstantMatrix(): mat\" + n);\n\t\t\t\tint typeID = DefineType(Type);\n\n\t\t\t\tList<int> vectorIDs;\n\t\t\t\tfor (int i = 0; i < n; i++)\n\t\t\t\t\tvectorIDs.Add(AddInstrConstantCompositeFloat(f + (i * n), n));\n\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpConstantComposite(CurrentID, typeID, vectorIDs);\n\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, Type, 0, typeID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrCompositeConstruct(ILOperand* op, RefPtr<ILType> Type, List<int> Arguments)\n\t\t\t\t// return ID of this instruction\n\t\t\t{\n\t\t\t\tint typeID = DefineType(Type);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpCompositeConstruct(CurrentID, typeID, Arguments);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, Type, op, typeID);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrCompositeExtract(int ID, RefPtr<ILType> baseType, int index)\n\t\t\t{\n\t\t\t\tint baseTypeID = DefineType(baseType);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpCompositeExtract(CurrentID, baseTypeID, ID, index);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, baseType, 0, baseTypeID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrCompositeInsert(RefPtr<ILType> Type, int ID, int index, int op)\n\t\t\t{\n\t\t\t\t//ID[index] = op\n\t\t\t\tint typeID = DefineType(Type);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpCompositeInsert(CurrentID, typeID, op, ID, index);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, Type, 0, typeID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrExtInst(ILOperand* op, RefPtr<ILType> Type, int instrNumber, List<int> Arguments)\n\t\t\t{\n\t\t\t\tint typeID = DefineType(Type);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpExtInst(CurrentID, typeID, instrNumber, Arguments);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, Type, op, typeID);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tvoid AddInstrStore(ILOperand *op, int op0, int op1) {\n\t\t\t\tCodeGen.OpStore(op0, op1);\n\t\t\t\tUpdateValue(op, op1);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tint AddInstrVariableDeclaration(ILOperand *op, RefPtr<ILType> typeIL, StorageClass store, String DebugName = \"\", int UniformOrBuffer = 0)\n\t\t\t{\n\t\t\t\tint typeID = DefineTypePointer(typeIL, store, UniformOrBuffer);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpVariable(CurrentID, typeID, store);\n\t\t\t\tUpdateVariable(op, CurrentID);\n\t\t\t\tIDInfos[CurrentID] =\n\t\t\t\t\tIDInfo::CreateIDInfoForPointer(CurrentID, op, typeID, typeIL, IDInfos[typeID]().GetBaseTypeID(), store);\n\t\t\t\t//Debug Information\n\t\t\t\tCodeGen.OpName(CurrentID, DebugName!=\"\"? DebugName : (op?op->Name:\"\"));\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrAccessChain_VectorMember(ILOperand *op, int ID, int indexID, int index)\n\t\t\t{\n\t\t\t\tString variableName = \"\";\n\t\t\t\tif (index == -1 && indexID == -1)\n\t\t\t\t\tthrow InvalidOperationException(\"indexID=-1 && index=-1 in AddInstrAccessChain_VectorMember()\");\n\n\t\t\t\tif (indexID == -1) {\n\t\t\t\t\t//indexID == -1 && index != -1\n\t\t\t\t\tindexID = AddInstrConstantInt(index);\n\t\t\t\t}\n\n\t\t\t\tif (index != -1)\n\t\t\t\t{\n\t\t\t\t\tvariableName = IDInfos[ID]().GetVariableName() + \"[\" + index + \"]\";\n\t\t\t\t}\n\n\t\t\t\tRefPtr<ILType> TypeIL = IDInfos[ID]().GetILType();\n\t\t\t\tRefPtr<ILType> memberTypeIL = nullptr;\n\t\t\t\tif (TypeIL->IsFloatMatrix())\n\t\t\t\t{\n\t\t\t\t\tif (TypeIL->ToString() == \"mat3\")\n\t\t\t\t\t\tmemberTypeIL = GetTypeFromString(\"vec3\");\n\t\t\t\t\telse if (TypeIL->ToString() == \"mat4\")\n\t\t\t\t\t\tmemberTypeIL = GetTypeFromString(\"vec4\");\n\t\t\t\t}\n\t\t\t\telse if (TypeIL->IsFloatVector())\n\t\t\t\t{\n\t\t\t\t\tmemberTypeIL = GetTypeFromString(\"float\");\n\t\t\t\t}\n\t\t\t\telse if (TypeIL->IsIntVector())\n\t\t\t\t{\n\t\t\t\t\tmemberTypeIL = GetTypeFromString(\"int\");\n\t\t\t\t}\n\t\t\t\telse if (TypeIL->IsUIntVector())\n\t\t\t\t{\n\t\t\t\t\tmemberTypeIL = GetTypeFromString(\"uint\");\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"invalid operand type for access chain: \" + TypeIL->ToString());\n\n\t\t\t\tint memberTypeID = DefineTypePointer(memberTypeIL, IDInfos[ID]().GetStorageClass());\n\n\t\t\t\t++CurrentID;\n\t\t\t\t/*FunctionBody << LR\"(%)\" << CurrentID << LR\"( = OpAccessChain %)\" << memberTypeID\n\t\t\t\t<< LR\"( %)\" << ID << LR\"( %)\" << indexID << EndLine;*/\n\t\t\t\tCodeGen.OpAccessChain(CurrentID, memberTypeID, ID, indexID);\n\t\t\t\tIDInfos[CurrentID] =\n\t\t\t\t\tIDInfo::CreateIDInfoForPointer(\n\t\t\t\t\t\tCurrentID,\n\t\t\t\t\t\top,\n\t\t\t\t\t\tmemberTypeID,\n\t\t\t\t\t\tmemberTypeIL,\n\t\t\t\t\t\tIDInfos[memberTypeID]().GetBaseTypeID(),\n\t\t\t\t\t\tIDInfos[ID]().GetStorageClass()\n\t\t\t\t\t);\n\t\t\t\tUpdateVariable(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrAccessChain_StructMember(ILOperand *op, int ID, int indexID, int index)\n\t\t\t{\n\t\t\t\tif (indexID == -1)\n\t\t\t\t\tindexID = AddInstrConstantInt(index);\n\t\t\t\tRefPtr<ILType> Type = IDInfos[ID]().GetILType();\n\t\t\t\tILStructType * structType = dynamic_cast<ILStructType*>(Type.Ptr());\n\t\t\t\tRefPtr<ILType> memberBasetypeIL = structType->Members[index].Type;\n\t\t\t\tint memberTypeID = DefineTypePointer(memberBasetypeIL, IDInfos[ID]().GetStorageClass());\n\n\t\t\t\t++CurrentID;\n\t\t\t\t/*\n\t\t\t\tFunctionBody << LR\"(%)\" << CurrentID << LR\"( = OpAccessChain %)\"\n\t\t\t\t<< memberTypeID\n\t\t\t\t<< LR\"( %)\" << ID << LR\"( %)\" << indexID << EndLine;\n\t\t\t\t*/\n\t\t\t\tCodeGen.OpAccessChain(CurrentID, memberTypeID, ID, indexID);\n\n\t\t\t\tUpdateVariable(op, CurrentID);\n\t\t\t\tIDInfos[CurrentID] =\n\t\t\t\t\tIDInfo::CreateIDInfoForPointer(\n\t\t\t\t\t\tCurrentID,\n\t\t\t\t\t\top,\n\t\t\t\t\t\tmemberTypeID,\n\t\t\t\t\t\tmemberBasetypeIL,\n\t\t\t\t\t\tIDInfos[memberTypeID]().GetBaseTypeID(),\n\t\t\t\t\t\tIDInfos[ID]().GetStorageClass()\n\t\t\t\t\t);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrAccessChain_StructMember(ILOperand *op, String memberName)\n\t\t\t{\n\t\t\t\tint structID = FindVariableID(op);\n\t\t\t\tILStructType* structIL = dynamic_cast<ILStructType*>(IDInfos[structID]().GetILType().Ptr());\n\t\t\t\tif (!structIL)\n\t\t\t\t\tthrow InvalidProgramException(\"can not convert to ILStruct in AddInstrAccessChain_StructMember()\");\n\t\t\t\tint index = structIL->Members.FindFirst([&](ILStructType::ILStructField member)\n\t\t\t\t{\n\t\t\t\t\treturn member.FieldName == memberName;\n\t\t\t\t});\n\t\t\t\tint indexID = AddInstrConstantInt(index);\n\t\t\t\treturn AddInstrAccessChain_StructMember(op, structID, indexID, index);\n\t\t\t}\n\n\t\t\tint AddInstrAccessChain_StructMember(ILOperand *op, int structID, String memberName)\n\t\t\t{\n\t\t\t\tILStructType* structIL = dynamic_cast<ILStructType*>(IDInfos[structID]().GetILType().Ptr());\n\t\t\t\tif (!structIL)\n\t\t\t\t\tthrow InvalidProgramException(\"can not convert to ILStruct in AddInstrAccessChain_StructMember()\");\n\t\t\t\tint index = structIL->Members.FindFirst([&](ILStructType::ILStructField member)\n\t\t\t\t{\n\t\t\t\t\treturn member.FieldName == memberName;\n\t\t\t\t});\n\t\t\t\tint indexID = AddInstrConstantInt(index);\n\t\t\t\treturn AddInstrAccessChain_StructMember(op, structID, indexID, index);\n\t\t\t}\n\n\t\t\tint AddInstrAccessChain_ArrayMember(ILOperand *op, RefPtr<ILType> Type, int ID, int indexID)\n\t\t\t{\n\t\t\t\tif (!Type)\n\t\t\t\t\tthrow InvalidProgramException(\"empty type in AddInstrAccessChain_ArrayMember()\");\n\t\t\t\tauto arrayType = dynamic_cast<ILArrayType*>(Type.Ptr());\n\t\t\t\tint baseTypeID = DefineTypePointer(arrayType->BaseType, IDInfos[ID]().GetStorageClass()); //it's a pointer\n\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpAccessChain(CurrentID, baseTypeID, ID, indexID);\n\t\t\t\tIDInfos[CurrentID] =\n\t\t\t\t\tIDInfo::CreateIDInfoForPointer(\n\t\t\t\t\t\tCurrentID,\n\t\t\t\t\t\top,\n\t\t\t\t\t\tbaseTypeID,\n\t\t\t\t\t\tarrayType->BaseType,\n\t\t\t\t\t\tIDInfos[baseTypeID]().GetBaseTypeID(),\n\t\t\t\t\t\tIDInfos[ID]().GetStorageClass()\n\t\t\t\t\t);\n\t\t\t\tUpdateVariable(op, CurrentID);\n\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrLoad(int variableID, MemoryAccess ma)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tRefPtr<ILType> Type = IDInfos[variableID]().GetILType();\n\t\t\t\tint TypeID = IDInfos[variableID]().GetBaseTypeID();\n\t\t\t\tCodeGen.OpLoad(CurrentID, TypeID, variableID, ma);\n\t\t\t\tIDInfos[CurrentID]\n\t\t\t\t\t= IDInfo::CreateIDInfoForValue(\n\t\t\t\t\t\tCurrentID,\n\t\t\t\t\t\tType,\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tTypeID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrLoad(ILOperand *op, ILOperand *targetOp, MemoryAccess ma)\n\t\t\t{\n\t\t\t\tint targetID = FindVariableID(targetOp);\n\t\t\t\tif (targetID == -1)\n\t\t\t\t\treturn -1;\n\t\t\t\tint typeID = IDInfos[targetID]().GetBaseTypeID();\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpLoad(CurrentID, typeID, targetID, ma);\n\t\t\t\tIDInfos[CurrentID]\n\t\t\t\t\t= IDInfo::CreateIDInfoForValue(\n\t\t\t\t\t\tCurrentID,\n\t\t\t\t\t\tIDInfos[targetID]().GetILType(),\n\t\t\t\t\t\top,\n\t\t\t\t\t\ttypeID);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrINotEqual(int id0, int id1)\n\t\t\t{\n\t\t\t\tRefPtr<ILType> typeIL = GetTypeFromString(\"bool\");\n\t\t\t\tint typeID = DefineType(typeIL);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpINotEqual(CurrentID, typeID, id0, id1);\n\t\t\t\tIDInfos[CurrentID]\n\t\t\t\t\t= IDInfo::CreateIDInfoForValue(\n\t\t\t\t\t\tCurrentID,\n\t\t\t\t\t\ttypeIL,\n\t\t\t\t\t\t0,\n\t\t\t\t\t\ttypeID\n\t\t\t\t\t);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrTexture(\n\t\t\t\tILOperand *op, \n\t\t\t\tint textureID, \n\t\t\t\tint coordinateID, \n\t\t\t\tExecutionModel currentExecutionModel,\n\t\t\t\tint Bias = -1,\n\t\t\t\tint GradX = -1,\n\t\t\t\tint GradY = -1)\n\t\t\t{\n\t\t\t\tRefPtr<ILType> typeIL = GetTypeFromString(\"vec4\");\n\t\t\t\tint typeID = DefineType(typeIL);\n\n\t\t\t\t++CurrentID;\n\t\t\t\tif (currentExecutionModel == ExecutionModel::Fragment && GradX == -1)\n\t\t\t\t{\n\t\t\t\t\t//implicit LOD\n\t\t\t\t\tCodeGen.OpImageSampleImplicitLod(CurrentID, typeID, textureID, coordinateID, Bias);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t//explicit LOD\n\t\t\t\t\tint zeroID = AddInstrConstantInt(0);\n\t\t\t\t\tCodeGen.OpImageSampleExplicitLod(CurrentID, typeID, textureID, coordinateID, zeroID, Bias, GradX, GradY);\n\t\t\t\t}\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\ttypeIL,\n\t\t\t\t\top,\n\t\t\t\t\ttypeID\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrTextureShadow(\n\t\t\t\tILOperand *op, \n\t\t\t\tint textureID, \n\t\t\t\tint coordinateID, \n\t\t\t\tExecutionModel currentExecutionModel) \n\t\t\t{\n\t\t\t\tRefPtr<ILType> typeIL = GetTypeFromString(\"vec4\");\n\t\t\t\tint typeID = DefineType(typeIL);\n\n\t\t\t\tint veclen = IDInfos[coordinateID]().GetILType()->GetVectorSize();\n\t\t\t\tint DrefID = AddInstrCompositeExtract(coordinateID, GetTypeFromString(\"float\"), veclen-1);\n\n\t\t\t\t++CurrentID;\n\t\t\t\tif (currentExecutionModel == ExecutionModel::Fragment)\n\t\t\t\t{\n\t\t\t\t\t//implicit LOD\n\t\t\t\t\tCodeGen.OpImageSampleDrefImplicitLod(CurrentID, typeID, textureID, coordinateID, DrefID);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t//explicit LOD\n\t\t\t\t\tint zeroID = AddInstrConstantInt(0);\n\t\t\t\t\tCodeGen.OpImageSampleDrefExplicitLod(CurrentID, typeID, textureID, coordinateID, DrefID, zeroID);\n\t\t\t\t}\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\ttypeIL,\n\t\t\t\t\top,\n\t\t\t\t\ttypeID\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrTexture2DShadowProj(\n\t\t\t\tILOperand *op,\n\t\t\t\tint textureID,\n\t\t\t\tint coordinateID,\t////coordinateID: u, v, depth, q\n\t\t\t\tExecutionModel currentExecutionModel)\n\t\t\t{\n\t\t\t\tRefPtr<ILType> typeIL = GetTypeFromString(\"vec4\");\n\t\t\t\tint typeID = DefineType(typeIL);\n\n\t\t\t\tint DrefID = AddInstrCompositeExtract(coordinateID, GetTypeFromString(\"float\"), 2);\n\t\t\t\tint qID = AddInstrCompositeExtract(coordinateID, GetTypeFromString(\"float\"), 3);\n\t\t\t\tint NewCoordinateID = AddInstrCompositeInsert(IDInfos[coordinateID]().GetILType(), coordinateID, 2, qID);\n\n\t\t\t\t++CurrentID;\n\t\t\t\tif (currentExecutionModel == ExecutionModel::Fragment)\n\t\t\t\t{\n\t\t\t\t\t//implicit LOD\n\t\t\t\t\tCodeGen.OpImageSampleProjDrefImplicitLod(CurrentID, typeID, textureID, NewCoordinateID, DrefID);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t//explicit LOD\n\t\t\t\t\tint zeroID = AddInstrConstantInt(0);\n\t\t\t\t\tCodeGen.OpImageSampleProjDrefExplicitLod(CurrentID, typeID, textureID, NewCoordinateID, DrefID, zeroID);\n\t\t\t\t}\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\ttypeIL,\n\t\t\t\t\top,\n\t\t\t\t\ttypeID\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrConvertSToF(int destTypeID, int operandID)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpConvertSToF(CurrentID, destTypeID, operandID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[destTypeID]().GetILType(),\n\t\t\t\t\t0,\n\t\t\t\t\tdestTypeID\n\t\t\t\t);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrConvertFToS(int destTypeID, int operandID)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpConvertFToS(CurrentID, destTypeID, operandID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[destTypeID]().GetILType(),\n\t\t\t\t\t0,\n\t\t\t\t\tdestTypeID\n\t\t\t\t);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrConvertUToF(int destTypeID, int operandID)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpConvertUToF(CurrentID, destTypeID, operandID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[destTypeID]().GetILType(),\n\t\t\t\t\t0,\n\t\t\t\t\tdestTypeID\n\t\t\t\t);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrConvertFToU(int destTypeID, int operandID)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpConvertFToU(CurrentID, destTypeID, operandID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[destTypeID]().GetILType(),\n\t\t\t\t\t0,\n\t\t\t\t\tdestTypeID\n\t\t\t\t);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrConvertSToU(int destTypeID, int operandID)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpBitCast(CurrentID, destTypeID, operandID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[destTypeID]().GetILType(),\n\t\t\t\t\t0,\n\t\t\t\t\tdestTypeID\n\t\t\t\t);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrConvertUToS(int destTypeID, int operandID) \n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpBitCast(CurrentID, destTypeID, operandID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[destTypeID]().GetILType(),\n\t\t\t\t\t0,\n\t\t\t\t\tdestTypeID\n\t\t\t\t);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrBitcast(int destTypeID, int operandID)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpBitCast(CurrentID, destTypeID, operandID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[destTypeID]().GetILType(),\n\t\t\t\t\t0,\n\t\t\t\t\tdestTypeID\n\t\t\t\t);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrFunctionCall(ILOperand *op, int typeID, int funcID, List<int> &args)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpFunctionCall(CurrentID, typeID, funcID, args);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[typeID]().GetILType(),\n\t\t\t\t\top,\n\t\t\t\t\ttypeID\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrFnegate(ILOperand *op, int typeID, int valueID)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpFNegate(CurrentID, typeID, valueID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[typeID]().GetILType(),\n\t\t\t\t\top, \n\t\t\t\t\ttypeID\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrSnegate(ILOperand *op, int typeID, int valueID)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpSNegate(CurrentID, typeID, valueID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[typeID]().GetILType(),\n\t\t\t\t\top,\n\t\t\t\t\ttypeID\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrNot(ILOperand *op, int typeID, int valueID)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpNot(CurrentID, typeID, valueID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[typeID]().GetILType(),\n\t\t\t\t\top,\n\t\t\t\t\ttypeID\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrLogicalNot(ILOperand *op, int typeID, int valueID)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpLogicalNot(CurrentID, typeID, valueID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[typeID]().GetILType(),\n\t\t\t\t\top,\n\t\t\t\t\ttypeID\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrMatrixTimesScalar(ILOperand *op, int ID0, int ID1)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpMatrixTimesScalar(CurrentID, IDInfos[ID0]().GetTypeID(), ID0, ID1);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[ID0]().GetILType(),\n\t\t\t\t\top,\n\t\t\t\t\tIDInfos[ID0]().GetTypeID()\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrVectorTimesMatrix(ILOperand *op, int ID0, int ID1)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpVectorTimesMatrix(CurrentID, IDInfos[ID0]().GetTypeID(), ID0, ID1);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[ID0]().GetILType(),\n\t\t\t\t\top,\n\t\t\t\t\tIDInfos[ID0]().GetTypeID()\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrMatrixTimesVector(ILOperand *op, int ID0, int ID1)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpMatrixTimesVector(CurrentID, IDInfos[ID1]().GetTypeID(), ID0, ID1);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[ID1]().GetILType(),\n\t\t\t\t\top,\n\t\t\t\t\tIDInfos[ID1]().GetTypeID()\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrMatrixTimesMatrix(ILOperand *op, int ID0, int ID1)\n\t\t\t{\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpMatrixTimesMatrix(CurrentID, IDInfos[ID0]().GetTypeID(), ID0, ID1);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\tIDInfos[ID0]().GetILType(),\n\t\t\t\t\top,\n\t\t\t\t\tIDInfos[ID0]().GetTypeID()\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrBinaryInstr(ILOperand *op, RefPtr<ILType> instrType, const String &opStr, int ID0, int ID1)\n\t\t\t{\n\t\t\t\tint instrTypeID = DefineType(instrType);\n\t\t\t\tCurrentID++;\n\t\t\t\tCodeGen.OpBinaryInstr(CurrentID, opStr, instrTypeID, ID0, ID1);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, instrType, op, instrTypeID);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrMulAdd(int operandID, float mul, float add)\n\t\t\t{\n\t\t\t\t//return 0.5*op+0.5\n\t\t\t\tint typeID = IDInfos[operandID]().GetTypeID();  //shoudl be float \n\t\t\t\tRefPtr<ILType> typeIL = IDInfos[operandID]().GetILType();\n\n\t\t\t\tint mul_ID = AddInstrConstantFloat(mul);\n\t\t\t\tmul_ID = ConvertBasicType(mul_ID, IDInfos[mul_ID]().GetILType(), IDInfos[operandID]().GetILType());\n\n\t\t\t\tint add_ID = AddInstrConstantFloat(add);\n\t\t\t\tadd_ID = ConvertBasicType(add_ID, IDInfos[add_ID]().GetILType(), IDInfos[operandID]().GetILType());\n\n\t\t\t\t++CurrentID;\n\t\t\t\t//ctx.FunctionBody << LR\"(%)\" << ctx.CurrentID << LR\"( = OpFMul %)\" << typeID << LR\"( %)\" << operandID << LR\"( %)\" << mul_ID << EndLine;\n\t\t\t\tCodeGen.OpFMul(CurrentID, typeID, operandID, mul_ID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, typeIL, 0, typeID);\n\t\t\t\t++CurrentID;\n\t\t\t\t//ctx.FunctionBody << LR\"(%)\" << ctx.CurrentID << LR\"( = OpFAdd %)\" << typeID << LR\"( %)\" << ctx.CurrentID-1 << LR\"( %)\" << add_ID << EndLine;\n\t\t\t\tCodeGen.OpFAdd(CurrentID, typeID, CurrentID - 1, add_ID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(CurrentID, typeIL, 0, typeID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint ConvertBasicType(int operandID, RefPtr<ILType> srcType, RefPtr<ILType> dstType)\n\t\t\t{\n\t\t\t\tString srcStr = srcType->ToString();\n\t\t\t\tString dstStr = dstType->ToString();\n\t\t\t\tif (srcStr == dstStr)\n\t\t\t\t\treturn operandID;\n\n\t\t\t\tif (dstType->IsBool())\n\t\t\t\t{\n\t\t\t\t\tif (srcType->IsInt())\n\t\t\t\t\t\treturn AddInstrINotEqual(operandID, AddInstrConstantInt(0));\n\t\t\t\t\tif (srcType->IsUInt())\n\t\t\t\t\t\treturn AddInstrINotEqual(operandID, AddInstrConstantUInt(0));\n\t\t\t\t\tthrow NotImplementedException(\"only convert int to bool in ConvertBasicType(): \" + srcType->ToString());\n\t\t\t\t}\n\n\t\t\t\t//from column vector to column vector\n\t\t\t\tbool srcIsColumnVector = (srcType->IsFloat() || srcType->IsFloatVector() || srcType->IsIntegral()) && !srcType->IsFloatMatrix();\n\t\t\t\tbool dstIsColumnVector = (dstType->IsFloat() || dstType->IsFloatVector() || dstType->IsIntegral()) && !dstType->IsFloatMatrix();\n\t\t\t\tif (srcIsColumnVector && dstIsColumnVector && srcType->GetVectorSize() != dstType->GetVectorSize())\n\t\t\t\t{\n\t\t\t\t\t//make src ID have length equal to destType\n\n\t\t\t\t\tRefPtr<ILType> elementType;\n\t\t\t\t\tif (srcType->IsInt() || srcType->IsUInt())\n\t\t\t\t\t\telementType = new ILBasicType(ILBaseType::Int);\n\t\t\t\t\telse if (srcType->IsUInt() || srcType->IsUIntVector())\n\t\t\t\t\t\telementType = new ILBasicType(ILBaseType::UInt);\n\t\t\t\t\telse\n\t\t\t\t\t\telementType = new ILBasicType(ILBaseType::Float);\n\t\t\t\t\tList<int> arguments;\n\t\t\t\t\tint extraID = -1;\n\n\t\t\t\t\tif (srcType->GetVectorSize() == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int i = 0; i < dstType->GetVectorSize(); i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\targuments.Add(operandID);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfor (int i = 0; i < dstType->GetVectorSize(); i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (i >= srcType->GetVectorSize())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (i == srcType->GetVectorSize())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (srcType->IsInt() || srcType->IsIntVector())\n\t\t\t\t\t\t\t\t\t\textraID = AddInstrConstantInt(0);\n\t\t\t\t\t\t\t\t\telse if (srcType->IsUInt() || srcType->IsUIntVector())\n\t\t\t\t\t\t\t\t\t\textraID = AddInstrConstantUInt(0);\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\textraID = AddInstrConstantFloat(0.0);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\targuments.Add(extraID);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (srcType->GetVectorSize() == 1)\n\t\t\t\t\t\t\t\t\targuments.Add(operandID);\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\targuments.Add(AddInstrCompositeExtract(operandID, elementType, i));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tint BaseType = (dynamic_cast<ILBasicType*>(srcType.Ptr()))->Type;\n\t\t\t\t\tint newBaseType = BaseType & ~15; // int or float\n\t\t\t\t\tnewBaseType += dstType->GetVectorSize() - 1;\n\t\t\t\t\tRefPtr<ILType> newSrcType = new ILBasicType(ILBaseType(newBaseType));\n\n\t\t\t\t\toperandID = AddInstrCompositeConstruct(0, newSrcType, arguments);\n\t\t\t\t\tsrcType = newSrcType;\n\t\t\t\t}\n\n\t\t\t\tsrcStr = srcType->ToString();\n\t\t\t\tdstStr = dstType->ToString();\n\t\t\t\tif (srcStr == dstStr)\n\t\t\t\t\treturn operandID;\n\n\t\t\t\t//from scalar to matrix\n\t\t\t\tif ((srcStr == \"float\" || srcStr == \"int\" || srcStr == \"uint\") && dstType->IsFloatMatrix())\n\t\t\t\t{\n\t\t\t\t\tthrow NotImplementedException(\"scalar to matrix conversion is not supported yet.\");\n\t\t\t\t}\n\n\t\t\t\t//from matrix to matrix\n\t\t\t\tif (srcType->IsFloatMatrix() && dstType->IsFloatMatrix())\n\t\t\t\t{\n\t\t\t\t\tthrow NotImplementedException(\"matrix to matrix conversion is not supported yet.\");\n\t\t\t\t}\n\n\t\t\t\tif (srcType->GetVectorSize() != dstType->GetVectorSize())\n\t\t\t\t{\n\t\t\t\t\tthrow NotImplementedException(\"can not convert \" + srcType->ToString() + \" to \" + dstType->ToString());\n\t\t\t\t}\n\n\t\t\t\t//component-wise conversion\n\n\t\t\t\tbool srcFloat = srcType->IsFloat() || srcType->IsFloatVector();\n\t\t\t\tbool srcInt = srcType->IsInt() || srcType->IsIntVector();\n\t\t\t\tbool srcUint = srcType->IsUInt() || srcType->IsUIntVector();\n\t\t\t\tbool dstFloat = dstType->IsFloat() || dstType->IsFloatVector();\n\t\t\t\tbool dstInt = dstType->IsInt() || dstType->IsIntVector();\n\t\t\t\tbool dstUint = dstType->IsUInt() || dstType->IsUIntVector();\n\n\t\t\t\tint destTypeID = DefineType(dstType);\n\t\t\t\tif (srcInt && dstFloat)\n\t\t\t\t\treturn AddInstrConvertSToF(destTypeID, operandID);\n\t\t\t\telse if (srcFloat && dstInt)\n\t\t\t\t\treturn AddInstrConvertFToS(destTypeID, operandID);\n\t\t\t\telse if (srcUint && dstFloat)\n\t\t\t\t\treturn AddInstrConvertUToF(destTypeID, operandID);\n\t\t\t\telse if (srcFloat && dstUint)\n\t\t\t\t\treturn AddInstrConvertFToU(destTypeID, operandID);\n\t\t\t\telse if (srcInt && dstUint)\n\t\t\t\t\treturn AddInstrConvertSToU(destTypeID, operandID);\n\t\t\t\telse if (srcUint && dstInt)\n\t\t\t\t\treturn AddInstrConvertUToS(destTypeID, operandID);\n\t\t\t\telse\n\t\t\t\t\tthrow NotImplementedException(\"can not convert \" + srcType->ToString() + \" to \" + dstType->ToString());\n\t\t\t}\n\n\t\t\tvoid AddInstrSelectionMerge(int MergeLabel) {\n\t\t\t\tCodeGen.OpSelectionMerge(MergeLabel);\n\t\t\t}\n\n\t\t\tvoid AddInstrBranchConditional(int ID, int TrueLabel, int FalseLabel)\n\t\t\t{\n\t\t\t\tCodeGen.OpBranchConditional(ID, TrueLabel, FalseLabel);\n\t\t\t}\n\n\t\t\tvoid AddInstrLabel_AtFunctionBody(int Label) {\n\t\t\t\tCodeGen.OpLabel_AtFunctionBody(Label);\n\t\t\t}\n\n\t\t\tvoid AddInstrLabel_AtFunctionHeader(int Label)\n\t\t\t{\n\t\t\t\tCodeGen.OpLabel_AtFunctionHeader(Label);\n\t\t\t}\n\n\t\t\tvoid AddInstrBranch(int Target)\n\t\t\t{\n\t\t\t\tCodeGen.OpBranch(Target);;\n\t\t\t}\n\n\t\t\tint AddInstrPhi(ILOperand *op, int ID1, int Label1, int ID2, int Label2)\n\t\t\t{\n\t\t\t\tList<int> branches;\n\t\t\t\tbranches.Add(ID1); branches.Add(Label1);\n\t\t\t\tbranches.Add(ID2); branches.Add(Label2);\n\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpPhi(CurrentID, IDInfos[ID1]().GetTypeID(), branches);\n\n\t\t\t\tIDInfos[CurrentID] =\n\t\t\t\t\tIDInfo::CreateIDInfoForValue(\n\t\t\t\t\t\tCurrentID,\n\t\t\t\t\t\tIDInfos[ID1]().GetILType(),\n\t\t\t\t\t\top,\n\t\t\t\t\t\tIDInfos[ID1]().GetTypeID()\n\t\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tvoid AddInstrLoopMerge(int MergeLabel, int ContinueLabel)\n\t\t\t{\n\t\t\t\tCodeGen.OpLoopMerge(MergeLabel, ContinueLabel);\n\t\t\t}\n\n\t\t\tvoid AddInstrReturnValue(int operandID) \n\t\t\t{\n\t\t\t\tCodeGen.OpReturnValue(operandID);\n\t\t\t}\n\n\t\t\tvoid AddInstrKill() \n\t\t\t{\n\t\t\t\tCodeGen.OpKill();\n\t\t\t}\n\n\t\t\tvoid AddInstrDecorate(int ID, Decoration deco, int ID1 = 0)\n\t\t\t{\n\t\t\t\tCodeGen.OpDecorate(ID, deco, ID1);\n\t\t\t}\n\n\t\t\tvoid AddInstrMemberDecorate(int ID, int index, Decoration deco, int ID1 = 0)\n\t\t\t{\n\t\t\t\tCodeGen.OpMemberDecorate(ID, index, deco, ID1);\n\t\t\t}\n\n\t\t\tvoid AddInstrFunction(int funcID, int returnTypeID, int funcTypeID, String funcName) \n\t\t\t{\n\t\t\t\tCodeGen.OpName(funcID, funcName);\n\t\t\t\tCodeGen.OpFunction(funcID, returnTypeID, funcTypeID);\n\t\t\t}\n\n\t\t\tvoid AddInstrFunctionParameter(ILOperand *op, int typeID, String DebugName)\n\t\t\t{\n\t\t\t\tint paramID = ++CurrentID;\n\t\t\t\tCodeGen.OpName(paramID, DebugName);\n\t\t\t\tCodeGen.OpFunctionParameter(paramID, typeID);\n\t\t\t\tIDInfos[paramID] = IDInfo::CreateIDInfoForPointer(\n\t\t\t\t\tparamID,\n\t\t\t\t\top,\n\t\t\t\t\ttypeID,\n\t\t\t\t\tIDInfos[typeID]().GetILType(),\n\t\t\t\t\tIDInfos[typeID]().GetBaseTypeID(),\n\t\t\t\t\tStorageClass::Function\n\t\t\t\t);\n\t\t\t\tParameterNameToID[op] = paramID;\n\t\t\t\tUpdateVariable(op, paramID);\n\t\t\t}\n\n\t\t\tvoid AddInstrReturn()\n\t\t\t{\n\t\t\t\tCodeGen.OpReturn();\n\t\t\t}\n\n\t\t\tvoid AddInstrFunctionEnd()\n\t\t\t{\n\t\t\t\tCodeGen.OpFunctionEnd();\n\t\t\t}\n\n\t\t\tvoid AddInstrEntryPoint(ExecutionModel EM, int entryID, const List<int>& interfaceIDs)\n\t\t\t{\n\t\t\t\tCodeGen.OpEntryPoint(EM, entryID, interfaceIDs);\n\t\t\t}\n\n\t\t\tvoid AddInstrExecutionMode(int ID, ExecutionMode mode, int op1 = -1, int op2 = -1, int op3 = -1) \n\t\t\t{\n\t\t\t\tCodeGen.OpExecutionMode(ID, mode, op1, op2, op3);\n\t\t\t}\n\n\t\t\tint AddInstrDot(ILOperand *op, RefPtr<ILType> typeIL, int ID0, int ID1)\n\t\t\t{\n\t\t\t\tint typeID = DefineType(typeIL);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpDot(CurrentID, typeID, ID0, ID1);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\ttypeIL,\n\t\t\t\t\top,\n\t\t\t\t\ttypeID\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrTranspose(ILOperand *op, RefPtr<ILType> typeIL, int ID)\n\t\t\t{\n\t\t\t\tint typeID = DefineType(typeIL);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpTranspose(CurrentID, typeID, ID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\ttypeIL,\n\t\t\t\t\top,\n\t\t\t\t\ttypeID\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrDFdx(ILOperand *op, RefPtr<ILType> typeIL, int ID)\n\t\t\t{\n\t\t\t\tint typeID = DefineType(typeIL);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpDPdx(CurrentID, typeID, ID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\ttypeIL,\n\t\t\t\t\top,\n\t\t\t\t\ttypeID\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrDFdy(ILOperand *op, RefPtr<ILType> typeIL, int ID)\n\t\t\t{\n\t\t\t\tint typeID = DefineType(typeIL);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpDPdy(CurrentID, typeID, ID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\ttypeIL,\n\t\t\t\t\top,\n\t\t\t\t\ttypeID\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tint AddInstrFwidth(ILOperand *op, RefPtr<ILType> typeIL, int ID)\n\t\t\t{\n\t\t\t\tint typeID = DefineType(typeIL);\n\t\t\t\t++CurrentID;\n\t\t\t\tCodeGen.OpFwidth(CurrentID, typeID, ID);\n\t\t\t\tIDInfos[CurrentID] = IDInfo::CreateIDInfoForValue(\n\t\t\t\t\tCurrentID,\n\t\t\t\t\ttypeIL,\n\t\t\t\t\top,\n\t\t\t\t\ttypeID\n\t\t\t\t);\n\t\t\t\tUpdateValue(op, CurrentID);\n\t\t\t\treturn CurrentID;\n\t\t\t}\n\n\t\t\tvoid ProduceFunction()\n\t\t\t{\n\t\t\t\tCodeGen.ProduceFunction();\n\t\t\t}\n\n\t\t\tList<unsigned int> ProduceWordStream()\n\t\t\t{\n\t\t\t\treturn CodeGen.ProduceWordStream(CurrentID);\n\t\t\t}\n\n\t\t\tString ProduceTextCode() \n\t\t\t{\n\t\t\t\treturn CodeGen.ProduceTextCode();\n\t\t\t}\n\t\t};\n\n\n\n\t\tclass SpirvModule\n\t\t{\n\t\tprivate:\n\t\t\tSpirVCodeGenContext ctx;\n\t\t\tExecutionModel currentExecutionModel;\n\t\t\tList<int> interfaceIDs;\n\t\t\tbool DepthReplacing;\n\t\t\tbool LocalSize;\n\t\t\tbool BufferImportOrExport;\n\t\t\tCompiledWorld * currentWorld;\n\n\t\t\tint GetOperandValue(ILOperand * op)\n\t\t\t{\n\t\t\t\tint id = -1;\n\t\t\t\tif (auto c = dynamic_cast<ILConstOperand*>(op))\n\t\t\t\t{\n\t\t\t\t\tauto type = c->Type.Ptr();\n\t\t\t\t\tif (type->IsFloat())\n\t\t\t\t\t{\n\t\t\t\t\t\tid = ctx.AddInstrConstantFloat(c->FloatValues[0]);\n\t\t\t\t\t}\n\t\t\t\t\telse if (type->IsInt())\n\t\t\t\t\t{\n\t\t\t\t\t\tid = ctx.AddInstrConstantInt(c->IntValues[0]);\n\t\t\t\t\t}\n\t\t\t\t\telse if (type->IsUInt())\n\t\t\t\t\t{\n\t\t\t\t\t\tid = ctx.AddInstrConstantUInt(*((unsigned int*)(&c->IntValues[0])));\n\t\t\t\t\t}\n\t\t\t\t\telse if (auto baseType = dynamic_cast<ILBasicType*>(type))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (baseType->Type == ILBaseType::Float2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid = ctx.AddInstrConstantCompositeFloat(c->FloatValues, 2);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (baseType->Type == ILBaseType::Float3)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid = ctx.AddInstrConstantCompositeFloat(c->FloatValues, 3);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (baseType->Type == ILBaseType::Float4)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid = ctx.AddInstrConstantCompositeFloat(c->FloatValues, 4);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (baseType->Type == ILBaseType::Float3x3)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid = ctx.AddInstrConstantMatrix(c->FloatValues, 3);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (baseType->Type == ILBaseType::Float4x4)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid = ctx.AddInstrConstantMatrix(c->FloatValues, 4);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (baseType->Type == ILBaseType::Int2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid = ctx.AddInstrConstantCompositeInt(c->IntValues, 2);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (baseType->Type == ILBaseType::Int3)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid = ctx.AddInstrConstantCompositeInt(c->IntValues, 3);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (baseType->Type == ILBaseType::Int4)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid = ctx.AddInstrConstantCompositeInt(c->IntValues, 4);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (baseType->Type == ILBaseType::UInt2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid = ctx.AddInstrConstantCompositeUInt((unsigned int*)c->IntValues, 2);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (baseType->Type == ILBaseType::UInt3)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid = ctx.AddInstrConstantCompositeUInt((unsigned int*)c->IntValues, 3);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (baseType->Type == ILBaseType::UInt4)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid = ctx.AddInstrConstantCompositeUInt((unsigned int*)c->IntValues, 4);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (baseType->Type == ILBaseType::Bool)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid = ctx.AddInstrConstantBool(c->IntValues[0]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow InvalidOperationException(\"Illegal constant.\");\n\t\t\t\t}\n\t\t\t\telse if (auto instr = dynamic_cast<ILInstruction*>(op))\n\t\t\t\t{\n\t\t\t\t\tid = ctx.FindValueID(op);\n\t\t\t\t\tif (id == -1)\n\t\t\t\t\t{\n\t\t\t\t\t\t//need to load it from storage\n\t\t\t\t\t\tid = ctx.AddInstrLoad(op, op, MemoryAccess::None);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"Unsupported operand type.\");\n\n\t\t\t\treturn id;\n\t\t\t}\n\n\t\t\tint GetOperandPointer(ILOperand * op)\n\t\t\t{\n\t\t\t\tint id = -1;\n\t\t\t\t//RefPtr<ILType> result_type;\n\t\t\t\tif (auto c = dynamic_cast<ILConstOperand*>(op))\n\t\t\t\t{\n\t\t\t\t\tint valueID = GetOperandValue(op);\n\t\t\t\t\tid = ctx.AddInstrVariableDeclaration(op, op->Type, StorageClass::Function);\n\t\t\t\t\tctx.AddInstrStore(op, id, valueID);\n\t\t\t\t}\n\t\t\t\telse if (auto instr = dynamic_cast<ILInstruction*>(op))\n\t\t\t\t{\n\t\t\t\t\tid = ctx.FindVariableID(op);\n\t\t\t\t\tif (id == -1)\n\t\t\t\t\t{\n\t\t\t\t\t\tint valueID = ctx.FindValueID(op);\n\t\t\t\t\t\tif (valueID == -1)\n\t\t\t\t\t\t\tthrow InvalidOperationException(\"can not find variable ID in Get OperandPointer(): \" + op->ToString());\n\t\t\t\t\t\tid = ctx.AddInstrVariableDeclaration(op, instr->Type, StorageClass::Function);\n\t\t\t\t\t\tctx.AddInstrStore(op, id, valueID);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"Unsupported operand type.\");\n\n\t\t\t\treturn id;\n\t\t\t}\n\n\t\t\tvoid PrintAllocVarInstr(AllocVarInstruction * instr, StorageClass store)\n\t\t\t{\n\t\t\t\tif (dynamic_cast<ILConstOperand*>(instr->Size.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrVariableDeclaration((ILOperand*)instr, instr->Type, store);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidProgramException(\"size operand of allocVar instr is not an intermediate.\");\n\t\t\t}\n\n\t\t\tDictionary<String, int> GLSLstd450InstructionSet = GenGLSLstd450InstructionSet();\n\n\t\t\tvoid PrintCallInstr(CallInstruction * instr)\n\t\t\t\t// return ID of this instruction\n\t\t\t{\n\t\t\t\tString callName = GetFuncOriginalName(instr->Function);\n\n\t\t\t\t//------------------------- texture instructions -------------------------\n\t\t\t\tif (callName == \"texture\")\n\t\t\t\t{\n\t\t\t\t\tif (instr->Arguments[0]->Type->IsNonShadowTexture())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (instr->Arguments[0]->Type->ToString() == \"sampler2D\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//*** no bias!!!\n\t\t\t\t\t\t\t//__intrinsic vec4 texture(sampler2D tex, vec2 coord);\n\t\t\t\t\t\t\tctx.AddInstrTexture(\n\t\t\t\t\t\t\t\t(ILOperand*)instr,\n\t\t\t\t\t\t\t\tGetOperandValue(instr->Arguments[0].Ptr()),\n\t\t\t\t\t\t\t\tGetOperandValue(instr->Arguments[1].Ptr()),\n\t\t\t\t\t\t\t\tcurrentExecutionModel\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (instr->Arguments[0]->Type->ToString() == \"samplerCube\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (instr->Arguments.Count() == 2)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t//__intrinsic vec4 texture(samplerCube tex, vec3 coord);\n\t\t\t\t\t\t\t\tctx.AddInstrTexture(\n\t\t\t\t\t\t\t\t\t(ILOperand*)instr,\n\t\t\t\t\t\t\t\t\tGetOperandValue(instr->Arguments[0].Ptr()),\n\t\t\t\t\t\t\t\t\tGetOperandValue(instr->Arguments[1].Ptr()),\n\t\t\t\t\t\t\t\t\tcurrentExecutionModel\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t//__intrinsic vec4 texture(samplerCube tex, vec3 coord, float bias);\n\t\t\t\t\t\t\t\tctx.AddInstrTexture(\n\t\t\t\t\t\t\t\t\t(ILOperand*)instr,\n\t\t\t\t\t\t\t\t\tGetOperandValue(instr->Arguments[0].Ptr()),\n\t\t\t\t\t\t\t\t\tGetOperandValue(instr->Arguments[1].Ptr()),\n\t\t\t\t\t\t\t\t\tcurrentExecutionModel,\n\t\t\t\t\t\t\t\t\tGetOperandValue(instr->Arguments[2].Ptr())\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t//instr->Arguments[0]->Type->IsShadowTexture\n\n\t\t\t\t\t\t//__intrinsic float texture(sampler2DShadow tex, vec3 coord);\n\t\t\t\t\t\t//__intrinsic float texture(samplerCubeShadow tex, vec4 coord);\n\t\t\t\t\t\tctx.AddInstrTextureShadow(\n\t\t\t\t\t\t\t(ILOperand*)instr,\n\t\t\t\t\t\t\tGetOperandValue(instr->Arguments[0].Ptr()),\n\t\t\t\t\t\t\tGetOperandValue(instr->Arguments[1].Ptr()),\n\t\t\t\t\t\t\tcurrentExecutionModel\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (callName == \"textureGrad\")\n\t\t\t\t{\n\t\t\t\t\t//__intrinsic vec4 textureGrad(sampler2D tex, vec2 coord, vec2 dPdx, vec2 dPdy);\n\t\t\t\t\t//__intrinsic vec4 textureGrad(samplerCube tex, vec3 coord, vec3 dPdx, vec3 dPdy);\n\t\t\t\t\tctx.AddInstrTexture(\n\t\t\t\t\t\t(ILOperand*)instr,\n\t\t\t\t\t\tGetOperandValue(instr->Arguments[0].Ptr()),\n\t\t\t\t\t\tGetOperandValue(instr->Arguments[1].Ptr()),\n\t\t\t\t\t\tcurrentExecutionModel,\n\t\t\t\t\t\t-1,\t//Bias\n\t\t\t\t\t\tGetOperandValue(instr->Arguments[2].Ptr()),\n\t\t\t\t\t\tGetOperandValue(instr->Arguments[3].Ptr())\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (callName == \"textureProj\")\n\t\t\t\t{\n\t\t\t\t\tif (instr->Arguments[0]->Type->ToString() == \"sampler2DShadow\")\n\t\t\t\t\t{\n\t\t\t\t\t\t//__intrinsic float textureProj(sampler2DShadow tex, vec4 coord);\n\t\t\t\t\t\tctx.AddInstrTexture2DShadowProj(\n\t\t\t\t\t\t\t(ILOperand*)instr,\n\t\t\t\t\t\t\tGetOperandValue(instr->Arguments[0].Ptr()),\n\t\t\t\t\t\t\tGetOperandValue(instr->Arguments[1].Ptr()),\n\t\t\t\t\t\t\tcurrentExecutionModel\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t//------------------------- Dot Instruction ------------------------------\n\t\t\t\tif (callName == \"dot\"\n\t\t\t\t\t&& instr->Arguments.Count() == 2\n\t\t\t\t\t&& instr->Arguments[0]->Type->ToString() == instr->Arguments[1]->Type->ToString()\n\t\t\t\t\t&& instr->Arguments[0]->Type->IsFloatVector()\n\t\t\t\t\t&& !instr->Arguments[0]->Type->IsFloatMatrix())\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrDot(\n\t\t\t\t\t\t(ILOperand*)instr,\n\t\t\t\t\t\tinstr->Type,\n\t\t\t\t\t\tGetOperandValue(instr->Arguments[0].Ptr()),\n\t\t\t\t\t\tGetOperandValue(instr->Arguments[1].Ptr())\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t//------------------------- Transpose Instruction ------------------------------\n\t\t\t\tif (callName == \"transpose\" && instr->Arguments.Count() == 1 && instr->Arguments[0]->Type->IsFloatMatrix())\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrTranspose((ILOperand*)instr, instr->Type, GetOperandValue(instr->Arguments[0].Ptr()));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t//------------------------- Derivative Instruction -----------------------------\n\t\t\t\tif (callName == \"dFdx\")\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrDFdx((ILOperand*)instr, instr->Type, GetOperandValue(instr->Arguments[0].Ptr()));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\telse if (callName == \"dFdy\")\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrDFdy((ILOperand*)instr, instr->Type, GetOperandValue(instr->Arguments[0].Ptr()));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\telse if (callName == \"fwidth\")\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrFwidth((ILOperand*)instr, instr->Type, GetOperandValue(instr->Arguments[0].Ptr()));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t//------------------------- user-defined  instructions -------------------------\n\t\t\t\tint funcID;\n\t\t\t\tif (ctx.FunctionNameToFunctionID.TryGetValue(instr->Function, funcID))\n\t\t\t\t{\n\t\t\t\t\tRefPtr<ILType> returnType = ctx.IDInfos[\n\t\t\t\t\t\tctx.FunctionNameToFunctionTypeID[instr->Function]()\n\t\t\t\t\t]().GetFunc()->ReturnType;\n\t\t\t\t\t\tint typeID = ctx.DefineType(returnType);\n\t\t\t\t\t\tList<int> args;\n\t\t\t\t\t\tfor (auto & arg : instr->Arguments) {\n\t\t\t\t\t\t\tint valueID = GetOperandValue(arg.Ptr());\n\t\t\t\t\t\t\tint paramID = ctx.AddInstrVariableDeclaration(0, arg->Type, StorageClass::Function, \"param\");\n\t\t\t\t\t\t\t// the name of the parameter must be empty; or may conflict with non-param variables\n\t\t\t\t\t\t\tctx.AddInstrStore(0, paramID, valueID);\n\t\t\t\t\t\t\targs.Add(paramID);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tctx.AddInstrFunctionCall((ILOperand*)instr, typeID, funcID, args);\n\t\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t//------------------------- ext-import  instructions -----------------------------\n\t\t\t\tList<int> Arguments;\n\n\t\t\t\tfor (auto & arg : instr->Arguments) {\n\t\t\t\t\tint valueID = GetOperandValue(arg.Ptr());\n\t\t\t\t\tif (callName == \"mix\") {\n\t\t\t\t\t\t//the mix instruction in spirv only accept mix(vec_, vec_, vec_);\n\t\t\t\t\t\t//however, front end of SPIRE can accept mix(vec_, vec_, float);\n\t\t\t\t\t\tvalueID = ctx.ConvertBasicType(valueID, arg->Type, instr->Type);\n\t\t\t\t\t}\n\t\t\t\t\tArguments.Add(valueID);\n\t\t\t\t}\n\n\t\t\t\tif (GLSLstd450InstructionSet.ContainsKey(callName))\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrExtInst((ILOperand*)instr, instr->Type, GLSLstd450InstructionSet[callName](), Arguments);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\n\t\t\t\t//------------------------- built-in constructors -----------------------------\n\n\t\t\t\tRefPtr<ILType> dstType = GetTypeFromString(callName);\n\t\t\t\tif (dstType == nullptr)\n\t\t\t\t\tthrow InvalidOperationException(\"can not call: \" + callName);\n\t\t\t\tRefPtr<ILBasicType> dstBasicType = dstType;\n\n\t\t\t\tif (instr->Arguments.Count() > 1)\n\t\t\t\t{\n\t\t\t\t\t//composite\n\t\t\t\t\tfor (auto & ID : Arguments)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto argBasicType = dynamic_cast<ILBasicType*>((ctx.IDInfos[ID]().GetILType()).Ptr());\n\t\t\t\t\t\tif (argBasicType)\n\t\t\t\t\t\t\tif (argBasicType->IsIntegral() != dstType->IsIntegral())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tRefPtr<ILType> argDstType = new ILBasicType(ILBaseType((dstBasicType->Type & ~15) + (argBasicType->Type & 15)));\n\t\t\t\t\t\t\t\tID = ctx.ConvertBasicType(ID, ctx.IDInfos[ID]().GetILType(), argDstType);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (instr->Type->IsFloatMatrix() &&\n\t\t\t\t\t\t(Arguments.Count() == 0 || (Arguments.Count() > 0 && ctx.IDInfos[Arguments[0]]().GetILType()->IsScalar())))\n\t\t\t\t\t{\n\t\t\t\t\t\t//need to arrange scalars into vectors\n\t\t\t\t\t\tint n = (int)sqrt((float)instr->Type->GetVectorSize() + 1e-6);\n\t\t\t\t\t\tint diff = n * n - Arguments.Count();\n\t\t\t\t\t\tif (diff > 0)\n\t\t\t\t\t\t\tfor (int i = 0; i < diff; i++)\n\t\t\t\t\t\t\t\tArguments.Add(ctx.AddInstrConstantFloat(0.0));\n\t\t\t\t\t\tList<int> newArguments;\n\t\t\t\t\t\tRefPtr<ILType> vectorType = new ILBasicType(ILBaseType(ILBaseType::Float + n - 1));\n\t\t\t\t\t\tfor (int i = 0; i < n; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tList<int> subArguments;\n\t\t\t\t\t\t\tfor (int j = 0; j < n; j++)\n\t\t\t\t\t\t\t\tsubArguments.Add(Arguments[i*n + j]);\n\t\t\t\t\t\t\tnewArguments.Add(ctx.AddInstrCompositeConstruct(0, vectorType, subArguments));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tArguments = newArguments;\n\t\t\t\t\t}\n\n\t\t\t\t\tctx.AddInstrCompositeConstruct((ILOperand*)instr, instr->Type, Arguments);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t//need conversion\n\t\t\t\t\tint ID = Arguments[0];\n\t\t\t\t\tID = ctx.ConvertBasicType(ID, ctx.IDInfos[ID]().GetILType(), dstType);\n\t\t\t\t\tctx.UpdateValue((ILOperand*)instr, ID);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvoid PrintUnaryInstr(UnaryInstruction * instr)\n\t\t\t{\n\t\t\t\tauto op0 = instr->Operand.Ptr();\n\t\t\t\tif (instr->Is<LoadInstruction>())\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrLoad((ILOperand*)instr, op0, MemoryAccess::None);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (instr->Is<NotInstruction>())\n\t\t\t\t\tinstr->Type = GetTypeFromString(\"bool\");\n\n\t\t\t\tint op0ValueID = GetOperandValue(op0);\n\t\t\t\top0ValueID = ctx.ConvertBasicType(op0ValueID, ctx.IDInfos[op0ValueID]().GetILType(), instr->Type);\n\t\t\t\tRefPtr<ILType> op0ILType = ctx.IDInfos[op0ValueID]().GetILType();\n\n\t\t\t\tif (instr->Is<Float2IntInstruction>() || instr->Is<Int2FloatInstruction>() || instr->Is<CopyInstruction>())\n\t\t\t\t{\n\t\t\t\t\tctx.UpdateValue((ILOperand*)instr, op0ValueID);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tint instrTypeID = ctx.DefineType(instr->Type);\n\n\t\t\t\tif (instr->Is<NegInstruction>())\n\t\t\t\t{\n\t\t\t\t\tif (op0ILType->IsFloat() || op0ILType->IsFloatVector())\n\t\t\t\t\t\tctx.AddInstrFnegate((ILOperand*)instr, instrTypeID, op0ValueID);\n\t\t\t\t\telse if (op0ILType->IsInt() || op0ILType->IsIntVector())\n\t\t\t\t\t\tctx.AddInstrSnegate((ILOperand*)instr, instrTypeID, op0ValueID);\n\t\t\t\t\telse if (op0ILType->IsUInt() || op0ILType->IsUIntVector())\n\t\t\t\t\t\tthrow InvalidOperationException(\"trying to negate a uint in PrintUnaryInstruction(): \" + instr->ToString());\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<BitNotInstruction>())\n\t\t\t\t\tctx.AddInstrNot((ILOperand*)instr, instrTypeID, op0ValueID);\n\t\t\t\telse if (instr->Is<NotInstruction>())\n\t\t\t\t\tctx.AddInstrLogicalNot((ILOperand*)instr, instrTypeID, op0ValueID);\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidProgramException(\"unsupported unary instruction.\");\n\t\t\t}\n\n\t\t\tvoid PrintBinaryInstr(BinaryInstruction * instr)\n\t\t\t{\n\t\t\t\tauto op0 = instr->Operands[0].Ptr();\n\t\t\t\tauto op1 = instr->Operands[1].Ptr();\n\n\t\t\t\t//-------------------------------------Store Instruction------------------------------------------\n\t\t\t\tif (instr->Is<StoreInstruction>())\n\t\t\t\t{\n\t\t\t\t\tif (auto structType = dynamic_cast<ILStructType*>(op0->Type.Ptr()))\n\t\t\t\t\t{\n\t\t\t\t\t\tint op0ID = ctx.FindVariableID(op0);\n\t\t\t\t\t\tint op1ID = ctx.FindVariableID(op1);\n\t\t\t\t\t\tint index = 0;\n\t\t\t\t\t\tfor (int i = 0; i < structType->Members.Count(); i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint indexID = ctx.AddInstrConstantInt(index);\n\t\t\t\t\t\t\tint dest = ctx.AddInstrAccessChain_StructMember(0, op0ID, indexID, index);\n\t\t\t\t\t\t\tint pSrc = ctx.AddInstrAccessChain_StructMember(0, op1ID, indexID, index);\n\t\t\t\t\t\t\tint vSrc = ctx.AddInstrLoad(pSrc, MemoryAccess::None);\n\t\t\t\t\t\t\tctx.AddInstrStore(0, dest, vSrc);\n\t\t\t\t\t\t\tindex++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tint op0ID = ctx.FindVariableID(op0); // should be a pointer \n\t\t\t\t\tint op1ID = GetOperandValue(op1);\n\t\t\t\t\top1ID = ctx.ConvertBasicType(op1ID, ctx.IDInfos[op1ID]().GetILType(), ctx.IDInfos[op0ID]().GetILType());\n\t\t\t\t\tctx.AddInstrStore(instr, op0ID, op1ID); //TO FIX\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t//----------------------------------Member Load Instruction---------------------------------------\n\t\t\t\tif (instr->Is<MemberLoadInstruction>())\n\t\t\t\t{\n\t\t\t\t\tint fatherID = GetOperandPointer(op0);\n\t\t\t\t\tif (op0->Type->IsVector())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (auto c = dynamic_cast<ILConstOperand*>(op1))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//if op1 is constant, take that as index of vector \n\t\t\t\t\t\t\tint memberID = ctx.AddInstrAccessChain_VectorMember((ILOperand*)instr, fatherID, -1, c->IntValues[0]);\n\t\t\t\t\t\t\tint retID = ctx.AddInstrLoad(memberID, MemoryAccess::None);\n\t\t\t\t\t\t\tctx.UpdateValue((ILOperand*)instr, retID);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//if op1 is not constant, compute it\n\t\t\t\t\t\t\tint memberID = ctx.AddInstrAccessChain_VectorMember((ILOperand*)instr, fatherID, GetOperandValue(op1), -1);\n\t\t\t\t\t\t\tint retID = ctx.AddInstrLoad(memberID, MemoryAccess::None);\n\t\t\t\t\t\t\tctx.UpdateValue((ILOperand*)instr, retID);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (auto structType = dynamic_cast<ILStructType*>(op0->Type.Ptr()))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (auto c = dynamic_cast<ILConstOperand*>(op1))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//index of struct must be constant\n\t\t\t\t\t\t\tint indexID = GetOperandValue(c);\n\t\t\t\t\t\t\tint memberID = ctx.AddInstrAccessChain_StructMember((ILOperand*)instr, fatherID, indexID, c->IntValues[0]);\n\t\t\t\t\t\t\tint retID = ctx.AddInstrLoad(memberID, MemoryAccess::None);\n\t\t\t\t\t\t\tctx.UpdateValue((ILOperand*)instr, retID);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tthrow InvalidOperationException(\"wrong: \" + instr->ToString());\n\t\t\t\t\t}\n\t\t\t\t\telse if (auto arrayType = dynamic_cast<ILArrayType*>(op0->Type.Ptr()))\n\t\t\t\t\t{\n\t\t\t\t\t\tint memberID = ctx.AddInstrAccessChain_ArrayMember((ILOperand*)instr, op0->Type, fatherID, GetOperandValue(op1));\n\t\t\t\t\t\tint retID = ctx.AddInstrLoad(memberID, MemoryAccess::None);\n\t\t\t\t\t\tctx.UpdateValue((ILOperand*)instr, retID);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow InvalidOperationException(\"wrong op0 type for MemberLoadInstruction(): \" + op0->Type->ToString());\n\t\t\t\t}\n\n\t\t\t\tint ID0 = GetOperandValue(op0);\n\t\t\t\tint ID1 = GetOperandValue(op1);\n\t\t\t\tRefPtr<ILType> ID0Type = ctx.IDInfos[ID0]().GetILType();\n\t\t\t\tRefPtr<ILType> ID1Type = ctx.IDInfos[ID1]().GetILType();\n\n\t\t\t\t//----------------------------------Vec/Mat Multiplication---------------------------------------\n\t\t\t\tif (instr->Is<MulInstruction>())\n\t\t\t\t{\n\t\t\t\t\t//scalar X matrix or matrix X scalar\n\t\t\t\t\tif (ID0Type->IsScalar() && ID1Type->IsFloatMatrix() ||\n\t\t\t\t\t\tID1Type->IsScalar() && ID0Type->IsFloatMatrix())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ID1Type->IsFloatMatrix())\n\t\t\t\t\t\t\tSwap(ID0, ID1);\n\t\t\t\t\t\t//now ID0 is matrix, ID1 is scalar, \n\t\t\t\t\t\tID1 = ctx.ConvertBasicType(ID1, ctx.IDInfos[ID1]().GetILType(), GetTypeFromString(\"float\"));\n\t\t\t\t\t\tctx.AddInstrMatrixTimesScalar((ILOperand*)instr, ID0, ID1);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t//vector X matrix\n\t\t\t\t\tif (ID0Type->IsFloatVector() && !ID0Type->IsFloatMatrix() && ID1Type->IsFloatMatrix())\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.AddInstrVectorTimesMatrix((ILOperand*)instr, ID0, ID1);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t//matrix X vector\n\t\t\t\t\tif (ID1Type->IsFloatVector() && !ID1Type->IsFloatMatrix() && ID0Type->IsFloatMatrix())\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.AddInstrMatrixTimesVector((ILOperand*)instr, ID0, ID1);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t//matrix X matrix\n\t\t\t\t\tif (ID0Type->IsFloatMatrix() && ID1Type->IsFloatMatrix())\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.AddInstrMatrixTimesMatrix((ILOperand*)instr, ID0, ID1);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t//---------------------------------Boolean-Related Instruction---------------------------------------\n\t\t\t\tbool ResultIsLogical =\n\t\t\t\t\tinstr->Is<OrInstruction>() || instr->Is<AndInstruction>() ||\n\t\t\t\t\tinstr->Is<CmpeqlInstruction>() || instr->Is<CmpgeInstruction>() || instr->Is<CmpgtInstruction>() ||\n\t\t\t\t\tinstr->Is<CmpleInstruction>() || instr->Is<CmpltInstruction>() || instr->Is<CmpneqInstruction>();\n\n\t\t\t\tif (dynamic_cast<ILBasicType*>(instr->Type.Ptr())->Type == 0)\n\t\t\t\t{\n\t\t\t\t\tinstr->Type = ID0Type;\n\t\t\t\t}\n\n\t\t\t\tif (ResultIsLogical)\n\t\t\t\t{\n\t\t\t\t\tRefPtr<ILType> OperandType = nullptr;\n\t\t\t\t\tif (instr->Is<OrInstruction>() || instr->Is<AndInstruction>())\n\t\t\t\t\t{\n\t\t\t\t\t\tOperandType = GetTypeFromString(\"bool\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ID0Type->IsFloat() || ID1Type->IsFloat())\n\t\t\t\t\t\t\tOperandType = GetTypeFromString(\"float\");\n\t\t\t\t\t\telse if (ID0Type->IsUInt() || ID1Type->IsUInt())\n\t\t\t\t\t\t\tOperandType = GetTypeFromString(\"uint\");\n\t\t\t\t\t\telse if (ID0Type->IsInt() || ID1Type->IsInt())\n\t\t\t\t\t\t\tOperandType = GetTypeFromString(\"int\");\n\t\t\t\t\t}\n\n\t\t\t\t\tID0 = ctx.ConvertBasicType(ID0, ID0Type, OperandType);\n\t\t\t\t\tID1 = ctx.ConvertBasicType(ID1, ID1Type, OperandType);\n\n\t\t\t\t\tinstr->Type = GetTypeFromString(\"bool\");\n\t\t\t\t\tID0Type = ctx.IDInfos[ID0]().GetILType();\n\t\t\t\t\tID1Type = ctx.IDInfos[ID1]().GetILType();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tID0 = ctx.ConvertBasicType(ID0, ID0Type, instr->Type);\n\t\t\t\t\tID1 = ctx.ConvertBasicType(ID1, ID1Type, instr->Type);\n\n\t\t\t\t\tID0Type = ctx.IDInfos[ID0]().GetILType();\n\t\t\t\t\tID1Type = ctx.IDInfos[ID1]().GetILType();\n\t\t\t\t}\n\n\t\t\t\t//--------------------------------------Get Binary Operator String---------------------------------------\n\t\t\t\tString opStr;\n\t\t\t\tbool needPrefix = false;\n\t\t\t\tbool Signed = false;\n\t\t\t\tif (instr->Is<MulInstruction>())\n\t\t\t\t{\n\t\t\t\t\topStr = \"Mu\";\n\t\t\t\t\tneedPrefix = true;\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<AddInstruction>())\n\t\t\t\t{\n\t\t\t\t\topStr = \"Add\";\n\t\t\t\t\tneedPrefix = true;\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<DivInstruction>())\n\t\t\t\t{\n\t\t\t\t\topStr = \"Div\";\n\t\t\t\t\tneedPrefix = true;\n\t\t\t\t\tSigned = true;\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<SubInstruction>())\n\t\t\t\t{\n\t\t\t\t\topStr = \"Sub\";\n\t\t\t\t\tneedPrefix = true;\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<ModInstruction>())\n\t\t\t\t{\n\t\t\t\t\topStr = \"Mod\";\n\t\t\t\t\tneedPrefix = true;\n\t\t\t\t\tSigned = true;\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<ShlInstruction>())\n\t\t\t\t{\n\t\t\t\t\topStr = \"ShiftLeftLogica\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<ShrInstruction>())\n\t\t\t\t{\n\t\t\t\t\tif (ID0Type->IsUInt() || ID0Type->IsUIntVector())\n\t\t\t\t\t\topStr = \"ShiftRightLogica\";\n\t\t\t\t\telse\n\t\t\t\t\t\topStr = \"ShiftRightArithmetic\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<BitXorInstruction>())\n\t\t\t\t{\n\t\t\t\t\topStr = \"BitwiseXor\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<BitAndInstruction>())\n\t\t\t\t{\n\t\t\t\t\topStr = \"BitwiseAnd\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<BitOrInstruction>())\n\t\t\t\t{\n\t\t\t\t\topStr = \"BitwiseOr\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<AndInstruction>())\n\t\t\t\t{\n\t\t\t\t\topStr = \"LogicalAnd\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<OrInstruction>())\n\t\t\t\t{\n\t\t\t\t\topStr = \"LogicalOr\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<CmpneqInstruction>())\n\t\t\t\t{\n\t\t\t\t\tif (ID0Type->IsIntegral())\n\t\t\t\t\t\topStr = \"INotEqua\";\n\t\t\t\t\telse\n\t\t\t\t\t\topStr = \"FOrdNotEqua\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<CmpeqlInstruction>())\n\t\t\t\t{\n\t\t\t\t\tif (ID0Type->IsIntegral())\n\t\t\t\t\t\topStr = \"IEqua\";\n\t\t\t\t\telse\n\t\t\t\t\t\topStr = \"FOrdEqua\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<CmpgeInstruction>())\n\t\t\t\t{\n\t\t\t\t\tif (ID0Type->IsIntegral())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ID0Type->IsUInt() || ID0Type->IsUIntVector())\n\t\t\t\t\t\t\topStr = \"UGreaterThanEqua\";\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\topStr = \"SGreaterThanEqua\";\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\topStr = \"FOrdGreaterThanEqua\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<CmpgtInstruction>())\n\t\t\t\t{\n\t\t\t\t\tif (ID0Type->IsIntegral())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ID0Type->IsUInt() || ID0Type->IsUIntVector())\n\t\t\t\t\t\t\topStr = \"UGreaterThan\";\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\topStr = \"SGreaterThan\";\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\topStr = \"FOrdGreaterThan\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<CmpleInstruction>())\n\t\t\t\t{\n\t\t\t\t\tif (ID0Type->IsIntegral())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ID0Type->IsUInt() || ID0Type->IsUIntVector())\n\t\t\t\t\t\t\topStr = \"ULessThanEqua\";\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\topStr = \"SLessThanEqua\";\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\topStr = \"FOrdLessThanEqua\";\n\t\t\t\t}\n\t\t\t\telse if (instr->Is<CmpltInstruction>())\n\t\t\t\t{\n\t\t\t\t\tif (ID0Type->IsIntegral())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ID0Type->IsUInt() || ID0Type->IsUIntVector())\n\t\t\t\t\t\t\topStr = \"ULessThan\";\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\topStr = \"SLessThan\";\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\topStr = \"FOrdLessThan\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidProgramException(\"unsupported binary instruction: \" + instr->ToString());\n\n\t\t\t\t//---------------------------------------Generate Instrction---------------------------------------\n\n\t\t\t\tString finalOpStr = LR\"(Op)\";\n\t\t\t\tif (needPrefix)\n\t\t\t\t{\n\t\t\t\t\tif (ID0Type->IsFloat() || ID0Type->IsFloatVector())\n\t\t\t\t\t\tfinalOpStr = finalOpStr + LR\"(F)\";\n\t\t\t\t\telse if (ID0Type->IsIntegral())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (Signed)\n\t\t\t\t\t\t\tfinalOpStr = finalOpStr + LR\"(S)\";\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tfinalOpStr = finalOpStr + LR\"(I)\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfinalOpStr = finalOpStr + opStr;\n\n\t\t\t\tctx.AddInstrBinaryInstr((ILOperand*)instr, instr->Type, finalOpStr, ID0, ID1);\n\t\t\t}\n\n\t\t\tvoid PrintUpdateInstr(MemberUpdateInstruction * instr)\n\t\t\t{\n\t\t\t\tint variableID = ctx.AddInstrVariableDeclaration((ILOperand*)instr, instr->Operands[0]->Type, StorageClass::Function);\n\t\t\t\tctx.AddInstrStore((ILOperand*)instr, variableID, GetOperandValue(instr->Operands[0].Ptr()));\n\n\t\t\t\tauto typeIL = ctx.IDInfos[variableID]().GetILType().Ptr();\n\t\t\t\tint memberID = -1;\n\t\t\t\tint indexID = GetOperandValue(instr->Operands[1].Ptr());\n\n\t\t\t\tif (indexID == -1)\n\t\t\t\t\tthrow InvalidOperationException(\"bad index in PrintUpdateInstr(): \" + instr->Operands[1]->ToString());\n\n\t\t\t\tif (auto structType = dynamic_cast<ILStructType*>(typeIL))\n\t\t\t\t{\n\t\t\t\t\tauto c = dynamic_cast<ILConstOperand*>(instr->Operands[1].Ptr());\n\t\t\t\t\tif (c)\n\t\t\t\t\t\tmemberID = ctx.AddInstrAccessChain_StructMember(0, variableID, indexID, c->IntValues[0]);\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow InvalidOperationException(\"index of struct must be const in PrintUpdateInstr(): \" + instr->Operands[1]->ToString());\n\t\t\t\t}\n\t\t\t\telse if (auto arrayType = dynamic_cast<ILArrayType*>(typeIL))\n\t\t\t\t{\n\t\t\t\t\tmemberID = ctx.AddInstrAccessChain_ArrayMember(0, typeIL, variableID, indexID);\n\t\t\t\t}\n\t\t\t\telse if (auto vecType = dynamic_cast<ILBasicType*>(typeIL))\n\t\t\t\t{\n\t\t\t\t\tif (!typeIL->IsVector())\n\t\t\t\t\t\tthrow InvalidOperationException(\"unable to update members of type: \" + typeIL->ToString());\n\t\t\t\t\tmemberID = ctx.AddInstrAccessChain_VectorMember(0, variableID, indexID, -1);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"not supported type in PrintUpdateInstr(): \" + typeIL->ToString());\n\n\t\t\t\tctx.AddInstrStore(\n\t\t\t\t\t0,\n\t\t\t\t\tmemberID,\n\t\t\t\t\tGetOperandValue(instr->Operands[2].Ptr())\n\t\t\t\t);\n\t\t\t\tctx.InvalidateValue((ILOperand*)instr);\n\t\t\t}\n\n\t\t\tvoid PrintSelectInstr(SelectInstruction * instr)\n\t\t\t{\n\t\t\t\tint ID0 = GetOperandValue(instr->Operands[0].Ptr());\n\t\t\t\tID0 = ctx.ConvertBasicType(\n\t\t\t\t\tID0,\n\t\t\t\t\tctx.IDInfos[ID0]().GetILType(),\n\t\t\t\t\tGetTypeFromString(\"bool\"));\n\n\t\t\t\tint TrueLabel = ++ctx.CurrentID;\n\t\t\t\tint FalseLabel = ++ctx.CurrentID;\n\t\t\t\tint MergeLabel = ++ctx.CurrentID;\n\n\t\t\t\tctx.AddInstrSelectionMerge(MergeLabel);\n\t\t\t\tctx.AddInstrBranchConditional(ID0, TrueLabel, FalseLabel);\n\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(TrueLabel);\n\t\t\t\tint ID1 = GetOperandValue(instr->Operands[1].Ptr());\n\t\t\t\tID1 = ctx.ConvertBasicType(ID1, ctx.IDInfos[ID1]().GetILType(), instr->Type);\n\t\t\t\tctx.AddInstrBranch(MergeLabel);\n\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(FalseLabel);\n\t\t\t\tint ID2 = GetOperandValue(instr->Operands[2].Ptr());\n\t\t\t\tID2 = ctx.ConvertBasicType(ID2, ctx.IDInfos[ID2]().GetILType(), instr->Type);\n\t\t\t\tctx.AddInstrBranch(MergeLabel);\n\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(MergeLabel);\n\n\t\t\t\tctx.AddInstrPhi((ILOperand*)instr, ID1, TrueLabel, ID2, FalseLabel);\n\t\t\t}\n\n\t\t\tvoid PrintFetchArgInstr(FetchArgInstruction * instr)\n\t\t\t{\n\t\t\t\tif (instr->ArgId == 0)\n\t\t\t\t{\n\t\t\t\t\tctx.ReturnID = ctx.AddInstrVariableDeclaration((ILOperand*)instr, instr->Type, StorageClass::Function);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid PrintExportInstr(ExportInstruction * instr)\n\t\t\t{\n\t\t\t\tString exportOpName = instr->ExportOperator;\n\n\t\t\t\tif (exportOpName == \"fragmentExport\")\n\t\t\t\t{\n\t\t\t\t\tCompiledComponent ccomp;\n\t\t\t\t\tbool isNormal = false;\n\t\t\t\t\tbool isDepthOutput = false;\n\t\t\t\t\tif (currentWorld->LocalComponents.TryGetValue(instr->ComponentName, ccomp))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ccomp.Attributes.ContainsKey(\"Norma\"))\n\t\t\t\t\t\t\tisNormal = true;\n\t\t\t\t\t\tif (ccomp.Attributes.ContainsKey(\"DepthOutput\"))\n\t\t\t\t\t\t\tisDepthOutput = true;\n\t\t\t\t\t}\n\t\t\t\t\tString exportName;\n\t\t\t\t\tif (isDepthOutput)\n\t\t\t\t\t\texportName = \"gl_FragDepth\";\n\t\t\t\t\telse\n\t\t\t\t\t\texportName = instr->ComponentName;\n\n\t\t\t\t\tint exportID = ctx.InterfaceNameToID[exportName];\n\t\t\t\t\tif (exportID == -1)\n\t\t\t\t\t\tthrow InvalidOperationException(\"can not find component for export instruction for fragmentExport in PrintExportInstr(): \" + exportName);\n\n\t\t\t\t\tint operandID = GetOperandValue(instr->Operand.Ptr());\n\t\t\t\t\tif (isNormal)\n\t\t\t\t\t\toperandID = ctx.AddInstrMulAdd(operandID, 0.5, 0.5);\n\n\t\t\t\t\tctx.AddInstrStore((ILOperand*)instr, exportID, operandID);\n\t\t\t\t}\n\n\t\t\t\telse if (exportOpName == \"standardExport\")\n\t\t\t\t{\n\t\t\t\t\tint storeID = ctx.AddInstrAccessChain_StructMember(0, ctx.InterfaceNameToID[\"blk\" + currentWorld->WorldOutput->Name], instr->ComponentName);\n\t\t\t\t\tctx.AddInstrStore((ILOperand*)instr, storeID, GetOperandValue(instr->Operand.Ptr()));\n\t\t\t\t}\n\n\t\t\t\telse if (exportOpName == \"bufferExport\")\n\t\t\t\t{\n\t\t\t\t\tauto & comp = currentWorld->WorldOutput->Entries[instr->ComponentName]();\n\n\t\t\t\t\tauto UIntType = GetTypeFromString(\"uint\");\n\t\t\t\t\tauto FloatType = GetTypeFromString(\"float\");\n\t\t\t\t\tint GIIDx = ctx.AddInstrLoad(\n\t\t\t\t\t\tctx.AddInstrAccessChain_VectorMember(0, ctx.InterfaceNameToID[\"gl_GlobalInvocationID\"], -1, 0),\n\t\t\t\t\t\tMemoryAccess::None\n\t\t\t\t\t);\t//GlobalInvocationID.x\n\t\t\t\t\tint baseIndex = ctx.AddInstrBinaryInstr(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tUIntType,\n\t\t\t\t\t\t\"OpIMu\",\n\t\t\t\t\t\tGIIDx,\n\t\t\t\t\t\tctx.AddInstrConstantUInt(currentWorld->WorldOutput->Size / 4)\n\t\t\t\t\t);\n\t\t\t\t\tbaseIndex = ctx.AddInstrBinaryInstr(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tUIntType,\n\t\t\t\t\t\t\"OpIAdd\",\n\t\t\t\t\t\tbaseIndex,\n\t\t\t\t\t\tctx.AddInstrConstantUInt(comp.Offset / 4)\n\t\t\t\t\t);\n\n\t\t\t\t\tRefPtr<ILType> compElementType =\n\t\t\t\t\t\t(!comp.Type->IsIntegral())\n\t\t\t\t\t\t? FloatType\n\t\t\t\t\t\t: ((comp.Type->IsUInt() || comp.Type->IsUIntVector()) ? UIntType : GetTypeFromString(\"int\"));\n\n\t\t\t\t\tfor (int i = 0; i < comp.Type->GetVectorSize(); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tint index = ctx.AddInstrBinaryInstr(\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tUIntType,\n\t\t\t\t\t\t\t\"OpIAdd\",\n\t\t\t\t\t\t\tbaseIndex,\n\t\t\t\t\t\t\tctx.AddInstrConstantUInt(i)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tint blockID = ctx.InterfaceNameToID[\"blk\" + currentWorld->WorldOutput->Name];\n\t\t\t\t\t\tint arrayID = ctx.AddInstrAccessChain_StructMember(0, blockID, -1, 0);\n\t\t\t\t\t\tint storeID = ctx.AddInstrAccessChain_ArrayMember(\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tctx.IDInfos[arrayID]().GetILType(),\n\t\t\t\t\t\t\tarrayID,\n\t\t\t\t\t\t\tindex\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tint valueID = -1;\n\t\t\t\t\t\tif (instr->Operand->Type->GetVectorSize() > 1)\n\t\t\t\t\t\t\tvalueID = ctx.AddInstrLoad(\n\t\t\t\t\t\t\t\tctx.AddInstrAccessChain_VectorMember(0, GetOperandPointer(instr->Operand.Ptr()), -1, i),\n\t\t\t\t\t\t\t\tMemoryAccess::None\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tvalueID = ctx.AddInstrLoad(\n\t\t\t\t\t\t\t\tGetOperandPointer(instr->Operand.Ptr()),\n\t\t\t\t\t\t\t\tMemoryAccess::None\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\tvalueID = ctx.ConvertBasicType(valueID, ctx.IDInfos[valueID]().GetILType(), compElementType);\n\n\t\t\t\t\t\tif (ctx.IDInfos[valueID]().GetILType()->IsIntegral())\n\t\t\t\t\t\t\tvalueID = ctx.AddInstrBitcast(ctx.DefineType(FloatType), valueID);\n\n\t\t\t\t\t\tctx.AddInstrStore(0, storeID, valueID);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\telse\n\t\t\t\t\tthrow InvalidOperationException(\"not valid export operator in PrintExportInstr(): \" + exportOpName);\n\t\t\t}\n\n\t\t\tvoid PrintImportInstr(ImportInstruction * instr)\n\t\t\t{\n\t\t\t\tauto block = instr->SourceWorld->WorldOutput;\n\n\t\t\t\tif (instr->ImportOperator->Name.Content == \"standardImport\")\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrAccessChain_StructMember(instr, ctx.InterfaceNameToID[\"blk\" + block->Name], instr->ComponentName);\n\t\t\t\t}\n\n\t\t\t\telse if (instr->ImportOperator->Name.Content == \"vertexImport\")\n\t\t\t\t{\n\t\t\t\t\tint componentID = ctx.InterfaceNameToID[instr->ComponentName];\n\t\t\t\t\tif (componentID == -1)\n\t\t\t\t\t\tthrow InvalidOperationException(\"can not find import component for vertexImport in PrintImportInstr(): \" + instr->ComponentName);\n\t\t\t\t\tctx.UpdateVariable(instr, componentID);\n\t\t\t\t}\n\n\t\t\t\telse if (instr->ImportOperator->Name.Content == \"uniformImport\")\n\t\t\t\t{\n\t\t\t\t\tif (instr->Type->IsTexture())\n\t\t\t\t\t{\n\t\t\t\t\t\tint pointerID = ctx.InterfaceNameToID[instr->ComponentName];\n\t\t\t\t\t\tif (pointerID == -1)\n\t\t\t\t\t\t\tthrow InvalidOperationException(\"can not find import component for uniformImport in PrintImportInstr(): \" + instr->ComponentName);\n\t\t\t\t\t\tctx.UpdateVariable(instr, pointerID);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.AddInstrAccessChain_StructMember(instr, ctx.InterfaceNameToID[\"blk\" + block->Name], instr->ComponentName);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\telse if (instr->ImportOperator->Name.Content == \"textureImport\")\n\t\t\t\t{\n\t\t\t\t\tint textureStorageID = ctx.InterfaceNameToID[instr->ComponentName];\n\t\t\t\t\tint textureValueID = ctx.AddInstrLoad(textureStorageID, MemoryAccess::None);\n\n\t\t\t\t\tint operandID = -1;\n\t\t\t\t\toperandID = ctx.AddInstrTexture(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\ttextureValueID,\n\t\t\t\t\t\tGetOperandValue(instr->Arguments[0].Ptr()),\n\t\t\t\t\t\tcurrentExecutionModel\n\t\t\t\t\t);\n\n\t\t\t\t\toperandID = ctx.ConvertBasicType(\n\t\t\t\t\t\toperandID,\n\t\t\t\t\t\tctx.IDInfos[operandID]().GetILType(),\n\t\t\t\t\t\tinstr->Type);\n\t\t\t\t\tCompiledComponent ccomp;\n\t\t\t\t\tif (instr->SourceWorld->LocalComponents.TryGetValue(instr->ComponentName, ccomp))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ccomp.Attributes.ContainsKey(\"Norma\"))\n\t\t\t\t\t\t\toperandID = ctx.AddInstrMulAdd(operandID, 2.0, -1.0);\n\t\t\t\t\t}\n\n\t\t\t\t\tint storeID = ctx.AddInstrVariableDeclaration((ILOperand*)instr, instr->Type, StorageClass::Function);\n\t\t\t\t\tctx.AddInstrStore((ILOperand*)instr, storeID, operandID);\n\t\t\t\t}\n\n\t\t\t\telse if (instr->ImportOperator->Name.Content == \"bufferImport\")\n\t\t\t\t{\n\t\t\t\t\t//instr->Name[][] = \n\t\t\t\t\t//\t*(int*/float*) \n\t\t\t\t\t//\t( block->Name + block->Entries[instr->ComponentName].GetValue().Offset / 4 + i + gl_GlobalInvocationID.x * block->Size / 4 )\n\n\t\t\t\t\tauto UIntType = GetTypeFromString(\"uint\");\n\t\t\t\t\tauto FloatType = GetTypeFromString(\"float\");\n\t\t\t\t\tint GIIDx = ctx.AddInstrLoad(\n\t\t\t\t\t\tctx.AddInstrAccessChain_VectorMember(0, ctx.InterfaceNameToID[\"gl_GlobalInvocationID\"], -1, 0),\n\t\t\t\t\t\tMemoryAccess::None\n\t\t\t\t\t);\t//GlobalInvocationID.x\n\t\t\t\t\tint baseIndex = ctx.AddInstrBinaryInstr(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tUIntType,\n\t\t\t\t\t\t\"OpIMu\",\n\t\t\t\t\t\tGIIDx,\n\t\t\t\t\t\tctx.AddInstrConstantUInt(block->Size / 4)\n\t\t\t\t\t);\n\t\t\t\t\tbaseIndex = ctx.AddInstrBinaryInstr(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tUIntType,\n\t\t\t\t\t\t\"OpIAdd\",\n\t\t\t\t\t\tbaseIndex,\n\t\t\t\t\t\tctx.AddInstrConstantUInt(block->Entries[instr->ComponentName]().Offset / 4)\n\t\t\t\t\t);\n\n\t\t\t\t\tRefPtr<ILType> instrElementType =\n\t\t\t\t\t\t(!instr->Type->IsIntegral())\n\t\t\t\t\t\t? FloatType\n\t\t\t\t\t\t: ((instr->Type->IsUInt() || instr->Type->IsUIntVector()) ? UIntType : GetTypeFromString(\"int\"));\n\n\t\t\t\t\tint vecSize = instr->Type->GetVectorSize();\n\t\t\t\t\tint srcIDs[16];\n\t\t\t\t\tfor (int i = 0; i < vecSize; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tint index = ctx.AddInstrBinaryInstr(\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tUIntType,\n\t\t\t\t\t\t\t\"OpIAdd\",\n\t\t\t\t\t\t\tbaseIndex,\n\t\t\t\t\t\t\tctx.AddInstrConstantUInt(i)\n\t\t\t\t\t\t);\n\t\t\t\t\t\tint blockID = ctx.InterfaceNameToID[\"blk\" + block->Name];\n\t\t\t\t\t\tint arrayID = ctx.AddInstrAccessChain_StructMember(0, blockID, -1, 0);\n\t\t\t\t\t\tint srcID = ctx.AddInstrLoad(\n\t\t\t\t\t\t\tctx.AddInstrAccessChain_ArrayMember(0, ctx.IDInfos[arrayID]().GetILType(), arrayID, index),\n\t\t\t\t\t\t\tMemoryAccess::None\n\t\t\t\t\t\t);\n\t\t\t\t\t\tsrcIDs[i] = ctx.AddInstrBitcast(ctx.DefineType(instrElementType), srcID);\n\t\t\t\t\t}\n\n\t\t\t\t\tint valueID = -1;\n\n\t\t\t\t\tif (instr->Type->IsFloatMatrix())\n\t\t\t\t\t{\n\t\t\t\t\t\tint n = 3;\n\t\t\t\t\t\tauto colType = GetTypeFromString(\"vec3\");\n\t\t\t\t\t\tif (instr->Type->GetVectorSize() == 16)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tn = 4;\n\t\t\t\t\t\t\tcolType = GetTypeFromString(\"vec4\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tint colIDs[4];\n\t\t\t\t\t\tfor (int i = 0; i < n; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tList<int> args;\n\t\t\t\t\t\t\tfor (int j = 0; j < n; j++)\n\t\t\t\t\t\t\t\targs.Add(srcIDs[i*n + j]);\n\t\t\t\t\t\t\tcolIDs[i] = ctx.AddInstrCompositeConstruct(0, colType, args);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tList<int> args;\n\t\t\t\t\t\tfor (int i = 0; i < n; i++)\n\t\t\t\t\t\t\targs.Add(colIDs[i]);\n\t\t\t\t\t\tvalueID = ctx.AddInstrCompositeConstruct(0, instr->Type, args);\n\t\t\t\t\t}\n\t\t\t\t\telse if (instr->Type->IsVector())\n\t\t\t\t\t{\n\t\t\t\t\t\tint n = 3;\n\t\t\t\t\t\tif (instr->Type->GetVectorSize() == 16)\n\t\t\t\t\t\t\tn = 4;\n\t\t\t\t\t\tList<int> args;\n\t\t\t\t\t\tfor (int i = 0; i < n; i++)\n\t\t\t\t\t\t\targs.Add(srcIDs[i]);\n\t\t\t\t\t\tvalueID = ctx.AddInstrCompositeConstruct(0, instr->Type, args);\n\t\t\t\t\t}\n\t\t\t\t\telse //scalar\n\t\t\t\t\t{\n\t\t\t\t\t\tvalueID = srcIDs[0];\n\t\t\t\t\t}\n\n\t\t\t\t\tint storeID = ctx.AddInstrVariableDeclaration(instr, instr->Type, StorageClass::Function);\n\t\t\t\t\tctx.AddInstrStore(instr, storeID, valueID);\n\t\t\t\t}\n\n\t\t\t\telse\n\t\t\t\t\tthrow NotImplementedException(\"import in PrintImportInstr(): \" + instr->ImportOperator->Name.Content);\n\t\t\t}\n\n\t\t\tvoid PrintInstr(ILInstruction & instr)\n\t\t\t{\n\t\t\t\tif (auto binInstr = instr.As<BinaryInstruction>())\n\t\t\t\t\tPrintBinaryInstr(binInstr);\n\t\t\t\telse if (auto allocVar = instr.As<AllocVarInstruction>())\n\t\t\t\t\tPrintAllocVarInstr(allocVar, StorageClass::Function);\n\t\t\t\telse if (auto call = instr.As<CallInstruction>())\n\t\t\t\t\tPrintCallInstr(call);\n\t\t\t\telse if (auto exportInstr = instr.As<ExportInstruction>())\n\t\t\t\t{\n\t\t\t\t\tPrintExportInstr(exportInstr);\n\t\t\t\t\t//throw InvalidOperationException(\"export instruction not supported\");\n\n\t\t\t\t}\n\t\t\t\telse if (auto import = instr.As<ImportInstruction>())\n\t\t\t\t{\n\t\t\t\t\tPrintImportInstr(import);\n\t\t\t\t\t//throw InvalidOperationException(\"import instruction not supported\");\n\t\t\t\t}\n\t\t\t\telse if (auto update = instr.As<MemberUpdateInstruction>())\n\t\t\t\t\tPrintUpdateInstr(update);\n\t\t\t\telse if (auto unaryInstr = instr.As<UnaryInstruction>())\n\t\t\t\t\tPrintUnaryInstr(unaryInstr);\n\t\t\t\telse if (auto select = instr.As<SelectInstruction>())\n\t\t\t\t\tPrintSelectInstr(select);\n\t\t\t\telse if (auto fetchArg = instr.As<FetchArgInstruction>()) //for function: return instruction\n\t\t\t\t\tPrintFetchArgInstr(fetchArg);\n\t\t\t\telse\n\t\t\t\t\tthrow NotImplementedException(\"unsupported instruction in PrintInstr()\" + instr.ToString());\n\t\t\t}\n\n\t\t\tvoid PrintIf(IfInstruction * instr)\n\t\t\t{\n\t\t\t\tint operandID = GetOperandValue(instr->Operand.Ptr());\n\t\t\t\toperandID = ctx.ConvertBasicType(\n\t\t\t\t\toperandID,\n\t\t\t\t\tctx.IDInfos[operandID]().GetILType(),\n\t\t\t\t\tGetTypeFromString(\"bool\"));\n\n\t\t\t\tint TrueLabel = ++ctx.CurrentID;\n\t\t\t\tint FalseLabel = ++ctx.CurrentID;\n\t\t\t\tint MergeLabel = ++ctx.CurrentID;\n\n\t\t\t\tctx.AddInstrSelectionMerge(MergeLabel);\n\t\t\t\tctx.AddInstrBranchConditional(operandID, TrueLabel, FalseLabel);\n\n\t\t\t\tctx.PushScope();\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(TrueLabel);\n\t\t\t\tGenerateCode(instr->TrueCode.Ptr(), TrueLabel);\n\t\t\t\tctx.AddInstrBranch(MergeLabel);\n\t\t\t\tctx.PopScope();\n\n\t\t\t\tctx.PushScope();\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(FalseLabel);\n\t\t\t\tif (instr->FalseCode)\n\t\t\t\t\tGenerateCode(instr->FalseCode.Ptr(), FalseLabel);\n\t\t\t\tctx.AddInstrBranch(MergeLabel);\n\t\t\t\tctx.PopScope();\n\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(MergeLabel);\n\t\t\t}\n\n\t\t\tvoid PrintFor(ForInstruction * instr)\n\t\t\t{\n\t\t\t\tint HeaderBlockLabel = ++ctx.CurrentID;\n\t\t\t\tint ConditionBlockLabel = ++ctx.CurrentID;\n\t\t\t\tint BodyBlockLabel = ++ctx.CurrentID;\n\t\t\t\tint UpdateBlockLabel = ++ctx.CurrentID;\n\t\t\t\tint MergeBlockLabel = ++ctx.CurrentID;\n\n\t\t\t\tctx.AddInstrBranch(HeaderBlockLabel);\n\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(HeaderBlockLabel);\n\t\t\t\tctx.AddInstrLoopMerge(MergeBlockLabel, UpdateBlockLabel);\n\t\t\t\tctx.AddInstrBranch(ConditionBlockLabel);\n\n\t\t\t\t// condition block\n\t\t\t\tctx.PushScope();\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(ConditionBlockLabel);\n\t\t\t\tGenerateCode(instr->ConditionCode.Ptr(), ConditionBlockLabel);\n\t\t\t\tint conditionID = GetOperandValue(instr->ConditionCode->GetLastInstruction());\n\t\t\t\tconditionID = ctx.ConvertBasicType(\n\t\t\t\t\tconditionID,\n\t\t\t\t\tctx.IDInfos[conditionID]().GetILType(),\n\t\t\t\t\tGetTypeFromString(\"bool\"));\n\t\t\t\tctx.AddInstrBranchConditional(conditionID, BodyBlockLabel, MergeBlockLabel);\n\t\t\t\tctx.PopScope();\n\n\t\t\t\t// body block\n\t\t\t\tctx.PushScope();\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(BodyBlockLabel);\n\t\t\t\tctx.StackMergeBlock.Add(MergeBlockLabel);\n\t\t\t\tctx.StackContinueBlock.Add(UpdateBlockLabel);\n\t\t\t\tGenerateCode(instr->BodyCode.Ptr(), BodyBlockLabel);\n\t\t\t\tctx.StackMergeBlock.RemoveAt(ctx.StackMergeBlock.Count() - 1);\n\t\t\t\tctx.StackContinueBlock.RemoveAt(ctx.StackContinueBlock.Count() - 1);\n\t\t\t\tctx.AddInstrBranch(UpdateBlockLabel);\n\t\t\t\tctx.PopScope();\n\n\t\t\t\t// update block\n\t\t\t\tctx.PushScope();\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(UpdateBlockLabel);\n\t\t\t\tGenerateCode(instr->SideEffectCode.Ptr(), UpdateBlockLabel);\n\t\t\t\tctx.AddInstrBranch(HeaderBlockLabel);\n\t\t\t\tctx.PopScope();\n\n\t\t\t\t// merge block\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(MergeBlockLabel);\n\t\t\t}\n\n\t\t\tvoid PrintWhileDo(WhileInstruction * instr)\n\t\t\t{\n\t\t\t\tint HeaderBlockLabel = ++ctx.CurrentID;\n\t\t\t\tint ConditionBlockLabel = ++ctx.CurrentID;\n\t\t\t\tint BodyBlockLabel = ++ctx.CurrentID;\n\t\t\t\tint UpdateBlockLabel = ++ctx.CurrentID;\n\t\t\t\tint MergeBlockLabel = ++ctx.CurrentID;\n\n\t\t\t\tctx.AddInstrBranch(HeaderBlockLabel);\n\n\t\t\t\t// header block\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(HeaderBlockLabel);\n\t\t\t\tctx.AddInstrLoopMerge(MergeBlockLabel, UpdateBlockLabel);\n\t\t\t\tctx.AddInstrBranch(ConditionBlockLabel);\n\n\t\t\t\t// condition block\n\t\t\t\tctx.PushScope();\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(ConditionBlockLabel);\n\t\t\t\tGenerateCode(instr->ConditionCode.Ptr(), ConditionBlockLabel, true);\n\t\t\t\tint conditionID = GetOperandValue(instr->ConditionCode->GetLastInstruction()->As<ReturnInstruction>()->Operand.Ptr());\n\t\t\t\tconditionID = ctx.ConvertBasicType(\n\t\t\t\t\tconditionID,\n\t\t\t\t\tctx.IDInfos[conditionID]().GetILType(),\n\t\t\t\t\tGetTypeFromString(\"bool\")\n\t\t\t\t);\n\t\t\t\tctx.AddInstrBranchConditional(conditionID, BodyBlockLabel, MergeBlockLabel);\n\t\t\t\tctx.PopScope();\n\n\t\t\t\t// body block\n\t\t\t\tctx.PushScope();\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(BodyBlockLabel);\n\t\t\t\tctx.StackMergeBlock.Add(MergeBlockLabel);\n\t\t\t\tctx.StackContinueBlock.Add(UpdateBlockLabel);\n\t\t\t\tGenerateCode(instr->BodyCode.Ptr(), BodyBlockLabel);\n\t\t\t\tctx.StackMergeBlock.RemoveAt(ctx.StackMergeBlock.Count() - 1);\n\t\t\t\tctx.StackContinueBlock.RemoveAt(ctx.StackContinueBlock.Count() - 1);\n\t\t\t\tctx.AddInstrBranch(UpdateBlockLabel);\n\t\t\t\tctx.PopScope();\n\n\t\t\t\t// update block (empty)\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(UpdateBlockLabel);\n\t\t\t\tctx.AddInstrBranch(HeaderBlockLabel);\n\n\t\t\t\t// merge block\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(MergeBlockLabel);\n\t\t\t}\n\n\t\t\tvoid PrintDoWhile(DoInstruction * instr)\n\t\t\t{\n\t\t\t\tint HeaderBlockLabel = ++ctx.CurrentID;\n\t\t\t\tint BodyBlockLabel = ++ctx.CurrentID;\n\t\t\t\tint ConditionBlockLabel = ++ctx.CurrentID;\n\t\t\t\tint MergeBlockLabel = ++ctx.CurrentID;\n\n\t\t\t\t//ctx.FunctionBody << LR\"(OpBranch %)\" << HeaderBlockLabel << EndLine;\n\t\t\t\tctx.AddInstrBranch(HeaderBlockLabel);\n\n\t\t\t\t// header block\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(HeaderBlockLabel);\n\t\t\t\tctx.AddInstrLoopMerge(MergeBlockLabel, ConditionBlockLabel);\n\t\t\t\tctx.AddInstrBranch(BodyBlockLabel);\n\n\t\t\t\t// body block\n\t\t\t\tctx.PushScope();\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(BodyBlockLabel);\n\t\t\t\tctx.StackMergeBlock.Add(MergeBlockLabel);\n\t\t\t\tctx.StackContinueBlock.Add(ConditionBlockLabel);\n\t\t\t\tGenerateCode(instr->BodyCode.Ptr(), BodyBlockLabel);\n\t\t\t\tctx.StackMergeBlock.RemoveAt(ctx.StackMergeBlock.Count() - 1);\n\t\t\t\tctx.StackContinueBlock.RemoveAt(ctx.StackContinueBlock.Count() - 1);\n\t\t\t\tctx.AddInstrBranch(ConditionBlockLabel);\n\t\t\t\tctx.PopScope();\n\n\t\t\t\t// condition block\n\t\t\t\tctx.PushScope();\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(ConditionBlockLabel);\n\t\t\t\tGenerateCode(instr->ConditionCode.Ptr(), ConditionBlockLabel, true);\n\t\t\t\tint conditionID = GetOperandValue(instr->ConditionCode->GetLastInstruction()->As<ReturnInstruction>()->Operand.Ptr());\n\t\t\t\tconditionID = ctx.ConvertBasicType(\n\t\t\t\t\tconditionID,\n\t\t\t\t\tctx.IDInfos[conditionID]().GetILType(),\n\t\t\t\t\tGetTypeFromString(\"bool\")\n\t\t\t\t);\n\t\t\t\tctx.AddInstrBranchConditional(conditionID, HeaderBlockLabel, MergeBlockLabel);\n\t\t\t\tctx.PopScope();\n\n\t\t\t\t// merge block\n\t\t\t\tctx.AddInstrLabel_AtFunctionBody(MergeBlockLabel);\n\t\t\t}\n\n\t\t\tvoid GenerateCode(CFGNode * code, int givenLabel = -1, bool LoopReturn = false)\n\t\t\t{\n\t\t\t\tif (givenLabel == -1)\n\t\t\t\t{\n\t\t\t\t\t++ctx.CurrentID; //label ID\n\t\t\t\t\tctx.AddInstrLabel_AtFunctionBody(ctx.CurrentID);\n\t\t\t\t}\n\n\t\t\t\tList<int> usedID;\n\t\t\t\tfor (auto & instr : *code)\n\t\t\t\t{\n\n\t\t\t\t\tif (auto ifInstr = instr.As<IfInstruction>())\n\t\t\t\t\t{\n\t\t\t\t\t\tPrintIf(ifInstr);\n\t\t\t\t\t}\n\t\t\t\t\telse if (auto forInstr = instr.As<ForInstruction>())\n\t\t\t\t\t{\n\t\t\t\t\t\tPrintFor(forInstr);\n\t\t\t\t\t}\n\t\t\t\t\telse if (auto doInstr = instr.As<DoInstruction>())\n\t\t\t\t\t{\n\t\t\t\t\t\tPrintDoWhile(doInstr);\n\t\t\t\t\t}\n\t\t\t\t\telse if (auto whileInstr = instr.As<WhileInstruction>())\n\t\t\t\t\t{\n\t\t\t\t\t\tPrintWhileDo(whileInstr);\n\t\t\t\t\t}\n\t\t\t\t\telse if (auto ret = instr.As<ReturnInstruction>())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!LoopReturn)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (ret->Operand)\n\t\t\t\t\t\t\t\tctx.AddInstrReturnValue(GetOperandValue(ret->Operand.Ptr()));\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tctx.AddInstrReturn();\n\t\t\t\t\t\t\tctx.AddInstrLabel_AtFunctionBody(++ctx.CurrentID);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (instr.Is<BreakInstruction>())\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.AddInstrBranch(ctx.StackMergeBlock.Last());\n\t\t\t\t\t\tctx.AddInstrLabel_AtFunctionBody(++ctx.CurrentID);\n\t\t\t\t\t}\n\t\t\t\t\telse if (instr.Is<ContinueInstruction>())\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.AddInstrBranch(ctx.StackContinueBlock.Last());\n\t\t\t\t\t\tctx.AddInstrLabel_AtFunctionBody(++ctx.CurrentID);\n\t\t\t\t\t}\n\t\t\t\t\telse if (instr.Is<DiscardInstruction>())\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.AddInstrKill();\n\t\t\t\t\t\tctx.AddInstrLabel_AtFunctionBody(++ctx.CurrentID);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tPrintInstr(instr);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\tpublic:\n\n\t\t\tbool BufferPreProcessed;\n\n\t\t\tvoid Initiate(ExecutionModel model, CompiledWorld * shaderWorld)\n\t\t\t{\n\t\t\t\tctx.Clear();\n\t\t\t\tctx.CodeGen.Initiate();\n\t\t\t\tctx.CurrentID = 1; // reserved for extinst\n\t\t\t\tctx.CodeGen.ProgramHeader();\n\t\t\t\tctx.PushScope();\n\t\t\t\tinterfaceIDs.Clear();\n\t\t\t\tDepthReplacing = false;\n\t\t\t\tLocalSize = false;\n\t\t\t\tBufferImportOrExport = false;\n\t\t\t\tBufferPreProcessed = false;\n\t\t\t\tcurrentWorld = shaderWorld;\n\t\t\t\tcurrentExecutionModel = model;\n\t\t\t}\n\n\t\t\tint GenerateFunctionDeclaration(CompiledFunction *func)\n\t\t\t\t//return the ID of the Function Type\n\t\t\t{\n\t\t\t\tList<RefPtr<ILType>> args;\n\t\t\t\tfor (auto & instr : *func->Code)\n\t\t\t\t\tif (auto arg = instr.As<FetchArgInstruction>())\n\t\t\t\t\t\tif (arg->ArgId != 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\targs.Add(arg->Type);\n\t\t\t\t\t\t}\n\t\t\t\tint funcTypeID = ctx.AddInstrTypeFunction(func, args, func->ReturnType);\n\t\t\t\tctx.FunctionNameToFunctionID[func->Name] = ++ctx.CurrentID;\n\t\t\t\treturn funcTypeID;\n\t\t\t}\n\n\t\t\tint GenerateFunctionDefinition(CompiledFunction *func, ILOperand *vertexOutput = nullptr)\n\t\t\t\t//return the ID of the Function\n\t\t\t{\n\t\t\t\tctx.ClearBuffer();\n\n\t\t\t\tctx.PushScope();\n\n\t\t\t\tint funcID = ctx.FunctionNameToFunctionID[func->Name]();\n\t\t\t\tint funcTypeID = ctx.FunctionNameToFunctionTypeID[func->Name]();\n\n\t\t\t\tctx.AddInstrFunction(funcID, ctx.DefineType(func->ReturnType), funcTypeID, GetFuncOriginalName(func->Name));\n\n\t\t\t\tfor (auto & instr : *func->Code)\n\t\t\t\t\tif (auto arg = instr.As<FetchArgInstruction>())\n\t\t\t\t\t\tif (arg->ArgId != 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!ctx.ParameterNameToID.ContainsKey((ILOperand*)&instr))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tctx.DefineType(arg->Type);\n\t\t\t\t\t\t\t\tint typeID = ctx.DefineTypePointer(arg->Type, StorageClass::Function);\n\t\t\t\t\t\t\t\tctx.AddInstrFunctionParameter((ILOperand*)&instr, typeID, arg->Name);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t++ctx.CurrentID;\n\t\t\t\tctx.AddInstrLabel_AtFunctionHeader(ctx.CurrentID);\n\n\t\t\t\tfunc->Code->NameAllInstructions();\n\t\t\t\tGenerateCode(func->Code.Ptr(), ctx.CurrentID);\n\n\t\t\t\tif (vertexOutput)\n\t\t\t\t{\n\t\t\t\t\tint valueID = ctx.AddInstrLoad(nullptr, vertexOutput, MemoryAccess::None);\n\t\t\t\t\tint gl_PositionID = ctx.AddInstrAccessChain_StructMember(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tctx.InterfaceNameToID[\"variable_gl_PerVertex\"],\n\t\t\t\t\t\t\"gl_Position\"\n\t\t\t\t\t);\n\t\t\t\t\tctx.AddInstrStore(0, gl_PositionID, valueID);\n\t\t\t\t}\n\n\t\t\t\tctx.AddInstrReturn();\n\t\t\t\tctx.AddInstrFunctionEnd();\n\n\t\t\t\tctx.ProduceFunction();\n\n\t\t\t\tctx.PopScope();\n\n\t\t\t\treturn funcID;\n\t\t\t}\n\n\t\t\tvoid Decorate(int ID, Decoration deco, int op1 = -1)\n\t\t\t{\n\t\t\t\tctx.AddInstrDecorate(ID, deco, op1);\n\t\t\t}\n\n\t\t\tvoid MemberDecorate(int ID, int index, Decoration deco, int op1 = -1)\n\t\t\t{\n\t\t\t\tctx.AddInstrMemberDecorate(ID, index, deco, op1);\n\t\t\t}\n\n\t\t\tvoid SetDepthReplacing()\n\t\t\t{\n\t\t\t\tDepthReplacing = true;\n\t\t\t}\n\n\t\t\tvoid SetLocalSize(unsigned int x)\n\t\t\t{\n\t\t\t\t//layout(local_size_x = <x> ) in;\n\t\t\t\tLocalSize = true;\n\t\t\t\tunsigned int workgroup[3] = { x, 1, 1 };\n\t\t\t\tctx.AddInstrDecorate(\n\t\t\t\t\tctx.AddInstrConstantCompositeUInt(workgroup, 3),\n\t\t\t\t\tDecoration::BuiltIn,\n\t\t\t\t\t(int)BuiltIn::WorkgroupSize\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tvoid GenerateEntryPoint(int mainFunctionID)\n\t\t\t{\n\t\t\t\tctx.AddInstrEntryPoint(currentExecutionModel, mainFunctionID, interfaceIDs);\n\t\t\t\tif (currentExecutionModel == ExecutionModel::Fragment)\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrExecutionMode(mainFunctionID, ExecutionMode::OriginUpperLeft);\n\t\t\t\t}\n\t\t\t\tif (DepthReplacing)\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrExecutionMode(mainFunctionID, ExecutionMode::DepthReplacing);\n\t\t\t\t}\n\t\t\t\tif (LocalSize)\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrExecutionMode(mainFunctionID, ExecutionMode::LocalSize, 256, 1, 1);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tint GenerateGlGlobalInvocationID()\n\t\t\t\t//return the ID of the gl_GlobalInvocationID variable\n\t\t\t{\n\t\t\t\tint GlobalInvocationID = ctx.AddInstrVariableDeclaration(0, GetTypeFromString(\"uvec3\"), StorageClass::Input, \"gl_GlobalInvocationID\", 0);\n\t\t\t\tctx.AddInstrDecorate(GlobalInvocationID, Decoration::BuiltIn, (int)BuiltIn::GlobalInvocationId);\n\t\t\t\tctx.InterfaceNameToID[\"gl_GlobalInvocationID\"] = GlobalInvocationID;\n\t\t\t\treturn GlobalInvocationID;\n\t\t\t}\n\n\t\t\tint GenerateInterfaceForSingleVariable(\n\t\t\t\tString varName,\n\t\t\t\tRefPtr<ILType> varType,\n\t\t\t\tStorageClass storageClass,\n\t\t\t\tint location = -1,\n\t\t\t\tint bindIndex = -1)\n\t\t\t\t//return the ID of the variable\n\t\t\t{\n\t\t\t\tint entID = ctx.AddInstrVariableDeclaration(0, varType, storageClass, varName, 0);\n\t\t\t\tctx.InterfaceNameToID[varName] = entID;\n\t\t\t\tif (location != -1)\n\t\t\t\t\tctx.AddInstrDecorate(entID, Decoration::Location, location);\n\t\t\t\tif (bindIndex != -1)\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrDecorate(entID, Decoration::DescriptorSet, 0);\n\t\t\t\t\tctx.AddInstrDecorate(entID, Decoration::Binding, bindIndex);\n\t\t\t\t}\n\t\t\t\tif (storageClass == StorageClass::Input || storageClass == StorageClass::Output)\n\t\t\t\t\tinterfaceIDs.Add(entID);\n\t\t\t\treturn entID;\n\t\t\t}\n\n\t\t\tstd::pair<int,int> GenerateInterfaceForStructVariable(\n\t\t\t\tString structTypeName,\n\t\t\t\tString structVariableName,\n\t\t\t\tList<RefPtr<ILType>> memberTypes,\n\t\t\t\tList<String> memberNames,\n\t\t\t\tint UniformOrBuffer,\n\t\t\t\tStorageClass storageClass,\n\t\t\t\tint location = -1,\n\t\t\t\tint bindindex = -1)\n\t\t\t\t//first  - the ID of the struct type\n\t\t\t\t//second - the ID of the variable \n\t\t\t{\n\t\t\t\tRefPtr<ILStructType> structIL = new ILStructType();\n\t\t\t\tstructIL->TypeName = structTypeName;\n\t\t\t\tint n = memberTypes.Count();\n\t\t\t\tfor (int i = 0; i < n; i++)\n\t\t\t\t{\n\t\t\t\t\tILStructType::ILStructField field;\n\t\t\t\t\tfield.Type = memberTypes[i];\n\t\t\t\t\tfield.FieldName = memberNames[i];\n\t\t\t\t\tstructIL->Members.Add(field);\n\t\t\t\t}\n\n\t\t\t\tint structTypeID = ctx.DefineType(structIL, UniformOrBuffer);\n\t\t\t\tint structVariableID = ctx.AddInstrVariableDeclaration(0, structIL, storageClass, structVariableName, UniformOrBuffer);\n\t\t\t\tctx.InterfaceNameToID[structVariableName] = structVariableID;\n\n\t\t\t\tif (UniformOrBuffer == 1)\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrDecorate(structVariableID, Decoration::DescriptorSet, 0);\n\t\t\t\t\tctx.AddInstrDecorate(structTypeID, Decoration::Block);\n\t\t\t\t}\n\t\t\t\telse if (UniformOrBuffer == 2)\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrDecorate(structVariableID, Decoration::DescriptorSet, 0);\n\t\t\t\t\tctx.AddInstrDecorate(structTypeID, Decoration::BufferBlock);\n\t\t\t\t}\n\n\t\t\t\tif (location != -1)\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrDecorate(structVariableID, Decoration::Location, location);\n\t\t\t\t}\n\n\t\t\t\tif (bindindex != -1)\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrDecorate(structVariableID, Decoration::Binding, bindindex);\n\t\t\t\t}\n\n\t\t\t\tif (storageClass == StorageClass::Input || storageClass == StorageClass::Output)\n\t\t\t\t{\n\t\t\t\t\tfor (int i = 0; i < n; i++)\n\t\t\t\t\t\tif (memberTypes[i]->IsIntegral())\n\t\t\t\t\t\t\tctx.AddInstrMemberDecorate(structTypeID, i, Decoration::Flat);\n\t\t\t\t\tinterfaceIDs.Add(structVariableID);\n\t\t\t\t}\n\n\t\t\t\treturn std::make_pair(structTypeID, structVariableID);\n\t\t\t}\n\n\t\t\tCompiledShaderSource GenerateShaderWorld()\n\t\t\t{\n\t\t\t\tCompiledShaderSource rs;\n\n\t\t\t\tauto binaryForm = ctx.ProduceWordStream();\n\t\t\t\trs.BinaryCode.SetSize(binaryForm.Count() * sizeof(unsigned int));\n\t\t\t\tmemcpy(rs.BinaryCode.Buffer(), binaryForm.Buffer(), rs.BinaryCode.Count());\n\n\t\t\t\trs.MainCode = ctx.ProduceTextCode();\n\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t};\n\n\t\tclass SpirVCodeGen : public CodeGenBackend\n\t\t{\n\t\t\tString vertexOutputName;\n\t\t\tEnumerableDictionary<String, String> backendArguments;\n\n\t\tpublic:\n\n\t\t\tExecutionModel currentExecutionModel = ExecutionModel::Invalid;\n\n\t\t\tvoid ProcessBufferImportOrExportInterfaces(SpirvModule & spvModule, String blkName, int index)\n\t\t\t{\n\t\t\t\tif (!spvModule.BufferPreProcessed)\n\t\t\t\t{\n\t\t\t\t\tspvModule.BufferPreProcessed = true;\n\t\t\t\t\tspvModule.SetLocalSize(256);\n\t\t\t\t\tspvModule.GenerateGlGlobalInvocationID();\n\n\t\t\t\t\tList<RefPtr<ILType>> memberTypes;\n\t\t\t\t\tList<String> memberNames;\n\t\t\t\t\tmemberTypes.Add(GetTypeFromString(\"uint\"));\n\t\t\t\t\tmemberNames.Add(\"sys_thread_count\");\n\t\t\t\t\tspvModule.GenerateInterfaceForStructVariable(\n\t\t\t\t\t\t\"SystemBlock\",\n\t\t\t\t\t\t\"blkSystemBlock\",\n\t\t\t\t\t\tmemberTypes,\n\t\t\t\t\t\tmemberNames,\n\t\t\t\t\t\t1,\n\t\t\t\t\t\tStorageClass::Uniform,\n\t\t\t\t\t\t-1,\n\t\t\t\t\t\t0\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tList<RefPtr<ILType>> memberTypes;\n\t\t\t\tList<String> memberNames;\n\t\t\t\tmemberTypes.Add(GetTypeFromString(\"float[0]\"));\n\t\t\t\tmemberNames.Add(\"a\");\n\t\t\t\tspvModule.GenerateInterfaceForStructVariable(\n\t\t\t\t\tblkName,\n\t\t\t\t\t\"blk\" + blkName,\n\t\t\t\t\tmemberTypes,\n\t\t\t\t\tmemberNames,\n\t\t\t\t\t2,\n\t\t\t\t\tStorageClass::Uniform,\n\t\t\t\t\t-1,\n\t\t\t\t\tindex\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tvirtual CompiledShaderSource GenerateShaderWorld(CompileResult & result, SymbolTable * /*symbols*/, CompiledWorld * shaderWorld, Dictionary<String, ImportOperatorHandler*>& opHandlers, Dictionary<String, ExportOperatorHandler*>& exportHandlers) override\n\t\t\t{\n\t\t\t\t\n\t\t\t\tcurrentExecutionModel = ExecutionModel::Invalid;\n\t\t\t\tif (shaderWorld->ExportOperator.Content == \"fragmentExport\")\n\t\t\t\t\tcurrentExecutionModel = ExecutionModel::Fragment;\n\t\t\t\telse if (shaderWorld->BackendParameters.ContainsKey(\"vertex\"))\n\t\t\t\t\tcurrentExecutionModel = ExecutionModel::Vertex;\n\t\t\t\telse if (shaderWorld->ExportOperator.Content == \"bufferExport\")\n\t\t\t\t\tcurrentExecutionModel = ExecutionModel::GLCompute;\n\n\t\t\t\tCompiledFunction mainFunction;\n\t\t\t\tmainFunction.Name = \"main\";\n\t\t\t\tmainFunction.ReturnType = nullptr;\n\t\t\t\tmainFunction.Code = shaderWorld->Code;\n\n\t\t\t\tSpirvModule spvModule;\n\t\t\t\tspvModule.Initiate(currentExecutionModel, shaderWorld);\n\t\t\t\tspvModule.GenerateFunctionDeclaration(&mainFunction);\n\n\t\t\t\tfor (auto funcName : shaderWorld->ReferencedFunctions)\n\t\t\t\t\tfor(auto & func : result.Program->Functions)\n\t\t\t\t\t\tif (funcName == func->Name)\n\t\t\t\t\t\t\tspvModule.GenerateFunctionDeclaration(func.Ptr());\n\n\t\t\t\tfor (auto funcName : shaderWorld->ReferencedFunctions)\n\t\t\t\t\tfor (auto & func : result.Program->Functions)\n\t\t\t\t\t\tif (funcName == func->Name)\n\t\t\t\t\t\t\tspvModule.GenerateFunctionDefinition(func.Ptr());\n\n\t\t\t\tfor (auto & inputBlock : shaderWorld->WorldInputs)\n\t\t\t\t{\n\t\t\t\t\tauto block = inputBlock.Value.Block;\n\t\t\t\t\tif (!block->UserWorlds.Contains(shaderWorld->WorldName))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tString impOpName = inputBlock.Value.ImportOperator.Name.Content;\n\n\t\t\t\t\tif (impOpName == \"standardImport\")\n\t\t\t\t\t{\n\t\t\t\t\t\tList<RefPtr<ILType>> memberTypes;\n\t\t\t\t\t\tList<String> memberNames;\n\t\t\t\t\t\tfor (auto & ent : block->Entries)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmemberTypes.Add(ent.Value.Type);\n\t\t\t\t\t\t\tmemberNames.Add(ent.Value.Name);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tspvModule.GenerateInterfaceForStructVariable(\n\t\t\t\t\t\t\tblock->Name,\n\t\t\t\t\t\t\t\"blk\"+block->Name,\n\t\t\t\t\t\t\tmemberTypes,\n\t\t\t\t\t\t\tmemberNames,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tStorageClass::Input,\n\t\t\t\t\t\t\t0\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\telse if (impOpName == \"vertexImport\")\n\t\t\t\t\t{\n\t\t\t\t\t\tint location = 0;\n\t\t\t\t\t\tfor (auto & ent : block->Entries)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tspvModule.GenerateInterfaceForSingleVariable(\n\t\t\t\t\t\t\t\tent.Key,\n\t\t\t\t\t\t\t\tent.Value.Type,\n\t\t\t\t\t\t\t\tStorageClass::Input,\n\t\t\t\t\t\t\t\tlocation\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tlocation++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telse if (impOpName == \"uniformImport\")\n\t\t\t\t\t{\n\t\t\t\t\t\tint nonTextureCount = 0;\n\t\t\t\t\t\tfor (auto & ent : block->Entries)\n\t\t\t\t\t\t\tif (!ent.Value.Type->IsTexture())\n\t\t\t\t\t\t\t\tnonTextureCount++;\n\n\t\t\t\t\t\tint TypeOfStruct = 1; //1: uniform buffer; 2: shader storage buffer; 0: not a buffer\n\t\t\t\t\t\tif (block->Attributes.ContainsKey(\"ShaderStorageBlock\"))\n\t\t\t\t\t\t\tTypeOfStruct = 2;\n\n\t\t\t\t\t\tif (nonTextureCount)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tList<RefPtr<ILType>> memberTypes;\n\t\t\t\t\t\t\tList<String> memberNames;\n\t\t\t\t\t\t\tfor (auto & ent : block->Entries)\n\t\t\t\t\t\t\t\tif (!ent.Value.Type->IsTexture())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tmemberTypes.Add(ent.Value.Type);\n\t\t\t\t\t\t\t\t\tmemberNames.Add(ent.Value.Name);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tString strIndex;\n\t\t\t\t\t\t\tint index = -1;\n\t\t\t\t\t\t\tif (block->Attributes.TryGetValue(\"Index\", strIndex))\n\t\t\t\t\t\t\t\tindex = StringToInt(strIndex);\n\t\t\t\t\t\t\tspvModule.GenerateInterfaceForStructVariable(\n\t\t\t\t\t\t\t\tblock->Name,\n\t\t\t\t\t\t\t\t\"blk\" + block->Name,\n\t\t\t\t\t\t\t\tmemberTypes,\n\t\t\t\t\t\t\t\tmemberNames,\n\t\t\t\t\t\t\t\tTypeOfStruct,\n\t\t\t\t\t\t\t\tStorageClass::Uniform,\n\t\t\t\t\t\t\t\t-1,\n\t\t\t\t\t\t\t\tindex\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tint bindPoint = 0;\n\t\t\t\t\t\tString bindingStart;\n\t\t\t\t\t\tif (backendArguments.TryGetValue(\"TextureBindingStart\", bindingStart))\n\t\t\t\t\t\t\tbindPoint = StringToInt(bindingStart);\n\n\t\t\t\t\t\tfor(auto & ent : block->Entries)\n\t\t\t\t\t\t\tif (ent.Value.Type->IsTexture())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tspvModule.GenerateInterfaceForSingleVariable(\n\t\t\t\t\t\t\t\t\tent.Key,\n\t\t\t\t\t\t\t\t\tent.Value.Type,\n\t\t\t\t\t\t\t\t\tStorageClass::UniformConstant,\n\t\t\t\t\t\t\t\t\t-1,\n\t\t\t\t\t\t\t\t\tbindPoint\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tbindPoint++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telse if (impOpName == \"textureImport\")\n\t\t\t\t\t{\n\t\t\t\t\t\tint bindPoint = 0;\n\t\t\t\t\t\tString strIndex;\n\t\t\t\t\t\tif (block->Attributes.TryGetValue(\"Index\", strIndex))\n\t\t\t\t\t\t\tbindPoint = StringToInt(strIndex);\n\t\t\t\t\t\tfor (auto & ent : block->Entries)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tspvModule.GenerateInterfaceForSingleVariable(\n\t\t\t\t\t\t\t\tent.Key,\n\t\t\t\t\t\t\t\tent.Value.Type,\n\t\t\t\t\t\t\t\tStorageClass::UniformConstant,\n\t\t\t\t\t\t\t\t-1,\n\t\t\t\t\t\t\t\tbindPoint\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tbindPoint++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telse if (impOpName == \"bufferImport\")\n\t\t\t\t\t{\n\t\t\t\t\t\tString strIdx;\n\t\t\t\t\t\tint index = 0;\n\t\t\t\t\t\tif (block->Attributes.TryGetValue(\"Index\", strIdx))\n\t\t\t\t\t\t\tindex = StringToInt(strIdx);\n\t\t\t\t\t\tProcessBufferImportOrExportInterfaces(spvModule, block->Name, index);\n\t\t\t\t\t}\n\n\t\t\t\t\telse \n\t\t\t\t\t\tthrow NotImplementedException(\"not implemented input interface: \" + impOpName);\n\t\t\t\t}\n\n\t\t\t\tif (shaderWorld->ExportOperator.Content == \"fragmentExport\")\n\t\t\t\t{\n\t\t\t\t\tint location = 0;\n\t\t\t\t\tfor (auto & ent : shaderWorld->WorldOutput->Entries)\n\t\t\t\t\t\tif (!ent.Value.LayoutAttribs.ContainsKey(\"DepthOutput\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tspvModule.GenerateInterfaceForSingleVariable(\n\t\t\t\t\t\t\t\tent.Key,\n\t\t\t\t\t\t\t\tent.Value.Type,\n\t\t\t\t\t\t\t\tStorageClass::Output,\n\t\t\t\t\t\t\t\tlocation\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tlocation++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint entID = spvModule.GenerateInterfaceForSingleVariable(\n\t\t\t\t\t\t\t\t\"gl_FragDepth\",\n\t\t\t\t\t\t\t\tent.Value.Type,\n\t\t\t\t\t\t\t\tStorageClass::Output,\n\t\t\t\t\t\t\t\tlocation\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tspvModule.SetDepthReplacing();\n\t\t\t\t\t\t\tspvModule.Decorate(entID, Decoration::BuiltIn, (int)BuiltIn::FragDepth);\n\t\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\telse if (shaderWorld->ExportOperator.Content == \"standardExport\")\n\t\t\t\t{\n\t\t\t\t\tList<RefPtr<ILType>> memberTypes;\n\t\t\t\t\tList<String> memberNames;\n\t\t\t\t\tfor (auto & ent : shaderWorld->WorldOutput->Entries)\n\t\t\t\t\t{\n\t\t\t\t\t\tmemberTypes.Add(ent.Value.Type);\n\t\t\t\t\t\tmemberNames.Add(ent.Value.Name);\n\t\t\t\t\t}\n\t\t\t\t\tspvModule.GenerateInterfaceForStructVariable(\n\t\t\t\t\t\tshaderWorld->WorldOutput->Name,\n\t\t\t\t\t\t\"blk\" + shaderWorld->WorldOutput->Name,\n\t\t\t\t\t\tmemberTypes,\n\t\t\t\t\t\tmemberNames,\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tStorageClass::Output,\n\t\t\t\t\t\t0\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\telse if (shaderWorld->ExportOperator.Content == \"bufferExport\")\n\t\t\t\t{\n\t\t\t\t\tString strIdx;\n\t\t\t\t\tint index = 0;\n\t\t\t\t\tif (shaderWorld->WorldOutput->Attributes.TryGetValue(\"Index\", strIdx))\n\t\t\t\t\t\tindex = StringToInt(strIdx);\n\t\t\t\t\tProcessBufferImportOrExportInterfaces(spvModule, shaderWorld->WorldOutput->Name, index);\n\t\t\t\t}\n\n\t\t\t\telse\n\t\t\t\t\tthrow NotImplementedException(\"not implemented output interface: \" + shaderWorld->ExportOperator.Content);\n\n\t\t\t\tif (vertexOutputName.Length())\n\t\t\t\t{\n\t\t\t\t\tCompiledComponent ccomp;\n\t\t\t\t\tif (shaderWorld->LocalComponents.TryGetValue(vertexOutputName, ccomp))\n\t\t\t\t\t{\n\t\t\t\t\t\tList<RefPtr<ILType>> memberTypes;\n\t\t\t\t\t\tList<String> memberNames;\n\t\t\t\t\t\tmemberTypes.Add(GetTypeFromString(\"vec4\"));\n\t\t\t\t\t\tmemberNames.Add(\"gl_Position\");\n\t\t\t\t\t\tmemberTypes.Add(GetTypeFromString(\"float\"));\n\t\t\t\t\t\tmemberNames.Add(\"gl_PointSize\");\n\t\t\t\t\t\tmemberTypes.Add(GetTypeFromString(\"float[1]\"));\n\t\t\t\t\t\tmemberNames.Add(\"gl_ClipDistance\");\n\t\t\t\t\t\tmemberTypes.Add(GetTypeFromString(\"float[1]\"));\n\t\t\t\t\t\tmemberNames.Add(\"gl_CullDistance\");\n\n\t\t\t\t\t\tint typeID = spvModule.GenerateInterfaceForStructVariable(\n\t\t\t\t\t\t\t\"gl_PerVertex\",\n\t\t\t\t\t\t\t\"variable_gl_PerVertex\",\n\t\t\t\t\t\t\tmemberTypes,\n\t\t\t\t\t\t\tmemberNames,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tStorageClass::Output,\n\t\t\t\t\t\t\t-1,\n\t\t\t\t\t\t\t-1\n\t\t\t\t\t\t).first;\n\n\t\t\t\t\t\tspvModule.Decorate(typeID, Decoration::Block);\n\t\t\t\t\t\tspvModule.MemberDecorate(typeID, 0, Decoration::BuiltIn, (int)BuiltIn::Position);\n\t\t\t\t\t\tspvModule.MemberDecorate(typeID, 1, Decoration::BuiltIn, (int)BuiltIn::PointSize);\n\t\t\t\t\t\tspvModule.MemberDecorate(typeID, 2, Decoration::BuiltIn, (int)BuiltIn::ClipDistance);\n\t\t\t\t\t\tspvModule.MemberDecorate(typeID, 3, Decoration::BuiltIn, (int)BuiltIn::CullDistance);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tILOperand *vertexOutput = nullptr;\n\t\t\t\tif (vertexOutputName.Length())\n\t\t\t\t{\n\t\t\t\t\tCompiledComponent ccomp;\n\t\t\t\t\tif (shaderWorld->LocalComponents.TryGetValue(vertexOutputName, ccomp))\n\t\t\t\t\t{\n\t\t\t\t\t\tvertexOutput = ccomp.CodeOperand;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow InvalidOperationException(\"can not find vertexOutputName\");\n\t\t\t\t}\n\n\t\t\t\tint mainFunctionID = spvModule.GenerateFunctionDefinition(&mainFunction, vertexOutput);\n\n\t\t\t\tspvModule.GenerateEntryPoint(mainFunctionID);\n\n\t\t\t\treturn spvModule.GenerateShaderWorld();\n\t\t\t\t\n\t\t\t\t/*\n\t\t\t\tctx.Clear();\n\n\t\t\t\tcurrentWorld = shaderWorld;\n\t\t\t\tCompiledShaderSource rs;\n\t\t\t\tctx.Result = &result;\n\n\t\t\t\tcurrentExecutionModel = ExecutionModel::Invalid;\n\t\t\t\tif (currentWorld->ExportOperator.Content == \"fragmentExport\")\n\t\t\t\t\tcurrentExecutionModel = ExecutionModel::Fragment;\n\t\t\t\telse if (currentWorld->BackendParameters.ContainsKey(\"vertex\"))\n\t\t\t\t\tcurrentExecutionModel = ExecutionModel::Vertex;\n\t\t\t\telse if (currentWorld->ExportOperator.Content == \"bufferExport\")\n\t\t\t\t\tcurrentExecutionModel = ExecutionModel::GLCompute;\n\n\t\t\t\tif (ExecutionModel::Invalid == currentExecutionModel)\n\t\t\t\t\tthrow InvalidOperationException(\"invalid execution model for shader world: \" + currentWorld->WorldName);\n\n\t\t\t\tctx.CurrentID = 1;\n\n\t\t\t\tctx.CodeGen.Initiate();\n\t\t\t\tctx.CodeGen.ProgramHeader();\n\n\t\t\t\t//add all functions type definition\n\t\t\t\tfor (auto funcName : shaderWorld->ReferencedFunctions)\n\t\t\t\t{\n\t\t\t\t\tfor (auto &func : result.Program->Functions)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (func->Name == funcName)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tList<RefPtr<ILType>> args;\n\t\t\t\t\t\t\tfor (auto & instr : *func->Code)\n\t\t\t\t\t\t\t\tif (auto arg = instr.As<FetchArgInstruction>())\n\t\t\t\t\t\t\t\t\tif (arg->ArgId != 0)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\targs.Add(arg->Type);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tctx.AddInstrTypeFunction(func.Ptr(), args, func->ReturnType);\n\t\t\t\t\t\t\tctx.FunctionNameToFunctionID[func->Name] = ++ctx.CurrentID; \n\t\t\t\t\t\t\t//this is reserverd for the result ID of the OpFunction instruction! \n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t//add all functions definition\n\t\t\t\tfor (auto funcName : shaderWorld->ReferencedFunctions)\n\t\t\t\t{\n\t\t\t\t\tfor (auto &func : result.Program->Functions)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (func->Name == funcName)\n\t\t\t\t\t\t{\n\n\t\t\t\t\t\t\tctx.ClearBuffer();\n\n\t\t\t\t\t\t\tctx.PushScope();\n\n\t\t\t\t\t\t\tint funcID = ctx.FunctionNameToFunctionID[func->Name]();\n\t\t\t\t\t\t\tint funcTypeID = ctx.FunctionNameToFunctionTypeID[func->Name]();\n\n\t\t\t\t\t\t\tctx.AddInstrFunction(funcID, ctx.DefineType(func->ReturnType), funcTypeID, GetFuncOriginalName(funcName));\n\n\t\t\t\t\t\t\tfor (auto & instr : *func->Code)\n\t\t\t\t\t\t\t\tif (auto arg = instr.As<FetchArgInstruction>())\n\t\t\t\t\t\t\t\t\tif (arg->ArgId != 0)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (!ctx.ParameterNameToID.ContainsKey((ILOperand*)&instr))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tctx.DefineType(arg->Type);\n\t\t\t\t\t\t\t\t\t\t\tint typeID = ctx.DefineTypePointer(arg->Type, StorageClass::Function);\n\t\t\t\t\t\t\t\t\t\t\tctx.AddInstrFunctionParameter((ILOperand*)&instr, typeID, arg->Name);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t++ctx.CurrentID;\n\t\t\t\t\t\t\tctx.AddInstrLabel_AtFunctionHeader(ctx.CurrentID);\n\n\t\t\t\t\t\t\tfunc->Code->NameAllInstructions();\n\t\t\t\t\t\t\tGenerateCode(func->Code.Ptr(), ctx.CurrentID);\n\n\t\t\t\t\t\t\tctx.AddInstrReturn();\n\t\t\t\t\t\t\tctx.AddInstrFunctionEnd();\n\n\t\t\t\t\t\t\tctx.ProduceFunction();\n\n\t\t\t\t\t\t\tctx.PopScope();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tctx.ClearBuffer();\n\n\t\t\t\tctx.PushScope();\n\n\t\t\t\tList<int> interfaceIDs;\n\t\t\t\tbool DepthReplacing = false;\n\t\t\t\tbool LocalSize = false;\n\t\t\t\tbool BufferImportOrExport = false;\n\t\t\t\tProcessInterfaces(interfaceIDs, shaderWorld, opHandlers, DepthReplacing, LocalSize, BufferImportOrExport);\n\n\t\t\t\t//for gl_Position\n\t\t\t\tif (vertexOutputName.Length())\n\t\t\t\t{\n\t\t\t\t\tCompiledComponent ccomp;\n\t\t\t\t\tif (currentWorld->LocalComponents.TryGetValue(vertexOutputName, ccomp))\n\t\t\t\t\t{\n\t\t\t\t\t\tRefPtr<ILStructType> structIL = new ILStructType();\n\t\t\t\t\t\tstructIL->TypeName = \"gl_PerVertex\";\n\n\t\t\t\t\t\tILStructType::ILStructField f1;\n\t\t\t\t\t\tf1.Type = GetTypeFromString(\"vec4\");\n\t\t\t\t\t\tf1.FieldName = \"gl_Position\";\n\t\t\t\t\t\tstructIL->Members.Add(f1);\n\t\t\t\t\t\tILStructType::ILStructField f2;\n\t\t\t\t\t\tf2.Type = GetTypeFromString(\"float\");\n\t\t\t\t\t\tf2.FieldName = \"gl_PointSize\";\n\t\t\t\t\t\tstructIL->Members.Add(f2);\n\t\t\t\t\t\tILStructType::ILStructField f3;\n\t\t\t\t\t\tf3.Type = GetTypeFromString(\"float[1]\");\n\t\t\t\t\t\tf3.FieldName = \"gl_ClipDistance\";\n\t\t\t\t\t\tstructIL->Members.Add(f3);\n\t\t\t\t\t\tILStructType::ILStructField f4;\n\t\t\t\t\t\tf4.Type = GetTypeFromString(\"float[1]\");\n\t\t\t\t\t\tf4.FieldName = \"gl_CullDistance\";\n\t\t\t\t\t\tstructIL->Members.Add(f4);\n\n\t\t\t\t\t\tint structTypeID = ctx.DefineType(structIL);\n\t\t\t\t\t\tint structVariableID = ctx.AddInstrVariableDeclaration(0, structIL, StorageClass::Output, \"gl_PerVertex\");\n\t\t\t\t\t\tctx.InterfaceNameToID[\"gl_PerVertex\"] = structVariableID;\n\n\t\t\t\t\t\tctx.AddInstrDecorate(structTypeID, Decoration::Block);\n\t\t\t\t\t\tctx.AddInstrMemberDecorate(structTypeID, 0, Decoration::BuiltIn, (int)BuiltIn::Position);\n\t\t\t\t\t\tctx.AddInstrMemberDecorate(structTypeID, 1, Decoration::BuiltIn, (int)BuiltIn::PointSize);\n\t\t\t\t\t\tctx.AddInstrMemberDecorate(structTypeID, 2, Decoration::BuiltIn, (int)BuiltIn::ClipDistance);\n\t\t\t\t\t\tctx.AddInstrMemberDecorate(structTypeID, 3, Decoration::BuiltIn, (int)BuiltIn::CullDistance);\n\n\t\t\t\t\t\tinterfaceIDs.Add(structVariableID);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow InvalidOperationException(\"can not find vertexOutputName\");\n\t\t\t\t}\n\n\t\t\t\t//add Main function type definition\n\t\t\t\tctx.MainFunctionTypeID = ctx.AddInstrTypeFunction(nullptr, List<RefPtr<ILType>>(), nullptr);\n\t\t\t\tctx.MainFunctionID = ++ctx.CurrentID;\n\n\t\t\t\t//Entry Point\n\t\t\t\tctx.AddInstrEntryPoint(currentExecutionModel, ctx.MainFunctionID, interfaceIDs);\n\n\t\t\t\t//execution mode\n\t\t\t\tif (currentExecutionModel == ExecutionModel::Fragment)\n\t\t\t\t{\n\t\t\t\t\t//CodeGen.OpExecutionMode(ctx.MainFunctionID, ExecutionMode::OriginUpperLeft);\n\t\t\t\t\tctx.AddInstrExecutionMode(ctx.MainFunctionID, ExecutionMode::OriginUpperLeft);\n\t\t\t\t}\n\t\t\t\tif (DepthReplacing)\n\t\t\t\t{\n\t\t\t\t\t//CodeGen.OpExecutionMode(ctx.MainFunctionID, ExecutionMode::DepthReplacing);\n\t\t\t\t\tctx.AddInstrExecutionMode(ctx.MainFunctionID, ExecutionMode::DepthReplacing);\n\t\t\t\t}\n\t\t\t\tif (LocalSize)\n\t\t\t\t{\n\t\t\t\t\tctx.AddInstrExecutionMode(ctx.MainFunctionID, ExecutionMode::LocalSize, 256, 1, 1);\n\t\t\t\t}\n\n\t\t\t\t//MainFunction\n\t\t\t\tctx.AddInstrFunction(ctx.MainFunctionID, ctx.TypeNameToID[\"void\"](), ctx.MainFunctionTypeID, \"main\");\n\n\t\t\t\t++ctx.CurrentID;\n\t\t\t\tctx.AddInstrLabel_AtFunctionHeader(ctx.CurrentID);\n\n\t\t\t\tif (BufferImportOrExport)\n\t\t\t\t{\n\t\t\t\t\tint GIIDx = ctx.AddInstrLoad(\n\t\t\t\t\t\tctx.AddInstrAccessChain_VectorMember(0, ctx.InterfaceNameToID[\"gl_GlobalInvocationID\"], -1, 0),\n\t\t\t\t\t\tMemoryAccess::None\n\t\t\t\t\t);\t//GlobalInvocationID.x\n\t\t\t\t\tint SysThreadCountID = ctx.AddInstrLoad(\n\t\t\t\t\t\tctx.AddInstrAccessChain_StructMember(0, ctx.InterfaceNameToID[\"SystemBlock\"], \"sys_thread_count\"),\n\t\t\t\t\t\tMemoryAccess::None\n\t\t\t\t\t);\n\t\t\t\t\tint conditionID = ctx.AddInstrBinaryInstr(\n\t\t\t\t\t\t0, GetTypeFromString(\"bool\"), \"OpUGreaterThanEqua\", GIIDx, SysThreadCountID\n\t\t\t\t\t);\n\t\t\t\t\tint MergeLabel = ++ctx.CurrentID;\n\t\t\t\t\tint TrueLabel = ++ctx.CurrentID;\n\t\t\t\t\tctx.AddInstrSelectionMerge(MergeLabel);\n\t\t\t\t\tctx.AddInstrBranchConditional(conditionID, TrueLabel, MergeLabel);\n\t\t\t\t\tctx.AddInstrLabel_AtFunctionBody(TrueLabel);\n\t\t\t\t\tctx.AddInstrReturn();\n\t\t\t\t\tctx.AddInstrLabel_AtFunctionBody(MergeLabel);\n\t\t\t\t}\n\n\t\t\t\tshaderWorld->Code->NameAllInstructions();\n\t\t\t\tGenerateCode(shaderWorld->Code.Ptr(), ctx.CurrentID);\n\n\t\t\t\tif (vertexOutputName.Length())\n\t\t\t\t{\n\t\t\t\t\tCompiledComponent ccomp;\n\t\t\t\t\tif (currentWorld->LocalComponents.TryGetValue(vertexOutputName, ccomp))\n\t\t\t\t\t{\n\t\t\t\t\t\tint valueID = ctx.AddInstrLoad(nullptr, ccomp.CodeOperand, MemoryAccess::None);\n\t\t\t\t\t\tint gl_PositionID = ctx.AddInstrAccessChain_StructMember(\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tctx.InterfaceNameToID[\"gl_PerVertex\"],\n\t\t\t\t\t\t\t\"gl_Position\"\n\t\t\t\t\t\t);\n\t\t\t\t\t\tctx.AddInstrStore(0, gl_PositionID, valueID);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow InvalidOperationException(\"can not find vertexOutputName\");\n\t\t\t\t}\n\n\t\t\t\t//MainFunction End\n\t\t\t\tctx.AddInstrReturn();\n\t\t\t\tctx.AddInstrFunctionEnd();\n\n\t\t\t\tctx.ProduceFunction();\n\n\t\t\t\tctx.PopScope();\n\n\t\t\t\tauto binaryForm = ctx.ProduceWordStream();\n\t\t\t\trs.BinaryCode.SetSize(binaryForm.Count() * sizeof(unsigned int));\n\t\t\t\tmemcpy(rs.BinaryCode.Buffer(), binaryForm.Buffer(), rs.BinaryCode.Count());\n\n\t\t\t\trs.MainCode = ctx.ProduceTextCode();\n\n\t\t\t\trs.OutputDeclarations = \"spirv\";\n\n\t\t\t\t//print IL \n\t\t\t\t{\n\t\t\t\t\tauto compiledProgram = result.Program.Ptr();\n\t\t\t\t\tStringBuilder sb;\n\n\t\t\t\t\t//function part\n\t\t\t\t\tsb << \"function\" << EndLine;\n\t\t\t\t\tsb << \"{\" << EndLine;\n\t\t\t\t\tfor (auto &pfunc : compiledProgram->Functions) {\n\t\t\t\t\t\tsb << pfunc->ReturnType->ToString() << \" \" << pfunc->Name << \"(\";\n\t\t\t\t\t\tbool first = true;\n\t\t\t\t\t\tfor (auto &name2param : pfunc->Parameters) {\n\t\t\t\t\t\t\tif (!first)\n\t\t\t\t\t\t\t\tsb << \", \";\n\t\t\t\t\t\t\tsb << name2param.Value->ToString() << \" \" << name2param.Key;\n\t\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsb << \")\" << EndLine;\n\t\t\t\t\t\tsb << \"{\" << EndLine;\n\t\t\t\t\t\tpfunc->Code->NameAllInstructions();\n\t\t\t\t\t\tsb << pfunc->Code->ToString() << EndLine;\n\t\t\t\t\t\tsb << \"}\" << EndLine;\n\t\t\t\t\t}\n\t\t\t\t\tsb << \"}\" << EndLine;\n\n\t\t\t\t\t//shader part\n\t\t\t\t\tfor (auto &pshader : compiledProgram->Shaders) {\n\t\t\t\t\t\tsb << \"Shader \" << pshader->MetaData.ShaderName << EndLine;\n\t\t\t\t\t\tsb << \"{\" << EndLine;\n\t\t\t\t\t\tfor (auto &pworld : pshader->Worlds) {\n\t\t\t\t\t\t\tsb << \"World \" << pworld.Key << EndLine;\n\t\t\t\t\t\t\tsb << \"{\" << EndLine;\n\t\t\t\t\t\t\tpworld.Value.Ptr()->Code->NameAllInstructions();\n\t\t\t\t\t\t\tsb << pworld.Value.Ptr()->Code->ToString() << EndLine;\n\t\t\t\t\t\t\tsb << \"}\" << EndLine;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsb << \"}\" << EndLine;\n\t\t\t\t\t}\n\n\t\t\t\t\tStringBuilder sb_indent;\n\t\t\t\t\tIndentString(sb_indent, sb.ToSt\\`ring());\n\t\t\t\t\tCoreLib::IO::StreamWriter sw(\"IL-\" + currentWorld->ShaderName + \"-\" + currentWorld->WorldOutput->Name + String(\".out\"));\n\t\t\t\t\tsw.Write(sb_indent.ToString());\n\t\t\t\t}\n\n\t\t\t\tcurrentWorld = nullptr;\n\n\t\t\t\treturn rs;\n\t\t\t\t*/\n\t\t\t}\n\n\t\t\tvirtual void SetParameters(const EnumerableDictionary<String, String>& arguments) override\n\t\t\t{\n\t\t\t\tbackendArguments = arguments;\n\t\t\t\tif (!arguments.TryGetValue(\"vertex\", vertexOutputName))\n\t\t\t\t\tvertexOutputName = \"\";\n\t\t\t}\n\t\t};\n\n\t\tCodeGenBackend * CreateSpirVCodeGen()\n\t\t{\n\t\t\treturn new SpirVCodeGen();\n\t\t}\n\t}\n}\n#endif"
  },
  {
    "path": "Source/SpireCore/SpireCore.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugClang|Win32\">\n      <Configuration>DebugClang</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugClang|x64\">\n      <Configuration>DebugClang</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug_VS2013|Win32\">\n      <Configuration>Debug_VS2013</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug_VS2013|x64\">\n      <Configuration>Debug_VS2013</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release_VS2013|Win32\">\n      <Configuration>Release_VS2013</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release_VS2013|x64\">\n      <Configuration>Release_VS2013</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>SpireCore</RootNamespace>\n    <ProjectName>SpireCore</ProjectName>\n    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140_clang_3_7</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140_Clang_3_7</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>../</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>../</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>EnableAllWarnings</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>../</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n      <RuntimeTypeInfo>true</RuntimeTypeInfo>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>../</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <BrowseInformation>true</BrowseInformation>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Bscmake>\n      <PreserveSbr>true</PreserveSbr>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>../</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <BrowseInformation>true</BrowseInformation>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Bscmake>\n      <PreserveSbr>true</PreserveSbr>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>../</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <BrowseInformation>true</BrowseInformation>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <Bscmake>\n      <PreserveSbr>true</PreserveSbr>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>../</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>../</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>../</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>../</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>false</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"CLikeCodeGen.h\" />\n    <ClInclude Include=\"Closure.h\" />\n    <ClInclude Include=\"CodeGenBackend.h\" />\n    <ClInclude Include=\"CodeWriter.h\" />\n    <ClInclude Include=\"CompiledProgram.h\" />\n    <ClInclude Include=\"DiagnosticDefs.h\" />\n    <ClInclude Include=\"Diagnostics.h\" />\n    <ClInclude Include=\"GetDependencyVisitor.h\" />\n    <ClInclude Include=\"Naming.h\" />\n    <ClInclude Include=\"Preprocessor.h\" />\n    <ClInclude Include=\"SamplerUsageAnalysis.h\" />\n    <ClInclude Include=\"Schedule.h\" />\n    <ClInclude Include=\"IL.h\" />\n    <ClInclude Include=\"Lexer.h\" />\n    <ClInclude Include=\"Parser.h\" />\n    <ClInclude Include=\"ScopeDictionary.h\" />\n    <ClInclude Include=\"ShaderCompiler.h\" />\n    <ClInclude Include=\"StringObject.h\" />\n    <ClInclude Include=\"SymbolTable.h\" />\n    <ClInclude Include=\"StdInclude.h\" />\n    <ClInclude Include=\"Syntax.h\" />\n    <ClInclude Include=\"SyntaxVisitors.h\" />\n    <ClInclude Include=\"TypeLayout.h\" />\n    <ClInclude Include=\"VariantIR.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"CLikeCodeGen.cpp\" />\n    <ClCompile Include=\"Closure.cpp\" />\n    <ClCompile Include=\"CodeGenerator.cpp\" />\n    <ClCompile Include=\"CompiledProgram.cpp\" />\n    <ClCompile Include=\"ConstantPool.cpp\" />\n    <ClCompile Include=\"Diagnostics.cpp\" />\n    <ClCompile Include=\"GetDependencyVisitor.cpp\" />\n    <ClCompile Include=\"GLSLCodeGen.cpp\" />\n    <ClCompile Include=\"HLSLCodeGen.cpp\" />\n    <ClCompile Include=\"InsertImplicitImportOperator.cpp\" />\n    <ClCompile Include=\"KeyHoleMatching.cpp\" />\n    <ClCompile Include=\"Naming.cpp\" />\n    <ClCompile Include=\"NewSpirVCodeGen.cpp\" />\n    <ClCompile Include=\"Preprocessor.cpp\" />\n    <ClCompile Include=\"SamplerUsageAnalysis.cpp\" />\n    <ClCompile Include=\"Schedule.cpp\" />\n    <ClCompile Include=\"IL.cpp\" />\n    <ClCompile Include=\"Lexer.cpp\" />\n    <ClCompile Include=\"ShaderCompiler.cpp\" />\n    <ClCompile Include=\"Parser.cpp\" />\n    <ClCompile Include=\"SemanticsVisitor.cpp\" />\n    <ClCompile Include=\"SpirVCodeGen.cpp\">\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\">true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"SymbolTable.cpp\" />\n    <ClCompile Include=\"StdInclude.cpp\" />\n    <ClCompile Include=\"Syntax.cpp\" />\n    <ClCompile Include=\"TypeLayout.cpp\" />\n    <ClCompile Include=\"VariantIR.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\CoreLib\\CoreLibBasic.vcxproj\">\n      <Project>{f9be7957-8399-899e-0c49-e714fddd4b65}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <Natvis Include=\"NatvisFile.natvis\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "Source/SpireCore/SpireCore.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Front End\">\n      <UniqueIdentifier>{d1e94d15-4d7f-41dd-937e-ae0f31fe5cd8}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Back End\">\n      <UniqueIdentifier>{bf6a2182-b6c8-4870-ac96-7cd4822903bf}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"Lexer.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Parser.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ScopeDictionary.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Syntax.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SyntaxVisitors.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"IL.h\">\n      <Filter>Back End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CodeWriter.h\">\n      <Filter>Back End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ShaderCompiler.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"StdInclude.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SymbolTable.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Schedule.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CompiledProgram.h\">\n      <Filter>Back End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CodeGenBackend.h\">\n      <Filter>Back End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Closure.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VariantIR.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"StringObject.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Naming.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CLikeCodeGen.h\">\n      <Filter>Back End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GetDependencyVisitor.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Diagnostics.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DiagnosticDefs.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Preprocessor.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TypeLayout.h\">\n      <Filter>Front End</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SamplerUsageAnalysis.h\">\n      <Filter>Back End</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"Lexer.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Syntax.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Parser.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SemanticsVisitor.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"IL.cpp\">\n      <Filter>Back End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ShaderCompiler.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"StdInclude.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"KeyHoleMatching.cpp\">\n      <Filter>Back End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SymbolTable.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Schedule.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GLSLCodeGen.cpp\">\n      <Filter>Back End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ConstantPool.cpp\">\n      <Filter>Back End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CompiledProgram.cpp\">\n      <Filter>Back End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Closure.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SpirVCodeGen.cpp\">\n      <Filter>Back End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"NewSpirVCodeGen.cpp\">\n      <Filter>Back End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CodeGenerator.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VariantIR.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"InsertImplicitImportOperator.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Naming.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"HLSLCodeGen.cpp\">\n      <Filter>Back End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CLikeCodeGen.cpp\">\n      <Filter>Back End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GetDependencyVisitor.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Diagnostics.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Preprocessor.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TypeLayout.cpp\">\n      <Filter>Front End</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SamplerUsageAnalysis.cpp\">\n      <Filter>Back End</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Natvis Include=\"NatvisFile.natvis\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Source/SpireCore/StdInclude.cpp",
    "content": "#include \"StdInclude.h\"\n#include \"Syntax.h\"\n\nconst char * LibIncludeString = R\"(\n__intrinsic float dFdx(float v);\n__intrinsic float dFdy(float v);\n__intrinsic float fwidth(float v);\n__intrinsic vec2 dFdx(vec2 v);\n__intrinsic vec2 dFdy(vec2 v);\n__intrinsic vec2 fwidth(vec2 v);\n__intrinsic vec3 dFdx(vec3 v);\n__intrinsic vec3 dFdy(vec3 v);\n__intrinsic vec3 fwidth(vec3 v);\n__intrinsic vec4 dFdx(vec4 v);\n__intrinsic vec4 dFdy(vec4 v);\n__intrinsic vec4 fwidth(vec4 v);\n\n__intrinsic float ddx(float v);\n__intrinsic float ddy(float v);\n__intrinsic vec2 ddx(vec2 v);\n__intrinsic vec2 ddy(vec2 v);\n__intrinsic vec3 ddx(vec3 v);\n__intrinsic vec3 ddy(vec3 v);\n__intrinsic vec4 ddx(vec4 v);\n__intrinsic vec4 ddy(vec4 v);\n\n__intrinsic float intBitsToFloat(int x);\n__intrinsic int floatBitsToInt(float x);\n\n__intrinsic vec3 normalize(vec3 v);\n__intrinsic float dot(vec2 v0, vec2 v1);\n__intrinsic float dot(vec3 v0, vec3 v1);\n__intrinsic float dot(vec4 v0, vec4 v1);\n__intrinsic float sin(float v);\n__intrinsic float cos(float v);\n__intrinsic float tan(float v);\n__intrinsic float sqrt(float v);\n__intrinsic vec2 sin(vec2 v);\n__intrinsic vec2 cos(vec2 v);\n__intrinsic vec2 tan(vec2 v);\n__intrinsic vec2 sqrt(vec2 v);\n__intrinsic vec3 sin(vec3 v);\n__intrinsic vec3 cos(vec3 v);\n__intrinsic vec3 tan(vec3 v);\n__intrinsic vec3 sqrt(vec3 v);\n__intrinsic vec4 sin(vec4 v);\n__intrinsic vec4 cos(vec4 v);\n__intrinsic vec4 tan(vec4 v);\n__intrinsic vec4 sqrt(vec4 v);\n__intrinsic float abs(float v);\n__intrinsic vec2 abs(vec2 v);\n__intrinsic vec3 abs(vec3 v);\n__intrinsic vec4 abs(vec4 v);\n\n__intrinsic float exp(float v);\n__intrinsic vec2 exp(vec2 v);\n__intrinsic vec3 exp(vec3 v);\n__intrinsic vec4 exp(vec4 v);\n\n__intrinsic float log(float v);\n__intrinsic vec2 log(vec2 v);\n__intrinsic vec3 log(vec3 v);\n__intrinsic vec4 log(vec4 v);\n\n__intrinsic float exp2(float v);\n__intrinsic vec2 exp2(vec2 v);\n__intrinsic vec3 exp2(vec3 v);\n__intrinsic vec4 exp2(vec4 v);\n\n__intrinsic float log2(float v);\n__intrinsic vec2 log2(vec2 v);\n__intrinsic vec3 log2(vec3 v);\n__intrinsic vec4 log2(vec4 v);\n\n__intrinsic float asin(float v);\n__intrinsic vec2 asin(vec2 v);\n__intrinsic vec3 asin(vec3 v);\n__intrinsic vec4 asin(vec4 v);\n\n__intrinsic float acos(float v);\n__intrinsic vec2 acos(vec2 v);\n__intrinsic vec3 acos(vec3 v);\n__intrinsic vec4 acos(vec4 v);\n\n__intrinsic float atan(float v);\n__intrinsic vec2 atan(vec2 v);\n__intrinsic vec3 atan(vec3 v);\n__intrinsic vec4 atan(vec4 v);\n\n__intrinsic float sign(float x);\n__intrinsic vec2 sign(vec2 x);\n__intrinsic vec3 sign(vec3 x);\n__intrinsic vec4 sign(vec4 x);\n\n__intrinsic float pow(float base, float e);\n__intrinsic vec2 pow(vec2 base, vec2 e);\n__intrinsic vec3 pow(vec3 base, vec3 e);\n__intrinsic vec4 pow(vec4 base, vec4 e);\n__intrinsic float atan2(float x, float y);\n__intrinsic float floor(float v);\n__intrinsic vec2 floor(vec2 v);\n__intrinsic vec3 floor(vec3 v);\n__intrinsic vec4 floor(vec4 v);\n__intrinsic float fract(float v);\n__intrinsic vec2 fract(vec2 v);\n__intrinsic vec3 fract(vec3 v);\n__intrinsic vec4 fract(vec4 v);\n__intrinsic float ceil(float v);\n__intrinsic vec2 ceil(vec2 v);\n__intrinsic vec3 ceil(vec3 v);\n__intrinsic vec4 ceil(vec4 v);\n__intrinsic float step(float v, float y);\n__intrinsic vec2 step(vec2 v, vec2 v1);\n__intrinsic vec3 step(vec3 v, vec3 v1);\n__intrinsic vec4 step(vec4 v, vec4 v1);\n__intrinsic float smoothstep(float e0, float e1, float v);\n__intrinsic vec2 smoothstep(vec2 e0, vec2 e1, vec2 v);\n__intrinsic vec3 smoothstep(vec3 e0, vec3 e1, vec3 v);\n__intrinsic vec4 smoothstep(vec4 e0, vec4 e1, vec4 v);\n__intrinsic vec4 Sample(Texture2D tex, SamplerState sampler, vec2 uv);\n__intrinsic vec4 Sample(Texture2D tex, SamplerState sampler, vec2 uv, ivec2 offset);\n__intrinsic vec4 Sample(Texture2DArray tex, SamplerState sampler, vec3 uv, ivec3 offset);\n__intrinsic vec4 Sample(TextureCube tex, SamplerState sampler, vec3 uv);\n__intrinsic vec4 Sample(Texture3D tex, SamplerState sampler, vec3 uv);\n__intrinsic vec4 Sample(Texture2DArray tex, SamplerState sampler, vec3 uv);\n__intrinsic vec4 Sample(TextureCubeArray tex, SamplerState sampler, vec4 uv);\n__intrinsic vec4 SampleLevel(Texture2D tex, SamplerState sampler, vec2 uv, float lod);\n__intrinsic vec4 SampleLevel(TextureCube tex, SamplerState sampler, vec3 uv, float lod);\n__intrinsic vec4 SampleLevel(Texture3D tex, SamplerState sampler, vec3 uv, float lod);\n__intrinsic vec4 SampleLevel(TextureCubeArray tex, SamplerState sampler, vec4 uv, float lod);\n__intrinsic float SampleCmp(Texture2DShadow tex, SamplerComparisonState s, vec2 location, float compareValue, ivec2 offset);\n__intrinsic float SampleCmp(Texture2DShadow tex, SamplerComparisonState s, vec2 location, float compareValue);\n__intrinsic float SampleCmp(Texture2DArrayShadow tex, SamplerComparisonState s, vec3 location, float compareValue, ivec2 offset);\n__intrinsic float SampleCmp(Texture2DArrayShadow tex, SamplerComparisonState s, vec3 location, float compareValue);\n__intrinsic float SampleCmp(TextureCubeShadowArray tex, SamplerComparisonState s, vec4 location, float compareValue);\n__intrinsic vec4 SampleGrad(Texture2D tex, SamplerState sampler, vec2 uv, vec2 ddx, vec2 ddy);\n__intrinsic vec4 SampleGrad(Texture2D tex, SamplerState sampler, vec2 uv, vec2 ddx, vec2 ddy, ivec2 offset);\n__intrinsic vec4 SampleGrad(TextureCube tex, SamplerState sampler, vec3 uv, vec3 ddx, vec3 ddy);\n__intrinsic vec4 SampleGrad(TextureCubeArray tex, SamplerState sampler, vec4 uv, vec3 ddx, vec3 ddy);\n__intrinsic vec4 SampleBias(Texture2D tex, SamplerState sampler, vec2 uv, float bias);\n__intrinsic vec4 SampleBias(Texture2D tex, SamplerState sampler, vec2 uv, float bias, ivec2 offset);\n__intrinsic vec4 SampleBias(TextureCube tex, SamplerState sampler, vec3 uv, float bias);\n__intrinsic vec4 SampleBias(TextureCubeArray tex, SamplerState sampler, vec4 uv, float bias);\n__intrinsic vec4 SampleBias(Texture2DArray tex, SamplerState sampler, vec3 uv, float bias);\n__intrinsic vec4 Load(Texture2D tex, int3 location);\n__intrinsic vec4 Load(Texture2D tex, int3 location, ivec2 offset);\n__intrinsic vec4 Load(Texture3D tex, int4 location);\n__intrinsic float diff(float v);\n__intrinsic float mod(float x, float y);\n__intrinsic float max(float v);\n__intrinsic float min(float v);\n__intrinsic float max(float v, float v1);\n__intrinsic float min(float v, float v1);\n__intrinsic vec2 max(vec2 v, vec2 v1);\n__intrinsic vec2 min(vec2 v, vec2 v1);\n__intrinsic vec3 max(vec3 v, vec3 v1);\n__intrinsic vec3 min(vec3 v, vec3 v1);\n__intrinsic vec4 max(vec4 v, vec4 v1);\n__intrinsic vec4 min(vec4 v, vec4 v1);\n__intrinsic vec2 max(vec2 v, float v1);\n__intrinsic vec2 min(vec2 v, float v1);\n__intrinsic vec3 max(vec3 v, float v1);\n__intrinsic vec3 min(vec3 v, float v1);\n__intrinsic vec4 max(vec4 v, float v1);\n__intrinsic vec4 min(vec4 v, float v1);\n__intrinsic float clamp(float v, float v1, float v2);\n__intrinsic vec2 clamp(vec2 v, vec2 v1, vec2 v2);\n__intrinsic vec3 clamp(vec3 v, vec3 v1, vec3 v2);\n__intrinsic vec4 clamp(vec4 v, vec4 v1, vec4 v2);\n__intrinsic vec2 clamp(vec2 v, float v1, float v2);\n__intrinsic vec3 clamp(vec3 v, float v1, float v2);\n__intrinsic vec4 clamp(vec4 v, float v1, float v2);\n\n__intrinsic vec3 reflect(vec3 I, vec3 N);\n__intrinsic vec3 refract(vec3 I, vec3 N, float eta);\n\n__intrinsic float length(vec2 v);\n__intrinsic float length(vec3 v);\n__intrinsic float length(vec4 v);\n\n__intrinsic void alphaTest(float alpha, float threshold);\n__intrinsic vec3 mix(vec3 v0, vec3 v1, float t);\n__intrinsic vec4 mix(vec4 v0, vec4 v1, float t);\n__intrinsic vec2 mix(vec2 v0, vec2 v1, float t);\n__intrinsic float mix(float v0, float v1, float t);\n__intrinsic vec3 mix(vec3 v0, vec3 v1, vec3 t);\n__intrinsic vec4 mix(vec4 v0, vec4 v1, vec4 t);\n__intrinsic vec2 mix(vec2 v0, vec2 v1, vec2 t);\n\n__intrinsic vec3 lerp(vec3 v0, vec3 v1, float t);\n__intrinsic vec4 lerp(vec4 v0, vec4 v1, float t);\n__intrinsic vec2 lerp(vec2 v0, vec2 v1, float t);\n__intrinsic float lerp(float v0, float v1, float t);\n__intrinsic vec3 lerp(vec3 v0, vec3 v1, vec3 t);\n__intrinsic vec4 lerp(vec4 v0, vec4 v1, vec4 t);\n__intrinsic vec2 lerp(vec2 v0, vec2 v1, vec2 t);\n\n__intrinsic mat3 mat3(vec3 a, vec3 b, vec3 c);\n__intrinsic mat3 mat3(float a0, float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8);\n__intrinsic mat4 mat4(vec4 a, vec4 b, vec4 c, vec4 d);\n__intrinsic mat4 mat4(float a0, float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8, float a9, float a10, float a11, float a12, float a13, float a14, float a15);\n__intrinsic vec3 cross(vec3 v1, vec3 v2);\n__intrinsic float float(float v);\n__intrinsic int int(int v);\n__intrinsic uint uint(uint v);\n__intrinsic bool bool(bool v);\n__intrinsic vec2 vec2(float v);\n__intrinsic vec3 vec3(float v);\n__intrinsic vec4 vec4(float v);\n__intrinsic vec2 vec2(float x, float y);\n__intrinsic vec3 vec3(float x, float y, float z);\n__intrinsic vec3 vec3(vec2 v, float z);\n__intrinsic vec4 vec4(float x, float y, float z, float w);\n__intrinsic vec4 vec4(vec3 v, float w);\n__intrinsic vec4 vec4(vec2 v, float z, float w);\n__intrinsic vec4 vec4(vec2 v, vec2 w);\n__intrinsic ivec2 ivec2(int x, int y);\n__intrinsic ivec3 ivec3(int x, int y, int z);\n__intrinsic ivec3 ivec3(ivec2 v, int z);\n__intrinsic ivec4 ivec4(int x, int y, int z, int w);\n__intrinsic ivec4 ivec4(ivec3 v, int w);\n__intrinsic ivec4 ivec4(ivec2 v, int z, int w);\n__intrinsic ivec4 ivec4(ivec2 v, ivec2 w);\n\n__intrinsic uvec2 uvec2(uint x, uint y);\n__intrinsic uvec3 uvec3(uint x, uint y, uint z);\n__intrinsic uvec3 uvec3(uvec2 v, uint z);\n__intrinsic uvec4 uvec4(uint x, uint y, uint z, uint w);\n__intrinsic uvec4 uvec4(uvec3 v, uint w);\n__intrinsic uvec4 uvec4(uvec2 v, uint z, uint w);\n__intrinsic uvec4 uvec4(uvec2 v, uvec2 w);\n\n__intrinsic int int(uint val);\n__intrinsic int int(float val);\n__intrinsic ivec2 ivec2(uvec2 val);\n__intrinsic ivec2 ivec2(vec2 val);\n__intrinsic ivec3 ivec3(uvec3 val);\n__intrinsic ivec3 ivec3(vec3 val);\n__intrinsic ivec4 ivec4(uvec4 val);\n__intrinsic ivec4 ivec4(vec4 val);\n\n__intrinsic uint uint(int val);\n__intrinsic uint uint(float val);\n__intrinsic uvec2 uvec2(ivec2 val);\n__intrinsic uvec2 uvec2(vec2 val);\n__intrinsic uvec3 uvec3(ivec3 val);\n__intrinsic uvec3 uvec3(vec3 val);\n__intrinsic uvec4 uvec4(ivec4 val);\n__intrinsic uvec4 uvec4(vec4 val);\n\n__intrinsic float float(int val);\n__intrinsic float float(uint val);\n__intrinsic vec2 vec2(ivec2 val);\n__intrinsic vec2 vec2(uvec2 val);\n__intrinsic vec3 vec3(ivec3 val);\n__intrinsic vec3 vec3(uvec3 val);\n__intrinsic vec4 vec4(ivec4 val);\n__intrinsic vec4 vec4(uvec4 val);\n\n__intrinsic mat3 transpose(mat3 in);\n__intrinsic mat4 transpose(mat4 in);\n__intrinsic mat3 mat3(mat4 in);\n\n__intrinsic float saturate(float v);\n__intrinsic vec2 saturate(vec2 v);\n__intrinsic vec3 saturate(vec3 v);\n__intrinsic vec4 saturate(vec4 v);\n\nstruct trait __intrinsic {};\n__intrinsic trait IsTriviallyPassable(float);\n__intrinsic trait IsTriviallyPassable(vec2);\n__intrinsic trait IsTriviallyPassable(vec3);\n__intrinsic trait IsTriviallyPassable(vec4);\n__intrinsic trait IsTriviallyPassable(mat3);\n__intrinsic trait IsTriviallyPassable(mat4);\n__intrinsic trait IsTriviallyPassable(int);\n__intrinsic trait IsTriviallyPassable(ivec2);\n__intrinsic trait IsTriviallyPassable(ivec3);\n__intrinsic trait IsTriviallyPassable(ivec4);\n__intrinsic trait IsTriviallyPassable(uint);\n__intrinsic trait IsTriviallyPassable(uvec2);\n__intrinsic trait IsTriviallyPassable(uvec3);\n__intrinsic trait IsTriviallyPassable(uvec4);\n__intrinsic trait IsTriviallyPassable(bool);\n#line default\n)\";\n\nusing namespace CoreLib::Basic;\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tString SpireStdLib::code;\n\n\t\tString SpireStdLib::GetCode()\n\t\t{\n\t\t\tif (code.Length() > 0)\n\t\t\t\treturn code;\n\t\t\tStringBuilder sb;\n\t\t\t// generate operator overloads\n\t\t\tOperator floatUnaryOps[] = { Operator::Neg, Operator::Not, Operator::PreInc, Operator::PreDec };\n\t\t\tOperator intUnaryOps[] = { Operator::Neg, Operator::Not, Operator::BitNot, Operator::PreInc, Operator::PreDec};\n\t\t\tOperator floatOps[] = { Operator::Mul, Operator::Div,\n\t\t\t\tOperator::Add, Operator::Sub, Operator::And, Operator::Or,\n\t\t\t\tOperator::Eql, Operator::Neq, Operator::Greater, Operator::Less, Operator::Geq, Operator::Leq };\n\t\t\tOperator intOps[] = {  Operator::Mul, Operator::Div, Operator::Mod,\n\t\t\t\tOperator::Add, Operator::Sub,\n\t\t\t\tOperator::Lsh, Operator::Rsh,\n\t\t\t\tOperator::Eql, Operator::Neq, Operator::Greater, Operator::Less, Operator::Geq, Operator::Leq,\n\t\t\t\tOperator::BitAnd, Operator::BitXor, Operator::BitOr,\n\t\t\t\tOperator::And,\n\t\t\t\tOperator::Or };\n\t\t\tString floatTypes[] = { \"float\", \"vec2\", \"vec3\", \"vec4\" };\n\t\t\tString intTypes[] = { \"int\", \"ivec2\", \"ivec3\", \"ivec4\" };\n\t\t\tString uintTypes[] = { \"uint\", \"uvec2\", \"uvec3\", \"uvec4\" };\n\n\t\t\tsb << \"__intrinsic vec3 operator * (vec3, mat3);\\n\";\n\t\t\tsb << \"__intrinsic vec3 operator * (mat3, vec3);\\n\";\n\n\t\t\tsb << \"__intrinsic vec4 operator * (vec4, mat4);\\n\";\n\t\t\tsb << \"__intrinsic vec4 operator * (mat4, vec4);\\n\";\n\n\t\t\tsb << \"__intrinsic mat3 operator * (mat3, mat3);\\n\";\n\t\t\tsb << \"__intrinsic mat4 operator * (mat4, mat4);\\n\";\n\n\t\t\tsb << \"__intrinsic bool operator && (bool, bool);\\n\";\n\t\t\tsb << \"__intrinsic bool operator || (bool, bool);\\n\";\n\n\t\t\tfor (auto type : intTypes)\n\t\t\t{\n\t\t\t\tsb << \"__intrinsic bool operator && (bool, \" << type << \");\\n\";\n\t\t\t\tsb << \"__intrinsic bool operator || (bool, \" << type << \");\\n\";\n\t\t\t\tsb << \"__intrinsic bool operator && (\" << type << \", bool);\\n\";\n\t\t\t\tsb << \"__intrinsic bool operator || (\" << type << \", bool);\\n\";\n\t\t\t}\n\n\t\t\tfor (auto op : intUnaryOps)\n\t\t\t{\n\t\t\t\tString opName = GetOperatorFunctionName(op);\n\t\t\t\tfor (int i = 0; i < 4; i++)\n\t\t\t\t{\n\t\t\t\t\tauto itype = intTypes[i];\n\t\t\t\t\tauto utype = uintTypes[i];\n\t\t\t\t\tfor (int j = 0; j < 2; j++)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto retType = (op == Operator::Not) ? \"bool\" : j == 0 ? itype : utype;\n\t\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << (j == 0 ? itype : utype) << \");\\n\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (auto op : floatUnaryOps)\n\t\t\t{\n\t\t\t\tString opName = GetOperatorFunctionName(op);\n\t\t\t\tfor (int i = 0; i < 4; i++)\n\t\t\t\t{\n\t\t\t\t\tauto type = floatTypes[i];\n\t\t\t\t\tauto retType = (op == Operator::Not) ? \"bool\" : type;\n\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << type << \");\\n\";\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (auto op : floatOps)\n\t\t\t{\n\t\t\t\tString opName = GetOperatorFunctionName(op);\n\t\t\t\tfor (int i = 0; i < 4; i++)\n\t\t\t\t{\n\t\t\t\t\tauto type = floatTypes[i];\n\t\t\t\t\tauto itype = intTypes[i];\n\t\t\t\t\tauto utype = uintTypes[i];\n\t\t\t\t\tauto retType = ((op >= Operator::Eql && op <= Operator::Leq) || op == Operator::And || op == Operator::Or) ? \"bool\" : type;\n\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << type << \", \" << type << \");\\n\";\n\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << itype << \", \" << type << \");\\n\";\n\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << utype << \", \" << type << \");\\n\";\n\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << type << \", \" << itype << \");\\n\";\n\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << type << \", \" << utype << \");\\n\";\n\t\t\t\t\tif (i > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << type << \", \" << floatTypes[0] << \");\\n\";\n\t\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << floatTypes[0] << \", \" << type << \");\\n\";\n\n\t\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << type << \", \" << intTypes[0] << \");\\n\";\n\t\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << intTypes[0] << \", \" << type << \");\\n\";\n\n\t\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << type << \", \" << uintTypes[0] << \");\\n\";\n\t\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << uintTypes[0] << \", \" << type << \");\\n\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (auto op : intOps)\n\t\t\t{\n\t\t\t\tString opName = GetOperatorFunctionName(op);\n\t\t\t\tfor (int i = 0; i < 4; i++)\n\t\t\t\t{\n\t\t\t\t\tauto type = intTypes[i];\n\t\t\t\t\tauto utype = uintTypes[i];\n\t\t\t\t\tauto retType = ((op >= Operator::Eql && op <= Operator::Leq) || op == Operator::And || op == Operator::Or) ? \"bool\" : type;\n\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << type << \", \" << type << \");\\n\";\n\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << utype << \", \" << type << \");\\n\";\n\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << type << \", \" << utype << \");\\n\";\n\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << utype << \", \" << utype << \");\\n\";\n\t\t\t\t\tif (i > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << type << \", \" << intTypes[0] << \");\\n\";\n\t\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << intTypes[0] << \", \" << type << \");\\n\";\n\n\t\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << type << \", \" << uintTypes[0] << \");\\n\";\n\t\t\t\t\t\tsb << \"__intrinsic \" << retType << \" operator \" << opName << \"(\" << uintTypes[0] << \", \" << type << \");\\n\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tsb << LibIncludeString;\n\t\t\tcode = sb.ProduceString();\n\t\t\treturn code;\n\t\t}\n\n\t\tvoid SpireStdLib::Finalize()\n\t\t{\n\t\t\tcode = nullptr;\n\t\t}\n\n\t}\n}\n\n"
  },
  {
    "path": "Source/SpireCore/StdInclude.h",
    "content": "#ifndef SHADER_COMPILER_STD_LIB_H\n#define SHADER_COMPILER_STD_LIB_H\n\n#include \"../CoreLib/Basic.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tclass SpireStdLib\n\t\t{\n\t\tprivate:\n\t\t\tstatic CoreLib::String code;\n\t\tpublic:\n\t\t\tstatic CoreLib::String GetCode();\n\t\t\tstatic void Finalize();\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/StringObject.h",
    "content": "#ifndef SPIRE_STRING_OBJECT_H\n#define SPIRE_STRING_OBJECT_H\n\n#include \"../CoreLib/Basic.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tclass StringObject : public CoreLib::Object\n\t\t{\n\t\tpublic:\n\t\t\tCoreLib::String Content;\n\t\t\tStringObject() {}\n\t\t\tStringObject(const CoreLib::String & str)\n\t\t\t\t: Content(str)\n\t\t\t{}\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/SymbolTable.cpp",
    "content": "#include \"SymbolTable.h\"\n#include \"ShaderCompiler.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\n\t\tbool SymbolTable::SortShaders()\n\t\t{\n\t\t\tHashSet<ShaderSymbol*> shaderSet;\n\t\t\tShaderDependenceOrder.Clear();\n\t\t\tList<ShaderSymbol *> nextShaders, currentShaders;\n\t\t\t// sort shaders in dependency order\n\t\t\tfor (auto & shader : Shaders)\n\t\t\t{\n\t\t\t\tif (shader.Value->DependentShaders.Count() == 0)\n\t\t\t\t{\n\t\t\t\t\tShaderDependenceOrder.Add(shader.Value.Ptr());\n\t\t\t\t\tshaderSet.Add(shader.Value.Ptr());\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tcurrentShaders.Add(shader.Value.Ptr());\n\t\t\t}\n\t\t\twhile (currentShaders.Count())\n\t\t\t{\n\t\t\t\tnextShaders.Clear();\n\t\t\t\tfor (auto & shader : currentShaders)\n\t\t\t\t{\n\t\t\t\t\tbool pass = true;\n\t\t\t\t\tfor (auto & dshader : shader->DependentShaders)\n\t\t\t\t\t\tif (!shaderSet.Contains(dshader))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpass = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\tif (pass)\n\t\t\t\t\t{\n\t\t\t\t\t\tShaderDependenceOrder.Add(shader);\n\t\t\t\t\t\tshaderSet.Add(shader);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tnextShaders.Add(shader);\n\t\t\t\t}\n\t\t\t\tcurrentShaders.SwapWith(nextShaders);\n\t\t\t}\n\t\t\treturn (ShaderDependenceOrder.Count() == Shaders.Count());\n\t\t}\n\t\tvoid SymbolTable::EvalFunctionReferenceClosure()\n\t\t{\n\t\t\tfor (auto & func : Functions)\n\t\t\t{\n\t\t\t\tif (!func.Value->IsReferencedFunctionsTransitiveClosureEvaluated)\n\t\t\t\t{\n\t\t\t\t\tList<String> funcList;\n\t\t\t\t\tEnumerableHashSet<String> funcSet;\n\t\t\t\t\tfor (auto & ref : func.Value->ReferencedFunctions)\n\t\t\t\t\t{\n\t\t\t\t\t\tfuncList.Add(ref);\n\t\t\t\t\t\tfuncSet.Add(ref);\n\t\t\t\t\t}\n\t\t\t\t\tfor (int i = 0; i < funcList.Count(); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tRefPtr<FunctionSymbol> funcSym;\n\t\t\t\t\t\tif (Functions.TryGetValue(funcList[i], funcSym))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (funcSym->IsReferencedFunctionsTransitiveClosureEvaluated)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor (auto rfunc : funcSym->ReferencedFunctions)\n\t\t\t\t\t\t\t\t\tfuncSet.Add(rfunc);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor (auto rfunc : funcSym->ReferencedFunctions)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (funcSet.Add(rfunc))\n\t\t\t\t\t\t\t\t\t\tfuncList.Add(rfunc);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfunc.Value->ReferencedFunctions = _Move(funcSet);\n\t\t\t\t\tfunc.Value->IsReferencedFunctionsTransitiveClosureEvaluated = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tList<ImportPath>& PipelineSymbol::GetPaths(String srcWorld, String destWorld)\n\t\t{\n\t\t\tif (auto first = pathCache.TryGetValue(srcWorld))\n\t\t\t{\n\t\t\t\tif (auto second = first->TryGetValue(destWorld))\n\t\t\t\t\treturn *second;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tpathCache[srcWorld] = EnumerableDictionary<String, List<ImportPath>>();\n\t\t\t}\n\t\t\tauto path = FindPaths(srcWorld, destWorld);\n\t\t\tauto & dict = pathCache[srcWorld]();\n\t\t\tdict[destWorld] = _Move(path);\n\t\t\treturn dict[destWorld]();\n\t\t}\n\n\t\tList<ImportPath> PipelineSymbol::FindPaths(String worldSrc, String worldDest)\n\t\t{\n\t\t\tList<ImportPath> resultPaths;\n\t\t\tif (worldSrc == worldDest)\n\t\t\t\treturn resultPaths;\n\t\t\tList<ImportPath> paths, paths2;\n\t\t\tpaths.Add(ImportPath());\n\t\t\tpaths[0].Nodes.Add(ImportPath::Node(worldSrc, nullptr));\n\t\t\twhile (paths.Count())\n\t\t\t{\n\t\t\t\tpaths2.Clear();\n\t\t\t\tfor (auto & p : paths)\n\t\t\t\t{\n\t\t\t\t\tString world0 = p.Nodes.Last().TargetWorld;\n\t\t\t\t\tfor (auto op : SyntaxNode->GetImportOperators())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (op->SourceWorld.Content == world0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tImportPath np = p;\n\t\t\t\t\t\t\tif (op->GetParameters().Count() != 0)\n\t\t\t\t\t\t\t\tnp.IsImplicitPath = false;\n\t\t\t\t\t\t\tfor (auto &req : op->Requirements)\n\t\t\t\t\t\t\t\tnp.TypeRequirements.Add(req.Ptr());\n\t\t\t\t\t\t\tnp.Nodes.Add(ImportPath::Node(op->DestWorld.Content, op.Ptr()));\n\t\t\t\t\t\t\tif (op->DestWorld.Content == worldDest)\n\t\t\t\t\t\t\t\tresultPaths.Add(np);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tpaths2.Add(np);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpaths.SwapWith(paths2);\n\t\t\t}\n\t\t\treturn resultPaths;\n\t\t}\n\n\t\tbool PipelineSymbol::IsAbstractWorld(String world)\n\t\t{\n\t\t\tWorldSyntaxNode* worldDecl;\n\t\t\tif (Worlds.TryGetValue(world, worldDecl))\n\t\t\t\treturn worldDecl->IsAbstract();\n\t\t\treturn false;\n\t\t}\n\n\t\tbool PipelineSymbol::IsChildOf(PipelineSymbol * parentPipeline)\n\t\t{\n\t\t\tif (this == parentPipeline)\n\t\t\t\treturn true;\n\t\t\telse if (ParentPipeline)\n\t\t\t\treturn ParentPipeline->IsChildOf(parentPipeline);\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\n\t\tList<String>& PipelineSymbol::GetWorldTopologyOrder()\n\t\t{\n\t\t\tif (WorldTopologyOrder.Count() != 0)\n\t\t\t\treturn WorldTopologyOrder;\n\t\t\tList<String> rs;\n\t\t\tHashSet<String> rsSet;\n\t\t\tbool changed = true;\n\t\t\twhile (changed)\n\t\t\t{\n\t\t\t\tchanged = false;\n\t\t\t\tfor (auto & w : WorldDependency)\n\t\t\t\t{\n\t\t\t\t\tif (!rsSet.Contains(w.Key))\n\t\t\t\t\t{\n\t\t\t\t\t\tbool canAdd = true;\n\t\t\t\t\t\tfor (auto & dw : w.Value)\n\t\t\t\t\t\t\tif (!rsSet.Contains(dw))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcanAdd = false;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\tif (canAdd)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\trsSet.Add(w.Key);\n\t\t\t\t\t\t\trs.Add(w.Key);\n\t\t\t\t\t\t\tchanged = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tWorldTopologyOrder = _Move(rs);\n\t\t\treturn WorldTopologyOrder;\n\t\t}\n\t\t\n\t\tList<ImportOperatorDefSyntaxNode*> PipelineSymbol::GetImportOperatorsFromSourceWorld(String worldSrc)\n\t\t{\n\t\t\tList<ImportOperatorDefSyntaxNode*> rs;\n\t\t\tauto dict = ImportOperatorsByPath.TryGetValue(worldSrc);\n\t\t\tif (dict)\n\t\t\t{\n\t\t\t\tfor (auto & op : *dict)\n\t\t\t\t{\n\t\t\t\t\tfor (auto & x : op.Value)\n\t\t\t\t\t\trs.Add(x.Ptr());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\t\tvoid PipelineSymbol::AddImportOperator(RefPtr<ImportOperatorDefSyntaxNode> op)\n\t\t{\n\t\t\tauto list = ImportOperators.TryGetValue(op->Name.Content);\n\t\t\tif (!list)\n\t\t\t{\n\t\t\t\tImportOperators[op->Name.Content] = List<RefPtr<ImportOperatorDefSyntaxNode>>();\n\t\t\t\tlist = ImportOperators.TryGetValue(op->Name.Content);\n\t\t\t}\n\t\t\tlist->Add(op);\n\n\t\t\tauto first = ImportOperatorsByPath.TryGetValue(op->SourceWorld.Content);\n\t\t\tif (!first)\n\t\t\t{\n\t\t\t\tImportOperatorsByPath[op->SourceWorld.Content] = EnumerableDictionary<String, List<RefPtr<ImportOperatorDefSyntaxNode>>>();\n\t\t\t\tfirst = ImportOperatorsByPath.TryGetValue(op->SourceWorld.Content);\n\t\t\t}\n\n\t\t\tauto second = first->TryGetValue(op->DestWorld.Content);\n\t\t\tif (!second)\n\t\t\t{\n\t\t\t\t(*first)[op->DestWorld.Content] = List<RefPtr<ImportOperatorDefSyntaxNode>>();\n\t\t\t\tsecond = first->TryGetValue(op->DestWorld.Content);\n\t\t\t}\n\t\t\tsecond->Add(op);\n\t\t}\n\n\t\tList<ShaderComponentSymbol*> ShaderSymbol::GetComponentDependencyOrder()\n\t\t{\n\t\t\tList<ShaderComponentSymbol*> components;\n\n\t\t\tfor (auto & comp : Components)\n\t\t\t{\n\t\t\t\tcomponents.Add(comp.Value.Ptr());\n\t\t\t}\n\t\t\tSortComponents(components);\n\t\t\treturn components;\n\t\t}\n\t\tvoid ShaderSymbol::SortComponents(List<ShaderComponentSymbol*>& comps)\n\t\t{\n\t\t\tcomps.Sort([&](ShaderComponentSymbol*c0, ShaderComponentSymbol*c1)\n\t\t\t{\n\t\t\t\treturn c0->Implementations.First()->SyntaxNode->Position < c1->Implementations.First()->SyntaxNode->Position;\n\t\t\t});\n\t\t\tHashSet<ShaderComponentSymbol*> allSymbols, addedSymbols;\n\t\t\tfor (auto & comp : comps)\n\t\t\t\tallSymbols.Add(comp);\n\t\t\tList<ShaderComponentSymbol*> sorted;\n\t\t\tbool changed = true;\n\t\t\twhile (changed)\n\t\t\t{\n\t\t\t\tchanged = false;\n\t\t\t\tfor (auto & comp : comps)\n\t\t\t\t{\n\t\t\t\t\tif (!addedSymbols.Contains(comp))\n\t\t\t\t\t{\n\t\t\t\t\t\tbool isFirst = true;\n\t\t\t\t\t\tfor (auto & impl : comp->Implementations)\n\t\t\t\t\t\t\tfor (auto & dep : impl->DependentComponents)\n\t\t\t\t\t\t\t\tif (allSymbols.Contains(dep.Key) && !addedSymbols.Contains(dep.Key))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tisFirst = false;\n\t\t\t\t\t\t\t\t\tgoto loopEnd;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\tloopEnd:;\n\t\t\t\t\t\tif (isFirst)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taddedSymbols.Add(comp);\n\t\t\t\t\t\t\tsorted.Add(comp);\n\t\t\t\t\t\t\tchanged = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcomps = _Move(sorted);\n\t\t}\n\n\t\tShaderSymbol::ComponentReference ShaderSymbol::ResolveComponentReference(String compName, bool topLevel)\n\t\t{\n\t\t\tComponentReference result;\n\t\t\tresult.IsAccessible = true;\n\t\t\tRefPtr<ShaderComponentSymbol> refComp, privateRefComp;\n\t\t\tif (Components.TryGetValue(compName, refComp))\n\t\t\t{\n\t\t\t\tresult.Component = refComp.Ptr();\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tfor (auto & shaderUsing : ShaderUsings)\n\t\t\t{\n\t\t\t\tif (shaderUsing.Shader->Components.TryGetValue(compName, refComp))\n\t\t\t\t{\n\t\t\t\t\tif (refComp->Implementations.First()->SyntaxNode->IsPublic())\n\t\t\t\t\t{\n\t\t\t\t\t\tresult.Component = refComp.Ptr();\n\t\t\t\t\t\tresult.IsAccessible = true;\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tresult.Component = refComp.Ptr();\n\t\t\t\t\t\tresult.IsAccessible = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (shaderUsing.IsPublic || topLevel)\n\t\t\t\t{\n\t\t\t\t\tauto rresult = shaderUsing.Shader->ResolveComponentReference(compName, false);\n\t\t\t\t\tif (rresult.IsAccessible)\n\t\t\t\t\t\treturn rresult;\n\t\t\t\t\telse\n\t\t\t\t\t\tresult = rresult;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (ParentPipeline && ParentPipeline->Components.TryGetValue(compName, refComp))\n\t\t\t{\n\t\t\t\tif (!refComp->IsRequire())\n\t\t\t\t{\n\t\t\t\t\tresult.Component = refComp.Ptr();\n\n                    // HACK(tfoley): I'm not sure if this is a valid bug fix or not.\n                    result.IsAccessible = true;\n\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult.IsAccessible = false;\n\t\t\treturn result;\n\t\t}\n\n\t\tbool SymbolTable::CheckComponentImplementationConsistency(DiagnosticSink * err, ShaderComponentSymbol * comp, ShaderComponentImplSymbol * impl)\n\t\t{\n\t\t\tbool rs = true;\n\t\t\tif (impl->SyntaxNode->Rate)\n\t\t\t{\n\t\t\t\tfor (auto & cimpl : comp->Implementations)\n\t\t\t\t{\n\t\t\t\t\tfor (auto & w : cimpl->Worlds)\n\t\t\t\t\t\tif (impl->Worlds.Contains(w))\n\t\t\t\t\t\t{\n                            err->diagnose(impl->SyntaxNode->Position, Diagnostics::componentIsAlreadyDefinedInThatWorld, comp->Name, w);\n\t\t\t\t\t\t\trs = false;\n\t\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (auto & cimpl : comp->Implementations)\n\t\t\t\t{\n\t\t\t\t\tif (cimpl->Worlds.Count() == 0 && impl->Worlds.Count() == 0)\n\t\t\t\t\t{\n                        err->diagnose(impl->SyntaxNode->Position, Diagnostics::componentIsAlreadyDefined, comp->Name);\n\t\t\t\t\t\trs = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (auto & cimpl : comp->Implementations)\n\t\t\t{\n\t\t\t\tif (impl->SyntaxNode->IsOutput() != cimpl->SyntaxNode->IsOutput())\n\t\t\t\t{\n                    err->diagnose(impl->SyntaxNode->Position,\n                        Diagnostics::inconsistentSignatureForComponent,\n                        comp->Name);\n                    err->diagnose(cimpl->SyntaxNode->Position,\n                        Diagnostics::seePreviousDefinition);\n\t\t\t\t\trs = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (impl->SyntaxNode->IsRequire() != cimpl->SyntaxNode->IsRequire())\n\t\t\t\t{\n                    err->diagnose(impl->SyntaxNode->Position,\n                        Diagnostics::inconsistentSignatureForComponent,\n                        comp->Name);\n                    err->diagnose(cimpl->SyntaxNode->Position,\n                        Diagnostics::seePreviousDefinition);\n\t\t\t\t\trs = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (impl->SyntaxNode->IsPublic() != cimpl->SyntaxNode->IsPublic())\n\t\t\t\t{\n                    err->diagnose(impl->SyntaxNode->Position,\n                        Diagnostics::inconsistentSignatureForComponent,\n                        comp->Name);\n                    err->diagnose(cimpl->SyntaxNode->Position,\n                        Diagnostics::seePreviousDefinition);\n\t\t\t\t\trs = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (!impl->SyntaxNode->Type->Equals(cimpl->SyntaxNode->Type.Ptr()))\n\t\t\t\t{\n                    err->diagnose(impl->SyntaxNode->Position,\n                        Diagnostics::inconsistentSignatureForComponent,\n                        comp->Name);\n                    err->diagnose(cimpl->SyntaxNode->Position,\n                        Diagnostics::seePreviousDefinition);\n\t\t\t\t\trs = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (impl->SyntaxNode->IsRequire() && comp->Implementations.Count() != 0)\n\t\t\t{\n                err->diagnose(impl->SyntaxNode->Position,\n                    Diagnostics::parameterNameConflictsWithExistingDefinition, comp->Name);\n\t\t\t\trs = false;\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\n\t\tString PrintType(RefPtr<ExpressionType> type, String recordReplaceStr)\n\t\t{\n\t\t\tif (auto basic = type->AsBasicType())\n\t\t\t{\n\t\t\t\tif (basic->BaseType == BaseType::Generic)\n\t\t\t\t\treturn recordReplaceStr;\n\t\t\t\telse\n\t\t\t\t\treturn basic->ToString();\n\t\t\t}\n\t\t\telse if (auto arr = type.As<ArrayExpressionType>())\n\t\t\t{\n\t\t\t\tif (arr->ArrayLength > 0)\n\t\t\t\t\treturn PrintType(arr->BaseType, recordReplaceStr) + \"[\" + arr->ArrayLength + \"]\";\n\t\t\t\telse\n\t\t\t\t\treturn PrintType(arr->BaseType, recordReplaceStr) + \"[]\";\n\t\t\t}\n\t\t\telse if (auto gen = type.As<GenericExpressionType>())\n\t\t\t{\n\t\t\t\treturn gen->GenericTypeName + \"<\" + PrintType(gen->BaseType, recordReplaceStr) + \">\";\n\t\t\t}\n\t\t\treturn \"\";\n\t\t}\n\n\t\tbool SymbolTable::CheckTypeRequirement(const ImportPath & p, RefPtr<ExpressionType> type)\n\t\t{\n\t\t\tfor (auto & req : p.TypeRequirements)\n\t\t\t{\n\t\t\t\tauto typeStr = type->ToString();\n\t\t\t\tauto retType = PrintType(req->ReturnType, typeStr);\n\t\t\t\tStringBuilder sbInternalName;\n\t\t\t\tsbInternalName << req->Name.Content;\n\t\t\t\tfor (auto & op : req->GetParameters())\n\t\t\t\t{\n\t\t\t\t\tsbInternalName << \"@\" << PrintType(op->Type, typeStr);\n\t\t\t\t}\n\t\t\t\tauto funcName = sbInternalName.ProduceString();\n\t\t\t\tauto func = Functions.TryGetValue(funcName);\n\t\t\t\tif (!func)\n\t\t\t\t\treturn false;\n\t\t\t\tif ((*func)->SyntaxNode->ReturnType->ToString() != retType)\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tbool SymbolTable::IsWorldReachable(PipelineSymbol * pipe, String src, String targetWorld, RefPtr<ExpressionType> type)\n\t\t{\n\t\t\tif (src == targetWorld)\n\t\t\t\treturn true;\n\t\t\treturn From(pipe->GetPaths(src, targetWorld)).Any([&](const ImportPath & p)\n\t\t\t{\n\t\t\t\treturn CheckTypeRequirement(p, type);\n\t\t\t});\n\t\t}\n\n\t\tbool SymbolTable::IsWorldImplicitlyReachable(PipelineSymbol * pipe, String src, String targetWorld, RefPtr<ExpressionType> type)\n\t\t{\n\t\t\tif (src == targetWorld)\n\t\t\t\treturn true;\n\t\t\treturn From(pipe->GetPaths(src, targetWorld)).Any([&](const ImportPath & p)\n\t\t\t{\n\t\t\t\treturn p.IsImplicitPath && CheckTypeRequirement(p, type);\n\t\t\t});\n\t\t}\n\n\t\tbool SymbolTable::IsWorldImplicitlyReachable(PipelineSymbol * pipe, EnumerableHashSet<String>& src, String targetWorld, RefPtr<ExpressionType> type)\n\t\t{\n\t\t\tfor (auto srcW : src)\n\t\t\t{\n\t\t\t\tif (IsWorldImplicitlyReachable(pipe, srcW, targetWorld, type))\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tbool SymbolTable::IsWorldReachable(PipelineSymbol * pipe, EnumerableHashSet<String>& src, String targetWorld, RefPtr<ExpressionType> type)\n\t\t{\n\t\t\tfor (auto srcW : src)\n\t\t\t{\n\t\t\t\tif (IsWorldReachable(pipe, srcW, targetWorld, type))\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tList<ImportPath> SymbolTable::FindImplicitImportOperatorChain(PipelineSymbol * pipe, String worldSrc, String worldDest, RefPtr<ExpressionType> type)\n\t\t{\n\t\t\treturn From(pipe->GetPaths(worldSrc, worldDest)).Where([&](const ImportPath & p)\n\t\t\t{\n\t\t\t\tif (p.IsImplicitPath)\n\t\t\t\t\treturn CheckTypeRequirement(p, type);\n\t\t\t\treturn false;\n\t\t\t}).ToList();\n\t\t}\n\n        Decl* SymbolTable::LookUp(String const& name)\n        {\n            Decl* decl = nullptr;\n            if (globalDecls.TryGetValue(name, decl))\n                return decl;\n            return nullptr;\n        }\n\n\t\tvoid SymbolTable::MergeWith(SymbolTable & symTable)\n\t\t{\n\t\t\tfor (auto & f : symTable.FunctionOverloads)\n\t\t\t\tFunctionOverloads[f.Key] = f.Value;\n\t\t\tfor (auto & f : symTable.Functions)\n\t\t\t\tFunctions[f.Key] = f.Value;\n\t\t\tfor (auto & f : symTable.Shaders)\n\t\t\t\tShaders[f.Key] = f.Value;\n\t\t\tfor (auto & f : symTable.Pipelines)\n\t\t\t\tPipelines[f.Key] = f.Value;\n\t\t\tfor (auto & f : symTable.globalDecls)\n\t\t\t\tglobalDecls[f.Key] = f.Value;\n\t\t\tSortShaders();\n\t\t}\n\n\t\tint UniqueIdGenerator::currentGUID = 0;\n\t\tvoid UniqueIdGenerator::Clear()\n\t\t{\n\t\t\tcurrentGUID = 0;\n\t\t}\n\t\tint UniqueIdGenerator::Next()\n\t\t{\n\t\t\treturn currentGUID++;\n\t\t}\n\t\tRefPtr<ShaderComponentSymbol> ShaderClosure::FindComponent(String name, bool findInPrivate, bool includeParams)\n\t\t{\n\t\t\tRefPtr<ShaderComponentSymbol> rs;\n\t\t\tif (RefMap.TryGetValue(name, rs))\n\t\t\t{\n\t\t\t\tif (includeParams || !rs->IsRequire())\n\t\t\t\t\treturn rs;\n\t\t\t\telse\n\t\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\tif (Components.TryGetValue(name, rs))\n\t\t\t{\n\t\t\t\tif (includeParams || !rs->IsRequire())\n\t\t\t\t\treturn rs;\n\t\t\t\telse\n\t\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\tfor (auto & subClosure : SubClosures)\n\t\t\t{\n\t\t\t\tif (subClosure.Value->IsInPlace)\n\t\t\t\t{\n\t\t\t\t\trs = subClosure.Value->FindComponent(name, findInPrivate, includeParams);\n\t\t\t\t\tif (rs && (findInPrivate || rs->Implementations.First()->SyntaxNode->IsPublic()))\n\t\t\t\t\t\treturn rs;\n\t\t\t\t\telse\n\t\t\t\t\t\trs = nullptr;\n\t\t\t\t}\n\t\t\t}\n\t\t\tShaderClosure * root = this;\n\t\t\twhile (root->Parent != nullptr)\n\t\t\t\troot = root->Parent;\n\t\t\tif (root != this)\n\t\t\t{\n\t\t\t\t// find global components in root (pipeline-defined components)\n\t\t\t\tif (root->Components.TryGetValue(name, rs))\n\t\t\t\t\treturn rs;\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<ShaderClosure> ShaderClosure::FindClosure(String name)\n\t\t{\n\t\t\tRefPtr<ShaderClosure> rs;\n\t\t\tif (SubClosures.TryGetValue(name, rs))\n\t\t\t\treturn rs;\n\t\t\tfor (auto & subClosure : SubClosures)\n\t\t\t{\n\t\t\t\tif (subClosure.Value->IsInPlace)\n\t\t\t\t{\n\t\t\t\t\trs = subClosure.Value->FindClosure(name);\n\t\t\t\t\tif (rs && rs->IsPublic)\n\t\t\t\t\t\treturn rs;\n\t\t\t\t\telse\n\t\t\t\t\t\trs = nullptr;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\t\tList<ShaderComponentSymbol*> ShaderClosure::GetDependencyOrder()\n\t\t{\n\t\t\tList<ShaderComponentSymbol*> comps;\n\t\t\tfor (auto & comp : AllComponents)\n\t\t\t\tcomps.Add(comp.Value.Symbol);\n\t\t\tcomps.Sort([&](ShaderComponentSymbol*c0, ShaderComponentSymbol*c1)\n\t\t\t{\n\t\t\t\treturn c0->Implementations.First()->SyntaxNode->Position < c1->Implementations.First()->SyntaxNode->Position;\n\t\t\t});\n\t\t\tHashSet<ShaderComponentSymbol*> allSymbols, addedSymbols;\n\t\t\tfor (auto & comp : comps)\n\t\t\t\tallSymbols.Add(comp);\n\t\t\tList<ShaderComponentSymbol*> sorted;\n\t\t\tbool changed = true;\n\t\t\twhile (changed)\n\t\t\t{\n\t\t\t\tchanged = false;\n\t\t\t\tfor (auto & comp : comps)\n\t\t\t\t{\n\t\t\t\t\tif (!addedSymbols.Contains(comp))\n\t\t\t\t\t{\n\t\t\t\t\t\tbool isFirst = true;\n\t\t\t\t\t\tfor (auto & impl : comp->Implementations)\n\t\t\t\t\t\t\tfor (auto & dep : impl->DependentComponents)\n\t\t\t\t\t\t\t\tif (allSymbols.Contains(dep.Key) && !addedSymbols.Contains(dep.Key))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tisFirst = false;\n\t\t\t\t\t\t\t\t\tgoto loopEnd;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\tloopEnd:;\n\t\t\t\t\t\tif (isFirst)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taddedSymbols.Add(comp);\n\t\t\t\t\t\t\tsorted.Add(comp);\n\t\t\t\t\t\t\tchanged = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn sorted;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Source/SpireCore/SymbolTable.h",
    "content": "#ifndef RASTER_RENDERER_SYMBOL_TABLE_H\n#define RASTER_RENDERER_SYMBOL_TABLE_H\n\n#include \"../CoreLib/Basic.h\"\n#include \"Syntax.h\"\n#include \"IL.h\"\n#include \"VariantIR.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\t\n\t\tclass FunctionSymbol\n\t\t{\n\t\tpublic:\n\t\t\tbool IsReferencedFunctionsTransitiveClosureEvaluated = false;\n\n\t\t\tFunctionSyntaxNode * SyntaxNode;\n\t\t\tEnumerableHashSet<String> ReferencedFunctions;\n\t\t};\n\t\tclass ShaderComponentSymbol;\n\t\tclass ShaderComponentImplSymbol : public RefObject\n\t\t{\n\t\tpublic:\n\t\t\tEnumerableHashSet<String> Worlds, ExportWorlds, SrcPinnedWorlds;\n\t\t\tRefPtr<ComponentSyntaxNode> SyntaxNode;\n\t\t\tEnumerableDictionary<ShaderComponentSymbol *, EnumerableHashSet<RefPtr<ImportExpressionSyntaxNode>>> DependentComponents; // key: dependent components, value: set of import expression nodes (null means implicit reference)\n\t\t\tEnumerableDictionary<ShaderComponentSymbol *, CodePosition> ComponentReferencePositions;\n\t\t\tShaderComponentImplSymbol() = default;\n\t\t\tShaderComponentImplSymbol(const ShaderComponentImplSymbol & other)\n\t\t\t{\n\t\t\t\tWorlds = other.Worlds;\n\t\t\t\tExportWorlds = other.ExportWorlds;\n\t\t\t\tSrcPinnedWorlds = other.SrcPinnedWorlds;\n\t\t\t\tCloneContext ctx;\n\t\t\t\tSyntaxNode = other.SyntaxNode->Clone(ctx);\n\t\t\t}\n\t\t};\n\n\t\tclass ShaderComponentSymbol : public RefObject\n\t\t{\n\t\tpublic:\n\t\t\tbool IsDceEntryPoint = false;\n\t\t\tString Name, UniqueName, UniqueKey;\n\t\t\tList<String> ChoiceNames;\n\t\t\tEnumerableDictionary<ShaderComponentSymbol *, EnumerableHashSet<RefPtr<ImportExpressionSyntaxNode>>> DependentComponents;\n\t\t\tList<RefPtr<ShaderComponentImplSymbol>> Implementations;\n\t\t\tRefPtr<Type> Type;\n\t\t\tbool IsRequire()\n\t\t\t{\n\t\t\t\tfor (auto & impl : Implementations)\n\t\t\t\t\tif (impl->SyntaxNode->IsRequire())\n\t\t\t\t\t\treturn true;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tShaderComponentSymbol() = default;\n\t\t\tShaderComponentSymbol(const ShaderComponentSymbol & other)\n\t\t\t{\n\t\t\t\tType = new Spire::Compiler::Type(*other.Type);\n\t\t\t\tfor (auto &impl : other.Implementations)\n\t\t\t\t\tthis->Implementations.Add(new ShaderComponentImplSymbol(*impl));\n\t\t\t\tthis->Name = other.Name;\n\t\t\t}\n\t\t};\n\n\t\tclass PipelineSymbol;\n\t\tclass ShaderClosure;\n\t\t\n\t\tclass ShaderSymbol;\n\n\t\tclass ShaderUsing\n\t\t{\n\t\tpublic:\n\t\t\tShaderSymbol * Shader;\n\t\t\tbool IsPublic;\n\t\t};\n\n        class ShaderSymbolBase\n        {\n        public:\n\t\t\tPipelineSymbol * ParentPipeline = nullptr;\n\n\t\t\t// components that are functions, they are also listed in Components, index by original names\n\t\t\tEnumerableDictionary<String, List<RefPtr<ShaderComponentSymbol>>> FunctionComponents; \n\t\t\t\n\t\t\t// all components in this shader, function components are indexed by their unique names\n\t\t\tEnumerableDictionary<String, RefPtr<ShaderComponentSymbol>> Components;\n        };\n\n\t\tclass ShaderSymbol : public ShaderSymbolBase\n\t\t{\n\t\tpublic:\n\t\t\tbool IsAbstract = false;\n\t\t\tbool SemanticallyChecked = false;\n\t\t\tRefPtr<ShaderSyntaxNode> SyntaxNode = nullptr;\n\n\t\t\tList<ShaderComponentSymbol*> GetComponentDependencyOrder();\n\t\t\tEnumerableHashSet<ShaderSymbol*> DependentShaders;\n\t\t\tList<ShaderUsing> ShaderUsings;\n\t\t\tEnumerableDictionary<String, ShaderUsing> ShaderObjects;\n\t\t\tvoid SortComponents(List<ShaderComponentSymbol*> & comps);\n\t\t\tstruct ComponentReference\n\t\t\t{\n\t\t\t\tShaderComponentSymbol * Component = nullptr;\n\t\t\t\tbool IsAccessible = false;\n\t\t\t};\n\t\t\tComponentReference ResolveComponentReference(String compName, bool topLevel = true);\n\t\t};\n\n\t\tclass ShaderClosure;\n\n\t\tclass ComponentInstance\n\t\t{\n\t\tpublic:\n\t\t\tShaderComponentSymbol * Symbol = nullptr;\n\t\t\tShaderClosure * Closure = nullptr;\n\t\t\tComponentInstance() = default;\n\t\t\tComponentInstance(ShaderClosure * closure, ShaderComponentSymbol * comp)\n\t\t\t{\n\t\t\t\tClosure = closure;\n\t\t\t\tSymbol = comp;\n\t\t\t}\n\t\t};\n\n\t\tclass ShaderClosure : public Object\n\t\t{\n\t\tpublic:\n\t\t\tShaderClosure * Parent = nullptr;\n\t\t\tShaderSyntaxNode * ModuleSyntaxNode = nullptr;\n\t\t\tCodePosition Position;\n\t\t\tPipelineSymbol * Pipeline = nullptr;\n\t\t\tint BindingIndex = -1;\n\t\t\tbool IsInPlace = false;\n\t\t\tbool IsPublic = false;\n\t\t\tString Name;\n\t\t\tCodePosition UsingPosition;\n\t\t\tEnumerableDictionary<String, RefPtr<ShaderComponentSymbol>> RefMap;\n\t\t\tEnumerableDictionary<String, RefPtr<ShaderComponentSymbol>> Components;\n\t\t\tEnumerableDictionary<String, ComponentInstance> AllComponents;\n\t\t\tEnumerableDictionary<String, RefPtr<ShaderClosure>> SubClosures;\n\t\t\tRefPtr<ShaderComponentSymbol> FindComponent(String name, bool findInPrivate = false, bool includeParams = true);\n\t\t\tRefPtr<ShaderClosure> FindClosure(String name);\n\t\t\tList<ShaderComponentSymbol*> GetDependencyOrder();\n\t\t\tRefPtr<ShaderIR> IR;\n\t\t};\n\n\t\tclass ImportPath\n\t\t{\n\t\tpublic:\n\t\t\tclass Node\n\t\t\t{\n\t\t\tpublic:\n\t\t\t\tString TargetWorld;\n\t\t\t\tImportOperatorDefSyntaxNode * ImportOperator;\n\t\t\t\tNode() = default;\n\t\t\t\tNode(String world, ImportOperatorDefSyntaxNode * imp)\n\t\t\t\t\t: TargetWorld(world), ImportOperator(imp)\n\t\t\t\t{}\n\t\t\t};\n\t\t\tbool IsImplicitPath = true;\n\t\t\tEnumerableHashSet<FunctionSyntaxNode*> TypeRequirements;\n\t\t\tList<Node> Nodes;\n\t\t};\n\n\t\tclass PipelineSymbol : public ShaderSymbolBase\n\t\t{\n\t\tprivate:\n\t\t\tList<String> WorldTopologyOrder;\n\t\t\tEnumerableDictionary<String, EnumerableDictionary<String, List<ImportPath>>> pathCache;\n\t\t\tList<ImportPath> FindPaths(String worldSrc, String worldDest);\n\t\tpublic:\n\t\t\tPipelineSyntaxNode * SyntaxNode;\n\t\t\tPipelineSymbol * ParentPipeline;\n\t\t\tEnumerableDictionary<String, List<RefPtr<ImportOperatorDefSyntaxNode>>> ImportOperators;\n\t\t\t// SourceWorld=>DestinationWorld=>ImportOperator\n\t\t\tEnumerableDictionary<String, EnumerableDictionary<String, List<RefPtr<ImportOperatorDefSyntaxNode>>>> ImportOperatorsByPath;\n\t\t\tEnumerableDictionary<String, EnumerableHashSet<String>> WorldDependency;\n            EnumerableDictionary<String, WorldSyntaxNode*> Worlds;\n\t\t\tbool IsAbstractWorld(String world);\n\t\t\tbool IsChildOf(PipelineSymbol * parentPipeline);\n\t\t\t\n\t\t\tList<String> & GetWorldTopologyOrder();\n\t\t\tList<ImportPath> & GetPaths(String srcWorld, String destWorld);\n\t\t\tList<ImportOperatorDefSyntaxNode*> GetImportOperatorsFromSourceWorld(String worldSrc);\n\t\t\tvoid AddImportOperator(RefPtr<ImportOperatorDefSyntaxNode> op);\n\t\t};\n\n\t\tclass CompileResult;\n\n\t\tclass SymbolTable\n\t\t{\n\t\tprivate:\n\t\t\tbool CheckTypeRequirement(const ImportPath & p, RefPtr<ExpressionType> type);\n\t\tpublic:\n\t\t\tEnumerableDictionary<String, List<RefPtr<FunctionSymbol>>> FunctionOverloads; // indexed by original name\n\t\t\tEnumerableDictionary<String, RefPtr<FunctionSymbol>> Functions; // indexed by internal name\n\t\t\tEnumerableDictionary<String, RefPtr<ShaderSymbol>> Shaders;\n\t\t\tEnumerableDictionary<String, RefPtr<PipelineSymbol>> Pipelines;\n\t\t\tEnumerableDictionary<String, Decl*> globalDecls;\n\t\t\tList<ShaderSymbol*> ShaderDependenceOrder;\n\t\t\tbool SortShaders(); // return true if success, return false if dependency is cyclic\n\t\t\tvoid EvalFunctionReferenceClosure();\n\t\t\tbool CheckComponentImplementationConsistency(DiagnosticSink * sink, ShaderComponentSymbol * comp, ShaderComponentImplSymbol * impl);\n\n\t\t\tbool IsWorldReachable(PipelineSymbol * pipe, EnumerableHashSet<String> & src, String targetWorld, RefPtr<ExpressionType> type);\n\t\t\tbool IsWorldReachable(PipelineSymbol * pipe, String src, String targetWorld, RefPtr<ExpressionType> type);\n\t\t\tbool IsWorldImplicitlyReachable(PipelineSymbol * pipe, EnumerableHashSet<String> & src, String targetWorld, RefPtr<ExpressionType> type);\n\t\t\tbool IsWorldImplicitlyReachable(PipelineSymbol * pipe, String src, String targetWorld, RefPtr<ExpressionType> type);\n\t\t\tList<ImportPath> FindImplicitImportOperatorChain(PipelineSymbol * pipe, String worldSrc, String worldDest, RefPtr<ExpressionType> type);\n\n            Decl* LookUp(String const& name);\n\t\t\tvoid MergeWith(SymbolTable & symTable);\n\t\t};\n\n\t\tclass UniqueIdGenerator\n\t\t{\n\t\tprivate:\n\t\t\tstatic int currentGUID;\n\t\tpublic:\n\t\t\tstatic void Clear();\n\t\t\tstatic int Next();\n\t\t};\n\n\n\t\ttemplate<typename T, typename GetDependencyFunc>\n\t\tvoid DependencySort(List<T> & list, const GetDependencyFunc & getDep)\n\t\t{\n\t\t\tHashSet<T> allSymbols, addedSymbols;\n\t\t\tfor (auto & comp : list)\n\t\t\t\tallSymbols.Add(comp);\n\t\t\tList<T> sorted;\n\t\t\tbool changed = true;\n\t\t\twhile (changed)\n\t\t\t{\n\t\t\t\tchanged = false;\n\t\t\t\tfor (auto & comp : list)\n\t\t\t\t{\n\t\t\t\t\tif (!addedSymbols.Contains(comp))\n\t\t\t\t\t{\n\t\t\t\t\t\tbool isFirst = true;\n\t\t\t\t\t\tauto && dependency = getDep(comp);\n\t\t\t\t\t\tfor (auto & dep : dependency)\n\t\t\t\t\t\t\tif (allSymbols.Contains(dep) && !addedSymbols.Contains(dep))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tisFirst = false;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\tif (isFirst)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taddedSymbols.Add(comp);\n\t\t\t\t\t\t\tsorted.Add(comp);\n\t\t\t\t\t\t\tchanged = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tlist = _Move(sorted);\n\t\t}\n\n\t}\n}\n#endif"
  },
  {
    "path": "Source/SpireCore/Syntax.cpp",
    "content": "#include \"Syntax.h\"\n#include \"SyntaxVisitors.h\"\n#include \"SymbolTable.h\"\n\n#include <assert.h>\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n        // Scope\n\n        Decl* Scope::LookUp(String const& name)\n        {\n            Scope* scope = this;\n            while (scope)\n            {\n                for (auto m : scope->containerDecl->Members)\n                {\n                    if (m->Name.Content == name)\n                        return m.Ptr();\n                }\n\n                scope = scope->Parent.Ptr();\n            }\n            return nullptr;\n        }\n\n        // Decl\n\n        bool Decl::FindSimpleAttribute(String const& key, Token& outValue)\n        {\n            for (auto attr : GetLayoutAttributes())\n            {\n                if (attr->Key == key)\n                {\n                    outValue = attr->Value;\n                    return true;\n                }\n            }\n            return false;\n        }\n        bool Decl::FindSimpleAttribute(String const& key, String& outValue)\n        {\n            for (auto attr : GetLayoutAttributes())\n            {\n                if (attr->Key == key)\n                {\n                    outValue = attr->Value.Content;\n                    return true;\n                }\n            }\n            return false;\n        }\n        bool Decl::HasSimpleAttribute(String const& key)\n        {\n            for (auto attr : GetLayoutAttributes())\n            {\n                if (attr->Key == key)\n                {\n                    return true;\n                }\n            }\n            return false;\n        }\n\n\t\tSpecializeModifier * Decl::FindSpecializeModifier()\n\t\t{\n\t\t\tauto list = GetModifiersOfType<SpecializeModifier>();\n\t\t\tif (list.begin() != list.end())\n\t\t\t\treturn *list.begin();\n\t\t\treturn nullptr;\n\t\t}\n\n        //\n\n\t\tbool BasicExpressionType::EqualsImpl(const ExpressionType * type) const\n\t\t{\n\t\t\tauto basicType = dynamic_cast<const BasicExpressionType*>(type);\n\t\t\tif (basicType == nullptr)\n\t\t\t\treturn false;\n\t\t\treturn (basicType->BaseType == BaseType &&\n\t\t\t\tbasicType->Func == Func &&\n\t\t\t\tbasicType->Shader == Shader &&\n\t\t\t\tbasicType->structDecl == structDecl &&\n\t\t\t\tbasicType->RecordTypeName == RecordTypeName);\n\t\t}\n\n        ExpressionType* BasicExpressionType::CreateCanonicalType()\n        {\n            // A basic type is already canonical, in our setup\n            return this;\n        }\n\n\t\tBindableResourceType BasicExpressionType::GetBindableResourceType() const\n\t\t{\n\t\t\tswitch (BaseType)\n\t\t\t{\n\t\t\tcase Compiler::BaseType::Texture2DArray:\n\t\t\tcase Compiler::BaseType::Texture2DArrayShadow:\n\t\t\tcase Compiler::BaseType::Texture2D:\n\t\t\tcase Compiler::BaseType::Texture2DShadow:\n\t\t\tcase Compiler::BaseType::Texture3D:\n\t\t\tcase Compiler::BaseType::TextureCube:\n\t\t\tcase Compiler::BaseType::TextureCubeShadow:\n\t\t\tcase Compiler::BaseType::TextureCubeArray:\n\t\t\tcase Compiler::BaseType::TextureCubeShadowArray:\n\t\t\t\treturn BindableResourceType::Texture;\n\t\t\tcase Compiler::BaseType::SamplerState:\n\t\t\tcase Compiler::BaseType::SamplerComparisonState:\n\t\t\t\treturn BindableResourceType::Sampler;\n\t\t\t}\n\t\t\treturn BindableResourceType::NonBindable;\n\t\t}\n\n\t\tbool BasicExpressionType::IsVectorTypeImpl() const\n\t\t{\n\t\t\treturn IsVector(BaseType);\n\t\t}\n\n\t\tCoreLib::Basic::String BasicExpressionType::ToString() const\n\t\t{\n\t\t\tCoreLib::Basic::StringBuilder res;\n\n\t\t\tswitch (BaseType)\n\t\t\t{\n\t\t\tcase Compiler::BaseType::Int:\n\t\t\t\tres.Append(\"int\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::UInt:\n\t\t\t\tres.Append(\"uint\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Bool:\n\t\t\t\tres.Append(\"bool\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Float:\n\t\t\t\tres.Append(\"float\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Int2:\n\t\t\t\tres.Append(\"ivec2\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::UInt2:\n\t\t\t\tres.Append(\"uvec2\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Float2:\n\t\t\t\tres.Append(\"vec2\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Int3:\n\t\t\t\tres.Append(\"ivec3\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::UInt3:\n\t\t\t\tres.Append(\"uvec3\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Float3:\n\t\t\t\tres.Append(\"vec3\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Int4:\n\t\t\t\tres.Append(\"ivec4\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::UInt4:\n\t\t\t\tres.Append(\"uvec4\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Float4:\n\t\t\t\tres.Append(\"vec4\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Float3x3:\n\t\t\t\tres.Append(\"mat3\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Float4x4:\n\t\t\t\tres.Append(\"mat4\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Texture2DArray:\n\t\t\t\tres.Append(\"sampler2DArray\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Texture2DArrayShadow:\n\t\t\t\tres.Append(\"sampler2DArrayShadow\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Texture2D:\n\t\t\t\tres.Append(\"sampler2D\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Texture2DShadow:\n\t\t\t\tres.Append(\"sampler2DShadow\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Texture3D:\n\t\t\t\tres.Append(\"sampler3D\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::TextureCube:\n\t\t\t\tres.Append(\"samplerCube\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::TextureCubeShadow:\n\t\t\t\tres.Append(\"samplerCubeShadow\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Function:\n\t\t\t\tres.Append(Func->SyntaxNode->InternalName);\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Shader:\n\t\t\t\tres.Append(Shader->SyntaxNode->Name.Content);\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Void:\n\t\t\t\tres.Append(\"void\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Struct:\n\t\t\t\tres.Append(structDecl->Name.Content);\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Record:\n\t\t\t\tres.Append(RecordTypeName);\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::SamplerState:\n\t\t\t\tres.Append(\"SamplerState\");\n\t\t\t\tbreak;\n\t\t\tcase Compiler::BaseType::Error:\n\t\t\t\tres.Append(\"<errtype>\");\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\treturn res.ProduceString();\n\t\t}\n\n\t\tExpressionType * BasicExpressionType::Clone()\n\t\t{\n\t\t\tBasicExpressionType * rs = new BasicExpressionType(*this);\n\t\t\treturn rs;\n\t\t}\n\n\n\t\tRefPtr<SyntaxNode> ProgramSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitProgram(this);\n\t\t}\n\t\tProgramSyntaxNode * ProgramSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new ProgramSyntaxNode(*this), ctx);\n\t\t\trs->Members.Clear();\n\t\t\tfor (auto & m : Members)\n\t\t\t\trs->Members.Add(m->Clone(ctx));\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> FunctionSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitFunction(this);\n\t\t}\n\t\tFunctionSyntaxNode * FunctionSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new FunctionSyntaxNode(*this), ctx);\n\t\t\tfor (auto & member : rs->Members)\n\t\t\t{\n\t\t\t\tmember = member->Clone(ctx);\n\t\t\t}\n\t\t\trs->ReturnTypeNode = ReturnTypeNode->Clone(ctx);\n\t\t\trs->Body = Body->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\n        //\n\n        RefPtr<SyntaxNode> ScopeDecl::Accept(SyntaxVisitor * visitor)\n        {\n            return visitor->VisitScopeDecl(this);\n        }\n\n        ScopeDecl* ScopeDecl::Clone(CloneContext & ctx)\n        {\n            auto rs = CloneSyntaxNodeFields(new ScopeDecl(*this), ctx);\n            for (auto & member : rs->Members)\n            {\n                member = member->Clone(ctx);\n            }\n            return rs;\n        }\n\n\n        //\n\n\t\tRefPtr<SyntaxNode> BlockStatementSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitBlockStatement(this);\n\t\t}\n\t\tBlockStatementSyntaxNode * BlockStatementSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new BlockStatementSyntaxNode(*this), ctx);\n\t\t\trs->Statements.Clear();\n\t\t\tfor (auto & stmt : Statements)\n\t\t\t{\n\t\t\t\trs->Statements.Add(stmt->Clone(ctx));\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> BreakStatementSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitBreakStatement(this);\n\t\t}\n\t\tBreakStatementSyntaxNode * BreakStatementSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\treturn CloneSyntaxNodeFields(new BreakStatementSyntaxNode(*this), ctx);\n\t\t}\n\t\tRefPtr<SyntaxNode> ContinueStatementSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitContinueStatement(this);\n\t\t}\n\t\tContinueStatementSyntaxNode * ContinueStatementSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\treturn CloneSyntaxNodeFields(new ContinueStatementSyntaxNode(*this), ctx);\n\t\t}\n\t\tRefPtr<SyntaxNode> DoWhileStatementSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitDoWhileStatement(this);\n\t\t}\n\t\tDoWhileStatementSyntaxNode * DoWhileStatementSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new DoWhileStatementSyntaxNode(*this), ctx);\n\t\t\tif (Predicate)\n\t\t\t\trs->Predicate = Predicate->Clone(ctx);\n\t\t\tif (Statement)\n\t\t\t\trs->Statement = Statement->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> EmptyStatementSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitEmptyStatement(this);\n\t\t}\n\t\tEmptyStatementSyntaxNode * EmptyStatementSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\treturn CloneSyntaxNodeFields(new EmptyStatementSyntaxNode(*this), ctx);\n\t\t}\n\t\tRefPtr<SyntaxNode> ForStatementSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitForStatement(this);\n\t\t}\n\t\tForStatementSyntaxNode * ForStatementSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new ForStatementSyntaxNode(*this), ctx);\n\t\t\tif (InitialStatement)\n\t\t\t\trs->InitialStatement = InitialStatement->Clone(ctx);\n\t\t\tif (SideEffectExpression)\n\t\t\t\trs->SideEffectExpression = SideEffectExpression->Clone(ctx);\n\t\t\tif (PredicateExpression)\n\t\t\t\trs->PredicateExpression = PredicateExpression->Clone(ctx);\n\t\t\tif (Statement)\n\t\t\t\trs->Statement = Statement->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> IfStatementSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitIfStatement(this);\n\t\t}\n\t\tIfStatementSyntaxNode * IfStatementSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new IfStatementSyntaxNode(*this), ctx);\n\t\t\tif (Predicate)\n\t\t\t\trs->Predicate = Predicate->Clone(ctx);\n\t\t\tif (PositiveStatement)\n\t\t\t\trs->PositiveStatement = PositiveStatement->Clone(ctx);\n\t\t\tif (NegativeStatement)\n\t\t\t\trs->NegativeStatement = NegativeStatement->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> ReturnStatementSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitReturnStatement(this);\n\t\t}\n\t\tReturnStatementSyntaxNode * ReturnStatementSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new ReturnStatementSyntaxNode(*this), ctx);\n\t\t\tif (Expression)\n\t\t\t\trs->Expression = Expression->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> VarDeclrStatementSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitVarDeclrStatement(this);\n\t\t}\n\t\tVarDeclrStatementSyntaxNode * VarDeclrStatementSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new VarDeclrStatementSyntaxNode(*this), ctx);\n            rs->decl = rs->decl->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> Variable::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitDeclrVariable(this);\n\t\t}\n\t\tVariable * Variable::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new Variable(*this), ctx);\n\t\t\tif (Expr)\n\t\t\t\trs->Expr = Expr->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> WhileStatementSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitWhileStatement(this);\n\t\t}\n\t\tWhileStatementSyntaxNode * WhileStatementSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new WhileStatementSyntaxNode(*this), ctx);\n\t\t\tif (Predicate)\n\t\t\t\trs->Predicate = Predicate->Clone(ctx);\n\t\t\tif (Statement)\n\t\t\t\trs->Statement = Statement->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> ExpressionStatementSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitExpressionStatement(this);\n\t\t}\n\t\tExpressionStatementSyntaxNode * ExpressionStatementSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new ExpressionStatementSyntaxNode(*this), ctx);\n\t\t\tif (Expression)\n\t\t\t\trs->Expression = Expression->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> BinaryExpressionSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitBinaryExpression(this);\n\t\t}\n\t\tBinaryExpressionSyntaxNode * BinaryExpressionSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new BinaryExpressionSyntaxNode(*this), ctx);\n\t\t\trs->LeftExpression = LeftExpression->Clone(ctx);\n\t\t\trs->RightExpression = RightExpression->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> ConstantExpressionSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitConstantExpression(this);\n\t\t}\n\t\tConstantExpressionSyntaxNode * ConstantExpressionSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\treturn CloneSyntaxNodeFields(new ConstantExpressionSyntaxNode(*this), ctx);\n\t\t}\n\t\tIndexExpressionSyntaxNode * IndexExpressionSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new IndexExpressionSyntaxNode(*this), ctx);\n\t\t\trs->BaseExpression = BaseExpression->Clone(ctx);\n\t\t\trs->IndexExpression = IndexExpression->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> IndexExpressionSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitIndexExpression(this);\n\t\t}\n\t\tRefPtr<SyntaxNode> MemberExpressionSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitMemberExpression(this);\n\t\t}\n\t\tMemberExpressionSyntaxNode * MemberExpressionSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new MemberExpressionSyntaxNode(*this), ctx);\n\t\t\trs->BaseExpression = BaseExpression->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> InvokeExpressionSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitInvokeExpression(this);\n\t\t}\n\t\tInvokeExpressionSyntaxNode * InvokeExpressionSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new InvokeExpressionSyntaxNode(*this), ctx);\n\t\t\trs->FunctionExpr = FunctionExpr->Clone(ctx);\n\t\t\trs->Arguments.Clear();\n\t\t\tfor (auto & arg : Arguments)\n\t\t\t{\n\t\t\t\trs->Arguments.Add(arg->Clone(ctx));\n\t\t\t}\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> TypeCastExpressionSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitTypeCastExpression(this);\n\t\t}\n\t\tTypeCastExpressionSyntaxNode * TypeCastExpressionSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new TypeCastExpressionSyntaxNode(*this), ctx);\n\t\t\trs->TargetType = TargetType->Clone(ctx);\n\t\t\trs->Expression = Expression->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> SelectExpressionSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitSelectExpression(this);\n\t\t}\n\t\tSelectExpressionSyntaxNode * SelectExpressionSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new SelectExpressionSyntaxNode(*this), ctx);\n\t\t\trs->SelectorExpr = SelectorExpr->Clone(ctx);\n\t\t\trs->Expr0 = Expr0->Clone(ctx);\n\t\t\trs->Expr1 = Expr1->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> UnaryExpressionSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitUnaryExpression(this);\n\t\t}\n\t\tUnaryExpressionSyntaxNode * UnaryExpressionSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new UnaryExpressionSyntaxNode(*this), ctx);\n\t\t\trs->Expression = Expression->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> VarExpressionSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitVarExpression(this);\n\t\t}\n\t\tVarExpressionSyntaxNode * VarExpressionSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\treturn CloneSyntaxNodeFields(new VarExpressionSyntaxNode(*this), ctx);\n\t\t}\n\t\tRefPtr<SyntaxNode> ParameterSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitParameter(this);\n\t\t}\n\t\tParameterSyntaxNode * ParameterSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new ParameterSyntaxNode(*this), ctx);\n\t\t\trs->TypeNode = TypeNode->Clone(ctx);\n\t\t\trs->Expr = Expr->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> BasicTypeSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitBasicType(this);\n\t\t}\n\t\tRefPtr<SyntaxNode> ComponentSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitComponent(this);\n\t\t}\n\t\tComponentSyntaxNode * ComponentSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new ComponentSyntaxNode(*this), ctx);\n\t\t\trs->TypeNode = TypeNode->Clone(ctx);\n\t\t\tif (Rate)\n\t\t\t\trs->Rate = Rate->Clone(ctx);\n\t\t\tif (BlockStatement)\n\t\t\t\trs->BlockStatement = BlockStatement->Clone(ctx);\n\t\t\tif (Expression)\n\t\t\t\trs->Expression = Expression->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> ShaderSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitShader(this);\n\t\t}\n\t\tShaderSyntaxNode * ShaderSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new ShaderSyntaxNode(*this), ctx);\n\t\t\trs->Members.Clear();\n\t\t\tfor (auto & comp : Members)\n\t\t\t\trs->Members.Add(comp->Clone(ctx));\n\t\t\treturn rs;\n\t\t}\n\n        // UsingFileDecl\n\n        RefPtr<SyntaxNode> UsingFileDecl::Accept(SyntaxVisitor * visitor)\n        {\n            return visitor->VisitUsingFileDecl(this);\n        }\n\n        UsingFileDecl* UsingFileDecl::Clone(CloneContext & ctx)\n        {\n            return CloneSyntaxNodeFields(new UsingFileDecl(*this), ctx);\n        }\n\n        //\n\n\t\tRateSyntaxNode * RateSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\treturn CloneSyntaxNodeFields(new RateSyntaxNode(*this), ctx);\n\t\t}\n\t\tWorldSyntaxNode * WorldSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\treturn CloneSyntaxNodeFields(new WorldSyntaxNode(*this), ctx);\n\t\t}\n\t\tRefPtr<SyntaxNode> ImportOperatorDefSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitImportOperatorDef(this); \n\t\t}\n\t\tImportOperatorDefSyntaxNode * ImportOperatorDefSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\treturn CloneSyntaxNodeFields(new ImportOperatorDefSyntaxNode(*this), ctx);\n\t\t}\n\t\tPipelineSyntaxNode * PipelineSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new PipelineSyntaxNode(*this), ctx);\n\t\t\trs->Members.Clear();\n\t\t\tfor (auto & m : Members)\n\t\t\t\trs->Members.Add(m->Clone(ctx));\n\t\t\treturn rs;\n\t\t}\n\t\tChoiceValueSyntaxNode * ChoiceValueSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\treturn CloneSyntaxNodeFields(new ChoiceValueSyntaxNode(*this), ctx);\n\t\t}\n\t\tRefPtr<SyntaxNode> ImportSyntaxNode::Accept(SyntaxVisitor * v)\n\t\t{\n\t\t\treturn v->VisitImport(this);\n\t\t}\n\t\tImportSyntaxNode * ImportSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new ImportSyntaxNode(*this), ctx);\n\t\t\trs->Arguments.Clear();\n\t\t\tfor (auto & arg : Arguments)\n\t\t\t\trs->Arguments.Add(arg->Clone(ctx));\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> ImportArgumentSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitImportArgument(this);\n\t\t}\n\t\tImportArgumentSyntaxNode * ImportArgumentSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new ImportArgumentSyntaxNode(*this), ctx);\n\t\t\trs->Expression = Expression->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> ImportStatementSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitImportStatement(this);\n\t\t}\n\t\tImportStatementSyntaxNode * ImportStatementSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new ImportStatementSyntaxNode(*this), ctx);\n\t\t\trs->Import = Import->Clone(ctx);\n\t\t\treturn rs;\n\t\t}\n\n\t\tRefPtr<SyntaxNode> StructField::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitStructField(this);\n\t\t}\n\t\tRefPtr<SyntaxNode> StructSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitStruct(this);\n\t\t}\n\n        RefPtr<SyntaxNode> TypeDefDecl::Accept(SyntaxVisitor * visitor)\n        {\n            return visitor->VisitTypeDefDecl(this);\n        }\n        TypeDefDecl* TypeDefDecl::Clone(CloneContext & ctx)\n        {\n            auto result = CloneSyntaxNodeFields(new TypeDefDecl(*this), ctx);\n            return result;\n        }\n\n\t\tRefPtr<SyntaxNode> DiscardStatementSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitDiscardStatement(this);\n\t\t}\n\t\tDiscardStatementSyntaxNode * DiscardStatementSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new DiscardStatementSyntaxNode(*this), ctx);\n\t\t\treturn rs;\n\t\t}\n\t\tbool BasicExpressionType::IsIntegralImpl() const\n\t\t{\n\t\t\treturn (BaseType == Compiler::BaseType::Int || BaseType == Compiler::BaseType::UInt || BaseType == Compiler::BaseType::Bool);\n\t\t}\n\n        bool ExpressionType::IsIntegral() const\n        {\n            return GetCanonicalType()->IsIntegralImpl();\n        }\n\n        bool ExpressionType::Equals(const ExpressionType * type) const\n        {\n            return GetCanonicalType()->EqualsImpl(type->GetCanonicalType());\n        }\n\n\t\tbool ExpressionType::Equals(RefPtr<ExpressionType> type) const\n\t\t{\n\t\t\treturn Equals(type.Ptr());\n\t\t}\n\n        bool ExpressionType::IsVectorType() const\n        {\n            return GetCanonicalType()->IsVectorTypeImpl();\n        }\n\n        bool ExpressionType::IsArray() const\n        {\n            return GetCanonicalType()->IsArrayImpl();\n        }\n\n        bool ExpressionType::IsGenericType(String typeName) const\n        {\n            return GetCanonicalType()->IsGenericTypeImpl(typeName);\n        }\n\n        BasicExpressionType * ExpressionType::AsBasicType() const\n        {\n            return GetCanonicalType()->AsBasicTypeImpl();\n        }\n\n        ArrayExpressionType * ExpressionType::AsArrayType() const\n        {\n            return GetCanonicalType()->AsArrayTypeImpl();\n        }\n\n        GenericExpressionType * ExpressionType::AsGenericType() const\n        {\n            return GetCanonicalType()->AsGenericTypeImpl();\n        }\n\n        NamedExpressionType* ExpressionType::AsNamedType() const\n        {\n            return AsNamedTypeImpl();\n        }\n\n        ExpressionType* ExpressionType::GetCanonicalType() const\n        {\n            ExpressionType* et = const_cast<ExpressionType*>(this);\n            if (!et->canonicalType)\n            {\n                // TODO(tfoley): worry about thread safety here?\n                et->canonicalType = et->CreateCanonicalType();\n            }\n            return et->canonicalType;\n        }\n\n\t\tbool ExpressionType::IsTexture() const\n\t\t{\n\t\t\tauto basicType = AsBasicType();\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->BaseType == BaseType::Texture2D ||\n\t\t\t\tbasicType->BaseType == BaseType::TextureCube ||\n\t\t\t\tbasicType->BaseType == BaseType::Texture2DArray ||\n\t\t\t\tbasicType->BaseType == BaseType::Texture2DShadow ||\n\t\t\t\tbasicType->BaseType == BaseType::TextureCubeShadow ||\n\t\t\t\tbasicType->BaseType == BaseType::Texture2DArrayShadow ||\n\t\t\t\tbasicType->BaseType == BaseType::TextureCubeArray ||\n\t\t\t\tbasicType->BaseType == BaseType::TextureCubeShadowArray ||\n\t\t\t\tbasicType->BaseType == BaseType::Texture3D;\n\t\t\treturn false;\n\t\t}\n\t\tbool ExpressionType::IsTextureOrSampler() const\n\t\t{\n\t\t\tauto basicType = AsBasicType();\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->BaseType == BaseType::Texture2D ||\n\t\t\t\t\tbasicType->BaseType == BaseType::TextureCube ||\n\t\t\t\t\tbasicType->BaseType == BaseType::Texture2DArray ||\n\t\t\t\t\tbasicType->BaseType == BaseType::Texture2DShadow ||\n\t\t\t\t\tbasicType->BaseType == BaseType::TextureCubeShadow ||\n\t\t\t\t\tbasicType->BaseType == BaseType::Texture2DArrayShadow ||\n\t\t\t\t\tbasicType->BaseType == BaseType::Texture3D ||\n\t\t\t\t\tbasicType->BaseType == BaseType::TextureCubeArray ||\n\t\t\t\t\tbasicType->BaseType == BaseType::TextureCubeShadowArray ||\n\t\t\t\t\tbasicType->BaseType == BaseType::SamplerState;\n\t\t\treturn false;\n\t\t}\n\t\tbool ExpressionType::IsStruct() const\n\t\t{\n\t\t\tauto basicType = AsBasicType();\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->structDecl != nullptr;\n\t\t\treturn false;\n\t\t}\n\t\tbool ExpressionType::IsShader() const\n\t\t{\n\t\t\tauto basicType = AsBasicType();\n\t\t\tif (basicType)\n\t\t\t\treturn basicType->Shader != nullptr;\n\t\t\treturn false;\n\t\t}\n\n\t\tRefPtr<ExpressionType> ExpressionType::Bool;\n\t\tRefPtr<ExpressionType> ExpressionType::UInt;\n\t\tRefPtr<ExpressionType> ExpressionType::UInt2;\n\t\tRefPtr<ExpressionType> ExpressionType::UInt3;\n\t\tRefPtr<ExpressionType> ExpressionType::UInt4;\n\t\tRefPtr<ExpressionType> ExpressionType::Int;\n\t\tRefPtr<ExpressionType> ExpressionType::Int2;\n\t\tRefPtr<ExpressionType> ExpressionType::Int3;\n\t\tRefPtr<ExpressionType> ExpressionType::Int4;\n\t\tRefPtr<ExpressionType> ExpressionType::Float;\n\t\tRefPtr<ExpressionType> ExpressionType::Float2;\n\t\tRefPtr<ExpressionType> ExpressionType::Float3;\n\t\tRefPtr<ExpressionType> ExpressionType::Float4;\n\t\tRefPtr<ExpressionType> ExpressionType::Void;\n\t\tRefPtr<ExpressionType> ExpressionType::Error;\n        List<RefPtr<ExpressionType>> ExpressionType::sCanonicalTypes;\n\n\t\tvoid ExpressionType::Init()\n\t\t{\n\t\t\tBool = new BasicExpressionType(BaseType::Bool);\n\t\t\tUInt = new BasicExpressionType(BaseType::UInt);\n\t\t\tUInt2 = new BasicExpressionType(BaseType::UInt2);\n\t\t\tUInt3 = new BasicExpressionType(BaseType::UInt3);\n\t\t\tUInt4 = new BasicExpressionType(BaseType::UInt4);\n\t\t\tInt = new BasicExpressionType(BaseType::Int);\n\t\t\tInt2 = new BasicExpressionType(BaseType::Int2);\n\t\t\tInt3 = new BasicExpressionType(BaseType::Int3);\n\t\t\tInt4 = new BasicExpressionType(BaseType::Int4);\n\t\t\tFloat = new BasicExpressionType(BaseType::Float);\n\t\t\tFloat2 = new BasicExpressionType(BaseType::Float2);\n\t\t\tFloat3 = new BasicExpressionType(BaseType::Float3);\n\t\t\tFloat4 = new BasicExpressionType(BaseType::Float4);\n\t\t\tVoid = new BasicExpressionType(BaseType::Void);\n\t\t\tError = new BasicExpressionType(BaseType::Error);\n\t\t}\n\t\tvoid ExpressionType::Finalize()\n\t\t{\n\t\t\tBool = nullptr;\n\t\t\tUInt = nullptr;\n\t\t\tUInt2 = nullptr;\n\t\t\tUInt3 = nullptr;\n\t\t\tUInt4 = nullptr;\n\t\t\tInt = nullptr;\n\t\t\tInt2 = nullptr;\n\t\t\tInt3 = nullptr;\n\t\t\tInt4 = nullptr;\n\t\t\tFloat = nullptr;\n\t\t\tFloat2 = nullptr;\n\t\t\tFloat3 = nullptr;\n\t\t\tFloat4 = nullptr;\n\t\t\tVoid = nullptr;\n\t\t\tError = nullptr;\n            // Note(tfoley): This seems to be just about the only way to clear out a List<T>\n            sCanonicalTypes = List<RefPtr<ExpressionType>>();\n\t\t}\n\t\tbool ArrayExpressionType::IsArrayImpl() const\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\tbool ArrayExpressionType::EqualsImpl(const ExpressionType * type) const\n\t\t{\n\t\t\tauto arrType = type->AsArrayType();\n\t\t\tif (!arrType)\n\t\t\t\treturn false;\n\t\t\treturn (ArrayLength == arrType->ArrayLength && BaseType->Equals(arrType->BaseType.Ptr()));\n\t\t}\n        ExpressionType* ArrayExpressionType::CreateCanonicalType()\n        {\n            auto canonicalBaseType = BaseType->GetCanonicalType();\n            auto canonicalArrayType = new ArrayExpressionType();\n            sCanonicalTypes.Add(canonicalArrayType);\n            canonicalArrayType->BaseType = canonicalBaseType;\n            canonicalArrayType->ArrayLength = ArrayLength;\n            return canonicalArrayType;\n        }\n\t\tCoreLib::Basic::String ArrayExpressionType::ToString() const\n\t\t{\n\t\t\tif (ArrayLength > 0)\n\t\t\t\treturn BaseType->ToString() + \"[\" + String(ArrayLength) + \"]\";\n\t\t\telse\n\t\t\t\treturn BaseType->ToString() + \"[]\";\n\t\t}\n\t\tExpressionType * ArrayExpressionType::Clone()\n\t\t{\n\t\t\tauto rs = new ArrayExpressionType(*this);\n\t\t\trs->BaseType = BaseType->Clone();\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> ArrayTypeSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitArrayType(this);\n\t\t}\n\t\tRefPtr<SyntaxNode> GenericTypeSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitGenericType(this);\n\t\t}\n\t\tbool GenericExpressionType::EqualsImpl(const ExpressionType * type) const\n\t\t{\n\t\t\tif (auto gtype = type->AsGenericType())\n\t\t\t\treturn GenericTypeName == gtype->GenericTypeName && gtype->BaseType->Equals(BaseType.Ptr());\n\t\t\t\n\t\t\treturn false;\n\t\t}\n        ExpressionType* GenericExpressionType::CreateCanonicalType()\n        {\n            auto canonicalBaseType = BaseType->GetCanonicalType();\n            auto canonicalGenericType = new GenericExpressionType();\n            sCanonicalTypes.Add(canonicalGenericType);\n            canonicalGenericType->BaseType = canonicalBaseType;\n            canonicalGenericType->GenericTypeName = GenericTypeName;\n            return canonicalGenericType;\n        }\n\t\tBindableResourceType GenericExpressionType::GetBindableResourceType() const\n\t\t{\n\t\t\tif (GenericTypeName == \"StructuredBuffer\" || GenericTypeName == \"RWStructuredBuffer\")\n\t\t\t\treturn BindableResourceType::StorageBuffer;\n\t\t\telse if (GenericTypeName == \"Uniform\")\n\t\t\t\treturn BindableResourceType::Buffer;\n\t\t\treturn BindableResourceType::NonBindable;\n\t\t}\n\t\tCoreLib::Basic::String GenericExpressionType::ToString() const\n\t\t{\n\t\t\treturn GenericTypeName + \"<\" + BaseType->ToString() + \">\";\n\t\t}\n\t\tExpressionType * GenericExpressionType::Clone()\n\t\t{\n\t\t\tauto rs = new GenericExpressionType(*this);\n\t\t\trs->BaseType = BaseType->Clone();\n\t\t\treturn rs;\n\t\t}\n\n        // NamedExpressionType\n\n        String NamedExpressionType::ToString() const\n        {\n            return decl->Name.Content;\n        }\n\n        ExpressionType * NamedExpressionType::Clone()\n        {\n            NamedExpressionType* result = new NamedExpressionType();\n            result->decl = decl;\n            return result;\n        }\n\n\t\tBindableResourceType NamedExpressionType::GetBindableResourceType() const\n\t\t{\n\t\t\treturn GetCanonicalType()->GetBindableResourceType();\n\t\t}\n\n        bool NamedExpressionType::EqualsImpl(const ExpressionType * /*type*/) const\n        {\n            assert(!\"unreachable\");\n            return false;\n        }\n\n        NamedExpressionType * NamedExpressionType::AsNamedTypeImpl() const\n        {\n            return const_cast<NamedExpressionType*>(this);\n        }\n\n        ExpressionType* NamedExpressionType::CreateCanonicalType()\n        {\n            return decl->Type->GetCanonicalType();\n        }\n\n\t\tRefPtr<SyntaxNode> ImportExpressionSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitImportExpression(this);\n\t\t}\n\t\tImportExpressionSyntaxNode * ImportExpressionSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tImportExpressionSyntaxNode * result = new ImportExpressionSyntaxNode(*this);\n\t\t\tCloneSyntaxNodeFields(result, ctx);\n\t\t\tresult->Component = Component->Clone(ctx);\n\t\t\tresult->Arguments.Clear();\n\t\t\tfor (auto & arg : Arguments)\n\t\t\t\tresult->Arguments.Add(arg->Clone(ctx));\n\t\t\treturn result;\n\t\t}\n\t\tStageSyntaxNode * StageSyntaxNode::Clone(CloneContext &)\n\t\t{\n\t\t\treturn new StageSyntaxNode(*this);\n\t\t}\n\t\tRefPtr<ComponentSyntaxNode> SyntaxVisitor::VisitComponent(ComponentSyntaxNode * comp)\n\t\t{\n\t\t\tif (comp->TypeNode)\n\t\t\t\tcomp->TypeNode = comp->TypeNode->Accept(this).As<TypeSyntaxNode>();\n\t\t\tif (comp->Expression)\n\t\t\t\tcomp->Expression = comp->Expression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\tif (comp->BlockStatement)\n\t\t\t\tcomp->BlockStatement = comp->BlockStatement->Accept(this).As<BlockStatementSyntaxNode>();\n\t\t\treturn comp;\n\t\t}\n\t\tString GetOperatorFunctionName(Operator op)\n\t\t{\n\t\t\tswitch (op)\n\t\t\t{\n\t\t\tcase Operator::Add:\n\t\t\tcase Operator::AddAssign:\n\t\t\t\treturn \"+\";\n\t\t\tcase Operator::Sub:\n\t\t\tcase Operator::SubAssign:\n\t\t\t\treturn \"-\";\n\t\t\tcase Operator::Neg:\n\t\t\t\treturn \"-\";\n\t\t\tcase Operator::Not:\n\t\t\t\treturn \"!\";\n\t\t\tcase Operator::BitNot:\n\t\t\t\treturn \"~\";\n\t\t\tcase Operator::PreInc:\n\t\t\tcase Operator::PostInc:\n\t\t\t\treturn \"++\";\n\t\t\tcase Operator::PreDec:\n\t\t\tcase Operator::PostDec:\n\t\t\t\treturn \"--\";\n\t\t\tcase Operator::Mul:\n\t\t\tcase Operator::MulAssign:\n\t\t\t\treturn \"*\";\n\t\t\tcase Operator::Div:\n\t\t\tcase Operator::DivAssign:\n\t\t\t\treturn \"/\";\n\t\t\tcase Operator::Mod:\n\t\t\tcase Operator::ModAssign:\n\t\t\t\treturn \"%\";\n\t\t\tcase Operator::Lsh:\n\t\t\tcase Operator::LshAssign:\n\t\t\t\treturn \"<<\";\n\t\t\tcase Operator::Rsh:\n\t\t\tcase Operator::RshAssign:\n\t\t\t\treturn \">>\";\n\t\t\tcase Operator::Eql:\n\t\t\t\treturn \"==\";\n\t\t\tcase Operator::Neq:\n\t\t\t\treturn \"!=\";\n\t\t\tcase Operator::Greater:\n\t\t\t\treturn \">\";\n\t\t\tcase Operator::Less:\n\t\t\t\treturn \"<\";\n\t\t\tcase Operator::Geq:\n\t\t\t\treturn \">=\";\n\t\t\tcase Operator::Leq:\n\t\t\t\treturn \"<=\";\n\t\t\tcase Operator::BitAnd:\n\t\t\tcase Operator::AndAssign:\n\t\t\t\treturn \"&\";\n\t\t\tcase Operator::BitXor:\n\t\t\tcase Operator::XorAssign:\n\t\t\t\treturn \"^\";\n\t\t\tcase Operator::BitOr:\n\t\t\tcase Operator::OrAssign:\n\t\t\t\treturn \"|\";\n\t\t\tcase Operator::And:\n\t\t\t\treturn \"&&\";\n\t\t\tcase Operator::Or:\n\t\t\t\treturn \"||\";\n\t\t\tdefault:\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t}\n\t\tRefPtr<SyntaxNode> ProjectExpressionSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitProject(this);\n\t\t}\n\t\tProjectExpressionSyntaxNode * ProjectExpressionSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto * result = new ProjectExpressionSyntaxNode(*this);\n\t\t\tresult->BaseExpression = BaseExpression->Clone(ctx);\n\t\t\treturn result;\n\t\t}\n\t\tRefPtr<SyntaxNode> InterfaceSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitInterface(this);\n\t\t}\n\t\tInterfaceSyntaxNode * InterfaceSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new InterfaceSyntaxNode(*this), ctx);\n\t\t\trs->Members.Clear();\n\t\t\tfor (auto & comp : Members)\n\t\t\t\trs->Members.Add(comp->Clone(ctx));\n\t\t\treturn rs;\n\t\t}\n\t\tRefPtr<SyntaxNode> TemplateShaderSyntaxNode::Accept(SyntaxVisitor * visitor)\n\t\t{\n\t\t\treturn visitor->VisitTemplateShader(this);\n\t\t}\n\t\tTemplateShaderSyntaxNode * TemplateShaderSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new TemplateShaderSyntaxNode(*this), ctx);\n\t\t\trs->Parameters.Clear();\n\t\t\tfor (auto & param : Parameters)\n\t\t\t\trs->Parameters.Add(param->Clone(ctx));\n\t\t\tfor (auto & member : Members)\n\t\t\t\trs->Members.Add(member->Clone(ctx));\n\t\t\treturn rs;\n\t\t}\n\t\tTemplateShaderParameterSyntaxNode * TemplateShaderParameterSyntaxNode::Clone(CloneContext & ctx)\n\t\t{\n\t\t\tauto rs = CloneSyntaxNodeFields(new TemplateShaderParameterSyntaxNode(*this), ctx);\n\t\t\treturn rs;\n\t\t}\n}\n}"
  },
  {
    "path": "Source/SpireCore/Syntax.h",
    "content": "#ifndef RASTER_RENDERER_SYNTAX_H\n#define RASTER_RENDERER_SYNTAX_H\n\n#include \"../CoreLib/Basic.h\"\n#include \"Lexer.h\"\n#include \"IL.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tusing namespace CoreLib::Basic;\n\t\tclass SyntaxVisitor;\n\t\tclass FunctionSyntaxNode;\n\n\t\t// We use a unified representation for modifiers on all declarations.\n\t\t// (Eventually this will also apply to statements that support attributes)\n\t\t//\n\t\t// The parser allows any set of modifiers on any declaration, and we leave\n\t\t// it to later phases of analysis to reject inappropriate uses.\n\t\t// TODO: implement rejection properly.\n\t\t//\n\t\t// Some common modifiers (thos represented by single keywords) are\n\t\t// specified via a simple set of flags.\n\t\t// TODO: consider using a real AST even for these, so we can give good\n\t\t// error messages on confliction modifiers.\n\t\ttypedef unsigned int ModifierFlags;\n\t\tenum ModifierFlag : ModifierFlags\n\t\t{\n\t\t\tNone = 0,\n\t\t\tUniform = 1 << 0,\n\t\t\tOut = 1 << 1,\n\t\t\tIn = 1 << 2,\n\t\t\tConst = 1 << 4,\n\t\t\tInstance = 1 << 5,\n\t\t\tBuiltin = 1 << 6,\n\n\t\t\tInline = 1 << 8,\n\t\t\tPublic = 1 << 9,\n\t\t\tRequire = 1 << 10,\n\t\t\tParam = (1 << 11) | ModifierFlag::Public,\n\t\t\tExtern = 1 << 12,\n\t\t\tInput = 1 << 13,\n\t\t\tIntrinsic = (1 << 14) | ModifierFlag::Extern,\n\t\t\t// TODO(tfoley): This should probably be its own flag\n\t\t\tInOut = ModifierFlag::In | ModifierFlag::Out,\n\t\t};\n\t\t//\n\t\t// Other modifiers may have more elaborate data, and so\n\t\t// are represented as heap-allocated objects, in a linked\n\t\t// list.\n\t\t//\n\t\tclass Modifier : public RefObject\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<Modifier> next;\n\t\t};\n\n\t\t// A `layout` modifier\n\t\tclass LayoutModifier : public Modifier\n\t\t{\n\t\tpublic:\n\t\t\tString LayoutString;\n\t\t};\n\n\t\t// An attribute of the form `[Name]` or `[Name: Value]`\n\t\tclass SimpleAttribute : public Modifier\n\t\t{\n\t\tpublic:\n\t\t\tString Key;\n\t\t\tToken Value;\n\n\t\t\tString const& GetValue() const { return Value.Content; }\n\t\t};\n\n\t\t// A set of modifiers attached to a syntax node\n\t\tstruct Modifiers\n\t\t{\n\t\t\t// The first modifier in the linked list of heap-allocated modifiers\n\t\t\tRefPtr<Modifier> first;\n\n\t\t\t// The bit-flags for the common modifiers\n\t\t\tModifierFlags flags = ModifierFlag::None;\n\t\t};\n\n\t\t// Helper class for iterating over a list of heap-allocated modifiers\n\t\tstruct ModifierList\n\t\t{\n\t\t\tstruct Iterator\n\t\t\t{\n\t\t\t\tModifier* current;\n\n\t\t\t\tModifier* operator*()\n\t\t\t\t{\n\t\t\t\t\treturn current;\n\t\t\t\t}\n\n\t\t\t\tvoid operator++()\n\t\t\t\t{\n\t\t\t\t\tcurrent = current->next.Ptr();\n\t\t\t\t}\n\n\t\t\t\tbool operator!=(Iterator other)\n\t\t\t\t{\n\t\t\t\t\treturn current != other.current;\n\t\t\t\t};\n\n\t\t\t\tIterator()\n\t\t\t\t\t: current(nullptr)\n\t\t\t\t{}\n\n\t\t\t\tIterator(Modifier* modifier)\n\t\t\t\t\t: current(modifier)\n\t\t\t\t{}\n\t\t\t};\n\n\t\t\tModifierList()\n\t\t\t\t: modifiers(nullptr)\n\t\t\t{}\n\n\t\t\tModifierList(Modifier* modifiers)\n\t\t\t\t: modifiers(modifiers)\n\t\t\t{}\n\n\t\t\tIterator begin() { return Iterator(modifiers); }\n\t\t\tIterator end() { return Iterator(nullptr); }\n\n\t\t\tModifier* modifiers;\n\t\t};\n\n\t\t// Helper class for iterating over heap-allocated modifiers\n\t\t// of a specific type.\n\t\ttemplate<typename T>\n\t\tstruct FilteredModifierList\n\t\t{\n\t\t\tstruct Iterator\n\t\t\t{\n\t\t\t\tModifier* current;\n\n\t\t\t\tT* operator*()\n\t\t\t\t{\n\t\t\t\t\treturn (T*)current;\n\t\t\t\t}\n\n\t\t\t\tvoid operator++()\n\t\t\t\t{\n\t\t\t\t\tcurrent = Adjust(current->next.Ptr());\n\t\t\t\t}\n\n\t\t\t\tbool operator!=(Iterator other)\n\t\t\t\t{\n\t\t\t\t\treturn current != other.current;\n\t\t\t\t};\n\n\t\t\t\tIterator()\n\t\t\t\t\t: current(nullptr)\n\t\t\t\t{}\n\n\t\t\t\tIterator(Modifier* modifier)\n\t\t\t\t\t: current(modifier)\n\t\t\t\t{}\n\t\t\t};\n\n\t\t\tFilteredModifierList()\n\t\t\t\t: modifiers(nullptr)\n\t\t\t{}\n\n\t\t\tFilteredModifierList(Modifier* modifiers)\n\t\t\t\t: modifiers(Adjust(modifiers))\n\t\t\t{}\n\n\t\t\tIterator begin() { return Iterator(modifiers); }\n\t\t\tIterator end() { return Iterator(nullptr); }\n\n\t\t\tstatic Modifier* Adjust(Modifier* modifier)\n\t\t\t{\n\t\t\t\tModifier* m = modifier;\n\t\t\t\tfor (;;)\n\t\t\t\t{\n\t\t\t\t\tif (!m) return m;\n\t\t\t\t\tif (dynamic_cast<T*>(m)) return m;\n\t\t\t\t\tm = m->next.Ptr();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tModifier* modifiers;\n\t\t};\n\n\t\tenum class BaseType\n\t\t{\n\t\t\tVoid = 0,\n\t\t\tInt = 16, Int2 = 17, Int3 = 18, Int4 = 19,\n\t\t\tFloat = 32, Float2 = 33, Float3 = 34, Float4 = 35,\n\t\t\tUInt = 512, UInt2 = 513, UInt3 = 514, UInt4 = 515,\n\t\t\tBool = 128, Bool2 = 129, Bool3 = 130, Bool4 = 131,\n\t\t\tFloat3x3 = 40, Float4x4 = 47,\n\t\t\tTexture2D = 48,\n\t\t\tTextureCube = 49,\n\t\t\tTexture2DArray = 50,\n\t\t\tTexture2DShadow = 51,\n\t\t\tTextureCubeShadow = 52,\n\t\t\tTexture2DArrayShadow = 53,\n\t\t\tTexture3D = 54,\n\t\t\tTextureCubeArray = 55,\n\t\t\tTextureCubeShadowArray = 56,\n\t\t\tSamplerState = 4096, SamplerComparisonState = 4097,\n\t\t\tFunction = 64,\n\t\t\tShader = 256,\n\t\t\tStruct = 1024,\n\t\t\tRecord = 2048,\n\t\t\tGeneric = 8192,\n\t\t\tError = 16384,\n\t\t};\n\n\t\tinline bool IsVector(BaseType type)\n\t\t{\n\t\t\treturn (((int)type) & 15) != 0;\n\t\t}\n\n\t\tinline int GetVectorSize(BaseType type)\n\t\t{\n\t\t\treturn (((int)type) & 15) + 1;\n\t\t}\n\n\t\tinline BaseType GetVectorBaseType(BaseType type)\n\t\t{\n\t\t\treturn (BaseType)(((int)type) & (~15));\n\t\t}\n\n\t\tclass Decl;\n\t\tclass SymbolTable;\n\t\tclass ShaderSymbol;\n\t\tclass ShaderClosure;\n\t\tclass StructSyntaxNode;\n\t\tclass ShaderComponentSymbol;\n\t\tclass FunctionSymbol;\n\t\tclass BasicExpressionType;\n\t\tclass ArrayExpressionType;\n\t\tclass GenericExpressionType;\n\t\tclass TypeDefDecl;\n\t\tclass NamedExpressionType;\n\n\t\tclass ExpressionType : public RefObject\n\t\t{\n\t\tpublic:\n\t\t\tstatic RefPtr<ExpressionType> Bool;\n\t\t\tstatic RefPtr<ExpressionType> UInt;\n\t\t\tstatic RefPtr<ExpressionType> UInt2;\n\t\t\tstatic RefPtr<ExpressionType> UInt3;\n\t\t\tstatic RefPtr<ExpressionType> UInt4;\n\t\t\tstatic RefPtr<ExpressionType> Int;\n\t\t\tstatic RefPtr<ExpressionType> Int2;\n\t\t\tstatic RefPtr<ExpressionType> Int3;\n\t\t\tstatic RefPtr<ExpressionType> Int4;\n\t\t\tstatic RefPtr<ExpressionType> Float;\n\t\t\tstatic RefPtr<ExpressionType> Float2;\n\t\t\tstatic RefPtr<ExpressionType> Float3;\n\t\t\tstatic RefPtr<ExpressionType> Float4;\n\t\t\tstatic RefPtr<ExpressionType> Void;\n\t\t\tstatic RefPtr<ExpressionType> Error;\n\t\t\t// Note: just exists to make sure we can clean up\n\t\t\t// canonical types we create along the way\n\t\t\tstatic List<RefPtr<ExpressionType>> sCanonicalTypes;\n\t\tpublic:\n\t\t\tvirtual String ToString() const = 0;\n\t\t\tvirtual ExpressionType * Clone() = 0;\n\n\t\t\tbool IsIntegral() const;\n\t\t\tbool Equals(const ExpressionType * type) const;\n\t\t\tbool Equals(RefPtr<ExpressionType> type) const;\n\n\t\t\tbool IsVectorType() const;\n\t\t\tbool IsArray() const;\n\t\t\tbool IsGenericType(String typeName) const;\n\t\t\tBasicExpressionType * AsBasicType() const;\n\t\t\tArrayExpressionType * AsArrayType() const;\n\t\t\tGenericExpressionType * AsGenericType() const;\n\t\t\tNamedExpressionType* AsNamedType() const;\n\t\t\tbool IsTextureOrSampler() const;\n\t\t\tbool IsTexture() const;\n\t\t\tbool IsStruct() const;\n\t\t\tbool IsShader() const;\n\t\t\tstatic void Init();\n\t\t\tstatic void Finalize();\n\t\t\tExpressionType* GetCanonicalType() const;\n\t\t\tvirtual BindableResourceType GetBindableResourceType() const { return BindableResourceType::NonBindable; }\n\t\tprotected:\n\t\t\tvirtual bool IsIntegralImpl() const { return false; }\n\t\t\tvirtual bool EqualsImpl(const ExpressionType * type) const = 0;\n\t\t\tvirtual bool IsVectorTypeImpl() const { return false; }\n\t\t\tvirtual bool IsArrayImpl() const { return false; }\n\t\t\tvirtual bool IsGenericTypeImpl(String typeName) const { return nullptr; }\n\t\t\tvirtual BasicExpressionType * AsBasicTypeImpl() const { return nullptr; }\n\t\t\tvirtual ArrayExpressionType * AsArrayTypeImpl() const { return nullptr; }\n\t\t\tvirtual GenericExpressionType * AsGenericTypeImpl() const { return nullptr; }\n\t\t\tvirtual NamedExpressionType * AsNamedTypeImpl() const { return nullptr; }\n\n\t\t\tvirtual ExpressionType* CreateCanonicalType() = 0;\n\t\t\tExpressionType* canonicalType = nullptr;\n\t\t};\n\n\t\tclass BasicExpressionType : public ExpressionType\n\t\t{\n\t\tpublic:\n\t\t\tbool IsLeftValue;\n\t\t\tbool IsReference;\n\t\t\tbool IsMaskedVector = false;\n\t\t\tBaseType BaseType;\n\t\t\tShaderSymbol * Shader = nullptr;\n\t\t\tShaderClosure * ShaderClosure = nullptr;\n\t\t\tFunctionSymbol * Func = nullptr;\n\t\t\tShaderComponentSymbol * Component = nullptr;\n\t\t\tStructSyntaxNode* structDecl = nullptr;\n\t\t\tString RecordTypeName, GenericTypeVar;\n\n\t\t\tBasicExpressionType()\n\t\t\t{\n\t\t\t\tBaseType = Compiler::BaseType::Int;\n\t\t\t\tFunc = 0;\n\t\t\t\tIsLeftValue = false;\n\t\t\t\tIsReference = false;\n\t\t\t}\n\t\t\tBasicExpressionType(Compiler::BaseType baseType)\n\t\t\t{\n\t\t\t\tBaseType = baseType;\n\t\t\t\tFunc = 0;\n\t\t\t\tIsLeftValue = false;\n\t\t\t\tIsReference = false;\n\t\t\t}\n\t\t\tBasicExpressionType(ShaderSymbol * shaderSym, Compiler::ShaderClosure * closure)\n\t\t\t{\n\t\t\t\tthis->BaseType = BaseType::Shader;\n\t\t\t\tthis->ShaderClosure = closure;\n\t\t\t\tthis->Shader = shaderSym;\n\t\t\t}\n\t\t\tvirtual CoreLib::Basic::String ToString() const override;\n\t\t\tvirtual ExpressionType * Clone() override;\n\t\tprotected:\n\t\t\tvirtual bool IsIntegralImpl() const override;\n\t\t\tvirtual bool EqualsImpl(const ExpressionType * type) const override;\n\t\t\tvirtual bool IsVectorTypeImpl() const override;\n\t\t\tvirtual BasicExpressionType * AsBasicTypeImpl() const override\n\t\t\t{\n\t\t\t\treturn const_cast<BasicExpressionType*>(this);\n\t\t\t}\n\t\t\tvirtual ExpressionType* CreateCanonicalType() override;\n\t\t\tvirtual BindableResourceType GetBindableResourceType() const override;\n\t\t};\n\n\t\tclass ArrayExpressionType : public ExpressionType\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionType> BaseType;\n\t\t\tint ArrayLength = 0;\n\t\t\tvirtual CoreLib::Basic::String ToString() const override;\n\t\t\tvirtual ExpressionType * Clone() override;\n\t\tprotected:\n\t\t\tvirtual bool IsArrayImpl() const override;\n\t\t\tvirtual bool EqualsImpl(const ExpressionType * type) const override;\n\t\t\tvirtual ArrayExpressionType * AsArrayTypeImpl() const override\n\t\t\t{\n\t\t\t\treturn const_cast<ArrayExpressionType*>(this);\n\t\t\t}\n\t\t\tvirtual ExpressionType* CreateCanonicalType() override;\n\t\t};\n\n\t\tclass GenericExpressionType : public ExpressionType\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionType> BaseType;\n\t\t\tString GenericTypeName;\n\t\t\tvirtual CoreLib::Basic::String ToString() const override;\n\t\t\tvirtual ExpressionType * Clone() override;\n\t\tprotected:\n\t\t\tvirtual bool EqualsImpl(const ExpressionType * type) const override;\n\t\t\tvirtual bool IsGenericTypeImpl(String typeName) const override\n\t\t\t{\n\t\t\t\treturn GenericTypeName == typeName;\n\t\t\t}\n\t\t\tvirtual GenericExpressionType * AsGenericTypeImpl() const override\n\t\t\t{\n\t\t\t\treturn const_cast<GenericExpressionType*>(this);\n\t\t\t}\n\t\t\tvirtual ExpressionType* CreateCanonicalType() override;\n\t\t\tvirtual BindableResourceType GetBindableResourceType() const override;\n\n\t\t};\n\n\t\tclass NamedExpressionType : public ExpressionType\n\t\t{\n\t\tpublic:\n\t\t\tTypeDefDecl* decl;\n\n\t\t\tvirtual String ToString() const override;\n\t\t\tvirtual ExpressionType * Clone() override;\n\t\t\tvirtual BindableResourceType GetBindableResourceType() const override;\n\n\t\tprotected:\n\t\t\tvirtual bool EqualsImpl(const ExpressionType * type) const override;\n\t\t\tvirtual NamedExpressionType * AsNamedTypeImpl() const override;\n\t\t\tvirtual ExpressionType* CreateCanonicalType() override;\n\t\t};\n\n\n\t\tclass Type\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionType> DataType;\n\t\t\t// ContrainedWorlds: Implementation must be defined at at least one of of these worlds in order to satisfy global dependency\n\t\t\t// FeasibleWorlds: The component can be computed at any of these worlds\n\t\t\tEnumerableHashSet<String> ConstrainedWorlds, FeasibleWorlds;\n\t\t\tEnumerableHashSet<String> PinnedWorlds;\n\t\t};\n\n\t\tclass ContainerDecl;\n\t\tclass Scope : public RefObject\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<Scope> Parent;\n\t\t\tContainerDecl*  containerDecl;\n\t\t\tDictionary<String, Decl*> decls;\n\t\t\tDecl* LookUp(String const& name);\n\t\t\tScope(RefPtr<Scope> parent, ContainerDecl* containerDecl)\n\t\t\t\t: Parent(parent)\n\t\t\t\t, containerDecl(containerDecl)\n\t\t\t{}\n\t\t};\n\n\t\tclass CloneContext\n\t\t{\n\t\tpublic:\n\t\t\tDictionary<Spire::Compiler::Scope*, RefPtr<Spire::Compiler::Scope>> ScopeTranslateTable;\n\t\t};\n\n\t\tclass SyntaxNode : public RefObject\n\t\t{\n\t\tprotected:\n\t\t\ttemplate<typename T>\n\t\t\tT* CloneSyntaxNodeFields(T * target, CloneContext & ctx)\n\t\t\t{\n\t\t\t\tif (this->Scope)\n\t\t\t\t{\n\t\t\t\t\tRefPtr<Spire::Compiler::Scope> newScope;\n\t\t\t\t\tif (ctx.ScopeTranslateTable.TryGetValue(this->Scope.Ptr(), newScope))\n\t\t\t\t\t\ttarget->Scope = newScope;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ttarget->Scope = new Spire::Compiler::Scope(*this->Scope);\n\t\t\t\t\t\tctx.ScopeTranslateTable[this->Scope.Ptr()] = target->Scope;\n\t\t\t\t\t\tRefPtr<Spire::Compiler::Scope> parentScope;\n\t\t\t\t\t\tif (ctx.ScopeTranslateTable.TryGetValue(target->Scope->Parent.Ptr(), parentScope))\n\t\t\t\t\t\t\ttarget->Scope->Parent = parentScope.Ptr();\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\ttarget->Position = this->Position;\n\t\t\t\ttarget->Tags = this->Tags;\n\t\t\t\treturn target;\n\t\t\t}\n\t\tpublic:\n\t\t\tEnumerableDictionary<String, RefPtr<Object>> Tags;\n\t\t\tCodePosition Position;\n\t\t\tRefPtr<Scope> Scope;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) = 0;\n\t\t\tvirtual SyntaxNode * Clone(CloneContext & ctx) = 0;\n\t\t};\n\n\t\tclass TypeSyntaxNode : public SyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tvirtual TypeSyntaxNode * Clone(CloneContext & ctx) = 0;\n\t\t};\n\n\t\tclass BasicTypeSyntaxNode : public TypeSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tString TypeName;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual BasicTypeSyntaxNode * Clone(CloneContext & ctx) override\n\t\t\t{\n\t\t\t\treturn CloneSyntaxNodeFields(new BasicTypeSyntaxNode(*this), ctx);\n\t\t\t}\n\t\t};\n\n\t\tclass ArrayTypeSyntaxNode : public TypeSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<TypeSyntaxNode> BaseType;\n\t\t\tint ArrayLength;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ArrayTypeSyntaxNode * Clone(CloneContext & ctx) override\n\t\t\t{\n\t\t\t\tauto rs = CloneSyntaxNodeFields(new ArrayTypeSyntaxNode(*this), ctx);\n\t\t\t\trs->BaseType = BaseType->Clone(ctx);\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t};\n\n\t\tclass GenericTypeSyntaxNode : public TypeSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<TypeSyntaxNode> BaseType;\n\t\t\tString GenericTypeName;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual GenericTypeSyntaxNode * Clone(CloneContext & ctx) override\n\t\t\t{\n\t\t\t\tauto rs = CloneSyntaxNodeFields(new GenericTypeSyntaxNode(*this), ctx);\n\t\t\t\trs->BaseType = BaseType->Clone(ctx);\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t};\n\n\t\tclass ContainerDecl;\n\t\tclass SpecializeModifier;\n\n\t\tclass Decl : public SyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tContainerDecl*  ParentDecl;\n\t\t\tToken Name;\n\t\t\tModifiers modifiers;\n\n\t\t\tbool HasModifier(ModifierFlags flags) { return (modifiers.flags & flags) == flags; }\n\n\t\t\ttemplate<typename T>\n\t\t\tFilteredModifierList<T> GetModifiersOfType() { return FilteredModifierList<T>(modifiers.first.Ptr()); }\n\n\t\t\tFilteredModifierList<SimpleAttribute> GetLayoutAttributes() { return GetModifiersOfType<SimpleAttribute>(); }\n\n\t\t\tbool FindSimpleAttribute(String const& key, Token& outValue);\n\t\t\tbool FindSimpleAttribute(String const& key, String& outValue);\n\t\t\tbool HasSimpleAttribute(String const& key);\n\t\t\tSpecializeModifier * FindSpecializeModifier();\n\n\t\t\tvirtual Decl * Clone(CloneContext & ctx) = 0;\n\t\t};\n\n\t\ttemplate<typename T>\n\t\tstruct FilteredMemberList\n\t\t{\n\t\t\ttypedef RefPtr<Decl> Element;\n\n\t\t\tFilteredMemberList()\n\t\t\t\t: mBegin(NULL)\n\t\t\t\t, mEnd(NULL)\n\t\t\t{}\n\n\t\t\texplicit FilteredMemberList(\n\t\t\t\tList<Element> const& list)\n\t\t\t\t: mBegin(Adjust(list.begin(), list.end()))\n\t\t\t\t, mEnd(list.end())\n\t\t\t{}\n\n\t\t\tstruct Iterator\n\t\t\t{\n\t\t\t\tElement* mCursor;\n\t\t\t\tElement* mEnd;\n\n\t\t\t\tbool operator!=(Iterator const& other)\n\t\t\t\t{\n\t\t\t\t\treturn mCursor != other.mCursor;\n\t\t\t\t}\n\n\t\t\t\tvoid operator++()\n\t\t\t\t{\n\t\t\t\t\tmCursor = Adjust(mCursor + 1, mEnd);\n\t\t\t\t}\n\n\t\t\t\tRefPtr<T>& operator*()\n\t\t\t\t{\n\t\t\t\t\treturn *(RefPtr<T>*)mCursor;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tIterator begin()\n\t\t\t{\n\t\t\t\tIterator iter = { mBegin, mEnd };\n\t\t\t\treturn iter;\n\t\t\t}\n\n\t\t\tIterator end()\n\t\t\t{\n\t\t\t\tIterator iter = { mEnd, mEnd };\n\t\t\t\treturn iter;\n\t\t\t}\n\n\t\t\tstatic Element* Adjust(Element* cursor, Element* end)\n\t\t\t{\n\t\t\t\twhile (cursor != end)\n\t\t\t\t{\n\t\t\t\t\tif ((*cursor).As<T>())\n\t\t\t\t\t\treturn cursor;\n\t\t\t\t\tcursor++;\n\t\t\t\t}\n\t\t\t\treturn cursor;\n\t\t\t}\n\n\t\t\t// TODO(tfoley): It is ugly to have these.\n\t\t\t// We should probably fix the call sites instead.\n\t\t\tRefPtr<T>& First() { return *begin(); }\n\t\t\tint Count()\n\t\t\t{\n\t\t\t\tint count = 0;\n\t\t\t\tfor (auto iter : (*this))\n\t\t\t\t{\n\t\t\t\t\t(void)iter;\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t\treturn count;\n\t\t\t}\n\n\t\t\tList<RefPtr<T>> ToArray()\n\t\t\t{\n\t\t\t\tList<RefPtr<T>> result;\n\t\t\t\tfor (auto element : (*this))\n\t\t\t\t{\n\t\t\t\t\tresult.Add(element);\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tElement* mBegin;\n\t\t\tElement* mEnd;\n\t\t};\n\n\t\t// A \"container\" decl is a parent to other declarations\n\t\tclass ContainerDecl : public Decl\n\t\t{\n\t\tpublic:\n\t\t\tList<RefPtr<Decl>> Members;\n\n\t\t\ttemplate<typename T>\n\t\t\tFilteredMemberList<T> GetMembersOfType()\n\t\t\t{\n\t\t\t\treturn FilteredMemberList<T>(Members);\n\t\t\t}\n\t\t};\n\n\t\tenum class ExpressionAccess\n\t\t{\n\t\t\tRead, Write\n\t\t};\n\n\t\tclass ExpressionSyntaxNode : public SyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionType> Type;\n\t\t\tExpressionAccess Access;\n\t\t\tExpressionSyntaxNode()\n\t\t\t{\n\t\t\t\tAccess = ExpressionAccess::Read;\n\t\t\t}\n\t\t\tExpressionSyntaxNode(const ExpressionSyntaxNode & expr) = default;\n\t\t\tvirtual ExpressionSyntaxNode* Clone(CloneContext & ctx) = 0;\n\t\t};\n\n\n\t\t// A 'specialize' modifier indicating the shader parameter should be specialized\n\t\tclass SpecializeModifier : public Modifier\n\t\t{\n\t\tpublic:\n\t\t\tList<RefPtr<ExpressionSyntaxNode>> Values;\n\n\t\t};\n\n\t\t//\n\t\t// Declarations\n\t\t//\n\n\t\t// Base class for all variable-like declarations\n\t\tclass VarDeclBase : public Decl\n\t\t{\n\t\tpublic:\n\t\t\t// Syntax for type specifier\n\t\t\tRefPtr<TypeSyntaxNode> TypeNode;\n\n\t\t\t// Resolved type of the variable\n\t\t\tRefPtr<ExpressionType> Type;\n\n\t\t\t// Initializer expression (optional)\n\t\t\tRefPtr<ExpressionSyntaxNode> Expr;\n\t\t};\n\n\t\t// A field of a `struct` type\n\t\tclass StructField : public VarDeclBase\n\t\t{\n\t\tpublic:\n\t\t\tStructField()\n\t\t\t{}\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual StructField * Clone(CloneContext & ctx) override\n\t\t\t{\n\t\t\t\tauto rs = CloneSyntaxNodeFields(new StructField(*this), ctx);\n\t\t\t\trs->TypeNode = TypeNode->Clone(ctx);\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t};\n\n\n\t\tclass StructSyntaxNode : public ContainerDecl\n\t\t{\n\t\tpublic:\n\t\t\tFilteredMemberList<StructField> GetFields()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<StructField>();\n\t\t\t}\n\t\t\tbool SemanticallyChecked = false;\n\t\t\tbool IsIntrinsic = false;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tStructField* FindField(String name)\n\t\t\t{\n\t\t\t\tfor (auto field : GetFields())\n\t\t\t\t{\n\t\t\t\t\tif (field->Name.Content == name)\n\t\t\t\t\t\treturn field.Ptr();\n\t\t\t\t}\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\tint FindFieldIndex(String name)\n\t\t\t{\n\t\t\t\tint index = 0;\n\t\t\t\tfor (auto field : GetFields())\n\t\t\t\t{\n\t\t\t\t\tif (field->Name.Content == name)\n\t\t\t\t\t\treturn index;\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tvirtual StructSyntaxNode * Clone(CloneContext & ctx) override\n\t\t\t{\n\t\t\t\tauto rs = CloneSyntaxNodeFields(new StructSyntaxNode(*this), ctx);\n\t\t\t\trs->Members.Clear();\n\t\t\t\tfor (auto & m : Members)\n\t\t\t\t\trs->Members.Add(m->Clone(ctx));\n\t\t\t\treturn rs;\n\t\t\t}\n\t\t};\n\n\t\t// A `typedef` declaration\n\t\tclass TypeDefDecl : public Decl\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<TypeSyntaxNode> TypeNode;\n\t\t\tRefPtr<ExpressionType> Type;\n\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual TypeDefDecl * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass StatementSyntaxNode : public SyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tvirtual StatementSyntaxNode* Clone(CloneContext & ctx) = 0;\n\t\t};\n\n\t\t// A scope for local declarations (e.g., as part of a statement)\n\t\tclass ScopeDecl : public ContainerDecl\n\t\t{\n\t\tpublic:\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ScopeDecl * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ScopeStmt : public StatementSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ScopeDecl> scopeDecl;\n\t\t};\n\n\t\tclass BlockStatementSyntaxNode : public ScopeStmt\n\t\t{\n\t\tpublic:\n\t\t\tList<RefPtr<StatementSyntaxNode>> Statements;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual BlockStatementSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\t// TODO(tfoley): Only used by IL at this point\n\t\tenum class ParameterQualifier\n\t\t{\n\t\t\tIn, Out, InOut, Uniform\n\t\t};\n\n\t\tclass ParameterSyntaxNode : public VarDeclBase\n\t\t{\n\t\tpublic:\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ParameterSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass FunctionDeclBase : public ContainerDecl\n\t\t{\n\t\tpublic:\n\t\t\tFilteredMemberList<ParameterSyntaxNode> GetParameters()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<ParameterSyntaxNode>();\n\t\t\t}\n\t\t\tRefPtr<BlockStatementSyntaxNode> Body;\n\t\t};\n\n\t\tclass FunctionSyntaxNode : public FunctionDeclBase\n\t\t{\n\t\tpublic:\n\t\t\tString InternalName;\n\t\t\tRefPtr<ExpressionType> ReturnType;\n\t\t\tRefPtr<TypeSyntaxNode> ReturnTypeNode;\n\t\t\tbool SemanticallyChecked = false;\n\t\t\tbool IsInline() { return HasModifier(ModifierFlag::Inline); }\n\t\t\tbool IsExtern() { return HasModifier(ModifierFlag::Extern); }\n\t\t\tbool HasSideEffect() { return !HasModifier(ModifierFlag::Intrinsic); }\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tFunctionSyntaxNode()\n\t\t\t{\n\t\t\t}\n\n\t\t\tvirtual FunctionSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ImportOperatorDefSyntaxNode : public FunctionDeclBase\n\t\t{\n\t\tpublic:\n\t\t\tToken SourceWorld, DestWorld;\n\t\t\tToken TypeName;\n\t\t\tList<RefPtr<FunctionSyntaxNode>> Requirements;\n\t\t\tList<String> Usings;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ImportOperatorDefSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ChoiceValueSyntaxNode : public ExpressionSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tString WorldName;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor *) { return this; }\n\t\t\tvirtual ChoiceValueSyntaxNode * Clone(CloneContext & ctx);\n\t\t};\n\n\t\tclass VarExpressionSyntaxNode : public ExpressionSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tString Variable;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual VarExpressionSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ConstantExpressionSyntaxNode : public ExpressionSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tenum class ConstantType\n\t\t\t{\n\t\t\t\tInt, UInt, Bool, Float\n\t\t\t};\n\t\t\tConstantType ConstType;\n\t\t\tunion\n\t\t\t{\n\t\t\t\tint IntValue;\n\t\t\t\tfloat FloatValue;\n\t\t\t};\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ConstantExpressionSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tenum class Operator\n\t\t{\n\t\t\tNeg, Not, BitNot, PreInc, PreDec, PostInc, PostDec,\n\t\t\tMul, Div, Mod,\n\t\t\tAdd, Sub,\n\t\t\tLsh, Rsh,\n\t\t\tEql, Neq, Greater, Less, Geq, Leq,\n\t\t\tBitAnd, BitXor, BitOr,\n\t\t\tAnd,\n\t\t\tOr,\n\t\t\tAssign = 200, AddAssign, SubAssign, MulAssign, DivAssign, ModAssign,\n\t\t\tLshAssign, RshAssign, OrAssign, AndAssign, XorAssign\n\t\t};\n\n\t\tString GetOperatorFunctionName(Operator op);\n\n\t\tclass ImportExpressionSyntaxNode : public ExpressionSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionSyntaxNode> Component;\n\t\t\tString ComponentUniqueName; // filled by ResolveDependence\n\t\t\tRefPtr<ImportOperatorDefSyntaxNode> ImportOperatorDef; // filled by semantics\n\t\t\tList<RefPtr<ExpressionSyntaxNode>> Arguments;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ImportExpressionSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ProjectExpressionSyntaxNode : public ExpressionSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionSyntaxNode> BaseExpression;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ProjectExpressionSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass UnaryExpressionSyntaxNode : public ExpressionSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tOperator Operator;\n\t\t\tRefPtr<ExpressionSyntaxNode> Expression;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual UnaryExpressionSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass BinaryExpressionSyntaxNode : public ExpressionSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tOperator Operator;\n\t\t\tRefPtr<ExpressionSyntaxNode> LeftExpression;\n\t\t\tRefPtr<ExpressionSyntaxNode> RightExpression;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual BinaryExpressionSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass IndexExpressionSyntaxNode : public ExpressionSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionSyntaxNode> BaseExpression;\n\t\t\tRefPtr<ExpressionSyntaxNode> IndexExpression;\n\t\t\tvirtual IndexExpressionSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t};\n\n\t\tclass MemberExpressionSyntaxNode : public ExpressionSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionSyntaxNode> BaseExpression;\n\t\t\tString MemberName;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual MemberExpressionSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass InvokeExpressionSyntaxNode : public ExpressionSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionSyntaxNode> FunctionExpr;\n\t\t\tList<RefPtr<ExpressionSyntaxNode>> Arguments;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual InvokeExpressionSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass TypeCastExpressionSyntaxNode : public ExpressionSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<TypeSyntaxNode> TargetType;\n\t\t\tRefPtr<ExpressionSyntaxNode> Expression;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual TypeCastExpressionSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass SelectExpressionSyntaxNode : public ExpressionSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionSyntaxNode> SelectorExpr, Expr0, Expr1;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual SelectExpressionSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\n\t\tclass EmptyStatementSyntaxNode : public StatementSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual EmptyStatementSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass DiscardStatementSyntaxNode : public StatementSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual DiscardStatementSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tstruct Variable : public VarDeclBase\n\t\t{\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual Variable * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass VarDeclrStatementSyntaxNode : public StatementSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<Decl> decl;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual VarDeclrStatementSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass RateWorld\n\t\t{\n\t\tpublic:\n\t\t\tToken World;\n\t\t\tbool Pinned = false;\n\t\t\tRateWorld() {}\n\t\t\tRateWorld(String world)\n\t\t\t{\n\t\t\t\tWorld.Content = world;\n\t\t\t\tWorld.Type = TokenType::Identifier;\n\t\t\t}\n\t\t};\n\n\t\tclass RateSyntaxNode : public SyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tList<RateWorld> Worlds;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor *) override\n\t\t\t{\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tvirtual RateSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ComponentSyntaxNode : public ContainerDecl\n\t\t{\n\t\tpublic:\n\t\t\tbool IsOutput() { return HasModifier(ModifierFlag::Out); }\n\t\t\tbool IsPublic() { return HasModifier(ModifierFlag::Public); }\n\t\t\tbool IsInline() { return HasModifier(ModifierFlag::Inline) || IsComponentFunction(); }\n\t\t\tbool IsRequire() { return HasModifier(ModifierFlag::Require); }\n\t\t\tbool IsInput() { return HasModifier(ModifierFlag::Extern); }\n\t\t\tbool IsParam() { return HasModifier(ModifierFlag::Param); }\n\t\t\tRefPtr<TypeSyntaxNode> TypeNode;\n\t\t\tRefPtr<ExpressionType> Type;\n\t\t\tRefPtr<RateSyntaxNode> Rate;\n\t\t\tRefPtr<BlockStatementSyntaxNode> BlockStatement;\n\t\t\tRefPtr<ExpressionSyntaxNode> Expression;\n\t\t\tFilteredMemberList<ParameterSyntaxNode> GetParameters()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<ParameterSyntaxNode>();\n\t\t\t}\n\t\t\tbool IsComponentFunction() { return GetParameters().Count() != 0; }\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ComponentSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass WorldSyntaxNode : public Decl\n\t\t{\n\t\tpublic:\n\t\t\tbool IsAbstract() { return HasModifier(ModifierFlag::Input); }\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor *) override { return this; }\n\t\t\tvirtual WorldSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass StageSyntaxNode : public Decl\n\t\t{\n\t\tpublic:\n\t\t\tToken StageType;\n\t\t\tEnumerableDictionary<String, Token> Attributes;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor *) override { return this; }\n\t\t\tvirtual StageSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\t// Shared functionality for \"shader class\"-like declarations\n\t\tclass ShaderDeclBase : public ContainerDecl\n\t\t{\n\t\tpublic:\n\t\t\tToken ParentPipelineName;\n\t\t\tList<Token> InterfaceNames;\n\t\t};\n\n\t\tclass PipelineSyntaxNode : public ShaderDeclBase\n\t\t{\n\t\tpublic:\n\t\t\t// Access members of specific types\n\t\t\tFilteredMemberList<WorldSyntaxNode> GetWorlds()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<WorldSyntaxNode>();\n\t\t\t}\n\t\t\tFilteredMemberList<ImportOperatorDefSyntaxNode> GetImportOperators()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<ImportOperatorDefSyntaxNode>();\n\t\t\t}\n\t\t\tFilteredMemberList<StageSyntaxNode> GetStages()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<StageSyntaxNode>();\n\t\t\t}\n\t\t\tFilteredMemberList<ComponentSyntaxNode> GetAbstractComponents()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<ComponentSyntaxNode>();\n\t\t\t}\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor *) override { return this; }\n\t\t\tvirtual PipelineSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ImportArgumentSyntaxNode : public SyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionSyntaxNode> Expression;\n\t\t\tToken ArgumentName;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor *) override;\n\t\t\tvirtual ImportArgumentSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ImportSyntaxNode : public Decl\n\t\t{\n\t\tpublic:\n\t\t\tbool IsInplace = false;\n\t\t\tbool IsPublic() { return HasModifier(ModifierFlag::Public); }\n\t\t\tToken ShaderName;\n\t\t\tToken ObjectName;\n\t\t\tList<RefPtr<ImportArgumentSyntaxNode>> Arguments;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor *) override;\n\t\t\tvirtual ImportSyntaxNode * Clone(CloneContext & ctx) override;\n\n\t\t};\n\n\t\tclass TemplateShaderParameterSyntaxNode : public SyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tToken ModuleName, InterfaceName;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * /*visitor*/) { return this; }\n\t\t\tvirtual TemplateShaderParameterSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass TemplateShaderSyntaxNode : public ShaderDeclBase\n\t\t{\n\t\tpublic:\n\t\t\tList<RefPtr<TemplateShaderParameterSyntaxNode>> Parameters;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual TemplateShaderSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ShaderSyntaxNode : public ShaderDeclBase\n\t\t{\n\t\tpublic:\n\t\t\tbool IsModule = false;\n\t\t\tbool SemanticallyChecked = false;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ShaderSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass InterfaceSyntaxNode : public ShaderDeclBase\n\t\t{\n\t\tpublic:\n\t\t\tbool SemanticallyChecked = false;\n\t\t\tFilteredMemberList<ComponentSyntaxNode> GetComponents()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<ComponentSyntaxNode>();\n\t\t\t}\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor *) override;\n\t\t\tvirtual InterfaceSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass UsingFileDecl : public Decl\n\t\t{\n\t\tpublic:\n\t\t\tToken fileName;\n\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual UsingFileDecl * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ProgramSyntaxNode : public ContainerDecl\n\t\t{\n\t\tpublic:\n\t\t\t// Access members of specific types\n\t\t\tFilteredMemberList<UsingFileDecl> GetUsings()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<UsingFileDecl>();\n\t\t\t}\n\t\t\tFilteredMemberList<FunctionSyntaxNode> GetFunctions()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<FunctionSyntaxNode>();\n\t\t\t}\n\t\t\tFilteredMemberList<PipelineSyntaxNode> GetPipelines()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<PipelineSyntaxNode>();\n\t\t\t}\n\t\t\tFilteredMemberList<InterfaceSyntaxNode> GetInterfaces()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<InterfaceSyntaxNode>();\n\t\t\t}\n\t\t\tFilteredMemberList<ShaderSyntaxNode> GetShaders()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<ShaderSyntaxNode>();\n\t\t\t}\n\t\t\tFilteredMemberList<StructSyntaxNode> GetStructs()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<StructSyntaxNode>();\n\t\t\t}\n\t\t\tFilteredMemberList<TypeDefDecl> GetTypeDefs()\n\t\t\t{\n\t\t\t\treturn GetMembersOfType<TypeDefDecl>();\n\t\t\t}\n\t\t\tvoid Include(ProgramSyntaxNode * other)\n\t\t\t{\n\t\t\t\tMembers.AddRange(other->Members);\n\t\t\t}\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ProgramSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ImportStatementSyntaxNode : public StatementSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ImportSyntaxNode> Import;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ImportStatementSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass IfStatementSyntaxNode : public StatementSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionSyntaxNode> Predicate;\n\t\t\tRefPtr<StatementSyntaxNode> PositiveStatement;\n\t\t\tRefPtr<StatementSyntaxNode> NegativeStatement;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual IfStatementSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ForStatementSyntaxNode : public ScopeStmt\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<StatementSyntaxNode> InitialStatement;\n\t\t\tRefPtr<ExpressionSyntaxNode> SideEffectExpression, PredicateExpression;\n\t\t\tRefPtr<StatementSyntaxNode> Statement;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ForStatementSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass WhileStatementSyntaxNode : public StatementSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionSyntaxNode> Predicate;\n\t\t\tRefPtr<StatementSyntaxNode> Statement;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual WhileStatementSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass DoWhileStatementSyntaxNode : public StatementSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<StatementSyntaxNode> Statement;\n\t\t\tRefPtr<ExpressionSyntaxNode> Predicate;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual DoWhileStatementSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass BreakStatementSyntaxNode : public StatementSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual BreakStatementSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ContinueStatementSyntaxNode : public StatementSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ContinueStatementSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ReturnStatementSyntaxNode : public StatementSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionSyntaxNode> Expression;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ReturnStatementSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass ExpressionStatementSyntaxNode : public StatementSyntaxNode\n\t\t{\n\t\tpublic:\n\t\t\tRefPtr<ExpressionSyntaxNode> Expression;\n\t\t\tvirtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override;\n\t\t\tvirtual ExpressionStatementSyntaxNode * Clone(CloneContext & ctx) override;\n\t\t};\n\n\t\tclass SyntaxVisitor : public Object\n\t\t{\n\t\tprotected:\n\t\t\tDiagnosticSink * sink = nullptr;\n\t\t\tDiagnosticSink* getSink() { return sink; }\n\t\tpublic:\n\t\t\tSyntaxVisitor(DiagnosticSink * sink)\n\t\t\t\t: sink(sink)\n\t\t\t{}\n\t\t\tvirtual RefPtr<ProgramSyntaxNode> VisitProgram(ProgramSyntaxNode* program)\n\t\t\t{\n\t\t\t\tfor (auto & m : program->Members)\n\t\t\t\t\tm = m->Accept(this).As<Decl>();\n\t\t\t\treturn program;\n\t\t\t}\n\t\t\tvirtual RefPtr<ShaderSyntaxNode> VisitShader(ShaderSyntaxNode * shader)\n\t\t\t{\n\t\t\t\tfor (auto & comp : shader->Members)\n\t\t\t\t\tcomp = comp->Accept(this).As<Decl>();\n\t\t\t\treturn shader;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<UsingFileDecl> VisitUsingFileDecl(UsingFileDecl * decl)\n\t\t\t{\n\t\t\t\treturn decl;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<ComponentSyntaxNode> VisitComponent(ComponentSyntaxNode * comp);\n\t\t\tvirtual RefPtr<FunctionSyntaxNode> VisitFunction(FunctionSyntaxNode* func)\n\t\t\t{\n\t\t\t\tfunc->ReturnTypeNode = func->ReturnTypeNode->Accept(this).As<TypeSyntaxNode>();\n\t\t\t\tfor (auto & member : func->Members)\n\t\t\t\t\tmember = member->Accept(this).As<Decl>();\n\t\t\t\tif (func->Body)\n\t\t\t\t\tfunc->Body = func->Body->Accept(this).As<BlockStatementSyntaxNode>();\n\t\t\t\treturn func;\n\t\t\t}\n\t\t\tvirtual RefPtr<ScopeDecl> VisitScopeDecl(ScopeDecl* decl)\n\t\t\t{\n\t\t\t\t// By default don't visit children, because they will always\n\t\t\t\t// be encountered in the ordinary flow of the corresponding statement.\n\t\t\t\treturn decl;\n\t\t\t}\n\t\t\tvirtual RefPtr<StructSyntaxNode> VisitStruct(StructSyntaxNode * s)\n\t\t\t{\n\t\t\t\tfor (auto & f : s->Members)\n\t\t\t\t\tf = f->Accept(this).As<Decl>();\n\t\t\t\treturn s;\n\t\t\t}\n\t\t\tvirtual RefPtr<TypeDefDecl> VisitTypeDefDecl(TypeDefDecl* decl)\n\t\t\t{\n\t\t\t\tdecl->TypeNode = decl->TypeNode->Accept(this).As<TypeSyntaxNode>();\n\t\t\t\treturn decl;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitDiscardStatement(DiscardStatementSyntaxNode * stmt)\n\t\t\t{\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StructField> VisitStructField(StructField * f)\n\t\t\t{\n\t\t\t\tf->TypeNode = f->TypeNode->Accept(this).As<TypeSyntaxNode>();\n\t\t\t\treturn f;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitBlockStatement(BlockStatementSyntaxNode* stmt)\n\t\t\t{\n\t\t\t\tfor (auto & s : stmt->Statements)\n\t\t\t\t\ts = s->Accept(this).As<StatementSyntaxNode>();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitBreakStatement(BreakStatementSyntaxNode* stmt)\n\t\t\t{\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitContinueStatement(ContinueStatementSyntaxNode* stmt)\n\t\t\t{\n\t\t\t\treturn stmt;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitDoWhileStatement(DoWhileStatementSyntaxNode* stmt)\n\t\t\t{\n\t\t\t\tif (stmt->Predicate)\n\t\t\t\t\tstmt->Predicate = stmt->Predicate->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (stmt->Statement)\n\t\t\t\t\tstmt->Statement = stmt->Statement->Accept(this).As<StatementSyntaxNode>();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitEmptyStatement(EmptyStatementSyntaxNode* stmt)\n\t\t\t{\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitForStatement(ForStatementSyntaxNode* stmt)\n\t\t\t{\n\t\t\t\tif (stmt->InitialStatement)\n\t\t\t\t\tstmt->InitialStatement = stmt->InitialStatement->Accept(this).As<StatementSyntaxNode>();\n\t\t\t\tif (stmt->PredicateExpression)\n\t\t\t\t\tstmt->PredicateExpression = stmt->PredicateExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (stmt->SideEffectExpression)\n\t\t\t\t\tstmt->SideEffectExpression = stmt->SideEffectExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (stmt->Statement)\n\t\t\t\t\tstmt->Statement = stmt->Statement->Accept(this).As<StatementSyntaxNode>();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitIfStatement(IfStatementSyntaxNode* stmt)\n\t\t\t{\n\t\t\t\tif (stmt->Predicate)\n\t\t\t\t\tstmt->Predicate = stmt->Predicate->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (stmt->PositiveStatement)\n\t\t\t\t\tstmt->PositiveStatement = stmt->PositiveStatement->Accept(this).As<StatementSyntaxNode>();\n\t\t\t\tif (stmt->NegativeStatement)\n\t\t\t\t\tstmt->NegativeStatement = stmt->NegativeStatement->Accept(this).As<StatementSyntaxNode>();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitReturnStatement(ReturnStatementSyntaxNode* stmt)\n\t\t\t{\n\t\t\t\tif (stmt->Expression)\n\t\t\t\t\tstmt->Expression = stmt->Expression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitVarDeclrStatement(VarDeclrStatementSyntaxNode* stmt)\n\t\t\t{\n\t\t\t\tstmt->decl = stmt->decl->Accept(this).As<Decl>();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitWhileStatement(WhileStatementSyntaxNode* stmt)\n\t\t\t{\n\t\t\t\tif (stmt->Predicate)\n\t\t\t\t\tstmt->Predicate = stmt->Predicate->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (stmt->Statement)\n\t\t\t\t\tstmt->Statement = stmt->Statement->Accept(this).As<StatementSyntaxNode>();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitExpressionStatement(ExpressionStatementSyntaxNode* stmt)\n\t\t\t{\n\t\t\t\tif (stmt->Expression)\n\t\t\t\t\tstmt->Expression = stmt->Expression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn stmt;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitBinaryExpression(BinaryExpressionSyntaxNode* expr)\n\t\t\t{\n\t\t\t\tif (expr->LeftExpression)\n\t\t\t\t\texpr->LeftExpression = expr->LeftExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (expr->RightExpression)\n\t\t\t\t\texpr->RightExpression = expr->RightExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitConstantExpression(ConstantExpressionSyntaxNode* expr)\n\t\t\t{\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitIndexExpression(IndexExpressionSyntaxNode* expr)\n\t\t\t{\n\t\t\t\tif (expr->BaseExpression)\n\t\t\t\t\texpr->BaseExpression = expr->BaseExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (expr->IndexExpression)\n\t\t\t\t\texpr->IndexExpression = expr->IndexExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitMemberExpression(MemberExpressionSyntaxNode * stmt)\n\t\t\t{\n\t\t\t\tif (stmt->BaseExpression)\n\t\t\t\t\tstmt->BaseExpression = stmt->BaseExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitInvokeExpression(InvokeExpressionSyntaxNode* stmt)\n\t\t\t{\n\t\t\t\tstmt->FunctionExpr->Accept(this);\n\t\t\t\tfor (auto & arg : stmt->Arguments)\n\t\t\t\t\targ = arg->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitImportExpression(ImportExpressionSyntaxNode * expr)\n\t\t\t{\n\t\t\t\tfor (auto & arg : expr->Arguments)\n\t\t\t\t\targ = arg->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (expr->ImportOperatorDef)\n\t\t\t\t\texpr->ImportOperatorDef->Accept(this);\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitTypeCastExpression(TypeCastExpressionSyntaxNode * stmt)\n\t\t\t{\n\t\t\t\tif (stmt->Expression)\n\t\t\t\t\tstmt->Expression = stmt->Expression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn stmt->Expression;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitSelectExpression(SelectExpressionSyntaxNode * expr)\n\t\t\t{\n\t\t\t\tif (expr->SelectorExpr)\n\t\t\t\t\texpr->SelectorExpr = expr->SelectorExpr->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (expr->Expr0)\n\t\t\t\t\texpr->Expr0 = expr->Expr0->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\tif (expr->Expr1)\n\t\t\t\t\texpr->Expr1 = expr->Expr1->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitUnaryExpression(UnaryExpressionSyntaxNode* expr)\n\t\t\t{\n\t\t\t\tif (expr->Expression)\n\t\t\t\t\texpr->Expression = expr->Expression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitVarExpression(VarExpressionSyntaxNode* expr)\n\t\t\t{\n\t\t\t\treturn expr;\n\t\t\t}\n\t\t\tvirtual RefPtr<PipelineSyntaxNode> VisitPipeline(PipelineSyntaxNode * pipe)\n\t\t\t{\n\t\t\t\tfor (auto & comp : pipe->Members)\n\t\t\t\t\tcomp = comp->Accept(this).As<Decl>();\n\t\t\t\treturn pipe;\n\t\t\t}\n\t\t\tvirtual RefPtr<ImportOperatorDefSyntaxNode> VisitImportOperatorDef(ImportOperatorDefSyntaxNode * imp)\n\t\t\t{\n\t\t\t\timp->Body = imp->Body->Accept(this).As<BlockStatementSyntaxNode>();\n\t\t\t\treturn imp;\n\t\t\t}\n\t\t\tvirtual RefPtr<ParameterSyntaxNode> VisitParameter(ParameterSyntaxNode* param)\n\t\t\t{\n\t\t\t\treturn param;\n\t\t\t}\n\t\t\tvirtual RefPtr<TypeSyntaxNode> VisitBasicType(BasicTypeSyntaxNode* type)\n\t\t\t{\n\t\t\t\treturn type;\n\t\t\t}\n\t\t\tvirtual RefPtr<TypeSyntaxNode> VisitArrayType(ArrayTypeSyntaxNode* type)\n\t\t\t{\n\t\t\t\treturn type;\n\t\t\t}\n\t\t\tvirtual RefPtr<TypeSyntaxNode> VisitGenericType(GenericTypeSyntaxNode* type)\n\t\t\t{\n\t\t\t\treturn type;\n\t\t\t}\n\n\t\t\tvirtual RefPtr<Variable> VisitDeclrVariable(Variable* dclr)\n\t\t\t{\n\t\t\t\tif (dclr->Expr)\n\t\t\t\t\tdclr->Expr = dclr->Expr->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn dclr;\n\t\t\t}\n\t\t\tvirtual RefPtr<ImportSyntaxNode> VisitImport(ImportSyntaxNode* imp)\n\t\t\t{\n\t\t\t\tfor (auto & arg : imp->Arguments)\n\t\t\t\t\tif (arg->Expression)\n\t\t\t\t\t\targ->Expression = arg->Expression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn imp;\n\t\t\t}\n\t\t\tvirtual RefPtr<StatementSyntaxNode> VisitImportStatement(ImportStatementSyntaxNode* stmt)\n\t\t\t{\n\t\t\t\tif (stmt->Import)\n\t\t\t\t\tstmt->Import = stmt->Import->Accept(this).As<ImportSyntaxNode>();\n\t\t\t\treturn stmt;\n\t\t\t}\n\t\t\tvirtual RefPtr<ImportArgumentSyntaxNode> VisitImportArgument(ImportArgumentSyntaxNode * arg)\n\t\t\t{\n\t\t\t\tif (arg->Expression)\n\t\t\t\t\targ->Expression = arg->Expression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn arg;\n\t\t\t}\n\t\t\tvirtual RefPtr<ExpressionSyntaxNode> VisitProject(ProjectExpressionSyntaxNode * project)\n\t\t\t{\n\t\t\t\tif (project->BaseExpression)\n\t\t\t\t\tproject->BaseExpression = project->BaseExpression->Accept(this).As<ExpressionSyntaxNode>();\n\t\t\t\treturn project;\n\t\t\t}\n\t\t\tvirtual RefPtr<InterfaceSyntaxNode> VisitInterface(InterfaceSyntaxNode * node)\n\t\t\t{\n\t\t\t\tfor (auto & member : node->GetComponents())\n\t\t\t\t{\n\t\t\t\t\tmember->Accept(this);\n\t\t\t\t}\n\t\t\t\treturn node;\n\t\t\t}\n\t\t\tvirtual RefPtr<SyntaxNode> VisitTemplateShader(TemplateShaderSyntaxNode * shader)\n\t\t\t{\n\t\t\t\tfor (auto & param : shader->Parameters)\n\t\t\t\t\tparam->Accept(this);\n\t\t\t\tfor (auto & member : shader->Members)\n\t\t\t\t\tmember->Accept(this);\n\t\t\t\treturn shader;\n\t\t\t}\n\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/SyntaxVisitors.h",
    "content": "#ifndef RASTER_RENDERER_SYNTAX_PRINTER_H\n#define RASTER_RENDERER_SYNTAX_PRINTER_H\n\n#include \"Diagnostics.h\"\n#include \"Syntax.h\"\n#include \"IL.h\"\n#include \"SymbolTable.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n        class CodeGenBackend;\n\t\tclass ShaderCompiler;\n\t\tclass ShaderLinkInfo;\n\t\tclass ShaderSymbol;\n\n\t\tclass ICodeGenerator : public SyntaxVisitor\n\t\t{\n\t\tpublic:\n\t\t\tICodeGenerator(DiagnosticSink * perr)\n\t\t\t\t: SyntaxVisitor(perr)\n\t\t\t{}\n\t\t\tvirtual void ProcessFunction(FunctionSyntaxNode * func) = 0;\n\t\t\tvirtual void ProcessShader(ShaderIR * shader) = 0;\n\t\t\tvirtual void ProcessStruct(StructSyntaxNode * st) = 0;\n\t\t};\n\n\t\tSyntaxVisitor * CreateSemanticsVisitor(SymbolTable * symbols, DiagnosticSink * err);\n\t\tICodeGenerator * CreateCodeGenerator(SymbolTable * symbols, CompileResult & result, CodeGenBackend* backend);\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/TypeLayout.cpp",
    "content": "// TypeLayout.cpp\n#include \"TypeLayout.h\"\n\n#include \"Syntax.h\"\n#include \"SymbolTable.h\"\n\n#include <assert.h>\n\nnamespace Spire {\nnamespace Compiler {\n\nsize_t RoundToAlignment(size_t offset, size_t alignment)\n{\n\tsize_t remainder = offset % alignment;\n\tif (remainder == 0)\n\t\treturn offset;\n\telse\n\t\treturn offset + (alignment - remainder);\n}\n\nstatic size_t RoundUpToPowerOfTwo( size_t value )\n{\n    // TODO(tfoley): I know this isn't a fast approach\n    size_t result = 1;\n    while (result < value)\n        result *= 2;\n    return result;\n}\n\nstruct DefaultLayoutRulesImpl : LayoutRulesImpl\n{\n    // Get size and alignment for a single value of base type.\n    LayoutInfo GetScalarLayout(BaseType baseType) override\n    {\n        switch (baseType)\n        {\n        case BaseType::Int:\n        case BaseType::UInt:\n        case BaseType::Float:\n\t\tcase BaseType::Bool:\n            return{ 4, 4 };\n\n        case BaseType::Int2:      return GetVectorLayout(GetScalarLayout(BaseType::Int),    2);\n\t\tcase BaseType::Bool2:      return GetVectorLayout(GetScalarLayout(BaseType::Bool),  2);\n        case BaseType::UInt2:     return GetVectorLayout(GetScalarLayout(BaseType::UInt),   2);\n        case BaseType::Float2:    return GetVectorLayout(GetScalarLayout(BaseType::Float),  2);\n        case BaseType::Int3:      return GetVectorLayout(GetScalarLayout(BaseType::Int),    3);\n        case BaseType::UInt3:     return GetVectorLayout(GetScalarLayout(BaseType::UInt),   3);\n        case  BaseType::Float3:   return GetVectorLayout(GetScalarLayout(BaseType::Float),  3);\n\t\tcase BaseType::Bool3:      return GetVectorLayout(GetScalarLayout(BaseType::Bool),  3);\n        case BaseType::Int4:      return GetVectorLayout(GetScalarLayout(BaseType::Int),    4);\n        case BaseType::UInt4:     return GetVectorLayout(GetScalarLayout(BaseType::UInt),   4);\n        case BaseType::Float4:    return GetVectorLayout(GetScalarLayout(BaseType::Float),  4);\n\t\tcase BaseType::Bool4:      return GetVectorLayout(GetScalarLayout(BaseType::Bool),  4);\n\n        case BaseType::Float3x3:  return GetMatrixLayout(GetScalarLayout(BaseType::Float),  3, 3);\n        case BaseType::Float4x4:  return GetMatrixLayout(GetScalarLayout(BaseType::Float),  4, 4);\n\n        case BaseType::Texture2D:\n        case BaseType::TextureCube:\n\t\tcase BaseType::Texture2DArray:\n\t\tcase BaseType::Texture2DArrayShadow:\n\t\tcase BaseType::Texture2DShadow:\n\t\tcase BaseType::Texture3D:\n\t\tcase BaseType::TextureCubeShadow:\n\t\tcase BaseType::TextureCubeArray:\n\t\tcase BaseType::TextureCubeShadowArray:\n            return{ 8, 8 };\n\n        default:\n            assert(!\"unimplemented\");\n            return{ 0, 1 };\n        }\n    }\n\n    LayoutInfo GetScalarLayout(ILBaseType baseType) override\n    {\n        switch (baseType)\n        {\n        case ILBaseType::Int:\n        case ILBaseType::UInt:\n        case ILBaseType::Float:\n\t\tcase ILBaseType::Bool:\n            return{ 4, 4 };\n\n        case ILBaseType::Int2:      return GetVectorLayout(GetScalarLayout(ILBaseType::Int),    2);\n        case ILBaseType::UInt2:     return GetVectorLayout(GetScalarLayout(ILBaseType::UInt),   2);\n        case ILBaseType::Float2:    return GetVectorLayout(GetScalarLayout(ILBaseType::Float),  2);\n        case ILBaseType::Int3:      return GetVectorLayout(GetScalarLayout(ILBaseType::Int),    3);\n        case ILBaseType::UInt3:     return GetVectorLayout(GetScalarLayout(ILBaseType::UInt),   3);\n        case  ILBaseType::Float3:   return GetVectorLayout(GetScalarLayout(ILBaseType::Float),  3);\n        case ILBaseType::Int4:      return GetVectorLayout(GetScalarLayout(ILBaseType::Int),    4);\n        case ILBaseType::UInt4:     return GetVectorLayout(GetScalarLayout(ILBaseType::UInt),   4);\n        case ILBaseType::Float4:    return GetVectorLayout(GetScalarLayout(ILBaseType::Float),  4);\n\n        case ILBaseType::Float3x3:  return GetMatrixLayout(GetScalarLayout(ILBaseType::Float),  3, 3);\n        case ILBaseType::Float4x4:  return GetMatrixLayout(GetScalarLayout(ILBaseType::Float),  4, 4);\n\n\t\tcase ILBaseType::Texture2D:\n\t\tcase ILBaseType::TextureCube:\n\t\tcase ILBaseType::Texture2DArray:\n\t\tcase ILBaseType::Texture2DArrayShadow:\n\t\tcase ILBaseType::Texture2DShadow:\n\t\tcase ILBaseType::Texture3D:\n\t\tcase ILBaseType::TextureCubeShadow:\n\t\tcase ILBaseType::TextureCubeArray:\n\t\tcase ILBaseType::TextureCubeShadowArray:\n            return{ 8, 8 };\n\n        default:\n            assert(!\"unimplemented\");\n            return{ 0, 1 };\n        }\n    }\n\n    LayoutInfo GetArrayLayout(LayoutInfo elementInfo, size_t elementCount) override\n    {\n        LayoutInfo arrayInfo;\n        arrayInfo.size = elementInfo.size * elementCount;\n        arrayInfo.alignment = elementInfo.alignment;\n        return arrayInfo;\n    }\n\n    LayoutInfo GetVectorLayout(LayoutInfo elementInfo, size_t elementCount) override\n    {\n        LayoutInfo vectorInfo;\n        vectorInfo.size = elementInfo.size * elementCount;\n        vectorInfo.alignment = RoundUpToPowerOfTwo(elementInfo.size * elementInfo.alignment);\n        return vectorInfo;\n    }\n\n    LayoutInfo GetMatrixLayout(LayoutInfo elementInfo, size_t rowCount, size_t columnCount) override\n    {\n        return GetArrayLayout(\n            GetVectorLayout(elementInfo, columnCount),\n            rowCount);\n    }\n\n    LayoutInfo BeginStructLayout() override\n    {\n        LayoutInfo structInfo;\n        structInfo.size = 0;\n        structInfo.alignment = 1;\n        return structInfo;\n    }\n\n    size_t AddStructField(LayoutInfo* ioStructInfo, LayoutInfo fieldInfo) override\n    {\n        ioStructInfo->alignment = std::max(ioStructInfo->alignment, fieldInfo.alignment);\n        ioStructInfo->size = RoundToAlignment(ioStructInfo->size, fieldInfo.alignment);\n        size_t fieldOffset = ioStructInfo->size;\n        ioStructInfo->size += fieldInfo.size;\n        return fieldOffset;\n    }\n\n\n    void EndStructLayout(LayoutInfo* ioStructInfo) override\n    {\n        ioStructInfo->size = RoundToAlignment(ioStructInfo->size, ioStructInfo->alignment);\n    }\n};\n\nstruct Std140LayoutRulesImpl : DefaultLayoutRulesImpl\n{\n    // The `std140` rules require that all array elements\n    // be a multiple of 16 bytes.\n    LayoutInfo GetArrayLayout(LayoutInfo elementInfo, size_t elementCount) override\n    {\n        if (elementInfo.alignment < 16)\n            elementInfo.alignment = 16;\n        elementInfo.size = RoundToAlignment(elementInfo.size, elementInfo.alignment);\n\n        return DefaultLayoutRulesImpl::GetArrayLayout(elementInfo, elementCount);\n    }\n\n    // The `std140` rules require that a `struct` type be\n    // alinged to at least 16.\n    LayoutInfo BeginStructLayout() override\n    {\n        LayoutInfo structInfo;\n        structInfo.size = 0;\n        structInfo.alignment = 16;\n        return structInfo;\n    }\n};\n\nstruct Std430LayoutRulesImpl : DefaultLayoutRulesImpl\n{\n};\n\nstruct PackedLayoutRulesImpl : DefaultLayoutRulesImpl\n{\n};\n\nstruct HLSLLayoutRulesImpl : Std140LayoutRulesImpl\n{\n\tLayoutInfo GetVectorLayout(LayoutInfo elementInfo, size_t elementCount) override\n\t{\n\t\tLayoutInfo vectorInfo;\n\t\tvectorInfo.size = elementInfo.size * elementCount;\n\t\tvectorInfo.alignment = elementInfo.alignment;\n\t\tvectorInfo.avoid16ByteBoundary = true;\n\t\treturn vectorInfo;\n\t}\n\n\tLayoutInfo BeginStructLayout() override\n\t{\n\t\tLayoutInfo structInfo;\n\t\tstructInfo.size = 0;\n\t\tstructInfo.alignment = 16;\n\t\tstructInfo.avoid16ByteBoundary = true;\n\t\treturn structInfo;\n\t}\n\n\tsize_t AddStructField(LayoutInfo* ioStructInfo, LayoutInfo fieldInfo) override\n\t{\n\t\tioStructInfo->size = RoundToAlignment(ioStructInfo->size, fieldInfo.alignment);\n\n        // If this field would straddle a 16-byte boundary, then round up to the start\n        // of a 16-byte boundary. Note that the computation is for the *last* byte\n        // offset for the field, and *not* the byte offset of the end of the field.\n        // It is okay for a field to end right on a 16-byte boundary without triggering\n        // this rule.\n        size_t firstOffset = ioStructInfo->size;\n        size_t lastOffset = firstOffset + fieldInfo.size - 1;\n        if( (firstOffset / 16) != (lastOffset / 16) )\n        {\n            ioStructInfo->size = RoundToAlignment(firstOffset, 16u);\n        }\n\n\t\tsize_t fieldOffset = ioStructInfo->size;\n\t\tioStructInfo->size += fieldInfo.size;\n\t\treturn fieldOffset;\n\t}\n\n\n\tvoid EndStructLayout(LayoutInfo* ioStructInfo) override\n\t{\n\t\tioStructInfo->size = RoundToAlignment(ioStructInfo->size, ioStructInfo->alignment);\n\t}\n};\n\nStd140LayoutRulesImpl kStd140LayoutRulesImpl;\nStd430LayoutRulesImpl kStd430LayoutRulesImpl;\nPackedLayoutRulesImpl kPackedLayoutRulesImpl;\nHLSLLayoutRulesImpl kHlslLayoutRulesImpl;\n\nLayoutRulesImpl* GetLayoutRulesImpl(LayoutRule rule)\n{\n    switch (rule)\n    {\n    case LayoutRule::Std140: return &kStd140LayoutRulesImpl;\n    case LayoutRule::Std430: return &kStd430LayoutRulesImpl;\n\tcase LayoutRule::HLSL: return &kHlslLayoutRulesImpl;\n    case LayoutRule::Packed: return &kPackedLayoutRulesImpl;\n    default:\n        return nullptr;\n    }\n}\n\nLayoutInfo GetLayout(ExpressionType* type, LayoutRulesImpl* rules)\n{\n    if (auto basicType = dynamic_cast<BasicExpressionType*>(type))\n    {\n        if (auto structDecl = basicType->structDecl)\n        {\n            LayoutInfo info = rules->BeginStructLayout();\n\n            for (auto field : structDecl->GetFields())\n            {\n                rules->AddStructField(&info,\n                    GetLayout(field->Type.Ptr(), rules));\n            }\n\n            rules->EndStructLayout(&info);\n            return info;\n        }\n        else\n        {\n            return rules->GetScalarLayout(basicType->BaseType);\n        }\n    }\n    else if (auto arrayType = dynamic_cast<ArrayExpressionType*>(type))\n    {\n        return rules->GetArrayLayout(\n            GetLayout(arrayType->BaseType.Ptr(), rules),\n            arrayType->ArrayLength);\n    }\n    else if (auto genericType = dynamic_cast<GenericExpressionType*>(type))\n    {\n        return GetLayout(genericType->BaseType.Ptr(), rules);\n    }\n    else\n    {\n        assert(!\"unimplemented\");\n        return{ 0, 1 };\n    }\n}\n\nLayoutInfo GetLayout(ILType* type, LayoutRulesImpl* rules)\n{\n    if (auto basicType = dynamic_cast<ILBasicType*>(type))\n    {\n        return rules->GetScalarLayout(basicType->Type);\n    }\n    else if (auto arrayType = dynamic_cast<ILArrayType*>(type))\n    {\n        return rules->GetArrayLayout(\n            GetLayout(arrayType->BaseType.Ptr(), rules),\n            arrayType->ArrayLength);\n    }\n    else if (auto structType = dynamic_cast<ILStructType*>(type))\n    {\n        LayoutInfo info = rules->BeginStructLayout();\n\n        for (auto field : structType->Members)\n        {\n            rules->AddStructField(&info,\n                GetLayout(field.Type.Ptr(), rules));\n        }\n\n        rules->EndStructLayout(&info);\n        return info;\n    }\n    else if (auto recordType = dynamic_cast<ILRecordType*>(type))\n    {\n        // TODO: this need to be implemented\n        LayoutInfo info = { 0, 1 };\n        return info;\n    }\n    else if (auto genericType = dynamic_cast<ILGenericType*>(type))\n    {\n        return GetLayout(genericType->BaseType.Ptr(), rules);\n    }\n    else\n    {\n        assert(!\"unimplemented\");\n        return{ 0, 1 };\n    }\n}\n\nLayoutInfo GetLayout(ExpressionType* type, LayoutRule rule)\n{\n    LayoutRulesImpl* rulesImpl = GetLayoutRulesImpl(rule);\n    return GetLayout(type, rulesImpl);\n}\n\nLayoutInfo GetLayout(ILType* type, LayoutRule rule)\n{\n    LayoutRulesImpl* rulesImpl = GetLayoutRulesImpl(rule);\n    return GetLayout(type, rulesImpl);\n}\n\n}}\n"
  },
  {
    "path": "Source/SpireCore/TypeLayout.h",
    "content": "#ifndef SPIRE_TYPE_LAYOUT_H\n#define SPIRE_TYPE_LAYOUT_H\n\n#include \"../CoreLib/Basic.h\"\n#include \"IL.h\"\n\nnamespace Spire {\nnamespace Compiler {\n\n// Forward declarations\n\nenum class BaseType;\nclass ExpressionType;\n\n//\n\nenum class LayoutRule\n{\n    Std140,\n    Std430,\n\tHLSL,\n    Packed,\n};\n\n\nstruct LayoutInfo\n{\n    size_t size = 0;\n    size_t alignment = 1;\n\tbool avoid16ByteBoundary = false;\n\tLayoutInfo() = default;\n\tLayoutInfo(size_t s, size_t a)\n\t{\n\t\tsize = s;\n\t\talignment = a;\n\t}\n};\n\nstruct LayoutRulesImpl\n{\n    // Get size and alignment for a single value of base type.\n    virtual LayoutInfo GetScalarLayout(BaseType baseType) = 0;\n    virtual LayoutInfo GetScalarLayout(ILBaseType baseType) = 0;\n\n    // Get size and alignment for an array of elements\n    virtual LayoutInfo GetArrayLayout(LayoutInfo elementInfo, size_t elementCount) = 0;\n\n    // Get layout for a vector or matrix type\n    virtual LayoutInfo GetVectorLayout(LayoutInfo elementInfo, size_t elementCount) = 0;\n    virtual LayoutInfo GetMatrixLayout(LayoutInfo elementInfo, size_t rowCount, size_t columnCount) = 0;\n\n    // Begin doing layout on a `struct` type\n    virtual LayoutInfo BeginStructLayout() = 0;\n\n    // Add a field to a `struct` type, and return the offset for the field\n    virtual size_t AddStructField(LayoutInfo* ioStructInfo, LayoutInfo fieldInfo) = 0;\n\n    // End layout for a struct, and finalize its size/alignment.\n    virtual void EndStructLayout(LayoutInfo* ioStructInfo) = 0;\n};\n\nLayoutRulesImpl* GetLayoutRulesImpl(LayoutRule rule);\n\nLayoutInfo GetLayout(ExpressionType* type, LayoutRulesImpl* rules);\nLayoutInfo GetLayout(ILType* type, LayoutRulesImpl* rules);\n\nLayoutInfo GetLayout(ExpressionType* type, LayoutRule rule = LayoutRule::Std430);\nLayoutInfo GetLayout(ILType* type, LayoutRule rule = LayoutRule::Std430);\n\ninline size_t GetTypeSize(ExpressionType* type, LayoutRule rule = LayoutRule::Std430)\n{\n    return GetLayout(type, rule).size;\n}\n\ninline size_t GetTypeSize(ILType* type, LayoutRule rule = LayoutRule::Std430)\n{\n    return GetLayout(type, rule).size;\n}\n\ninline size_t GetTypeAlignment(ExpressionType* type, LayoutRule rule = LayoutRule::Std430)\n{\n    return GetLayout(type, rule).alignment;\n}\n\ninline size_t GetTypeAlignment(ILType* type, LayoutRule rule = LayoutRule::Std430)\n{\n    return GetLayout(type, rule).alignment;\n}\n\n}}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/TypeTranslation.cpp",
    "content": "#include \"TypeTranslation.h\"\n#include \"SymbolTable.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tRefPtr<ILType> TranslateExpressionType(ExpressionType * type, Dictionary<String, RefPtr<ILType>> * genericTypeMappings)\n\t\t{\n\t\t\tRefPtr<ILType> resultType = 0;\n\t\t\tif (auto basicType = type->AsBasicType())\n\t\t\t{\n\t\t\t\tif (basicType->BaseType == BaseType::Struct)\n\t\t\t\t{\n\t\t\t\t\tresultType = basicType->Struct->Type;\n\t\t\t\t}\n\t\t\t\telse if (basicType->BaseType == BaseType::Record)\n\t\t\t\t{\n\t\t\t\t\tif (genericTypeMappings)\n\t\t\t\t\t\treturn (*genericTypeMappings)[basicType->RecordTypeName]();\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow InvalidProgramException(\"unexpected record type.\");\n\t\t\t\t}\n\t\t\t\telse if (basicType->BaseType == BaseType::Generic)\n\t\t\t\t{\n\t\t\t\t\tif (genericTypeMappings)\n\t\t\t\t\t\treturn (*genericTypeMappings)[basicType->GenericTypeVar]();\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow InvalidProgramException(\"unexpected generic type.\");\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto base = new ILBasicType();\n\t\t\t\t\tbase->Type = (ILBaseType)basicType->BaseType;\n\t\t\t\t\tresultType = base;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (auto arrType = type->AsArrayType())\n\t\t\t{\n\t\t\t\tauto nArrType = new ILArrayType();\n\t\t\t\tnArrType->BaseType = TranslateExpressionType(arrType->BaseType.Ptr(), genericTypeMappings);\n\t\t\t\tnArrType->ArrayLength = arrType->ArrayLength;\n\t\t\t\tresultType = nArrType;\n\t\t\t}\n\t\t\telse if (auto genType = type->AsGenericType())\n\t\t\t{\n\t\t\t\tauto gType = new ILGenericType();\n\t\t\t\tgType->GenericTypeName = genType->GenericTypeName;\n\t\t\t\tgType->BaseType = TranslateExpressionType(genType->BaseType.Ptr(), genericTypeMappings);\n\t\t\t\tresultType = gType;\n\t\t\t}\n\t\t\treturn resultType;\n\t\t}\n\n\t\tRefPtr<ILType> TranslateExpressionType(const RefPtr<ExpressionType> & type, Dictionary<String, RefPtr<ILType>> * genericTypeMappings)\n\t\t{\n\t\t\treturn TranslateExpressionType(type.Ptr(), genericTypeMappings);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/SpireCore/TypeTranslation.h",
    "content": "#ifndef SPIRE_TYPE_TRANSLATION_H\n#define SPIRE_TYPE_TRANSLATION_H\n\n#include \"Syntax.h\"\n#include \"IL.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tRefPtr<ILType> TranslateExpressionType(ExpressionType * type, Dictionary<String, RefPtr<ILType>> * genericTypeMappings = nullptr);\n\t\tRefPtr<ILType> TranslateExpressionType(const RefPtr<ExpressionType> & type, Dictionary<String, RefPtr<ILType>> * genericTypeMappings = nullptr);\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireCore/VariantIR.cpp",
    "content": "#include \"VariantIR.h\"\n#include \"Closure.h\"\n#include \"StringObject.h\"\n#include \"GetDependencyVisitor.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tvoid ShaderIR::EliminateDeadCode()\n\t\t{\n\t\t\t// mark entry points\n\t\t\tauto MarkUsing = [&](String compName, String userWorld)\n\t\t\t{\n\t\t\t\tif (auto defs = DefinitionsByComponent.TryGetValue(compName))\n\t\t\t\t{\n\t\t\t\t\tif (auto def = defs->TryGetValue(userWorld))\n\t\t\t\t\t\t(*def)->IsEntryPoint = true;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto & world : Shader->Pipeline->WorldDependency[userWorld]())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (auto def2 = defs->TryGetValue(world))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t(*def2)->IsEntryPoint = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t\tfor (auto & impOp : Shader->Pipeline->SyntaxNode->GetImportOperators())\n\t\t\t\tfor (auto & ref : impOp->Usings)\n\t\t\t\t\tMarkUsing(ref, impOp->DestWorld.Content);\n\t\t\tfor (auto & req : Shader->Pipeline->Components)\n\t\t\t\tif (req.Value->IsRequire())\n\t\t\t\t{\n\t\t\t\t\tfor (auto & impl : req.Value->Implementations)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (impl->Worlds.Count())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto & world : impl->Worlds)\n\t\t\t\t\t\t\t\tMarkUsing(req.Key, world);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto & world : Shader->Pipeline->Worlds)\n\t\t\t\t\t\t\t\tMarkUsing(req.Key, world.Key);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tfor (auto & def : Definitions)\n\t\t\t\tif (def->SyntaxNode->HasSimpleAttribute(\"FragDepth\"))\n\t\t\t\t\tdef->IsEntryPoint = true;\n\t\t\tList<ComponentDefinitionIR*> workList;\n\t\t\tHashSet<ComponentDefinitionIR*> referencedDefs;\n\t\t\tfor (auto & def : Definitions)\n\t\t\t{\n\t\t\t\tif (def->IsEntryPoint)\n\t\t\t\t{\n\t\t\t\t\tif (referencedDefs.Add(def.Ptr()))\n\t\t\t\t\t\tworkList.Add(def.Ptr());\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (int i = 0; i < workList.Count(); i++)\n\t\t\t{\n\t\t\t\tauto def = workList[i];\n\t\t\t\tfor (auto & dep : def->Dependency)\n\t\t\t\t{\n\t\t\t\t\tif (referencedDefs.Add(dep))\n\t\t\t\t\t\tworkList.Add(dep);\n\t\t\t\t}\n\t\t\t}\n\t\t\tList<RefPtr<ComponentDefinitionIR>> newDefinitions;\n\t\t\tfor (auto & def : Definitions)\n\t\t\t{\n\t\t\t\tif (referencedDefs.Contains(def.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tnewDefinitions.Add(def);\n\t\t\t\t\tEnumerableHashSet<ComponentDefinitionIR*> newSet;\n\t\t\t\t\tfor (auto & comp : def->Users)\n\t\t\t\t\t\tif (referencedDefs.Contains(comp))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnewSet.Add(comp);\n\t\t\t\t\t\t}\n\t\t\t\t\tdef->Users = newSet;\n\t\t\t\t\tnewSet.Clear();\n\t\t\t\t\tfor (auto & comp : def->Dependency)\n\t\t\t\t\t\tif (referencedDefs.Contains(comp))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnewSet.Add(comp);\n\t\t\t\t\t\t}\n\t\t\t\t\tdef->Dependency = newSet;\n\t\t\t\t}\n\t\t\t}\n\t\t\tDefinitions = _Move(newDefinitions);\n\t\t\tfor (auto & kv : DefinitionsByComponent)\n\t\t\t{\n\t\t\t\tfor (auto & def : kv.Value)\n\t\t\t\t\tif (!referencedDefs.Contains(def.Value))\n\t\t\t\t\t\tkv.Value.Remove(def.Key);\n\t\t\t}\n\t\t}\n\n\t\tclass ReferenceWorkItem\n\t\t{\n\t\tpublic:\n\t\t\tComponentDependency Dependency;\n\t\t\tString SourceWorld;\n\t\t\tint GetHashCode()\n\t\t\t{\n\t\t\t\treturn Dependency.GetHashCode();\n\t\t\t}\n\t\t\tbool operator == (const ReferenceWorkItem & other)\n\t\t\t{\n\t\t\t\treturn Dependency == other.Dependency && SourceWorld == other.SourceWorld;\n\t\t\t}\n\t\t};\n\n\t\tvoid ShaderIR::ResolveComponentReference()\n\t\t{\n\t\t\t// build bidirectional dependency map of component definitions\n\t\t\tfor (auto & comp : Definitions)\n\t\t\t{\n\t\t\t\tcomp->Dependency.Clear();\n\t\t\t\tcomp->Users.Clear();\n\t\t\t}\n\t\t\tfor (auto & comp : Definitions)\n\t\t\t{\n\t\t\t\tList<ReferenceWorkItem> workList;\n\t\t\t\tfor (auto & dep : GetDependentComponents(comp->SyntaxNode.Ptr()))\n\t\t\t\t{\n\t\t\t\t\tReferenceWorkItem item;\n\t\t\t\t\titem.Dependency = dep;\n\t\t\t\t\titem.SourceWorld = dep.ImportOperator ? dep.ImportOperator->SourceWorld.Content : comp->World;\n\t\t\t\t\tworkList.Add(item);\n\t\t\t\t}\n\t\t\t\tHashSet<ReferenceWorkItem> proceseedDefCompss;\n\t\t\t\tfor (int i = 0; i < workList.Count(); i++)\n\t\t\t\t{\n\t\t\t\t\tauto dep = workList[i];\n\t\t\t\t\tif (!proceseedDefCompss.Add(dep))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tauto & depDefs = DefinitionsByComponent[dep.Dependency.ReferencedComponent]();\n\t\t\t\t\t// select the best overload according to import operator ordering,\n\t\t\t\t\t// prefer user-pinned definitions (as provided in the choice file)\n\t\t\t\t\tList<String> depWorlds;\n\t\t\t\t\tdepWorlds.Add(dep.SourceWorld);\n\t\t\t\t\tfor (auto & w : Shader->Pipeline->WorldDependency[dep.SourceWorld]())\n\t\t\t\t\t\tdepWorlds.Add(w);\n\t\t\t\t\tdepWorlds.Add(\"<uniform>\");\n\t\t\t\t\tfor (int pass = 0; pass < 2; pass++)\n\t\t\t\t\t{\n\t\t\t\t\t\t// in the first pass, examine the pinned definitions only\n\t\t\t\t\t\t// in the second pass, examine all the rest definitions\n\t\t\t\t\t\tfor (auto & depWorld : depWorlds)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto refComp = Shader->AllComponents[dep.Dependency.ReferencedComponent]();\n\t\t\t\t\t\t\tbool isPinned = refComp.Symbol->Type->PinnedWorlds.Contains(depWorld);\n\t\t\t\t\t\t\tif ((pass == 0 && !isPinned) || (pass == 1 && isPinned)) continue;\n\t\t\t\t\t\t\tComponentDefinitionIR * depDef;\n\t\t\t\t\t\t\tif (depDefs.TryGetValue(depWorld, depDef))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcomp->Dependency.Add(depDef);\n\t\t\t\t\t\t\t\tdepDef->Users.Add(comp.Ptr());\n\t\t\t\t\t\t\t\t// add additional dependencies due to import operators\n\t\t\t\t\t\t\t\tauto processImportOperatorUsings = [&](ImportOperatorDefSyntaxNode * importOp)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfor (auto & importUsing : importOp->Usings)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tComponentInstance refComp;\n\t\t\t\t\t\t\t\t\t\tif (!Shader->AllComponents.TryGetValue(importUsing, refComp))\n\t\t\t\t\t\t\t\t\t\t\tthrow InvalidProgramException(\"import operator dependency not exists.\");\n\t\t\t\t\t\t\t\t\t\tReferenceWorkItem workItem;\n\t\t\t\t\t\t\t\t\t\tworkItem.Dependency = ComponentDependency(refComp.Symbol->UniqueName, nullptr);\n\t\t\t\t\t\t\t\t\t\tworkItem.SourceWorld = importOp->SourceWorld.Content;\n\t\t\t\t\t\t\t\t\t\tworkList.Add(workItem);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tif (dep.Dependency.ImportOperator)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tprocessImportOperatorUsings(dep.Dependency.ImportOperator);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (depWorld != dep.SourceWorld && depWorld != \"<uniform>\")\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tauto importPath = SymbolTable->FindImplicitImportOperatorChain(Shader->Pipeline, depWorld, dep.SourceWorld, refComp.Symbol->Type->DataType);\n\t\t\t\t\t\t\t\t\tif (importPath.Count() == 0)\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\tprocessImportOperatorUsings(importPath.First().Nodes.Last().ImportOperator);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tgoto selectionEnd; // first preferred overload is found, terminate searching\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tselectionEnd:;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tList<String> ShaderIR::GetComponentDependencyOrder()\n\t\t{\n\t\t\tList<String> result, workList;\n\t\t\tHashSet<String> set;\n\t\t\tfor (auto & comp : DefinitionsByComponent)\n\t\t\t{\n\t\t\t\tbool emptyDependency = true;\n\t\t\t\tfor (auto & def : comp.Value)\n\t\t\t\t\tif (def.Value->Dependency.Count())\n\t\t\t\t\t{\n\t\t\t\t\t\temptyDependency = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\tif (emptyDependency)\n\t\t\t\t{\n\t\t\t\t\tworkList.Add(comp.Key);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (int i = 0; i < workList.Count(); i++)\n\t\t\t{\n\t\t\t\tauto comp = workList[i];\n\t\t\t\tif (!set.Contains(comp))\n\t\t\t\t{\n\t\t\t\t\tbool insertable = true;\n\t\t\t\t\tfor (auto & def : DefinitionsByComponent[comp]())\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto & dep : def.Value->Dependency)\n\t\t\t\t\t\t\tif (!set.Contains(dep->UniqueName))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tinsertable = false;\n\t\t\t\t\t\t\t\tgoto breakLoc;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tbreakLoc:;\n\t\t\t\t\tif (insertable)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (set.Add(comp))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tresult.Add(comp);\n\t\t\t\t\t\t\tfor (auto & def : DefinitionsByComponent[comp]())\n\t\t\t\t\t\t\t\tfor (auto & user : def.Value->Users)\n\t\t\t\t\t\t\t\t\tworkList.Add(user->UniqueName);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\tEnumerableHashSet<ComponentDefinitionIR*>& ComponentDefinitionIR::GetComponentFunctionDependencyClosure()\n\t\t{\n\t\t\tif (dependencyClosure.Count() || Dependency.Count() == 0)\n\t\t\t\treturn dependencyClosure;\n\t\t\tfor (auto & dep : Dependency)\n\t\t\t{\n\t\t\t\tdependencyClosure.Add(dep);\n\t\t\t\tif (dep->SyntaxNode->IsComponentFunction())\n\t\t\t\t{\n\t\t\t\t\tfor (auto & x : dep->GetComponentFunctionDependencyClosure())\n\t\t\t\t\t\tdependencyClosure.Add(x);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn dependencyClosure;\n\t\t}\n}\n}"
  },
  {
    "path": "Source/SpireCore/VariantIR.h",
    "content": "#ifndef VARIANT_IR_H\n#define VARIANT_IR_H\n\n#include \"Syntax.h\"\n\nnamespace Spire\n{\n\tnamespace Compiler\n\t{\n\t\tclass ShaderClosure;\n\t\tclass ModuleInstanceIR : public RefObject\n\t\t{\n\t\tpublic:\n\t\t\tShaderSyntaxNode * SyntaxNode;\n\t\t\tString BindingName;\n\t\t\tCodePosition UsingPosition;\n\t\t\tint BindingIndex;\n\t\t\tbool IsTopLevel = false;\n\t\t\tList<ModuleInstanceIR*> SubModuleInstances;\n\t\t};\n\t\tclass ComponentDefinitionIR : public RefObject\n\t\t{\n\t\tprivate:\n\t\t\tEnumerableHashSet<ComponentDefinitionIR *> dependencyClosure;\n\t\tpublic:\n\t\t\tString OriginalName, UniqueName, UniqueKey;\n\t\t\tRefPtr<ComponentSyntaxNode> SyntaxNode;\n\t\t\tRefPtr<ExpressionType> Type;\n\t\t\tModuleInstanceIR * ModuleInstance = nullptr;\n\t\t\tString World;\n\t\t\tbool IsEntryPoint = false;\n\t\t\tEnumerableHashSet<ComponentDefinitionIR *> Users, Dependency; // Bidirectional dependency;\n\t\t\tEnumerableHashSet<ComponentDefinitionIR *> & GetComponentFunctionDependencyClosure();\n\t\t\tvoid ClearDependency()\n\t\t\t{\n\t\t\t\tDependency.Clear();\n\t\t\t\tdependencyClosure.Clear();\n\t\t\t}\n\t\t};\n\n\t\tclass ShaderIR : public RefObject\n\t\t{\n\t\tpublic:\n\t\t\tShaderClosure * Shader;\n\t\t\tSymbolTable * SymbolTable;\n\t\t\tList<RefPtr<ModuleInstanceIR>> ModuleInstances;\n\t\t\tList<RefPtr<ComponentDefinitionIR>> Definitions;\n\t\t\tEnumerableDictionary<String, EnumerableDictionary<String, ComponentDefinitionIR*>> DefinitionsByComponent;\n\t\t\tvoid EliminateDeadCode(); // returns remaining definitions in reverse dependency order\n\t\t\tvoid ResolveComponentReference(); // resolve reference and build dependency map\n\t\t\tList<String> GetComponentDependencyOrder(); // returns a list of all components' unique names in dependency order\n\t\t\ttemplate<typename ShouldRemoveFunc>\n\t\t\tvoid RemoveDefinitions(const ShouldRemoveFunc &shouldRemove)\n\t\t\t{\n\t\t\t\tList<RefPtr<ComponentDefinitionIR>> newDefinitions;\n\t\t\t\tfor (auto & def : Definitions)\n\t\t\t\t{\n\t\t\t\t\tif (!shouldRemove(def.Ptr()))\n\t\t\t\t\t{\n\t\t\t\t\t\tnewDefinitions.Add(def);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tDefinitions = _Move(newDefinitions);\n\t\t\t\tfor (auto & kv : DefinitionsByComponent)\n\t\t\t\t{\n\t\t\t\t\tfor (auto & def : kv.Value)\n\t\t\t\t\t\tif (shouldRemove(def.Value))\n\t\t\t\t\t\t\tkv.Value.Remove(def.Key);\n\t\t\t\t}\n\t\t\t}\n\n\t\t};\n\t}\n}\n\n#endif"
  },
  {
    "path": "Source/SpireLib/SpireLib.cpp",
    "content": "#include \"SpireLib.h\"\n#include \"../CoreLib/LibIO.h\"\n#include \"../CoreLib/Tokenizer.h\"\n#include \"../SpireCore/StdInclude.h\"\n#include \"../../Spire.h\"\n#include \"../SpireCore/TypeLayout.h\"\n#include \"../SpireCore/Preprocessor.h\"\n\nusing namespace CoreLib::Basic;\nusing namespace CoreLib::IO;\nusing namespace CoreLib::Text;\nusing namespace Spire::Compiler;\n\nstruct SpireDiagnosticSink\n{\n\tint errorCount;\n\tCoreLib::List<Spire::Compiler::Diagnostic> diagnostics;\n};\n\nstruct SpireUniformFieldImpl\n{\n\tint offset;\n\tint size;\n\tString name;\n\tString type;\n};\n\nstruct SpireParameterSet\n{\n\tILModuleParameterSet * paramSet = nullptr;\n\tint bindingSlotCount = 0;\n\tint uniformBufferLegacyBindingPoint = -1;\n\tList<SpireResourceBindingInfo> bindings;\n\tList<SpireParameterSet> subsets;\n\tList<SpireUniformFieldImpl> uniforms;\n};\n\n\nclass ComponentMetaData\n{\npublic:\n\tRefPtr<ExpressionType> Type;\n\tString TypeName;\n\tString Name;\n\tbool IsSpecialize = false;\n\tList<int> Values;\n\tint Offset = 0;\n\tint Alignment = 0;\n\tint Size = 0;\n\tBindableResourceType bindableType;\n\tint typeSpecificBindingIndex = -1;\n\tint typeAgnosticBindingIndex = -1;\n\tint GetHashCode()\n\t{\n\t\treturn Name.GetHashCode();\n\t}\n\tbool operator == (const ComponentMetaData & other)\n\t{\n\t\treturn Name == other.Name;\n\t}\n};\n\nstruct CompilerState;\n\nstruct SpireModule\n{\n\tString Name;\n\tint Id = 0;\n\tint UniformBufferSize = 0;\n\tint UniformBufferOffset = 0;\n\tSpireBindingIndex BindingIndex;\n\tList<ComponentMetaData> Parameters;\n\tEnumerableDictionary<String, ComponentMetaData> ParameterMap;\n\tList<ComponentMetaData> Requirements;\n\tDictionary<String, String> Attribs;\n\tList<RefPtr<SpireModule>> SubModules;\n\tCompilerState * State = nullptr;\n\tstatic int IdAllocator;\n};\n\nint SpireModule::IdAllocator = 0;\n\nnamespace SpireLib\n{\n\tvoid ReadSource(EnumerableDictionary<String, StageSource> & sources, CoreLib::Text::TokenReader & parser, String src)\n\t{\n\t\tauto getShaderSource = [&]()\n\t\t{\n\t\t\tauto token = parser.ReadToken();\n\t\t\tint endPos = token.Position.Pos + 1;\n\t\t\tint brace = 0;\n\t\t\twhile (endPos < src.Length() && !(src[endPos] == '}' && brace == 0))\n\t\t\t{\n\t\t\t\tif (src[endPos] == '{')\n\t\t\t\t\tbrace++;\n\t\t\t\telse if (src[endPos] == '}')\n\t\t\t\t\tbrace--;\n\t\t\t\tendPos++;\n\t\t\t}\n\t\t\twhile (!parser.IsEnd() && parser.NextToken().Position.Pos != endPos)\n\t\t\t\tparser.ReadToken();\n\t\t\tparser.ReadToken();\n\t\t\treturn src.SubString(token.Position.Pos + 1, endPos - token.Position.Pos - 1);\n\t\t};\n\t\twhile (!parser.IsEnd() && !parser.LookAhead(\"}\"))\n\t\t{\n\t\t\tauto worldName = parser.ReadWord();\n\t\t\tStageSource compiledSrc;\n\t\t\tif (parser.LookAhead(\"binary\"))\n\t\t\t{\n\t\t\t\tparser.ReadToken();\n\t\t\t\tparser.Read(\"{\");\n\t\t\t\twhile (!parser.LookAhead(\"}\") && !parser.IsEnd())\n\t\t\t\t{\n\t\t\t\t\tauto val = parser.ReadUInt();\n\t\t\t\t\tcompiledSrc.BinaryCode.AddRange((unsigned char*)&val, sizeof(unsigned int));\n\t\t\t\t\tif (parser.LookAhead(\",\"))\n\t\t\t\t\t\tparser.ReadToken();\n\t\t\t\t}\n\t\t\t\tparser.Read(\"}\");\n\t\t\t}\n\t\t\tif (parser.LookAhead(\"text\"))\n\t\t\t{\n\t\t\t\tparser.ReadToken();\n\t\t\t\tcompiledSrc.MainCode = getShaderSource();\n\t\t\t}\n\t\t\tsources[worldName] = compiledSrc;\n\t\t}\n\t}\n\tStageSource ShaderLib::GetStageSource(String stage)\n\t{\n\t\tStageSource rs;\n\t\tSources.TryGetValue(stage, rs);\n\t\treturn rs;\n\t}\n\tShaderLib::ShaderLib(CoreLib::Basic::String fileName)\n\t{\n\t\tReload(fileName);\n\t}\n\tvoid ShaderLib::Reload(CoreLib::Basic::String fileName)\n\t{\n\t\tLoad(fileName);\n\t}\n\tbool ShaderLib::CompileFrom(String symbolName, String sourceFileName, String schedule)\n\t{\n\t\tSpire::Compiler::CompileResult result;\n\t\tCompileOptions options;\n\t\toptions.ScheduleSource = schedule;\n\t\toptions.SymbolToCompile = symbolName;\n\t\toptions.Mode = CompilerMode::ProduceShader;\n\t\tauto shaderLibs = CompileShaderSourceFromFile(result, sourceFileName, options);\n\t\tif (result.GetErrorCount() == 0)\n\t\t{\n\t\t\tfor (auto & lib : shaderLibs)\n\t\t\t{\n\t\t\t\tif (lib.MetaData.ShaderName == symbolName)\n\t\t\t\t{\n\t\t\t\t\tFromString(shaderLibs[0].ToString());\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tresult.PrintDiagnostics();\n\t\treturn false;\n\t}\n\n\tList<ShaderLibFile> CompileUnits(Spire::Compiler::CompileResult & compileResult,\n\t\tShaderCompiler * compiler, List<CompileUnit> & units,\n\t\tSpire::Compiler::CompileOptions & options)\n\t{\n\t\tList<ShaderLibFile> resultFiles;\n\t\tcompiler->Compile(compileResult, units, options);\n\t\tif (compileResult.GetErrorCount() == 0)\n\t\t{\n\t\t\tif (options.Mode == CompilerMode::ProduceShader)\n\t\t\t{\n\t\t\t\tEnumerableDictionary<String, ShaderLibFile> shaderLibs;\n\t\t\t\tfor (auto file : compileResult.CompiledSource)\n\t\t\t\t{\n\t\t\t\t\tShaderLibFile libFile;\n\t\t\t\t\tlibFile.MetaData = file.Value.MetaData;\n\t\t\t\t\tlibFile.Sources = file.Value.Stages;\n\t\t\t\t\tresultFiles.Add(libFile);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn resultFiles;\n\t}\n\n\tList<ShaderLibFile> CompileShaderSource(Spire::Compiler::CompileResult & compileResult,\n\t\tconst CoreLib::String & src, const CoreLib::String & fileName, Spire::Compiler::CompileOptions & options)\n\t{\n\t\tstruct IncludeHandlerImpl : IncludeHandler\n\t\t{\n\t\t\tList<String> searchDirs;\n\n\t\t\tvirtual bool TryToFindIncludeFile(\n\t\t\t\tCoreLib::String const& pathToInclude,\n\t\t\t\tCoreLib::String const& pathIncludedFrom,\n\t\t\t\tCoreLib::String* outFoundPath,\n\t\t\t\tCoreLib::String* outFoundSource) override\n\t\t\t{\n\t\t\t\tString path = Path::Combine(Path::GetDirectoryName(pathIncludedFrom), pathToInclude);\n\t\t\t\tif (File::Exists(path))\n\t\t\t\t{\n\t\t\t\t\t*outFoundPath = path;\n\t\t\t\t\t*outFoundSource = File::ReadAllText(path);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tfor (auto & dir : searchDirs)\n\t\t\t\t{\n\t\t\t\t\tpath = Path::Combine(dir, pathToInclude);\n\t\t\t\t\tif (File::Exists(path))\n\t\t\t\t\t{\n\t\t\t\t\t\t*outFoundPath = path;\n\t\t\t\t\t\t*outFoundSource = File::ReadAllText(path);\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t};\n\n\t\tIncludeHandlerImpl includeHandler;\n\t\tincludeHandler.searchDirs = options.SearchDirectories;\n\n\t\tSpire::Compiler::NamingCounter = 0;\n\t\tRefPtr<ShaderCompiler> compiler = CreateShaderCompiler();\n\t\tList<CompileUnit> units;\n\t\tHashSet<String> processedUnits;\n\t\tList<String> unitsToInclude;\n\t\tunitsToInclude.Add(fileName);\n\t\tprocessedUnits.Add(fileName);\n\t\tauto searchDirs = options.SearchDirectories;\n\t\tsearchDirs.Add(Path::GetDirectoryName(fileName));\n\t\tsearchDirs.Reverse();\n\t\tauto predefUnit = compiler->Parse(compileResult, SpireStdLib::GetCode(), \"stdlib\", &includeHandler, options.PreprocessorDefinitions);\n\t\tfor (int i = 0; i < unitsToInclude.Count(); i++)\n\t\t{\n\t\t\tauto inputFileName = unitsToInclude[i];\n\t\t\ttry\n\t\t\t{\n\t\t\t\tString source = src;\n\t\t\t\tif (i > 0)\n\t\t\t\t\tsource = File::ReadAllText(inputFileName);\n\t\t\t\tauto unit = compiler->Parse(compileResult, source, inputFileName, &includeHandler, options.PreprocessorDefinitions);\n\t\t\t\tunits.Add(unit);\n\t\t\t\tif (unit.SyntaxNode)\n\t\t\t\t{\n\t\t\t\t\tfor (auto inc : unit.SyntaxNode->GetUsings())\n\t\t\t\t\t{\n\t\t\t\t\t\tbool found = false;\n\t\t\t\t\t\tfor (auto & dir : searchDirs)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tString includeFile = Path::Combine(dir, inc->fileName.Content);\n\t\t\t\t\t\t\tif (File::Exists(includeFile))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (processedUnits.Add(includeFile))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tunitsToInclude.Add(includeFile);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!found)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcompileResult.GetErrorWriter()->diagnose(inc->fileName.Position, Diagnostics::cannotFindFile, inc->fileName);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IOException)\n\t\t\t{\n\t\t\t\tcompileResult.GetErrorWriter()->diagnose(CodePosition(0, 0, 0, \"\"), Diagnostics::cannotOpenFile, inputFileName);\n\t\t\t}\n\t\t}\n\t\tunits.Add(predefUnit);\n\t\tif (compileResult.GetErrorCount() == 0)\n\t\t\treturn CompileUnits(compileResult, compiler.Ptr(), units, options);\n\t\telse\n\t\t\treturn List<ShaderLibFile>();\n\t}\n\n\tList<ShaderLibFile> CompileShaderSourceFromFile(Spire::Compiler::CompileResult & compileResult,\n\t\tconst CoreLib::Basic::String & sourceFileName,\n\t\tSpire::Compiler::CompileOptions & options)\n\t{\n\t\ttry\n\t\t{\n\t\t\treturn CompileShaderSource(compileResult, File::ReadAllText(sourceFileName), sourceFileName, options);\n\t\t}\n\t\tcatch (IOException)\n\t\t{\n\t\t\tcompileResult.GetErrorWriter()->diagnose(CodePosition(0, 0, 0, \"\"), Diagnostics::cannotOpenFile, Path::GetFileName(sourceFileName));\n\t\t}\n\t\treturn List<ShaderLibFile>();\n\t}\n\tvoid ShaderLibFile::AddSource(CoreLib::Basic::String source, CoreLib::Text::TokenReader & parser)\n\t{\n\t\tReadSource(Sources, parser, source);\n\t}\n\n\tCoreLib::String ShaderLibFile::ToString()\n\t{\n\t\tStringBuilder writer;\n\t\twriter << \"name \" << MetaData.ShaderName << EndLine;\n\t\tfor (auto & ublock : MetaData.ParameterSets)\n\t\t{\n\t\t\twriter << \"paramset \\\"\" << ublock.Key << \"\\\" size \" << ublock.Value->BufferSize\n\t\t\t\t<< \" binding \" << ublock.Value->DescriptorSetId << \"\\n{\\n\";\n\t\t\tfor (auto & entry : ublock.Value->Parameters)\n\t\t\t{\n\t\t\t\twriter << entry.Value->Name << \"(\\\"\" << entry.Key << \"\\\") : \";\n\t\t\t\tentry.Value->Type->Serialize(writer);\n\t\t\t\twriter << \" at \";\n\t\t\t\tif (entry.Value->BufferOffset == -1)\n\t\t\t\t{\n\t\t\t\t\twriter << \"binding(\";\n\t\t\t\t\tfor (auto binding : entry.Value->BindingPoints)\n\t\t\t\t\t\twriter << binding << \" \";\n\t\t\t\t\twriter << \")\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n                    // TODO(tfoley): Should use the correct layout rule here, and not assume `Std140`\n\t\t\t\t\twriter << \"buffer(\" << entry.Value->BufferOffset << \", \"\n\t\t\t\t\t\t<< (int)GetTypeSize(entry.Value->Type.Ptr(), LayoutRule::Std140) << \")\";\n\t\t\t\t}\n\t\t\t\twriter << \";\\n\";\n\t\t\t}\n\t\t\twriter << \"}\\n\";\n\t\t}\n\t\twriter << \"source\" << EndLine << \"{\" << EndLine;\n\t\tfor (auto & src : Sources)\n\t\t{\n\t\t\twriter << src.Key << EndLine;\n\t\t\tif (src.Value.BinaryCode.Count())\n\t\t\t{\n\t\t\t\twriter << \"binary\" << EndLine << \"{\" << EndLine;\n\t\t\t\tauto binaryBuffer = (unsigned int*)src.Value.BinaryCode.Buffer();\n\t\t\t\tfor (int i = 0; i < src.Value.BinaryCode.Count() / 4; i++)\n\t\t\t\t{\n\t\t\t\t\twriter << String((long long)binaryBuffer[i]) << \",\";\n\t\t\t\t\tif ((i + 1) % 10)\n\t\t\t\t\t\twriter << EndLine;\n\t\t\t\t}\n\t\t\t\twriter << EndLine << \"}\" << EndLine;\n\t\t\t}\n\t\t\twriter << \"text\" << EndLine << \"{\" << EndLine;\n\t\t\twriter << src.Value.MainCode << EndLine;\n\n\t\t\twriter << \"}\" << EndLine;\n\t\t}\n\t\twriter << \"}\" << EndLine;\n\t\tStringBuilder formatSB;\n\t\tIndentString(formatSB, writer.ProduceString());\n\t\treturn formatSB.ProduceString();\n\t}\n\n\tvoid ShaderLibFile::Clear()\n\t{\n\t\tSources.Clear();\n\t\tMetaData.ParameterSets.Clear();\n\t\tSources.Clear();\n\t}\n\n\tvoid ShaderLibFile::SaveToFile(CoreLib::Basic::String fileName)\n\t{\n\t\tStreamWriter fwriter(fileName);\n\t\tfwriter.Write(ToString());\n\t}\n\n\tvoid ShaderLibFile::FromString(const String & src)\n\t{\n\t\tClear();\n\t\tCoreLib::Text::TokenReader parser(src);\n\t\twhile (!parser.IsEnd())\n\t\t{\n\t\t\tauto fieldName = parser.ReadWord();\n\t\t\tif (fieldName == \"name\")\n\t\t\t{\n\t\t\t\tMetaData.ShaderName = parser.ReadWord();\n\t\t\t}\n\t\t\telse if (fieldName == \"source\")\n\t\t\t{\n\t\t\t\tparser.Read(\"{\");\n\t\t\t\tReadSource(Sources, parser, src);\n\t\t\t\tparser.Read(\"}\");\n\t\t\t}\n\t\t\telse if (fieldName == \"paramset\")\n\t\t\t{\n\t\t\t\tRefPtr<ILModuleParameterSet> paramSet = new ILModuleParameterSet();\n\t\t\t\tparamSet->BindingName = parser.ReadStringLiteral();\n\t\t\t\tif (parser.LookAhead(\"size\"))\n\t\t\t\t{\n\t\t\t\t\tparser.ReadToken();\n\t\t\t\t\tparamSet->BufferSize = parser.ReadInt();\n\t\t\t\t}\n\t\t\t\tif (parser.LookAhead(\"binding\"))\n\t\t\t\t{\n\t\t\t\t\tparser.ReadToken();\n\t\t\t\t\tparamSet->DescriptorSetId = parser.ReadInt();\n\t\t\t\t}\n\t\t\t\tparser.Read(\"{\");\n\t\t\t\twhile (!parser.LookAhead(\"}\"))\n\t\t\t\t{\n\t\t\t\t\tRefPtr<ILModuleParameterInstance> inst = new ILModuleParameterInstance();\n\t\t\t\t\tinst->Name = parser.ReadWord();\n\t\t\t\t\tparser.Read(\"(\");\n\t\t\t\t\tauto key = parser.ReadStringLiteral();\n\t\t\t\t\tparser.Read(\")\");\n\t\t\t\t\tinst->Type = ILType::Deserialize(parser);\n\t\t\t\t\tparser.Read(\"at\");\n\t\t\t\t\tif (parser.LookAhead(\"binding\"))\n\t\t\t\t\t{\n\t\t\t\t\t\tparser.ReadToken();\n\t\t\t\t\t\tparser.Read(\"(\");\n\t\t\t\t\t\twhile (!parser.LookAhead(\")\"))\n\t\t\t\t\t\t\tinst->BindingPoints.Add(parser.ReadInt());\n\t\t\t\t\t\tparser.Read(\")\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tparser.Read(\"buffer\");\n\t\t\t\t\t\tparser.Read(\"(\");\n\t\t\t\t\t\tinst->BufferOffset = parser.ReadInt();\n\t\t\t\t\t\tparser.Read(\")\");\n\t\t\t\t\t}\n\t\t\t\t\tparamSet->Parameters.Add(key, inst);\n\t\t\t\t}\n\t\t\t\tparser.Read(\"}\");\n\t\t\t\tMetaData.ParameterSets.Add(paramSet->BindingName, paramSet);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid ShaderLibFile::Load(String fileName)\n\t{\n\t\tString src = File::ReadAllText(fileName);\n\t\tFromString(src);\n\t}\n\n\t\n}\n\nusing namespace SpireLib;\n\n\nstruct ShaderParameter\n{\n\tString TypeName;\n\tString Name;\n\tint BindingId;\n};\n\nclass Shader\n{\n\tfriend class ::CompilationContext;\nprivate:\n\tString shaderName;\n\tString src;\npublic:\n\tint Id;\n\tList<ShaderParameter> Parameters;\n\tRefPtr<Decl> Syntax;\n\tShader(String name, String source)\n\t{\n\t\tstatic int idAllocator = 0;\n\t\tId = idAllocator++;\n\t\tshaderName = name;\n\t\tsrc = source;\n\t}\n\tString GetName() const\n\t{\n\t\treturn shaderName;\n\t}\n\tString GetSource() const\n\t{\n\t\treturn src;\n\t}\n};\n\nclass CompileResult\n{\npublic:\n\tCoreLib::EnumerableDictionary<String, CompiledShaderSource> Sources;\n\tCoreLib::EnumerableDictionary<String, List<SpireParameterSet>> ParamSets;\n\n};\n\nstruct CompilerState : public RefObject\n{\n\tList<CompileUnit> moduleUnits;\n\tHashSet<String> processedModuleUnits;\n\tEnumerableDictionary<String, RefPtr<SpireModule>> modules;\n\tEnumerableDictionary<String, RefPtr<Shader>> shaders;\n\tRefPtr<Spire::Compiler::CompilationContext> context;\n\tRefPtr<CompilerState> Parent;\n\t// the version of this state\n\tint Version = 0;\n\t// the version of parent states cached in this state\n\tint CachedParentVersion = 0;\n\tvoid Update() // update this state to include latest version of parent\n\t{\n\t\tif (Parent)\n\t\t{\n\t\t\tParent->Update();\n\t\t\tif (Parent->Version != CachedParentVersion)\n\t\t\t{\n\t\t\t\tcontext->MergeWith(Parent->context.Ptr());\n\t\t\t\tCachedParentVersion = Parent->Version;\n\t\t\t\tVersion++;\n\t\t\t}\n\t\t}\n\t}\n\n\tint errorCount = 0;\n\tCompilerState()\n\t{\n\t\tcontext = new Spire::Compiler::CompilationContext();\n\t}\n\tCompilerState(RefPtr<CompilerState> parent)\n\t{\n\t\tthis->Parent = parent;\n\n\t\t// Do the ugly thing to copy parent's symbol table to child\n\t\tif (parent)\n\t\t\tcontext = new Spire::Compiler::CompilationContext(*parent->context);\n\t}\n\t~CompilerState()\n\t{\n\t\tprintf(\"break\");\n\t}\n};\n\nclass CompilationContext;\n\nstruct SpireCompilationEnvironment\n{\n\t::CompilationContext * context;\n\tRefPtr<::CompilerState> state;\n};\n\nclass CompilationContext\n{\npublic:\n\tbool useCache = false;\n\tCoreLib::String cacheDir;\n\n\tList<RefPtr<::CompilerState>> states;\n\tRefPtr<ShaderCompiler> compiler;\n\n\tstruct IncludeHandlerImpl : IncludeHandler\n\t{\n\t\tList<String> searchDirs;\n\n\t\tvirtual bool TryToFindIncludeFile(\n\t\t\tCoreLib::String const& pathToInclude,\n\t\t\tCoreLib::String const& pathIncludedFrom,\n\t\t\tCoreLib::String* outFoundPath,\n\t\t\tCoreLib::String* outFoundSource) override\n\t\t{\n\t\t\tString path = Path::Combine(Path::GetDirectoryName(pathIncludedFrom), pathToInclude);\n\t\t\tif (File::Exists(path))\n\t\t\t{\n\t\t\t\t*outFoundPath = path;\n\t\t\t\t*outFoundSource = File::ReadAllText(path);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tfor (auto & dir : searchDirs)\n\t\t\t{\n\t\t\t\tpath = Path::Combine(dir, pathToInclude);\n\t\t\t\tif (File::Exists(path))\n\t\t\t\t{\n\t\t\t\t\t*outFoundPath = path;\n\t\t\t\t\t*outFoundSource = File::ReadAllText(path);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t};\n\tIncludeHandlerImpl includeHandler;\n\npublic:\n\tCompileOptions Options;\n\n\tCompilationContext(bool /*pUseCache*/, CoreLib::String /*pCacheDir*/)\n\t{\n\t\tcompiler = CreateShaderCompiler();\n\t\tstates.Add(new ::CompilerState());\n\t\tLoadModuleSource(states.First().Ptr(), SpireStdLib::GetCode(), \"stdlib\", NULL);\n\t}\n\n\t~CompilationContext()\n\t{\n\t\tSpireStdLib::Finalize();\n\t}\n\n\tSpireModule * FindModule(CoreLib::String moduleName)\n\t{\n\t\tauto ptr = states.Last()->modules.TryGetValue(moduleName);\n\t\tif (ptr)\n\t\t\treturn ptr->Ptr();\n\t\telse\n\t\t\treturn nullptr;\n\t}\n\n\tStringBuilder moduleKeyBuilder;\n\tSpireModule * SpecializeModule(SpireModule * module, int * params, int numParams, SpireDiagnosticSink * sink)\n\t{\n\t\tmoduleKeyBuilder.Clear();\n\t\tmoduleKeyBuilder.Append(module->Name);\n\t\tfor (auto & param : module->Parameters)\n\t\t{\n\t\t\tif (param.IsSpecialize)\n\t\t\t{\n\t\t\t\tint id = -1;\n\t\t\t\tfor (int i = 0; i < numParams; i++)\n\t\t\t\t{\n\t\t\t\t\tmoduleKeyBuilder.Append(params[id]);\n\t\t\t\t\tmoduleKeyBuilder.Append('_');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (auto smodule = module->State->modules.TryGetValue(moduleKeyBuilder.Buffer()))\n\t\t\treturn smodule->Ptr();\n\t\tRefPtr<ShaderSymbol> originalModule;\n\t\tmodule->State->context->Symbols.Shaders.TryGetValue(module->Name, originalModule);\n\t\tCompileUnit unit;\n\t\tunit.SyntaxNode = new ProgramSyntaxNode();\n\t\tCloneContext cloneCtx;\n\t\tauto newModule = originalModule->SyntaxNode->Clone(cloneCtx);\n\t\tnewModule->Name.Content = moduleKeyBuilder.ToString();\n\t\tint id = 0;\n\t\tfor (auto & member : newModule->Members)\n\t\t{\n\t\t\tif (auto param = member.As<ComponentSyntaxNode>())\n\t\t\t{\n\t\t\t\tif (auto specialize = param->FindSpecializeModifier())\n\t\t\t\t{\n\t\t\t\t\tif (id >= numParams)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn nullptr;\n\t\t\t\t\t}\n\t\t\t\t\tauto newParam = param->Clone(cloneCtx);\n\t\t\t\t\tnewParam->modifiers.first = nullptr;\n\t\t\t\t\tnewParam->modifiers.flags = ModifierFlag::Public;\n\t\t\t\t\tparam->BlockStatement = nullptr;\n\t\t\t\t\tauto expr = new ConstantExpressionSyntaxNode();\n\t\t\t\t\tif (param->Type->Equals(ExpressionType::Bool))\n\t\t\t\t\t\texpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Bool;\n\t\t\t\t\telse\n\t\t\t\t\t\texpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Int;\n\t\t\t\t\texpr->IntValue = params[id];\n\t\t\t\t\tnewParam->Expression = expr;\n\t\t\t\t\tnewModule->Members.Add(newParam);\n\t\t\t\t\tparam->Name.Content = param->Name.Content + \"placeholder\";\n\t\t\t\t\tid++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tunit.SyntaxNode->Members.Add(newModule);\n\t\tList<CompileUnit> units;\n\t\tunits.Add(unit);\n\t\tUpdateModuleLibrary(module->State, units, sink);\n\t\treturn FindModule(newModule->Name.Content);\n\t}\n\n\tLayoutRule GetUniformBufferLayoutRule()\n\t{\n\t\tif (this->Options.Target == CodeGenTarget::HLSL)\n\t\t\treturn LayoutRule::HLSL;\n\t\telse\n\t\t\treturn LayoutRule::Std140;\n\t}\n\n\tRefPtr<SpireModule> CreateModule(CompilerState * state, Spire::Compiler::ShaderSymbol * shader, LayoutInfo & parentParamStruct, SpireBindingIndex & bindingIndex)\n\t{\n\t\tRefPtr<SpireModule> newModule = new SpireModule();\n\t\tnewModule->State = state;\n\t\tauto & meta = *newModule;\n\t\tmeta.Id = SpireModule::IdAllocator++;\n\t\tmeta.Name = shader->SyntaxNode->Name.Content;\n\t\tmeta.BindingIndex = bindingIndex;\n\t\tint offsets[2] = { 0, 0 };\n\t\tfor (auto attrib : shader->SyntaxNode->GetModifiersOfType<Spire::Compiler::SimpleAttribute>())\n\t\t\tmeta.Attribs[attrib->Key] = attrib->Value.Content;\n\t\tauto layout = GetLayoutRulesImpl(GetUniformBufferLayoutRule());\n\t\tLayoutInfo requireStruct = layout->BeginStructLayout();\n\t\tbool firstCompEncountered = false;\n\t\tfor (auto & comp : shader->Components)\n\t\t{\n\t\t\tif (comp.Value->Implementations.Count() != 1)\n\t\t\t\tcontinue;\n\t\t\tauto impl = comp.Value->Implementations.First();\n\t\t\tif (!impl->SyntaxNode->IsRequire() && !impl->SyntaxNode->IsParam())\n\t\t\t\tcontinue;\n\t\t\tif (comp.Value->Implementations.First()->SyntaxNode->IsComponentFunction())\n\t\t\t\tcontinue;\n\t\t\tauto & structInfo = impl->SyntaxNode->IsParam() ? parentParamStruct : requireStruct;\n\t\t\tComponentMetaData compMeta;\n\t\t\tcompMeta.Name = comp.Key;\n\t\t\tcompMeta.Type = comp.Value->Type->DataType;\n\t\t\tcompMeta.TypeName = compMeta.Type->ToString();\n\t\t\tif (auto specialize = impl->SyntaxNode->FindSpecializeModifier())\n\t\t\t{\n\t\t\t\tfor (auto val : specialize->Values)\n\t\t\t\t{\n\t\t\t\t\tcompMeta.Values.Add(dynamic_cast<ConstantExpressionSyntaxNode*>(val.Ptr())->IntValue);\n\t\t\t\t}\n\t\t\t\tcompMeta.IsSpecialize = true;\n\t\t\t}\n\t\t\tauto bindableType = compMeta.Type->GetBindableResourceType();\n\t\t\tif (compMeta.Type->GetBindableResourceType() == BindableResourceType::NonBindable)\n\t\t\t{\n\t\t\t\tif (!firstCompEncountered)\n\t\t\t\t{\n                    // TODO(tfoley): This logic seems very wrong.\n                    // We should be handling things by adding a field to the `parentParamStruct`\n                    // (which should handle whatever layout rules it wants to use)\n                    // rather than doing this ad hoc logic to special-case HLSL...\n\n\t\t\t\t\tfirstCompEncountered = true;\n\t\t\t\t\tif (GetUniformBufferLayoutRule() == LayoutRule::HLSL)\n\t\t\t\t\t\tparentParamStruct.size = (size_t)RoundToAlignment((int)parentParamStruct.size, 16);\n\t\t\t\t\tmeta.UniformBufferOffset = (int)parentParamStruct.size;\n\t\t\t\t}\n\t\t\t\tcompMeta.Alignment = (int)GetTypeAlignment(compMeta.Type.Ptr(), GetUniformBufferLayoutRule());\n\t\t\t\tcompMeta.Size = (int)GetTypeSize(compMeta.Type.Ptr(), GetUniformBufferLayoutRule());\n\t\t\t\tauto fieldInfo = GetLayout(compMeta.Type.Ptr(), layout);\n\t\t\t\tcompMeta.Offset = (int)layout->AddStructField(&structInfo, fieldInfo);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tswitch (bindableType)\n\t\t\t\t{\n\t\t\t\tcase BindableResourceType::Texture:\n\t\t\t\t\tcompMeta.typeSpecificBindingIndex = bindingIndex.texture;\n\t\t\t\t\tbindingIndex.texture++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase BindableResourceType::Sampler:\n\t\t\t\t\tcompMeta.typeSpecificBindingIndex = bindingIndex.sampler;\n\t\t\t\t\tbindingIndex.sampler++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase BindableResourceType::Buffer:\n\t\t\t\t\tcompMeta.typeSpecificBindingIndex = bindingIndex.uniformBuffer;\n\t\t\t\t\tbindingIndex.uniformBuffer++;\n\t\t\t\t\tbreak; \n\t\t\t\tcase BindableResourceType::StorageBuffer:\n\t\t\t\t\tcompMeta.typeSpecificBindingIndex = bindingIndex.storageBuffer;\n\t\t\t\t\tbindingIndex.storageBuffer++;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcompMeta.typeAgnosticBindingIndex = bindingIndex.general;\n\t\t\t\tbindingIndex.general++;\n\t\t\t}\n\t\t\tif (impl->SyntaxNode->IsRequire())\n\t\t\t\tmeta.Requirements.Add(compMeta);\n\t\t\telse\n\t\t\t{\n\t\t\t\tmeta.Parameters.Add(compMeta);\n\t\t\t\tmeta.ParameterMap[compMeta.Name] = compMeta;\n\t\t\t}\n\t\t}\n\t\tlayout->EndStructLayout(&requireStruct);\n\t\t\n\t\tfor (auto sub : shader->SyntaxNode->GetMembersOfType<ImportSyntaxNode>())\n\t\t{\n\t\t\tnewModule->SubModules.Add(CreateModule(state, state->context->Symbols.Shaders[sub->ShaderName.Content]().Ptr(), parentParamStruct, bindingIndex));\n\t\t}\n\t\tmeta.UniformBufferSize = (int)(parentParamStruct.size - meta.UniformBufferOffset);\n\t\treturn newModule;\n\t}\n\n\tvoid UpdateModuleLibrary(CompilerState * state, List<CompileUnit> & units, SpireDiagnosticSink * sink)\n\t{\n\t\tSpire::Compiler::CompileResult result;\n\t\tcompiler->Compile(result, *state->context, units, Options);\n\t\tstate->Version++;\n\t\tfor (auto & shader : state->context->Symbols.Shaders)\n\t\t{\n\t\t\tif (!state->modules.ContainsKey(shader.Key))\n\t\t\t{\n\t\t\t\tSpireBindingIndex bindingIndex;\n\t\t\t\tauto layout = GetLayoutRulesImpl(GetUniformBufferLayoutRule());\n\t\t\t\tLayoutInfo paramStruct = layout->BeginStructLayout();\n\t\t\t\tRefPtr<SpireModule> newModule = CreateModule(state, shader.Value.Ptr(), paramStruct, bindingIndex);\n\t\t\t\tnewModule->BindingIndex;\n\t\t\t\tlayout->EndStructLayout(&paramStruct);\n\t\t\t\tnewModule->UniformBufferSize = (int)paramStruct.size;\n\t\t\t\tstate->modules.Add(shader.Key, newModule);\n\t\t\t}\n\t\t}\n\t\tfor (auto & unit : units)\n\t\t{\n\t\t\tfor (auto & shader : unit.SyntaxNode->GetMembersOfType<TemplateShaderSyntaxNode>())\n\t\t\t{\n\t\t\t\tRefPtr<Shader> rs = new Shader(shader->Name.Content, \"\");\n\t\t\t\tint i = 0;\n\t\t\t\trs->Syntax = shader;\n\t\t\t\tfor (auto & param : shader->Parameters)\n\t\t\t\t{\n\t\t\t\t\tShaderParameter p;\n\t\t\t\t\tp.BindingId = i;\n\t\t\t\t\tp.Name = param->ModuleName.Content;\n\t\t\t\t\tp.TypeName = param->InterfaceName.Content;\n\t\t\t\t\trs->Parameters.Add(p);\n\t\t\t\t\ti++;\n\t\t\t\t}\n\t\t\t\tstate->shaders[shader->Name.Content] = rs;\n\t\t\t}\n\t\t\tfor (auto & shader : unit.SyntaxNode->GetMembersOfType<ShaderSyntaxNode>())\n\t\t\t{\n\t\t\t\tif (shader->IsModule)\n\t\t\t\t\tcontinue;\n\t\t\t\tRefPtr<Shader> rs = new Shader(shader->Name.Content, \"\");\n\t\t\t\trs->Syntax = shader;\n\t\t\t\tHashSet<int> usedIds;\n\t\t\t\tfor (auto & imp : unit.SyntaxNode->GetMembersOfType<ImportSyntaxNode>())\n\t\t\t\t{\n\t\t\t\t\tShaderParameter param;\n\t\t\t\t\tparam.TypeName = imp->ShaderName.Content;\n\t\t\t\t\tparam.Name = imp->ObjectName.Content;\n\t\t\t\t\tparam.BindingId = -1;\n\t\t\t\t\tString binding;\n\t\t\t\t\tif (imp->FindSimpleAttribute(\"Binding\", binding))\n\t\t\t\t\t{\n\t\t\t\t\t\tparam.BindingId = StringToInt(binding);\n\t\t\t\t\t\tusedIds.Add(param.BindingId);\n\t\t\t\t\t}\n\t\t\t\t\trs->Parameters.Add(param);\n\t\t\t\t}\n\t\t\t\tint idAlloc = 0;\n\t\t\t\tfor (auto & param : rs->Parameters)\n\t\t\t\t{\n\t\t\t\t\tif (param.BindingId == -1)\n\t\t\t\t\t{\n\t\t\t\t\t\twhile (usedIds.Contains(idAlloc))\n\t\t\t\t\t\t\tidAlloc++;\n\t\t\t\t\t\tparam.BindingId = idAlloc;\n\t\t\t\t\t\tidAlloc++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstate->shaders[shader->Name.Content] = rs;\n\t\t\t}\n\t\t}\n\t\tif (sink)\n\t\t{\n\t\t\tsink->diagnostics.AddRange(result.sink.diagnostics);\n\t\t\tsink->errorCount += result.GetErrorCount();\n\t\t}\n\t}\n\n\tint LoadModuleSource(CompilerState * state, CoreLib::String src, CoreLib::String fileName, SpireDiagnosticSink* sink)\n\t{\n\t\tList<CompileUnit> units;\n\t\tint errCount = LoadModuleUnits(state, units, src, fileName, sink);\n\t\tstate->moduleUnits.AddRange(units);\n\t\tUpdateModuleLibrary(state, units, sink);\n\t\treturn errCount;\n\t}\n\n\tint LoadModuleUnits(CompilerState * state, List<CompileUnit> & units, CoreLib::String src, CoreLib::String fileName, SpireDiagnosticSink* sink)\n\t{\n\t\tauto & processedUnits = state->processedModuleUnits;\n\t\tSpire::Compiler::CompileResult result;\n\t\tList<String> unitsToInclude;\n\t\tunitsToInclude.Add(fileName);\n\t\tprocessedUnits.Add(fileName);\n\t\tauto searchDirs = Options.SearchDirectories;\n\t\tsearchDirs.Add(Path::GetDirectoryName(fileName));\n\t\tsearchDirs.Reverse();\n\t\tfor (int i = 0; i < unitsToInclude.Count(); i++)\n\t\t{\n\t\t\tauto inputFileName = unitsToInclude[i];\n\t\t\ttry\n\t\t\t{\n\t\t\t\tString source = src;\n\t\t\t\tif (i > 0)\n\t\t\t\t\tsource = File::ReadAllText(inputFileName);\n\t\t\t\tauto unit = compiler->Parse(result, source, inputFileName, &includeHandler, Options.PreprocessorDefinitions);\n\t\t\t\tunits.Add(unit);\n\t\t\t\tif (unit.SyntaxNode)\n\t\t\t\t{\n\t\t\t\t\tfor (auto inc : unit.SyntaxNode->GetUsings())\n\t\t\t\t\t{\n\t\t\t\t\t\tbool found = false;\n\t\t\t\t\t\tfor (auto & dir : searchDirs)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tString includeFile = Path::Combine(dir, inc->fileName.Content);\n\t\t\t\t\t\t\tif (File::Exists(includeFile))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (processedUnits.Add(includeFile))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tunitsToInclude.Add(includeFile);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!found)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tresult.GetErrorWriter()->diagnose(inc->fileName.Position, Diagnostics::cannotFindFile, inc->fileName);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IOException)\n\t\t\t{\n\t\t\t\tresult.GetErrorWriter()->diagnose(CodePosition(0, 0, 0, \"\"), Diagnostics::cannotOpenFile, inputFileName);\n\t\t\t}\n\t\t}\n\t\tif (sink)\n\t\t{\n\t\t\tsink->diagnostics.AddRange(result.sink.diagnostics);\n\t\t\tsink->errorCount += result.GetErrorCount();\n\t\t}\n\t\treturn result.GetErrorCount();\n\t}\n\tShader * FindShader(const char * name)\n\t{\n\t\tRefPtr<Shader> rs;\n\t\tif (states.Last()->shaders.TryGetValue(name, rs))\n\t\t\treturn rs.Ptr();\n\t\treturn nullptr;\n\t}\n\tShader * GetShader(int index)\n\t{\n\t\tint i = 0;\n\t\tfor (auto & shader : states.Last()->shaders)\n\t\t{\n\t\t\tif (i == index)\n\t\t\t\treturn shader.Value.Ptr();\n\t\t\ti++;\n\t\t}\n\t\treturn nullptr;\n\t}\n\tint GetShaderCount()\n\t{\n\t\tif (states.Count())\n\t\t\treturn states.Last()->shaders.Count();\n\t\treturn 0;\n\t}\n\tShader * NewShaderFromSource(CompilerState * state, const char * source, const char * fileName, SpireDiagnosticSink * sink)\n\t{\n\t\tint shaderCount = GetShaderCount();\n\t\tLoadModuleSource(state, source, fileName, sink);\n\t\tint newShaderCount = GetShaderCount();\n\t\tif (newShaderCount > shaderCount)\n\t\t\treturn GetShader(shaderCount);\n\t\treturn nullptr;\n\t}\n\tShader * NewShaderFromFile(CompilerState * state, const char * fileName, SpireDiagnosticSink * sink)\n\t{\n\t\ttry\n\t\t{\n\t\t\treturn NewShaderFromSource(state, File::ReadAllText(fileName).Buffer(), fileName, sink);\n\t\t}\n\t\tcatch (Exception)\n\t\t{\n\t\t\treturn nullptr;\n\t\t}\n\t}\n\tvoid PushContext()\n\t{\n\t\tstates.Add(new CompilerState(states.Last()));\n\t}\n\tvoid PopContext()\n\t{\n\t\tstates.Last() = nullptr;\n\t\tstates.SetSize(states.Count() - 1);\n\t}\n\tbool Compile(::CompileResult & result, RefPtr<CompilerState> currentState, const Shader & shader, ArrayView<SpireModule*> modulesArgs, const char * additionalSource, SpireDiagnosticSink* sink)\n\t{\n\t\tOptions.SymbolToCompile = shader.GetName();\n\t\tOptions.TemplateShaderArguments.Clear();\n\t\tfor (auto module : modulesArgs)\n\t\t\tOptions.TemplateShaderArguments.Add(module->Name);\n\t\treturn Compile(result, currentState, shader.Syntax, additionalSource, shader.GetName(), sink);\n\t}\n\tSpireParameterSet GetParameterSet(ILModuleParameterSet * module)\n\t{\n\t\tSpireParameterSet set;\n\t\tset.paramSet = module;\n\t\tset.uniformBufferLegacyBindingPoint = module->UniformBufferLegacyBindingPoint;\n\t\tfor (auto & item : module->Parameters)\n\t\t{\n\t\t\tauto resType = item.Value->Type->GetBindableResourceType();\n\t\t\tif (resType != BindableResourceType::NonBindable)\n\t\t\t{\n\t\t\t\tSpireResourceBindingInfo info;\n\t\t\t\tinfo.Type = (SpireBindableResourceType)resType;\n\t\t\t\tinfo.NumLegacyBindingPoints = item.Value->BindingPoints.Count();\n\t\t\t\tinfo.LegacyBindingPoints = item.Value->BindingPoints.Buffer();\n\t\t\t\tinfo.Name = item.Value->Name.Buffer();\n\t\t\t\tset.bindings.Add(info);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tSpireUniformFieldImpl ufield;\n\t\t\t\tufield.name = item.Key.Buffer();\n\t\t\t\tufield.offset = item.Value->BufferOffset;\n\t\t\t\tufield.size = item.Value->Size;\n\t\t\t\tStringBuilder sb;\n\t\t\t\titem.Value->Type->Serialize(sb);\n\t\t\t\tufield.type = sb.ProduceString();\n\t\t\t\tset.uniforms.Add(ufield);\n\t\t\t}\n\t\t}\n\t\tfor (auto & submodule : module->SubModules)\n\t\t\tset.subsets.Add(GetParameterSet(submodule.Ptr()));\n\t\treturn set;\n\t}\n\tbool Compile(::CompileResult & result, RefPtr<CompilerState> currentState, RefPtr<Decl> entryPoint, CoreLib::String source, CoreLib::String fileName, SpireDiagnosticSink* sink)\n\t{\n\t\tif (currentState->errorCount != 0)\n\t\t\treturn false;\n\t\tcurrentState->Update();\n\t\tList<CompileUnit> units;\n\t\tcurrentState->errorCount += LoadModuleUnits(currentState.Ptr(), units, source, fileName, sink);\n\t\tif (currentState->errorCount != 0)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\tif (entryPoint)\n\t\t{\n\t\t\tCompileUnit newUnit;\n\t\t\tnewUnit.SyntaxNode = new ProgramSyntaxNode();\n\t\t\tnewUnit.SyntaxNode->Members.Add(entryPoint);\n\t\t\tunits.Add(newUnit);\n\t\t}\n\t\t\n\t\tSpire::Compiler::CompileResult cresult;\n\t\tcompiler->Compile(cresult, *(currentState->context), units, Options);\n\t\tresult.Sources = cresult.CompiledSource;\n\t\tcurrentState->errorCount += cresult.GetErrorCount();\n\t\tif (sink)\n\t\t{\n\t\t\tsink->diagnostics.AddRange(cresult.sink.diagnostics);\n\t\t\tsink->errorCount += cresult.GetErrorCount();\n\t\t}\n\t\tif (currentState->errorCount == 0)\n\t\t{\n\t\t\tfor (auto shader : result.Sources)\n\t\t\t{\n\t\t\t\tList<SpireParameterSet> paramSets;\n\t\t\t\tfor (auto & pset : shader.Value.MetaData.ParameterSets)\n\t\t\t\t{\n\t\t\t\t\tif (!pset.Value->IsTopLevel)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tparamSets.Add(GetParameterSet(pset.Value.Ptr()));\n\t\t\t\t}\n\t\t\t\tresult.ParamSets[shader.Key] = _Move(paramSets);\n\t\t\t}\n\t\t}\n\t\tbool succ = currentState->errorCount == 0;\n\t\treturn succ;\n\t}\n};\n\n// implementation of C interface\n\n#define CTX(x) reinterpret_cast<::CompilationContext *>(x)\n#define SHADER(x) reinterpret_cast<::Shader*>(x)\n#define RS(x) reinterpret_cast<::CompileResult*>(x)\n\nSpireCompilationContext * spCreateCompilationContext(const char * cacheDir)\n{\n\treturn reinterpret_cast<SpireCompilationContext *>(new ::CompilationContext((cacheDir ? true : false), cacheDir));\n}\n\nvoid spSetCodeGenTarget(SpireCompilationContext * ctx, int target)\n{\n\tCTX(ctx)->Options.Target = (CodeGenTarget)target;\n}\n\nvoid spAddSearchPath(SpireCompilationContext * ctx, const char * searchDir)\n{\n\tCTX(ctx)->Options.SearchDirectories.Add(searchDir);\n}\n\nvoid spAddPreprocessorDefine(SpireCompilationContext * ctx, const char * key, const char * value)\n{\n\tCTX(ctx)->Options.PreprocessorDefinitions[key] = value;\n}\n\nvoid spSetBackendParameter(SpireCompilationContext * ctx, const char * paramName, const char * value)\n{\n\tCTX(ctx)->Options.BackendArguments[paramName] = value;\n}\n\nvoid spSetShaderToCompile(SpireCompilationContext * ctx, const char * shaderName)\n{\n\tCTX(ctx)->Options.SymbolToCompile = shaderName;\n}\n\nvoid spDestroyCompilationContext(SpireCompilationContext * ctx)\n{\n\tdelete CTX(ctx);\n}\n\n// `SpireDiagnosticSink` implementation\n\nSpireDiagnosticSink* spCreateDiagnosticSink(SpireCompilationContext * /*ctx*/)\n{\n\tSpireDiagnosticSink* sink = new SpireDiagnosticSink();\n\tsink->errorCount = 0;\n\treturn sink;\n}\n\nvoid spClearDiagnosticSink(SpireDiagnosticSink* sink)\n{\n\tif (!sink) return;\n\n\tsink->errorCount = 0;\n\tsink->diagnostics.Clear();\n}\n\nvoid spDestroyDiagnosticSink(SpireDiagnosticSink* sink)\n{\n\tdelete sink;\n}\n\n//\n\nvoid spLoadModuleLibrary(SpireCompilationContext * ctx, const char * fileName, SpireDiagnosticSink* sink)\n{\n\tCTX(ctx)->LoadModuleSource(CTX(ctx)->states.Last().Ptr(), File::ReadAllText(fileName), fileName, sink);\n}\n\nvoid spEnvLoadModuleLibrary(SpireCompilationEnvironment * env, const char * fileName, SpireDiagnosticSink * sink)\n{\n\tenv->context->LoadModuleSource(env->state.Ptr(), File::ReadAllText(fileName), fileName, sink);\n}\n\nvoid spLoadModuleLibraryFromSource(SpireCompilationContext * ctx, const char * source, const char * fileName, SpireDiagnosticSink* sink)\n{\n\tCTX(ctx)->LoadModuleSource(CTX(ctx)->states.Last().Ptr(), source, fileName, sink);\n}\n\nvoid spEnvLoadModuleLibraryFromSource(SpireCompilationEnvironment * env, const char * source, const char * fileName, SpireDiagnosticSink * sink)\n{\n\tenv->context->LoadModuleSource(env->state.Ptr(), source, fileName, sink);\n}\n\nvoid spPushContext(SpireCompilationContext * ctx)\n{\n\tCTX(ctx)->PushContext();\n}\n\nvoid spPopContext(SpireCompilationContext * ctx)\n{\n\tCTX(ctx)->PopContext();\n}\n\nSpireCompilationEnvironment * spGetCurrentEnvironment(SpireCompilationContext * ctx)\n{\n\tauto rs = new SpireCompilationEnvironment();\n\trs->context = CTX(ctx);\n\trs->state = CTX(ctx)->states.Last();\n\treturn rs;\n}\n\nSpireCompilationEnvironment * spCreateEnvironment(SpireCompilationContext * ctx, SpireCompilationEnvironment * forkOrigin)\n{\n\tauto rs = new SpireCompilationEnvironment();\n\trs->context = CTX(ctx);\n\tif (forkOrigin)\n\t\trs->state = new CompilerState(*forkOrigin->state);\n\telse\n\t\trs->state = new CompilerState();\n\treturn rs;\n}\n\nvoid spReleaseEnvironment(SpireCompilationEnvironment * env)\n{\n\tdelete env;\n}\n\nSpireShader* spCreateShaderFromSource(SpireCompilationContext * ctx, const char * source, SpireDiagnosticSink * sink)\n{\n\treturn reinterpret_cast<SpireShader*>(CTX(ctx)->NewShaderFromSource(CTX(ctx)->states.Last().Ptr(), source, \"\", sink));\n}\n\nSpireShader * spEnvCreateShaderFromSource(SpireCompilationEnvironment * env, const char * source, SpireDiagnosticSink * sink)\n{\n\treturn reinterpret_cast<SpireShader*>(env->context->NewShaderFromSource(env->state.Ptr(), source, \"\", sink));\n}\n\nSpireShader * spFindShader(SpireCompilationContext * ctx, const char * name)\n{\n\treturn reinterpret_cast<SpireShader*>(CTX(ctx)->FindShader(name));\n}\n\nSpireShader * spEnvFindShader(SpireCompilationEnvironment * env, const char * name)\n{\n\tRefPtr<Shader> rs;\n\tif (env->state->shaders.TryGetValue(name, rs))\n\t\treturn reinterpret_cast<SpireShader*>(rs.Ptr());\n\treturn nullptr;\n}\n\nint spGetShaderCount(SpireCompilationContext * ctx)\n{\n\treturn CTX(ctx)->GetShaderCount();\n}\n\nint spEnvGetShaderCount(SpireCompilationEnvironment * env)\n{\n\treturn env->state->shaders.Count();\n}\n\nSpireShader * spGetShader(SpireCompilationContext * ctx, int index)\n{\n\treturn reinterpret_cast<SpireShader*>(CTX(ctx)->GetShader(index));\n}\n\nSpireShader * spEnvGetShader(SpireCompilationEnvironment * env, int index)\n{\n\tint i = 0;\n\tfor (auto & shader : env->state->shaders)\n\t{\n\t\tif (i == index)\n\t\t\treturn reinterpret_cast<SpireShader*>(shader.Value.Ptr());\n\t\ti++;\n\t}\n\treturn nullptr;\n}\n\nSpireShader* spCreateShaderFromFile(SpireCompilationContext * ctx, const char * fileName, SpireDiagnosticSink * sink)\n{\n\treturn reinterpret_cast<SpireShader*>(CTX(ctx)->NewShaderFromFile(CTX(ctx)->states.Last().Ptr(), fileName, sink));\n}\n\nSpireShader * spEnvCreateShaderFromFile(SpireCompilationEnvironment * env, const char * fileName, SpireDiagnosticSink * sink)\n{\n\treturn reinterpret_cast<SpireShader*>(env->context->NewShaderFromFile(env->state.Ptr(), fileName, sink));\n\n}\n\nunsigned int spShaderGetId(SpireShader * shader)\n{\n\treturn SHADER(shader)->Id;\n}\n\nconst char* spShaderGetName(SpireShader * shader)\n{\n\treturn SHADER(shader)->GetName().Buffer();\n}\n\nconst char * spShaderGetParameterType(SpireShader * shader, int i)\n{\n\tif (shader && i >= 0 && i < SHADER(shader)->Parameters.Count())\n\t\treturn SHADER(shader)->Parameters[i].TypeName.Buffer();\n\treturn nullptr;\n}\n\nconst char * spShaderGetParameterName(SpireShader * shader, int i)\n{\n\tif (shader && i >= 0 && i < SHADER(shader)->Parameters.Count())\n\t\treturn SHADER(shader)->Parameters[i].Name.Buffer();\n\treturn nullptr;\n}\n\nint spShaderGetParameterBinding(SpireShader * shader, int i)\n{\n\tif (shader && i >= 0 && i < SHADER(shader)->Parameters.Count())\n\t\treturn SHADER(shader)->Parameters[i].BindingId;\n\treturn -1;\n}\n\nint spShaderGetParameterCount(SpireShader * shader)\n{\n\treturn SHADER(shader)->Parameters.Count();\n}\n\nSpireModule * spFindModule(SpireCompilationContext * ctx, const char * moduleName)\n{\n\treturn CTX(ctx)->FindModule(moduleName);\n}\n\nSpireModule * spEnvFindModule(SpireCompilationEnvironment * env, const char * moduleName)\n{\n\tauto ptr = env->state->modules.TryGetValue(moduleName);\n\tif (ptr)\n\t\treturn ptr->Ptr();\n\telse\n\t\treturn nullptr;\n}\n\nunsigned int spGetModuleUID(SpireModule * module)\n{\n\treturn module->Id;\n}\n\nconst char * spGetModuleName(SpireModule * module)\n{\n\tif (!module) return nullptr;\n\tauto moduleNode = module;\n\treturn moduleNode->Name.Buffer();\n}\n\nSpireModule * spSpecializeModule(SpireCompilationContext * ctx, SpireModule * module, int * paramValues, int numParams, SpireDiagnosticSink * sink)\n{\n\treturn CTX(ctx)->SpecializeModule(module, paramValues, numParams, sink);\n}\n\nint spModuleGetParameterCount(SpireModule * module)\n{\n\tauto moduleNode = module;\n\treturn moduleNode->Parameters.Count();\n}\nint spModuleGetParameterBufferSize(SpireModule * module)\n{\n\treturn module->UniformBufferSize;\n}\nint spModuleHasAttrib(SpireModule * module, const char * name)\n{\n\treturn module->Attribs.ContainsKey(name);\n}\n\nint spModuleGetParameter(SpireModule * module, int index, SpireComponentInfo * result)\n{\n\tauto moduleNode = module;\n\tauto & param = moduleNode->Parameters[index];\n\tresult->TypeName = param.TypeName.Buffer();\n\tresult->Size = param.Size;\n\tresult->Offset = param.Offset;\n\tresult->Alignment = param.Alignment;\n\tresult->Name = param.Name.Buffer();\n\tresult->BindableResourceType = (int)param.Type->GetBindableResourceType();\n\tresult->Specialize = param.IsSpecialize;\n\treturn 1;\n}\n\nint spModuleGetParameterByName(SpireModule * module, const char * name, SpireComponentInfo * result)\n{\n\tComponentMetaData param;\n\tif (module->ParameterMap.TryGetValue(name, param))\n\t{\n\t\tresult->TypeName = param.TypeName.Buffer();\n\t\tresult->Size = param.Size;\n\t\tresult->Offset = param.Offset;\n\t\tresult->Alignment = param.Alignment;\n\t\tresult->Name = param.Name.Buffer();\n\t\tresult->BindableResourceType = (int)param.Type->GetBindableResourceType();\n\t\tresult->Specialize = param.IsSpecialize;\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nint spModuleGetSubModuleCount(SpireModule * module)\n{\n\treturn module->SubModules.Count();\n}\n\nSpireModule * spModuleGetSubModule(SpireModule * module, int index)\n{\n\treturn module->SubModules[index].Ptr();\n}\n\nint spModuleGetBufferOffset(SpireModule * module)\n{\n\treturn module->UniformBufferOffset;\n}\n\nint spModuleGetBindingOffset(SpireModule * module, SpireBindingIndex * pIndexOut)\n{\n\t*pIndexOut = module->BindingIndex;\n\treturn 0;\n}\n\nint spModuleGetRequiredComponents(SpireModule * module, SpireComponentInfo * buffer, int bufferSize)\n{\n\tauto moduleNode = module;\n\tauto & components = moduleNode->Requirements;\n\tif (!buffer)\n\t\treturn components.Count();\n\tif (bufferSize < components.Count())\n\t\treturn SPIRE_ERROR_INSUFFICIENT_BUFFER;\n\tint ptr = 0;\n\tfor (auto & comp : components)\n\t{\n\t\tbuffer[ptr].Name = comp.Name.Buffer();\n\t\tbuffer[ptr].TypeName = comp.TypeName.Buffer();\n\t\tbuffer[ptr].Alignment = (int)GetTypeAlignment(comp.Type.Ptr());\n\t\tbuffer[ptr].Size = (int)GetTypeSize(comp.Type.Ptr());\n\t\tbuffer[ptr].Offset = comp.Offset;\n\t\tptr++;\n\t}\n\treturn ptr;\n}\n\nSpireCompilationResult * spCompileShader(SpireCompilationContext * ctx, SpireShader * shader,\n\tSpireModule** args,\n\tint argCount,\n\tconst char * additionalSource,\n\tSpireDiagnosticSink* sink)\n{\n\t::CompileResult * rs = new ::CompileResult();\n\tCTX(ctx)->PushContext();\n\tCTX(ctx)->Compile(*rs, CTX(ctx)->states.Last(), *SHADER(shader), ArrayView<SpireModule*>(args, argCount), additionalSource, sink);\n\tCTX(ctx)->PopContext();\n\treturn reinterpret_cast<SpireCompilationResult*>(rs);\n}\n\nSPIRE_API SpireCompilationResult * spEnvCompileShader(SpireCompilationEnvironment * env, SpireShader * shader, SpireModule ** args, int argCount, const char * additionalSource, SpireDiagnosticSink * sink)\n{\n\t::CompileResult * rs = new ::CompileResult();\n\tenv->context->Compile(*rs, env->state, *SHADER(shader), ArrayView<SpireModule*>(args, argCount), additionalSource, sink);\n\treturn reinterpret_cast<SpireCompilationResult*>(rs);\n}\n\nSpireCompilationResult * spCompileShaderFromSource(SpireCompilationContext * ctx, const char * source, const char * fileName, SpireDiagnosticSink* sink)\n{\n\t::CompileResult * rs = new ::CompileResult();\n\tCTX(ctx)->PushContext();\n\tCTX(ctx)->Compile(*rs, CTX(ctx)->states.Last(), nullptr, source, fileName, sink);\n\tCTX(ctx)->PopContext();\n\treturn reinterpret_cast<SpireCompilationResult*>(rs);\n}\n\nint spDiagnosticSinkHasAnyErrors(SpireDiagnosticSink* sink)\n{\n\tif (!sink) return false;\n\treturn sink->errorCount != 0;\n}\n\nint spGetDiagnosticCount(SpireDiagnosticSink* sink)\n{\n\treturn sink->diagnostics.Count();\n}\n\nint spGetDiagnosticByIndex(SpireDiagnosticSink* sink, int index, SpireDiagnostic * outDiagnostic)\n{\n\tif (!sink)          return SPIRE_ERROR_INVALID_PARAMETER;\n\tif (!outDiagnostic) return SPIRE_ERROR_INVALID_PARAMETER;\n\tif (index < 0)      return SPIRE_ERROR_INVALID_PARAMETER;\n\n\tauto & diagnostics = sink->diagnostics;\n\tif (index >= diagnostics.Count())\n\t\treturn SPIRE_ERROR_INVALID_PARAMETER;\n\n\tauto & msg = diagnostics[index];\n\toutDiagnostic->Message = msg.Message.Buffer();\n\toutDiagnostic->ErrorId = msg.ErrorID;\n\toutDiagnostic->FileName = msg.Position.FileName.Buffer();\n\toutDiagnostic->Line = msg.Position.Line;\n\toutDiagnostic->Col = msg.Position.Col;\n\t// Note: we rely here on the `SpireSeverity` and `Spire::Compiler::Severity`\n\t// enums having the same members. Realistically, we should probably just\n\t// use the external enum internally too.\n\toutDiagnostic->severity = (SpireSeverity)msg.severity;\n\treturn 1;\n}\n\nint ReturnStr(const char * content, char * buffer, int bufferSize)\n{\n\tint len = (int)strlen(content);\n\tif (buffer)\n\t{\n\t\tif (bufferSize >= len + 1)\n\t\t{\n\t\t\tmemcpy(buffer, content, len + 1);\n\t\t\treturn len + 1;\n\t\t}\n\t\telse\n\t\t\treturn SPIRE_ERROR_INSUFFICIENT_BUFFER;\n\t}\n\telse\n\t\treturn len + 1;\n}\n\nint spGetDiagnosticOutput(SpireDiagnosticSink* sink, char * buffer, int bufferSize)\n{\n\tStringBuilder sb;\n\tfor (auto & x : sink->diagnostics)\n\t{\n\t\tsb << x.Position.ToString() << \": \" << Spire::Compiler::getSeverityName(x.severity);\n\t\tif (x.ErrorID >= 0)\n\t\t{\n\t\t\tsb << \" \" << x.ErrorID;\n\t\t}\n\t\tsb << \": \" << x.Message << \"\\n\";\n\t}\n\tauto str = sb.ProduceString();\n\treturn ReturnStr(str.Buffer(), buffer, bufferSize);\n}\n\nint spGetCompiledShaderNames(SpireCompilationResult * result, char * buffer, int bufferSize)\n{\n\tStringBuilder sb;\n\tauto rs = RS(result);\n\tbool first = true;\n\tfor (auto x : rs->Sources)\n\t{\n\t\tif (!first)\n\t\t\tsb << \"\\n\";\n\t\tsb << x.Key;\n\t\tfirst = false;\n\t}\n\tauto str = sb.ProduceString();\n\treturn ReturnStr(str.Buffer(), buffer, bufferSize);\n}\n\nint spGetCompiledShaderStageNames(SpireCompilationResult * result, const char * shaderName, char * buffer, int bufferSize)\n{\n\tauto rs = RS(result);\n\tif (auto src = rs->Sources.TryGetValue(shaderName))\n\t{\n\t\tStringBuilder sb;\n\t\tbool first = true;\n\t\tfor (auto x : src->Stages)\n\t\t{\n\t\t\tif (!first)\n\t\t\t\tsb << \"\\n\";\n\t\t\tsb << x.Key;\n\t\t\tfirst = false;\n\t\t}\n\t\tauto str = sb.ProduceString();\n\t\treturn ReturnStr(str.Buffer(), buffer, bufferSize);\n\t}\n\telse\n\t{\n\t\treturn SPIRE_ERROR_INVALID_PARAMETER;\n\t}\n}\n\nconst char * spGetShaderStageSource(SpireCompilationResult * result, const char * shaderName, const char * stage, int * length)\n{\n\tauto rs = RS(result);\n\tCompiledShaderSource * src = nullptr;\n\tif (shaderName == nullptr)\n\t{\n\t\tif (rs->Sources.Count())\n\t\t\tsrc = &rs->Sources.First().Value;\n\t}\n\telse\n\t{\n\t\tsrc = rs->Sources.TryGetValue(shaderName);\n\t}\n\tif (src)\n\t{\n\t\tif (auto state = src->Stages.TryGetValue(stage))\n\t\t{\n\t\t\tif (state->MainCode.Length())\n\t\t\t{\n\t\t\t\tif (length)\n\t\t\t\t\t*length = state->MainCode.Length() + 1;\n\t\t\t\treturn state->MainCode.Buffer();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (length)\n\t\t\t\t\t*length = state->BinaryCode.Count();\n\t\t\t\treturn (const char*)state->BinaryCode.Buffer();\n\t\t\t}\n\t\t}\n\t}\n\treturn nullptr;\n}\n\nint spGetShaderParameterSetCount(SpireCompilationResult * result, const char * shaderName)\n{\n\tauto rs = RS(result);\n\tList<SpireParameterSet> * list = nullptr;\n\tif (shaderName == nullptr)\n\t{\n\t\tif (rs->ParamSets.Count())\n\t\t\tlist = &rs->ParamSets.First().Value;\n\t}\n\telse\n\t{\n\t\tlist = rs->ParamSets.TryGetValue(shaderName);\n\t}\n\tif (list)\n\t{\n\t\treturn list->Count();\n\t}\n\treturn 0;\n}\nSpireParameterSet * spGetShaderParameterSet(SpireCompilationResult * result, const char * shaderName, int index)\n{\n\tauto rs = RS(result);\n\tList<SpireParameterSet> * sets = nullptr;\n\tif (shaderName == nullptr)\n\t{\n\t\tif (rs->ParamSets.Count())\n\t\t\tsets = &rs->ParamSets.First().Value;\n\t}\n\telse\n\t{\n\t\tsets = rs->ParamSets.TryGetValue(shaderName);\n\t}\n\tif (sets)\n\t{\n\t\treturn &(*sets)[index];\n\t}\n\treturn nullptr;\n}\nint spParameterSetGetBufferSize(SpireParameterSet * set)\n{\n\treturn set->paramSet->BufferSize;\n}\nint spParameterSetGetBufferOffset(SpireParameterSet * set)\n{\n\treturn set->paramSet->UniformBufferOffset;\n}\nint spParameterSetGetStartBindingIndex(SpireParameterSet * set, SpireBindingIndex * pIndexOut)\n{\n\tpIndexOut->texture = set->paramSet->TextureBindingStartIndex;\n\tpIndexOut->sampler = set->paramSet->SamplerBindingStartIndex;\n\tpIndexOut->storageBuffer = set->paramSet->StorageBufferBindingStartIndex;\n\tpIndexOut->uniformBuffer = set->paramSet->UniformBindingStartIndex;\n\treturn 0;\n}\nint spParameterSetGetUniformField(SpireParameterSet * set, int index, SpireUniformField * pUniformLayout)\n{\n\tpUniformLayout->name = set->uniforms[index].name.Buffer();\n\tpUniformLayout->type = set->uniforms[index].type.Buffer();\n\tpUniformLayout->offset = set->uniforms[index].offset;\n\tpUniformLayout->size = set->uniforms[index].size;\n\treturn 0;\n}\nint spParameterSetGetUniformFieldCount(SpireParameterSet * set)\n{\n\treturn set->uniforms.Count();\n}\nint spParameterSetGetSubSetCount(SpireParameterSet * set)\n{\n\treturn set->subsets.Count();\n}\nSpireParameterSet * spParameterSetGetSubSet(SpireParameterSet * set, int index)\n{\n\treturn &set->subsets[index];\n}\nconst char * spParameterSetGetBindingName(SpireParameterSet * set)\n{\n\treturn set->paramSet->BindingName.Buffer();\n}\nint spParameterSetGetBindingIndex(SpireParameterSet * set)\n{\n\treturn set->paramSet->DescriptorSetId;\n}\nint spParameterSetGetUniformBufferLegacyBindingPoint(SpireParameterSet * set)\n{\n\treturn set->paramSet->UniformBufferLegacyBindingPoint;\n}\nint spParameterSetGetBindingSlotCount(SpireParameterSet * set)\n{\n\treturn set->bindings.Count();\n}\nSpireResourceBindingInfo * spParameterSetGetBindingSlot(SpireParameterSet * set, int index)\n{\n\treturn &set->bindings[index];\n}\nvoid spDestroyCompilationResult(SpireCompilationResult * result)\n{\n\tdelete RS(result);\n}\n"
  },
  {
    "path": "Source/SpireLib/SpireLib.h",
    "content": "#ifndef LIB_BAKER_SL_H\n#define LIB_BAKER_SL_H\n\n#include \"../CoreLib/Basic.h\"\n#include \"../CoreLib/Tokenizer.h\"\n#include \"../SpireCore/ShaderCompiler.h\"\n\nnamespace SpireLib\n{\n\tclass ShaderLibFile : public CoreLib::Basic::Object\n\t{\n\tpublic:\n\t\tCoreLib::Basic::EnumerableDictionary<CoreLib::Basic::String, Spire::Compiler::StageSource> Sources; // indexed by world\n\t\tSpire::Compiler::ShaderMetaData MetaData;\n\t\tvoid AddSource(CoreLib::Basic::String source, CoreLib::Text::TokenReader & parser);\n\t\tvoid FromString(const CoreLib::String & str);\n\t\tCoreLib::String ToString();\n\t\tvoid SaveToFile(CoreLib::Basic::String fileName);\n\t\tShaderLibFile() = default;\n\t\tvoid Clear();\n\t\tvoid Load(CoreLib::Basic::String fileName);\n\t};\n\t\n\tCoreLib::Basic::List<ShaderLibFile> CompileShaderSourceFromFile(Spire::Compiler::CompileResult & result,\n\t\tconst CoreLib::Basic::String & sourceFileName,\n\t\tSpire::Compiler::CompileOptions &options);\n\n\tCoreLib::Basic::List<ShaderLibFile> CompileShaderSource(Spire::Compiler::CompileResult & result,\n\t\tconst CoreLib::Basic::String &source, const CoreLib::Basic::String & sourceFileName, Spire::Compiler::CompileOptions &options);\n\n\tclass ShaderLib : public ShaderLibFile\n\t{\n\tpublic:\n\t\tSpire::Compiler::StageSource GetStageSource(CoreLib::Basic::String world);\n\t\tShaderLib() = default;\n\t\tShaderLib(CoreLib::Basic::String fileName);\n\t\tvoid Reload(CoreLib::Basic::String fileName);\n\t\tbool CompileFrom(CoreLib::Basic::String symbolName, CoreLib::Basic::String sourceFileName, CoreLib::Basic::String schedule);\n\t};\n\n}\n\n#endif"
  },
  {
    "path": "Source/SpireLib/SpireLib.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugClang|Win32\">\n      <Configuration>DebugClang</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugClang|x64\">\n      <Configuration>DebugClang</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug_VS2013|Win32\">\n      <Configuration>Debug_VS2013</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug_VS2013|x64\">\n      <Configuration>Debug_VS2013</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release_VS2013|Win32\">\n      <Configuration>Release_VS2013</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release_VS2013|x64\">\n      <Configuration>Release_VS2013</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{1168C449-66A5-4D23-80E2-2C1A07E58F83}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>SpireLib</RootNamespace>\n    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\n    <ProjectName>SpireLib</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140_clang_3_7</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140_Clang_3_7</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup />\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>../;</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>../;</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>EnableAllWarnings</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>../;</AdditionalIncludeDirectories>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <RuntimeTypeInfo>true</RuntimeTypeInfo>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;</AdditionalIncludeDirectories>\n      <GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugClang|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;</AdditionalIncludeDirectories>\n      <GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <AdditionalIncludeDirectories>../;</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\..\\Spire.h\" />\n    <ClInclude Include=\"..\\..\\SpireAllSource.h\" />\n    <ClInclude Include=\"SpireLib.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"SpireLib.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\CoreLib\\CoreLibBasic.vcxproj\">\n      <Project>{f9be7957-8399-899e-0c49-e714fddd4b65}</Project>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\SpireCore\\SpireCore.vcxproj\">\n      <Project>{db00da62-0533-4afd-b59f-a67d5b3a0808}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>\n"
  },
  {
    "path": "Source/SpireLib/SpireLib.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"SpireLib.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\Spire.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\..\\SpireAllSource.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"SpireLib.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Spire.h",
    "content": "#ifndef SPIRE_H\n#define SPIRE_H\n\n#ifdef _MSC_VER\n#ifdef SPIRE_COMPILING_DLL\n#define SPIRE_API __declspec(dllexport)\n#else\n#ifdef SPIRE_DYNAMIC\n#define SPIRE_API __declspec(dllimport)\n#else\n#define SPIRE_API\n#endif\n#endif\n#else\n#define SPIRE_API\n#endif\n\n#ifdef __cplusplus  \nextern \"C\"\n{\n#endif\n\t/*!\n\t@mainpage Introduction\n\tSpire is a shading language and compiler framework that facilitates modular shader authoring and rapid exploration of\n\tshader optimization choices (such as frequency reduction and algorithmic approximation) afforded by modern real-time\n\tgraphics engines. The current implementation of the Spire compiler can generate either GLSL or SPIR-V output for use\n\twith OpenGL and Vulkan based engines.\n\n\tPaper: http://graphics.cs.cmu.edu/projects/spire/\n\n\n\tAPI Reference: Spire.h\n\n\t@file Spire.h\n\t*/\n\n\t/*!\n\t@brief Severity of a diagnostic generated by the compiler.\n\tValues come from the enum below, with higher values representing more severe\n\tconditions, and all values >= SPIRE_SEVERITY_ERROR indicating compilation\n\tfailure.\n\t*/\n\ttypedef int SpireSeverity;\n\tenum\n\t{\n\t\tSPIRE_SEVERITY_NOTE = 0,    /**< An informative message. */\n\t\tSPIRE_SEVERITY_WARNING,     /**< A warning, which indicates a possible proble. */\n\t\tSPIRE_SEVERITY_ERROR,       /**< An error, indicating that compilation failed. */\n\t\tSPIRE_SEVERITY_FATAL,       /**< An unrecoverable error, which forced compilation to abort. */\n\t\tSPIRE_SEVERITY_INTERNAL,    /**< An internal error, indicating a logic error in the compiler. */\n\t};\n\n\ttypedef int SpireBindableResourceType;\n\tenum\n\t{\n\t\tSPIRE_NON_BINDABLE = 0,\n\t\tSPIRE_TEXTURE,\n\t\tSPIRE_SAMPLER,\n\t\tSPIRE_UNIFORM_BUFFER,\n\t\tSPIRE_STORAGE_BUFFER,\n\t};\n\n\tenum\n\t{\n\t\tSPIRE_GLSL = 0,\n\t\tSPIRE_GLSL_VULKAN,\n\t\tSPIRE_GLSL_VULKAN_ONE_DESC,\n\t\tSPIRE_HLSL,\n\t\tSPIRE_SPIRV\n\t};\n\n//#define SPIRE_LAYOUT_UNIFORM 0\n//#define SPIRE_LAYOUT_PACKED 1\n//#define SPIRE_LAYOUT_STORAGE 2\n\n#define SPIRE_ERROR_INSUFFICIENT_BUFFER -1\n#define SPIRE_ERROR_INVALID_PARAMETER -2\n\n\t/*!\n\t@brief Represents a compilation context. Created by spCreateCompilationContext().\n\n\tRelated Functions\n\t- spCreateCompilationContext()\n\t- spDestroyCompilationContext()\n\t- spCreateShaderFromSource()\n\t- spCreateShaderFromFile()\n\t- spCompileShader()\n\t- spSetCodeGenTarget()\n\t- spAddSearchPath()\n\t- spSetBackendParameter()\n\t*/\n\tstruct SpireCompilationContext {};\n\tstruct SpireCompilationEnvironment;\n\n\t/*!\n\t@brief Represents a shader. A SpireShader can be created by calling spCreateShaderFromSource(), or by loading a module library via spLoadModuleLibrary()\n\n\tRelated Functions\n\t- spShaderGetName()\n\t- spCompileShader()\n\t- spShaderGetParameterType()\n\t- spShaderGetParameterName()\n\t- spShaderGetParameterBinding()\n\t*/\n\tstruct SpireShader {};\n\n\t/*!\n\t@brief SpireModule objects provide reflection data about a module.\n\tModule objects can be obtained by calling spFindModule() once a module library is loaded via spLoadModuleLibrary().\n\n\tRelated Functions\n\t- spLoadModuleLibrary()\n\t- spLoadModuleLibraryFromSource()\n\t- spFindModule()\n\t- spSpecializeModule()\n\t- spModuleGetParameterCount()\n\t- spModuleGetParameter()\n\t- spModuleGetParameterBufferSize()\n\t- spModuleGetRequiredComponents()\n\t*/\n\tstruct SpireModule;\n\n\t/*!\n\t@brief Represents the compilation result, including error messages and compiled source code for each stage.\n\n\tRelated Functions\n\t- spCompileShader()\n\t- spCompileShaderFromSource()\n\t- spIsCompilationSucessful()\n\t- spGetCompilerOutput()\n\t- spGetDiagnosticCount()\n\t- spGetDiagnosticByIndex()\n\t- spGetCompiledShaderNames()\n\t- spGetCompiledShaderStageNames()\n\t- spGetShaderStageSource()\n\t- spDestroyCompilationResult()\n\t*/\n\tstruct SpireCompilationResult {};\n\n\tstruct SpireBindingIndex\n\t{\n\t\tint texture = 0;\n\t\tint sampler = 0;\n\t\tint storageBuffer = 0;\n\t\tint uniformBuffer = 0;\n\t\tint general = 0;\n\t};\n\n\tstruct SpireUniformField\n\t{\n\t\tint offset;\n\t\tint size;\n\t\tconst char * name;\n\t\tconst char * type;\n\t};\n\n    /*!\n    @brief A collection of diagnostic messages output by the compiler.\n    */\n    typedef struct SpireDiagnosticSink SpireDiagnosticSink;\n\n\t/*!\n\t@brief Represents a diagnostic message from the compiler.\n\t*/\n\tstruct SpireDiagnostic\n\t{\n\t\tconst char * Message;    /**< Content of the message. Storage is owned by SpireCompilationContext.*/\n        SpireSeverity severity;  /**< Severity of the diagnostic.*/\n\t\tint ErrorId;             /**< A unique identifier for this type of error.*/\n\t\tconst char * FileName;   /**< The source file name of this error. Storage is owned by SpireCompilationContext*/\n\t\tint Line;                /**< The line number of this error.*/\n\t\tint Col;                 /**< The column position of this error.*/\n\t};\n\n\t/*!\n\t@brief Stores description of a component.\n\t*/\n\tstruct SpireComponentInfo\n\t{\n\t\tconst char * Name;         /**< The name of the component. Storage is owned by SpireCompilationContext.*/\n\t\tconst char * TypeName;     /**< The type name of the component. Storage is owned by SpireCompilationContext.*/\n\t\tSpireBindableResourceType BindableResourceType; /**< The type of bindable resource this component represents.*/\n\t\tint Size;                  /**< The size (in bytes) of the component. For opaque types (e.g. sampler and texture), this value is 0.*/\n\t\tint Alignment;             /**< The alignment (in bytes) of the component. For opaque types (e.g. sampler and texture), this value is 0.*/\n\t\tint Offset;\t\t\t\t   /**< The offset (in bytes) of the component. For opaque types (e.g. sampler and texture), this value is 0.*/\n\t\tbool Specialize;\t\t   /**< Indicating whether this is a specialization parameter.*/\n\t};\n\n\t/*!\n\t@brief Represents a parameter set.\n\t*/\n\ttypedef struct SpireParameterSet SpireParameterSet;\n\n\t/*!\n\t@brief Represents information on a binding slot of a parameter set.\n\t*/\n\tstruct SpireResourceBindingInfo\n\t{\n\t\tSpireBindableResourceType Type; /**< The type of this binding slot. */\n\t\tint NumLegacyBindingPoints;     /**< The number of legacy binding points. */\n\t\tint * LegacyBindingPoints;      /**< The legacy binding points. Storage is owned by SpireCompilationResult.*/\n\t\tconst char * Name;              /**< The shader code name of this resource. Storage is owned by SpireCompilationResult.*/\n\t};\n\n\t/*!\n\t@brief Create a compilation context.\n\t@param cacheDir The directory used to store cached compilation results. Pass NULL to disable caching.\n\t@return A new compilation context.\n\t*/\n\tSPIRE_API SpireCompilationContext * spCreateCompilationContext(const char * cacheDir);\n\n\t/*!\n\t@brief Sets the target for code generation.\n\t@param ctx The compilation context.\n\t@param target The code generation target. Possible values are:\n\t- SPIRE_GLSL. Generates GLSL code.\n\t- SPIRE_HLSL. Generates HLSL code.\n\t- SPIRE_SPIRV. Generates SPIR-V code.\n\t*/\n\tSPIRE_API void spSetCodeGenTarget(SpireCompilationContext * ctx, int target);\n\n\t/*!\n\t@brief Add a path in which source files are being search. When the programmer specifies @code using <file_name> @endcode in code, the compiler searches the file\n\tin all search pathes in order.\n\t@param ctx The compilation context.\n\t@param searchDir The additional search directory.\n\t*/\n\tSPIRE_API void spAddSearchPath(SpireCompilationContext * ctx, const char * searchDir);\n\n\t/*!\n\t@brief Add a macro definition to be used during preprocessing.\n\t@param key The name of the macro to define.\n\t@param value The value of the macro to define.\n\t*/\n    SPIRE_API void spAddPreprocessorDefine(SpireCompilationContext * ctx, const char * key, const char * value);\n\n\t/*!\n\t@brief Sets a parameter used by the compiler back-end.\n\t@param ctx The compilation context.\n\t@param paramName The name of the parameter.\n\t@param value The value of the parameter.\n\t*/\n\tSPIRE_API void spSetBackendParameter(SpireCompilationContext * ctx, const char * paramName, const char * value);\n\n\t/*!\n\t@brief Sets a shader to compile. By default, the compiler will generate code for all shaders in current context. After setting this option,\n\tthe compiler will only generate code for the specified shader.\n\t@param ctx The compilation context.\n\t@param shaderName The name of the shader to compile.\n\t*/\n\tSPIRE_API void spSetShaderToCompile(SpireCompilationContext * ctx, const char * shaderName);\n\n\t/*!\n\t@brief Destorys the compilation context. Destorying a compilation context will free the memory for all strings owned by the\n\tSpireComilationContext and all SpireModule objects. These objects will not be available after a call to spDestroyCompilationContext.\n\tHowever, all SpireCompilationResult objects will continue to be available until they are destroyed.\n\t@param ctx The compilation context to destroy.\n\t*/\n\tSPIRE_API void spDestroyCompilationContext(SpireCompilationContext * ctx);\n\n    /*!\n    @brief Create a sink for diagnostic messages.\n    This sink can be used to capture diagnostic output from compilation operations, and\n    can then be used to iterate over the diagnostics produced.\n    @param ctx The compilation context.\n    */\n    SPIRE_API SpireDiagnosticSink* spCreateDiagnosticSink(SpireCompilationContext * ctx);\n\n    /*!\n    @brief Reset a diagnostic sink to its original state.\n    This clears out any diagnostic messages that have been written to the sink.\n    Re-using a single sink across multiple operations may be more efficeint than\n    creating and destroying a sink every time.\n    @param sink The diagnostic sink to reset.\n    */\n    SPIRE_API void spClearDiagnosticSink(SpireDiagnosticSink* sink);\n\n    /*!\n    @brief Destroy a diagnostic sink.\n    @param sink The diagnostic sink to destroy.\n    */\n    SPIRE_API void spDestroyDiagnosticSink(SpireDiagnosticSink* sink);\n\n\t/*!\n\t@brief Load and precompile spire modules from spire source file. Compilation status and error messages can be obtained via spIsCompilationSucessful(),\n\tspGetDiagnosticCount() and spGetDiagnosticByIndex() functions.\n\t@param ctx The compilation context.\n\t@param fileName The filename of the spire source code.\n    @param sink The sink where diagnostic output should be sent, or NULL to ignore messages.\n\t*/\n\tSPIRE_API void spLoadModuleLibrary(SpireCompilationContext * ctx, const char * fileName, SpireDiagnosticSink* sink);\n\tSPIRE_API void spEnvLoadModuleLibrary(SpireCompilationEnvironment * env, const char * fileName, SpireDiagnosticSink* sink);\n\n\t/*!\n\t@brief Load and precompile spire modules from spire source code in memory. Compilation status and error messages can be obtained via spIsCompilationSucessful(),\n\tspGetDiagnosticCount() and spGetDiagnosticByIndex() functions.\n\t@param ctx The compilation context.\n\t@param source The spire source code to precompile. All strings should be in UTF-8 encoding.\n\t@param fileName The filename used to report error messages regarding to code in @p source.\n    @param sink The sink where diagnostic output should be sent, or NULL to ignore messages.\n\t*/\n\tSPIRE_API void spLoadModuleLibraryFromSource(SpireCompilationContext * ctx, const char * source, const char * fileName, SpireDiagnosticSink* sink);\n\tSPIRE_API void spEnvLoadModuleLibraryFromSource(SpireCompilationEnvironment * env, const char * source, const char * fileName, SpireDiagnosticSink* sink);\n\n\n\t/*!\n\t@brief Store current compilation context to a stack. spLoadModuleLibrary() and spLoadModuleLibraryFromSource() load new symbols to\n\t       a compilation context. spPushContext() and spPopContext() can be used to save and restore context state.\n\t@param ctx The compilation context whose state to store.\n\t*/\n\tvoid spPushContext(SpireCompilationContext * ctx);\n\t/*!\n\t@brief Restore current compilation context to a previously saved state. spLoadModuleLibrary() and spLoadModuleLibraryFromSource() load new symbols to\n\t\t   a compilation context. spPushContext() and spPopContext() can be used to save and restore context state.\n\t@param ctx The compilation context whose state to restore.\n\t*/\n\tvoid spPopContext(SpireCompilationContext * ctx);\n\n\tSPIRE_API SpireCompilationEnvironment * spGetCurrentEnvironment(SpireCompilationContext * ctx);\n\tSPIRE_API SpireCompilationEnvironment * spCreateEnvironment(SpireCompilationContext * ctx, SpireCompilationEnvironment * forkOrigin);\n\tSPIRE_API void spReleaseEnvironment(SpireCompilationEnvironment* env);\n\n\t/*!\n\t@brief Create a template shader object from Spire source code. This is equivalent to calling spLoadModuleLibrary() and spGetShader().\n\t@param ctx The compilation context.\n\t@param name The source code of the shader.\n\t*/\n\tSPIRE_API SpireShader* spCreateShaderFromSource(SpireCompilationContext * ctx, const char * source, SpireDiagnosticSink * sink);\n\tSPIRE_API SpireShader* spEnvCreateShaderFromSource(SpireCompilationEnvironment * env, const char * source, SpireDiagnosticSink * sink);\n\n\t/*!\n\t@brief Create a template shader object from a Spire source file.\n\t@param ctx The compilation context.\n\t@param name The source code of the shader.\n\t*/\n\tSPIRE_API SpireShader* spCreateShaderFromFile(SpireCompilationContext * ctx, const char * fileName, SpireDiagnosticSink * sink);\n\tSPIRE_API SpireShader* spEnvCreateShaderFromFile(SpireCompilationEnvironment * env, const char * fileName, SpireDiagnosticSink * sink);\n\n\t/*!\n\t@brief Find a template shader from current context.\n\t@param ctx The compilation context in which to find shaders.\n\t@param name The name of the shader object to find.\n\t@return A handle to the template shader object that can be used for code generation and reflection. NULL if the shader with specified name does not exist.\n\t*/\n\tSPIRE_API SpireShader* spFindShader(SpireCompilationContext * ctx, const char * name);\n\tSPIRE_API SpireShader* spEnvFindShader(SpireCompilationEnvironment * env, const char * name);\n\n\t/*!\n\t@brief Returns the total number of entry point shaders in current compilation context.\n\t@param ctx The compilation context.\n\t*/\n\tSPIRE_API int spGetShaderCount(SpireCompilationContext * ctx);\n\tSPIRE_API int spEnvGetShaderCount(SpireCompilationEnvironment * env);\n\n\t/*!\n\t@brief Retrieves the handle to the specified shader object.\n\t@param ctx The compilation context in which to retrieve shaders.\n\t@param name The index of the shader object to retrieve.\n\t@return A handle to the template shader object that can be used for code generation and reflection. NULL if the shader at specified index does not exist.\n\t*/\n\tSPIRE_API SpireShader* spGetShader(SpireCompilationContext * ctx, int index);\n\tSPIRE_API SpireShader* spEnvGetShader(SpireCompilationEnvironment * ctx, int index);\n\t\n\t/*!\n\t@brief Retrieves the runtime unique Id of a shader.\n\t@param shader The shader object whose Id to retrieve.\n\t@return Id of the shader object.\n\t*/\n\tSPIRE_API unsigned int spShaderGetId(SpireShader * shader);\n\n\t/*!\n\t@brief Retrieves the name of a shader.\n\t@param shader The shader object whose name to retrieve.\n\t@return Name of the shader object.\n\t*/\n\tSPIRE_API const char * spShaderGetName(SpireShader * shader);\n\n\tSPIRE_API const char * spShaderGetParameterType(SpireShader * shader, int i);\n\tSPIRE_API const char * spShaderGetParameterName(SpireShader * shader, int i);\n\n\tSPIRE_API int spShaderGetParameterBinding(SpireShader * shader, int i);\n\tSPIRE_API int spShaderGetParameterCount(SpireShader * shader);\n\n\t/*!\n\t@brief Find a precompiled module in a SpireCompilationContext.\n\t@param ctx The compilation context.\n\t@param moduleName The name of the module to find.\n\t@return If a module with the specified name exists in the current context, a handle to the module is returned. Otherwise, the return value is NULL.\n\t@note All SpireModule objects are destroyed when its containing SpireCompilationContext is destroyed.\n\t*/\n\tSPIRE_API SpireModule * spFindModule(SpireCompilationContext * ctx, const char * moduleName);\n\tSPIRE_API SpireModule * spEnvFindModule(SpireCompilationEnvironment * env, const char * moduleName);\n\n\t\n\t/*!\n\t@brief Retrieve the run-time unique Id of a SpireModule.\n\t@param module The module to get the unique Id of.\n\t@return The unique Id of the module.\n\t*/\n\tSPIRE_API unsigned int spGetModuleUID(SpireModule * module);\n\n\t/*!\n\t@brief Retrieve the name of a SpireModule.\n\t@param module The module to get the name of.\n\t@return The name of the module as a null-terminated string, or NULL if ther are any errors.\n\t@note The memory for the return value will be freed when the containing SpireCopmilationContext is destroyed.\n\t*/\n\tSPIRE_API const char * spGetModuleName(SpireModule * module);\n\t\n\t/*!\n\t@brief Create a specialized module from an existing module.\n\t@param ctx A spire compilation context used to hold the specialized module.\n\t@param module The module to create specialization from.\n\t@param paramValues The values of specialization parameters.\n\t@param numParams Number of entries in @p paramValues array.\n\t@param sink [Optional] A SpireDiagnosticSink object used to receive error messages.\n\t@return If succesfull, this function returns the specialized module; otherwise the return value is NULL.\n\t@note The memory for the returning SpireModule will be freed when the @p ctx is destroyed, or when the current context is poped via spPopContext(). \n\t*/\n\tSPIRE_API SpireModule * spSpecializeModule(SpireCompilationContext * ctx, SpireModule * module, int * paramValues, int numParams, SpireDiagnosticSink * sink);\n\n\t/*!\n\t@brief Retrieves number of parameters defined by a module.\n\t@param module The module from which to retrieve parameters.\n\t@return Number of parameters defined in @p module.\n\t*/\n\tSPIRE_API int spModuleGetParameterCount(SpireModule * module);\n\n\t/*!\n\t@brief Retrieves buffer size required to hold all parameters defined by a module.\n\t@param module The module from which to retrieve parameter buffer size information.\n\t@return Number of bytes required to store all parameters defined by @p module.\n\t*/\n\tSPIRE_API int spModuleGetParameterBufferSize(SpireModule * module);\n\n\t/*!\n\t@brief Returns whether a module has defined an attribute with specified name.\n\t@param module The module from which to query attribute definition.\n\t@param componentName The name of the attribute to test existence of.\n\t@return 1 if the component is defined, 0 otherwise.\n\t*/\n\tSPIRE_API int spModuleHasAttrib(SpireModule * module, const char * attribName);\n\n\t/*!\n\t@brief Retrieves parameter info from a SpireModule.\n\t@param module The module from which to retrieve parameters.\n\t@param index Index of the requesting parameter.\n\t@param result A pointer to a SpireComponentInfo structure used to receive info on the specified parameter.\n\t@return\n\tIf successful, this function returns 0. \n\tOtherwise, the return value is one of the following error codes:\n\t- SPIRE_ERROR_INVALID_PARAMETER if any of the parameters are invalid.\n\t*/\n\tSPIRE_API int spModuleGetParameter(SpireModule * module, int index, SpireComponentInfo * result);\n\tSPIRE_API int spModuleGetParameterByName(SpireModule * module, const char * name, SpireComponentInfo * result);\n\tSPIRE_API int spModuleGetSubModuleCount(SpireModule * module);\n\tSPIRE_API SpireModule * spModuleGetSubModule(SpireModule * module, int index);\n\tSPIRE_API int spModuleGetBufferOffset(SpireModule * module);\n\tSPIRE_API int spModuleGetBindingOffset(SpireModule * module, SpireBindingIndex * pIndexOut);\n\t\n\t/*!\n\t@brief Retrieve a list of components that are required by the specified module.\n\t@param module The module from where to retrieve components.\n\t@param buffer A user allocated buffer of SpireComponentInfo for receiving outputs.\n\t@param bufferSize The size (in number of SpireComponentInfo structs) of the specified buffer.\n\t@return\n\tIf @p buffer is NULL, the return value is the required size, in number of SpireComponentInfo.\n\tOtherwise, if the function suceeds, the return value is the number of SpireComponentInfo instances written to\n\t@p buffer. The function returns a negative value if it does not suceed. Possible error codes are:\n\t- SPIRE_ERROR_INSUFFICIENT_BUFFER. The supplied buffer size was not large enough.\n\t- SPIRE_ERROR_INVALID_PARAMETER. Any of the parameter values was invalid.\n\t*/\n\tSPIRE_API int spModuleGetRequiredComponents(SpireModule * module, SpireComponentInfo * buffer, int bufferSize);\n\n\t/*!\n\t@brief Compiles a shader object.\n\t@param ctx A shader compilation context.\n\t@param shader The shader object to compile.\n\t@param args The modules used as template shader arguments.\n\t@param argCount The number of elements in @p args array.\n\t@param additionalSource Additional source code to append before passing to compiler.\n    @param sink The sink where diagnostic output should be sent, or NULL to ignore messages.\n\t@return The return value is a handle to a SpireCompilationResult object that contains error messages and compiled source code.\n\t@note You are responsible for destorying a SpireCompilationResult object when it is no longer used. Destroying a SpireCompilationContext\n\tdoes not automatically destroy SpireCompilationResult objects.\n\t*/\n\tSPIRE_API SpireCompilationResult* spCompileShader(SpireCompilationContext * ctx, \n\t\tSpireShader * shader, \n\t\tSpireModule** args, \n\t\tint argCount,\n\t\tconst char * additionalSource,\n\t\tSpireDiagnosticSink* sink);\n\n\tSPIRE_API SpireCompilationResult* spEnvCompileShader(SpireCompilationEnvironment * env,\n\t\tSpireShader * shader,\n\t\tSpireModule** args,\n\t\tint argCount,\n\t\tconst char * additionalSource,\n\t\tSpireDiagnosticSink* sink);\n\n\t/*!\n\t@brief Compiles a shader object.\n\t@param ctx A shader compilation context.\n\t@param source A string that represents the Spire source code that defines a shader.\n\t@param fileName The filename to use to report error messages regarding to @p source.\n    @param sink The sink where diagnostic output should be sent, or NULL to ignore messages.\n\t@return The return value is a handle to a SpireCompilationResult object that contains error messages and compiled source code.\n\t@note You are responsible for destorying a SpireCompilationResult object when it is no longer used. Destroying a SpireCompilationContext\n\tdoes not automatically destroy SpireCompilationResult objects.\n\t@see spDestroyCompilationResult()\n\t*/\n\tSPIRE_API SpireCompilationResult* spCompileShaderFromSource(SpireCompilationContext * ctx, \n\t\tconst char * source, \n\t\tconst char * fileName,\n\t\tSpireDiagnosticSink* sink);  /*deprecated*/\n\n\t/*!\n\t@brief Checks if any errors have been output to the diagnostic sink.\n    @param sink The SpireDiagnosticSink to be checked.\n    @return 1 if any errors have been output, 0 otherwise.\n\t*/\n\tSPIRE_API int spDiagnosticSinkHasAnyErrors(SpireDiagnosticSink* sink);\n\n\t/*!\n\t@brief Retrieve the number of compiler diagnostics in a SpireCompilationResult object.\n\t@param result A SpireCompilationResult object.\n\t@return The number of diagnostics available.\n\t*/\n\tSPIRE_API int spGetDiagnosticCount(SpireDiagnosticSink* sink);\n\n\t/*!\n\t@brief Retrieve the content of compiler diagnostics in a SpireCompilationResult object.\n\t@param result A SpireCompilationResult object.\n\t@param index The index of the compiler diagnostic to retrieve.\n\t@param pMsg A pointer to a SpireDiagnostic structure to receive the diagnostic.\n\t@return 1 if successful. SPIRE_ERROR_INVALID_PARAMETER if any of the parameters is invalid.\n\t*/\n\tSPIRE_API int spGetDiagnosticByIndex(SpireDiagnosticSink* sink, int index, SpireDiagnostic * pMsg);\n\n\t/*!\n\t@brief Get compiler output messages as a single string.\n\t@param result A SpireCompilationResult object.\n\t@param buffer The buffer used to receive compiler messages. If this parameter is NULL, the function returns the number of bytes required for the buffer.\n\t@param bufferSize The size of @p buffer (in bytes).\n\t@return\n\t\tIf successful, the return value is the number of bytes written to @p buffer. If @p buffer is NULL, the return value is the number of bytes required for @p buffer\n\t\tto store the entire output message. Otherwise, the function returns one of the following error codes:\n\t\t- SPIRE_ERROR_INSUFFICIENT_BUFFER. if @p bufferSize is smaller than required buffer size.\n\t\t- SPIRE_ERROR_INVALID_PARAMETER. if any of the parameters is invalid.\n\t*/\n\tSPIRE_API int spGetDiagnosticOutput(SpireDiagnosticSink* sink, char * buffer, int bufferSize);\n\n\t/*!\n\t@brief Retrieve a list of shader names that has been compiled.\n\t@param result A SpireCompilationResult object.\n\t@param buffer A buffer used to receive shader names. Shader names are separated by '\\\\n'. If this parameter is NULL, the function returns the required buffer size.\n\t@param bufferSize The size (in bytes) of @p buffer.\n\t@return If sucessful, the return value is greater or equal to 0 representing the number of charaters required or written to buffer, including the trailing 0.\n\tOtherwise, it returns one of the following error codes:\n\t- SPIRE_ERROR_INSUFFICIENT_BUFFER. The supplied buffer size was not large enough.\n\t- SPIRE_ERROR_INVALID_PARAMETER. Any of the parameter values was invalid.\n\t*/\n\tSPIRE_API int spGetCompiledShaderNames(SpireCompilationResult * result, char * buffer, int bufferSize);\n\n\t/*!\n\t@brief Retrieve a list of stage names in a compiled shader.\n\t@param result A SpireCompilationResult object.\n\t@param shaderName The name of a shader.\n\t@param buffer A buffer used to receive stage names. Stage names are separated by '\\\\n'. If this parameter is NULL, the function returns the required buffer size.\n\t@param bufferSize The size (in bytes) of @p buffer.\n\t@return If sucessful, the return value is greater or equal to 0 representing the number of charaters required or written to buffer, including the trailing 0.\n\tOtherwise, it returns one of the following error codes:\n\t- SPIRE_ERROR_INSUFFICIENT_BUFFER. The supplied buffer size was not large enough.\n\t- SPIRE_ERROR_INVALID_PARAMETER. Any of the parameter values was invalid.\n\t*/\n\tSPIRE_API int spGetCompiledShaderStageNames(SpireCompilationResult * result, const char * shaderName, char * buffer, int bufferSize);\n\n\t/*!\n\t@brief Retrieve the compiled code (binary or textual, depending on the target language) of a stage in a compiled shader.\n\t@param result A SpireCompilationResult object.\n\t@param shaderName The name of a shader. If @p shaderName is NULL, the function returns the source code of the first shader in @p result.\n\t@param stage The name of a stage.\n\t@param[out] length A pointer used to receive the length of the compiled code, can be set to NULL.\n\t@return If sucessful, the return value is a pointer to the buffer storing the compiled code. Otherwise, the return value is NULL.\n\t@note The backing memory of the returned code buffer is owned by the SpireCompilationResult object. Destroying the SpireCompilationResult object will render this code\n\tbuffer unusable.\n\t*/\n\tSPIRE_API const char * spGetShaderStageSource(SpireCompilationResult * result, const char * shaderName, const char * stage, int * length);\n\n\t/*!\n\t@brief Retrieve the number of parameter sets defined by a compiled shader.\n\t@param result A SpireCompilationResult object, as a result of shader compilation.\n\t@param shaderName The name of a shader. If @p shaderName is NULL, the function returns the source code of the first shader in @p result.\n\t@return The number of parameter sets in specified shader.\n\t*/\n\tSPIRE_API int spGetShaderParameterSetCount(SpireCompilationResult * result, const char * shaderName);\n\n\t/*!\n\t@brief Retrieve a SpireParameterSet object representing a parameter set defined by a compiled shader.\n\t@param result A SpireCompilationResult object, as a result of shader compilation.\n\t@param shaderName The name of a shader. If @p shaderName is NULL, the function returns the source code of the first shader in @p result.\n\t@param index The index of the parameter set to return\n\t@return A SpireParameterSet object representing the requested parameter set. The life-time of the returned object is owned by @p result.\n\t*/\n\tSPIRE_API SpireParameterSet * spGetShaderParameterSet(SpireCompilationResult * result, const char * shaderName, int index);\n\n\t/*!\n\t@brief Get the required uniform buffer size of a SpireParameterSet object.\n\t@param set A SpireParameterSet object whose uniform buffer size to get.\n\t@return Required uniform buffer size.\n\t*/\n\tSPIRE_API int spParameterSetGetBufferSize(SpireParameterSet * set);\n\n\t/*!\n\t@brief Get the uniform buffer offset of a SpireParameterSet object.\n\t@param set A SpireParameterSet object whose uniform buffer offset to get.\n\t@return uniform buffer offset.\n\t*/\n\tSPIRE_API int spParameterSetGetBufferOffset(SpireParameterSet * set);\n\n\t/*!\n\t@brief Get the uniform buffer offset of a SpireParameterSet object.\n\t@param set A SpireParameterSet object whose uniform buffer offset to get.\n\t@return uniform buffer offset.\n\t*/\n\tSPIRE_API int spParameterSetGetStartBindingIndex(SpireParameterSet * set, SpireBindingIndex * pIndexOut);\n\n\tSPIRE_API int spParameterSetGetUniformField(SpireParameterSet * set, int index, SpireUniformField * pUniformLayout);\n\tSPIRE_API int spParameterSetGetUniformFieldCount(SpireParameterSet * set);\n\n\tSPIRE_API int spParameterSetGetSubSetCount(SpireParameterSet * set);\n\tSPIRE_API SpireParameterSet* spParameterSetGetSubSet(SpireParameterSet * set, int index);\n\n\t/*!\n\t@brief Get the binding name of a SpireParameterSet object.\n\t@param set A SpireParameterSet object whose binding name to get.\n\t@return The binding name. The life-time of the returned string is owned by @p set.\n\t*/\n\tSPIRE_API const char * spParameterSetGetBindingName(SpireParameterSet * set);\n\n\t/*!\n\t@brief Get the binding index of a SpireParameterSet object.\n\t@param set A SpireParameterSet object whose binding index to get.\n\t@return The binding index.\n\t*/\n\tSPIRE_API int spParameterSetGetBindingIndex(SpireParameterSet * set);\n\n\t/*!\n\t@brief Get the legacy binding index for the uniform buffer of a SpireParameterSet object.\n\t@param set A SpireParameterSet object whose uniform buffer legacy binding index to get.\n\t@return The legacy binding index.\n\t*/\n\tSPIRE_API int spParameterSetGetUniformBufferLegacyBindingPoint(SpireParameterSet * set);\n\n\t/*!\n\t@brief Get the number of binding slots of a SpireParameterSet object.\n\t@param set A SpireParameterSet object whose number of binding slots to get.\n\t@return The number of binding slots.\n\t*/\n\tSPIRE_API int spParameterSetGetBindingSlotCount(SpireParameterSet * set);\n\n\t/*!\n\t@brief Get information on a binding slot in a SpireParameterSet object.\n\t@param set A SpireParameterSet object whose binding slot information to get.\n\t@return The pointer to a SpireResourceBindingInfo structure that holds information about the requested binding slot.\n\t        The life-time of the returned structure is owned by @p set and should be freed by the user.\n\t*/\n\tSPIRE_API SpireResourceBindingInfo * spParameterSetGetBindingSlot(SpireParameterSet * set, int index);\n\n\t/*!\n\t@brief Destroys the SpireCompilationResult object.\n\t@param result A SpireCompilationResult object to destroy.\n\t@note Destroying a SpireCompilationContext object does not automatically destroy SpireCompilationResult objects. You are required to destroy a SpireCompilationResult object\n\tonce it is no longer in use.\n\t*/\n\tSPIRE_API void spDestroyCompilationResult(SpireCompilationResult * result);\n\n#ifdef __cplusplus  \n}\n#endif  \n\n#endif"
  },
  {
    "path": "SpireAllSource.h",
    "content": "#ifndef SPIRE_NO_CORE_LIB\n#include \"Source/CoreLib/CommandLineParser.cpp\"\n#include \"Source/CoreLib/LibIO.cpp\"\n#include \"Source/CoreLib/LibMath.cpp\"\n#include \"Source/CoreLib/LibString.cpp\"\n#include \"Source/CoreLib/Stream.cpp\"\n#include \"Source/CoreLib/TextIO.cpp\"\n#include \"Source/CoreLib/Tokenizer.cpp\"\n#include \"Source/CoreLib/VectorMath.cpp\"\n#endif\n#include \"Source/SpireCore/CLikeCodeGen.cpp\"\n#include \"Source/SpireCore/Closure.cpp\"\n#include \"Source/SpireCore/CodeGenerator.cpp\"\n#include \"Source/SpireCore/CompiledProgram.cpp\"\n#include \"Source/SpireCore/ConstantPool.cpp\"\n#include \"Source/SpireCore/Diagnostics.cpp\"\n#include \"Source/SpireCore/GetDependencyVisitor.cpp\"\n#include \"Source/SpireCore/GLSLCodeGen.cpp\"\n#include \"Source/SpireCore/HLSLCodeGen.cpp\"\n#include \"Source/SpireCore/IL.cpp\"\n#include \"Source/SpireCore/InsertImplicitImportOperator.cpp\"\n#include \"Source/SpireCore/KeyHoleMatching.cpp\"\n#include \"Source/SpireCore/Lexer.cpp\"\n#include \"Source/SpireCore/Naming.cpp\"\n#include \"Source/SpireCore/NewSpirVCodeGen.cpp\"\n#include \"Source/SpireCore/Parser.cpp\"\n#include \"Source/SpireCore/Preprocessor.cpp\"\n#include \"Source/SpireCore/Schedule.cpp\"\n#include \"Source/SpireCore/SemanticsVisitor.cpp\"\n#include \"Source/SpireCore/ShaderCompiler.cpp\"\n#include \"Source/SpireCore/SpirVCodeGen.cpp\"\n#include \"Source/SpireCore/StdInclude.cpp\"\n#include \"Source/SpireCore/SymbolTable.cpp\"\n#include \"Source/SpireCore/Syntax.cpp\"\n#include \"Source/SpireCore/TypeLayout.cpp\"\n#include \"Source/SpireCore/SamplerUsageAnalysis.cpp\"\n#include \"Source/SpireCore/VariantIR.cpp\"\n#include \"Source/SpireLib/SpireLib.cpp\"\n"
  },
  {
    "path": "Tests/Diagnostics/break-outside-loop.spire",
    "content": "// `break` where it isn't allowed\n\nvoid foo() { break; }\n"
  },
  {
    "path": "Tests/Diagnostics/break-outside-loop.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/break-outside-loop.spire(3): error 30003: 'break' must appear inside loop constructs.\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Diagnostics/call-argument-type.spire",
    "content": "// call function with wrong argument type\n\nstruct A {};\nstruct B {};\n\nvoid f(A a) {}\nvoid g(B b)\n{\n\tf(b);\n}\n"
  },
  {
    "path": "Tests/Diagnostics/call-argument-type.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/call-argument-type.spire(9): error 30021: f: no overload takes arguments ()\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Diagnostics/continue-outside-loop.spire",
    "content": "// `continue` where it isn't allowed\n\nvoid foo() { continue; }\n"
  },
  {
    "path": "Tests/Diagnostics/continue-outside-loop.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/continue-outside-loop.spire(3): error 30004: 'continue' must appear inside loop constructs.\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Diagnostics/expected-token-eof.spire",
    "content": "// expected one token, but got EOF\n\nint foo()\n{\n\tint a = 3"
  },
  {
    "path": "Tests/Diagnostics/expected-token-eof.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/expected-token-eof.spire(0): error 20001: unexpected end of file, expected ';'\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Diagnostics/expected-token.spire",
    "content": "// expected one token, but got another\n\nint foo()\n{\n\tint a = 3 ]\n}"
  },
  {
    "path": "Tests/Diagnostics/expected-token.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/expected-token.spire(5): error 20001: unexpected ']', expected ';'\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Diagnostics/function-redefinition.spire",
    "content": "// redefining a function\n\nint foo(int a) { return 0; }\nint foo(int b) { return 1; }\n"
  },
  {
    "path": "Tests/Diagnostics/function-redefinition.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/function-redefinition.spire(4): error 30001: 'foo(int)': function redefinition.\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Diagnostics/hull-shader-invalid-domain.spire",
    "content": "// `HullShader` without `Domain` attribute\n\npipeline P\n{\n    world CoarseVertex;\n    world ControlPoint;\n    world CornerPoint;\n    world TessPatch;\n    world FineVertex;\n    \n    require @FineVertex vec4 RS_Position; \n    require @ControlPoint vec2 tessLevelInner;\n    require @ControlPoint vec4 tessLevelOuter;\n        \n    // implicit import operator CoarseVertex->CornerPoint\n    extern @CornerPoint CoarseVertex[] CoarseVertex_ControlPoint;\n    [PerCornerIterator]\n    extern @CornerPoint int HS_CornerID;\n    \n    extern @ControlPoint CoarseVertex[] CoarseVertex_ControlPoint;\n    extern @TessPatch CoarseVertex[] CoarseVertex_ControlPoint;\n    [InvocationId]\n    extern @ControlPoint int invocationId;\n    extern @FineVertex ControlPoint[] ControlPoint_tes;\n    extern @FineVertex Patch<TessPatch> perPatch_tes;\n    \n    extern @FineVertex Patch<CornerPoint[3]> perCorner_tes;\n    [TessCoord]\n    extern @FineVertex vec3 tessCoord;\n      \n    stage hs : HullShader\n    {\n        PatchWorld: TessPatch;\n        ControlPointWorld: ControlPoint;\n        CornerPointWorld: CornerPoint;\n        InputControlPointCount: 3;\n        ControlPointCount: 1;\n        Domain: pentagons;\n        TessLevelOuter: tessLevelOuter;\n        TessLevelInner: tessLevelInner;\n\t\tPartitioning: integer;\n\t\tOutputTopology: triangle_ccw;\n    }\n}\n\nshader S\n    targets P\n{\n\t@FineVertex float4 RS_Position = float4(0.0);\n\t@ControlPoint float2 tessLevelInner = float2(2.0);\n\t@ControlPoint float4 tessLevelOuter = float4(2.0);\n}"
  },
  {
    "path": "Tests/Diagnostics/hull-shader-invalid-domain.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/hull-shader-invalid-domain.spire(38): error 50053: 'Domain' should be either 'triangles' or 'quads'.\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Diagnostics/hull-shader-no-domain.spire",
    "content": "// `HullShader` without `Domain` attribute\n\npipeline P\n{\n    world CoarseVertex;\n    world ControlPoint;\n    world CornerPoint;\n    world TessPatch;\n    world FineVertex;\n    \n    require @FineVertex vec4 RS_Position; \n    require @ControlPoint vec2 tessLevelInner;\n    require @ControlPoint vec4 tessLevelOuter;\n        \n    // implicit import operator CoarseVertex->CornerPoint\n    extern @CornerPoint CoarseVertex[] CoarseVertex_ControlPoint;\n    [PerCornerIterator]\n    extern @CornerPoint int HS_CornerID;\n    \n    extern @ControlPoint CoarseVertex[] CoarseVertex_ControlPoint;\n    extern @TessPatch CoarseVertex[] CoarseVertex_ControlPoint;\n    [InvocationId]\n    extern @ControlPoint int invocationId;\n    extern @FineVertex ControlPoint[] ControlPoint_tes;\n    extern @FineVertex Patch<TessPatch> perPatch_tes;\n    \n    extern @FineVertex Patch<CornerPoint[3]> perCorner_tes;\n    [TessCoord]\n    extern @FineVertex vec3 tessCoord;\n      \n    stage hs : HullShader\n    {\n        PatchWorld: TessPatch;\n        ControlPointWorld: ControlPoint;\n        CornerPointWorld: CornerPoint;\n        InputControlPointCount: 3;\n        ControlPointCount: 1;\n//        Domain: triangles;\n        TessLevelOuter: tessLevelOuter;\n        TessLevelInner: tessLevelInner;\n\t\tPartitioning: integer;\n\t\tOutputTopology: triangle_ccw;\n    }\n}\n\nshader S\n    targets P\n{\n\t@FineVertex float4 RS_Position = float4(0.0);\n\t@ControlPoint float2 tessLevelInner = float2(2.0);\n\t@ControlPoint float4 tessLevelOuter = float4(2.0);\n}"
  },
  {
    "path": "Tests/Diagnostics/hull-shader-no-domain.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/hull-shader-no-domain.spire(31): error 50052: 'HullShader' requires attribute 'Domain'.\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Diagnostics/illegal-character.spire",
    "content": "// illegal character\n\n$\n\n"
  },
  {
    "path": "Tests/Diagnostics/illegal-character.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/illegal-character.spire(3): error 10000: Illegal character '\\x24'\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Diagnostics/missing-file.spire",
    "content": "// trying to import a non-existant file\n\nusing \"does-not-exist.spire\"\n"
  },
  {
    "path": "Tests/Diagnostics/missing-file.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/missing-file.spire(0): error 20001: unexpected end of file, expected ';'\nTests/Diagnostics/missing-file.spire(3): error 2: cannot find file 'does-not-exist.spire'.\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Diagnostics/parameter-already-defined.spire",
    "content": "// re-use parameter name\n\nint foo( int a, float a ) { return 0; }\n"
  },
  {
    "path": "Tests/Diagnostics/parameter-already-defined.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/parameter-already-defined.spire(3): error 30002: parameter 'a' already defined.\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Diagnostics/undefined-identifier.spire",
    "content": "// use of undefined identifier\n\nvoid foo()\n{\n\tint a = b;\n}\n"
  },
  {
    "path": "Tests/Diagnostics/undefined-identifier.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/undefined-identifier.spire(5): error 30015: undefined identifier 'b'.\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Diagnostics/variable-void-type.spire",
    "content": "// variable with `void` type\n\nvoid foo()\n{\n\tvoid a;\n}\n"
  },
  {
    "path": "Tests/Diagnostics/variable-void-type.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/variable-void-type.spire(5): error 30009: invalid type 'void'.\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Diagnostics/while-predicate-type.spire",
    "content": "// bad type for `while` predicate\n\nstruct S {};\n\nvoid foo()\n{\n\tS s;\n\twhile(s) {break;}\n}\n"
  },
  {
    "path": "Tests/Diagnostics/while-predicate-type.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Diagnostics/while-predicate-type.spire(8): error 30010: 'while': expression must evaluate to int.\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/FrontEnd/lexer-comments.spire",
    "content": "// confirming that the lexer handles comments correctly\n\n// line comment\n\n/* block comment\n*/\n\n/* block comments don't nest\n   /*\n*/\n\nfloat f(float f) { return f; }"
  },
  {
    "path": "Tests/FrontEnd/parser-decls.spire",
    "content": "// test that we can parse all the expected kinds of declarations\n\n// global-scope `using` is another test\n\n// pipeline\npipeline P\n{\n\n}\n\n// empty declaration\n;\n\n// struct type\nstruct Pair\n{\n\tint head;\n\tfloat tail;\n}\n\n// function at global scope\nfloat tail(Pair p) { return p.tail; }\n\n// module\nmodule M\n{\n\t// component declarations\n\n\t// using declarations\n\t\n}\n\n// a module can \"inherit\" from a pipeline\nmodule M2\n\ttargets P\n{\n}\n\n// shader\nshader S\n{\n\t// component declarations\n\n\t// using declarations\n\n}\n\n"
  },
  {
    "path": "Tests/FrontEnd/parser-empty.spire",
    "content": ""
  },
  {
    "path": "Tests/FrontEnd/parser-error-unclosed-curly.spire",
    "content": "shader Test {\n// Note: no closing curly brace\n"
  },
  {
    "path": "Tests/FrontEnd/parser-error-unclosed-curly.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/FrontEnd/parser-error-unclosed-curly.spire(0): error 20001: unexpected end of file, expected '}'\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/FrontEnd/parser-using-file-a.spireh",
    "content": "// this file exists to be included by \"parser-using-file.spire\"\n\nfloat a(float x) { return x * x; }\n"
  },
  {
    "path": "Tests/FrontEnd/parser-using-file.spire",
    "content": "// test that we can include a file via `using`\n\nusing \"parser-using-file-a.spireh\";\n\nfloat base( float x ) { return a(x); }"
  },
  {
    "path": "Tests/FrontEnd/pipeline-simple.spireh",
    "content": "// pipeline-simple.spireh\n\n\n// TODO(tfoley): strip this down to a minimal pipeline\n\npipeline StandardPipeline\n{\n    [Pinned]\n    input world MeshVertex;\n    \n    world CoarseVertex;// : \"glsl(vertex:projCoord)\" using projCoord export standardExport;\n    world Fragment;// : \"glsl\" export fragmentExport;\n    \n    require @CoarseVertex vec4 projCoord; \n    \n    [VertexInput]\n    extern @CoarseVertex MeshVertex vertAttribIn;\n    import(MeshVertex->CoarseVertex) vertexImport()\n    {\n        return project(vertAttribIn);\n    }\n    \n    extern @Fragment CoarseVertex CoarseVertexIn;\n    import(CoarseVertex->Fragment) standardImport()\n// TODO(tfoley): this trait doesn't seem to be implemented on `vec3`\n//        require trait IsTriviallyPassable(CoarseVertex)\n    {\n        return project(CoarseVertexIn);\n    }\n    \n    stage vs : VertexShader\n    {\n        World: CoarseVertex;\n        Position: projCoord;\n    }\n    \n    stage fs : FragmentShader\n    {\n        World: Fragment;\n    }\n}"
  },
  {
    "path": "Tests/FrontEnd/struct.spire",
    "content": "// test that `struct` decls work\n\n#include \"pipeline-simple.spireh\"\n\n// struct declaration\nstruct Foo\n{\n\tvec3 a;\n\tvec3 b;\n};\n\n// function on a struct\nFoo makeFoo(float x, float y)\n{\n\t// local of struct type\n\tFoo foo;\n\tfoo.a = vec3(x);\n\tfoo.b = vec3(y);\n\treturn foo;\n}\n\nshader Test\n    targets StandardPipeline\n{\n\t// Uniform of struct type\n\tparam Foo foo1;\n\n    @MeshVertex vec3 position;\n    @MeshVertex vec3 color;\n\n    param mat4 modelViewProjection;\n\n    public vec4 projCoord = modelViewProjection * vec4(position, 1.0);\n\n    // Component of struct type\n    // Note(tfoley): use of `public` here required to work around parser limitations\n    public Foo foo2 = makeFoo(color.x, color.y);\n\n    //\n    vec3 result = foo1.a + foo2.b;\n\n    out @Fragment vec4 colorTarget = vec4(result,1);\n}\n"
  },
  {
    "path": "Tests/FrontEnd/typedef.spire",
    "content": "// test that we can `typedef` a type\n\ntypedef float F32;\n\nF32 foo()\n{\n\tfloat x = 123.0;\n\treturn x;\n}\n\nfloat bar()\n{\n\treturn foo();\n}\n"
  },
  {
    "path": "Tests/HLSLCodeGen/DeferredLighting.fs.hlsl",
    "content": "#pragma warning(disable: 3576)\n#pragma pack_matrix( row_major )\nstruct ArrInStruct\n{\nfloat3 ttt;\nfloat3 points[4];\n};\nstruct SkinningResult\n{\nfloat3 pos;\nfloat3 tangent;\nfloat3 binormal;\n};\nTexture2D DeferredLightingParams_albedoTex: register(t0);\nTexture2D DeferredLightingParams_pbrTex: register(t1);\nTexture2D DeferredLightingParams_normalTex: register(t2);\nTexture2D DeferredLightingParams_depthTex: register(t3);\nSamplerState DeferredLightingParams_nearestSampler: register(s0);\ncbuffer bufForwardBasePassParams : register(b1)\n{\nstruct {\nfloat4x4 viewTransform;\nfloat4x4 viewProjectionTransform;\nfloat4x4 invViewTransform;\nfloat4x4 invViewProjTransform;\nfloat3 cameraPos;\nfloat time;\n} ForwardBasePassParams;\n};\nSamplerState ForwardBasePassParams_textureSampler: register(s1);\ncbuffer buflighting : register(b2)\n{\nstruct {\nfloat3 lightDir;\nfloat3 lightColor;\nfloat ambient;\nint shadowMapId;\nint numCascades;\nfloat4x4 lightMatrix[8];\nfloat4 zPlanes[2];\n} lighting;\n};\nTexture2DArray lighting_shadowMapArray: register(t4);\nSamplerComparisonState lighting_shadowMapSampler: register(s2);\nTextureCube lighting_envMap: register(t5);\nTexture2D layers_l0_albedoTex: register(t6);\nSamplerState layers_l0_samplerState: register(s3);\nTexture2D layers_l1_albedoTex: register(t7);\nSamplerState layers_l1_samplerState: register(s4);\nTexture2D layers_l2_albedoTex: register(t8);\nSamplerState layers_l2_samplerState: register(s5);\nint Test(float3 p_b, inout ArrInStruct p_testOut);\nfloat PhongApprox(float p_Roughness, float p_RoL);\nfloat3 EnvBRDFApprox(float3 p_SpecularColor, float p_Roughness, float p_NoV);\nfloat DeferredLighting_selfShadow_vec3(float3 p0_x);\nfloat4 SubModuleWithParam_Eval_vec2(Texture2D p0_albedoTex, SamplerState p1_samplerState, float2 p2_uv);\nfloat4 SubModuleWithParam1_Eval_vec2(Texture2D p0_albedoTex, SamplerState p1_samplerState, float2 p2_uv);\nint Test(float3 p_b, inout ArrInStruct p_testOut)\n{\nint i = 0;\np_testOut.ttt = p_b;\ni = 0;\nfor (; (i < 4); (i = (i + 1)))\n{\np_testOut.points[i] = 0;\n}\nreturn 0;\n}\nfloat PhongApprox(float p_Roughness, float p_RoL)\n{\nfloat a;\nfloat a2;\nfloat rcp_a2;\nfloat c;\nfloat p;\na = (p_Roughness * p_Roughness);\na = max(a, 8.000000379980e-03);\na2 = (a * a);\nrcp_a2 = (1.000000000000e+00 / a2);\nc = ((7.213475108147e-01 * rcp_a2) + 3.967411220074e-01);\np = (rcp_a2 * exp2(((c * p_RoL) - c)));\nreturn min(p, rcp_a2);\n}\nfloat3 EnvBRDFApprox(float3 p_SpecularColor, float p_Roughness, float p_NoV)\n{\nfloat4 c0;\nfloat4 c1;\nfloat4 r;\nfloat a004;\nfloat2 AB;\nc0 = float4((-1), (-2.749999985099e-02), (-5.720000267029e-01), 2.199999988079e-02);\nc1 = float4(1, 4.250000044703e-02, 1.039999961853e+00, (-3.999999910593e-02));\nr = ((p_Roughness * c0) + c1);\na004 = ((min((r.x * r.x), exp2(((-9.279999732971e+00) * p_NoV))) * r.x) + r.y);\nAB = ((float2((-1.039999961853e+00), 1.039999961853e+00) * a004) + r.zw);\nAB.y = (AB.y * min((5.000000000000e+01 * p_SpecularColor.y), 1.000000000000e+00));\nreturn ((p_SpecularColor * AB.x) + AB.y);\n}\nfloat DeferredLighting_selfShadow_vec3(float3 p0_x)\n{\nreturn 1.000000000000e+00;\n}\nfloat4 SubModuleWithParam_Eval_vec2(Texture2D p0_albedoTex, SamplerState p1_samplerState, float2 p2_uv)\n{\nreturn p0_albedoTex.Sample(p1_samplerState, p2_uv);\n}\nfloat4 SubModuleWithParam1_Eval_vec2(Texture2D p0_albedoTex, SamplerState p1_samplerState, float2 p2_uv)\n{\nreturn p0_albedoTex.Sample(p1_samplerState, p2_uv);\n}\nstruct TCoarseVertex\n{\nfloat2 vertUV_CoarseVertex : A0A;\n};\nstruct TFragment\n{\nfloat4 outputColor : A0A;\n};\nstruct TFragmentExt\n{\nTFragment user : SV_Target;\n};\nTFragmentExt main(\n    TCoarseVertex stage_input)\n{ \nTFragmentExt stage_output;\nfloat2 vertUV;\nfloat4 normalSample;\nfloat3 normal;\nfloat4 pbr;\nfloat3 albedo;\nfloat3 lightParam;\nfloat4 t45F;\nfloat4 position;\nfloat3 pos;\nfloat3 view;\nfloat shadow;\nfloat3 viewPos;\nint i = 0;\nint t474 = 0;\nint t476 = 0;\nfloat4 lightSpacePosT;\nfloat3 lightSpacePos;\nfloat val;\nfloat3 lNormal;\nfloat dielectricSpecluar;\nfloat3 diffuseColor;\nfloat3 specularColor;\nfloat NoV;\nfloat3 R;\nfloat RoL;\nfloat3 result;\nfloat3 specularIBL;\nfloat3 diffuseIBL;\nfloat4 outputColor;\nArrInStruct s;\nint t4CD = 0;\nvertUV = stage_input/*standard*/.vertUV_CoarseVertex;\nnormalSample = DeferredLightingParams_normalTex.Sample(DeferredLightingParams_nearestSampler, vertUV);\nnormal = ((normalSample.xyz * 2.000000000000e+00) - 1.000000000000e+00);\npbr = DeferredLightingParams_pbrTex.Sample(DeferredLightingParams_nearestSampler, vertUV);\nalbedo = DeferredLightingParams_albedoTex.Sample(DeferredLightingParams_nearestSampler, vertUV).xyz;\nlightParam = float3(pbr.x, pbr.y, pbr.z);\nt45F = DeferredLightingParams_depthTex.Sample(DeferredLightingParams_nearestSampler, vertUV);\nposition = mul(float4(((vertUV.x * 2) - 1), ((vertUV.y * 2) - 1), t45F.x, 1.000000000000e+00), ForwardBasePassParams.invViewProjTransform);\npos = (position.xyz / position.w);\nview = normalize((ForwardBasePassParams.cameraPos - pos));\nshadow = DeferredLighting_selfShadow_vec3(lighting.lightDir);\nif (bool(lighting.numCascades))\n{\nviewPos = mul(float4(pos, 1.000000000000e+00), ForwardBasePassParams.viewTransform).xyz;\ni = 0;\nfor (; (i < lighting.numCascades); (i = (i + 1)))\n{\nt474 = (i >> 2);\nt476 = (i & 3);\nif (bool(((-viewPos.z) < lighting.zPlanes[t474][t476])))\n{\nlightSpacePosT = mul(float4(pos, 1.000000000000e+00), lighting.lightMatrix[i]);\nlightSpacePos = (lightSpacePosT.xyz / lightSpacePosT.w);\nval = lighting_shadowMapArray.SampleCmp(lighting_shadowMapSampler, float3(lightSpacePos.xy, (i + lighting.shadowMapId)), lightSpacePos.z);\nshadow = (shadow * val);\nbreak;\n}\n}\n}\nif (bool((normalSample.w != 0.000000000000e+00)))\n{\nlNormal = ((dot(normal, view) < 0)?(-normal):normal);\n}\nelse\n{\nlNormal = normal;\n}\ndielectricSpecluar = (1.999999955297e-02 * lightParam.z);\ndiffuseColor = (albedo - (albedo * lightParam.y));\nspecularColor = (((float3) (dielectricSpecluar - (dielectricSpecluar * lightParam.y))) + (albedo * lightParam.y));\nNoV = max(dot(lNormal, view), 0.000000000000e+00);\nspecularColor = EnvBRDFApprox(specularColor, lightParam.x, NoV);\nR = reflect((-view), lNormal);\nRoL = max(0, dot(R, lighting.lightDir));\nresult = (((lighting.lightColor * clamp(dot(lNormal, lighting.lightDir), 9.999999776483e-03, 9.900000095367e-01)) * (diffuseColor + (specularColor * PhongApprox(lightParam.x, RoL)))) * shadow);\nspecularIBL = (specularColor * lighting_envMap.SampleLevel(ForwardBasePassParams_textureSampler, R, (clamp(lightParam.x, 0.000000000000e+00, 1.000000000000e+00) * 8.000000000000e+00)).xyz);\ndiffuseIBL = ((diffuseColor * lighting_envMap.SampleLevel(ForwardBasePassParams_textureSampler, lNormal, 8.000000000000e+00).xyz) * lighting.ambient);\nresult = (result + (specularIBL + diffuseIBL));\nresult = (result * pbr.w);\noutputColor = (float4(result, 1.000000000000e+00) + ((SubModuleWithParam_Eval_vec2(layers_l0_albedoTex, layers_l0_samplerState, ((float2) 0.000000000000e+00)) + SubModuleWithParam_Eval_vec2(layers_l1_albedoTex, layers_l1_samplerState, ((float2) 0.000000000000e+00))) + SubModuleWithParam1_Eval_vec2(layers_l2_albedoTex, layers_l2_samplerState, ((float2) 0.000000000000e+00))));\nt4CD = Test(((float3) 1.000000000000e+00), s);\nstage_output.user.outputColor = outputColor;\nstage_output.user.outputColor = outputColor;\nreturn stage_output;\n}"
  },
  {
    "path": "Tests/HLSLCodeGen/DeferredLighting.vs.hlsl",
    "content": "#pragma warning(disable: 3576)\n#pragma pack_matrix( row_major )\nstruct SkinningResult\n{\nfloat3 pos;\nfloat3 tangent;\nfloat3 binormal;\n};\nTexture2D DeferredLightingParams_albedoTex: register(t0, space-1);\nTexture2D DeferredLightingParams_pbrTex: register(t1, space-1);\nTexture2D DeferredLightingParams_normalTex: register(t2, space-1);\nTexture2D DeferredLightingParams_depthTex: register(t3, space-1);\nSamplerState DeferredLightingParams_nearestSampler: register(s0, space-1);\nSamplerState ForwardBasePassParams_textureSampler: register(s1, space-1);\nTexture2DArray lighting_shadowMapArray: register(t4, space-1);\nSamplerComparisonState lighting_shadowMapSampler: register(s2, space-1);\nTextureCube lighting_envMap: register(t5, space-1);\nTexture2D layers_l0_albedoTex: register(t6, space-1);\nSamplerState layers_l0_samplerState: register(s3, space-1);\nTexture2D layers_l1_albedoTex: register(t7, space-1);\nSamplerState layers_l1_samplerState: register(s4, space-1);\nTexture2D layers_l2_albedoTex: register(t8, space-1);\nSamplerState layers_l2_samplerState: register(s5, space-1);\nTexture2D DeferredLightingParams_albedoTex: register(t0, space0);\nTexture2D DeferredLightingParams_pbrTex: register(t1, space0);\nTexture2D DeferredLightingParams_normalTex: register(t2, space0);\nTexture2D DeferredLightingParams_depthTex: register(t3, space0);\nSamplerState DeferredLightingParams_nearestSampler: register(s0, space0);\ncbuffer bufForwardBasePassParams : register(b1)\n{\nstruct {\nfloat4x4 viewTransform;\nfloat4x4 viewProjectionTransform;\nfloat4x4 invViewTransform;\nfloat4x4 invViewProjTransform;\nfloat3 cameraPos;\nfloat time;\n} ForwardBasePassParams;\n};\nSamplerState ForwardBasePassParams_textureSampler: register(s0, space1);\ncbuffer buflighting : register(b2)\n{\nstruct {\nfloat3 lightDir;\nfloat3 lightColor;\nfloat ambient;\nint shadowMapId;\nint numCascades;\nfloat4x4 lightMatrix[8];\nfloat4 zPlanes[2];\n} lighting;\n};\nTexture2DArray lighting_shadowMapArray: register(t0, space2);\nSamplerComparisonState lighting_shadowMapSampler: register(s0, space2);\nTextureCube lighting_envMap: register(t1, space2);\nTexture2D layers_l0_albedoTex: register(t0, space3);\nSamplerState layers_l0_samplerState: register(s0, space3);\nTexture2D layers_l1_albedoTex: register(t1, space3);\nSamplerState layers_l1_samplerState: register(s1, space3);\nTexture2D layers_l2_albedoTex: register(t2, space3);\nSamplerState layers_l2_samplerState: register(s2, space3);\nstruct TMeshVertex\n{\nfloat2 vertPos : A0A;\nfloat2 vertUV : A1A;\n};\nstruct TCoarseVertex\n{\nfloat2 vertUV_CoarseVertex : A0A;\n};\nstruct TCoarseVertexExt\n{\nTCoarseVertex user;\nfloat4 sv_position : SV_Position;\n};\nTCoarseVertexExt main(\n    TMeshVertex stage_input : A)\n{ \nTCoarseVertexExt stage_output;\nfloat2 vertPos;\nfloat2 vertUV;\nvertPos = stage_input/*standard*/.vertPos;\nvertUV = stage_input/*standard*/.vertUV;\nstage_output.user.vertUV_CoarseVertex = vertUV;\nstage_output.sv_position = float4(vertPos.xy, 0.000000000000e+00, 1.000000000000e+00);\nreturn stage_output;\n}"
  },
  {
    "path": "Tests/HLSLCodeGen/StandardPipeline.spire",
    "content": "pipeline StandardPipeline\n{\n    [Pinned]\n    input world MeshVertex;\n\n    world CoarseVertex;\n    world Fragment;\n    \n    require @CoarseVertex vec4 projCoord; \n        \n    [VertexInput]\n    extern @CoarseVertex MeshVertex vertAttribIn;\n    import(MeshVertex->CoarseVertex) vertexImport()\n    {\n        return project(vertAttribIn);\n    }\n    \n    extern @Fragment CoarseVertex CoarseVertexIn;\n    import(CoarseVertex->Fragment) standardImport<T>()\n        require trait IsTriviallyPassable(T)\n    {\n        return project(CoarseVertexIn);\n    }\n    \n    stage vs : VertexShader\n    {\n        World: CoarseVertex;\n        Position: projCoord;\n    }\n    \n    stage fs : FragmentShader\n    {\n        World: Fragment;\n    }\n}\n\npipeline TessellationPipeline : StandardPipeline\n{\n    [Pinned]\n    input world MeshVertex;\n\n    world CoarseVertex;\n    world ControlPoint;\n    world CornerPoint;\n    world TessPatch;\n    world FineVertex;\n    world Fragment;\n    \n    require @FineVertex vec4 projCoord; \n    require @ControlPoint vec2 tessLevelInner;\n    require @ControlPoint vec4 tessLevelOuter;\n\n    [VertexInput]\n    extern @CoarseVertex MeshVertex vertAttribs;\n    import(MeshVertex->CoarseVertex) vertexImport() { return project(vertAttribs); }\n    \n    // implicit import operator CoarseVertex->CornerPoint\n    extern @CornerPoint CoarseVertex[] CoarseVertex_ControlPoint;\n    [PerCornerIterator]\n    extern @CornerPoint int sysLocalIterator;\n    import (CoarseVertex->CornerPoint) standardImport<T>()\n        require trait IsTriviallyPassable(T)\n    {\n        return project(CoarseVertex_ControlPoint[sysLocalIterator]);\n    } \n    \n    // implicit import operator FineVertex->Fragment\n    extern @Fragment FineVertex tes_Fragment;\n    import(FineVertex->Fragment) standardImport<T>()\n        require trait IsTriviallyPassable(T)\n    {\n        return project(tes_Fragment);\n    } \n\n    extern @ControlPoint CoarseVertex[] CoarseVertex_ControlPoint;\n    extern @TessPatch CoarseVertex[] CoarseVertex_ControlPoint;\n    [InvocationId]\n    extern @ControlPoint int invocationId;\n    import(CoarseVertex->ControlPoint) indexImport<T>(int id)\n        require trait IsTriviallyPassable(T)\n    {\n        return project(CoarseVertex_ControlPoint[id]);\n    }\n    import(CoarseVertex->TessPatch) indexImport<T>(int id)\n        require trait IsTriviallyPassable(T)\n    {\n        return project(CoarseVertex_ControlPoint[id]);\n    }\n    extern @FineVertex ControlPoint[] ControlPoint_tes;\n    import(ControlPoint->FineVertex) indexImport<T>(int id)\n        require trait IsTriviallyPassable(T)\n    {\n        return project(ControlPoint_tes[id]);\n    }\n    extern @FineVertex Patch<TessPatch> perPatch_tes;\n    import (TessPatch->FineVertex) standardImport<T>()\n        require trait IsTriviallyPassable(T)\n    {\n        return project(perPatch_tes);\n    }\n    \n    extern @FineVertex Patch<CornerPoint[3]> perCorner_tes;\n    [TessCoord]\n    extern @FineVertex vec3 tessCoord;\n    import(CornerPoint->FineVertex) standardImport<T>()\n        require T operator + (T, T)\n        require T operator * (T, float)\n    {\n        return project(perCorner_tes[0]) * tessCoord.x +\n               project(perCorner_tes[1]) * tessCoord.y +\n               project(perCorner_tes[2]) * tessCoord.z;\n    }\n      \n    stage vs : VertexShader\n    {\n        VertexInput: vertAttribs;\n        World: CoarseVertex;\n    }\n\n    stage tcs : HullShader\n    {\n        PatchWorld: TessPatch;\n        ControlPointWorld: ControlPoint;\n        CornerPointWorld: CornerPoint;\n        ControlPointCount: 1;\n        Domain: triangles;\n        TessLevelOuter: tessLevelOuter;\n        TessLevelInner: tessLevelInner;\n    }\n    \n    stage tes : DomainShader\n    {\n        World : FineVertex;\n        Position : projCoord;\n        Domain: triangles;\n    }\n    \n    stage fs : FragmentShader\n    {\n        World: Fragment;\n        CoarseVertexInput: vertexOutputBlock;\n    }\n}"
  },
  {
    "path": "Tests/HLSLCodeGen/Utils.spire",
    "content": "\nvec4 QuaternionMul(vec4 q1, vec4 q2)\n{\n    vec4 rs;\n    rs.x = q1.w*q2.x + q1.x*q2.w + q1.y*q2.z - q1.z*q2.y;\n    rs.y = q1.w*q2.y + q1.y*q2.w + q1.z*q2.x - q1.x*q2.z;\n    rs.z = q1.w*q2.z + q1.z*q2.w + q1.x*q2.y - q1.y*q2.x;\n    rs.w = q1.w*q2.w - q1.x*q2.x - q1.y*q2.y - q1.z*q2.z;\n    return rs;\n}\n\nvec4 QuaternionConjugate(vec4 q)\n{\n    return vec4(-q.x, -q.y, -q.z, q.w);    \n}\n\nvec3 QuaternionRotate(vec4 q, vec3 pos)\n{\n    return QuaternionMul(QuaternionMul(q, vec4(pos, 0.0)), QuaternionConjugate(q)).xyz;\n}\n\nfloat ComputeLuminance(vec3 color)\n{\n    return color.x * 0.3 + color.y * 0.59 + color.z * 0.11;\n}\n\nvec3 desaturate(vec3 color, float factor)\n{\n    float lum = ComputeLuminance(color);\n    return mix(color, vec3(lum, lum, lum), factor);\n}\n\nmodule TangentSpaceTransform\n{\n    require vec3 coarseVertTangent;\n    require vec3 coarseVertBinormal;\n    require vec3 worldTransformTangent(vec3 pos);\n    public vec3 vTangent = worldTransformTangent(coarseVertTangent);\n    public vec3 vBiTangent = worldTransformTangent(coarseVertBinormal);\n    public vec3 vNormal = cross(vBiTangent, vTangent);\n    \n    public vec3 WorldSpaceToTangentSpace(vec3 v)\n    {\n        return vec3(dot(v, vTangent), dot(v, vBiTangent), dot(v, vNormal));    \n    }\n    public vec3 TangentSpaceToWorldSpace(vec3 v)\n    {\n        return v.x * vTangent + v.y * vBiTangent + v.z * vNormal;        \n    }\n}\n\nmodule VertexTransform\n{\n    require vec3 fineVertPos;\n    require vec3 displacement;\n    require mat4 viewProjectionTransform;\n    require vec3 worldTransformPos(vec3 pos);\n\n    public vec3 pos = worldTransformPos(fineVertPos+displacement); \n    public vec4 projCoord\n    {\n        vec4 rs = viewProjectionTransform * vec4(pos, 1);\n        return rs;\n    } \n}\n\nmodule NoAnimation\n{\n    param mat4 modelMatrix;\n\n    require vec3 vertPos;\n    require vec3 vertNormal;\n    require vec3 vertTangent;\n    require vec3 vertBinormal;\n    \n    public @CoarseVertex vec3 coarseVertPos = vertPos;\n    public @CoarseVertex vec3 coarseVertNormal = vertNormal;\n    public @CoarseVertex vec3 coarseVertTangent = vertTangent;\n    public @CoarseVertex vec3 coarseVertBinormal = vertBinormal;\n\n    public vec3 worldTransformPos(vec3 pos)\n    {\n        return (modelMatrix * vec4(pos, 1)).xyz;\n    }\n    public vec3 worldTransformTangent(vec3 tangent)\n    {\n        return normalize(mat3(modelMatrix) * tangent);\n    }\n}\n\nstruct SkinningResult\n{\n    vec3 pos;\n    vec3 tangent;\n    vec3 binormal;\n}\n\nmodule SkeletalAnimation\n{\n    require vec3 vertPos;\n    require vec3 vertBinormal;\n    require vec3 vertTangent;\n    require uint boneIds;\n    require uint boneWeights;\n\n    require mat4 viewProjectionTransform;\n\n    param mat4[128] boneTransforms;\n    \n    public SkinningResult skinning\n    {\n        SkinningResult result;\n        result.pos = vec3(0.0);\n        result.binormal = vec3(0.0);\n        result.tangent = vec3(0.0);\n        for (int i = 0; i < 4; i++)\n        {\n            uint boneId = (boneIds >> (i*8)) & 255;\n            if (boneId == 255) continue;\n            float boneWeight = float((boneWeights >> (i*8)) & 255) * (1.0/255.0);\n            vec3 tp = (boneTransforms[boneId] * vec4(vertPos, 1.0)).xyz;\n            result.pos += tp * boneWeight;\n            tp = mat3(boneTransforms[boneId]) * vertBinormal;\n            result.binormal += tp * boneWeight;\n            tp = mat3(boneTransforms[boneId]) * vertTangent;\n            result.tangent += tp * boneWeight;\n        }\n        result.binormal = normalize(result.binormal);\n        result.tangent = normalize(result.tangent);\n        return result;\n    }\n    public @CoarseVertex vec3 coarseVertPos = skinning.pos;\n    public @CoarseVertex vec3 coarseVertBinormal = skinning.binormal;\n    public @CoarseVertex vec3 coarseVertTangent = skinning.tangent;\n    public @CoarseVertex vec3 coarseVertNormal = normalize(cross(coarseVertBinormal, coarseVertTangent));\n\n\tpublic vec3 worldTransformPos(vec3 pos)\n    {\n        return pos;\n    }\n    public vec3 worldTransformTangent(vec3 tangent)\n    {\n        return tangent;\n    }\n}\n\nmodule NoTessellation\n{\n    require vec3 coarseVertPos;\n    public vec3 fineVertPos = coarseVertPos;\n}\n\nmodule PN_Tessellation targets TessellationPipeline\n{\n    require vec3 coarseVertPos;\n    require vec3 coarseVertNormal;\n    \n    public @ControlPoint vec4 tessLevelOuter = vec4(3, 3, 3, 0);\n    public @ControlPoint vec2 tessLevelInner = vec2(3.0);\n    \n    vec3 ProjectToPlane(vec3 Point, vec3 PlanePoint, vec3 PlaneNormal)\n    {\n        vec3 v = Point - PlanePoint;\n        float Len = dot(v, PlaneNormal);\n        vec3 d = Len * PlaneNormal;\n        return (Point - d);\n    }\n    \n    @ControlPoint vec3 WorldPos_B030 = indexImport(coarseVertPos, 0);\n    @ControlPoint vec3 WorldPos_B003 = indexImport(coarseVertPos, 1);\n    @ControlPoint vec3 WorldPos_B300 = indexImport(coarseVertPos, 2);\n\n    // Edges are names according to the opposing vertex\n    vec3 EdgeB300 = WorldPos_B003 - WorldPos_B030;\n    vec3 EdgeB030 = WorldPos_B300 - WorldPos_B003;\n    vec3 EdgeB003 = WorldPos_B030 - WorldPos_B300;\n\n    // Generate two midpoints on each edge\n    vec3 WorldPos_B021t = WorldPos_B030 + EdgeB300 / 3.0;\n    vec3 WorldPos_B012t = WorldPos_B030 + EdgeB300 * 2.0 / 3.0;\n    vec3 WorldPos_B102t = WorldPos_B003 + EdgeB030 / 3.0;\n    vec3 WorldPos_B201t = WorldPos_B003 + EdgeB030 * 2.0 / 3.0;\n    vec3 WorldPos_B210t = WorldPos_B300 + EdgeB003 / 3.0;\n    vec3 WorldPos_B120t = WorldPos_B300 + EdgeB003 * 2.0 / 3.0;\n\n    // Project each midpoint on the plane defined by the nearest vertex and its normal\n    @ControlPoint vec3 WorldPos_B021 = ProjectToPlane(WorldPos_B021t, WorldPos_B030,\n                                         indexImport(coarseVertNormal, 0));\n    @ControlPoint vec3 WorldPos_B012 = ProjectToPlane(WorldPos_B012t, WorldPos_B003,\n                                         indexImport(coarseVertNormal, 1));\n    @ControlPoint vec3 WorldPos_B102 = ProjectToPlane(WorldPos_B102t, WorldPos_B003,\n                                         indexImport(coarseVertNormal, 1));\n    @ControlPoint vec3 WorldPos_B201 = ProjectToPlane(WorldPos_B201t, WorldPos_B300,\n                                         indexImport(coarseVertNormal, 2));\n    @ControlPoint vec3 WorldPos_B210 = ProjectToPlane(WorldPos_B210t, WorldPos_B300,\n                                         indexImport(coarseVertNormal, 2));\n    @ControlPoint vec3 WorldPos_B120 = ProjectToPlane(WorldPos_B120t, WorldPos_B030,\n                                         indexImport(coarseVertNormal, 0));\n\n    // Handle the center\n    vec3 Center = (WorldPos_B003 + WorldPos_B030 + WorldPos_B300) / 3.0;\n    vec3 WorldPos_B111t = (WorldPos_B021 + WorldPos_B012 + WorldPos_B102 +\n                          WorldPos_B201 + WorldPos_B210 + WorldPos_B120) / 6.0;\n    vec3 WorldPos_B111 = WorldPos_B111t + (WorldPos_B111t - Center) / 2.0;\n\n    \n    float u = tessCoord.x;\n    float v = tessCoord.y;\n    float w = tessCoord.z;\n\n    float vPow2 = v*v;\n    float uPow2 = u*u;\n    float wPow2 = w*w;\n    float uPow3 = uPow2 * u;\n    float vPow3 = vPow2 * v;\n    float wPow3 = wPow2 * w;\n\n    public @FineVertex float3 fineVertPos = indexImport(WorldPos_B300, 0) * wPow3 +\n                    indexImport(WorldPos_B030, 0) * uPow3 +\n                    indexImport(WorldPos_B003, 0) * vPow3 +\n                    indexImport(WorldPos_B210, 0) * 3.0 * wPow2 * u +\n                    indexImport(WorldPos_B120, 0) * 3.0 * w * uPow2 +\n                    indexImport(WorldPos_B201, 0) * 3.0 * wPow2 * v +\n                    indexImport(WorldPos_B021, 0) * 3.0 * uPow2 * v +\n                    indexImport(WorldPos_B102, 0) * 3.0 * w * vPow2 +\n                    indexImport(WorldPos_B012, 0) * 3.0 * u * vPow2 +\n                    indexImport(WorldPos_B111, 0) * 6.0 * w * u * v;\n}\n\nmodule ParallaxOcclusionMapping\n{\n    require float GetHeight(vec2 uvCoord);\n    require vec3 viewDirTangentSpace;\n    require vec2 uv;\n    require float parallaxScale;\n    require SamplerState textureSampler;\n\n    vec3 parallaxMapping\n    {\n        vec3 V = viewDirTangentSpace;\n        vec2 T = uv;\n        \n        float parallaxHeight;\n        // determine optimal number of layers\n        float minLayers = 10;\n        float maxLayers = 15;\n        float numLayers = mix(maxLayers, minLayers, abs(V.z));\n\n        // height of each layer\n        float layerHeight = 1.0 / numLayers;\n        // current depth of the layer\n        float curLayerHeight = 0.01;\n        // shift of texture coordinates for each layer\n        vec2 dtex = parallaxScale * V.xy / max(V.z, 1e-5) / numLayers;\n        dtex.y = -dtex.y;\n        // current texture coordinates\n        vec2 currentTextureCoords = T;\n\n        // depth from heightmap\n        float heightFromTexture = 1.0 - GetHeight(currentTextureCoords);//heightTexture.Sample(textureSampler, currentTextureCoords).r;\n\n        // while point is above the surface\n        while (heightFromTexture > curLayerHeight) \n        {\n            // to the next layer\n            curLayerHeight += layerHeight; \n            // shift of texture coordinates\n            currentTextureCoords -= dtex;\n            // new depth from heightmap\n            heightFromTexture = 1.0 - GetHeight(currentTextureCoords);//-heightTexture.Sample(textureSampler, currentTextureCoords).r;\n        }\n         ///////////////////////////////////////////////////////////\n        // Start of Relief Parallax Mapping\n\n        // decrease shift and height of layer by half\n        vec2 deltaTexCoord = dtex / 2;\n        float deltaHeight = layerHeight / 2;\n\n        // return to the mid point of previous layer\n        currentTextureCoords += deltaTexCoord;\n        curLayerHeight -= deltaHeight;\n\n        // binary search to increase precision of Steep Paralax Mapping\n        int numSearches = 5;\n        for (int i = 0; i <= numSearches; i++)\n        {\n            // decrease shift and height of layer by half\n            deltaTexCoord /= 2;\n            deltaHeight /= 2;\n\n            // new depth from heightmap\n            heightFromTexture = 1.0 - GetHeight(currentTextureCoords);//heightTexture.Sample(textureSampler, currentTextureCoords).r;\n\n            // shift along or agains vector V\n            if(heightFromTexture > curLayerHeight) // below the surface\n            {\n                currentTextureCoords -= deltaTexCoord;\n                curLayerHeight += deltaHeight;\n            }\n            else // above the surface\n            {\n                currentTextureCoords += deltaTexCoord;\n                curLayerHeight -= deltaHeight;\n            }\n        }\n        parallaxHeight = curLayerHeight; \n        return vec3(currentTextureCoords, parallaxHeight);\n    }\n\n    public vec2 uvOut = parallaxMapping.xy;\n    public float heightOut = parallaxMapping.z;\n\n    public float selfShadow(vec3 L_tangentSpace)\n    {\n        float initialHeight = heightOut - 0.05;\n        vec3 L = L_tangentSpace;\n        vec2 initialTexCoord = uvOut;\n        \n        float shadowMultiplier = 1;\n        float minLayers = 15;\n        float maxLayers = 30;\n\n        // calculate lighting only for surface oriented to the light source\n        if (L.z > 0)\n        {\n            // calculate initial parameters\n            float numSamplesUnderSurface = 0;\n            shadowMultiplier = 0;\n            float numLayers\t= mix(maxLayers, minLayers, abs(L.z));\n            float layerHeight = max(0.03, abs(initialHeight / numLayers));\n            vec2 texStep = parallaxScale * L.xy / L.z / numLayers;\n            texStep.y = -texStep.y;        \n            // current parameters\n            float currentLayerHeight = initialHeight - layerHeight;\n            vec2 currentTextureCoords = initialTexCoord + texStep;\n            float heightFromTexture\t= 1.0 - GetHeight(currentTextureCoords); //heightTexture.Sample(textureSampler, currentTextureCoords).r;\n            // while point is below depth 0.0 )\n            while(currentLayerHeight > 0)\n            {\n                // if point is under the surface\n                if(heightFromTexture < currentLayerHeight)\n                {\n                    numSamplesUnderSurface += 1;\n                    break;\n                }\n\n                // ofFragmentet to the next layer\n                currentLayerHeight -= layerHeight;\n                currentTextureCoords += texStep;\n                heightFromTexture = 1.0 - GetHeight(currentTextureCoords); //-heightTexture.Sample(textureSampler, currentTextureCoords).r;\n            }\n\n            // Shadowing factor should be 1 if there were no points under the surface\n            if(numSamplesUnderSurface < 1)\n            {\n                shadowMultiplier = 1;\n            }\n            else\n            {\n                shadowMultiplier = 0.0;\n            }\n        }\n        return shadowMultiplier;\n    }\n}\n\n float PhongApprox(float Roughness, float RoL)\n{\n    float a = Roughness * Roughness;\t\n    a = max(a, 0.008);\t\t\t\t\t\n    float a2 = a * a;\t\t\t\t\t\t\n    float rcp_a2 = 1.0/(a2);\t\t\t\t\t\n    float c = 0.72134752 * rcp_a2 + 0.39674113;\t\n    float p = rcp_a2 * exp2(c * RoL - c);\t\n    // Total 7 instr\n    return min(p, rcp_a2);\n}\nvec3 EnvBRDFApprox( vec3 SpecularColor, float Roughness, float NoV )\n{\n    vec4 c0 = vec4(-1, -0.0275, -0.572, 0.022);\n    vec4 c1 = vec4(1, 0.0425, 1.04, -0.04);\n    vec4 r = Roughness * c0 + c1;\n    float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\n    vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n    AB.y *= min(50.0 * SpecularColor.g, 1.0);\n    return SpecularColor * AB.x + AB.y;\n}\n\nmodule Lighting\n{\n    public param vec3 lightDir;\n    public param vec3 lightColor;\n    public param float ambient;\n    public param int shadowMapId;\n    public param int numCascades;\n    public param mat4[8] lightMatrix;\n    public param vec4[2] zPlanes;\n    public param Texture2DArrayShadow shadowMapArray;\n    public param SamplerComparisonState shadowMapSampler;\n    public param TextureCube envMap;\n\n    require vec3 normal;   \n    require vec3 albedo;\n    require vec3 lightParam;\n    require float ao;\n    require vec3 pos;\n    require vec3 cameraPos;\n    require float selfShadow(vec3 lightDir);\n    require mat4 viewTransform;\n    require bool isDoubleSided;\n    require SamplerState textureSampler;\n\n    vec3 lNormal\n    {\n\t\tvec3 result;\n        if (isDoubleSided)\n        {\n            result = dot(normal, view) < 0 ? -normal : normal;\n        }\n        else\n        {\n            result = normal;\n        }\n\t\treturn result;\n    }\n\n    vec3 view = normalize(cameraPos - pos);\n    inline float roughness_in = lightParam.x;\n    inline float metallic_in = lightParam.y;\n    inline float specular_in = lightParam.z;\n    vec3 L = lightDir;\n    vec3 H = normalize(view+L);\n    float dotNL = clamp(dot(lNormal,L), 0.01, 0.99);\n    float dotLH = clamp(dot(L,H), 0.01, 0.99);\n    float dotNH = clamp(dot(lNormal,H), 0.01, 0.99);\n    \n    float Pow4(float x)\n    {\n        return (x*x)*(x*x);\n    }\n\n    vec2 LightingFuncGGX_FV(float dotLH, float roughness)\n    {\n        float alpha = roughness*roughness;/*sf*/\n\n        // F\n        float F_a; float F_b;\n        float dotLH5 = Pow4(1.0-dotLH) * (1.0 - dotLH);\n        F_a = 1.0;\n        F_b = dotLH5;\n\n        // V\n        float vis;\n        float k = alpha/2.0;\n        float k2 = k*k;\n        float invK2 = 1.0-k2;\n        vis = 1.0/(dotLH*dotLH*invK2 + k2);\n\n        return vec2(F_a*vis, F_b*vis);\n    }\n\n    float LightingFuncGGX_D(float dotNH, float roughness)\n    {\n        float alpha = roughness*roughness;\n        float alphaSqr = alpha*alpha;\n        float pi = 3.14159;\n        float denom = dotNH * dotNH *(alphaSqr-1.0) + 1.0;\n\n        float D = alphaSqr/(pi * denom * denom);\n        return D;\n    }\n\n    float shadow\n    {\n        float result = selfShadow(lightDir);\n        if (numCascades)\n        {\n            vec3 viewPos = (viewTransform * vec4(pos, 1.0)).xyz;\n            for (int i = 0; i < numCascades; i++)\n            {\n                if (-viewPos.z < zPlanes[i>>2][i&3])\n                {\n                    vec4 lightSpacePosT = lightMatrix[i] * vec4(pos, 1.0);\n                    vec3 lightSpacePos = lightSpacePosT.xyz / lightSpacePosT.w;\n                    float val = shadowMapArray.SampleCmp(shadowMapSampler, \n                        vec3(lightSpacePos.xy, i+shadowMapId), lightSpacePos.z);\n                    result *= val;\n                    break;\n                }\n            }\n        }\n        return result;\n    }\n    \n    float brightness = clamp(dot(lightDir, lNormal), 0.0, 1.0) * shadow;\n\n    public vec3 result\n    {\n        float dielectricSpecluar = 0.02 * specular_in;\n        vec3 diffuseColor = albedo - albedo * metallic_in;\n        vec3 specularColor = vec3(dielectricSpecluar - dielectricSpecluar * metallic_in) + albedo * metallic_in;\n        float NoV = max(dot(lNormal, view), 0.0);\n        specularColor = EnvBRDFApprox(specularColor, roughness_in, NoV);\n        vec3 R = reflect(-view, lNormal);\n        float RoL = max(0, dot(R, lightDir));\n        vec3 color = lightColor * dotNL * (diffuseColor + specularColor * PhongApprox(roughness_in, RoL)) * shadow;\n        vec3 specularIBL = specularColor * envMap.SampleLevel(textureSampler, R, \n                            clamp(roughness_in, 0.0, 1.0) * 8.0).xyz;\n        vec3 diffuseIBL = diffuseColor * envMap.SampleLevel(textureSampler, lNormal, \n                            8.0).xyz * ambient;\n        color += specularIBL + diffuseIBL;\n        color *= ao;\n        return color;\n    }\n}\n\nmodule ForwardBasePassParams\n{\n    public param mat4 viewTransform;\n    public param mat4 viewProjectionTransform;\n    public param mat4 invViewTransform;\n    public param mat4 invViewProjTransform;\n    public param vec3 cameraPos;\n    public param float time;  \n    public param SamplerState textureSampler;  \n}\n\ninterface IMaterialPattern\n{\n    vec3 albedo = vec3(1.0);\n    vec3 normal = vec3(0.0, 0.0, 1.0);\n    float roughness = 0.5;\n    float metallic = 0.3;\n    float specular = 0.8;\n    float opacity = 1.0;\n    float ao = 1.0;\n    bool isDoubleSided = false;\n    float selfShadow(vec3 lightDir)\n    {\n        return 1.0;        \n    }\n}\n\ninterface IMaterialGeometry\n{\n    public vec3 fineVertPos;\n    public vec3 displacement;\n}"
  },
  {
    "path": "Tests/HLSLCodeGen/shader1.spire",
    "content": "using \"StandardPipeline.spire\";\nusing \"Utils.spire\";\n\nstruct ArrInStruct\n{\n\tvec3 ttt;\n\tvec3[4] points;\n}\n\nint Test(in vec3 b, inout ArrInStruct testOut)\n{\n\ttestOut.ttt = b;\n\tfor (int i = 0; i < 4; i++)\n\t\ttestOut.points[i] = 0;\n\treturn 0;\n}\n\n\nmodule DeferredLightingParams\n{\n\tparam Texture2D albedoTex;\n\tparam Texture2D pbrTex;\n\tparam Texture2D normalTex;\n\tparam Texture2D depthTex;\n\tparam SamplerState nearestSampler;\n}\n\nmodule SubModuleWithParam\n{\n\tparam Texture2D albedoTex;\n\tparam SamplerState samplerState;\n\tvec4 Eval(vec2 uv)\n\t{\n\t\treturn albedoTex.Sample(samplerState, uv);\n\t}\n}\n\nmodule SubModuleWithParam1\n{\n\tparam Texture2D albedoTex;\n\tparam SamplerState samplerState;\n\tvec4 Eval(vec2 uv)\n\t{\n\t\treturn albedoTex.Sample(samplerState, uv);\n\t}\n}\n\nmodule TopModule\n{\n\tusing l0 = SubModuleWithParam();\n\tusing l1 = SubModuleWithParam();\n\tusing l2 = SubModuleWithParam1();\n\tvec4 shadingResult = l0.Eval(vec2(0.0)) + l1.Eval(vec2(0.0)) + l2.Eval(vec2(0.0));\n}\n\nshader DeferredLighting targets StandardPipeline\n{\n    [Binding: \"0\"]\n\tpublic using DeferredLightingParams;\n\n\t[Binding: \"1\"]\n\tpublic using ForwardBasePassParams;\n\n\tpublic @MeshVertex vec2 vertPos;\n\tpublic @MeshVertex vec2 vertUV;\n\n\tpublic vec4 projCoord = vec4(vertPos.xy, 0.0, 1.0);\n\n\tpublic vec4 normalSample = normalTex.Sample(nearestSampler, vertUV);\n\tpublic vec3 normal = normalSample.xyz * 2.0 - 1.0;\n\tpublic vec4 pbr = pbrTex.Sample(nearestSampler, vertUV);\n\tpublic float roughness = pbr.x;\n\tpublic float metallic = pbr.y;\n\tpublic float specular = pbr.z;\n\tpublic float ao = pbr.w;\n\tpublic vec3 albedo = albedoTex.Sample(nearestSampler, vertUV).xyz;\n\tpublic float selfShadow(vec3 x) { return 1.0; }\n\tpublic bool isDoubleSided = normalSample.w != 0.0;\n    vec3 lightParam = vec3(roughness, metallic, specular);\n\tfloat z = depthTex.Sample(nearestSampler, vertUV).r;\n    float x = vertUV.x*2-1;\n    float y = vertUV.y*2-1;\n\tvec4 position = invViewProjTransform * vec4(x, y, z, 1.0f);\n\tvec3 pos = position.xyz / position.w;\n\t\n\t[Binding: \"2\"]\n\tusing lighting = Lighting();\n\n\t[Binding: \"3\"]\n\tusing layers = TopModule();\n\n    public out @Fragment vec4 outputColor\n\t{\n\t\tvec4 rs = vec4(lighting.result, 1.0) + layers.shadingResult;\n\t\tArrInStruct s;\n\t\tTest(vec3(1.0f), s);\n\t\treturn rs;\n\t} \n\t\t\n}\n\n\n/*\ntemplate shader ForwardBase(passParams : ForwardBasePassParams, \n                            lightingModule, \n                            geometryModule : IMaterialGeometry, \n                            materialModule : IMaterialPattern, \n                            animationModule) targets StandardPipeline\n{\n    public using VertexAttributes;\n    public using passParams;\n    public using animationModule;\n    public using TangentSpaceTransform;\n    public using geometryModule;\n    public using VertexTransform;\n    public using materialModule;\n    vec3 lightParam = vec3(roughness, metallic, specular);\n    using lighting = lightingModule(TangentSpaceToWorldSpace(vec3(normal.x, -normal.y, normal.z)));\n    public out @Fragment vec4 outputColor\n    {\n\t\tArrInStruct t;\n\t\tint r = Test(vec3(1.0f), t);\n        if (opacity < 0.01f) discard;\n        return vec4(lighting.result, opacity + (float)r);\n    }\n    \n}\n\n*/"
  },
  {
    "path": "Tests/Preprocessor/define-function-like.spire",
    "content": "// support for function-like macros\n\n#define FOO(x) 1.0 + x\n\nfloat foo(float y) { return FOO(y) * 2.0; }\n\n// simple token pasting\n\n#define PASTE(a,b) a##b\n\nPASTE(flo,at) bar() { return 0.0; }\n\n// no space before parens? not a function-like macro\n\n#define M (x) - (x)\n\n// Error: undefined identifier `x`\nfloat bar(float a) { return M(a); }\n"
  },
  {
    "path": "Tests/Preprocessor/define-function-like.spire.expected",
    "content": "result code = -1\nstandard error = {\nTests/Preprocessor/define-function-like.spire(15): error 30015: undefined identifier 'x'.\nTests/Preprocessor/define-function-like.spire(15): error 30015: undefined identifier 'x'.\n}\nstandard output = {\n}\n"
  },
  {
    "path": "Tests/Preprocessor/define-simple.spire",
    "content": "// #define support\n\n#define FOO 1.0f\n\nfloat foo() { return FOO + 2.0; }\n\n#define BAR 99\n\n#if BAR > 10\nint bar() { return 0; }\n#else\nBadThing shouldntCompile;\n#endif\n"
  },
  {
    "path": "Tests/Preprocessor/if.spire",
    "content": "// #ifdef support\n\n\n#if (1 - 1*2) < 0\nint foo() { return 0; }\n#else\nBadThing thatWontCompile;\n#endif\n\n#if (1 >> 1) && ~999\nAnotherError onThisLine;\n#else\nint bar() { return foo(); }\n#endif"
  },
  {
    "path": "Tests/Preprocessor/ifdef.spire",
    "content": "// #ifdef support\n\n#define A\n\n#ifdef A\nint foo() { return 0; }\n#else\nBadThing thatWontCompile;\n#endif\n\n#ifdef BadThing\nAnotherError onThisLine;\n#else\nint bar() { return foo(); }\n#endif"
  },
  {
    "path": "Tests/Preprocessor/include-a.spireh",
    "content": "// #include support\n\nint bar() { return foo(); }"
  },
  {
    "path": "Tests/Preprocessor/include.spire",
    "content": "// #include support\n\nint foo() { return 0; }\n\n#include \"include-a.spireh\"\n\nint baz() { return bar(); }"
  },
  {
    "path": "Tests/SpireTestTool/SpireTestTool.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug_VS2013|Win32\">\n      <Configuration>Debug_VS2013</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug_VS2013|x64\">\n      <Configuration>Debug_VS2013</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release_VS2013|Win32\">\n      <Configuration>Release_VS2013</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release_VS2013|x64\">\n      <Configuration>Release_VS2013</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{0C768A18-1D25-4000-9F37-DA5FE99E3B64}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>SpireTestTool</RootNamespace>\n    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Label=\"Configuration\" Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'\">\n    <PlatformToolset>v140</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Label=\"Configuration\" Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\">\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release_VS2013|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'\">\n    <ClCompile>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <Optimization>Disabled</Optimization>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"main.cpp\" />\n    <ClCompile Include=\"os.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"os.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Source\\CoreLib\\CoreLibBasic.vcxproj\">\n      <Project>{f9be7957-8399-899e-0c49-e714fddd4b65}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "Tests/SpireTestTool/SpireTestTool.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"main.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"os.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"os.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Tests/SpireTestTool/main.cpp",
    "content": "// main.cpp\n\n#include \"../../Source/CoreLib/LibIO.h\"\n\nusing namespace CoreLib::Basic;\nusing namespace CoreLib::IO;\n\n#include \"os.h\"\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n\n// Called for an error in the test-runner (not for an error involving\n// a test itself).\nvoid error(char const* message, ...)\n{\n\tfprintf(stderr, \"error: \");\n\n\tva_list args;\n\tva_start(args, message);\n\tvfprintf(stderr, message, args);\n\tva_end(args);\n\n\tfprintf(stderr, \"\\n\");\n}\n\nenum TestResult\n{\n\tkTestResult_Fail,\n\tkTestResult_Pass,\n};\n\nTestResult runTestImpl(\n\tString\tfilePath)\n{\n\t// need to execute the stand-alone Spire compiler on the file, and compare its output to what we expect\n\n\tOSProcessSpawner spawner;\n\n\tspawner.pushExecutableName(\"Source/Debug/SpireCompiler.exe\");\n\tspawner.pushArgument(filePath);\n\n\tif (spawner.spawnAndWaitForCompletion() != kOSError_None)\n\t{\n\t\terror(\"failed to run test '%S'\", filePath.ToWString());\n\t\treturn kTestResult_Fail;\n\t}\n\n\t// We ignore output to stdout, and only worry about what the compiler\n\t// wrote to stderr.\n\n\tOSProcessSpawner::ResultCode resultCode = spawner.getResultCode();\n\n\tString standardOuptut = spawner.getStandardOutput();\n\tString standardError = spawner.getStandardError();\n\n\t// We construct a single output string that captures the results\n\tStringBuilder actualOutputBuilder;\n\tactualOutputBuilder.Append(\"result code = \");\n\tactualOutputBuilder.Append(resultCode);\n\tactualOutputBuilder.Append(\"\\nstandard error = {\\n\");\n\tactualOutputBuilder.Append(standardError);\n\tactualOutputBuilder.Append(\"}\\nstandard output = {\\n\");\n\tactualOutputBuilder.Append(standardOuptut);\n\tactualOutputBuilder.Append(\"}\\n\");\n\n\tString actualOutput = actualOutputBuilder.ProduceString();\n\n\tString expectedOutputPath = filePath + \".expected\";\n\tString expectedOutput;\n\ttry\n\t{\n\t\texpectedOutput = CoreLib::IO::File::ReadAllText(expectedOutputPath);\n\t}\n\tcatch (CoreLib::IO::IOException)\n\t{\n\t}\n\n\tTestResult result = kTestResult_Pass;\n\n\t// If no expected output file was found, then we\n\t// expect everything to be empty\n\tif (expectedOutput.Length() == 0)\n\t{\n\t\tif (resultCode != 0)\t\t\t\tresult = kTestResult_Fail;\n\t\tif (standardError.Length() != 0)\tresult = kTestResult_Fail;\n\t\tif (standardOuptut.Length() != 0)\tresult = kTestResult_Fail;\n\t}\n\t// Otherwise we compare to the expected output\n\telse if (actualOutput != expectedOutput)\n\t{\n\t\tresult = kTestResult_Fail;\n\t}\n\n\t// If the test failed, then we write the actual output to a file\n\t// so that we can easily diff it from the command line and\n\t// diagnose the problem.\n\tif (result == kTestResult_Fail)\n\t{\n\t\tString actualOutputPath = filePath + \".actual\";\n\t\tCoreLib::IO::File::WriteAllText(actualOutputPath, actualOutput);\n\t}\n\n\treturn result;\n}\n\nstruct TestContext\n{\n\tint totalTestCount;\n\tint passedTestCount;\n\tint failedTestCount;\n};\n\nvoid runTest(\n\tTestContext*\tcontext,\n\tString\t\t\tfilePath)\n{\n\n\tcontext->totalTestCount++;\n\tTestResult result = runTestImpl(filePath);\n\tif (result == kTestResult_Pass)\n\t{\n\t\tprintf(\"passed\");\n\t\tcontext->passedTestCount++;\n\t}\n\telse\n\t{\n\t\tprintf(\"FAILED\");\n\t\tcontext->failedTestCount++;\n\t}\n\n\tprintf(\" test: '%S'\\n\", filePath.ToWString());\n}\n\nvoid runTestsInDirectory(\n\tTestContext*\t\tcontext,\n\tString\t\t\t\tdirectoryPath)\n{\n\tfor (auto file : osFindFilesInDirectoryMatchingPattern(directoryPath, \"*.spire\"))\n\t{\n\t\trunTest(context, file);\n\t}\n}\n\n//\n\nint main(\n\tint\t\targc,\n\tchar**\targv)\n{\n\tTestContext context = { 0 };\n\n\t// Enumerate test files according to policy\n\t// TODO: add more directories to this list\n\t// TODO: allow for a command-line argument to select a particular directory\n\trunTestsInDirectory(&context, \"Tests/FrontEnd/\");\n\trunTestsInDirectory(&context, \"Tests/Diagnostics/\");\n\trunTestsInDirectory(&context, \"Tests/Preprocessor/\");\n\n\tif (!context.totalTestCount)\n\t{\n\t\tprintf(\"no tests run\");\n\t\treturn 0;\n\t}\n\n\tprintf(\"\\n===\\n%d%% of tests passed (%d/%d)\\n===\\n\\n\", (context.passedTestCount*100) / context.totalTestCount, context.passedTestCount, context.totalTestCount);\n\treturn context.passedTestCount == context.totalTestCount ? 0 : 1;\n}\n"
  },
  {
    "path": "Tests/SpireTestTool/os.cpp",
    "content": "// os.cpp\n#include \"os.h\"\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n\nusing namespace CoreLib::Basic;\n\n// Platform-specific code follows\n\n#ifdef _WIN32\n\n#include <Windows.h>\n\nbool OSFindFilesResult::findNextFile()\n{\n\tBOOL result = FindNextFileW(\n\t\tfindHandle_,\n\t\t&fileData_);\n\tif (!result)\n\t\treturn false;\n\n\tfilePath_ = directoryPath_ + String::FromWString(fileData_.cFileName);\n\n\treturn true;\n}\n\nOSFindFilesResult osFindFilesInDirectoryMatchingPattern(\n\tCoreLib::Basic::String directoryPath,\n\tCoreLib::Basic::String pattern)\n{\n\t// TODO: add separator to end of directory path if needed\n\n\tString searchPath = directoryPath + pattern;\n\n\tOSFindFilesResult result;\n\tHANDLE findHandle = FindFirstFileW(\n\t\tsearchPath.ToWString(),\n\t\t&result.fileData_);\n\n\tresult.directoryPath_ = directoryPath;\n\tresult.findHandle_ = findHandle;\n\n\tif (findHandle == INVALID_HANDLE_VALUE)\n\t{\n\t\tresult.error_ = kOSError_FileNotFound;\n\t}\n\telse\n\t{\n\t\tresult.filePath_ = directoryPath + String::FromWString(result.fileData_.cFileName);\n\t\tresult.error_ = kOSError_None;\n\t}\n\n\treturn result;\n}\n\n// OSProcessSpawner\n\nstruct OSProcessSpawner_ReaderThreadInfo\n{\n\tHANDLE\tfile;\n\tString\toutput;\n};\n\nstatic DWORD WINAPI osReaderThreadProc(LPVOID threadParam)\n{\n\tOSProcessSpawner_ReaderThreadInfo* info = (OSProcessSpawner_ReaderThreadInfo*)threadParam;\n\tHANDLE file = info->file;\n\n\tstatic const int kChunkSize = 1024;\n\tchar buffer[kChunkSize];\n\n\tStringBuilder outputBuilder;\n\n\t// We need to re-write the output to deal with line\n\t// endings, so we check for paired '\\r' and '\\n'\n\t// characters, which may span chunks.\n\tint prevChar = -1;\n\n\tfor (;;)\n\t{\n\t\tDWORD bytesRead = 0;\n\t\tBOOL readResult = ReadFile(file, buffer, kChunkSize, &bytesRead, nullptr);\n\n\t\tif (!readResult || GetLastError() == ERROR_BROKEN_PIPE)\n\t\t{\n\t\t\tbreak;\n\t\t}\n\n\t\t// walk the buffer and rewrite to eliminate '\\r' '\\n' pairs\n\t\tchar* readCursor = buffer;\n\t\tchar const* end = buffer + bytesRead;\n\t\tchar* writeCursor = buffer;\n\n\t\twhile (readCursor != end)\n\t\t{\n\t\t\tint p = prevChar;\n\t\t\tint c = *readCursor++;\n\t\t\tprevChar = c;\n\t\t\tswitch (c)\n\t\t\t{\n\t\t\tcase '\\r': case '\\n':\n\t\t\t\t// swallow input if '\\r' and '\\n' appear in sequence\n\t\t\t\tif ((p ^ c) == ('\\r' ^ '\\n'))\n\t\t\t\t{\n\t\t\t\t\t// but don't swallow the next byte\n\t\t\t\t\tprevChar = -1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// always replace '\\r' with '\\n'\n\t\t\t\tc = '\\n';\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t*writeCursor++ = c;\n\t\t}\n\t\tbytesRead = (DWORD)(writeCursor - buffer);\n\n\t\t// Note: Current Spire CoreLib gives no way to know\n\t\t// the length of the buffer, so we ultimately have\n\t\t// to just assume null termination...\n\t\toutputBuilder.Append(buffer, bytesRead);\n\t}\n\n\tinfo->output = outputBuilder.ProduceString();\n\n\treturn 0;\n}\n\nvoid OSProcessSpawner::pushExecutableName(\n\tCoreLib::Basic::String executableName)\n{\n\texecutableName_ = executableName;\n\tcommandLine_.Append(executableName);\n}\n\nvoid OSProcessSpawner::pushArgument(\n\tCoreLib::Basic::String argument)\n{\n\t// TODO(tfoley): handle cases where arguments need some escaping\n\tcommandLine_.Append(\" \");\n\tcommandLine_.Append(argument);\n}\n\nOSError OSProcessSpawner::spawnAndWaitForCompletion()\n{\n    SECURITY_ATTRIBUTES securityAttributes;\n    securityAttributes.nLength = sizeof(securityAttributes);\n    securityAttributes.lpSecurityDescriptor = nullptr;\n    securityAttributes.bInheritHandle = true;\n\n    // create stdout pipe for child process\n    HANDLE childStdOutReadTmp = nullptr;\n    HANDLE childStdOutWrite = nullptr;\n    if (!CreatePipe(&childStdOutReadTmp, &childStdOutWrite, &securityAttributes, 0))\n    {\n\t\treturn kOSError_OperationFailed;\n    }\n\n    // create stderr pipe for child process\n    HANDLE childStdErrReadTmp = nullptr;\n    HANDLE childStdErrWrite = nullptr;\n    if (!CreatePipe(&childStdErrReadTmp, &childStdErrWrite, &securityAttributes, 0))\n    {\n\t\treturn kOSError_OperationFailed;\n    }\n\n    // create stdin pipe for child process\n    HANDLE childStdInRead = nullptr;\n    HANDLE childStdInWriteTmp = nullptr;\n    if (!CreatePipe(&childStdInRead, &childStdInWriteTmp, &securityAttributes, 0))\n    {\n\t\treturn kOSError_OperationFailed;\n    }\n\n    HANDLE currentProcess = GetCurrentProcess();\n\n    // create a non-inheritable duplicate of the stdout reader\n    HANDLE childStdOutRead = nullptr;\n    if (!DuplicateHandle(\n        currentProcess, childStdOutReadTmp,\n        currentProcess, &childStdOutRead,\n        0, FALSE, DUPLICATE_SAME_ACCESS))\n    {\n\t\treturn kOSError_OperationFailed;\n    }\n    if (!CloseHandle(childStdOutReadTmp))\n    {\n\t\treturn kOSError_OperationFailed;\n    }\n\n    // create a non-inheritable duplicate of the stderr reader\n    HANDLE childStdErrRead = nullptr;\n    if (!DuplicateHandle(\n        currentProcess, childStdErrReadTmp,\n        currentProcess, &childStdErrRead,\n        0, FALSE, DUPLICATE_SAME_ACCESS))\n    {\n\t\treturn kOSError_OperationFailed;\n    }\n    if (!CloseHandle(childStdErrReadTmp))\n    {\n\t\treturn kOSError_OperationFailed;\n    }\n\n    // create a non-inheritable duplicate of the stdin writer\n    HANDLE childStdInWrite = nullptr;\n    if (!DuplicateHandle(\n        currentProcess, childStdInWriteTmp,\n        currentProcess, &childStdInWrite,\n        0, FALSE, DUPLICATE_SAME_ACCESS))\n    {\n\t\treturn kOSError_OperationFailed;\n    }\n    if (!CloseHandle(childStdInWriteTmp))\n    {\n\t\treturn kOSError_OperationFailed;\n    }\n\n    // Now we can actually get around to starting a process\n    PROCESS_INFORMATION processInfo;\n    ZeroMemory(&processInfo, sizeof(processInfo));\n\n    // TODO: switch to proper wide-character versions of these...\n    STARTUPINFOW startupInfo;\n    ZeroMemory(&startupInfo, sizeof(startupInfo));\n    startupInfo.cb = sizeof(startupInfo);\n    startupInfo.hStdError = childStdErrWrite;\n    startupInfo.hStdOutput = childStdOutWrite;\n    startupInfo.hStdInput = childStdInRead;\n    startupInfo.dwFlags = STARTF_USESTDHANDLES;\n\n    // `CreateProcess` requires write access to this, for some reason...\n\tBOOL success = CreateProcessW(\n\t\texecutableName_.ToWString(),\n\t\t(LPWSTR)commandLine_.ToString().ToWString(),\n\t\tnullptr,\n\t\tnullptr,\n\t\ttrue,\n\t\tCREATE_NO_WINDOW,\n\t\tnullptr, // TODO: allow specifying environment variables?\n        nullptr,\n        &startupInfo,\n        &processInfo);\n    if (!success)\n    {\n\t\treturn kOSError_OperationFailed;\n    }\n\n    // close handles we are now done with\n    CloseHandle(processInfo.hThread);\n    CloseHandle(childStdOutWrite);\n    CloseHandle(childStdErrWrite);\n    CloseHandle(childStdInRead);\n\n    // Create a thread to read from the child's stdout.\n    OSProcessSpawner_ReaderThreadInfo stdOutThreadInfo;\n    stdOutThreadInfo.file = childStdOutRead;\n    HANDLE stdOutThread = CreateThread(nullptr, 0, &osReaderThreadProc, (LPVOID)&stdOutThreadInfo, 0, nullptr);\n\n    // Create a thread to read from the child's stderr.\n    OSProcessSpawner_ReaderThreadInfo stdErrThreadInfo;\n    stdErrThreadInfo.file = childStdErrRead;\n    HANDLE stdErrThread = CreateThread(nullptr, 0, &osReaderThreadProc, (LPVOID)&stdErrThreadInfo, 0, nullptr);\n\n    // wait for the process to exit\n    // TODO: set a timeout as a safety measure...\n    WaitForSingleObject(processInfo.hProcess, INFINITE);\n\n    // get exit code for process\n    DWORD childExitCode = 0;\n    if (!GetExitCodeProcess(processInfo.hProcess, &childExitCode))\n    {\n        return kOSError_OperationFailed;\n    }\n\n    // wait for the reader threads\n    WaitForSingleObject(stdOutThread, INFINITE);\n    WaitForSingleObject(stdErrThread, INFINITE);\n\n    CloseHandle(processInfo.hProcess);\n    CloseHandle(childStdOutRead);\n    CloseHandle(childStdErrRead);\n    CloseHandle(childStdInWrite);\n\n\tstandardOutput_ = stdOutThreadInfo.output;\n\tstandardError_ = stdErrThreadInfo.output;\n\tresultCode_ = childExitCode;\n\n\treturn kOSError_None;\n}\n\n#else\n\n// TODO(tfoley): write a default POSIX implementation\n\n#endif\n"
  },
  {
    "path": "Tests/SpireTestTool/os.h",
    "content": "// os.h\n\n#include \"../../Source/CoreLib/LibIO.h\"\n\n// This file encapsulates the platform-specific operations needed by the test\n// runner that are not already provided by the core Spire libs\n\n#ifdef _WIN32\n\n// Include Windows header in a way that minimized namespace pollution.\n// TODO: We could try to avoid including this at all, but it would\n// mean trying to hide certain struct layouts, which would add\n// more dynamic allocation.\n#define WIN32_LEAN_AND_MEAN\n#define NOMINMAX\n#include <Windows.h>\n#undef WIN32_LEAN_AND_MEAN\n#undef NOMINMAX\n\n#else\n#endif\n\n// A simple set of error codes for possible runtime failures\nenum OSError\n{\n\tkOSError_None = 0,\n\tkOSError_InvalidArgument,\n\tkOSError_OperationFailed,\n\tkOSError_FileNotFound,\n};\n\n// A helper type used during enumeration of files in a directory.\nstruct OSFindFilesResult\n{\n\tCoreLib::Basic::String\t\t\t\tdirectoryPath_;\n\tCoreLib::Basic::String\t\t\t\tfilePath_;\n#ifdef WIN32\n\tHANDLE\t\t\t\tfindHandle_;\n\tWIN32_FIND_DATAW\tfileData_;\n\tOSError\t\t\t\terror_;\n#else\n#endif\n\n\tbool findNextFile();\n\n\tstruct Iterator\n\t{\n\t\tOSFindFilesResult* context_;\n\n\t\tbool operator!=(Iterator other) const { return context_ != other.context_; }\n\t\tvoid operator++()\n\t\t{\n\t\t\tif (!context_->findNextFile())\n\t\t\t{\n\t\t\t\tcontext_ = NULL;\n\t\t\t}\n\t\t}\n\t\tCoreLib::Basic::String const& operator*() const\n\t\t{\n\t\t\treturn context_->filePath_;\n\t\t}\n\t};\n\n\tIterator begin()\n\t{\n\t\tIterator result = { this };\n\t\treturn result;\n\t}\n\n\tIterator end()\n\t{\n\t\tIterator result = { NULL };\n\t\treturn result;\n\t}\n};\n\n// Enumerate files in the given `directoryPath` that match the provided\n// `pattern` as a simplified regex for files to return (e.g., \"*.txt\")\n// and return a logical collection of the results\n// that can be iterated with a range-based `for` loop:\n//\n// for( auto file : osFindFilesInDirectoryMatchingPattern(dir, \"*.txt\"))\n// { ... }\n//\n// Each element in the range is a `CoreLib::Basic::String` representing the\n// path to a file in the directory.\nOSFindFilesResult osFindFilesInDirectoryMatchingPattern(\n\tCoreLib::Basic::String directoryPath,\n\tCoreLib::Basic::String pattern);\n\n// An `OSProcessSpawner` can be used to launch a process, and handles\n// putting together the arguments in the form required by the target\n// platform, as well as capturing any output from the process (both\n// standard output and standard error) as strings.\nstruct OSProcessSpawner\n{\n\t// Set the executable name for the process to be spawned.\n\t// Note: this call must be made before any arguments are pushed.\n\tvoid pushExecutableName(\n\t\tCoreLib::Basic::String executableName);\n\n\t// Append an argument for the process to be spawned.\n\tvoid pushArgument(\n\t\tCoreLib::Basic::String argument);\n\n\t// Attempt to spawn the process, and wait for it to complete.\n\t// Returns an error if the attempt to spawn and/or wait fails,\n\t// but returns `kOSError_None` if the process is run to completion,\n\t// whether or not the process returns \"successfully\" (with a zero\n\t// result code);\n\tOSError spawnAndWaitForCompletion();\n\n\t// If the process is successfully spawned and completes, then\n\t// the user can query the result code that the process produce\n\t// on exit, along with the output it wrote to stdout and stderr.\n\ttypedef int ResultCode;\n\tResultCode getResultCode() { return resultCode_; }\n\tCoreLib::Basic::String const& getStandardOutput() { return standardOutput_; }\n\tCoreLib::Basic::String const& getStandardError() { return standardError_; }\n\n\t// \"private\" data follows\n\tCoreLib::Basic::String standardOutput_;\n\tCoreLib::Basic::String standardError_;\n\tResultCode resultCode_;\n#ifdef WIN32\n\tCoreLib::Basic::String executableName_;\n\tCoreLib::Basic::StringBuilder commandLine_;\n#else\n#endif\n};\n"
  },
  {
    "path": "test.bat",
    "content": "@echo off\nsetlocal\npushd %~dp0\n\n:: TODO: ensure that everything is built?\n\n.\\Source\\Debug\\SpireTestTool.exe"
  }
]