Wrap FunctionName in a newtype struct.
Function names display differently than normal strings since they need quotes and escaping. Move the FunctionName type into its own module.
This commit is contained in:
@@ -29,7 +29,7 @@ ebb100(v20: i32):
|
|||||||
vx200 = iadd v20, v1000
|
vx200 = iadd v20, v1000
|
||||||
jump ebb100(v1000)
|
jump ebb100(v1000)
|
||||||
}
|
}
|
||||||
; sameln: function "use_value"() {
|
; sameln: function use_value() {
|
||||||
; nextln: ebb0(vx0: i32):
|
; nextln: ebb0(vx0: i32):
|
||||||
; nextln: v0 = iadd_imm vx0, 5
|
; nextln: v0 = iadd_imm vx0, 5
|
||||||
; nextln: v1 = iadd vx0, v0
|
; nextln: v1 = iadd vx0, v0
|
||||||
|
|||||||
77
cranelift/src/libcretonne/ir/funcname.rs
Normal file
77
cranelift/src/libcretonne/ir/funcname.rs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
//! Function names.
|
||||||
|
//!
|
||||||
|
//! The name of a function doesn't have any meaning to Cretonne which compiles functions
|
||||||
|
//! independently.
|
||||||
|
|
||||||
|
use std::fmt::{self, Write};
|
||||||
|
use std::ascii::AsciiExt;
|
||||||
|
|
||||||
|
/// The name of a function can be any UTF-8 string.
|
||||||
|
///
|
||||||
|
/// Function names are mostly a testing and debugging tool.
|
||||||
|
/// In particular, `.cton` files use function names to identify functions.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||||
|
pub struct FunctionName(String);
|
||||||
|
|
||||||
|
impl FunctionName {
|
||||||
|
pub fn new<S: Into<String>>(s: S) -> FunctionName {
|
||||||
|
FunctionName(s.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_id_start(c: char) -> bool {
|
||||||
|
c.is_ascii() && (c == '_' || c.is_alphabetic())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_id_continue(c: char) -> bool {
|
||||||
|
c.is_ascii() && (c == '_' || c.is_alphanumeric())
|
||||||
|
}
|
||||||
|
|
||||||
|
// The function name may need quotes if it doesn't parse as an identifier.
|
||||||
|
fn needs_quotes(name: &str) -> bool {
|
||||||
|
let mut iter = name.chars();
|
||||||
|
if let Some(ch) = iter.next() {
|
||||||
|
!is_id_start(ch) || !iter.all(is_id_continue)
|
||||||
|
} else {
|
||||||
|
// A blank function name needs quotes.
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for FunctionName {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if needs_quotes(&self.0) {
|
||||||
|
try!(f.write_char('"'));
|
||||||
|
for c in self.0.chars().flat_map(char::escape_default) {
|
||||||
|
try!(f.write_char(c));
|
||||||
|
}
|
||||||
|
f.write_char('"')
|
||||||
|
} else {
|
||||||
|
f.write_str(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{needs_quotes, FunctionName};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn quoting() {
|
||||||
|
assert_eq!(needs_quotes(""), true);
|
||||||
|
assert_eq!(needs_quotes("x"), false);
|
||||||
|
assert_eq!(needs_quotes(" "), true);
|
||||||
|
assert_eq!(needs_quotes("0"), true);
|
||||||
|
assert_eq!(needs_quotes("x0"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn escaping() {
|
||||||
|
assert_eq!(FunctionName::new("").to_string(), "\"\"");
|
||||||
|
assert_eq!(FunctionName::new("x").to_string(), "x");
|
||||||
|
assert_eq!(FunctionName::new(" ").to_string(), "\" \"");
|
||||||
|
assert_eq!(FunctionName::new(" \n").to_string(), "\" \\n\"");
|
||||||
|
assert_eq!(FunctionName::new("a\u{1000}v").to_string(),
|
||||||
|
"\"a\\u{1000}v\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,7 +52,7 @@ impl Function {
|
|||||||
|
|
||||||
/// Create a new empty, anomymous function.
|
/// Create a new empty, anomymous function.
|
||||||
pub fn new() -> Function {
|
pub fn new() -> Function {
|
||||||
Self::with_name_signature(FunctionName::new(), Signature::new())
|
Self::with_name_signature(FunctionName::default(), Signature::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the signature of this function.
|
/// Get the signature of this function.
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ pub mod jumptable;
|
|||||||
pub mod dfg;
|
pub mod dfg;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod function;
|
pub mod function;
|
||||||
|
mod funcname;
|
||||||
|
|
||||||
pub use ir::types::{Type, FunctionName, Signature};
|
pub use ir::funcname::FunctionName;
|
||||||
|
pub use ir::types::{Type, Signature};
|
||||||
pub use ir::entities::{Ebb, Inst, Value, StackSlot, JumpTable};
|
pub use ir::entities::{Ebb, Inst, Value, StackSlot, JumpTable};
|
||||||
pub use ir::instructions::{Opcode, InstructionData};
|
pub use ir::instructions::{Opcode, InstructionData};
|
||||||
pub use ir::stackslot::StackSlotData;
|
pub use ir::stackslot::StackSlotData;
|
||||||
|
|||||||
@@ -191,12 +191,6 @@ impl Default for Type {
|
|||||||
//
|
//
|
||||||
// ====--------------------------------------------------------------------------------------====//
|
// ====--------------------------------------------------------------------------------------====//
|
||||||
|
|
||||||
/// The name of a function can be any UTF-8 string.
|
|
||||||
///
|
|
||||||
/// Function names are mostly a testing and debugging tool. In partucular, `.cton` files use
|
|
||||||
/// function names to identify functions.
|
|
||||||
pub type FunctionName = String;
|
|
||||||
|
|
||||||
/// Function argument extension options.
|
/// Function argument extension options.
|
||||||
///
|
///
|
||||||
/// On some architectures, small integer function arguments are extended to the width of a
|
/// On some architectures, small integer function arguments are extended to the width of a
|
||||||
|
|||||||
@@ -29,30 +29,8 @@ pub fn write_function(w: &mut Write, func: &Function) -> Result {
|
|||||||
//
|
//
|
||||||
// ====--------------------------------------------------------------------------------------====//
|
// ====--------------------------------------------------------------------------------------====//
|
||||||
|
|
||||||
// The function name may need quotes if it doesn't parse as an identifier.
|
|
||||||
fn needs_quotes(name: &str) -> bool {
|
|
||||||
let mut iter = name.chars();
|
|
||||||
if let Some(ch) = iter.next() {
|
|
||||||
!ch.is_alphabetic() || !iter.all(char::is_alphanumeric)
|
|
||||||
} else {
|
|
||||||
// A blank function name needs quotes.
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use Rust's escape_default which provides a few simple \t \r \n \' \" \\ escapes and uses
|
|
||||||
// \u{xxxx} for anything else outside the ASCII printable range.
|
|
||||||
fn escaped(name: &str) -> String {
|
|
||||||
name.chars().flat_map(char::escape_default).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_spec(w: &mut Write, func: &Function) -> Result {
|
fn write_spec(w: &mut Write, func: &Function) -> Result {
|
||||||
let sig = func.own_signature();
|
write!(w, "function {}{}", func.name, func.own_signature())
|
||||||
if !needs_quotes(&func.name) {
|
|
||||||
write!(w, "function {}{}", func.name, sig)
|
|
||||||
} else {
|
|
||||||
write!(w, "function \"{}\"{}", escaped(&func.name), sig)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_preamble(w: &mut Write, func: &Function) -> result::Result<bool, Error> {
|
fn write_preamble(w: &mut Write, func: &Function) -> result::Result<bool, Error> {
|
||||||
@@ -208,34 +186,15 @@ pub fn write_instruction(w: &mut Write, func: &Function, inst: Inst) -> Result {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{needs_quotes, escaped};
|
use ir::{Function, FunctionName, StackSlotData};
|
||||||
use ir::{Function, StackSlotData};
|
|
||||||
use ir::types;
|
use ir::types;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn quoting() {
|
|
||||||
assert_eq!(needs_quotes(""), true);
|
|
||||||
assert_eq!(needs_quotes("x"), false);
|
|
||||||
assert_eq!(needs_quotes(" "), true);
|
|
||||||
assert_eq!(needs_quotes("0"), true);
|
|
||||||
assert_eq!(needs_quotes("x0"), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn escaping() {
|
|
||||||
assert_eq!(escaped(""), "");
|
|
||||||
assert_eq!(escaped("x"), "x");
|
|
||||||
assert_eq!(escaped(" "), " ");
|
|
||||||
assert_eq!(escaped(" \n"), " \\n");
|
|
||||||
assert_eq!(escaped("a\u{1000}v"), "a\\u{1000}v");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic() {
|
fn basic() {
|
||||||
let mut f = Function::new();
|
let mut f = Function::new();
|
||||||
assert_eq!(f.to_string(), "function \"\"() {\n}\n");
|
assert_eq!(f.to_string(), "function \"\"() {\n}\n");
|
||||||
|
|
||||||
f.name.push_str("foo");
|
f.name = FunctionName::new("foo".to_string());
|
||||||
assert_eq!(f.to_string(), "function foo() {\n}\n");
|
assert_eq!(f.to_string(), "function foo() {\n}\n");
|
||||||
|
|
||||||
f.stack_slots.push(StackSlotData::new(4));
|
f.stack_slots.push(StackSlotData::new(4));
|
||||||
|
|||||||
@@ -470,11 +470,11 @@ impl<'a> Parser<'a> {
|
|||||||
//
|
//
|
||||||
// function ::= "function" * name signature { ... }
|
// function ::= "function" * name signature { ... }
|
||||||
//
|
//
|
||||||
fn parse_function_name(&mut self) -> Result<String> {
|
fn parse_function_name(&mut self) -> Result<FunctionName> {
|
||||||
match self.token() {
|
match self.token() {
|
||||||
Some(Token::Identifier(s)) => {
|
Some(Token::Identifier(s)) => {
|
||||||
self.consume();
|
self.consume();
|
||||||
Ok(s.to_string())
|
Ok(FunctionName::new(s))
|
||||||
}
|
}
|
||||||
_ => err!(self.loc, "expected function name"),
|
_ => err!(self.loc, "expected function name"),
|
||||||
}
|
}
|
||||||
@@ -1161,7 +1161,7 @@ mod tests {
|
|||||||
}")
|
}")
|
||||||
.parse_function()
|
.parse_function()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(func.name, "foo");
|
assert_eq!(func.name.to_string(), "foo");
|
||||||
let mut iter = func.stack_slots.keys();
|
let mut iter = func.stack_slots.keys();
|
||||||
let ss0 = iter.next().unwrap();
|
let ss0 = iter.next().unwrap();
|
||||||
assert_eq!(ss0.to_string(), "ss0");
|
assert_eq!(ss0.to_string(), "ss0");
|
||||||
@@ -1190,7 +1190,7 @@ mod tests {
|
|||||||
}")
|
}")
|
||||||
.parse_function()
|
.parse_function()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(func.name, "ebbs");
|
assert_eq!(func.name.to_string(), "ebbs");
|
||||||
|
|
||||||
let mut ebbs = func.layout.ebbs();
|
let mut ebbs = func.layout.ebbs();
|
||||||
|
|
||||||
@@ -1219,7 +1219,7 @@ mod tests {
|
|||||||
; More trailing.")
|
; More trailing.")
|
||||||
.parse_function()
|
.parse_function()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(&func.name, "comment");
|
assert_eq!(func.name.to_string(), "comment");
|
||||||
assert_eq!(comments.len(), 8); // no 'before' comment.
|
assert_eq!(comments.len(), 8); // no 'before' comment.
|
||||||
assert_eq!(comments[0],
|
assert_eq!(comments[0],
|
||||||
Comment {
|
Comment {
|
||||||
@@ -1252,6 +1252,6 @@ mod tests {
|
|||||||
assert_eq!(tf.commands[0].command, "cfg");
|
assert_eq!(tf.commands[0].command, "cfg");
|
||||||
assert_eq!(tf.commands[1].command, "verify");
|
assert_eq!(tf.commands[1].command, "verify");
|
||||||
assert_eq!(tf.functions.len(), 1);
|
assert_eq!(tf.functions.len(), 1);
|
||||||
assert_eq!(tf.functions[0].0.name, "comment");
|
assert_eq!(tf.functions[0].0.name.to_string(), "comment");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user