this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
3/*
4 * Main authors:
5 * Kevin Leo <kevin.leo@monash.edu>
6 */
7
8/* This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
11
12#include <minizinc/MIPdomains.hh>
13#include <minizinc/astexception.hh>
14#include <minizinc/astiterator.hh>
15#include <minizinc/builtins.hh>
16#include <minizinc/copy.hh>
17#include <minizinc/eval_par.hh>
18#include <minizinc/flatten.hh>
19#include <minizinc/flatten_internal.hh>
20#include <minizinc/hash.hh>
21#include <minizinc/optimize.hh>
22#include <minizinc/parser.hh>
23#include <minizinc/passes/compile_pass.hh>
24#include <minizinc/prettyprinter.hh>
25#include <minizinc/timer.hh>
26#include <minizinc/typecheck.hh>
27
28#include <fstream>
29#include <utility>
30
31namespace MiniZinc {
32
33using std::string;
34using std::vector;
35
36Env* change_library(Env& e, vector<string>& includePaths, const string& globals_dir,
37 CompilePassFlags& compflags, bool verbose = false) {
38 GCLock lock;
39 CopyMap cm;
40 Model* m = e.envi().originalModel != nullptr ? e.envi().originalModel : e.envi().model;
41 auto* new_mod = new Model();
42 new_mod->setFilename(m->filename());
43 new_mod->setFilepath(m->filepath());
44
45 vector<string> new_includePaths;
46
47 if (std::find(includePaths.begin(), includePaths.end(), globals_dir) == includePaths.end()) {
48 new_includePaths.push_back(globals_dir);
49 }
50 new_includePaths.insert(new_includePaths.end(), includePaths.begin(), includePaths.end());
51
52 // Collect include items
53 vector<ASTString> include_names;
54 for (Item* item : *m) {
55 if (auto* inc = item->dynamicCast<IncludeI>()) {
56 include_names.push_back(inc->m()->filepath());
57 } else {
58 new_mod->addItem(copy(e.envi(), cm, item));
59 }
60 }
61
62 std::stringstream ss;
63 for (auto& name : include_names) {
64 ss << "include \"" << Printer::escapeStringLit(name) << "\";";
65 }
66
67 vector<SyntaxError> syntax_errors;
68 Env* fenv = new Env(new_mod);
69 // Model* inc_mod = parse(*fenv, include_names, {}, new_includePaths, true, true, verbose,
70 // std::cerr);
71 std::ostringstream dummy_file;
72 dummy_file << m->filepath() << "_Dummy.mzn";
73 Model* inc_mod = parse_from_string(*fenv, ss.str(), dummy_file.str(), new_includePaths, false,
74 false, true, verbose, std::cerr, syntax_errors);
75 if (inc_mod == nullptr) {
76 for (const SyntaxError& se : syntax_errors) {
77 std::cerr << std::endl;
78 std::cerr << se.what() << ": " << se.msg() << std::endl;
79 std::cerr << se.loc() << std::endl;
80 }
81 return nullptr;
82 }
83 auto* new_inc = new IncludeI(Location().introduce(), string("MultiPassDummy.mzn"));
84 new_inc->m(inc_mod);
85 inc_mod->setParent(new_mod);
86 new_mod->addItem(new_inc);
87
88 return fenv;
89}
90
91CompilePass::CompilePass(Env* e, FlatteningOptions& opts, CompilePassFlags& cflags,
92 string globals_library, vector<string> include_paths, bool change_lib,
93 bool ignore_unknown)
94 : _env(e),
95 _fopts(opts),
96 _compflags(cflags),
97 _library(std::move(globals_library)),
98 _includePaths(std::move(include_paths)),
99 _changeLibrary(change_lib),
100 _ignoreUnknownIds(ignore_unknown) {}
101
102Env* CompilePass::run(Env* store, std::ostream& log) {
103 Timer lasttime;
104 if (_compflags.verbose) {
105 log << "\n\tCompilePass: Flatten with \'" << _library << "\' library ...\n";
106 }
107
108 Env* new_env;
109 if (_changeLibrary) {
110 new_env = change_library(*_env, _includePaths, _library, _compflags, _compflags.verbose);
111 if (new_env == nullptr) {
112 return nullptr;
113 }
114 new_env->envi().copyPathMapsAndState(store->envi());
115 } else {
116 new_env = _env;
117 }
118 new_env->envi().ignoreUnknownIds = _ignoreUnknownIds;
119
120 vector<TypeError> typeErrors;
121 MiniZinc::typecheck(*new_env, new_env->model(), typeErrors,
122 _compflags.modelCheckOnly || _compflags.modelInterfaceOnly,
123 _compflags.allowMultiAssign);
124 if (!typeErrors.empty()) {
125 std::ostringstream errstream;
126 for (auto& typeError : typeErrors) {
127 errstream << typeError.what() << ": " << typeError.msg() << std::endl;
128 errstream << typeError.loc() << std::endl;
129 }
130 throw Error(errstream.str());
131 }
132
133 register_builtins(*new_env);
134
135 try {
136 flatten(*new_env, _fopts);
137 } catch (LocationException& e) {
138 if (_compflags.verbose) {
139 log << std::endl;
140 }
141 std::ostringstream errstream;
142 errstream << e.what() << ": " << std::endl;
143 new_env->dumpErrorStack(errstream);
144 errstream << " " << e.msg() << std::endl;
145 throw Error(errstream.str());
146 }
147
148 if (!_compflags.noMIPdomains) {
149 if (_compflags.verbose) {
150 log << "MIP domains ...";
151 }
152 mip_domains(*new_env, _compflags.statistics);
153 if (_compflags.verbose) {
154 log << " done (" << lasttime.stoptime() << ")" << std::endl;
155 }
156 }
157
158 if (_compflags.optimize) {
159 if (_compflags.verbose) {
160 log << "Optimizing ...";
161 }
162 optimize(*new_env, _compflags.chainCompression);
163 if (_compflags.verbose) {
164 log << " done (" << lasttime.stoptime() << ")" << std::endl;
165 }
166 }
167
168 for (const auto& i : new_env->warnings()) {
169 log << (_compflags.werror ? "\n ERROR: " : "\n WARNING: ") << i;
170 }
171 if (_compflags.werror && !new_env->warnings().empty()) {
172 throw Error("errors encountered");
173 }
174 new_env->clearWarnings();
175
176 if (!_compflags.newfzn) {
177 if (_compflags.verbose) {
178 log << "Converting to old FlatZinc ...";
179 }
180 oldflatzinc(*new_env);
181 if (_compflags.verbose) {
182 log << " done (" << lasttime.stoptime() << ")" << std::endl;
183 }
184 } else {
185 new_env->flat()->compact();
186 new_env->output()->compact();
187 }
188
189 if (_compflags.verbose) {
190 log << " done (" << lasttime.stoptime() << ")" << std::endl;
191 }
192
193 return new_env;
194}
195
196CompilePass::~CompilePass(){};
197
198} // namespace MiniZinc