1 // astreplacement.h
2 // this file is part of Context Free
3 // ---------------------
4 // Copyright (C) 2011-2013 John Horigan - john@glyphic.com
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 //
20 // John Horigan can be contacted at john@glyphic.com or at
21 // John Horigan, 1209 Villa St., Mountain View, CA 94041-1123, USA
22 //
23 //
24 
25 
26 #ifndef INCLUDE_ASTREPLACEMENT_H
27 #define INCLUDE_ASTREPLACEMENT_H
28 
29 #include "ast.h"
30 #include "astexpression.h"
31 #include "location.hh"
32 #include "cfdg.h"
33 #include "rendererAST.h"
34 #include "shape.h"
35 #include "primShape.h"
36 #include <string>
37 #include <map>
38 #include <list>
39 #include <cstddef>
40 #include "CmdInfo.h"
41 #include "agg2/agg_path_storage.h"
42 
43 #include "json_fwd.hpp"
44 using json = nlohmann::json;
45 
46 namespace agg {
47     struct trans_affine;
48 }
49 
50 struct StackRule;
51 class Builder;
52 
53 namespace AST {
54     void to_json(json& j, const ASTparameter& m);
55 
56     class ASTreplacement {
57     public:
58         enum repElemListEnum { rule = 8, replacement = 4, mixed = 3, command = 2, op = 1, empty = 0 };
59         ASTruleSpecifier mShapeSpec;
60         int mRepType;
61         pathOpEnum mPathOp;
62         ASTmodification mChildChange;
63         yy::location mLocation;
64         void replace(Shape& s, RendererAST* r) const;
65 
66         ASTreplacement(const ASTreplacement&) = delete;
67         ASTreplacement(ruleSpec_ptr shapeSpec, mod_ptr mods,
68                        const yy::location& loc = CfdgError::Default,
69                        repElemListEnum t = replacement) noexcept;
70         ASTreplacement(mod_ptr mods, const yy::location& loc = CfdgError::Default,
71                        repElemListEnum t = replacement);
72         ASTreplacement(const std::string& s, const yy::location& loc);
73         virtual ~ASTreplacement();
74         virtual void traverse(const Shape& parent, bool tr, RendererAST* r) const;
75         virtual void compile(CompilePhase ph, Builder* b);
76         virtual void to_json(json& j) const;
77     };
78 
79     void to_json(json& j, const ASTreplacement& p);
80 
81     class ASTrepContainer {
82     public:
83         pathOpEnum mPathOp;
84         int mRepType;
85         ASTbody mBody;
86         ASTparameters mParameters;
87         bool isGlobal;
88 
ASTrepContainer()89         ASTrepContainer()
90         : mPathOp(unknownPathop), mRepType(ASTreplacement::empty),
91           isGlobal(false) {};
92         ASTrepContainer(const ASTrepContainer&) = delete;
93         ASTrepContainer& operator=(const ASTrepContainer&) = delete;
94         ASTrepContainer(ASTrepContainer&&) = delete;
95         ~ASTrepContainer();
96         void traverse(const Shape& parent, bool tr, RendererAST* r,
97                       bool getParams = false) const
98         {
99             std::size_t s = r->mStackSize;
100             if (getParams && parent.mParameters)
101                 r->initStack(parent.mParameters.get());
102             for (const rep_ptr& rep: mBody)
103                 rep->traverse(parent, tr, r);
104             r->unwindStack(s, mParameters);
105         }
106         void compile(CompilePhase ph, Builder* b, ASTloop* loop = nullptr, ASTdefine* def = nullptr);
107         void addParameter(const std::string& type, int index,
108                           const yy::location& typeLoc, const yy::location& nameLoc);
109         ASTparameter& addDefParameter(int index, ASTdefine* def,
110                           const yy::location& nameLoc, const yy::location& expLoc);
111         void addLoopParameter(int index, const yy::location& nameLoc);
112     };
113 
114     void to_json(json& j, const ASTrepContainer& p);
115 
116     class ASTloop final: public ASTreplacement {
117     public:
118         exp_ptr mLoopArgs;
119         mod_ptr mLoopModHolder;
120         std::array<double,3>  mLoopData;
121         ASTrepContainer mLoopBody;
122         ASTrepContainer mFinallyBody;
123         int mLoopIndexName;
124         std::string mLoopName;
125 
126         static void setupLoop(double& start, double& end, double& step,
127                               const ASTexpression* e, RendererAST* rti = nullptr);
128 
129         ASTloop(int nameIndex, const std::string& name, const yy::location& nameLoc,
130                 exp_ptr args, const yy::location& argsLoc,
131                 mod_ptr mods);
132         ~ASTloop() final;
133         void traverse(const Shape& parent, bool tr, RendererAST* r) const final;
134         void compile(CompilePhase ph, Builder* b) final;
135         void compileLoopMod(Builder* b);
136         void to_json(json& j) const final;
137     };
138     class ASTtransform: public ASTreplacement {
139     public:
140         ASTrepContainer mBody;
141         exp_ptr mExpHolder;              // strong pointer
142         bool mClone;
143 
144         ASTtransform(const yy::location& loc, exp_ptr mods);
145         ~ASTtransform() final;
146         void traverse(const Shape& parent, bool tr, RendererAST* r) const final;
147         void compile(CompilePhase ph, Builder* b) final;
148         void to_json(json& j) const final;
149     };
150     class ASTif final: public ASTreplacement {
151     public:
152         exp_ptr mCondition;
153         ASTrepContainer mThenBody;
154         ASTrepContainer mElseBody;
155 
156         ASTif(exp_ptr ifCond, const yy::location& condLoc);
157         ~ASTif() final;
158         void traverse(const Shape& parent, bool tr, RendererAST* r) const final;
159         void compile(CompilePhase ph, Builder* b) final;
160         void to_json(json& j) const final;
161     };
162 
163     class ASTswitch final: public ASTreplacement {
164     public:
165         using caseType = std::int64_t;
166         using caseRange = std::pair<caseType, caseType>;
167         struct compareRange {
operatorcompareRange168             bool operator()(const caseRange& a, const caseRange& b) const {
169                 return a.second < b.first;
170             }
171         };
172         using switchMap = std::map<caseRange, const ASTrepContainer*, compareRange>;
173 
174         exp_ptr mSwitchExp;
175         switchMap mCaseMap;
176         std::vector<std::pair<exp_ptr, cont_ptr>> mCases;
177         ASTrepContainer mElseBody;
178 
179         ASTswitch(exp_ptr switchExp, const yy::location& expLoc);
180         ~ASTswitch() final;
181         void traverse(const Shape& parent, bool tr, RendererAST* r) const final;
182         void compile(CompilePhase ph, Builder* b) final;
183 
184         void unify();
185         void to_json(json& j) const final;
186     };
187     class ASTdefine final : public ASTreplacement {
188     public:
189         enum define_t { StackDefine, ConstDefine, ConfigDefine, FunctionDefine, LetDefine };
190         define_t mDefineType;
191         exp_ptr mExpression;
192         int mTuplesize;
193         AST::expType mType;
194         bool isNatural;
195         ASTparameters mParameters;
196         unsigned mParamSize;
197         std::string mName;
198         int mConfigDepth;
199 
200         ASTdefine(std::string& name, const yy::location& loc);
201         void traverse(const Shape& parent, bool tr, RendererAST* r) const final;
202         void compile(CompilePhase ph, Builder* b) final;
203         ~ASTdefine() final = default;
204         ASTdefine& operator=(const ASTdefine&) = delete;
205         void to_json(json& j) const final;
206     };
207     class ASTrule final : public ASTreplacement {
208     public:
209         enum WeightTypes { NoWeight = 1, PercentWeight = 2, ExplicitWeight = 4};
210         ASTrepContainer mRuleBody;
211         mutable cpath_ptr mCachedPath;
212         double mWeight;
213         bool isPath;
214         int mNameIndex;
215         WeightTypes weightType;
216 
217         static bool compareLT(const ASTrule* a, const ASTrule* b);
218 
ASTrule(int ruleIndex,double weight,bool percent,const yy::location & loc)219         ASTrule(int ruleIndex, double weight, bool percent, const yy::location& loc)
220         : ASTreplacement(nullptr, loc, rule), mCachedPath(nullptr),
221           mWeight(weight <= 0.0 ? 1.0 : weight), isPath(false), mNameIndex(ruleIndex),
222           weightType(percent ? PercentWeight : ExplicitWeight) {
223               if (weight <= 0.0)
224                   CfdgError::Warning(loc, "Rule weight coerced to 1.0");
225           };
ASTrule(int ruleIndex,const yy::location & loc)226         ASTrule(int ruleIndex, const yy::location& loc)
227         : ASTreplacement(nullptr, loc, rule), mCachedPath(nullptr),
228           mWeight(1.0), isPath(false), mNameIndex(ruleIndex), weightType(NoWeight) { };
229         ASTrule(int i);
230         ~ASTrule() final;
231         void traversePath(const Shape& parent, RendererAST* r) const;
232         void traverseRule(Shape& parent, RendererAST* r) const;
233         void traverse(const Shape& parent, bool tr, RendererAST* r) const final;
234         void compile(CompilePhase ph, Builder* b) final;
235         void to_json(json& j) const final;
236     };
237     class ASTpathOp final : public ASTreplacement {
238     public:
239         exp_ptr mArguments;
240         mod_ptr mOldStyleArguments;
241         int mArgCount;
242         int mFlags;
243 
244         ASTpathOp(const std::string& s, mod_ptr a, const yy::location& loc);
245         ASTpathOp(const std::string& s, exp_ptr a, const yy::location& loc);
246         ~ASTpathOp() final;
247         void traverse(const Shape& parent, bool tr, RendererAST* r) const final;
248         void compile(CompilePhase ph, Builder* b) final;
249     private:
250         void pathData(double* data, RendererAST* rti) const;
251         void pathDataConst(Builder* b);
252         void makePositional(Builder* b);
253         void checkArguments(Builder* b);
254     public:
255         void to_json(json& j) const final;
256     };
257     class ASTpathCommand final : public ASTreplacement {
258     public:
259         double  mMiterLimit;
260         double  mStrokeWidth;
261         exp_ptr mParameters;
262         int     mFlags;
263 
264         // Empty constructor
ASTpathCommand()265         ASTpathCommand() :
266         ASTreplacement(nullptr),
267         mMiterLimit(4.0), mStrokeWidth(0.1), mParameters(nullptr),
268         mFlags(CF_MITER_JOIN + CF_BUTT_CAP + CF_FILL)
269         {
270         }
271 
272         ASTpathCommand(const std::string& s, mod_ptr mods, exp_ptr params,
273                        const yy::location& loc);
274 
275         void traverse(const Shape& parent, bool tr, RendererAST* r) const final;
276         void compile(CompilePhase ph, Builder* b) final;
277         ~ASTpathCommand() final = default;
278         void to_json(json& j) const final;
279     private:
280         mutable CommandInfo mInfoCache;
281     };
282     class ASTcompiledPath {
283     public:
284         bool mCached;
285         agg::path_storage mPath;
286         InfoCache mCommandInfo;
287         ASTpathCommand mTerminalCommand;
288         bool mUseTerminal;
289         param_ptr mParameters;
290         CommandInfo::UIDtype mPathUID;
291 
292         void finish(bool setAttr, RendererAST* r);
293         void addPathOp(const ASTpathOp* pop, double data[6], const Shape& s,
294                        bool tr, RendererAST* r);
295 
296         ASTcompiledPath();
297         ~ASTcompiledPath();
298         static UIDdatatype NextPathUID();
299     private:
300         static CommandInfo::UIDtype GlobalPathUID;
301     };
302 }
303 
304 #endif //INCLUDE_ASTREPLACEMENT_H
305