diff --git a/Sources/backends/cstyle.c b/Sources/backends/cstyle.c index da5e08d..f9c976b 100644 --- a/Sources/backends/cstyle.c +++ b/Sources/backends/cstyle.c @@ -170,11 +170,21 @@ void cstyle_write_opcode(char *code, size_t *offset, opcode *o, type_string_func break; } case OPCODE_IF: { - *offset += sprintf(&code[*offset], "\tif (_%" PRIu64 ")\n", o->op_if.condition.index); - break; - } - case OPCODE_ELSE: { - *offset += sprintf(&code[*offset], "\telse\n"); + if (o->op_if.condition.index != 0) { + *offset += sprintf(&code[*offset], "\tif (_%" PRIu64, o->op_if.condition.index); + } + else { + *offset += sprintf(&code[*offset], "\tif ("); + } + for (uint8_t i = 0; i < o->op_if.exclusions_size; ++i) { + if (i == 0 && o->op_if.condition.index == 0) { + *offset += sprintf(&code[*offset], "!_%" PRIu64, o->op_if.exclusions[i].index); + } + else { + *offset += sprintf(&code[*offset], " && !_%" PRIu64, o->op_if.exclusions[i].index); + } + } + *offset += sprintf(&code[*offset], ")\n"); break; } case OPCODE_WHILE_START: { diff --git a/Sources/compiler.c b/Sources/compiler.c index fc39f75..cf24ad5 100644 --- a/Sources/compiler.c +++ b/Sources/compiler.c @@ -539,30 +539,56 @@ void emit_statement(opcodes *code, block *parent, statement *statement) { break; } case STATEMENT_IF: { + variable previous_conditions[64]; + uint8_t previous_conditions_size = 0; + { opcode o; o.type = OPCODE_IF; o.size = OP_SIZE(o, op_if); - variable v = emit_expression(code, parent, statement->iffy.test); + variable initial_condition = emit_expression(code, parent, statement->iffy.test); - o.op_if.condition = v; + o.op_if.condition = initial_condition; + o.op_if.exclusions_size = 0; emit_op(code, &o); + + previous_conditions[previous_conditions_size] = initial_condition; + previous_conditions_size += 1; } emit_statement(code, parent, statement->iffy.if_block); - if (statement->iffy.else_block != NULL) { + for (uint16_t i = 0; i < statement->iffy.else_size; ++i) { opcode o; - o.type = OPCODE_ELSE; - o.size = OP_SIZE(o, op_nothing); + o.type = OPCODE_IF; + o.size = OP_SIZE(o, op_if) + sizeof(variable) * i; + + for (uint8_t previous_condition_index = 0; previous_condition_index < previous_conditions_size; ++previous_condition_index) { + o.op_if.exclusions[previous_condition_index] = previous_conditions[previous_condition_index]; + } + o.op_if.exclusions_size = previous_conditions_size; + + if (statement->iffy.else_tests[i] != NULL) { + variable v = emit_expression(code, parent, statement->iffy.else_tests[i]); + o.op_if.condition = v; + + previous_conditions[previous_conditions_size] = v; + previous_conditions_size += 1; + } + else { + o.op_if.condition.index = 0; + o.op_if.condition.kind = VARIABLE_GLOBAL; + o.op_if.condition.type.name = NO_NAME; + o.op_if.condition.type.type = NO_TYPE; + } emit_op(code, &o); - emit_statement(code, parent, statement->iffy.else_block); + emit_statement(code, parent, statement->iffy.else_blocks[i]); } - + break; } case STATEMENT_WHILE: { diff --git a/Sources/compiler.h b/Sources/compiler.h index 656873f..1c85dac 100644 --- a/Sources/compiler.h +++ b/Sources/compiler.h @@ -45,7 +45,6 @@ typedef struct opcode { OPCODE_AND, OPCODE_OR, OPCODE_IF, - OPCODE_ELSE, OPCODE_WHILE_START, OPCODE_WHILE_CONDITION, OPCODE_WHILE_END, @@ -102,6 +101,8 @@ typedef struct opcode { } op_binary; struct { variable condition; + uint8_t exclusions_size; + variable exclusions[1]; } op_if; struct { variable condition; diff --git a/Sources/kong.c b/Sources/kong.c index ebbc76e..206da5d 100644 --- a/Sources/kong.c +++ b/Sources/kong.c @@ -272,8 +272,11 @@ void resolve_types_in_block(statement *parent, statement *block) { case STATEMENT_IF: { resolve_types_in_expression(block, s->iffy.test); resolve_types_in_block(block, s->iffy.if_block); - if (s->iffy.else_block != NULL) { - resolve_types_in_block(block, s->iffy.else_block); + for (uint16_t i = 0; i < s->iffy.else_size; ++i) { + if (s->iffy.else_tests[i] != NULL) { + resolve_types_in_expression(block, s->iffy.else_tests[i]); + } + resolve_types_in_block(block, s->iffy.else_blocks[i]); } break; } diff --git a/Sources/parser.c b/Sources/parser.c index 6944ec8..f53dd47 100644 --- a/Sources/parser.c +++ b/Sources/parser.c @@ -306,14 +306,33 @@ static statement *parse_statement(state_t *state, block *parent_block) { s->iffy.test = test; s->iffy.if_block = if_block; - if (current(state).kind == TOKEN_ELSE) { + s->iffy.else_size = 0; + + while (current(state).kind == TOKEN_ELSE) { advance_state(state); - statement *else_block = parse_statement(state, parent_block); - s->iffy.else_block = else_block; - } - else { - s->iffy.else_block = NULL; + if (current(state).kind == TOKEN_IF) { + advance_state(state); + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + expression *test = parse_expression(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + + statement *if_block = parse_statement(state, parent_block); + + s->iffy.else_tests[s->iffy.else_size] = test; + s->iffy.else_blocks[s->iffy.else_size] = if_block; + } + else { + statement *else_block = parse_statement(state, parent_block); + s->iffy.else_tests[s->iffy.else_size] = NULL; + s->iffy.else_blocks[s->iffy.else_size] = else_block; + } + + s->iffy.else_size += 1; + assert(s->iffy.else_size < 64); } return s; diff --git a/Sources/parser.h b/Sources/parser.h index 6e1fc2e..0147ceb 100644 --- a/Sources/parser.h +++ b/Sources/parser.h @@ -103,7 +103,9 @@ typedef struct statement { struct { expression *test; struct statement *if_block; - struct statement *else_block; + expression *else_tests[64]; + struct statement *else_blocks[64]; + uint16_t else_size; } iffy; struct { expression *test;