| #!/usr/bin/env python | 
 | # Copyright (c) 2016 Google Inc. | 
 |  | 
 | # Licensed under the Apache License, Version 2.0 (the "License"); | 
 | # you may not use this file except in compliance with the License. | 
 | # You may obtain a copy of the License at | 
 | # | 
 | #     http://www.apache.org/licenses/LICENSE-2.0 | 
 | # | 
 | # Unless required by applicable law or agreed to in writing, software | 
 | # distributed under the License is distributed on an "AS IS" BASIS, | 
 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | # See the License for the specific language governing permissions and | 
 | # limitations under the License. | 
 | """Generates Vim syntax rules for SPIR-V assembly (.spvasm) files""" | 
 |  | 
 | import json | 
 |  | 
 | PREAMBLE="""" Vim syntax file | 
 | " Language:   spvasm | 
 | " Generated by SPIRV-Tools | 
 |  | 
 | if version < 600 | 
 |   syntax clear | 
 | elseif exists("b:current_syntax") | 
 |   finish | 
 | endif | 
 |  | 
 | syn case match | 
 | """ | 
 |  | 
 | POSTAMBLE=""" | 
 |  | 
 | syntax keyword spvasmTodo TODO FIXME contained | 
 |  | 
 | syn match   spvasmIdNumber /%\d\+\>/ | 
 |  | 
 | " The assembler treats the leading minus sign as part of the number token. | 
 | " This applies to integers, and to floats below. | 
 | syn match   spvasmNumber /-\?\<\d\+\>/ | 
 |  | 
 | " Floating point literals. | 
 | " In general, C++ requires at least digit in the mantissa, and the | 
 | " floating point is optional.  This applies to both the regular decimal float | 
 | " case and the hex float case. | 
 |  | 
 | " First case: digits before the optional decimal, no trailing digits. | 
 | syn match   spvasmFloat  /-\?\d\+\.\?\(e[+-]\d\+\)\?/ | 
 | " Second case: optional digits before decimal, trailing digits | 
 | syn match   spvasmFloat  /-\?\d*\.\d\+\(e[+-]\d\+\)\?/ | 
 |  | 
 | " First case: hex digits before the optional decimal, no trailing hex digits. | 
 | syn match   spvasmFloat  /-\?0[xX]\\x\+\.\?p[-+]\d\+/ | 
 | " Second case: optional hex digits before decimal, trailing hex digits | 
 | syn match   spvasmFloat  /-\?0[xX]\\x*\.\\x\+p[-+]\d\+/ | 
 |  | 
 | syn match   spvasmComment /;.*$/ contains=spvasmTodo | 
 | syn region  spvasmString start=/"/ skip=/\\\\"/ end=/"/ | 
 | syn match   spvasmId /%[a-zA-Z_][a-zA-Z_0-9]*/ | 
 |  | 
 | " Highlight unknown constants and statements as errors | 
 | syn match   spvasmError /[a-zA-Z][a-zA-Z_0-9]*/ | 
 |  | 
 |  | 
 | if version >= 508 || !exists("did_c_syn_inits") | 
 |   if version < 508 | 
 |     let did_c_syn_inits = 1 | 
 |     command -nargs=+ HiLink hi link <args> | 
 |   else | 
 |     command -nargs=+ HiLink hi def link <args> | 
 |   endif | 
 |  | 
 |   HiLink spvasmStatement Statement | 
 |   HiLink spvasmNumber Number | 
 |   HiLink spvasmComment Comment | 
 |   HiLink spvasmString String | 
 |   HiLink spvasmFloat Float | 
 |   HiLink spvasmConstant Constant | 
 |   HiLink spvasmIdNumber Identifier | 
 |   HiLink spvasmId Identifier | 
 |   HiLink spvasmTodo Todo | 
 |  | 
 |   delcommand HiLink | 
 | endif | 
 |  | 
 | let b:current_syntax = "spvasm" | 
 | """ | 
 |  | 
 | # This list is taken from the description of OpSpecConstantOp in SPIR-V 1.1. | 
 | # TODO(dneto): Propose that this information be embedded in the grammar file. | 
 | SPEC_CONSTANT_OP_OPCODES = """ | 
 |         OpSConvert, OpFConvert | 
 |         OpSNegate, OpNot | 
 |         OpIAdd, OpISub | 
 |         OpIMul, OpUDiv, OpSDiv, OpUMod, OpSRem, OpSMod | 
 |         OpShiftRightLogical, OpShiftRightArithmetic, OpShiftLeftLogical | 
 |         OpBitwiseOr, OpBitwiseXor, OpBitwiseAnd | 
 |         OpVectorShuffle, OpCompositeExtract, OpCompositeInsert | 
 |         OpLogicalOr, OpLogicalAnd, OpLogicalNot, | 
 |         OpLogicalEqual, OpLogicalNotEqual | 
 |         OpSelect | 
 |         OpIEqual, OpINotEqual | 
 |         OpULessThan, OpSLessThan | 
 |         OpUGreaterThan, OpSGreaterThan | 
 |         OpULessThanEqual, OpSLessThanEqual | 
 |         OpUGreaterThanEqual, OpSGreaterThanEqual | 
 |  | 
 |         OpQuantizeToF16 | 
 |  | 
 |         OpConvertFToS, OpConvertSToF | 
 |         OpConvertFToU, OpConvertUToF | 
 |         OpUConvert | 
 |         OpConvertPtrToU, OpConvertUToPtr | 
 |         OpGenericCastToPtr, OpPtrCastToGeneric | 
 |         OpBitcast | 
 |         OpFNegate | 
 |         OpFAdd, OpFSub | 
 |         OpFMul, OpFDiv | 
 |         OpFRem, OpFMod | 
 |         OpAccessChain, OpInBoundsAccessChain | 
 |         OpPtrAccessChain, OpInBoundsPtrAccessChain""" | 
 |  | 
 |  | 
 | def EmitAsStatement(name): | 
 |     """Emits the given name as a statement token""" | 
 |     print('syn keyword spvasmStatement', name) | 
 |  | 
 |  | 
 | def EmitAsEnumerant(name): | 
 |     """Emits the given name as an named operand token""" | 
 |     print('syn keyword spvasmConstant', name) | 
 |  | 
 |  | 
 | def main(): | 
 |     """Parses arguments, then generates the Vim syntax rules for SPIR-V assembly | 
 |     on stdout.""" | 
 |     import argparse | 
 |     parser = argparse.ArgumentParser(description='Generate SPIR-V info tables') | 
 |     parser.add_argument('--spirv-core-grammar', metavar='<path>', | 
 |                         type=str, required=True, | 
 |                         help='input JSON grammar file for core SPIR-V ' | 
 |                         'instructions') | 
 |     parser.add_argument('--extinst-glsl-grammar', metavar='<path>', | 
 |                         type=str, required=False, default=None, | 
 |                         help='input JSON grammar file for GLSL extended ' | 
 |                         'instruction set') | 
 |     parser.add_argument('--extinst-opencl-grammar', metavar='<path>', | 
 |                         type=str, required=False, default=None, | 
 |                         help='input JSON grammar file for OpenGL extended ' | 
 |                         'instruction set') | 
 |     parser.add_argument('--extinst-debuginfo-grammar', metavar='<path>', | 
 |                         type=str, required=False, default=None, | 
 |                         help='input JSON grammar file for DebugInfo extended ' | 
 |                         'instruction set') | 
 |     args = parser.parse_args() | 
 |  | 
 |     # Generate the syntax rules. | 
 |     print(PREAMBLE) | 
 |  | 
 |     core = json.loads(open(args.spirv_core_grammar).read()) | 
 |     print('\n" Core instructions') | 
 |     for inst in core["instructions"]: | 
 |         EmitAsStatement(inst['opname']) | 
 |     print('\n" Core operand enums') | 
 |     for operand_kind in core["operand_kinds"]: | 
 |         if 'enumerants' in operand_kind: | 
 |             for e in operand_kind['enumerants']: | 
 |                 EmitAsEnumerant(e['enumerant']) | 
 |  | 
 |     if args.extinst_glsl_grammar is not None: | 
 |         print('\n" GLSL.std.450 extended instructions') | 
 |         glsl = json.loads(open(args.extinst_glsl_grammar).read()) | 
 |         # These opcodes are really enumerant operands for the OpExtInst | 
 |         # instruction. | 
 |         for inst in glsl["instructions"]: | 
 |             EmitAsEnumerant(inst['opname']) | 
 |  | 
 |     if args.extinst_opencl_grammar is not None: | 
 |         print('\n" OpenCL.std extended instructions') | 
 |         opencl = json.loads(open(args.extinst_opencl_grammar).read()) | 
 |         for inst in opencl["instructions"]: | 
 |             EmitAsEnumerant(inst['opname']) | 
 |  | 
 |     if args.extinst_debuginfo_grammar is not None: | 
 |         print('\n" DebugInfo extended instructions') | 
 |         debuginfo = json.loads(open(args.extinst_debuginfo_grammar).read()) | 
 |         for inst in debuginfo["instructions"]: | 
 |             EmitAsEnumerant(inst['opname']) | 
 |         print('\n" DebugInfo operand enums') | 
 |         for operand_kind in debuginfo["operand_kinds"]: | 
 |             if 'enumerants' in operand_kind: | 
 |                 for e in operand_kind['enumerants']: | 
 |                     EmitAsEnumerant(e['enumerant']) | 
 |  | 
 |     print('\n" OpSpecConstantOp opcodes') | 
 |     for word in SPEC_CONSTANT_OP_OPCODES.split(' '): | 
 |         stripped = word.strip('\n,') | 
 |         if stripped != "": | 
 |             # Treat as an enumerant, but without the leading "Op" | 
 |             EmitAsEnumerant(stripped[2:]) | 
 |     print(POSTAMBLE) | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |     main() |