This commit is contained in:
2026-06-26 00:37:41 +02:00
parent c78c9985f4
commit fda193b8ff
4 changed files with 1052 additions and 0 deletions
+175
View File
@@ -0,0 +1,175 @@
use mist_parser::ast::*;
use crate::fmt::{Context, GenMist, GetMist, MistCodegen};
impl GenMist for Expression {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
let ensure_semicolon = if ctx.expr_ensure_semicolon {
ctx.expr_ensure_semicolon = false;
true
} else {
false
};
match self {
Expression::Path(path) => cg.add(&path.get_mist()),
Expression::Literal(literal) => literal.gen_mist(ctx, cg),
Expression::Statement(stmt) => stmt.gen_mist(ctx, cg),
Expression::Array(values) => {
cg.add("[");
for (i, val) in values.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
val.gen_mist(ctx, cg);
}
cg.add("]");
}
Expression::ArrayRepeat(value, repeat) => {
cg.add("[");
value.gen_mist(ctx, cg);
cg.add("; ");
repeat.gen_mist(ctx, cg);
cg.add("]");
}
Expression::Fix {
initial,
prefixes,
postfixes,
} => {
for prefix in prefixes {
prefix.gen_mist(ctx, cg);
}
initial.gen_mist(ctx, cg);
for postfix in postfixes {
postfix.gen_mist(ctx, cg);
}
}
Expression::Binary { lhs, op, rhs } => {
lhs.gen_mist(ctx, cg);
cg.add(" ");
cg.add(op);
cg.add(" ");
rhs.gen_mist(ctx, cg);
}
Expression::Closure {
return_type,
params,
body,
} => {
cg.add("(");
for (i, arg) in params.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
arg.gen_mist(ctx, cg);
}
cg.add(") => ");
if let Some(ty) = return_type {
cg.add(&ty.get_mist());
cg.add(" ");
cg.ensure_brackets_expr(ctx, body);
} else {
body.gen_mist(ctx, cg);
}
}
}
if ensure_semicolon {
ctx.expr_ensure_semicolon = true;
if !self.is_block() {
cg.add(";");
}
}
}
}
impl GenMist for Prefix {
fn gen_mist(&self, _ctx: &mut Context, cg: &mut MistCodegen) {
match self {
Self::Deref => cg.add("*"),
Self::Ref => cg.add("&"),
Self::RefMut => cg.add("&mut "),
Self::Not => cg.add("!"),
Self::Neg => cg.add("-"),
}
}
}
impl GenMist for Postfix {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
match self {
Postfix::TupleFieldAccess(field, generics) => {
cg.add(&format!(
".{}{}",
field,
generics
.iter()
.map(|v| format!("::{}", v.get_mist()))
.collect::<String>()
));
}
Postfix::FieldAccess(field, generics) => {
cg.add(&format!(
".{}{}",
field.get_mist(),
generics
.iter()
.map(|v| format!("::{}", v.get_mist()))
.collect::<String>()
));
}
Postfix::Call(args) => {
cg.add("(");
for (i, arg) in args.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
arg.gen_mist(ctx, cg);
}
cg.add(")");
}
Postfix::MacroCall { inner, delimiter } => {
let (open, close) = match delimiter {
MacroDelimiter::Paren => ("!(", ")"),
MacroDelimiter::Bracket => ("![", "]"),
MacroDelimiter::Brace => ("!{", "}"),
};
cg.add(open);
cg.add(inner);
cg.add(close);
}
Postfix::StructCall(fields) => {
cg.add("{");
for (name, expr) in fields {
cg.add(&name.get_mist());
if let Some(expr) = expr {
cg.add(": ");
expr.gen_mist(ctx, cg);
}
cg.add(", ");
}
cg.add("}");
}
Postfix::Index(idx) => {
cg.add("[");
idx.gen_mist(ctx, cg);
cg.add("]");
}
Postfix::As(ty) => {
cg.add(" as ");
cg.add(&ty.get_mist());
}
Postfix::Try => cg.add("?"),
Postfix::Assign(cmp, expr) => {
cg.add(" ");
cg.add(cmp);
cg.add(" ");
expr.gen_mist(ctx, cg);
}
Postfix::Increment => cg.add(" += 1"),
Postfix::Decrement => cg.add(" -= 1"),
}
}
}
+405
View File
@@ -0,0 +1,405 @@
pub mod expr;
pub mod statement;
pub mod top_level;
use mist_parser::ast::*;
pub struct Context {
pub expr_ensure_semicolon: bool,
}
pub struct MistCodegen {
indent_amount: u8,
output: String,
indent: usize,
}
impl MistCodegen {
pub fn new() -> Self {
Self {
output: String::new(),
indent: 0,
indent_amount: 4,
}
}
fn indent_str(&self) -> String {
" ".repeat(self.indent_amount as usize).repeat(self.indent)
}
pub fn add(&mut self, s: &str) {
self.output.push_str(s);
}
pub fn addln(&mut self, s: &str) {
self.add(s);
self.add("\n");
}
pub fn add_indented(&mut self, s: &str) {
let line = format!("{}{}", self.indent_str(), s);
self.add(&line);
}
pub fn add_indentedln(&mut self, s: &str) {
let line = format!("{}{}\n", self.indent_str(), s);
self.add(&line);
}
pub fn into_output(self) -> String {
self.output
}
pub fn generate(&mut self, toplevels: Vec<TopLevel>) -> String {
let mut ctx = Context {
expr_ensure_semicolon: true,
};
for (i, tl) in toplevels.iter().enumerate() {
if i > 0 {
self.add("\n");
}
tl.gen_mist(&mut ctx, self);
}
self.output.clone()
}
pub fn ensure_brackets(&mut self, ctx: &mut Context, stmt: &Box<Statement>) {
match &**stmt {
Statement::Block(_) => stmt.gen_mist(ctx, self),
_ => {
self.add("{");
self.indent += 1;
stmt.gen_mist(ctx, self);
self.indent -= 1;
self.add_indented("}");
}
}
}
pub fn ensure_brackets_expr(&mut self, ctx: &mut Context, expr: &Expression) {
match expr {
Expression::Statement(stmt) => self.ensure_brackets(ctx, stmt),
_ => {
self.add("{");
self.indent += 1;
expr.gen_mist(ctx, self);
self.indent -= 1;
self.add_indented("}");
}
}
}
}
pub trait GenMist {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen);
}
pub trait GetMist {
fn get_mist(&self) -> String;
}
impl GetMist for Path {
fn get_mist(&self) -> String {
self.0
.iter()
.map(Identifier::get_mist)
.collect::<Vec<String>>()
.join("::")
}
}
impl GetMist for Identifier {
fn get_mist(&self) -> String {
self.0.clone()
}
}
impl GetMist for Visibility {
fn get_mist(&self) -> String {
match self {
Visibility::Public => "pub ".to_string(),
Visibility::PublicTarget(path) => format!("pub({}) ", path.get_mist()),
Visibility::Private => "".to_string(),
}
}
}
impl GetMist for TypeExpr {
fn get_mist(&self) -> String {
match self {
Self::Path(path, generics) => {
if let Some(generics) = generics {
format!("{}{}", path.get_mist(), generics.get_mist())
} else {
path.get_mist()
}
}
Self::Lifetime(name) => format!("'{}", name.get_mist()),
Self::Tuple(types) => format!(
"({})",
types
.iter()
.map(|t| t.get_mist())
.collect::<Vec<_>>()
.join(", ")
),
Self::StaticFn(types, return_type) => {
if let Some(return_type) = return_type {
format!(
"fn({}) -> {}",
types
.iter()
.map(|t| t.get_mist())
.collect::<Vec<_>>()
.join(", "),
return_type.get_mist()
)
} else {
format!(
"fn({})",
types
.iter()
.map(|t| t.get_mist())
.collect::<Vec<_>>()
.join(", "),
)
}
}
Self::UnsafePtr { mutable, ty } => {
let mutable = if *mutable { "mut " } else { "const " };
format!("*{mutable}{}", ty.get_mist())
}
Self::Ref {
lifetime,
mutable,
ty,
} => {
let base = ty.get_mist();
if let Some(lifetime) = lifetime {
match lifetime {
Lifetime::Lifetime(v) => {
format!(
"{} &'{} {}",
base,
v.get_mist(),
if *mutable { "mut" } else { "" }
)
}
Lifetime::Unsafe => {
format!("{} *{}", base, if *mutable { "mut" } else { "const" })
}
}
} else if *mutable {
format!("{} &mut", base)
} else {
format!("{}&", base)
}
}
Self::Dyn(ty) => {
format!("dyn {}", ty.get_mist())
}
}
}
}
impl GetMist for ExprPath {
fn get_mist(&self) -> String {
self.0
.iter()
.map(ExprPathSegment::get_mist)
.collect::<Vec<_>>()
.join("::")
}
}
impl GetMist for ExprPathSegment {
fn get_mist(&self) -> String {
format!(
"{}{}",
self.ident.get_mist(),
self.generics
.as_ref()
.map(|v| format!("::{}", v.get_mist()))
.unwrap_or_default()
)
}
}
impl GetMist for Generics {
fn get_mist(&self) -> String {
if self.0.is_empty() {
String::new()
} else {
format!(
"<{}>",
self.0
.iter()
.map(Generic::get_mist)
.collect::<Vec<_>>()
.join(", ")
)
}
}
}
impl GetMist for Generic {
fn get_mist(&self) -> String {
match self {
Self::Lifetime(name) => format!("'{}", name.get_mist()),
Self::Type(ty) => ty.get_mist(),
}
}
}
impl GetMist for GenericsDecl {
fn get_mist(&self) -> String {
if self.0.is_empty() {
String::new()
} else {
format!(
"<{}>",
self.0
.iter()
.map(|v| v.get_mist())
.collect::<Vec<_>>()
.join(", ")
)
}
}
}
impl GetMist for GenericDecl {
fn get_mist(&self) -> String {
match self {
GenericDecl::Lifetime(name) => format!("'{}", name.get_mist()),
GenericDecl::Type(name, requirements) => {
name.get_mist()
+ &(if !requirements.is_empty() {
format!(
": {}",
requirements
.iter()
.map(TypeExpr::get_mist)
.collect::<Vec<_>>()
.join(" + ")
)
} else {
String::new()
})
}
}
}
}
impl<T: GetMist> GenMist for T {
fn gen_mist(&self, _: &mut Context, cg: &mut MistCodegen) {
cg.add(&self.get_mist());
}
}
impl<T: GenMist> GenMist for Spanned<T> {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
self.item.gen_mist(ctx, cg);
}
}
impl GenMist for Attribute {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
match self {
Self::Path(path) => cg.add(&path.get_mist()),
Self::NameValue { path, value } => {
cg.add(&format!("{} = ", path.get_mist()));
value.gen_mist(ctx, cg);
}
Self::List { path, items } => {
cg.add(&path.get_mist());
cg.add("(");
for (i, item) in items.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
item.gen_mist(ctx, cg);
}
cg.add(")");
}
}
}
}
impl GenMist for Pattern {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
match self {
Self::Etc => cg.add(".."),
Self::Literal(lit) => lit.gen_mist(ctx, cg),
Self::Path(mutable, path) => {
if *mutable {
cg.add("mut ");
}
cg.add(&path.get_mist())
}
Self::Struct(path, inner) => {
cg.add(&path.get_mist());
cg.add(" {");
for (idx, i) in inner.iter().enumerate() {
if idx > 0 {
cg.add(", ");
}
if let Some((name, pat)) = i {
cg.add(&name.get_mist());
if let Some(pat) = pat {
cg.add(": ");
pat.gen_mist(ctx, cg);
}
} else {
cg.add("..");
}
}
cg.add("}");
}
Self::NamedTuple(path, inner) => {
cg.add(&path.get_mist());
cg.add("(");
for (i, pat) in inner.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
pat.gen_mist(ctx, cg);
}
cg.add(")");
}
Self::Tuple(inner) => {
cg.add("(");
for (i, pat) in inner.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
pat.gen_mist(ctx, cg);
}
cg.add(")");
}
}
}
}
impl GenMist for Literal {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
match self {
Self::Int(n) => cg.add(&n.to_string()),
Self::Float(n) => cg.add(&format!("{n:?}")),
Self::Bool(b) => cg.add(&b.to_string()),
Self::String(s) => cg.add(&format!("\"{s}\"")),
Self::Tuple(values) => {
cg.add("(");
for (i, val) in values.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
val.gen_mist(ctx, cg);
}
cg.add(")");
}
}
}
}
+156
View File
@@ -0,0 +1,156 @@
use mist_parser::ast::*;
use crate::fmt::{Context, GenMist, GetMist, MistCodegen};
impl GenMist for Block {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
cg.addln("{");
cg.indent += 1;
for stmt in &self.statements {
ctx.expr_ensure_semicolon = true;
cg.add_indented("");
stmt.gen_mist(ctx, cg);
cg.addln("");
}
if let Some(soft_return) = &self.soft_return {
ctx.expr_ensure_semicolon = false;
cg.add_indented("");
soft_return.gen_mist(ctx, cg);
cg.addln("");
}
cg.indent -= 1;
cg.add_indented("}");
}
}
impl GenMist for Statement {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
match self {
Statement::UnsafeBlock(block) => {
cg.add("unsafe ");
block.gen_mist(ctx, cg);
}
Statement::Block(block) => block.gen_mist(ctx, cg),
Statement::VarDecl(VarDeclStmt { decl, init }) => {
if decl.type_.is_some() {
cg.add(&decl.type_.as_ref().unwrap().get_mist());
cg.add(" ");
decl.name.gen_mist(ctx, cg);
} else {
cg.add("let ");
decl.name.gen_mist(ctx, cg);
}
if let Some(init) = init {
cg.add(" = ");
init.gen_mist(ctx, cg);
}
}
Statement::Match(expr, match_items) => {
cg.add("match ");
expr.gen_mist(ctx, cg);
cg.add(" {");
if !match_items.is_empty() {
cg.addln("");
cg.indent += 1;
for match_item in match_items {
let MatchItem(pat, body) = &match_item.item;
cg.add_indented("");
for (i, p) in pat.iter().enumerate() {
if i > 0 {
cg.add(" | ");
}
p.gen_mist(ctx, cg);
}
cg.add(" => ");
if body.is_block() {
body.gen_mist(ctx, cg);
cg.addln("");
} else {
body.gen_mist(ctx, cg);
cg.addln(",");
}
}
cg.indent -= 1;
cg.add_indented("}");
} else {
cg.add("}");
}
}
Statement::If {
initial,
else_if,
else_branch,
} => {
cg.add("if ");
ctx.expr_ensure_semicolon = false;
initial.condition.gen_mist(ctx, cg);
cg.add(" ");
initial.body.gen_mist(ctx, cg);
for else_if_branch in else_if {
cg.add(" else if ");
ctx.expr_ensure_semicolon = false;
else_if_branch.condition.gen_mist(ctx, cg);
cg.add(" ");
else_if_branch.body.gen_mist(ctx, cg);
}
if let Some(else_br) = else_branch {
cg.add(" else ");
else_br.gen_mist(ctx, cg);
}
}
Statement::While(StatementBranch { condition, body }) => {
cg.add("while ");
condition.gen_mist(ctx, cg);
cg.add(" ");
body.gen_mist(ctx, cg);
}
Statement::Loop(body) => {
cg.add("loop ");
body.gen_mist(ctx, cg);
}
Statement::CStyleFor {
init,
condition,
update,
body,
} => {
cg.add("for (");
ctx.expr_ensure_semicolon = true;
init.gen_mist(ctx, cg);
cg.add(" ");
ctx.expr_ensure_semicolon = false;
condition.gen_mist(ctx, cg);
cg.add(" ");
update.gen_mist(ctx, cg);
cg.add(") ");
body.gen_mist(ctx, cg);
}
Statement::For {
pattern,
iterator,
body,
} => {
cg.add("for ");
pattern.gen_mist(ctx, cg);
cg.add(" in ");
iterator.gen_mist(ctx, cg);
cg.add(" ");
body.gen_mist(ctx, cg);
}
Statement::Return(expr) => {
cg.add("return");
if let Some(expr) = expr {
cg.add(" ");
expr.gen_mist(ctx, cg);
}
}
Statement::Break => cg.add("break"),
Statement::Continue => cg.add("continue"),
}
}
}
+316
View File
@@ -0,0 +1,316 @@
use mist_parser::ast::*;
use crate::fmt::{Context, GenMist, GetMist, MistCodegen};
impl GenMist for ImplDecl {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
cg.add_indented("impl");
let generics = self.generics.get_mist();
if !generics.is_empty() {
cg.add(&generics);
cg.add(" ");
}
cg.add(&self.target.get_mist());
if let Some(trait_) = &self.trait_ {
cg.add(" for ");
cg.add(&trait_.get_mist());
}
cg.addln(" {");
cg.indent += 1;
for method in &self.methods {
method.gen_mist(ctx, cg);
}
cg.indent -= 1;
cg.add_indentedln("}");
}
}
impl GenMist for FunctionDecl {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
cg.add_indented(&self.visibility.get_mist());
if self.return_type.is_none() {
cg.add("void ");
} else {
cg.add(&self.return_type.as_ref().unwrap().get_mist());
cg.add(" ");
}
cg.add(&self.name.get_mist());
cg.add(&self.generics.get_mist());
cg.add("(");
if let Some((is_ref, lifetime, is_mut)) = &self.self_param {
if *is_ref {
cg.add("&");
}
if let Some(lifetime) = lifetime {
cg.add(&format!("'{} ", lifetime.0));
}
if *is_mut {
cg.add("mut ");
}
cg.add("self");
if !self.params.0.is_empty() {
cg.add(", ");
}
}
for (i, param) in self.params.0.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
param.gen_mist(ctx, cg);
}
cg.add(")");
if let Some(override_spec) = &self.is_override {
cg.add(" override");
if let Some(path) = &override_spec.0 {
cg.add("(");
cg.add(&path.get_mist());
cg.add(")");
}
}
if let Some(body) = &self.body {
cg.add(" ");
body.gen_mist(ctx, cg);
} else {
cg.addln(";");
}
}
}
impl GenMist for ParamList {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
for (i, param) in self.0.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
param.gen_mist(ctx, cg);
}
}
}
impl GenMist for VarDecl {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
if let Some(type_) = &self.type_ {
cg.add(&type_.get_mist());
cg.add(" ");
}
self.name.gen_mist(ctx, cg);
}
}
impl GetMist for FieldDecl {
fn get_mist(&self) -> String {
format!(
"{}{} {}",
self.visibility.get_mist(),
self.type_.get_mist(),
self.name.get_mist(),
)
}
}
impl GetMist for EnumItem {
fn get_mist(&self) -> String {
match self {
Self::Named(id) => id.get_mist(),
Self::Struct(id, s) => format!(
"{} {{{}}}",
id.get_mist(),
s.iter()
.map(|field| format!("{}: {}", field.name.get_mist(), field.type_.get_mist()))
.collect::<Vec<_>>()
.join(", ")
),
Self::Tuple(id, t) => format!(
"{}({})",
id.get_mist(),
t.iter()
.map(TypeExpr::get_mist)
.collect::<Vec<_>>()
.join(", ")
),
}
}
}
impl GenMist for TopLevel {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
if let TopLevelKind::ModAttribute = self.0.item {
for attr in &self.1 {
cg.add("#![");
attr.gen_mist(ctx, cg);
cg.addln("]");
}
} else {
for attr in &self.1 {
cg.add("#[");
attr.gen_mist(ctx, cg);
cg.addln("]");
}
}
self.0.gen_mist(ctx, cg);
}
}
impl GenMist for TopLevelKind {
fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) {
match self {
Self::ModAttribute => {}
Self::Import(vis, path) => {
cg.addln(&format!("{}use {};", vis.get_mist(), path.get_mist()))
}
Self::DeclareModule(vis, name) => {
cg.addln(&format!("{}module {};", vis.get_mist(), name.get_mist()))
}
Self::FunctionDecl(decl) => decl.gen_mist(ctx, cg),
Self::ImplDecl(impl_) => impl_.gen_mist(ctx, cg),
Self::StructDecl {
visibility,
name,
generics,
fields,
} => {
cg.add(&format!(
"{}struct {}{} {{",
visibility.get_mist(),
name.get_mist(),
generics.get_mist()
));
if !fields.is_empty() {
cg.addln("");
cg.indent += 1;
for field in fields {
cg.add_indentedln(&format!("{},", field.item.get_mist()));
}
cg.indent -= 1;
cg.add_indented("}");
} else {
cg.add("}");
}
cg.addln("");
}
Self::EnumDecl {
visibility,
name,
generics,
fields,
} => {
cg.add(&format!(
"{}enum {}{} {{",
visibility.get_mist(),
name.get_mist(),
generics.get_mist()
));
if !fields.is_empty() {
cg.addln("");
cg.indent += 1;
for field in fields {
cg.add_indentedln(&format!("{},", field.item.get_mist()));
}
cg.indent -= 1;
cg.add_indented("}");
} else {
cg.add("}");
}
cg.addln("");
}
Self::TraitDecl {
visibility,
name,
generics,
requirements,
items,
} => {
cg.add(&format!(
"{}trait {}{}",
visibility.get_mist(),
name.get_mist(),
generics.get_mist()
));
if !requirements.is_empty() {
cg.add(": ");
cg.add(
&requirements
.iter()
.map(TypeExpr::get_mist)
.collect::<Vec<_>>()
.join(" + "),
);
}
cg.addln(" {");
cg.indent += 1;
for item in items {
item.gen_mist(ctx, cg);
}
cg.indent -= 1;
cg.add_indentedln("}");
}
Self::ClassDecl {
visibility,
name,
generics,
inherits,
fields,
constructor,
items,
} => {
cg.add(&format!(
"{}class {}{}",
visibility.get_mist(),
name.get_mist(),
generics.get_mist()
));
if let Some(inherits) = inherits {
cg.add(" : ");
cg.add(&inherits.get_mist());
}
cg.addln(" {");
cg.indent += 1;
for field in fields {
cg.add_indented(&field.item.decl.get_mist());
if let Some(init) = &field.item.init {
cg.add(" = ");
init.gen_mist(ctx, cg);
}
cg.addln(";");
}
if let Some(constructor) = constructor {
cg.add_indented(&constructor.item.visibility.get_mist());
cg.add("constructor");
cg.add(&constructor.item.generics.get_mist());
cg.add("(");
for (i, param) in constructor.item.params.0.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
param.gen_mist(ctx, cg);
}
cg.add(") ");
constructor.item.body.gen_mist(ctx, cg);
cg.addln("");
}
for item in items {
match item {
ClassItem::Method(method) => method.gen_mist(ctx, cg),
ClassItem::ImplDecl(impl_) => impl_.gen_mist(ctx, cg),
}
}
cg.indent -= 1;
cg.add_indentedln("}");
}
}
}
}