summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <mike@xagasoft.com>2026-06-09 10:16:19 -0700
committerMike Buland <mike@xagasoft.com>2026-06-09 10:16:19 -0700
commitf724cea337965419618d7d587015c9593a67834d (patch)
tree4dfde406f727f27f0ec77738506e5061ff648d07
parent9c5da7c258a49d911b20629be6b4ef426d4f431e (diff)
downloadcrimtag-f724cea337965419618d7d587015c9593a67834d.tar.gz
crimtag-f724cea337965419618d7d587015c9593a67834d.tar.bz2
crimtag-f724cea337965419618d7d587015c9593a67834d.tar.xz
crimtag-f724cea337965419618d7d587015c9593a67834d.zip
Removed root, view, and output AST tokens.
They are built as their final objects during parsing now. It's no more complex and we have no useless tokens now.
-rw-r--r--src/lexer.rs4
-rw-r--r--src/lib.rs98
-rw-r--r--src/parser.rs122
3 files changed, 103 insertions, 121 deletions
diff --git a/src/lexer.rs b/src/lexer.rs
index c7249b7..0724df2 100644
--- a/src/lexer.rs
+++ b/src/lexer.rs
@@ -5,12 +5,12 @@ use std::fmt;
5 5
6use crate::Position; 6use crate::Position;
7 7
8#[derive(Debug,Copy,Clone,PartialEq)] 8#[derive(Debug,Copy,Clone,PartialEq,Eq)]
9pub enum ErrorType { 9pub enum ErrorType {
10 UnexpectedChar(char), 10 UnexpectedChar(char),
11} 11}
12 12
13#[derive(Debug,Copy,Clone,PartialEq)] 13#[derive(Debug,Copy,Clone,PartialEq,Eq)]
14pub enum SymbolType<'a> { 14pub enum SymbolType<'a> {
15 StartFlat, 15 StartFlat,
16 StartPoint, 16 StartPoint,
diff --git a/src/lib.rs b/src/lib.rs
index 4ebb643..7790b9a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -30,6 +30,7 @@ pub enum ViewSource {
30 30
31#[derive(Debug)] 31#[derive(Debug)]
32struct View { 32struct View {
33 name: String,
33 source: usize, 34 source: usize,
34 outputs: Vec<Output>, 35 outputs: Vec<Output>,
35// theme: Option<String> 36// theme: Option<String>
@@ -40,11 +41,9 @@ impl View {
40 fn process(&self, input: &Value) -> Result<Value, ParseError> { 41 fn process(&self, input: &Value) -> Result<Value, ParseError> {
41 let mut out_vars = HashMap::new(); 42 let mut out_vars = HashMap::new();
42 for output in &self.outputs { 43 for output in &self.outputs {
43 if let Token::Output(_,/*_,*/tokens) = &output.ast_root { 44 let mut buf = String::new();
44 let mut buf = String::new(); 45 exec( input, &output.code, &mut buf )?;
45 exec( input, tokens, &mut buf )?; 46 out_vars.insert( output.name.clone(), Value::String(buf) );
46 out_vars.insert( output.name.clone(), Value::String(buf) );
47 }
48 } 47 }
49 Ok(Value::Dictionary(out_vars)) 48 Ok(Value::Dictionary(out_vars))
50 } 49 }
@@ -53,16 +52,13 @@ impl View {
53#[derive(Debug)] 52#[derive(Debug)]
54struct Output { 53struct Output {
55 name: String, 54 name: String,
56 ast_root: Token, 55 code: Vec<Token>,
57} 56}
58 57
59type Properties = HashMap<String, String>; 58type Properties = HashMap<String, String>;
60 59
61#[derive(Debug)] 60#[derive(Debug)]
62enum Token { 61enum Token {
63 Root(Vec<Token>),
64 View(String,Properties,Vec<Token>),
65 Output(String,/*Properties,*/ Vec<Token>),
66 Show(String,Properties), 62 Show(String,Properties),
67 Text(String), 63 Text(String),
68} 64}
@@ -109,78 +105,44 @@ impl Crimtag {
109 } else { 105 } else {
110 SystemTime::now() 106 SystemTime::now()
111 }; 107 };
112 108 let source_id = self.id_source(
109 &ViewSource::File {
110 path: path.to_path_buf(),
111 loaded: time,
112 }
113 );
113 let p = parser::Parser::new(); 114 let p = parser::Parser::new();
114 self.register_views( 115 self.register_views(
115 p.parse( &String::from_utf8( std::fs::read( path )? )? )?, 116 p.parse(
116 ViewSource::File { 117 &String::from_utf8( std::fs::read( path )? )?,
117 path: path.to_path_buf(), 118 source_id
118 loaded: time, 119 )?,
119 })?; 120 )?;
120 Ok(()) 121 Ok(())
121 } 122 }
122 123
123 pub fn load_static(&mut self, data: &str) -> Result<(),ParseError> { 124 pub fn load_static(&mut self, data: &str) -> Result<(),ParseError> {
125 let source_id = self.id_source( &ViewSource::Static );
124 let p = parser::Parser::new(); 126 let p = parser::Parser::new();
125 self.register_views( p.parse( &data )?, ViewSource::Static ) 127 self.register_views( p.parse( &data, source_id )? )
126 } 128 }
127 129
128 pub fn load_external(&mut self, key: &str, data: &str) -> Result<(),ParseError> { 130 pub fn load_external(&mut self, key: &str, data: &str) -> Result<(),ParseError> {
129 let p = parser::Parser::new(); 131 let source_id = self.id_source(
132 &ViewSource::External{ key: key.to_string()}
133 );
134
135 let p = parser::Parser::new();
130 self.register_views( 136 self.register_views(
131 p.parse( &data )?, 137 p.parse( &data, source_id )?,
132 ViewSource::External{ key: key.to_string()}
133 ) 138 )
134 } 139 }
135 140
136 fn register_views(&mut self, token: Token, source: ViewSource) -> Result<(),ParseError> { 141 fn register_views(&mut self, views: Vec<View>) -> Result<(),ParseError> {
137 let source_id = self.id_source( &source ); 142 for view in views {
138 if let Token::Root(views) = token { 143 self.views.insert( view.name.clone(), view );
139 for token in views {
140 if let Token::View(name,props,output_tokens) = token {
141 let mut outputs = Vec::new();
142 for ot in output_tokens {
143 let output_name = if let Token::Output(on,..) = &ot {
144 on.clone()
145 } else {
146 return Err(ParseError::new(
147 Position::new(0,0),
148 "Broken parser? Item in view is not an output."
149 ));
150 };
151 outputs.push(
152 Output {
153 name: output_name,
154 ast_root: ot,
155 }
156 );
157 }
158
159 let layout = if let Some(l) = props.get("layout") {
160 Some(l.clone())
161 } else {
162 None
163 };
164
165 self.views.insert( name, View {
166 source: source_id,
167 outputs: outputs,
168 layout: layout,
169 });
170 } else {
171 return Err(ParseError::new(
172 Position::new(0,0),
173 "Broken parser? Item in root is not a view."
174 ));
175 }
176 }
177 Ok(())
178 } else {
179 Err(ParseError::new(
180 Position::new(0,0),
181 "Broken parser? Root is not a root token."
182 ))
183 } 144 }
145 Ok(())
184 } 146 }
185 147
186 pub fn get_view_source(&self, view: &str) -> Option<ViewSource> { 148 pub fn get_view_source(&self, view: &str) -> Option<ViewSource> {
@@ -228,10 +190,6 @@ impl Crimtag {
228fn exec(input: &Value, tokens: &Vec<Token>, buf: &mut String) -> Result<(),ParseError> { 190fn exec(input: &Value, tokens: &Vec<Token>, buf: &mut String) -> Result<(),ParseError> {
229 for token in tokens { 191 for token in tokens {
230 match token { 192 match token {
231 Token::Root(..) | Token::View(..) | Token::Output(..) => {
232 println!("Too high!?");
233 // Error?
234 }
235 Token::Show(s,p) => { 193 Token::Show(s,p) => {
236 let format = if let Some(s) = p.get("format") { 194 let format = if let Some(s) = p.get("format") {
237 s 195 s
diff --git a/src/parser.rs b/src/parser.rs
index c7a8abe..297230c 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -40,16 +40,18 @@ struct Context<'a> {
40 cur: [Option<Symbol<'a>>;2], 40 cur: [Option<Symbol<'a>>;2],
41 icur: usize, 41 icur: usize,
42 ll: Lexer<'a>, 42 ll: Lexer<'a>,
43 source: usize,
43} 44}
44 45
45impl<'a> Context<'a> { 46impl<'a> Context<'a> {
46 pub fn new( mut ll: Lexer<'a> ) -> Self { 47 pub fn new( mut ll: Lexer<'a>, source: usize ) -> Self {
47 let cur = [ll.next(), ll.next()]; 48 let cur = [ll.next(), ll.next()];
48 //println!(" - cur: {:?}, peek: {:?}", cur[0], cur[1] ); 49 //println!(" - cur: {:?}, peek: {:?}", cur[0], cur[1] );
49 Self { 50 Self {
50 cur, 51 cur,
51 icur: 0, 52 icur: 0,
52 ll 53 ll,
54 source,
53 } 55 }
54 } 56 }
55 57
@@ -75,6 +77,10 @@ impl<'a> Context<'a> {
75 Ok(f( self.cur().unwrap().symbol(), self.peek().unwrap().symbol())) 77 Ok(f( self.cur().unwrap().symbol(), self.peek().unwrap().symbol()))
76 } 78 }
77 } 79 }
80
81 pub fn source(&self) -> usize {
82 self.source
83 }
78} 84}
79 85
80trait SymbolHelper { 86trait SymbolHelper {
@@ -195,7 +201,7 @@ impl Parser {
195 } 201 }
196 } 202 }
197 203
198 fn lex_error(&self, error: &Symbol) -> ParseResult<Token> { 204 fn lex_error<T>(&self, error: &Symbol) -> ParseResult<T> {
199 if let SymbolType::Error{what} = error.symbol() { 205 if let SymbolType::Error{what} = error.symbol() {
200 Err(ParseError { 206 Err(ParseError {
201 position: error.start().clone(), 207 position: error.start().clone(),
@@ -209,15 +215,15 @@ impl Parser {
209 } 215 }
210 } 216 }
211 217
212 pub fn parse(&self, src: &str ) -> ParseResult<Token> { 218 pub fn parse(&self, src: &str, source: usize ) -> ParseResult<Vec<View>> {
213 let ll = Lexer::new( src ); 219 let ll = Lexer::new( src );
214 let mut ctx = Context::new( ll ); 220 let mut ctx = Context::new( ll, source );
215 221
216 // Parse the root of the file, the input context 222 // Parse the root of the file, the input context
217 self.p_input( &mut ctx ) 223 self.p_input( &mut ctx )
218 } 224 }
219 225
220 fn p_input(&self, ctx: &mut Context ) -> ParseResult<Token> { 226 fn p_input(&self, ctx: &mut Context ) -> ParseResult<Vec<View>> {
221 let mut children = Vec::new(); 227 let mut children = Vec::new();
222 loop { 228 loop {
223 if ctx.cur().is_none() { 229 if ctx.cur().is_none() {
@@ -229,7 +235,7 @@ impl Parser {
229 children.push( self.parse_tag_view( ctx )? ); 235 children.push( self.parse_tag_view( ctx )? );
230 } 236 }
231 SymbolType::Error{..} => { 237 SymbolType::Error{..} => {
232 return self.lex_error( &ctx.cur().unwrap() ); 238 self.lex_error( &ctx.cur().unwrap() )?;
233 } 239 }
234 _ => { 240 _ => {
235 241
@@ -237,11 +243,11 @@ impl Parser {
237 } 243 }
238 ctx.next(); 244 ctx.next();
239 } 245 }
240 Ok(Token::Root(children)) 246 Ok(children)
241 } 247 }
242 248
243 fn parse_tag_view(&self, ctx: &mut Context) -> ParseResult<Token> { 249 fn parse_tag_view(&self, ctx: &mut Context) -> ParseResult<View> {
244 let mut tb = self.parse_open_tag( ctx )?; 250 let tb = self.parse_open_tag( ctx )?;
245 if !tb.is_name( &SymbolType::View ) { 251 if !tb.is_name( &SymbolType::View ) {
246 return Err(ParseError{ 252 return Err(ParseError{
247 position: tb.start_pos(), 253 position: tb.start_pos(),
@@ -250,9 +256,10 @@ impl Parser {
250 } 256 }
251 257
252 if tb.is_unary() { 258 if tb.is_unary() {
253 return tb.build(); 259 return tb.build_view(ctx, Vec::new());
254 } 260 }
255 let mut children = Vec::new(); 261 let mut children = Vec::new();
262 let mut outputs = Vec::new();
256 263
257 //println!("--parse-tag-view-- tag parsed, next token: {:?}", ctx.cur() ); 264 //println!("--parse-tag-view-- tag parsed, next token: {:?}", ctx.cur() );
258 loop { 265 loop {
@@ -265,47 +272,37 @@ impl Parser {
265 ctx.next(); 272 ctx.next();
266 } 273 }
267 SymbolType::StartFlat => { 274 SymbolType::StartFlat => {
268 //child.is_name(SymbolType::Output) 275 let subtb = self.parse_tag_body( ctx )?;
269 children.push( self.parse_tag_body( ctx )? ); 276 if subtb.is_name(&SymbolType::Output) {
277 outputs.push(subtb.build_output(ctx)?);
278 } else {
279 children.push(subtb.build()?);
280 }
270 } 281 }
271 SymbolType::StartPoint => { 282 SymbolType::StartPoint => {
272 let end = self.parse_end_tag( ctx )?; 283 let end = self.parse_end_tag( ctx )?;
273 //println!("End tag: {:?}, open tag: {:?}", end, tb.name() ); 284 //println!("End tag: {:?}, open tag: {:?}", end, tb.name() );
274 if tb.is_name(end.symbol()) { 285 if tb.is_name(end.symbol()) {
275 // They match, time to decide what we're doing. 286 // They match, time to decide what we're doing.
276 let any_outputs = children.iter().any( 287 let any_outputs = outputs.len() > 0;
277 |t| matches!(t, Token::Output(..)) 288 let all_text = children.iter().all(
289 |t| matches!(t, Token::Text(..))
278 ); 290 );
279 if children.iter().all(|t| matches!(t, Token::Text(..)) || matches!(t, Token::Output(..))) { 291 if !any_outputs {
280 // Everything is either text or output 292 // Create an implicit output called "content"
281 if !any_outputs { 293 outputs.push(Output{
282 // Special case, if it's only text then we create an implicit output. 294 name: "content".to_string(),
283 tb.add_child(Token::Output("content".to_string(), /*Properties::new(),*/ children )); 295 code: children,
284 } 296 });
285 else {
286 // Standard case, outputs are included, text is
287 // skipped.
288 for token in children {
289 if matches!(token, Token::Output(..)) {
290 tb.add_child( token );
291 }
292 }
293 }
294 } else { 297 } else {
295 // We have another mix, now check to see if there 298 if !all_text {
296 // are any outptus, if so this is an error.
297 if any_outputs {
298 return Err(ParseError{ 299 return Err(ParseError{
299 position: *end.start(), 300 position: *end.start(),
300 what: "You cannot mix non-output and output tags in a view.".to_string() 301 what: "You cannot mix non-output and output tags in a view.".to_string()
301 }); 302 });
302 } else {
303 // No outputs at all, we create an implict output
304 tb.add_child(Token::Output("content".to_string(), /*Properties::new(), */children ));
305 } 303 }
306 } 304 }
307 305 return tb.build_view(ctx,outputs);
308 return tb.build();
309 } else { 306 } else {
310 // They don't match, complain. 307 // They don't match, complain.
311 return Err(ParseError{ 308 return Err(ParseError{
@@ -392,10 +389,10 @@ impl Parser {
392 Ok(name) 389 Ok(name)
393 } 390 }
394 391
395 fn parse_tag_body(&self, ctx: &mut Context ) -> ParseResult<Token> { 392 fn parse_tag_body<'a>(&self, ctx: &mut Context<'a> ) -> ParseResult<TagBuilder<'a>> {
396 let mut tb = self.parse_open_tag( ctx )?; 393 let mut tb = self.parse_open_tag( ctx )?;
397 if tb.is_unary() { 394 if tb.is_unary() {
398 return tb.build(); 395 return Ok(tb);
399 } 396 }
400 397
401 loop { 398 loop {
@@ -408,13 +405,13 @@ impl Parser {
408 ctx.next(); 405 ctx.next();
409 } 406 }
410 SymbolType::StartFlat => { 407 SymbolType::StartFlat => {
411 tb.add_child( self.parse_tag_body( ctx )? ); 408 tb.add_child( self.parse_tag_body( ctx )?.build()? );
412 } 409 }
413 SymbolType::StartPoint => { 410 SymbolType::StartPoint => {
414 let end = self.parse_end_tag( ctx )?; 411 let end = self.parse_end_tag( ctx )?;
415 if tb.is_name(end.symbol()) { 412 if tb.is_name(end.symbol()) {
416 // They match, end. 413 // They match, end.
417 return tb.build(); 414 return Ok(tb);
418 } else { 415 } else {
419 // They don't match, complain. 416 // They don't match, complain.
420 return Err(ParseError{ 417 return Err(ParseError{
@@ -424,7 +421,7 @@ impl Parser {
424 } 421 }
425 } 422 }
426 SymbolType::Error{..} => { 423 SymbolType::Error{..} => {
427 self.lex_error( &ctx.cur().unwrap() )?; 424 return self.lex_error( &ctx.cur().unwrap() );
428 } 425 }
429 _ => { 426 _ => {
430 427
@@ -565,15 +562,42 @@ impl<'a> TagBuilder<'a> {
565 self.tag_type 562 self.tag_type
566 } 563 }
567 564
565 pub fn build_view(mut self, ctx: &Context, outputs: Vec<Output>) -> ParseResult<View> {
566 if let Some(sym) = self.name {
567 if *sym.symbol() == SymbolType::View {
568 Ok(View {
569 name: self.params.swap_remove(0),
570 source: ctx.source(),
571 outputs: outputs,
572 //theme: Option<String>
573 layout: self.props.get("layout").cloned(),
574 })
575 } else {
576 Err(ParseError::new(self.start_pos, &format!("Expected tag type view, found {:?}", sym.symbol())))
577 }
578 } else {
579 Err(ParseError::new(self.start_pos, "Broken Parser? No tag type found when building view."))
580 }
581 }
582
583 pub fn build_output(mut self, ctx: &Context) -> ParseResult<Output> {
584 if let Some(sym) = self.name {
585 if *sym.symbol() == SymbolType::Output {
586 Ok(Output {
587 name: self.params.swap_remove(0),
588 code: self.children,
589 })
590 } else {
591 Err(ParseError::new(self.start_pos, &format!("Expected tag type view, found {:?}", sym.symbol())))
592 }
593 } else {
594 Err(ParseError::new(self.start_pos, "Broken Parser? No tag type found when building view."))
595 }
596 }
597
568 pub fn build(mut self) -> ParseResult<Token> { 598 pub fn build(mut self) -> ParseResult<Token> {
569 if let Some(sym) = self.name { 599 if let Some(sym) = self.name {
570 match sym.symbol() { 600 match sym.symbol() {
571 SymbolType::View => {
572 Ok(Token::View(self.params.swap_remove(0), self.props, self.children))
573 }
574 SymbolType::Output => {
575 Ok(Token::Output(self.params.swap_remove(0), /*self.props,*/ self.children))
576 }
577 SymbolType::Show => { 601 SymbolType::Show => {
578 Ok(Token::Show(self.params.swap_remove(0), self.props)) 602 Ok(Token::Show(self.params.swap_remove(0), self.props))
579 } 603 }