diff options
Diffstat (limited to 'src/parser.rs')
| -rw-r--r-- | src/parser.rs | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..54b77ac --- /dev/null +++ b/src/parser.rs | |||
| @@ -0,0 +1,280 @@ | |||
| 1 | use crate::lexer::*; | ||
| 2 | use crate::*; | ||
| 3 | |||
| 4 | use core::error::Error; | ||
| 5 | use std::fmt; | ||
| 6 | |||
| 7 | #[derive(Debug)] | ||
| 8 | struct ParseError { | ||
| 9 | line: u32, | ||
| 10 | row: u32, | ||
| 11 | what: String, | ||
| 12 | } | ||
| 13 | |||
| 14 | impl fmt::Display for ParseError { | ||
| 15 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| 16 | write!(f, "Error parsing input: {}", "yeah") | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | impl Error for ParseError { } | ||
| 21 | |||
| 22 | struct Context<'a> { | ||
| 23 | cur: [Option<Symbol<'a>>;2], | ||
| 24 | icur: usize, | ||
| 25 | ll: Lexer<'a>, | ||
| 26 | } | ||
| 27 | |||
| 28 | impl<'a> Context<'a> { | ||
| 29 | pub fn new( mut ll: Lexer<'a> ) -> Self { | ||
| 30 | let cur = [ll.next(), ll.next()]; | ||
| 31 | Self { | ||
| 32 | cur, | ||
| 33 | icur: 0, | ||
| 34 | ll | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | pub fn next(&mut self) -> Option<Symbol<'a>> { | ||
| 39 | self.cur[self.icur] = self.ll.next(); | ||
| 40 | self.icur = (self.icur+1)%2; | ||
| 41 | println!(" - cur: {:?}, peek: {:?}", self.cur(), self.peek() ); | ||
| 42 | self.cur[self.icur] | ||
| 43 | } | ||
| 44 | |||
| 45 | pub fn cur(&self) -> Option<Symbol<'a>> { | ||
| 46 | self.cur[self.icur] | ||
| 47 | } | ||
| 48 | |||
| 49 | pub fn peek(&self) -> Option<Symbol<'a>> { | ||
| 50 | self.cur[(self.icur+1)%2] | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | pub struct Parser { | ||
| 55 | } | ||
| 56 | |||
| 57 | /** | ||
| 58 | * input: input tag | ||
| 59 | * | input tag_pair | ||
| 60 | * | input text | ||
| 61 | * | | ||
| 62 | * ; | ||
| 63 | * | ||
| 64 | * tag: '[|' tag_guts '|]' | ||
| 65 | * ; | ||
| 66 | * | ||
| 67 | * tag_pair: open_tag tag_body close_tag | ||
| 68 | * ; | ||
| 69 | * | ||
| 70 | * tag_body: tag_body tag | ||
| 71 | * | tag_body tag_pair | ||
| 72 | * | tag_body text | ||
| 73 | * | | ||
| 74 | * ; | ||
| 75 | * | ||
| 76 | * open_tag: '[|' tag_guts '|>' | ||
| 77 | * ; | ||
| 78 | * | ||
| 79 | * close_tag: '<|' token '|]' | ||
| 80 | * ; | ||
| 81 | * | ||
| 82 | * tag_guts: 'fragment' literal props | ||
| 83 | * | 'section' literal | ||
| 84 | * | 'output' literal | ||
| 85 | * ; | ||
| 86 | * | ||
| 87 | * literal: '"' [^"]* '"' | ||
| 88 | * ; | ||
| 89 | * | ||
| 90 | * props: props token '=' literal | ||
| 91 | * | | ||
| 92 | * ; | ||
| 93 | * | ||
| 94 | * disambiguate (tm): | ||
| 95 | * | ||
| 96 | * input: input tag | ||
| 97 | * | input text | ||
| 98 | * | | ||
| 99 | * ; | ||
| 100 | * | ||
| 101 | * tag: open_tag_base unary_tag | ||
| 102 | * | open_tag_base binary_tag | ||
| 103 | * ; | ||
| 104 | * | ||
| 105 | * open_tag_base: '[|' tag_guts | ||
| 106 | * ; | ||
| 107 | * | ||
| 108 | * unary_tag: '|]' | ||
| 109 | * ; | ||
| 110 | * | ||
| 111 | * binary_tag: '|>' tag_body close_tag | ||
| 112 | * ; | ||
| 113 | * | ||
| 114 | * tag_body: tag_body tag | ||
| 115 | * | tag_body text | ||
| 116 | * | | ||
| 117 | * ; | ||
| 118 | * | ||
| 119 | * close_tag: '<|' token '|]' | ||
| 120 | * ; | ||
| 121 | * | ||
| 122 | * tag_guts: 'fragment' literal props | ||
| 123 | * | 'section' literal | ||
| 124 | * | 'output' literal | ||
| 125 | * ; | ||
| 126 | * | ||
| 127 | * literal: '"' [^"]* '"' | ||
| 128 | * ; | ||
| 129 | * | ||
| 130 | * props: props token '=' literal | ||
| 131 | * | | ||
| 132 | * ; | ||
| 133 | */ | ||
| 134 | impl Parser { | ||
| 135 | pub fn new() -> Self { | ||
| 136 | Self { | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | fn lex_error(&self, error: &Symbol) -> Result<(),Box<dyn Error>> { | ||
| 141 | if let Symbol::Error{line,row,what} = error { | ||
| 142 | Err(Box::new(ParseError { | ||
| 143 | line: *line, | ||
| 144 | row: *row, | ||
| 145 | what: format!("What: {:?}", *what) | ||
| 146 | })) | ||
| 147 | } else { | ||
| 148 | Err(Box::new(ParseError { | ||
| 149 | line: 0, row: 0, what: "Not an error?".to_string() | ||
| 150 | })) | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | pub fn parse(&mut self, crim: &mut Crimtag, src: &str ) -> Result<(),Box<dyn Error>> { | ||
| 155 | let mut ll = Lexer::new( src ); | ||
| 156 | let mut ctx = Context::new( ll ); | ||
| 157 | |||
| 158 | // Parse the root of the file, the input context | ||
| 159 | self.p_input( &mut ctx )?; | ||
| 160 | |||
| 161 | Ok(()) | ||
| 162 | } | ||
| 163 | |||
| 164 | fn p_input(&mut self, ctx: &mut Context ) -> Result<(), Box<dyn Error>> { | ||
| 165 | loop { | ||
| 166 | if ctx.cur().is_none() { | ||
| 167 | break; | ||
| 168 | } | ||
| 169 | match ctx.cur() { | ||
| 170 | Some(Symbol::Text(_)) => { /* Skip top level text */ } | ||
| 171 | Some(Symbol::StartFlat) => { | ||
| 172 | self.parse_tag( ctx ); | ||
| 173 | } | ||
| 174 | Some(Symbol::Error{..}) => { | ||
| 175 | return self.lex_error( &ctx.cur().unwrap() ); | ||
| 176 | } | ||
| 177 | _ => { | ||
| 178 | |||
| 179 | } | ||
| 180 | } | ||
| 181 | ctx.next(); | ||
| 182 | } | ||
| 183 | Ok(()) | ||
| 184 | } | ||
| 185 | |||
| 186 | fn parse_tag(&mut self, ctx: &mut Context) -> Result<(), Box<dyn Error>> { | ||
| 187 | let mut tb = TagBuilder::new(); | ||
| 188 | |||
| 189 | let start_sym = ctx.cur().unwrap(); | ||
| 190 | |||
| 191 | if let Some(Symbol::Token(s)) = ctx.next() { | ||
| 192 | tb.set_name( s.to_string() ); | ||
| 193 | } else { | ||
| 194 | return Err(Box::new(ParseError{line: 0, row: 0, what: "Unexpecetd symbol".to_string()})); | ||
| 195 | } | ||
| 196 | |||
| 197 | self.parse_tag_params( ctx, &mut tb )?; | ||
| 198 | self.parse_tag_props( ctx, &mut tb )?; | ||
| 199 | |||
| 200 | Ok(()) | ||
| 201 | } | ||
| 202 | |||
| 203 | fn parse_tag_params(&mut self, ctx: &mut Context, tb: &mut TagBuilder ) -> Result<(), Box<dyn Error>> { | ||
| 204 | loop { | ||
| 205 | if let Some(Symbol::Token(s)) = ctx.cur() { | ||
| 206 | if matches!(ctx.peek(), Some(Symbol::Equals)) { | ||
| 207 | // Done with parameters | ||
| 208 | break; | ||
| 209 | } | ||
| 210 | else { | ||
| 211 | tb.add_param( s.to_string() ); | ||
| 212 | } | ||
| 213 | } | ||
| 214 | ctx.next(); | ||
| 215 | } | ||
| 216 | Ok(()) | ||
| 217 | } | ||
| 218 | |||
| 219 | fn parse_tag_props(&mut self, ctx: &mut Context, tb: &mut TagBuilder ) -> Result<(), Box<dyn Error>> { | ||
| 220 | loop { | ||
| 221 | if let Some(Symbol::Token(s)) = ctx.cur() { | ||
| 222 | if matches!(ctx.peek(), Some(Symbol::Equals)) { | ||
| 223 | ctx.next(); | ||
| 224 | if let Some(Symbol::Literal(lv)) = ctx.next() { | ||
| 225 | tb.add_prop( s.to_string(), lv.to_string() ); | ||
| 226 | } else { | ||
| 227 | return Err(Box::new(ParseError{line: 0, row: 0, what: "Expected quoted literal string".to_string()})); | ||
| 228 | } | ||
| 229 | } else { | ||
| 230 | return Err(Box::new(ParseError{line: 0, row: 0, what: "Expected = ".to_string()})); | ||
| 231 | } | ||
| 232 | } else { | ||
| 233 | break; | ||
| 234 | } | ||
| 235 | ctx.next(); | ||
| 236 | } | ||
| 237 | Ok(()) | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | enum TagType { | ||
| 242 | Unknown, | ||
| 243 | Unary, | ||
| 244 | BinaryOpen, | ||
| 245 | BinaryClose, | ||
| 246 | } | ||
| 247 | |||
| 248 | struct TagBuilder { | ||
| 249 | name: String, | ||
| 250 | params: Vec<String>, | ||
| 251 | props: Vec<(String,String)>, | ||
| 252 | tag_type: TagType, | ||
| 253 | } | ||
| 254 | |||
| 255 | impl TagBuilder { | ||
| 256 | pub fn new() -> TagBuilder { | ||
| 257 | TagBuilder { | ||
| 258 | name: String::new(), | ||
| 259 | params: Vec::new(), | ||
| 260 | props: Vec::new(), | ||
| 261 | tag_type: TagType::Unknown, | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | pub fn set_name(&mut self, name: String) { | ||
| 266 | self.name = name; | ||
| 267 | } | ||
| 268 | |||
| 269 | pub fn add_param(&mut self, param: String) { | ||
| 270 | self.params.push( param ); | ||
| 271 | } | ||
| 272 | |||
| 273 | pub fn add_prop(&mut self, key: String, value: String) { | ||
| 274 | self.props.push( (key, value) ); | ||
| 275 | } | ||
| 276 | |||
| 277 | pub fn set_type(&mut self, tag_type: TagType) { | ||
| 278 | self.tag_type = tag_type; | ||
| 279 | } | ||
| 280 | } | ||
