diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 2b0eb9e..ce8f95d 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -97,7 +97,8 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) { } return Success(SolsType, charptr, type.as.success); } - case SNT_OP_EQUAL: { + case SNT_OP_EQUAL: + case SNT_OP_INEQUAL: { if (node->children.count < 2) { return Error(SolsType, charptr, "Not enough children to determine type"); } @@ -128,6 +129,32 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) { return Error(SolsType, charptr, ""); } + case SNT_OP_GREATER: + case SNT_OP_LESSER: + case SNT_OP_EQGREATER: + case SNT_OP_EQLESSER: { + 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 compare with left type"); + } + + if (!(rightType.as.success.type == STT_INT || rightType.as.success.type == STT_DOUBLE)) { + return Error(SolsType, charptr, "Cannot compare with right type"); + } + return Success(SolsType, charptr, STT_BOOL); + } case SNT_LITERAL: { switch (node->as.literal.type) { case SLT_INT: { @@ -363,6 +390,170 @@ static inline ResultType(GroundProgram, charptr) generateEqualNode(SolsNode* nod return Success(GroundProgram, charptr, gp); } +static inline ResultType(GroundProgram, charptr) generateInequalNode(SolsNode* node, SolsScope* scope) { + if (node->children.count < 2) { + return Error(GroundProgram, charptr, "inequal 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(INEQUAL); + 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 inequal"); + } + snprintf(tmpId, 64, "__SOLS_TMP_INEQUAL_%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) generateGreaterNode(SolsNode* node, SolsScope* scope) { + if (node->children.count < 2) { + return Error(GroundProgram, charptr, "greater 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(GREATER); + 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 greater"); + } + snprintf(tmpId, 64, "__SOLS_TMP_GREATER_%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) generateEqGreaterNode(SolsNode* node, SolsScope* scope) { + if (node->children.count < 2) { + return Error(GroundProgram, charptr, "eqgreater 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(LESSER); + 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 eqgreater"); + } + snprintf(tmpId, 64, "__SOLS_TMP_EQGREATER_%zu", scope->tmpCounter++); + + groundAddReferenceToInstruction(&add, groundCreateReference(DIRREF, tmpId)); + + node->accessArg = groundCreateReference(VALREF, tmpId); + + groundAddInstructionToProgram(&gp, add); + + GroundInstruction not = groundCreateInstruction(NOT); + groundAddReferenceToInstruction(¬, groundCreateReference(VALREF, tmpId)); + groundAddReferenceToInstruction(¬, groundCreateReference(DIRREF, tmpId)); + + groundAddInstructionToProgram(&gp, not); + + return Success(GroundProgram, charptr, gp); +} + +static inline ResultType(GroundProgram, charptr) generateLesserNode(SolsNode* node, SolsScope* scope) { + if (node->children.count < 2) { + return Error(GroundProgram, charptr, "lesser 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(LESSER); + 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 lesser"); + } + snprintf(tmpId, 64, "__SOLS_TMP_LESSER_%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) generateEqLesserNode(SolsNode* node, SolsScope* scope) { + if (node->children.count < 2) { + return Error(GroundProgram, charptr, "eqlesser 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(GREATER); + 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 eqlesser"); + } + snprintf(tmpId, 64, "__SOLS_TMP_LESSER_%zu", scope->tmpCounter++); + + groundAddReferenceToInstruction(&add, groundCreateReference(DIRREF, tmpId)); + + node->accessArg = groundCreateReference(VALREF, tmpId); + + groundAddInstructionToProgram(&gp, add); + + GroundInstruction not = groundCreateInstruction(NOT); + groundAddReferenceToInstruction(¬, groundCreateReference(VALREF, tmpId)); + groundAddReferenceToInstruction(¬, groundCreateReference(DIRREF, tmpId)); + + groundAddInstructionToProgram(&gp, not); + + return Success(GroundProgram, charptr, gp); +} + ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope) { GroundProgram program = groundCreateProgram(); @@ -388,6 +579,11 @@ ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope case SNT_OP_MUL: generate(Mul); case SNT_OP_DIV: generate(Div); case SNT_OP_EQUAL: generate(Equal); + case SNT_OP_INEQUAL: generate(Inequal); + case SNT_OP_GREATER: generate(Greater); + case SNT_OP_EQGREATER: generate(EqGreater); + case SNT_OP_LESSER: generate(Lesser); + case SNT_OP_EQLESSER: generate(EqLesser); } return Success(GroundProgram, charptr, program); } diff --git a/src/parser/parser.c b/src/parser/parser.c index 715109b..5892327 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -535,6 +535,321 @@ static inline ResultType(Nothing, charptr) parseEqual(SolsParser* parser) { return Success(Nothing, charptr, {}); } +static inline ResultType(Nothing, charptr) parseInequal(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_COMPARE) { + break; + } + parserConsume(parser); + addTokenToSolsTokens(&tokens.as.success, peek.as.success); + } + + // Create node + ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_INEQUAL); + 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 equal node where the idNode was + parser->currentParent->children.count--; + addChildToSolsNode(parser->currentParent, node.as.success); + + return Success(Nothing, charptr, {}); +} + +static inline ResultType(Nothing, charptr) parseGreater(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_COMPARE) { + break; + } + parserConsume(parser); + addTokenToSolsTokens(&tokens.as.success, peek.as.success); + } + + // Create node + ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_GREATER); + 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 equal node where the idNode was + parser->currentParent->children.count--; + addChildToSolsNode(parser->currentParent, node.as.success); + + return Success(Nothing, charptr, {}); +} + +static inline ResultType(Nothing, charptr) parseLesser(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_COMPARE) { + break; + } + parserConsume(parser); + addTokenToSolsTokens(&tokens.as.success, peek.as.success); + } + + // Create node + ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_LESSER); + 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 equal node where the idNode was + parser->currentParent->children.count--; + addChildToSolsNode(parser->currentParent, node.as.success); + + return Success(Nothing, charptr, {}); +} + +static inline ResultType(Nothing, charptr) parseEqGreater(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_COMPARE) { + break; + } + parserConsume(parser); + addTokenToSolsTokens(&tokens.as.success, peek.as.success); + } + + // Create node + ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_EQGREATER); + 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 equal node where the idNode was + parser->currentParent->children.count--; + addChildToSolsNode(parser->currentParent, node.as.success); + + return Success(Nothing, charptr, {}); +} + +static inline ResultType(Nothing, charptr) parseEqLesser(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_COMPARE) { + break; + } + parserConsume(parser); + addTokenToSolsTokens(&tokens.as.success, peek.as.success); + } + + // Create node + ResultType(SolsNode, charptr) node = createSolsNode(SNT_OP_EQLESSER); + 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 equal 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) { ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0); if (peek.error) { @@ -643,6 +958,11 @@ ResultType(Nothing, charptr) parse(SolsParser* parser) { case STT_OP_MUL: PARSER_HANDLE(Mul); case STT_OP_DIV: PARSER_HANDLE(Div); case STT_OP_EQUAL: PARSER_HANDLE(Equal); + case STT_OP_INEQUAL: PARSER_HANDLE(Inequal); + case STT_OP_GREATER: PARSER_HANDLE(Greater); + case STT_OP_LESSER: PARSER_HANDLE(Lesser); + case STT_OP_EQGREATER: PARSER_HANDLE(EqGreater); + case STT_OP_EQLESSER: PARSER_HANDLE(EqLesser); } } if (parser->errors.count > 0) { diff --git a/test.sols b/test.sols index 4d83b05..b18490b 100644 --- a/test.sols +++ b/test.sols @@ -17,3 +17,12 @@ 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