312 lines
8.1 KiB
Rust
312 lines
8.1 KiB
Rust
pub mod class_decl;
|
|
pub mod expr;
|
|
pub mod statement;
|
|
pub mod top_level;
|
|
|
|
use std::collections::HashSet;
|
|
|
|
use mist_parser::{
|
|
ast::*,
|
|
rev_mapper::{MistMap, RustMap},
|
|
};
|
|
|
|
pub struct Context {
|
|
pub expr_ensure_semicolon: bool,
|
|
pub expr_super: Option<ExprPath>,
|
|
}
|
|
|
|
pub trait GenRust {
|
|
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen);
|
|
}
|
|
|
|
pub trait GetRust {
|
|
fn get_rust(&self) -> String;
|
|
fn get_rust_ctx(&self, cx: &mut Context) -> String {
|
|
let _ = cx;
|
|
self.get_rust()
|
|
}
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct RustCodegen {
|
|
output: String,
|
|
indent: usize,
|
|
mapping: HashSet<(RustMap, MistMap)>,
|
|
position: RustMap,
|
|
}
|
|
|
|
impl RustCodegen {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
output: String::new(),
|
|
indent: 0,
|
|
mapping: HashSet::new(),
|
|
position: RustMap(0, 0),
|
|
}
|
|
}
|
|
|
|
fn indent_str(&self) -> String {
|
|
" ".repeat(self.indent)
|
|
}
|
|
|
|
fn add(&mut self, s: &str) {
|
|
for c in s.chars() {
|
|
match c {
|
|
'\n' => {
|
|
self.position.0 += 1;
|
|
self.position.1 = 0;
|
|
}
|
|
_ => {
|
|
self.position.1 += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
self.output.push_str(s);
|
|
}
|
|
|
|
fn addln(&mut self, s: &str) {
|
|
self.add(s);
|
|
self.add("\n");
|
|
}
|
|
|
|
fn add_indented(&mut self, s: &str) {
|
|
let line = format!("{}{}", self.indent_str(), s);
|
|
self.add(&line);
|
|
}
|
|
|
|
fn add_indentedln(&mut self, s: &str) {
|
|
let line = format!("{}{}\n", self.indent_str(), s);
|
|
self.add(&line);
|
|
}
|
|
|
|
pub fn generate(&mut self, toplevels: Vec<TopLevel>) -> String {
|
|
let mut ctx = Context {
|
|
expr_ensure_semicolon: true,
|
|
expr_super: None,
|
|
};
|
|
|
|
for tl in toplevels {
|
|
tl.gen_rust(&mut ctx, self);
|
|
}
|
|
|
|
self.output.clone()
|
|
}
|
|
|
|
pub fn ensure_brackets(&mut self, ctx: &mut Context, stmt: &Box<Statement>) {
|
|
match &**stmt {
|
|
Statement::Block(_) => stmt.gen_rust(ctx, self),
|
|
_ => {
|
|
self.add("{");
|
|
self.indent += 1;
|
|
stmt.gen_rust(ctx, self);
|
|
self.indent -= 1;
|
|
self.add("}");
|
|
}
|
|
}
|
|
}
|
|
|
|
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_rust(ctx, self);
|
|
self.indent -= 1;
|
|
self.add("}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GenRust for Attribute {
|
|
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
|
|
match self {
|
|
Self::Path(path) => cg.add(&path.get_rust()),
|
|
Self::NameValue { path, value } => {
|
|
cg.add(&format!("{} = ", path.get_rust()));
|
|
value.gen_rust(ctx, cg);
|
|
}
|
|
Self::List { path, items } => {
|
|
cg.add(&path.get_rust());
|
|
cg.add("(");
|
|
for (i, item) in items.iter().enumerate() {
|
|
if i > 0 {
|
|
cg.add(", ");
|
|
}
|
|
|
|
item.gen_rust(ctx, cg);
|
|
}
|
|
cg.add(")");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: GetRust> GenRust for T {
|
|
fn gen_rust(&self, _: &mut Context, cg: &mut RustCodegen) {
|
|
cg.add(&self.get_rust());
|
|
}
|
|
}
|
|
|
|
impl<T: GenRust> GenRust for Spanned<T> {
|
|
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
|
|
cg.mapping
|
|
.insert((cg.position, MistMap(self.line, self.column)));
|
|
|
|
self.item.gen_rust(ctx, cg);
|
|
}
|
|
}
|
|
|
|
impl GetRust for Path {
|
|
fn get_rust(&self) -> String {
|
|
self.0
|
|
.iter()
|
|
.map(Identifier::get_rust)
|
|
.collect::<Vec<String>>()
|
|
.join("::")
|
|
}
|
|
}
|
|
|
|
impl GetRust for Visibility {
|
|
fn get_rust(&self) -> String {
|
|
match self {
|
|
Visibility::Public => "pub ".to_string(),
|
|
Visibility::PublicTarget(path) => format!("pub({}) ", path.get_rust()),
|
|
Visibility::Private => "".to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GetRust for Identifier {
|
|
fn get_rust(&self) -> String {
|
|
self.0.clone()
|
|
}
|
|
}
|
|
|
|
impl GetRust for TypeExpr {
|
|
fn get_rust(&self) -> String {
|
|
match self {
|
|
Self::Path(path, generics) => {
|
|
if let Some(generics) = generics {
|
|
format!("{}{}", path.get_rust(), generics.get_rust())
|
|
} else {
|
|
path.get_rust()
|
|
}
|
|
}
|
|
Self::Lifetime(name) => format!("'{}", name.get_rust()),
|
|
Self::Tuple(types) => format!(
|
|
"({})",
|
|
types
|
|
.into_iter()
|
|
.map(|t| t.get_rust())
|
|
.collect::<Vec<_>>()
|
|
.join(", ")
|
|
),
|
|
Self::StaticFn(types, return_type) => {
|
|
if let Some(return_type) = return_type {
|
|
format!(
|
|
"fn({}) -> {}",
|
|
types
|
|
.into_iter()
|
|
.map(|t| t.get_rust())
|
|
.collect::<Vec<_>>()
|
|
.join(", "),
|
|
return_type.get_rust()
|
|
)
|
|
} else {
|
|
format!(
|
|
"fn({})",
|
|
types
|
|
.into_iter()
|
|
.map(|t| t.get_rust())
|
|
.collect::<Vec<_>>()
|
|
.join(", "),
|
|
)
|
|
}
|
|
}
|
|
|
|
Self::UnsafePtr { mutable, ty } => {
|
|
let mutable = if *mutable { "mut " } else { "const " };
|
|
format!("*{mutable}{}", ty.get_rust())
|
|
}
|
|
|
|
Self::Ref {
|
|
lifetime,
|
|
mutable,
|
|
ty,
|
|
} => {
|
|
let mutable = if *mutable { "mut " } else { "" };
|
|
|
|
if let Some(lifetime) = lifetime {
|
|
format!("&'{} {mutable}{}", lifetime.get_rust(), ty.get_rust())
|
|
} else {
|
|
format!("&{mutable}{}", ty.get_rust())
|
|
}
|
|
}
|
|
|
|
Self::Dyn(ty) => {
|
|
format!("dyn {}", ty.get_rust())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GenRust for Pattern {
|
|
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
|
|
match self {
|
|
Self::Etc => cg.add(".."),
|
|
Self::Literal(lit) => lit.gen_rust(ctx, cg),
|
|
Self::Path(mutable, path) => {
|
|
if *mutable {
|
|
cg.add("mut ");
|
|
};
|
|
|
|
cg.add(&path.get_rust())
|
|
}
|
|
Self::Struct(path, inner) => {
|
|
cg.add(&path.get_rust());
|
|
cg.add(" {");
|
|
|
|
for (idx, i) in inner.iter().enumerate() {
|
|
if idx > 0 {
|
|
cg.add(", ");
|
|
}
|
|
|
|
if let Some((name, pat)) = i {
|
|
cg.add(&name.get_rust());
|
|
if let Some(pat) = pat {
|
|
cg.add(": ");
|
|
pat.gen_rust(ctx, cg);
|
|
}
|
|
} else {
|
|
cg.add("..");
|
|
}
|
|
}
|
|
|
|
cg.add("}");
|
|
}
|
|
|
|
Self::NamedTuple(path, inner) => {
|
|
cg.add(&path.get_rust());
|
|
cg.add(" (");
|
|
for pat in inner {
|
|
pat.gen_rust(ctx, cg);
|
|
cg.add(",");
|
|
}
|
|
cg.add(")");
|
|
}
|
|
|
|
Self::Tuple(inner) => {
|
|
cg.add("(");
|
|
for pat in inner {
|
|
pat.gen_rust(ctx, cg);
|
|
cg.add(",");
|
|
}
|
|
cg.add(")");
|
|
}
|
|
}
|
|
}
|
|
}
|