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, " ");
|
sbAppend(buff, " ");
|
||||||
appendNodeToBuff(node->data.AST_FOR_STATEMENT.ident, buff);
|
appendNodeToBuff(node->data.AST_FOR_STATEMENT.ident, buff);
|
||||||
sbAppend(buff, " in ");
|
sbAppend(buff, " in ");
|
||||||
appendNodeToBuff(node->data.AST_FOR_STATEMENT.start, buff);
|
|
||||||
sbAppend(buff, "..");
|
if (node->data.AST_FOR_STATEMENT.array) {
|
||||||
appendNodeToBuff(node->data.AST_FOR_STATEMENT.end, buff);
|
appendNodeToBuff(node->data.AST_FOR_STATEMENT.array, buff);
|
||||||
sbAppend(buff, " step ");
|
} else {
|
||||||
appendNodeToBuff(node->data.AST_FOR_STATEMENT.step, buff);
|
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");
|
sbAppend(buff, " {\n");
|
||||||
appendNodeToBuff(node->data.AST_FOR_STATEMENT.program, buff);
|
appendNodeToBuff(node->data.AST_FOR_STATEMENT.program, buff);
|
||||||
sbAppend(buff, " }");
|
sbAppend(buff, " }");
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ struct CometASTNode {
|
|||||||
CometASTNode* end;
|
CometASTNode* end;
|
||||||
CometASTNode* step;
|
CometASTNode* step;
|
||||||
CometASTNode* program;
|
CometASTNode* program;
|
||||||
|
CometASTNode* array;
|
||||||
} AST_FOR_STATEMENT;
|
} AST_FOR_STATEMENT;
|
||||||
struct AST_IF_STATEMENT {
|
struct AST_IF_STATEMENT {
|
||||||
CometASTNode* expression;
|
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);
|
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
|
// resolve start and end types
|
||||||
ResultType(CometType, ErrorMessage) startType = resolveType(c, forStmt.start);
|
ResultType(CometType, ErrorMessage) startType = resolveType(c, forStmt.start);
|
||||||
if (startType.error)
|
if (startType.error)
|
||||||
@@ -3866,11 +3965,7 @@ ResultType(CompiledValue, ErrorMessage) visitForStatement(CometCompiler* c, Come
|
|||||||
return Error(CompiledValue, ErrorMessage, endType.as.error);
|
return Error(CompiledValue, ErrorMessage, endType.as.error);
|
||||||
CometType resultType = unifyType(startType.as.success, endType.as.success);
|
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
|
// define iterator variable
|
||||||
ResultType(CompiledValue, ErrorMessage) start = visitValue(c, forStmt.start);
|
ResultType(CompiledValue, ErrorMessage) start = visitValue(c, forStmt.start);
|
||||||
@@ -3909,7 +4004,7 @@ ResultType(CompiledValue, ErrorMessage) visitForStatement(CometCompiler* c, Come
|
|||||||
if (step.error)
|
if (step.error)
|
||||||
return Error(CompiledValue, ErrorMessage, step.as.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
|
// add the step to the iterator var
|
||||||
buildAdd(c, addType);
|
buildAdd(c, addType);
|
||||||
|
|||||||
@@ -473,6 +473,9 @@ CometASTNode* controlFlowSimplify(CometCompiler* c, CometASTNode* ast) {
|
|||||||
if (expr->nodeType == AST_BOOL && expr->data.AST_BOOL.value == false) {
|
if (expr->nodeType == AST_BOOL && expr->data.AST_BOOL.value == false) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast->data.AST_IF_STATEMENT.program = controlFlowSimplify(c, ast->data.AST_IF_STATEMENT.program);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,6 +485,14 @@ CometASTNode* controlFlowSimplify(CometCompiler* c, CometASTNode* ast) {
|
|||||||
if (expr->nodeType == AST_BOOL && expr->data.AST_BOOL.value == false) {
|
if (expr->nodeType == AST_BOOL && expr->data.AST_BOOL.value == false) {
|
||||||
return NULL;
|
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;
|
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) {
|
ResultType(astNodePtr, ErrorMessage) parseForStatement(CometParser* parser) {
|
||||||
// basic format
|
// basic format
|
||||||
// for int i in 0 .. 10 {}
|
// for int i in 0 .. 10 {}
|
||||||
|
// for int x in y {}
|
||||||
|
|
||||||
uint32_t lineNum = parser->currentToken->lineNum;
|
uint32_t lineNum = parser->currentToken->lineNum;
|
||||||
uint32_t startCol = parser->currentToken->startCol;
|
uint32_t startCol = parser->currentToken->startCol;
|
||||||
@@ -1174,6 +1175,35 @@ ResultType(astNodePtr, ErrorMessage) parseForStatement(CometParser* parser) {
|
|||||||
|
|
||||||
parserNextToken(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);
|
ResultType(astNodePtr, ErrorMessage) start = parseExpression(parser, PRECEDENCE_LOWEST);
|
||||||
if (start.error) {
|
if (start.error) {
|
||||||
return start;
|
return start;
|
||||||
@@ -1217,7 +1247,8 @@ ResultType(astNodePtr, ErrorMessage) parseForStatement(CometParser* parser) {
|
|||||||
start.as.success,
|
start.as.success,
|
||||||
end.as.success,
|
end.as.success,
|
||||||
stepNode.as.success,
|
stepNode.as.success,
|
||||||
block.as.success
|
block.as.success,
|
||||||
|
NULL
|
||||||
);
|
);
|
||||||
stmt->startCol = startCol;
|
stmt->startCol = startCol;
|
||||||
stmt->endCol = block.as.success->endCol;
|
stmt->endCol = block.as.success->endCol;
|
||||||
|
|||||||
21
test.comet
21
test.comet
@@ -1,18 +1,11 @@
|
|||||||
struct Foo {
|
import io
|
||||||
int x = 5 + 5
|
|
||||||
|
|
||||||
func foo() -> int {
|
|
||||||
int f = 2 * 10
|
|
||||||
return 2 + 2 + f + self.x
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() -> int {
|
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