1
0

refactor 1

This commit is contained in:
2024-11-13 12:32:09 +03:00
parent 0f31e7a52e
commit 60001f0bb4
8 changed files with 310 additions and 240 deletions

55
Cargo.lock generated
View File

@@ -4,9 +4,9 @@ version = 3
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.15" version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"anstyle-parse", "anstyle-parse",
@@ -19,43 +19,43 @@ dependencies = [
[[package]] [[package]]
name = "anstyle" name = "anstyle"
version = "1.0.8" version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]] [[package]]
name = "anstyle-parse" name = "anstyle-parse"
version = "0.2.5" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [ dependencies = [
"utf8parse", "utf8parse",
] ]
[[package]] [[package]]
name = "anstyle-query" name = "anstyle-query"
version = "1.1.1" version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
name = "anstyle-wincon" name = "anstyle-wincon"
version = "3.0.4" version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.89" version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
@@ -89,9 +89,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.19" version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@@ -99,9 +99,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.19" version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@@ -129,9 +129,9 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]] [[package]]
name = "colorchoice" name = "colorchoice"
version = "1.0.2" version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]] [[package]]
name = "crossterm" name = "crossterm"
@@ -166,6 +166,7 @@ dependencies = [
"byteorder", "byteorder",
"clap", "clap",
"inquire", "inquire",
"integer-encoding",
"itertools", "itertools",
"thiserror", "thiserror",
] ]
@@ -223,6 +224,12 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "integer-encoding"
version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d762194228a2f1c11063e46e32e5acb96e66e906382b9eb5441f2e0504bbd5a"
[[package]] [[package]]
name = "is_terminal_polyfill" name = "is_terminal_polyfill"
version = "1.70.1" version = "1.70.1"
@@ -312,9 +319,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.86" version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@@ -489,9 +496,9 @@ dependencies = [
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]

View File

@@ -8,5 +8,6 @@ anyhow = "1.0.89"
byteorder = "1.5.0" byteorder = "1.5.0"
clap = { version = "4.5.19", features = ["derive"] } clap = { version = "4.5.19", features = ["derive"] }
inquire = "0.7.5" inquire = "0.7.5"
integer-encoding = "4.0.2"
itertools = "0.13.0" itertools = "0.13.0"
thiserror = "2.0.3" thiserror = "2.0.3"

144
src/interpreter/mod.rs Normal file
View File

