|  | require "./encoding" | 
        
          |  | include Encoding | 
        
          |  |  | 
        
          |  | # https://webassembly.github.io/spec/core/binary/modules.html#sections | 
        
          |  | enum Section : UInt8 | 
        
          |  | Custom | 
        
          |  | Type | 
        
          |  | Import | 
        
          |  | Func | 
        
          |  | Table | 
        
          |  | Memory | 
        
          |  | Global | 
        
          |  | Export | 
        
          |  | Start | 
        
          |  | Element | 
        
          |  | Code | 
        
          |  | Data | 
        
          |  | end | 
        
          |  |  | 
        
          |  | # https://webassembly.github.io/spec/core/binary/types.html | 
        
          |  | module Valtype | 
        
          |  | I32 = 0x7f | 
        
          |  | I64 = 0x7e | 
        
          |  | F32 = 0x7d | 
        
          |  | end | 
        
          |  |  | 
        
          |  |  | 
        
          |  | # https://webassembly.github.io/spec/core/binary/instructions.html | 
        
          |  | module Opcodes | 
        
          |  | End = 0x0b | 
        
          |  | GetLocal = 0x20 | 
        
          |  | F32Add = 0x92 | 
        
          |  | end | 
        
          |  |  | 
        
          |  | # http://webassembly.github.io/spec/core/binary/modules.html#export-section | 
        
          |  | module ExportType | 
        
          |  | Func = 0x00 | 
        
          |  | Table = 0x01 | 
        
          |  | Mem = 0x02 | 
        
          |  | Global = 0x03 | 
        
          |  | end | 
        
          |  |  | 
        
          |  | # http://webassembly.github.io/spec/core/binary/types.html#function-types | 
        
          |  | FunctionType = 0x60 | 
        
          |  |  | 
        
          |  | EmptyArray = 0x0 | 
        
          |  |  | 
        
          |  |  | 
        
          |  | # https://webassembly.github.io/spec/core/binary/conventions.html#binary-vec | 
        
          |  | def encode_vector(data) : Array(UInt8) | 
        
          |  | size = [data.size.to_u8] of UInt8 | 
        
          |  | size + data.flatten.map(&.to_u8) | 
        
          |  | end | 
        
          |  |  | 
        
          |  | # https://webassembly.github.io/spec/core/binary/modules.html#sections | 
        
          |  | def create_section(type : Section, data) : Array(UInt8) | 
        
          |  | type = [type.value] of UInt8 | 
        
          |  | type + encode_vector(data) | 
        
          |  | end | 
        
          |  |  | 
        
          |  |  | 
        
          |  | magic_module_header = [0x00, 0x61, 0x73, 0x6d] of UInt8 | 
        
          |  | module_version = [0x01, 0x00, 0x00, 0x00] of UInt8 | 
        
          |  | header = magic_module_header + module_version | 
        
          |  |  | 
        
          |  | add_function_type = [FunctionType] + encode_vector([Valtype::F32, Valtype::F32]) + encode_vector([Valtype::F32]) | 
        
          |  | type_section = create_section(Section::Type, encode_vector([add_function_type])) | 
        
          |  | func_section = create_section(Section::Func, encode_vector([0x00])) | 
        
          |  | export_section = create_section(Section::Export, encode_vector([encode_string("add") + [ExportType::Func, 0x00]])) | 
        
          |  |  | 
        
          |  | code = [ | 
        
          |  | Opcodes::GetLocal, | 
        
          |  | unsigned_LEB128(0), | 
        
          |  | Opcodes::GetLocal, | 
        
          |  | unsigned_LEB128(1), | 
        
          |  | Opcodes::F32Add | 
        
          |  | ].flatten | 
        
          |  |  | 
        
          |  | function_body = encode_vector([ | 
        
          |  | EmptyArray, | 
        
          |  | code, | 
        
          |  | Opcodes::End | 
        
          |  | ].flatten) | 
        
          |  |  | 
        
          |  | code_section = create_section(Section::Code, encode_vector([function_body])) | 
        
          |  |  | 
        
          |  | buffer = (header + type_section + func_section + export_section + code_section) | 
        
          |  |  | 
        
          |  | File.open("crystal.wasm", "wb") do |f| | 
        
          |  | ptr = (buffer.to_unsafe.as(UInt8*)) | 
        
          |  | f.write(ptr.to_slice(buffer.size * sizeof(UInt8))) | 
        
          |  | end |