45 using std::ostringstream;
49 DefaultIStreamBuilder::Build(
const string &filename,
50 std::ios_base::openmode mode)
const {
51 return unique_ptr<istream>(
new std::ifstream(filename, mode));
55 Interpreter::IsAbsolute(
const string &filename)
const {
56 return filename.length() > 0 && filename[0] ==
'/';
60 Interpreter::CanReadFile(
const string &filename)
const {
61 unique_ptr<istream> file = std::move(istream_builder_->Build(filename));
66 Interpreter::CanReadFile(
const string &f1,
const string &f2,
67 string *filename)
const {
68 if (CanReadFile(f1)) {
71 }
else if (CanReadFile(f2)) {
80 Interpreter::HasCycle(
const string &filename,
81 const vector<string> &filenames)
const {
82 for (
const string &f : filenames) {
91 Interpreter::Eval(
const string &filename) {
92 if (!CanReadFile(filename)) {
94 err_ss <<
"infact::Interpreter: error: cannot read file "
95 <<
"\"" << filename <<
"\" (or file does not exist)\n";
105 Interpreter::EvalFile(
const string &filename) {
106 filenames_.push_back(filename);
107 unique_ptr<istream> file =
108 std::move(istream_builder_->Build(curr_filename()));
110 filenames_.pop_back();
114 Interpreter::Import(StreamTokenizer &st) {
118 if (st.PeekTokenType() != StreamTokenizer::STRING) {
119 string expected_type =
120 string(StreamTokenizer::TypeName(StreamTokenizer::RESERVED_WORD));
121 string found_type = StreamTokenizer::TypeName(st.PeekTokenType());
122 WrongTokenTypeError(st, st.PeekTokenStart(), expected_type, found_type,
127 std::cerr <<
"infact::Interpreter: from file \"" << curr_filename()
128 <<
"\" importing \"" << st.Peek() <<
"\"\n";
132 string original_import_filename = st.Next();
133 string relative_import_filename = original_import_filename;
139 bool relative =
false;
140 if (!IsAbsolute(original_import_filename)) {
141 size_t slash_pos = curr_filename().rfind(
'/');
142 if (slash_pos != string::npos) {
143 string dirname = curr_filename().substr(0, slash_pos);
144 relative_import_filename = dirname +
'/' + original_import_filename;
149 string import_filename;
150 if (!CanReadFile(relative_import_filename, original_import_filename,
152 ostringstream err_ss;
153 err_ss <<
"infact::Interpreter: " << filestack(st, st.tellg())
154 <<
"error: cannot read file \"";
156 err_ss << relative_import_filename <<
"\" or \"";
158 err_ss << original_import_filename <<
"\" (or file does not exist)\n";
162 std::cerr <<
"infact::Interpreter: tested paths \""
163 << relative_import_filename <<
"\" and \""
164 << original_import_filename <<
"\" and found that \""
165 << import_filename <<
"\" exists and is readable\n";
169 if (HasCycle(import_filename, filenames_)) {
170 ostringstream err_ss;
171 err_ss <<
"infact::Interpreter: " << filestack(st, st.tellg())
172 <<
"attempted import of file \"" << import_filename <<
"\" "
173 <<
"from file \"" << curr_filename() <<
"\" introduces cycle";
179 EvalFile(import_filename);
181 if (st.Peek() !=
";") {
182 WrongTokenError(st, st.PeekTokenStart(),
";", st.Peek(),
191 Interpreter::Eval(StreamTokenizer &st) {
194 while (st.PeekTokenType() != StreamTokenizer::EOF_TYPE) {
195 #ifdef INFACT_THROW_EXCEPTIONS
198 StreamTokenizer::TokenType token_type = st.PeekTokenType();
200 if (token_type == StreamTokenizer::RESERVED_WORD && st.Peek() ==
"import") {
206 VarMapBase *varmap = env_->GetVarMapForType(st.Peek());
207 bool is_type_specifier = varmap !=
nullptr;
208 if (token_type != StreamTokenizer::IDENTIFIER && !is_type_specifier) {
209 string expected_type =
210 string(StreamTokenizer::TypeName(StreamTokenizer::IDENTIFIER)) +
211 " or type specifier";
212 string found_type = StreamTokenizer::TypeName(token_type);
213 WrongTokenTypeError(st, st.PeekTokenStart(), expected_type, found_type,
218 if (is_type_specifier) {
221 type = varmap->Name();
224 StreamTokenizer::TokenType token_type = st.PeekTokenType();
225 if (token_type != StreamTokenizer::IDENTIFIER) {
226 WrongTokenTypeError(st, st.PeekTokenStart(),
227 StreamTokenizer::IDENTIFIER, token_type, st.Peek());
231 string varname = st.Next();
234 token_type = st.PeekTokenType();
235 if (st.Peek() !=
"=") {
236 WrongTokenError(st, st.PeekTokenStart(),
"=", st.Peek(),
243 if (st.PeekTokenType() == StreamTokenizer::EOF_TYPE) {
244 ostringstream err_ss;
245 err_ss <<
"infact::Interpreter: " << filestack(st, st.tellg())
246 <<
"error: unexpected EOF";
251 env_->ReadAndSet(varname, st, type);
253 token_type = st.PeekTokenType();
254 if (st.Peek() !=
";") {
255 WrongTokenError(st, st.PeekTokenStart(),
";", st.Peek(),
260 #ifdef INFACT_THROW_EXCEPTIONS
262 catch (std::runtime_error &e) {
263 cerr <<
"infact::Interpreter: caught exception\n"
264 << filestack(st, st.tellg())
265 <<
"==================\n"
266 <<
"Exception message:\n"
267 <<
"==================\n" << e.what() <<
"\n"
277 Interpreter::filestack(StreamTokenizer &st,
size_t pos)
const {
278 ostringstream message;
279 message <<
"in file \"" << curr_filename() <<
"\" "
280 <<
"(stream pos: " << pos <<
")\n";
281 auto it = filenames_.rbegin();
282 if (it != filenames_.rend()) {
285 for (; it != filenames_.rend(); ++it) {
286 const string &filename = *it;
287 message <<
"\timported from \"" << filename <<
"\"\n";
289 string line = st.line();
290 message <<
"here:\n" << line <<
"\n";
291 if (st.PeekPrevTokenLineStart() <= pos) {
292 for (
int i = pos - st.PeekPrevTokenLineStart(); i > 0; --i) {
297 return message.str();
301 Interpreter::WrongTokenError(StreamTokenizer &st,
303 const string &expected,
305 StreamTokenizer::TokenType found_type)
const {
310 ostringstream err_ss;
311 err_ss <<
"infact::Interpreter: " << filestack(st, pos)
312 <<
"expected token \"" << expected <<
"\" but found \"" << found
313 <<
"\" (token type: " << StreamTokenizer::TypeName(found_type)
319 Interpreter::WrongTokenTypeError(StreamTokenizer &st,
321 StreamTokenizer::TokenType expected,
322 StreamTokenizer::TokenType found,
323 const string &token)
const {
324 WrongTokenTypeError(st, pos,
325 StreamTokenizer::TypeName(expected),
326 StreamTokenizer::TypeName(found),
331 Interpreter::WrongTokenTypeError(StreamTokenizer &st,
333 const string &expected_type,
334 const string &found_type,
335 const string &token)
const {
340 ostringstream err_ss;
341 err_ss <<
"infact::Interpreter: " << filestack(st, pos)
342 <<
"expected token type " << expected_type
343 <<
" but found " << found_type
344 <<
"; token=\"" << token <<
"\"";
Provides an interpreter for assigning primitives and Factory-constructible objects to named variables...
Provides an error handling function that optionally throws an exception.
void Error(const std::string &message)
Reports an error encountered during parsing and/or construction of an object.