Tasmota/lib/libesp32/berry/src/be_repl.c

107 lines
3.3 KiB
C

/********************************************************************
** Copyright (c) 2018-2020 Guan Wenliang
** This file is part of the Berry default interpreter.
** skiars@qq.com, https://github.com/Skiars/berry
** See Copyright Notice in the LICENSE file or at
** https://github.com/Skiars/berry/blob/master/LICENSE
********************************************************************/
#include "berry.h"
#include "be_repl.h"
#include <string.h>
#define safecall(func, ...) if (func) { func(__VA_ARGS__); }
#if BE_USE_SCRIPT_COMPILER
static int try_return(bvm *vm, const char *line)
{
int res, idx;
line = be_pushfstring(vm, "return (%s)", line);
idx = be_absindex(vm, -1); /* get the source text absolute index */
res = be_loadbuffer(vm, "stdin", line, strlen(line)); /* compile line */
be_remove(vm, idx); /* remove source string */
return res;
}
static bbool is_multline(bvm *vm)
{
const char *msg = be_tostring(vm, -1);
size_t len = strlen(msg);
if (len > 5) { /* multi-line text if the error message is 'EOS' at the end */
return !strcmp(msg + len - 5, "'EOS'");
}
return bfalse;
}
static int compile(bvm *vm, char *line, breadline getl, bfreeline freel)
{
int res = try_return(vm, line);
if (be_getexcept(vm, res) == BE_SYNTAX_ERROR) {
be_pop(vm, 2); /* pop exception values */
be_pushstring(vm, line);
safecall(freel, line); /* free line buffer */
for (;;) {
const char *src = be_tostring(vm, -1); /* get source code */
int idx = be_absindex(vm, -1); /* get the source text absolute index */
/* compile source line */
res = be_loadbuffer(vm, "stdin", src, strlen(src));
if (!res || !is_multline(vm)) {
be_remove(vm, idx); /* remove source code */
return res;
}
be_pop(vm, 2); /* pop exception values */
line = getl(">> "); /* read a new input line */
be_pushfstring(vm, "\n%s", line);
safecall(freel, line); /* free line buffer */
be_strconcat(vm, -2);
be_pop(vm, 1); /* pop new line */
}
} else {
safecall(freel, line); /* free line buffer */
}
return res;
}
static int call_script(bvm *vm)
{
int res = be_pcall(vm, 0); /* call the main function */
switch (res) {
case BE_OK: /* execution succeed */
if (!be_isnil(vm, -1)) { /* print return value when it's not nil */
be_dumpvalue(vm, -1);
}
be_pop(vm, 1); /* pop the result value */
break;
case BE_EXCEPTION: /* vm run error */
be_dumpexcept(vm);
be_pop(vm, 1); /* pop the function value */
break;
default: /* BE_EXIT or BE_MALLOC_FAIL */
return res;
}
return 0;
}
BERRY_API int be_repl(bvm *vm, breadline getline, bfreeline freeline)
{
char *line;
be_assert(getline != NULL);
while ((line = getline("> ")) != NULL) {
int res = compile(vm, line, getline, freeline);
if (res == BE_MALLOC_FAIL)
return BE_MALLOC_FAIL;
if (res) {
be_dumpexcept(vm);
} else { /* compiled successfully */
res = call_script(vm);
if (res) {
return res == BE_EXIT ? be_toindex(vm, -1) : res;
}
}
}
be_writenewline();
return 0;
}
#endif