68 karma · joined December 3, 2018
What you probably shouldn't do is try to come up with your own encryption scheme/mode of operation/padding scheme and think you've learned something valuable. By all means, try that as well, but know that you've now entered the really dangerous territory.
Not really notable, expect perhaps being the only one on the list with an ES1 mode? :) (Can't promise it's accurate though, as it was hard to find examples).
Otherwise pretty boring (C++, hand-written parser, AST interpreter, ES1/ES3/ES5.1 support minus some regexp/timezone/locale stuff).
But looking into the details of how object prototypes and properties really work is essential for getting a good grasp of the language.
Recently did this myself (https://github.com/mras0/scc/blob/master/scc.c) but it took waaaaay more than 10 hours and I had many previous failed attempts before that.
write(STDERR_FILENO,"test",4); // OK, write to normal stderr
close(STDERR_FILENO);
open(....); // Open some log file
// later
write(STDERR_FILENO,"x",1); // OK, write to log file
Even though fd 2 refers to different files I think the above is required to work for POSIX compliance.It might be possible with some hacks/heuristics to catch many errors (perhaps one could create a valgrind tool/santizier), but I suspect it's not possible in general since there's no way of knowing if the call to write(2,....) meant the old stderr or the new one.
Keep it simple and focus on making it composable. By that I mean if you're targeting x86 keep the current value in [r|e]ax (forget about non-integer stuff for now :), if it's a stack based VM: focus on the stack top. A numeric literal loads [r|e]ax (or pushes it on the stack). Binary operators first pushes computes the lhs; pushes the result; computes rhs, combines and leaves the result in [r|e]ax (or the stack top).
Output to some kind of text format and lean on existing tools. It's probably not a bad idea to output C, LLVM bitcode, JVM/.NET bytecode or x86 assembly at first rather than going all the way to machine code starting out.
Postpone thinking about optimizations and reduce your level of ambition. All of my previous attempts at finishing compiler projects failed because the complexity got out of hand. For instance in a C compiler don't try to optimize expressions of smaller-than-int types. Maybe all expressions in your language can be calculated using doubles?
Finally as GP says: You need to be comfortable with the output language (assembly or otherwise). Study the output of similar compilers and translate code by hand into assembly to get a feel of what your compiler should be doing.
If it isn't - and especially if you're dealing with a closed source library - you have to assume the worst and even then you're often unpleasantly suprised :/
But I've tried to keep the code reasonably small and (hopefully) readable - which is why it's currently targeting ES1997 - rather than having lots of features, so it's probably more understandable than V8.
All pointers are tracked automatically (except for specially optimized classes), so that part isn't so bad, but it's still (too) easy to accidentally use a stale pointer value.
At the moment I can safely collect after every statement, but there is still work to be done before I can claim to support collecting after every expression (like I'd ideally be able to - so I can collect when I run out of heap).
Yesterday I finished an article (https://mras0.github.io/mjs/doc/gc/initial.html) on how I implemented the GC and some of the challenges, if you're curious.