| 1 | <?php |
| 2 | namespace Std\Lib\Syntax; |
| 3 | |
| 4 | class Hlsl extends Language { |
| 5 | protected bool $preprocessor = true; |
| 6 | protected array $headerDirectives = ['include']; |
| 7 | protected array $strings = ['"']; |
| 8 | protected string $digitSep = ''; |
| 9 | |
| 10 | protected array $tokens = [ |
| 11 | 'keyword' => [ |
| 12 | 'if', 'else', 'for', 'while', 'do', 'break', 'continue', 'discard', 'return', 'switch', 'case', 'default', |
| 13 | 'struct', 'class', 'interface', 'namespace', 'typedef', 'cbuffer', 'tbuffer', 'register', 'packoffset', 'static', 'const', |
| 14 | 'uniform', 'volatile', 'extern', 'inline', 'export', 'in', 'out', 'inout', 'groupshared', 'nointerpolation', 'linear', |
| 15 | 'centroid', 'noperspective', 'sample', 'precise', 'row_major', 'column_major', 'snorm', 'unorm', 'globallycoherent', |
| 16 | 'shared', 'template', 'typename', 'using', 'sizeof', 'this', 'enum', 'operator', 'payload', 'vertices', 'indices', 'primitives', |
| 17 | ], |
| 18 | 'constant' => [ |
| 19 | 'true', 'false', |
| 20 | ], |
| 21 | 'type' => [ |
| 22 | 'void', 'vector', 'matrix', 'string', |
| 23 | 'Texture1D', 'Texture1DArray', 'Texture2D', 'Texture2DArray', 'Texture2DMS', 'Texture2DMSArray', 'Texture3D', 'TextureCube', 'TextureCubeArray', |
| 24 | 'RWTexture1D', 'RWTexture1DArray', 'RWTexture2D', 'RWTexture2DArray', 'RWTexture3D', 'RWTexture2DMS', 'RWTexture2DMSArray', |
| 25 | 'RasterizerOrderedTexture1D', 'RasterizerOrderedTexture2D', 'RasterizerOrderedTexture3D', 'RasterizerOrderedBuffer', |
| 26 | 'FeedbackTexture2D', 'FeedbackTexture2DArray', |
| 27 | 'Buffer', 'RWBuffer', 'StructuredBuffer', 'RWStructuredBuffer', 'ByteAddressBuffer', 'RWByteAddressBuffer', |
| 28 | 'AppendStructuredBuffer', 'ConsumeStructuredBuffer', 'ConstantBuffer', 'TextureBuffer', |
| 29 | 'SamplerState', 'SamplerComparisonState', 'sampler', 'sampler1D', 'sampler2D', 'sampler3D', 'samplerCUBE', |
| 30 | 'RaytracingAccelerationStructure', 'RayDesc', 'RayQuery', 'BuiltInTriangleIntersectionAttributes', |
| 31 | 'InputPatch', 'OutputPatch', 'PointStream', 'LineStream', 'TriangleStream', |
| 32 | ], |
| 33 | 'builtin' => [ |
| 34 | 'abort', 'abs', 'acos', 'all', 'AllMemoryBarrier', 'AllMemoryBarrierWithGroupSync', 'any', 'asdouble', 'asfloat', 'asfloat16', 'asin', 'asint', |
| 35 | 'asint16', 'asuint', 'asuint16', 'atan', 'atan2', 'ceil', 'CheckAccessFullyMapped', 'clamp', 'clip', 'cos', 'cosh', 'countbits', 'cross', |
| 36 | 'D3DCOLORtoUBYTE4', 'ddx', 'ddx_coarse', 'ddx_fine', 'ddy', 'ddy_coarse', 'ddy_fine', 'degrees', 'determinant', 'DeviceMemoryBarrier', |
| 37 | 'DeviceMemoryBarrierWithGroupSync', 'distance', 'dot', 'dst', 'errorf', 'EvaluateAttributeAtCentroid', 'EvaluateAttributeAtSample', |
| 38 | 'EvaluateAttributeSnapped', 'exp', 'exp2', 'f16tof32', 'f32tof16', 'faceforward', 'firstbithigh', 'firstbitlow', 'floor', 'fma', 'fmod', |
| 39 | 'frac', 'frexp', 'fwidth', 'GetRenderTargetSampleCount', 'GetRenderTargetSamplePosition', 'GroupMemoryBarrier', 'GroupMemoryBarrierWithGroupSync', |
| 40 | 'InterlockedAdd', 'InterlockedAnd', 'InterlockedCompareExchange', 'InterlockedCompareStore', 'InterlockedExchange', 'InterlockedMax', |
| 41 | 'InterlockedMin', 'InterlockedOr', 'InterlockedXor', 'isfinite', 'isinf', 'isnan', 'ldexp', 'length', 'lerp', 'lit', 'log', 'log10', 'log2', |
| 42 | 'mad', 'max', 'min', 'modf', 'msad4', 'mul', 'noise', 'normalize', 'pow', 'printf', 'radians', 'rcp', 'reflect', 'refract', 'reversebits', |
| 43 | 'round', 'rsqrt', 'saturate', 'sign', 'sin', 'sincos', 'sinh', 'smoothstep', 'sqrt', 'step', 'tan', 'tanh', 'tex1D', 'tex2D', 'tex3D', 'texCUBE', |
| 44 | 'transpose', 'trunc', 'NonUniformResourceIndex', 'select', 'and', 'or', |
| 45 | 'WaveActiveAllEqual', 'WaveActiveAllTrue', 'WaveActiveAnyTrue', 'WaveActiveBallot', 'WaveActiveBitAnd', 'WaveActiveBitOr', 'WaveActiveBitXor', |
| 46 | 'WaveActiveCountBits', 'WaveActiveMax', 'WaveActiveMin', 'WaveActiveProduct', 'WaveActiveSum', 'WaveGetLaneCount', 'WaveGetLaneIndex', |
| 47 | 'WaveIsFirstLane', 'WavePrefixCountBits', 'WavePrefixProduct', 'WavePrefixSum', 'WaveReadLaneAt', 'WaveReadLaneFirst', |
| 48 | 'QuadReadAcrossDiagonal', 'QuadReadAcrossX', 'QuadReadAcrossY', 'QuadReadLaneAt', |
| 49 | 'TraceRay', 'ReportHit', 'IgnoreHit', 'AcceptHitAndEndSearch', 'CallShader', 'DispatchRaysIndex', 'DispatchRaysDimensions', |
| 50 | 'WorldRayOrigin', 'WorldRayDirection', 'ObjectRayOrigin', 'ObjectRayDirection', 'RayTMin', 'RayTCurrent', 'RayFlags', 'InstanceIndex', |
| 51 | 'InstanceID', 'GeometryIndex', 'PrimitiveIndex', 'HitKind', 'ObjectToWorld3x4', 'ObjectToWorld4x3', 'WorldToObject3x4', 'WorldToObject4x3', |
| 52 | 'SetMeshOutputCounts', 'DispatchMesh', |
| 53 | // リソースのメソッド |
| 54 | 'Sample', 'SampleLevel', 'SampleGrad', 'SampleBias', 'SampleCmp', 'SampleCmpLevel', 'SampleCmpLevelZero', 'Load', 'Store', 'GetDimensions', |
| 55 | 'Gather', 'GatherRed', 'GatherGreen', 'GatherBlue', 'GatherAlpha', 'GatherCmp', 'CalculateLevelOfDetail', 'Append', 'Consume', |
| 56 | 'IncrementCounter', 'DecrementCounter', 'Load2', 'Load3', 'Load4', 'Store2', 'Store3', 'Store4', |
| 57 | ], |
| 58 | ]; |
| 59 | |
| 60 | /** @var string[] 「[」の直後だけ属性として扱う名前(「loop」「branch」等は普通の単語でもある) */ |
| 61 | protected array $attributes = [ |
| 62 | 'numthreads', 'unroll', 'loop', 'branch', 'flatten', 'fastopt', 'allow_uav_condition', 'call', 'forcecase', 'earlydepthstencil', |
| 63 | 'maxvertexcount', 'domain', 'partitioning', 'outputtopology', 'outputcontrolpoints', 'patchconstantfunc', 'maxtessfactor', |
| 64 | 'instance', 'RootSignature', 'shader', 'WaveSize', 'NodeLaunch', 'NodeDispatchGrid', 'NodeMaxDispatchGrid', 'NumThreads', 'vk', |
| 65 | ]; |
| 66 | |
| 67 | /** @var string[] スカラー型(ベクトル・行列型を作る元) */ |
| 68 | protected array $scalars = [ |
| 69 | 'bool', 'int', 'uint', 'dword', 'half', 'float', 'double', 'min16float', 'min10float', 'min16int', 'min12int', 'min16uint', |
| 70 | 'int16_t', 'uint16_t', 'int32_t', 'uint32_t', 'int64_t', 'uint64_t', 'float16_t', 'float32_t', 'float64_t', |
| 71 | ]; |
| 72 | |
| 73 | public function prepare(string $code): void { |
| 74 | $tokens = $this->tokens; |
| 75 | foreach (self::vectorTypes($this->scalars) as $t) $tokens['type'][] = $t; |
| 76 | $this->words = $this->buildWords($tokens); |
| 77 | } |
| 78 | |
| 79 | public function classify(string $word, array $ctx): ?string { |
| 80 | // セマンティクス(: SV_Position, : TEXCOORD0) |
| 81 | if (str_starts_with($word, 'SV_')) return 'variable'; |
| 82 | if ($ctx['prev'] === ':' && preg_match('/^[A-Z][A-Z0-9_]*$/', $word)) return 'variable'; |
| 83 | // 属性([numthreads(8, 8, 1)]) |
| 84 | if ($ctx['prev'] === '[' && in_array($word, $this->attributes, true)) return 'attribute'; |
| 85 | return parent::classify($word, $ctx); |
| 86 | } |
| 87 | } |