added "for x in y" loops

This commit is contained in:
2026-07-11 15:16:43 +10:00
parent f777d55775
commit 8ef6a4e649
6 changed files with 163 additions and 25 deletions

View File

@@ -519,11 +519,18 @@ void appendNodeToBuff(CometASTNode* node, StringBuffer* buff) {
sbAppend(buff, " ");
appendNodeToBuff(node->data.AST_FOR_STATEMENT.ident, buff);
sbAppend(buff, " in ");
appendNodeToBuff(node->data.AST_FOR_STATEMENT.start, buff);
sbAppend(buff, "..");
appendNodeToBuff(node->data.AST_FOR_STATEMENT.end, buff);
sbAppend(buff, " step ");
appendNodeToBuff(node->data.AST_FOR_STATEMENT.step, buff);
if (node->data.AST_FOR_STATEMENT.array) {
appendNodeToBuff(node->data.AST_FOR_STATEMENT.array, buff);
} else {
appendNodeToBuff(node->data.AST_FOR_STATEMENT.start, buff);
sbAppend(buff, "..");
appendNodeToBuff(node->data.AST_FOR_STATEMENT.end, buff);
sbAppend(buff, " step ");
appendNodeToBuff(node->data.AST_FOR_STATEMENT.step, buff);
}
sbAppend(buff, " {\n");
appendNodeToBuff(node->data.AST_FOR_STATEMENT.program, buff);
sbAppend(buff, " }");

View File

@@ -108,6 +108,7 @@ struct CometASTNode {
CometASTNode* end;
CometASTNode* step;
CometASTNode* program;
CometASTNode* array;
} AST_FOR_STATEMENT;
struct AST_IF_STATEMENT {
CometASTNode* expression;

View File

@@ -3857,6 +3857,105 @@ ResultType(CompiledValue, ErrorMessage) visitForStatement(CometCompiler* c, Come
};
append(c->loopContexts, loopContext);
char* ident = forStmt.ident->data.AST_IDENTIFIER.ident;
// create env for for loop
CometEnvironment* forLoopEnv = newEnvironment("forLoop", c->env, false);
c->env = forLoopEnv;
ResultType(CometType, ErrorMessage) iterType = getType(c, forStmt.type);
if (iterType.error)
return Error(CompiledValue, ErrorMessage, iterType.as.error);
if (forStmt.array) { // we're looping over an array
// get array type
ResultType(CometType, ErrorMessage) arrayType = resolveType(c, forStmt.array);
if (arrayType.as.success.typeKind != COMET_ARRAY) {
ErrorMessage errMsg = createError(
c->inputFilePath,
c->sourceCode,
"TypeMismatch",
"Attempted to loop over something that isn't an array",
NULL,
forStmt.array->lineNum,
forStmt.array->startCol,
forStmt.array->endCol
);
return Error(CompiledValue, ErrorMessage, errMsg);
}
CometType elemType = *arrayType.as.success.arrayType->elem;
// build zero
CometOperand zeroVal = createOperand(CO_IMMEDIATE);
zeroVal.imm.typeKind = COMET_INT;
zeroVal.imm.intVal = 0;
CometOperand zeroConst = storeConst(c, zeroVal);
buildPushConst(c, zeroConst);
uint32_t idx = defineVar(c->env, "i", RECORD_LOCAL, zeroVal, iterType.as.success, false);
uint32_t currentValue = defineVar(c->env, ident, RECORD_LOCAL, zeroVal, elemType, false);
buildStore(c, idx);
resolveLabel(c, mainLabel);
// get iterator
buildLoad(c, idx);
// get list size
ResultType(CompiledValue, ErrorMessage) arrayVal = visitValue(c, forStmt.array);
if (arrayVal.error)
return arrayVal;
buildListLength(c);
buildEq(c, iterType.as.success);
buildJumpIfTrue(c, endLabel);
// get value
arrayVal = visitValue(c, forStmt.array);
if (arrayVal.error)
return arrayVal;
buildLoad(c, idx);
buildListAt(c);
buildStore(c, currentValue);
// compile the body of the for loop
ResultType(CompiledValue, ErrorMessage) bodyResult = compile(c, forStmt.program);
if (bodyResult.error)
return bodyResult;
resolveLabel(c, continueLabel);
buildLoad(c, idx);
// build one
CometOperand oneVal = createOperand(CO_IMMEDIATE);
oneVal.imm.typeKind = COMET_SMALL;
oneVal.imm.smallVal = 1;
CometOperand oneConst = storeConst(c, oneVal);
buildPushConst(c, oneConst);
// add the one to the iterator var
buildAdd(c, iterType.as.success);
// save the iterator value
buildStore(c, idx);
// jump back to the start of the for loop
buildJump(c, mainLabel);
resolveLabel(c, endLabel);
// exit the for loop's env
c->env = destroyEnv(forLoopEnv);
pop(c->loopContexts);
return Success(CompiledValue, ErrorMessage, NO_VALUE);
}
// resolve start and end types
ResultType(CometType, ErrorMessage) startType = resolveType(c, forStmt.start);
if (startType.error)
@@ -3866,11 +3965,7 @@ ResultType(CompiledValue, ErrorMessage) visitForStatement(CometCompiler* c, Come
return Error(CompiledValue, ErrorMessage, endType.as.error);
CometType resultType = unifyType(startType.as.success, endType.as.success);
char* ident = forStmt.ident->data.AST_IDENTIFIER.ident;
// create env for for loop
CometEnvironment* forLoopEnv = newEnvironment("forLoop", c->env, false);
c->env = forLoopEnv;
// define iterator variable
ResultType(CompiledValue, ErrorMessage) start = visitValue(c, forStmt.start);
@@ -3909,7 +4004,7 @@ ResultType(CompiledValue, ErrorMessage) visitForStatement(CometCompiler* c, Come
if (step.error)
return Error(CompiledValue, ErrorMessage, step.as.error);
CometType addType = unifyType(startType.as.success, stepType.as.success);
CometType addType = unifyType(iterType.as.success, stepType.as.success);
// add the step to the iterator var
buildAdd(c, addType);

View File

@@ -473,6 +473,9 @@ CometASTNode* controlFlowSimplify(CometCompiler* c, CometASTNode* ast) {
if (expr->nodeType == AST_BOOL && expr->data.AST_BOOL.value == false) {
return NULL;
}
ast->data.AST_IF_STATEMENT.program = controlFlowSimplify(c, ast->data.AST_IF_STATEMENT.program);
break;
}
@@ -482,6 +485,14 @@ CometASTNode* controlFlowSimplify(CometCompiler* c, CometASTNode* ast) {
if (expr->nodeType == AST_BOOL && expr->data.AST_BOOL.value == false) {
return NULL;
}
ast->data.AST_WHILE_STATEMENT.program = controlFlowSimplify(c, ast->data.AST_WHILE_STATEMENT.program);
break;
}
case AST_FOR_STATEMENT: {
ast->data.AST_FOR_STATEMENT.program = controlFlowSimplify(c, ast->data.AST_FOR_STATEMENT.program);
break;
}

View File

@@ -1143,6 +1143,7 @@ ResultType(astNodePtr, ErrorMessage) parseWhileStatement(CometParser* parser) {
ResultType(astNodePtr, ErrorMessage) parseForStatement(CometParser* parser) {
// basic format
// for int i in 0 .. 10 {}
// for int x in y {}
uint32_t lineNum = parser->currentToken->lineNum;
uint32_t startCol = parser->currentToken->startCol;
@@ -1174,6 +1175,35 @@ ResultType(astNodePtr, ErrorMessage) parseForStatement(CometParser* parser) {
parserNextToken(parser);
bool isArrayLoop = !currentTokenIs(parser, CT_DOT_DOT);
if (isArrayLoop) { // we're looping over an array
ResultType(astNodePtr, ErrorMessage) array = parseExpression(parser, PRECEDENCE_LOWEST);
if (array.error) {
return array;
}
ResultType(astNodePtr, ErrorMessage) block = parseOptionalBlockStatement(parser);
if (block.error) {
return block;
}
CometASTNode* stmt = AST_NODE(
AST_FOR_STATEMENT,
lineNum,
type.as.success,
ident,
NULL,
NULL,
NULL,
block.as.success,
array.as.success
);
stmt->startCol = startCol;
stmt->endCol = block.as.success->endCol;
return Success(astNodePtr, ErrorMessage, stmt);
}
ResultType(astNodePtr, ErrorMessage) start = parseExpression(parser, PRECEDENCE_LOWEST);
if (start.error) {
return start;
@@ -1217,7 +1247,8 @@ ResultType(astNodePtr, ErrorMessage) parseForStatement(CometParser* parser) {
start.as.success,
end.as.success,
stepNode.as.success,
block.as.success
block.as.success,
NULL
);
stmt->startCol = startCol;
stmt->endCol = block.as.success->endCol;

View File

@@ -1,18 +1,11 @@
struct Foo {
int x = 5 + 5
func foo() -> int {
int f = 2 * 10
return 2 + 2 + f + self.x
}
init() {
}
}
import io
func main() -> int {
Foo f = new Foo()
int[3] array = [1, 2, 3]
return f.foo()
for int x in array {
io.println("%n", x)
}
return 0
}