01:26
<Bakkot>
ok I found it it didn't change in 2019
01:26
<Bakkot>
it is quoted here: https://www.quora.com/Why-do-you-think-modulus-is-not-defined-for-floating-point-numbers
01:29
<Bakkot>
but... uh... this is wrong, right? like, set x = 9, y = 5, and then it says to find "n" as "the integer nearest the exact number x/y", i.e. the integer nearest 9/5, i.e. 2, and then r = x - y * n, i.e. r=9 - 5 * 2, i.e. r = -1
01:30
<Bakkot>
which is... not what remainder(9, 5) is
01:30
<Bakkot>
... right?
01:30
<Bakkot>
am I crazy?
01:31
<devsnek>
> Floating point remainder. This is not like a normal modulo operation, it can be negative for two positive numbers. It returns the exact value of x–(round(x/y)·y).
01:33
<Bakkot>
whyyyyy
01:33
<devsnek>
computers be that way sometimes
01:33
<Bakkot>
ok so when number::remainder says it "the floating-point remainder r from a dividend n and a divisor d is defined by the mathematical relation [...]", that doesn't actually mean the IEEE floating-point remainder
01:38
<devsnek>
right
01:38
<Bakkot>
it should probably not claim to be the floating-point remainder then
01:39
<Bakkot>
sidebar: was creating a demo to share this, got the best URL for it: https://repl.it/repls/ImpracticalDearestRuntimelibrary
01:50
<devsnek>
nice
02:29
<devsnek>
TIL es6 didn't have the ?/! macros
02:35
<shu>
we must remember what has been lost https://i.imgflip.com/49yuel.jpg
02:37
<devsnek>
your meme has an off-by-one error
02:37
<devsnek>
or off by three i guess
02:38
<shu>
wat
02:39
<ljharb>
lol
02:43
<devsnek>
shu: 5, 5.1, and 6 have no assigned doge
02:45
<rkirsling>
we don't ~talk~ meme about the "middle times"
15:14
<devsnek>
the second test in built-ins/String/raw/special-characters.js
15:15
<devsnek>
it turns \<CR>\<CR><LF>\<LF>
15:16
<devsnek>
into \<LF>\<LF>\<LF>
15:16
<devsnek>
does that sound correct
16:47
<devsnek>
Bakkot: in an ast, would you ever expect to see a node of type "ForBinding"
16:47
<Bakkot>
devsnek probably not
16:47
<Bakkot>
LHS of a for-of is either a let-style binding or the LHS of an assignment expression
16:47
<Bakkot>
woudl be weird to have the type not be... those
16:48
<Bakkot>
I guess one difference is that you can have a `const` binding which isn't initialized?
16:48
<Bakkot>
but doesn't seem worth splitting out
16:48
<devsnek>
i'm more trying to figure out the organization of uh
16:48
<devsnek>
when a certain production gets its own node type vs when it's just its children
16:49
<devsnek>
maybe a better way to ask is: would you ever expect to see { type: 'BindingProperty', SingleNameBinding: ... }
16:50
<devsnek>
instead of BindingProperty : SingleNameBinding just becoming SingleNameBinding
17:04
<Bakkot>
for most ASTs, you never have a node type which only has one legal parent
17:05
<Bakkot>
though I think sometimes it's unavoidable because the type system is too constrained
17:07
<Bakkot>
I guess "one legal parent" isn't quite right, but rather one legal _position_
17:52
<Bakkot>
the exception to that is that sometimes you need a wrapper type to separate semantics: like `{ a, ...a }`, you need to differentiate between the two kinds of thing which are otherwise identical, so you might have a `SpreadProperty` which can only appear in objects
18:01
<devsnek>
i should get a bunch of parser nerds to review the engine262 ast when i finish it
18:01
<Bakkot>
just use shift's
18:02
<Bakkot>
inventing new ASTs makes things harder to use, it needs a pretty good justification
18:03
<devsnek>
well i'm not expecting anyone to use this
18:03
<devsnek>
outside of engine262
18:04
<Bakkot>
yeah, but it is less overhead for people to contribute to your project, and less overhead for contributors to your project to contribute to other projects, if you use a standard AST
18:05
<devsnek>
i'd argue the opposite in this context actually
18:05
<Bakkot>
how so?
18:05
<devsnek>
it takes a lot of effort to map the spec's semantics to an ast that doesn't match
18:06
<Bakkot>
shift matches the spec pretty precisely
18:06
<Bakkot>
just elides intermediate nodes, which pretty much every AST does
18:07
<Bakkot>
and has slightly tighter constraints in some places where the spec enforces those constraints with early errors
18:08
<devsnek>
hm for example
18:08
<devsnek>
FunctionDeclaration with isAsync/isGenerator
18:08
<devsnek>
vs having GeneratorFunctionDeclaration and AsyncFunctionDeclaration
18:09
<Bakkot>
ah, sure, I can see the argument for having a lot more node types rather than having fields on nodes
18:09
<Bakkot>
I think it'll probably end up being a lot more code that way, though
18:10
<Bakkot>
like most places you want to treat those things identically
18:10
<devsnek>
i would say, engine262 has a lot of superfluous structure in order to have less "is this a node of x type" code
18:10
<Bakkot>
for Contains or whatever
18:10
<devsnek>
yeah
18:10
<devsnek>
its more annoying in static semantics for sure
18:10
<devsnek>
although the way we were writing static semantics with acorn was already annoying
18:11
<devsnek>
basically everything in the acorn version goes through this https://github.com/engine262/engine262/blob/master/src/ast.mjs
18:11
<devsnek>
never actually check `node.type` directly
18:13
<Bakkot>
fun
18:13
<Bakkot>
we usually just do `switch (node.type)`
18:13
<Bakkot>
well, actually, in practice we just have one place that does that and everything else uses it
18:14
<Bakkot>
https://github.com/shapesecurity/shift-reducer-js/blob/2732f575213b200a9acb9fe1a5da47e9b8f13c1e/gen/director.js
18:14
<Bakkot>
(ok, it uses an object with mappings rather than a switch, but close enough)
18:15
<devsnek>
ya saw that
18:15
<devsnek>
with the new ast i just switch on type as well: https://github.com/engine262/engine262/blob/parser/src/evaluator.mjs#L83
18:18
<Bakkot>
yeah
18:18
<Bakkot>
I am generally quite happy with the tradeoff Shift makes with having the appropriate number of types of node
18:19
<devsnek>
if i was going to make a general purpose ast it would probably look like shift
18:20
<Bakkot>
every AST ends up being general purpose eventually
18:20
<Bakkot>
that's how we ended up with estree
18:20
<Bakkot>
(but yeah a custom one sounds reasonable for your case)
18:21
<devsnek>
i don't think you can even use the parser in engine262 without accidentally including the entire runtime
18:21
<Bakkot>
couldn't use estree without including an entire browser for a long time and that didn't stop anyone
18:22
<devsnek>
lol
19:36
<jmdyck>
Bakkot: Does https://github.com/tc39/ecma262/pull/2007#issuecomment-667271814 mean that you're going to want my review soon, or just that there will soon be a new version available for review? (Or possibly both)
19:37
<Bakkot>
that there will soon be a new version available for review
19:37
<Bakkot>
we're fixing the issues we're aware of (dates are indeed a particularly tricky one)
19:38
<Bakkot>
if you are able to review that one to find the issues we miss (of which I am sure there will be a number) that will be much appreciated
19:40
<Bakkot>
my current stumbling block is that operations `MakeDate` have math being performed on Numbers, and these _might_ have different semantics if you use IEEE floating point math rather than doing the math in the math domain and converting to/from at the boundary of the function, and I need to figure out if the difference is observable and, if so, which is intended/implemented
19:40
<Bakkot>
*operations like MakeDate
19:41
<Bakkot>
(ps ryzokuken or other datetime people, if you know the answer to the above question I would love to hear it)
19:42
<devsnek>
choose the most confusing behaviour so our successors don't have it too easy
19:42
<ryzokuken>
Damn
19:43
<ryzokuken>
I'm on phone can someone please link me to MakeDate?
19:43
<Bakkot>
https://tc39.es/ecma262/#sec-makedate
19:43
<Bakkot>
The abstract operation MakeDate takes arguments day (a Number) and time (a Number). It calculates a number of milliseconds. It performs the following steps when called:
19:43
<Bakkot>
If day is not finite or time is not finite, return NaN.
19:43
<Bakkot>
Return day × msPerDay + time.
19:46
<devsnek>
I doubt the difference is observable cuz I implemented that in engine262 using floating point math
19:47
<devsnek>
then again test262 might be lacking
19:47
<Bakkot>
that doesn't mean it's not observable, just means that the difference either is not exercised in the tests (extremely likely) or that the intention is to use floating point math (also likely)
19:49
<Bakkot>
I guess for now I will assume floating piont
19:49
<Bakkot>
part of my hesitation is that MakeTime explicitly says to use IEEE arithmetic
19:49
<Bakkot>
and none of the rest of them do
19:50
<ryzokuken>
Hmm
19:50
<Bakkot>
the MakeTime one is also confusing because it does two additions without parentheses, but IEEE arithmetic is not associative
19:52
<ryzokuken>
Can we just convert to real numbers?
19:52
<ryzokuken>
Before that math?
19:52
<Bakkot>
well, yes, that's the question
19:53
<Bakkot>
we could do that, but this might have observably different semantics
19:53
<ryzokuken>
So idk what the original intent was either
19:53
<ryzokuken>
Probably need to check in implemeters
19:54
<ryzokuken>
And no harm in specifying now if it doesn't break web reality, is there?
19:54
<ryzokuken>
Implementations*
19:55
<Bakkot>
well, two things: a.) if it's a normative change I'd have to bring it to plenary, and b.) implementations are unlikely to want to actually do arbitrary-precisino math
19:59
<ryzokuken>
Since the aim of the pr seems to be reducing ambiguity, we need to specify it one way or the other, I suppose.
19:59
<Bakkot>
it looks like in es5 this was explicitly not specified: "an implementation is permitted a choice of internal representations of time values, for example as a 64-bit signed integer or as a 64-bit floating-point value"
19:59
<ryzokuken>
Oh wow
20:00
<ryzokuken>
I didn't know we accepted integers like that.
20:00
<ryzokuken>
What about the date value? Surely that accepts floats.
20:00
<Bakkot>
it wouldn't be observable except that the arithmetic would be more precise
20:02
<ryzokuken>
I see
20:03
<ryzokuken>
Don't really know, to be honest 😅
20:04
<ryzokuken>
I'll dig deeper into this
21:21
<Bakkot>
$ eshost -s -e 'Date.UTC(1970, 0, 1, 80063993375, 29, 1, -288230376151711740)'
21:21
<Bakkot>
#### Chakra, SpiderMonkey, V8, XS
21:21
<Bakkot>
29312
21:21
<Bakkot>
#### JavaScriptCore
21:21
<Bakkot>
NaN
21:21
<Bakkot>
JSC what are you doing
21:22
<devsnek>
Bakkot: https://gc.gy/63935557.png
21:23
<Bakkot>
Hah! Graal is _exactly_ what I was looking for there
21:23
<devsnek>
using u64?
21:23
<Bakkot>
mm, no, just parenthesizing differently
21:23
<devsnek>
oh no
21:24
<Bakkot>
`80063993375 * 3600000 + 29 * 60000 + 1 * 1000 - 2**58` is, in math, 29256
21:24
<devsnek>
so quickjs wins
21:24
<Bakkot>
in double-precision floats, if you do your `+` left-associate, it's 29312
21:24
<Bakkot>
if you parenthesize as 80063993375 * 3600000 + (29 * 60000 + 1 * 1000) - 2**58, it's 29248
21:25
<devsnek>
what if you return nan
21:25
<Bakkot>
I think the way you end up with NaN is by time-clipping before doing the arithmetic, which is not allowed per spec
21:26
<devsnek>
> `return JSValue::encode(jsNumber(timeClip(ms)));`
21:26
<Bakkot>
is that from jsc's source?
21:26
<devsnek>
ya
21:27
<Bakkot>
sweet
21:27
<Bakkot>
link?
21:27
<Bakkot>
this is gonna be a fun test262 test
21:27
<devsnek>
https://github.com/WebKit/webkit/blob/de7fb331a9fb6ed6773508765f9498fb12f90b4d/Source/JavaScriptCore/runtime/DateConstructor.cpp#L173
21:27
<Bakkot>
thank
21:28
<devsnek>
so glad we support -2**58 milliseconds
21:29
<devsnek>
and 80 billion hours
21:35
<jmdyck>
Yeah, it looks like TimeClip is the only place we enforce the restricted range for 'time values', and TimeClip is generally called very late in Date functions, so all the date-related operations are potentially dealing with "out of range" Number values.
21:36
<devsnek>
Bakkot: actually JSC is a lot scarier than i thought
21:36
<devsnek>
its not the clipping, its this https://github.com/WebKit/webkit/blob/de7fb331a9fb6ed6773508765f9498fb12f90b4d/Source/JavaScriptCore/runtime/DateConstructor.cpp#L84-L96
21:37
<devsnek>
it throws everything away if the args don't fit in i32
21:38
<Bakkot>
$ eshost -s -e 'Date.UTC(1970, 0, 1, 0, 0, 0, 2**32)'
21:38
<Bakkot>
#### Chakra, SpiderMonkey, V8, XS
21:38
<Bakkot>
4294967296
21:38
<Bakkot>
#### JavaScriptCore
21:38
<Bakkot>
NaN
21:38
<Bakkot>
lol
21:38
<devsnek>
:^)
21:39
<Bakkot>
that's like a month and a half into the start of the epoch
21:39
<Bakkot>
2**32 is a totally reasonable number of milliseconds
21:39
<devsnek>
🤷🏻
21:40
<Bakkot>
I wonder why they even bother with timeClip, then
21:42
<devsnek>
wow i have a webkit bugzilla account
21:44
<devsnek>
https://bugs.webkit.org/show_bug.cgi?id=215034
21:46
<rkirsling>
is there a test262 test
21:47
<devsnek>
i don't think so but i'm not 100% sure
21:48
<Bakkot>
at a quick glance, no
21:49
<Bakkot>
if jsc has a place which records expectations for test262, that would be an easy way to check
21:49
<devsnek>
am i the only one who uses `-ts` instead of `-s` in eshost
21:49
<Bakkot>
omitting the -t makes output which is more suitable for copy-pasting
21:50
<devsnek>
https://test262.report/browse/built-ins/Date?engines=javascriptcore
21:59
<shu>
Bakkot: product excellence is about not living in the past
22:01
<Bakkot>
shu: pretty sure I can come up with an example that may or may not be in the past depending on the implementation :P
22:01
<shu>
anyway this sounds like a fun friday activity
22:09
<Bakkot>
https://github.com/tc39/ecma262/pull/2120
22:09
<Bakkot>
yeah floats are dumb
22:09
<Bakkot>
it started as a fun thursday activity
22:09
<Bakkot>
and we went until we got stuck
22:09
<Bakkot>
and then I got distracted trying to figure out of any of this was observably problematic
22:19
<jmdyck>
Bakkot: in 2120, the second parenthesization doesn't look right (to left)
22:20
<Bakkot>
jmdyck in the PR message, or the commit?
22:20
<Bakkot>
in the message, yeah, it's not right-to-left, but it is a legal parenthesization
22:21
<jmdyck>
PR msg: deepest term would be "(1 * 1000 + -288230376151711744)", no?
22:21
<jmdyck>
ah, ok
22:22
<Bakkot>
I guess the full right-to-left order has the same result as my mixed-order, so I might as well use that as my example
22:48
<shu>
we agreed to \8 \9 erroring inside template literals regardless of strictness, right?
22:49
<shu>
or... just strict mode?
22:52
<Bakkot>
shu: that was the existing behavior and has not changed
22:52
<Bakkot>
(for untagged templates only, of course)
22:53
<shu>
ah so it's an existing bug...
22:53
<shu>
i see SM and V8 both accept ``\8`` and ``\9``
22:53
<shu>
that didn't quote the way i intended...
23:35
<devsnek>
am i blind or is there no definition of BindingInitialization for ForBinding
23:35
<Bakkot>
without looking I would guess you don't need one because of the chain production rule
23:37
<devsnek>
so ForBinding : BindingPattern and ForBinding: BindingIdentifier
23:37
<devsnek>
automatically go to 13.3.3.5 and 12.1.5?
23:38
<Bakkot>
> Unless explicitly specified otherwise, all chain productions have an implicit definition for every operation that might be applied to that production's left-hand side nonterminal. The implicit definition simply reapplies the same operation with the same parameters, if any, to the chain production's sole right-hand side nonterminal and then returns the result.
23:38
<devsnek>
i see