From 60001f0bb4cd9fdb27a2f88a6b5a4d6a2025fea8 Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 13 Nov 2024 12:32:09 +0300 Subject: [PATCH] refactor 1 --- Cargo.lock | 55 +++++---- Cargo.toml | 1 + src/interpreter/mod.rs | 144 ++++++++++++++++++++++ src/interpreter/value.rs | 34 ++++++ src/lib.rs | 1 + src/main.rs | 189 +++++------------------------ src/representation/intermediate.rs | 49 ++++---- src/symbols/mod.rs | 77 +++++++----- 8 files changed, 310 insertions(+), 240 deletions(-) create mode 100644 src/interpreter/mod.rs create mode 100644 src/interpreter/value.rs diff --git a/Cargo.lock b/Cargo.lock index 29eeba9..a1d2821 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -19,43 +19,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "autocfg" @@ -89,9 +89,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.19" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -99,9 +99,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.19" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -129,9 +129,9 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "crossterm" @@ -166,6 +166,7 @@ dependencies = [ "byteorder", "clap", "inquire", + "integer-encoding", "itertools", "thiserror", ] @@ -223,6 +224,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "integer-encoding" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d762194228a2f1c11063e46e32e5acb96e66e906382b9eb5441f2e0504bbd5a" + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -312,9 +319,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -489,9 +496,9 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets 0.52.6", ] diff --git a/Cargo.toml b/Cargo.toml index 1a4410c..5d46741 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,5 +8,6 @@ anyhow = "1.0.89" byteorder = "1.5.0" clap = { version = "4.5.19", features = ["derive"] } inquire = "0.7.5" +integer-encoding = "4.0.2" itertools = "0.13.0" thiserror = "2.0.3" diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs new file mode 100644 index 0000000..3a6f334 --- /dev/null +++ b/src/interpreter/mod.rs @@ -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 { + exprs: Vec, + symbols: SymbolsTable, + initializer: I, +} + +type Variables = HashMap; + +impl Interpreter +where + I: Fn(&Type, &str) -> Value, +{ + pub fn new(exprs: Vec, symbols: SymbolsTable, initializer: I) -> Self { + Self { + symbols, + exprs, + initializer, + } + } + + pub fn run(&mut self) -> anyhow::Result> { + 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 { + 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 { + 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 { + 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 { + 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(()) + } +} diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs new file mode 100644 index 0000000..c7e80ca --- /dev/null +++ b/src/interpreter/value.rs @@ -0,0 +1,34 @@ +use std::fmt; + +#[derive(Debug, Clone, Copy)] +pub enum Value { + Int(i64), + Float(f64), +} + +impl From for Value { + fn from(value: i64) -> Self { + Self::Int(value) + } +} + +impl From 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) + } + }, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 2bcf013..d3c9de5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ pub mod ast; pub mod error; +pub mod interpreter; pub mod parse; pub mod representation; pub mod symbols; diff --git a/src/main.rs b/src/main.rs index 3257923..d5f1e5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,16 @@ mod cli; -use std::collections::HashMap; +use std::fs; use std::io::{self, Write}; use std::path::Path; -use std::{fmt, fs}; -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use cli::GenMode; -use developing_compilers::ast::BinOp; use developing_compilers::ast::typed::Type; -use developing_compilers::representation::intermediate::{IntermediateExpr, IntermediateValue}; -use developing_compilers::symbols::Symbol; +use developing_compilers::interpreter::{Interpreter, Value}; +use developing_compilers::representation::intermediate::IntermediateExpr; use developing_compilers::*; use inquire::CustomType; +use integer_encoding::{VarIntReader, VarIntWriter}; use parse::parser::Parser; use symbols::SymbolsTable; @@ -44,175 +42,42 @@ fn main() -> anyhow::Result<()> { if let Err(e) = result { eprintln!("error: {}", e); - return Ok(()); } Ok(()) } 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) -> 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) -> 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 mut reader = io::BufReader::new(fs::File::open(input)?); - let symbols = SymbolsTable::from_reader(&mut reader)?; - let n = reader.read_u64::()?; + let symbols = SymbolsTable::read(&mut reader)?; + let n = reader.read_varint::()?; let mut ir = Vec::with_capacity(n as usize); for _ in 0..n { - ir.push(IntermediateExpr::from_reader(&mut reader)?); + ir.push(IntermediateExpr::read(&mut reader)?); } (symbols, ir) }; - let mut vars = HashMap::new(); - for (_, data) in &symbols { - let value = match data.ty { - Some(Type::Int) if !data.temporary => VarValue::Int( - CustomType::new(&format!("Input int {}", data.name)) - .with_default(0) - .prompt()?, - ), - Some(Type::Float) if !data.temporary => VarValue::Float( - CustomType::new(&format!("Input float {}", data.name)) - .with_default(0.0) - .prompt()?, - ), - Some(Type::Int) => VarValue::Int(0), - Some(Type::Float) => VarValue::Float(0.0), - None => continue, - }; - vars.insert(data.id, value); - } + let mut interpreter = Interpreter::new(ir, symbols, |ty, name| match ty { + Type::Int => Value::Int( + CustomType::new(&format!("Input int {}", name)) + .with_default(0) + .prompt() + .unwrap_or_default(), + ), + Type::Float => Value::Float( + CustomType::new(&format!("Input float {}", name)) + .with_default(0.0) + .prompt() + .unwrap_or_default(), + ), + }); - let mut last_result = None; - for expr in ir { - match expr { - IntermediateExpr::IntToFloat { result, value } => { - let value = value_as_i64(&value, &vars) as f64; + let result = interpreter.run()?; - match vars.get_mut(&result) { - Some(VarValue::Float(v)) => *v = value, - _ => 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()); + if let Some(result) = result { + println!("Result: {}", result); } else { 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)?); - symbols.to_writer(&mut writer)?; - writer.write_u64::(ir.len() as u64)?; + symbols.write(&mut writer)?; + writer.write_varint::(ir.len() as u64)?; for expr in ir { - expr.to_writer(&mut writer)?; + expr.write(&mut writer)?; } Ok(()) diff --git a/src/representation/intermediate.rs b/src/representation/intermediate.rs index 49c3b25..e3bc6c3 100644 --- a/src/representation/intermediate.rs +++ b/src/representation/intermediate.rs @@ -1,13 +1,14 @@ use std::{fmt, io}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use integer_encoding::{VarIntReader, VarIntWriter}; use crate::ast::BinOp; use crate::ast::typed::TypedExpr; use crate::representation::util::TempVarContext; use crate::symbols::{Symbol, SymbolsTable}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum IntermediateValue { Int { value: i64 }, 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())?; match self { - IntermediateValue::Int { value } => writer.write_i64::(*value)?, + IntermediateValue::Int { value } => _ = writer.write_varint(*value)?, IntermediateValue::Float { value } => writer.write_f64::(*value)?, - IntermediateValue::Var { name } => writer.write_u64::(name.into())?, + IntermediateValue::Var { name } => _ = name.write(writer), } Ok(()) } - pub fn from_reader(reader: &mut impl io::Read) -> io::Result { + pub fn read(reader: &mut impl io::Read) -> io::Result { let b = reader.read_u8()?; match b { b'i' => Ok(IntermediateValue::Int { - value: reader.read_i64::()?, + value: reader.read_varint()?, }), b'f' => Ok(IntermediateValue::Float { value: reader.read_f64::()?, }), b'v' => Ok(IntermediateValue::Var { - name: reader.read_u64::()?.into(), + name: Symbol::read(reader)?, }), b => Err(io::Error::new( io::ErrorKind::InvalidData, @@ -71,7 +72,7 @@ impl fmt::Display for IntermediateValue { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum IntermediateExpr { IntToFloat { 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())?; match self { IntermediateExpr::IntToFloat { result, value } => { - writer.write_u64::(result.into())?; - value.to_writer(writer)?; + result.write(writer)?; + value.write(writer)?; }, IntermediateExpr::BinOp { result, @@ -133,37 +134,37 @@ impl IntermediateExpr { op, rhs, } => { - writer.write_u64::(result.into())?; - lhs.to_writer(writer)?; + result.write(writer)?; + lhs.write(writer)?; writer.write_u8(op.into())?; - rhs.to_writer(writer)?; + rhs.write(writer)?; }, IntermediateExpr::Identity { result, value } => { - writer.write_u64::(result.into())?; - value.to_writer(writer)?; + result.write(writer)?; + value.write(writer)?; }, } Ok(()) } - pub fn from_reader(reader: &mut impl io::Read) -> io::Result { + pub fn read(reader: &mut impl io::Read) -> io::Result { let b = reader.read_u8()?; match b { 0x01 => Ok(IntermediateExpr::IntToFloat { - result: reader.read_u64::()?.into(), - value: IntermediateValue::from_reader(reader)?, + result: Symbol::read(reader)?, + value: IntermediateValue::read(reader)?, }), 0x02 => Ok(IntermediateExpr::BinOp { - result: reader.read_u64::()?.into(), - lhs: IntermediateValue::from_reader(reader)?, + result: Symbol::read(reader)?, + lhs: IntermediateValue::read(reader)?, op: BinOp::try_from(reader.read_u8()?) .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid bin op"))?, - rhs: IntermediateValue::from_reader(reader)?, + rhs: IntermediateValue::read(reader)?, }), 0x03 => Ok(IntermediateExpr::Identity { - result: reader.read_u64::()?.into(), - value: IntermediateValue::from_reader(reader)?, + result: Symbol::read(reader)?, + value: IntermediateValue::read(reader)?, }), b => Err(io::Error::new( io::ErrorKind::InvalidData, diff --git a/src/symbols/mod.rs b/src/symbols/mod.rs index f155019..00a90af 100644 --- a/src/symbols/mod.rs +++ b/src/symbols/mod.rs @@ -1,14 +1,28 @@ +use std::collections::hash_map::Entry; use std::collections::{HashMap, hash_map}; use std::fmt::Display; use std::io; -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use integer_encoding::{VarIntReader, VarIntWriter}; use crate::ast::typed::Type; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Symbol(u64); +impl Symbol { + pub fn write(&self, writer: &mut W) -> io::Result<()> { + _ = writer.write_varint::(self.0)?; + + Ok(()) + } + + pub fn read(reader: &mut R) -> io::Result { + Ok(Self(reader.read_varint::()?)) + } +} + impl From<&Symbol> for u64 { fn from(value: &Symbol) -> Self { value.0 @@ -30,11 +44,11 @@ pub struct SymbolData { } impl SymbolData { - fn from_reader(reader: &mut impl io::Read) -> io::Result { - let id = reader.read_u64::()?; + fn read(reader: &mut impl io::Read) -> io::Result { + let id = Symbol::read(reader)?; let name = { - let n = reader.read_u64::()?; - let mut buf = vec![0; n as usize]; + let n = reader.read_varint::()? as usize; + let mut buf = vec![0; n]; reader.read_exact(&mut buf)?; String::from_utf8(buf) .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid utf-8"))? @@ -48,16 +62,16 @@ impl SymbolData { let temporary = reader.read_u8()? != 0; Ok(Self { - id: Symbol(id), + id, name, ty, temporary, }) } - fn to_writer(&self, writer: &mut impl io::Write) -> io::Result<()> { - writer.write_u64::(self.id.0)?; - writer.write_u64::(self.name.len() as u64)?; + fn write(&self, writer: &mut impl io::Write) -> io::Result<()> { + self.id.write(writer)?; + writer.write_varint::(self.name.len() as u64)?; writer.write_all(self.name.as_bytes())?; writer.write_u8(self.ty.map_or(0, |ty| ty.into()))?; writer.write_u8(self.temporary as u8)?; @@ -103,13 +117,13 @@ impl SymbolsTable { } } - pub fn from_reader(reader: &mut impl io::Read) -> io::Result { - let n = reader.read_u64::()?; + pub fn read(reader: &mut impl io::Read) -> io::Result { + let n = reader.read_varint::()?; let mut max_id = 0; let mut symbols = Vec::with_capacity(n as usize); for _ in 0..n { - let data = SymbolData::from_reader(reader)?; + let data = SymbolData::read(reader)?; max_id = max_id.max(data.id.0); symbols.push(data); } @@ -123,11 +137,11 @@ impl SymbolsTable { }) } - pub fn to_writer(&self, writer: &mut impl io::Write) -> io::Result<()> { - writer.write_u64::(self.symbols.len() as u64)?; + pub fn write(&self, writer: &mut impl io::Write) -> io::Result<()> { + writer.write_varint::(self.symbols.len() as u64)?; for data in self.symbols.values() { - data.to_writer(writer)?; + data.write(writer)?; } Ok(()) @@ -137,25 +151,28 @@ impl SymbolsTable { self.symbols.retain(|_, data| symbols.contains(&data.id)); } - pub fn add(&mut self, symbol: impl Into) -> Symbol { - let symbol = symbol.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; + pub fn add(&mut self, name: impl Into) -> Symbol { + let name = name.into(); - 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 { - self.symbols.get(symbol).map(|data| data.id) + pub fn get(&self, name: &str) -> Option { + self.symbols.get(name).map(|data| data.id) } pub fn resolve(&self, symbol: &Symbol) -> Option<&SymbolData> {