diff --git a/bril-rs/Cargo.toml b/bril-rs/Cargo.toml index bcc11148d..950244a4a 100644 --- a/bril-rs/Cargo.toml +++ b/bril-rs/Cargo.toml @@ -25,6 +25,7 @@ ssa = [] speculate = [] position = [] import = [] +char = [] [[example]] name = "bril2txt" @@ -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"] } \ No newline at end of file +bril-rs = { path = ".", features = ["memory", "float", "ssa", "speculate", "position", "import", "char"] } diff --git a/bril-rs/bril2json/Cargo.toml b/bril-rs/bril2json/Cargo.toml index 02620bd65..b9212d8a8 100644 --- a/bril-rs/bril2json/Cargo.toml +++ b/bril-rs/bril2json/Cargo.toml @@ -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"] diff --git a/bril-rs/bril2json/src/bril_grammar.lalrpop b/bril-rs/bril2json/src/bril_grammar.lalrpop index 124440954..742ce25df 100644 --- a/bril-rs/bril2json/src/bril_grammar.lalrpop +++ b/bril-rs/bril2json/src/bril_grammar.lalrpop @@ -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); @@ -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, _ } @@ -189,6 +190,7 @@ Literal: Literal = { => Literal::Int(n), => Literal::Bool(b), => Literal::Float(f), + => Literal::Char(c), } Num: i64 = => i64::from_str(s).unwrap(); @@ -199,6 +201,8 @@ Bool: bool = { Float: f64 = => f64::from_str(f).unwrap(); +Char: char = => {let c = c.trim_matches('\''); escape_control_chars(c).unwrap()}; + // https://lalrpop.github.io/lalrpop/tutorial/006_macros.html Comma: Vec = { // (1) ",")*> => match e { // (2) diff --git a/bril-rs/bril2json/src/lib.rs b/bril-rs/bril2json/src/lib.rs index b5134ca20..032a69b67 100644 --- a/bril-rs/bril2json/src/lib.rs +++ b/bril-rs/bril2json/src/lib.rs @@ -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 { + 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 { diff --git a/bril-rs/brild/src/lib.rs b/bril-rs/brild/src/lib.rs index 92de3babe..4e92ad0bb 100644 --- a/bril-rs/brild/src/lib.rs +++ b/bril-rs/brild/src/lib.rs @@ -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; diff --git a/bril-rs/brillvm/Makefile b/bril-rs/brillvm/Makefile index f551b01e0..a48e4929a 100644 --- a/bril-rs/brillvm/Makefile +++ b/bril-rs/brillvm/Makefile @@ -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 diff --git a/bril-rs/brillvm/src/lib.rs b/bril-rs/brillvm/src/lib.rs index 4419eb70b..255f2e2b9 100644 --- a/bril-rs/brillvm/src/lib.rs +++ b/bril-rs/brillvm/src/lib.rs @@ -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; diff --git a/bril-rs/src/conversion.rs b/bril-rs/src/conversion.rs index 232b2faaa..3db1aa79a 100644 --- a/bril-rs/src/conversion.rs +++ b/bril-rs/src/conversion.rs @@ -245,6 +245,20 @@ impl TryFrom 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")] @@ -313,6 +327,8 @@ impl TryFrom 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" => { diff --git a/bril-rs/src/program.rs b/bril-rs/src/program.rs index 4b29c88a4..ef9acb9ab 100644 --- a/bril-rs/src/program.rs +++ b/bril-rs/src/program.rs @@ -451,6 +451,27 @@ pub enum ValueOps { /// #[cfg(feature = "float")] Fge, + /// + #[cfg(feature = "char")] + Ceq, + /// + #[cfg(feature = "char")] + Clt, + /// + #[cfg(feature = "char")] + Cgt, + /// + #[cfg(feature = "char")] + Cle, + /// + #[cfg(feature = "char")] + Cge, + /// + #[cfg(feature = "char")] + Char2int, + /// + #[cfg(feature = "char")] + Int2char, /// #[cfg(feature = "memory")] Alloc, @@ -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")] @@ -520,6 +555,9 @@ pub enum Type { /// #[cfg(feature = "float")] Float, + /// + #[cfg(feature = "char")] + Char, /// #[cfg(feature = "memory")] #[serde(rename = "ptr")] @@ -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}>"), } @@ -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 { @@ -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] @@ -573,6 +633,8 @@ impl Literal { Self::Bool(_) => Type::Bool, #[cfg(feature = "float")] Self::Float(_) => Type::Float, + #[cfg(feature = "char")] + Self::Char(_) => Type::Char, } } } diff --git a/brilift/Makefile b/brilift/Makefile index 44f1f4400..68ee4d78a 100644 --- a/brilift/Makefile +++ b/brilift/Makefile @@ -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)) diff --git a/brilift/run.sh b/brilift/run.sh index 07d1b6bf1..c932b849f 100755 --- a/brilift/run.sh +++ b/brilift/run.sh @@ -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 diff --git a/brilirs/Cargo.toml b/brilirs/Cargo.toml index 096bb9069..f16e3341a 100644 --- a/brilirs/Cargo.toml +++ b/brilirs/Cargo.toml @@ -13,12 +13,12 @@ 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" @@ -26,7 +26,7 @@ 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" @@ -39,4 +39,4 @@ lto = true panic = "abort" [features] -completions = ["clap_complete"] \ No newline at end of file +completions = ["clap_complete"] diff --git a/brilirs/Makefile b/brilirs/Makefile index 76007ccf9..f142c5f13 100644 --- a/brilirs/Makefile +++ b/brilirs/Makefile @@ -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 \ diff --git a/brilirs/src/check.rs b/brilirs/src/check.rs index d6fea25da..f14a56e12 100644 --- a/brilirs/src/check.rs +++ b/brilirs/src/check.rs @@ -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, diff --git a/brilirs/src/error.rs b/brilirs/src/error.rs index 7ff7a5a0a..7aaa3d038 100644 --- a/brilirs/src/error.rs +++ b/brilirs/src/error.rs @@ -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")] @@ -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), } diff --git a/brilirs/src/interp.rs b/brilirs/src/interp.rs index b14fd2ef9..17c5a5596 100644 --- a/brilirs/src/interp.rs +++ b/brilirs/src/interp.rs @@ -1,5 +1,6 @@ use crate::basic_block::{BBFunction, BBProgram, BasicBlock}; use crate::error::{InterpError, PositionalInterpError}; +use bril2json::escape_control_chars; use bril_rs::Instruction; use fxhash::FxHashMap; @@ -169,6 +170,7 @@ enum Value { Int(i64), Bool(bool), Float(f64), + Char(char), Pointer(Pointer), #[default] Uninitialized, @@ -197,6 +199,7 @@ impl fmt::Display for Value { Self::Float(v) if v.is_infinite() && v.is_sign_positive() => write!(f, "Infinity"), Self::Float(v) if v.is_infinite() && v.is_sign_negative() => write!(f, "-Infinity"), Self::Float(v) => write!(f, "{v:.17}"), + Self::Char(c) => write!(f, "{c}"), Self::Pointer(p) => write!(f, "{p:?}"), Self::Uninitialized => unreachable!(), } @@ -206,11 +209,15 @@ impl fmt::Display for Value { fn optimized_val_output(out: &mut T, val: &Value) -> Result<(), std::io::Error> { match val { Value::Int(i) => out.write_all(itoa::Buffer::new().format(*i).as_bytes()), - Value::Bool(b) => out.write_all(b.to_string().as_bytes()), + Value::Bool(b) => out.write_all(if *b { b"true" } else { b"false" }), Value::Float(f) if f.is_infinite() && f.is_sign_positive() => out.write_all(b"Infinity"), Value::Float(f) if f.is_infinite() && f.is_sign_negative() => out.write_all(b"-Infinity"), Value::Float(f) if f.is_nan() => out.write_all(b"NaN"), Value::Float(f) => out.write_all(format!("{f:.17}").as_bytes()), + Value::Char(c) => { + let buf = &mut [0_u8; 2]; + out.write_all(c.encode_utf8(buf).as_bytes()) + } Value::Pointer(p) => out.write_all(format!("{p:?}").as_bytes()), Value::Uninitialized => unreachable!(), } @@ -222,6 +229,7 @@ impl From<&bril_rs::Literal> for Value { bril_rs::Literal::Int(i) => Self::Int(*i), bril_rs::Literal::Bool(b) => Self::Bool(*b), bril_rs::Literal::Float(f) => Self::Float(*f), + bril_rs::Literal::Char(c) => Self::Char(*c), } } } @@ -232,6 +240,7 @@ impl From for Value { bril_rs::Literal::Int(i) => Self::Int(i), bril_rs::Literal::Bool(b) => Self::Bool(b), bril_rs::Literal::Float(f) => Self::Float(f), + bril_rs::Literal::Char(c) => Self::Char(c), } } } @@ -266,6 +275,16 @@ impl From<&Value> for f64 { } } +impl From<&Value> for char { + fn from(value: &Value) -> Self { + if let Value::Char(c) = value { + *c + } else { + unreachable!() + } + } +} + impl<'a> From<&'a Value> for &'a Pointer { fn from(value: &'a Value) -> Self { if let Value::Pointer(p) = value { @@ -305,8 +324,8 @@ fn execute_value_op( last_label: Option<&String>, ) -> Result<(), InterpError> { use bril_rs::ValueOps::{ - Add, Alloc, And, Call, Div, Eq, Fadd, Fdiv, Feq, Fge, Fgt, Fle, Flt, Fmul, Fsub, Ge, Gt, Id, - Le, Load, Lt, Mul, Not, Or, Phi, PtrAdd, Sub, + Add, Alloc, And, Call, Ceq, Cge, Cgt, Char2int, Cle, Clt, Div, Eq, Fadd, Fdiv, Feq, Fge, Fgt, + Fle, Flt, Fmul, Fsub, Ge, Gt, Id, Int2char, Le, Load, Lt, Mul, Not, Or, Phi, PtrAdd, Sub, }; match op { Add => { @@ -420,6 +439,45 @@ fn execute_value_op( let arg1 = get_arg::(&state.env, 1, args); state.env.set(dest, Value::Bool(arg0 >= arg1)); } + Ceq => { + let arg0 = get_arg::(&state.env, 0, args); + let arg1 = get_arg::(&state.env, 1, args); + state.env.set(dest, Value::Bool(arg0 == arg1)); + } + Clt => { + let arg0 = get_arg::(&state.env, 0, args); + let arg1 = get_arg::(&state.env, 1, args); + state.env.set(dest, Value::Bool(arg0 < arg1)); + } + Cgt => { + let arg0 = get_arg::(&state.env, 0, args); + let arg1 = get_arg::(&state.env, 1, args); + state.env.set(dest, Value::Bool(arg0 > arg1)); + } + Cle => { + let arg0 = get_arg::(&state.env, 0, args); + let arg1 = get_arg::(&state.env, 1, args); + state.env.set(dest, Value::Bool(arg0 <= arg1)); + } + Cge => { + let arg0 = get_arg::(&state.env, 0, args); + let arg1 = get_arg::(&state.env, 1, args); + state.env.set(dest, Value::Bool(arg0 >= arg1)); + } + Char2int => { + let arg0 = get_arg::(&state.env, 0, args); + state.env.set(dest, Value::Int(u32::from(arg0).into())); + } + Int2char => { + let arg0 = get_arg::(&state.env, 0, args); + + let arg0_char = u32::try_from(arg0) + .ok() + .and_then(char::from_u32) + .ok_or(InterpError::ToCharError(arg0))?; + + state.env.set(dest, Value::Char(arg0_char)); + } Call => { let callee_func = state.prog.get(funcs[0]).unwrap(); @@ -574,7 +632,7 @@ fn execute<'a, T: std::io::Write>( bril_rs::Literal::Float(f) => { state.env.set(numified_code.dest.unwrap(), Value::Float(*f)); } - bril_rs::Literal::Bool(_) => unreachable!(), + bril_rs::Literal::Char(_) | bril_rs::Literal::Bool(_) => unreachable!(), } } else { state @@ -687,6 +745,14 @@ fn parse_args( Ok(()) } bril_rs::Type::Pointer(..) => unreachable!(), + bril_rs::Type::Char => escape_control_chars(inputs.get(index).unwrap().as_ref()) + .map_or_else( + || Err(InterpError::NotOneChar), + |c| { + env.set(*arg_as_num, Value::Char(c)); + Ok(()) + }, + ), })?; Ok(env) } diff --git a/docs/tools/brilirs.md b/docs/tools/brilirs.md index 187ff1e92..fd238b2ca 100644 --- a/docs/tools/brilirs.md +++ b/docs/tools/brilirs.md @@ -3,7 +3,7 @@ Fast Interpreter in Rust The `brilirs` directory contains a fast Bril interpreter written in [Rust][]. It is a drop-in replacement for the [reference interpreter](interp.md) that prioritizes speed over completeness and hackability. -It implements [core Bril](../lang/core.md) along with the [SSA][], [memory][], and [floating point][float] extensions. +It implements [core Bril](../lang/core.md) along with the [SSA][], [memory][], [char][], and [floating point][float] extensions. Read [more about the implementation][blog], which is originally by Wil Thomason and Daniel Glus. @@ -36,4 +36,5 @@ To see all of the supported flags, run: [ssa]: ../lang/ssa.md [memory]: ../lang/memory.md [float]: ../lang/float.md +[char]: ../lang/char.md [blog]: https://www.cs.cornell.edu/courses/cs6120/2019fa/blog/faster-interpreter/ diff --git a/docs/tools/rust.md b/docs/tools/rust.md index 2611c23c3..c299113b5 100644 --- a/docs/tools/rust.md +++ b/docs/tools/rust.md @@ -1,7 +1,7 @@ Rust Library ============ -This is a no-frills interface between Bril's JSON and your [Rust][] code. It supports the [Bril core][core] along with the [SSA][], [memory][], [floating point][float], [speculative execution][spec], and [source positions][pos] extensions. +This is a no-frills interface between Bril's JSON and your [Rust][] code. It supports the [Bril core][core] along with the [SSA][], [memory][], [floating point][float], [speculative execution][spec], [char][], and [source positions][pos] extensions. Use --- @@ -55,4 +55,5 @@ make features [float]: ../lang/float.md [spec]: ../lang/spec.md [pos]: ../lang/syntax.md +[char]: ../lang/char.md [import]: ../lang/import.md diff --git a/test/interp-error/char-error/badconversion.bril b/test/interp-error/char-error/badconversion.bril index 7937f13d5..e6b742382 100644 --- a/test/interp-error/char-error/badconversion.bril +++ b/test/interp-error/char-error/badconversion.bril @@ -1,6 +1,6 @@ @main { i: int = const 56193; - + c: char = int2char i; print c;