refactor 1
This commit is contained in:
55
Cargo.lock
generated
55
Cargo.lock
generated
@@ -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",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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
144
src/interpreter/mod.rs
Normal 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
34
src/interpreter/value.rs
Normal 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)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
189
src/main.rs
189
src/main.rs
@@ -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(())
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
Reference in New Issue
Block a user