bellard / quickjs

Public repository of the QuickJS Javascript Engine.
https://bellard.org/quickjs
Other
8.55k stars 895 forks source link

Strange behavior of QuickJS interpreter #338

Open LazataknesSoftware opened 3 months ago

LazataknesSoftware commented 3 months ago

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

chqrlie commented 3 months ago

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.

LazataknesSoftware commented 3 months ago

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