Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
scriptparser.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2019 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
21
23
24#include <ql/errors.hpp>
25
26#include <boost/algorithm/string/replace.hpp>
27#include <boost/algorithm/string/trim.hpp>
28
29namespace ore {
30namespace data {
31
32std::ostream& operator<<(std::ostream& out, const ParserError& error) {
33 if (!error.stoppedParsingAt.initialised) {
34 out << "parsing succeeded";
35 } else {
36 out << "parsing stopped at " << to_string(error.stoppedParsingAt) << "\n";
37 if (error.expectedWhere.initialised) {
38 out << "expected " << error.expectedWhat << " in " << to_string(error.expectedWhere) << ":\n";
39 out << error.scriptCurrentLine << "\n";
40 out << std::string(std::max<Size>(error.expectedWhere.columnStart, 1) - 1, ' ') << "^--- here\n";
41 } else {
42 out << "remaining input is\n<<<<<<<<<<\n" << error.remainingInput << "\n>>>>>>>>>>\n";
43 }
44 }
45 return out;
46}
47
49 ScriptGrammarIterator first(script.begin()), iter = first, last(script.end());
50 ScriptGrammar grammar(first);
51 success_ = qi::phrase_parse(iter, last, grammar, boost::spirit::qi::space);
52 if (!success_ || iter != last) {
53 success_ = false;
55 LocationInfo(boost::spirit::get_line(iter), boost::spirit::get_column(first, iter),
56 boost::spirit::get_line(iter), boost::spirit::get_column(first, iter));
57 parserError_.remainingInput = std::string(iter, last);
58 if (grammar.hasError) {
61 boost::spirit::get_line(grammar.errorPos), boost::spirit::get_column(first, grammar.errorPos),
62 boost::spirit::get_line(grammar.errorPos), boost::spirit::get_column(first, grammar.errorPos));
63 parserError_.scriptContext = std::string(grammar.errorBegin, grammar.errorEnd);
64 parserError_.errorPos = std::distance(grammar.errorBegin, grammar.errorPos);
65 auto currentLine = boost::spirit::get_current_line(grammar.errorBegin, grammar.errorPos, grammar.errorEnd);
66 parserError_.scriptCurrentLine = std::string(currentLine.begin(), currentLine.end());
67 }
68 } else {
69 QL_REQUIRE(grammar.evalStack.size() == 1,
70 "ScriptParser: unexpected eval stack size (" << grammar.evalStack.size() << "), should be 1");
71 ast_ = grammar.evalStack.top();
72 QL_REQUIRE(ast_, "ScriptParser: ast is null");
73 }
74}
75
76std::string printCodeContext(std::string script, const ASTNode* loc, bool compact) {
77
78 if (!loc)
79 return "(script reference is not available)\n";
80
81 // assume we have either newline or return, but not return alone (old mac csv format?)
82 boost::replace_all(script, "\r", "");
83
84 auto l = loc->locationInfo;
85 if (l.lineEnd < l.lineStart || (l.lineEnd == l.lineStart && l.columnEnd <= l.columnStart))
86 return "(script reference invalid: " + to_string(l) + ")\n";
87
88 std::string res;
89 // if compact is true, we remove leading/trailing symbols used for DLOGGERSTREAM for cleaner error message in log
90 if (compact == false)
91 res += "<<<<<<<<<<\n";
92
93 Size pos = 0, currentLine = 1;
94 for (Size line = l.lineStart; line <= l.lineEnd; ++line) {
95 // look for the current line
96 while (pos < script.size() && currentLine < line) {
97 if (script[pos] == '\n')
98 ++currentLine;
99 ++pos;
100 }
101 if (pos == script.size())
102 break;
103 // look for the line end position in the current line
104 Size posLineEnd = pos;
105 while (posLineEnd < script.size() && script[posLineEnd] != '\n')
106 ++posLineEnd;
107 // add current line to the result
108 std::string curr = std::string(std::next(script.begin(), pos), std::next(script.begin(), posLineEnd));
109 if (compact) {
110 boost::algorithm::trim(curr);
111 res += curr + ' ';
112 } else {
113 res += curr + '\n';
114 }
115 // underline the relevant part of the current line
116 Size columnStart = 1, columnEnd = posLineEnd - pos + 1;
117 if (line == l.lineStart)
118 columnStart = l.columnStart;
119 if (line == l.lineEnd)
120 columnEnd = l.columnEnd;
121 if (columnEnd < columnStart)
122 return "(script reference internal error: columnEnd (" + std::to_string(columnEnd) +
123 ") should be >= columnStart (" + std::to_string(columnStart) + "))";
124 // adjust column start so that trailing spaces are not underlined
125 while (columnStart < columnEnd && pos + columnStart < script.size() &&
126 script[pos + std::max<Size>(columnStart, 1) - 1] == ' ')
127 ++columnStart;
128 if (compact == false)
129 res +=
130 std::string(std::max<Size>(columnStart, 1) - 1, ' ') + std::string(columnEnd - columnStart, '=') + '\n';
131 }
132
133 if (compact == false)
134 res += ">>>>>>>>>>\n";
135 return res;
136}
137
138} // namespace data
139} // namespace ore
std::string script
ScriptParser(const std::string &script)
payoff script grammar
@ data
Definition: log.hpp:77
Real error
Definition: utilities.cpp:65
std::ostream & operator<<(std::ostream &out, EquityReturnType t)
boost::spirit::line_pos_iterator< std::string::const_iterator > ScriptGrammarIterator
Definition: grammar.hpp:46
std::string printCodeContext(std::string script, const ASTNode *loc, bool compact)
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
Serializable Credit Default Swap.
Definition: namespaces.docs:23
script parser
LocationInfo locationInfo
Definition: ast.hpp:63
LocationInfo stoppedParsingAt
LocationInfo expectedWhere
std::string remainingInput
std::string scriptCurrentLine
ScriptGrammarIterator errorBegin
Definition: grammar.hpp:63
std::stack< ASTNodePtr > evalStack
Definition: grammar.hpp:65
ScriptGrammarIterator errorEnd
Definition: grammar.hpp:63
ScriptGrammarIterator errorPos
Definition: grammar.hpp:63
boost::spirit::info errorWhat
Definition: grammar.hpp:64
string conversion utilities