diff options
| -rw-r--r-- | src/lexer.rs | 5 | ||||
| -rw-r--r-- | src/lib.rs | 80 | ||||
| -rw-r--r-- | src/parser.rs | 57 | ||||
| -rw-r--r-- | src/position.rs | 96 |
4 files changed, 173 insertions, 65 deletions
diff --git a/src/lexer.rs b/src/lexer.rs index 5ce7929..c7249b7 100644 --- a/src/lexer.rs +++ b/src/lexer.rs | |||
| @@ -24,7 +24,6 @@ pub enum SymbolType<'a> { | |||
| 24 | Literal(&'a str), | 24 | Literal(&'a str), |
| 25 | Text(&'a str), | 25 | Text(&'a str), |
| 26 | Error{ what: ErrorType }, | 26 | Error{ what: ErrorType }, |
| 27 | EOS, | ||
| 28 | } | 27 | } |
| 29 | 28 | ||
| 30 | #[derive(Copy,Clone)] | 29 | #[derive(Copy,Clone)] |
| @@ -36,7 +35,7 @@ pub struct Symbol<'a> { | |||
| 36 | 35 | ||
| 37 | impl<'a> fmt::Debug for Symbol<'a> { | 36 | impl<'a> fmt::Debug for Symbol<'a> { |
| 38 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 37 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 39 | write!(f, "{:?} @ {}:{}", self.symbol, self.start.line, self.start.column ) | 38 | write!(f, "{:?} @ {:?}-{:?}", self.symbol, self.start, self.end ) |
| 40 | } | 39 | } |
| 41 | } | 40 | } |
| 42 | 41 | ||
| @@ -64,6 +63,7 @@ impl<'a> Symbol<'a> { | |||
| 64 | } | 63 | } |
| 65 | } | 64 | } |
| 66 | 65 | ||
| 66 | #[derive(Debug)] | ||
| 67 | enum Mode { | 67 | enum Mode { |
| 68 | Text, | 68 | Text, |
| 69 | InTag, | 69 | InTag, |
| @@ -300,6 +300,7 @@ impl<'a> Lexer<'a> { | |||
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | fn parse_end_tag(&mut self) -> Option<Symbol<'a>> { | 302 | fn parse_end_tag(&mut self) -> Option<Symbol<'a>> { |
| 303 | self.skip_ws(); | ||
| 303 | let start_pos = self.pos.clone(); | 304 | let start_pos = self.pos.clone(); |
| 304 | if let Some(chr) = self.cur() && chr == '|' { | 305 | if let Some(chr) = self.cur() && chr == '|' { |
| 305 | match self.peek() { | 306 | match self.peek() { |
| @@ -5,22 +5,10 @@ use std::time::SystemTime; | |||
| 5 | 5 | ||
| 6 | mod lexer; | 6 | mod lexer; |
| 7 | mod parser; | 7 | mod parser; |
| 8 | mod position; | ||
| 8 | 9 | ||
| 9 | pub use parser::ParseError; | 10 | pub use parser::ParseError; |
| 10 | 11 | pub use position::*; | |
| 11 | #[derive(Debug,Copy,Clone)] | ||
| 12 | pub struct Position { | ||
| 13 | pub line: u32, | ||
| 14 | pub column: u32, | ||
| 15 | } | ||
| 16 | |||
| 17 | impl Position { | ||
| 18 | pub fn new( line: u32, column: u32 ) -> Self { | ||
| 19 | Self { | ||
| 20 | line, column, | ||
| 21 | } | ||
| 22 | } | ||
| 23 | } | ||
| 24 | 12 | ||
| 25 | #[derive(Debug)] | 13 | #[derive(Debug)] |
| 26 | pub struct Crimtag { | 14 | pub struct Crimtag { |
| @@ -29,7 +17,7 @@ pub struct Crimtag { | |||
| 29 | } | 17 | } |
| 30 | 18 | ||
| 31 | #[derive(PartialEq,Eq,Debug,Clone)] | 19 | #[derive(PartialEq,Eq,Debug,Clone)] |
| 32 | enum ViewSource { | 20 | pub enum ViewSource { |
| 33 | File { | 21 | File { |
| 34 | path: PathBuf, | 22 | path: PathBuf, |
| 35 | loaded: SystemTime, | 23 | loaded: SystemTime, |
| @@ -52,7 +40,7 @@ impl View { | |||
| 52 | fn process(&self, input: &Value) -> Result<Value, ParseError> { | 40 | fn process(&self, input: &Value) -> Result<Value, ParseError> { |
| 53 | let mut out_vars = HashMap::new(); | 41 | let mut out_vars = HashMap::new(); |
| 54 | for output in &self.outputs { | 42 | for output in &self.outputs { |
| 55 | if let Token::Output(_,_,tokens) = &output.ast_root { | 43 | if let Token::Output(_,/*_,*/tokens) = &output.ast_root { |
| 56 | let mut buf = String::new(); | 44 | let mut buf = String::new(); |
| 57 | exec( input, tokens, &mut buf )?; | 45 | exec( input, tokens, &mut buf )?; |
| 58 | out_vars.insert( output.name.clone(), Value::String(buf) ); | 46 | out_vars.insert( output.name.clone(), Value::String(buf) ); |
| @@ -74,17 +62,9 @@ type Properties = HashMap<String, String>; | |||
| 74 | enum Token { | 62 | enum Token { |
| 75 | Root(Vec<Token>), | 63 | Root(Vec<Token>), |
| 76 | View(String,Properties,Vec<Token>), | 64 | View(String,Properties,Vec<Token>), |
| 77 | Output(String,Properties,Vec<Token>), | 65 | Output(String,/*Properties,*/ Vec<Token>), |
| 78 | Show(String,Properties), | 66 | Show(String,Properties), |
| 79 | Text(String), | 67 | Text(String), |
| 80 | Literal(String), | ||
| 81 | /* | ||
| 82 | Tag{ | ||
| 83 | name: String, | ||
| 84 | params: Vec<String>, | ||
| 85 | props: Properties, | ||
| 86 | children: Vec<Token> | ||
| 87 | },*/ | ||
| 88 | } | 68 | } |
| 89 | 69 | ||
| 90 | #[derive(Debug)] | 70 | #[derive(Debug)] |
| @@ -203,6 +183,18 @@ impl Crimtag { | |||
| 203 | } | 183 | } |
| 204 | } | 184 | } |
| 205 | 185 | ||
| 186 | pub fn get_view_source(&self, view: &str) -> Option<ViewSource> { | ||
| 187 | if let Some(view) = self.views.get(view) { | ||
| 188 | if view.source < self.sources.len() { | ||
| 189 | Some(self.sources[view.source].clone()) | ||
| 190 | } else { | ||
| 191 | None | ||
| 192 | } | ||
| 193 | } else { | ||
| 194 | None | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 206 | pub fn view_partial(&self, view: &str, input: &Value ) -> Result<Value,ParseError> { | 198 | pub fn view_partial(&self, view: &str, input: &Value ) -> Result<Value,ParseError> { |
| 207 | if let Some(view) = self.views.get(view) { | 199 | if let Some(view) = self.views.get(view) { |
| 208 | return view.process( input ) | 200 | return view.process( input ) |
| @@ -213,12 +205,10 @@ impl Crimtag { | |||
| 213 | 205 | ||
| 214 | pub fn view(&self, view: &str, input: &Value ) -> Result<String,ParseError> { | 206 | pub fn view(&self, view: &str, input: &Value ) -> Result<String,ParseError> { |
| 215 | if let Some(view) = self.views.get( view ) { | 207 | if let Some(view) = self.views.get( view ) { |
| 216 | let mut output = view.process( input )?; | 208 | let output = view.process( input )?; |
| 217 | if let Some(l) = &view.layout { | 209 | if let Some(l) = &view.layout { |
| 218 | println!("Layout: {}", l ); | ||
| 219 | self.view( l, &output ) | 210 | self.view( l, &output ) |
| 220 | } else { | 211 | } else { |
| 221 | println!("No layout, at the top"); | ||
| 222 | if let Value::Dictionary(mut d) = output && | 212 | if let Value::Dictionary(mut d) = output && |
| 223 | let Some(content) = d.remove("content") && | 213 | let Some(content) = d.remove("content") && |
| 224 | let Value::String(s) = content { | 214 | let Value::String(s) = content { |
| @@ -242,18 +232,40 @@ fn exec(input: &Value, tokens: &Vec<Token>, buf: &mut String) -> Result<(),Parse | |||
| 242 | println!("Too high!?"); | 232 | println!("Too high!?"); |
| 243 | // Error? | 233 | // Error? |
| 244 | } | 234 | } |
| 245 | Token::Show(s,_) => { | 235 | Token::Show(s,p) => { |
| 236 | let format = if let Some(s) = p.get("format") { | ||
| 237 | s | ||
| 238 | } else { | ||
| 239 | &"".to_string() | ||
| 240 | }; | ||
| 246 | if let Value::Dictionary(d) = input && | 241 | if let Value::Dictionary(d) = input && |
| 247 | let Some(Value::String(s)) = d.get(s) { | 242 | let Some(value) = d.get(s) { |
| 248 | buf.push_str(s); | 243 | match value { |
| 244 | Value::Dictionary(_) => { | ||
| 245 | buf.push_str("<dictionary>"); | ||
| 246 | } | ||
| 247 | Value::List(_) => { | ||
| 248 | buf.push_str("<list>"); | ||
| 249 | } | ||
| 250 | Value::String(s) => { | ||
| 251 | buf.push_str(s); | ||
| 252 | } | ||
| 253 | Value::Int(i) => { | ||
| 254 | buf.push_str(&i.to_string()); | ||
| 255 | } | ||
| 256 | Value::Float(f) => { | ||
| 257 | if format == "" { | ||
| 258 | buf.push_str(&f.to_string()); | ||
| 259 | } else { | ||
| 260 | buf.push_str(&f.to_string()); | ||
| 261 | } | ||
| 262 | } | ||
| 263 | } | ||
| 249 | } | 264 | } |
| 250 | } | 265 | } |
| 251 | Token::Text(s) => { | 266 | Token::Text(s) => { |
| 252 | buf.push_str( s ); | 267 | buf.push_str( s ); |
| 253 | } | 268 | } |
| 254 | Token::Literal(..) => { | ||
| 255 | println!("Literal!?"); | ||
| 256 | } | ||
| 257 | } | 269 | } |
| 258 | } | 270 | } |
| 259 | Ok(()) | 271 | Ok(()) |
diff --git a/src/parser.rs b/src/parser.rs index 13e89aa..c7a8abe 100644 --- a/src/parser.rs +++ b/src/parser.rs | |||
| @@ -17,6 +17,13 @@ impl ParseError { | |||
| 17 | what: what.to_string(), | 17 | what: what.to_string(), |
| 18 | } | 18 | } |
| 19 | } | 19 | } |
| 20 | |||
| 21 | pub fn eos( context: &str ) -> Self { | ||
| 22 | ParseError { | ||
| 23 | position: Position::none(), | ||
| 24 | what: format!("Premature end of stream while looking for {}", context), | ||
| 25 | } | ||
| 26 | } | ||
| 20 | } | 27 | } |
| 21 | 28 | ||
| 22 | impl fmt::Display for ParseError { | 29 | impl fmt::Display for ParseError { |
| @@ -61,12 +68,9 @@ impl<'a> Context<'a> { | |||
| 61 | self.cur[(self.icur+1)%2] | 68 | self.cur[(self.icur+1)%2] |
| 62 | } | 69 | } |
| 63 | 70 | ||
| 64 | pub fn check_unwrapped<T: Fn( &SymbolType, &SymbolType ) -> bool>(&self, f: T) -> ParseResult<bool> { | 71 | pub fn check_unwrapped<T: Fn( &SymbolType, &SymbolType ) -> bool>(&self, context: &str, f: T) -> ParseResult<bool> { |
| 65 | if self.cur().is_none() || self.peek().is_none() { | 72 | if self.cur().is_none() || self.peek().is_none() { |
| 66 | Err(ParseError{ | 73 | Err(ParseError::eos( context )) |
| 67 | position: Position::new(0,0), | ||
| 68 | what: "Unexpected end of stream.".to_string() | ||
| 69 | }) | ||
| 70 | } else { | 74 | } else { |
| 71 | Ok(f( self.cur().unwrap().symbol(), self.peek().unwrap().symbol())) | 75 | Ok(f( self.cur().unwrap().symbol(), self.peek().unwrap().symbol())) |
| 72 | } | 76 | } |
| @@ -74,19 +78,16 @@ impl<'a> Context<'a> { | |||
| 74 | } | 78 | } |
| 75 | 79 | ||
| 76 | trait SymbolHelper { | 80 | trait SymbolHelper { |
| 77 | fn is<T: Fn( &SymbolType ) -> bool>(&self, f: T ) -> ParseResult<bool>; | 81 | fn is<T: Fn( &SymbolType ) -> bool>(&self, context: &str, f: T ) -> ParseResult<bool>; |
| 78 | fn is_valid_tag_name(&self) -> ParseResult<bool>; | 82 | fn is_valid_tag_name(&self) -> ParseResult<bool>; |
| 79 | } | 83 | } |
| 80 | 84 | ||
| 81 | impl<'a> SymbolHelper for Option<Symbol<'a>> { | 85 | impl<'a> SymbolHelper for Option<Symbol<'a>> { |
| 82 | fn is<T: Fn( &SymbolType ) -> bool>(&self, f: T ) -> ParseResult<bool> { | 86 | fn is<T: Fn( &SymbolType ) -> bool>(&self, context: &str, f: T ) -> ParseResult<bool> { |
| 83 | if let Some(st) = self { | 87 | if let Some(st) = self { |
| 84 | Ok(f( &st.symbol() )) | 88 | Ok(f( &st.symbol() )) |
| 85 | } else { | 89 | } else { |
| 86 | Err(ParseError{ | 90 | Err(ParseError::eos( context )) |
| 87 | position: Position::new(0,0), | ||
| 88 | what: "Unexpected end of stream.".to_string() | ||
| 89 | }) | ||
| 90 | } | 91 | } |
| 91 | } | 92 | } |
| 92 | 93 | ||
| @@ -256,10 +257,7 @@ impl Parser { | |||
| 256 | //println!("--parse-tag-view-- tag parsed, next token: {:?}", ctx.cur() ); | 257 | //println!("--parse-tag-view-- tag parsed, next token: {:?}", ctx.cur() ); |
| 257 | loop { | 258 | loop { |
| 258 | if ctx.cur().is_none() { | 259 | if ctx.cur().is_none() { |
| 259 | return Err(ParseError{ | 260 | return Err(ParseError::eos(format!("close tag for {:?}", tb.name()).as_str())) |
| 260 | position: Position::new(0,0), | ||
| 261 | what: "Unexpected end of stream.".to_string() | ||
| 262 | }); | ||
| 263 | } | 261 | } |
| 264 | match ctx.cur().unwrap().symbol() { | 262 | match ctx.cur().unwrap().symbol() { |
| 265 | SymbolType::Text(s) => { | 263 | SymbolType::Text(s) => { |
| @@ -282,7 +280,7 @@ impl Parser { | |||
| 282 | // Everything is either text or output | 280 | // Everything is either text or output |
| 283 | if !any_outputs { | 281 | if !any_outputs { |
| 284 | // Special case, if it's only text then we create an implicit output. | 282 | // Special case, if it's only text then we create an implicit output. |
| 285 | tb.add_child(Token::Output("content".to_string(), Properties::new(), children )); | 283 | tb.add_child(Token::Output("content".to_string(), /*Properties::new(),*/ children )); |
| 286 | } | 284 | } |
| 287 | else { | 285 | else { |
| 288 | // Standard case, outputs are included, text is | 286 | // Standard case, outputs are included, text is |
| @@ -303,7 +301,7 @@ impl Parser { | |||
| 303 | }); | 301 | }); |
| 304 | } else { | 302 | } else { |
| 305 | // No outputs at all, we create an implict output | 303 | // No outputs at all, we create an implict output |
| 306 | tb.add_child(Token::Output("content".to_string(), Properties::new(), children )); | 304 | tb.add_child(Token::Output("content".to_string(), /*Properties::new(), */children )); |
| 307 | } | 305 | } |
| 308 | } | 306 | } |
| 309 | 307 | ||
| @@ -339,11 +337,11 @@ impl Parser { | |||
| 339 | tb.set_name( name_sym ); | 337 | tb.set_name( name_sym ); |
| 340 | } | 338 | } |
| 341 | _ => { | 339 | _ => { |
| 342 | return Err(ParseError{position: ctx.cur().unwrap().start().clone(), what: "Unexpecetd symbol".to_string()}); | 340 | return Err(ParseError{position: ctx.cur().unwrap().start().clone(), what: "Unexpected symbol".to_string()}); |
| 343 | } | 341 | } |
| 344 | } | 342 | } |
| 345 | } else { | 343 | } else { |
| 346 | return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}); | 344 | return Err(ParseError::eos("tag type")); |
| 347 | } | 345 | } |
| 348 | 346 | ||
| 349 | self.parse_tag_params( ctx, &mut tb )?; | 347 | self.parse_tag_params( ctx, &mut tb )?; |
| @@ -358,7 +356,10 @@ impl Parser { | |||
| 358 | tb.set_type( TagType::Unary ); | 356 | tb.set_type( TagType::Unary ); |
| 359 | } | 357 | } |
| 360 | _ => { | 358 | _ => { |
| 361 | return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}); | 359 | return Err(ParseError::new( |
| 360 | end_sym.start().clone(), | ||
| 361 | format!("Unexpected symbol {:?} looking for end of tag.", end_sym.symbol()).as_str() | ||
| 362 | )); | ||
| 362 | } | 363 | } |
| 363 | } | 364 | } |
| 364 | } | 365 | } |
| @@ -369,7 +370,7 @@ impl Parser { | |||
| 369 | } | 370 | } |
| 370 | 371 | ||
| 371 | fn parse_end_tag<'a>(&self, ctx: &mut Context<'a> ) -> ParseResult<Symbol<'a>> { | 372 | fn parse_end_tag<'a>(&self, ctx: &mut Context<'a> ) -> ParseResult<Symbol<'a>> { |
| 372 | if !ctx.cur().is(|s| *s == SymbolType::StartPoint )? { | 373 | if !ctx.cur().is("end tag",|s| *s == SymbolType::StartPoint )? { |
| 373 | return Err(ParseError{ | 374 | return Err(ParseError{ |
| 374 | position: *ctx.cur().unwrap().start(), | 375 | position: *ctx.cur().unwrap().start(), |
| 375 | what: "Invalid end tag?".to_string(), | 376 | what: "Invalid end tag?".to_string(), |
| @@ -382,7 +383,7 @@ impl Parser { | |||
| 382 | }); | 383 | }); |
| 383 | } | 384 | } |
| 384 | let name = ctx.cur().unwrap(); | 385 | let name = ctx.cur().unwrap(); |
| 385 | if !ctx.next().is(|s| *s == SymbolType::EndFlat )? { | 386 | if !ctx.next().is("end of end tag", |s| *s == SymbolType::EndFlat )? { |
| 386 | return Err(ParseError{ | 387 | return Err(ParseError{ |
| 387 | position: *ctx.cur().unwrap().start(), | 388 | position: *ctx.cur().unwrap().start(), |
| 388 | what: "Tag should be <| |] style end tag.".to_string(), | 389 | what: "Tag should be <| |] style end tag.".to_string(), |
| @@ -399,7 +400,7 @@ impl Parser { | |||
| 399 | 400 | ||
| 400 | loop { | 401 | loop { |
| 401 | if ctx.cur().is_none() { | 402 | if ctx.cur().is_none() { |
| 402 | return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}); | 403 | return Err(ParseError::eos(format!("close tag for {:?}", tb.name()).as_str())); |
| 403 | } | 404 | } |
| 404 | match ctx.cur().unwrap().symbol() { | 405 | match ctx.cur().unwrap().symbol() { |
| 405 | SymbolType::Text(s) => { | 406 | SymbolType::Text(s) => { |
| @@ -435,8 +436,7 @@ impl Parser { | |||
| 435 | fn parse_tag_params(&self, ctx: &mut Context, tb: &mut TagBuilder ) -> ParseResult<()> { | 436 | fn parse_tag_params(&self, ctx: &mut Context, tb: &mut TagBuilder ) -> ParseResult<()> { |
| 436 | loop { | 437 | loop { |
| 437 | if ctx.cur().is_none() { | 438 | if ctx.cur().is_none() { |
| 438 | 439 | return Err(ParseError::eos("tag parameters")); | |
| 439 | return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}); | ||
| 440 | } | 440 | } |
| 441 | match ctx.cur().unwrap().symbol() { | 441 | match ctx.cur().unwrap().symbol() { |
| 442 | SymbolType::Literal(s) => { | 442 | SymbolType::Literal(s) => { |
| @@ -454,7 +454,7 @@ impl Parser { | |||
| 454 | fn parse_tag_props(&self, ctx: &mut Context, tb: &mut TagBuilder ) -> ParseResult<()> { | 454 | fn parse_tag_props(&self, ctx: &mut Context, tb: &mut TagBuilder ) -> ParseResult<()> { |
| 455 | loop { | 455 | loop { |
| 456 | if ctx.cur().is_none() { | 456 | if ctx.cur().is_none() { |
| 457 | return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}); | 457 | return Err(ParseError::eos("tag properties")); |
| 458 | } | 458 | } |
| 459 | if let SymbolType::Token(s) = ctx.cur().unwrap().symbol() { | 459 | if let SymbolType::Token(s) = ctx.cur().unwrap().symbol() { |
| 460 | if ctx.peek().is_some_and(|s|s.check_type(|t| matches!(t,SymbolType::Equals))) { | 460 | if ctx.peek().is_some_and(|s|s.check_type(|t| matches!(t,SymbolType::Equals))) { |
| @@ -466,7 +466,7 @@ impl Parser { | |||
| 466 | return Err(ParseError{position: Position::new(0,0), what: "Expected quoted literal string".to_string()}); | 466 | return Err(ParseError{position: Position::new(0,0), what: "Expected quoted literal string".to_string()}); |
| 467 | } | 467 | } |
| 468 | } else { | 468 | } else { |
| 469 | return Err(ParseError{position:Position::new(0,0), what: "Expected = ".to_string()}); | 469 | break; |
| 470 | } | 470 | } |
| 471 | } else { | 471 | } else { |
| 472 | break; | 472 | break; |
| @@ -482,7 +482,6 @@ enum TagType { | |||
| 482 | Unknown, | 482 | Unknown, |
| 483 | Unary, | 483 | Unary, |
| 484 | BinaryOpen, | 484 | BinaryOpen, |
| 485 | BinaryClose, | ||
| 486 | } | 485 | } |
| 487 | 486 | ||
| 488 | struct TagBuilder<'a> { | 487 | struct TagBuilder<'a> { |
| @@ -573,7 +572,7 @@ impl<'a> TagBuilder<'a> { | |||
| 573 | Ok(Token::View(self.params.swap_remove(0), self.props, self.children)) | 572 | Ok(Token::View(self.params.swap_remove(0), self.props, self.children)) |
| 574 | } | 573 | } |
| 575 | SymbolType::Output => { | 574 | SymbolType::Output => { |
| 576 | Ok(Token::Output(self.params.swap_remove(0), self.props, self.children)) | 575 | Ok(Token::Output(self.params.swap_remove(0), /*self.props,*/ self.children)) |
| 577 | } | 576 | } |
| 578 | SymbolType::Show => { | 577 | SymbolType::Show => { |
| 579 | Ok(Token::Show(self.params.swap_remove(0), self.props)) | 578 | Ok(Token::Show(self.params.swap_remove(0), self.props)) |
diff --git a/src/position.rs b/src/position.rs new file mode 100644 index 0000000..24f5309 --- /dev/null +++ b/src/position.rs | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | use std::fmt; | ||
| 2 | use std::cmp::Ordering; | ||
| 3 | |||
| 4 | #[derive(Copy,Clone)] | ||
| 5 | pub struct Position { | ||
| 6 | pub line: u32, | ||
| 7 | pub column: u32, | ||
| 8 | } | ||
| 9 | |||
| 10 | impl Position { | ||
| 11 | pub fn new( line: u32, column: u32 ) -> Self { | ||
| 12 | Self { | ||
| 13 | line, column, | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | pub fn none() -> Self { | ||
| 18 | Self { | ||
| 19 | line: 0, | ||
| 20 | column: 0, | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | pub fn is_none(&self) -> bool { | ||
| 25 | self.line == 0 || self.column == 0 | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | impl fmt::Debug for Position { | ||
| 30 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| 31 | if self.is_none() { | ||
| 32 | write!(f, "none") | ||
| 33 | } else { | ||
| 34 | write!(f, "{}:{}", self.line, self.column ) | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | impl PartialOrd for Position { | ||
| 40 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
| 41 | let ord = self.line.partial_cmp( &other.line ); | ||
| 42 | if Some(Ordering::Equal) == ord { | ||
| 43 | self.column.partial_cmp( &other.column ) | ||
| 44 | } else { | ||
| 45 | ord | ||
| 46 | } | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | impl Ord for Position { | ||
| 51 | fn cmp(&self, other: &Self) -> Ordering { | ||
| 52 | let ord = self.line.cmp( &other.line ); | ||
| 53 | if Ordering::Equal == ord { | ||
| 54 | self.column.cmp( &other.column ) | ||
| 55 | } else { | ||
| 56 | ord | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | impl PartialEq for Position { | ||
| 62 | fn eq(&self, other: &Self) -> bool { | ||
| 63 | self.line == other.line && self.column == other.column | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | impl Eq for Position {} | ||
| 68 | |||
| 69 | #[derive(Copy,Clone)] | ||
| 70 | pub struct Range { | ||
| 71 | start: Position, | ||
| 72 | end: Position, | ||
| 73 | } | ||
| 74 | |||
| 75 | impl Range { | ||
| 76 | pub fn new( start: Position, end: Position ) -> Self { | ||
| 77 | Self { | ||
| 78 | start, end, | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | pub fn include(&mut self, pos: &Position ) { | ||
| 83 | if *pos < self.start { | ||
| 84 | self.start = pos.clone(); | ||
| 85 | } | ||
| 86 | if *pos > self.end { | ||
| 87 | self.end = pos.clone(); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | impl fmt::Debug for Range { | ||
| 93 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| 94 | write!(f, "{:?}-{:?}", self.start, self.end ) | ||
| 95 | } | ||
| 96 | } | ||
