Interpreter/compiler with an emphasis on code transformation and reflection.
The interpreter is nice and all, but it's slow. With tree-shaking, we can (eventually) compile to optimal bundles in other languages.
-
JavaScript (ES5)
- I considered ES6, but:
- Still not really supported anywhere...
- Dart has every ES6 feature, done way better
- ES5 is compatible with pretty much everything now
- I considered ES6, but:
-
Dart
- It's fast
- I like Dart
- Several Fray features inspired by Dart, as well as the idea of an asset pipeline
-
C (this is a big IF)
- It would be challenging to compile to C, however:
- C is supported by everything
- Many highly-optimized compilers available
- It would be challenging to compile to C, however:
The interpreter will include:
- Control flow
- break
- continue
- Private variables
- Functions should be closures
- Expressions
- Assignment
- Identifiers
- Simple and Prefixed
- Indexers
- Numbers
- Long
- Literals
- Dictionary
- Operators
- Unary
- Prefix: !, ++, -- (turn the latter two into += and -= with transformer)
- Postfix: ++, --
- Binary
- Arithmetic: -, /, ^
- Boolean: !=, <, <=, >, >=
- Unary
- Strings
- Raw
- Escaping
- Imported and exported need to use separate symbol tables...
- Also, it's not properly exporting top-level variables :(
- Hoist functions
All additional functionality can hopefully be implemented in Fray, in the form of libraries.
- Custom stack traces
- Source maps :)
- Get hashmap of symbols in scope
- Print like in Node, with curses too
- Tree shaker
- Just run this through asset pipeline :)
- Access members through
getFieldinstead of directly touching symbol tableExtensibleshim
Should remove all unused functions and variables intuitively.
- Use a visitor, organize all declarations into scopes
- Declarations include:
- Function/Variable declarations (top-level or otherwise)
- Members declared on classes
- Each symbol should have a flag,
used, defaults tofalse. - Each symbol should also have a
sourcepointing to its declaration.
- Declarations include:
- Using another visitor, go through all possible usages
- Mark symbols as
usedonly if they are actually used. - Recurse through symbols, and for any that are not used, remove their declarations. :)
- Suggestions
- Defined/updated (count updates) but not accessed
- final definitions of null are redundant
- Dict/Set never queried
- Safe delete :)
- Detecting usages should be straightforward.
- Should probably be in a
List<ParserRuleContext> usages... - Zero usages: Suggest removing
- One usage: Suggest making into a local variable
- Only suggest this if variable is referenced in a child scope
- Should probably be in a
- Detect non-existent member references - should also be easy :)
- Tree-shake
- This means build a new file, only including what we used
- Not just removing dead code
- Should be relatively easy for Fray following dead code removal :)
- This means build a new file, only including what we used
- Transform libraries into static objects
- Use an
Extensible- Perhaps include a variant that sets everything
final?
- Perhaps include a variant that sets everything
- Use an
- Minify
- Rename all identifiers to the shortest available variant
- Transpile
- Use a visitor
foo.fray
class Foo {
let bar;
constructor(bar) {
this.bar = bar;
}
fn greet() => 'Hello, %{this.bar}!';
}
fn main() => new Foo('world').greet();
foo.js (ES5)
(function() {
function Foo(bar) {
this.bar = bar;
}
Foo.prototype.greet = function() {
return 'Hello, ' + this.bar + '!';
}
function main() {
new Foo('world').greet();
}
return main([]);
})();foo.js (ES6)
class Foo {
constructor(bar) {
this.bar = bar;
}
greet() {
return `Hello, ${bar}!`;
}
}
function main() {
new Foo('world').greet();
}
main([]);ES6 compilation would be nice, but wouldn't work in the browser out-of-the-box.