Merge pull request #14 from mist-go/docs-allman-fixes
Fix Allman brace style and field terminator consistency across docs
This commit is contained in:
@@ -7,8 +7,9 @@ icon: Shapes
|
|||||||
Mist introduces `class` as syntactic sugar for a Rust struct with a virtual method table (vtable).
|
Mist introduces `class` as syntactic sugar for a Rust struct with a virtual method table (vtable).
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
pub class Animal {
|
pub class Animal
|
||||||
str& name,
|
{
|
||||||
|
str& name;
|
||||||
|
|
||||||
pub constructor(str& name)
|
pub constructor(str& name)
|
||||||
{
|
{
|
||||||
@@ -25,19 +26,21 @@ pub class Animal {
|
|||||||
Class fields can have default initializers:
|
Class fields can have default initializers:
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
class Player {
|
class Player
|
||||||
i32 health = 100,
|
{
|
||||||
str& name,
|
i32 health = 100;
|
||||||
|
str& name;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Inheritance
|
### Inheritance
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
class Dog : Animal {
|
class Dog : Animal
|
||||||
|
{
|
||||||
pub constructor(str& name)
|
pub constructor(str& name)
|
||||||
{
|
{
|
||||||
super(name);
|
super = Super::new(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void speak(&self) override
|
void speak(&self) override
|
||||||
@@ -56,6 +59,25 @@ void speak(&self) override(Animal)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Implementations
|
||||||
|
|
||||||
|
You can implement directly on the class body:
|
||||||
|
|
||||||
|
```mist
|
||||||
|
class Circle
|
||||||
|
{
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
impl std::fmt::Display
|
||||||
|
{
|
||||||
|
Result<(), std::fmt::Error> fmt(&self, Formatter<'_> f)
|
||||||
|
{
|
||||||
|
write!(f, "●")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Under the Hood
|
### Under the Hood
|
||||||
|
|
||||||
A class `Dog : Animal` generates:
|
A class `Dog : Animal` generates:
|
||||||
@@ -67,3 +89,102 @@ A class `Dog : Animal` generates:
|
|||||||
5. A `new()` constructor that initializes via `MaybeUninit` and calls the user's `constructor(&mut self)`
|
5. A `new()` constructor that initializes via `MaybeUninit` and calls the user's `constructor(&mut self)`
|
||||||
|
|
||||||
The vtable is unified: parent entries are copied, overridden entries replace parent slots, and new methods are appended.
|
The vtable is unified: parent entries are copied, overridden entries replace parent slots, and new methods are appended.
|
||||||
|
|
||||||
|
### Safety
|
||||||
|
|
||||||
|
Classes use `MaybeUninit::zeroed().assume_init()` inside the generated `new()` function — an inherently unsafe operation. This raises a natural question: **Are class constructors unsafe?**
|
||||||
|
|
||||||
|
The answer is **no**. The compiler statically verifies that every field is initialized before the constructor returns, eliminating the undefined behavior that raw `MaybeUninit` would normally carry.
|
||||||
|
|
||||||
|
#### Static Field Initialization Verification
|
||||||
|
|
||||||
|
When a class has a constructor, the semantic checker (`check_class_semantics`) collects every declared field and walks the constructor body to prove each one is written to:
|
||||||
|
|
||||||
|
1. **Direct assignment tracking** — Expressions like `self.field = value` are recognized as mutations of `field`. The analyzer checks for `=` and `->` operators whose left-hand side is a `self.field` path.
|
||||||
|
|
||||||
|
2. **`&mut self.field` tracking** — Taking a mutable reference to a field (`&mut self.field`) also counts as initializing it, since the reference can only be taken if the field is being set up.
|
||||||
|
|
||||||
|
3. **Transitive method calls** — If the constructor calls `self.helper()`, the analyzer follows into `helper`'s body and tracks which fields *it* initializes. This transitively propagates through nested calls:
|
||||||
|
|
||||||
|
```mist
|
||||||
|
class Player
|
||||||
|
{
|
||||||
|
str& name;
|
||||||
|
i32 health;
|
||||||
|
|
||||||
|
pub constructor(str& name)
|
||||||
|
{
|
||||||
|
self.name = name;
|
||||||
|
self.setup_health();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_health(&mut self)
|
||||||
|
{
|
||||||
|
self.health = 100; // Counts toward constructor's verification
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Branch intersection** — For `if`/`else`, `match`, and loops, fields must be initialized in **all** branches. If one branch initializes `x` but another does not, `x` is considered uninitialized. This ensures soundness regardless of the runtime path:
|
||||||
|
|
||||||
|
```mist
|
||||||
|
pub constructor(bool flag)
|
||||||
|
{
|
||||||
|
if flag {
|
||||||
|
self.health = 100;
|
||||||
|
} else {
|
||||||
|
self.health = 0;
|
||||||
|
}
|
||||||
|
// Both branches init health ✓
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Super initialization** — When a class inherits, the `_super` field is added to the required-field list. Any assignment to `super` counts:
|
||||||
|
|
||||||
|
```mist
|
||||||
|
pub constructor(str& name)
|
||||||
|
{
|
||||||
|
super = Super::new(name);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If any field is uninitialized after the full analysis, a compile-time error is reported with the field's exact source location:
|
||||||
|
|
||||||
|
```
|
||||||
|
class field `Player.health` is uninitialized
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Override Validation at Compile Time
|
||||||
|
|
||||||
|
When a method uses the `override` keyword, the codegen emits a hidden test function that verifies the Deref chain at compile time:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[allow(invalid_value)]
|
||||||
|
fn __test_vt() {
|
||||||
|
let this: &Self = &unsafe { std::mem::MaybeUninit::<Self>::zeroed().assume_init() };
|
||||||
|
let _: &Target = this; // Forces compiler to check Deref<Target = Target>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This ensures `&Self` can always deref into the base class type. If the inheritance hierarchy is invalid, the Rust compiler rejects it.
|
||||||
|
|
||||||
|
#### VTable Safety
|
||||||
|
|
||||||
|
The `_vptr` (vtable pointer) is set *twice* during construction:
|
||||||
|
|
||||||
|
1. **Before** the constructor body runs — enabling virtual dispatch inside the constructor itself
|
||||||
|
2. **After** the constructor body — in case a base-class constructor ran and overwrote the pointer
|
||||||
|
|
||||||
|
This ensures that virtual method calls work correctly even during object construction, without exposing uninitialized memory through the vtable.
|
||||||
|
|
||||||
|
#### Summary
|
||||||
|
|
||||||
|
| Risk | Mitigation |
|
||||||
|
|------|-----------|
|
||||||
|
| Uninitialized fields via `MaybeUninit` | Static field-initialization verification rejects incomplete constructors |
|
||||||
|
| UB from reading uninitialized fields | Intersection analysis ensures all branches init the same fields |
|
||||||
|
| Invalid override signatures | Compile-time Deref test validates the inheritance chain |
|
||||||
|
| Vtable corruption during construction | `_vptr` is set before and after the constructor body |
|
||||||
|
| Unsafe code in generated constructors | `#[allow(invalid_value)]` is scoped to the generated `new()` only |
|
||||||
|
|
||||||
|
The `MaybeUninit` pattern is an implementation detail of the generated code — the Mist compiler proves soundness at the language level, so the user's constructor body is safe Mist code with no manual `unsafe` annotations required.
|
||||||
|
|||||||
@@ -7,17 +7,20 @@ icon: ArrowLeftRight
|
|||||||
### If/Else
|
### If/Else
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
if condition {
|
if condition
|
||||||
|
{
|
||||||
// body
|
// body
|
||||||
} else if other_condition {
|
}
|
||||||
|
else if other_condition
|
||||||
|
{
|
||||||
// body
|
// body
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// body
|
// body
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Conditions must be parenthesized: `if (expr) { }` or `if expr_no_struct { }` (struct literals require parentheses).
|
|
||||||
|
|
||||||
Used as an expression:
|
Used as an expression:
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
@@ -27,7 +30,8 @@ let x = if true { 1 } else { 2 };
|
|||||||
### While
|
### While
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
while condition {
|
while condition
|
||||||
|
{
|
||||||
// body
|
// body
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -35,11 +39,13 @@ while condition {
|
|||||||
### For
|
### For
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
for pattern in iterator {
|
for pattern in iterator
|
||||||
|
{
|
||||||
// body
|
// body
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0 .. 10 {
|
for i in 0 .. 10
|
||||||
|
{
|
||||||
// body
|
// body
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -47,7 +53,8 @@ for i in 0 .. 10 {
|
|||||||
### C-Style For
|
### C-Style For
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
for (let mut i = 0; i < 10; i++) {
|
for (let mut i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
// body
|
// body
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -55,7 +62,8 @@ for (let mut i = 0; i < 10; i++) {
|
|||||||
### Loop
|
### Loop
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
loop {
|
loop
|
||||||
|
{
|
||||||
// infinite loop
|
// infinite loop
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -42,13 +42,9 @@ unsafe i32 dangerous()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Function syntax: `[pub] [void | <type>] <name>[<generics>](<params>) [override] { <body> }`
|
|
||||||
|
|
||||||
Functions use **Allman brace style** (opening brace on the next line).
|
|
||||||
|
|
||||||
### Self Parameter
|
### Self Parameter
|
||||||
|
|
||||||
Methods can take `self`, `mut self`, `&self`, `&mut self` additionally with lifetimes:
|
Methods can take `self`, `mut self`, `&self`, `&mut self`, and `&'a self` / `&'a mut self` with lifetimes:
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
pub void set_value(&mut self, i32 v)
|
pub void set_value(&mut self, i32 v)
|
||||||
|
|||||||
@@ -12,15 +12,17 @@ T id<T>(T x)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generic struct
|
// Generic struct
|
||||||
struct Pair<A, B> {
|
struct Pair<A, B>
|
||||||
|
{
|
||||||
A first,
|
A first,
|
||||||
B second,
|
B second,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic enum
|
// Generic enum
|
||||||
enum Result<T, E> {
|
enum Result<T, E>
|
||||||
Ok(T),
|
{
|
||||||
Err(E),
|
Ok(T);
|
||||||
|
Err(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic with trait bounds
|
// Generic with trait bounds
|
||||||
|
|||||||
@@ -25,11 +25,11 @@ match value {
|
|||||||
// Named tuple patterns (newtype)
|
// Named tuple patterns (newtype)
|
||||||
let MyType(value) = my_var;
|
let MyType(value) = my_var;
|
||||||
|
|
||||||
// Wildcard / etc
|
// Wildcard / rest
|
||||||
let _ = get_side_effect();
|
let _ = get_side_effect();
|
||||||
match x {
|
match x {
|
||||||
1 => ...,
|
1 => expr,
|
||||||
.. => ..., // rest / etc
|
.. => expr, // rest / etc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutable binding in pattern
|
// Mutable binding in pattern
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ icon: Box
|
|||||||
### Structs
|
### Structs
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
pub struct Point {
|
pub struct Point
|
||||||
|
{
|
||||||
i32 x,
|
i32 x,
|
||||||
i32 y,
|
i32 y,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Generic<T> {
|
pub struct Generic<T>
|
||||||
|
{
|
||||||
T value,
|
T value,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -20,7 +22,8 @@ pub struct Generic<T> {
|
|||||||
Fields can be public or private:
|
Fields can be public or private:
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
struct User {
|
struct User
|
||||||
|
{
|
||||||
pub str& name,
|
pub str& name,
|
||||||
i32 age, // private
|
i32 age, // private
|
||||||
}
|
}
|
||||||
@@ -29,12 +32,14 @@ struct User {
|
|||||||
### Enums
|
### Enums
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
pub enum Option<T> {
|
pub enum Option<T>
|
||||||
|
{
|
||||||
Some(T),
|
Some(T),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Message {
|
pub enum Message
|
||||||
|
{
|
||||||
Quit,
|
Quit,
|
||||||
Move(i32, i32),
|
Move(i32, i32),
|
||||||
Write { str& content, i32 length },
|
Write { str& content, i32 length },
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ icon: Puzzle
|
|||||||
### Traits
|
### Traits
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
pub trait Drawable {
|
pub trait Drawable
|
||||||
|
{
|
||||||
void draw(&self);
|
void draw(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Comparable<T> : Eq {
|
pub trait Comparable<T> : Eq
|
||||||
|
{
|
||||||
i32 cmp(&self, T other);
|
i32 cmp(&self, T other);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -19,7 +21,8 @@ pub trait Comparable<T> : Eq {
|
|||||||
Trait requirements are specified after `:`:
|
Trait requirements are specified after `:`:
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
trait MyTrait : SuperTrait + OtherTrait {
|
trait MyTrait : SuperTrait + OtherTrait
|
||||||
|
{
|
||||||
void required_method(&self);
|
void required_method(&self);
|
||||||
void another(&self);
|
void another(&self);
|
||||||
}
|
}
|
||||||
@@ -28,15 +31,18 @@ trait MyTrait : SuperTrait + OtherTrait {
|
|||||||
### Impl Blocks
|
### Impl Blocks
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
impl MyType {
|
impl MyType
|
||||||
|
{
|
||||||
void method(&self) { }
|
void method(&self) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Trait for MyType {
|
impl Trait for MyType
|
||||||
|
{
|
||||||
void method(&self) { }
|
void method(&self) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> GenericTrait<T> for MyType {
|
impl<T> GenericTrait<T> for MyType
|
||||||
|
{
|
||||||
void method(&self, T value) { }
|
void method(&self, T value) { }
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ The semantic checker (`semantics.rs`) performs class field initialization analys
|
|||||||
The primary semantic check ensures all class fields are initialized in the constructor:
|
The primary semantic check ensures all class fields are initialized in the constructor:
|
||||||
|
|
||||||
```mist
|
```mist
|
||||||
class Player {
|
class Player
|
||||||
i32 health,
|
{
|
||||||
str& name,
|
i32 health;
|
||||||
|
str& name;
|
||||||
|
|
||||||
pub constructor(str& name)
|
pub constructor(str& name)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,8 +21,9 @@ The transpiler (`transpiler.mist` in `mist_api`) orchestrates the full pipeline.
|
|||||||
|
|
||||||
The `Module` struct represents the file-to-module mapping:
|
The `Module` struct represents the file-to-module mapping:
|
||||||
|
|
||||||
```rust
|
```mist
|
||||||
pub class Module {
|
pub class Module
|
||||||
|
{
|
||||||
pub String name;
|
pub String name;
|
||||||
pub PathBuf path;
|
pub PathBuf path;
|
||||||
pub Vec<Module> children;
|
pub Vec<Module> children;
|
||||||
|
|||||||
Reference in New Issue
Block a user