summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lexer.rs105
-rw-r--r--src/lib.rs24
-rw-r--r--src/parser.rs56
3 files changed, 133 insertions, 52 deletions
diff --git a/src/lexer.rs b/src/lexer.rs
index 94825b2..04be350 100644
--- a/src/lexer.rs
+++ b/src/lexer.rs
@@ -2,13 +2,15 @@ use std::iter::Iterator;
2//use core::error::Error; 2//use core::error::Error;
3use std::str::CharIndices; 3use std::str::CharIndices;
4 4
5use crate::Position;
6
5#[derive(Debug,Copy,Clone)] 7#[derive(Debug,Copy,Clone)]
6pub enum ErrorType { 8pub enum ErrorType {
7 UnexpectedChar(char), 9 UnexpectedChar(char),
8} 10}
9 11
10#[derive(Debug,Copy,Clone)] 12#[derive(Debug,Copy,Clone)]
11pub enum Symbol<'a> { 13pub enum SymbolType<'a> {
12 StartFlat, 14 StartFlat,
13 StartPoint, 15 StartPoint,
14 EndFlat, 16 EndFlat,
@@ -20,10 +22,41 @@ pub enum Symbol<'a> {
20 Token(&'a str), 22 Token(&'a str),
21 Literal(&'a str), 23 Literal(&'a str),
22 Text(&'a str), 24 Text(&'a str),
23 Error{ line: u32, row: u32, what: ErrorType }, 25 Error{ what: ErrorType },
24 EOS, 26 EOS,
25} 27}
26 28
29#[derive(Debug,Copy,Clone)]
30pub struct Symbol<'a> {
31 symbol: SymbolType<'a>,
32 start: Position,
33 end: Position,
34}
35
36impl<'a> Symbol<'a> {
37 pub fn new( symbol: SymbolType<'a>, start: Position, end: Position ) -> Self {
38 Self {
39 symbol, start, end,
40 }
41 }
42
43 pub fn check_type<T: Fn( &SymbolType ) -> bool>(&self, f: T ) -> bool {
44 f( &self.symbol )
45 }
46
47 pub fn symbol(&self) -> &SymbolType<'a> {
48 &self.symbol
49 }
50
51 pub fn start(&self) -> &Position {
52 &self.start
53 }
54
55 pub fn end(&self) -> &Position {
56 &self.end
57 }
58}
59
27enum Mode { 60enum Mode {
28 Text, 61 Text,
29 InTag, 62 InTag,
@@ -35,8 +68,7 @@ pub struct Lexer<'a> {
35 cur: [Option<(usize, char)>;2], 68 cur: [Option<(usize, char)>;2],
36 icur: usize, 69 icur: usize,
37 mode: Mode, 70 mode: Mode,
38 line: u32, 71 pos: Position,
39 row: u32,
40} 72}
41 73
42fn is_valid_token_char( c: char ) -> bool { 74fn is_valid_token_char( c: char ) -> bool {
@@ -61,8 +93,7 @@ impl<'a> Lexer<'a> {
61 cur: [cur, cur2], 93 cur: [cur, cur2],
62 icur: 0, 94 icur: 0,
63 mode: Mode::Text, 95 mode: Mode::Text,
64 line: 0, 96 pos: Position::new(1,1),
65 row: 0,
66 } 97 }
67 } 98 }
68 99
@@ -71,6 +102,12 @@ impl<'a> Lexer<'a> {
71 self.icur = (self.icur+1)%2; 102 self.icur = (self.icur+1)%2;
72 //println!(" - cur: {:?}, peek: {:?}", self.cur(), self.peek() ); 103 //println!(" - cur: {:?}, peek: {:?}", self.cur(), self.peek() );
73 if let Some((_,chr)) = self.cur[self.icur] { 104 if let Some((_,chr)) = self.cur[self.icur] {
105 if chr == '\n' {
106 self.pos.column = 1;
107 self.pos.line += 1;
108 } else {
109 self.pos.column += 1;
110 }
74 Some(chr) 111 Some(chr)
75 } else { 112 } else {
76 None 113 None
@@ -110,11 +147,9 @@ impl<'a> Lexer<'a> {
110 } 147 }
111 148
112 fn error( &self, what: ErrorType ) -> Option<Symbol<'a>> { 149 fn error( &self, what: ErrorType ) -> Option<Symbol<'a>> {
113 Some(Symbol::Error { 150 Some(Symbol::new( SymbolType::Error {
114 line: self.line,
115 row: self.row,
116 what: what 151 what: what
117 }) 152 }, self.pos, self.pos ))
118 } 153 }
119 154
120 fn skip_ws( &mut self ) { 155 fn skip_ws( &mut self ) {
@@ -149,14 +184,16 @@ impl<'a> Lexer<'a> {
149 184
150 fn parse_text(&mut self) -> Option<Symbol<'a>> { 185 fn parse_text(&mut self) -> Option<Symbol<'a>> {
151 let start = self.cur_index(); 186 let start = self.cur_index();
187 let start_pos = self.pos.clone();
152 while self.next().is_some() && !self.is_start_tag() { } 188 while self.next().is_some() && !self.is_start_tag() { }
153 let end = self.cur_index(); 189 let end = self.cur_index();
190 let end_pos = self.pos.clone();
154 let s = &self.data[start..end]; 191 let s = &self.data[start..end];
155 //println!(" text: >>>{}<<<", s); 192 //println!(" text: >>>{}<<<", s);
156 if start == end { 193 if start == end {
157 None 194 None
158 } else { 195 } else {
159 Some(Symbol::Text(s)) 196 Some(Symbol::new( SymbolType::Text(s), start_pos, end_pos ))
160 } 197 }
161 } 198 }
162 199
@@ -168,25 +205,27 @@ impl<'a> Lexer<'a> {
168 } 205 }
169 Some('=') => { 206 Some('=') => {
170 self.next(); 207 self.next();
171 return Some(Symbol::Equals); 208 return Some(Symbol::new(SymbolType::Equals, self.pos, self.pos));
172 } 209 }
173 _ => {} 210 _ => {}
174 } 211 }
175 let start = self.cur_index(); 212 let start = self.cur_index();
213 let start_pos = self.pos.clone();
176 214
177 while self.next().is_some_and(|ch| is_valid_token_char(ch) ) && 215 while self.next().is_some_and(|ch| is_valid_token_char(ch) ) &&
178 !self.is_end_tag() {} 216 !self.is_end_tag() {}
179 let end = self.cur_index(); 217 let end = self.cur_index();
218 let end_pos = self.pos.clone();
180 let s = &self.data[start..end]; 219 let s = &self.data[start..end];
181 if start == end { 220 if start == end {
182 None 221 None
183 } else { 222 } else {
184 Some(match s { 223 Some(Symbol::new( match s {
185 "fragment" => Symbol::Fragment, 224 "fragment" => SymbolType::Fragment,
186 "section" => Symbol::Section, 225 "section" => SymbolType::Section,
187 "output" => Symbol::Output, 226 "output" => SymbolType::Output,
188 _ => Symbol::Token(s) 227 _ => SymbolType::Token(s)
189 }) 228 }, start_pos, end_pos ))
190 } 229 }
191 } 230 }
192 231
@@ -195,11 +234,13 @@ impl<'a> Lexer<'a> {
195 return self.error( ErrorType::UnexpectedChar(chr) ); 234 return self.error( ErrorType::UnexpectedChar(chr) );
196 } 235 }
197 let start = self.peek_index(); 236 let start = self.peek_index();
237 let start_pos = self.pos.clone();
198 while self.next().is_some_and(|chr| chr != '"') { } 238 while self.next().is_some_and(|chr| chr != '"') { }
199 let end = self.cur_index(); 239 let end = self.cur_index();
240 let end_pos = self.pos.clone();
200 self.next(); 241 self.next();
201 let s = &self.data[start..end]; 242 let s = &self.data[start..end];
202 Some(Symbol::Literal(s)) 243 Some(Symbol::new(SymbolType::Literal(s), start_pos, end_pos ))
203 } 244 }
204 245
205 fn is_start_tag(&mut self) -> bool { 246 fn is_start_tag(&mut self) -> bool {
@@ -212,21 +253,26 @@ impl<'a> Lexer<'a> {
212 } 253 }
213 254
214 fn parse_start_tag(&mut self) -> Option<Symbol<'a>> { 255 fn parse_start_tag(&mut self) -> Option<Symbol<'a>> {
256 let start_pos = self.pos.clone();
215 match self.cur() { 257 match self.cur() {
216 Some('[') => { 258 Some('[') => {
217 if let Some(p) = self.peek() && p == '|' { 259 if let Some(p) = self.peek() && p == '|' {
218 self.next(); self.next(); 260 self.next();
261 let end_pos = self.pos.clone();
262 self.next();
219 self.mode = Mode::InTag; 263 self.mode = Mode::InTag;
220 Some(Symbol::StartFlat) 264 Some(Symbol::new( SymbolType::StartFlat, start_pos, end_pos ) )
221 } else { 265 } else {
222 None 266 None
223 } 267 }
224 } 268 }
225 Some('<') => { 269 Some('<') => {
226 if let Some(p) = self.peek() && p == '|' { 270 if let Some(p) = self.peek() && p == '|' {
227 self.next(); self.next(); 271 self.next();
272 let end_pos = self.pos.clone();
273 self.next();
228 self.mode = Mode::InTag; 274 self.mode = Mode::InTag;
229 Some(Symbol::StartPoint) 275 Some(Symbol::new(SymbolType::StartPoint, start_pos, end_pos ) )
230 } else { 276 } else {
231 None 277 None
232 } 278 }
@@ -247,17 +293,22 @@ impl<'a> Lexer<'a> {
247 } 293 }
248 294
249 fn parse_end_tag(&mut self) -> Option<Symbol<'a>> { 295 fn parse_end_tag(&mut self) -> Option<Symbol<'a>> {
296 let start_pos = self.pos.clone();
250 if let Some(chr) = self.cur() && chr == '|' { 297 if let Some(chr) = self.cur() && chr == '|' {
251 match self.peek() { 298 match self.peek() {
252 Some(']') => { 299 Some(']') => {
253 self.next(); self.next(); 300 self.next();
301 let end_pos = self.pos.clone();
302 self.next();
254 self.mode = Mode::Text; 303 self.mode = Mode::Text;
255 Some(Symbol::EndFlat) 304 Some(Symbol::new( SymbolType::EndFlat, start_pos, end_pos))
256 } 305 }
257 Some('>') => { 306 Some('>') => {
258 self.next(); self.next(); 307 self.next();
308 let end_pos = self.pos.clone();
309 self.next();
259 self.mode = Mode::Text; 310 self.mode = Mode::Text;
260 Some(Symbol::EndPoint) 311 Some(Symbol::new( SymbolType::EndPoint, start_pos, end_pos))
261 } 312 }
262 _ => { 313 _ => {
263 None 314 None
diff --git a/src/lib.rs b/src/lib.rs
index 0f6d01d..7d0e7f2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,6 +8,20 @@ use std::io::Read;
8mod lexer; 8mod lexer;
9mod parser; 9mod parser;
10 10
11#[derive(Debug,Copy,Clone)]
12pub struct Position {
13 pub line: u32,
14 pub column: u32,
15}
16
17impl Position {
18 pub fn new( line: u32, column: u32 ) -> Self {
19 Self {
20 line, column,
21 }
22 }
23}
24
11pub struct Crimtag { 25pub struct Crimtag {
12 fragments: HashMap<String, Fragment>, 26 fragments: HashMap<String, Fragment>,
13 sources: Vec<FragmentSource>, 27 sources: Vec<FragmentSource>,
@@ -104,13 +118,15 @@ impl Crimtag {
104mod tests { 118mod tests {
105 use super::*; 119 use super::*;
106 120
121 use crate::lexer::*;
122
107 #[test] 123 #[test]
108 fn lexing() { 124 fn lexing() {
109 let data = r#"Leading comment: [|fragment "basic" something="yeup"|>Hello there <|fragment|] Trailing text"#; 125 let data = r#"Leading comment: [|fragment "basic" something="yeup"|>Hello there <|fragment|] Trailing text"#;
110 let ll = lexer::Lexer::new( &data ); 126 let ll = lexer::Lexer::new( &data );
111 for sym in ll { 127 for sym in ll {
112 if let lexer::Symbol::Error{line,row,what} = sym { 128 if let SymbolType::Error{what} = sym.symbol() {
113 println!("Error {}:{}: {:?}", line, row, what ); 129 println!("Error {}:{}: {:?}", sym.start().line, sym.start().column, what );
114 break; 130 break;
115 } else { 131 } else {
116 println!("Symbol: {:?}", sym ); 132 println!("Symbol: {:?}", sym );
@@ -121,6 +137,8 @@ mod tests {
121 #[test] 137 #[test]
122 fn parsing() { 138 fn parsing() {
123 let mut ct = Crimtag::new(); 139 let mut ct = Crimtag::new();
124 ct.load_static(r#"Here is a sample [|frament "index" theme="standard"|><html><body>Hi</body></html><|fragment|] That was fun!"#); 140 ct.load_static(r#"Here is a sample
141[|frament "index" theme="standard"|><html><body>Hi</body></html><|fragment|]
142That was fun!"#);
125 } 143 }
126} 144}
diff --git a/src/parser.rs b/src/parser.rs
index 54b77ac..e5ea1f5 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -6,8 +6,7 @@ use std::fmt;
6 6
7#[derive(Debug)] 7#[derive(Debug)]
8struct ParseError { 8struct ParseError {
9 line: u32, 9 position: Position,
10 row: u32,
11 what: String, 10 what: String,
12} 11}
13 12
@@ -138,15 +137,15 @@ impl Parser {
138 } 137 }
139 138
140 fn lex_error(&self, error: &Symbol) -> Result<(),Box<dyn Error>> { 139 fn lex_error(&self, error: &Symbol) -> Result<(),Box<dyn Error>> {
141 if let Symbol::Error{line,row,what} = error { 140 if let SymbolType::Error{what} = error.symbol() {
142 Err(Box::new(ParseError { 141 Err(Box::new(ParseError {
143 line: *line, 142 position: error.start().clone(),
144 row: *row,
145 what: format!("What: {:?}", *what) 143 what: format!("What: {:?}", *what)
146 })) 144 }))
147 } else { 145 } else {
148 Err(Box::new(ParseError { 146 Err(Box::new(ParseError {
149 line: 0, row: 0, what: "Not an error?".to_string() 147 position: Position::new(0,0),
148 what: "Not an error?".to_string(),
150 })) 149 }))
151 } 150 }
152 } 151 }
@@ -166,12 +165,12 @@ impl Parser {
166 if ctx.cur().is_none() { 165 if ctx.cur().is_none() {
167 break; 166 break;
168 } 167 }
169 match ctx.cur() { 168 match ctx.cur().unwrap().symbol() {
170 Some(Symbol::Text(_)) => { /* Skip top level text */ } 169 SymbolType::Text(_) => { /* Skip top level text */ }
171 Some(Symbol::StartFlat) => { 170 SymbolType::StartFlat => {
172 self.parse_tag( ctx ); 171 self.parse_tag( ctx );
173 } 172 }
174 Some(Symbol::Error{..}) => { 173 SymbolType::Error{..} => {
175 return self.lex_error( &ctx.cur().unwrap() ); 174 return self.lex_error( &ctx.cur().unwrap() );
176 } 175 }
177 _ => { 176 _ => {
@@ -188,10 +187,14 @@ impl Parser {
188 187
189 let start_sym = ctx.cur().unwrap(); 188 let start_sym = ctx.cur().unwrap();
190 189
191 if let Some(Symbol::Token(s)) = ctx.next() { 190 if ctx.next().is_some() {
192 tb.set_name( s.to_string() ); 191 if let SymbolType::Token(s) = ctx.next().unwrap().symbol() {
192 tb.set_name( s.to_string() );
193 } else {
194 return Err(Box::new(ParseError{position: ctx.cur().unwrap().start().clone(), what: "Unexpecetd symbol".to_string()}));
195 }
193 } else { 196 } else {
194 return Err(Box::new(ParseError{line: 0, row: 0, what: "Unexpecetd symbol".to_string()})); 197 return Err(Box::new(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}));
195 } 198 }
196 199
197 self.parse_tag_params( ctx, &mut tb )?; 200 self.parse_tag_params( ctx, &mut tb )?;
@@ -202,10 +205,15 @@ impl Parser {
202 205
203 fn parse_tag_params(&mut self, ctx: &mut Context, tb: &mut TagBuilder ) -> Result<(), Box<dyn Error>> { 206 fn parse_tag_params(&mut self, ctx: &mut Context, tb: &mut TagBuilder ) -> Result<(), Box<dyn Error>> {
204 loop { 207 loop {
205 if let Some(Symbol::Token(s)) = ctx.cur() { 208 if ctx.cur().is_none() {
206 if matches!(ctx.peek(), Some(Symbol::Equals)) { 209
207 // Done with parameters 210 return Err(Box::new(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}));
208 break; 211 }
212 if let SymbolType::Token(s) = ctx.cur().unwrap().symbol() {
213 if let Some(p) = ctx.peek() {
214 if p.check_type(|t| matches!(t, SymbolType::Equals)) {
215 break;
216 }
209 } 217 }
210 else { 218 else {
211 tb.add_param( s.to_string() ); 219 tb.add_param( s.to_string() );
@@ -218,16 +226,20 @@ impl Parser {
218 226
219 fn parse_tag_props(&mut self, ctx: &mut Context, tb: &mut TagBuilder ) -> Result<(), Box<dyn Error>> { 227 fn parse_tag_props(&mut self, ctx: &mut Context, tb: &mut TagBuilder ) -> Result<(), Box<dyn Error>> {
220 loop { 228 loop {
221 if let Some(Symbol::Token(s)) = ctx.cur() { 229 if ctx.cur().is_none() {
222 if matches!(ctx.peek(), Some(Symbol::Equals)) { 230 return Err(Box::new(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}));
231 }
232 if let SymbolType::Token(s) = ctx.cur().unwrap().symbol() {
233 if ctx.peek().is_some_and(|s|s.check_type(|t| matches!(t,SymbolType::Equals))) {
223 ctx.next(); 234 ctx.next();
224 if let Some(Symbol::Literal(lv)) = ctx.next() { 235 if let Some(sym) = ctx.next() &&
236 let SymbolType::Literal(lv) = sym.symbol() {
225 tb.add_prop( s.to_string(), lv.to_string() ); 237 tb.add_prop( s.to_string(), lv.to_string() );
226 } else { 238 } else {
227 return Err(Box::new(ParseError{line: 0, row: 0, what: "Expected quoted literal string".to_string()})); 239 return Err(Box::new(ParseError{position: Position::new(0,0), what: "Expected quoted literal string".to_string()}));
228 } 240 }
229 } else { 241 } else {
230 return Err(Box::new(ParseError{line: 0, row: 0, what: "Expected = ".to_string()})); 242 return Err(Box::new(ParseError{position:Position::new(0,0), what: "Expected = ".to_string()}));
231 } 243 }
232 } else { 244 } else {
233 break; 245 break;