Commit 61c22e25 by John Kessenich

Web: Add separate texture/sampler, exclude *CubeArray*.

Looks like will add about 1K compressed size to executable footprint.
parent 5e634c89
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 7
; Bound: 99
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %color %i
OpExecutionMode %main OriginUpperLeft
OpSource ESSL 310
OpName %main "main"
OpName %color "color"
OpName %t2d "t2d"
OpName %s "s"
OpName %t3d "t3d"
OpName %sA "sA"
OpName %sShadow "sShadow"
OpName %i "i"
OpName %tex2D "tex2D"
OpName %texCube "texCube"
OpName %tex2DArray "tex2DArray"
OpName %itex2D "itex2D"
OpName %itex3D "itex3D"
OpName %itexCube "itexCube"
OpName %itex2DArray "itex2DArray"
OpName %utex2D "utex2D"
OpName %utex3D "utex3D"
OpName %utexCube "utexCube"
OpName %utex2DArray "utex2DArray"
OpName %tex3D "tex3D"
OpDecorate %color Location 0
OpDecorate %t2d RelaxedPrecision
OpDecorate %t2d DescriptorSet 0
OpDecorate %t2d Binding 3
OpDecorate %14 RelaxedPrecision
OpDecorate %s DescriptorSet 0
OpDecorate %s Binding 0
OpDecorate %23 RelaxedPrecision
OpDecorate %t3d DescriptorSet 0
OpDecorate %t3d Binding 4
OpDecorate %sA DescriptorSet 0
OpDecorate %sA Binding 2
OpDecorate %48 RelaxedPrecision
OpDecorate %51 RelaxedPrecision
OpDecorate %sShadow DescriptorSet 0
OpDecorate %sShadow Binding 1
OpDecorate %i RelaxedPrecision
OpDecorate %i Flat
OpDecorate %i Location 0
OpDecorate %tex2D RelaxedPrecision
OpDecorate %tex2D DescriptorSet 0
OpDecorate %tex2D Binding 5
OpDecorate %texCube RelaxedPrecision
OpDecorate %texCube DescriptorSet 0
OpDecorate %texCube Binding 6
OpDecorate %tex2DArray DescriptorSet 0
OpDecorate %tex2DArray Binding 15
OpDecorate %itex2D DescriptorSet 0
OpDecorate %itex2D Binding 16
OpDecorate %itex3D DescriptorSet 0
OpDecorate %itex3D Binding 17
OpDecorate %itexCube DescriptorSet 0
OpDecorate %itexCube Binding 18
OpDecorate %itex2DArray DescriptorSet 0
OpDecorate %itex2DArray Binding 19
OpDecorate %utex2D DescriptorSet 0
OpDecorate %utex2D Binding 20
OpDecorate %utex3D DescriptorSet 0
OpDecorate %utex3D Binding 21
OpDecorate %utexCube DescriptorSet 0
OpDecorate %utexCube Binding 22
OpDecorate %utex2DArray DescriptorSet 0
OpDecorate %utex2DArray Binding 23
OpDecorate %tex3D DescriptorSet 0
OpDecorate %tex3D Binding 36
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%color = OpVariable %_ptr_Output_v4float Output
%10 = OpTypeImage %float 2D 0 0 0 1 Unknown
%11 = OpTypeSampledImage %10
%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
%t2d = OpVariable %_ptr_UniformConstant_11 UniformConstant
%15 = OpTypeSampler
%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15
%s = OpVariable %_ptr_UniformConstant_15 UniformConstant
%v2float = OpTypeVector %float 2
%float_0_5 = OpConstant %float 0.5
%22 = OpConstantComposite %v2float %float_0_5 %float_0_5
%24 = OpTypeImage %float 3D 0 0 0 1 Unknown
%25 = OpTypeSampledImage %24
%uint = OpTypeInt 32 0
%uint_4 = OpConstant %uint 4
%_arr_25_uint_4 = OpTypeArray %25 %uint_4
%_ptr_UniformConstant__arr_25_uint_4 = OpTypePointer UniformConstant %_arr_25_uint_4
%t3d = OpVariable %_ptr_UniformConstant__arr_25_uint_4 UniformConstant
%int = OpTypeInt 32 1
%int_1 = OpConstant %int 1
%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25
%_arr_15_uint_4 = OpTypeArray %15 %uint_4
%_ptr_UniformConstant__arr_15_uint_4 = OpTypePointer UniformConstant %_arr_15_uint_4
%sA = OpVariable %_ptr_UniformConstant__arr_15_uint_4 UniformConstant
%int_2 = OpConstant %int 2
%v3float = OpTypeVector %float 3
%44 = OpConstantComposite %v3float %float_0_5 %float_0_5 %float_0_5
%sShadow = OpVariable %_ptr_UniformConstant_15 UniformConstant
%_ptr_Input_int = OpTypePointer Input %int
%i = OpVariable %_ptr_Input_int Input
%tex2D = OpVariable %_ptr_UniformConstant_11 UniformConstant
%58 = OpTypeImage %float Cube 0 0 0 1 Unknown
%59 = OpTypeSampledImage %58
%_ptr_UniformConstant_59 = OpTypePointer UniformConstant %59
%texCube = OpVariable %_ptr_UniformConstant_59 UniformConstant
%62 = OpTypeImage %float 2D 0 1 0 1 Unknown
%63 = OpTypeSampledImage %62
%_ptr_UniformConstant_63 = OpTypePointer UniformConstant %63
%tex2DArray = OpVariable %_ptr_UniformConstant_63 UniformConstant
%66 = OpTypeImage %int 2D 0 0 0 1 Unknown
%67 = OpTypeSampledImage %66
%_ptr_UniformConstant_67 = OpTypePointer UniformConstant %67
%itex2D = OpVariable %_ptr_UniformConstant_67 UniformConstant
%70 = OpTypeImage %int 3D 0 0 0 1 Unknown
%71 = OpTypeSampledImage %70
%_ptr_UniformConstant_71 = OpTypePointer UniformConstant %71
%itex3D = OpVariable %_ptr_UniformConstant_71 UniformConstant
%74 = OpTypeImage %int Cube 0 0 0 1 Unknown
%75 = OpTypeSampledImage %74
%_ptr_UniformConstant_75 = OpTypePointer UniformConstant %75
%itexCube = OpVariable %_ptr_UniformConstant_75 UniformConstant
%78 = OpTypeImage %int 2D 0 1 0 1 Unknown
%79 = OpTypeSampledImage %78
%_ptr_UniformConstant_79 = OpTypePointer UniformConstant %79
%itex2DArray = OpVariable %_ptr_UniformConstant_79 UniformConstant
%82 = OpTypeImage %uint 2D 0 0 0 1 Unknown
%83 = OpTypeSampledImage %82
%_ptr_UniformConstant_83 = OpTypePointer UniformConstant %83
%utex2D = OpVariable %_ptr_UniformConstant_83 UniformConstant
%86 = OpTypeImage %uint 3D 0 0 0 1 Unknown
%87 = OpTypeSampledImage %86
%_ptr_UniformConstant_87 = OpTypePointer UniformConstant %87
%utex3D = OpVariable %_ptr_UniformConstant_87 UniformConstant
%90 = OpTypeImage %uint Cube 0 0 0 1 Unknown
%91 = OpTypeSampledImage %90
%_ptr_UniformConstant_91 = OpTypePointer UniformConstant %91
%utexCube = OpVariable %_ptr_UniformConstant_91 UniformConstant
%94 = OpTypeImage %uint 2D 0 1 0 1 Unknown
%95 = OpTypeSampledImage %94
%_ptr_UniformConstant_95 = OpTypePointer UniformConstant %95
%utex2DArray = OpVariable %_ptr_UniformConstant_95 UniformConstant
%tex3D = OpVariable %_ptr_UniformConstant_25 UniformConstant
%main = OpFunction %void None %3
%5 = OpLabel
%14 = OpLoad %11 %t2d
%18 = OpLoad %15 %s
%19 = OpSampledImage %11 %14 %18
%23 = OpImageSampleImplicitLod %v4float %19 %22
OpStore %color %23
%34 = OpAccessChain %_ptr_UniformConstant_25 %t3d %int_1
%35 = OpLoad %25 %34
%40 = OpAccessChain %_ptr_UniformConstant_15 %sA %int_2
%41 = OpLoad %15 %40
%42 = OpSampledImage %25 %35 %41
%45 = OpImageSampleImplicitLod %v4float %42 %44
%46 = OpLoad %v4float %color
%47 = OpFAdd %v4float %46 %45
OpStore %color %47
%48 = OpLoad %11 %t2d
%49 = OpLoad %15 %s
%50 = OpSampledImage %11 %48 %49
%51 = OpImageSampleImplicitLod %v4float %50 %22
%52 = OpLoad %v4float %color
%53 = OpFAdd %v4float %52 %51
OpStore %color %53
OpReturn
OpFunctionEnd
#version 310 es
precision highp sampler;
precision highp samplerShadow;
precision highp texture2DArray;
precision highp itexture2D;
precision highp itexture3D;
precision highp itextureCube;
precision highp itexture2DArray;
precision highp utexture2D;
precision highp utexture3D;
precision highp utextureCube;
precision highp utexture2DArray;
precision highp texture3D;
precision highp float;
layout(binding = 0) uniform sampler s;
layout(binding = 1) uniform samplerShadow sShadow;
layout(binding = 2) uniform sampler sA[4];
layout(binding = 3) uniform texture2D t2d;
layout(binding = 4) uniform texture3D t3d[4];
layout(location = 0) flat in int i;
layout(location = 0) out vec4 color;
void main()
{
color = texture(sampler2D(t2d, s), vec2(0.5));
color += texture(sampler3D(t3d[1], sA[2]), vec3(0.5));
color += texture(sampler2D(t2d, s), vec2(0.5));
}
layout(binding = 5) uniform texture2D tex2D;
layout(binding = 6) uniform textureCube texCube;
layout(binding = 15) uniform texture2DArray tex2DArray;
layout(binding = 16) uniform itexture2D itex2D;
layout(binding = 17) uniform itexture3D itex3D;
layout(binding = 18) uniform itextureCube itexCube;
layout(binding = 19) uniform itexture2DArray itex2DArray;
layout(binding = 20) uniform utexture2D utex2D;
layout(binding = 21) uniform utexture3D utex3D;
layout(binding = 22) uniform utextureCube utexCube;
layout(binding = 23) uniform utexture2DArray utex2DArray;
layout(binding = 36) uniform texture3D tex3D;
void foo()
{
sampler2D (tex2D, s);
samplerCube (texCube, s);
samplerCubeShadow (texCube, sShadow);
sampler2DArray (tex2DArray, s);
sampler2DArrayShadow (tex2DArray, sShadow);
isampler2D (itex2D, s);
isampler3D (itex3D, s);
isamplerCube (itexCube, s);
isampler2DArray (itex2DArray, s);
usampler2D (utex2D, s);
usampler3D (utex3D, s);
usamplerCube (utexCube, s);
usampler2DArray (utex2DArray, s);
sampler3D (tex3D, s);
sampler2DShadow (tex2D, sShadow);
}
......@@ -5,3 +5,4 @@ web.controlFlow.frag
web.operations.frag
web.texture.frag
web.array.frag
web.separate.frag
......@@ -79,6 +79,7 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
bool ms : 1;
bool image : 1; // image, combined should be false
bool combined : 1; // true means texture is combined with a sampler, false means texture with no sampler
bool sampler : 1; // true means a pure sampler, other fields should be clear()
#ifdef ENABLE_HLSL
unsigned int vectorSize : 3; // vector return type size.
unsigned int getVectorSize() const { return vectorSize; }
......@@ -105,8 +106,6 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
bool isRect() const { return false; }
bool isSubpass() const { return false; }
bool isCombined() const { return true; }
bool isPureSampler() const { return false; }
bool isTexture() const { return false; }
bool isImage() const { return false; }
bool isImageClass() const { return false; }
bool isMultiSample() const { return false; }
......@@ -114,7 +113,6 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
void setExternal(bool e) { }
bool isYuv() const { return false; }
#else
bool sampler : 1; // true means a pure sampler, other fields should be clear()
bool external : 1; // GL_OES_EGL_image_external
bool yuv : 1; // GL_EXT_YUV_target
// Some languages support structures as sample results. Storing the whole structure in the
......@@ -125,8 +123,6 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
bool isRect() const { return dim == EsdRect; }
bool isSubpass() const { return dim == EsdSubpass; }
bool isCombined() const { return combined; }
bool isPureSampler() const { return sampler; }
bool isTexture() const { return !sampler && !image; }
bool isImage() const { return image && !isSubpass(); }
bool isImageClass() const { return image; }
bool isMultiSample() const { return ms; }
......@@ -134,6 +130,9 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
void setExternal(bool e) { external = e; }
bool isYuv() const { return yuv; }
#endif
bool isTexture() const { return !sampler && !image; }
bool isPureSampler() const { return sampler; }
void setCombined(bool c) { combined = c; }
void setBasicType(TBasicType t) { type = t; }
TBasicType getBasicType() const { return type; }
......@@ -149,8 +148,8 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
ms = false;
image = false;
combined = false;
#ifndef GLSLANG_WEB
sampler = false;
#ifndef GLSLANG_WEB
external = false;
yuv = false;
#endif
......@@ -197,6 +196,14 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
ms = m;
}
// make a pure sampler, no texture, no image, nothing combined, the 'sampler' keyword
void setPureSampler(bool s)
{
clear();
sampler = true;
shadow = s;
}
#ifndef GLSLANG_WEB
// make a subpass input attachment
void setSubpass(TBasicType t, bool m = false)
......@@ -207,14 +214,6 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
dim = EsdSubpass;
ms = m;
}
// make a pure sampler, no texture, no image, nothing combined, the 'sampler' keyword
void setPureSampler(bool s)
{
clear();
sampler = true;
shadow = s;
}
#endif
bool operator==(const TSampler& right) const
......@@ -1922,6 +1921,7 @@ public:
case EbtFloat: return "float";
case EbtInt: return "int";
case EbtUint: return "uint";
case EbtSampler: return "sampler/image";
#ifndef GLSLANG_WEB
case EbtVoid: return "void";
case EbtDouble: return "double";
......@@ -1934,7 +1934,6 @@ public:
case EbtUint64: return "uint64_t";
case EbtBool: return "bool";
case EbtAtomicUint: return "atomic_uint";
case EbtSampler: return "sampler/image";
case EbtStruct: return "structure";
case EbtBlock: return "block";
case EbtAccStructNV: return "accelerationStructureNV";
......
......@@ -5314,7 +5314,7 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c
#ifdef GLSLANG_WEB
const int ms = 0;
#else
for (int ms = 0; ms <= 1; ++ms)
for (int ms = 0; ms <= 1; ++ms) // loop over "bool" multisample or not
#endif
{
#ifndef GLSLANG_WEB
......
......@@ -2794,10 +2794,8 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
// See if it's a matrix
bool constructingMatrix = false;
switch (op) {
#ifndef GLSLANG_WEB
case EOpConstructTextureSampler:
return constructorTextureSamplerError(loc, function);
#endif
case EOpConstructMat2x2:
case EOpConstructMat2x3:
case EOpConstructMat2x4:
......
......@@ -564,10 +564,6 @@ void TScanContext::fillInKeywordMap()
(*KeywordMap)["sampler2D"] = SAMPLER2D;
(*KeywordMap)["samplerCube"] = SAMPLERCUBE;
(*KeywordMap)["samplerCubeArray"] = SAMPLERCUBEARRAY;
(*KeywordMap)["samplerCubeArrayShadow"] = SAMPLERCUBEARRAYSHADOW;
(*KeywordMap)["isamplerCubeArray"] = ISAMPLERCUBEARRAY;
(*KeywordMap)["usamplerCubeArray"] = USAMPLERCUBEARRAY;
(*KeywordMap)["samplerCubeShadow"] = SAMPLERCUBESHADOW;
(*KeywordMap)["sampler2DArray"] = SAMPLER2DARRAY;
(*KeywordMap)["sampler2DArrayShadow"] = SAMPLER2DARRAYSHADOW;
......@@ -582,7 +578,30 @@ void TScanContext::fillInKeywordMap()
(*KeywordMap)["sampler3D"] = SAMPLER3D;
(*KeywordMap)["sampler2DShadow"] = SAMPLER2DSHADOW;
(*KeywordMap)["texture2D"] = TEXTURE2D;
(*KeywordMap)["textureCube"] = TEXTURECUBE;
(*KeywordMap)["texture2DArray"] = TEXTURE2DARRAY;
(*KeywordMap)["itexture2D"] = ITEXTURE2D;
(*KeywordMap)["itexture3D"] = ITEXTURE3D;
(*KeywordMap)["itextureCube"] = ITEXTURECUBE;
(*KeywordMap)["itexture2DArray"] = ITEXTURE2DARRAY;
(*KeywordMap)["utexture2D"] = UTEXTURE2D;
(*KeywordMap)["utexture3D"] = UTEXTURE3D;
(*KeywordMap)["utextureCube"] = UTEXTURECUBE;
(*KeywordMap)["utexture2DArray"] = UTEXTURE2DARRAY;
(*KeywordMap)["texture3D"] = TEXTURE3D;
(*KeywordMap)["sampler"] = SAMPLER;
(*KeywordMap)["samplerShadow"] = SAMPLERSHADOW;
#ifndef GLSLANG_WEB
(*KeywordMap)["textureCubeArray"] = TEXTURECUBEARRAY;
(*KeywordMap)["itextureCubeArray"] = ITEXTURECUBEARRAY;
(*KeywordMap)["utextureCubeArray"] = UTEXTURECUBEARRAY;
(*KeywordMap)["samplerCubeArray"] = SAMPLERCUBEARRAY;
(*KeywordMap)["samplerCubeArrayShadow"] = SAMPLERCUBEARRAYSHADOW;
(*KeywordMap)["isamplerCubeArray"] = ISAMPLERCUBEARRAY;
(*KeywordMap)["usamplerCubeArray"] = USAMPLERCUBEARRAY;
(*KeywordMap)["sampler1DArrayShadow"] = SAMPLER1DARRAYSHADOW;
(*KeywordMap)["isampler1DArray"] = ISAMPLER1DARRAY;
(*KeywordMap)["usampler1D"] = USAMPLER1D;
......@@ -609,28 +628,11 @@ void TScanContext::fillInKeywordMap()
(*KeywordMap)["__samplerExternal2DY2YEXT"] = SAMPLEREXTERNAL2DY2YEXT; // GL_EXT_YUV_target
(*KeywordMap)["sampler"] = SAMPLER;
(*KeywordMap)["samplerShadow"] = SAMPLERSHADOW;
(*KeywordMap)["texture2D"] = TEXTURE2D;
(*KeywordMap)["textureCube"] = TEXTURECUBE;
(*KeywordMap)["textureCubeArray"] = TEXTURECUBEARRAY;
(*KeywordMap)["itextureCubeArray"] = ITEXTURECUBEARRAY;
(*KeywordMap)["utextureCubeArray"] = UTEXTURECUBEARRAY;
(*KeywordMap)["itexture1DArray"] = ITEXTURE1DARRAY;
(*KeywordMap)["utexture1D"] = UTEXTURE1D;
(*KeywordMap)["itexture1D"] = ITEXTURE1D;
(*KeywordMap)["utexture1DArray"] = UTEXTURE1DARRAY;
(*KeywordMap)["textureBuffer"] = TEXTUREBUFFER;
(*KeywordMap)["texture2DArray"] = TEXTURE2DARRAY;
(*KeywordMap)["itexture2D"] = ITEXTURE2D;
(*KeywordMap)["itexture3D"] = ITEXTURE3D;
(*KeywordMap)["itextureCube"] = ITEXTURECUBE;
(*KeywordMap)["itexture2DArray"] = ITEXTURE2DARRAY;
(*KeywordMap)["utexture2D"] = UTEXTURE2D;
(*KeywordMap)["utexture3D"] = UTEXTURE3D;
(*KeywordMap)["utextureCube"] = UTEXTURECUBE;
(*KeywordMap)["utexture2DArray"] = UTEXTURE2DARRAY;
(*KeywordMap)["itexture2DRect"] = ITEXTURE2DRECT;
(*KeywordMap)["utexture2DRect"] = UTEXTURE2DRECT;
(*KeywordMap)["itextureBuffer"] = ITEXTUREBUFFER;
......@@ -642,7 +644,6 @@ void TScanContext::fillInKeywordMap()
(*KeywordMap)["itexture2DMSArray"] = ITEXTURE2DMSARRAY;
(*KeywordMap)["utexture2DMSArray"] = UTEXTURE2DMSARRAY;
(*KeywordMap)["texture1D"] = TEXTURE1D;
(*KeywordMap)["texture3D"] = TEXTURE3D;
(*KeywordMap)["texture2DRect"] = TEXTURE2DRECT;
(*KeywordMap)["texture1DArray"] = TEXTURE1DARRAY;
......@@ -1321,7 +1322,6 @@ int TScanContext::tokenizeIdentifier()
return keyword;
return identifierOrType();
#endif
case SAMPLERCUBEARRAY:
case SAMPLERCUBEARRAYSHADOW:
......@@ -1335,6 +1335,15 @@ int TScanContext::tokenizeIdentifier()
reservedWord();
return keyword;
case TEXTURECUBEARRAY:
case ITEXTURECUBEARRAY:
case UTEXTURECUBEARRAY:
if (parseContext.spvVersion.vulkan > 0)
return keyword;
else
return identifierOrType();
#endif
case UINT:
case UVEC2:
case UVEC3:
......@@ -1369,6 +1378,25 @@ int TScanContext::tokenizeIdentifier()
}
return keyword;
case TEXTURE2D:
case TEXTURECUBE:
case TEXTURE2DARRAY:
case ITEXTURE2D:
case ITEXTURE3D:
case ITEXTURECUBE:
case ITEXTURE2DARRAY:
case UTEXTURE2D:
case UTEXTURE3D:
case UTEXTURECUBE:
case UTEXTURE2DARRAY:
case TEXTURE3D:
case SAMPLER:
case SAMPLERSHADOW:
if (parseContext.spvVersion.vulkan > 0)
return keyword;
else
return identifierOrType();
#ifndef GLSLANG_WEB
case ISAMPLER1D:
case ISAMPLER1DARRAY:
......@@ -1458,25 +1486,11 @@ int TScanContext::tokenizeIdentifier()
return keyword;
return identifierOrType();
case TEXTURE2D:
case TEXTURECUBE:
case TEXTURECUBEARRAY:
case ITEXTURECUBEARRAY:
case UTEXTURECUBEARRAY:
case ITEXTURE1DARRAY:
case UTEXTURE1D:
case ITEXTURE1D:
case UTEXTURE1DARRAY:
case TEXTUREBUFFER:
case TEXTURE2DARRAY:
case ITEXTURE2D:
case ITEXTURE3D:
case ITEXTURECUBE:
case ITEXTURE2DARRAY:
case UTEXTURE2D:
case UTEXTURE3D:
case UTEXTURECUBE:
case UTEXTURE2DARRAY:
case ITEXTURE2DRECT:
case UTEXTURE2DRECT:
case ITEXTUREBUFFER:
......@@ -1488,11 +1502,8 @@ int TScanContext::tokenizeIdentifier()
case ITEXTURE2DMSARRAY:
case UTEXTURE2DMSARRAY:
case TEXTURE1D:
case TEXTURE3D:
case TEXTURE2DRECT:
case TEXTURE1DARRAY:
case SAMPLER:
case SAMPLERSHADOW:
if (parseContext.spvVersion.vulkan > 0)
return keyword;
else
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment