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;
|
use serde::Serialize;
|
||||||
|
|
||||||
#[derive(Debug, Clone, 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)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct Block(pub Vec<Statement>);
|
pub struct Block(pub Vec<Statement>);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub enum TypeExpr {
|
pub enum TypePostfix {
|
||||||
Identifier(String),
|
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)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub enum BinaryOp {
|
pub enum BinaryOp {
|
||||||
Plus,
|
Plus,
|
||||||
@@ -34,13 +51,13 @@ pub enum TopLevel {
|
|||||||
StructDecl {
|
StructDecl {
|
||||||
export: bool,
|
export: bool,
|
||||||
name: String,
|
name: String,
|
||||||
fields: ParamList,
|
fields: FieldList,
|
||||||
},
|
},
|
||||||
FunctionDecl {
|
FunctionDecl {
|
||||||
export: bool,
|
export: bool,
|
||||||
name: String,
|
name: String,
|
||||||
params: ParamList,
|
params: ParamList,
|
||||||
return_type: Option<TypeExpr>,
|
return_type: TypeExpr,
|
||||||
body: Block,
|
body: Block,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -71,13 +88,18 @@ pub enum Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct VarDeclStmt {
|
pub struct VarDecl {
|
||||||
pub mutable: bool,
|
pub mutable: bool,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub init: Option<Expression>,
|
|
||||||
pub type_: Option<TypeExpr>,
|
pub type_: Option<TypeExpr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct VarDeclStmt {
|
||||||
|
pub decl: VarDecl,
|
||||||
|
pub init: Option<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct VarAssignStmt {
|
pub struct VarAssignStmt {
|
||||||
pub target: Expression,
|
pub target: Expression,
|
||||||
@@ -107,7 +129,7 @@ pub struct ForStmt {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
Identifier(String),
|
Path(StaticPath),
|
||||||
IntLiteral(i64),
|
IntLiteral(i64),
|
||||||
FloatLiteral(f64),
|
FloatLiteral(f64),
|
||||||
BoolLiteral(bool),
|
BoolLiteral(bool),
|
||||||
|
|||||||
+12
-8
@@ -4,12 +4,13 @@ COMMENT = _{ "//" ~ (!"\n" ~ ANY)* }
|
|||||||
program = { SOI ~ top_level* ~ EOI }
|
program = { SOI ~ top_level* ~ EOI }
|
||||||
|
|
||||||
// primitives
|
// primitives
|
||||||
identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
|
identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
|
||||||
integer = @{ ASCII_DIGIT+ }
|
integer = @{ ASCII_DIGIT+ }
|
||||||
float = @{ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ }
|
float = @{ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ }
|
||||||
boolean = { "true" | "false" }
|
boolean = { "true" | "false" }
|
||||||
string_lit = { "\"" ~ inner_str ~ "\"" }
|
string_lit = { "\"" ~ inner_str ~ "\"" }
|
||||||
inner_str = @{ (!"\"" ~ ANY)* }
|
inner_str = @{ (!"\"" ~ ANY)* }
|
||||||
|
static_path = { identifier ~ ("::" ~ identifier)* }
|
||||||
|
|
||||||
export = { "public" }
|
export = { "public" }
|
||||||
mutable = { "mut" }
|
mutable = { "mut" }
|
||||||
@@ -72,14 +73,17 @@ while_stmt = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ================= EXPRESSIONS =================
|
// ================= 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 = {
|
primary = {
|
||||||
integer
|
integer
|
||||||
| float
|
| float
|
||||||
| boolean
|
| boolean
|
||||||
| string_lit
|
| string_lit
|
||||||
| identifier
|
| static_path
|
||||||
}
|
}
|
||||||
|
|
||||||
postfix = {
|
postfix = {
|
||||||
|
|||||||
+125
-62
@@ -1,5 +1,3 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use pest::Parser;
|
use pest::Parser;
|
||||||
use pest_derive::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> {
|
pub fn parse(source: &str) -> Result<Vec<TopLevel>, ParseError> {
|
||||||
let mut pairs = MistParser::parse(Rule::program, source)?;
|
let mut pairs = MistParser::parse(Rule::program, source)?;
|
||||||
|
|
||||||
println!("{pairs:#?}");
|
|
||||||
|
|
||||||
let mut statements = vec![];
|
let mut statements = vec![];
|
||||||
|
|
||||||
for pair in pairs.next().unwrap().into_inner() {
|
for pair in pairs.next().unwrap().into_inner() {
|
||||||
@@ -30,44 +26,95 @@ pub fn parse(source: &str) -> Result<Vec<TopLevel>, ParseError> {
|
|||||||
Ok(statements)
|
Ok(statements)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<pest::iterators::Pair<'_, Rule>> for TypeExpr {
|
impl From<pest::iterators::Pair<'_, Rule>> for TypeExpr {
|
||||||
type Error = ();
|
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
|
||||||
|
match pair.as_rule() {
|
||||||
fn try_from(pair: pest::iterators::Pair<'_, Rule>) -> Result<Self, Self::Error> {
|
|
||||||
if pair.as_str() == "void" {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(match pair.as_rule() {
|
|
||||||
Rule::type_expr => {
|
Rule::type_expr => {
|
||||||
let inner = pair.into_inner().next().unwrap();
|
let mut inner = pair.into_inner();
|
||||||
TypeExpr::try_from(inner)?
|
TypeExpr(
|
||||||
|
TypeExprKind::from(inner.next().unwrap()),
|
||||||
|
inner.map(TypePostfix::from).collect(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Rule::identifier => TypeExpr::Identifier(pair.as_str().to_string()),
|
|
||||||
_ => unimplemented!("{pair:#?}"),
|
_ => unimplemented!("{pair:#?}"),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(bool, pest::iterators::Pair<'_, Rule>)> for ParamList {
|
impl From<pest::iterators::Pair<'_, Rule>> for TypePostfix {
|
||||||
fn from((export_allowed, pair): (bool, pest::iterators::Pair<Rule>)) -> Self {
|
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
|
let params = pair
|
||||||
.into_inner()
|
.into_inner()
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
let mut param_inner = p.into_inner();
|
let mut param_inner = p.into_inner();
|
||||||
let export =
|
let export = if param_inner.peek().unwrap().as_rule() == Rule::export {
|
||||||
if export_allowed && param_inner.peek().unwrap().as_rule() == Rule::export {
|
param_inner.next().unwrap();
|
||||||
param_inner.next().unwrap();
|
true
|
||||||
true
|
} else {
|
||||||
} else {
|
false
|
||||||
false
|
};
|
||||||
};
|
let param_type = TypeExpr::from(param_inner.next().unwrap());
|
||||||
let param_type = TypeExpr::try_from(param_inner.next().unwrap()).unwrap();
|
|
||||||
let param_name = param_inner.next().unwrap().as_str().to_string();
|
let param_name = param_inner.next().unwrap().as_str().to_string();
|
||||||
(param_name, (export, param_type))
|
(param_name, (export, param_type))
|
||||||
})
|
})
|
||||||
.collect();
|
.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)
|
ParamList(params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,21 +141,13 @@ impl TryFrom<pest::iterators::Pair<'_, Rule>> for TopLevel {
|
|||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
let return_type = if let Some(next) = inner.peek() {
|
let return_type = TypeExpr::from(inner.next().unwrap());
|
||||||
if next.as_rule() == Rule::type_expr {
|
|
||||||
TypeExpr::try_from(inner.next().unwrap()).ok()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let name = inner.next().unwrap().as_str().to_string();
|
let name = inner.next().unwrap().as_str().to_string();
|
||||||
let params = if inner.peek().unwrap().as_rule() == Rule::param_list {
|
let params = if inner.peek().unwrap().as_rule() == Rule::param_list {
|
||||||
ParamList::from((false, inner.next().unwrap()))
|
ParamList::from(inner.next().unwrap())
|
||||||
} else {
|
} else {
|
||||||
ParamList(HashMap::new())
|
ParamList(Vec::new())
|
||||||
};
|
};
|
||||||
|
|
||||||
let body = Block::from(inner.next().unwrap());
|
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 name = inner.next().unwrap().as_str().to_string();
|
||||||
let fields_pair = inner.next().unwrap();
|
let fields_pair = inner.next().unwrap();
|
||||||
let fields = ParamList::from((true, fields_pair));
|
let fields = FieldList::from(fields_pair);
|
||||||
|
|
||||||
Ok(TopLevel::StructDecl {
|
Ok(TopLevel::StructDecl {
|
||||||
export,
|
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::block => Statement::Block(Block::from(pair.into_inner().next().unwrap())),
|
||||||
|
|
||||||
Rule::var_decl_statement => {
|
Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::from(pair)),
|
||||||
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::return_stmt => {
|
Rule::return_stmt => {
|
||||||
let mut inner = pair.into_inner();
|
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::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 => {
|
Rule::integer => {
|
||||||
let value = pair.as_str().parse::<i64>().unwrap();
|
let value = pair.as_str().parse::<i64>().unwrap();
|
||||||
Expression::IntLiteral(value)
|
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::{
|
use parser::ast::{
|
||||||
BinaryOp, Block, Expression, IfStmt, Postfix, Statement, TopLevel, TypeExpr, VarAssignStmt,
|
BinaryOp, Block, Expression, IfStmt, Postfix, Statement, StaticPath, TopLevel, TypeExpr,
|
||||||
VarDeclStmt, WhileStmt,
|
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 {
|
pub struct RustCodegen {
|
||||||
output: String,
|
output: String,
|
||||||
indent: usize,
|
indent: usize,
|
||||||
@@ -30,21 +50,154 @@ impl RustCodegen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add_indentedln(&mut self, s: &str) {
|
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 {
|
pub fn generate(&mut self, toplevels: &[TopLevel]) -> String {
|
||||||
for tl in toplevels {
|
for tl in toplevels {
|
||||||
self.generate_toplevel(tl);
|
tl.to_rust(self);
|
||||||
}
|
}
|
||||||
self.output.clone()
|
self.output.clone()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_toplevel(&mut self, tl: &TopLevel) {
|
impl Default for RustCodegen {
|
||||||
match tl {
|
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) => {
|
TopLevel::Import(path) => {
|
||||||
let path = path.replace("\"", "");
|
let path = path.replace('"', "");
|
||||||
self.addln(&format!("use {};", path));
|
cg.addln(&format!("use {};", path));
|
||||||
}
|
}
|
||||||
|
|
||||||
TopLevel::StructDecl {
|
TopLevel::StructDecl {
|
||||||
@@ -53,17 +206,16 @@ impl RustCodegen {
|
|||||||
fields,
|
fields,
|
||||||
} => {
|
} => {
|
||||||
let vis = if *export { "pub " } else { "" };
|
let vis = if *export { "pub " } else { "" };
|
||||||
|
cg.addln(&format!("{}struct {} {{", vis, name));
|
||||||
self.addln(&format!("{}struct {} {{", vis, name));
|
cg.indent += 1;
|
||||||
self.indent += 1;
|
|
||||||
|
|
||||||
for (field_name, (_, ty)) in &fields.0 {
|
for (field_name, (_, ty)) in &fields.0 {
|
||||||
let ty = self.translate_type(ty);
|
let ty = ty.get_rust();
|
||||||
self.add_indentedln(&format!("pub {}: {},", field_name, ty));
|
cg.add_indentedln(&format!("pub {}: {},", field_name, ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.indent -= 1;
|
cg.indent -= 1;
|
||||||
self.addln("}\n");
|
cg.addln("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TopLevel::FunctionDecl {
|
TopLevel::FunctionDecl {
|
||||||
@@ -78,86 +230,52 @@ impl RustCodegen {
|
|||||||
let params_str = params
|
let params_str = params
|
||||||
.0
|
.0
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(n, (_, t))| format!("{}: {}", n, self.translate_type(t)))
|
.map(VarDecl::get_rust)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", ");
|
.join(", ");
|
||||||
|
|
||||||
let ret = return_type
|
cg.addln(&format!(
|
||||||
.as_ref()
|
"{}fn {}({}) -> {} {{",
|
||||||
.map(|t| format!(" -> {}", self.translate_type(t)))
|
vis,
|
||||||
.unwrap_or_default();
|
name,
|
||||||
|
params_str,
|
||||||
self.addln(&format!("{}fn {}({}){} {{", vis, name, params_str, ret));
|
return_type.get_rust()
|
||||||
|
));
|
||||||
self.indent += 1;
|
cg.indent += 1;
|
||||||
self.generate_block(body);
|
body.to_rust(cg);
|
||||||
self.indent -= 1;
|
cg.indent -= 1;
|
||||||
|
cg.addln("}\n");
|
||||||
self.addln("}\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn translate_type(&self, ty: &TypeExpr) -> String {
|
impl ToRust for Statement {
|
||||||
match ty {
|
fn to_rust(&self, cg: &mut RustCodegen) {
|
||||||
TypeExpr::Identifier(name) => match name.as_str() {
|
match self {
|
||||||
"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 {
|
|
||||||
Statement::Expression(expr) => {
|
Statement::Expression(expr) => {
|
||||||
self.add_indentedln(&format!("{};", self.generate_expression(expr)));
|
cg.add_indentedln(&format!("{};", expr.get_rust()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::Block(block) => {
|
Statement::Block(block) => {
|
||||||
self.add_indentedln("{");
|
cg.add_indentedln("{");
|
||||||
self.indent += 1;
|
cg.indent += 1;
|
||||||
self.generate_block(block);
|
block.to_rust(cg);
|
||||||
self.indent -= 1;
|
cg.indent -= 1;
|
||||||
self.add_indentedln("}");
|
cg.add_indentedln("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::VarDecl(VarDeclStmt {
|
Statement::VarDecl(VarDeclStmt { decl, init }) => {
|
||||||
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();
|
|
||||||
|
|
||||||
let init = init
|
let init = init
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|e| format!(" = {}", self.generate_expression(e)))
|
.map(|e| format!(" = {}", e.get_rust()))
|
||||||
.unwrap_or_default();
|
.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 }) => {
|
Statement::VarAssign(VarAssignStmt { target, value }) => {
|
||||||
self.add_indentedln(&format!(
|
cg.add_indentedln(&format!("{} = {};", target.get_rust(), value.get_rust(),));
|
||||||
"{} = {};",
|
|
||||||
self.generate_expression(target),
|
|
||||||
self.generate_expression(value)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::If(IfStmt {
|
Statement::If(IfStmt {
|
||||||
@@ -165,122 +283,83 @@ impl RustCodegen {
|
|||||||
then_branch,
|
then_branch,
|
||||||
else_branch,
|
else_branch,
|
||||||
}) => {
|
}) => {
|
||||||
self.add_indentedln(&format!("if {} {{", self.generate_expression(condition)));
|
cg.add_indentedln(&format!("if {} {{", condition.get_rust()));
|
||||||
|
cg.indent += 1;
|
||||||
self.indent += 1;
|
then_branch.to_rust(cg);
|
||||||
self.generate_statement(then_branch);
|
cg.indent -= 1;
|
||||||
self.indent -= 1;
|
cg.add_indentedln("}");
|
||||||
|
|
||||||
self.add_indentedln("}");
|
|
||||||
|
|
||||||
if let Some(else_br) = else_branch {
|
if let Some(else_br) = else_branch {
|
||||||
self.add_indentedln("else {");
|
cg.add_indentedln("else {");
|
||||||
self.indent += 1;
|
cg.indent += 1;
|
||||||
self.generate_statement(else_br);
|
else_br.to_rust(cg);
|
||||||
self.indent -= 1;
|
cg.indent -= 1;
|
||||||
self.add_indentedln("}");
|
cg.add_indentedln("}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::While(WhileStmt { condition, body }) => {
|
Statement::While(WhileStmt { condition, body }) => {
|
||||||
self.add_indentedln(&format!("while {} {{", self.generate_expression(condition)));
|
cg.add_indentedln(&format!("while {} {{", condition.get_rust()));
|
||||||
|
cg.indent += 1;
|
||||||
self.indent += 1;
|
body.to_rust(cg);
|
||||||
self.generate_statement(body);
|
cg.indent -= 1;
|
||||||
self.indent -= 1;
|
cg.add_indentedln("}");
|
||||||
|
|
||||||
self.add_indentedln("}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::For { .. } => {
|
Statement::For { .. } => {
|
||||||
// Rust doesn't support C-style for loops
|
cg.add_indentedln("// TODO: transform into iterator-based loop");
|
||||||
self.add_indentedln("// TODO: transform into iterator-based loop");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::Return(expr) => {
|
Statement::Return(expr) => {
|
||||||
let val = expr
|
let val = expr.as_ref().map(|e| e.get_rust()).unwrap_or_default();
|
||||||
.as_ref()
|
cg.add_indentedln(&format!("return {};", val));
|
||||||
.map(|e| self.generate_expression(e))
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
self.add_indentedln(&format!("return {};", val));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::Break => self.add_indentedln("break;"),
|
Statement::Break => cg.add_indentedln("break;"),
|
||||||
Statement::Continue => self.add_indentedln("continue;"),
|
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 {
|
impl GetRust for VarDecl {
|
||||||
fn default() -> Self {
|
fn get_rust(&self) -> String {
|
||||||
Self::new()
|
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() {
|
i32 add(i32* a, i32* b) {}
|
||||||
int mut a = 10;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user