Ignore line feeds and indentation in some contexts
This commit is contained in:
parent
132542c6ab
commit
90a4dd678d
29
compiler.c
29
compiler.c
@ -43,6 +43,7 @@ typedef struct {
|
|||||||
KrkToken previous;
|
KrkToken previous;
|
||||||
int hadError;
|
int hadError;
|
||||||
int panicMode;
|
int panicMode;
|
||||||
|
int eatingWhitespace;
|
||||||
} Parser;
|
} Parser;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -223,6 +224,9 @@ static void advance() {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
parser.current = krk_scanToken();
|
parser.current = krk_scanToken();
|
||||||
|
|
||||||
|
if (parser.eatingWhitespace &&
|
||||||
|
(parser.current.type == TOKEN_INDENTATION || parser.current.type == TOKEN_EOL)) continue;
|
||||||
|
|
||||||
#ifdef ENABLE_SCAN_TRACING
|
#ifdef ENABLE_SCAN_TRACING
|
||||||
if (vm.flags & KRK_ENABLE_SCAN_TRACING) {
|
if (vm.flags & KRK_ENABLE_SCAN_TRACING) {
|
||||||
fprintf(stderr, "[%s %d:%d '%.*s'] ",
|
fprintf(stderr, "[%s %d:%d '%.*s'] ",
|
||||||
@ -241,6 +245,18 @@ static void advance() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void startEatingWhitespace() {
|
||||||
|
parser.eatingWhitespace++;
|
||||||
|
if (parser.current.type == TOKEN_INDENTATION || parser.current.type == TOKEN_EOL) advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stopEatingWhitespace() {
|
||||||
|
if (parser.eatingWhitespace == 0) {
|
||||||
|
error("Internal scanner error: Invalid nesting of `startEatingWhitespace`/`stopEatingWhitespace` calls.");
|
||||||
|
}
|
||||||
|
parser.eatingWhitespace--;
|
||||||
|
}
|
||||||
|
|
||||||
static void consume(KrkTokenType type, const char * message) {
|
static void consume(KrkTokenType type, const char * message) {
|
||||||
if (parser.current.type == type) {
|
if (parser.current.type == type) {
|
||||||
advance();
|
advance();
|
||||||
@ -704,6 +720,7 @@ static void function(FunctionType type, size_t blockWidth) {
|
|||||||
int hasCollectors = 0;
|
int hasCollectors = 0;
|
||||||
|
|
||||||
consume(TOKEN_LEFT_PAREN, "Expected start of parameter list after function name.");
|
consume(TOKEN_LEFT_PAREN, "Expected start of parameter list after function name.");
|
||||||
|
startEatingWhitespace();
|
||||||
if (!check(TOKEN_RIGHT_PAREN)) {
|
if (!check(TOKEN_RIGHT_PAREN)) {
|
||||||
do {
|
do {
|
||||||
if (match(TOKEN_SELF)) {
|
if (match(TOKEN_SELF)) {
|
||||||
@ -779,6 +796,7 @@ static void function(FunctionType type, size_t blockWidth) {
|
|||||||
}
|
}
|
||||||
} while (match(TOKEN_COMMA));
|
} while (match(TOKEN_COMMA));
|
||||||
}
|
}
|
||||||
|
stopEatingWhitespace();
|
||||||
consume(TOKEN_RIGHT_PAREN, "Expected end of parameter list.");
|
consume(TOKEN_RIGHT_PAREN, "Expected end of parameter list.");
|
||||||
|
|
||||||
consume(TOKEN_COLON, "Expected colon after function signature.");
|
consume(TOKEN_COLON, "Expected colon after function signature.");
|
||||||
@ -1335,8 +1353,10 @@ static void statement() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void grouping(int canAssign) {
|
static void grouping(int canAssign) {
|
||||||
|
startEatingWhitespace();
|
||||||
expression();
|
expression();
|
||||||
consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
|
consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
|
||||||
|
stopEatingWhitespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unary(int canAssign) {
|
static void unary(int canAssign) {
|
||||||
@ -1481,6 +1501,8 @@ static void super_(int canAssign) {
|
|||||||
static void list(int canAssign) {
|
static void list(int canAssign) {
|
||||||
size_t chunkBefore = currentChunk()->count;
|
size_t chunkBefore = currentChunk()->count;
|
||||||
|
|
||||||
|
startEatingWhitespace();
|
||||||
|
|
||||||
KrkToken listOf = syntheticToken("listOf");
|
KrkToken listOf = syntheticToken("listOf");
|
||||||
size_t ind = identifierConstant(&listOf);
|
size_t ind = identifierConstant(&listOf);
|
||||||
EMIT_CONSTANT_OP(OP_GET_GLOBAL, ind);
|
EMIT_CONSTANT_OP(OP_GET_GLOBAL, ind);
|
||||||
@ -1588,6 +1610,7 @@ static void list(int canAssign) {
|
|||||||
* offset as the exit target for the OP_JUMP_IF_FALSE above */
|
* offset as the exit target for the OP_JUMP_IF_FALSE above */
|
||||||
patchJump(exitJump);
|
patchJump(exitJump);
|
||||||
/* Parse the ] that indicates the end of the list comprehension */
|
/* Parse the ] that indicates the end of the list comprehension */
|
||||||
|
stopEatingWhitespace();
|
||||||
consume(TOKEN_RIGHT_SQUARE,"Expected ] at end of list expression.");
|
consume(TOKEN_RIGHT_SQUARE,"Expected ] at end of list expression.");
|
||||||
/* Pop the last loop expression result which was already stored */
|
/* Pop the last loop expression result which was already stored */
|
||||||
emitByte(OP_POP);
|
emitByte(OP_POP);
|
||||||
@ -1628,17 +1651,20 @@ static void list(int canAssign) {
|
|||||||
expression();
|
expression();
|
||||||
argCount++;
|
argCount++;
|
||||||
}
|
}
|
||||||
|
stopEatingWhitespace();
|
||||||
consume(TOKEN_RIGHT_SQUARE,"Expected ] at end of list expression.");
|
consume(TOKEN_RIGHT_SQUARE,"Expected ] at end of list expression.");
|
||||||
EMIT_CONSTANT_OP(OP_CALL, argCount);
|
EMIT_CONSTANT_OP(OP_CALL, argCount);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Empty list expression */
|
/* Empty list expression */
|
||||||
|
stopEatingWhitespace();
|
||||||
advance();
|
advance();
|
||||||
emitBytes(OP_CALL, 0);
|
emitBytes(OP_CALL, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dict(int canAssign) {
|
static void dict(int canAssign) {
|
||||||
|
startEatingWhitespace();
|
||||||
KrkToken dictOf = syntheticToken("dictOf");
|
KrkToken dictOf = syntheticToken("dictOf");
|
||||||
size_t ind = identifierConstant(&dictOf);
|
size_t ind = identifierConstant(&dictOf);
|
||||||
EMIT_CONSTANT_OP(OP_GET_GLOBAL, ind);
|
EMIT_CONSTANT_OP(OP_GET_GLOBAL, ind);
|
||||||
@ -1651,6 +1677,7 @@ static void dict(int canAssign) {
|
|||||||
argCount += 2;
|
argCount += 2;
|
||||||
} while (match(TOKEN_COMMA));
|
} while (match(TOKEN_COMMA));
|
||||||
}
|
}
|
||||||
|
stopEatingWhitespace();
|
||||||
consume(TOKEN_RIGHT_BRACE,"Expected } at end of dict expression.");
|
consume(TOKEN_RIGHT_BRACE,"Expected } at end of dict expression.");
|
||||||
EMIT_CONSTANT_OP(OP_CALL, argCount);
|
EMIT_CONSTANT_OP(OP_CALL, argCount);
|
||||||
}
|
}
|
||||||
@ -1810,6 +1837,7 @@ static void defineVariable(size_t global) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void call(int canAssign) {
|
static void call(int canAssign) {
|
||||||
|
startEatingWhitespace();
|
||||||
size_t argCount = 0, specialArgs = 0, keywordArgs = 0, seenKeywordUnpacking = 0;
|
size_t argCount = 0, specialArgs = 0, keywordArgs = 0, seenKeywordUnpacking = 0;
|
||||||
if (!check(TOKEN_RIGHT_PAREN)) {
|
if (!check(TOKEN_RIGHT_PAREN)) {
|
||||||
do {
|
do {
|
||||||
@ -1866,6 +1894,7 @@ static void call(int canAssign) {
|
|||||||
argCount++;
|
argCount++;
|
||||||
} while (match(TOKEN_COMMA));
|
} while (match(TOKEN_COMMA));
|
||||||
}
|
}
|
||||||
|
stopEatingWhitespace();
|
||||||
consume(TOKEN_RIGHT_PAREN, "Expected ')' after arguments.");
|
consume(TOKEN_RIGHT_PAREN, "Expected ')' after arguments.");
|
||||||
if (specialArgs) {
|
if (specialArgs) {
|
||||||
/*
|
/*
|
||||||
|
21
test/testEatWhitespace.krk
Normal file
21
test/testEatWhitespace.krk
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
def foo(a,b,c,d):
|
||||||
|
print a,b,c,d
|
||||||
|
|
||||||
|
|
||||||
|
foo(
|
||||||
|
a=1,
|
||||||
|
b=2,
|
||||||
|
c=3,
|
||||||
|
d=4
|
||||||
|
)
|
||||||
|
|
||||||
|
let l = [
|
||||||
|
1,2,
|
||||||
|
3,4
|
||||||
|
]
|
||||||
|
|
||||||
|
print l
|
||||||
|
|
||||||
|
for i in [1,2
|
||||||
|
3,4]:
|
||||||
|
print "lol",i
|
Loading…
Reference in New Issue
Block a user