Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement char extension in Rust tools #254

Merged
merged 8 commits into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions bril-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ ssa = []
speculate = []
position = []
import = []
char = []

[[example]]
name = "bril2txt"
Expand All @@ -33,10 +34,10 @@ path = "examples/bril2txt.rs"
# However this currently does not work as expected and is being hashed out in https://github.com/rust-lang/rfcs/pull/3020 and https://github.com/rust-lang/rfcs/pull/2887
# Until a solution is reached, I'm using `required-features` so that these features must be passed by flag. This is less ergonomic at the moment, however the user will get a nicer error that they need a feature flag instead of an Result::unwrap() error.
# Note: See dev-dependencies for a hack to not need the user to pass that feature flag.
required-features = ["memory", "float", "ssa", "speculate", "position", "import"]
required-features = ["memory", "float", "ssa", "speculate", "position", "import", "char"]

[dev-dependencies]
# trick to enable all features in test
# This is actually really hacky because it is used in all tests/examples/benchmarks but since we currently only have one example this works for enabling the following feature flags for our users.
# If the above rfcs every get resolved, then dev-dependencies will no longer be needed.
bril-rs = { path = ".", features = ["memory", "float", "ssa", "speculate", "position", "import"] }
bril-rs = { path = ".", features = ["memory", "float", "ssa", "speculate", "position", "import", "char"] }
2 changes: 1 addition & 1 deletion bril-rs/bril2json/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ lalrpop = "0.20"
[dependencies.bril-rs]
version = "0.1.0"
path = "../../bril-rs"
features = ["ssa", "memory", "float", "speculate", "position", "import"]
features = ["ssa", "memory", "float", "speculate", "position", "import", "char"]
6 changes: 5 additions & 1 deletion bril-rs/bril2json/src/bril_grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

use std::str::FromStr;
use std::path::PathBuf;
use crate::{Lines, ParsingArgs};
use crate::{Lines, ParsingArgs, escape_control_chars};
use bril_rs::{AbstractProgram, AbstractFunction, AbstractArgument, AbstractCode, AbstractInstruction, ConstOps, AbstractType, Literal, Import, ImportedFunction};

grammar(lines : &Lines);
Expand All @@ -33,6 +33,7 @@ match {
r"(\+|-)?[0-9]+" => INT_TOKEN, // int
r"(\+|-)?(((([0-9]+\.?[0-9]*)|(\.[0-9]+))(E|e)(\+|-)?[0-9]+)|(([0-9]+\.[0-9]*)|(\.[0-9]+)))" => FLOAT_TOKEN, // https://stackoverflow.com/questions/12643009/regular-expression-for-floating-point-numbers
r"(_|%|[[:alpha:]])(_|%|\.|[[:alnum:]])*" => IDENT_TOKEN,
r"('.')|('\\[0abtnvfr]')" => CHAR_TOKEN,
r#""[^"]*""# => STRING_TOKEN,
_
}
Expand Down Expand Up @@ -189,6 +190,7 @@ Literal: Literal = {
<n: Num> => Literal::Int(n),
<b: Bool> => Literal::Bool(b),
<f: Float> => Literal::Float(f),
<c: Char> => Literal::Char(c),
}

