summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <mike@xagasoft.com>2026-06-07 16:37:28 -0700
committerMike Buland <mike@xagasoft.com>2026-06-07 16:37:28 -0700
commit83ab8c67beecfc05684c9400e29f7d77225d3af9 (patch)
tree2ec5042814bfb8a485797672cfef66fea04fd85f
parent3dd9ca69340512e42867b43db689e494bada2000 (diff)
downloadcrimtag-83ab8c67beecfc05684c9400e29f7d77225d3af9.tar.gz
crimtag-83ab8c67beecfc05684c9400e29f7d77225d3af9.tar.bz2
crimtag-83ab8c67beecfc05684c9400e29f7d77225d3af9.tar.xz
crimtag-83ab8c67beecfc05684c9400e29f7d77225d3af9.zip
Cleaned up a lot of parsing code.
-rw-r--r--src/lexer.rs13
-rw-r--r--src/lib.rs24
-rw-r--r--src/parser.rs142
3 files changed, 137 insertions, 42 deletions
diff --git a/src/lexer.rs b/src/lexer.rs
index 04be350..902bb64 100644
--- a/src/lexer.rs
+++ b/src/lexer.rs
@@ -1,15 +1,16 @@
1use std::iter::Iterator; 1use std::iter::Iterator;
2//use core::error::Error; 2//use core::error::Error;
3use std::str::CharIndices; 3use std::str::CharIndices;
4use std::fmt;
4 5
5use crate::Position; 6use crate::Position;
6 7
7#[derive(Debug,Copy,Clone)] 8#[derive(Debug,Copy,Clone,PartialEq)]
8pub enum ErrorType { 9pub enum ErrorType {
9 UnexpectedChar(char), 10 UnexpectedChar(char),
10} 11}
11 12
12#[derive(Debug,Copy,Clone)] 13#[derive(Debug,Copy,Clone,PartialEq)]
13pub enum SymbolType<'a> { 14pub enum SymbolType<'a> {
14 StartFlat, 15 StartFlat,
15 StartPoint, 16 StartPoint,
@@ -26,13 +27,19 @@ pub enum SymbolType<'a> {
26 EOS, 27 EOS,
27} 28}
28 29
29#[derive(Debug,Copy,Clone)] 30#[derive(Copy,Clone)]
30pub struct Symbol<'a> { 31pub struct Symbol<'a> {
31 symbol: SymbolType<'a>, 32 symbol: SymbolType<'a>,
32 start: Position, 33 start: Position,
33 end: Position, 34 end: Position,
34} 35}
35 36
37impl<'a> fmt::Debug for Symbol<'a> {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 write!(f, "{:?} @ {}:{}", self.symbol, self.start.line, self.start.column )
40 }
41}
42
36impl<'a> Symbol<'a> { 43impl<'a> Symbol<'a> {
37 pub fn new( symbol: SymbolType<'a>, start: Position, end: Position ) -> Self { 44 pub fn new( symbol: SymbolType<'a>, start: Position, end: Position ) -> Self {
38 Self { 45 Self {
diff --git a/src/lib.rs b/src/lib.rs
index 7d0e7f2..5e912cf 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,8 +2,6 @@ use std::path::{PathBuf,Path};
2use std::collections::HashMap; 2use std::collections::HashMap;
3use core::error::Error; 3use core::error::Error;
4use std::time::SystemTime; 4use std::time::SystemTime;
5use std::fs::File;
6use std::io::Read;
7 5
8mod lexer; 6mod lexer;
9mod parser; 7mod parser;
@@ -57,6 +55,14 @@ enum Token {
57 Fragment(String,Properties,Vec<Token>), 55 Fragment(String,Properties,Vec<Token>),
58 Section(String,Properties,Vec<Token>), 56 Section(String,Properties,Vec<Token>),
59 Text(String), 57 Text(String),
58 Literal(String),
59 /*
60 Tag{
61 name: String,
62 params: Vec<String>,
63 props: Properties,
64 children: Vec<Token>
65 },*/
60} 66}
61 67
62struct State { 68struct State {
@@ -97,14 +103,14 @@ impl Crimtag {
97 }; 103 };
98 104
99 let mut p = parser::Parser::new(); 105 let mut p = parser::Parser::new();
100 p.parse( self, &String::from_utf8( std::fs::read( path )? )? ); 106 p.parse( &String::from_utf8( std::fs::read( path )? )? );
101 107
102 Ok(()) 108 Ok(())
103 } 109 }
104 110
105 pub fn load_static(&mut self, data: &str) -> Result<(),Box::<dyn Error>> { 111 pub fn load_static(&mut self, data: &str) -> Result<(),Box::<dyn Error>> {
106 let mut p = parser::Parser::new(); 112 let mut p = parser::Parser::new();
107 p.parse( self, &data ); 113 p.parse( &data );
108 114
109 Ok(()) 115 Ok(())
110 } 116 }
@@ -137,8 +143,12 @@ mod tests {
137 #[test] 143 #[test]
138 fn parsing() { 144 fn parsing() {
139 let mut ct = Crimtag::new(); 145 let mut ct = Crimtag::new();
140 ct.load_static(r#"Here is a sample 146 if let Err(e) = ct.load_static(r#"Here is a sample
141[|frament "index" theme="standard"|><html><body>Hi</body></html><|fragment|] 147[|fragment "index" theme="standard"|><html><body>Hi</body></html><|fragment|]
142That was fun!"#); 148That was fun!"#) {
149 println!("Error: {:?}", e );
150 } else {
151 println!("It finished");
152 }
143 } 153 }
144} 154}
diff --git a/src/parser.rs b/src/parser.rs
index e5ea1f5..2d845cd 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -27,6 +27,7 @@ struct Context<'a> {
27impl<'a> Context<'a> { 27impl<'a> Context<'a> {
28 pub fn new( mut ll: Lexer<'a> ) -> Self { 28 pub fn new( mut ll: Lexer<'a> ) -> Self {
29 let cur = [ll.next(), ll.next()]; 29 let cur = [ll.next(), ll.next()];
30 //println!(" - cur: {:?}, peek: {:?}", cur[0], cur[1] );
30 Self { 31 Self {
31 cur, 32 cur,
32 icur: 0, 33 icur: 0,
@@ -37,7 +38,7 @@ impl<'a> Context<'a> {
37 pub fn next(&mut self) -> Option<Symbol<'a>> { 38 pub fn next(&mut self) -> Option<Symbol<'a>> {
38 self.cur[self.icur] = self.ll.next(); 39 self.cur[self.icur] = self.ll.next();
39 self.icur = (self.icur+1)%2; 40 self.icur = (self.icur+1)%2;
40 println!(" - cur: {:?}, peek: {:?}", self.cur(), self.peek() ); 41 //println!(" - cur: {:?}, peek: {:?}", self.cur(), self.peek() );
41 self.cur[self.icur] 42 self.cur[self.icur]
42 } 43 }
43 44
@@ -136,7 +137,7 @@ impl Parser {
136 } 137 }
137 } 138 }
138 139
139 fn lex_error(&self, error: &Symbol) -> Result<(),Box<dyn Error>> { 140 fn lex_error(&self, error: &Symbol) -> Result<Token,Box<dyn Error>> {
140 if let SymbolType::Error{what} = error.symbol() { 141 if let SymbolType::Error{what} = error.symbol() {
141 Err(Box::new(ParseError { 142 Err(Box::new(ParseError {
142 position: error.start().clone(), 143 position: error.start().clone(),
@@ -150,17 +151,16 @@ impl Parser {
150 } 151 }
151 } 152 }
152 153
153 pub fn parse(&mut self, crim: &mut Crimtag, src: &str ) -> Result<(),Box<dyn Error>> { 154 pub fn parse(&mut self, src: &str ) -> Result<Token,Box<dyn Error>> {
154 let mut ll = Lexer::new( src ); 155 let mut ll = Lexer::new( src );
155 let mut ctx = Context::new( ll ); 156 let mut ctx = Context::new( ll );
156 157
157 // Parse the root of the file, the input context 158 // Parse the root of the file, the input context
158 self.p_input( &mut ctx )?; 159 self.p_input( &mut ctx )
159
160 Ok(())
161 } 160 }
162 161
163 fn p_input(&mut self, ctx: &mut Context ) -> Result<(), Box<dyn Error>> { 162 fn p_input(&mut self, ctx: &mut Context ) -> Result<Token, Box<dyn Error>> {
163 let mut children = Vec::new();
164 loop { 164 loop {
165 if ctx.cur().is_none() { 165 if ctx.cur().is_none() {
166 break; 166 break;
@@ -168,7 +168,7 @@ impl Parser {
168 match ctx.cur().unwrap().symbol() { 168 match ctx.cur().unwrap().symbol() {
169 SymbolType::Text(_) => { /* Skip top level text */ } 169 SymbolType::Text(_) => { /* Skip top level text */ }
170 SymbolType::StartFlat => { 170 SymbolType::StartFlat => {
171 self.parse_tag( ctx ); 171 children.push( self.parse_tag( ctx )? );
172 } 172 }
173 SymbolType::Error{..} => { 173 SymbolType::Error{..} => {
174 return self.lex_error( &ctx.cur().unwrap() ); 174 return self.lex_error( &ctx.cur().unwrap() );
@@ -179,28 +179,57 @@ impl Parser {
179 } 179 }
180 ctx.next(); 180 ctx.next();
181 } 181 }
182 Ok(()) 182 Ok(Token::Root(children))
183 } 183 }
184 184
185 fn parse_tag(&mut self, ctx: &mut Context) -> Result<(), Box<dyn Error>> { 185 fn parse_tag(&mut self, ctx: &mut Context) -> Result<Token, Box<dyn Error>> {
186 let mut tb = TagBuilder::new(); 186 let mut tb = TagBuilder::new();
187
188 println!("--> Begin parse_tag <--");
187 189
188 let start_sym = ctx.cur().unwrap(); 190 let start_sym = ctx.cur().unwrap();
189 191
192 println!("--> Start sym: {:?}", start_sym );
193
190 if ctx.next().is_some() { 194 if ctx.next().is_some() {
191 if let SymbolType::Token(s) = ctx.next().unwrap().symbol() { 195 match ctx.cur().unwrap().symbol() {
192 tb.set_name( s.to_string() ); 196 SymbolType::Fragment | SymbolType::Section |
193 } else { 197 SymbolType::Output => {
194 return Err(Box::new(ParseError{position: ctx.cur().unwrap().start().clone(), what: "Unexpecetd symbol".to_string()})); 198 let name_sym = ctx.cur().unwrap();
199 ctx.next();
200 tb.set_name( name_sym );
201 }
202 _ => {
203 return Err(Box::new(ParseError{position: ctx.cur().unwrap().start().clone(), what: "Unexpecetd symbol".to_string()}));
204 }
195 } 205 }
196 } else { 206 } else {
197 return Err(Box::new(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()})); 207 return Err(Box::new(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}));
198 } 208 }
199 209
210 println!("--> Begin parse_tag_params <--");
200 self.parse_tag_params( ctx, &mut tb )?; 211 self.parse_tag_params( ctx, &mut tb )?;
212 println!("--> End parse_tag_params <--");
213 println!("--> Begin parse_tag_props <--");
201 self.parse_tag_props( ctx, &mut tb )?; 214 self.parse_tag_props( ctx, &mut tb )?;
215 println!("--> End parse_tag_props <--");
202 216
203 Ok(()) 217 println!("---> {:?}", ctx.cur() );
218 if let Some(end_sym) = ctx.cur() {
219 match end_sym.symbol() {
220 SymbolType::EndPoint => {
221 tb.set_type( TagType::BinaryOpen );
222 }
223 SymbolType::EndFlat => {
224 tb.set_type( TagType::Unary );
225 }
226 _ => {
227 return Err(Box::new(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}));
228 }
229 }
230 }
231
232 tb.build()
204 } 233 }
205 234
206 fn parse_tag_params(&mut self, ctx: &mut Context, tb: &mut TagBuilder ) -> Result<(), Box<dyn Error>> { 235 fn parse_tag_params(&mut self, ctx: &mut Context, tb: &mut TagBuilder ) -> Result<(), Box<dyn Error>> {
@@ -209,15 +238,13 @@ impl Parser {
209 238
210 return Err(Box::new(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()})); 239 return Err(Box::new(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}));
211 } 240 }
212 if let SymbolType::Token(s) = ctx.cur().unwrap().symbol() { 241 match ctx.cur().unwrap().symbol() {
213 if let Some(p) = ctx.peek() { 242 SymbolType::Literal(s) => {
214 if p.check_type(|t| matches!(t, SymbolType::Equals)) {
215 break;
216 }
217 }
218 else {
219 tb.add_param( s.to_string() ); 243 tb.add_param( s.to_string() );
220 } 244 }
245 _ => {
246 break;
247 }
221 } 248 }
222 ctx.next(); 249 ctx.next();
223 } 250 }
@@ -250,6 +277,7 @@ impl Parser {
250 } 277 }
251} 278}
252 279
280#[derive(PartialEq)]
253enum TagType { 281enum TagType {
254 Unknown, 282 Unknown,
255 Unary, 283 Unary,
@@ -257,36 +285,86 @@ enum TagType {
257 BinaryClose, 285 BinaryClose,
258} 286}
259 287
260struct TagBuilder { 288struct TagBuilder<'a> {
261 name: String, 289 name: Option<Symbol<'a>>,
262 params: Vec<String>, 290 params: Vec<String>,
263 props: Vec<(String,String)>, 291 props: Properties,
292 children: Vec<Token>,
264 tag_type: TagType, 293 tag_type: TagType,
265} 294}
266 295
267impl TagBuilder { 296impl<'a> TagBuilder<'a> {
268 pub fn new() -> TagBuilder { 297 pub fn new() -> TagBuilder<'a> {
269 TagBuilder { 298 TagBuilder {
270 name: String::new(), 299 name: None,
271 params: Vec::new(), 300 params: Vec::new(),
272 props: Vec::new(), 301 props: Properties::new(),
302 children: Vec::new(),
273 tag_type: TagType::Unknown, 303 tag_type: TagType::Unknown,
274 } 304 }
275 } 305 }
276 306
277 pub fn set_name(&mut self, name: String) { 307 pub fn has_children(&self) -> bool {
278 self.name = name; 308 if self.tag_type == TagType::BinaryOpen {
309 true
310 } else {
311 false
312 }
313 }
314
315 pub fn is_same_name(&self, name: Symbol<'a>) -> bool {
316 if let Some(a) = self.name {
317 a.symbol() == name.symbol()
318 } else {
319 false
320 }
321 }
322
323 pub fn set_name(&mut self, name: Symbol<'a>) {
324 self.name = Some(name);
325 println!("Tag name: {:?}", self.name );
279 } 326 }
280 327
281 pub fn add_param(&mut self, param: String) { 328 pub fn add_param(&mut self, param: String) {
329 println!("Add param: {:?}", param );
282 self.params.push( param ); 330 self.params.push( param );
283 } 331 }
284 332
285 pub fn add_prop(&mut self, key: String, value: String) { 333 pub fn add_prop(&mut self, key: String, value: String) {
286 self.props.push( (key, value) ); 334 println!("Add prop: {:?} = {:?}", key, value );
335 self.props.insert( key, value );
336 }
337
338 pub fn add_child(&mut self, token: Token) {
339 self.children.push( token );
287 } 340 }
288 341
289 pub fn set_type(&mut self, tag_type: TagType) { 342 pub fn set_type(&mut self, tag_type: TagType) {
290 self.tag_type = tag_type; 343 self.tag_type = tag_type;
291 } 344 }
345
346 pub fn build(mut self) -> Result<Token,Box<dyn Error>> {
347 if let Some(sym) = self.name {
348 match sym.symbol() {
349 SymbolType::Fragment => {
350 Ok(Token::Fragment(self.params.swap_remove(0), self.props, self.children))
351 }
352 SymbolType::Output => {
353 Ok(Token::Section(self.params.swap_remove(0), self.props, self.children))
354 }
355 _ => {
356 println!("Unkown tag type");
357 Err(Box::new(ParseError {
358 position: Position::new(0,0),
359 what: "Bad tag type".to_string(),
360 }))
361 }
362 }
363 } else {
364 Err(Box::new(ParseError {
365 position: Position::new(0,0),
366 what: "Bad tag type".to_string(),
367 }))
368 }
369 }
292} 370}