1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the utils of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 #ifndef GENERATOR_H
29 #define GENERATOR_H
30 
31 #include <QTextStream>
32 #include <QStringList>
33 
34 #include "nfa.h"
35 
36 class LineStream
37 {
38 private:
39     struct SharedStream
40     {
41         int ref;
42         QTextStream *stream;
43     };
44 
45 public:
LineStream(QTextStream * textStream)46     LineStream(QTextStream *textStream)
47     {
48         shared = new SharedStream;
49         shared->ref = 1;
50         shared->stream = textStream;
51     }
LineStream(const LineStream & other)52     LineStream(const LineStream &other)
53     {
54         shared = other.shared;
55         shared->ref++;
56     }
57     LineStream &operator=(const LineStream &other)
58     {
59         if (this == &other)
60             return *this;
61         LineStream copy(other); // keep refcount up
62         qSwap(*shared, *other.shared);
63         return *this;
64     }
~LineStream()65     ~LineStream()
66     {
67         if (!--shared->ref) {
68             (*shared->stream) << endl;
69             delete shared;
70         }
71     }
72 
73     template <typename T>
74     LineStream &operator<<(const T &value)
75     { (*shared->stream) << value; return *this; }
76 
77     SharedStream *shared;
78 };
79 
80 class CodeBlock
81 {
82 public:
CodeBlock()83     inline CodeBlock() { stream.setString(&output, QIODevice::WriteOnly); }
84 
indent()85     inline void indent() { indentStr += QLatin1String("    "); }
outdent()86     inline void outdent() { indentStr.remove(0, 4); }
87 
88     template <typename T>
89     LineStream operator<<(const T &value)
90     { stream << indentStr; stream << value; return LineStream(&stream); }
91 
addNewLine()92     inline void addNewLine() { stream << endl; }
93 
toString()94     inline QString toString() const { stream.flush(); return output; }
95 
96 private:
97     QString output;
98     mutable QTextStream stream;
99     QString indentStr;
100 };
101 
102 class Function
103 {
104 public:
Function(const QString & returnType,const QString & name)105     inline Function(const QString &returnType, const QString &name)
106         : rtype(returnType), fname(name), iline(false), cnst(false) {}
Function()107     inline Function() : iline(false), cnst(false) {}
108 
setName(const QString & name)109     inline void setName(const QString &name) { fname = name; }
name()110     inline QString name() const { return fname; }
111 
setInline(bool i)112     inline void setInline(bool i) { iline = i; }
isInline()113     inline bool isInline() const { return iline; }
114 
setReturnType(const QString & type)115     inline void setReturnType(const QString &type) { rtype = type; }
returnType()116     inline QString returnType() const { return rtype; }
117 
addBody(const QString & _body)118     inline void addBody(const QString &_body) { body += _body; }
addBody(const CodeBlock & block)119     inline void addBody(const CodeBlock &block) { body += block.toString(); }
hasBody()120     inline bool hasBody() const { return !body.isEmpty(); }
121 
setConst(bool konst)122     inline void setConst(bool konst) { cnst = konst; }
isConst()123     inline bool isConst() const { return cnst; }
124 
125     void printDeclaration(CodeBlock &block, const QString &funcNamePrefix = QString()) const;
126     QString definition() const;
127 
128 private:
129     QString signature(const QString &funcNamePrefix = QString()) const;
130 
131     QString rtype;
132     QString fname;
133     QString body;
134     bool iline;
135     bool cnst;
136 };
137 
138 class Class
139 {
140 public:
141     enum Access { PublicMember, ProtectedMember, PrivateMember };
142 
Class(const QString & name)143     inline Class(const QString &name) : cname(name) {}
144 
setName(const QString & name)145     inline void setName(const QString &name) { cname = name; }
name()146     inline QString name() const { return cname; }
147 
addMember(Access access,const QString & name)148     inline void addMember(Access access, const QString &name)
149     { sections[access].variables.append(name); }
addMember(Access access,const Function & func)150     inline void addMember(Access access, const Function &func)
151     { sections[access].functions.append(func); }
152 
153     void addConstructor(Access access, const QString &body, const QString &args = QString());
154     inline void addConstructor(Access access, const CodeBlock &body, const QString &args = QString())
155     { addConstructor(access, body.toString(), args); }
156 
157     QString declaration() const;
158     QString definition() const;
159 
160 private:
161     QString cname;
162     struct Section
163     {
164         QVector<Function> functions;
165         QStringList variables;
166         QVector<Function> constructors;
167 
isEmptySection168         inline bool isEmpty() const
169         { return functions.isEmpty() && variables.isEmpty() && constructors.isEmpty(); }
170 
171         void printDeclaration(const Class *klass, CodeBlock &block) const;
172         QString definition(const Class *klass) const;
173     };
174 
175     Section sections[3];
176 };
177 
178 class Generator
179 {
180 public:
181     Generator(const DFA &dfa, const Config &config);
182 
183     QString generate();
184 
185 private:
186     void generateTransitions(CodeBlock &body, const TransitionMap &transitions);
187     bool isSingleReferencedFinalState(int i) const;
188 
189     DFA dfa;
190     Config cfg;
191     InputType minInput;
192     InputType maxInput;
193     QHash<int, int> backReferenceMap;
194     QString headerFileName;
195 public:
196     struct TransitionSequence
197     {
TransitionSequenceTransitionSequence198         inline TransitionSequence() : first(-1), last(-1), transition(-1) {}
199         InputType first;
200         InputType last;
201         int transition;
202         QString testFunction;
203     };
204 private:
205     QVector<TransitionSequence> charFunctionRanges;
206 };
207 
208 #endif
209