quickjs icon indicating copy to clipboard operation
quickjs copied to clipboard

Strange behavior of QuickJS interpreter

Open LazataknesSoftware opened this issue 1 year ago • 2 comments

I am trying to run following code:

let w = /\/(?<group>\w+)(:(?<value>\w+))?/i
//scriptArgs = require("process").argv
// for Node.js 
let r = []
scriptArgs.slice(1).map(a => r.push(w.exec(a).groups))
for (let z of r) {
console.log(z)
}

Error in QuickJS:

TypeError: toPrimitive
at log (native)
at <eval> (args.js:7)

In Node.js that code work without problems, but it does not on QuickJS. I don't understand why.

Note: if I will run console.log({a:2}) in REPL, then it will work without problems!

QuickJS version 2024-01-13 Termux on Android 9.0 Go I installed it (QuickJS) by: pkg i quickjs

LazataknesSoftware avatar Aug 02 '24 17:08 LazataknesSoftware

Here is a more telling test:

let w = /\/(?<group>\w+)(:(?<value>\w+))?/i;
let m = w.exec("/a:2");
console.log('console.log(m):');
console.log(m);
console.log('console.log(m.toString()):');
console.log(m.toString());
console.log('console.log(Object.getPrototypeOf(m) == Object.getPrototypeOf([])):');
console.log(Object.getPrototypeOf(m) == Object.getPrototypeOf([]));
console.log('console.log(Object.getPrototypeOf(m.groups)):');
console.log(Object.getPrototypeOf(m.groups));
console.log('console.log(m.groups.toString):');
console.log(m.groups.toString);
console.log('console.log(m.groups):');
console.log(m.groups);

node outputs this:

console.log(m):
[
  '/a:2',
  'a',
  ':2',
  '2',
  index: 0,
  input: '/a:2',
  groups: [Object: null prototype] { group: 'a', value: '2' }
]
console.log(m.toString()):
/a:2,a,:2,2
console.log(Object.getPrototypeOf(m) == Object.getPrototypeOf([])):
true
console.log(Object.getPrototypeOf(m.groups)):
null
console.log(m.groups.toString):
undefined
console.log(m.groups):
[Object: null prototype] { group: 'a', value: '2' }

while QuickJS outputs this:

console.log(m):
/a:2,a,:2,2
console.log(m.toString()):
/a:2,a,:2,2
console.log(Object.getPrototypeOf(m) == Object.getPrototypeOf([])):
true
console.log(Object.getPrototypeOf(m.groups)):
null
console.log(m.groups.toString):
undefined
console.log(m.groups):
TypeError: toPrimitive
    at log (native)
    at <eval> (issue-338.js:14)

The problem is in console.log. Node's implementation is more advanced than QuickJS'. m.groups is a special object with a null prototype, hence it has neither a toString nor a valueOf method, so console.log(m.groups) throws an exception when converting its argument to a primitive object.

If you type m.groups in the REPL, it will show as { group: "a", value: "2" } because REPL uses more advanced code to dump expression values.

console.log is not specified in the ECMA Standard, but is supported with some variations in all browsers and most javascript runtimes. I shall try and extend support in QuickJS to match the Firefox specification, along with the substitutions, except %c.

chqrlie avatar Aug 03 '24 10:08 chqrlie

I.e. if Object.getPrototypeOf(object) is null, then it is cannot be processed by console.log(object) or print(object)?

LazataknesSoftware avatar Aug 03 '24 14:08 LazataknesSoftware

It should work as expected now.

bellard avatar May 06 '25 11:05 bellard