diff --git a/lib/base/exception.cpp b/lib/base/exception.cpp index da5be3e35..5a13d2ea9 100644 --- a/lib/base/exception.cpp +++ b/lib/base/exception.cpp @@ -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) { } diff --git a/lib/base/exception.hpp b/lib/base/exception.hpp index a74aa045b..3270a332b 100644 --- a/lib/base/exception.hpp +++ b/lib/base/exception.hpp @@ -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); diff --git a/lib/cli/consolecommand.cpp b/lib/cli/consolecommand.cpp index 3f37dae7a..7e2c2c26e 100644 --- a/lib/cli/consolecommand.cpp +++ b/lib/cli/consolecommand.cpp @@ -80,22 +80,37 @@ int ConsoleCommand::Run(const po::variables_map& vm, const std::vector"; 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 > *, ConfigCompiler *, const char *err) +void yyerror(const YYLTYPE *locp, std::vector > *, 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 > *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 dlist; typedef std::pair 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 dlist; typedef std::pair 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, @$); } ; diff --git a/lib/config/configcompiler.cpp b/lib/config/configcompiler.cpp index 688206510..8b087c77b 100644 --- a/lib/config/configcompiler.cpp +++ b/lib/config/configcompiler.cpp @@ -39,7 +39,7 @@ std::vector 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(); } diff --git a/lib/config/configcompiler.hpp b/lib/config/configcompiler.hpp index dec32390b..b1f7697a8 100644 --- a/lib/config/configcompiler.hpp +++ b/lib/config/configcompiler.hpp @@ -118,6 +118,7 @@ private: public: bool m_Eof; + int m_OpenBraces; int m_IgnoreNewlines; std::ostringstream m_LexBuffer;