| 1039 | } |
| 1040 | |
| 1041 | fn add_debug_string_arg(xpath: &str) -> Result<String> { |
| 1042 | // lazy_static! { |
| 1043 | // static ref OPEN_OR_CLOSE_PAREN: Regex = Regex::new("^['\"][()]").unwrap(); // match paren that doesn't follow a quote |
| 1044 | // } |
| 1045 | // Find all the DEBUG(...) commands in 'xpath' and adds a string argument. |
| 1046 | // The DEBUG function that is used internally takes two arguments, the second one being a string version of the DEBUG arg. |
| 1047 | // Being a string, any quotes need to be escaped, and DEBUGs inside of DEBUGs need more escaping. |
| 1048 | // This is done via recursive calls to this function. |
| 1049 | // FIX: this doesn't handle parens in strings correctly -- it only catches the common case of quoted parens |
| 1050 | // FIX: to do this right, one has to be careful about escape chars, so it gets ugly for nesting |
| 1051 | let debug_start = xpath.find("DEBUG("); |
| 1052 | if debug_start.is_none() { |
| 1053 | return Ok( xpath.to_string() ); |
| 1054 | } |
| 1055 | let debug_start = debug_start.unwrap(); |
| 1056 | let string_start = xpath[..debug_start+6].to_string(); // includes "DEBUG(" |
| 1057 | let mut count = 1; // open/close count -- starting after "(" in "DEBUG(" |
| 1058 | let mut remainder: &str = &xpath[debug_start+6..]; |
| 1059 | |
| 1060 | loop { |
| 1061 | // debug!(" add_debug_string_arg: count={}, remainder='{}'", count, remainder); |
| 1062 | let next = remainder.find(|c| c=='(' || c==')'); |
| 1063 | match next { |
| 1064 | None => bail!("Did not find closing paren for DEBUG in\n{}", xpath), |
| 1065 | Some(i_paren) => { |
| 1066 | let remainder_as_bytes = remainder.as_bytes(); |
| 1067 | |
| 1068 | // if the paren is inside of quote (' or "), don't count it |
| 1069 | // FIX: this could be on a non-char boundary |
| 1070 | if i_paren == 0 || remainder_as_bytes[i_paren-1] != b'\'' || |
| 1071 | i_paren+1 >= remainder.len() || remainder_as_bytes[i_paren+1] != b'\'' { |
| 1072 | // debug!(" found '{}'", remainder_as_bytes[i_paren].to_string()); |
| 1073 | if remainder_as_bytes[i_paren] == b'(' { |
| 1074 | count += 1; |
| 1075 | } else { // must be ')' |
| 1076 | count -= 1; |
| 1077 | if count == 0 { |
| 1078 | let i_end = xpath.len() - remainder.len() + i_paren; |
| 1079 | let escaped_arg = &xpath[debug_start+6..i_end].to_string().replace('"', "\\\""); |
| 1080 | let contents = MyXPath::add_debug_string_arg(&xpath[debug_start+6..i_end])?; |
| 1081 | return Ok( string_start + &contents + ", \"" + escaped_arg + "\" " |
| 1082 | + &MyXPath::add_debug_string_arg(&xpath[i_end..])? ); |
| 1083 | } |
| 1084 | } |
| 1085 | } |
| 1086 | remainder = &remainder[i_paren+1..]; |
| 1087 | } |
| 1088 | } |
| 1089 | } |
| 1090 | } |
| 1091 | |
| 1092 | fn is_true(&self, context: &Context, mathml: Element) -> Result<bool> { |
| 1093 | // return true if there is no condition or if the condition evaluates to true |