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(); declaration();
if (check(TOKEN_EOL)) endOfLine(); if (check(TOKEN_EOL)) endOfLine();
} while (check(TOKEN_INDENTATION)); } 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 { } else {
errorAtCurrent("Expected indentation for block"); errorAtCurrent("Expected indentation for block");
} }
@ -691,26 +703,71 @@ static void forStatement() {
/* For now this is going to be kinda broken */ /* For now this is going to be kinda broken */
beginScope(); beginScope();
/* actually should be `for NAME in ITERABLE` ... */ ssize_t loopInd = current->localCount;
varDeclaration(); varDeclaration();
consume(TOKEN_COMMA,"expect ,"); int loopStart;
int exitJump;
int loopStart = currentChunk()->count; if (match(TOKEN_IN)) {
expression(); /* condition */ defineVariable(loopInd);
int exitJump = emitJump(OP_JUMP_IF_FALSE);
emitByte(OP_POP);
if (check(TOKEN_COMMA)) { KrkToken _it = syntheticToken("__loop_iter");
advance(); KrkToken _iter = syntheticToken("__iter__");
int bodyJump = emitJump(OP_JUMP); size_t indLoopIter, indIterCall;
int incrementStart = currentChunk()->count;
/* __loop_iter = */
indLoopIter = current->localCount;
addLocal(_it);
defineVariable(indLoopIter);
/* ITERABLE.__iter__() */
expression(); 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); emitByte(OP_POP);
emitLoop(loopStart); } else {
loopStart = incrementStart; consume(TOKEN_COMMA,"expect ,");
patchJump(bodyJump); 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 :"); consume(TOKEN_COLON,"expect :");

View File

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

View File

@ -36,11 +36,44 @@ class List:
base = base + ", " base = base + ", "
base = base + self._get(self._list,i) base = base + self._get(self._list,i)
return base + "]" 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() let module = SystemModule()
module.sleep = __krk_builtin_sleep module.sleep = __krk_builtin_sleep
module.HashMap = HashMap module.HashMap = HashMap
module.List = List module.List = List
module.Range = Range
return module 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_FLOATING: return AS_FLOATING(a) == AS_FLOATING(b);
case VAL_OBJECT: { case VAL_OBJECT: {
if (IS_STRING(a) && IS_STRING(b)) return AS_OBJECT(a) == AS_OBJECT(b); 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; return 0;
} }
default: return 0; default: return 0;