1 unstable release
Uses old Rust 2015
0.1.0 | Sep 8, 2017 |
---|
#44 in #transpiler
93KB
2.5K
SLoC
dyon_to_rust
Dyon to Rust transpiler
For more information, check the documentation.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT) at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions.
lib.rs
:
Dyon to Rust transpiler
For more information about Dyon, visit http://www.piston.rs/dyon-tutorial/
Notice: This transpiler is in early development and will contain bugs and missing features!
Motivation
Dyon has no garbage collector, but uses a lifetime checker. Like Rust, this design choice has the potential to improve runtime performance. Unlike Rust, Dyon has no borrowing semantics, but uses copy-on-write. Dyon also has a mutability checker which makes translating into Rust easier.
Dyon is designed for scripting ergonomics and has a syntax and object model
similar to Javascript, go
coroutines (like Go) and optional type checking,
and error handling with ?
syntax (like Rust).
In addition Dyon has a lot of features that for logic (mathematical loops), problem solving (proof composition trackign using secrets), fast generation of text and efficient memory usage (link structure), 4D vectors and html hex colors, closures and current objects (something better than globals).
There is a strong motivation to translate Dyon code into Rust, because a lot of code might be prototyped in Dyon during a project. In later stages when the code is tested, performance starts to matter more. Instead of rewriting in Rust for performance, a transpiler makes it easier to automate some parts of this process.
Goals
Assumingly, the Dyon-to-Rust transpiler will never work perfectly. Therefore, the focus will be on a useful subset of Dyon.
- In the short term, developers will focus on making translation of snippets work
- In the medium term, developers will focus on high performance of snippets code
- In the long term, developers will try to support as many language features as possible, and integrate the transpiler runtime with the Dyon standard library
- In very long term, you might be able to transpile a whole module created by a loader script and expect it to work without problems
For example, the transpiler might make assumptions about types in your code, in a way that generates efficient code, but might not pass the Rust compiler. In general, if the transpiler "can not prove it's wrong then it will do it". With other words, it will be optimistic and hope it turns out OK in the end. It is not as dangerous as it sounds, because the Rust compiler is very strict. These assumptions are not meant to allow unsafe code, but only the transpiler's choice of Rust types.
By this assumption, the transpiler will become useful at earlier stages, and exploit the similarity between Dyon and Rust to offload some of the work of type checking to the Rust compiler. It will also be easier for people to contribute since the code is mostly translating directly from Dyon AST (Abstract Syntax Tree).
Design
This library serves two roles:
- As a transpiler
- Runtime environment for transpiled code
A runtime is required because:
- Some features in Dyon are different enough that the transpiled code needs helper methods to look up the right functions.
- Some features require interaction with the Dyon library.
Working on the transpiler
The "source" folder contains a pair of ".dyon" and ".rs" files with same name. Files ending with ".dyon" contains the original Dyon source, and files ending with ".rs" contains the translated code in Rust.
The source files are checked when typing cargo test
in the Terminal window.
An error will be reported if there are any character mismatch.
Therefore, when making changes to the transpiler,
you have to go through all failed cases and check that the code turns out right.
This workflow is very strict, but it help the confidence that some changes will not affect translation of existing code too much.
There are two special files in the "source" folder:
- "test.dyon" - used to write some test code.
- "test.rs" - generated Rust code
The "tests::test" unit test overwrites "test.rs" by default. You can change this behavior with a flag in the unit test code.
To compile, type rustc source/test.rs -L target/debug/deps
in the Terminal window.
To run, type ./test
.
Behind the scenes
The transpiler is really just a huge function generating Rust code (single file) from a Dyon module.
The Dyon mode contains the AST (Abstract Syntax Tree) that is used when executing Dyon. It contains all information required to run Dyon code, except for functions. Functions are stored in the module and have different kinds depending on whether they are intrinsics (Dyon standard library), loaded functions (Dyon script) or external functions (Rust).
The AST contains static ids resolved upfront that tells where variables live on the stack.
This means that the transpiler only needs to keep track of the length of the stack.
In the code, this is passed as the stack_len
parameter.
The correct usage of stack length tracking is determined from Dyon's runtime behavior. Therefore, the transpiler is mirroring the behavior of how Dyon executes. Variables with overlapping indices are kept in separate scopes using Rust blocks.
Function calls uses relative indices because Dyon modules can be composed dynamically. This means that extra testing is required when a module depends on other modules.
Functionality
Currently, due to very early stage, there is no map of supported language features.
At the moment, the generated Rust code only uses indices.
For example, you will not see the variable names:
let mut _0 = 2.0;
foo(&mut _0);
In the future you might be able to tell the code generator
to use variable names from Dyon through a CodeSettings
struct.
Dependencies
~1.5MB
~33K SLoC