Mechanized LambdaJS
brownplt.github.com
brownplt.github.com
Has anyone else taken a tour through their codebase?
Actually, what the hell, I'll download haskell, run their interpreter, and see about getting the underscore.js test suite to run.
There have been a few attempts to formalize the semantics of JS, but the lambdaJS approach is the most practical: by factoring out the incidental details (the "syntactic sugar") as a translation ("desugaring") to a kernel language, any work you do on the formal semantics of the language only has to focus on the smaller kernel.
This is also a really practical way to approach building tools for JS, like static analysis: if you design a single desugaring pass as a translation, then you can build a whole bunch of tools on the kernel language. Same idea roughly as the standard compilers approach of translating to an IR.
But that said, having read through their blog posts, I was under the impression that their interpreter doesn't in fact support all of the SpiderMonkey test suite, and so, as a practical matter is still only supporting a subset of JS.
My attempts to get underscore working have been unsuccessful thus far (the debug info isn't terribly useful, not knowing their codebase).
Another implementation of the core semantics + desugaring approach, dubbed S5 (https://github.com/brownplt/lambdas5), is better engineered and actually uses SpiderMonkey's parser to handle more programs.
S5 runs underscore.js without any issues. Do give it a shot if you're still interested in trying things out.
Also, it's worth mentioning that S5 handles features of the new ECMAScript 5 specification, like strict mode, getters and setters, and new APIs, that the original λJS simply doesn't handle, so it's a much more complete account of JavaScript.
I lament that HN has lost its way enough that this thread didn't make it anywhere near the top of the homepage.
Dave
> JS: { x : 2 + 3, y : 9 }["x"] * (11 + 23)
> Lua: ({ x = 2 + 3, y = 9 })["x"] * (11 + 23)
> Lua: ({ x = 2 + 3, y = 9 }).x * (11 + 23)Of course, this holds when λJS is really correct and a good model for JavaScript. Unfortunately they have found that there is a severe hole left in λJS after they had a (now wrong) correctness theorem. In light of this problem, they now mechanically proved that there are no more holes left in λJS. Unlike a hand-written proof a mechanized proof can be verified by a relatively simple[1] program, so you don't need to believe yourself but just the program. As mechanized proofs need to describe every detail, this is not a simple task, and that's what they did.
[1] A lot simpler than the actual human.
I don't know what you mean when you say it's not a "traditional mathematical definition". It's both traditional and mathematical enough.
An "operational semantics" is not necessarily a simplification. Whether or not it's a simplification is a function of what you are specifying.
We chose a route whereby a compiler reduces all of JS to a simpler language (λJS) and then provided an operational semantics for that simpler language. Neither is this non-mathematical nor is the simplification inherent to an operational semantics.
Your restatement of soundness contains dangerous words that have other, technical meanings (like "valid") and is also not quite right. The soundness being proven here is called "untyped soundness", and it simply means "the semantics didn't forget any cases that should have been defined". Perhaps that is what you meant to say, but I'd suggest this way of saying it is a lot less obscure.
Our previous formulation missed a few cases. The cases were sufficiently obscure that all our prior testing and use did not catch them. So I'd say this hardly warrants the label "severe". You can see the sum total of change here (the link was in the original post):
https://github.com/brownplt/LambdaJS/commit/9a7e67ab896c8db3...
Also, our previous attempt to confirm untyped soundness was not hand-written. It too was mechanical, but it used a state-exploration strategy. This caught lots of problems, which we fixed, but because it could not explore the state exhaustively, it missed a few that we hadn't noticed. The strategy in this post explores the state exhaustively (through a proof-assistant).
Hope that clarifies.
Having tried to augment and test λJS myself, I'm very glad to hear that it is now fully mechanized. Keep up good work, :-)