ucglib/build/
format.rs

1// Copyright 2017 Jeremy Wall <jeremy@marzhillstudios.com>
2//
3//  Licensed under the Apache License, Version 2.0 (the "License");
4//  you may not use this file except in compliance with the License.
5//  You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14
15//! The format string logic for ucg format expressions.
16use std::error::Error;
17use std::str::Chars;
18
19use abortable_parser::iter::SliceIter;
20use abortable_parser::Result as ParseResult;
21
22use crate::ast::*;
23use crate::iter;
24use crate::parse;
25use crate::tokenizer;
26
27pub trait FormatRenderer {
28    fn render(&self, pos: &Position) -> Result<String, Box<dyn Error>>;
29}
30
31pub type TemplateResult = Result<Vec<TemplatePart>, Box<dyn Error>>;
32
33pub trait TemplateParser {
34    fn parse(&self, input: &str) -> TemplateResult;
35}
36
37pub struct SimpleTemplate();
38
39impl SimpleTemplate {
40    pub fn new() -> Self {
41        Self()
42    }
43}
44
45impl TemplateParser for SimpleTemplate {
46    fn parse(&self, input: &str) -> TemplateResult {
47        let mut result = Vec::new();
48        let mut count = 0;
49        let mut should_escape = false;
50        let mut buf: Vec<char> = Vec::new();
51        for c in input.chars() {
52            if c == '@' && !should_escape {
53                result.push(TemplatePart::Str(buf));
54                buf = Vec::new();
55                // This is a placeholder in our template.
56                result.push(TemplatePart::PlaceHolder(count));
57                count += 1;
58            } else if c == '\\' && !should_escape {
59                should_escape = true;
60                continue;
61            } else {
62                buf.push(c);
63            }
64            should_escape = false;
65        }
66        if buf.len() != 0 {
67            result.push(TemplatePart::Str(buf));
68        }
69        Ok(result)
70    }
71}
72
73pub struct ExpressionTemplate();
74
75impl ExpressionTemplate {
76    pub fn new() -> Self {
77        ExpressionTemplate()
78    }
79
80    fn consume_expr(&self, iter: &mut Chars) -> Result<Expression, Box<dyn Error>> {
81        let mut result = String::new();
82        let mut brace_count = 0;
83        loop {
84            let c = match iter.next() {
85                Some(c) => c,
86                None => break,
87            };
88            if c == '{' {
89                brace_count += 1;
90                // We ignore the starting brace
91                if brace_count == 1 {
92                    continue;
93                }
94            }
95            if c == '}' {
96                brace_count -= 1;
97            }
98            // We ignore the closing brace
99            if brace_count == 0 {
100                break;
101            }
102            result.push(c);
103        }
104        let str_iter = iter::OffsetStrIter::new(&result);
105        let toks = match tokenizer::tokenize(str_iter, None) {
106            Ok(toks) => toks,
107            Err(_e) => panic!("TODO(jwall): make this not a thing"),
108        };
109
110        let i = SliceIter::new(&toks);
111        match parse::expression(i) {
112            ParseResult::Complete(_, expr) => Ok(expr),
113            ParseResult::Abort(_e) | ParseResult::Fail(_e) => {
114                panic!("TODO(jwall): make this not a thing")
115            }
116            ParseResult::Incomplete(_ei) => panic!("TODO(jwall): make this not a thing"),
117        }
118    }
119}
120
121impl TemplateParser for ExpressionTemplate {
122    fn parse(&self, input: &str) -> TemplateResult {
123        let mut parts = Vec::new();
124        let mut should_escape = false;
125        let mut iter = input.chars();
126        let mut buf: Vec<char> = Vec::new();
127        loop {
128            let c = match iter.next() {
129                Some(c) => c,
130                None => break,
131            };
132            if c == '@' && !should_escape {
133                parts.push(TemplatePart::Str(buf));
134                buf = Vec::new();
135                // consume our expression here
136                parts.push(TemplatePart::Expression(self.consume_expr(&mut iter)?));
137            } else if c == '\\' && !should_escape {
138                should_escape = true;
139                continue;
140            } else {
141                buf.push(c);
142            }
143            should_escape = false;
144        }
145        if buf.len() != 0 {
146            parts.push(TemplatePart::Str(buf));
147        }
148        Ok(parts)
149    }
150}