Merge pull request #17 from mist-go/types-and-refactor
Types and refactor
This commit is contained in:
+30
-8
@@ -3,16 +3,33 @@ use std::collections::HashMap;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct ParamList(pub HashMap<String, (bool, TypeExpr)>);
|
||||
pub struct FieldList(pub HashMap<String, (bool, TypeExpr)>);
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct ParamList(pub Vec<VarDecl>);
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct Block(pub Vec<Statement>);
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub enum TypeExpr {
|
||||
Identifier(String),
|
||||
pub enum TypePostfix {
|
||||
Ref,
|
||||
RefMut,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub enum TypeExprKind {
|
||||
Path(StaticPath),
|
||||
PathParams(StaticPath, Vec<TypeExpr>),
|
||||
Tuple(Vec<TypeExpr>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct TypeExpr(pub TypeExprKind, pub Vec<TypePostfix>);
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct StaticPath(pub Vec<String>);
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub enum BinaryOp {
|
||||
Plus,
|
||||
@@ -34,13 +51,13 @@ pub enum TopLevel {
|
||||
StructDecl {
|
||||
export: bool,
|
||||
name: String,
|
||||
fields: ParamList,
|
||||
fields: FieldList,
|
||||
},
|
||||
FunctionDecl {
|
||||
export: bool,
|
||||
name: String,
|
||||
params: ParamList,
|
||||
return_type: Option<TypeExpr>,
|
||||
return_type: TypeExpr,
|
||||
body: Block,
|
||||
},
|
||||
}
|
||||
@@ -71,13 +88,18 @@ pub enum Statement {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct VarDeclStmt {
|
||||
pub struct VarDecl {
|
||||
pub mutable: bool,
|
||||
pub name: String,
|
||||
pub init: Option<Expression>,
|
||||
pub type_: Option<TypeExpr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct VarDeclStmt {
|
||||
pub decl: VarDecl,
|
||||
pub init: Option<Expression>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct VarAssignStmt {
|
||||
pub target: Expression,
|
||||
@@ -107,7 +129,7 @@ pub struct ForStmt {
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub enum Expression {
|
||||
Identifier(String),
|
||||
Path(StaticPath),
|
||||
IntLiteral(i64),
|
||||
FloatLiteral(f64),
|
||||
BoolLiteral(bool),
|
||||
|
||||
+12
-8
@@ -4,12 +4,13 @@ COMMENT = _{ "//" ~ (!"\n" ~ ANY)* }
|
||||
program = { SOI ~ top_level* ~ EOI }
|
||||
|
||||
// primitives
|
||||
identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
|
||||
integer = @{ ASCII_DIGIT+ }
|
||||
float = @{ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ }
|
||||
boolean = { "true" | "false" }
|
||||
string_lit = { "\"" ~ inner_str ~ "\"" }
|
||||
inner_str = @{ (!"\"" ~ ANY)* }
|
||||
identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
|
||||
integer = @{ ASCII_DIGIT+ }
|
||||
float = @{ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ }
|
||||
boolean = { "true" | "false" }
|
||||
string_lit = { "\"" ~ inner_str ~ "\"" }
|
||||
inner_str = @{ (!"\"" ~ ANY)* }
|
||||
static_path = { identifier ~ ("::" ~ identifier)* }
|
||||
|
||||
export = { "public" }
|
||||
mutable = { "mut" }
|
||||
@@ -72,14 +73,17 @@ while_stmt = {
|
||||
}
|
||||
|
||||
// ================= EXPRESSIONS =================
|
||||
type_expr = { identifier }
|
||||
tuple_type = { "(" ~ (type_expr ~ ("," ~ type_expr)*)? ~ ")" }
|
||||
path_type = { static_path ~ ("<" ~ (type_expr ~ ("," ~ type_expr)*)? ~ ">")? }
|
||||
ref_type = { mutable? ~ "*" }
|
||||
type_expr = { (path_type | tuple_type) ~ ref_type* }
|
||||
|
||||
primary = {
|
||||
integer
|
||||
| float
|
||||
| boolean
|
||||
| string_lit
|
||||
| identifier
|
||||
| static_path
|
||||
}
|
||||
|
||||
postfix = {
|
||||
|
||||
+125
-62
@@ -1,5 +1,3 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use pest::Parser;
|
||||
use pest_derive::Parser;
|
||||
|
||||
@@ -17,8 +15,6 @@ pub type ParseError = pest::error::Error<Rule>;
|
||||
pub fn parse(source: &str) -> Result<Vec<TopLevel>, ParseError> {
|
||||
let mut pairs = MistParser::parse(Rule::program, source)?;
|
||||
|
||||
println!("{pairs:#?}");
|
||||
|
||||
let mut statements = vec![];
|
||||
|
||||
for pair in pairs.next().unwrap().into_inner() {
|
||||
@@ -30,44 +26,95 @@ pub fn parse(source: &str) -> Result<Vec<TopLevel>, ParseError> {
|
||||
Ok(statements)
|
||||
}
|
||||
|
||||
impl TryFrom<pest::iterators::Pair<'_, Rule>> for TypeExpr {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(pair: pest::iterators::Pair<'_, Rule>) -> Result<Self, Self::Error> {
|
||||
if pair.as_str() == "void" {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
Ok(match pair.as_rule() {
|
||||
impl From<pest::iterators::Pair<'_, Rule>> for TypeExpr {
|
||||
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
|
||||
match pair.as_rule() {
|
||||
Rule::type_expr => {
|
||||
let inner = pair.into_inner().next().unwrap();
|
||||
TypeExpr::try_from(inner)?
|
||||
let mut inner = pair.into_inner();
|
||||
TypeExpr(
|
||||
TypeExprKind::from(inner.next().unwrap()),
|
||||
inner.map(TypePostfix::from).collect(),
|
||||
)
|
||||
}
|
||||
Rule::identifier => TypeExpr::Identifier(pair.as_str().to_string()),
|
||||
_ => unimplemented!("{pair:#?}"),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(bool, pest::iterators::Pair<'_, Rule>)> for ParamList {
|
||||
fn from((export_allowed, pair): (bool, pest::iterators::Pair<Rule>)) -> Self {
|
||||
impl From<pest::iterators::Pair<'_, Rule>> for TypePostfix {
|
||||
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
|
||||
match pair.as_rule() {
|
||||
Rule::ref_type => {
|
||||
if pair.into_inner().peek().is_some() {
|
||||
TypePostfix::RefMut
|
||||
} else {
|
||||
TypePostfix::Ref
|
||||
}
|
||||
}
|
||||
_ => unimplemented!("{pair:#?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pest::iterators::Pair<'_, Rule>> for TypeExprKind {
|
||||
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
|
||||
match pair.as_rule() {
|
||||
Rule::tuple_type => {
|
||||
TypeExprKind::Tuple(pair.into_inner().map(TypeExpr::from).collect())
|
||||
}
|
||||
Rule::path_type => {
|
||||
let mut inner = pair.into_inner();
|
||||
let path = StaticPath::from(inner.next().unwrap());
|
||||
let params = inner.map(TypeExpr::from).collect::<Vec<_>>();
|
||||
|
||||
if params.len() == 0 {
|
||||
TypeExprKind::Path(path)
|
||||
} else {
|
||||
TypeExprKind::PathParams(path, params)
|
||||
}
|
||||
}
|
||||
_ => unimplemented!("{pair:#?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pest::iterators::Pair<'_, Rule>> for StaticPath {
|
||||
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
|
||||
match pair.as_rule() {
|
||||
Rule::static_path => {
|
||||
StaticPath(pair.into_inner().map(|i| i.as_str().to_string()).collect())
|
||||
}
|
||||
_ => unimplemented!("{pair:#?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pest::iterators::Pair<'_, Rule>> for FieldList {
|
||||
fn from(pair: pest::iterators::Pair<Rule>) -> Self {
|
||||
let params = pair
|
||||
.into_inner()
|
||||
.map(|p| {
|
||||
let mut param_inner = p.into_inner();
|
||||
let export =
|
||||
if export_allowed && param_inner.peek().unwrap().as_rule() == Rule::export {
|
||||
param_inner.next().unwrap();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let param_type = TypeExpr::try_from(param_inner.next().unwrap()).unwrap();
|
||||
let export = if param_inner.peek().unwrap().as_rule() == Rule::export {
|
||||
param_inner.next().unwrap();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let param_type = TypeExpr::from(param_inner.next().unwrap());
|
||||
let param_name = param_inner.next().unwrap().as_str().to_string();
|
||||
(param_name, (export, param_type))
|
||||
})
|
||||
.collect();
|
||||
|
||||
FieldList(params)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pest::iterators::Pair<'_, Rule>> for ParamList {
|
||||
fn from(pair: pest::iterators::Pair<Rule>) -> Self {
|
||||
let params = pair.into_inner().map(VarDecl::from).collect();
|
||||
|
||||
ParamList(params)
|
||||
}
|
||||
}
|
||||
@@ -94,21 +141,13 @@ impl TryFrom<pest::iterators::Pair<'_, Rule>> for TopLevel {
|
||||
false
|
||||
};
|
||||
|
||||
let return_type = if let Some(next) = inner.peek() {
|
||||
if next.as_rule() == Rule::type_expr {
|
||||
TypeExpr::try_from(inner.next().unwrap()).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let return_type = TypeExpr::from(inner.next().unwrap());
|
||||
|
||||
let name = inner.next().unwrap().as_str().to_string();
|
||||
let params = if inner.peek().unwrap().as_rule() == Rule::param_list {
|
||||
ParamList::from((false, inner.next().unwrap()))
|
||||
ParamList::from(inner.next().unwrap())
|
||||
} else {
|
||||
ParamList(HashMap::new())
|
||||
ParamList(Vec::new())
|
||||
};
|
||||
|
||||
let body = Block::from(inner.next().unwrap());
|
||||
@@ -136,7 +175,7 @@ impl TryFrom<pest::iterators::Pair<'_, Rule>> for TopLevel {
|
||||
};
|
||||
let name = inner.next().unwrap().as_str().to_string();
|
||||
let fields_pair = inner.next().unwrap();
|
||||
let fields = ParamList::from((true, fields_pair));
|
||||
let fields = FieldList::from(fields_pair);
|
||||
|
||||
Ok(TopLevel::StructDecl {
|
||||
export,
|
||||
@@ -182,28 +221,7 @@ impl From<pest::iterators::Pair<'_, Rule>> for Statement {
|
||||
|
||||
Rule::block => Statement::Block(Block::from(pair.into_inner().next().unwrap())),
|
||||
|
||||
Rule::var_decl_statement => {
|
||||
let mut inner = pair.into_inner();
|
||||
|
||||
let mut var_decl = inner.next().unwrap().into_inner();
|
||||
|
||||
let type_ = var_decl.next().map(TypeExpr::try_from).unwrap().ok();
|
||||
let mutable = if var_decl.peek().unwrap().as_rule() == Rule::mutable {
|
||||
var_decl.next();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let name = var_decl.next().unwrap().as_str().to_string();
|
||||
let init = inner.next().map(Expression::from);
|
||||
|
||||
Statement::VarDecl(VarDeclStmt {
|
||||
mutable,
|
||||
name: name.as_str().to_string(),
|
||||
init,
|
||||
type_,
|
||||
})
|
||||
}
|
||||
Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::from(pair)),
|
||||
|
||||
Rule::return_stmt => {
|
||||
let mut inner = pair.into_inner();
|
||||
@@ -269,7 +287,7 @@ impl From<pest::iterators::Pair<'_, Rule>> for Expression {
|
||||
}
|
||||
}
|
||||
Rule::primary => Expression::from(pair.into_inner().next().unwrap()),
|
||||
Rule::identifier => Expression::Identifier(pair.as_str().to_string()),
|
||||
Rule::static_path => Expression::Path(StaticPath::from(pair)),
|
||||
Rule::integer => {
|
||||
let value = pair.as_str().parse::<i64>().unwrap();
|
||||
Expression::IntLiteral(value)
|
||||
@@ -348,3 +366,48 @@ impl From<pest::iterators::Pair<'_, Rule>> for Postfix {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pest::iterators::Pair<'_, Rule>> for VarDeclStmt {
|
||||
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
|
||||
match pair.as_rule() {
|
||||
Rule::var_decl_statement => {
|
||||
let mut inner = pair.into_inner();
|
||||
|
||||
let decl = VarDecl::from(inner.next().unwrap());
|
||||
|
||||
let init = inner.next().map(Expression::from);
|
||||
|
||||
VarDeclStmt { decl, init }
|
||||
}
|
||||
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pest::iterators::Pair<'_, Rule>> for VarDecl {
|
||||
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
|
||||
match pair.as_rule() {
|
||||
Rule::var_decl => {
|
||||
let mut inner = pair.into_inner();
|
||||
|
||||
let type_ = Some(inner.next().map(TypeExpr::from).unwrap());
|
||||
let mutable = if inner.peek().unwrap().as_rule() == Rule::mutable {
|
||||
inner.next();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let name = inner.next().unwrap().as_str().to_string();
|
||||
|
||||
VarDecl {
|
||||
mutable,
|
||||
name,
|
||||
type_,
|
||||
}
|
||||
}
|
||||
|
||||
_ => unimplemented!("{:?}", pair.as_rule()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+253
-174
@@ -1,8 +1,28 @@
|
||||
use parser::ast::{
|
||||
BinaryOp, Block, Expression, IfStmt, Postfix, Statement, TopLevel, TypeExpr, VarAssignStmt,
|
||||
VarDeclStmt, WhileStmt,
|
||||
BinaryOp, Block, Expression, IfStmt, Postfix, Statement, StaticPath, TopLevel, TypeExpr,
|
||||
TypeExprKind, TypePostfix, VarAssignStmt, VarDecl, VarDeclStmt, WhileStmt,
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Traits
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Implemented by nodes that *write* into the codegen output buffer.
|
||||
/// Requires `&mut RustCodegen` because it calls `add` / `addln` / indentation helpers.
|
||||
pub trait ToRust {
|
||||
fn to_rust(&self, cg: &mut RustCodegen);
|
||||
}
|
||||
|
||||
/// Implemented by nodes that *produce* a `String` without mutating the codegen.
|
||||
/// Only needs `&RustCodegen` (e.g. for indent level or helper access).
|
||||
pub trait GetRust {
|
||||
fn get_rust(&self) -> String;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Codegen struct
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
pub struct RustCodegen {
|
||||
output: String,
|
||||
indent: usize,
|
||||
@@ -30,21 +50,154 @@ impl RustCodegen {
|
||||
}
|
||||
|
||||
fn add_indentedln(&mut self, s: &str) {
|
||||
self.add(&format!("{}{}\n", self.indent_str(), s));
|
||||
let line = format!("{}{}\n", self.indent_str(), s);
|
||||
self.add(&line);
|
||||
}
|
||||
|
||||
pub fn generate(&mut self, toplevels: &[TopLevel]) -> String {
|
||||
for tl in toplevels {
|
||||
self.generate_toplevel(tl);
|
||||
tl.to_rust(self);
|
||||
}
|
||||
self.output.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_toplevel(&mut self, tl: &TopLevel) {
|
||||
match tl {
|
||||
impl Default for RustCodegen {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GetRust — pure string production (expressions, types)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
impl GetRust for TypeExpr {
|
||||
fn get_rust(&self) -> String {
|
||||
get_type_postfixes(&self.1) + &self.0.get_rust()
|
||||
}
|
||||
}
|
||||
|
||||
impl GetRust for TypeExprKind {
|
||||
fn get_rust(&self) -> String {
|
||||
match self {
|
||||
TypeExprKind::Path(path) => get_static_type_path(path),
|
||||
TypeExprKind::PathParams(path, params) => {
|
||||
format!(
|
||||
"{}<{}>",
|
||||
get_static_type_path(path),
|
||||
params
|
||||
.iter()
|
||||
.map(|t| t.get_rust())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
}
|
||||
TypeExprKind::Tuple(types) => format!(
|
||||
"({})",
|
||||
types
|
||||
.iter()
|
||||
.map(|t| t.get_rust())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GetRust for Expression {
|
||||
fn get_rust(&self) -> String {
|
||||
match self {
|
||||
Expression::Path(path) => path.get_rust(),
|
||||
Expression::IntLiteral(n) => n.to_string(),
|
||||
Expression::FloatLiteral(n) => n.to_string(),
|
||||
Expression::BoolLiteral(b) => b.to_string(),
|
||||
Expression::StringLiteral(s) => format!("\"{}\".to_string()", s),
|
||||
|
||||
Expression::Postfix { initial, postfixes } => {
|
||||
let base = initial.get_rust();
|
||||
postfixes.get_rust_with_base(&base)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper — applies a slice of postfixes onto an already-rendered base string.
|
||||
trait PostfixChain {
|
||||
fn get_rust_with_base(&self, base: &str) -> String;
|
||||
}
|
||||
|
||||
impl PostfixChain for [Postfix] {
|
||||
fn get_rust_with_base(&self, base: &str) -> String {
|
||||
let mut result = base.to_string();
|
||||
|
||||
for postfix in self {
|
||||
result = match postfix {
|
||||
Postfix::FieldAccess(field) => format!("{}.{}", result, field),
|
||||
|
||||
Postfix::Call(args) => {
|
||||
let args = args
|
||||
.iter()
|
||||
.map(|a| a.get_rust())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
format!("{}({})", result, args)
|
||||
}
|
||||
|
||||
Postfix::StructCall(fields) => {
|
||||
let fields = fields
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{}: {}", k, v.get_rust()))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
format!("{} {{ {} }}", result, fields)
|
||||
}
|
||||
|
||||
Postfix::Index(idx) => {
|
||||
format!("{}[{}]", result, idx.get_rust())
|
||||
}
|
||||
|
||||
Postfix::Binary(op, rhs) => {
|
||||
let op_str = match op {
|
||||
BinaryOp::Plus => "+",
|
||||
BinaryOp::Minus => "-",
|
||||
BinaryOp::Multiply => "*",
|
||||
BinaryOp::Divide => "/",
|
||||
BinaryOp::Modulo => "%",
|
||||
BinaryOp::Equal => "==",
|
||||
BinaryOp::NotEqual => "!=",
|
||||
BinaryOp::LessThan => "<",
|
||||
BinaryOp::GreaterThan => ">",
|
||||
BinaryOp::LessThanOrEqual => "<=",
|
||||
BinaryOp::GreaterThanOrEqual => ">=",
|
||||
};
|
||||
format!("{} {} {}", result, op_str, rhs.get_rust())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ToRust — output-writing (top-level, statements, blocks)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
impl ToRust for Block {
|
||||
fn to_rust(&self, cg: &mut RustCodegen) {
|
||||
for stmt in &self.0 {
|
||||
stmt.to_rust(cg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToRust for TopLevel {
|
||||
fn to_rust(&self, cg: &mut RustCodegen) {
|
||||
match self {
|
||||
TopLevel::Import(path) => {
|
||||
let path = path.replace("\"", "");
|
||||
self.addln(&format!("use {};", path));
|
||||
let path = path.replace('"', "");
|
||||
cg.addln(&format!("use {};", path));
|
||||
}
|
||||
|
||||
TopLevel::StructDecl {
|
||||
@@ -53,17 +206,16 @@ impl RustCodegen {
|
||||
fields,
|
||||
} => {
|
||||
let vis = if *export { "pub " } else { "" };
|
||||
|
||||
self.addln(&format!("{}struct {} {{", vis, name));
|
||||
self.indent += 1;
|
||||
cg.addln(&format!("{}struct {} {{", vis, name));
|
||||
cg.indent += 1;
|
||||
|
||||
for (field_name, (_, ty)) in &fields.0 {
|
||||
let ty = self.translate_type(ty);
|
||||
self.add_indentedln(&format!("pub {}: {},", field_name, ty));
|
||||
let ty = ty.get_rust();
|
||||
cg.add_indentedln(&format!("pub {}: {},", field_name, ty));
|
||||
}
|
||||
|
||||
self.indent -= 1;
|
||||
self.addln("}\n");
|
||||
cg.indent -= 1;
|
||||
cg.addln("}\n");
|
||||
}
|
||||
|
||||
TopLevel::FunctionDecl {
|
||||
@@ -78,86 +230,52 @@ impl RustCodegen {
|
||||
let params_str = params
|
||||
.0
|
||||
.iter()
|
||||
.map(|(n, (_, t))| format!("{}: {}", n, self.translate_type(t)))
|
||||
.map(VarDecl::get_rust)
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
let ret = return_type
|
||||
.as_ref()
|
||||
.map(|t| format!(" -> {}", self.translate_type(t)))
|
||||
.unwrap_or_default();
|
||||
|
||||
self.addln(&format!("{}fn {}({}){} {{", vis, name, params_str, ret));
|
||||
|
||||
self.indent += 1;
|
||||
self.generate_block(body);
|
||||
self.indent -= 1;
|
||||
|
||||
self.addln("}\n");
|
||||
cg.addln(&format!(
|
||||
"{}fn {}({}) -> {} {{",
|
||||
vis,
|
||||
name,
|
||||
params_str,
|
||||
return_type.get_rust()
|
||||
));
|
||||
cg.indent += 1;
|
||||
body.to_rust(cg);
|
||||
cg.indent -= 1;
|
||||
cg.addln("}\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_type(&self, ty: &TypeExpr) -> String {
|
||||
match ty {
|
||||
TypeExpr::Identifier(name) => match name.as_str() {
|
||||
"int" => "i32".into(),
|
||||
"float" | "float64" => "f64".into(),
|
||||
"float32" => "f32".into(),
|
||||
"bool" => "bool".into(),
|
||||
"string" => "String".into(),
|
||||
_ => name.clone(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_block(&mut self, block: &Block) {
|
||||
for stmt in &block.0 {
|
||||
self.generate_statement(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_statement(&mut self, stmt: &Statement) {
|
||||
match stmt {
|
||||
impl ToRust for Statement {
|
||||
fn to_rust(&self, cg: &mut RustCodegen) {
|
||||
match self {
|
||||
Statement::Expression(expr) => {
|
||||
self.add_indentedln(&format!("{};", self.generate_expression(expr)));
|
||||
cg.add_indentedln(&format!("{};", expr.get_rust()));
|
||||
}
|
||||
|
||||
Statement::Block(block) => {
|
||||
self.add_indentedln("{");
|
||||
self.indent += 1;
|
||||
self.generate_block(block);
|
||||
self.indent -= 1;
|
||||
self.add_indentedln("}");
|
||||
cg.add_indentedln("{");
|
||||
cg.indent += 1;
|
||||
block.to_rust(cg);
|
||||
cg.indent -= 1;
|
||||
cg.add_indentedln("}");
|
||||
}
|
||||
|
||||
Statement::VarDecl(VarDeclStmt {
|
||||
mutable,
|
||||
name,
|
||||
init,
|
||||
type_,
|
||||
}) => {
|
||||
let mutability = if *mutable { "mut " } else { "" };
|
||||
|
||||
let ty = type_
|
||||
.as_ref()
|
||||
.map(|t| format!(": {}", self.translate_type(t)))
|
||||
.unwrap_or_default();
|
||||
|
||||
Statement::VarDecl(VarDeclStmt { decl, init }) => {
|
||||
let init = init
|
||||
.as_ref()
|
||||
.map(|e| format!(" = {}", self.generate_expression(e)))
|
||||
.map(|e| format!(" = {}", e.get_rust()))
|
||||
.unwrap_or_default();
|
||||
|
||||
self.add_indentedln(&format!("let {}{}{}{};", mutability, name, ty, init));
|
||||
cg.add_indentedln(&format!("let {}{};", decl.get_rust(), init));
|
||||
}
|
||||
|
||||
Statement::VarAssign(VarAssignStmt { target, value }) => {
|
||||
self.add_indentedln(&format!(
|
||||
"{} = {};",
|
||||
self.generate_expression(target),
|
||||
self.generate_expression(value)
|
||||
));
|
||||
cg.add_indentedln(&format!("{} = {};", target.get_rust(), value.get_rust(),));
|
||||
}
|
||||
|
||||
Statement::If(IfStmt {
|
||||
@@ -165,122 +283,83 @@ impl RustCodegen {
|
||||
then_branch,
|
||||
else_branch,
|
||||
}) => {
|
||||
self.add_indentedln(&format!("if {} {{", self.generate_expression(condition)));
|
||||
|
||||
self.indent += 1;
|
||||
self.generate_statement(then_branch);
|
||||
self.indent -= 1;
|
||||
|
||||
self.add_indentedln("}");
|
||||
cg.add_indentedln(&format!("if {} {{", condition.get_rust()));
|
||||
cg.indent += 1;
|
||||
then_branch.to_rust(cg);
|
||||
cg.indent -= 1;
|
||||
cg.add_indentedln("}");
|
||||
|
||||
if let Some(else_br) = else_branch {
|
||||
self.add_indentedln("else {");
|
||||
self.indent += 1;
|
||||
self.generate_statement(else_br);
|
||||
self.indent -= 1;
|
||||
self.add_indentedln("}");
|
||||
cg.add_indentedln("else {");
|
||||
cg.indent += 1;
|
||||
else_br.to_rust(cg);
|
||||
cg.indent -= 1;
|
||||
cg.add_indentedln("}");
|
||||
}
|
||||
}
|
||||
|
||||
Statement::While(WhileStmt { condition, body }) => {
|
||||
self.add_indentedln(&format!("while {} {{", self.generate_expression(condition)));
|
||||
|
||||
self.indent += 1;
|
||||
self.generate_statement(body);
|
||||
self.indent -= 1;
|
||||
|
||||
self.add_indentedln("}");
|
||||
cg.add_indentedln(&format!("while {} {{", condition.get_rust()));
|
||||
cg.indent += 1;
|
||||
body.to_rust(cg);
|
||||
cg.indent -= 1;
|
||||
cg.add_indentedln("}");
|
||||
}
|
||||
|
||||
Statement::For { .. } => {
|
||||
// Rust doesn't support C-style for loops
|
||||
self.add_indentedln("// TODO: transform into iterator-based loop");
|
||||
cg.add_indentedln("// TODO: transform into iterator-based loop");
|
||||
}
|
||||
|
||||
Statement::Return(expr) => {
|
||||
let val = expr
|
||||
.as_ref()
|
||||
.map(|e| self.generate_expression(e))
|
||||
.unwrap_or_default();
|
||||
|
||||
self.add_indentedln(&format!("return {};", val));
|
||||
let val = expr.as_ref().map(|e| e.get_rust()).unwrap_or_default();
|
||||
cg.add_indentedln(&format!("return {};", val));
|
||||
}
|
||||
|
||||
Statement::Break => self.add_indentedln("break;"),
|
||||
Statement::Continue => self.add_indentedln("continue;"),
|
||||
Statement::Break => cg.add_indentedln("break;"),
|
||||
Statement::Continue => cg.add_indentedln("continue;"),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_expression(&self, expr: &Expression) -> String {
|
||||
match expr {
|
||||
Expression::Identifier(name) => name.clone(),
|
||||
Expression::IntLiteral(n) => n.to_string(),
|
||||
Expression::FloatLiteral(n) => n.to_string(),
|
||||
Expression::BoolLiteral(b) => b.to_string(),
|
||||
Expression::StringLiteral(s) => format!("\"{}\".to_string()", s),
|
||||
|
||||
Expression::Postfix { initial, postfixes } => {
|
||||
let base = self.generate_expression(initial);
|
||||
self.apply_postfixes(&base, postfixes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_postfixes(&self, base: &str, postfixes: &[Postfix]) -> String {
|
||||
let mut result = base.to_string();
|
||||
|
||||
for postfix in postfixes {
|
||||
result = match postfix {
|
||||
Postfix::FieldAccess(field) => format!("{}.{}", result, field),
|
||||
|
||||
Postfix::Call(args) => {
|
||||
let args = args
|
||||
.iter()
|
||||
.map(|a| self.generate_expression(a))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
format!("{}({})", result, args)
|
||||
}
|
||||
|
||||
Postfix::StructCall(fields) => {
|
||||
let fields = fields
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{}: {}", k, self.generate_expression(v)))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
format!("{} {{ {} }}", result, fields)
|
||||
}
|
||||
|
||||
Postfix::Index(idx) => {
|
||||
format!("{}[{}]", result, self.generate_expression(idx))
|
||||
}
|
||||
|
||||
Postfix::Binary(op, rhs) => {
|
||||
let op = match op {
|
||||
BinaryOp::Plus => "+",
|
||||
BinaryOp::Minus => "-",
|
||||
BinaryOp::Multiply => "*",
|
||||
BinaryOp::Divide => "/",
|
||||
BinaryOp::Modulo => "%",
|
||||
BinaryOp::Equal => "==",
|
||||
BinaryOp::NotEqual => "!=",
|
||||
BinaryOp::LessThan => "<",
|
||||
BinaryOp::GreaterThan => ">",
|
||||
BinaryOp::LessThanOrEqual => "<=",
|
||||
BinaryOp::GreaterThanOrEqual => ">=",
|
||||
};
|
||||
|
||||
format!("{} {} {}", result, op, self.generate_expression(rhs))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RustCodegen {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
impl GetRust for VarDecl {
|
||||
fn get_rust(&self) -> String {
|
||||
let mutability = if self.mutable { "mut " } else { "" };
|
||||
|
||||
let ty = self
|
||||
.type_
|
||||
.as_ref()
|
||||
.map(|t| format!(": {}", t.get_rust()))
|
||||
.unwrap_or_default();
|
||||
|
||||
format!("{}{}{}", mutability, self.name, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl GetRust for StaticPath {
|
||||
fn get_rust(&self) -> String {
|
||||
self.0.join("::")
|
||||
}
|
||||
}
|
||||
|
||||
impl GetRust for TypePostfix {
|
||||
fn get_rust(&self) -> String {
|
||||
match self {
|
||||
TypePostfix::Ref => format!("&"),
|
||||
TypePostfix::RefMut => format!("&mut "),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_static_type_path(path: &StaticPath) -> String {
|
||||
let rust_path = path.get_rust();
|
||||
|
||||
if rust_path == "void" {
|
||||
format!("()")
|
||||
} else {
|
||||
rust_path
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_type_postfixes(postfixes: &[TypePostfix]) -> String {
|
||||
postfixes.iter().map(TypePostfix::get_rust).collect()
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,3 +1 @@
|
||||
int test() {
|
||||
int mut a = 10;
|
||||
}
|
||||
i32 add(i32* a, i32* b) {}
|
||||
Reference in New Issue
Block a user