summaryrefslogtreecommitdiff
path: root/src
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 /src
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.
Diffstat (limited to '')
-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 }