Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

137 lines (117 sloc) 4.421 kB
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "formula.hpp"
#include "preprocessor.hpp"
#include "filesystem.hpp"
#include "json_parser.hpp"
#include "module.hpp"
#include "string_utils.hpp"
#include "variant_callable.hpp"
std::string preprocess(const std::string& input){
std::string output_string;
bool in_comment = false;
std::string::const_iterator i = input.begin();
while(i != input.end()){
if(*i == '#'){//enter a single-line comment
in_comment = true;}
if(*i == '\n' && in_comment){
in_comment = false;}
if(*i == '@' && !in_comment){
// process pre-processing directive here. See what comes after the '@' and do something appropriate
static const std::string IncludeString = "@include";
if(input.end() - i > IncludeString.size() && std::equal(IncludeString.begin(), IncludeString.end(), i)) {
std::string filename_string;
i += IncludeString.size(); //skip past the directive - we've tested that it exists
//test for an argument to @include - e.g. "filename.cfg". First the open quote:
std::string::const_iterator quote = std::find(i, input.end(), '"');
if(quote == input.end()) {
std::cerr << "We didn't find a opening quote. Syntax error." << std::endl;
}
if(std::count_if(i, quote, util::c_isspace) != quote - i) {
// # of whitespaces != number of intervening chars => something else was present. Syntax Error.
std::cerr << "# of whitespaces != number of intervening chars." << std::endl;
}
i = quote + 1; //we've found a quote, advance past it
//now the closing quote, and use it to find what's inbetween:
std::string::const_iterator endQuote = std::find(i, input.end(), '"');
if(endQuote == input.end()) {
std::cerr << "We didn't find a closing quote. Syntax error." << std::endl;
}
filename_string = std::string(i, endQuote);
i = endQuote + 1;
output_string += preprocess(sys::read_file(module::map_file(filename_string)));
}
} else {
//nothing special to process, just copy the chars across
output_string.push_back(*i);
}
++i;
}
return output_string;
}
variant preprocess_string_value(const std::string& input, const game_logic::formula_callable* callable)
{
if(input.empty() || input[0] != '@') {
return variant(input);
}
if(input.size() > 1 && input[1] == '@') {
//two @ at start of input just means a literal '@'.
return variant(std::string(input.begin()+1, input.end()));
}
if(input == "@base" || input == "@derive" || input == "@call" || input == "@flatten") {
return variant(input);
}
std::string::const_iterator i = std::find(input.begin(), input.end(), ' ');
const std::string directive(input.begin(), i);
if(directive == "@include") {
while(i != input.end() && *i == ' ') {
++i;
}
const std::string fname(i, input.end());
//Search for a colon, which indicates an expression after the filename.
std::string::const_iterator colon = std::find(fname.begin(), fname.end(), ':');
if(colon != fname.end() && std::count(fname.begin(), colon, ' ') == 0) {
const std::string file(fname.begin(), colon);
variant doc = json::parse_from_file(module::map_file(file));
const std::string expr(colon+1, fname.end());
const variant expr_variant(expr);
const game_logic::formula f(expr_variant);
game_logic::formula_callable* vars = new game_logic::map_formula_callable(doc);
const variant callable(vars);
if(vars) {
return f.execute(*vars);
}
}
std::vector<std::string> includes = util::split(fname, ' ');
if(includes.size() == 1) {
return json::parse_from_file(module::map_file(fname));
} else {
//treatment of a list of @includes is to make non-list items
//into singleton lists, and then concatenate all lists together.
std::vector<variant> res;
foreach(const std::string& inc, includes) {
variant v = json::parse_from_file(module::map_file(inc));
if(v.is_list()) {
foreach(const variant& item, v.as_list()) {
res.push_back(item);
}
} else {
res.push_back(v);
}
}
return variant(&res);
}
} else if(directive == "@eval") {
game_logic::formula f(variant(std::string(i, input.end())));
if(callable) {
return f.execute(*callable);
} else {
return f.execute();
}
} else {
throw preprocessor_error();
}
}
Jump to Line
Something went wrong with that request. Please try again.