Implement line continuation for "icinga2 console"

fixes #8133
This commit is contained in:
Gunnar Beutner 2015-02-10 13:27:02 +01:00
parent 2de89fe8d4
commit 0490fe73f7
6 changed files with 74 additions and 24 deletions

View File

@ -208,8 +208,8 @@ ScriptError::ScriptError(const String& message)
: m_Message(message)
{ }
ScriptError::ScriptError(const String& message, const DebugInfo& di)
: m_Message(message), m_DebugInfo(di)
ScriptError::ScriptError(const String& message, const DebugInfo& di, bool incompleteExpr)
: m_Message(message), m_DebugInfo(di), m_IncompleteExpr(incompleteExpr)
{ }
ScriptError::~ScriptError(void) throw()
@ -225,6 +225,11 @@ DebugInfo ScriptError::GetDebugInfo(void) const
return m_DebugInfo;
}
bool ScriptError::IsIncompleteExpression(void) const
{
return m_IncompleteExpr;;
}
posix_error::posix_error(void)
: m_Message(NULL)
{ }

View File

@ -50,16 +50,18 @@ class I2_BASE_API ScriptError : virtual public user_error
{
public:
ScriptError(const String& message);
ScriptError(const String& message, const DebugInfo& di);
ScriptError(const String& message, const DebugInfo& di, bool incompleteExpr = false);
~ScriptError(void) throw();
virtual const char *what(void) const throw();
DebugInfo GetDebugInfo(void) const;
bool IsIncompleteExpression(void) const;
private:
String m_Message;
DebugInfo m_DebugInfo;
bool m_IncompleteExpr;
};
I2_BASE_API StackTrace *GetLastExceptionStack(void);

View File

@ -80,22 +80,37 @@ int ConsoleCommand::Run(const po::variables_map& vm, const std::vector<std::stri
String fileName = "<" + Convert::ToString(next_line) + ">";
next_line++;
bool continuation = false;
std::string command;
incomplete:
std::cout << ConsoleColorTag(Console_ForegroundCyan)
<< fileName
<< ConsoleColorTag(Console_ForegroundRed)
<< " => "
<< ConsoleColorTag(Console_Normal);
<< ConsoleColorTag(Console_ForegroundRed);
if (!continuation)
std::cout << " => ";
else
std::cout << " .. ";
std::cout << ConsoleColorTag(Console_Normal);
std::string line;
std::getline(std::cin, line);
if (!command.empty())
command += "\n";
command += line;
if (addr.IsEmpty()) {
Expression *expr;
try {
lines[fileName] = line;
lines[fileName] = command;
expr = ConfigCompiler::CompileText(fileName, line);
expr = ConfigCompiler::CompileText(fileName, command);
if (expr) {
Value result = expr->Evaluate(frame);
@ -107,6 +122,11 @@ int ConsoleCommand::Run(const po::variables_map& vm, const std::vector<std::stri
std::cout << ConsoleColorTag(Console_Normal) << "\n";
}
} catch (const ScriptError& ex) {
if (ex.IsIncompleteExpression()) {
continuation = true;
goto incomplete;
}
DebugInfo di = ex.GetDebugInfo();
if (lines.find(di.Path) != lines.end()) {

View File

@ -236,9 +236,10 @@ int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
extern int yydebug;
void yyerror(const YYLTYPE *locp, std::vector<std::pair<Expression *, EItemInfo> > *, ConfigCompiler *, const char *err)
void yyerror(const YYLTYPE *locp, std::vector<std::pair<Expression *, EItemInfo> > *, ConfigCompiler *context, const char *err)
{
BOOST_THROW_EXCEPTION(ScriptError(err, *locp));
bool incomplete = context->m_Eof && (context->m_OpenBraces > 0);
BOOST_THROW_EXCEPTION(ScriptError(err, *locp, incomplete));
}
int yyparse(std::vector<std::pair<Expression *, EItemInfo> > *llist, ConfigCompiler *context);
@ -372,11 +373,13 @@ type: T_TYPE identifier
typerulelist: '{'
{
context->m_OpenBraces++;
context->m_RuleLists.push(new TypeRuleList());
}
typerules
'}'
{
context->m_OpenBraces--;
$$ = new Value(context->m_RuleLists.top());
context->m_RuleLists.pop();
}
@ -681,46 +684,65 @@ rterm_items_inner: rterm
}
;
rterm_array: '[' newlines rterm_items ']'
rterm_array: '['
{
context->m_OpenBraces++;
}
newlines rterm_items ']'
{
context->m_OpenBraces--;
$$ = new ArrayExpression(*$4, @$);
delete $4;
}
| '['
{
context->m_OpenBraces++;
}
rterm_items ']'
{
$$ = new ArrayExpression(*$3, @$);
delete $3;
}
| '[' rterm_items ']'
{
$$ = new ArrayExpression(*$2, @$);
delete $2;
}
;
rterm_scope_require_side_effect: '{' statements '}'
rterm_scope_require_side_effect: '{'
{
context->m_OpenBraces++;
}
statements '}'
{
context->m_OpenBraces--;
std::vector<Expression *> dlist;
typedef std::pair<Expression *, EItemInfo> EListItem;
int num = 0;
BOOST_FOREACH(const EListItem& litem, *$2) {
BOOST_FOREACH(const EListItem& litem, *$3) {
if (!litem.second.SideEffect)
yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used.");
dlist.push_back(litem.first);
num++;
}
delete $2;
delete $3;
$$ = new DictExpression(dlist, @$);
}
;
rterm_scope: '{' statements '}'
rterm_scope: '{'
{
context->m_OpenBraces++;
}
statements '}'
{
context->m_OpenBraces--;
std::vector<Expression *> dlist;
typedef std::pair<Expression *, EItemInfo> EListItem;
int num = 0;
BOOST_FOREACH(const EListItem& litem, *$2) {
if (!litem.second.SideEffect && num != $2->size() - 1)
BOOST_FOREACH(const EListItem& litem, *$3) {
if (!litem.second.SideEffect && num != $3->size() - 1)
yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used.");
dlist.push_back(litem.first);
num++;
}
delete $2;
delete $3;
$$ = new DictExpression(dlist, @$);
}
;

View File

@ -39,7 +39,7 @@ std::vector<String> ConfigCompiler::m_IncludeSearchDirs;
* @param zone The zone.
*/
ConfigCompiler::ConfigCompiler(const String& path, std::istream *input, const String& zone)
: m_Path(path), m_Input(input), m_Zone(zone), m_Eof(false), m_IgnoreNewlines(0)
: m_Path(path), m_Input(input), m_Zone(zone), m_Eof(false), m_IgnoreNewlines(0), m_OpenBraces(0)
{
InitializeScanner();
}

View File

@ -118,6 +118,7 @@ private:
public:
bool m_Eof;
int m_OpenBraces;
int m_IgnoreNewlines;
std::ostringstream m_LexBuffer;