mirror of https://gitee.com/bigwinds/arangodb
237 lines
7.0 KiB
C++
237 lines
7.0 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief MR line editor
|
|
///
|
|
/// @file
|
|
///
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
|
|
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
|
|
///
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
/// you may not use this file except in compliance with the License.
|
|
/// You may obtain a copy of the License at
|
|
///
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
///
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
/// See the License for the specific language governing permissions and
|
|
/// limitations under the License.
|
|
///
|
|
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
|
///
|
|
/// @author Dr. Frank Celler
|
|
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
|
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "MRLineEditor.h"
|
|
|
|
|
|
#include "Basics/tri-strings.h"
|
|
#include "Utilities/ShellImplFactory.h"
|
|
|
|
|
|
|
|
#include "mruby.h"
|
|
#include "mruby/compile.h"
|
|
|
|
using namespace std;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- private functions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks if the code block is open
|
|
///
|
|
/// Copied from mirb.c
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int IsCodeBlockOpen (struct mrb_parser_state *parser)
|
|
{
|
|
int code_block_open = FALSE;
|
|
|
|
/* check for heredoc */
|
|
if (parser->parsing_heredoc != NULL) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (parser->heredoc_end_now) {
|
|
parser->heredoc_end_now = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
/* check if parser error are available */
|
|
if (0 < parser->nerr) {
|
|
const char *unexpected_end = "syntax error, unexpected $end";
|
|
const char *message = parser->error_buffer[0].message;
|
|
|
|
/* a parser error occur, we have to check if */
|
|
/* we need to read one more line or if there is */
|
|
/* a different issue which we have to show to */
|
|
/* the user */
|
|
|
|
if (strncmp(message, unexpected_end, strlen(unexpected_end)) == 0) {
|
|
code_block_open = TRUE;
|
|
}
|
|
else if (strcmp(message, "syntax error, unexpected keyword_end") == 0) {
|
|
code_block_open = FALSE;
|
|
}
|
|
else if (strcmp(message, "syntax error, unexpected tREGEXP_BEG") == 0) {
|
|
code_block_open = FALSE;
|
|
}
|
|
|
|
return code_block_open;
|
|
}
|
|
|
|
/* check for unterminated string */
|
|
if (parser->lex_strterm) return TRUE;
|
|
|
|
switch (parser->lstate) {
|
|
|
|
/* all states which need more code */
|
|
|
|
case EXPR_BEG:
|
|
/* an expression was just started, */
|
|
/* we can't end it like this */
|
|
code_block_open = TRUE;
|
|
break;
|
|
|
|
case EXPR_DOT:
|
|
/* a message dot was the last token, */
|
|
/* there has to come more */
|
|
code_block_open = TRUE;
|
|
break;
|
|
|
|
case EXPR_CLASS:
|
|
/* a class keyword is not enough! */
|
|
/* we need also a name of the class */
|
|
code_block_open = TRUE;
|
|
break;
|
|
|
|
case EXPR_FNAME:
|
|
/* a method name is necessary */
|
|
code_block_open = TRUE;
|
|
break;
|
|
|
|
case EXPR_VALUE:
|
|
/* if, elsif, etc. without condition */
|
|
code_block_open = TRUE;
|
|
break;
|
|
|
|
/* now all the states which are closed */
|
|
|
|
case EXPR_ARG:
|
|
/* an argument is the last token */
|
|
code_block_open = FALSE;
|
|
break;
|
|
|
|
/* all states which are unsure */
|
|
|
|
case EXPR_CMDARG:
|
|
break;
|
|
|
|
case EXPR_END:
|
|
/* an expression was ended */
|
|
break;
|
|
|
|
case EXPR_ENDARG:
|
|
/* closing parenthese */
|
|
break;
|
|
|
|
case EXPR_ENDFN:
|
|
/* definition end */
|
|
break;
|
|
case EXPR_MID:
|
|
/* jump keyword like break, return, ... */
|
|
break;
|
|
|
|
case EXPR_MAX_STATE:
|
|
/* don't know what to do with this token */
|
|
break;
|
|
|
|
default:
|
|
/* this state is unexpected! */
|
|
break;
|
|
}
|
|
|
|
return code_block_open;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- class MRCompleter
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- public methods
|
|
// -----------------------------------------------------------------------------
|
|
bool MRCompleter::isComplete (string const& source, size_t lineno, size_t column) {
|
|
char* text = TRI_DuplicateString(source.c_str());
|
|
|
|
mrb_state* mrb = mrb_open();
|
|
mrb_parser_state* parser = mrb_parser_new(mrb);
|
|
parser->s = text;
|
|
parser->send = text + source.size();
|
|
parser->capture_errors = 1;
|
|
parser->lineno = 1;
|
|
|
|
mrbc_context* cxt = mrbc_context_new(mrb);
|
|
cxt->capture_errors = 1;
|
|
|
|
mrb_parser_parse(parser, cxt);
|
|
bool codeBlockOpen = IsCodeBlockOpen(parser);
|
|
|
|
TRI_FreeString(TRI_CORE_MEM_ZONE, text);
|
|
|
|
mrbc_context_free(mrb, cxt);
|
|
mrb_parser_free(parser);
|
|
mrb_close(mrb);
|
|
|
|
return ! codeBlockOpen;
|
|
}
|
|
|
|
void MRCompleter::getAlternatives(char const *, vector<string> &) {
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- class MRLineEditor
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- constructors and destructors
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructs a new editor
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
MRLineEditor::MRLineEditor (mrb_state* mrb, string const& history)
|
|
: LineEditor(history), _current(), _completer() {
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- public methods
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- protected methods
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void MRLineEditor::initializeShell() {
|
|
ShellImplFactory factory;
|
|
_shellImpl = factory.buildShell(_history, &_completer);
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- END-OF-FILE
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Local Variables:
|
|
// mode: outline-minor
|
|
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
|
// End:
|