@@ -3,6 +3,7 @@ package gensym.wasm.parser
33import gensym .wasm .ast ._
44import gensym .wasm .source ._
55
6+ import scala .util .Try
67import scala .util .parsing .combinator ._
78import scala .util .parsing .input .Positional
89import scala .util .matching .Regex
@@ -14,6 +15,9 @@ import scala.collection.JavaConverters._
1415import collection .mutable .{HashMap , ListBuffer }
1516import gensym .wasm ._
1617
18+ import java .io .OutputStream
19+
20+
1721import scala .collection .mutable
1822
1923class GSWasmVisitor extends WatParserBaseVisitor [WIR ] {
@@ -188,23 +192,78 @@ class GSWasmVisitor extends WatParserBaseVisitor[WIR] {
188192 ???
189193 }
190194
195+ // TODO: This doesn't seems quite correct
196+ def parseHexFloat (text : String ): Float = {
197+ if (text.startsWith(" 0x" ) || text.startsWith(" -0x" ) || text.startsWith(" +0x" )) {
198+ // Remove optional sign and "0x" prefix
199+ val cleanText = text.replaceFirst(" ^[+-]?0x" , " " )
200+ // why removing the seemling irrelevant following two lines will effect
201+ // the value being parsed?
202+ val value : Float = BigDecimal (text).floatValue
203+ print(f " cleanText = $cleanText, value = $value\n " )
204+
205+ val Array (mantissa, exponent) = cleanText.split(" p" , 2 )
206+
207+ // Convert mantissa and exponent
208+ val mantissaValue = java.lang.Float .intBitsToFloat(java.lang.Integer .parseUnsignedInt(mantissa.replace(" ." , " " ), 16 ))
209+ val exponentValue = Math .pow(2 , exponent.toInt).toFloat
210+ // print(s"mantissaValue = $mantissaValue, exponentValue = $exponentValue\n")
211+ mantissaValue * exponentValue
212+ } else {
213+ text.toFloat // Fall back to regular decimal parsing
214+ }
215+ }
216+
217+
191218 def visitLiteralWithType (ctx : LiteralContext , ty : NumType ): Num = {
192219 if (ctx.NAT != null ) {
193220 ty.kind match {
194- case I32Type => I32V (ctx.NAT .getText.toInt)
195- case I64Type => I64V (ctx.NAT .getText.toLong)
221+ case I32Type => {
222+ if (ctx.NAT .getText.startsWith(" 0x" )) {
223+ I32V (Integer .parseInt(ctx.NAT .getText.substring(2 ), 16 ))
224+ } else {
225+ I32V (ctx.NAT .getText.toInt)
226+ }
227+ }
228+ case I64Type => {
229+ if (ctx.NAT .getText.startsWith(" 0x" )) {
230+ I64V (java.lang.Long .parseLong(ctx.NAT .getText.substring(2 ), 16 ))
231+ } else {
232+ I64V (ctx.NAT .getText.toLong)
233+ }
234+ }
196235 }
197236 } else if (ctx.INT != null ) {
198237 ty.kind match {
199- case I32Type => I32V (ctx.INT .getText.toInt)
200- case I64Type => I64V (ctx.INT .getText.toLong)
238+ case I32Type => {
239+ if (ctx.INT .getText.startsWith(" 0x" )) {
240+ I32V (Integer .parseInt(ctx.INT .getText.substring(2 ), 16 ))
241+ } else {
242+ I32V (ctx.INT .getText.toInt)
243+ }
244+ }
245+ case I64Type => {
246+ if (ctx.INT .getText.startsWith(" 0x" )) {
247+ I64V (java.lang.Long .parseLong(ctx.INT .getText.substring(2 ), 16 ))
248+ } else {
249+ I64V (ctx.INT .getText.toLong)
250+ }
251+ }
201252 }
253+ // TODO: parsing support for hex representation for f32/f64 not quite there yet
202254 } else if (ctx.FLOAT != null ) {
203255 ty.kind match {
204- case F32Type => F32V (ctx.FLOAT .getText.toFloat)
205- case F64Type => F64V (ctx.FLOAT .getText.toDouble)
256+ case F32Type =>
257+ val parsedValue = Try (parseHexFloat(ctx.FLOAT .getText).toFloat).getOrElse(ctx.FLOAT .getText.toFloat)
258+ F32V (parsedValue)
259+
260+ case F64Type =>
261+ // TODO: not processed at all
262+ val parsedValue = ctx.FLOAT .getText.toDouble
263+ F64V (parsedValue)
206264 }
207- } else error
265+ }
266+ else error
208267 }
209268
210269 override def visitPlainInstr (ctx : PlainInstrContext ): Instr = {
@@ -635,10 +694,45 @@ class GSWasmVisitor extends WatParserBaseVisitor[WIR] {
635694 else error
636695 }
637696
638- override def visitScriptModule (ctx : ScriptModuleContext ): Module = {
697+ override def visitScriptModule (ctx : ScriptModuleContext ): Module = {
639698 if (ctx.module_ != null ) {
640699 visitModule_(ctx.module_).asInstanceOf [Module ]
641- } else {
700+ }
701+ else if (ctx.BIN != null ) {
702+
703+ val bin = ctx.STRING_
704+ val hexString = bin.asScala.toList.map(_.getText.substring(1 ).dropRight(1 )).mkString
705+
706+ val byteArray : Array [Byte ] = hexStringToByteArray(hexString)
707+
708+ // just for fact checking
709+ // val filePath = "temp.bin"
710+ // Files.write(Paths.get(filePath), byteArray)
711+
712+ // use `wasmfx-tools` to convert the binary file to a text file
713+ val processBuilder = new ProcessBuilder (" ./third-party/wasmfx-tools/target/release/wasm-tools" , " print" )
714+
715+ val process = processBuilder.start()
716+ val outputStream : OutputStream = process.getOutputStream
717+ try {
718+ outputStream.write(byteArray)
719+ outputStream.flush()
720+ } finally {
721+ outputStream.close() // Close the stream to signal end of input
722+ }
723+
724+ val output = scala.io.Source .fromInputStream(process.getInputStream).mkString
725+ val errorOutput = scala.io.Source .fromInputStream(process.getErrorStream).mkString
726+ val exitCode = process.waitFor()
727+
728+ // println(s"Exit code: $exitCode")
729+ // println(s"Output:\n$output")
730+ // println(s"Error Output:\n$errorOutput")
731+
732+ val module = Parser .parse(output)
733+ module
734+ }
735+ else {
642736 throw new RuntimeException (" Unsupported" )
643737 }
644738 }
@@ -688,14 +782,20 @@ class GSWasmVisitor extends WatParserBaseVisitor[WIR] {
688782 Script (cmds.toList)
689783 }
690784
691- override def visitTag (ctx : TagContext ): WIR = {
692- val name = getVar(ctx.bindVar)
693- val ty = visitFuncType(ctx.funcType)
694- Tag (name, ty)
785+ // Function to convert a hex string representation to an Array[Byte]
786+ def hexStringToByteArray (hex : String ): Array [Byte ] = {
787+ // Split the input string by '\' and filter out empty strings
788+ val byteStrings = hex.split(" \\\\ " ).filter(_.nonEmpty)
789+
790+ byteStrings.map { byteStr =>
791+ // Parse the hex value to a byte
792+ Integer .parseInt(byteStr, 16 ).toByte
793+ }
695794 }
696795
697796}
698797
798+
699799object Parser {
700800 private def makeWatVisitor (input : String ) = {
701801 val charStream = new ANTLRInputStream (input)
0 commit comments