1
0
Files
developing-compilers/src/ast/mod.rs
2024-11-10 10:34:38 +03:00

196 lines
5.5 KiB
Rust

pub mod typed;
pub mod untyped;
use core::fmt;
use std::str::FromStr;
use typed::{Type, TypedExpr};
pub use untyped::UntypedExpr;
use crate::{
error::{self, SemanticError, SemanticErrorKind},
symbols::SymbolsTable,
};
#[derive(Debug, Copy, Clone)]
pub struct Span {
pub start: usize,
pub end: usize,
}
impl Span {
pub fn new(start: usize, end: usize) -> Self {
Self { start, end }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinOp {
Add,
Sub,
Mul,
Div,
}
impl BinOp {
pub fn precedence(&self) -> u8 {
match self {
BinOp::Add => 1,
BinOp::Sub => 1,
BinOp::Mul => 2,
BinOp::Div => 2,
}
}
}
impl fmt::Display for BinOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
match self {
BinOp::Add => f.write_str("add"),
BinOp::Sub => f.write_str("sub"),
BinOp::Mul => f.write_str("mul"),
BinOp::Div => f.write_str("div"),
}
} else {
match self {
BinOp::Add => f.write_str("+"),
BinOp::Sub => f.write_str("-"),
BinOp::Mul => f.write_str("*"),
BinOp::Div => f.write_str("/"),
}
}
}
}
pub fn to_typed_expr(expr: UntypedExpr, symbols: &mut SymbolsTable) -> error::Result<TypedExpr> {
let expr = convert_to_typed_expr(expr, symbols)?;
let expr = coerce_types(expr, symbols)?;
Ok(expr)
}
fn convert_to_typed_expr(
expr: UntypedExpr,
symbols: &mut SymbolsTable,
) -> error::Result<TypedExpr> {
let expr = match expr {
UntypedExpr::Int { span, value } => TypedExpr::Int { span, value },
UntypedExpr::Float { span, value } => TypedExpr::Float { span, value },
UntypedExpr::Var {
span,
name,
typename,
} => {
let ty = typename
.and_then(|t| symbols.resolve(&t))
.map(|data| data.name.as_str())
.map(Type::from_str)
.transpose()
.map_err(|e| SemanticError::new(span, e))?;
{
let symbol = symbols.resolve_mut(&name).unwrap();
match (symbol.ty, ty) {
(Some(ty), Some(ty2)) if ty != ty2 => {
return Err(SemanticError::new(
span,
SemanticErrorKind::DuplicateSymbol(symbol.name.clone()),
)
.into())
}
(None, Some(ty)) => {
symbol.ty = Some(ty);
}
_ => {}
}
}
TypedExpr::Var { span, name }
}
UntypedExpr::BinOp { span, lhs, op, rhs } => {
let rhs = *rhs;
let lhs = *lhs;
match op {
BinOp::Div
if matches!(rhs, UntypedExpr::Int { .. } | UntypedExpr::Float { .. }) =>
{
match &rhs {
UntypedExpr::Int { span, value } if *value == 0 => {
return Err(SemanticError::new(
*span,
SemanticErrorKind::DivisionByZero,
)
.into())
}
UntypedExpr::Float { span, value } if *value == 0.0 => {
return Err(SemanticError::new(
*span,
SemanticErrorKind::DivisionByZero,
)
.into())
}
_ => {}
}
}
_ => {}
}
let lhs = convert_to_typed_expr(lhs, symbols)?;
let rhs = convert_to_typed_expr(rhs, symbols)?;
TypedExpr::BinOp {
span,
lhs: Box::new(lhs),
op,
rhs: Box::new(rhs),
}
}
};
Ok(expr)
}
fn coerce_types(expr: TypedExpr, symbols: &mut SymbolsTable) -> error::Result<TypedExpr> {
let expr = match expr {
TypedExpr::Int { .. } => expr,
TypedExpr::Float { .. } => expr,
TypedExpr::Var { name, .. } => {
let symbol = symbols.resolve_mut(&name).unwrap();
if symbol.ty.is_none() {
symbol.ty = Some(Type::Int);
}
expr
}
TypedExpr::BinOp { lhs, rhs, op, span } => {
let lhs = coerce_types(*lhs, symbols)?;
let rhs = coerce_types(*rhs, symbols)?;
let (lhs, rhs) = match (lhs.ty(symbols), rhs.ty(symbols)) {
(Type::Int, Type::Int) => (lhs, rhs),
(Type::Float, Type::Float) => (lhs, rhs),
(Type::Int, Type::Float) => {
let lhs = TypedExpr::cast_to_float(lhs);
(lhs, rhs)
}
(Type::Float, Type::Int) => {
let rhs = TypedExpr::cast_to_float(rhs);
(lhs, rhs)
}
};
TypedExpr::BinOp {
span,
lhs: Box::new(lhs),
op,
rhs: Box::new(rhs),
}
}
TypedExpr::IntToFloat { .. } => expr,
};
Ok(expr)
}