|
|
|
@ -8,7 +8,7 @@ It provides the [create_formatter_fun]. It's syntax supports most of the
|
|
|
|
|
Rust string formatting functionality. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
use crate::vval::{VVal, Env, VValFun}; |
|
|
|
|
use crate::vval::{Env, VVal, VValFun}; |
|
|
|
|
|
|
|
|
|
use crate::parser::state::State; |
|
|
|
|
use crate::parser::state::{ParseError, ParseErrorKind}; |
|
|
|
@ -18,15 +18,18 @@ use std::fmt::Write;
|
|
|
|
|
fn parse_argument(ps: &mut State) -> Result<VVal, ParseError> { |
|
|
|
|
let mut is_integer = true; |
|
|
|
|
let mut identifier = String::new(); |
|
|
|
|
let mut index = String::new(); |
|
|
|
|
let mut index = String::new(); |
|
|
|
|
|
|
|
|
|
while !ps.lookahead_one_of(":$.}") { |
|
|
|
|
match ps.expect_some(ps.peek())? { |
|
|
|
|
c if c.is_digit(10) => { |
|
|
|
|
ps.consume(); |
|
|
|
|
if is_integer { index.push(c); } |
|
|
|
|
else { identifier.push(c); } |
|
|
|
|
}, |
|
|
|
|
if is_integer { |
|
|
|
|
index.push(c); |
|
|
|
|
} else { |
|
|
|
|
identifier.push(c); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
c => { |
|
|
|
|
if !index.is_empty() { |
|
|
|
|
identifier = index.clone(); |
|
|
|
@ -43,7 +46,7 @@ fn parse_argument(ps: &mut State) -> Result<VVal, ParseError> {
|
|
|
|
|
if is_integer { |
|
|
|
|
Ok(VVal::vec2(VVal::new_sym("index"), VVal::new_str_mv(index))) |
|
|
|
|
} else { |
|
|
|
|
Ok(VVal::vec2(VVal::new_sym("key"), VVal::new_str_mv(identifier))) |
|
|
|
|
Ok(VVal::vec2(VVal::new_sym("key"), VVal::new_str_mv(identifier))) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -55,18 +58,16 @@ fn parse_count(ps: &mut State) -> Result<VVal, ParseError> {
|
|
|
|
|
if let Ok(idx) = integer.to_string().parse::<u32>() { |
|
|
|
|
Ok(VVal::vec2(VVal::new_sym("count"), VVal::Int(idx as i64))) |
|
|
|
|
} else { |
|
|
|
|
Err(ps.err( |
|
|
|
|
ParseErrorKind::BadFormat( |
|
|
|
|
"expected proper integer".to_string()))) |
|
|
|
|
Err(ps.err(ParseErrorKind::BadFormat("expected proper integer".to_string()))) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq)] |
|
|
|
|
pub(crate) enum CastType { |
|
|
|
|
Str = 0, |
|
|
|
|
Int = 1, |
|
|
|
|
Flt = 2, |
|
|
|
|
Str = 0, |
|
|
|
|
Int = 1, |
|
|
|
|
Flt = 2, |
|
|
|
|
Written = 4, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -84,9 +85,9 @@ impl CastType {
|
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq)] |
|
|
|
|
pub(crate) enum FormatType { |
|
|
|
|
Unknown = 0, |
|
|
|
|
Hex = 1, |
|
|
|
|
Oct = 2, |
|
|
|
|
Bin = 3, |
|
|
|
|
Hex = 1, |
|
|
|
|
Oct = 2, |
|
|
|
|
Bin = 3, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl FormatType { |
|
|
|
@ -101,93 +102,92 @@ impl FormatType {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn parse_format_spec(ps: &mut State, arg: &VVal) -> Result<VVal, ParseError> { |
|
|
|
|
let mut fill : Option<char> = None; |
|
|
|
|
let mut align_char : Option<char> = None; |
|
|
|
|
let mut fill: Option<char> = None; |
|
|
|
|
let mut align_char: Option<char> = None; |
|
|
|
|
|
|
|
|
|
let align = ps.peek2(); |
|
|
|
|
if let Some(align) = align { |
|
|
|
|
match align.at(1) { |
|
|
|
|
c @ '<' |
|
|
|
|
| c @ '^' |
|
|
|
|
| c @ '>' => { |
|
|
|
|
fill = Some(align.at(0)); |
|
|
|
|
c @ '<' | c @ '^' | c @ '>' => { |
|
|
|
|
fill = Some(align.at(0)); |
|
|
|
|
align_char = Some(c); |
|
|
|
|
ps.consume(); |
|
|
|
|
ps.consume(); |
|
|
|
|
}, |
|
|
|
|
_ => { }, |
|
|
|
|
} |
|
|
|
|
_ => {} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if align_char .is_none() { |
|
|
|
|
if align_char.is_none() { |
|
|
|
|
match ps.expect_some(ps.peek())? { |
|
|
|
|
c @ '<' |
|
|
|
|
| c @ '^' |
|
|
|
|
| c @ '>' => { |
|
|
|
|
c @ '<' | c @ '^' | c @ '>' => { |
|
|
|
|
align_char = Some(c); |
|
|
|
|
ps.consume(); |
|
|
|
|
}, |
|
|
|
|
_ => { }, |
|
|
|
|
} |
|
|
|
|
_ => {} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let mut sign : Option<char> = None; |
|
|
|
|
let mut sign: Option<char> = None; |
|
|
|
|
match ps.expect_some(ps.peek())? { |
|
|
|
|
c @ '-' |
|
|
|
|
| c @ '+' => { |
|
|
|
|
c @ '-' | c @ '+' => { |
|
|
|
|
sign = Some(c); |
|
|
|
|
ps.consume(); |
|
|
|
|
}, |
|
|
|
|
_ => { }, |
|
|
|
|
} |
|
|
|
|
_ => {} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let alternate = ps.consume_if_eq('#'); |
|
|
|
|
let pad0 = ps.consume_if_eq('0'); |
|
|
|
|
let pad0 = ps.consume_if_eq('0'); |
|
|
|
|
|
|
|
|
|
let width = |
|
|
|
|
if ps.find_char_not_of('$', ".").is_some() |
|
|
|
|
|| ( ps.peek().is_some() |
|
|
|
|
&& ps.lookahead_one_of("0123456789")) { |
|
|
|
|
parse_count(ps)? |
|
|
|
|
} else { |
|
|
|
|
VVal::None |
|
|
|
|
}; |
|
|
|
|
let width = if ps.find_char_not_of('$', ".").is_some() |
|
|
|
|
|| (ps.peek().is_some() && ps.lookahead_one_of("0123456789")) |
|
|
|
|
{ |
|
|
|
|
parse_count(ps)? |
|
|
|
|
} else { |
|
|
|
|
VVal::None |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let precision = |
|
|
|
|
if ps.consume_if_eq('.') { |
|
|
|
|
if ps.consume_if_eq('*') { |
|
|
|
|
if arg.at(0).unwrap().with_s_ref(|s| s == "index") { |
|
|
|
|
let idx = arg.at(1).unwrap(); |
|
|
|
|
arg.set(1, VVal::Int(idx.i() + 1)); |
|
|
|
|
let precision = if ps.consume_if_eq('.') { |
|
|
|
|
if ps.consume_if_eq('*') { |
|
|
|
|
if arg.at(0).unwrap().with_s_ref(|s| s == "index") { |
|
|
|
|
let idx = arg.at(1).unwrap(); |
|
|
|
|
arg.set(1, VVal::Int(idx.i() + 1)); |
|
|
|
|
|
|
|
|
|
VVal::vec2(VVal::new_sym("index"), idx) |
|
|
|
|
} else { |
|
|
|
|
return Err(ps.err( |
|
|
|
|
ParseErrorKind::BadFormat( |
|
|
|
|
"can't use * in combination with named arg".to_string()))); |
|
|
|
|
} |
|
|
|
|
VVal::vec2(VVal::new_sym("index"), idx) |
|
|
|
|
} else { |
|
|
|
|
parse_count(ps)? |
|
|
|
|
return Err(ps.err(ParseErrorKind::BadFormat( |
|
|
|
|
"can't use * in combination with named arg".to_string(), |
|
|
|
|
))); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
VVal::None |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let mut cast_type = |
|
|
|
|
if ps.consume_if_eq('!') { |
|
|
|
|
match ps.expect_some(ps.peek())? { |
|
|
|
|
'i' => { ps.consume(); Some(CastType::Int) }, |
|
|
|
|
'f' => { ps.consume(); Some(CastType::Flt) }, |
|
|
|
|
'w' => { ps.consume(); Some(CastType::Written) }, |
|
|
|
|
c => { |
|
|
|
|
return Err(ps.err( |
|
|
|
|
ParseErrorKind::BadFormat( |
|
|
|
|
format!("Unknown cast type: {}", c)))); |
|
|
|
|
} |
|
|
|
|
parse_count(ps)? |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
VVal::None |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let mut cast_type = if ps.consume_if_eq('!') { |
|
|
|
|
match ps.expect_some(ps.peek())? { |
|
|
|
|
'i' => { |
|
|
|
|
ps.consume(); |
|
|
|
|
Some(CastType::Int) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
None |
|
|
|
|
}; |
|
|
|
|
'f' => { |
|
|
|
|
ps.consume(); |
|
|
|
|
Some(CastType::Flt) |
|
|
|
|
} |
|
|
|
|
'w' => { |
|
|
|
|
ps.consume(); |
|
|
|
|
Some(CastType::Written) |
|
|
|
|
} |
|
|
|
|
c => { |
|
|
|
|
return Err(ps.err(ParseErrorKind::BadFormat(format!("Unknown cast type: {}", c)))); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
None |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let m = VVal::map(); |
|
|
|
|
|
|
|
|
@ -195,15 +195,15 @@ fn parse_format_spec(ps: &mut State, arg: &VVal) -> Result<VVal, ParseError> {
|
|
|
|
|
'x' => { |
|
|
|
|
ps.consume(); |
|
|
|
|
m.set_key_str("type", VVal::Int(FormatType::Hex as i64)).unwrap(); |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
'o' => { |
|
|
|
|
ps.consume(); |
|
|
|
|
m.set_key_str("type", VVal::Int(FormatType::Oct as i64)).unwrap(); |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
'b' => { |
|
|
|
|
ps.consume(); |
|
|
|
|
m.set_key_str("type", VVal::Int(FormatType::Bin as i64)).unwrap(); |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
_ => { |
|
|
|
|
m.set_key_str("type", VVal::Int(FormatType::Unknown as i64)).unwrap(); |
|
|
|
|
} |
|
|
|
@ -215,18 +215,28 @@ fn parse_format_spec(ps: &mut State, arg: &VVal) -> Result<VVal, ParseError> {
|
|
|
|
|
m.set_key_str("fill", VVal::new_str(" ")).unwrap(); |
|
|
|
|
} |
|
|
|
|
match align_char { |
|
|
|
|
Some('<') => { m.set_key_str("align", VVal::Int(-1)).unwrap(); }, |
|
|
|
|
Some('>') => { m.set_key_str("align", VVal::Int( 1)).unwrap(); }, |
|
|
|
|
Some('^') => { m.set_key_str("align", VVal::Int( 2)).unwrap(); }, |
|
|
|
|
_ => (), |
|
|
|
|
Some('<') => { |
|
|
|
|
m.set_key_str("align", VVal::Int(-1)).unwrap(); |
|
|
|
|
} |
|
|
|
|
Some('>') => { |
|
|
|
|
m.set_key_str("align", VVal::Int(1)).unwrap(); |
|
|
|
|
} |
|
|
|
|
Some('^') => { |
|
|
|
|
m.set_key_str("align", VVal::Int(2)).unwrap(); |
|
|
|
|
} |
|
|
|
|
_ => (), |
|
|
|
|
} |
|
|
|
|
match sign { |
|
|
|
|
Some('-') => { m.set_key_str("sign", VVal::Int(-1)).unwrap(); }, |
|
|
|
|
Some('+') => { m.set_key_str("sign", VVal::Int( 1)).unwrap(); }, |
|
|
|
|
_ => (), |
|
|
|
|
Some('-') => { |
|
|
|
|
m.set_key_str("sign", VVal::Int(-1)).unwrap(); |
|
|
|
|
} |
|
|
|
|
Some('+') => { |
|
|
|
|
m.set_key_str("sign", VVal::Int(1)).unwrap(); |
|
|
|
|
} |
|
|
|
|
_ => (), |
|
|
|
|
} |
|
|
|
|
m.set_key_str("alternate", VVal::Bol(alternate)).unwrap(); |
|
|
|
|
m.set_key_str("pad0", VVal::Bol(pad0)).unwrap(); |
|
|
|
|
m.set_key_str("alternate", VVal::Bol(alternate)).unwrap(); |
|
|
|
|
m.set_key_str("pad0", VVal::Bol(pad0)).unwrap(); |
|
|
|
|
if width.is_some() { |
|
|
|
|
m.set_key_str("width", width).unwrap(); |
|
|
|
|
} |
|
|
|
@ -250,17 +260,14 @@ fn parse_format(ps: &mut State, implicit_index: &mut usize) -> Result<VVal, Pars
|
|
|
|
|
|
|
|
|
|
let mut was_implicit_idx = false; |
|
|
|
|
let c = ps.expect_some(ps.peek())?; |
|
|
|
|
let arg = |
|
|
|
|
if c != ':' && c != '}' { |
|
|
|
|
parse_argument(ps)? |
|
|
|
|
} else { |
|
|
|
|
let arg = VVal::vec2(VVal::new_sym("index"), |
|
|
|
|
VVal::Int(*implicit_index as i64)); |
|
|
|
|
*implicit_index += 1; |
|
|
|
|
was_implicit_idx = true; |
|
|
|
|
arg |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let arg = if c != ':' && c != '}' { |
|
|
|
|
parse_argument(ps)? |
|
|
|
|
} else { |
|
|
|
|
let arg = VVal::vec2(VVal::new_sym("index"), VVal::Int(*implicit_index as i64)); |
|
|
|
|
*implicit_index += 1; |
|
|
|
|
was_implicit_idx = true; |
|
|
|
|
arg |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let c = ps.expect_some(ps.peek())?; |
|
|
|
|
if c == ':' { |
|
|
|
@ -278,8 +285,7 @@ fn parse_format(ps: &mut State, implicit_index: &mut usize) -> Result<VVal, Pars
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !ps.consume_if_eq('}') { |
|
|
|
|
return Err(ps.err( |
|
|
|
|
ParseErrorKind::ExpectedToken('}', "format end"))); |
|
|
|
|
return Err(ps.err(ParseErrorKind::ExpectedToken('}', "format end"))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ok(VVal::vec3(VVal::new_sym("format"), arg, fmt)) |
|
|
|
@ -303,23 +309,24 @@ fn parse_formatter(s: &str) -> Result<VVal, ParseError> {
|
|
|
|
|
ps.consume(); |
|
|
|
|
|
|
|
|
|
if !cur_text.is_empty() { |
|
|
|
|
fmt.push(VVal::vec2(VVal::new_sym("text"), |
|
|
|
|
VVal::new_str(&cur_text))); |
|
|
|
|
fmt.push(VVal::vec2(VVal::new_sym("text"), VVal::new_str(&cur_text))); |
|
|
|
|
cur_text = String::new(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fmt.push(parse_format(&mut ps, &mut impl_idx)?); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
'}' => { |
|
|
|
|
if ps.consume_lookahead("}}") { |
|
|
|
|
cur_text.push('}'); |
|
|
|
|
} else { |
|
|
|
|
return Err(ps.err( |
|
|
|
|
ParseErrorKind::UnexpectedToken('}', "format end"))); |
|
|
|
|
return Err(ps.err(ParseErrorKind::UnexpectedToken('}', "format end"))); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
c => { ps.consume(); cur_text.push(c); }, |
|
|
|
|
} |
|
|
|
|
c => { |
|
|
|
|
ps.consume(); |
|
|
|
|
cur_text.push(c); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -332,7 +339,7 @@ fn parse_formatter(s: &str) -> Result<VVal, ParseError> {
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)] |
|
|
|
|
pub(crate) struct FormatState { |
|
|
|
|
str_data: Option<String>, |
|
|
|
|
str_data: Option<String>, |
|
|
|
|
byte_data: Option<Vec<u8>>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -346,7 +353,7 @@ impl core::fmt::Write for FormatState {
|
|
|
|
|
if let Some(sd) = &mut self.str_data.as_mut() { |
|
|
|
|
sd.push_str(s); |
|
|
|
|
} else if let Some(bd) = &mut self.byte_data.as_mut() { |
|
|
|
|
let r : &[u8] = s.as_ref(); |
|
|
|
|
let r: &[u8] = s.as_ref(); |
|
|
|
|
for b in r.iter() { |
|
|
|
|
bd.push(*b); |
|
|
|
|
} |
|
|
|
@ -356,16 +363,16 @@ impl core::fmt::Write for FormatState {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl FormatState { |
|
|
|
|
// fn add_char(&mut self, c: char) {
|
|
|
|
|
// if let Some(sd) = &mut self.str_data.as_mut() {
|
|
|
|
|
// sd.push(c);
|
|
|
|
|
// } else if let Some(bd) = &mut self.byte_data.as_mut() {
|
|
|
|
|
// let mut b = [0; 4];
|
|
|
|
|
// for cb in c.encode_utf8(&mut b).as_bytes().iter() {
|
|
|
|
|
// bd.push(*cb);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// fn add_char(&mut self, c: char) {
|
|
|
|
|
// if let Some(sd) = &mut self.str_data.as_mut() {
|
|
|
|
|
// sd.push(c);
|
|
|
|
|
// } else if let Some(bd) = &mut self.byte_data.as_mut() {
|
|
|
|
|
// let mut b = [0; 4];
|
|
|
|
|
// for cb in c.encode_utf8(&mut b).as_bytes().iter() {
|
|
|
|
|
// bd.push(*cb);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
fn cur_len(&self) -> usize { |
|
|
|
|
if let Some(sd) = &self.str_data.as_ref() { |
|
|
|
@ -400,14 +407,12 @@ impl FormatState {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub(crate) type FormatNode = Box<dyn Fn(&mut FormatState, &[VVal]) -> std::fmt::Result>; |
|
|
|
|
pub(crate) type CountNode = Box<dyn Fn(&mut FormatState, &[VVal]) -> usize>; |
|
|
|
|
pub(crate) type CountNode = Box<dyn Fn(&mut FormatState, &[VVal]) -> usize>; |
|
|
|
|
|
|
|
|
|
pub(crate) fn compile_count(count: &VVal) -> CountNode { |
|
|
|
|
if count.v_with_s_ref(0, |s| s == "count") { |
|
|
|
|
let count = count.v_i(1); |
|
|
|
|
Box::new(move |_fs: &mut FormatState, _args: &[VVal]| -> usize { |
|
|
|
|
count as usize |
|
|
|
|
}) |
|
|
|
|
Box::new(move |_fs: &mut FormatState, _args: &[VVal]| -> usize { count as usize }) |
|
|
|
|
} else { |
|
|
|
|
let count = count.clone(); |
|
|
|
|
Box::new(move |_fs: &mut FormatState, _args: &[VVal]| -> usize { |
|
|
|
@ -417,8 +422,14 @@ pub(crate) fn compile_count(count: &VVal) -> CountNode {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[allow(clippy::many_single_char_names)] |
|
|
|
|
pub(crate) fn write_vval<F>(arg: &VVal, fs: &mut FormatState, ct: CastType, mut f: F) -> std::fmt::Result |
|
|
|
|
where F: FnMut(&mut FormatState, &VVal) -> std::fmt::Result |
|
|
|
|
pub(crate) fn write_vval<F>( |
|
|
|
|
arg: &VVal, |
|
|
|
|
fs: &mut FormatState, |
|
|
|
|
ct: CastType, |
|
|
|
|
mut f: F, |
|
|
|
|
) -> std::fmt::Result |
|
|
|
|
where |
|
|
|
|
F: FnMut(&mut FormatState, &VVal) -> std::fmt::Result, |
|
|
|
|
{ |
|
|
|
|
use crate::nvec::NVec; |
|
|
|
|
|
|
|
|
@ -434,14 +445,14 @@ pub(crate) fn write_vval<F>(arg: &VVal, fs: &mut FormatState, ct: CastType, mut
|
|
|
|
|
f(fs, &VVal::Int(*a))?; |
|
|
|
|
write!(fs, ",")?; |
|
|
|
|
f(fs, &VVal::Int(*b))?; |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
NVec::Vec3(a, b, c) => { |
|
|
|
|
f(fs, &VVal::Int(*a))?; |
|
|
|
|
write!(fs, ",")?; |
|
|
|
|
f(fs, &VVal::Int(*b))?; |
|
|
|
|
write!(fs, ",")?; |
|
|
|
|
f(fs, &VVal::Int(*c))?; |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
NVec::Vec4(a, b, c, d) => { |
|
|
|
|
f(fs, &VVal::Int(*a))?; |
|
|
|
|
write!(fs, ",")?; |
|
|
|
@ -450,10 +461,10 @@ pub(crate) fn write_vval<F>(arg: &VVal, fs: &mut FormatState, ct: CastType, mut
|
|
|
|
|
f(fs, &VVal::Int(*c))?; |
|
|
|
|
write!(fs, ",")?; |
|
|
|
|
f(fs, &VVal::Int(*d))?; |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
write!(fs, ")")?; |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
VVal::FVec(v) => { |
|
|
|
|
write!(fs, "(")?; |
|
|
|
|
match v.as_ref() { |
|
|
|
@ -461,14 +472,14 @@ pub(crate) fn write_vval<F>(arg: &VVal, fs: &mut FormatState, ct: CastType, mut
|
|
|
|
|
f(fs, &VVal::Flt(*a))?; |
|
|
|
|
write!(fs, ",")?; |
|
|
|
|
f(fs, &VVal::Flt(*b))?; |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
NVec::Vec3(a, b, c) => { |
|
|
|
|
f(fs, &VVal::Flt(*a))?; |
|
|
|
|
write!(fs, ",")?; |
|
|
|
|
f(fs, &VVal::Flt(*b))?; |
|
|
|
|
write!(fs, ",")?; |
|
|
|
|
f(fs, &VVal::Flt(*c))?; |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
NVec::Vec4(a, b, c, d) => { |
|
|
|
|
f(fs, &VVal::Flt(*a))?; |
|
|
|
|
write!(fs, ",")?; |
|
|
|
@ -477,10 +488,10 @@ pub(crate) fn write_vval<F>(arg: &VVal, fs: &mut FormatState, ct: CastType, mut
|
|
|
|
|
f(fs, &VVal::Flt(*c))?; |
|
|
|
|
write!(fs, ",")?; |
|
|
|
|
f(fs, &VVal::Flt(*d))?; |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
write!(fs, ")")?; |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
VVal::Pair(ab) => { |
|
|
|
|
let (a, b) = ab.as_ref(); |
|
|
|
|
write!(fs, "(")?; |
|
|
|
@ -488,29 +499,35 @@ pub(crate) fn write_vval<F>(arg: &VVal, fs: &mut FormatState, ct: CastType, mut
|
|
|
|
|
write!(fs, ",")?; |
|
|
|
|
f(fs, b)?; |
|
|
|
|
write!(fs, ")")?; |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
VVal::Lst(_) => { |
|
|
|
|
write!(fs, "[")?; |
|
|
|
|
let mut first = true; |
|
|
|
|
for (a, _) in arg.iter() { |
|
|
|
|
if first { first = false; } |
|
|
|
|
else { write!(fs, ",")?; } |
|
|
|
|
if first { |
|
|
|
|
first = false; |
|
|
|
|
} else { |
|
|
|
|
write!(fs, ",")?; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
f(fs, &a)?; |
|
|
|
|
} |
|
|
|
|
write!(fs, "]")?; |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
VVal::Map(m) => { |
|
|
|
|
use crate::str_int::*; |
|
|
|
|
write!(fs, "{{")?; |
|
|
|
|
let hm = m.borrow(); |
|
|
|
|
let mut keys : Vec<&Symbol> = hm.keys().collect(); |
|
|
|
|
let mut keys: Vec<&Symbol> = hm.keys().collect(); |
|
|
|
|
keys.sort(); |
|
|
|
|
|
|
|
|
|
let mut first = true; |
|
|
|
|
for k in keys { |
|
|
|
|
if first { first = false; } |
|
|
|
|
else { write!(fs, ", ")?; } |
|
|
|
|
if first { |
|
|
|
|
first = false; |
|
|
|
|
} else { |
|
|
|
|
write!(fs, ", ")?; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let v = hm.get(k).unwrap(); |
|
|
|
|
write!(fs, "{}:", k.as_ref())?; |
|
|
|
@ -518,60 +535,78 @@ pub(crate) fn write_vval<F>(arg: &VVal, fs: &mut FormatState, ct: CastType, mut
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
write!(fs, "}}")?; |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
v => f(fs, v)?, |
|
|
|
|
} |
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub(crate) fn with_format_arg_write<F>(arg: &FormatArg, args: &[VVal], fs: &mut FormatState, ct: CastType, f: F) -> std::fmt::Result |
|
|
|
|
where F: FnMut(&mut FormatState, &VVal) -> std::fmt::Result |
|
|
|
|
pub(crate) fn with_format_arg_write<F>( |
|
|
|
|
arg: &FormatArg, |
|
|
|
|
args: &[VVal], |
|
|
|
|
fs: &mut FormatState, |
|
|
|
|
ct: CastType, |
|
|
|
|
f: F, |
|
|
|
|
) -> std::fmt::Result |
|
|
|
|
where |
|
|
|
|
F: FnMut(&mut FormatState, &VVal) -> std::fmt::Result, |
|
|
|
|
{ |
|
|
|
|
match arg { |
|
|
|
|
FormatArg::Index(i) => { write_vval(&args[*i], fs, ct, f) }, |
|
|
|
|
FormatArg::Index(i) => write_vval(&args[*i], fs, ct, f), |
|
|
|
|
FormatArg::Key(k) => { |
|
|
|
|
let val = |
|
|
|
|
k.with_s_ref(|ks| |
|
|
|
|
args[0].get_key(ks).unwrap_or(VVal::None)); |
|
|
|
|
let val = k.with_s_ref(|ks| args[0].get_key(ks).unwrap_or(VVal::None)); |
|
|
|
|
write_vval(&val, fs, ct, f) |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
macro_rules! ft_align_write { |
|
|
|
|
($ftype: ident, $align: ident, $fs: ident, $prefix: literal, $postfix: expr, $arg0: expr, $arg1: expr) => { |
|
|
|
|
match $ftype { |
|
|
|
|
FormatType::Bin => |
|
|
|
|
align_write!($align, $fs, $prefix, concat!($postfix, "b"), $arg0, $arg1), |
|
|
|
|
FormatType::Oct => |
|
|
|
|
align_write!($align, $fs, $prefix, concat!($postfix, "o"), $arg0, $arg1), |
|
|
|
|
FormatType::Hex => |
|
|
|
|
align_write!($align, $fs, $prefix, concat!($postfix, "x"), $arg0, $arg1), |
|
|
|
|
FormatType::Unknown => |
|
|
|
|
align_write!($align, $fs, $prefix, $postfix, $arg0, $arg1), |
|
|
|
|
FormatType::Bin => { |
|
|
|
|
align_write!($align, $fs, $prefix, concat!($postfix, "b"), $arg0, $arg1) |
|
|
|
|
} |
|
|
|
|
FormatType::Oct => { |
|
|
|
|
align_write!($align, $fs, $prefix, concat!($postfix, "o"), $arg0, $arg1) |
|
|
|
|
} |
|
|
|
|
FormatType::Hex => { |
|
|
|
|
align_write!($align, $fs, $prefix, concat!($postfix, "x"), $arg0, $arg1) |
|
|
|
|
} |
|
|
|
|
FormatType::Unknown => align_write!($align, $fs, $prefix, $postfix, $arg0, $arg1), |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
macro_rules! align_write { |
|
|
|
|
($align: ident, $fs: ident, $prefix: literal, $postfix: expr, $arg0: expr, $arg1: expr) => { |
|
|
|
|
match $align { |
|
|
|
|
1 => { write!($fs, concat!("{", $prefix, ">", $postfix, "}"), $arg0, $arg1) }, |
|
|
|
|
2 => { write!($fs, concat!("{", $prefix, "^", $postfix, "}"), $arg0, $arg1) }, |
|
|
|
|
_ => { write!($fs, concat!("{", $prefix, "<", $postfix, "}"), $arg0, $arg1) }, |
|
|
|
|
1 => { |
|
|
|
|
write!($fs, concat!("{", $prefix, ">", $postfix, "}"), $arg0, $arg1) |
|
|
|
|
} |
|
|
|
|
2 => { |
|
|
|
|
write!($fs, concat!("{", $prefix, "^", $postfix, "}"), $arg0, $arg1) |
|
|
|
|
} |
|
|
|
|
_ => { |
|
|
|
|
write!($fs, concat!("{", $prefix, "<", $postfix, "}"), $arg0, $arg1) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
($align: ident, $fs: ident, $prefix: literal, $postfix: expr, $arg0: expr, $arg1: expr, $arg2: expr) => { |
|
|
|
|
match $align { |
|
|
|
|
1 => { write!($fs, concat!("{", $prefix, ">", $postfix, "}"), $arg0, $arg1, $arg2) }, |
|
|
|
|
2 => { write!($fs, concat!("{", $prefix, "^", $postfix, "}"), $arg0, $arg1, $arg2) }, |
|
|
|
|
_ => { write!($fs, concat!("{", $prefix, "<", $postfix, "}"), $arg0, $arg1, $arg2) }, |
|
|
|
|
1 => { |
|
|
|
|
write!($fs, concat!("{", $prefix, ">", $postfix, "}"), $arg0, $arg1, $arg2) |
|
|
|
|
} |
|
|
|
|
2 => { |
|
|
|
|
write!($fs, concat!("{", $prefix, "^", $postfix, "}"), $arg0, $arg1, $arg2) |
|
|
|
|
} |
|
|
|
|
_ => { |
|
|
|
|
write!($fs, concat!("{", $prefix, "<", $postfix, "}"), $arg0, $arg1, $arg2) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub(crate) type AlignNode = Box<dyn Fn(&mut FormatState, &[VVal], usize) -> std::fmt::Result>; |
|
|
|
|
pub(crate) type AlignNode = Box<dyn Fn(&mut FormatState, &[VVal], usize) -> std::fmt::Result>; |
|
|
|
|
|
|
|
|
|
pub(crate) fn compile_align_fun(fill: String, width: Option<CountNode>, align: i64) -> AlignNode { |
|
|
|
|
if let Some(width) = width { |
|
|
|
@ -583,30 +618,26 @@ pub(crate) fn compile_align_fun(fill: String, width: Option<CountNode>, align: i
|
|
|
|
|
let pad_len = width - len; |
|
|
|
|
|
|
|
|
|
match align { |
|
|
|
|
1 => { |
|
|
|
|
1 => { |
|
|
|
|
let idx = fs.cur_len() - len; |
|
|
|
|
let pad = fill.repeat(pad_len); |
|
|
|
|
fs.insert_at(idx, &pad); |
|
|
|
|
}, |
|
|
|
|
2 => { |
|
|
|
|
let first_half_pad = pad_len / 2; |
|
|
|
|
} |
|
|
|
|
2 => { |
|
|
|
|
let first_half_pad = pad_len / 2; |
|
|
|
|
let second_half_pad = |
|
|
|
|
if first_half_pad <= pad_len { |
|
|
|
|
pad_len - first_half_pad |
|
|
|
|
} else { |
|
|
|
|
0 |
|
|
|
|
}; |
|
|
|
|
if first_half_pad <= pad_len { pad_len - first_half_pad } else { 0 }; |
|
|
|
|
let idx = fs.cur_len() - len; |
|
|
|
|
let pad_l = fill.repeat(first_half_pad); |
|
|
|
|
let pad_r = fill.repeat(second_half_pad); |
|
|
|
|
fs.insert_at(idx, &pad_l); |
|
|
|
|
fs.insert_at(fs.cur_len(), &pad_r); |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
-1 => { |
|
|
|
|
let pad = fill.repeat(pad_len); |
|
|
|
|
fs.insert_at(fs.cur_len(), &pad); |
|
|
|
|
}, |
|
|
|
|
_ => (), |
|
|
|
|
} |
|
|
|
|
_ => (), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -623,23 +654,15 @@ pub(crate) fn compile_align_fun(fill: String, width: Option<CountNode>, align: i
|
|
|
|
|
#[allow(clippy::collapsible_else_if)] |
|
|
|
|
pub(crate) fn compile_format(arg: FormatArg, fmt: &VVal) -> FormatNode { |
|
|
|
|
let width = fmt.get_key("width"); |
|
|
|
|
let width : Option<CountNode> = |
|
|
|
|
if let Some(width) = width { |
|
|
|
|
Some(compile_count(&width)) |
|
|
|
|
} else { |
|
|
|
|
None |
|
|
|
|
}; |
|
|
|
|
let width: Option<CountNode> = |
|
|
|
|
if let Some(width) = width { Some(compile_count(&width)) } else { None }; |
|
|
|
|
|
|
|
|
|
let prec = fmt.get_key("precision"); |
|
|
|
|
let prec : Option<CountNode> = |
|
|
|
|
if let Some(prec) = prec { |
|
|
|
|
Some(compile_count(&prec)) |
|
|
|
|
} else { |
|
|
|
|
None |
|
|
|
|
}; |
|
|
|
|
let prec: Option<CountNode> = |
|
|
|
|
if let Some(prec) = prec { Some(compile_count(&prec)) } else { None }; |
|
|
|
|
|
|
|
|
|
let align = fmt.v_ik("align"); |
|
|
|
|
let mut fill = fmt.v_s_rawk("fill"); |
|
|
|
|
let mut fill = fmt.v_s_rawk("fill"); |
|
|
|
|
if fill.is_empty() { |
|
|
|
|
fill = String::from(" "); |
|
|
|
|
} |
|
|
|
@ -651,8 +674,7 @@ pub(crate) fn compile_format(arg: FormatArg, fmt: &VVal) -> FormatNode {
|
|
|
|
|
match cast_type { |
|
|
|
|
CastType::Int => { |
|
|
|
|
if let Some(width) = width { |
|
|
|
|
let align = |
|
|
|
|
if align == 0 { 1 } else { align }; |
|
|
|
|
let align = if align == 0 { 1 } else { align }; |
|
|
|
|
|
|
|
|
|
if fmt.v_ik("pad0") > 0 { |
|
|
|
|
Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
@ -662,7 +684,6 @@ pub(crate) fn compile_format(arg: FormatArg, fmt: &VVal) -> FormatNode {
|
|
|
|
|
ft_align_write!(ftype, align, fs, "0:", "01$", v.i(), width) |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
let width = (*width)(fs, args); |
|
|
|
@ -672,56 +693,49 @@ pub(crate) fn compile_format(arg: FormatArg, fmt: &VVal) -> FormatNode {
|
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
match ftype { |
|
|
|
|
FormatType::Bin => |
|
|
|
|
Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
with_format_arg_write(&arg, args, fs, cast_type, |fs, v| { |
|
|
|
|
write!(fs, concat!("{:b}"), v.i()) |
|
|
|
|
}) |
|
|
|
|
}), |
|
|
|
|
FormatType::Oct => |
|
|
|
|
Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
with_format_arg_write(&arg, args, fs, cast_type, |fs, v| { |
|
|
|
|
write!(fs, concat!("{:o}"), v.i()) |
|
|
|
|
}) |
|
|
|
|
}), |
|
|
|
|
FormatType::Hex => |
|
|
|
|
Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
with_format_arg_write(&arg, args, fs, cast_type, |fs, v| { |
|
|
|
|
write!(fs, concat!("{:x}"), v.i()) |
|
|
|
|
}) |
|
|
|
|
}), |
|
|
|
|
FormatType::Unknown => |
|
|
|
|
Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
with_format_arg_write(&arg, args, fs, cast_type, |fs, v| { |
|
|
|
|
write!(fs, concat!("{}"), v.i()) |
|
|
|
|
}) |
|
|
|
|
FormatType::Bin => Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
with_format_arg_write(&arg, args, fs, cast_type, |fs, v| { |
|
|
|
|
write!(fs, concat!("{:b}"), v.i()) |
|
|
|
|
}) |
|
|
|
|
}), |
|
|
|
|
FormatType::Oct => Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
with_format_arg_write(&arg, args, fs, cast_type, |fs, v| { |
|
|
|
|
write!(fs, concat!("{:o}"), v.i()) |
|
|
|
|
}) |
|
|
|
|
}), |
|
|
|
|
FormatType::Hex => Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
with_format_arg_write(&arg, args, fs, cast_type, |fs, v| { |
|
|
|
|
write!(fs, concat!("{:x}"), v.i()) |
|
|
|
|
}) |
|
|
|
|
}), |
|
|
|
|
FormatType::Unknown => Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
with_format_arg_write(&arg, args, fs, cast_type, |fs, v| { |
|
|
|
|
write!(fs, concat!("{}"), v.i()) |
|
|
|
|
}) |
|
|
|
|
}), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
CastType::Flt => { |
|
|
|
|
if let Some(width) = width { |
|
|
|
|
let align = |
|
|
|
|
if align == 0 { 1 } else { align }; |
|
|
|
|
let align = if align == 0 { 1 } else { align }; |
|
|
|
|
|
|
|
|
|
if let Some(prec) = prec { |
|
|
|
|
if fmt.v_ik("pad0") > 0 { |
|
|
|
|
Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
let width = (*width)(fs, args); |
|
|
|
|
let prec = (*prec)(fs, args); |
|
|
|
|
let prec = (*prec)(fs, args); |
|
|
|
|
|
|
|
|
|
with_format_arg_write(&arg, args, fs, cast_type, |fs, v| { |
|
|
|
|
align_write!(align, fs, "0:", "01$.2$", v.f(), width, prec) |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
let width = (*width)(fs, args); |
|
|
|
|
let prec = (*prec)(fs, args); |
|
|
|
|
let prec = (*prec)(fs, args); |
|
|
|
|
|
|
|
|
|
with_format_arg_write(&arg, args, fs, cast_type, |fs, v| { |
|
|
|
|
align_write!(align, fs, "0:", "1$.2$", v.f(), width, prec) |
|
|
|
@ -737,7 +751,6 @@ pub(crate) fn compile_format(arg: FormatArg, fmt: &VVal) -> FormatNode {
|
|
|
|
|
align_write!(align, fs, "0:", "01$", v.f(), width) |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
let width = (*width)(fs, args); |
|
|
|
@ -748,7 +761,6 @@ pub(crate) fn compile_format(arg: FormatArg, fmt: &VVal) -> FormatNode {
|
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} else if let Some(prec) = prec { |
|
|
|
|
Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
let prec = (*prec)(fs, args); |
|
|
|
@ -786,7 +798,7 @@ pub(crate) fn compile_format(arg: FormatArg, fmt: &VVal) -> FormatNode {
|
|
|
|
|
|
|
|
|
|
Box::new(move |fs: &mut FormatState, args: &[VVal]| { |
|
|
|
|
let mut len = 0; |
|
|
|
|
with_format_arg_write(&arg, args, fs, cast_type,|fs, v| { |
|
|
|
|
with_format_arg_write(&arg, args, fs, cast_type, |fs, v| { |
|
|
|
|
if v.is_bytes() { |
|
|
|
|
v.with_bv_ref(|bv| { |
|
|
|
|
len = bv.len(); |
|
|
|
@ -812,7 +824,7 @@ pub(crate) fn compile_format(arg: FormatArg, fmt: &VVal) -> FormatNode {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub(crate) fn compile_formatter(fmt: &VVal) -> (FormatNode, usize) { |
|
|
|
|
let mut fmts : Vec<FormatNode> = vec![]; |
|
|
|
|
let mut fmts: Vec<FormatNode> = vec![]; |
|
|
|
|
|
|
|
|
|
let mut max_argc = 0; |
|
|
|
|
for (item, _) in fmt.iter() { |
|
|
|
@ -823,44 +835,41 @@ pub(crate) fn compile_formatter(fmt: &VVal) -> (FormatNode, usize) {
|
|
|
|
|
fmts.push(Box::new(move |fs: &mut FormatState, _args: &[VVal]| { |
|
|
|
|
arg.with_s_ref(|s| fs.write_str(s)) |
|
|
|
|
})); |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
_ => { |
|
|
|
|
let arg = |
|
|
|
|
arg.at(0).unwrap().with_s_ref(|arg_syn| { |
|
|
|
|
match arg_syn { |
|
|
|
|
"index" => { |
|
|
|
|
if max_argc < arg.v_i(1) + 1 { |
|
|
|
|
max_argc = arg.v_i(1) + 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
FormatArg::Index(arg.v_i(1) as usize) |
|
|
|
|
}, |
|
|
|
|
_ => { |
|
|
|
|
if max_argc < 1 { |
|
|
|
|
max_argc = 1; |
|
|
|
|
|