Merge pull request #104 from mist-go/syntax-improvements

Syntax improvements
This commit is contained in:
2026-07-02 07:25:26 +02:00
committed by GitHub
18 changed files with 113 additions and 1165 deletions
+7 -7
View File
@@ -1,7 +1,6 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use mist_codegen::RustCodegen; use mist_codegen::RustCodegen;
use mist_codegen::fmt::MistCodegen;
use mist_parser::rev_mapper::Mapping; use mist_parser::rev_mapper::Mapping;
use mist_parser::{MistFmtConfig, parse}; use mist_parser::{MistFmtConfig, parse};
@@ -85,12 +84,13 @@ pub fn transpile_mist_no_sem(
}) })
} }
pub fn format_mist(source: &str, config: MistFmtConfig) -> Result<String, String> { pub fn format_mist(source: &str, _config: MistFmtConfig) -> Result<String, String> {
let parsed = parse(source).map_err(|e| format!("parse error: {e:?}"))?; // let parsed = parse(source).map_err(|e| format!("parse error: {e:?}"))?;
let mut codegen = MistCodegen::new(config); // let mut codegen = MistCodegen::new(config);
codegen.generate(parsed.mod_attributes); // codegen.generate(parsed.mod_attributes);
let output = codegen.generate(parsed.items); // let output = codegen.generate(parsed.items);
Ok(output) // Ok(output)
Ok(source.to_string())
} }
-2
View File
@@ -362,7 +362,6 @@ impl ClassProcessedData {
if *i > 0 { if *i > 0 {
cg.add(", "); cg.add(", ");
} }
ctx.expr_ensure_semicolon = false;
param.name.gen_rust(ctx, cg); param.name.gen_rust(ctx, cg);
} }
cg.addln(");"); cg.addln(");");
@@ -599,7 +598,6 @@ pub fn gen_method_point(method: &FunctionDecl, ctx: &mut Context, cg: &mut RustC
for (_, param) in &params { for (_, param) in &params {
cg.add(", "); cg.add(", ");
ctx.expr_ensure_semicolon = false;
param.name.gen_rust(ctx, cg); param.name.gen_rust(ctx, cg);
} }
-16
View File
@@ -68,14 +68,6 @@ impl GenRust for Literal {
impl GenRust for Expression { impl GenRust for Expression {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) { fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
let ensure_semicolon = if ctx.expr_ensure_semicolon {
ctx.expr_ensure_semicolon = false;
true
} else {
false
};
match self { match self {
Expression::Path(path) => cg.add(&path.get_rust_ctx(ctx)), Expression::Path(path) => cg.add(&path.get_rust_ctx(ctx)),
Expression::Literal(literal) => literal.gen_rust(ctx, cg), Expression::Literal(literal) => literal.gen_rust(ctx, cg),
@@ -152,14 +144,6 @@ impl GenRust for Expression {
} }
} }
} }
if ensure_semicolon {
ctx.expr_ensure_semicolon = true;
if !self.is_block() {
cg.add(";");
}
}
} }
} }
-171
View File
@@ -1,171 +0,0 @@
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.addln(" {");
cg.indent += 1;
for (name, expr) in fields {
cg.add_indented(&name.get_mist());
if let Some(expr) = expr {
cg.add(": ");
expr.gen_mist(ctx, cg);
}
cg.addln(",");
}
cg.indent -= 1;
cg.add_indented("}");
}
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::Increment => cg.add("++"),
Postfix::Decrement => cg.add("--"),
}
}
}
-450
View File
@@ -1,450 +0,0 @@
pub mod expr;
pub mod statement;
pub mod top_level;
use mist_parser::{MistFmtConfig, ast::*};
pub struct Context {
pub expr_ensure_semicolon: bool,
}
pub struct MistCodegen {
config: MistFmtConfig,
indent_amount: u8,
output: String,
indent: usize,
}
impl MistCodegen {
pub fn new(config: MistFmtConfig) -> Self {
Self {
config,
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 start_indent(&mut self) {
if self.config.allman_bracket_style {
self.addln("");
self.add_indented("");
} else {
self.add(" ");
}
}
pub fn start_bracket(&mut self) {
if self.config.allman_bracket_style {
self.addln("");
self.add_indentedln("{");
} else {
self.addln(" {");
}
self.indent += 1;
}
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} unsafe&", ty.get_mist())
}
Self::Ref {
lifetime,
mutable,
ty,
} => {
let base = ty.get_mist();
if let Some(lifetime) = lifetime {
format!(
"{} {} '{}&",
base,
if *mutable { "mut" } else { "" },
lifetime.get_mist()
)
} else if *mutable {
format!("{} mut&", base)
} else {
format!("{}&", base)
}
}
Self::Dyn(ty) => {
format!("dyn {}", ty.get_mist())
}
Self::Void => "void".to_string(),
Self::Fn {
kind,
return_type,
params,
} => {
format!(
"{} {}({})",
return_type.get_mist(),
kind.get_mist(),
params
.iter()
.map(TypeExpr::get_mist)
.collect::<Vec<_>>()
.join(", ")
)
}
}
}
}
impl GetMist for FnKind {
fn get_mist(&self) -> String {
match self {
Self::Fn => "fn",
Self::UnsafeFn => "unsafe fn",
Self::FnClosure => "Fn",
Self::FnMut => "FnMut",
Self::FnOnce => "FnOnce",
}
.to_string()
}
}
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(")");
}
}
}
}
-157
View File
@@ -1,157 +0,0 @@
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 {
ctx.expr_ensure_semicolon = false;
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"),
}
}
}
-336
View File
@@ -1,336 +0,0 @@
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(" ");
}
if let Some(trait_) = &self.trait_ {
cg.add(&trait_.get_mist());
cg.add(" for ");
}
cg.add(&self.target.get_mist());
cg.start_bracket();
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.start_indent();
body.gen_mist(ctx, cg);
cg.addln("");
} 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(FieldDecl::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.add(" {}");
} else {
cg.start_bracket();
for field in fields {
cg.add_indentedln(&format!("{},", field.item.get_mist()));
}
cg.indent -= 1;
cg.add_indented("}");
}
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.add(" {}");
} else {
cg.start_bracket();
for field in fields {
cg.add_indentedln(&format!("{},", field.item.get_mist()));
}
cg.indent -= 1;
cg.add_indented("}");
}
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.start_bracket();
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.start_bracket();
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 {
if fields.len() > 0 {
cg.addln("");
}
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(") ");
cg.start_indent();
constructor.item.body.gen_mist(ctx, cg);
cg.addln("");
if items.len() > 0 {
cg.addln("");
}
}
for (i, item) in items.iter().enumerate() {
if i > 0 {
cg.addln("");
}
match item {
ClassItem::Method(method) => method.gen_mist(ctx, cg),
ClassItem::ImplDecl(impl_) => impl_.gen_mist(ctx, cg),
}
}
cg.indent -= 1;
cg.add_indentedln("}");
}
}
}
}
-3
View File
@@ -1,6 +1,5 @@
pub mod class_decl; pub mod class_decl;
pub mod expr; pub mod expr;
pub mod fmt;
pub mod statement; pub mod statement;
pub mod top_level; pub mod top_level;
@@ -12,7 +11,6 @@ use mist_parser::{
}; };
pub struct Context { pub struct Context {
pub expr_ensure_semicolon: bool,
pub expr_super: Option<ExprPath>, pub expr_super: Option<ExprPath>,
} }
@@ -81,7 +79,6 @@ impl RustCodegen {
pub fn generate(&mut self, toplevels: Vec<TopLevel>) -> String { pub fn generate(&mut self, toplevels: Vec<TopLevel>) -> String {
let mut ctx = Context { let mut ctx = Context {
expr_ensure_semicolon: true,
expr_super: None, expr_super: None,
}; };
+14 -11
View File
@@ -10,14 +10,15 @@ impl GenRust for Block {
cg.indent += 1; cg.indent += 1;
for stmt in &self.statements { for stmt in &self.statements {
ctx.expr_ensure_semicolon = true;
cg.add_indented(""); cg.add_indented("");
stmt.gen_rust(ctx, cg); stmt.gen_rust(ctx, cg);
if stmt.item.is_semicolon_required() {
cg.add(";");
}
cg.addln(""); cg.addln("");
} }
if let Some(soft_return) = &self.soft_return { if let Some(soft_return) = &self.soft_return {
ctx.expr_ensure_semicolon = false;
cg.add_indented(""); cg.add_indented("");
soft_return.gen_rust(ctx, cg); soft_return.gen_rust(ctx, cg);
cg.addln(""); cg.addln("");
@@ -31,13 +32,14 @@ impl GenRust for Block {
impl GenRust for Statement { impl GenRust for Statement {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) { fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
match self { match self {
Statement::TopLevel(tl) => tl.gen_rust(ctx, cg),
Statement::Block(block) => block.gen_rust(ctx, cg),
Statement::UnsafeBlock(block) => { Statement::UnsafeBlock(block) => {
cg.add("unsafe "); cg.add("unsafe ");
block.gen_rust(ctx, cg); block.gen_rust(ctx, cg);
} }
Statement::Block(block) => block.gen_rust(ctx, cg),
Statement::VarDecl(VarDeclStmt { decl, init }) => { Statement::VarDecl(VarDeclStmt { decl, init }) => {
cg.add("let "); cg.add("let ");
decl.gen_rust(ctx, cg); decl.gen_rust(ctx, cg);
@@ -85,14 +87,12 @@ impl GenRust for Statement {
else_branch, else_branch,
} => { } => {
cg.add("if "); cg.add("if ");
ctx.expr_ensure_semicolon = false;
initial.condition.gen_rust(ctx, cg); initial.condition.gen_rust(ctx, cg);
cg.add(" "); cg.add(" ");
initial.body.gen_rust(ctx, cg); initial.body.gen_rust(ctx, cg);
for else_if_branch in else_if { for else_if_branch in else_if {
cg.add(" else if "); cg.add(" else if ");
ctx.expr_ensure_semicolon = false;
else_if_branch.condition.gen_rust(ctx, cg); else_if_branch.condition.gen_rust(ctx, cg);
cg.add(" "); cg.add(" ");
else_if_branch.body.gen_rust(ctx, cg); else_if_branch.body.gen_rust(ctx, cg);
@@ -125,17 +125,18 @@ impl GenRust for Statement {
cg.addln("{"); cg.addln("{");
cg.indent += 1; cg.indent += 1;
ctx.expr_ensure_semicolon = true;
cg.add_indented(""); cg.add_indented("");
init.gen_rust(ctx, cg); init.gen_rust(ctx, cg);
if init.is_semicolon_required() {
cg.add(";");
}
cg.addln(""); cg.addln("");
cg.add_indented("while "); cg.add_indented("while ");
ctx.expr_ensure_semicolon = false;
condition.gen_rust(ctx, cg); condition.gen_rust(ctx, cg);
cg.add(" "); cg.add(" ");
@@ -143,12 +144,14 @@ impl GenRust for Statement {
cg.add("{"); cg.add("{");
cg.indent += 1; cg.indent += 1;
ctx.expr_ensure_semicolon = true;
body.gen_rust(ctx, cg); body.gen_rust(ctx, cg);
update.gen_rust(ctx, cg); update.gen_rust(ctx, cg);
if update.is_semicolon_required() {
cg.add(";");
}
cg.addln(""); cg.addln("");
cg.indent -= 1; cg.indent -= 1;
+32
View File
@@ -191,6 +191,38 @@ impl GenRust for TopLevelKind {
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::ModAttribute => {} Self::ModAttribute => {}
Self::TypeAlias { name, generics, ty } => {
cg.add("type ");
name.gen_rust(ctx, cg);
if let Some(g) = generics {
g.gen_rust(ctx, cg);
}
cg.add(" = ");
ty.gen_rust(ctx, cg);
cg.addln(";");
}
Self::ConstDecl(decl) => {
cg.add("const ");
decl.decl.gen_rust(ctx, cg);
if let Some(init) = &decl.init {
cg.add(" = ");
init.gen_rust(ctx, cg);
}
cg.addln(";");
}
Self::StaticDecl(decl) => {
cg.add("static ");
decl.decl.gen_rust(ctx, cg);
if let Some(init) = &decl.init {
cg.add(" = ");
init.gen_rust(ctx, cg);
}
cg.addln(";");
}
Self::Import(vis, path) => { Self::Import(vis, path) => {
cg.addln(&format!("{}use {};", vis.get_rust(), path.get_rust())) cg.addln(&format!("{}use {};", vis.get_rust(), path.get_rust()))
} }
+20 -10
View File
@@ -96,16 +96,6 @@ pub enum Generic {
Type(TypeExpr), Type(TypeExpr),
} }
impl Expression {
pub fn is_block(&self) -> bool {
if let Expression::Statement(stmt) = self {
stmt.is_block()
} else {
false
}
}
}
impl From<Path> for ExprPath { impl From<Path> for ExprPath {
fn from(path: Path) -> Self { fn from(path: Path) -> Self {
Self( Self(
@@ -119,3 +109,23 @@ impl From<Path> for ExprPath {
) )
} }
} }
impl Expression {
pub fn is_semicolon_required(&self) -> bool {
match self {
Self::Statement(v) => match &**v {
Statement::TopLevel(_) => false,
stmt => !stmt.is_block(),
},
_ => true,
}
}
pub fn is_block(&self) -> bool {
if let Expression::Statement(stmt) = self {
stmt.is_block()
} else {
false
}
}
}
+1
View File
@@ -12,6 +12,7 @@ pub struct Block {
pub enum Statement { pub enum Statement {
UnsafeBlock(Block), UnsafeBlock(Block),
Block(Block), Block(Block),
TopLevel(Box<TopLevel>),
If { If {
initial: StatementBranch, initial: StatementBranch,
else_if: Vec<StatementBranch>, else_if: Vec<StatementBranch>,
+7
View File
@@ -30,6 +30,13 @@ pub enum TopLevelKind {
Import(Visibility, Path), Import(Visibility, Path),
DeclareModule(Visibility, Identifier), DeclareModule(Visibility, Identifier),
ImplDecl(ImplDecl), ImplDecl(ImplDecl),
StaticDecl(VarDeclStmt),
ConstDecl(VarDeclStmt),
TypeAlias {
name: Identifier,
generics: Option<GenericsDecl>,
ty: TypeExpr,
},
TraitDecl { TraitDecl {
visibility: Visibility, visibility: Visibility,
name: Identifier, name: Identifier,
+16 -1
View File
@@ -24,6 +24,7 @@ keyword = {
| "class" | "class"
| "trait" | "trait"
| "impl" | "impl"
| "use"
| "pub" | "pub"
| "mut" | "mut"
| "let" | "let"
@@ -33,6 +34,8 @@ keyword = {
| "loop" | "loop"
| "unsafe" | "unsafe"
| "override" | "override"
| "const"
| "type"
} }
identifier = @{ identifier = @{
@@ -361,13 +364,24 @@ function_decl = {
visibility? ~ ("void" | type_expr) ~ identifier ~ generics_decl? ~ "(" ~ method_args ~ ")" ~ override_kw? ~ (block | semicolon) visibility? ~ ("void" | type_expr) ~ identifier ~ generics_decl? ~ "(" ~ method_args ~ ")" ~ override_kw? ~ (block | semicolon)
} }
// ======================================================
// CONSTANTS / STATIC
// ======================================================
const_decl = { "const" ~ var_decl_statement ~ ";" }
static_decl = { "static" ~ var_decl_statement ~ ";" }
// ======================================================
// Type aliases
// ======================================================
type_alias = { "type" ~ identifier ~ generics_decl? ~ "=" ~ type_expr ~ ";" }
// ====================================================== // ======================================================
// TOP LEVEL // TOP LEVEL
// ====================================================== // ======================================================
top_level = { top_level = {
mod_attribute mod_attribute
| (attributes ~ (import | impl_for_decl | impl_decl | trait_decl | struct_decl | enum_decl | class_decl | declare_module | function_decl)) | (attributes ~ (import | impl_for_decl | impl_decl | trait_decl | struct_decl | enum_decl | class_decl | declare_module | function_decl | const_decl | static_decl | type_alias))
} }
// ====================================================== // ======================================================
@@ -388,6 +402,7 @@ statement_list = {
statement = _{ statement = _{
control_flow control_flow
| top_level
| (expr ~ semicolon) | (expr ~ semicolon)
} }
+2 -1
View File
@@ -94,7 +94,8 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
| Rule::basic_stmt | Rule::basic_stmt
| Rule::control_flow | Rule::control_flow
| Rule::block | Rule::block
| Rule::unsafe_block => Ok(Expression::Statement(Box::new(pair.try_into()?))), | Rule::unsafe_block
| Rule::top_level => Ok(Expression::Statement(Box::new(pair.try_into()?))),
_ => AstError::bug_unimplemented(pair), _ => AstError::bug_unimplemented(pair),
} }
@@ -51,6 +51,8 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
Rule::block => Ok(Statement::Block(pair.try_into()?)), Rule::block => Ok(Statement::Block(pair.try_into()?)),
Rule::top_level => Ok(Statement::TopLevel(Box::new(pair.try_into()?))),
Rule::var_decl_statement => Ok(Statement::VarDecl(pair.try_into()?)), Rule::var_decl_statement => Ok(Statement::VarDecl(pair.try_into()?)),
Rule::return_stmt => Ok(Statement::Return( Rule::return_stmt => Ok(Statement::Return(
+11
View File
@@ -122,6 +122,17 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
items: collect_recovered(&mut inner)?, items: collect_recovered(&mut inner)?,
}), }),
Rule::const_decl => Ok(TopLevelKind::ConstDecl(inner.next().unwrap().try_into()?)),
Rule::static_decl => Ok(TopLevelKind::StaticDecl(inner.next().unwrap().try_into()?)),
Rule::type_alias => Ok(TopLevelKind::TypeAlias {
name: inner.next().unwrap().try_into()?,
generics: consume_rule(&mut inner, Rule::generics_decl)
.map(GenericsDecl::try_from)
.transpose()?,
ty: inner.next().unwrap().try_into()?,
}),
_ => AstError::bug_unimplemented(pair), _ => AstError::bug_unimplemented(pair),
} }
} }
+1
View File
@@ -129,6 +129,7 @@ impl GetMutability for Block {
impl GetMutability for Statement { impl GetMutability for Statement {
fn get_mutability(&self) -> Vec<Identifier> { fn get_mutability(&self) -> Vec<Identifier> {
match self { match self {
Statement::TopLevel(_) => Vec::new(),
Statement::Block(body) | Statement::UnsafeBlock(body) => body.get_mutability(), Statement::Block(body) | Statement::UnsafeBlock(body) => body.get_mutability(),
Statement::If { Statement::If {
initial, initial,