@@ -0,0 +1,144 @@
mod value;
use std::collections::HashMap;
use anyhow::Context;
pub use value::Value;
use crate::ast::BinOp;
use crate::ast::typed::Type;
use crate::representation::intermediate::{IntermediateExpr, IntermediateValue};
use crate::symbols::{Symbol, SymbolsTable};
pub struct Interpreter<I> {
exprs: Vec<IntermediateExpr>,
symbols: SymbolsTable,
initializer: I,
}
type Variables = HashMap<Symbol, Value>;
impl<I> Interpreter<I>
where
I: Fn(&Type, &str) -> Value,
{
pub fn new(exprs: Vec<IntermediateExpr>, symbols: SymbolsTable, initializer: I) -> Self {
Self {
symbols,
exprs,
initializer,
}
}
pub fn run(&mut self) -> anyhow::Result<Option<Value>> {
let mut variables = self.initialize_variables()?;
let mut last_value = None;
for expr in &self.exprs {
let (result, value) = match expr {
IntermediateExpr::IntToFloat { result, value } => {
let value = Self::intermediate_value(&variables, value)?;
(result, self.int2float(value))
},
IntermediateExpr::BinOp {
result,
lhs,
op,
rhs,
} => {
let lhs = Self::intermediate_value(&variables, lhs)?;
let rhs = Self::intermediate_value(&variables, rhs)?;
(result, self.bin_op(lhs, op, rhs)?)
},
IntermediateExpr::Identity { result, value } => {
let value = Self::intermediate_value(&variables, value)?;
(result, self.identity(value))
},
};
Self::store(&mut variables, result, value)?;
last_value = Some(value);
}
Ok(last_value)
}
fn initialize_variables(&self) -> anyhow::Result<Variables> {
let mut variables = Variables::new();
for (_, data) in &self.symbols {
if data.ty.is_none() {
anyhow::bail!("type not found for '{}'", data.name);
}
if !data.temporary {
variables.insert(data.id, (self.initializer)(&data.ty.unwrap(), &data.name));
} else {
variables.insert(data.id, match data.ty {
None => continue,
Some(Type::Int) => Value::Int(0),
Some(Type::Float) => Value::Float(0.0),
});
};
}
Ok(variables)
}
fn int2float(&self, value: Value) -> Value {
match value {
Value::Int(v) => Value::Float(v as f64),
_ => value,
}
}
fn identity(&self, value: Value) -> Value {
value
}
fn bin_op(&self, lhs: Value, op: &BinOp, rhs: Value) -> anyhow::Result<Value> {
match (lhs, rhs) {
(Value::Int(lhs), Value::Int(rhs)) => Ok(Value::Int(match op {
BinOp::Add => lhs + rhs,
BinOp::Sub => lhs - rhs,
BinOp::Mul => lhs * rhs,
BinOp::Div => lhs / rhs,
})),
(Value::Float(lhs), Value::Float(rhs)) => Ok(Value::Float(match op {
BinOp::Add => lhs + rhs,
BinOp::Sub => lhs - rhs,
BinOp::Mul => lhs * rhs,
BinOp::Div => lhs / rhs,
})),
_ => Err(anyhow::anyhow!("invalid types for binary operation")),
}
}
fn intermediate_value(
variables: &Variables,
value: &IntermediateValue,
) -> anyhow::Result<Value> {
Ok(match value {
IntermediateValue::Int { value } => Value::Int(*value),
IntermediateValue::Float { value } => Value::Float(*value),
IntermediateValue::Var { name } => Self::load(variables, name)?,
})
}
fn load(variables: &Variables, symbol: &Symbol) -> anyhow::Result<Value> {
let symbol_value = variables.get(symbol).context("no such variable")?;
Ok(*symbol_value)
}
fn store(variables: &mut Variables, symbol: &Symbol, value: Value) -> anyhow::Result<()> {
let symbol_value = variables.get_mut(symbol).context("no such variable")?;
match (symbol_value, value) {
(Value::Int(v), Value::Int(a)) => *v = a,
(Value::Float(v), Value::Float(a)) => *v = a,
_ => return Err(anyhow::anyhow!("invalid types for assignment")),
};
Ok(())
}
}

34
src/interpreter/value.rs Normal file
View File

@@ -0,0 +1,34 @@
use std::fmt;
#[derive(Debug, Clone, Copy)]
pub enum Value {
Int(i64),
Float(f64),
}
impl From<i64> for Value {
fn from(value: i64) -> Self {
Self::Int(value)
}
}
impl From<f64> for Value {
fn from(value: f64) -> Self {
Self::Float(value)
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::Int(v) => write!(f, "{}", v),
Value::Float(v) => {
if v == &v.trunc() {
write!(f, "{}.0", v)
} else {
write!(f, "{}", v)
}
},
}
}
}

View File

@@ -1,5 +1,6 @@
pub mod ast; pub mod ast;
pub mod error; pub mod error;
pub mod interpreter;
pub mod parse; pub mod parse;
pub mod representation; pub mod representation;
pub mod symbols; pub mod symbols;

View File

