Merge pull request #25 from mist-go/lifetimes-and-proper-tests
Lifetimes and proper tests
This commit is contained in:
+2
-2
@@ -26,5 +26,5 @@ target
|
|||||||
|
|
||||||
/target
|
/target
|
||||||
|
|
||||||
/test/build
|
/mist-test/build
|
||||||
/test/output.json
|
/mist-test/output.json
|
||||||
Generated
+7
@@ -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"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "mist-test"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "main"
|
||||||
|
path = "build/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
public enum Event {
|
||||||
|
Startup,
|
||||||
|
Shutdown,
|
||||||
|
TaskExecuted(String),
|
||||||
|
PluginLoaded(String),
|
||||||
|
Error(String),
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
@@ -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
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
|
|||||||
+29
-8
@@ -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,14 +49,26 @@ 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);
|
||||||
TypePostfix::RefMut
|
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
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
TypePostfix::Ref
|
if let Some(lifetime) = lifetime {
|
||||||
|
TypePostfix::RefLifetime(lifetime)
|
||||||
|
} else {
|
||||||
|
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) {
|
||||||
Identifier::from(inner.next().unwrap()),
|
Generic::Lifetime(Identifier::from(pair.into_inner().next().unwrap()))
|
||||||
inner.map(Path::from).collect(),
|
} else {
|
||||||
)
|
Generic::Type(
|
||||||
|
Identifier::from(inner.next().unwrap()),
|
||||||
|
inner.map(TypeExpr::from).collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
|
|||||||
+45
-18
@@ -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,20 +738,7 @@ 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 {
|
|
||||||
String::new()
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
": {}",
|
|
||||||
generic
|
|
||||||
.1
|
|
||||||
.iter()
|
|
||||||
.map(Path::get_rust)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("+")
|
|
||||||
)
|
|
||||||
}))
|
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", ")
|
.join(", ")
|
||||||
)
|
)
|
||||||
@@ -742,6 +746,29 @@ impl GetRust for Generics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
": {}",
|
||||||
|
requirements
|
||||||
|
.iter()
|
||||||
|
.map(TypeExpr::get_rust)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("+")
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_static_type_path(path: &Path) -> String {
|
pub fn get_static_type_path(path: &Path) -> String {
|
||||||
let rust_path = path.get_rust();
|
let rust_path = path.get_rust();
|
||||||
|
|
||||||
|
|||||||
+103
-49
@@ -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,58 +26,108 @@ 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);
|
||||||
|
let out_dir = root.join(&config.output);
|
||||||
|
|
||||||
for entry in fs::read_dir(src).unwrap() {
|
build_dir(&root, &src_dir, &src_dir, &out_dir);
|
||||||
if let Ok(entry) = entry {
|
|
||||||
let entry_path = root.join(&entry.path());
|
|
||||||
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
|
|
||||||
let source = match fs::read_to_string(&entry_path) {
|
|
||||||
Ok(s) => s,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("error: failed to read entry file\n {}", e);
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let parser_result = parser::parse(&source).map_err(|e| e.to_string());
|
|
||||||
|
|
||||||
let ast = match parser_result {
|
|
||||||
Ok(ast) => ast,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("error: parse failed\n{}", e);
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// semantic::walk_ast(semantic::scope::Scope::from_top(&root, &ast), &mut ast);
|
|
||||||
|
|
||||||
let mut gc = crate::codegen::RustCodegen::new();
|
|
||||||
let output = gc.generate(&ast);
|
|
||||||
|
|
||||||
if let Err(e) = fs::create_dir_all(&out_dir) {
|
|
||||||
eprintln!("error: failed to create build dir\n {}", e);
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
|
|
||||||
println!("build finished in {:.2?}", 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,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("error: failed to read file {}\n {}", path.display(), e);
|
||||||
|
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let parser_result = parser::parse(&source).map_err(|e| e.to_string());
|
||||||
|
|
||||||
|
let ast = match parser_result {
|
||||||
|
Ok(ast) => ast,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("error: parse failed in {}\n{}", path.display(), e);
|
||||||
|
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// semantic::walk_ast(semantic::scope::Scope::from_top(root, &ast), &mut ast);
|
||||||
|
|
||||||
|
let mut gc = crate::codegen::RustCodegen::new();
|
||||||
|
let output = gc.generate(&ast);
|
||||||
|
|
||||||
|
if let Err(e) = fs::write(&output_path, output) {
|
||||||
|
eprintln!(
|
||||||
|
"error: failed to write output {}\n {}",
|
||||||
|
output_path.display(),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_project_root() -> Option<PathBuf> {
|
pub fn find_project_root() -> Option<PathBuf> {
|
||||||
let mut dir = std::env::current_dir().ok()?;
|
let mut dir = std::env::current_dir().ok()?;
|
||||||
|
|
||||||
@@ -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")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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 => {
|
|
||||||
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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 }
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user