added "for x in y" loops
This commit is contained in:
17
src/ast.c
17
src/ast.c
@@ -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, " }");
|
||||
|
||||
@@ -108,6 +108,7 @@ struct CometASTNode {
|
||||
CometASTNode* end;
|
||||
CometASTNode* step;
|
||||
CometASTNode* program;
|
||||
CometASTNode* array;
|
||||
} AST_FOR_STATEMENT;
|
||||
struct AST_IF_STATEMENT {
|
||||
CometASTNode* expression;
|
||||
|
||||
105
src/compiler.c
105
src/compiler.c
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
33
src/parser.c
33
src/parser.c
@@ -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;
|
||||
|
||||
21
test.comet
21
test.comet
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user