mirror of
https://github.com/ganelson/inform.git
synced 2024-07-08 18:14:21 +03:00
1614 lines
54 KiB
OpenEdge ABL
1614 lines
54 KiB
OpenEdge ABL
[Ramification::] Ramification.
|
|
|
|
Turning textual code written in Inform 6 syntax into an inter schema.
|
|
|
|
@h Introduction.
|
|
Once //Tokenisation// has been done, we have an inter schema which is not
|
|
really a tree, but a linked list in all but name --
|
|
= (text)
|
|
EXPRESSION_ISNT
|
|
T1
|
|
T2
|
|
T3
|
|
T4
|
|
...
|
|
=
|
|
So, there is no internal structure yet. "Ramification" performs a series of
|
|
transformations on this tree, gradually shaking out the (sometimes ambiguous)
|
|
syntactic markers such as |COMMA_ISTT| and replacing them with semantically
|
|
clear subtrees.
|
|
|
|
=
|
|
void Ramification::go(inter_schema *sch) {
|
|
REPEATEDLY_APPLY(Ramification::implied_braces);
|
|
REPEATEDLY_APPLY(Ramification::unbrace_schema);
|
|
REPEATEDLY_APPLY(Ramification::divide_schema);
|
|
REPEATEDLY_APPLY(Ramification::undivide_schema);
|
|
REPEATEDLY_APPLY(Ramification::resolve_halfopen_blocks);
|
|
REPEATEDLY_APPLY(Ramification::break_early_bracings);
|
|
REPEATEDLY_APPLY(Ramification::strip_leading_white_space);
|
|
REPEATEDLY_APPLY(Ramification::split_switches_into_cases);
|
|
REPEATEDLY_APPLY(Ramification::strip_leading_white_space);
|
|
REPEATEDLY_APPLY(Ramification::split_print_statements);
|
|
REPEATEDLY_APPLY(Ramification::identify_constructs);
|
|
REPEATEDLY_APPLY(Ramification::treat_constructs);
|
|
REPEATEDLY_APPLY(Ramification::add_missing_bodies);
|
|
REPEATEDLY_APPLY(Ramification::remove_empties);
|
|
REPEATEDLY_APPLY(Ramification::outer_subexpressions);
|
|
REPEATEDLY_APPLY(Ramification::top_level_commas);
|
|
REPEATEDLY_APPLY(Ramification::alternatecases);
|
|
REPEATEDLY_APPLY(Ramification::outer_subexpressions);
|
|
REPEATEDLY_APPLY(Ramification::strip_all_white_space);
|
|
REPEATEDLY_APPLY(Ramification::debracket);
|
|
REPEATEDLY_APPLY(Ramification::implied_return_values);
|
|
REPEATEDLY_APPLY(Ramification::message_calls);
|
|
}
|
|
|
|
@ Each transformation will be applied until it returns |FALSE| to say that
|
|
it could see nothing to do, or |NOT_APPLICABLE| to say that it did but
|
|
that it doesn't want to be called again. Some transformations make use
|
|
of temporary markers attached to nodes or tokens in the tree, so we clear
|
|
these out at the start of each iteration.
|
|
|
|
@d REPEATEDLY_APPLY(X)
|
|
{
|
|
Ramification::unmark(sch->node_tree);
|
|
while (TRUE) {
|
|
int rv = X(NULL, sch->node_tree);
|
|
if (rv == FALSE) break;
|
|
LOGIF(SCHEMA_COMPILATION_DETAILS, "After round of " #X ":\n$1\n", sch);
|
|
if (rv == NOT_APPLICABLE) break;
|
|
}
|
|
}
|
|
|
|
=
|
|
void Ramification::unmark(inter_schema_node *isn) {
|
|
for (; isn; isn=isn->next_node) {
|
|
isn->node_marked = FALSE;
|
|
for (inter_schema_token *t = isn->expression_tokens; t; t=t->next) {
|
|
t->preinsert = 0;
|
|
t->postinsert = 0;
|
|
}
|
|
Ramification::unmark(isn->child_node);
|
|
}
|
|
}
|
|
|
|
@h The implied braces ramification.
|
|
In common with most C-like languages, though unlike Perl, Inform 6 makes braces
|
|
optional around code blocks which contain only a single statement. Thus:
|
|
= (text as Inform 6)
|
|
if (x == 1) print "x is 1.^";
|
|
=
|
|
is understood as if it were
|
|
= (text as Inform 6)
|
|
if (x == 1) { print "x is 1.^"; }
|
|
=
|
|
But we will find future ramifications much easier to code up if braces are
|
|
always used. So this one looks for cases where braces have been omitted,
|
|
and inserts them around the single statements in question.
|
|
|
|
=
|
|
int Ramification::implied_braces(inter_schema_node *par, inter_schema_node *at) {
|
|
for (inter_schema_node *isn = at; isn; isn=isn->next_node) {
|
|
for (inter_schema_token *t = isn->expression_tokens; t; t=t->next) {
|
|
if ((t->ist_type == RESERVED_ISTT) &&
|
|
((t->reserved_word == IF_I6RW) ||
|
|
(t->reserved_word == WHILE_I6RW) ||
|
|
(t->reserved_word == FOR_I6RW) ||
|
|
(t->reserved_word == SWITCH_I6RW) ||
|
|
(t->reserved_word == OBJECTLOOP_I6RW))) {
|
|
inter_schema_token *n = t->next;
|
|
int bl = 0;
|
|
while (n) {
|
|
if (n->ist_type == OPEN_ROUND_ISTT) bl++;
|
|
if (n->ist_type == CLOSE_ROUND_ISTT) {
|
|
bl--;
|
|
if (bl == 0) { n = n->next; break; }
|
|
}
|
|
n = n->next;
|
|
}
|
|
if ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
if ((n) && (n->ist_type != OPEN_BRACE_ISTT))
|
|
@<Make pre and post markers from here@>;
|
|
}
|
|
if ((t->ist_type == RESERVED_ISTT) &&
|
|
(t->reserved_word == ELSE_I6RW)) {
|
|
inter_schema_token *n = t->next;
|
|
if ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
if ((n) && (n->ist_type != OPEN_BRACE_ISTT))
|
|
@<Make pre and post markers from here@>;
|
|
}
|
|
}
|
|
}
|
|
|
|
int changed = TRUE, rounds = 0;
|
|
while (changed) {
|
|
changed = FALSE; rounds++;
|
|
for (inter_schema_node *isn = at; isn; isn=isn->next_node) {
|
|
for (inter_schema_token *t = isn->expression_tokens, *prev = NULL;
|
|
t; prev = t, t=t->next) {
|
|
if ((prev) && (t->preinsert > 0)) {
|
|
t->preinsert--;
|
|
inter_schema_token *open_b =
|
|
InterSchemas::new_token(OPEN_BRACE_ISTT, I"{", 0, 0, -1);
|
|
InterSchemas::add_token_after(open_b, prev);
|
|
changed = TRUE;
|
|
}
|
|
if (t->postinsert > 0) {
|
|
t->postinsert--;
|
|
inter_schema_token *close_b =
|
|
InterSchemas::new_token(CLOSE_BRACE_ISTT, I"}", 0, 0, -1);
|
|
InterSchemas::add_token_after(close_b, t);
|
|
changed = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (rounds > 1) return NOT_APPLICABLE;
|
|
return FALSE;
|
|
}
|
|
|
|
@<Make pre and post markers from here@> =
|
|
n->preinsert++;
|
|
int found_if = FALSE, brl = 0, posted = FALSE, upped = FALSE;
|
|
inter_schema_token *last_n = n;
|
|
while (n) {
|
|
if (n->ist_type == OPEN_BRACE_ISTT) { brl++; upped = TRUE; }
|
|
if (n->ist_type == CLOSE_BRACE_ISTT) brl--;
|
|
if (n->ist_type == OPEN_ROUND_ISTT) brl++;
|
|
if (n->ist_type == CLOSE_ROUND_ISTT) brl--;
|
|
if ((brl == 0) && (n->ist_type == RESERVED_ISTT) && (n->reserved_word == IF_I6RW))
|
|
found_if = TRUE;
|
|
if ((brl == 0) &&
|
|
((n->ist_type == DIVIDER_ISTT) ||
|
|
((upped) && (n->ist_type == CLOSE_BRACE_ISTT)))) {
|
|
inter_schema_token *m = n->next;
|
|
while ((m) && (m->ist_type == WHITE_SPACE_ISTT)) m = m->next;
|
|
if ((found_if == FALSE) || (m == NULL) || (m->ist_type != RESERVED_ISTT) ||
|
|
(m->reserved_word != ELSE_I6RW)) {
|
|
n->postinsert++; posted = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
last_n = n;
|
|
n = n->next;
|
|
}
|
|
if (posted == FALSE) {
|
|
last_n->postinsert++;
|
|
}
|
|
|
|
@h The unbrace schema ramification.
|
|
We now remove braces used to delimit code blocks and replace them with |CODE_ISNT|
|
|
subtrees. So for example
|
|
= (text)
|
|
EXPRESSION_ISNT
|
|
T1
|
|
OPEN_BRACE_ISTT
|
|
T2
|
|
T3
|
|
CLOSE_BRACE_ISTT
|
|
T4
|
|
=
|
|
becomes
|
|
= (text)
|
|
EXPRESSION_ISNT
|
|
T1
|
|
CODE_ISNT
|
|
EXPRESSION_ISNT
|
|
T2
|
|
T3
|
|
EXPRESSION_ISNT
|
|
T4
|
|
=
|
|
In this way, all matching pairs of |OPEN_BRACE_ISTT| and |CLOSE_BRACE_ISTT| tokens
|
|
are removed.
|
|
|
|
=
|
|
int Ramification::unbrace_schema(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (; isn; isn=isn->next_node) {
|
|
for (inter_schema_token *t = isn->expression_tokens, *prev = NULL; t; prev = t, t=t->next) {
|
|
if ((prev) && (t->ist_type == OPEN_BRACE_ISTT)) {
|
|
prev->next = NULL;
|
|
inter_schema_node *code_isn =
|
|
InterSchemas::new_node(isn->parent_schema, CODE_ISNT);
|
|
isn->child_node = code_isn;
|
|
code_isn->parent_node = isn;
|
|
|
|
inter_schema_node *new_isn =
|
|
InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
code_isn->child_node = new_isn;
|
|
new_isn->parent_node = code_isn;
|
|
|
|
prev = t; t = t->next;
|
|
while ((t) && (t->ist_type == WHITE_SPACE_ISTT)) { prev = t; t = t->next; }
|
|
|
|
new_isn->expression_tokens = t;
|
|
inter_schema_token *n = new_isn->expression_tokens, *pn = NULL;
|
|
int brl = 1;
|
|
while (n) {
|
|
if (n->ist_type == OPEN_BRACE_ISTT) brl++;
|
|
if (n->ist_type == CLOSE_BRACE_ISTT) brl--;
|
|
if (n->ist_type == OPEN_ROUND_ISTT) brl++;
|
|
if (n->ist_type == CLOSE_ROUND_ISTT) brl--;
|
|
n->owner = new_isn;
|
|
if (brl == 0) {
|
|
if (pn == NULL) new_isn->expression_tokens = NULL;
|
|
else pn->next = NULL;
|
|
break;
|
|
}
|
|
pn = n; n = n->next;
|
|
}
|
|
if (n) {
|
|
inter_schema_token *resumed = n->next;
|
|
n->next = NULL;
|
|
while ((resumed) && (resumed->ist_type == WHITE_SPACE_ISTT))
|
|
resumed = resumed->next;
|
|
if (resumed) {
|
|
inter_schema_node *new_isn =
|
|
InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
new_isn->expression_tokens = resumed;
|
|
new_isn->parent_node = isn->parent_node;
|
|
for (inter_schema_token *l = new_isn->expression_tokens; l; l=l->next) {
|
|
l->owner = new_isn;
|
|
}
|
|
inter_schema_node *saved = isn->next_node;
|
|
isn->next_node = new_isn;
|
|
new_isn->next_node = saved;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
if (Ramification::unbrace_schema(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
@h The divide schema ramification.
|
|
A |DIVIDER_ISTT| token represents a semicolon used to divide I6 statements.
|
|
We want to represent them, however, by independent subtrees. So:
|
|
= (text)
|
|
EXPRESSION_ISNT
|
|
T1
|
|
T2
|
|
DIVIDER_ISTT
|
|
T3
|
|
T4
|
|
DIVIDER_ISTT
|
|
=
|
|
becomes
|
|
= (text)
|
|
EXPRESSION_ISNT
|
|
T1
|
|
T2
|
|
DIVIDER_ISTT
|
|
EXPRESSION_ISNT
|
|
T3
|
|
T4
|
|
DIVIDER_ISTT
|
|
=
|
|
After this stage, therefore, each statement occupies its own |EXPRESSION_ISNT|.
|
|
|
|
=
|
|
int Ramification::divide_schema(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (; isn; isn=isn->next_node) {
|
|
int bl = 0;
|
|
for (inter_schema_token *t = isn->expression_tokens; t; t=t->next) {
|
|
if (t->ist_type == OPEN_ROUND_ISTT) bl++;
|
|
if (t->ist_type == CLOSE_ROUND_ISTT) bl--;
|
|
if ((bl == 0) && (t->ist_type == DIVIDER_ISTT) && (t->next)) {
|
|
inter_schema_node *new_isn = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
new_isn->expression_tokens = t->next;
|
|
new_isn->parent_node = isn->parent_node;
|
|
if (isn->child_node) {
|
|
new_isn->child_node = isn->child_node;
|
|
new_isn->child_node->parent_node = new_isn;
|
|
isn->child_node = NULL;
|
|
}
|
|
for (inter_schema_token *l = new_isn->expression_tokens; l; l=l->next) {
|
|
l->owner = new_isn;
|
|
}
|
|
inter_schema_node *saved = isn->next_node;
|
|
isn->next_node = new_isn;
|
|
new_isn->next_node = saved;
|
|
t->next = NULL;
|
|
return TRUE;
|
|
}
|
|
}
|
|
if (Ramification::divide_schema(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
@h The undivide schema ramification.
|
|
The expression nodes for statements now tend to end with |DIVIDER_ISTT| tokens
|
|
which no longer have any useful meaning. We remove them. For example:
|
|
= (text)
|
|
EXPRESSION_ISNT
|
|
T1
|
|
T2
|
|
DIVIDER_ISTT
|
|
EXPRESSION_ISNT
|
|
T3
|
|
T4
|
|
DIVIDER_ISTT
|
|
=
|
|
becomes
|
|
= (text)
|
|
EXPRESSION_ISNT
|
|
T1
|
|
T2
|
|
EXPRESSION_ISNT
|
|
T3
|
|
T4
|
|
=
|
|
After this, then, there are no further |DIVIDER_ISTT| tokens in the tree.
|
|
|
|
=
|
|
int Ramification::undivide_schema(inter_schema_node *par, inter_schema_node *isn) {
|
|
int rv = FALSE;
|
|
for (; isn; isn=isn->next_node) {
|
|
inter_schema_token *t = isn->expression_tokens;
|
|
if ((t) && (t->ist_type == DIVIDER_ISTT)) {
|
|
isn->expression_tokens = NULL;
|
|
isn->semicolon_terminated = TRUE;
|
|
rv = TRUE;
|
|
} else {
|
|
while ((t) && (t->next)) {
|
|
if (t->next->ist_type == DIVIDER_ISTT) {
|
|
t->next = NULL; isn->semicolon_terminated = TRUE; rv = TRUE; break;
|
|
}
|
|
t = t->next;
|
|
}
|
|
}
|
|
if (Ramification::undivide_schema(isn, isn->child_node)) rv = TRUE;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
@h The resolve halfopen blocks ramification.
|
|
At this point, all matching pairs of open and close braces have been removed.
|
|
But that doesn't quite solve the problem of code blocks, because an inline
|
|
phrase in Inform 7 can use the notations |{-open-brace}| or |{-close-brace}|
|
|
to indicate that a code block must be opened or closed, in a way which does
|
|
not pair up.
|
|
|
|
There is clearly no way for a tree structure to encode a half-open subtree,
|
|
so the schema itself has to have a special annotation made in this case, which
|
|
is done by calling //InterSchemas::mark_unclosed// or //InterSchemas::mark_unopened//.
|
|
It is inconvenient to delete the brace command node (we might end up with an
|
|
empty |EXPRESSION_ISNT| list), so instead we convert it to a harmless piece
|
|
of white space.
|
|
|
|
At the end of this process, then, all code blocks are correctly handled, and
|
|
all statements are held as single |EXPRESSION_ISNT| nodes. So the coarse
|
|
structure of the code is correctly handled -- we have a clear tree structure
|
|
of statements (or expressions), hierarchically arranged in code blocks.
|
|
|
|
=
|
|
int Ramification::resolve_halfopen_blocks(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (; isn; isn=isn->next_node) {
|
|
inter_schema_token *t = isn->expression_tokens;
|
|
while ((t) && (t->ist_type == WHITE_SPACE_ISTT)) t = t->next;
|
|
if ((t) && (t->ist_type == INLINE_ISTT) && (t->inline_command == open_brace_ISINC)) {
|
|
InterSchemas::mark_unclosed(isn);
|
|
t->ist_type = WHITE_SPACE_ISTT;
|
|
t->material = I" ";
|
|
return TRUE;
|
|
}
|
|
if ((t) && (t->ist_type == INLINE_ISTT) && (t->inline_command == close_brace_ISINC)) {
|
|
InterSchemas::mark_unopened(isn);
|
|
t->ist_type = WHITE_SPACE_ISTT;
|
|
t->material = I" ";
|
|
if (t->next) {
|
|
inter_schema_node *new_isn = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
new_isn->expression_tokens = t->next;
|
|
new_isn->parent_node = isn->parent_node;
|
|
if (isn->child_node) {
|
|
new_isn->child_node = isn->child_node;
|
|
new_isn->child_node->parent_node = new_isn;
|
|
isn->child_node = NULL;
|
|
}
|
|
for (inter_schema_token *l = new_isn->expression_tokens; l; l=l->next) {
|
|
l->owner = new_isn;
|
|
}
|
|
inter_schema_node *saved = isn->next_node;
|
|
isn->next_node = new_isn;
|
|
new_isn->next_node = saved;
|
|
t->next = NULL;
|
|
}
|
|
return TRUE;
|
|
}
|
|
if (Ramification::resolve_halfopen_blocks(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
@h The break early bracings ramification.
|
|
If an expression list begins with one or more braced commands, perhaps with some
|
|
white space, and then continues with some honest I6 material, we divide the
|
|
early commands off from the subsequent matter. Thus:
|
|
= (text)
|
|
EXPRESSION_ISNT
|
|
INLINE_ISTT
|
|
WHITE_SPACE_ISTT
|
|
INLINE_ISTT
|
|
WHITE_SPACE_ISTT
|
|
T1
|
|
T2
|
|
T3
|
|
=
|
|
becomes
|
|
= (text)
|
|
EXPRESSION_ISNT
|
|
INLINE_ISTT
|
|
WHITE_SPACE_ISTT
|
|
INLINE_ISTT
|
|
WHITE_SPACE_ISTT
|
|
EXPRESSION_ISNT
|
|
T1
|
|
T2
|
|
T3
|
|
=
|
|
|
|
=
|
|
int Ramification::break_early_bracings(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (; isn; isn=isn->next_node) {
|
|
inter_schema_token *n = isn->expression_tokens;
|
|
if (n) {
|
|
inter_schema_token *m = NULL;
|
|
while (Ramification::permitted_early(n)) {
|
|
m = n;
|
|
n = n->next;
|
|
}
|
|
if ((m) && (n) && (n->ist_type == RESERVED_ISTT)) {
|
|
inter_schema_node *new_isn =
|
|
InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
new_isn->expression_tokens = n;
|
|
new_isn->parent_node = isn->parent_node;
|
|
if (isn->child_node) {
|
|
new_isn->child_node = isn->child_node;
|
|
new_isn->child_node->parent_node = new_isn;
|
|
isn->child_node = NULL;
|
|
}
|
|
for (inter_schema_token *l = new_isn->expression_tokens; l; l=l->next) {
|
|
l->owner = new_isn;
|
|
}
|
|
inter_schema_node *saved = isn->next_node;
|
|
isn->next_node = new_isn;
|
|
new_isn->next_node = saved;
|
|
m->next = NULL;
|
|
return TRUE;
|
|
}
|
|
}
|
|
if (Ramification::break_early_bracings(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
int Ramification::permitted_early(inter_schema_token *n) {
|
|
if ((n) && (n->ist_type == INLINE_ISTT)) return TRUE;
|
|
if ((n) && (n->ist_type == WHITE_SPACE_ISTT)) return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
@h The strip leading white space ramification.
|
|
If an expression begins with white space, remove it. (This makes coding subsequent
|
|
ramifications easier -- because we can assume the first token is substantive.)
|
|
|
|
=
|
|
int Ramification::strip_leading_white_space(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (; isn; isn=isn->next_node) {
|
|
inter_schema_token *t = isn->expression_tokens;
|
|
if ((t) && (t->ist_type == WHITE_SPACE_ISTT)) {
|
|
isn->expression_tokens = t->next;
|
|
return TRUE;
|
|
}
|
|
if (Ramification::strip_leading_white_space(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
@h The split switches into cases ramification.
|
|
Unlike most C-like languages, Inform 6 does not have a |case| reserved word to
|
|
introduce cases in a |switch| statement. For example:
|
|
= (text as Inform 6)
|
|
switch (x) {
|
|
1, 2, 3: print "Do one thing.";
|
|
4: print "Do a different thing.";
|
|
default: print "Otherwise, do this other thing.";
|
|
}
|
|
=
|
|
Here, the colons and the reserved word |default| are the important syntactic markers.
|
|
We break this up as three code blocks:
|
|
= (text)
|
|
STATEMENT_ISNT "case"
|
|
EXPRESSION_ISNT
|
|
1
|
|
COMMA_ISTT
|
|
WHITE_SPACE_ISTT
|
|
2
|
|
COMMA_ISTT
|
|
WHITE_SPACE_ISTT
|
|
3
|
|
CODE_ISNT
|
|
...
|
|
STATEMENT_ISNT "case"
|
|
EXPRESSION_ISNT
|
|
4
|
|
CODE_ISNT
|
|
...
|
|
STATEMENT_ISNT "default"
|
|
CODE_ISNT
|
|
...
|
|
=
|
|
|
|
=
|
|
int Ramification::split_switches_into_cases(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (; isn; isn=isn->next_node) {
|
|
if (isn->expression_tokens) {
|
|
inter_schema_token *n = isn->expression_tokens, *prev = isn->expression_tokens;
|
|
int bl = 0;
|
|
while (n) {
|
|
if (n->ist_type == OPEN_ROUND_ISTT) bl++;
|
|
if (n->ist_type == CLOSE_ROUND_ISTT) bl--;
|
|
if ((n->ist_type == COLON_ISTT) && (bl == 0)) {
|
|
inter_schema_node *original_child = isn->child_node;
|
|
|
|
int defaulter = FALSE;
|
|
if ((isn->expression_tokens) &&
|
|
(isn->expression_tokens->ist_type == RESERVED_ISTT) &&
|
|
(isn->expression_tokens->reserved_word == DEFAULT_I6RW)) defaulter = TRUE;
|
|
|
|
inter_schema_node *sw_val = NULL;
|
|
inter_schema_node *sw_code = NULL;
|
|
if (defaulter) {
|
|
sw_code = InterSchemas::new_node(isn->parent_schema, CODE_ISNT);
|
|
isn->child_node = sw_code;
|
|
sw_code->parent_node = isn;
|
|
} else {
|
|
sw_val = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
sw_code = InterSchemas::new_node(isn->parent_schema, CODE_ISNT);
|
|
sw_val->next_node = sw_code;
|
|
sw_val->parent_node = isn; isn->child_node = sw_val;
|
|
sw_code->parent_node = isn;
|
|
}
|
|
|
|
int switch_begins = FALSE;
|
|
int switch_ends = FALSE;
|
|
inter_schema_node *pn = isn->parent_node;
|
|
while (pn) {
|
|
if ((pn->expression_tokens) &&
|
|
(pn->expression_tokens->ist_type == RESERVED_ISTT) &&
|
|
(pn->expression_tokens->reserved_word == SWITCH_I6RW)) {
|
|
switch_begins = TRUE;
|
|
inter_schema_node *pn2 = isn;
|
|
while (pn2) {
|
|
if (pn2->next_node) { switch_ends = TRUE; break; }
|
|
pn2 = pn2->parent_node;
|
|
}
|
|
break;
|
|
}
|
|
pn = pn->parent_node;
|
|
}
|
|
if (switch_ends == FALSE) InterSchemas::mark_unclosed(sw_code);
|
|
if (switch_begins == FALSE) InterSchemas::mark_case_closed(isn);
|
|
if (sw_val) sw_val->expression_tokens = isn->expression_tokens;
|
|
prev->next = NULL;
|
|
isn->expression_tokens = NULL;
|
|
isn->isn_type = STATEMENT_ISNT;
|
|
if (defaulter)
|
|
isn->isn_clarifier = DEFAULT_BIP;
|
|
else
|
|
isn->isn_clarifier = CASE_BIP;
|
|
|
|
inter_schema_node *sw_code_exp =
|
|
InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
sw_code_exp->expression_tokens = n->next;
|
|
|
|
sw_code->child_node = sw_code_exp;
|
|
sw_code_exp->parent_node = sw_code;
|
|
|
|
if (sw_val)
|
|
for (inter_schema_token *t = sw_val->expression_tokens; t; t = t->next)
|
|
t->owner = sw_val;
|
|
for (inter_schema_token *t = sw_code_exp->expression_tokens; t; t = t->next)
|
|
t->owner = sw_code_exp;
|
|
|
|
sw_code_exp->child_node = original_child;
|
|
|
|
inter_schema_node *at = isn->next_node;
|
|
inter_schema_node *attach = sw_code_exp;
|
|
while ((at) && (Ramification::casey(at) == FALSE)) {
|
|
inter_schema_node *next_at = at->next_node;
|
|
at->next_node = NULL;
|
|
at->parent_node = sw_code;
|
|
attach->next_node = at;
|
|
attach = at;
|
|
isn->next_node = next_at;
|
|
at = next_at;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
prev = n; n = n->next;
|
|
}
|
|
}
|
|
if (Ramification::split_switches_into_cases(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
@ =
|
|
int Ramification::casey(inter_schema_node *isn) {
|
|
if (isn == NULL) return FALSE;
|
|
if (isn->expression_tokens) {
|
|
inter_schema_token *n = isn->expression_tokens;
|
|
int bl = 0;
|
|
while (n) {
|
|
if (n->ist_type == OPEN_ROUND_ISTT) bl++;
|
|
if (n->ist_type == CLOSE_ROUND_ISTT) bl--;
|
|
if ((n->ist_type == COLON_ISTT) && (bl == 0)) return TRUE;
|
|
n = n->next;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
@h The split print statements ramification.
|
|
Inform 6 supports composite print statements, like so:
|
|
= (text as Inform 6)
|
|
print_ret "X is ", x, ".";
|
|
=
|
|
This example currently looks like:
|
|
= (text)
|
|
EXPRESSION_ISNT
|
|
RESERVED_ISTT "print_ret"
|
|
WHITE_SPACE_ISTT
|
|
DQUOTED_ISTT "X is "
|
|
COMMA_ISTT
|
|
WHITE_SPACE_ISTT
|
|
IDENTIFIER_ISTT "x"
|
|
COMMA_ISTT
|
|
WHITE_SPACE_ISTT
|
|
DQUOTED_ISTT "."
|
|
=
|
|
We break this up as three individual prints:
|
|
= (text)
|
|
EXPRESSION_ISNT
|
|
RESERVED_ISTT "print"
|
|
WHITE_SPACE_ISTT
|
|
DQUOTED_ISTT "X is "
|
|
EXPRESSION_ISNT
|
|
RESERVED_ISTT "print"
|
|
WHITE_SPACE_ISTT
|
|
IDENTIFIER_ISTT "x"
|
|
EXPRESSION_ISNT
|
|
RESERVED_ISTT "print_ret"
|
|
WHITE_SPACE_ISTT
|
|
DQUOTED_ISTT "."
|
|
=
|
|
Note that, for obvious reasons, in the |print_ret| case only the third of the
|
|
prints should perform a return.
|
|
|
|
The point of this stage is to get rid of one source of |COMMA_ISTT| tokens;
|
|
commas can mean a number of different things in Inform 6 syntax and it makes
|
|
our work simpler to take one of those meanings out of the picture.
|
|
|
|
=
|
|
int Ramification::split_print_statements(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (; isn; isn=isn->next_node) {
|
|
if (isn->expression_tokens) {
|
|
if ((isn->expression_tokens->ist_type == RESERVED_ISTT)
|
|
&& ((isn->expression_tokens->reserved_word == PRINT_I6RW) ||
|
|
(isn->expression_tokens->reserved_word == PRINTRET_I6RW))) {
|
|
inter_schema_token *n = isn->expression_tokens->next, *prev = isn->expression_tokens;
|
|
int bl = 0;
|
|
while (n) {
|
|
if (n->ist_type == OPEN_ROUND_ISTT) bl++;
|
|
if (n->ist_type == CLOSE_ROUND_ISTT) bl--;
|
|
if ((n->ist_type == COMMA_ISTT) && (bl == 0)) {
|
|
prev->next = NULL;
|
|
n->ist_type = RESERVED_ISTT;
|
|
n->reserved_word = isn->expression_tokens->reserved_word;
|
|
isn->expression_tokens->reserved_word = PRINT_I6RW;
|
|
isn->expression_tokens->material = I"print";
|
|
if (n->reserved_word == PRINT_I6RW) n->material = I"print";
|
|
else n->material = I"print_ret";
|
|
inter_schema_node *new_isn = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
new_isn->expression_tokens = n;
|
|
new_isn->parent_node = isn->parent_node;
|
|
for (inter_schema_token *l = new_isn->expression_tokens; l; l=l->next) {
|
|
l->owner = new_isn;
|
|
}
|
|
inter_schema_node *saved = isn->next_node;
|
|
isn->next_node = new_isn;
|
|
new_isn->next_node = saved;
|
|
new_isn->semicolon_terminated = isn->semicolon_terminated;
|
|
return TRUE;
|
|
}
|
|
prev = n; n = n->next;
|
|
}
|
|
}
|
|
}
|
|
if (Ramification::split_print_statements(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
@h The identify constructs ramification.
|
|
|
|
=
|
|
int Ramification::identify_constructs(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (; isn; isn=isn->next_node) {
|
|
if (isn->expression_tokens) {
|
|
inter_ti subordinate_to = 0, subordinate_store_val = 0;
|
|
inter_schema_token *operand1 = NULL, *operand2 = NULL;
|
|
inter_schema_node *operand2_node = NULL;
|
|
int dangle = NOT_APPLICABLE;
|
|
int dangle_number = -1;
|
|
text_stream *dangle_text = NULL;
|
|
if (isn->expression_tokens->ist_type == RESERVED_ISTT) {
|
|
switch (isn->expression_tokens->reserved_word) {
|
|
case PRINT_I6RW:
|
|
case PRINTRET_I6RW:
|
|
subordinate_to = PRINTNUMBER_BIP;
|
|
inter_schema_token *n = isn->expression_tokens->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
if ((n) && (n->ist_type == OPEN_ROUND_ISTT)) {
|
|
n = n->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
inter_schema_token *pr = n;
|
|
if (pr) {
|
|
n = n->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
if ((n) && (n->ist_type == CLOSE_ROUND_ISTT)) {
|
|
n = n->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
if (Str::eq(pr->material, I"address")) {
|
|
subordinate_to = PRINTDWORD_BIP;
|
|
operand1 = n;
|
|
} else if (Str::eq(pr->material, I"char")) {
|
|
subordinate_to = PRINTCHAR_BIP;
|
|
operand1 = n;
|
|
} else if (Str::eq(pr->material, I"string")) {
|
|
subordinate_to = PRINTSTRING_BIP;
|
|
operand1 = n;
|
|
} else if (Str::eq(pr->material, I"object")) {
|
|
subordinate_to = PRINTOBJ_BIP;
|
|
operand1 = n;
|
|
} else {
|
|
if (Str::eq(pr->material, I"the")) pr->material = I"DefArt";
|
|
if (Str::eq(pr->material, I"The")) pr->material = I"CDefArt";
|
|
if ((Str::eq(pr->material, I"a")) || (Str::eq(pr->material, I"an"))) pr->material = I"IndefArt";
|
|
if ((Str::eq(pr->material, I"A")) || (Str::eq(pr->material, I"An"))) pr->material = I"CIndefArt";
|
|
if (Str::eq(pr->material, I"number")) pr->material = I"LanguageNumber";
|
|
if (Str::eq(pr->material, I"name")) pr->material = I"PrintShortName";
|
|
if (Str::eq(pr->material, I"property")) pr->material = I"DebugProperty";
|
|
isn->expression_tokens = pr;
|
|
inter_schema_token *open_b =
|
|
InterSchemas::new_token(OPEN_ROUND_ISTT, I"(", 0, 0, -1);
|
|
InterSchemas::add_token_after(open_b, isn->expression_tokens);
|
|
open_b->next = n;
|
|
n = open_b;
|
|
while ((n) && (n->next)) n = n->next;
|
|
inter_schema_token *close_b =
|
|
InterSchemas::new_token(CLOSE_ROUND_ISTT, I")", 0, 0, -1);
|
|
InterSchemas::add_token_after(close_b, n);
|
|
subordinate_to = 0;
|
|
operand1 = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (subordinate_to == PRINTNUMBER_BIP) {
|
|
inter_schema_token *n = isn->expression_tokens->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
if ((n) && (n->ist_type == DQUOTED_ISTT)) {
|
|
subordinate_to = PRINT_BIP;
|
|
Tokenisation::de_escape_text(n->material);
|
|
}
|
|
}
|
|
if (isn->expression_tokens->reserved_word == PRINTRET_I6RW) {
|
|
inter_schema_node *save_next = isn->next_node;
|
|
isn->next_node = InterSchemas::new_node(isn->parent_schema, STATEMENT_ISNT);
|
|
isn->next_node->parent_node = isn->parent_node;
|
|
isn->next_node->isn_clarifier = PRINT_BIP;
|
|
isn->next_node->child_node = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
isn->next_node->child_node->parent_node = isn->next_node;
|
|
InterSchemas::add_token_to_node(isn->next_node->child_node, InterSchemas::new_token(DQUOTED_ISTT, I"\n", 0, 0, -1));
|
|
isn->next_node->next_node = InterSchemas::new_node(isn->parent_schema, STATEMENT_ISNT);
|
|
isn->next_node->next_node->parent_node = isn->parent_node;
|
|
isn->next_node->next_node->isn_clarifier = RETURN_BIP;
|
|
isn->next_node->next_node->next_node = save_next;
|
|
}
|
|
break;
|
|
case STYLE_I6RW: {
|
|
inter_schema_token *n = isn->expression_tokens->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
if ((n) && (Str::eq(n->material, I"roman"))) {
|
|
subordinate_to = STYLE_BIP;
|
|
dangle_number = 0;
|
|
} else if ((n) && (Str::eq(n->material, I"bold"))) {
|
|
subordinate_to = STYLE_BIP;
|
|
dangle_number = 1;
|
|
} else if ((n) && (Str::eq(n->material, I"underline"))) {
|
|
subordinate_to = STYLE_BIP;
|
|
dangle_number = 2;
|
|
} else if ((n) && (Str::eq(n->material, I"reverse"))) {
|
|
subordinate_to = STYLE_BIP;
|
|
dangle_number = 3;
|
|
} else {
|
|
subordinate_to = STYLE_BIP;
|
|
}
|
|
break;
|
|
}
|
|
case INVERSION_I6RW:
|
|
subordinate_to = PRINT_BIP;
|
|
dangle_text = I"v6";
|
|
break;
|
|
case FONT_I6RW: {
|
|
subordinate_to = FONT_BIP;
|
|
inter_schema_token *n = isn->expression_tokens->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
if ((n) && (Str::eq(n->material, I"on"))) dangle = 1;
|
|
if ((n) && (Str::eq(n->material, I"off"))) dangle = 0;
|
|
break;
|
|
}
|
|
case OBJECTLOOP_I6RW:
|
|
subordinate_to = OBJECTLOOP_BIP;
|
|
break;
|
|
case SWITCH_I6RW:
|
|
subordinate_to = SWITCH_BIP;
|
|
break;
|
|
case IF_I6RW: {
|
|
subordinate_to = IF_BIP;
|
|
inter_schema_token *n = isn->expression_tokens->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
operand1 = n;
|
|
inter_schema_node *next_isn = isn->next_node;
|
|
if ((next_isn) && (next_isn->expression_tokens) &&
|
|
(next_isn->expression_tokens->ist_type == RESERVED_ISTT) &&
|
|
(next_isn->expression_tokens->reserved_word == ELSE_I6RW) &&
|
|
(next_isn->child_node)) {
|
|
inter_schema_token *n = next_isn->child_node->child_node->expression_tokens;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
operand2 = n;
|
|
if (n) {
|
|
subordinate_to = IFELSE_BIP;
|
|
operand2_node = next_isn->child_node;
|
|
}
|
|
isn->next_node = next_isn->next_node;
|
|
}
|
|
break;
|
|
}
|
|
case FOR_I6RW:
|
|
subordinate_to = FOR_BIP;
|
|
break;
|
|
case WHILE_I6RW:
|
|
subordinate_to = WHILE_BIP;
|
|
break;
|
|
case DO_I6RW:
|
|
subordinate_to = DO_BIP;
|
|
inter_schema_node *next_isn = isn->next_node;
|
|
if ((next_isn) && (next_isn->expression_tokens) &&
|
|
(next_isn->expression_tokens->ist_type == RESERVED_ISTT) &&
|
|
(next_isn->expression_tokens->reserved_word == UNTIL_I6RW)) {
|
|
isn->next_node = next_isn->next_node;
|
|
inter_schema_token *n = next_isn->expression_tokens->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
operand1 = n;
|
|
} else {
|
|
internal_error("do without until");
|
|
}
|
|
break;
|
|
case JUMP_I6RW:
|
|
subordinate_to = JUMP_BIP;
|
|
break;
|
|
case RETURN_I6RW:
|
|
subordinate_to = RETURN_BIP;
|
|
break;
|
|
case RTRUE_I6RW:
|
|
subordinate_to = RETURN_BIP;
|
|
dangle = TRUE;
|
|
break;
|
|
case RFALSE_I6RW:
|
|
subordinate_to = RETURN_BIP;
|
|
dangle = FALSE;
|
|
break;
|
|
case BREAK_I6RW:
|
|
subordinate_to = BREAK_BIP;
|
|
break;
|
|
case CONTINUE_I6RW:
|
|
subordinate_to = CONTINUE_BIP;
|
|
break;
|
|
case QUIT_I6RW:
|
|
subordinate_to = QUIT_BIP;
|
|
break;
|
|
case RESTORE_I6RW:
|
|
subordinate_to = RESTORE_BIP;
|
|
break;
|
|
case SPACES_I6RW:
|
|
subordinate_to = SPACES_BIP;
|
|
break;
|
|
case NEWLINE_I6RW:
|
|
subordinate_to = PRINT_BIP;
|
|
dangle_text = I"\n";
|
|
break;
|
|
case MOVE_I6RW: {
|
|
inter_schema_token *n = isn->expression_tokens->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
operand1 = n;
|
|
while (n) {
|
|
if (Str::eq(n->material, I"to")) {
|
|
n->ist_type = WHITE_SPACE_ISTT;
|
|
n->material = I" ";
|
|
operand2 = n->next;
|
|
n->next = NULL;
|
|
while ((operand2) && (operand2->ist_type == WHITE_SPACE_ISTT)) operand2 = operand2->next;
|
|
break;
|
|
}
|
|
n = n->next;
|
|
}
|
|
if ((operand1) && (operand2)) subordinate_to = MOVE_BIP;
|
|
break;
|
|
}
|
|
case READ_I6RW: {
|
|
inter_schema_token *n = isn->expression_tokens->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
operand1 = n;
|
|
n = n->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
operand2 = n;
|
|
operand1->next = NULL;
|
|
operand2->next = NULL;
|
|
if ((operand1) && (operand2)) subordinate_to = READ_XBIP;
|
|
break;
|
|
}
|
|
case REMOVE_I6RW:
|
|
subordinate_to = REMOVE_BIP;
|
|
break;
|
|
case GIVE_I6RW: {
|
|
inter_schema_token *n = isn->expression_tokens->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
operand1 = n;
|
|
n = n->next;
|
|
operand1->next = NULL;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
if ((n) && (n->ist_type == OPERATOR_ISTT) && (n->operation_primitive == BITWISENOT_BIP)) {
|
|
subordinate_to = STORE_BIP; subordinate_store_val = 0;
|
|
n = n->next;
|
|
} else {
|
|
subordinate_to = STORE_BIP; subordinate_store_val = 1;
|
|
}
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
operand2 = n;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ((isn->expression_tokens) && (isn->expression_tokens->ist_type == DIRECTIVE_ISTT)) {
|
|
isn->isn_type = DIRECTIVE_ISNT;
|
|
isn->dir_clarifier = isn->expression_tokens->reserved_word;
|
|
if (isn->expression_tokens->next) {
|
|
inter_schema_node *new_isn = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
isn->child_node = new_isn;
|
|
new_isn->parent_node = isn;
|
|
new_isn->expression_tokens = isn->expression_tokens->next;
|
|
for (inter_schema_token *n = new_isn->expression_tokens; n; n = n->next)
|
|
n->owner = new_isn;
|
|
}
|
|
isn->expression_tokens = NULL;
|
|
subordinate_to = 0;
|
|
}
|
|
if ((isn->expression_tokens) && (isn->expression_tokens->ist_type == OPCODE_ISTT)) {
|
|
if (Str::eq(isn->expression_tokens->material, I"@push")) subordinate_to = PUSH_BIP;
|
|
else if (Str::eq(isn->expression_tokens->material, I"@pull")) subordinate_to = PULL_BIP;
|
|
else {
|
|
isn->isn_type = ASSEMBLY_ISNT;
|
|
inter_schema_node *prev_node = NULL;
|
|
for (inter_schema_token *l = isn->expression_tokens, *n = l?(l->next):NULL; l; l=n, n=n?(n->next):NULL) {
|
|
if (l->ist_type != WHITE_SPACE_ISTT) {
|
|
inter_schema_node *new_isn = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
new_isn->expression_tokens = l; l->next = NULL; l->owner = new_isn;
|
|
if (l->operation_primitive) {
|
|
l->ist_type = IDENTIFIER_ISTT;
|
|
l->operation_primitive = 0;
|
|
}
|
|
if ((n) && (Str::eq(l->material, I"-"))) {
|
|
l->material = Str::new();
|
|
WRITE_TO(l->material, "-%S", n->material);
|
|
l->ist_type = NUMBER_ISTT;
|
|
n = n->next;
|
|
}
|
|
if (Str::eq(l->material, I"->")) l->ist_type = ASM_ARROW_ISTT;
|
|
if (Str::eq(l->material, I"sp")) l->ist_type = ASM_SP_ISTT;
|
|
if ((Str::eq(l->material, I"?")) && (n)) {
|
|
l->ist_type = ASM_LABEL_ISTT;
|
|
l->material = n->material;
|
|
n = n->next;
|
|
if (Str::eq(l->material, I"~")) {
|
|
l->ist_type = ASM_NEGATED_LABEL_ISTT;
|
|
l->material = n->material;
|
|
n = n->next;
|
|
}
|
|
}
|
|
if (isn->child_node == NULL) isn->child_node = new_isn;
|
|
else if (prev_node) prev_node->next_node = new_isn;
|
|
new_isn->parent_node = isn;
|
|
prev_node = new_isn;
|
|
}
|
|
}
|
|
isn->expression_tokens = NULL;
|
|
}
|
|
}
|
|
if (subordinate_to) {
|
|
inter_schema_node *new_isn = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
if (operand1 == NULL) operand1 = isn->expression_tokens->next;
|
|
new_isn->expression_tokens = operand1;
|
|
if ((new_isn->expression_tokens) &&
|
|
(new_isn->expression_tokens->ist_type == WHITE_SPACE_ISTT))
|
|
new_isn->expression_tokens = new_isn->expression_tokens->next;
|
|
for (inter_schema_token *l = new_isn->expression_tokens; l; l=l->next) {
|
|
l->owner = new_isn;
|
|
}
|
|
isn->isn_clarifier = subordinate_to;
|
|
isn->isn_type = STATEMENT_ISNT;
|
|
isn->expression_tokens = NULL;
|
|
new_isn->next_node = isn->child_node;
|
|
isn->child_node = new_isn;
|
|
new_isn->parent_node = isn;
|
|
if (dangle != NOT_APPLICABLE) {
|
|
text_stream *T = Str::new();
|
|
WRITE_TO(T, "%d", dangle);
|
|
new_isn->expression_tokens = InterSchemas::new_token(NUMBER_ISTT, T, 0, 0, -1);
|
|
new_isn->expression_tokens->owner = new_isn;
|
|
}
|
|
if (dangle_number >= 0) {
|
|
text_stream *T = Str::new();
|
|
WRITE_TO(T, "%d", dangle_number);
|
|
new_isn->expression_tokens = InterSchemas::new_token(NUMBER_ISTT, T, 0, 0, -1);
|
|
new_isn->expression_tokens->owner = new_isn;
|
|
}
|
|
if (dangle_text) {
|
|
new_isn->expression_tokens = InterSchemas::new_token(DQUOTED_ISTT, dangle_text, 0, 0, -1);
|
|
new_isn->expression_tokens->owner = new_isn;
|
|
Tokenisation::de_escape_text(new_isn->expression_tokens->material);
|
|
}
|
|
if (operand2) {
|
|
inter_schema_node *new_new_isn = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
if (subordinate_to == IFELSE_BIP) {
|
|
new_new_isn->semicolon_terminated = TRUE;
|
|
new_new_isn->next_node = new_isn->next_node->next_node;
|
|
new_isn->next_node->next_node = new_new_isn;
|
|
} else {
|
|
new_new_isn->next_node = new_isn->next_node;
|
|
new_isn->next_node = new_new_isn;
|
|
}
|
|
new_new_isn->parent_node = isn;
|
|
new_new_isn->expression_tokens = operand2;
|
|
if ((new_new_isn->expression_tokens) && (new_new_isn->expression_tokens->ist_type == WHITE_SPACE_ISTT))
|
|
new_new_isn->expression_tokens = new_new_isn->expression_tokens->next;
|
|
for (inter_schema_token *l = new_new_isn->expression_tokens; l; l=l->next) {
|
|
l->owner = new_new_isn;
|
|
}
|
|
}
|
|
if (operand2_node) {
|
|
operand2_node->next_node = NULL;
|
|
new_isn->next_node->next_node = operand2_node;
|
|
operand2_node->parent_node = isn;
|
|
for (inter_schema_token *l = operand2_node->child_node->expression_tokens; l; l=l->next) {
|
|
l->owner = operand2_node->child_node;
|
|
}
|
|
}
|
|
if (subordinate_to == STORE_BIP) {
|
|
isn->isn_clarifier = 0;
|
|
isn->isn_type = EXPRESSION_ISNT;
|
|
inter_schema_node *A = isn->child_node;
|
|
inter_schema_node *B = isn->child_node->next_node;
|
|
isn->child_node = NULL;
|
|
isn->expression_tokens = A->expression_tokens;
|
|
isn->expression_tokens->next =
|
|
InterSchemas::new_token(OPERATOR_ISTT, I".", PROPERTYVALUE_BIP, 0, -1);
|
|
isn->expression_tokens->next->next = B->expression_tokens;
|
|
isn->expression_tokens->next->next->next = InterSchemas::new_token(OPERATOR_ISTT, I"=", STORE_BIP, 0, -1);
|
|
text_stream *T = Str::new();
|
|
WRITE_TO(T, "%d", subordinate_store_val);
|
|
isn->expression_tokens->next->next->next->next = InterSchemas::new_token(NUMBER_ISTT, T, 0, 0, -1);
|
|
for (inter_schema_token *l = isn->expression_tokens; l; l=l->next)
|
|
l->owner = isn;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
if ((isn->isn_type != ASSEMBLY_ISNT) && (isn->isn_type != DIRECTIVE_ISNT))
|
|
if (Ramification::identify_constructs(isn, isn->child_node)) return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@h The strip all white space ramification.
|
|
White space has an important role to play earlier on in the process, but once
|
|
our tree structure contains the information it carries, we can discard it.
|
|
This simply deletes every token of type |WHITE_SPACE_ISTT|.
|
|
|
|
=
|
|
int Ramification::strip_all_white_space(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (; isn; isn=isn->next_node) {
|
|
if ((isn->expression_tokens) && (isn->expression_tokens->ist_type == WHITE_SPACE_ISTT)) {
|
|
isn->expression_tokens = isn->expression_tokens->next;
|
|
return TRUE;
|
|
}
|
|
int d = 0;
|
|
inter_schema_token *prev = isn->expression_tokens;
|
|
if (prev) {
|
|
inter_schema_token *n = prev->next;
|
|
while (n) {
|
|
if (n->ist_type == WHITE_SPACE_ISTT) { prev->next = n->next; d++; }
|
|
prev = n; n = n->next;
|
|
}
|
|
}
|
|
if (d > 0) return TRUE;
|
|
if (Ramification::strip_all_white_space(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
@ =
|
|
int Ramification::alternatecases(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (; isn; isn=isn->next_node) {
|
|
if ((isn->isn_clarifier == CASE_BIP) && (isn->child_node)) {
|
|
inter_schema_node *A = isn->child_node;
|
|
inter_schema_node *B = isn->child_node->next_node;
|
|
if ((A) && (B) && (B->next_node)) {
|
|
inter_schema_node *C = InterSchemas::new_node(isn->parent_schema, OPERATION_ISNT);
|
|
C->isn_clarifier = ALTERNATIVECASE_BIP;
|
|
C->child_node = A;
|
|
A->parent_node = C; B->parent_node = C;
|
|
isn->child_node = C; C->next_node = B->next_node; B->next_node = NULL;
|
|
C->parent_node = isn;
|
|
return TRUE;
|
|
}
|
|
}
|
|
if (Ramification::alternatecases(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
@ =
|
|
int Ramification::treat_constructs(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (; isn; isn=isn->next_node) {
|
|
if ((isn->isn_type == STATEMENT_ISNT) &&
|
|
(isn->isn_clarifier == FOR_BIP) &&
|
|
(isn->node_marked == FALSE)) {
|
|
inter_schema_node *predicates = isn->child_node;
|
|
if ((predicates == NULL) || (predicates->isn_type != EXPRESSION_ISNT))
|
|
internal_error("malformed proto-for");
|
|
inter_schema_token *n = predicates->expression_tokens;
|
|
inter_schema_node *code_node = predicates->next_node;
|
|
int bl = 0, cw = 0;
|
|
inter_schema_token *from[3], *to[3];
|
|
for (int i=0; i<3; i++) { from[i] = 0; to[i] = 0; }
|
|
while (n) {
|
|
if (n->ist_type == OPEN_ROUND_ISTT) {
|
|
if ((bl > 0) && (from[cw] == NULL)) from[cw] = n;
|
|
bl++;
|
|
} else if (n->ist_type == CLOSE_ROUND_ISTT) {
|
|
bl--;
|
|
if (bl == 0) @<End a wodge@>;
|
|
} else if (bl == 1) {
|
|
if (n->ist_type == COLON_ISTT) @<End a wodge@>
|
|
else {
|
|
if (from[cw] == NULL) from[cw] = n;
|
|
}
|
|
}
|
|
n = n->next;
|
|
}
|
|
if (cw != 3) internal_error("malformed for prototype");
|
|
for (int i=0; i<3; i++) {
|
|
inter_schema_node *eval_isn = InterSchemas::new_node(isn->parent_schema, EVAL_ISNT);
|
|
if (i == 0) isn->child_node = eval_isn;
|
|
if (i == 1) isn->child_node->next_node = eval_isn;
|
|
if (i == 2) {
|
|
isn->child_node->next_node->next_node = eval_isn;
|
|
eval_isn->next_node = code_node;
|
|
}
|
|
eval_isn->parent_node = isn;
|
|
|
|
inter_schema_node *expr_isn = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
eval_isn->child_node = expr_isn;
|
|
expr_isn->parent_node = eval_isn;
|
|
|
|
inter_schema_token *m = from[i];
|
|
while ((m) && (m->ist_type == WHITE_SPACE_ISTT)) m = m->next;
|
|
expr_isn->expression_tokens = m;
|
|
if (m == to[i]) expr_isn->expression_tokens = NULL;
|
|
else {
|
|
while (m) {
|
|
m->owner = expr_isn;
|
|
if (m->next == to[i]) m->next = NULL;
|
|
m = m->next;
|
|
}
|
|
}
|
|
}
|
|
isn->node_marked = TRUE;
|
|
return TRUE;
|
|
}
|
|
if (Ramification::treat_constructs(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
@<End a wodge@> =
|
|
if (from[cw] == NULL) to[cw] = NULL;
|
|
else to[cw] = n;
|
|
if (from[cw] == to[cw]) { from[cw] = NULL; to[cw] = NULL; }
|
|
cw++;
|
|
|
|
@ =
|
|
int Ramification::add_missing_bodies(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (; isn; isn=isn->next_node) {
|
|
int req = 0;
|
|
if ((isn->isn_type == STATEMENT_ISNT) && (isn->isn_clarifier == IF_BIP)) req = 2;
|
|
if ((isn->isn_type == STATEMENT_ISNT) && (isn->isn_clarifier == IFELSE_BIP)) req = 3;
|
|
if ((isn->isn_type == STATEMENT_ISNT) && (isn->isn_clarifier == FOR_BIP)) req = 4;
|
|
if ((isn->isn_type == STATEMENT_ISNT) && (isn->isn_clarifier == WHILE_BIP)) req = 2;
|
|
if ((isn->isn_type == STATEMENT_ISNT) && (isn->isn_clarifier == OBJECTLOOP_BIP)) req = 2;
|
|
if ((req > 0) && (isn->node_marked == FALSE)) {
|
|
int actual = 0;
|
|
for (inter_schema_node *ch = isn->child_node; ch; ch=ch->next_node) actual++;
|
|
if (actual < req-1) internal_error("far too few child nodes");
|
|
if (actual > req) internal_error("too many child nodes");
|
|
if (actual == req-1) {
|
|
inter_schema_node *code_isn = InterSchemas::new_node(isn->parent_schema, CODE_ISNT);
|
|
code_isn->parent_node = isn;
|
|
|
|
inter_schema_node *ch = isn->child_node;
|
|
while ((ch) && (ch->next_node)) ch=ch->next_node;
|
|
ch->next_node = code_isn;
|
|
|
|
InterSchemas::mark_unclosed(code_isn);
|
|
isn->node_marked = TRUE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
if (Ramification::add_missing_bodies(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int Ramification::remove_empties(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (inter_schema_node *prev = NULL; isn; prev = isn, isn = isn->next_node) {
|
|
if ((isn->isn_type == EXPRESSION_ISNT) && (isn->expression_tokens == NULL)) {
|
|
if (prev) prev->next_node = isn->next_node;
|
|
else if (par) par->child_node = isn->next_node;
|
|
else isn->parent_schema->node_tree = isn->next_node;
|
|
return TRUE;
|
|
}
|
|
if (Ramification::remove_empties(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int Ramification::top_level_commas(inter_schema_node *par, inter_schema_node *isn) {
|
|
for ( ; isn; isn = isn->next_node) {
|
|
if (isn->isn_type == EXPRESSION_ISNT) {
|
|
inter_schema_token *n = isn->expression_tokens, *prev = NULL;
|
|
int bl = 0;
|
|
while (n) {
|
|
if (n->ist_type == OPEN_ROUND_ISTT) bl++;
|
|
if (n->ist_type == CLOSE_ROUND_ISTT) bl--;
|
|
if ((n->ist_type == COMMA_ISTT) && (bl == 0) && (prev)) {
|
|
prev->next = NULL;
|
|
prev = n; n = n->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) { prev = n; n = n->next; }
|
|
inter_schema_node *new_isn = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
new_isn->expression_tokens = n;
|
|
new_isn->parent_node = isn->parent_node;
|
|
for (inter_schema_token *l = new_isn->expression_tokens; l; l=l->next) {
|
|
l->owner = new_isn;
|
|
}
|
|
inter_schema_node *saved = isn->next_node;
|
|
isn->next_node = new_isn;
|
|
new_isn->next_node = saved;
|
|
new_isn->semicolon_terminated = isn->semicolon_terminated;
|
|
return TRUE;
|
|
}
|
|
prev = n; n = n->next;
|
|
}
|
|
}
|
|
if (Ramification::top_level_commas(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int Ramification::debracket(inter_schema_node *par, inter_schema_node *isn) {
|
|
if (Ramification::outer_subexpressions(par, isn)) return TRUE;
|
|
if (Ramification::op_subexpressions(par, isn)) return TRUE;
|
|
if (Ramification::place_calls(par, isn)) return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
int Ramification::outer_subexpressions(inter_schema_node *par, inter_schema_node *isn) {
|
|
for ( ; isn; isn = isn->next_node) {
|
|
if (isn->isn_type == EXPRESSION_ISNT) {
|
|
inter_schema_token *n = isn->expression_tokens;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
if ((n) && (n->ist_type == OPEN_ROUND_ISTT)) {
|
|
int bl = 1, fails = FALSE;
|
|
n = n->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
inter_schema_token *from = n, *to = NULL;
|
|
while (n) {
|
|
if ((bl == 0) && (n->ist_type != WHITE_SPACE_ISTT)) fails = TRUE;
|
|
if (n->ist_type == OPEN_ROUND_ISTT) bl++;
|
|
else if (n->ist_type == CLOSE_ROUND_ISTT) {
|
|
bl--;
|
|
if (bl == 0) to = n;
|
|
}
|
|
n = n->next;
|
|
}
|
|
if ((fails == FALSE) && (from) && (to) && (from != to)) {
|
|
inter_schema_node *new_isn = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
new_isn->expression_tokens = from;
|
|
for (inter_schema_token *l = new_isn->expression_tokens; l; l=l->next) {
|
|
l->owner = new_isn;
|
|
if (l->next == to) l->next = NULL;
|
|
}
|
|
isn->isn_type = SUBEXPRESSION_ISNT;
|
|
isn->expression_tokens = NULL;
|
|
|
|
isn->child_node = new_isn;
|
|
new_isn->parent_node = isn;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (Ramification::outer_subexpressions(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int Ramification::prefer_over(inter_ti p, inter_ti existing) {
|
|
if (existing == 0) return TRUE;
|
|
if (BIPMetadata::precedence(p) < BIPMetadata::precedence(existing)) return TRUE;
|
|
if ((BIPMetadata::precedence(p) == BIPMetadata::precedence(existing)) &&
|
|
(BIPMetadata::right_associative(p)) &&
|
|
(BIPMetadata::arity(p) == 2) &&
|
|
(BIPMetadata::arity(existing) == 2)) return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
int Ramification::op_subexpressions(inter_schema_node *par, inter_schema_node *isn) {
|
|
for ( ; isn; isn = isn->next_node) {
|
|
if ((isn->node_marked == FALSE) && (isn->isn_type == EXPRESSION_ISNT)) {
|
|
isn->node_marked = TRUE;
|
|
inter_schema_token *n = isn->expression_tokens;
|
|
int bl = 0;
|
|
inter_ti best_operator = 0;
|
|
inter_schema_token *break_at = NULL;
|
|
while (n) {
|
|
if (n->ist_type == OPEN_ROUND_ISTT) bl++;
|
|
if (n->ist_type == CLOSE_ROUND_ISTT) bl--;
|
|
if ((bl == 0) && (n->ist_type == OPERATOR_ISTT)) {
|
|
inter_ti this_operator = n->operation_primitive;
|
|
if (Ramification::prefer_over(this_operator, best_operator)) {
|
|
break_at = n; best_operator = this_operator;
|
|
}
|
|
}
|
|
n = n->next;
|
|
}
|
|
if (break_at) {
|
|
inter_schema_token *n = isn->expression_tokens;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
inter_schema_token *from = n, *to = break_at;
|
|
int has_operand_before = FALSE, has_operand_after = FALSE;
|
|
if ((from) && (from != to)) {
|
|
inter_schema_node *new_isn = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
new_isn->expression_tokens = from;
|
|
for (inter_schema_token *l = new_isn->expression_tokens; l; l=l->next) {
|
|
l->owner = new_isn;
|
|
if (l->next == to) l->next = NULL;
|
|
}
|
|
if (isn->child_node == NULL) {
|
|
isn->child_node = new_isn;
|
|
} else {
|
|
isn->child_node->next_node = new_isn;
|
|
}
|
|
new_isn->parent_node = isn;
|
|
has_operand_before = TRUE;
|
|
} else {
|
|
if (best_operator == IN_BIP) {
|
|
break_at->ist_type = IDENTIFIER_ISTT;
|
|
break_at->operation_primitive = 0;
|
|
break_at = NULL;
|
|
}
|
|
}
|
|
if (break_at) {
|
|
n = break_at->next;
|
|
while ((n) && (n->ist_type == WHITE_SPACE_ISTT)) n = n->next;
|
|
from = n; to = NULL;
|
|
if ((from) && (from != to)) {
|
|
inter_schema_node *new_isn = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
new_isn->expression_tokens = from;
|
|
for (inter_schema_token *l = new_isn->expression_tokens; l; l=l->next) {
|
|
l->owner = new_isn;
|
|
if (l->next == to) l->next = NULL;
|
|
}
|
|
if (isn->child_node == NULL) {
|
|
isn->child_node = new_isn;
|
|
} else {
|
|
isn->child_node->next_node = new_isn;
|
|
}
|
|
new_isn->parent_node = isn;
|
|
has_operand_after = TRUE;
|
|
}
|
|
|
|
isn->isn_type = OPERATION_ISNT;
|
|
isn->expression_tokens = NULL;
|
|
isn->isn_clarifier = break_at->operation_primitive;
|
|
if ((break_at->operation_primitive == MINUS_BIP) && (has_operand_before == FALSE))
|
|
isn->isn_clarifier = UNARYMINUS_BIP;
|
|
if ((break_at->operation_primitive == POSTINCREMENT_BIP) && (has_operand_before == FALSE))
|
|
isn->isn_clarifier = PREINCREMENT_BIP;
|
|
if ((break_at->operation_primitive == POSTDECREMENT_BIP) && (has_operand_before == FALSE))
|
|
isn->isn_clarifier = PREDECREMENT_BIP;
|
|
if ((break_at->operation_primitive == PROPERTYVALUE_BIP) && (has_operand_before == FALSE)) {
|
|
isn->isn_type = LABEL_ISNT;
|
|
isn->isn_clarifier = 0;
|
|
} else {
|
|
int a = 0;
|
|
if (has_operand_before) a++;
|
|
if (has_operand_after) a++;
|
|
if (a != BIPMetadata::arity(isn->isn_clarifier)) {
|
|
LOG("Seem to have arity %d with isn %S which needs %d\n",
|
|
a, Primitives::BIP_to_name(isn->isn_clarifier),
|
|
BIPMetadata::arity(isn->isn_clarifier));
|
|
LOG("$1\n", isn->parent_schema);
|
|
internal_error("bad arity");
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (Ramification::op_subexpressions(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int Ramification::place_calls(inter_schema_node *par, inter_schema_node *isn) {
|
|
for ( ; isn; isn = isn->next_node) {
|
|
if (isn->isn_type == EXPRESSION_ISNT) {
|
|
if ((isn->expression_tokens) && (isn->expression_tokens->ist_type == OPEN_ROUND_ISTT)) {
|
|
int bl = 0, term_count = 0, tops = 0;
|
|
inter_schema_token *opener = NULL, *closer = NULL;
|
|
for (inter_schema_token *n = isn->expression_tokens; n; n = n->next) {
|
|
if (n->ist_type == OPEN_ROUND_ISTT) {
|
|
bl++;
|
|
if (bl == 1) { opener = n; closer = NULL; term_count++; }
|
|
} else if (n->ist_type == CLOSE_ROUND_ISTT) {
|
|
bl--;
|
|
if (bl == 0) { closer = n; }
|
|
} else if (bl == 0) tops++;
|
|
}
|
|
if ((term_count == 2) && (tops == 0) && (opener) && (closer)) {
|
|
@<Call brackets found@>;
|
|
}
|
|
}
|
|
inter_schema_token *n = isn->expression_tokens;
|
|
inter_schema_token *opener = NULL, *closer = NULL;
|
|
int pre_count = 0, pre_bracings = 0, post_count = 0, veto = FALSE, bl = 0;
|
|
while (n) {
|
|
if (n->ist_type == OPEN_ROUND_ISTT) {
|
|
bl++;
|
|
if (bl == 1) {
|
|
if (opener == NULL) opener = n;
|
|
else veto = TRUE;
|
|
}
|
|
} else if (n->ist_type == CLOSE_ROUND_ISTT) {
|
|
bl--;
|
|
if ((bl == 0) && (closer == NULL)) closer = n;
|
|
} else if ((bl == 0) && (n->ist_type != INLINE_ISTT)) {
|
|
if (opener == NULL) pre_count++;
|
|
if ((opener) && (closer)) post_count++;
|
|
} else if (bl == 0) {
|
|
if (opener == NULL) pre_bracings++;
|
|
}
|
|
n = n->next;
|
|
}
|
|
if (((pre_count == 1) || ((pre_count == 0) && (pre_bracings > 0))) &&
|
|
(post_count == 0) && (opener) && (closer) && (veto == FALSE))
|
|
@<Call brackets found@>;
|
|
}
|
|
if (Ramification::place_calls(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
@<Call brackets found@> =
|
|
inter_schema_token *from = isn->expression_tokens, *to = opener, *resume = opener->next;
|
|
@<Relegate node@>;
|
|
inter_schema_token *n = resume; from = n; int bl = 0;
|
|
while ((n != closer) && (n)) {
|
|
if (n->ist_type == OPEN_ROUND_ISTT) bl++;
|
|
if (n->ist_type == CLOSE_ROUND_ISTT) bl--;
|
|
if ((bl == 0) && (n->ist_type == COMMA_ISTT)) {
|
|
to = n; resume = n->next;
|
|
@<Relegate node@>;
|
|
from = resume; n = from;
|
|
} else {
|
|
n = n->next;
|
|
}
|
|
}
|
|
to = closer;
|
|
@<Relegate node@>;
|
|
|
|
isn->expression_tokens = NULL; isn->isn_type = CALL_ISNT;
|
|
return TRUE;
|
|
|
|
@<Relegate node@> =
|
|
if ((from) && (to) && (from != to)) {
|
|
inter_schema_node *new_isn = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
new_isn->expression_tokens = from;
|
|
for (inter_schema_token *l = new_isn->expression_tokens; l; l=l->next) {
|
|
l->owner = new_isn;
|
|
if (l->next == to) l->next = NULL;
|
|
}
|
|
if (isn->child_node == NULL) {
|
|
isn->child_node = new_isn;
|
|
} else {
|
|
inter_schema_node *xisn = isn->child_node;
|
|
while ((xisn) && (xisn->next_node)) xisn = xisn->next_node;
|
|
xisn->next_node = new_isn;
|
|
}
|
|
new_isn->parent_node = isn;
|
|
}
|
|
|
|
@ =
|
|
int Ramification::implied_return_values(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (inter_schema_node *prev = NULL; isn; prev = isn, isn = isn->next_node) {
|
|
if ((isn->isn_type == STATEMENT_ISNT) && (isn->isn_clarifier == RETURN_BIP) && (isn->child_node == FALSE)) {
|
|
isn->child_node = InterSchemas::new_node(isn->parent_schema, EXPRESSION_ISNT);
|
|
isn->child_node->parent_node = isn;
|
|
isn->child_node->expression_tokens = InterSchemas::new_token(NUMBER_ISTT, I"1", 0, 0, -1);
|
|
isn->child_node->expression_tokens->owner = isn->child_node;
|
|
return TRUE;
|
|
}
|
|
if (Ramification::implied_return_values(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
@ =
|
|
int Ramification::message_calls(inter_schema_node *par, inter_schema_node *isn) {
|
|
for (inter_schema_node *prev = NULL; isn; prev = isn, isn = isn->next_node) {
|
|
if ((isn->isn_type == OPERATION_ISNT) && (isn->isn_clarifier == PROPERTYVALUE_BIP) &&
|
|
(isn->child_node) && (isn->child_node->next_node) && (isn->child_node->next_node->isn_type == CALL_ISNT)) {
|
|
inter_schema_node *obj = isn->child_node;
|
|
inter_schema_node *message = isn->child_node->next_node->child_node;
|
|
inter_schema_node *args = isn->child_node->next_node->child_node->next_node;
|
|
isn->isn_type = MESSAGE_ISNT; isn->isn_clarifier = 0;
|
|
obj->next_node = message; message->parent_node = isn; message->next_node = args;
|
|
if (message->isn_type == EXPRESSION_ISNT) {
|
|
inter_schema_token *n = message->expression_tokens;
|
|
if ((n) && (Str::eq(n->material, I"call"))) {
|
|
obj->next_node = args; isn->isn_type = CALLMESSAGE_ISNT;
|
|
}
|
|
}
|
|
while (args) { args->parent_node = isn; args = args->next_node; }
|
|
return TRUE;
|
|
}
|
|
if (Ramification::message_calls(isn, isn->child_node)) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|