dscx language design concept
This commit is contained in:
@@ -0,0 +1,126 @@
|
|||||||
|
include maths::sqrt
|
||||||
|
|
||||||
|
trait AsUnit {
|
||||||
|
fn unit(self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Point2 {
|
||||||
|
let x: isize,
|
||||||
|
let y: isize,
|
||||||
|
|
||||||
|
fn len(self) -> isize {
|
||||||
|
sqrt(self.x * self.x + self.y * self.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// can inherit from a single class + many traits
|
||||||
|
class Point3: Point2 + AsUnit {
|
||||||
|
let z: isize,`
|
||||||
|
|
||||||
|
fn len(self) -> isize {
|
||||||
|
// implicit return of internal expressions
|
||||||
|
sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn AsUnit.unit(self) -> Self {
|
||||||
|
let len = self.len();
|
||||||
|
Self {
|
||||||
|
x: self.x / len,
|
||||||
|
y: self.y / len,
|
||||||
|
z: self.y / len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_matches(val: AsUnit) -> bool {
|
||||||
|
|
||||||
|
// can use kotlin-style "is" syntax to find sub-classes and implementors.
|
||||||
|
if match val {
|
||||||
|
is Point3 => true, // only Point3 as it has no subclasses.
|
||||||
|
// this also implicitly downcasts us to a Point3 so we can use methods specific to this class!
|
||||||
|
is Point2 => true, // returns true for Point2 and Point3 as it is a subclass
|
||||||
|
is AsUnit => true, // always true.
|
||||||
|
} { return true; }
|
||||||
|
|
||||||
|
unreachable() // this should probably crash the program
|
||||||
|
|
||||||
|
// we can match against any boolean expression. this lazily evaluates each arm one by one.
|
||||||
|
match {
|
||||||
|
do_some_processing() == 1 => println("success!") { style => style.colour = Colour::Red }
|
||||||
|
something_else() == 1 => println!("success") // we can omit the trailing lambda when it's
|
||||||
|
|
||||||
|
// alternative syntax for the same thing as above!
|
||||||
|
val is Point3 => { return true; }
|
||||||
|
val is AsUnit => { return true; }
|
||||||
|
false == true => { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// of course normal rust matches also apply
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* uilib.dscx */
|
||||||
|
|
||||||
|
class UiBuilder {
|
||||||
|
...
|
||||||
|
fn text_entry() -> Interaction
|
||||||
|
}
|
||||||
|
|
||||||
|
class Interaction {
|
||||||
|
fn clicked() -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* app.dscx */
|
||||||
|
|
||||||
|
pub enum Action {
|
||||||
|
SubmitForm(PasswordForm)
|
||||||
|
}
|
||||||
|
|
||||||
|
class PasswordForm {
|
||||||
|
let username: String,
|
||||||
|
let password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class UserInterface {
|
||||||
|
const MESSAGE: str = "Run Emulator";
|
||||||
|
let form: PasswordForm;
|
||||||
|
let state: EmulatorState;
|
||||||
|
|
||||||
|
fn new(state: EmulatorState) -> Self {
|
||||||
|
Self {
|
||||||
|
form: PasswordForm {
|
||||||
|
username: String::new(),
|
||||||
|
password: String::new()
|
||||||
|
},
|
||||||
|
state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ui(self, ui: UiBuilder) -> Action {
|
||||||
|
|
||||||
|
ui_lib::Form(self.form, ui, "login") { form, ui ->
|
||||||
|
ui.text_entry(form.username) { view ->
|
||||||
|
view.placeholder = "enter username";
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.text_entry(form.password); // also acceptable syntax. placeholder has a default value!
|
||||||
|
|
||||||
|
if ui.button("Submit").clicked() {
|
||||||
|
return Action::SubmitForm(form);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.vertical {
|
||||||
|
my_lib::StatusIndicator(self.state.status, ui);
|
||||||
|
|
||||||
|
if ui.button("Run Emulator").clicked() {
|
||||||
|
self.state.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user