lab5
This commit is contained in:
50
src/cli.rs
50
src/cli.rs
@@ -27,6 +27,20 @@ pub enum Command {
|
||||
input: PathBuf,
|
||||
output_tree: PathBuf,
|
||||
},
|
||||
Gen {
|
||||
mode: GenMode,
|
||||
input: PathBuf,
|
||||
output: PathBuf,
|
||||
output_symbols: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, clap::ValueEnum)]
|
||||
pub enum GenMode {
|
||||
#[clap(name = "intermediate", alias = "i")]
|
||||
Intermediate,
|
||||
#[clap(name = "postfix", alias = "p")]
|
||||
Postfix,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
@@ -60,6 +74,12 @@ fn validate_inner(args: ArgsInner) -> Result<ArgsInner, clap::Error> {
|
||||
} => validate_lex(input, output_tokens, output_symbols)?,
|
||||
Command::Syn { input, output_tree } => validate_syn(input, output_tree)?,
|
||||
Command::Sem { input, output_tree } => validate_sem(input, output_tree)?,
|
||||
Command::Gen {
|
||||
mode,
|
||||
input,
|
||||
output,
|
||||
output_symbols,
|
||||
} => validate_gen(mode, input, output, output_symbols)?,
|
||||
};
|
||||
|
||||
Ok(args)
|
||||
@@ -129,3 +149,33 @@ fn validate_sem(input: &PathBuf, output_tree: &PathBuf) -> Result<(), clap::Erro
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_gen(
|
||||
_mode: &GenMode,
|
||||
input: &PathBuf,
|
||||
output: &PathBuf,
|
||||
output_symbols: &PathBuf,
|
||||
) -> Result<(), clap::Error> {
|
||||
if !input.is_file() {
|
||||
return Err(clap::Error::raw(
|
||||
clap::error::ErrorKind::InvalidValue,
|
||||
format!("Input file '{}' does not exist", input.display()),
|
||||
));
|
||||
}
|
||||
|
||||
if input == output {
|
||||
return Err(clap::Error::raw(
|
||||
clap::error::ErrorKind::InvalidValue,
|
||||
"Input and output files cannot be the same",
|
||||
));
|
||||
};
|
||||
|
||||
if input == output_symbols {
|
||||
return Err(clap::Error::raw(
|
||||
clap::error::ErrorKind::InvalidValue,
|
||||
"Input and output files cannot be the same",
|
||||
));
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
281
src/main.rs
281
src/main.rs
@@ -2,107 +2,19 @@ mod ast;
|
||||
mod cli;
|
||||
mod error;
|
||||
mod parse;
|
||||
mod representation;
|
||||
mod symbols;
|
||||
mod util;
|
||||
|
||||
use std::io::{self, Write};
|
||||
use std::{
|
||||
io::{self, Write},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use ast::{typed::TypedExpr, UntypedExpr};
|
||||
use cli::GenMode;
|
||||
use parse::parser::Parser;
|
||||
use symbols::SymbolsTable;
|
||||
|
||||
fn write_typed_expr(
|
||||
expr: &TypedExpr,
|
||||
symbols: &SymbolsTable,
|
||||
writer: &mut impl Write,
|
||||
prefix: &str,
|
||||
is_last: bool,
|
||||
) -> io::Result<()> {
|
||||
let branch = if is_last { "└──" } else { "├──" };
|
||||
|
||||
write!(writer, "{}{}", prefix, branch)?;
|
||||
|
||||
match expr {
|
||||
TypedExpr::Int { value, .. } => writeln!(writer, "<{}>", value),
|
||||
TypedExpr::Float { value, .. } => writeln!(writer, "<{}>", value),
|
||||
TypedExpr::Var { name, .. } => {
|
||||
let ty = symbols.resolve(*name).unwrap().ty.unwrap();
|
||||
writeln!(writer, "<id,{},{}>", name, ty)
|
||||
}
|
||||
TypedExpr::BinOp { lhs, op, rhs, .. } => {
|
||||
writeln!(writer, "<{}>", op)?;
|
||||
|
||||
let new_prefix = if is_last {
|
||||
format!("{} ", prefix)
|
||||
} else {
|
||||
format!("{}│ ", prefix)
|
||||
};
|
||||
|
||||
write_typed_expr(lhs, symbols, writer, &new_prefix, false)?;
|
||||
write_typed_expr(rhs, symbols, writer, &new_prefix, true)
|
||||
}
|
||||
TypedExpr::IntToFloat { value, .. } => {
|
||||
writeln!(writer, "i2f")?;
|
||||
|
||||
let new_prefix = if is_last {
|
||||
format!("{} ", prefix)
|
||||
} else {
|
||||
format!("{}│ ", prefix)
|
||||
};
|
||||
|
||||
write_typed_expr(value, symbols, writer, &new_prefix, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_typed_expr(
|
||||
expr: &TypedExpr,
|
||||
symbols: &SymbolsTable,
|
||||
writer: &mut impl Write,
|
||||
) -> io::Result<()> {
|
||||
write_typed_expr(expr, symbols, writer, "", true)
|
||||
}
|
||||
|
||||
fn write_untyped_expr(
|
||||
expr: &UntypedExpr,
|
||||
writer: &mut impl Write,
|
||||
prefix: &str,
|
||||
is_last: bool,
|
||||
) -> io::Result<()> {
|
||||
let branch = if is_last { "└──" } else { "├──" };
|
||||
|
||||
write!(writer, "{}{}", prefix, branch)?;
|
||||
|
||||
match expr {
|
||||
UntypedExpr::Int { value, .. } => writeln!(writer, "<{}>", value),
|
||||
UntypedExpr::Float { value, .. } => writeln!(writer, "<{}>", value),
|
||||
UntypedExpr::Var {
|
||||
name: id, typename, ..
|
||||
} => {
|
||||
write!(writer, "<id,{}", id)?;
|
||||
if let Some(typename) = typename {
|
||||
write!(writer, ",{}", typename)?;
|
||||
}
|
||||
writeln!(writer, ">")
|
||||
}
|
||||
UntypedExpr::BinOp { lhs, op, rhs, .. } => {
|
||||
writeln!(writer, "<{}>", op)?;
|
||||
|
||||
let new_prefix = if is_last {
|
||||
format!("{} ", prefix)
|
||||
} else {
|
||||
format!("{}│ ", prefix)
|
||||
};
|
||||
|
||||
write_untyped_expr(lhs, writer, &new_prefix, false)?;
|
||||
write_untyped_expr(rhs, writer, &new_prefix, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_untyped_expr(expr: &UntypedExpr, writer: &mut impl Write) -> io::Result<()> {
|
||||
write_untyped_expr(expr, writer, "", true)
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let args = cli::Args::parse();
|
||||
|
||||
@@ -112,66 +24,137 @@ fn main() -> anyhow::Result<()> {
|
||||
output_tokens,
|
||||
output_symbols,
|
||||
} => {
|
||||
let input = std::fs::read_to_string(input)?;
|
||||
let mut symbols = SymbolsTable::default();
|
||||
let tokens =
|
||||
parse::lexer::make_tokenizer(&input, &mut symbols).collect::<Result<Vec<_>, _>>();
|
||||
|
||||
match tokens {
|
||||
Ok(tokens) => {
|
||||
let mut writer_tokens =
|
||||
io::BufWriter::new(std::fs::File::create(output_tokens)?);
|
||||
|
||||
for (_, token, _) in tokens {
|
||||
writeln!(writer_tokens, "{token:>6} - {}", token.as_str())?;
|
||||
}
|
||||
|
||||
let mut writer_symbols =
|
||||
io::BufWriter::new(std::fs::File::create(output_symbols)?);
|
||||
for (name, data) in &symbols {
|
||||
writeln!(writer_symbols, "{name} -> {}", data)?;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("error: {}", e);
|
||||
}
|
||||
}
|
||||
lex_command(input, output_tokens, output_symbols)?;
|
||||
}
|
||||
cli::Command::Syn { input, output_tree } => {
|
||||
let input = std::fs::read_to_string(input)?;
|
||||
let mut symbols = SymbolsTable::default();
|
||||
let tokens = parse::lexer::make_tokenizer(&input, &mut symbols);
|
||||
|
||||
let mut parser = Parser::new(tokens);
|
||||
let res = parser.parse();
|
||||
|
||||
match res {
|
||||
Ok(expr) => {
|
||||
let mut writer_tree = io::BufWriter::new(std::fs::File::create(output_tree)?);
|
||||
print_untyped_expr(&expr, &mut writer_tree)?;
|
||||
}
|
||||
Err(e) => eprintln!("error: {}", e),
|
||||
}
|
||||
syn_command(input, output_tree)?;
|
||||
}
|
||||
cli::Command::Sem { input, output_tree } => {
|
||||
let input = std::fs::read_to_string(input)?;
|
||||
let mut symbols = SymbolsTable::default();
|
||||
let res = {
|
||||
let tokens = parse::lexer::make_tokenizer(&input, &mut symbols);
|
||||
let mut parser = Parser::new(tokens);
|
||||
parser.parse()
|
||||
}
|
||||
.and_then(|expr| ast::to_typed_expr(expr, &mut symbols));
|
||||
|
||||
match res {
|
||||
Ok(expr) => {
|
||||
let mut writer_tree = io::BufWriter::new(std::fs::File::create(output_tree)?);
|
||||
print_typed_expr(&expr, &symbols, &mut writer_tree)?;
|
||||
}
|
||||
Err(e) => eprintln!("error: {}", e),
|
||||
}
|
||||
sem_command(input, output_tree)?;
|
||||
}
|
||||
cli::Command::Gen {
|
||||
mode,
|
||||
input,
|
||||
output,
|
||||
output_symbols,
|
||||
} => {
|
||||
gen_command(mode, input, output, output_symbols)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn gen_command(
|
||||
mode: &GenMode,
|
||||
input: &Path,
|
||||
output: &Path,
|
||||
output_symbols: &Path,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let input = std::fs::read_to_string(input)?;
|
||||
let mut symbols = SymbolsTable::default();
|
||||
let typed_expr = match {
|
||||
let tokens = parse::lexer::make_tokenizer(&input, &mut symbols);
|
||||
let mut parser = Parser::new(tokens);
|
||||
parser.parse()
|
||||
}
|
||||
.and_then(|expr| ast::to_typed_expr(expr, &mut symbols))
|
||||
{
|
||||
Ok(expr) => expr,
|
||||
Err(e) => {
|
||||
eprintln!("error: {}", e);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let mut writer = io::BufWriter::new(std::fs::File::create(output)?);
|
||||
|
||||
match mode {
|
||||
GenMode::Intermediate => {
|
||||
let intermediate_exprs =
|
||||
representation::intermediate::to_intermediate_expr(typed_expr, &mut symbols);
|
||||
util::print_intermediate_exprs(&intermediate_exprs, &mut writer)?;
|
||||
}
|
||||
GenMode::Postfix => {
|
||||
util::print_postfix_exprs(&typed_expr, &mut writer)?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut writer_symbols = io::BufWriter::new(std::fs::File::create(output_symbols)?);
|
||||
for (name, data) in &symbols {
|
||||
writeln!(writer_symbols, "{name} -> {}", data)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sem_command(input: &Path, output_tree: &Path) -> Result<(), anyhow::Error> {
|
||||
let input = std::fs::read_to_string(input)?;
|
||||
let mut symbols = SymbolsTable::default();
|
||||
|
||||
let res = {
|
||||
let tokens = parse::lexer::make_tokenizer(&input, &mut symbols);
|
||||
let mut parser = Parser::new(tokens);
|
||||
parser.parse()
|
||||
}
|
||||
.and_then(|expr| ast::to_typed_expr(expr, &mut symbols));
|
||||
|
||||
match res {
|
||||
Ok(expr) => {
|
||||
let mut writer_tree = io::BufWriter::new(std::fs::File::create(output_tree)?);
|
||||
util::print_typed_expr(&expr, &symbols, &mut writer_tree)?;
|
||||
}
|
||||
Err(e) => eprintln!("error: {}", e),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn syn_command(input: &Path, output_tree: &Path) -> Result<(), anyhow::Error> {
|
||||
let input = std::fs::read_to_string(input)?;
|
||||
let mut symbols = SymbolsTable::default();
|
||||
|
||||
let tokens = parse::lexer::make_tokenizer(&input, &mut symbols);
|
||||
let mut parser = Parser::new(tokens);
|
||||
let res = parser.parse();
|
||||
|
||||
match res {
|
||||
Ok(expr) => {
|
||||
let mut writer_tree = io::BufWriter::new(std::fs::File::create(output_tree)?);
|
||||
util::print_untyped_expr(&expr, &mut writer_tree)?;
|
||||
}
|
||||
Err(e) => eprintln!("error: {}", e),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lex_command(
|
||||
input: &Path,
|
||||
output_tokens: &Path,
|
||||
output_symbols: &Path,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let input = std::fs::read_to_string(input)?;
|
||||
let mut symbols = SymbolsTable::default();
|
||||
let tokens = parse::lexer::make_tokenizer(&input, &mut symbols).collect::<Result<Vec<_>, _>>();
|
||||
|
||||
match tokens {
|
||||
Ok(tokens) => {
|
||||
let mut writer_tokens = io::BufWriter::new(std::fs::File::create(output_tokens)?);
|
||||
|
||||
for (_, token, _) in tokens {
|
||||
writeln!(writer_tokens, "{token:>6} - {}", token.as_str())?;
|
||||
}
|
||||
|
||||
let mut writer_symbols = io::BufWriter::new(std::fs::File::create(output_symbols)?);
|
||||
for (name, data) in &symbols {
|
||||
writeln!(writer_symbols, "{name} -> {}", data)?;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("error: {}", e);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ impl<'s, T: Iterator<Item = (usize, char)>> Lexer<'s, T> {
|
||||
if let Some(id) = self.symbols.get(&name) {
|
||||
Ok((start, Token::Name(id), end))
|
||||
} else {
|
||||
self.symbols.add(name.clone());
|
||||
let id = self.symbols.get(&name).unwrap();
|
||||
let id = self.symbols.add(name.clone());
|
||||
// let id = self.symbols.get(&name).unwrap();
|
||||
Ok((start, Token::Name(id), end))
|
||||
}
|
||||
}
|
||||
|
||||
90
src/representation/intermediate.rs
Normal file
90
src/representation/intermediate.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
use std::fmt;
|
||||
|
||||
use crate::{
|
||||
ast::{typed::TypedExpr, BinOp},
|
||||
symbols::{Symbol, SymbolsTable},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum IntermediateValue {
|
||||
Int { value: i64 },
|
||||
Float { value: f64 },
|
||||
Var { name: Symbol },
|
||||
}
|
||||
|
||||
impl fmt::Display for IntermediateValue {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
IntermediateValue::Int { value } => write!(f, "{}", value),
|
||||
IntermediateValue::Float { value } => write!(f, "{}", value),
|
||||
IntermediateValue::Var { name } => write!(f, "<id,{}>", name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum IntermediateExpr {
|
||||
IntToFloat {
|
||||
result: Symbol,
|
||||
value: IntermediateValue,
|
||||
},
|
||||
BinOp {
|
||||
result: Symbol,
|
||||
lhs: IntermediateValue,
|
||||
op: BinOp,
|
||||
rhs: IntermediateValue,
|
||||
},
|
||||
}
|
||||
|
||||
fn to_intermediate_expr_inner(
|
||||
expr: TypedExpr,
|
||||
symbols: &mut SymbolsTable,
|
||||
intermediate_var_counter: &mut usize,
|
||||
exprs: &mut Vec<IntermediateExpr>,
|
||||
) -> IntermediateValue {
|
||||
let ty = expr.ty(symbols);
|
||||
|
||||
match expr {
|
||||
TypedExpr::Int { value, .. } => IntermediateValue::Int { value },
|
||||
TypedExpr::Float { value, .. } => IntermediateValue::Float { value },
|
||||
TypedExpr::Var { name, .. } => IntermediateValue::Var { name },
|
||||
TypedExpr::BinOp { lhs, op, rhs, .. } => {
|
||||
let lhs = to_intermediate_expr_inner(*lhs, symbols, intermediate_var_counter, exprs);
|
||||
let rhs = to_intermediate_expr_inner(*rhs, symbols, intermediate_var_counter, exprs);
|
||||
|
||||
let result = symbols.add(format!("#T{}", intermediate_var_counter));
|
||||
symbols.resolve_mut(result).unwrap().ty = Some(ty);
|
||||
*intermediate_var_counter += 1;
|
||||
|
||||
exprs.push(IntermediateExpr::BinOp {
|
||||
result,
|
||||
lhs,
|
||||
op,
|
||||
rhs,
|
||||
});
|
||||
|
||||
IntermediateValue::Var { name: result }
|
||||
}
|
||||
TypedExpr::IntToFloat { value, .. } => {
|
||||
let value =
|
||||
to_intermediate_expr_inner(*value, symbols, intermediate_var_counter, exprs);
|
||||
|
||||
let result = symbols.add(format!("#T{}", intermediate_var_counter));
|
||||
symbols.resolve_mut(result).unwrap().ty = Some(ty);
|
||||
*intermediate_var_counter += 1;
|
||||
|
||||
exprs.push(IntermediateExpr::IntToFloat { result, value });
|
||||
|
||||
IntermediateValue::Var { name: result }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_intermediate_expr(expr: TypedExpr, symbols: &mut SymbolsTable) -> Vec<IntermediateExpr> {
|
||||
let mut exprs = Vec::new();
|
||||
let mut intermediate_var_counter = 0;
|
||||
|
||||
to_intermediate_expr_inner(expr, symbols, &mut intermediate_var_counter, &mut exprs);
|
||||
|
||||
exprs
|
||||
}
|
||||
1
src/representation/mod.rs
Normal file
1
src/representation/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod intermediate;
|
||||
@@ -19,12 +19,14 @@ pub struct SymbolData {
|
||||
|
||||
impl Display for SymbolData {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.id)?;
|
||||
let mut builder = f.debug_struct("symbol");
|
||||
builder.field("id", &self.id.0);
|
||||
|
||||
if let Some(ty) = self.ty {
|
||||
write!(f, ":{}", ty)?;
|
||||
builder.field("type", &ty);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
builder.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +50,7 @@ impl SymbolsTable {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, symbol: impl Into<String>) {
|
||||
pub fn add(&mut self, symbol: impl Into<String>) -> Symbol {
|
||||
let symbol = symbol.into();
|
||||
if let hash_map::Entry::Vacant(e) = self.symbols.entry(symbol.clone()) {
|
||||
e.insert(SymbolData {
|
||||
@@ -57,7 +59,11 @@ impl SymbolsTable {
|
||||
ty: None,
|
||||
});
|
||||
self.next_id += 1;
|
||||
|
||||
return Symbol(self.next_id - 1);
|
||||
}
|
||||
|
||||
self.get(&symbol).unwrap()
|
||||
}
|
||||
|
||||
pub fn get(&self, symbol: &str) -> Option<Symbol> {
|
||||
|
||||
154
src/util.rs
Normal file
154
src/util.rs
Normal file
@@ -0,0 +1,154 @@
|
||||
use std::io;
|
||||
|
||||
use crate::{
|
||||
ast::{typed::TypedExpr, BinOp, UntypedExpr},
|
||||
representation::intermediate::IntermediateExpr,
|
||||
symbols::SymbolsTable,
|
||||
};
|
||||
|
||||
pub fn print_intermediate_exprs(
|
||||
exprs: &[IntermediateExpr],
|
||||
writer: &mut impl io::Write,
|
||||
) -> io::Result<()> {
|
||||
for expr in exprs {
|
||||
match expr {
|
||||
IntermediateExpr::IntToFloat { result, value } => {
|
||||
writeln!(writer, "i2f <id,{}>, {}", result, value)?;
|
||||
}
|
||||
IntermediateExpr::BinOp {
|
||||
result,
|
||||
lhs,
|
||||
op,
|
||||
rhs,
|
||||
} => {
|
||||
writeln!(
|
||||
writer,
|
||||
"{} <id,{}>, {}, {}",
|
||||
match op {
|
||||
BinOp::Add => "add",
|
||||
BinOp::Sub => "sub",
|
||||
BinOp::Mul => "mul",
|
||||
BinOp::Div => "div",
|
||||
},
|
||||
result,
|
||||
lhs,
|
||||
rhs
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn print_postfix_exprs(expr: &TypedExpr, writer: &mut impl io::Write) -> io::Result<()> {
|
||||
match expr {
|
||||
TypedExpr::Int { value, .. } => write!(writer, "{} ", value)?,
|
||||
TypedExpr::Float { value, .. } => write!(writer, "{} ", value)?,
|
||||
TypedExpr::Var { name, .. } => write!(writer, "<id,{}> ", name)?,
|
||||
TypedExpr::BinOp { lhs, op, rhs, .. } => {
|
||||
print_postfix_exprs(lhs, writer)?;
|
||||
print_postfix_exprs(rhs, writer)?;
|
||||
write!(writer, "{} ", op)?;
|
||||
}
|
||||
TypedExpr::IntToFloat { value, .. } => {
|
||||
print_postfix_exprs(value, writer)?;
|
||||
write!(writer, "i2f ")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_typed_expr(
|
||||
expr: &TypedExpr,
|
||||
symbols: &SymbolsTable,
|
||||
writer: &mut impl io::Write,
|
||||
prefix: &str,
|
||||
is_last: bool,
|
||||
) -> io::Result<()> {
|
||||
let branch = if is_last { "└──" } else { "├──" };
|
||||
|
||||
write!(writer, "{}{}", prefix, branch)?;
|
||||
|
||||
match expr {
|
||||
TypedExpr::Int { value, .. } => writeln!(writer, "<{}>", value),
|
||||
TypedExpr::Float { value, .. } => writeln!(writer, "<{}>", value),
|
||||
TypedExpr::Var { name, .. } => {
|
||||
let ty = symbols.resolve(*name).unwrap().ty.unwrap();
|
||||
writeln!(writer, "<id,{},{}>", name, ty)
|
||||
}
|
||||
TypedExpr::BinOp { lhs, op, rhs, .. } => {
|
||||
writeln!(writer, "<{}>", op)?;
|
||||
|
||||
let new_prefix = if is_last {
|
||||
format!("{} ", prefix)
|
||||
} else {
|
||||
format!("{}│ ", prefix)
|
||||
};
|
||||
|
||||
write_typed_expr(lhs, symbols, writer, &new_prefix, false)?;
|
||||
write_typed_expr(rhs, symbols, writer, &new_prefix, true)
|
||||
}
|
||||
TypedExpr::IntToFloat { value, .. } => {
|
||||
writeln!(writer, "i2f")?;
|
||||
|
||||
let new_prefix = if is_last {
|
||||
format!("{} ", prefix)
|
||||
} else {
|
||||
format!("{}│ ", prefix)
|
||||
};
|
||||
|
||||
write_typed_expr(value, symbols, writer, &new_prefix, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_typed_expr(
|
||||
expr: &TypedExpr,
|
||||
symbols: &SymbolsTable,
|
||||
writer: &mut impl io::Write,
|
||||
) -> io::Result<()> {
|
||||
write_typed_expr(expr, symbols, writer, "", true)
|
||||
}
|
||||
|
||||
fn write_untyped_expr(
|
||||
expr: &UntypedExpr,
|
||||
writer: &mut impl io::Write,
|
||||
prefix: &str,
|
||||
is_last: bool,
|
||||
) -> io::Result<()> {
|
||||
let branch = if is_last { "└──" } else { "├──" };
|
||||
|
||||
write!(writer, "{}{}", prefix, branch)?;
|
||||
|
||||
match expr {
|
||||
UntypedExpr::Int { value, .. } => writeln!(writer, "<{}>", value),
|
||||
UntypedExpr::Float { value, .. } => writeln!(writer, "<{}>", value),
|
||||
UntypedExpr::Var {
|
||||
name: id, typename, ..
|
||||
} => {
|
||||
write!(writer, "<id,{}", id)?;
|
||||
if let Some(typename) = typename {
|
||||
write!(writer, ",{}", typename)?;
|
||||
}
|
||||
writeln!(writer, ">")
|
||||
}
|
||||
UntypedExpr::BinOp { lhs, op, rhs, .. } => {
|
||||
writeln!(writer, "<{}>", op)?;
|
||||
|
||||
let new_prefix = if is_last {
|
||||
format!("{} ", prefix)
|
||||
} else {
|
||||
format!("{}│ ", prefix)
|
||||
};
|
||||
|
||||
write_untyped_expr(lhs, writer, &new_prefix, false)?;
|
||||
write_untyped_expr(rhs, writer, &new_prefix, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_untyped_expr(expr: &UntypedExpr, writer: &mut impl io::Write) -> io::Result<()> {
|
||||
write_untyped_expr(expr, writer, "", true)
|
||||
}
|
||||
Reference in New Issue
Block a user