25 typedef State<TextProcessingMachine::Type> TextProcessingState;
26 typedef TextProcessingMachine::Transition TextProcessingTransition;
28 typedef LexerObject<TextProcessingState, NullTest, MarksClearer> ChurningState;
29 typedef LexerObject<TextProcessingState, NullTest, TokenFinalizer>
31 typedef LexerObject<TextProcessingTransition, NullTest, TokenFinalizer>
33 typedef LexerObject<TextProcessingTransition, NullTest,
34 TokenFinalizerWithTrimming>
35 EofHandlerWithTrimming;
37 typedef CharacterTransition<
'{'> MaybeTemplateSyntaxHandler;
39 typedef CharacterTransition<'%', MarkStartSyntax> TagStartHandler;
40 typedef CharacterTransition<'#', MarkStartSyntax> CommentStartHandler;
41 typedef CharacterTransition<'%'> TagEndHandler;
42 typedef CharacterTransition<'#'> CommentEndHandler;
43 typedef CharacterTransition<
'{', MarkStartSyntax> BeginValueHandler;
44 typedef CharacterTransition<'}'> MaybeEndValueHandler;
45 typedef CharacterTransition<'\n', MarkNewline> NewlineHandler;
46 typedef CharacterTransition<'}', MarkEndSyntax> EndTemplateSyntaxHandler;
47 typedef NegateCharacterTransition<'}'> NotEndTemplateSyntaxHandler;
50 TextProcessingTransition,
51 Negate<OrTest<CharacterTest<
'{'>,
52 OrTest<CharacterTest<'#'>, CharacterTest<'%'>>>>>
53 NotBeginTemplateSyntaxHandler;
56 TextProcessingTransition,
57 Negate<OrTest<CharacterTest<
'{'>,
58 OrTest<CharacterTest<'#'>,
59 OrTest<CharacterTest<'%'>, CharacterTest<'\n'>>>>>>
60 NotBeginTemplateSyntaxOrNewlineHandler;
63 TextProcessingTransition,
64 Negate<OrTest<CharacterTest<'#'>,
65 OrTest<CharacterTest<'%'>, CharacterTest<'\n'>>>>>
66 NotTagCommentOrNewlineHandler;
68 typedef LexerObject<TextProcessingTransition,
69 Negate<OrTest<IsSpace, CharacterTest<
'{'>>>>
70 NonWhitespaceLineTextHandler;
72 typedef LexerObject<TextProcessingTransition,
73 AndTest<Negate<CharacterTest<'\n'>>, IsSpace>>
74 WhitespaceNonNewlineHandler;
76 typedef LexerObject<TextProcessingTransition,
77 Negate<OrTest<CharacterTest<
'{'>, IsSpace>>, TokenFinalizer>
78 FinalizingLineTextHandler;
80 typedef CharacterTransition<'\n', TokenFinalizerWithTrimmingAndNewline>
81 SyntaxBoundaryNewlineHandler;
82 typedef CharacterTransition<
'{', FinalizeAndMarkStartSyntax>
83 SyntaxBoundaryHandler;
85 template <
typename Transition>
86 void addTransition(TextProcessingState *source, Lexer *lexer,
87 TextProcessingState *target)
89 auto tr =
new Transition(lexer, source);
90 tr->setTargetState(target);
93 TextProcessingMachine *createMachine(Lexer *lexer, Lexer::TrimType type)
95 auto machine =
new TextProcessingMachine;
97 auto notFinished =
new TextProcessingState(machine);
98 auto finished =
new TextProcessingState(machine);
99 machine->setInitialState(notFinished);
101 auto processingText =
new ChurningState(lexer, notFinished);
102 auto processingPostNewline =
new TextProcessingState(notFinished);
103 auto processingBeginTemplateSyntax =
new TextProcessingState(notFinished);
104 auto processingTag =
new TextProcessingState(notFinished);
105 auto processingComment =
new TextProcessingState(notFinished);
106 auto processingValue =
new TextProcessingState(notFinished);
107 auto maybeProcessingValue =
new TextProcessingState(notFinished);
108 auto processingEndTag =
new TextProcessingState(notFinished);
109 auto processingEndComment =
new TextProcessingState(notFinished);
110 auto processingEndValue =
new TextProcessingState(notFinished);
111 TextProcessingState *processingPostTemplateSyntax;
113 if (type == Lexer::SmartTrim)
114 processingPostTemplateSyntax =
new TextProcessingState(notFinished);
116 processingPostTemplateSyntax =
new FinalizeTokenState(lexer, notFinished);
117 auto processingPostTemplateSyntaxWhitespace
118 =
new TextProcessingState(notFinished);
120 if (type == Lexer::SmartTrim)
121 notFinished->setInitialState(processingPostNewline);
123 notFinished->setInitialState(processingText);
125 if (type == Lexer::SmartTrim) {
126 addTransition<NewlineHandler>(processingText, lexer, processingPostNewline);
128 addTransition<NewlineHandler>(processingPostNewline, lexer,
129 processingPostNewline);
130 addTransition<MaybeTemplateSyntaxHandler>(processingPostNewline, lexer,
131 processingBeginTemplateSyntax);
132 addTransition<NonWhitespaceLineTextHandler>(processingPostNewline, lexer,
135 addTransition<MaybeTemplateSyntaxHandler>(processingText, lexer,
136 processingBeginTemplateSyntax);
138 addTransition<TagStartHandler>(processingBeginTemplateSyntax, lexer,
140 addTransition<CommentStartHandler>(processingBeginTemplateSyntax, lexer,
142 addTransition<BeginValueHandler>(processingBeginTemplateSyntax, lexer,
143 maybeProcessingValue);
145 if (type == Lexer::SmartTrim) {
146 addTransition<NotBeginTemplateSyntaxOrNewlineHandler>(
147 processingBeginTemplateSyntax, lexer, processingText);
148 addTransition<NewlineHandler>(processingBeginTemplateSyntax, lexer,
149 processingPostNewline);
151 addTransition<NotBeginTemplateSyntaxHandler>(processingBeginTemplateSyntax,
152 lexer, processingText);
155 addTransition<NewlineHandler>(processingTag, lexer,
156 type == Lexer::SmartTrim ? processingPostNewline
158 addTransition<TagEndHandler>(processingTag, lexer, processingEndTag);
160 addTransition<NewlineHandler>(processingComment, lexer,
161 type == Lexer::SmartTrim ? processingPostNewline
163 addTransition<CommentEndHandler>(processingComment, lexer,
164 processingEndComment);
166 addTransition<TagStartHandler>(maybeProcessingValue, lexer, processingTag);
167 addTransition<CommentStartHandler>(maybeProcessingValue, lexer,
169 addTransition<NotTagCommentOrNewlineHandler>(maybeProcessingValue, lexer,
171 addTransition<NewlineHandler>(maybeProcessingValue, lexer,
172 type == Lexer::SmartTrim ? processingPostNewline
175 addTransition<NewlineHandler>(processingValue, lexer,
176 type == Lexer::SmartTrim ? processingPostNewline
178 addTransition<MaybeEndValueHandler>(processingValue, lexer,
181 addTransition<NewlineHandler>(processingEndTag, lexer, processingPostNewline);
182 addTransition<NotEndTemplateSyntaxHandler>(processingEndTag, lexer,
184 addTransition<EndTemplateSyntaxHandler>(processingEndTag, lexer,
185 processingPostTemplateSyntax);
187 addTransition<NewlineHandler>(processingEndComment, lexer,
188 processingPostNewline);
189 addTransition<NotEndTemplateSyntaxHandler>(processingEndComment, lexer,
191 addTransition<EndTemplateSyntaxHandler>(processingEndComment, lexer,
192 processingPostTemplateSyntax);
194 addTransition<NewlineHandler>(processingEndValue, lexer,
195 processingPostNewline);
196 addTransition<NotEndTemplateSyntaxHandler>(processingEndValue, lexer,
198 addTransition<EndTemplateSyntaxHandler>(processingEndValue, lexer,
199 processingPostTemplateSyntax);
201 if (type != Lexer::SmartTrim) {
202 processingPostTemplateSyntax->setUnconditionalTransition(processingText);
204 addTransition<SyntaxBoundaryNewlineHandler>(processingPostTemplateSyntax,
205 lexer, processingPostNewline);
206 addTransition<WhitespaceNonNewlineHandler>(
207 processingPostTemplateSyntax, lexer,
208 processingPostTemplateSyntaxWhitespace);
209 addTransition<FinalizingLineTextHandler>(processingPostTemplateSyntax,
210 lexer, processingText);
211 addTransition<SyntaxBoundaryHandler>(processingPostTemplateSyntax, lexer,
212 processingBeginTemplateSyntax);
218 addTransition<SyntaxBoundaryNewlineHandler>(
219 processingPostTemplateSyntaxWhitespace, lexer, processingPostNewline);
220 addTransition<FinalizingLineTextHandler>(
221 processingPostTemplateSyntaxWhitespace, lexer, processingText);
222 addTransition<SyntaxBoundaryHandler>(processingPostTemplateSyntaxWhitespace,
223 lexer, processingBeginTemplateSyntax);
227 auto handler =
new EofHandler(lexer, notFinished);
228 handler->setTargetState(finished);
229 notFinished->setEndTransition(handler);
232 if (type == Lexer::SmartTrim) {
234 auto handler =
new EofHandlerWithTrimming(
235 lexer, processingPostTemplateSyntaxWhitespace);
236 handler->setTargetState(finished);
237 processingPostTemplateSyntaxWhitespace->setEndTransition(handler);
241 =
new EofHandlerWithTrimming(lexer, processingPostTemplateSyntax);
242 handler->setTargetState(finished);
243 processingPostTemplateSyntax->setEndTransition(handler);
249 Lexer::Lexer(
const QString &templateString) : m_templateString(templateString)
255 void Lexer::clearMarkers()
257 m_startSyntaxPosition = -1;
258 m_endSyntaxPosition = -1;
259 m_newlinePosition = -1;
271 QList<Token> Lexer::tokenize(TrimType type)
273 auto machine = createMachine(
this, type);
277 auto it = m_templateString.constBegin();
278 const auto end = m_templateString.constEnd();
281 for (; it != end; ++it, ++m_upto)
282 machine->processCharacter(it);
293 void Lexer::markStartSyntax() { m_startSyntaxPosition = m_upto; }
295 void Lexer::markEndSyntax() { m_endSyntaxPosition = m_upto + 1; }
297 void Lexer::markNewline()
299 m_newlinePosition = m_upto;
303 void Lexer::finalizeToken()
305 auto nextPosition = m_upto;
306 const auto validSyntax = m_endSyntaxPosition > m_startSyntaxPosition
307 && (m_startSyntaxPosition >= m_processedUpto);
310 Q_ASSERT(m_startSyntaxPosition >= 0);
311 nextPosition = m_startSyntaxPosition - 1;
313 finalizeToken(nextPosition, validSyntax);
316 void Lexer::finalizeTokenWithTrimmedWhitespace()
318 auto nextPosition = m_upto;
324 Q_ASSERT(m_endSyntaxPosition > m_startSyntaxPosition);
326 Q_ASSERT(m_startSyntaxPosition >= 0);
327 if (m_newlinePosition >= 0 && m_newlinePosition >= m_processedUpto)
328 nextPosition = qMin(m_startSyntaxPosition - 1, m_newlinePosition);
330 nextPosition = m_startSyntaxPosition - 1;
331 finalizeToken(nextPosition,
true);
334 void Lexer::finalizeToken(
int nextPosition,
bool processSyntax)
339 = m_templateString.mid(m_processedUpto, nextPosition - m_processedUpto);
342 m_tokenList.append(token);
345 m_processedUpto = nextPosition;
350 m_processedUpto = m_endSyntaxPosition;
352 const auto differentiator
353 = *(m_templateString.constData() + m_startSyntaxPosition);
354 if (differentiator == QLatin1Char(
'#'))
360 .mid(m_startSyntaxPosition + 1,
361 m_endSyntaxPosition - m_startSyntaxPosition - 3)
365 if (differentiator == QLatin1Char(
'{')) {
368 Q_ASSERT(differentiator == QLatin1Char(
'%'));
371 m_tokenList.append(syntaxToken);
The Cutelee namespace holds all public Cutelee API.
@ BlockToken
The Token is a block, ie, part of a tag.
@ TextToken
The Token is a text fragment.
@ VariableToken
The Token is a variable node.
int linenumber
The line number this Token starts at.
QString content
The content of this Token.
int tokenType
The Type of this Token.