Merge pull request #25 from mist-go/lifetimes-and-proper-tests

Lifetimes and proper tests
This commit is contained in:
2026-05-10 04:09:05 +02:00
committed by GitHub
18 changed files with 414 additions and 568 deletions
+2 -2
View File
@@ -26,5 +26,5 @@ target
/target /target
/test/build /mist-test/build
/test/output.json /mist-test/output.json
+7
View File
@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "mist-test"
version = "0.1.0"
+10
View File
@@ -0,0 +1,10 @@
[package]
name = "mist-test"
version = "0.1.0"
edition = "2024"
[[bin]]
name = "main"
path = "build/main.rs"
[dependencies]
+95
View File
@@ -0,0 +1,95 @@
use <super::task>;
use <super::logger>;
use <super::event>;
public class Application {
String name;
Vec<task::Task> tasks;
Vec<String> plugins;
logger::Logger logger;
bool running;
i32 ticks;
public constructor(str* name) {
self.name = name.to_string();
self.tasks = new Vec();
self.plugins = new Vec();
self.logger = new logger::Logger("app");
self.running = false;
self.ticks = 0;
}
public void boot(self mut*) {
self.logger.info("booting application");
self.running = true;
self.emit(event::Event::Startup);
}
public void run(self mut*) {
while(self.running) {
self.tick();
if(self.ticks >= 5) {
self.shutdown();
}
}
}
void tick(self mut*) {
self.logger.info("tick");
self.ticks = self.ticks + 1;
var task = task::create_task("background-job");
self.tasks.push(task);
println!("tasks: {}", self.tasks.len());
}
public void shutdown(self mut*) {
self.emit(event::Event::Shutdown);
self.logger.warning("shutdown");
self.running = false;
}
public void register_plugin(self mut*, String name) {
self.plugins.push(name.clone());
self.emit(event::Event::PluginLoaded(name));
}
void emit(self*, event::Event event) {
match(event) {
event::Event::Startup => {
self.logger.info("startup event");
}
event::Event::Shutdown => {
self.logger.info("shutdown event");
}
event::Event::PluginLoaded(name) => {
println!("plugin loaded: {}", name);
}
event::Event::TaskExecuted(name) => {
println!("task executed: {}", name);
}
event::Event::Error(message) => {
self.logger.error(&message);
}
}
}
}
+7
View File
@@ -0,0 +1,7 @@
public enum Event {
Startup,
Shutdown,
TaskExecuted(String),
PluginLoaded(String),
Error(String),
}
+41
View File
@@ -0,0 +1,41 @@
public enum LogLevel {
Info,
Warning,
Error,
}
public class Logger {
String prefix;
public constructor(str* prefix) {
self.prefix = prefix.to_string();
}
public void info(self*, str* message) {
self.log(LogLevel::Info, message);
}
public void warning(self*, str* message) {
self.log(LogLevel::Warning, message);
}
public void error(self*, str* message) {
self.log(LogLevel::Error, message);
}
void log(self*, LogLevel level, str* message) {
match(level) {
LogLevel::Info => {
println!("[INFO] {} {}", self.prefix, message);
}
LogLevel::Warning => {
println!("[WARN] {} {}", self.prefix, message);
}
LogLevel::Error => {
println!("[ERROR] {} {}", self.prefix, message);
}
}
}
}
+15
View File
@@ -0,0 +1,15 @@
mod app;
mod task;
mod plugin;
mod logger;
mod event;
void main() {
var mut app_instance = new app::Application("mist-app");
// greeting::register(&mut app_instance);
// statistics::register(&mut app_instance);
app_instance.boot();
app_instance.run();
}
+16
View File
@@ -0,0 +1,16 @@
public struct PluginInfo {
public String name,
public String version,
}
public class PluginRegistry<T> {
T plugins;
public constructor(T plugins) {
self.plugins = plugins;
}
public T plugins(self) {
return self.plugins;
}
}
+20
View File
@@ -0,0 +1,20 @@
public enum TaskState {
Pending,
Running,
Finished,
Failed,
}
public struct Task {
public String name,
public TaskState state,
public i32 executions,
}
public Task create_task(str* name) {
return Task {
name: name.to_string(),
state: TaskState::Pending,
executions: 0,
};
}
+10 -1
View File
@@ -16,6 +16,8 @@ pub struct Block(pub Vec<Statement>);
pub enum TypePostfix { pub enum TypePostfix {
Ref, Ref,
RefMut, RefMut,
RefLifetime(Identifier),
RefMutLifetime(Identifier),
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
@@ -41,6 +43,7 @@ pub enum TypeExprKind {
Path(Path), Path(Path),
PathParams(Path, Vec<TypeExpr>), PathParams(Path, Vec<TypeExpr>),
Tuple(Vec<TypeExpr>), Tuple(Vec<TypeExpr>),
Lifetime(Identifier),
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
@@ -98,7 +101,13 @@ pub enum TopLevelKind {
} }
#[derive(Debug, Clone, Serialize, Default)] #[derive(Debug, Clone, Serialize, Default)]
pub struct Generics(pub Vec<(Identifier, Vec<Path>)>); pub struct Generics(pub Vec<Generic>);
#[derive(Debug, Clone, Serialize)]
pub enum Generic {
Lifetime(Identifier),
Type(Identifier, Vec<TypeExpr>),
}
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub enum Pattern { pub enum Pattern {
+14 -5
View File
@@ -55,7 +55,7 @@ var = { "var" }
// ====================================================== // ======================================================
// GENERICS // GENERICS
// ====================================================== // ======================================================
generic = { identifier ~ (":" ~ static_path ~ ("+" ~ static_path)*)? } generic = { lifetime | (identifier ~ (":" ~ type_expr_param ~ ("+" ~ type_expr_param)*)?) }
generics = { "<" ~ (generic ~ ("," ~ generic)*)? ~ ">" } generics = { "<" ~ (generic ~ ("," ~ generic)*)? ~ ">" }
// ====================================================== // ======================================================
@@ -67,17 +67,26 @@ tuple_type = {
} }
path_type = { path_type = {
static_path ~ ("<" ~ (type_expr ~ ("," ~ type_expr)*)? ~ ">")? static_path ~ ("<" ~ (type_expr_param ~ ("," ~ type_expr_param)*)? ~ ">")?
} }
ref_type = { ref_type = {
mutable? ~ "*" mutable? ~ lifetime? ~ "*"
} }
type_expr = { type_expr = {
(path_type | tuple_type) ~ ref_type* (path_type | tuple_type) ~ ref_type*
} }
lifetime = {
"'" ~ identifier
}
type_expr_param = {
type_expr
| lifetime
}
// ====================================================== // ======================================================
// LITERALS // LITERALS
// ====================================================== // ======================================================
@@ -224,7 +233,7 @@ self_param = {
} }
method = { method = {
export? ~ type_expr ~ identifier ~ generics? ~ "(" ~ self_param? ~ param_list? ~ ")" ~ block export? ~ type_expr ~ identifier ~ generics? ~ "(" ~ self_param? ~ ("," ~ param_list?)? ~ ")" ~ block
} }
class_decl = { class_decl = {
@@ -263,7 +272,6 @@ statement_list = {
statement = _{ statement = _{
expr_stmt expr_stmt
| match_stmt | match_stmt
| var_decl_statement
| assign_statement | assign_statement
| if_stmt | if_stmt
| while_stmt | while_stmt
@@ -273,6 +281,7 @@ statement = _{
| break_stmt | break_stmt
| continue_stmt | continue_stmt
| block | block
| var_decl_statement
} }
// ------------------------------------------------------ // ------------------------------------------------------
+25 -4
View File
@@ -36,6 +36,11 @@ impl From<pest::iterators::Pair<'_, Rule>> for TypeExpr {
TypeExprKind::from(inner.next().unwrap()), TypeExprKind::from(inner.next().unwrap()),
inner.map(TypePostfix::from).collect(), inner.map(TypePostfix::from).collect(),
), ),
Rule::type_expr_param => TypeExpr::from(inner.next().unwrap()),
Rule::lifetime => TypeExpr(
TypeExprKind::Lifetime(Identifier::from(inner.next().unwrap())),
Vec::new(),
),
_ => unimplemented!("{rule:#?}"), _ => unimplemented!("{rule:#?}"),
} }
} }
@@ -44,16 +49,28 @@ impl From<pest::iterators::Pair<'_, Rule>> for TypeExpr {
impl From<pest::iterators::Pair<'_, Rule>> for TypePostfix { impl From<pest::iterators::Pair<'_, Rule>> for TypePostfix {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule(); let rule = pair.as_rule();
let inner = pair.into_inner(); let mut inner = pair.into_inner();
match rule { match rule {
Rule::ref_type => { Rule::ref_type => {
if inner.peek().is_some() { let mutable = listen_rule(&mut inner, Rule::mutable);
let lifetime = consume_rule(&mut inner, Rule::lifetime)
.map(|pair| Identifier::from(pair.into_inner().next().unwrap()));
if mutable {
if let Some(lifetime) = lifetime {
TypePostfix::RefMutLifetime(lifetime)
} else {
TypePostfix::RefMut TypePostfix::RefMut
}
} else {
if let Some(lifetime) = lifetime {
TypePostfix::RefLifetime(lifetime)
} else { } else {
TypePostfix::Ref TypePostfix::Ref
} }
} }
}
_ => unimplemented!("{rule:#?}"), _ => unimplemented!("{rule:#?}"),
} }
} }
@@ -238,10 +255,14 @@ impl From<pest::iterators::Pair<'_, Rule>> for Generics {
inner inner
.map(|pair| { .map(|pair| {
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
( if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) {
Generic::Lifetime(Identifier::from(pair.into_inner().next().unwrap()))
} else {
Generic::Type(
Identifier::from(inner.next().unwrap()), Identifier::from(inner.next().unwrap()),
inner.map(Path::from).collect(), inner.map(TypeExpr::from).collect(),
) )
}
}) })
.collect(), .collect(),
), ),
+40 -13
View File
@@ -1,7 +1,7 @@
use parser::ast::{ use parser::ast::{
Attribute, BinaryOp, Block, EnumItem, Expression, FunctionDecl, Generics, Identifier, Literal, Attribute, BinaryOp, Block, EnumItem, Expression, FunctionDecl, Generic, Generics, Identifier,
Path, Pattern, Postfix, Prefix, Statement, StatementBranch, TopLevel, TopLevelKind, TypeExpr, Literal, Path, Pattern, Postfix, Prefix, Statement, StatementBranch, TopLevel, TopLevelKind,
TypeExprKind, TypePostfix, VarAssignStmt, VarDecl, VarDeclStmt, Visibility, TypeExpr, TypeExprKind, TypePostfix, VarAssignStmt, VarDecl, VarDeclStmt, Visibility,
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -96,6 +96,7 @@ impl GetRust for TypeExprKind {
fn get_rust(&self) -> String { fn get_rust(&self) -> String {
match self { match self {
TypeExprKind::Path(path) => get_static_type_path(path), TypeExprKind::Path(path) => get_static_type_path(path),
TypeExprKind::Lifetime(name) => format!("'{}", name.get_rust()),
TypeExprKind::PathParams(path, params) => { TypeExprKind::PathParams(path, params) => {
format!( format!(
"{}<{}>", "{}<{}>",
@@ -382,7 +383,20 @@ impl ToRust for TopLevelKind {
cg.addln("}\n"); cg.addln("}\n");
// Constructor // Constructor
cg.addln(&format!("impl {} {{", name.get_rust())); cg.addln(&format!(
"impl{} {}{} {{",
generics.get_rust(),
name.get_rust(),
format!(
"<{}>",
generics
.0
.iter()
.map(|v| (false, v).get_rust())
.collect::<Vec<_>>()
.join(", ")
)
));
cg.indent += 1; cg.indent += 1;
let params_str = constructor let params_str = constructor
@@ -393,6 +407,7 @@ impl ToRust for TopLevelKind {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", "); .join(", ");
cg.add_indentedln("#[allow(invalid_value)]");
cg.add_indentedln(&format!( cg.add_indentedln(&format!(
"{}fn new{}({}) -> Self {{", "{}fn new{}({}) -> Self {{",
constructor.visibility.get_rust(), constructor.visibility.get_rust(),
@@ -633,6 +648,8 @@ impl GetRust for TypePostfix {
match self { match self {
TypePostfix::Ref => format!("&"), TypePostfix::Ref => format!("&"),
TypePostfix::RefMut => format!("&mut "), TypePostfix::RefMut => format!("&mut "),
TypePostfix::RefLifetime(lifetime) => format!("&'{} ", lifetime.get_rust()),
TypePostfix::RefMutLifetime(lifetime) => format!("&'{} mut ", lifetime.get_rust()),
} }
} }
} }
@@ -721,23 +738,33 @@ impl GetRust for Generics {
"<{}>", "<{}>",
self.0 self.0
.iter() .iter()
.map(|generic| generic.0.get_rust() .map(|v| (true, v).get_rust())
+ &(if generic.1.len() == 0 { .collect::<Vec<_>>()
.join(", ")
)
}
}
}
impl GetRust for (bool, &Generic) {
fn get_rust(&self) -> String {
match &self.1 {
Generic::Lifetime(name) => format!("'{}", name.get_rust()),
Generic::Type(name, requirements) => {
name.get_rust()
+ &(if !self.0 && requirements.len() == 0 {
String::new() String::new()
} else { } else {
format!( format!(
": {}", ": {}",
generic requirements
.1
.iter() .iter()
.map(Path::get_rust) .map(TypeExpr::get_rust)
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("+") .join("+")
) )
})) })
.collect::<Vec<_>>() }
.join(", ")
)
} }
} }
} }
+83 -29
View File
@@ -1,4 +1,9 @@
use std::{fs, path::PathBuf, process, time::Instant}; use std::{
fs,
path::{Path, PathBuf},
process,
time::Instant,
};
use serde::Deserialize; use serde::Deserialize;
@@ -21,20 +26,76 @@ pub fn build() {
// 2. load config // 2. load config
let config = load_config(&root); let config = load_config(&root);
let src = root.join(&config.src); let src_dir = root.join(&config.src);
for entry in fs::read_dir(src).unwrap() {
if let Ok(entry) = entry {
let entry_path = root.join(&entry.path());
let out_dir = root.join(&config.output); let out_dir = root.join(&config.output);
let file_name = entry.file_name();
let file_name = file_name.to_string_lossy();
// 3. read entry file build_dir(&root, &src_dir, &src_dir, &out_dir);
let source = match fs::read_to_string(&entry_path) {
let elapsed = start.elapsed();
println!("build finished in {:.2?}", elapsed);
}
fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) {
let entries = match fs::read_dir(current_dir) {
Ok(entries) => entries,
Err(e) => {
eprintln!(
"error: failed to read directory {}\n {}",
current_dir.display(),
e
);
process::exit(1);
}
};
for entry in entries {
let entry = match entry {
Ok(entry) => entry,
Err(e) => {
eprintln!("error: failed to read directory entry\n {}", e);
process::exit(1);
}
};
let path = entry.path();
// recurse into nested directories
if path.is_dir() {
build_dir(root, base_src, &path, out_dir);
continue;
}
// skip non-mist files
if path.extension().and_then(|e| e.to_str()) != Some("mist") {
continue;
}
let relative = path.strip_prefix(base_src).unwrap();
let output_path = out_dir.join(relative).with_extension("rs");
// create parent directories
if let Some(parent) = output_path.parent() {
if let Err(e) = fs::create_dir_all(parent) {
eprintln!(
"error: failed to create output directory {}\n {}",
parent.display(),
e
);
process::exit(1);
}
}
// read source
let source = match fs::read_to_string(&path) {
Ok(s) => s, Ok(s) => s,
Err(e) => { Err(e) => {
eprintln!("error: failed to read entry file\n {}", e); eprintln!("error: failed to read file {}\n {}", path.display(), e);
process::exit(1); process::exit(1);
} }
}; };
@@ -44,33 +105,27 @@ pub fn build() {
let ast = match parser_result { let ast = match parser_result {
Ok(ast) => ast, Ok(ast) => ast,
Err(e) => { Err(e) => {
eprintln!("error: parse failed\n{}", e); eprintln!("error: parse failed in {}\n{}", path.display(), e);
process::exit(1); process::exit(1);
} }
}; };
// semantic::walk_ast(semantic::scope::Scope::from_top(&root, &ast), &mut ast); // semantic::walk_ast(semantic::scope::Scope::from_top(root, &ast), &mut ast);
let mut gc = crate::codegen::RustCodegen::new(); let mut gc = crate::codegen::RustCodegen::new();
let output = gc.generate(&ast); let output = gc.generate(&ast);
if let Err(e) = fs::create_dir_all(&out_dir) { if let Err(e) = fs::write(&output_path, output) {
eprintln!("error: failed to create build dir\n {}", e); eprintln!(
process::exit(1); "error: failed to write output {}\n {}",
} output_path.display(),
e
);
let out_file = out_dir.join(file_name.replace(".mist", ".rs"));
if let Err(e) = fs::write(&out_file, output) {
eprintln!("error: failed to write output\n {}", e);
process::exit(1); process::exit(1);
} }
} }
}
let elapsed = start.elapsed();
println!("build finished in {:.2?}", elapsed);
} }
pub fn find_project_root() -> Option<PathBuf> { pub fn find_project_root() -> Option<PathBuf> {
@@ -87,9 +142,8 @@ pub fn find_project_root() -> Option<PathBuf> {
} }
} }
fn load_config(root: &std::path::Path) -> Config { fn load_config(root: &Path) -> Config {
let content = let content = fs::read_to_string(root.join("mist.json")).expect("failed to read mist.json");
std::fs::read_to_string(root.join("mist.json")).expect("failed to read mist.json");
serde_json::from_str(&content).expect("invalid mist.json format") serde_json::from_str(&content).expect("invalid mist.json format")
} }
-450
View File
@@ -1,450 +0,0 @@
{
"fmt": {
"package_name": "fmt",
"structs": {},
"functions": {
"append": {
"export": true,
"name": "Append",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"b": {
"export": true,
"var_type": "[]byte",
"name": "b"
}
},
"return_types": [
"[]byte"
]
},
"appendf": {
"export": true,
"name": "Appendf",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"b": {
"export": true,
"var_type": "[]byte",
"name": "b"
},
"format": {
"export": true,
"var_type": "string",
"name": "format"
}
},
"return_types": [
"[]byte"
]
},
"appendln": {
"export": true,
"name": "Appendln",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"b": {
"export": true,
"var_type": "[]byte",
"name": "b"
}
},
"return_types": [
"[]byte"
]
},
"errorf": {
"export": true,
"name": "Errorf",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"format": {
"export": true,
"var_type": "string",
"name": "format"
}
},
"return_types": [
"error"
]
},
"formatString": {
"export": true,
"name": "FormatString",
"params": {
"state": {
"export": true,
"var_type": "fmt.State",
"name": "state"
},
"verb": {
"export": true,
"var_type": "rune",
"name": "verb"
}
},
"return_types": [
"string"
]
},
"fprint": {
"export": true,
"name": "Fprint",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"w": {
"export": true,
"var_type": "io.Writer",
"name": "w"
}
},
"return_types": [
"int",
"error"
]
},
"fprintf": {
"export": true,
"name": "Fprintf",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"format": {
"export": true,
"var_type": "string",
"name": "format"
},
"w": {
"export": true,
"var_type": "io.Writer",
"name": "w"
}
},
"return_types": [
"int",
"error"
]
},
"fprintln": {
"export": true,
"name": "Fprintln",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"w": {
"export": true,
"var_type": "io.Writer",
"name": "w"
}
},
"return_types": [
"int",
"error"
]
},
"fscan": {
"export": true,
"name": "Fscan",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"r": {
"export": true,
"var_type": "io.Reader",
"name": "r"
}
},
"return_types": [
"int",
"error"
]
},
"fscanf": {
"export": true,
"name": "Fscanf",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"format": {
"export": true,
"var_type": "string",
"name": "format"
},
"r": {
"export": true,
"var_type": "io.Reader",
"name": "r"
}
},
"return_types": [
"int",
"error"
]
},
"fscanln": {
"export": true,
"name": "Fscanln",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"r": {
"export": true,
"var_type": "io.Reader",
"name": "r"
}
},
"return_types": [
"int",
"error"
]
},
"print": {
"export": true,
"name": "Print",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
}
},
"return_types": [
"int",
"error"
]
},
"printf": {
"export": true,
"name": "Printf",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"format": {
"export": true,
"var_type": "string",
"name": "format"
}
},
"return_types": [
"int",
"error"
]
},
"println": {
"export": true,
"name": "Println",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
}
},
"return_types": [
"int",
"error"
]
},
"scan": {
"export": true,
"name": "Scan",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
}
},
"return_types": [
"int",
"error"
]
},
"scanf": {
"export": true,
"name": "Scanf",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"format": {
"export": true,
"var_type": "string",
"name": "format"
}
},
"return_types": [
"int",
"error"
]
},
"scanln": {
"export": true,
"name": "Scanln",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
}
},
"return_types": [
"int",
"error"
]
},
"sprint": {
"export": true,
"name": "Sprint",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
}
},
"return_types": [
"string"
]
},
"sprintf": {
"export": true,
"name": "Sprintf",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"format": {
"export": true,
"var_type": "string",
"name": "format"
}
},
"return_types": [
"string"
]
},
"sprintln": {
"export": true,
"name": "Sprintln",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
}
},
"return_types": [
"string"
]
},
"sscan": {
"export": true,
"name": "Sscan",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"str": {
"export": true,
"var_type": "string",
"name": "str"
}
},
"return_types": [
"int",
"error"
]
},
"sscanf": {
"export": true,
"name": "Sscanf",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"format": {
"export": true,
"var_type": "string",
"name": "format"
},
"str": {
"export": true,
"var_type": "string",
"name": "str"
}
},
"return_types": [
"int",
"error"
]
},
"sscanln": {
"export": true,
"name": "Sscanln",
"params": {
"a": {
"export": true,
"var_type": "[]any",
"name": "a"
},
"str": {
"export": true,
"var_type": "string",
"name": "str"
}
},
"return_types": [
"int",
"error"
]
}
}
}
}
-18
View File
@@ -1,18 +0,0 @@
mod my_class;
use <my_class::MyClass>;
use <my_class::MyEnum>;
void main() {
var my_class = new MyClass("World");
my_class.greet();
match (MyEnum::Tuple(10, String::new())) {
MyEnum::Tuple(i, _) => {
println!("{i}");
}
MyEnum::Named => {
}
_ => {}
}
}
-17
View File
@@ -1,17 +0,0 @@
public class MyClass {
String message;
public constructor(str* name) {
self.message = format!("Hello {}!", name);
}
public void greet(self*) {
println!("{}", self.message);
}
}
public enum MyEnum {
Named,
Tuple(i32, String),
Struct { i32 x }
}