Compare commits
35
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe96e3aec6 | ||
|
|
72010faf03 | ||
|
|
e5df8df9b0 | ||
|
|
ee40450f3a | ||
|
|
be6d2de39c | ||
|
|
aff15f67c7 | ||
|
|
cfd1910f39 | ||
|
|
082981f0bd | ||
|
|
b384f55c77 | ||
|
|
c4756262e1 | ||
|
|
74f10cc74b | ||
|
|
acef0888a3 | ||
|
|
18ab88af64 | ||
|
|
5e6cdc84b9 | ||
|
|
2dc5cdc9d9 | ||
|
|
893c981a41 | ||
|
|
0b3c4b8143 | ||
|
|
86a1df7ad5 | ||
|
|
3fa04cddd0 | ||
|
|
371365b8cf | ||
|
|
b74da3255a | ||
|
|
83e5e98641 | ||
|
|
c774737074 | ||
|
|
9e1b9ad564 | ||
|
|
97b2cc4413 | ||
|
|
99ff0ead2d | ||
|
|
b0f3dccc87 | ||
|
|
86a781c3f2 | ||
|
|
583d51141f | ||
|
|
ad11a3bd6a | ||
|
|
7a2ba74d9c | ||
|
|
7007aa32f1 | ||
|
|
3444f93546 | ||
|
|
e09c7926e5 | ||
|
|
83e98573aa |
Generated
+19
-12
@@ -442,7 +442,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mist-analyzer"
|
name = "mist-analyzer"
|
||||||
version = "0.0.3"
|
version = "0.1.7-alpha.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cargo_metadata",
|
"cargo_metadata",
|
||||||
"dashmap 6.1.0",
|
"dashmap 6.1.0",
|
||||||
@@ -456,27 +456,34 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mist-codegen"
|
name = "mist-api"
|
||||||
version = "0.1.2"
|
version = "0.1.7-alpha.1"
|
||||||
dependencies = [
|
|
||||||
"mist-parser",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mist-lang"
|
|
||||||
version = "0.0.5-alpha0"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cargo_metadata",
|
"cargo_metadata",
|
||||||
"mist-analyzer",
|
|
||||||
"mist-codegen",
|
"mist-codegen",
|
||||||
"mist-parser",
|
"mist-parser",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mist-codegen"
|
||||||
|
version = "0.1.7-alpha.0"
|
||||||
|
dependencies = [
|
||||||
|
"mist-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mist-lang"
|
||||||
|
version = "0.1.7-alpha.2"
|
||||||
|
dependencies = [
|
||||||
|
"mist-analyzer",
|
||||||
|
"mist-api",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mist-parser"
|
name = "mist-parser"
|
||||||
version = "0.1.6"
|
version = "0.1.7-alpha.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pest",
|
"pest",
|
||||||
"pest_derive",
|
"pest_derive",
|
||||||
|
|||||||
+7
-18
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mist-lang"
|
name = "mist-lang"
|
||||||
version = "0.0.5-alpha0"
|
version = "0.1.7-alpha.2"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "The Mist programming language compiler"
|
description = "The Mist programming language compiler"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
@@ -16,19 +16,15 @@ include = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mist-parser = { workspace = true }
|
|
||||||
mist-analyzer = { workspace = true }
|
mist-analyzer = { workspace = true }
|
||||||
mist-codegen = { workspace = true }
|
mist-api = { workspace = true }
|
||||||
|
|
||||||
serde = { version = "1.0.228", features = ["serde_derive"] }
|
|
||||||
serde_json = "1.0.149"
|
|
||||||
cargo_metadata = "0.23.1"
|
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"crates/parser",
|
"crates/parser",
|
||||||
"crates/analyzer",
|
"crates/analyzer",
|
||||||
"crates/codegen",
|
"crates/codegen",
|
||||||
|
"crates/mist-api",
|
||||||
]
|
]
|
||||||
|
|
||||||
exclude = [
|
exclude = [
|
||||||
@@ -36,22 +32,15 @@ exclude = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
mist-parser = { path = "crates/parser", version = "0.1.6" }
|
mist-parser = { path = "crates/parser", version = "0.1.7-alpha.0" }
|
||||||
mist-analyzer = { path = "crates/analyzer", version = "0.0.3" }
|
mist-analyzer = { path = "crates/analyzer", version = "0.1.7-alpha.0" }
|
||||||
mist-codegen = { path = "crates/codegen", version = "0.1.2" }
|
mist-codegen = { path = "crates/codegen", version = "0.1.7-alpha.0" }
|
||||||
|
mist-api = { path = "crates/mist-api", version = "0.1.7-alpha.0" }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "mist"
|
name = "mist"
|
||||||
path = ".mist/src/main.rs"
|
path = ".mist/src/main.rs"
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "mist-lsp"
|
|
||||||
path = ".mist/lsp/main.rs"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "mist-header"
|
|
||||||
path = "src/_header.rs"
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "mist-analyzer"
|
name = "mist-analyzer"
|
||||||
path = ".mist/src/analyzer.rs"
|
path = ".mist/src/analyzer.rs"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mist-analyzer"
|
name = "mist-analyzer"
|
||||||
version = "0.0.3"
|
version = "0.1.7-alpha.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "The Mist programming language Analyzer LSP"
|
description = "The Mist programming language Analyzer LSP"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
|||||||
@@ -573,7 +573,7 @@ pub fn from_mist_to_rust(mut path: PathBuf) -> PathBuf {
|
|||||||
let mut comps: Vec<Component> = path.components().collect();
|
let mut comps: Vec<Component> = path.components().collect();
|
||||||
|
|
||||||
if let Some(pos) = comps.iter().rposition(|c| c.as_os_str() == "src") {
|
if let Some(pos) = comps.iter().rposition(|c| c.as_os_str() == "src") {
|
||||||
let replacement = std::path::Path::new(".mist/lsp");
|
let replacement = std::path::Path::new(".mist/src");
|
||||||
comps.splice(pos..=pos, replacement.components());
|
comps.splice(pos..=pos, replacement.components());
|
||||||
comps.iter().collect()
|
comps.iter().collect()
|
||||||
} else {
|
} else {
|
||||||
@@ -587,8 +587,7 @@ pub fn from_rust_to_mist(mut path: PathBuf) -> PathBuf {
|
|||||||
|
|
||||||
let comps: Vec<Component> = path.components().collect();
|
let comps: Vec<Component> = path.components().collect();
|
||||||
|
|
||||||
// pattern we originally inserted: ".mist/lsp"
|
let pattern: Vec<Component> = std::path::Path::new(".mist/src").components().collect();
|
||||||
let pattern: Vec<Component> = std::path::Path::new(".mist/lsp").components().collect();
|
|
||||||
|
|
||||||
// find the last occurrence of the pattern
|
// find the last occurrence of the pattern
|
||||||
if let Some(pos) = comps
|
if let Some(pos) = comps
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use mist_parser::{ast::TopLevel, error::ParseError};
|
|||||||
|
|
||||||
pub fn build(root: &PathBuf) {
|
pub fn build(root: &PathBuf) {
|
||||||
let src_dir = root.join("src");
|
let src_dir = root.join("src");
|
||||||
let out_dir = root.join(".mist/lsp");
|
let out_dir = root.join(".mist/src");
|
||||||
|
|
||||||
if let Err(e) = build_dir(root, &src_dir, &src_dir, &out_dir) {
|
if let Err(e) = build_dir(root, &src_dir, &src_dir, &out_dir) {
|
||||||
eprintln!("Warning: Build directory run aborted safely: {e}");
|
eprintln!("Warning: Build directory run aborted safely: {e}");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mist-codegen"
|
name = "mist-codegen"
|
||||||
version = "0.1.2"
|
version = "0.1.7-alpha.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "The Mist programming language Rust code generator"
|
description = "The Mist programming language Rust code generator"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
|||||||
+19
-16
@@ -4,10 +4,6 @@ pub mod top_level;
|
|||||||
|
|
||||||
use mist_parser::ast::*;
|
use mist_parser::ast::*;
|
||||||
|
|
||||||
pub fn get_mutable(mutable: bool) -> String {
|
|
||||||
if mutable { "mut " } else { "" }.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub expr_ensure_semicolon: bool,
|
pub expr_ensure_semicolon: bool,
|
||||||
}
|
}
|
||||||
@@ -112,11 +108,12 @@ impl GenRust for Attribute {
|
|||||||
match self {
|
match self {
|
||||||
Self::Path(path) => cg.add(&path.get_rust()),
|
Self::Path(path) => cg.add(&path.get_rust()),
|
||||||
Self::NameValue { path, value } => {
|
Self::NameValue { path, value } => {
|
||||||
cg.add(&format!("{} =", path.get_rust()));
|
cg.add(&format!("{} = ", path.get_rust()));
|
||||||
value.gen_rust(ctx, cg);
|
value.gen_rust(ctx, cg);
|
||||||
}
|
}
|
||||||
Self::List { path, items } => {
|
Self::List { path, items } => {
|
||||||
cg.add(&path.get_rust());
|
cg.add(&path.get_rust());
|
||||||
|
cg.add("(");
|
||||||
for (i, item) in items.iter().enumerate() {
|
for (i, item) in items.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
cg.add(", ");
|
cg.add(", ");
|
||||||
@@ -124,6 +121,7 @@ impl GenRust for Attribute {
|
|||||||
|
|
||||||
item.gen_rust(ctx, cg);
|
item.gen_rust(ctx, cg);
|
||||||
}
|
}
|
||||||
|
cg.add(")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,34 +236,39 @@ impl GetRust for TypeExprKind {
|
|||||||
impl GenRust for Pattern {
|
impl GenRust for Pattern {
|
||||||
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
|
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
|
||||||
match self {
|
match self {
|
||||||
Self::Id(id) => cg.add(&id.get_rust()),
|
Self::Path(mutable, path) => {
|
||||||
Self::Path(path) => cg.add(&path.get_rust()),
|
if *mutable {
|
||||||
|
cg.add("mut ");
|
||||||
|
};
|
||||||
|
|
||||||
|
cg.add(&path.get_rust())
|
||||||
|
}
|
||||||
Self::Literal(lit) => lit.gen_rust(ctx, cg),
|
Self::Literal(lit) => lit.gen_rust(ctx, cg),
|
||||||
|
|
||||||
Self::Struct(path, ids) => {
|
Self::Struct(path, inner) => {
|
||||||
cg.add(&path.get_rust());
|
cg.add(&path.get_rust());
|
||||||
cg.add(" {");
|
cg.add(" {");
|
||||||
for id in ids {
|
for pat in inner {
|
||||||
cg.add(&id.get_rust());
|
pat.gen_rust(ctx, cg);
|
||||||
cg.add(",");
|
cg.add(",");
|
||||||
}
|
}
|
||||||
cg.add("}");
|
cg.add("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::NamedTuple(path, ids) => {
|
Self::NamedTuple(path, inner) => {
|
||||||
cg.add(&path.get_rust());
|
cg.add(&path.get_rust());
|
||||||
cg.add(" (");
|
cg.add(" (");
|
||||||
for id in ids {
|
for pat in inner {
|
||||||
cg.add(&id.get_rust());
|
pat.gen_rust(ctx, cg);
|
||||||
cg.add(",");
|
cg.add(",");
|
||||||
}
|
}
|
||||||
cg.add(")");
|
cg.add(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::Tuple(ids) => {
|
Self::Tuple(inner) => {
|
||||||
cg.add("(");
|
cg.add("(");
|
||||||
for id in ids {
|
for pat in inner {
|
||||||
cg.add(&id.get_rust());
|
pat.gen_rust(ctx, cg);
|
||||||
cg.add(",");
|
cg.add(",");
|
||||||
}
|
}
|
||||||
cg.add(")");
|
cg.add(")");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use mist_parser::ast::*;
|
use mist_parser::ast::*;
|
||||||
|
|
||||||
use crate::{Context, get_mutable};
|
use crate::Context;
|
||||||
|
|
||||||
use crate::{GenRust, GetRust, RustCodegen};
|
use crate::{GenRust, GetRust, RustCodegen};
|
||||||
|
|
||||||
@@ -59,7 +59,11 @@ impl GenRust for Statement {
|
|||||||
cg.add(" {");
|
cg.add(" {");
|
||||||
cg.indent += 1;
|
cg.indent += 1;
|
||||||
|
|
||||||
for (pat, body) in match_items {
|
for match_item in match_items {
|
||||||
|
cg.add_indentedln(&match_item.get_comment());
|
||||||
|
|
||||||
|
let MatchItem(pat, body) = &match_item.item;
|
||||||
|
|
||||||
for (i, p) in pat.iter().enumerate() {
|
for (i, p) in pat.iter().enumerate() {
|
||||||
cg.addln("");
|
cg.addln("");
|
||||||
cg.add_indented("");
|
cg.add_indented("");
|
||||||
@@ -158,13 +162,11 @@ impl GenRust for Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Statement::For {
|
Statement::For {
|
||||||
mutable,
|
|
||||||
pattern,
|
pattern,
|
||||||
iterator,
|
iterator,
|
||||||
body,
|
body,
|
||||||
} => {
|
} => {
|
||||||
cg.add("for ");
|
cg.add("for ");
|
||||||
cg.add(&get_mutable(*mutable));
|
|
||||||
pattern.gen_rust(ctx, cg);
|
pattern.gen_rust(ctx, cg);
|
||||||
cg.add(" in ");
|
cg.add(" in ");
|
||||||
iterator.gen_rust(ctx, cg);
|
iterator.gen_rust(ctx, cg);
|
||||||
@@ -186,8 +188,6 @@ impl GenRust for Statement {
|
|||||||
|
|
||||||
impl GenRust for VarDecl {
|
impl GenRust for VarDecl {
|
||||||
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
|
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
|
||||||
cg.add(&get_mutable(self.mutable));
|
|
||||||
|
|
||||||
self.name.gen_rust(ctx, cg);
|
self.name.gen_rust(ctx, cg);
|
||||||
|
|
||||||
cg.add(
|
cg.add(
|
||||||
|
|||||||
@@ -212,8 +212,7 @@ impl GenRust for (&Vec<Spanned<FieldDeclStmt>>, &Spanned<ClassConstructor>) {
|
|||||||
cg.add_indentedln("}\n");
|
cg.add_indentedln("}\n");
|
||||||
|
|
||||||
let mut constructor_params = vec![VarDecl {
|
let mut constructor_params = vec![VarDecl {
|
||||||
mutable: false,
|
name: Pattern::Path(false, Path(vec![Identifier(String::from("self"))])),
|
||||||
name: Pattern::Id(Identifier(String::from("self"))),
|
|
||||||
type_: Some(TypeExpr(
|
type_: Some(TypeExpr(
|
||||||
TypeExprKind::Path(Path(vec![Identifier(String::from("Self"))])),
|
TypeExprKind::Path(Path(vec![Identifier(String::from("Self"))])),
|
||||||
vec![TypePostfix::RefMut],
|
vec![TypePostfix::RefMut],
|
||||||
@@ -326,6 +325,7 @@ impl GenRust for TopLevelKind {
|
|||||||
visibility,
|
visibility,
|
||||||
name,
|
name,
|
||||||
generics,
|
generics,
|
||||||
|
inherits,
|
||||||
fields,
|
fields,
|
||||||
constructor,
|
constructor,
|
||||||
items,
|
items,
|
||||||
@@ -339,6 +339,12 @@ impl GenRust for TopLevelKind {
|
|||||||
));
|
));
|
||||||
cg.indent += 1;
|
cg.indent += 1;
|
||||||
|
|
||||||
|
if let Some(inherits) = inherits {
|
||||||
|
cg.add_indented("pub _super: ");
|
||||||
|
cg.add(&inherits.get_rust());
|
||||||
|
cg.addln(",");
|
||||||
|
}
|
||||||
|
|
||||||
for field in fields.clone() {
|
for field in fields.clone() {
|
||||||
cg.add_indentedln(&field.get_comment());
|
cg.add_indentedln(&field.get_comment());
|
||||||
cg.add_indentedln(&field.item.decl.get_rust());
|
cg.add_indentedln(&field.item.decl.get_rust());
|
||||||
@@ -396,6 +402,38 @@ impl GenRust for TopLevelKind {
|
|||||||
ClassItem::Method(_) => {}
|
ClassItem::Method(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(inherits) = inherits {
|
||||||
|
cg.add("impl std::ops::Deref for ");
|
||||||
|
cg.add(&name.get_rust());
|
||||||
|
|
||||||
|
cg.addln(" {");
|
||||||
|
cg.indent += 1;
|
||||||
|
|
||||||
|
cg.add_indented("type Target = ");
|
||||||
|
cg.add(&inherits.get_rust());
|
||||||
|
cg.addln(";");
|
||||||
|
|
||||||
|
cg.add_indentedln("fn deref(&self) -> &Self::Target {&self._super}");
|
||||||
|
|
||||||
|
cg.indent -= 1;
|
||||||
|
cg.addln("}");
|
||||||
|
|
||||||
|
// Mut
|
||||||
|
|
||||||
|
cg.add("impl std::ops::DerefMut for ");
|
||||||
|
cg.add(&name.get_rust());
|
||||||
|
|
||||||
|
cg.addln(" {");
|
||||||
|
cg.indent += 1;
|
||||||
|
|
||||||
|
cg.add_indentedln(
|
||||||
|
"fn deref_mut(&mut self) -> &mut Self::Target {&mut self._super}",
|
||||||
|
);
|
||||||
|
|
||||||
|
cg.indent -= 1;
|
||||||
|
cg.addln("}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
[package]
|
||||||
|
name = "mist-api"
|
||||||
|
version = "0.1.7-alpha.1"
|
||||||
|
edition = "2024"
|
||||||
|
description = "The Mist programming language module system"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
repository = "https://github.com/mist-go/mist"
|
||||||
|
keywords = ["compiler", "language", "mist", "module-system"]
|
||||||
|
categories = ["compilers"]
|
||||||
|
|
||||||
|
include = [
|
||||||
|
".mist/src/**",
|
||||||
|
"Cargo.toml",
|
||||||
|
"README.md",
|
||||||
|
]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = { version = "1.0.228", features = ["serde_derive"] }
|
||||||
|
serde_json = "1.0.149"
|
||||||
|
cargo_metadata = "0.23.1"
|
||||||
|
mist-parser = { workspace = true }
|
||||||
|
mist-codegen = { workspace = true }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "mist_api"
|
||||||
|
path = ".mist/src/lib.rs"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod builder;
|
||||||
|
pub mod transpiler;
|
||||||
|
pub mod modules;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
pub mod builder;
|
||||||
|
pub mod transpiler;
|
||||||
|
pub mod modules;
|
||||||
|
|
||||||
|
void main() {}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
use <std::path::Path>;
|
||||||
|
use <std::path::PathBuf>;
|
||||||
|
use <std::fs>;
|
||||||
|
use <std::process>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub class Module {
|
||||||
|
pub String name;
|
||||||
|
pub PathBuf path;
|
||||||
|
pub Vec<Self> children;
|
||||||
|
|
||||||
|
pub constructor(String name, PathBuf mist_path, PathBuf rust_path) {
|
||||||
|
self.children = new Vec();
|
||||||
|
self.name = name;
|
||||||
|
self.path = mist_path;
|
||||||
|
|
||||||
|
if (self.path.is_dir()) {
|
||||||
|
PathBuf dir = self.path.clone();
|
||||||
|
|
||||||
|
// Behavior 2: It's a directory node. Check for gateway package.mist first.
|
||||||
|
PathBuf pkg_gate = self.path.join("package.mist");
|
||||||
|
if (pkg_gate.exists()) {
|
||||||
|
self.path = pkg_gate;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.scan_directory(&dir, &rust_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scan_directory(self mut*, Path* search_dir, Path* rust_path) {
|
||||||
|
var entries = match (fs::read_dir(search_dir)) {
|
||||||
|
Ok[entries] => entries;
|
||||||
|
Err[e] => {
|
||||||
|
eprintln!("error: failed to read directory {}\n {}", search_dir.display(), e);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (entry : entries) {
|
||||||
|
var entry = match (entry) {
|
||||||
|
Ok[entry] => entry;
|
||||||
|
Err[e] => {
|
||||||
|
eprintln!("error: failed to read directory entry\n {}", e);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PathBuf child_path = entry.path();
|
||||||
|
|
||||||
|
if (child_path == self.path) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String child_name = child_path.file_stem()
|
||||||
|
.and_then(|var s| s.to_str())
|
||||||
|
.expect("Failed to get module name")
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
PathBuf child_output = rust_path.join(&child_name).with_extension("rs");
|
||||||
|
|
||||||
|
if (!child_path.is_dir() && should_skip(&child_path, &child_output)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.children.push(new Module(child_name, child_path, child_output));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub PathBuf output_dir(self*, PathBuf* parent_dir) {
|
||||||
|
if (self.path.is_dir() || Some("package.mist") == self.path.file_name().unwrap().to_str()) {
|
||||||
|
parent_dir.join(&self.name)
|
||||||
|
} else {
|
||||||
|
parent_dir.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub PathBuf output_path(self*, PathBuf* parent_dir) {
|
||||||
|
if (self.path.is_dir() || Some("package.mist") == self.path.file_name().unwrap().to_str()) {
|
||||||
|
parent_dir.join(&self.name).join("mod.rs")
|
||||||
|
} else {
|
||||||
|
parent_dir.join(&self.name).with_extension("rs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub Module master_package(PathBuf mist_path, PathBuf rust_path) {
|
||||||
|
String name = mist_path.file_stem()
|
||||||
|
.and_then(|var s| s.to_str())
|
||||||
|
.expect("Failed to get module name")
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
var mut root_mod = new Module(name, mist_path.clone(), rust_path.clone());
|
||||||
|
|
||||||
|
if (!mist_path.is_dir()) {
|
||||||
|
PathBuf parent_dir = mist_path.parent()
|
||||||
|
.expect("Failed to get parent directory of root file")
|
||||||
|
.to_path_buf();
|
||||||
|
|
||||||
|
root_mod.scan_directory(&parent_dir, &rust_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
root_mod
|
||||||
|
}
|
||||||
|
|
||||||
|
bool should_skip(Path* source, Path* output) {
|
||||||
|
var src_time = fs::metadata(source)
|
||||||
|
.ok()
|
||||||
|
.and_then(|var v| v.modified().ok());
|
||||||
|
|
||||||
|
var out_time = fs::metadata(output)
|
||||||
|
.ok()
|
||||||
|
.and_then(|var v| v.modified().ok());
|
||||||
|
|
||||||
|
out_time
|
||||||
|
.map(|var out_time| out_time >= src_time.unwrap())
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
use <std::fs>;
|
||||||
|
use <std::path::Path>;
|
||||||
|
use <std::path::PathBuf>;
|
||||||
|
use <std::process>;
|
||||||
|
use <std::time>;
|
||||||
|
use <std::env>;
|
||||||
|
|
||||||
|
use <mist_parser::error>;
|
||||||
|
use <crate::modules>;
|
||||||
|
|
||||||
|
pub PathBuf build(bool force) {
|
||||||
|
var start = time::Instant::now();
|
||||||
|
|
||||||
|
var root = env::current_dir().expect("Unable to find project root");
|
||||||
|
|
||||||
|
PathBuf src = root.join("src");
|
||||||
|
PathBuf out = root.join(".mist/src");
|
||||||
|
|
||||||
|
var master = modules::master_package(src.join("main.mist"), out.join("main.rs"));
|
||||||
|
|
||||||
|
master.transpile(&out);
|
||||||
|
|
||||||
|
var elapsed = start.elapsed();
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"\x1b[32m\nTranspile successful\x1b[0m in \x1b[34m{:.2?}\x1b[0m",
|
||||||
|
elapsed
|
||||||
|
);
|
||||||
|
|
||||||
|
root
|
||||||
|
}
|
||||||
|
|
||||||
|
impl modules::Module {
|
||||||
|
String transpile(self*, PathBuf* parent_dir) {
|
||||||
|
PathBuf dir = self.output_dir(&parent_dir);
|
||||||
|
PathBuf output_file = self.output_path(&parent_dir);
|
||||||
|
|
||||||
|
var _ = fs::create_dir_all(&dir);
|
||||||
|
|
||||||
|
String mut output = String::new();
|
||||||
|
|
||||||
|
for (child : &self.children) {
|
||||||
|
output.push_str(&child.transpile(&dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.path.is_dir()) {
|
||||||
|
var res = fs::write(&output_file, output);
|
||||||
|
|
||||||
|
if (res.is_err()) {
|
||||||
|
eprintln!(
|
||||||
|
"error: failed to write output {}\n {}",
|
||||||
|
output_file.display(),
|
||||||
|
res.unwrap_err(),
|
||||||
|
);
|
||||||
|
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
transpile_file(&self.path, &output_file, &output);
|
||||||
|
}
|
||||||
|
|
||||||
|
format!("pub mod {};\n", self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void transpile_file(PathBuf* path, PathBuf* output_file, str* mod_decl) {
|
||||||
|
String 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var mut gc = mist_codegen::RustCodegen::new();
|
||||||
|
|
||||||
|
String output = gc.generate(match (mist_parser::parse(&source)) {
|
||||||
|
Ok[ast] => ast;
|
||||||
|
Err[e] => {
|
||||||
|
match (e) {
|
||||||
|
error::ParseError::Ast[e] => {
|
||||||
|
var start_pos = e.span.start_pos().line_col();
|
||||||
|
|
||||||
|
var span = e.span.as_str();
|
||||||
|
|
||||||
|
eprintln!(
|
||||||
|
"\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}\n\t{}{}\t{}",
|
||||||
|
path.as_os_str().display(),
|
||||||
|
start_pos.0,
|
||||||
|
start_pos.1,
|
||||||
|
e.error_message,
|
||||||
|
span,
|
||||||
|
if span.ends_with("\n") { "" } else { "\n" },
|
||||||
|
"^".repeat(span.trim().len()),
|
||||||
|
);
|
||||||
|
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
error::ParseError::PreAst[e] => {
|
||||||
|
eprintln!("error: parse failed in {}\n{}", path.display(), e);
|
||||||
|
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var res = fs::write(&output_file, format!("{mod_decl}{output}"));
|
||||||
|
|
||||||
|
if (res.is_err()) {
|
||||||
|
eprintln!(
|
||||||
|
"error: failed to write output {}\n {}",
|
||||||
|
output_file.display(),
|
||||||
|
res.unwrap_err(),
|
||||||
|
);
|
||||||
|
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mist-parser"
|
name = "mist-parser"
|
||||||
version = "0.1.6"
|
version = "0.1.7-alpha.2"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "The Mist programming language parser"
|
description = "The Mist programming language parser"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
|||||||
@@ -32,12 +32,11 @@ pub enum Literal {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub enum Pattern {
|
pub enum Pattern {
|
||||||
NamedTuple(Path, Vec<Identifier>),
|
NamedTuple(Path, Vec<Box<Pattern>>),
|
||||||
Struct(Path, Vec<Identifier>),
|
Struct(Path, Vec<Box<Pattern>>),
|
||||||
Tuple(Vec<Identifier>),
|
Tuple(Vec<Box<Pattern>>),
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
Path(Path),
|
Path(bool, Path),
|
||||||
Id(Identifier),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
|||||||
@@ -31,12 +31,11 @@ pub enum Statement {
|
|||||||
body: StatementBody,
|
body: StatementBody,
|
||||||
},
|
},
|
||||||
For {
|
For {
|
||||||
mutable: bool,
|
|
||||||
pattern: Pattern,
|
pattern: Pattern,
|
||||||
iterator: Expression,
|
iterator: Expression,
|
||||||
body: StatementBody,
|
body: StatementBody,
|
||||||
},
|
},
|
||||||
Match(Expression, Vec<(Vec<Pattern>, Expression)>),
|
Match(Expression, Vec<Spanned<MatchItem>>),
|
||||||
|
|
||||||
VarDecl(VarDeclStmt),
|
VarDecl(VarDeclStmt),
|
||||||
Return(Option<Expression>),
|
Return(Option<Expression>),
|
||||||
@@ -44,9 +43,11 @@ pub enum Statement {
|
|||||||
Continue,
|
Continue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct MatchItem(pub Vec<Pattern>, pub Expression);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct VarDecl {
|
pub struct VarDecl {
|
||||||
pub mutable: bool,
|
|
||||||
pub name: Pattern,
|
pub name: Pattern,
|
||||||
pub type_: Option<TypeExpr>,
|
pub type_: Option<TypeExpr>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ pub enum TopLevelKind {
|
|||||||
visibility: Visibility,
|
visibility: Visibility,
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
generics: GenericsDecl,
|
generics: GenericsDecl,
|
||||||
|
inherits: Option<TypeExpr>,
|
||||||
fields: Vec<Spanned<FieldDeclStmt>>,
|
fields: Vec<Spanned<FieldDeclStmt>>,
|
||||||
constructor: Spanned<ClassConstructor>,
|
constructor: Spanned<ClassConstructor>,
|
||||||
items: Vec<ClassItem>,
|
items: Vec<ClassItem>,
|
||||||
|
|||||||
@@ -134,16 +134,24 @@ literal = {
|
|||||||
// PATTERNS
|
// PATTERNS
|
||||||
// ======================================================
|
// ======================================================
|
||||||
|
|
||||||
|
multi_pat_template = _{
|
||||||
|
(pattern ~ ("," ~ pattern)*)?
|
||||||
|
}
|
||||||
|
|
||||||
tuple_pattern = {
|
tuple_pattern = {
|
||||||
"[" ~ (identifier ~ ("," ~ identifier)*) ~ "]"
|
"[" ~ pattern ~ "," ~ multi_pat_template ~ "]"
|
||||||
}
|
}
|
||||||
|
|
||||||
named_tuple_pattern = {
|
named_tuple_pattern = {
|
||||||
static_path ~ "[" ~ (identifier ~ ("," ~ identifier)*)? ~ "]"
|
static_path ~ "[" ~ multi_pat_template ~ "]"
|
||||||
}
|
}
|
||||||
|
|
||||||
struct_pattern = {
|
struct_pattern = {
|
||||||
static_path ~ "{" ~ (identifier ~ ("," ~ identifier)*)? ~ "}"
|
static_path ~ "{" ~ multi_pat_template ~ "}"
|
||||||
|
}
|
||||||
|
|
||||||
|
path_pattern = {
|
||||||
|
mutable? ~ static_path
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern = _{
|
pattern = _{
|
||||||
@@ -151,7 +159,7 @@ pattern = _{
|
|||||||
| tuple_pattern
|
| tuple_pattern
|
||||||
| struct_pattern
|
| struct_pattern
|
||||||
| literal
|
| literal
|
||||||
| static_path
|
| path_pattern
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================================================
|
// ======================================================
|
||||||
@@ -171,7 +179,7 @@ meta = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
meta_list = {
|
meta_list = {
|
||||||
meta ~ ("," ~ meta)* ~ ","?
|
(meta ~ ("," ~ meta)* ~ ","?)?
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes = {
|
attributes = {
|
||||||
@@ -182,7 +190,7 @@ attributes = {
|
|||||||
// DECLARATION HELPERS
|
// DECLARATION HELPERS
|
||||||
// ======================================================
|
// ======================================================
|
||||||
var_decl = {
|
var_decl = {
|
||||||
(var | type_expr) ~ mutable? ~ pattern
|
(var | type_expr) ~ pattern
|
||||||
}
|
}
|
||||||
|
|
||||||
field = {
|
field = {
|
||||||
@@ -190,11 +198,11 @@ field = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
field_list = {
|
field_list = {
|
||||||
field ~ ("," ~ field)* ~ ","?
|
(field ~ ("," ~ field)* ~ ","?)?
|
||||||
}
|
}
|
||||||
|
|
||||||
param_list = {
|
param_list = {
|
||||||
var_decl ~ ("," ~ var_decl)* ~ ","?
|
(var_decl ~ ("," ~ var_decl)* ~ ","?)?
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================================================
|
// ======================================================
|
||||||
@@ -252,7 +260,7 @@ enum_decl = {
|
|||||||
// ======================================================
|
// ======================================================
|
||||||
|
|
||||||
class_constructor = {
|
class_constructor = {
|
||||||
visibility? ~ "constructor" ~ generics_decl? ~ "(" ~ param_list? ~ ")" ~ block
|
visibility? ~ "constructor" ~ generics_decl? ~ "(" ~ param_list ~ ")" ~ block
|
||||||
}
|
}
|
||||||
|
|
||||||
class_fields = {
|
class_fields = {
|
||||||
@@ -268,7 +276,7 @@ self_param = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
method = {
|
method = {
|
||||||
visibility? ~ type_expr ~ identifier ~ generics_decl? ~ "(" ~ self_param? ~ ("," ~ param_list?)? ~ ")" ~ block
|
visibility? ~ type_expr ~ identifier ~ generics_decl? ~ "(" ~ self_param? ~ ("," ~ param_list)? ~ ")" ~ block
|
||||||
}
|
}
|
||||||
|
|
||||||
class_item = _{
|
class_item = _{
|
||||||
@@ -277,7 +285,7 @@ class_item = _{
|
|||||||
}
|
}
|
||||||
|
|
||||||
class_decl = {
|
class_decl = {
|
||||||
visibility? ~ "class" ~ identifier ~ generics_decl? ~ "{" ~ class_fields ~ class_constructor ~ class_item* ~ "}"
|
visibility? ~ "class" ~ identifier ~ generics_decl? ~ (":" ~ type_expr)? ~ "{" ~ class_fields ~ class_constructor ~ class_item* ~ "}"
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================================================
|
// ======================================================
|
||||||
@@ -297,7 +305,7 @@ impl_decl = {
|
|||||||
trait_requirements = { ":" ~ type_expr_param ~ ("+" ~ type_expr_param)* }
|
trait_requirements = { ":" ~ type_expr_param ~ ("+" ~ type_expr_param)* }
|
||||||
|
|
||||||
method_no_body = {
|
method_no_body = {
|
||||||
visibility? ~ type_expr ~ identifier ~ generics_decl? ~ "(" ~ self_param? ~ ("," ~ param_list?)? ~ ")" ~ semicolon
|
visibility? ~ type_expr ~ identifier ~ generics_decl? ~ "(" ~ self_param? ~ ("," ~ param_list)? ~ ")" ~ semicolon
|
||||||
}
|
}
|
||||||
|
|
||||||
trait_item = _{
|
trait_item = _{
|
||||||
@@ -314,7 +322,7 @@ trait_decl = {
|
|||||||
// ======================================================
|
// ======================================================
|
||||||
|
|
||||||
function_decl = {
|
function_decl = {
|
||||||
visibility? ~ type_expr ~ identifier ~ "(" ~ param_list? ~ ")" ~ block
|
visibility? ~ type_expr ~ identifier ~ "(" ~ param_list ~ ")" ~ block
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================================================
|
// ======================================================
|
||||||
@@ -415,7 +423,7 @@ c_for_stmt = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for_stmt = {
|
for_stmt = {
|
||||||
"for" ~ "(" ~ mutable? ~ pattern ~ ":" ~ expr ~ ")" ~ statement_body
|
"for" ~ "(" ~ pattern ~ ":" ~ expr ~ ")" ~ statement_body
|
||||||
}
|
}
|
||||||
|
|
||||||
loop_stmt = {
|
loop_stmt = {
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ use crate::{
|
|||||||
Rule,
|
Rule,
|
||||||
ast::*,
|
ast::*,
|
||||||
ast_expr,
|
ast_expr,
|
||||||
error::{AstError, AstResult, IntoErr},
|
error::{AstError, IntoErr},
|
||||||
parser::listen_rule,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDeclStmt {
|
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDeclStmt {
|
||||||
@@ -63,13 +62,10 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDecl {
|
|||||||
})
|
})
|
||||||
.transpose();
|
.transpose();
|
||||||
|
|
||||||
let mutable: AstResult<'_, bool> = Ok(listen_rule(&mut inner, Rule::mutable));
|
|
||||||
|
|
||||||
let name = Pattern::try_from(inner.next().unwrap());
|
let name = Pattern::try_from(inner.next().unwrap());
|
||||||
|
|
||||||
ast_expr!(VarDecl {
|
ast_expr!(VarDecl {
|
||||||
type_: type_,
|
type_: type_,
|
||||||
mutable: mutable,
|
|
||||||
name: name,
|
name: name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ use crate::{
|
|||||||
Rule,
|
Rule,
|
||||||
ast::*,
|
ast::*,
|
||||||
ast_ensure, ast_expr,
|
ast_ensure, ast_expr,
|
||||||
error::{AstError, IntoErr, collect_recovered},
|
error::{AstError, AstResult, IntoErr, collect_recovered, collect_recovered_map},
|
||||||
parser::consume_rule,
|
parser::{consume_rule, listen_rule},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Identifier {
|
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Identifier {
|
||||||
@@ -60,23 +60,26 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Pattern {
|
|||||||
let mut inner = pair.clone().into_inner();
|
let mut inner = pair.clone().into_inner();
|
||||||
|
|
||||||
match rule {
|
match rule {
|
||||||
Rule::tuple_pattern => ast_expr!(Pattern::Tuple(collect_recovered(pair.into_inner()))),
|
Rule::tuple_pattern => ast_expr!(Pattern::Tuple(collect_recovered_map(inner, |v| {
|
||||||
|
Self::try_from(v).map(Box::new)
|
||||||
|
}))),
|
||||||
|
|
||||||
Rule::named_tuple_pattern => ast_expr!(Pattern::NamedTuple(
|
Rule::named_tuple_pattern => ast_expr!(Pattern::NamedTuple(
|
||||||
Path::try_from(inner.next().unwrap()),
|
Path::try_from(inner.next().unwrap()),
|
||||||
collect_recovered(inner),
|
collect_recovered_map(inner, |v| Self::try_from(v).map(Box::new)),
|
||||||
)),
|
)),
|
||||||
|
|
||||||
Rule::struct_pattern => ast_expr!(Pattern::Struct(
|
Rule::struct_pattern => ast_expr!(Pattern::Struct(
|
||||||
Path::try_from(inner.next().unwrap()),
|
Path::try_from(inner.next().unwrap()),
|
||||||
collect_recovered(inner),
|
collect_recovered_map(inner, |v| Self::try_from(v).map(Box::new)),
|
||||||
)),
|
)),
|
||||||
|
|
||||||
Rule::literal => ast_expr!(Pattern::Literal(pair.try_into())),
|
Rule::literal => ast_expr!(Pattern::Literal(pair.try_into())),
|
||||||
|
|
||||||
Rule::identifier => ast_expr!(Pattern::Id(pair.try_into())),
|
Rule::path_pattern => ast_expr!(Pattern::Path(
|
||||||
|
Ok(listen_rule(&mut inner, Rule::mutable)) as AstResult<'_, bool>,
|
||||||
Rule::static_path => ast_expr!(Pattern::Path(pair.try_into())),
|
inner.next().unwrap().try_into()
|
||||||
|
)),
|
||||||
|
|
||||||
_ => AstError::bug_unimplemented(pair),
|
_ => AstError::bug_unimplemented(pair),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ use crate::{
|
|||||||
Rule,
|
Rule,
|
||||||
ast::*,
|
ast::*,
|
||||||
ast_ensure, ast_expr,
|
ast_ensure, ast_expr,
|
||||||
error::{AstError, AstResult, IntoErr, collect_recovered},
|
error::{AstError, IntoErr, collect_recovered},
|
||||||
parser::listen_rule,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Block {
|
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Block {
|
||||||
@@ -97,7 +96,6 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
Rule::for_stmt => ast_expr!(Statement::For {
|
Rule::for_stmt => ast_expr!(Statement::For {
|
||||||
mutable: Ok(listen_rule(&mut inner, Rule::mutable)) as AstResult<'_, bool>,
|
|
||||||
pattern: inner.next().unwrap().try_into(),
|
pattern: inner.next().unwrap().try_into(),
|
||||||
iterator: inner.next().unwrap().try_into(),
|
iterator: inner.next().unwrap().try_into(),
|
||||||
body: inner.next().unwrap().try_into(),
|
body: inner.next().unwrap().try_into(),
|
||||||
@@ -105,18 +103,23 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
|
|||||||
|
|
||||||
Rule::match_stmt => ast_expr!(Statement::Match(
|
Rule::match_stmt => ast_expr!(Statement::Match(
|
||||||
inner.next().unwrap().try_into(),
|
inner.next().unwrap().try_into(),
|
||||||
inner
|
collect_recovered(inner),
|
||||||
.map(|match_itms| {
|
|
||||||
let mut match_inner = match_itms.into_inner();
|
|
||||||
Ok((
|
|
||||||
collect_recovered(match_inner.next().unwrap().into_inner()).get()?,
|
|
||||||
Expression::try_from(match_inner.next().unwrap()).get()?,
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.collect::<AstResult<'a, Vec<_>>>(),
|
|
||||||
)),
|
)),
|
||||||
|
|
||||||
_ => AstError::bug_unimplemented(pair),
|
_ => AstError::bug_unimplemented(pair),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for MatchItem {
|
||||||
|
type Error = AstError<'a, Self>;
|
||||||
|
|
||||||
|
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||||
|
let mut match_inner = pair.into_inner();
|
||||||
|
|
||||||
|
Ok(MatchItem(
|
||||||
|
collect_recovered(match_inner.next().unwrap().into_inner()).get()?,
|
||||||
|
Expression::try_from(match_inner.next().unwrap()).get()?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Attribute {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Some(next) => match next.as_rule() {
|
Some(next) => match next.as_rule() {
|
||||||
Rule::primary => {
|
Rule::literal => {
|
||||||
// #[path = literal]
|
// #[path = literal]
|
||||||
Ok(Attribute::NameValue {
|
Ok(Attribute::NameValue {
|
||||||
path,
|
path,
|
||||||
value: inner.next().unwrap().try_into().get()?,
|
value: next.try_into().get()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,14 +23,11 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
|
|||||||
|
|
||||||
let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| {
|
let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| {
|
||||||
let mut param_inner = param.into_inner();
|
let mut param_inner = param.into_inner();
|
||||||
let name = Pattern::Id(Identifier(String::from("self")));
|
|
||||||
|
|
||||||
let mutable = listen_rule(&mut param_inner, Rule::mutable);
|
let mutable = listen_rule(&mut param_inner, Rule::mutable);
|
||||||
|
|
||||||
let is_ref = listen_rule(&mut param_inner, Rule::deref_px);
|
let is_ref = listen_rule(&mut param_inner, Rule::deref_px);
|
||||||
|
let name = Pattern::Path(mutable && !is_ref, Path(vec![Identifier(String::from("self"))]));
|
||||||
|
|
||||||
VarDecl {
|
VarDecl {
|
||||||
mutable: mutable && !is_ref,
|
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
type_: Some(TypeExpr(
|
type_: Some(TypeExpr(
|
||||||
TypeExprKind::Path(Path(vec![Identifier("Self".to_string())])),
|
TypeExprKind::Path(Path(vec![Identifier("Self".to_string())])),
|
||||||
|
|||||||
@@ -69,6 +69,10 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
|
|||||||
.transpose()
|
.transpose()
|
||||||
.map(|v| v.unwrap_or_default()),
|
.map(|v| v.unwrap_or_default()),
|
||||||
|
|
||||||
|
inherits: consume_rule(&mut inner, Rule::type_expr)
|
||||||
|
.map(TypeExpr::try_from)
|
||||||
|
.transpose(),
|
||||||
|
|
||||||
fields: collect_recovered(inner.next().unwrap().into_inner()),
|
fields: collect_recovered(inner.next().unwrap().into_inner()),
|
||||||
|
|
||||||
constructor: inner.next().unwrap().try_into(),
|
constructor: inner.next().unwrap().try_into(),
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
package = "main.mist"
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
pub mod app;
|
|
||||||
pub mod task;
|
|
||||||
pub mod plugin;
|
|
||||||
pub mod logger;
|
|
||||||
pub mod event;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
var mut app_instance = new app::Application("mist-app");
|
var mut app_instance = new app::Application("mist-app");
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
pub mod builder;
|
|
||||||
|
|
||||||
fn main() {}
|
|
||||||
+2
-3
@@ -1,9 +1,8 @@
|
|||||||
use <std::process>;
|
use <std::process>;
|
||||||
use <std::env>;
|
use <std::env>;
|
||||||
use <std::fs>;
|
use <std::fs>;
|
||||||
|
use <mist_api::builder>;
|
||||||
pub mod builder;
|
use <mist_api::transpiler>;
|
||||||
pub mod transpiler;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
Vec<String> args = env::args().collect();
|
Vec<String> args = env::args().collect();
|
||||||
|
|||||||
@@ -1,162 +0,0 @@
|
|||||||
use <std::fs>;
|
|
||||||
use <std::path::Path>;
|
|
||||||
use <std::path::PathBuf>;
|
|
||||||
use <std::process>;
|
|
||||||
use <std::time>;
|
|
||||||
use <std::env>;
|
|
||||||
|
|
||||||
use <mist_parser::error>;
|
|
||||||
|
|
||||||
pub PathBuf build(bool force) {
|
|
||||||
var start = time::Instant::now();
|
|
||||||
|
|
||||||
var root = env::current_dir().expect("Unable to find project root");
|
|
||||||
|
|
||||||
PathBuf src = root.join("src");
|
|
||||||
PathBuf out = root.join(".mist/src");
|
|
||||||
|
|
||||||
build_dir(&root, &src, &src, &out, force);
|
|
||||||
|
|
||||||
var elapsed = start.elapsed();
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"\x1b[32m\nTranspile successful\x1b[0m in \x1b[34m{:.2?}\x1b[0m",
|
|
||||||
elapsed
|
|
||||||
);
|
|
||||||
|
|
||||||
root
|
|
||||||
}
|
|
||||||
|
|
||||||
void build_dir(Path* root, Path* base_src, Path* current, Path* out, bool force) {
|
|
||||||
var entries = match (fs::read_dir(current)) {
|
|
||||||
Ok[entries] => entries;
|
|
||||||
Err[e] => {
|
|
||||||
eprintln!(
|
|
||||||
"error: failed to read directory {}\n {}",
|
|
||||||
current.display(),
|
|
||||||
e
|
|
||||||
);
|
|
||||||
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (entry : entries) {
|
|
||||||
var entry = match (entry) {
|
|
||||||
Ok[entry] => entry;
|
|
||||||
Err[e] => {
|
|
||||||
eprintln!("error: failed to read directory entry\n {}", e);
|
|
||||||
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
PathBuf path = entry.path();
|
|
||||||
|
|
||||||
if (path.is_dir()) {
|
|
||||||
build_dir(root, base_src, &path, out, force);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Path* relative = path.strip_prefix(base_src).expect("Failed to strip base src from path");
|
|
||||||
|
|
||||||
if (path.extension().and_then(|var e| e.to_str()) != Some("mist")) {
|
|
||||||
PathBuf dest = out.join(relative);
|
|
||||||
|
|
||||||
Option<Path*> parent = dest.parent();
|
|
||||||
|
|
||||||
if (parent.is_some()) {
|
|
||||||
fs::create_dir_all(parent.unwrap()).expect("failed to create output directory");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!force && should_skip(&path, &dest)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::copy(&path, dest).expect("Failed to copy non-mist file");
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
PathBuf output_file = out.join(relative).with_extension("rs");
|
|
||||||
|
|
||||||
if (!force && should_skip(&path, &output_file)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Option<Path*> parent = output_file.parent();
|
|
||||||
|
|
||||||
if (parent.is_some()) {
|
|
||||||
fs::create_dir_all(parent.unwrap()).expect("failed to create output directory");
|
|
||||||
}
|
|
||||||
|
|
||||||
String 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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var mut gc = mist_codegen::RustCodegen::new();
|
|
||||||
|
|
||||||
String output = gc.generate(match (mist_parser::parse(&source)) {
|
|
||||||
Ok[ast] => ast;
|
|
||||||
Err[e] => {
|
|
||||||
match (e) {
|
|
||||||
error::ParseError::Ast[e] => {
|
|
||||||
var start_pos = e.span.start_pos().line_col();
|
|
||||||
|
|
||||||
var span = e.span.as_str();
|
|
||||||
|
|
||||||
eprintln!(
|
|
||||||
"\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}\n\t{}{}\t{}",
|
|
||||||
path.as_os_str().display(),
|
|
||||||
start_pos.0,
|
|
||||||
start_pos.1,
|
|
||||||
e.error_message,
|
|
||||||
span,
|
|
||||||
if span.ends_with("\n") { "" } else { "\n" },
|
|
||||||
"^".repeat(span.trim().len()),
|
|
||||||
);
|
|
||||||
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
error::ParseError::PreAst[e] => {
|
|
||||||
eprintln!("error: parse failed in {}\n{}", path.display(), e);
|
|
||||||
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var res = fs::write(&output_file, output);
|
|
||||||
|
|
||||||
if (res.is_err()) {
|
|
||||||
eprintln!(
|
|
||||||
"error: failed to write output {}\n {}",
|
|
||||||
output_file.display(),
|
|
||||||
res.unwrap_err(),
|
|
||||||
);
|
|
||||||
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool should_skip(Path* source, Path* output) {
|
|
||||||
var src_time = fs::metadata(source)
|
|
||||||
.ok()
|
|
||||||
.and_then(|var v| v.modified().ok());
|
|
||||||
|
|
||||||
var out_time = fs::metadata(output)
|
|
||||||
.ok()
|
|
||||||
.and_then(|var v| v.modified().ok());
|
|
||||||
|
|
||||||
out_time
|
|
||||||
.map(|var out_time| out_time >= src_time.unwrap())
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user