New '__options__' psuedo-module with compile-time changes

This commit is contained in:
K. Lange 2022-06-04 15:59:24 +09:00
parent b2846c13ce
commit cdcfb63f41
3 changed files with 83 additions and 0 deletions

View File

@ -221,8 +221,12 @@ typedef struct Compiler {
size_t annotationCount; /**< Number of type annotations found while compiling function signature. */ size_t annotationCount; /**< Number of type annotations found while compiling function signature. */
int delSatisfied; /**< Flag indicating if a 'del' target has been completed. */ int delSatisfied; /**< Flag indicating if a 'del' target has been completed. */
size_t optionsFlags; /**< Special __options__ imports; similar to __future__ in Python */
} Compiler; } Compiler;
#define OPTIONS_FLAG_COMPILE_TIME_BUILTINS (1 << 0)
/** /**
* @brief Class compilation context. * @brief Class compilation context.
* *
@ -346,6 +350,7 @@ static void initCompiler(Compiler * compiler, FunctionType type) {
compiler->properties = NULL; compiler->properties = NULL;
compiler->annotationCount = 0; compiler->annotationCount = 0;
compiler->delSatisfied = 0; compiler->delSatisfied = 0;
compiler->optionsFlags = compiler->enclosing ? compiler->enclosing->optionsFlags : 0;
if (type != TYPE_MODULE) { if (type != TYPE_MODULE) {
current->codeobject->name = krk_copyString(parser.previous.start, parser.previous.length); current->codeobject->name = krk_copyString(parser.previous.start, parser.previous.length);
@ -662,6 +667,15 @@ static ssize_t parseVariable(const char * errorMessage) {
declareVariable(); declareVariable();
if (current->scopeDepth > 0) return 0; if (current->scopeDepth > 0) return 0;
if ((current->optionsFlags & OPTIONS_FLAG_COMPILE_TIME_BUILTINS) && *parser.previous.start != '_') {
KrkValue value;
if (krk_tableGet_fast(&vm.builtins->fields, krk_copyString(parser.previous.start, parser.previous.length), &value)) {
error("Conflicting declaration of global '%.*s' is invalid when 'compile_time_builtins' is enabled.",
(int)parser.previous.length, parser.previous.start);
return 0;
}
}
return identifierConstant(&parser.previous); return identifierConstant(&parser.previous);
} }
@ -2260,11 +2274,56 @@ static void importStatement(void) {
} while (match(TOKEN_COMMA)); } while (match(TOKEN_COMMA));
} }
static void optionsImport(void) {
int expectCloseParen = 0;
KrkToken compile_time_builtins = syntheticToken("compile_time_builtins");
advance();
consume(TOKEN_IMPORT, "__options__ is not a package\n");
if (match(TOKEN_LEFT_PAREN)) {
expectCloseParen = 1;
startEatingWhitespace();
}
do {
consume(TOKEN_IDENTIFIER, "Expected member name");
/* Okay, what is it? */
if (identifiersEqual(&parser.previous, &compile_time_builtins)) {
current->optionsFlags |= OPTIONS_FLAG_COMPILE_TIME_BUILTINS;
} else {
error("'%.*s' is not a recognized __options__ import",
(int)parser.previous.length, parser.previous.start);
break;
}
if (check(TOKEN_AS)) {
errorAtCurrent("__options__ imports can not be given names");
break;
}
} while (match(TOKEN_COMMA) && !check(TOKEN_RIGHT_PAREN));
if (expectCloseParen) {
stopEatingWhitespace();
consume(TOKEN_RIGHT_PAREN, "Expected ')' after import list started with '('");
}
}
static void fromImportStatement(void) { static void fromImportStatement(void) {
int expectCloseParen = 0; int expectCloseParen = 0;
KrkToken startOfName = {0}; KrkToken startOfName = {0};
int leadingDots = 0; int leadingDots = 0;
KrkToken options = syntheticToken("__options__");
if (check(TOKEN_IDENTIFIER) && identifiersEqual(&parser.current, &options)) {
/* from __options__ import ... */
optionsImport();
return;
}
while (match(TOKEN_DOT)) { while (match(TOKEN_DOT)) {
leadingDots++; leadingDots++;
} }
@ -2769,6 +2828,23 @@ static void namedVariable(KrkToken name, int exprType) {
} else if ((arg = resolveUpvalue(current, &name)) != -1) { } else if ((arg = resolveUpvalue(current, &name)) != -1) {
DO_VARIABLE(OP_SET_UPVALUE, OP_GET_UPVALUE, OP_NONE); DO_VARIABLE(OP_SET_UPVALUE, OP_GET_UPVALUE, OP_NONE);
} else { } else {
if ((current->optionsFlags & OPTIONS_FLAG_COMPILE_TIME_BUILTINS) && *name.start != '_') {
KrkValue value;
if (krk_tableGet_fast(&vm.builtins->fields, krk_copyString(name.start, name.length), &value)) {
if ((exprType == EXPR_ASSIGN_TARGET && matchComplexEnd()) ||
(exprType == EXPR_CAN_ASSIGN && match(TOKEN_EQUAL)) ||
(exprType == EXPR_CAN_ASSIGN && matchAssignment())) {
error("Can not assign to '%.*s' when 'compile_time_builtins' is enabled.",
(int)name.length, name.start);
} else if (exprType == EXPR_DEL_TARGET && checkEndOfDel()) {
error("Can not delete '%.*s' when 'compile_time_builtins' is enabled.",
(int)name.length, name.start);
} else {
emitConstant(value);
}
return;
}
}
arg = identifierConstant(&name); arg = identifierConstant(&name);
DO_VARIABLE(OP_SET_GLOBAL, OP_GET_GLOBAL, OP_DEL_GLOBAL); DO_VARIABLE(OP_SET_GLOBAL, OP_GET_GLOBAL, OP_DEL_GLOBAL);
} }

View File

@ -0,0 +1,5 @@
from __options__ import compile_time_builtins
print('hello world')
print(sum(abs(x) for x in range(-4,4)))

View File

@ -0,0 +1,2 @@
hello world
16