separate cs_parser.cc, drop cs_util.cc
parent
68b66c0b28
commit
4b6c284ea1
|
@ -12,7 +12,7 @@ namespace cscript {
|
||||||
std::string_view cs_gen_state::get_str() {
|
std::string_view cs_gen_state::get_str() {
|
||||||
size_t nl;
|
size_t nl;
|
||||||
char const *beg = source;
|
char const *beg = source;
|
||||||
source = util::parse_string(
|
source = cs_parse_string(
|
||||||
cs, std::string_view{source, std::size_t(send - source)}, nl
|
cs, std::string_view{source, std::size_t(send - source)}, nl
|
||||||
);
|
);
|
||||||
current_line += nl - 1;
|
current_line += nl - 1;
|
||||||
|
@ -92,7 +92,7 @@ void cs_gen_state::skip_comments() {
|
||||||
|
|
||||||
std::string_view cs_gen_state::get_word() {
|
std::string_view cs_gen_state::get_word() {
|
||||||
char const *beg = source;
|
char const *beg = source;
|
||||||
source = util::parse_word(
|
source = cs_parse_word(
|
||||||
cs, std::string_view{source, std::size_t(send - source)}
|
cs, std::string_view{source, std::size_t(send - source)}
|
||||||
);
|
);
|
||||||
return std::string_view{beg, std::size_t(source - beg)};
|
return std::string_view{beg, std::size_t(source - beg)};
|
||||||
|
@ -484,7 +484,7 @@ static bool compileblockstr(cs_gen_state &gs, char const *str, char const *send)
|
||||||
break;
|
break;
|
||||||
case '\"': {
|
case '\"': {
|
||||||
char const *start = str;
|
char const *start = str;
|
||||||
str = util::parse_string(
|
str = cs_parse_string(
|
||||||
gs.cs, std::string_view{str, send}
|
gs.cs, std::string_view{str, send}
|
||||||
);
|
);
|
||||||
memcpy(&buf[len], start, std::size_t(str - start));
|
memcpy(&buf[len], start, std::size_t(str - start));
|
||||||
|
|
|
@ -1,116 +1,115 @@
|
||||||
#include <cubescript/cubescript.hh>
|
#include <cubescript/cubescript.hh>
|
||||||
#include "cs_vm.hh"
|
|
||||||
#include "cs_strman.hh"
|
|
||||||
|
|
||||||
#include <cctype>
|
#include "cs_std.hh"
|
||||||
#include <cmath>
|
|
||||||
#include <iterator>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace cscript {
|
namespace cscript {
|
||||||
|
|
||||||
namespace util {
|
/* string/word parsers are also useful to have public */
|
||||||
LIBCUBESCRIPT_EXPORT char const *parse_string(
|
|
||||||
cs_state &cs, std::string_view str, size_t &nlines
|
LIBCUBESCRIPT_EXPORT char const *cs_parse_string(
|
||||||
) {
|
cs_state &cs, std::string_view str, size_t &nlines
|
||||||
size_t nl = 0;
|
) {
|
||||||
nlines = nl;
|
size_t nl = 0;
|
||||||
if (str.empty() || (str.front() != '\"')) {
|
nlines = nl;
|
||||||
return str.data();
|
if (str.empty() || (str.front() != '\"')) {
|
||||||
}
|
return str.data();
|
||||||
char const *beg = str.begin();
|
}
|
||||||
char const *end = str.end();
|
char const *beg = str.begin();
|
||||||
char const *orig = beg++;
|
char const *end = str.end();
|
||||||
++nl;
|
char const *orig = beg++;
|
||||||
while (beg != end) {
|
++nl;
|
||||||
switch (*beg) {
|
while (beg != end) {
|
||||||
case '\r':
|
switch (*beg) {
|
||||||
case '\n':
|
case '\r':
|
||||||
case '\"':
|
case '\n':
|
||||||
|
case '\"':
|
||||||
|
goto end;
|
||||||
|
case '^':
|
||||||
|
case '\\': {
|
||||||
|
bool needn = (*beg == '\\');
|
||||||
|
if (++beg == end) {
|
||||||
goto end;
|
goto end;
|
||||||
case '^':
|
}
|
||||||
case '\\': {
|
if ((*beg == '\r') || (*beg == '\n')) {
|
||||||
bool needn = (*beg == '\\');
|
char c = *beg++;
|
||||||
if (++beg == end) {
|
++nl;
|
||||||
goto end;
|
if ((beg != end) && (c == '\r') && (*beg == '\n')) {
|
||||||
}
|
|
||||||
if ((*beg == '\r') || (*beg == '\n')) {
|
|
||||||
char c = *beg++;
|
|
||||||
++nl;
|
|
||||||
if ((beg != end) && (c == '\r') && (*beg == '\n')) {
|
|
||||||
++beg;
|
|
||||||
}
|
|
||||||
} else if (needn) {
|
|
||||||
goto end;
|
|
||||||
} else {
|
|
||||||
++beg;
|
++beg;
|
||||||
}
|
}
|
||||||
continue;
|
} else if (needn) {
|
||||||
|
goto end;
|
||||||
|
} else {
|
||||||
|
++beg;
|
||||||
}
|
}
|
||||||
default:
|
continue;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
++beg;
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
++beg;
|
||||||
|
}
|
||||||
end:
|
end:
|
||||||
nlines = nl;
|
nlines = nl;
|
||||||
if ((beg == end) || (*beg != '\"')) {
|
if ((beg == end) || (*beg != '\"')) {
|
||||||
throw cs_error(
|
throw cs_error(
|
||||||
cs, "unfinished string '%s'",
|
cs, "unfinished string '%s'",
|
||||||
std::string_view{orig, std::size_t(beg - orig)}
|
std::string_view{orig, std::size_t(beg - orig)}
|
||||||
);
|
);
|
||||||
}
|
|
||||||
return ++beg;
|
|
||||||
}
|
}
|
||||||
|
return ++beg;
|
||||||
|
}
|
||||||
|
|
||||||
LIBCUBESCRIPT_EXPORT char const *parse_word(cs_state &cs, std::string_view str) {
|
LIBCUBESCRIPT_EXPORT char const *cs_parse_word(
|
||||||
char const *it = str.begin();
|
cs_state &cs, std::string_view str
|
||||||
char const *end = str.end();
|
) {
|
||||||
for (; it != end; ++it) {
|
char const *it = str.begin();
|
||||||
std::string_view chrs{"\"/;()[] \t\r\n"};
|
char const *end = str.end();
|
||||||
it = std::find_first_of(it, end, chrs.begin(), chrs.end());
|
for (; it != end; ++it) {
|
||||||
if (it == end) {
|
std::string_view chrs{"\"/;()[] \t\r\n"};
|
||||||
return it;
|
it = std::find_first_of(it, end, chrs.begin(), chrs.end());
|
||||||
}
|
if (it == end) {
|
||||||
switch (*it) {
|
return it;
|
||||||
case '"':
|
}
|
||||||
case ';':
|
switch (*it) {
|
||||||
case ' ':
|
case '"':
|
||||||
case '\t':
|
case ';':
|
||||||
case '\r':
|
case ' ':
|
||||||
case '\n':
|
case '\t':
|
||||||
return it;
|
case '\r':
|
||||||
case '/':
|
case '\n':
|
||||||
if (((end - it) > 1) && (it[1] == '/')) {
|
return it;
|
||||||
return it;
|
case '/':
|
||||||
}
|
if (((end - it) > 1) && (it[1] == '/')) {
|
||||||
break;
|
return it;
|
||||||
case '[':
|
}
|
||||||
++it;
|
break;
|
||||||
it = parse_word(cs, std::string_view{
|
case '[':
|
||||||
it, std::size_t(end - it)
|
++it;
|
||||||
});
|
it = cs_parse_word(cs, std::string_view{
|
||||||
if ((it == end) || (*it != ']')) {
|
it, std::size_t(end - it)
|
||||||
throw cs_error(cs, "missing \"]\"");
|
});
|
||||||
}
|
if ((it == end) || (*it != ']')) {
|
||||||
break;
|
throw cs_error(cs, "missing \"]\"");
|
||||||
case '(':
|
}
|
||||||
++it;
|
break;
|
||||||
it = parse_word(cs, std::string_view{
|
case '(':
|
||||||
it, std::size_t(end - it)
|
++it;
|
||||||
});
|
it = cs_parse_word(cs, std::string_view{
|
||||||
if ((it == end) || (*it != ')')) {
|
it, std::size_t(end - it)
|
||||||
throw cs_error(cs, "missing \")\"");
|
});
|
||||||
}
|
if ((it == end) || (*it != ')')) {
|
||||||
break;
|
throw cs_error(cs, "missing \")\"");
|
||||||
case ']':
|
}
|
||||||
case ')':
|
break;
|
||||||
return it;
|
case ']':
|
||||||
}
|
case ')':
|
||||||
|
return it;
|
||||||
}
|
}
|
||||||
return it;
|
|
||||||
}
|
}
|
||||||
} /* namespace util */
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* list parser public implementation */
|
||||||
|
|
||||||
LIBCUBESCRIPT_EXPORT bool cs_list_parser::parse() {
|
LIBCUBESCRIPT_EXPORT bool cs_list_parser::parse() {
|
||||||
skip_until_item();
|
skip_until_item();
|
||||||
|
@ -120,7 +119,7 @@ LIBCUBESCRIPT_EXPORT bool cs_list_parser::parse() {
|
||||||
switch (*p_input_beg) {
|
switch (*p_input_beg) {
|
||||||
case '"': {
|
case '"': {
|
||||||
char const *qi = p_input_beg;
|
char const *qi = p_input_beg;
|
||||||
p_input_beg = util::parse_string(*p_state, get_input());
|
p_input_beg = cs_parse_string(*p_state, get_input());
|
||||||
p_quoted_item = std::string_view{qi, p_input_beg};
|
p_quoted_item = std::string_view{qi, p_input_beg};
|
||||||
p_item = p_quoted_item.substr(1, p_quoted_item.size() - 2);
|
p_item = p_quoted_item.substr(1, p_quoted_item.size() - 2);
|
||||||
break;
|
break;
|
||||||
|
@ -143,7 +142,7 @@ LIBCUBESCRIPT_EXPORT bool cs_list_parser::parse() {
|
||||||
case '"':
|
case '"':
|
||||||
/* the quote is needed in str parsing */
|
/* the quote is needed in str parsing */
|
||||||
--p_input_beg;
|
--p_input_beg;
|
||||||
p_input_beg = util::parse_string(*p_state, get_input());
|
p_input_beg = cs_parse_string(*p_state, get_input());
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
if (
|
if (
|
||||||
|
@ -180,7 +179,7 @@ endblock:
|
||||||
case ']':
|
case ']':
|
||||||
return false;
|
return false;
|
||||||
default: {
|
default: {
|
||||||
char const *e = util::parse_word(*p_state, get_input());
|
char const *e = cs_parse_word(*p_state, get_input());
|
||||||
p_quoted_item = p_item = std::string_view{p_input_beg, e};
|
p_quoted_item = p_item = std::string_view{p_input_beg, e};
|
||||||
p_input_beg = e;
|
p_input_beg = e;
|
||||||
break;
|
break;
|
||||||
|
@ -230,28 +229,4 @@ LIBCUBESCRIPT_EXPORT void cs_list_parser::skip_until_item() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LIBCUBESCRIPT_EXPORT cs_strref value_list_concat(
|
|
||||||
cs_state &cs, std::span<cs_value> vals, std::string_view sep
|
|
||||||
) {
|
|
||||||
cs_charbuf buf{cs};
|
|
||||||
for (std::size_t i = 0; i < vals.size(); ++i) {
|
|
||||||
switch (vals[i].get_type()) {
|
|
||||||
case cs_value_type::INT:
|
|
||||||
case cs_value_type::FLOAT:
|
|
||||||
case cs_value_type::STRING:
|
|
||||||
std::ranges::copy(
|
|
||||||
cs_value{vals[i]}.force_str(), std::back_inserter(buf)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i == (vals.size() - 1)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
std::ranges::copy(sep, std::back_inserter(buf));
|
|
||||||
}
|
|
||||||
return cs_strref{cs, buf.str()};
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace cscript */
|
} /* namespace cscript */
|
|
@ -427,4 +427,30 @@ bool cs_stacked_value::pop() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* public utilities */
|
||||||
|
|
||||||
|
LIBCUBESCRIPT_EXPORT cs_strref cs_concat_values(
|
||||||
|
cs_state &cs, std::span<cs_value> vals, std::string_view sep
|
||||||
|
) {
|
||||||
|
cs_charbuf buf{cs};
|
||||||
|
for (std::size_t i = 0; i < vals.size(); ++i) {
|
||||||
|
switch (vals[i].get_type()) {
|
||||||
|
case cs_value_type::INT:
|
||||||
|
case cs_value_type::FLOAT:
|
||||||
|
case cs_value_type::STRING:
|
||||||
|
std::ranges::copy(
|
||||||
|
cs_value{vals[i]}.force_str(), std::back_inserter(buf)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == (vals.size() - 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::ranges::copy(sep, std::back_inserter(buf));
|
||||||
|
}
|
||||||
|
return cs_strref{cs, buf.str()};
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace cscript */
|
} /* namespace cscript */
|
||||||
|
|
|
@ -230,7 +230,7 @@ static inline void callcommand(
|
||||||
case 'C': {
|
case 'C': {
|
||||||
i = std::max(i + 1, numargs);
|
i = std::max(i + 1, numargs);
|
||||||
cs_value tv{cs};
|
cs_value tv{cs};
|
||||||
tv.set_str(value_list_concat(
|
tv.set_str(cs_concat_values(
|
||||||
cs, std::span{args, std::size_t(i)}, " "
|
cs, std::span{args, std::size_t(i)}, " "
|
||||||
));
|
));
|
||||||
static_cast<cs_command_impl *>(id)->call(
|
static_cast<cs_command_impl *>(id)->call(
|
||||||
|
@ -1146,7 +1146,7 @@ static uint32_t *runcode(cs_state &cs, uint32_t *code, cs_value &result) {
|
||||||
result.force_none();
|
result.force_none();
|
||||||
{
|
{
|
||||||
cs_value tv{cs};
|
cs_value tv{cs};
|
||||||
tv.set_str(value_list_concat(cs, std::span{
|
tv.set_str(cs_concat_values(cs, std::span{
|
||||||
&args[offset], callargs
|
&args[offset], callargs
|
||||||
}, " "));
|
}, " "));
|
||||||
id->call(cs, std::span<cs_value>{&tv, 1}, result);
|
id->call(cs, std::span<cs_value>{&tv, 1}, result);
|
||||||
|
@ -1165,7 +1165,7 @@ static uint32_t *runcode(cs_state &cs, uint32_t *code, cs_value &result) {
|
||||||
case CS_CODE_CONC_W | CS_RET_FLOAT:
|
case CS_CODE_CONC_W | CS_RET_FLOAT:
|
||||||
case CS_CODE_CONC_W | CS_RET_INT: {
|
case CS_CODE_CONC_W | CS_RET_INT: {
|
||||||
std::size_t numconc = op >> 8;
|
std::size_t numconc = op >> 8;
|
||||||
auto buf = value_list_concat(
|
auto buf = cs_concat_values(
|
||||||
cs, std::span{&args[numargs - numconc], numconc},
|
cs, std::span{&args[numargs - numconc], numconc},
|
||||||
((op & CS_CODE_OP_MASK) == CS_CODE_CONC) ? " " : ""
|
((op & CS_CODE_OP_MASK) == CS_CODE_CONC) ? " " : ""
|
||||||
);
|
);
|
||||||
|
@ -1181,7 +1181,7 @@ static uint32_t *runcode(cs_state &cs, uint32_t *code, cs_value &result) {
|
||||||
case CS_CODE_CONC_M | CS_RET_FLOAT:
|
case CS_CODE_CONC_M | CS_RET_FLOAT:
|
||||||
case CS_CODE_CONC_M | CS_RET_INT: {
|
case CS_CODE_CONC_M | CS_RET_INT: {
|
||||||
std::size_t numconc = op >> 8;
|
std::size_t numconc = op >> 8;
|
||||||
auto buf = value_list_concat(
|
auto buf = cs_concat_values(
|
||||||
cs, std::span{&args[numargs - numconc], numconc}
|
cs, std::span{&args[numargs - numconc], numconc}
|
||||||
);
|
);
|
||||||
numargs = numargs - numconc;
|
numargs = numargs - numconc;
|
||||||
|
|
|
@ -90,11 +90,11 @@ void cs_init_lib_string(cs_state &cs) {
|
||||||
});
|
});
|
||||||
|
|
||||||
cs.new_command("concat", "V", [](auto &ccs, auto args, auto &res) {
|
cs.new_command("concat", "V", [](auto &ccs, auto args, auto &res) {
|
||||||
res.set_str(value_list_concat(ccs, args, " "));
|
res.set_str(cs_concat_values(ccs, args, " "));
|
||||||
});
|
});
|
||||||
|
|
||||||
cs.new_command("concatword", "V", [](auto &ccs, auto args, auto &res) {
|
cs.new_command("concatword", "V", [](auto &ccs, auto args, auto &res) {
|
||||||
res.set_str(value_list_concat(ccs, args));
|
res.set_str(cs_concat_values(ccs, args));
|
||||||
});
|
});
|
||||||
|
|
||||||
cs.new_command("format", "V", [](auto &ccs, auto args, auto &res) {
|
cs.new_command("format", "V", [](auto &ccs, auto args, auto &res) {
|
||||||
|
|
|
@ -8,10 +8,10 @@ libcubescript_src = [
|
||||||
'cs_error.cc',
|
'cs_error.cc',
|
||||||
'cs_gen.cc',
|
'cs_gen.cc',
|
||||||
'cs_ident.cc',
|
'cs_ident.cc',
|
||||||
|
'cs_parser.cc',
|
||||||
'cs_state.cc',
|
'cs_state.cc',
|
||||||
'cs_std.cc',
|
'cs_std.cc',
|
||||||
'cs_strman.cc',
|
'cs_strman.cc',
|
||||||
'cs_util.cc',
|
|
||||||
'cs_val.cc',
|
'cs_val.cc',
|
||||||
'cs_vm.cc',
|
'cs_vm.cc',
|
||||||
'cubescript.cc',
|
'cubescript.cc',
|
||||||
|
|
Loading…
Reference in New Issue