summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lexer.rs14
-rw-r--r--src/lib.rs30
-rw-r--r--src/parser.rs280
3 files changed, 310 insertions, 14 deletions
diff --git a/src/lexer.rs b/src/lexer.rs
index e80e461..94825b2 100644
--- a/src/lexer.rs
+++ b/src/lexer.rs
@@ -2,7 +2,12 @@ use std::iter::Iterator;
2//use core::error::Error; 2//use core::error::Error;
3use std::str::CharIndices; 3use std::str::CharIndices;
4 4
5#[derive(Debug)] 5#[derive(Debug,Copy,Clone)]
6pub enum ErrorType {
7 UnexpectedChar(char),
8}
9
10#[derive(Debug,Copy,Clone)]
6pub enum Symbol<'a> { 11pub enum Symbol<'a> {
7 StartFlat, 12 StartFlat,
8 StartPoint, 13 StartPoint,
@@ -15,7 +20,7 @@ pub enum Symbol<'a> {
15 Token(&'a str), 20 Token(&'a str),
16 Literal(&'a str), 21 Literal(&'a str),
17 Text(&'a str), 22 Text(&'a str),
18 Error{ line: u32, row: u32, what: String }, 23 Error{ line: u32, row: u32, what: ErrorType },
19 EOS, 24 EOS,
20} 25}
21 26
@@ -104,7 +109,7 @@ impl<'a> Lexer<'a> {
104 } 109 }
105 } 110 }
106 111
107 fn error( &self, what: String ) -> Option<Symbol<'a>> { 112 fn error( &self, what: ErrorType ) -> Option<Symbol<'a>> {
108 Some(Symbol::Error { 113 Some(Symbol::Error {
109 line: self.line, 114 line: self.line,
110 row: self.row, 115 row: self.row,
@@ -162,6 +167,7 @@ impl<'a> Lexer<'a> {
162 return self.parse_literal_str(); 167 return self.parse_literal_str();
163 } 168 }
164 Some('=') => { 169 Some('=') => {
170 self.next();
165 return Some(Symbol::Equals); 171 return Some(Symbol::Equals);
166 } 172 }
167 _ => {} 173 _ => {}
@@ -186,7 +192,7 @@ impl<'a> Lexer<'a> {
186 192
187 fn parse_literal_str(&mut self) -> Option<Symbol<'a>> { 193 fn parse_literal_str(&mut self) -> Option<Symbol<'a>> {
188 if let Some(chr) = self.cur() && chr != '"' { 194 if let Some(chr) = self.cur() && chr != '"' {
189 return self.error(format!("Expected '\"' but found '{}'", chr)); 195 return self.error( ErrorType::UnexpectedChar(chr) );
190 } 196 }
191 let start = self.peek_index(); 197 let start = self.peek_index();
192 while self.next().is_some_and(|chr| chr != '"') { } 198 while self.next().is_some_and(|chr| chr != '"') { }
diff --git a/src/lib.rs b/src/lib.rs
index 16bef07..0f6d01d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,10 +2,13 @@ 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;
5 7
6mod lexer; 8mod lexer;
9mod parser;
7 10
8pub struct Tx { 11pub struct Crimtag {
9 fragments: HashMap<String, Fragment>, 12 fragments: HashMap<String, Fragment>,
10 sources: Vec<FragmentSource>, 13 sources: Vec<FragmentSource>,
11} 14}
@@ -40,23 +43,22 @@ enum Token {
40 Fragment(String,Properties,Vec<Token>), 43 Fragment(String,Properties,Vec<Token>),
41 Section(String,Properties,Vec<Token>), 44 Section(String,Properties,Vec<Token>),
42 Text(String), 45 Text(String),
43
44} 46}
45 47
46struct State { 48struct State {
47} 49}
48 50
49impl Tx { 51impl Crimtag {
50 pub fn new() -> Self { 52 pub fn new() -> Self {
51 Self { 53 Self {
52 fragments: HashMap::new(), 54 fragments: HashMap::new(),
53 sources: vec![Frament::Static], 55 sources: vec![FragmentSource::Static],
54 } 56 }
55 } 57 }
56 58
57 fn id_source(&mut self, src: &FragmentSource ) -> usize { 59 fn id_source(&mut self, src: &FragmentSource ) -> usize {
58 for idx in 0..self.sources.len() { 60 for idx in 0..self.sources.len() {
59 if self.sources[idx] == src { 61 if self.sources[idx] == *src {
60 return idx; 62 return idx;
61 } 63 }
62 } 64 }
@@ -77,16 +79,18 @@ impl Tx {
77 SystemTime::now() 79 SystemTime::now()
78 } 80 }
79 } else { 81 } else {
80 SystemTime.now() 82 SystemTime::now()
81 }; 83 };
82 84
83 let mut file = File::open( path )?; 85 let mut p = parser::Parser::new();
86 p.parse( self, &String::from_utf8( std::fs::read( path )? )? );
84 87
85 let mut ll = lexer::Lexer( &String::from_utf8( file.read()? )? );
86 Ok(()) 88 Ok(())
87 } 89 }
88 90
89 pub fn load_static(&mut self, data: &str) -> Result<(),Box::<dyn Error>> { 91 pub fn load_static(&mut self, data: &str) -> Result<(),Box::<dyn Error>> {
92 let mut p = parser::Parser::new();
93 p.parse( self, &data );
90 94
91 Ok(()) 95 Ok(())
92 } 96 }
@@ -102,15 +106,21 @@ mod tests {
102 106
103 #[test] 107 #[test]
104 fn lexing() { 108 fn lexing() {
105 let data = r#"Leading comment: [|fragment "basic"|>Hello there <|fragment|] Trailing text"#; 109 let data = r#"Leading comment: [|fragment "basic" something="yeup"|>Hello there <|fragment|] Trailing text"#;
106 let ll = lexer::Lexer::new( &data ); 110 let ll = lexer::Lexer::new( &data );
107 for sym in ll { 111 for sym in ll {
108 if let lexer::Symbol::Error{line,row,what} = sym { 112 if let lexer::Symbol::Error{line,row,what} = sym {
109 println!("Error {}:{}: {}", line, row, what ); 113 println!("Error {}:{}: {:?}", line, row, what );
110 break; 114 break;
111 } else { 115 } else {
112 println!("Symbol: {:?}", sym ); 116 println!("Symbol: {:?}", sym );
113 } 117 }
114 } 118 }
115 } 119 }
120
121 #[test]
122 fn parsing() {
123 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!"#);
125 }
116} 126}
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 @@
1use crate::lexer::*;
2use crate::*;
3
4use core::error::Error;
5use std::fmt;
6
7#[derive(Debug)]
8struct ParseError {
9 line: u32,
10 row: u32,
11 what: String,
12}
13
14impl fmt::Display for ParseError {
15 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16 write!(f, "Error parsing input: {}", "yeah")
17 }
18}
19
20impl Error for ParseError { }
21
22struct Context<'a> {
23 cur: [Option<Symbol<'a>>;2],
24 icur: usize,
25 ll: Lexer<'a>,
26}
27
28impl<'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
54pub 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 */
134impl 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
241enum TagType {
242 Unknown,
243 Unary,
244 BinaryOpen,
245 BinaryClose,
246}
247
248struct TagBuilder {
249 name: String,
250 params: Vec<String>,
251 props: Vec<(String,String)>,
252 tag_type: TagType,
253}
254
255impl 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}