fix: break and continue

This commit is contained in:
Matthieu Bessat 2022-05-15 23:00:16 +02:00
parent c3af6bd5ca
commit bcaf2cb3b7
4 changed files with 135 additions and 83 deletions

View file

@ -1,7 +1,14 @@
# show case of 'continue' and 'break' keyword in their natural environment
set i to 0 set i to 0
while 1 do while 1 do
if i > 10 then if i > 10 then
break break
end end
if i = 5 then
set i to i+1
continue
end
print_number(i)
set i to i+1 set i to i+1
end end
print_number(i)

View file

@ -360,12 +360,96 @@ int process_line(struct StateContainer* state, char* str)
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("recognize end state->blockStackAnchor: %d \n", state->blockStackAnchor); if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("recognize end state->blockStackAnchor: %d \n", state->blockStackAnchor);
if (state->skipping && int_stack_length(state->blockStack) == state->blockStackAnchor) { if (state->skipping && int_stack_length(state->blockStack) == state->blockStackAnchor) {
// end of skipping // end of skipping
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("end of skipping \n");
state->skipping = 0; state->skipping = 0;
} }
state->linePtr++; state->linePtr++;
return 1; return 1;
} }
struct IfStatement ifStatementParsing;
byte ifRecognized = recognize_if_statement(str, &ifStatementParsing);
struct WhileStatement whileStatementParsing;
byte whileRecognized = recognize_while_statement(str, &whileStatementParsing);
if (ifRecognized) {
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("If statement recognized express (%d:%d)\n", ifStatementParsing.expression_start, ifStatementParsing.expression_stop);
int_stack_push(state->blockStack, BLOCK_IF);
if (state->skipping) {
state->linePtr++;
return 1;
}
// expression to evaluate
int expressLen = ifStatementParsing.expression_stop - ifStatementParsing.expression_start;
char dest[len];
str_extract((char*) &dest, str, ifStatementParsing.expression_start, expressLen);
// printf("expression to eval in if '%s' \n", dest);
int res;
byte resType;
int evalStat = evaluate(state, (char*) &dest, &res, &resType);
if (evalStat != 0) {
printf("Syntax error for line \"%s\"\n", str);
return 0;
}
byte doFollow = convert_to_bool(resType, res);
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Got %s, doFollow: %d \n", get_repr(resType, &res), doFollow);
if (!doFollow) {
state->blockStackAnchor = int_stack_length(state->blockStack)-1;
state->skipping = 1;
}
state->linePtr++;
return 1;
}
if (whileRecognized) {
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("While statement recognized express (%d:%d)\n", whileStatementParsing.expression_start, whileStatementParsing.expression_stop);
int_stack_push(state->blockStack, BLOCK_WHILE);
if (state->skipping) {
state->linePtr++;
return 1;
}
// expression to evaluate
int expressLen = whileStatementParsing.expression_stop - whileStatementParsing.expression_start;
char dest[len];
str_extract((char*) &dest, str, whileStatementParsing.expression_start, expressLen);
// printf("expression to eval in if '%s' \n", dest);
int res;
byte resType;
int evalStat = evaluate(state, (char*) &dest, &res, &resType);
if (evalStat != 0) {
printf("Syntax error for line \"%s\"\n", str);
return 0;
}
byte doFollow = convert_to_bool(resType, res);
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Got %s, doFollow: %d \n", get_repr(resType, &res), doFollow);
if (doFollow) {
// follow the line
int_stack_push(state->loopStack, state->linePtr);
}
if (!doFollow) {
state->blockStackAnchor = int_stack_length(state->blockStack)-1;
state->skipping = 1;
}
state->linePtr++;
return 1;
}
if (state->skipping) {
// we've finish to analyse structure-aware blocks
state->linePtr++;
return 1;
}
if (recognize_word(str, "continue")) { if (recognize_word(str, "continue")) {
int lastLoopLine; int lastLoopLine;
if (!int_stack_pop(state->loopStack, &lastLoopLine)) { if (!int_stack_pop(state->loopStack, &lastLoopLine)) {
@ -400,23 +484,13 @@ int process_line(struct StateContainer* state, char* str)
if (state->blockStack->data[lastLoopAnchor] == BLOCK_WHILE) break; if (state->blockStack->data[lastLoopAnchor] == BLOCK_WHILE) break;
lastLoopAnchor--; lastLoopAnchor--;
} }
state->blockStackAnchor = lastLoopAnchor+1; state->blockStackAnchor = lastLoopAnchor;
state->skipping = 1; state->skipping = 1;
return 1;
}
struct IfStatement ifStatementParsing;
byte ifRecognized = recognize_if_statement(str, &ifStatementParsing);
struct WhileStatement whileStatementParsing;
byte whileRecognized = recognize_while_statement(str, &whileStatementParsing);
if (state->skipping) {
// we've finish to analyse structure-aware blocks
state->linePtr++; state->linePtr++;
return 1; return 1;
} }
struct SetStatement setStatementParsing; struct SetStatement setStatementParsing;
if (recognize_set_statement(str, &setStatementParsing)) { if (recognize_set_statement(str, &setStatementParsing)) {
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) { if (LINE_PROCESSING_DEBUG_LEVEL >= 2) {
@ -454,69 +528,6 @@ int process_line(struct StateContainer* state, char* str)
return 1; return 1;
} }
if (ifRecognized) {
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("If statement recognized express (%d:%d)\n", ifStatementParsing.expression_start, ifStatementParsing.expression_stop);
// expression to evaluate
int expressLen = ifStatementParsing.expression_stop - ifStatementParsing.expression_start;
char dest[len];
str_extract((char*) &dest, str, ifStatementParsing.expression_start, expressLen);
// printf("expression to eval in if '%s' \n", dest);
int res;
byte resType;
int evalStat = evaluate(state, (char*) &dest, &res, &resType);
if (evalStat != 0) {
printf("Syntax error for line \"%s\"\n", str);
return 0;
}
byte doFollow = convert_to_bool(resType, res);
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Got %s, doFollow: %d \n", get_repr(resType, &res), doFollow);
if (!doFollow) {
state->blockStackAnchor = int_stack_length(state->blockStack);
state->skipping = 1;
}
int_stack_push(state->blockStack, BLOCK_IF);
state->linePtr++;
return 1;
}
if (whileRecognized) {
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("While statement recognized express (%d:%d)\n", whileStatementParsing.expression_start, whileStatementParsing.expression_stop);
// expression to evaluate
int expressLen = whileStatementParsing.expression_stop - whileStatementParsing.expression_start;
char dest[len];
str_extract((char*) &dest, str, whileStatementParsing.expression_start, expressLen);
// printf("expression to eval in if '%s' \n", dest);
int res;
byte resType;
int evalStat = evaluate(state, (char*) &dest, &res, &resType);
if (evalStat != 0) {
printf("Syntax error for line \"%s\"\n", str);
return 0;
}
byte doFollow = convert_to_bool(resType, res);
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Got %s, doFollow: %d \n", get_repr(resType, &res), doFollow);
if (doFollow) {
// follow the line
int_stack_push(state->loopStack, state->linePtr);
}
if (!doFollow) {
state->blockStackAnchor = int_stack_length(state->blockStack);
state->skipping = 1;
}
int_stack_push(state->blockStack, BLOCK_WHILE);
state->linePtr++;
return 1;
}
// we evaluate but we dont care about the result // we evaluate but we dont care about the result
int res; int res;
byte resType; byte resType;

View file

@ -17,13 +17,13 @@
#define INTERACTIVE_FLAG 8 #define INTERACTIVE_FLAG 8
#define STDIN_EXP_FLAG 16 #define STDIN_EXP_FLAG 16
int help_mode() { int help_mode(char* cmdName) {
char* helpStr = "Usage: langatator [options] [file]\n" char* helpStr = "Usage: %s [options] [file]\n"
" -h --help print this usage and exit\n" " -h --help print this usage and exit\n"
" -v --version print version information and exit\n" " -v --version print version information and exit\n"
" -i --interactive force interactive mode\n" " -i --interactive force interactive mode\n"
" -e --stdin-expression evaluate expression from stdin\n"; " -e --stdin-expression evaluate expression from stdin\n";
printf(helpStr); printf(helpStr, cmdName);
return 0; return 0;
} }
@ -47,7 +47,7 @@ int file_mode(char* fileName) {
FILE* f = fopen(fileName, "rb"); FILE* f = fopen(fileName, "rb");
if (!f) { if (!f) {
printf(stderr, "Cannot load file '%s' status: %d\n", fileName, f); fprintf(stderr, "Cannot load file '%s' status: %d\n", fileName, (int) f);
return 1; return 1;
} }
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
@ -56,7 +56,7 @@ int file_mode(char* fileName) {
char* buff = (char*) malloc(length); char* buff = (char*) malloc(length);
if (!buff) { if (!buff) {
printf(stderr, "Could not allocate buffer to process file content\n"); fprintf(stderr, "Could not allocate buffer to process file content\n");
return 1; return 1;
} }
if (buff) { if (buff) {
@ -96,7 +96,7 @@ int main (int argc, char** argv) {
} }
// no flag match // no flag match
if (str_starts_with("--", argv[i])) { if (str_starts_with("--", argv[i])) {
printf(stderr, "Invalid flag '%s'\n", argv[i]); fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
return 1; return 1;
} }
nonFlagArgumentCount++; nonFlagArgumentCount++;
@ -104,11 +104,11 @@ int main (int argc, char** argv) {
} }
if (nonFlagArgumentCount == 1) return file_mode(argv[nonFlagArgumentPos]); if (nonFlagArgumentCount == 1) return file_mode(argv[nonFlagArgumentPos]);
if (flags & HELP_FLAG) return help_mode(); if (flags & HELP_FLAG) return help_mode(cmdName);
if (flags & VERSION_FLAG) return version_mode(); if (flags & VERSION_FLAG) return version_mode();
if (flags & INTERACTIVE_FLAG) return interactive_mode(); if (flags & INTERACTIVE_FLAG) return interactive_mode();
if (flags & STDIN_EXP_FLAG) return stdin_expression_mode(); if (flags & STDIN_EXP_FLAG) return stdin_expression_mode();
help_mode(); help_mode(cmdName);
return 1; return 1;
} }

View file

@ -115,4 +115,38 @@ void test_line_processing()
assert(!state2->skipping); assert(!state2->skipping);
printf("got i: %d \n", var_store_get_int(state2->varStore, "i")); printf("got i: %d \n", var_store_get_int(state2->varStore, "i"));
assert(9 == var_store_get_int(state2->varStore, "i")); assert(9 == var_store_get_int(state2->varStore, "i"));
// test break keyword
char* lines5 = "set i to 0\n"
"while 1 do\n"
" if (i = 10) then\n"
" break\n"
" end\n"
" set i to i+1\n"
"end\n";
process_script(state2, lines5);
assert(!state2->skipping);
printf("got i: %d \n", var_store_get_int(state2->varStore, "i"));
assert(10 == var_store_get_int(state2->varStore, "i"));
// test continue keyword
char* lines6 = "set sum to 0\n"
"set i to 0\n"
"while 1 do\n"
" if (i = 5) then\n"
" set i to i+1\n"
" continue\n"
" end\n"
" if (i = 10) then\n"
" break\n"
" end\n"
" set sum to sum+1\n"
" set i to i+1\n"
"end\n";
process_script(state2, lines6);
assert(!state2->skipping);
assert(10 == var_store_get_int(state2->varStore, "i"));
assert(9 == var_store_get_int(state2->varStore, "sum"));
} }