Add support for iterators

This commit is contained in:
K. Lange 2020-12-28 13:35:02 +09:00
parent 1d3368861b
commit 0f508c38dc
5 changed files with 121 additions and 16 deletions

View File

@ -443,6 +443,18 @@ static void block(int indentation) {
declaration();
if (check(TOKEN_EOL)) endOfLine();
} while (check(TOKEN_INDENTATION));
#ifdef ENABLE_DEBUGGING
if (vm.enableDebugging) {
fprintf(stderr, "On line %d, ", (int)parser.current.line);
if (check(TOKEN_INDENTATION)) {
fprintf(stderr, "Exiting block from %d to %d\n",
(int)currentIndentation, (int)parser.current.length);
} else {
fprintf(stderr, "Exiting block from %d to something that isn't indentation.\n",
(int)currentIndentation);
}
}
#endif
} else {
errorAtCurrent("Expected indentation for block");
}
@ -691,26 +703,71 @@ static void forStatement() {
/* For now this is going to be kinda broken */
beginScope();
/* actually should be `for NAME in ITERABLE` ... */
ssize_t loopInd = current->localCount;
varDeclaration();
consume(TOKEN_COMMA,"expect ,");
int loopStart;
int exitJump;
int loopStart = currentChunk()->count;
expression(); /* condition */
int exitJump = emitJump(OP_JUMP_IF_FALSE);
emitByte(OP_POP);
if (match(TOKEN_IN)) {
defineVariable(loopInd);
if (check(TOKEN_COMMA)) {
advance();
int bodyJump = emitJump(OP_JUMP);
int incrementStart = currentChunk()->count;
KrkToken _it = syntheticToken("__loop_iter");
KrkToken _iter = syntheticToken("__iter__");
size_t indLoopIter, indIterCall;
/* __loop_iter = */
indLoopIter = current->localCount;
addLocal(_it);
defineVariable(indLoopIter);
/* ITERABLE.__iter__() */
expression();
ssize_t ind = identifierConstant(&_iter);
EMIT_CONSTANT_OP(OP_GET_PROPERTY, ind);
emitBytes(OP_CALL, 0);
/* assign */
EMIT_CONSTANT_OP(OP_SET_LOCAL, indLoopIter);
/* LOOP STARTS HERE */
loopStart = currentChunk()->count;
emitByte(0xFF);
/* Call the iterator */
EMIT_CONSTANT_OP(OP_GET_LOCAL, indLoopIter);
emitBytes(OP_CALL, 0);
/* Assign the result to our loop index */
EMIT_CONSTANT_OP(OP_SET_LOCAL, loopInd);
/* Get the loop iterator again */
EMIT_CONSTANT_OP(OP_GET_LOCAL, indLoopIter);
emitByte(OP_EQUAL);
emitByte(OP_NOT);
exitJump = emitJump(OP_JUMP_IF_FALSE);
emitByte(OP_POP);
emitLoop(loopStart);
loopStart = incrementStart;
patchJump(bodyJump);
} else {
consume(TOKEN_COMMA,"expect ,");
loopStart = currentChunk()->count;
expression(); /* condition */
exitJump = emitJump(OP_JUMP_IF_FALSE);
emitByte(OP_POP);
if (check(TOKEN_COMMA)) {
advance();
int bodyJump = emitJump(OP_JUMP);
int incrementStart = currentChunk()->count;
expression();
emitByte(OP_POP);
emitLoop(loopStart);
loopStart = incrementStart;
patchJump(bodyJump);
}
}
consume(TOKEN_COLON,"expect :");

View File

@ -749,12 +749,12 @@ int syn_py_calculate(struct syntax_state * state) {
case 0:
if (charat() == '#') {
paint_comment(state);
} else if (state->i == 0 && match_and_paint(state, "import", FLAG_PRAGMA, c_keyword_qualifier)) {
return 0;
#if 0
} else if (charat() == '@') {
paint(1, FLAG_PRAGMA);
while (c_keyword_qualifier(charat())) paint(1, FLAG_PRAGMA);
return 0;
#endif
} else if (charat() == '"') {
if (nextchar() == '"' && charrel(2) == '"') {
paint(3, FLAG_STRING);

View File

@ -36,11 +36,44 @@ class List:
base = base + ", "
base = base + self._get(self._list,i)
return base + "]"
def __iter__(self):
let me = self
def makeIter(ind):
let l = me
let len = l.length()
let i = ind
def iter():
if i >= len:
return iter
let out = l[i]
i = i + 1
return out
return iter
return makeIter(0)
class Range:
def __init__(self, min, max):
self.min = min
self.max = max
def __iter__(self):
let me = self
def makeIter(ind):
let l = me
let i = ind
def iter():
if i >= l.max:
return iter
let out = i
i = i + 1
return out
return iter
return makeIter(self.min)
let module = SystemModule()
module.sleep = __krk_builtin_sleep
module.HashMap = HashMap
module.List = List
module.Range = Range
return module

13
testList.krk Normal file
View File

@ -0,0 +1,13 @@
import system
let l = system.List()
l.append(1)
l.append(2)
l.append("string")
l.append(3.14159)
for v in l:
print v
return 0

View File

@ -49,7 +49,9 @@ int krk_valuesEqual(KrkValue a, KrkValue b) {
case VAL_FLOATING: return AS_FLOATING(a) == AS_FLOATING(b);
case VAL_OBJECT: {
if (IS_STRING(a) && IS_STRING(b)) return AS_OBJECT(a) == AS_OBJECT(b);
/* otherwise we need to do... fun stuff (push, call compare, etc.)*/
/* If their pointers are equal, assume they are always equivalent */
if (AS_OBJECT(a) == AS_OBJECT(b)) return 1;
/* TODO: __eq__ */
return 0;
}
default: return 0;