Functional usability testing of passing "js_string" to JavaScript

I found in an article written by a Japanese frontend compiler.

author: mizchi
link: moonbit 言語仕様の確認

Here are mine.

main.mbt

fn print_out(d : Js_string) -> Unit = "spectest" "print_char"

pub fn test_print() -> Unit {
 
  let x = Js_string::new("Hello, ")
  let y = Js_string::new("Js_string!")
  let z = x + y
  z.log()
  print_out(z)
} 
main.js

const importObject = { 

    print : {
        out:function(a,b){
                console.log(a,b)
        }
    },
    spectest: {
        print_char: (_)=>console.log("#@",_)
    },
    js_string : {
        new : (...a)=>{
            console.log("new#",a)
            return a
        },
        log : (...a)=>{
            console.log("log#",a)
        },
        append : (a,b)=>{
            console.log("a#",a,b)
            return a+b
        },
        empty : (...a)=>{
            console.log("empty#",a)
        },
        
    }
}; 


readFileAsync("./target/wasm-gc/release/build/lib/lib.wasm")
    .then(buffer => WebAssembly.instantiate(buffer, importObject))
    .then(obj => {
        obj.instance.exports._start(); 
        obj.instance.exports["test_print"](); 
    })
    .catch(error => {
        console.error('Error loading WebAssembly module:', error);
    });


console info
new# [ 0, 7 ]    * 7 is the len("Hello, ") of x
new# [ 0, 10 ]       * 10 is the len("Js_string!") of y
a# [ 0, 7 ] [ 0, 10 ]    * append x and y
log# [ '0,70,10' ]    * z.log()
#@ 0,70,10   * spectest.print_char(z)

??? whats the "0" in that.

when i didnt set the importObject with js_string :{new ,log,append …}

i got some error of that
Error loading WebAssembly module: [LinkError: WebAssembly.instantiate(): Import #5 module="js_string" function="empty": function import requires a callable]  

empty or new or log and append

And, despite searching in repositories on GitHub and taolun.moonbitlang.cn, I haven’t found something about. I am in need of technical assistance, even though I have already obtained alternative solutions.

The Js_string is an experimental API and users should consider write their own FFIs for passing strings around.

All right,but i cant passing Array[Int]

such as

fn print_out(a:Array[Int]) -> Unit = "log" "log"

pub fn test_print() -> Unit {
 
  print_out("hi".to_bytes().to_array())
} 

Maybe I misunderstood some syntax.

We have some limit on the FFI boundary. You can only pass some basic types.

This is my solution, for your reference.
It is a bit complicated and primitive.

moonbit

fn newJs_string()-> Int = "Js_stringMAp" "newJs_string"
fn appendJs_string(n:Int,ch:Int)-> Unit = "Js_stringMAp" "appendJs_string"
fn endJs_string(n:Int)-> Unit = "Js_stringMAp" "endJs_string"
fn printJs_string(n:Int)-> Unit = "Js_stringMAp" "printJs_string"
 
pub fn test_print()-> Unit {
  let newStringFlag : Int = newJs_string()
  let moonbitString = "<《moonbit》_001\nhi~ here\r\n___something\ris".to_array()
  let moonbitStringLength = moonbitString.length()
  let mut i = 0
  while i < moonbitStringLength {
    appendJs_string(newStringFlag,moonbitString[i].to_int())
    i+=1
  } else {
    endJs_string(newStringFlag)
  }
  printJs_string(newStringFlag)

  println("\n\nwhats_up")
}

JavaScript

const [log, flush] = (() => {
    var buffer = [];
    function flush() {
        if (buffer.length > 0) {
            console.log(new TextDecoder("utf-16").decode(new Uint16Array(buffer)));
            buffer = [];
        }
    }
    function log(ch) { 
        if (ch === '\n'.charCodeAt(0)) { flush(); }
        else if (ch === '\r'.charCodeAt(0)) { /* noop */ }
        else { buffer.push(ch); }
    }
    return [log, flush];
})();


const [newJs_string,appendJs_string, endJs_string,printJs_string] = (() => {
    const Js_stringMAp  = new Map(); // set to Global?
    const bufferMap = new Map();
    const endJs_string = (n) => {
        const buffer = bufferMap.get(n);
                //    bufferMap.set(n,undefined); // ?
        if (buffer.length > 0)
            Js_stringMAp.set(n,  new TextDecoder("utf-16").decode(new Uint16Array(buffer)))
    }
    const appendJs_string = (n,ch) =>bufferMap.get(n).push(ch);

    const newJs_string = () => {
       
        const n = randomInt(20240617);
        console.log(`The randomInt rolled: ${n}\n\n\n`);
        bufferMap.set(n,[])
        return n
    };
    const printJs_string = (n) => {
        console.log(`Flag: ${n}\n\n${Js_stringMAp.get(n)}`);
    }
    return [newJs_string,appendJs_string, endJs_string,printJs_string];
})();


const importObject = { 
    spectest: {
        print_char: log
    },
    Js_stringMAp : {
        newJs_string,
        appendJs_string,
        endJs_string,
        printJs_string,
    },
};  

works well

image

Thank you a lot