If and while (scoping coming soon)
This commit is contained in:
@@ -17,7 +17,10 @@ char* createCodegenError(char* what) {
|
|||||||
|
|
||||||
ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) {
|
ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) {
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case SNT_PUTS: {
|
case SNT_PUTS:
|
||||||
|
case SNT_IF:
|
||||||
|
case SNT_WHILE:
|
||||||
|
case SNT_CODE_BLOCK: {
|
||||||
return Error(SolsType, charptr, "Specified node does not return data");
|
return Error(SolsType, charptr, "Specified node does not return data");
|
||||||
}
|
}
|
||||||
case SNT_OP_SET: {
|
case SNT_OP_SET: {
|
||||||
@@ -560,10 +563,108 @@ ResultType(GroundProgram, charptr) generateCodeBlockNode(SolsNode* node, SolsSco
|
|||||||
return Success(GroundProgram, charptr, groundCreateProgram());
|
return Success(GroundProgram, charptr, groundCreateProgram());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline ResultType(GroundProgram, charptr) generateWhileNode(SolsNode* node, SolsScope* scope) {
|
||||||
|
GroundProgram gp = groundCreateProgram();
|
||||||
|
|
||||||
|
char* start_label = malloc(64);
|
||||||
|
snprintf(start_label, 64, "__SOLS_WHILE_START_%zu", scope->tmpCounter++);
|
||||||
|
|
||||||
|
char* end_label = malloc(64);
|
||||||
|
snprintf(end_label, 64, "__SOLS_WHILE_END_%zu", scope->tmpCounter++);
|
||||||
|
|
||||||
|
GroundInstruction start_label_inst = groundCreateInstruction(CREATELABEL);
|
||||||
|
groundAddReferenceToInstruction(&start_label_inst, groundCreateReference(LABEL, start_label));
|
||||||
|
groundAddInstructionToProgram(&gp, start_label_inst);
|
||||||
|
|
||||||
|
ResultType(GroundProgram, charptr) cond_code = generateCode(&node->children.at[0], scope);
|
||||||
|
if (cond_code.error) return cond_code;
|
||||||
|
for (size_t i = 0; i < cond_code.as.success.size; i++) {
|
||||||
|
groundAddInstructionToProgram(&gp, cond_code.as.success.instructions[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultType(SolsType, charptr) type = getNodeType(&node->children.at[0], scope);
|
||||||
|
if (type.error) return Error(GroundProgram, charptr, type.as.error);
|
||||||
|
if (type.as.success.type != STT_BOOL) {
|
||||||
|
return Error(GroundProgram, charptr, "While condition must be a boolean");
|
||||||
|
}
|
||||||
|
|
||||||
|
char* tmp_inverted_cond = malloc(64);
|
||||||
|
snprintf(tmp_inverted_cond, 64, "__SOLS_IF_COND_NOT_%zu", scope->tmpCounter++);
|
||||||
|
GroundInstruction not_inst = groundCreateInstruction(NOT);
|
||||||
|
groundAddReferenceToInstruction(¬_inst, node->children.at[0].accessArg);
|
||||||
|
groundAddReferenceToInstruction(¬_inst, groundCreateReference(DIRREF, tmp_inverted_cond));
|
||||||
|
groundAddInstructionToProgram(&gp, not_inst);
|
||||||
|
|
||||||
|
GroundInstruction if_inst = groundCreateInstruction(IF);
|
||||||
|
groundAddReferenceToInstruction(&if_inst, groundCreateReference(VALREF, tmp_inverted_cond));
|
||||||
|
groundAddReferenceToInstruction(&if_inst, groundCreateReference(LINEREF, end_label));
|
||||||
|
groundAddInstructionToProgram(&gp, if_inst);
|
||||||
|
|
||||||
|
ResultType(GroundProgram, charptr) body_code = generateCode(&node->children.at[1], scope);
|
||||||
|
if (body_code.error) return body_code;
|
||||||
|
for (size_t i = 0; i < body_code.as.success.size; i++) {
|
||||||
|
groundAddInstructionToProgram(&gp, body_code.as.success.instructions[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundInstruction jump_inst = groundCreateInstruction(JUMP);
|
||||||
|
groundAddReferenceToInstruction(&jump_inst, groundCreateReference(LINEREF, start_label));
|
||||||
|
groundAddInstructionToProgram(&gp, jump_inst);
|
||||||
|
|
||||||
|
GroundInstruction end_label_inst = groundCreateInstruction(CREATELABEL);
|
||||||
|
groundAddReferenceToInstruction(&end_label_inst, groundCreateReference(LABEL, end_label));
|
||||||
|
groundAddInstructionToProgram(&gp, end_label_inst);
|
||||||
|
|
||||||
|
return Success(GroundProgram, charptr, gp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ResultType(GroundProgram, charptr) generateIfNode(SolsNode* node, SolsScope* scope) {
|
||||||
|
GroundProgram gp = groundCreateProgram();
|
||||||
|
|
||||||
|
ResultType(GroundProgram, charptr) cond_code = generateCode(&node->children.at[0], scope);
|
||||||
|
if (cond_code.error) return cond_code;
|
||||||
|
for (size_t i = 0; i < cond_code.as.success.size; i++) {
|
||||||
|
groundAddInstructionToProgram(&gp, cond_code.as.success.instructions[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultType(SolsType, charptr) type = getNodeType(&node->children.at[0], scope);
|
||||||
|
if (type.error) return Error(GroundProgram, charptr, type.as.error);
|
||||||
|
if (type.as.success.type != STT_BOOL) {
|
||||||
|
return Error(GroundProgram, charptr, "If condition must be a boolean");
|
||||||
|
}
|
||||||
|
|
||||||
|
char* end_label = malloc(64);
|
||||||
|
snprintf(end_label, 64, "__SOLS_IF_END_%zu", scope->tmpCounter++);
|
||||||
|
|
||||||
|
char* tmp_inverted_cond = malloc(64);
|
||||||
|
snprintf(tmp_inverted_cond, 64, "__SOLS_IF_COND_NOT_%zu", scope->tmpCounter++);
|
||||||
|
GroundInstruction not_inst = groundCreateInstruction(NOT);
|
||||||
|
groundAddReferenceToInstruction(¬_inst, node->children.at[0].accessArg);
|
||||||
|
groundAddReferenceToInstruction(¬_inst, groundCreateReference(DIRREF, tmp_inverted_cond));
|
||||||
|
groundAddInstructionToProgram(&gp, not_inst);
|
||||||
|
|
||||||
|
GroundInstruction if_inst = groundCreateInstruction(IF);
|
||||||
|
groundAddReferenceToInstruction(&if_inst, groundCreateReference(VALREF, tmp_inverted_cond));
|
||||||
|
groundAddReferenceToInstruction(&if_inst, groundCreateReference(LINEREF, end_label));
|
||||||
|
groundAddInstructionToProgram(&gp, if_inst);
|
||||||
|
|
||||||
|
ResultType(GroundProgram, charptr) body_code = generateCode(&node->children.at[1], scope);
|
||||||
|
if (body_code.error) return body_code;
|
||||||
|
for (size_t i = 0; i < body_code.as.success.size; i++) {
|
||||||
|
groundAddInstructionToProgram(&gp, body_code.as.success.instructions[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundInstruction label_inst = groundCreateInstruction(CREATELABEL);
|
||||||
|
groundAddReferenceToInstruction(&label_inst, groundCreateReference(LABEL, end_label));
|
||||||
|
groundAddInstructionToProgram(&gp, label_inst);
|
||||||
|
|
||||||
|
return Success(GroundProgram, charptr, gp);
|
||||||
|
}
|
||||||
|
|
||||||
ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope) {
|
ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope) {
|
||||||
|
|
||||||
GroundProgram program = groundCreateProgram();
|
GroundProgram program = groundCreateProgram();
|
||||||
|
|
||||||
|
if (node->type != SNT_IF && node->type != SNT_WHILE) {
|
||||||
// Generate code for all children before generating this node's code
|
// Generate code for all children before generating this node's code
|
||||||
for (size_t i = 0; i < node->children.count; i++) {
|
for (size_t i = 0; i < node->children.count; i++) {
|
||||||
ResultType(GroundProgram, charptr) generated = generateCode(&node->children.at[i], scope);
|
ResultType(GroundProgram, charptr) generated = generateCode(&node->children.at[i], scope);
|
||||||
@@ -574,6 +675,7 @@ ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope
|
|||||||
groundAddInstructionToProgram(&program, generated.as.success.instructions[j]);
|
groundAddInstructionToProgram(&program, generated.as.success.instructions[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Now generate code for this node
|
// Now generate code for this node
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
@@ -591,6 +693,8 @@ ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope
|
|||||||
case SNT_OP_LESSER: generate(Lesser);
|
case SNT_OP_LESSER: generate(Lesser);
|
||||||
case SNT_OP_EQLESSER: generate(EqLesser);
|
case SNT_OP_EQLESSER: generate(EqLesser);
|
||||||
case SNT_CODE_BLOCK: generate(CodeBlock);
|
case SNT_CODE_BLOCK: generate(CodeBlock);
|
||||||
|
case SNT_IF: generate(If);
|
||||||
|
case SNT_WHILE: generate(While);
|
||||||
}
|
}
|
||||||
return Success(GroundProgram, charptr, program);
|
return Success(GroundProgram, charptr, program);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ SolsTokenPrecedence getPrecedence(SolsToken *token) {
|
|||||||
switch (token->type) {
|
switch (token->type) {
|
||||||
case STT_LINE_END: return STP_NEWLINE;
|
case STT_LINE_END: return STP_NEWLINE;
|
||||||
case STT_KW_PUTS: return STP_PUTS;
|
case STT_KW_PUTS: return STP_PUTS;
|
||||||
|
case STT_KW_IF: return STP_IF;
|
||||||
|
case STT_KW_WHILE: return STP_WHILE;
|
||||||
case STT_OP_ADDTO:
|
case STT_OP_ADDTO:
|
||||||
case STT_OP_SUBTO:
|
case STT_OP_SUBTO:
|
||||||
case STT_OP_MULTO:
|
case STT_OP_MULTO:
|
||||||
@@ -998,6 +1000,130 @@ static inline ResultType(Nothing, charptr) parseCodeBlock(SolsParser* parser) {
|
|||||||
return Success(Nothing, charptr, {});
|
return Success(Nothing, charptr, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline ResultType(Nothing, charptr) parseWhile(SolsParser* parser) {
|
||||||
|
// Collect tokens for node
|
||||||
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
||||||
|
if (tokens.error) {
|
||||||
|
return Error(Nothing, charptr, tokens.as.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
||||||
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
||||||
|
if (peek.error) break;
|
||||||
|
if (peek.as.success.type == STT_OPEN_CURLY) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parserConsume(parser);
|
||||||
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create node
|
||||||
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_WHILE);
|
||||||
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
||||||
|
node.as.success.line = peek.as.success.line;
|
||||||
|
|
||||||
|
// Parse selected tokens
|
||||||
|
ResultType(SolsParser, charptr) whileParser = createSolsParser(&tokens.as.success);
|
||||||
|
if (whileParser.error) return Error(Nothing, charptr, whileParser.as.error);
|
||||||
|
whileParser.as.success.currentParent = &whileParser.as.success.output;
|
||||||
|
ResultType(Nothing, charptr) parsed = parse(&whileParser.as.success);
|
||||||
|
|
||||||
|
// Add any error messages from parsing
|
||||||
|
if (parsed.error) {
|
||||||
|
addToParserErrors(parser, parsed.as.error);
|
||||||
|
return Success(Nothing, charptr, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy nodes into the sols node
|
||||||
|
for (size_t i = 0; i < whileParser.as.success.output.children.count; i++) {
|
||||||
|
addChildToSolsNode(&node.as.success, whileParser.as.success.output.children.at[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
||||||
|
|
||||||
|
if(parserPeek(parser, 1).as.success.type != STT_OPEN_CURLY) {
|
||||||
|
return Error(Nothing, charptr, "Expecting opening curly brace for while loop body");
|
||||||
|
}
|
||||||
|
|
||||||
|
parserConsume(parser);
|
||||||
|
|
||||||
|
ResultType(Nothing, charptr) res = parseCodeBlock(parser);
|
||||||
|
if(res.error) return res;
|
||||||
|
|
||||||
|
// Last child of parent is code block, we need to move it
|
||||||
|
SolsNode codeBlock = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
||||||
|
parser->currentParent->children.count--;
|
||||||
|
addChildToSolsNode(&node.as.success, codeBlock);
|
||||||
|
|
||||||
|
|
||||||
|
return Success(Nothing, charptr, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ResultType(Nothing, charptr) parseIf(SolsParser* parser) {
|
||||||
|
// Collect tokens for node
|
||||||
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
||||||
|
if (tokens.error) {
|
||||||
|
return Error(Nothing, charptr, tokens.as.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
||||||
|
if (peek.error) return Error(Nothing, charptr, "ruh roh");
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 1);
|
||||||
|
if (peek.error) break;
|
||||||
|
if (peek.as.success.type == STT_OPEN_CURLY) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parserConsume(parser);
|
||||||
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create node
|
||||||
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_IF);
|
||||||
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
||||||
|
node.as.success.line = peek.as.success.line;
|
||||||
|
|
||||||
|
// Parse selected tokens
|
||||||
|
ResultType(SolsParser, charptr) ifParser = createSolsParser(&tokens.as.success);
|
||||||
|
if (ifParser.error) return Error(Nothing, charptr, ifParser.as.error);
|
||||||
|
ifParser.as.success.currentParent = &ifParser.as.success.output;
|
||||||
|
ResultType(Nothing, charptr) parsed = parse(&ifParser.as.success);
|
||||||
|
|
||||||
|
// Add any error messages from parsing
|
||||||
|
if (parsed.error) {
|
||||||
|
addToParserErrors(parser, parsed.as.error);
|
||||||
|
return Success(Nothing, charptr, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy nodes into the sols node
|
||||||
|
for (size_t i = 0; i < ifParser.as.success.output.children.count; i++) {
|
||||||
|
addChildToSolsNode(&node.as.success, ifParser.as.success.output.children.at[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
||||||
|
|
||||||
|
if(parserPeek(parser, 1).as.success.type != STT_OPEN_CURLY) {
|
||||||
|
return Error(Nothing, charptr, "Expecting opening curly brace for if statement body");
|
||||||
|
}
|
||||||
|
|
||||||
|
parserConsume(parser);
|
||||||
|
|
||||||
|
ResultType(Nothing, charptr) res = parseCodeBlock(parser);
|
||||||
|
if(res.error) return res;
|
||||||
|
|
||||||
|
// Last child of parent is code block, we need to move it
|
||||||
|
SolsNode codeBlock = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
||||||
|
parser->currentParent->children.count--;
|
||||||
|
addChildToSolsNode(&node.as.success, codeBlock);
|
||||||
|
|
||||||
|
|
||||||
|
return Success(Nothing, charptr, {});
|
||||||
|
}
|
||||||
|
|
||||||
static inline ResultType(Nothing, charptr) parseCloseCurly(SolsParser* parser) {
|
static inline ResultType(Nothing, charptr) parseCloseCurly(SolsParser* parser) {
|
||||||
(void)parser;
|
(void)parser;
|
||||||
return Error(Nothing, charptr, "Extra closing curly brace");
|
return Error(Nothing, charptr, "Extra closing curly brace");
|
||||||
@@ -1014,6 +1140,8 @@ ResultType(Nothing, charptr) parse(SolsParser* parser) {
|
|||||||
case STT_IDENTIFIER: PARSER_HANDLE(Identifier);
|
case STT_IDENTIFIER: PARSER_HANDLE(Identifier);
|
||||||
case STT_LITERAL: PARSER_HANDLE(Literal);
|
case STT_LITERAL: PARSER_HANDLE(Literal);
|
||||||
case STT_KW_PUTS: PARSER_HANDLE(Puts);
|
case STT_KW_PUTS: PARSER_HANDLE(Puts);
|
||||||
|
case STT_KW_IF: PARSER_HANDLE(If);
|
||||||
|
case STT_KW_WHILE: PARSER_HANDLE(While);
|
||||||
case STT_OP_SET: PARSER_HANDLE(Set);
|
case STT_OP_SET: PARSER_HANDLE(Set);
|
||||||
case STT_OP_ADD: PARSER_HANDLE(Add);
|
case STT_OP_ADD: PARSER_HANDLE(Add);
|
||||||
case STT_OP_SUB: PARSER_HANDLE(Sub);
|
case STT_OP_SUB: PARSER_HANDLE(Sub);
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
typedef enum SolsTokenPrecedence {
|
typedef enum SolsTokenPrecedence {
|
||||||
STP_NEWLINE = 0,
|
STP_NEWLINE = 0,
|
||||||
STP_PUTS = 1,
|
STP_PUTS = 1,
|
||||||
|
STP_IF = 1,
|
||||||
|
STP_WHILE = 1,
|
||||||
STP_COMPARE = 2,
|
STP_COMPARE = 2,
|
||||||
STP_SET = 3,
|
STP_SET = 3,
|
||||||
STP_FUNCTION = 4,
|
STP_FUNCTION = 4,
|
||||||
|
|||||||
40
test.sols
40
test.sols
@@ -1,33 +1,15 @@
|
|||||||
// heheheha comment
|
a = 0
|
||||||
|
b = 1
|
||||||
|
n = 92
|
||||||
|
|
||||||
x = 5
|
i = 0
|
||||||
puts x + 3
|
|
||||||
puts 5 * 7
|
|
||||||
puts 3.0 / 2
|
|
||||||
puts 10 - 3
|
|
||||||
puts "dingle" + "dongle"
|
|
||||||
|
|
||||||
// Uh oh it's the order of operations
|
while i != n {
|
||||||
|
temp = a + b
|
||||||
|
a = b
|
||||||
|
b = temp
|
||||||
|
|
||||||
puts 5 + 3 * 7
|
i = i + 1
|
||||||
puts 5 * 3 + 7
|
|
||||||
|
|
||||||
// Let's do some equalities
|
|
||||||
puts 5 == 5
|
|
||||||
puts 3 == 2
|
|
||||||
puts "dingus" == "dongus"
|
|
||||||
puts 3.14 == 3.14
|
|
||||||
puts 3 + 5 == 3 + 5
|
|
||||||
|
|
||||||
// And now some of the other thingys
|
|
||||||
puts 3 > 5
|
|
||||||
puts 3 < 5
|
|
||||||
|
|
||||||
puts 10 != 3
|
|
||||||
puts 3 >= 2
|
|
||||||
puts 3 >= 3
|
|
||||||
|
|
||||||
// Put stuff inside a code block, what could possibly go wrong
|
|
||||||
{
|
|
||||||
puts "Hi from the code block!"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
puts a
|
||||||
|
|||||||
Reference in New Issue
Block a user