@@ -1,18 +1,16 @@
mod cli; mod cli;
use std::collections::HashMap; use std::fs;
use std::io::{self, Write}; use std::io::{self, Write};
use std::path::Path; use std::path::Path;
use std::{fmt, fs};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use cli::GenMode; use cli::GenMode;
use developing_compilers::ast::BinOp;
use developing_compilers::ast::typed::Type; use developing_compilers::ast::typed::Type;
use developing_compilers::representation::intermediate::{IntermediateExpr, IntermediateValue}; use developing_compilers::interpreter::{Interpreter, Value};
use developing_compilers::symbols::Symbol; use developing_compilers::representation::intermediate::IntermediateExpr;
use developing_compilers::*; use developing_compilers::*;
use inquire::CustomType; use inquire::CustomType;
use integer_encoding::{VarIntReader, VarIntWriter};
use parse::parser::Parser; use parse::parser::Parser;
use symbols::SymbolsTable; use symbols::SymbolsTable;
@@ -44,175 +42,42 @@ fn main() -> anyhow::Result<()> {
if let Err(e) = result { if let Err(e) = result {
eprintln!("error: {}", e); eprintln!("error: {}", e);
return Ok(());
} }
Ok(()) Ok(())
} }
fn int_command(input: &Path) -> Result<(), anyhow::Error> { fn int_command(input: &Path) -> Result<(), anyhow::Error> {
enum VarValue {
Int(i64),
Float(f64),
}
impl fmt::Display for VarValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
VarValue::Int(v) => write!(f, "{}", v),
VarValue::Float(v) => {
if v == &v.trunc() {
write!(f, "{}.0", v)
} else {
write!(f, "{}", v)
}
},
}
}
}
fn value_as_i64(value: &IntermediateValue, vars: &HashMap<Symbol, VarValue>) -> i64 {
match value {
IntermediateValue::Int { value } => *value,
IntermediateValue::Var { name } => match vars.get(name) {
Some(VarValue::Int(v)) => *v,
_ => unreachable!(),
},
_ => unreachable!(),
}
}
fn value_as_f64(value: &IntermediateValue, vars: &HashMap<Symbol, VarValue>) -> f64 {
match value {
IntermediateValue::Float { value } => *value,
IntermediateValue::Var { name } => match vars.get(name) {
Some(VarValue::Float(v)) => *v,
_ => unreachable!(),
},
_ => unreachable!(),
}
}
let (symbols, ir) = { let (symbols, ir) = {
let mut reader = io::BufReader::new(fs::File::open(input)?); let mut reader = io::BufReader::new(fs::File::open(input)?);
let symbols = SymbolsTable::from_reader(&mut reader)?; let symbols = SymbolsTable::read(&mut reader)?;
let n = reader.read_u64::<BigEndian>()?; let n = reader.read_varint::<u64>()?;
let mut ir = Vec::with_capacity(n as usize); let mut ir = Vec::with_capacity(n as usize);
for _ in 0..n { for _ in 0..n {
ir.push(IntermediateExpr::from_reader(&mut reader)?); ir.push(IntermediateExpr::read(&mut reader)?);
} }
(symbols, ir) (symbols, ir)
}; };
let mut vars = HashMap::new(); let mut interpreter = Interpreter::new(ir, symbols, |ty, name| match ty {
for (_, data) in &symbols { Type::Int => Value::Int(
let value = match data.ty { CustomType::new(&format!("Input int {}", name))
Some(Type::Int) if !data.temporary => VarValue::Int( .with_default(0)
CustomType::new(&format!("Input int {}", data.name)) .prompt()
.with_default(0) .unwrap_or_default(),
.prompt()?, ),
), Type::Float => Value::Float(
Some(Type::Float) if !data.temporary => VarValue::Float( CustomType::new(&format!("Input float {}", name))
CustomType::new(&format!("Input float {}", data.name)) .with_default(0.0)
.with_default(0.0) .prompt()
.prompt()?, .unwrap_or_default(),
), ),
Some(Type::Int) => VarValue::Int(0), });
Some(Type::Float) => VarValue::Float(0.0),
None => continue,
};
vars.insert(data.id, value);
}
let mut last_result = None; let result = interpreter.run()?;
for expr in ir {
match expr {
IntermediateExpr::IntToFloat { result, value } => {
let value = value_as_i64(&value, &vars) as f64;
match vars.get_mut(&result) { if let Some(result) = result {
Some(VarValue::Float(v)) => *v = value, println!("Result: {}", result);
_ => unreachable!(),
};
last_result = Some(result);
},
IntermediateExpr::BinOp {
result,
lhs,
op,
rhs,
} if symbols.type_of(&result) == Some(Type::Int) => {
let lhs = value_as_i64(&lhs, &vars);
let rhs = value_as_i64(&rhs, &vars);
let value = match op {
BinOp::Add => lhs + rhs,
BinOp::Sub => lhs - rhs,
BinOp::Mul => lhs * rhs,
BinOp::Div => lhs / rhs,
};
match vars.get_mut(&result) {
Some(VarValue::Int(v)) => *v = value,
_ => unreachable!(),
};
last_result = Some(result);
},
IntermediateExpr::BinOp {
result,
lhs,
op,
rhs,
} if symbols.type_of(&result) == Some(Type::Float) => {
let lhs = value_as_f64(&lhs, &vars);
let rhs = value_as_f64(&rhs, &vars);
let value = match op {
BinOp::Add => lhs + rhs,
BinOp::Sub => lhs - rhs,
BinOp::Mul => lhs * rhs,
BinOp::Div => lhs / rhs,
};
match vars.get_mut(&result) {
Some(VarValue::Float(v)) => *v = value,
_ => unreachable!(),
};
last_result = Some(result);
},
IntermediateExpr::Identity { result, value }
if symbols.type_of(&result) == Some(Type::Float) =>
{
let value = value_as_f64(&value, &vars);
match vars.get_mut(&result) {
Some(VarValue::Float(v)) => *v = value,
_ => unreachable!(),
};
last_result = Some(result);
},
IntermediateExpr::Identity { result, value }
if symbols.type_of(&result) == Some(Type::Int) =>
{
let value = value_as_i64(&value, &vars);
match vars.get_mut(&result) {
Some(VarValue::Int(v)) => *v = value,
_ => unreachable!(),
};
last_result = Some(result);
},
_ => unreachable!(),
}
}
if let Some(result) = last_result {
println!("Result: {}", vars.get(&result).unwrap());
} else { } else {
println!("No result"); println!("No result");
} }
@@ -243,10 +108,10 @@ fn com_command(optimize: bool, input: &Path, output: &Path) -> Result<(), anyhow
} }
let mut writer = io::BufWriter::new(fs::File::create(output)?); let mut writer = io::BufWriter::new(fs::File::create(output)?);
symbols.to_writer(&mut writer)?; symbols.write(&mut writer)?;
writer.write_u64::<BigEndian>(ir.len() as u64)?; writer.write_varint::<u64>(ir.len() as u64)?;
for expr in ir { for expr in ir {
expr.to_writer(&mut writer)?; expr.write(&mut writer)?;
} }
Ok(()) Ok(())