Num: i64 = <s:INT_TOKEN> => i64::from_str(s).unwrap();
Expand All @@ -199,6 +201,8 @@ Bool: bool = {

Float: f64 = <f:FLOAT_TOKEN> => f64::from_str(f).unwrap();

Char: char = <c:CHAR_TOKEN> => {let c = c.trim_matches('\''); escape_control_chars(c).unwrap()};

// https://lalrpop.github.io/lalrpop/tutorial/006_macros.html
Comma<T>: Vec<T> = { // (1)
<mut v:(<T> ",")*> <e:T?> => match e { // (2)
Expand Down
17 changes: 17 additions & 0 deletions bril-rs/bril2json/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ use std::fs::File;

use bril_rs::{AbstractProgram, ColRow, Position};

/// A helper function for processing the accepted Bril characters from their text representation
#[must_use]
pub fn escape_control_chars(s: &str) -> Option<char> {
match s {
"\\0" => Some('\u{0000}'),
"\\a" => Some('\u{0007}'),
"\\b" => Some('\u{0008}'),
"\\t" => Some('\u{0009}'),
"\\n" => Some('\u{000A}'),
"\\v" => Some('\u{000B}'),
"\\f" => Some('\u{000C}'),
"\\r" => Some('\u{000D}'),
s if s.chars().count() == 1 => s.chars().next(),
_ => None,
}
}

#[doc(hidden)]
#[derive(Clone)]
pub struct Lines {
Expand Down
2 changes: 2 additions & 0 deletions bril-rs/brild/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#![warn(missing_docs)]
#![doc = include_str!("../README.md")]
#![allow(clippy::module_name_repetitions)]
// todo until multiple versions of some really far down dependency are fixed
#![allow(clippy::multiple_crate_versions)]

#[doc(hidden)]
pub mod cli;
Expand Down
4 changes: 2 additions & 2 deletions bril-rs/brillvm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ TESTS := ../../test/interp/core/*.bril \
../../test/interp/float/*.bril \
../../test/interp/ssa/*.bril \
../../test/interp/mem/*.bril \
../../test/interp/mixed/*.bril \
../../test/interp/mixed/*[^r].bril # A hack to exclude store-char.bril by excluding any file ending in r.bril

# Currently ignoring the Cholesky benchmark because of (probably) a floating point rounding bug.
BENCHMARKS := ../../benchmarks/core/*.bril \
../../benchmarks/float/*.bril \
../../benchmarks/mem/*.bril \
../../benchmarks/mixed/[!cholesky]*.bril
../../benchmarks/mixed/[^c]*.bril # A hack to exclude cholesky.bril by excluding any file starting in c.

clean:
cargo clean
Expand Down
2 changes: 2 additions & 0 deletions bril-rs/brillvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#![allow(clippy::too_many_lines)]
#![allow(clippy::needless_for_each)]
#![doc = include_str!("../README.md")]
// When you run with --all-targets, you also get --target=all which includes --target=redox. This pulls in redox_sys via a chain of deps through inkwell-parking_lot which uses an older version of bitflags 1.3.2. Given backwards compatibility, it's going to be a very long time, if ever, that this gets updated(because of msrv changes).
#![allow(clippy::multiple_crate_versions)]

#[doc(hidden)]
pub mod cli;
Expand Down
16 changes: 16 additions & 0 deletions bril-rs/src/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,20 @@ impl TryFrom<AbstractInstruction> for Instruction {
"fle" => ValueOps::Fle,
#[cfg(feature = "float")]
"fge" => ValueOps::Fge,
#[cfg(feature = "char")]
"ceq" => ValueOps::Ceq,
#[cfg(feature = "char")]
"clt" => ValueOps::Clt,
#[cfg(feature = "char")]
"cgt" => ValueOps::Cgt,
#[cfg(feature = "char")]
"cle" => ValueOps::Cle,
#[cfg(feature = "char")]
"cge" => ValueOps::Cge,
#[cfg(feature = "char")]
"char2int" => ValueOps::Char2int,
#[cfg(feature = "char")]
"int2char" => ValueOps::Int2char,
#[cfg(feature = "memory")]
"alloc" => ValueOps::Alloc,
#[cfg(feature = "memory")]
Expand Down Expand Up @@ -313,6 +327,8 @@ impl TryFrom<AbstractType> for Type {
AbstractType::Primitive(t) if t == "bool" => Self::Bool,
#[cfg(feature = "float")]
AbstractType::Primitive(t) if t == "float" => Self::Float,
#[cfg(feature = "char")]
AbstractType::Primitive(t) if t == "char" => Self::Char,
AbstractType::Primitive(t) => return Err(ConversionError::InvalidPrimitive(t)),
#[cfg(feature = "memory")]
AbstractType::Parameterized(t, ty) if t == "ptr" => {
Expand Down
62 changes: 62 additions & 0 deletions bril-rs/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,27 @@ pub enum ValueOps {
/// <https://capra.cs.cornell.edu/bril/lang/float.html#operations>
#[cfg(feature = "float")]
Fge,
/// <https://capra.cs.cornell.edu/bril/lang/char.html#operations>
#[cfg(feature = "char")]
Ceq,
/// <https://capra.cs.cornell.edu/bril/lang/char.html#operations>
#[cfg(feature = "char")]
Clt,
/// <https://capra.cs.cornell.edu/bril/lang/char.html#operations>
#[cfg(feature = "char")]
Cgt,
/// <https://capra.cs.cornell.edu/bril/lang/char.html#operations>
#[cfg(feature = "char")]
Cle,
/// <https://capra.cs.cornell.edu/bril/lang/char.html#operations>
#[cfg(feature = "char")]
Cge,
/// <https://capra.cs.cornell.edu/bril/lang/char.html#operations>
#[cfg(feature = "char")]
Char2int,
/// <https://capra.cs.cornell.edu/bril/lang/char.html#operations>
#[cfg(feature = "char")]
Int2char,
/// <https://capra.cs.cornell.edu/bril/lang/memory.html#operations>
#[cfg(feature = "memory")]
Alloc,
Expand Down Expand Up @@ -499,6 +520,20 @@ impl Display for ValueOps {
Self::Fle => write!(f, "fle"),
#[cfg(feature = "float")]
Self::Fge => write!(f, "fge"),
#[cfg(feature = "char")]
Self::Ceq => write!(f, "ceq"),
#[cfg(feature = "char")]
Self::Clt => write!(f, "clt"),
#[cfg(feature = "char")]
Self::Cgt => write!(f, "cgt"),
#[cfg(feature = "char")]
Self::Cle => write!(f, "cle"),
#[cfg(feature = "char")]
Self::Cge => write!(f, "cge"),
#[cfg(feature = "char")]
Self::Char2int => write!(f, "char2int"),
#[cfg(feature = "char")]
Self::Int2char => write!(f, "int2char"),
#[cfg(feature = "memory")]
Self::Alloc => write!(f, "alloc"),
#[cfg(feature = "memory")]
Expand All @@ -520,6 +555,9 @@ pub enum Type {
/// <https://capra.cs.cornell.edu/bril/lang/float.html#types>
#[cfg(feature = "float")]
Float,
/// <https://capra.cs.cornell.edu/bril/lang/char.html#types>
#[cfg(feature = "char")]
Char,
/// <https://capra.cs.cornell.edu/bril/lang/memory.html#types>
#[cfg(feature = "memory")]
#[serde(rename = "ptr")]
Expand All @@ -533,6 +571,8 @@ impl Display for Type {
Self::Bool => write!(f, "bool"),
#[cfg(feature = "float")]
Self::Float => write!(f, "float"),
#[cfg(feature = "char")]
Self::Char => write!(f, "char"),
#[cfg(feature = "memory")]
Self::Pointer(tpe) => write!(f, "ptr<{tpe}>"),
}
Expand All @@ -551,6 +591,9 @@ pub enum Literal {
/// Floating Points
#[cfg(feature = "float")]
Float(f64),
/// UTF-16 Characters
#[cfg(feature = "char")]
Char(char),
}

impl Display for Literal {
Expand All @@ -560,10 +603,27 @@ impl Display for Literal {
Self::Bool(b) => write!(f, "{b}"),
#[cfg(feature = "float")]
Self::Float(x) => write!(f, "{x}"),
#[cfg(feature = "char")]
Self::Char(c) => write!(f, "\'{}\'", escape_char(*c)),
}
}
}

#[cfg(feature = "char")]
fn escape_char(c: char) -> String {
match c {
'\u{0000}' => "\\0".to_string(),
'\u{0007}' => "\\a".to_string(),
'\u{0008}' => "\\b".to_string(),
'\u{0009}' => "\\t".to_string(),
'\u{000A}' => "\\n".to_string(),
'\u{000B}' => "\\v".to_string(),
'\u{000C}' => "\\f".to_string(),
'\u{000D}' => "\\r".to_string(),
c => c.to_string(),
}
}

impl Literal {
/// A helper function to get the type of literal values
#[must_use]
Expand All @@ -573,6 +633,8 @@ impl Literal {
Self::Bool(_) => Type::Bool,
#[cfg(feature = "float")]
Self::Float(_) => Type::Float,
#[cfg(feature = "char")]
Self::Char(_) => Type::Char,
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion brilift/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ endif

# Brilift only supports core Bril for now, so we select those tests &
# benchmarks.
TESTS := ../test/interp/core/*.bril ../test/interp/float/*.bril ../test/interp/mem/*.bril ../test/interp/mixed/*.bril
TESTS := ../test/interp/core/*.bril ../test/interp/float/*.bril ../test/interp/mem/*.bril ../test/interp/mixed/*[^r].bril # A hack to exclude store-char.bril by excluding any file ending in r.bril
BENCHMARKS := ../benchmarks/core/*.bril ../benchmarks/float/*.bril ../benchmarks/mem/*.bril ../benchmarks/mixed/*.bril

CFLAGS := $(if $(TARGET),-target $(TARGET))
Expand Down
2 changes: 1 addition & 1 deletion brilift/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ set -e
#

OS=$(uname -m)
if [[ "$OS" == 'arm64' ]]; then
if [ "$OS" = 'arm64' ]; then
export TARGET=x86_64-unknown-darwin-macho
fi

Expand Down
10 changes: 5 additions & 5 deletions brilirs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ keywords = ["compiler", "bril", "interpreter", "data-structures", "language"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
clap = { version = "4.2", features = ["derive"] }
clap_complete= { version = "4.2", optional = true }
clap = { version = "4.3", features = ["derive"] }
clap_complete= { version = "4.3", optional = true }

[dependencies]
thiserror = "1.0"
clap = { version = "4.2", features = ["derive"] }
clap = { version = "4.3", features = ["derive"] }
fxhash = "0.2"
mimalloc = "0.1"
itoa = "1.0"

[dependencies.bril-rs]
version = "0.1.0"
path = "../bril-rs"
features = ["ssa", "memory", "float", "speculate"]
features = ["ssa", "memory", "float", "speculate", "char"]

[dependencies.bril2json]
version = "0.1.0"
Expand All @@ -39,4 +39,4 @@ lto = true
panic = "abort"

[features]
completions = ["clap_complete"]
completions = ["clap_complete"]
1 change: 1 addition & 0 deletions brilirs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ TESTS := ../test/check/*.bril \
../test/interp*/core*/*.bril \
../test/interp*/float/*.bril \
../test/interp*/mem*/*.bril \
../test/interp*/char*/*.bril \
../test/interp*/mixed/*.bril \
../test/interp*/ssa*/*.bril \

Expand Down
49 changes: 49 additions & 0 deletions brilirs/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,55 @@ fn type_check_instruction<'a>(
check_asmt_type(&Type::Bool, op_type)?;
update_env(env, dest, op_type)
}
Instruction::Value {
op: ValueOps::Ceq | ValueOps::Cge | ValueOps::Clt | ValueOps::Cgt | ValueOps::Cle,
args,
dest,
funcs,
labels,
pos: _,
op_type,
} => {
check_num_args(2, args)?;
check_num_funcs(0, funcs)?;
check_num_labels(0, labels)?;
check_asmt_type(&Type::Char, get_type(env, 0, args)?)?;
check_asmt_type(&Type::Char, get_type(env, 1, args)?)?;
check_asmt_type(&Type::Bool, op_type)?;
update_env(env, dest, op_type)
}
Instruction::Value {
op: ValueOps::Char2int,
args,
dest,
funcs,
labels,
pos: _,
op_type,
} => {
check_num_args(1, args)?;
check_num_funcs(0, funcs)?;
check_num_labels(0, labels)?;
check_asmt_type(&Type::Char, get_type(env, 0, args)?)?;
check_asmt_type(&Type::Int, op_type)?;
update_env(env, dest, op_type)
}
Instruction::Value {
op: ValueOps::Int2char,
args,
dest,
funcs,
labels,
pos: _,
op_type,
} => {
check_num_args(1, args)?;
check_num_funcs(0, funcs)?;
check_num_labels(0, labels)?;
check_asmt_type(&Type::Int, get_type(env, 0, args)?)?;
check_asmt_type(&Type::Char, op_type)?;
update_env(env, dest, op_type)
}
Instruction::Value {
op: ValueOps::Call,
dest,
Expand Down
4 changes: 4 additions & 0 deletions brilirs/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pub enum InterpError {
NoMainFunction,
#[error("phi node has unequal numbers of labels and args")]
UnequalPhiNode,
#[error("char must have one character")]
NotOneChar,
#[error("multiple functions of the same name found")]
DuplicateFunction,
#[error("Expected empty return for `{0}`, found value")]
Expand Down Expand Up @@ -53,6 +55,8 @@ pub enum InterpError {
BadAsmtType(bril_rs::Type, bril_rs::Type), // (expected, actual). For when the LHS type of an instruction is bad
#[error("There has been an io error: `{0:?}`")]
IoError(#[from] std::io::Error),
#[error("value ${0} cannot be converted to char")]
ToCharError(i64),
#[error("You probably shouldn't see this error, this is here to handle conversions between InterpError and PositionalError")]
PositionalInterpErrorConversion(#[from] PositionalInterpError),
}
Expand Down
Loading