Math stuff (with order of operations yay)
This commit is contained in:
@@ -64,6 +64,39 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) {
|
|||||||
}
|
}
|
||||||
return Error(SolsType, charptr, "Cannot add these types together");
|
return Error(SolsType, charptr, "Cannot add these types together");
|
||||||
}
|
}
|
||||||
|
case SNT_OP_MUL:
|
||||||
|
case SNT_OP_DIV:
|
||||||
|
case SNT_OP_SUB: {
|
||||||
|
if (node->children.count < 2) {
|
||||||
|
return Error(SolsType, charptr, "Not enough children to determine type");
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultType(SolsType, charptr) leftType = getNodeType(&node->children.at[0], scope);
|
||||||
|
if (leftType.error) {
|
||||||
|
return Error(SolsType, charptr, leftType.as.error);
|
||||||
|
}
|
||||||
|
ResultType(SolsType, charptr) rightType = getNodeType(&node->children.at[1], scope);
|
||||||
|
if (rightType.error) {
|
||||||
|
return Error(SolsType, charptr, rightType.as.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(leftType.as.success.type == STT_INT || leftType.as.success.type == STT_DOUBLE)) {
|
||||||
|
return Error(SolsType, charptr, "Cannot operate on left type");
|
||||||
|
}
|
||||||
|
if (!(rightType.as.success.type == STT_INT || rightType.as.success.type == STT_DOUBLE)) {
|
||||||
|
return Error(SolsType, charptr, "Cannot operate on right type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leftType.as.success.type == rightType.as.success.type) {
|
||||||
|
return Success(SolsType, charptr, leftType.as.success);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultType(SolsType, charptr) type = createSolsType(STT_DOUBLE);
|
||||||
|
if (type.error) {
|
||||||
|
return Error(SolsType, charptr, type.as.error);
|
||||||
|
}
|
||||||
|
return Success(SolsType, charptr, type.as.success);
|
||||||
|
}
|
||||||
case SNT_LITERAL: {
|
case SNT_LITERAL: {
|
||||||
switch (node->as.literal.type) {
|
switch (node->as.literal.type) {
|
||||||
case SLT_INT: {
|
case SLT_INT: {
|
||||||
@@ -179,6 +212,96 @@ static inline ResultType(GroundProgram, charptr) generateAddNode(SolsNode* node,
|
|||||||
return Success(GroundProgram, charptr, gp);
|
return Success(GroundProgram, charptr, gp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline ResultType(GroundProgram, charptr) generateSubNode(SolsNode* node, SolsScope* scope) {
|
||||||
|
if (node->children.count < 2) {
|
||||||
|
return Error(GroundProgram, charptr, "sub requires arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use this function for type checking
|
||||||
|
ResultType(SolsType, charptr) type = getNodeType(node, scope);
|
||||||
|
if (type.error) {
|
||||||
|
return Error(GroundProgram, charptr, type.as.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundProgram gp = groundCreateProgram();
|
||||||
|
GroundInstruction add = groundCreateInstruction(SUBTRACT);
|
||||||
|
groundAddReferenceToInstruction(&add, node->children.at[0].accessArg);
|
||||||
|
groundAddReferenceToInstruction(&add, node->children.at[1].accessArg);
|
||||||
|
|
||||||
|
char* tmpId = malloc(sizeof(char) * 64);
|
||||||
|
if (tmpId == NULL) {
|
||||||
|
return Error(GroundProgram, charptr, "Failed to allocate memory for temporary identifier in subtract");
|
||||||
|
}
|
||||||
|
snprintf(tmpId, 64, "__SOLS_TMP_SUB_%zu", scope->tmpCounter++);
|
||||||
|
|
||||||
|
groundAddReferenceToInstruction(&add, groundCreateReference(DIRREF, tmpId));
|
||||||
|
|
||||||
|
node->accessArg = groundCreateReference(VALREF, tmpId);
|
||||||
|
|
||||||
|
groundAddInstructionToProgram(&gp, add);
|
||||||
|
return Success(GroundProgram, charptr, gp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ResultType(GroundProgram, charptr) generateMulNode(SolsNode* node, SolsScope* scope) {
|
||||||
|
if (node->children.count < 2) {
|
||||||
|
return Error(GroundProgram, charptr, "mul requires arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use this function for type checking
|
||||||
|
ResultType(SolsType, charptr) type = getNodeType(node, scope);
|
||||||
|
if (type.error) {
|
||||||
|
return Error(GroundProgram, charptr, type.as.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundProgram gp = groundCreateProgram();
|
||||||
|
GroundInstruction add = groundCreateInstruction(MULTIPLY);
|
||||||
|
groundAddReferenceToInstruction(&add, node->children.at[0].accessArg);
|
||||||
|
groundAddReferenceToInstruction(&add, node->children.at[1].accessArg);
|
||||||
|
|
||||||
|
char* tmpId = malloc(sizeof(char) * 64);
|
||||||
|
if (tmpId == NULL) {
|
||||||
|
return Error(GroundProgram, charptr, "Failed to allocate memory for temporary identifier in multiply");
|
||||||
|
}
|
||||||
|
snprintf(tmpId, 64, "__SOLS_TMP_MUL_%zu", scope->tmpCounter++);
|
||||||
|
|
||||||
|
groundAddReferenceToInstruction(&add, groundCreateReference(DIRREF, tmpId));
|
||||||
|
|
||||||
|
node->accessArg = groundCreateReference(VALREF, tmpId);
|
||||||
|
|
||||||
|
groundAddInstructionToProgram(&gp, add);
|
||||||
|
return Success(GroundProgram, charptr, gp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ResultType(GroundProgram, charptr) generateDivNode(SolsNode* node, SolsScope* scope) {
|
||||||
|
if (node->children.count < 2) {
|
||||||
|
return Error(GroundProgram, charptr, "div requires arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use this function for type checking
|
||||||
|
ResultType(SolsType, charptr) type = getNodeType(node, scope);
|
||||||
|
if (type.error) {
|
||||||
|
return Error(GroundProgram, charptr, type.as.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundProgram gp = groundCreateProgram();
|
||||||
|
GroundInstruction add = groundCreateInstruction(DIVIDE);
|
||||||
|
groundAddReferenceToInstruction(&add, node->children.at[0].accessArg);
|
||||||
|
groundAddReferenceToInstruction(&add, node->children.at[1].accessArg);
|
||||||
|
|
||||||
|
char* tmpId = malloc(sizeof(char) * 64);
|
||||||
|
if (tmpId == NULL) {
|
||||||
|
return Error(GroundProgram, charptr, "Failed to allocate memory for temporary identifier in divide");
|
||||||
|
}
|
||||||
|
snprintf(tmpId, 64, "__SOLS_TMP_DIV_%zu", scope->tmpCounter++);
|
||||||
|
|
||||||
|
groundAddReferenceToInstruction(&add, groundCreateReference(DIRREF, tmpId));
|
||||||
|
|
||||||
|
node->accessArg = groundCreateReference(VALREF, tmpId);
|
||||||
|
|
||||||
|
groundAddInstructionToProgram(&gp, add);
|
||||||
|
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();
|
||||||
@@ -200,6 +323,9 @@ ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope
|
|||||||
case SNT_LITERAL: generate(Literal);
|
case SNT_LITERAL: generate(Literal);
|
||||||
case SNT_OP_SET: generate(Set);
|
case SNT_OP_SET: generate(Set);
|
||||||
case SNT_OP_ADD: generate(Add);
|
case SNT_OP_ADD: generate(Add);
|
||||||
|
case SNT_OP_SUB: generate(Sub);
|
||||||
|
case SNT_OP_MUL: generate(Mul);
|
||||||
|
case SNT_OP_DIV: generate(Div);
|
||||||
}
|
}
|
||||||
return Success(GroundProgram, charptr, program);
|
return Success(GroundProgram, charptr, program);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -277,6 +277,196 @@ static inline ResultType(Nothing, charptr) parseAdd(SolsParser* parser) {
|
|||||||
return Success(Nothing, charptr, {});
|
return Success(Nothing, charptr, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline ResultType(Nothing, charptr) parseSub(SolsParser* parser) {
|
||||||
|
if (parser->currentParent->children.count < 1) {
|
||||||
|
return Error(Nothing, charptr, "Expecting something before '-'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect tokens for node
|
||||||
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
||||||
|
if (tokens.error) {
|
||||||
|
return Error(Nothing, charptr, tokens.as.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the previous node
|
||||||
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
||||||
|
|
||||||
|
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 (getPrecedence(&peek.as.success) <= STP_ADD) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parserConsume(parser);
|
||||||
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create node
|
||||||
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_SUB);
|
||||||
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
||||||
|
node.as.success.line = peek.as.success.line;
|
||||||
|
|
||||||
|
// Parse selected tokens
|
||||||
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
||||||
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
||||||
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
||||||
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
||||||
|
|
||||||
|
// Add any error messages from parsing
|
||||||
|
if (parsed.error) {
|
||||||
|
addToParserErrors(parser, parsed.as.error);
|
||||||
|
return Success(Nothing, charptr, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (putsParser.as.success.output.children.count < 1) {
|
||||||
|
return Error(Nothing, charptr, "Expecting token after '-'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy idnode into set node
|
||||||
|
addChildToSolsNode(&node.as.success, idNode);
|
||||||
|
|
||||||
|
// Copy nodes into the set node
|
||||||
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
||||||
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put the set node where the idNode was
|
||||||
|
parser->currentParent->children.count--;
|
||||||
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
||||||
|
|
||||||
|
return Success(Nothing, charptr, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ResultType(Nothing, charptr) parseMul(SolsParser* parser) {
|
||||||
|
if (parser->currentParent->children.count < 1) {
|
||||||
|
return Error(Nothing, charptr, "Expecting something before '*'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect tokens for node
|
||||||
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
||||||
|
if (tokens.error) {
|
||||||
|
return Error(Nothing, charptr, tokens.as.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the previous node
|
||||||
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
||||||
|
|
||||||
|
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 (getPrecedence(&peek.as.success) <= STP_MUL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parserConsume(parser);
|
||||||
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create node
|
||||||
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_MUL);
|
||||||
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
||||||
|
node.as.success.line = peek.as.success.line;
|
||||||
|
|
||||||
|
// Parse selected tokens
|
||||||
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
||||||
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
||||||
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
||||||
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
||||||
|
|
||||||
|
// Add any error messages from parsing
|
||||||
|
if (parsed.error) {
|
||||||
|
addToParserErrors(parser, parsed.as.error);
|
||||||
|
return Success(Nothing, charptr, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (putsParser.as.success.output.children.count < 1) {
|
||||||
|
return Error(Nothing, charptr, "Expecting token after '*'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy idnode into set node
|
||||||
|
addChildToSolsNode(&node.as.success, idNode);
|
||||||
|
|
||||||
|
// Copy nodes into the set node
|
||||||
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
||||||
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put the set node where the idNode was
|
||||||
|
parser->currentParent->children.count--;
|
||||||
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
||||||
|
|
||||||
|
return Success(Nothing, charptr, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ResultType(Nothing, charptr) parseDiv(SolsParser* parser) {
|
||||||
|
if (parser->currentParent->children.count < 1) {
|
||||||
|
return Error(Nothing, charptr, "Expecting something before '/'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect tokens for node
|
||||||
|
ResultType(SolsTokens, charptr) tokens = createSolsTokens();
|
||||||
|
if (tokens.error) {
|
||||||
|
return Error(Nothing, charptr, tokens.as.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the previous node
|
||||||
|
SolsNode idNode = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
||||||
|
|
||||||
|
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 (getPrecedence(&peek.as.success) <= STP_MUL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parserConsume(parser);
|
||||||
|
addTokenToSolsTokens(&tokens.as.success, peek.as.success);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create node
|
||||||
|
ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_SUB);
|
||||||
|
if (node.error) return Error(Nothing, charptr, node.as.error);
|
||||||
|
node.as.success.line = peek.as.success.line;
|
||||||
|
|
||||||
|
// Parse selected tokens
|
||||||
|
ResultType(SolsParser, charptr) putsParser = createSolsParser(&tokens.as.success);
|
||||||
|
if (putsParser.error) return Error(Nothing, charptr, putsParser.as.error);
|
||||||
|
putsParser.as.success.currentParent = &putsParser.as.success.output;
|
||||||
|
ResultType(Nothing, charptr) parsed = parse(&putsParser.as.success);
|
||||||
|
|
||||||
|
// Add any error messages from parsing
|
||||||
|
if (parsed.error) {
|
||||||
|
addToParserErrors(parser, parsed.as.error);
|
||||||
|
return Success(Nothing, charptr, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (putsParser.as.success.output.children.count < 1) {
|
||||||
|
return Error(Nothing, charptr, "Expecting token after '/'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy idnode into set node
|
||||||
|
addChildToSolsNode(&node.as.success, idNode);
|
||||||
|
|
||||||
|
// Copy nodes into the set node
|
||||||
|
for (size_t i = 0; i < putsParser.as.success.output.children.count; i++) {
|
||||||
|
addChildToSolsNode(&node.as.success, putsParser.as.success.output.children.at[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put the set node where the idNode was
|
||||||
|
parser->currentParent->children.count--;
|
||||||
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
||||||
|
|
||||||
|
return Success(Nothing, charptr, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline ResultType(Nothing, charptr) parseLiteral(SolsParser* parser) {
|
static inline ResultType(Nothing, charptr) parseLiteral(SolsParser* parser) {
|
||||||
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
||||||
if (peek.error) {
|
if (peek.error) {
|
||||||
@@ -381,6 +571,9 @@ ResultType(Nothing, charptr) parse(SolsParser* parser) {
|
|||||||
case STT_KW_PUTS: PARSER_HANDLE(Puts);
|
case STT_KW_PUTS: PARSER_HANDLE(Puts);
|
||||||
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_MUL: PARSER_HANDLE(Mul);
|
||||||
|
case STT_OP_DIV: PARSER_HANDLE(Div);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (parser->errors.count > 0) {
|
if (parser->errors.count > 0) {
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ typedef enum SolsTokenPrecedence {
|
|||||||
STP_PUTS = 1,
|
STP_PUTS = 1,
|
||||||
STP_SET = 2,
|
STP_SET = 2,
|
||||||
STP_FUNCTION = 3,
|
STP_FUNCTION = 3,
|
||||||
STP_MUL = 4,
|
STP_ADD = 4,
|
||||||
STP_ADD = 5,
|
STP_MUL = 5,
|
||||||
STP_OTHER = 7,
|
STP_OTHER = 7,
|
||||||
} SolsTokenPrecedence;
|
} SolsTokenPrecedence;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user