View File

@@ -1,13 +1,14 @@
use std::{fmt, io}; use std::{fmt, io};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use integer_encoding::{VarIntReader, VarIntWriter};
use crate::ast::BinOp; use crate::ast::BinOp;
use crate::ast::typed::TypedExpr; use crate::ast::typed::TypedExpr;
use crate::representation::util::TempVarContext; use crate::representation::util::TempVarContext;
use crate::symbols::{Symbol, SymbolsTable}; use crate::symbols::{Symbol, SymbolsTable};
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum IntermediateValue { pub enum IntermediateValue {
Int { value: i64 }, Int { value: i64 },
Float { value: f64 }, Float { value: f64 },
@@ -23,29 +24,29 @@ impl IntermediateValue {
} }
} }
pub fn to_writer(&self, writer: &mut impl io::Write) -> io::Result<()> { pub fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
writer.write_u8(self.as_u8())?; writer.write_u8(self.as_u8())?;
match self { match self {
IntermediateValue::Int { value } => writer.write_i64::<BigEndian>(*value)?, IntermediateValue::Int { value } => _ = writer.write_varint(*value)?,
IntermediateValue::Float { value } => writer.write_f64::<BigEndian>(*value)?, IntermediateValue::Float { value } => writer.write_f64::<BigEndian>(*value)?,
IntermediateValue::Var { name } => writer.write_u64::<BigEndian>(name.into())?, IntermediateValue::Var { name } => _ = name.write(writer),
} }
Ok(()) Ok(())
} }
pub fn from_reader(reader: &mut impl io::Read) -> io::Result<Self> { pub fn read(reader: &mut impl io::Read) -> io::Result<Self> {
let b = reader.read_u8()?; let b = reader.read_u8()?;
match b { match b {
b'i' => Ok(IntermediateValue::Int { b'i' => Ok(IntermediateValue::Int {
value: reader.read_i64::<BigEndian>()?, value: reader.read_varint()?,
}), }),
b'f' => Ok(IntermediateValue::Float { b'f' => Ok(IntermediateValue::Float {
value: reader.read_f64::<BigEndian>()?, value: reader.read_f64::<BigEndian>()?,
}), }),
b'v' => Ok(IntermediateValue::Var { b'v' => Ok(IntermediateValue::Var {
name: reader.read_u64::<BigEndian>()?.into(), name: Symbol::read(reader)?,
}), }),
b => Err(io::Error::new( b => Err(io::Error::new(
io::ErrorKind::InvalidData, io::ErrorKind::InvalidData,
@@ -71,7 +72,7 @@ impl fmt::Display for IntermediateValue {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum IntermediateExpr { pub enum IntermediateExpr {
IntToFloat { IntToFloat {
result: Symbol, result: Symbol,
@@ -119,13 +120,13 @@ impl IntermediateExpr {
} }
} }
pub fn to_writer(&self, writer: &mut impl io::Write) -> io::Result<()> { pub fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
writer.write_u8(self.as_u8())?; writer.write_u8(self.as_u8())?;
match self { match self {
IntermediateExpr::IntToFloat { result, value } => { IntermediateExpr::IntToFloat { result, value } => {
writer.write_u64::<BigEndian>(result.into())?; result.write(writer)?;
value.to_writer(writer)?; value.write(writer)?;
}, },
IntermediateExpr::BinOp { IntermediateExpr::BinOp {
result, result,
@@ -133,37 +134,37 @@ impl IntermediateExpr {
op, op,
rhs, rhs,
} => { } => {
writer.write_u64::<BigEndian>(result.into())?; result.write(writer)?;
lhs.to_writer(writer)?; lhs.write(writer)?;
writer.write_u8(op.into())?; writer.write_u8(op.into())?;
rhs.to_writer(writer)?; rhs.write(writer)?;
}, },
IntermediateExpr::Identity { result, value } => { IntermediateExpr::Identity { result, value } => {
writer.write_u64::<BigEndian>(result.into())?; result.write(writer)?;
value.to_writer(writer)?; value.write(writer)?;
}, },
} }
Ok(()) Ok(())
} }
pub fn from_reader(reader: &mut impl io::Read) -> io::Result<Self> { pub fn read(reader: &mut impl io::Read) -> io::Result<Self> {
let b = reader.read_u8()?; let b = reader.read_u8()?;
match b { match b {
0x01 => Ok(IntermediateExpr::IntToFloat { 0x01 => Ok(IntermediateExpr::IntToFloat {
result: reader.read_u64::<BigEndian>()?.into(), result: Symbol::read(reader)?,
value: IntermediateValue::from_reader(reader)?, value: IntermediateValue::read(reader)?,
}), }),
0x02 => Ok(IntermediateExpr::BinOp { 0x02 => Ok(IntermediateExpr::BinOp {
result: reader.read_u64::<BigEndian>()?.into(), result: Symbol::read(reader)?,
lhs: IntermediateValue::from_reader(reader)?, lhs: IntermediateValue::read(reader)?,
op: BinOp::try_from(reader.read_u8()?) op: BinOp::try_from(reader.read_u8()?)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid bin op"))?, .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid bin op"))?,
rhs: IntermediateValue::from_reader(reader)?, rhs: IntermediateValue::read(reader)?,
}), }),
0x03 => Ok(IntermediateExpr::Identity { 0x03 => Ok(IntermediateExpr::Identity {
result: reader.read_u64::<BigEndian>()?.into(), result: Symbol::read(reader)?,
value: IntermediateValue::from_reader(reader)?, value: IntermediateValue::read(reader)?,
}), }),
b => Err(io::Error::new( b => Err(io::Error::new(
io::ErrorKind::InvalidData, io::ErrorKind::InvalidData,

View File

@@ -1,14 +1,28 @@
use std::collections::hash_map::Entry;
use std::collections::{HashMap, hash_map}; use std::collections::{HashMap, hash_map};
use std::fmt::Display; use std::fmt::Display;
use std::io; use std::io;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{ReadBytesExt, WriteBytesExt};
use integer_encoding::{VarIntReader, VarIntWriter};
use crate::ast::typed::Type; use crate::ast::typed::Type;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Symbol(u64); pub struct Symbol(u64);
impl Symbol {
pub fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
_ = writer.write_varint::<u64>(self.0)?;
Ok(())
}
pub fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
Ok(Self(reader.read_varint::<u64>()?))
}
}
impl From<&Symbol> for u64 { impl From<&Symbol> for u64 {
fn from(value: &Symbol) -> Self { fn from(value: &Symbol) -> Self {
value.0 value.0
@@ -30,11 +44,11 @@ pub struct SymbolData {
} }
impl SymbolData { impl SymbolData {
fn from_reader(reader: &mut impl io::Read) -> io::Result<Self> { fn read(reader: &mut impl io::Read) -> io::Result<Self> {
let id = reader.read_u64::<BigEndian>()?; let id = Symbol::read(reader)?;
let name = { let name = {
let n = reader.read_u64::<BigEndian>()?; let n = reader.read_varint::<u64>()? as usize;
let mut buf = vec![0; n as usize]; let mut buf = vec![0; n];
reader.read_exact(&mut buf)?; reader.read_exact(&mut buf)?;
String::from_utf8(buf) String::from_utf8(buf)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid utf-8"))? .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid utf-8"))?
@@ -48,16 +62,16 @@ impl SymbolData {
let temporary = reader.read_u8()? != 0; let temporary = reader.read_u8()? != 0;
Ok(Self { Ok(Self {
id: Symbol(id), id,
name, name,
ty, ty,
temporary, temporary,
}) })
} }
fn to_writer(&self, writer: &mut impl io::Write) -> io::Result<()> { fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
writer.write_u64::<BigEndian>(self.id.0)?; self.id.write(writer)?;
writer.write_u64::<BigEndian>(self.name.len() as u64)?; writer.write_varint::<u64>(self.name.len() as u64)?;
writer.write_all(self.name.as_bytes())?; writer.write_all(self.name.as_bytes())?;
writer.write_u8(self.ty.map_or(0, |ty| ty.into()))?; writer.write_u8(self.ty.map_or(0, |ty| ty.into()))?;
writer.write_u8(self.temporary as u8)?; writer.write_u8(self.temporary as u8)?;
@@ -103,13 +117,13 @@ impl SymbolsTable {
} }
} }
pub fn from_reader(reader: &mut impl io::Read) -> io::Result<Self> { pub fn read(reader: &mut impl io::Read) -> io::Result<Self> {
let n = reader.read_u64::<BigEndian>()?; let n = reader.read_varint::<u64>()?;
let mut max_id = 0; let mut max_id = 0;
let mut symbols = Vec::with_capacity(n as usize); let mut symbols = Vec::with_capacity(n as usize);
for _ in 0..n { for _ in 0..n {
let data = SymbolData::from_reader(reader)?; let data = SymbolData::read(reader)?;
max_id = max_id.max(data.id.0); max_id = max_id.max(data.id.0);
symbols.push(data); symbols.push(data);
} }
@@ -123,11 +137,11 @@ impl SymbolsTable {
}) })
} }
pub fn to_writer(&self, writer: &mut impl io::Write) -> io::Result<()> { pub fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
writer.write_u64::<BigEndian>(self.symbols.len() as u64)?; writer.write_varint::<u64>(self.symbols.len() as u64)?;
for data in self.symbols.values() { for data in self.symbols.values() {
data.to_writer(writer)?; data.write(writer)?;
} }
Ok(()) Ok(())
@@ -137,25 +151,28 @@ impl SymbolsTable {
self.symbols.retain(|_, data| symbols.contains(&data.id)); self.symbols.retain(|_, data| symbols.contains(&data.id));
} }
pub fn add(&mut self, symbol: impl Into<String>) -> Symbol { pub fn add(&mut self, name: impl Into<String>) -> Symbol {
let symbol = symbol.into(); let name = name.into();
if let hash_map::Entry::Vacant(e) = self.symbols.entry(symbol.clone()) {
e.insert(SymbolData {
id: Symbol(self.next_id),
name: symbol,
ty: None,
temporary: false,
});
self.next_id += 1;
return Symbol(self.next_id - 1); match self.symbols.entry(name.clone()) {
Entry::Occupied(e) => e.get().id,
Entry::Vacant(e) => {
let id = self.next_id.into();
e.insert(SymbolData {
id,
name,
ty: None,
temporary: false,
});
self.next_id += 1;
id
},
} }
self.get(&symbol).unwrap()
} }
pub fn get(&self, symbol: &str) -> Option<Symbol> { pub fn get(&self, name: &str) -> Option<Symbol> {
self.symbols.get(symbol).map(|data| data.id) self.symbols.get(name).map(|data| data.id)
} }
pub fn resolve(&self, symbol: &Symbol) -> Option<&SymbolData> { pub fn resolve(&self, symbol: &Symbol) -> Option<&SymbolData> {