Representing the ActionScript 3 semantics in Rust #3169
Replies: 2 comments
-
|
There's a TTF parser for Rust already, so less problems, but glyph mathematics might not be easy for me Summing up the tough parts might be handling all of MXML together (components, style sheets, data bindings, and the exact same processing of MXML). There are additional things I'm not mentioning about Flex because I'm not familiar, like external AJAX resources. What I think is that MXML translates to ActionScript 3 syntactic nodes and later are applied Flex specific verifications over these nodes. |
Beta Was this translation helpful? Give feedback.
-
|
(I've added the |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
A verifier, or symbol solver, which reports verify errors and warnings, attaches meaning (symbols) to syntactic nodes, and builds control flow graphs for activations, consists of a semantic module defining the available symbols.
In usual compiler infrastructures, the miscellaneous symbols (packages, namespaces, types, slots, and value variations) are unified into a single type that delegates high-level accesses to specific symbol variant structures.
That single type, usually called Symbol, may be represented as simply a class or interface in Java, .NET, or ActionScript 3.
In Rust, there's no equivalent class to these high-level languages, so you might have thought of depending on the alpha-phase
gccrate from crates.io, which provides Rust with a limited form of garbage collection, so that you could represent theSymboltype. But actually, withgcyou won't be able to use theas3_parsercrate since it uses reference counting (Rc) within nodes instead.The Arena
The best solution I found is to use an arena container that uses reference counting and define
Symbolas a structure consisting of aWeakreference pointing back to memory in that arena.This guide allows for circular references without memory leak, since
Symbolholds a weak reference rather than a strong reference, and upgrades it to a strong reference upon access methods, such asis_variable_slot(),prototype(), et cetera.An arena is a container consisting of a possibly large collection of reference counted objects that get deallocated upon the arena's deallocation, that is, usually when a compiler terminates.
Here is how you would define
Arenain Rust:You can then allocate multiple resources, receiving a weak reference that is always set as long as you hold the arena somewhere.
You would usually use that arena in a symbol factory.
The Symbol type
The
Symboltype can be defined as a tuple structure consisting of solely a weak reference to memory in your arena.You may make the tuple's
Weakelement public by insertingpuborpub(crate)before it (visible within the entire crate).Deriving the
Clonetrait forSymbolwill make it such that writingsymbol.clone()clones the symbol reference (not its actual contents).You can also implement equality comparison between two
Symbolreferences, as well as hashing for use in containers such asHashMap:In the
Symbolstructure, you can defineSymbol1as an enumeration describing the various possibilities of what is the actual symbol:You can now define methods like
is_variable_slot()at theSymbolstructure to facilitate checking whether a symbol is a variable slot:The only thing you saw verbose so far is the fact that you have to usually write
self.0.upgrade().unwrap().as_ref()within all yourSymbolmethods. If you find that verbose, you may define a declarative macro:You can then simplify the above
is_variable_slot()definition:For better documenting and using the miscellaneous symbols, you may define structures for each, delegating accesses to
Symbol:Extra tips:
Full example: Rust playground
Tree semantics
In a verifier, you will want to attach symbol references to nodes. Do so using the
TreeSemanticsstructure:It is essentially just a way to attach meaning to nodes.
Compiler Host
It would make sense to hold the arena (the factory) and several possibly deferred references to the global objects such as
RegExp, inside a container that may be calledCompilerHost. When you try to lookup a global object and you find out that it is still undefined, you defer verification by returning anUnresolvedsymbol.Shared Containers
The
VecandHashMaptypes as they are may not be useful at all within theSymbolinternal structures, so you may use these two helper types:SharedArrayandSharedMap.Shared containers
Put this at the top of your crate's main file:
#![feature(decl_macro)]SharedArrayandshared_array! [ ... ]macroSharedMapandshared_map! { ... }macroPattern Matching in Rust
The
refand borrow terms are way mixed in Rust, andmutsometimes is related to&mut(muttable borrows). Borrow types (&T) are transitively immutable reference types, while mutable borrow types (&mut T) are transitively mutable reference types.Specially, within pattern matching in Rust you may use a
refprefix sometimes to destructure a value by borrowing it rather than copying it (escaping out of compile-time errors).Throwing errors
Examples:
Borrows and Lifetimes
Borrow types (
&Tand&mut T) consist of a lifetime, although it's inferred by default. The lifetime is expressed by the'idtoken (note the apostrophe), as in&'a T. It's usually named as a lowercase letter, but any lifetime name is available in Rust, such as in&'long_name_lifetime T. The reserved'staticlifetime means the entire program's lifetime.Lifetimes may be explicitly declared in Rust types and functions, as in:
It's often not needed as it's done implicitly for functions.
Owned or borrowed
There are a range of types that are owned and others that are borrowed. Examples:
&stris a slice of an existing stringStringis a string that you "own", which is always heap-allocated&Stringis similiar to&str, but not a slice, but a borrow of aStringTraits
Traits (what you know as "interfaces") are non opaque types in Rust, which means you can't use them like structures at all. Trait objects is where you run type erasure in Rust, which explicitly requires the
dynkeyword.&dyn YourTraitBox<dyn YourTrait>Rc<dyn YourTrait>Conclusion
This is very simplified and I've just shown mostly empty structures, but this may give some pointers as how you can use Rust with
as3_parserto build a compiler.As things are moving ahead with ActionScript 3, I'm feeling afraid of working in a verifier and being backwards in terms of semantics. For example, Apache Royale recently introduced basic type inference for function signatures; I've not tested it, but if it just infers for the result type, then it might not be that much trouble.
It might also be difficult to handle embedding fonts like in the Flex compiler! I'm not really sure how would be the procedure to convert a TTF file to font glyphs in a SWF. There might be many things to take into consideration when handling the
Embedmeta-data.Beta Was this translation helpful? Give feedback.
All reactions