{ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE DuplicateRecordFields #-} module Language.Wasm.Parser ( parseModule ) where import qualified Data.Text as T import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy.Encoding as TLEncoding import qualified Data.Text.Lazy.Read as TLRead import qualified Data.ByteString.Lazy as LBS import Data.Maybe (fromMaybe) import Data.List (foldl') import Numeric.Natural (Natural) import Language.Wasm.Lexer ( Token ( TKeyword, TIntLit, TFloatLit, TStringLit, TId, TOpenBracket, TCloseBracket, TReserved, EOF ), Lexeme(..), AlexPosn(..) ) import Debug.Trace as Debug } %name parseModule mod %tokentype { Lexeme } %token '(' { Lexeme _ TOpenBracket } ')' { Lexeme _ TCloseBracket } 'func' { Lexeme _ (TKeyword "func") } 'param' { Lexeme _ (TKeyword "param") } 'result' { Lexeme _ (TKeyword "result") } 'i32' { Lexeme _ (TKeyword "i32") } 'i64' { Lexeme _ (TKeyword "i64") } 'f32' { Lexeme _ (TKeyword "f32") } 'f64' { Lexeme _ (TKeyword "f64") } 'mut' { Lexeme _ (TKeyword "mut") } 'anyfunc' { Lexeme _ (TKeyword "anyfunc") } 'type' { Lexeme _ (TKeyword "type") } 'unreachable' { Lexeme _ (TKeyword "unreachable") } 'nop' { Lexeme _ (TKeyword "nop") } 'br' { Lexeme _ (TKeyword "br") } 'br_if' { Lexeme _ (TKeyword "br_if") } 'br_table' { Lexeme _ (TKeyword "br_table") } 'return' { Lexeme _ (TKeyword "return") } 'call' { Lexeme _ (TKeyword "call") } 'call_indirect' { Lexeme _ (TKeyword "call_indirect") } 'drop' { Lexeme _ (TKeyword "drop") } 'select' { Lexeme _ (TKeyword "select") } 'get_local' { Lexeme _ (TKeyword "get_local") } 'set_local' { Lexeme _ (TKeyword "set_local") } 'tee_local' { Lexeme _ (TKeyword "tee_local") } 'get_global' { Lexeme _ (TKeyword "get_global") } 'set_global' { Lexeme _ (TKeyword "set_global") } 'i32.load' { Lexeme _ (TKeyword "i32.load") } 'i64.load' { Lexeme _ (TKeyword "i64.load") } 'f32.load' { Lexeme _ (TKeyword "f32.load") } 'f64.load' { Lexeme _ (TKeyword "f64.load") } 'i32.load8_s' { Lexeme _ (TKeyword "i32.load8_s") } 'i32.load8_u' { Lexeme _ (TKeyword "i32.load8_u") } 'i32.load16_s' { Lexeme _ (TKeyword "i32.load16_s") } 'i32.load16_u' { Lexeme _ (TKeyword "i32.load16_u") } 'i64.load8_s' { Lexeme _ (TKeyword "i64.load8_s") } 'i64.load8_u' { Lexeme _ (TKeyword "i64.load8_u") } 'i64.load16_s' { Lexeme _ (TKeyword "i64.load16_s") } 'i64.load16_u' { Lexeme _ (TKeyword "i64.load16_u") } 'i64.load32_s' { Lexeme _ (TKeyword "i64.load32_s") } 'i64.load32_u' { Lexeme _ (TKeyword "i64.load32_u") } 'i32.store' { Lexeme _ (TKeyword "i32.store") } 'i64.store' { Lexeme _ (TKeyword "i64.store") } 'f32.store' { Lexeme _ (TKeyword "f32.store") } 'f64.store' { Lexeme _ (TKeyword "f64.store") } 'i32.store8' { Lexeme _ (TKeyword "i32.store8") } 'i32.store16' { Lexeme _ (TKeyword "i32.store16") } 'i64.store8' { Lexeme _ (TKeyword "i64.store") } 'i64.store16' { Lexeme _ (TKeyword "i64.store") } 'i64.store32' { Lexeme _ (TKeyword "i64.store") } 'current_memory' { Lexeme _ (TKeyword "current_memory") } 'grow_memory' { Lexeme _ (TKeyword "grow_memory") } 'i32.const' { Lexeme _ (TKeyword "i32.const") } 'i64.const' { Lexeme _ (TKeyword "i64.const") } 'f32.const' { Lexeme _ (TKeyword "f32.const") } 'f64.const' { Lexeme _ (TKeyword "f64.const") } 'i32.clz' { Lexeme _ (TKeyword "i32.clz") } 'i32.ctz' { Lexeme _ (TKeyword "i32.ctz") } 'i32.popcnt' { Lexeme _ (TKeyword "i32.popcnt") } 'i32.add' { Lexeme _ (TKeyword "i32.add") } 'i32.sub' { Lexeme _ (TKeyword "i32.sub") } 'i32.mul' { Lexeme _ (TKeyword "i32.mul") } 'i32.div_s' { Lexeme _ (TKeyword "i32.div_s") } 'i32.div_u' { Lexeme _ (TKeyword "i32.div_u") } 'i32.rem_s' { Lexeme _ (TKeyword "i32.rem_s") } 'i32.rem_u' { Lexeme _ (TKeyword "i32.rem_u") } 'i32.and' { Lexeme _ (TKeyword "i32.and") } 'i32.or' { Lexeme _ (TKeyword "i32.or") } 'i32.xor' { Lexeme _ (TKeyword "i32.xor") } 'i32.shl' { Lexeme _ (TKeyword "i32.shl") } 'i32.shr_s' { Lexeme _ (TKeyword "i32.shr_s") } 'i32.shr_u' { Lexeme _ (TKeyword "i32.shr_u") } 'i32.rotl' { Lexeme _ (TKeyword "i32.rotl") } 'i32.rotr' { Lexeme _ (TKeyword "i32.rotr") } 'i64.clz' { Lexeme _ (TKeyword "i64.clz") } 'i64.ctz' { Lexeme _ (TKeyword "i64.ctz") } 'i64.popcnt' { Lexeme _ (TKeyword "i64.popcnt") } 'i64.add' { Lexeme _ (TKeyword "i64.add") } 'i64.sub' { Lexeme _ (TKeyword "i64.sub") } 'i64.mul' { Lexeme _ (TKeyword "i64.mul") } 'i64.div_s' { Lexeme _ (TKeyword "i64.div_s") } 'i64.div_u' { Lexeme _ (TKeyword "i64.div_u") } 'i64.rem_s' { Lexeme _ (TKeyword "i64.rem_s") } 'i64.rem_u' { Lexeme _ (TKeyword "i64.rem_u") } 'i64.and' { Lexeme _ (TKeyword "i64.and") } 'i64.or' { Lexeme _ (TKeyword "i64.or") } 'i64.xor' { Lexeme _ (TKeyword "i64.xor") } 'i64.shl' { Lexeme _ (TKeyword "i64.shl") } 'i64.shr_s' { Lexeme _ (TKeyword "i64.shr_s") } 'i64.shr_u' { Lexeme _ (TKeyword "i64.shr_u") } 'i64.rotl' { Lexeme _ (TKeyword "i64.rotl") } 'i64.rotr' { Lexeme _ (TKeyword "i64.rotr") } 'f32.abs' { Lexeme _ (TKeyword "f32.abs") } 'f32.neg' { Lexeme _ (TKeyword "f32.neg") } 'f32.ceil' { Lexeme _ (TKeyword "f32.ceil") } 'f32.floor' { Lexeme _ (TKeyword "f32.floor") } 'f32.trunc' { Lexeme _ (TKeyword "f32.trunc") } 'f32.nearest' { Lexeme _ (TKeyword "f32.nearest") } 'f32.sqrt' { Lexeme _ (TKeyword "f32.sqrt") } 'f32.add' { Lexeme _ (TKeyword "f32.add") } 'f32.sub' { Lexeme _ (TKeyword "f32.sub") } 'f32.mul' { Lexeme _ (TKeyword "f32.mul") } 'f32.div' { Lexeme _ (TKeyword "f32.div") } 'f32.min' { Lexeme _ (TKeyword "f32.min") } 'f32.max' { Lexeme _ (TKeyword "f32.max") } 'f32.copysign' { Lexeme _ (TKeyword "f32.copysign") } 'f64.abs' { Lexeme _ (TKeyword "f64.abs") } 'f64.neg' { Lexeme _ (TKeyword "f64.neg") } 'f64.ceil' { Lexeme _ (TKeyword "f64.ceil") } 'f64.floor' { Lexeme _ (TKeyword "f64.floor") } 'f64.trunc' { Lexeme _ (TKeyword "f64.trunc") } 'f64.nearest' { Lexeme _ (TKeyword "f64.nearest") } 'f64.sqrt' { Lexeme _ (TKeyword "f64.sqrt") } 'f64.add' { Lexeme _ (TKeyword "f64.add") } 'f64.sub' { Lexeme _ (TKeyword "f64.sub") } 'f64.mul' { Lexeme _ (TKeyword "f64.mul") } 'f64.div' { Lexeme _ (TKeyword "f64.div") } 'f64.min' { Lexeme _ (TKeyword "f64.min") } 'f64.max' { Lexeme _ (TKeyword "f64.max") } 'f64.copysign' { Lexeme _ (TKeyword "f64.copysign") } 'i32.eqz' { Lexeme _ (TKeyword "i32.eqz") } 'i32.eq' { Lexeme _ (TKeyword "i32.eq") } 'i32.ne' { Lexeme _ (TKeyword "i32.ne") } 'i32.lt_s' { Lexeme _ (TKeyword "i32.lt_s") } 'i32.lt_u' { Lexeme _ (TKeyword "i32.lt_u") } 'i32.gt_s' { Lexeme _ (TKeyword "i32.gt_s") } 'i32.gt_u' { Lexeme _ (TKeyword "i32.gt_u") } 'i32.le_s' { Lexeme _ (TKeyword "i32.le_s") } 'i32.le_u' { Lexeme _ (TKeyword "i32.le_u") } 'i32.ge_s' { Lexeme _ (TKeyword "i32.ge_s") } 'i32.ge_u' { Lexeme _ (TKeyword "i32.ge_u") } 'i64.eqz' { Lexeme _ (TKeyword "i64.eqz") } 'i64.eq' { Lexeme _ (TKeyword "i64.eq") } 'i64.ne' { Lexeme _ (TKeyword "i64.ne") } 'i64.lt_s' { Lexeme _ (TKeyword "i64.lt_s") } 'i64.lt_u' { Lexeme _ (TKeyword "i64.lt_u") } 'i64.gt_s' { Lexeme _ (TKeyword "i64.gt_s") } 'i64.gt_u' { Lexeme _ (TKeyword "i64.gt_u") } 'i64.le_s' { Lexeme _ (TKeyword "i64.le_s") } 'i64.le_u' { Lexeme _ (TKeyword "i64.le_u") } 'i64.ge_s' { Lexeme _ (TKeyword "i64.ge_s") } 'i64.ge_u' { Lexeme _ (TKeyword "i64.ge_u") } 'f32.eq' { Lexeme _ (TKeyword "f32.eq") } 'f32.ne' { Lexeme _ (TKeyword "f32.ne") } 'f32.lt' { Lexeme _ (TKeyword "f32.lt") } 'f32.gt' { Lexeme _ (TKeyword "f32.gt") } 'f32.le' { Lexeme _ (TKeyword "f32.le") } 'f32.ge' { Lexeme _ (TKeyword "f32.ge") } 'f64.eq' { Lexeme _ (TKeyword "f64.eq") } 'f64.ne' { Lexeme _ (TKeyword "f64.ne") } 'f64.lt' { Lexeme _ (TKeyword "f64.lt") } 'f64.gt' { Lexeme _ (TKeyword "f64.gt") } 'f64.le' { Lexeme _ (TKeyword "f64.le") } 'f64.ge' { Lexeme _ (TKeyword "f64.ge") } 'i32.wrap/i64' { Lexeme _ (TKeyword "i32.wrap/i64") } 'i32.trunc_s/f32' { Lexeme _ (TKeyword "i32.trunc_s/f32") } 'i32.trunc_u/f32' { Lexeme _ (TKeyword "i32.trunc_u/f32") } 'i32.trunc_s/f64' { Lexeme _ (TKeyword "i32.trunc_s/f64") } 'i32.trunc_u/f64' { Lexeme _ (TKeyword "i32.trunc_u/f64") } 'i64.extend_s/i32' { Lexeme _ (TKeyword "i64.extend_s/i32") } 'i64.extend_u/i32' { Lexeme _ (TKeyword "i64.extend_u/i32") } 'i64.trunc_s/f32' { Lexeme _ (TKeyword "i64.trunc_s/f32") } 'i64.trunc_u/f32' { Lexeme _ (TKeyword "i64.trunc_u/f32") } 'i64.trunc_s/f64' { Lexeme _ (TKeyword "i64.trunc_s/f64") } 'i64.trunc_u/f64' { Lexeme _ (TKeyword "i64.trunc_u/f64") } 'f32.convert_s/i32' { Lexeme _ (TKeyword "f32.convert_s/i32") } 'f32.convert_u/i32' { Lexeme _ (TKeyword "f32.convert_u/i32") } 'f32.convert_s/i64' { Lexeme _ (TKeyword "f32.convert_s/i64") } 'f32.convert_u/i64' { Lexeme _ (TKeyword "f32.convert_u/i64") } 'f32.demote/f64' { Lexeme _ (TKeyword "f32.demote/f64") } 'f64.convert_s/i32' { Lexeme _ (TKeyword "f64.convert_s/i32") } 'f64.convert_u/i32' { Lexeme _ (TKeyword "f64.convert_u/i32") } 'f64.convert_s/i64' { Lexeme _ (TKeyword "f64.convert_s/i64") } 'f64.convert_u/i64' { Lexeme _ (TKeyword "f64.convert_u/i64") } 'f64.promote/f32' { Lexeme _ (TKeyword "f64.promote/f32") } 'i32.reinterpret/f32' { Lexeme _ (TKeyword "i32.reinterpret/f32") } 'i64.reinterpret/f64' { Lexeme _ (TKeyword "i64.reinterpret/f64") } 'f32.reinterpret/i32' { Lexeme _ (TKeyword "f32.reinterpret/i32") } 'f64.reinterpret/i64' { Lexeme _ (TKeyword "f64.reinterpret/i64") } 'block' { Lexeme _ (TKeyword "block") } 'loop' { Lexeme _ (TKeyword "loop") } 'if' { Lexeme _ (TKeyword "if") } 'else' { Lexeme _ (TKeyword "else") } 'end' { Lexeme _ (TKeyword "end") } 'then' { Lexeme _ (TKeyword "then") } 'table' { Lexeme _ (TKeyword "table") } 'memory' { Lexeme _ (TKeyword "memory") } 'global' { Lexeme _ (TKeyword "global") } 'import' { Lexeme _ (TKeyword "import") } 'export' { Lexeme _ (TKeyword "export") } 'local' { Lexeme _ (TKeyword "local") } 'elem' { Lexeme _ (TKeyword "elem") } 'data' { Lexeme _ (TKeyword "data") } 'offset' { Lexeme _ (TKeyword "offset") } 'start' { Lexeme _ (TKeyword "start") } 'module' { Lexeme _ (TKeyword "module") } id { Lexeme _ (TId $$) } u32 { Lexeme _ (TIntLit (asUInt32 -> Just $$)) } i32 { Lexeme _ (TIntLit (asInt32 -> Just $$)) } i64 { Lexeme _ (TIntLit (asInt64 -> Just $$)) } f32 { Lexeme _ (TFloatLit (asFloat32 -> $$)) } f64 { Lexeme _ (TFloatLit (asFloat64 -> $$)) } offset { Lexeme _ (TKeyword (asOffset -> Just $$)) } align { Lexeme _ (TKeyword (asAlign -> Just $$)) } name { Lexeme _ (TStringLit (asName -> Just $$)) } string { Lexeme _ (TStringLit (asString -> Just $$)) } EOF { Lexeme _ EOF } %% functype :: { FuncType } : '(' 'func' params_results { $3 } params_results :: { FuncType } : ')' { FuncType [] [] } | '(' paramsresultstypeuse ')' { $2 } ident :: { Ident } : id { Ident (TL.toStrict (TLEncoding.decodeUtf8 $1)) } valtype :: { ValueType } : 'i32' { I32 } | 'i64' { I64 } | 'f32' { F32 } | 'f64' { F64 } globaltype :: { GlobalType } : valtype { Const $1 } | '(' 'mut' valtype ')' { Mut $3 } labelidx :: { LabelIndex } : u32 { Index $1 } | ident { Named $1 } funcidx :: { FuncIndex } : u32 { Index $1 } | ident { Named $1 } typeidx :: { TypeIndex } : u32 { Index $1 } | ident { Named $1 } localidx :: { LocalIndex } : u32 { Index $1 } | ident { Named $1 } globalidx :: { GlobalIndex } : u32 { Index $1 } | ident { Named $1 } tableidx :: { TableIndex } : u32 { Index $1 } | ident { Named $1 } memidx :: { MemoryIndex } : u32 { Index $1 } | ident { Named $1 } int32 :: { Integer } : u32 { fromIntegral $1 } | i32 { $1 } int64 :: { Integer } : u32 { fromIntegral $1 } | i32 { $1 } | i64 { $1 } float32 :: { Float } : u32 { fromIntegral $1 } | i32 { fromIntegral $1 } | f32 { $1 } float64 :: { Double } : u32 { fromIntegral $1 } | i32 { fromIntegral $1 } | f32 { realToFrac $1 } | f64 { realToFrac $1 } plaininstr :: { PlainInstr } -- control instructions : 'unreachable' { Unreachable } | 'nop' { Nop } | 'br' labelidx { Br $2 } | 'br_if' labelidx { BrIf $2 } | 'br_table' rev_list1(labelidx) { BrTable (reverse $ tail $2) (head $2) } | 'return' { Return } | 'call' funcidx { Call $2 } -- | 'call_indirect' typeuse { CallIndirect $2 } -- call_inderict has special case in folded form -- parametric instructions | 'drop' { Drop } | 'select' { Select } -- variable instructions | 'get_local' localidx { GetLocal $2 } | 'set_local' localidx { SetLocal $2 } | 'tee_local' localidx { TeeLocal $2 } | 'get_global' globalidx { GetGlobal $2 } | 'set_global' globalidx { SetGlobal $2 } -- memory instructions | 'i32.load' memarg4 { I32Load $2 } | 'i64.load' memarg8 { I64Load $2 } | 'f32.load' memarg4 { F32Load $2 } | 'f64.load' memarg8 { F64Load $2 } | 'i32.load8_s' memarg1 { I32Load8S $2 } | 'i32.load8_u' memarg1 { I32Load8U $2 } | 'i32.load16_s' memarg2 { I32Load16S $2 } | 'i32.load16_u' memarg2 { I32Load16U $2 } | 'i64.load8_s' memarg1 { I64Load8S $2 } | 'i64.load8_u' memarg1 { I64Load8U $2 } | 'i64.load16_s' memarg2 { I64Load16S $2 } | 'i64.load16_u' memarg2 { I64Load16U $2 } | 'i64.load32_s' memarg4 { I64Load32S $2 } | 'i64.load32_u' memarg4 { I64Load32U $2 } | 'i32.store' memarg4 { I32Store $2 } | 'i64.store' memarg8 { I64Store $2 } | 'f32.store' memarg4 { F32Store $2 } | 'f64.store' memarg8 { F64Store $2 } | 'i32.store8' memarg1 { I32Store8 $2 } | 'i32.store16' memarg2 { I32Store16 $2 } | 'i64.store8' memarg1 { I64Store8 $2 } | 'i64.store16' memarg2 { I64Store16 $2 } | 'i64.store32' memarg4 { I64Store32 $2 } | 'current_memory' { CurrentMemory } | 'grow_memory' { GrowMemory } -- numeric instructions | 'i32.const' int32 { I32Const $2 } | 'i64.const' int64 { I64Const $2 } | 'f32.const' float32 { F32Const $2 } | 'f64.const' float64 { F64Const $2 } | 'i32.clz' { I32Clz } | 'i32.ctz' { I32Ctz } | 'i32.popcnt' { I32Popcnt } | 'i32.add' { I32Add } | 'i32.sub' { I32Sub } | 'i32.mul' { I32Mul } | 'i32.div_s' { I32DivS } | 'i32.div_u' { I32DivU } | 'i32.rem_s' { I32RemS } | 'i32.rem_u' { I32RemU } | 'i32.and' { I32And } | 'i32.or' { I32Or } | 'i32.xor' { I32Xor } | 'i32.shl' { I32Shl } | 'i32.shr_s' { I32ShrS } | 'i32.shr_u' { I32ShrU } | 'i32.rotl' { I32Rotl } | 'i32.rotr' { I32Rotr } | 'i64.clz' { I64Clz } | 'i64.ctz' { I64Ctz } | 'i64.popcnt' { I64Popcnt } | 'i64.add' { I64Add } | 'i64.sub' { I64Sub } | 'i64.mul' { I64Mul } | 'i64.div_s' { I64DivS } | 'i64.div_u' { I64DivU } | 'i64.rem_s' { I64RemS } | 'i64.rem_u' { I64RemU } | 'i64.and' { I64And } | 'i64.or' { I64Or } | 'i64.xor' { I64Xor } | 'i64.shl' { I64Shl } | 'i64.shr_s' { I64ShrS } | 'i64.shr_u' { I64ShrU } | 'i64.rotl' { I64Rotl } | 'i64.rotr' { I64Rotr } | 'f32.abs' { F32Abs } | 'f32.neg' { F32Neg } | 'f32.ceil' { F32Ceil } | 'f32.floor' { F32Floor } | 'f32.trunc' { F32Trunc } | 'f32.nearest' { F32Nearest } | 'f32.sqrt' { F32Sqrt } | 'f32.add' { F32Add } | 'f32.sub' { F32Sub } | 'f32.mul' { F32Mul } | 'f32.div' { F32Div } | 'f32.min' { F32Min } | 'f32.max' { F32Max } | 'f32.copysign' { F32Copysign } | 'f64.abs' { F64Abs } | 'f64.neg' { F64Neg } | 'f64.ceil' { F64Ceil } | 'f64.floor' { F64Floor } | 'f64.trunc' { F64Trunc } | 'f64.nearest' { F64Nearest } | 'f64.sqrt' { F64Sqrt } | 'f64.add' { F64Add } | 'f64.sub' { F64Sub } | 'f64.mul' { F64Mul } | 'f64.div' { F64Div } | 'f64.min' { F64Min } | 'f64.max' { F64Max } | 'f64.copysign' { F64Copysign } | 'i32.eqz' { I32Eqz } | 'i32.eq' { I32Eq } | 'i32.ne' { I32Ne } | 'i32.lt_s' { I32LtS } | 'i32.lt_u' { I32LtU } | 'i32.gt_s' { I32GtS } | 'i32.gt_u' { I32GtU } | 'i32.le_s' { I32LeS } | 'i32.le_u' { I32LeU } | 'i32.ge_s' { I32GeS } | 'i32.ge_u' { I32GeU } | 'i64.eqz' { I64Eqz } | 'i64.eq' { I64Eq } | 'i64.ne' { I64Ne } | 'i64.lt_s' { I64LtS } | 'i64.lt_u' { I64LtU } | 'i64.gt_s' { I64GtS } | 'i64.gt_u' { I64GtU } | 'i64.le_s' { I64LeS } | 'i64.le_u' { I64LeU } | 'i64.ge_s' { I64GeS } | 'i64.ge_u' { I64GeU } | 'f32.eq' { F32Eq } | 'f32.ne' { F32Ne } | 'f32.lt' { F32Lt } | 'f32.gt' { F32Gt } | 'f32.le' { F32Le } | 'f32.ge' { F32Ge } | 'f64.eq' { F64Eq } | 'f64.ne' { F64Ne } | 'f64.lt' { F64Lt } | 'f64.gt' { F64Gt } | 'f64.le' { F64Le } | 'f64.ge' { F64Ge } | 'i32.wrap/i64' { I32WrapI64 } | 'i32.trunc_s/f32' { I32TruncSF32 } | 'i32.trunc_u/f32' { I32TruncUF32 } | 'i32.trunc_s/f64' { I32TruncSF64 } | 'i32.trunc_u/f64' { I32TruncUF64 } | 'i64.extend_s/i32' { I64ExtendSI32 } | 'i64.extend_u/i32' { I64ExtendUI32 } | 'i64.trunc_s/f32' { I64TruncSF32 } | 'i64.trunc_u/f32' { I64TruncUF32 } | 'i64.trunc_s/f64' { I64TruncSF64 } | 'i64.trunc_u/f64' { I64TruncUF64 } | 'f32.convert_s/i32' { F32ConvertSI32 } | 'f32.convert_u/i32' { F32ConvertUI32 } | 'f32.convert_s/i64' { F32ConvertSI64 } | 'f32.convert_u/i64' { F32ConvertUI64 } | 'f32.demote/f64' { F32DemoteF64 } | 'f64.convert_s/i32' { F64ConvertSI32 } | 'f64.convert_u/i32' { F64ConvertUI32 } | 'f64.convert_s/i64' { F64ConvertSI64 } | 'f64.convert_u/i64' { F64ConvertUI64 } | 'f64.promote/f32' { F64PromoteF32 } | 'i32.reinterpret/f32' { I32ReinterpretF32 } | 'i64.reinterpret/f64' { I64ReinterpretF64 } | 'f32.reinterpret/i32' { F32ReinterpretI32 } | 'f64.reinterpret/i64' { F64ReinterpretI64 } typedef :: { TypeDef } : 'type' opt(ident) functype ')' { TypeDef $2 $3 } -- TODO: it does not properly handle call_indirect instruction use. it expects to be last expression before common ')' typeuse :: { TypeUse } : '(' typeuse1 { $2 } | {- empty -} { AnonimousTypeUse $ FuncType [] [] } typeuse1 :: { TypeUse } : 'type' typeidx ')' typedtypeuse { IndexedTypeUse $2 $4 } | paramsresultstypeuse { AnonimousTypeUse $1 } typedtypeuse :: { Maybe FuncType } : '(' paramsresultstypeuse { Just $2 } | {- empty -} { Nothing } paramsresultstypeuse :: { FuncType } : paramsresultstypeuse '(' paramsresulttypeuse { mergeFuncType $1 $3 } | paramsresulttypeuse { $1 } paramsresulttypeuse :: { FuncType } : 'param' list(valtype) ')' { FuncType (map (ParamType Nothing) $2) [] } | 'param' ident valtype ')' { FuncType [ParamType (Just $2) $3] [] } | 'result' list(valtype) ')' { FuncType [] $2 } memarg1 :: { MemArg } : opt(offset) opt(align) { MemArg (fromMaybe 0 $1) (fromMaybe 1 $2) } memarg2 :: { MemArg } : opt(offset) opt(align) { MemArg (fromMaybe 0 $1) (fromMaybe 2 $2) } memarg4 :: { MemArg } : opt(offset) opt(align) { MemArg (fromMaybe 0 $1) (fromMaybe 4 $2) } memarg8 :: { MemArg } : opt(offset) opt(align) { MemArg (fromMaybe 0 $1) (fromMaybe 8 $2) } resulttype :: { [ValueType] } : '(' 'result' list(valtype) ')' { $3 } instr :: { Instruction } : plaininstr { PlainInstr $1 } -- TODO: check if optional labels are equal if they exist | 'block' opt(ident) opt(resulttype) list(instr) 'end' opt(ident) { BlockInstr $2 (fromMaybe [] $3) $4 } -- TODO: check if optional labels are equal if they exist | 'loop' opt(ident) opt(resulttype) list(instr) 'end' opt(ident) { LoopInstr $2 (fromMaybe [] $3) $4 } -- TODO: check if optional labels are equal if they exist | 'if' opt(ident) opt(resulttype) list(instr) 'else' opt(ident) list(instr) 'end' opt(ident) { IfInstr $2 (fromMaybe [] $3) $4 $7 } foldedinstr :: { [Instruction] } : '(' foldedinst1 { $2 } foldedinst1 :: { [Instruction] } : plaininstr list(foldedinstr) ')' { concat $2 ++ [PlainInstr $1] } | 'call_indirect' folded_call_indirect { $2 } | 'block' opt(ident) folded_block { [$3 $2] } | 'loop' opt(ident) folded_loop { [$3 $2] } | 'if' opt(ident) '(' folded_if_result { $4 $2 } folded_block :: { Maybe Ident -> Instruction } : ')' { \ident -> BlockInstr ident [] [] } | '(' folded_block1 { $2 } folded_block1 :: { Maybe Ident -> Instruction } : 'result' valtype ')' list(foldedinstr) ')' { \ident -> BlockInstr ident [$2] (concat $4) } | foldedinst1 list(foldedinstr) ')' { \ident -> BlockInstr ident [] ($1 ++ concat $2) } folded_loop :: { Maybe Ident -> Instruction } : ')' { \ident -> LoopInstr ident [] [] } | '(' folded_loop1 { $2 } folded_loop1 :: { Maybe Ident -> Instruction } : 'result' valtype ')' list(foldedinstr) ')' { \ident -> LoopInstr ident [$2] (concat $4) } | foldedinst1 list(foldedinstr) ')' { \ident -> LoopInstr ident [] ($1 ++ concat $2) } folded_if_result :: { Maybe Ident -> [Instruction] } : 'result' valtype ')' '(' folded_then_else { \ident -> [IfInstr ident [$2] (fst $5) (snd $5)] } | 'result' valtype ')' '(' foldedinst1 '(' folded_then_else { \ident -> $5 ++ [IfInstr ident [$2] (fst $7) (snd $7)] } | folded_if { $1 } folded_if :: { Maybe Ident -> [Instruction] } : folded_then_else { \ident -> [IfInstr ident [] (fst $1) (snd $1)] } | foldedinst1 '(' folded_then_else { \ident -> $1 ++ [IfInstr ident [] (fst $3) (snd $3)] } folded_then_else :: { ([Instruction], [Instruction]) } : 'then' list(foldedinstr) ')' folded_else { (concat $2, $4)} folded_else :: { [Instruction] } : ')' { [] } | '(' 'else' list(foldedinstr) ')' ')' { concat $3 } folded_call_indirect :: { [Instruction] } : ')' { [PlainInstr $ CallIndirect $ AnonimousTypeUse $ FuncType [] []] } | '(' folded_call_indirect_typeuse { (PlainInstr $ CallIndirect $ fst $2) : snd $2 } folded_call_indirect_typeuse :: { (TypeUse, [Instruction]) } : 'type' typeidx ')' folded_call_indirect_functype { (IndexedTypeUse $2 $ fst $4, snd $4) } | folded_call_indirect_functype1 { (AnonimousTypeUse $ fromMaybe (FuncType [] []) $ fst $1, snd $1) } folded_call_indirect_functype :: { (Maybe FuncType, [Instruction]) } : '(' folded_call_indirect_functype1 { $2 } | ')' { (Nothing, []) } folded_call_indirect_functype1 :: { (Maybe FuncType, [Instruction]) } : paramsresulttypeuse folded_call_indirect_functype { (Just $ mergeFuncType $1 $ fromMaybe emptyFuncType $ fst $2, snd $2) } | foldedinst1 list(foldedinstr) ')' { (Nothing, $1 ++ concat $2) } importdesc :: { ImportDesc } : 'func' opt(ident) typeuse ')' { ImportFunc $2 $3 } | 'table' opt(ident) tabletype ')' { ImportTable $2 $3 } | 'memory' opt(ident) limits ')' { ImportMemory $2 $3 } | 'global' opt(ident) globaltype ')' { ImportGlobal $2 $3 } import :: { Import } : 'import' name name '(' importdesc ')' { Import $2 $3 $5 } localtypes :: { [LocalType] } : list(localtype) { concat $1 } localtype :: { [LocalType] } : '(' 'local' ident valtype ')' { [LocalType (Just $3) $4] } | '(' 'local' list(valtype) ')' { map (LocalType Nothing) $3 } -- FUNCTION -- function :: { [ModuleField] } : 'func' opt(ident) export_import_typeuse_locals_body { map (appendIdent $2) $3 } export_import_typeuse_locals_body :: { [ModuleField] } : ')' { [MFFunc $ Function Nothing (AnonimousTypeUse $ FuncType [] []) [] []] } | '(' export_import_typeuse_locals_body1 { $2 } export_import_typeuse_locals_body1 :: { [ModuleField] } : 'export' name ')' export_import_typeuse_locals_body { (MFExport $ Export $2 $ ExportFunc Nothing) : $4 } | import_typeuse_locals_body1 { [$1] } import_typeuse_locals_body :: { ModuleField } : '(' import_typeuse_locals_body1 { $2 } | ')' { MFFunc $ Function Nothing (AnonimousTypeUse $ FuncType [] []) [] [] } import_typeuse_locals_body1 :: { ModuleField } : 'import' name name ')' typeuse ')' { MFImport $ Import $2 $3 $ ImportFunc Nothing $5 } | typeuse_locals_body1 { MFFunc $ Function Nothing (t3fst $1) (t3snd $1) (t3thd $1) } typeuse_locals_body :: { (TypeUse, [LocalType], [Instruction]) } : '(' typeuse_locals_body1 { $2 } | ')' { (AnonimousTypeUse $ FuncType [] [], [], []) } typeuse_locals_body1 :: { (TypeUse, [LocalType], [Instruction]) } : 'type' typeidx ')' signature_locals_body { (IndexedTypeUse $2 (t3fst $4), t3snd $4, t3thd $4) } | signature_locals_body1 { (AnonimousTypeUse (fromMaybe emptyFuncType $ t3fst $1), t3snd $1, t3thd $1) } signature_locals_body :: { (Maybe FuncType, [LocalType], [Instruction]) } : ')' { (Nothing, [], []) } | '(' signature_locals_body1 { $2 } signature_locals_body1 :: { (Maybe FuncType, [LocalType], [Instruction]) } : 'param' list(valtype) ')' signature_locals_body { (Just $ prependFuncParams (map (ParamType Nothing) $2) $ fromMaybe emptyFuncType $ t3fst $4, t3snd $4, t3thd $4) } | 'param' ident valtype ')' signature_locals_body { (Just $ prependFuncParams [ParamType (Just $2) $3] $ fromMaybe emptyFuncType $ t3fst $5, t3snd $5, t3thd $5) } | 'result' list(valtype) ')' signature_locals_body { (Just $ prependFuncResults $2 $ fromMaybe emptyFuncType $ t3fst $4, t3snd $4, t3thd $4) } | locals_body1 { (Nothing, fst $1, snd $1) } locals_body :: { ([LocalType], [Instruction]) } : ')' { ([], []) } | '(' locals_body1 { $2 } locals_body1 :: { ([LocalType], [Instruction]) } : 'local' list(valtype) ')' locals_body { (map (LocalType Nothing) $2 ++ fst $4, snd $4) } | 'local' ident valtype ')' locals_body { (LocalType (Just $2) $3 : fst $5, snd $5) } | foldedinst1 list(foldedinstr) ')' { ([], $1 ++ concat $2) } -- FUNCTION END -- global :: { Global } : 'global' opt(ident) globaltype list(foldedinstr) ')' { Global $2 $3 (concat $4) } memory :: { Memory } : 'memory' opt(ident) limits ')' { Memory $2 $3 } -- TABLE -- limits :: { Limit } : u32 opt(u32) { Limit (fromIntegral $1) (fromIntegral `fmap` $2) } elemtype :: { ElemType } : 'anyfunc' { AnyFunc } tabletype :: { TableType } : limits elemtype { TableType $1 $2 } table :: { [ModuleField] } : 'table' opt(ident) limits_elemtype_elem { map (appendIdent $2) $3 } limits_elemtype_elem :: { [ModuleField] } : tabletype ')' { [MFTable $ Table Nothing $1] } | elemtype '(' 'elem' list(funcidx) ')' ')' { let funcsLen = fromIntegral $ length $4 in [ MFTable $ Table Nothing $ TableType (Limit funcsLen (Just funcsLen)) $1, MFElem $ ElemSegment (Index 0) [PlainInstr $ I32Const 0] $4 ] } | '(' import_export_table { $2 } import_export_table :: { [ModuleField] } : 'import' name name ')' tabletype ')' { [MFImport $ Import $2 $3 $ ImportTable Nothing $5] } | 'export' name ')' limits_elemtype_elem { (MFExport $ Export $2 $ ExportTable Nothing) : $4 } -- TABLE END -- exportdesc :: { ExportDesc } : 'func' funcidx ')' { ExportFunc (Just $2) } | 'table' tableidx ')' { ExportTable (Just $2) } | 'memory' memidx ')' { ExportMemory $2 } | 'global' globalidx ')' { ExportGlobal $2 } export :: { Export } : 'export' name '(' exportdesc ')' { Export $2 $4 } start :: { StartFunction } : 'start' funcidx ')' { StartFunction $2 } -- TODO: Spec from 09 Jan 2018 declares 'offset' keyword as mandatory, -- but collection of testcases omits 'offset' in this position -- I am going to support both options for now, but maybe it has to be updated in future. offsetexpr :: { [Instruction] } : '(' 'offset' foldedinstr ')' { $3 } | foldedinstr { $1 } elemsegment :: { ElemSegment } : 'elem' opt(tableidx) offsetexpr list(funcidx) ')' { ElemSegment (fromMaybe (Index 0) $2) $3 $4 } datasegment :: { DataSegment } : 'data' opt(memidx) offsetexpr list(string) ')' { DataSegment (fromMaybe (Index 0) $2) $3 (TL.concat $4) } modulefield1_single :: { ModuleField } : typedef { MFType $1 } | import { MFImport $1 } | memory { MFMem $1 } | global { MFGlobal $1 } | export { MFExport $1 } | start { MFStart $1 } | elemsegment { MFElem $1 } | datasegment { MFData $1 } modulefield1_multi :: { [ModuleField] } : function { $1 } | table { $1 } modulefield1 :: { [ModuleField] } : modulefield1_single { [$1] } | modulefield1_multi { $1 } modulefield :: { [ModuleField] } : '(' modulefield1 { $2 } modulefields :: { Module } : modulefields modulefield { foldl' (flip appendModuleField) $1 $2 } | {- empty -} { emptyModule } mod :: { Module } : '(' 'module' modulefields ')' EOF { reverseModuleFields $3 } | modulefields EOF { reverseModuleFields $1 } -- utils rev_list(p) : rev_list(p) p { $2 : $1 } | {- empty -} { [] } rev_list1(p) : rev_list1(p) p { $2 : $1 } | p { [$1] } list(p) : rev_list(p) { reverse $1 } list1(p) : rev_list1(p) { reverse $1 } opt(p) : p { Just $1 } | { Nothing } { t3fst :: (a, b, c) -> a t3fst (a, _, _) = a t3snd :: (a, b, c) -> b t3snd (_, a, _) = a t3thd :: (a, b, c) -> c t3thd (_, _, a) = a appendIdent :: Maybe Ident -> ModuleField -> ModuleField appendIdent i (MFFunc fun) = MFFunc $ fun { ident = i } appendIdent i (MFImport (Import sm name (ImportFunc _ typeUse))) = MFImport $ Import sm name $ ImportFunc i typeUse appendIdent i (MFImport (Import sm name (ImportTable _ elemType))) = MFImport $ Import sm name $ ImportTable i elemType appendIdent i (MFExport (Export name (ExportFunc _))) = MFExport $ Export name $ ExportFunc $ Named <$> i appendIdent i (MFExport (Export name (ExportTable _))) = MFExport $ Export name $ ExportTable $ Named <$> i appendIdent i (MFTable (Table _ tableType)) = MFTable $ Table i tableType appendIdent (Just id) (MFElem segm) = MFElem $ segm { tableIndex = Named id } appendIdent _ mf = mf prependFuncParams :: [ParamType] -> FuncType -> FuncType prependFuncParams prep (FuncType params results) = FuncType (prep ++ params) results prependFuncResults :: [ValueType] -> FuncType -> FuncType prependFuncResults prep (FuncType params results) = FuncType params (prep ++ results) mergeFuncType :: FuncType -> FuncType -> FuncType mergeFuncType (FuncType lps lrs) (FuncType rps rrs) = FuncType (lps ++ rps) (lrs ++ rrs) asUInt32 :: Integer -> Maybe Natural asUInt32 val | val >= 0, val < 2 ^ 32 = Just $ fromIntegral val | otherwise = Nothing asInt32 :: Integer -> Maybe Integer asInt32 val | val >= -2 ^ 31, val < 2 ^ 32 = Just $ fromIntegral val | otherwise = Nothing asInt64 :: Integer -> Maybe Integer asInt64 val | val >= -2 ^ 63, val < 2 ^ 64 = Just $ fromIntegral val | otherwise = Nothing asFloat32 :: Double -> Float asFloat32 = realToFrac asFloat64 :: Double -> Double asFloat64 = id asOffset :: LBS.ByteString -> Maybe Natural asOffset str = do num <- TL.stripPrefix "offset=" $ TLEncoding.decodeUtf8 str fromIntegral . fst <$> eitherToMaybe (TLRead.decimal num) asAlign :: LBS.ByteString -> Maybe Natural asAlign str = do num <- TL.stripPrefix "align=" $ TLEncoding.decodeUtf8 str fromIntegral . fst <$> eitherToMaybe (TLRead.decimal num) -- TODO: check name conditions. -- Presuming the source text is itself encoded correctly, -- strings that do not contain any uses of hexadecimal byte escapes are always valid names. asName :: LBS.ByteString -> Maybe TL.Text asName = Just . TLEncoding.decodeUtf8 asString :: LBS.ByteString -> Maybe TL.Text asString = Just . TLEncoding.decodeUtf8 eitherToMaybe :: Either left right -> Maybe right eitherToMaybe = either (const Nothing) Just data ValueType = I32 | I64 | F32 | F64 deriving (Show, Eq) data FuncType = FuncType { params :: [ParamType], results :: [ValueType] } deriving (Show, Eq) emptyFuncType :: FuncType emptyFuncType = FuncType [] [] data ParamType = ParamType { ident :: Maybe Ident, paramType :: ValueType } deriving (Show, Eq) newtype Ident = Ident T.Text deriving (Show, Eq) data GlobalType = Const ValueType | Mut ValueType deriving (Show, Eq) data Limit = Limit Natural (Maybe Natural) deriving (Show, Eq) data ElemType = AnyFunc deriving (Show, Eq) data TableType = TableType Limit ElemType deriving (Show, Eq) data Index = Named Ident | Index Natural deriving (Show, Eq) type LabelIndex = Index type FuncIndex = Index type TypeIndex = Index type LocalIndex = Index type GlobalIndex = Index type TableIndex = Index type MemoryIndex = Index data PlainInstr = -- Control instructions Unreachable | Nop | Br LabelIndex | BrIf LabelIndex | BrTable [LabelIndex] LabelIndex | Return | Call FuncIndex | CallIndirect TypeUse -- Parametric instructions | Drop | Select -- Variable instructions | GetLocal LocalIndex | SetLocal LocalIndex | TeeLocal LocalIndex | GetGlobal GlobalIndex | SetGlobal GlobalIndex -- Memory instructions | I32Load MemArg | I64Load MemArg | F32Load MemArg | F64Load MemArg | I32Load8S MemArg | I32Load8U MemArg | I32Load16S MemArg | I32Load16U MemArg | I64Load8S MemArg | I64Load8U MemArg | I64Load16S MemArg | I64Load16U MemArg | I64Load32S MemArg | I64Load32U MemArg | I32Store MemArg | I64Store MemArg | F32Store MemArg | F64Store MemArg | I32Store8 MemArg | I32Store16 MemArg | I64Store8 MemArg | I64Store16 MemArg | I64Store32 MemArg | CurrentMemory | GrowMemory -- Numeric instructions | I32Const Integer | I64Const Integer | F32Const Float | F64Const Double | I32Clz | I32Ctz | I32Popcnt | I32Add | I32Sub | I32Mul | I32DivS | I32DivU | I32RemS | I32RemU | I32And | I32Or | I32Xor | I32Shl | I32ShrS | I32ShrU | I32Rotl | I32Rotr | I64Clz | I64Ctz | I64Popcnt | I64Add | I64Sub | I64Mul | I64DivS | I64DivU | I64RemS | I64RemU | I64And | I64Or | I64Xor | I64Shl | I64ShrS | I64ShrU | I64Rotl | I64Rotr | F32Abs | F32Neg | F32Ceil | F32Floor | F32Trunc | F32Nearest | F32Sqrt | F32Add | F32Sub | F32Mul | F32Div | F32Min | F32Max | F32Copysign | F64Abs | F64Neg | F64Ceil | F64Floor | F64Trunc | F64Nearest | F64Sqrt | F64Add | F64Sub | F64Mul | F64Div | F64Min | F64Max | F64Copysign | I32Eqz | I32Eq | I32Ne | I32LtS | I32LtU | I32GtS | I32GtU | I32LeS | I32LeU | I32GeS | I32GeU | I64Eqz | I64Eq | I64Ne | I64LtS | I64LtU | I64GtS | I64GtU | I64LeS | I64LeU | I64GeS | I64GeU | F32Eq | F32Ne | F32Lt | F32Gt | F32Le | F32Ge | F64Eq | F64Ne | F64Lt | F64Gt | F64Le | F64Ge | I32WrapI64 | I32TruncSF32 | I32TruncUF32 | I32TruncSF64 | I32TruncUF64 | I64ExtendSI32 | I64ExtendUI32 | I64TruncSF32 | I64TruncUF32 | I64TruncSF64 | I64TruncUF64 | F32ConvertSI32 | F32ConvertUI32 | F32ConvertSI64 | F32ConvertUI64 | F32DemoteF64 | F64ConvertSI32 | F64ConvertUI32 | F64ConvertSI64 | F64ConvertUI64 | F64PromoteF32 | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 deriving (Show, Eq) data TypeDef = TypeDef (Maybe Ident) FuncType deriving (Show, Eq) data TypeUse = IndexedTypeUse TypeIndex (Maybe FuncType) | AnonimousTypeUse FuncType deriving (Show, Eq) data MemArg = MemArg { offset :: Natural, align :: Natural } deriving (Show, Eq) data Instruction = PlainInstr PlainInstr | BlockInstr { label :: Maybe Ident, resultType :: [ValueType], body :: [Instruction] } | LoopInstr { label :: Maybe Ident, resultType :: [ValueType], body :: [Instruction] } | IfInstr { label :: Maybe Ident, resultType :: [ValueType], trueBranch :: [Instruction], falseBranch :: [Instruction] } deriving (Show, Eq) data Import = Import { sourceModule :: TL.Text, name :: TL.Text, desc :: ImportDesc } deriving (Show, Eq) data ImportDesc = ImportFunc (Maybe Ident) TypeUse | ImportTable (Maybe Ident) TableType | ImportMemory (Maybe Ident) Limit | ImportGlobal (Maybe Ident) GlobalType deriving (Show, Eq) data LocalType = LocalType { ident :: Maybe Ident, localType :: ValueType } deriving (Show, Eq) data Function = Function { ident :: Maybe Ident, funType :: TypeUse, locals :: [LocalType], body :: [Instruction] } deriving (Show, Eq) data Global = Global { ident :: Maybe Ident, globalType :: GlobalType, initializer :: [Instruction] } deriving (Show, Eq) data Memory = Memory (Maybe Ident) Limit deriving (Show, Eq) data Table = Table (Maybe Ident) TableType deriving (Show, Eq) data ExportDesc = ExportFunc (Maybe FuncIndex) | ExportTable (Maybe TableIndex) | ExportMemory MemoryIndex | ExportGlobal GlobalIndex deriving (Show, Eq) data Export = Export { name :: TL.Text, desc :: ExportDesc } deriving (Show, Eq) data StartFunction = StartFunction FuncIndex deriving (Show, Eq) data ElemSegment = ElemSegment { tableIndex :: TableIndex, offset :: [Instruction], funcIndexes :: [FuncIndex] } deriving (Show, Eq) data DataSegment = DataSegment { memIndex :: MemoryIndex, offset :: [Instruction], datastring :: TL.Text } deriving (Show, Eq) data ModuleField = MFType TypeDef | MFImport Import | MFFunc Function | MFTable Table | MFMem Memory | MFGlobal Global | MFExport Export | MFStart StartFunction | MFElem ElemSegment | MFData DataSegment deriving(Show, Eq) data Module = Module { types :: [TypeDef], imports :: [Import], functions :: [Function], tables :: [Table], memories :: [Memory], globals :: [Global], exports :: [Export], start :: Maybe StartFunction, elems :: [ElemSegment], datas :: [DataSegment] } deriving (Show, Eq) emptyModule :: Module emptyModule = Module { types = [], imports = [], functions = [], tables = [], memories = [], globals = [], exports = [], start = Nothing, elems = [], datas = [] } appendModuleField :: ModuleField -> Module -> Module appendModuleField field mod = case field of MFType typeDef -> mod { types = typeDef : types mod } MFImport imp -> mod { imports = imp : imports mod } MFFunc func -> mod { functions = func : functions mod } MFTable table -> mod { tables = table : tables mod } MFMem mem -> mod { memories = mem : memories mod } MFGlobal global -> mod { globals = global : globals mod } MFExport exp -> mod { exports = exp : exports mod } MFStart startFunc -> mod { start = Just startFunc } MFElem elem -> mod { elems = elem : elems mod } MFData dataSeg -> mod { datas = dataSeg : datas mod } reverseModuleFields :: Module -> Module reverseModuleFields mod = Module { types = reverse $ types mod, imports = reverse $ imports mod, functions = reverse $ functions mod, tables = reverse $ tables mod, memories = reverse $ memories mod, globals = reverse $ globals mod, exports = reverse $ exports mod, start = start mod, elems = reverse $ elems mod, datas = reverse $ datas mod } happyError (Lexeme _ EOF : []) = error $ "Error occuried during parsing phase at the end of file" happyError (Lexeme (AlexPn abs line col) tok : tokens) = error $ "Error occuried during parsing phase. " ++ "Line " ++ show line ++ ", " ++ "Column " ++ show col ++ ", " ++ "Token " ++ show tok ++ ". " ++ "Token lookahed: " ++ show (take 3 tokens) }