lab4.1
This commit is contained in:
@@ -54,7 +54,17 @@ impl fmt::Display for BinOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_typed_expr(expr: UntypedExpr, symbols: &SymbolsTable) -> error::Result<TypedExpr> {
|
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 {
|
let expr = match expr {
|
||||||
UntypedExpr::Int { span, value } => TypedExpr::Int { span, value },
|
UntypedExpr::Int { span, value } => TypedExpr::Int { span, value },
|
||||||
UntypedExpr::Float { span, value } => TypedExpr::Float { span, value },
|
UntypedExpr::Float { span, value } => TypedExpr::Float { span, value },
|
||||||
@@ -65,12 +75,28 @@ pub fn to_typed_expr(expr: UntypedExpr, symbols: &SymbolsTable) -> error::Result
|
|||||||
} => {
|
} => {
|
||||||
let ty = typename
|
let ty = typename
|
||||||
.and_then(|t| symbols.resolve(t))
|
.and_then(|t| symbols.resolve(t))
|
||||||
|
.map(|data| data.name.as_str())
|
||||||
.map(Type::from_str)
|
.map(Type::from_str)
|
||||||
.transpose()
|
.transpose()
|
||||||
.map_err(|e| SemanticError::new(span, e))?
|
.map_err(|e| SemanticError::new(span, e))?;
|
||||||
.unwrap_or(Type::Int);
|
{
|
||||||
|
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, ty }
|
TypedExpr::Var { span, name }
|
||||||
}
|
}
|
||||||
UntypedExpr::BinOp { span, lhs, op, rhs } => {
|
UntypedExpr::BinOp { span, lhs, op, rhs } => {
|
||||||
let rhs = *rhs;
|
let rhs = *rhs;
|
||||||
@@ -101,10 +127,39 @@ pub fn to_typed_expr(expr: UntypedExpr, symbols: &SymbolsTable) -> error::Result
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let lhs = to_typed_expr(lhs, symbols)?;
|
let lhs = convert_to_typed_expr(lhs, symbols)?;
|
||||||
let rhs = to_typed_expr(rhs, symbols)?;
|
let rhs = convert_to_typed_expr(rhs, symbols)?;
|
||||||
|
|
||||||
let (lhs, rhs) = match (lhs.ty(), rhs.ty()) {
|
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::Int, Type::Int) => (lhs, rhs),
|
||||||
(Type::Float, Type::Float) => (lhs, rhs),
|
(Type::Float, Type::Float) => (lhs, rhs),
|
||||||
(Type::Int, Type::Float) => {
|
(Type::Int, Type::Float) => {
|
||||||
@@ -124,6 +179,7 @@ pub fn to_typed_expr(expr: UntypedExpr, symbols: &SymbolsTable) -> error::Result
|
|||||||
rhs: Box::new(rhs),
|
rhs: Box::new(rhs),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TypedExpr::IntToFloat { .. } => expr,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
use std::{fmt, str::FromStr};
|
use std::{fmt, str::FromStr};
|
||||||
|
|
||||||
use crate::{error::SemanticErrorKind, symbols::Symbol};
|
use crate::{
|
||||||
|
error::SemanticErrorKind,
|
||||||
|
symbols::{Symbol, SymbolsTable},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{BinOp, Span};
|
use super::{BinOp, Span};
|
||||||
|
|
||||||
@@ -44,7 +47,6 @@ pub enum TypedExpr {
|
|||||||
Var {
|
Var {
|
||||||
span: Span,
|
span: Span,
|
||||||
name: Symbol,
|
name: Symbol,
|
||||||
ty: Type,
|
|
||||||
},
|
},
|
||||||
BinOp {
|
BinOp {
|
||||||
span: Span,
|
span: Span,
|
||||||
@@ -74,12 +76,16 @@ impl TypedExpr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ty(&self) -> Type {
|
pub fn ty(&self, symbols: &SymbolsTable) -> Type {
|
||||||
match self {
|
match self {
|
||||||
TypedExpr::Int { .. } => Type::Int,
|
TypedExpr::Int { .. } => Type::Int,
|
||||||
TypedExpr::Float { .. } => Type::Float,
|
TypedExpr::Float { .. } => Type::Float,
|
||||||
TypedExpr::Var { ty, .. } => *ty,
|
TypedExpr::Var { name, .. } => symbols
|
||||||
TypedExpr::BinOp { rhs, .. } => rhs.ty(),
|
.resolve(*name)
|
||||||
|
.expect("symbol not found")
|
||||||
|
.ty
|
||||||
|
.expect("type not found"),
|
||||||
|
TypedExpr::BinOp { rhs, .. } => rhs.ty(symbols),
|
||||||
TypedExpr::IntToFloat { .. } => Type::Float,
|
TypedExpr::IntToFloat { .. } => Type::Float,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ pub struct SemanticError {
|
|||||||
pub enum SemanticErrorKind {
|
pub enum SemanticErrorKind {
|
||||||
UnknownType(String),
|
UnknownType(String),
|
||||||
DivisionByZero,
|
DivisionByZero,
|
||||||
|
DuplicateSymbol(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
@@ -197,6 +198,7 @@ impl fmt::Display for SemanticErrorKind {
|
|||||||
match self {
|
match self {
|
||||||
SemanticErrorKind::UnknownType(s) => write!(f, "unknown type '{}'", s),
|
SemanticErrorKind::UnknownType(s) => write!(f, "unknown type '{}'", s),
|
||||||
SemanticErrorKind::DivisionByZero => write!(f, "division by zero"),
|
SemanticErrorKind::DivisionByZero => write!(f, "division by zero"),
|
||||||
|
SemanticErrorKind::DuplicateSymbol(s) => write!(f, "duplicate symbol '{}'", s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
src/main.rs
28
src/main.rs
@@ -12,6 +12,7 @@ use symbols::SymbolsTable;
|
|||||||
|
|
||||||
fn write_typed_expr(
|
fn write_typed_expr(
|
||||||
expr: &TypedExpr,
|
expr: &TypedExpr,
|
||||||
|
symbols: &SymbolsTable,
|
||||||
writer: &mut impl Write,
|
writer: &mut impl Write,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
is_last: bool,
|
is_last: bool,
|
||||||
@@ -23,8 +24,9 @@ fn write_typed_expr(
|
|||||||
match expr {
|
match expr {
|
||||||
TypedExpr::Int { value, .. } => writeln!(writer, "<{}>", value),
|
TypedExpr::Int { value, .. } => writeln!(writer, "<{}>", value),
|
||||||
TypedExpr::Float { value, .. } => writeln!(writer, "<{}>", value),
|
TypedExpr::Float { value, .. } => writeln!(writer, "<{}>", value),
|
||||||
TypedExpr::Var { name: id, ty, .. } => {
|
TypedExpr::Var { name, .. } => {
|
||||||
writeln!(writer, "<id,{},{}>", id, ty)
|
let ty = symbols.resolve(*name).unwrap().ty.unwrap();
|
||||||
|
writeln!(writer, "<id,{},{}>", name, ty)
|
||||||
}
|
}
|
||||||
TypedExpr::BinOp { lhs, op, rhs, .. } => {
|
TypedExpr::BinOp { lhs, op, rhs, .. } => {
|
||||||
writeln!(writer, "<{}>", op)?;
|
writeln!(writer, "<{}>", op)?;
|
||||||
@@ -35,8 +37,8 @@ fn write_typed_expr(
|
|||||||
format!("{}│ ", prefix)
|
format!("{}│ ", prefix)
|
||||||
};
|
};
|
||||||
|
|
||||||
write_typed_expr(lhs, writer, &new_prefix, false)?;
|
write_typed_expr(lhs, symbols, writer, &new_prefix, false)?;
|
||||||
write_typed_expr(rhs, writer, &new_prefix, true)
|
write_typed_expr(rhs, symbols, writer, &new_prefix, true)
|
||||||
}
|
}
|
||||||
TypedExpr::IntToFloat { value, .. } => {
|
TypedExpr::IntToFloat { value, .. } => {
|
||||||
writeln!(writer, "i2f")?;
|
writeln!(writer, "i2f")?;
|
||||||
@@ -47,13 +49,17 @@ fn write_typed_expr(
|
|||||||
format!("{}│ ", prefix)
|
format!("{}│ ", prefix)
|
||||||
};
|
};
|
||||||
|
|
||||||
write_typed_expr(value, writer, &new_prefix, true)
|
write_typed_expr(value, symbols, writer, &new_prefix, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_typed_expr(expr: &TypedExpr, writer: &mut impl Write) -> io::Result<()> {
|
fn print_typed_expr(
|
||||||
write_typed_expr(expr, writer, "", true)
|
expr: &TypedExpr,
|
||||||
|
symbols: &SymbolsTable,
|
||||||
|
writer: &mut impl Write,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
write_typed_expr(expr, symbols, writer, "", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_untyped_expr(
|
fn write_untyped_expr(
|
||||||
@@ -122,8 +128,8 @@ fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let mut writer_symbols =
|
let mut writer_symbols =
|
||||||
io::BufWriter::new(std::fs::File::create(output_symbols)?);
|
io::BufWriter::new(std::fs::File::create(output_symbols)?);
|
||||||
for (name, id) in &symbols {
|
for (name, data) in &symbols {
|
||||||
writeln!(writer_symbols, "{name} -> {id}")?;
|
writeln!(writer_symbols, "{name} -> {}", data)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -155,12 +161,12 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let mut parser = Parser::new(tokens);
|
let mut parser = Parser::new(tokens);
|
||||||
parser.parse()
|
parser.parse()
|
||||||
}
|
}
|
||||||
.and_then(|expr| ast::to_typed_expr(expr, &symbols));
|
.and_then(|expr| ast::to_typed_expr(expr, &mut symbols));
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok(expr) => {
|
Ok(expr) => {
|
||||||
let mut writer_tree = io::BufWriter::new(std::fs::File::create(output_tree)?);
|
let mut writer_tree = io::BufWriter::new(std::fs::File::create(output_tree)?);
|
||||||
print_typed_expr(&expr, &mut writer_tree)?;
|
print_typed_expr(&expr, &symbols, &mut writer_tree)?;
|
||||||
}
|
}
|
||||||
Err(e) => eprintln!("error: {}", e),
|
Err(e) => eprintln!("error: {}", e),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,29 @@ use std::{
|
|||||||
fmt::Display,
|
fmt::Display,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::ast::typed::Type;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Symbol(usize);
|
pub struct Symbol(usize);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SymbolData {
|
||||||
|
pub id: Symbol,
|
||||||
|
pub name: String,
|
||||||
|
pub ty: Option<Type>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for SymbolData {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.id)?;
|
||||||
|
if let Some(ty) = self.ty {
|
||||||
|
write!(f, ":{}", ty)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Symbol {
|
impl Display for Symbol {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{}", self.0)
|
write!(f, "{}", self.0)
|
||||||
@@ -16,7 +36,7 @@ impl Display for Symbol {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SymbolsTable {
|
pub struct SymbolsTable {
|
||||||
symbols: HashMap<String, Symbol>,
|
symbols: HashMap<String, SymbolData>,
|
||||||
next_id: usize,
|
next_id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,24 +49,43 @@ impl SymbolsTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, symbol: impl Into<String>) {
|
pub fn add(&mut self, symbol: impl Into<String>) {
|
||||||
if let hash_map::Entry::Vacant(e) = self.symbols.entry(symbol.into()) {
|
let symbol = symbol.into();
|
||||||
e.insert(Symbol(self.next_id));
|
if let hash_map::Entry::Vacant(e) = self.symbols.entry(symbol.clone()) {
|
||||||
|
e.insert(SymbolData {
|
||||||
|
id: Symbol(self.next_id),
|
||||||
|
name: symbol,
|
||||||
|
ty: None,
|
||||||
|
});
|
||||||
self.next_id += 1;
|
self.next_id += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, symbol: &str) -> Option<Symbol> {
|
pub fn get(&self, symbol: &str) -> Option<Symbol> {
|
||||||
self.symbols.get(symbol).copied()
|
self.symbols.get(symbol).map(|data| data.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve(&self, symbol: Symbol) -> Option<&str> {
|
pub fn resolve(&self, symbol: Symbol) -> Option<&SymbolData> {
|
||||||
self.symbols.iter().find_map(|(name, id)| {
|
self.symbols.iter().find_map(
|
||||||
if *id == symbol {
|
|(_name, data)| {
|
||||||
Some(name.as_str())
|
if data.id == symbol {
|
||||||
|
Some(data)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_mut(&mut self, symbol: Symbol) -> Option<&mut SymbolData> {
|
||||||
|
self.symbols.iter_mut().find_map(
|
||||||
|
|(_name, data)| {
|
||||||
|
if data.id == symbol {
|
||||||
|
Some(data)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,8 +96,8 @@ impl Default for SymbolsTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IntoIterator for SymbolsTable {
|
impl IntoIterator for SymbolsTable {
|
||||||
type Item = (String, Symbol);
|
type Item = (String, SymbolData);
|
||||||
type IntoIter = hash_map::IntoIter<String, Symbol>;
|
type IntoIter = hash_map::IntoIter<String, SymbolData>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.symbols.into_iter()
|
self.symbols.into_iter()
|
||||||
@@ -66,8 +105,8 @@ impl IntoIterator for SymbolsTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoIterator for &'a SymbolsTable {
|
impl<'a> IntoIterator for &'a SymbolsTable {
|
||||||
type Item = (&'a String, &'a Symbol);
|
type Item = (&'a String, &'a SymbolData);
|
||||||
type IntoIter = hash_map::Iter<'a, String, Symbol>;
|
type IntoIter = hash_map::Iter<'a, String, SymbolData>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.symbols.iter()
|
self.symbols.iter()
|
||||||
|
|||||||
Reference in New Issue
Block a user