rewirte compileblockmain
parent
eac137e3c8
commit
e5cf9452f2
185
src/cs_parser.cc
185
src/cs_parser.cc
|
@ -593,7 +593,10 @@ lookup_id:
|
||||||
lookup_invalid(gs, ltype);
|
lookup_invalid(gs, ltype);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parses @... macro substitutions within block strings */
|
/* parses @... macro substitutions within block strings
|
||||||
|
*
|
||||||
|
* only called from within parse_blockarg
|
||||||
|
*/
|
||||||
bool parser_state::parse_subblock() {
|
bool parser_state::parse_subblock() {
|
||||||
charbuf lookup{ts};
|
charbuf lookup{ts};
|
||||||
switch (current()) {
|
switch (current()) {
|
||||||
|
@ -646,130 +649,158 @@ lookup_id:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileblockmain(parser_state &gs, int wordtype) {
|
/* [...] argument parser */
|
||||||
char const *start = gs.source;
|
void parser_state::parse_blockarg(int ltype) {
|
||||||
size_t curline = gs.current_line;
|
char const *start = source;
|
||||||
int concs = 0;
|
/* current bracket level */
|
||||||
for (int brak = 1; brak;) {
|
std::size_t blevel = 1;
|
||||||
switch (gs.skip_until("@\"/[]")) {
|
std::size_t curline = current_line;
|
||||||
|
/* number of strings to concatenate */
|
||||||
|
std::size_t concs = 0;
|
||||||
|
while (blevel > 0) {
|
||||||
|
/* skip until a significant character */
|
||||||
|
switch (skip_until("@\"/[]")) {
|
||||||
|
/* EOS */
|
||||||
case '\0':
|
case '\0':
|
||||||
throw error{*gs.ts.pstate, "missing \"]\""};
|
throw error{*ts.pstate, "missing \"]\""};
|
||||||
return;
|
/* inner string, parse through it */
|
||||||
case '\"':
|
case '\"':
|
||||||
gs.get_str();
|
get_str();
|
||||||
break;
|
break;
|
||||||
|
/* possibly a comment */
|
||||||
case '/':
|
case '/':
|
||||||
gs.next_char();
|
next_char();
|
||||||
if (gs.current() == '/') {
|
if (current() == '/') {
|
||||||
gs.skip_until('\n');
|
/* yup, just go until we reach a newline */
|
||||||
|
skip_until('\n');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
/* keep it nice and balanced */
|
||||||
case '[':
|
case '[':
|
||||||
gs.next_char();
|
next_char();
|
||||||
brak++;
|
++blevel;
|
||||||
break;
|
break;
|
||||||
case ']':
|
case ']':
|
||||||
gs.next_char();
|
next_char();
|
||||||
brak--;
|
--blevel;
|
||||||
break;
|
break;
|
||||||
|
/* macro substitution */
|
||||||
case '@': {
|
case '@': {
|
||||||
char const *esc = gs.source;
|
char const *end = source;
|
||||||
int level = 0;
|
std::size_t alevel = 0;
|
||||||
while (gs.current() == '@') {
|
while (current() == '@') {
|
||||||
++level;
|
++alevel;
|
||||||
gs.next_char();
|
next_char();
|
||||||
}
|
}
|
||||||
if (brak > level) {
|
if (blevel > alevel) {
|
||||||
continue;
|
/* deeper block level than macro level
|
||||||
} else if (brak < level) {
|
* we can't substitute at this point so leave it alone
|
||||||
throw error{*gs.ts.pstate, "too many @s"};
|
*/
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
gs.gs.gen_val_block(std::string_view{start, esc});
|
if (blevel < alevel) {
|
||||||
concs++;
|
/* shallower block level than macro level
|
||||||
if (gs.parse_subblock()) {
|
* this is an error, we can't substitute this
|
||||||
concs++;
|
*/
|
||||||
|
throw error{*ts.pstate, "too many @s"};
|
||||||
|
}
|
||||||
|
/* generate a block string for everything until now */
|
||||||
|
if (start != end) {
|
||||||
|
gs.gen_val_block(std::string_view{start, end});
|
||||||
|
++concs;
|
||||||
|
}
|
||||||
|
if (parse_subblock()) {
|
||||||
|
++concs;
|
||||||
}
|
}
|
||||||
if (concs) {
|
if (concs) {
|
||||||
start = gs.source;
|
start = source;
|
||||||
curline = gs.current_line;
|
curline = current_line;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* actually unreachable, we handle all incl. EOS */
|
||||||
default:
|
default:
|
||||||
gs.next_char();
|
next_char();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (gs.source - 1 > start) {
|
if ((source - 1) <= start) {
|
||||||
if (!concs) {
|
/* possibly empty */
|
||||||
switch (wordtype) {
|
goto done;
|
||||||
case VAL_POP:
|
}
|
||||||
return;
|
/* non-empty */
|
||||||
case VAL_CODE:
|
if (!concs) {
|
||||||
case VAL_COND: {
|
/* one contiguous string */
|
||||||
auto ret = gs.gs.gen_block(std::string_view{
|
switch (ltype) {
|
||||||
start, gs.send
|
case VAL_POP:
|
||||||
}, curline, VAL_NULL, ']');
|
/* ignore */
|
||||||
gs.source = ret.second.data();
|
return;
|
||||||
gs.send = ret.second.data() + ret.second.size();
|
case VAL_CODE:
|
||||||
gs.current_line = ret.first;
|
case VAL_COND: {
|
||||||
return;
|
/* compile */
|
||||||
}
|
auto ret = gs.gen_block(
|
||||||
case VAL_IDENT:
|
std::string_view{start, send}, curline, VAL_NULL, ']'
|
||||||
gs.gs.gen_val_ident(std::string_view{
|
);
|
||||||
start, std::size_t((gs.source - 1) - start)
|
source = ret.second.data();
|
||||||
});
|
send = source + ret.second.size();
|
||||||
return;
|
current_line = ret.first;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
case VAL_IDENT:
|
||||||
gs.gs.gen_val_block(std::string_view{start, gs.source - 1});
|
gs.gen_val_ident(std::string_view{start, source - 1});
|
||||||
if (concs > 1) {
|
return;
|
||||||
concs++;
|
default:
|
||||||
|
gs.gen_val_block(std::string_view{start, source - 1});
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gs.gs.gen_concat(concs, false, wordtype);
|
gs.gen_val_block(std::string_view{start, source - 1});
|
||||||
switch (wordtype) {
|
/* concat the pieces */
|
||||||
|
gs.gen_concat(++concs, false, ltype);
|
||||||
|
done:
|
||||||
|
bool got_val = (concs || ((source - 1) > start));
|
||||||
|
/* handle the result */
|
||||||
|
switch (ltype) {
|
||||||
case VAL_POP:
|
case VAL_POP:
|
||||||
if (concs || gs.source - 1 > start) {
|
if (got_val) {
|
||||||
gs.gs.gen_pop();
|
gs.gen_pop();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VAL_COND:
|
case VAL_COND:
|
||||||
if (!concs && gs.source - 1 <= start) {
|
if (!got_val) {
|
||||||
gs.gs.gen_val_null();
|
gs.gen_val_null();
|
||||||
} else {
|
} else {
|
||||||
gs.gs.gen_compile(true);
|
gs.gen_compile(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VAL_CODE:
|
case VAL_CODE:
|
||||||
if (!concs && gs.source - 1 <= start) {
|
if (!got_val) {
|
||||||
gs.gs.gen_block();
|
gs.gen_block();
|
||||||
} else {
|
} else {
|
||||||
gs.gs.gen_compile();
|
gs.gen_compile();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VAL_IDENT:
|
case VAL_IDENT:
|
||||||
if (!concs && gs.source - 1 <= start) {
|
if (!got_val) {
|
||||||
gs.gs.gen_val_ident();
|
gs.gen_val_ident();
|
||||||
} else {
|
} else {
|
||||||
gs.gs.gen_ident_lookup();
|
gs.gen_ident_lookup();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VAL_STRING:
|
case VAL_STRING:
|
||||||
case VAL_NULL:
|
case VAL_NULL:
|
||||||
case VAL_ANY:
|
case VAL_ANY:
|
||||||
case VAL_WORD:
|
case VAL_WORD:
|
||||||
if (!concs && gs.source - 1 <= start) {
|
if (!got_val) {
|
||||||
gs.gs.gen_val_string();
|
gs.gen_val_string();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (!concs) {
|
if (!concs) {
|
||||||
if (gs.source - 1 <= start) {
|
if ((source - 1) <= start) {
|
||||||
gs.gs.gen_val(wordtype);
|
gs.gen_val(ltype);
|
||||||
} else {
|
} else {
|
||||||
gs.gs.gen_force(wordtype);
|
gs.gen_force(ltype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -852,7 +883,7 @@ static bool compilearg(
|
||||||
}
|
}
|
||||||
case '[':
|
case '[':
|
||||||
gs.next_char();
|
gs.next_char();
|
||||||
compileblockmain(gs, wordtype);
|
gs.parse_blockarg(wordtype);
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
switch (wordtype) {
|
switch (wordtype) {
|
||||||
|
|
|
@ -70,6 +70,7 @@ struct parser_state {
|
||||||
|
|
||||||
void parse_lookup(int ltype);
|
void parse_lookup(int ltype);
|
||||||
bool parse_subblock();
|
bool parse_subblock();
|
||||||
|
void parse_blockarg(int ltype);
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace cubescript */
|
} /* namespace cubescript */
|
||||||
|
|
Loading…
Reference in New Issue