literals renamed to constants

Since the functions and classes will be moved to the constants buffer
rather than having their own (function buffer and class buffer) the
rename is essential, and to make the refactoring process easier all the
intermediate steps are done with its own pr.
This commit is contained in:
Thakee Nathees 2022-04-10 06:09:56 +05:30
parent a69718b020
commit 05a516d47d
6 changed files with 93 additions and 72 deletions

View File

@ -1958,22 +1958,22 @@ static void compilerAddForward(Compiler* compiler, int instruction, Fn* fn,
// Add a literal constant to scripts literals and return it's index.
static int compilerAddConstant(Compiler* compiler, Var value) {
pkVarBuffer* literals = &compiler->script->literals;
pkVarBuffer* constants = &compiler->script->constants;
for (uint32_t i = 0; i < literals->count; i++) {
if (isValuesSame(literals->data[i], value)) {
for (uint32_t i = 0; i < constants->count; i++) {
if (isValuesSame(constants->data[i], value)) {
return i;
}
}
// Add new constant to script.
if (literals->count < MAX_CONSTANTS) {
pkVarBufferWrite(literals, compiler->parser.vm, value);
if (constants->count < MAX_CONSTANTS) {
pkVarBufferWrite(constants, compiler->parser.vm, value);
} else {
parseError(compiler, "A script should contain at most %d "
"unique constants.", MAX_CONSTANTS);
}
return (int)literals->count - 1;
return (int)constants->count - 1;
}
// Enters inside a block.
@ -2665,12 +2665,12 @@ static void compileRegularImport(Compiler* compiler) {
// If it has a module name use it as binding variable.
// Core libs names are it's module name but for local libs it's optional
// to define a module name for a script.
if (lib && lib->module != NULL) {
if (lib && lib->name != NULL) {
// Get the variable to bind the imported symbol, if we already have a
// variable with that name override it, otherwise use a new variable.
const char* name = lib->module->data;
uint32_t length = lib->module->length;
const char* name = lib->name->data;
uint32_t length = lib->name->length;
int line = compiler->parser.previous.line;
var_index = compilerImportName(compiler, line, name, length);
@ -3015,14 +3015,14 @@ PkResult compile(PKVM* vm, Script* script, const char* source,
// If the script running a REPL or compiled multiple times by hosting
// application module attribute might already set. In that case make it
// Compile error.
if (script->module != NULL) {
if (script->name != NULL) {
parseError(compiler, "Module name already defined.");
} else {
consume(compiler, TK_NAME, "Expected a name for the module.");
const char* name = compiler->parser.previous.start;
uint32_t len = compiler->parser.previous.length;
script->module = newStringLength(vm, name, len);
script->name = newStringLength(vm, name, len);
consumeEndStatement(compiler);
}
}

View File

@ -820,13 +820,13 @@ static inline void assertModuleNameDef(PKVM* vm, Script* script,
// Check if function with the same name already exists.
if (scriptGetFunc(script, name, (uint32_t)strlen(name)) != -1) {
__ASSERT(false, stringFormat(vm, "A function named '$' already esists "
"on module '@'", name, script->module)->data);
"on module '@'", name, script->name)->data);
}
// Check if a global variable with the same name already exists.
if (scriptGetGlobals(script, name, (uint32_t)strlen(name)) != -1) {
__ASSERT(false, stringFormat(vm, "A global variable named '$' already "
"esists on module '@'", name, script->module)->data);
"esists on module '@'", name, script->name)->data);
}
}

View File

@ -107,8 +107,8 @@ void dumpFunctionCode(PKVM* vm, Function* func) {
case OP_PUSH_CONSTANT:
{
int index = READ_SHORT();
ASSERT_INDEX((uint32_t)index, func->owner->literals.count);
Var value = func->owner->literals.data[index];
ASSERT_INDEX((uint32_t)index, func->owner->constants.count);
Var value = func->owner->constants.data[index];
// Prints: %5d [val]\n
PRINT_INT(index);

View File

@ -209,7 +209,7 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
vm->bytes_allocated += sizeof(Script);
markObject(vm, &scr->path->_super);
markObject(vm, &scr->module->_super);
markObject(vm, &scr->name->_super);
markVarBuffer(vm, &scr->globals);
vm->bytes_allocated += sizeof(Var) * scr->globals.capacity;
@ -217,8 +217,8 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
// Integer buffer has no gray call.
vm->bytes_allocated += sizeof(uint32_t) * scr->global_names.capacity;
markVarBuffer(vm, &scr->literals);
vm->bytes_allocated += sizeof(Var) * scr->literals.capacity;
markVarBuffer(vm, &scr->constants);
vm->bytes_allocated += sizeof(Var) * scr->constants.capacity;
markFunctionBuffer(vm, &scr->functions);
vm->bytes_allocated += sizeof(Function*) * scr->functions.capacity;
@ -401,16 +401,16 @@ Script* newScript(PKVM* vm, String* name, bool is_core) {
ASSERT(name != NULL && name->length > 0, OOPS);
script->path = name;
script->module = NULL;
script->name = NULL;
script->initialized = is_core;
script->body = NULL;
// Core modules has its name as the module name.
if (is_core) script->module = name;
if (is_core) script->name = name;
pkVarBufferInit(&script->globals);
pkUintBufferInit(&script->global_names);
pkVarBufferInit(&script->literals);
pkVarBufferInit(&script->constants);
pkFunctionBufferInit(&script->functions);
pkClassBufferInit(&script->classes);
pkStringBufferInit(&script->names);
@ -454,7 +454,7 @@ Function* newFunction(PKVM* vm, const char* name, int length, Script* owner,
func->name = owner->names.data[name_index]->data;
func->owner = owner;
func->arity = -2; // -1 means variadic args.
func->arity = -2; // -2 means un-initialized (TODO: make it as a macro).
}
func->is_native = is_native;
@ -499,6 +499,7 @@ Upvalue* newUpvalue(PKVM* vm, Var* value) {
upvalue->ptr = value;
upvalue->closed = VAR_NULL;
upvalue->next = NULL;
return upvalue;
}
Fiber* newFiber(PKVM* vm, Function* fn) {
@ -550,52 +551,51 @@ Fiber* newFiber(PKVM* vm, Function* fn) {
}
Class* newClass(PKVM* vm, Script* scr, const char* name, uint32_t length) {
Class* type = ALLOCATE(vm, Class);
varInitObject(&type->_super, vm, OBJ_CLASS);
vmPushTempRef(vm, &type->_super); // type.
Class* cls = ALLOCATE(vm, Class);
varInitObject(&cls->_super, vm, OBJ_CLASS);
pkClassBufferWrite(&scr->classes, vm, type);
type->owner = scr;
type->name = scriptAddName(scr, vm, name, length);
pkUintBufferInit(&type->field_names);
vmPushTempRef(vm, &cls->_super); // type.
// Can't use '$' in string format, since it has a special meaning.
// TODO: escape the character.
String* ty_name = scr->names.data[type->name];
String* dollar = newStringLength(vm, "$", 1);
vmPushTempRef(vm, &dollar->_super); // dollar
String* ctor_name = stringFormat(vm, "@(Ctor:@)", dollar, ty_name);
vmPopTempRef(vm); // dollar
pkClassBufferWrite(&scr->classes, vm, cls);
pkUintBufferInit(&cls->field_names);
cls->owner = scr;
cls->name = scriptAddName(scr, vm, name, length);
// FIXME:
// Make it possible to escape '@' and '$' character in formated string and
// replace below '%' with excaped '\@' (SPECIAL_NAME_CHAR) character.
String* ty_name = scr->names.data[cls->name];
String* ctor_name = stringFormat(vm, "%(Ctor:@)", ty_name);
// Constructor.
vmPushTempRef(vm, &ctor_name->_super); // ctor_name
type->ctor = newFunction(vm, ctor_name->data, ctor_name->length,
cls->ctor = newFunction(vm, ctor_name->data, ctor_name->length,
scr, false, NULL);
vmPopTempRef(vm); // ctor_name
vmPopTempRef(vm); // type.
return type;
return cls;
}
Instance* newInstance(PKVM* vm, Class* ty, bool initialize) {
Instance* newInstance(PKVM* vm, Class* cls, bool initialize) {
Instance* inst = ALLOCATE(vm, Instance);
varInitObject(&inst->_super, vm, OBJ_INST);
vmPushTempRef(vm, &inst->_super); // inst.
ASSERT(ty->name < ty->owner->names.count, OOPS);
inst->ty_name = ty->owner->names.data[ty->name]->data;
ASSERT(cls->name < cls->owner->names.count, OOPS);
inst->ty_name = cls->owner->names.data[cls->name]->data;
inst->is_native = false;
Inst* ins = ALLOCATE(vm, Inst);
inst->ins = ins;
ins->type = ty;
ins->type = cls;
pkVarBufferInit(&ins->fields);
if (initialize && ty->field_names.count != 0) {
pkVarBufferFill(&ins->fields, vm, VAR_NULL, ty->field_names.count);
if (initialize && cls->field_names.count != 0) {
pkVarBufferFill(&ins->fields, vm, VAR_NULL, cls->field_names.count);
}
vmPopTempRef(vm); // inst.
@ -1083,7 +1083,7 @@ void freeObject(PKVM* vm, Object* self) {
Script* scr = (Script*)self;
pkVarBufferClear(&scr->globals, vm);
pkUintBufferClear(&scr->global_names, vm);
pkVarBufferClear(&scr->literals, vm);
pkVarBufferClear(&scr->constants, vm);
pkFunctionBufferClear(&scr->functions, vm);
pkClassBufferClear(&scr->classes, vm);
pkStringBufferClear(&scr->names, vm);
@ -1109,8 +1109,8 @@ void freeObject(PKVM* vm, Object* self) {
} break;
case OBJ_CLASS: {
Class* type = (Class*)self;
pkUintBufferClear(&type->field_names, vm);
Class* cls = (Class*)self;
pkUintBufferClear(&cls->field_names, vm);
} break;
case OBJ_INST:
@ -1271,11 +1271,11 @@ bool instGetAttrib(PKVM* vm, Instance* inst, String* attrib, Var* value) {
} else {
// TODO: Optimize this with binary search.
Class* ty = inst->ins->type;
for (uint32_t i = 0; i < ty->field_names.count; i++) {
ASSERT_INDEX(i, ty->field_names.count);
ASSERT_INDEX(ty->field_names.data[i], ty->owner->names.count);
String* f_name = ty->owner->names.data[ty->field_names.data[i]];
Class* cls = inst->ins->type;
for (uint32_t i = 0; i < cls->field_names.count; i++) {
ASSERT_INDEX(i, cls->field_names.count);
ASSERT_INDEX(cls->field_names.data[i], cls->owner->names.count);
String* f_name = cls->owner->names.data[cls->field_names.data[i]];
if (IS_STR_EQ(f_name, attrib)) {
*value = inst->ins->fields.data[i];
return true;
@ -1637,9 +1637,9 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff,
case OBJ_SCRIPT: {
const Script* scr = (const Script*)obj;
pkByteBufferAddString(buff, vm, "[Module:", 8);
if (scr->module != NULL) {
pkByteBufferAddString(buff, vm, scr->module->data,
scr->module->length);
if (scr->name != NULL) {
pkByteBufferAddString(buff, vm, scr->name->data,
scr->name->length);
} else {
pkByteBufferWrite(buff, vm, '"');
pkByteBufferAddString(buff, vm, scr->path->data, scr->path->length);
@ -1682,9 +1682,9 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff,
}
case OBJ_CLASS: {
const Class* ty = (const Class*)obj;
const Class* cls = (const Class*)obj;
pkByteBufferAddString(buff, vm, "[Class:", 7);
String* ty_name = ty->owner->names.data[ty->name];
String* ty_name = cls->owner->names.data[cls->name];
pkByteBufferAddString(buff, vm, ty_name->data, ty_name->length);
pkByteBufferWrite(buff, vm, ']');
return;
@ -1699,15 +1699,15 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff,
pkByteBufferWrite(buff, vm, ':');
if (!inst->is_native) {
const Class* ty = inst->ins->type;
const Class* cls = inst->ins->type;
const Inst* ins = inst->ins;
ASSERT(ins->fields.count == ty->field_names.count, OOPS);
ASSERT(ins->fields.count == cls->field_names.count, OOPS);
for (uint32_t i = 0; i < ty->field_names.count; i++) {
for (uint32_t i = 0; i < cls->field_names.count; i++) {
if (i != 0) pkByteBufferWrite(buff, vm, ',');
pkByteBufferWrite(buff, vm, ' ');
String* f_name = ty->owner->names.data[ty->field_names.data[i]];
String* f_name = cls->owner->names.data[cls->field_names.data[i]];
pkByteBufferAddString(buff, vm, f_name->data, f_name->length);
pkByteBufferWrite(buff, vm, '=');
_toStringInternal(vm, ins->fields.data[i], buff, outer, repr);

View File

@ -276,20 +276,36 @@ struct Range {
struct Script {
Object _super;
// For core libraries the module and the path are same and points to the
// For core libraries the name and the path are same and points to the
// same String objects.
String* module; //< Module name of the script.
String* name; //< Module name of the script.
String* path; //< Path of the script.
pkVarBuffer globals; //< Script level global variables.
pkUintBuffer global_names; //< Name map to index in globals.
// The constant pool of the module, which contains literal values like
// numbers, strings, and functions which are considered constants to
// a moduel as well as classes.
pkVarBuffer constants;
// All the variable names, globals name, attribute name etc, are stored in
// the [names] buffer. They can be stored in the constants but to make it
// more clear different between string literal and names they're stored in
// a different location.
pkStringBuffer names;
// TODO:
// Consider merging names and constants. Java's class file doesn't have
// a seperation between string literals and names in it's constant pool.
// Globals is an array of global variables of the module. All the names
// (including global variables) are stored in the names buffer of the script
// (defined bellow). The (i)th global variables names is located at index (j)
// in the names buffer where j = global_names[i].
pkVarBuffer globals;
pkUintBuffer global_names;
pkFunctionBuffer functions; //< Functions of the script.
pkClassBuffer classes; //< Classes of the script.
pkStringBuffer names; //< Name literals, attribute names, etc.
pkVarBuffer literals; //< Script literal constant values.
Function* body; //< Script body is an anonymous function.
// When a script has globals, it's body need to be executed to initialize the
@ -310,7 +326,12 @@ struct Function {
const char* name; //< Name in the script [owner] or C literal.
Script* owner; //< Owner script of the function.
int arity; //< Number of argument the function expects.
// Number of argument the function expects. If the arity is -1 that means
// the function has a variadic number of parameters. When a function is
// constructed the value for arity is set to -2 to indicate that it hasn't
// initialized.
int arity;
// Number of upvalues it uses, we're defining it here (and not in object Fn)
// is prevent checking is_native everytime (which might be a bit faster).
@ -539,7 +560,7 @@ Class* newClass(PKVM* vm, Script* scr, const char* name, uint32_t length);
// Allocate new instance with of the base [type]. Note that if [initialize] is
// false, the field value buffer of the instance would be un initialized (ie.
// the buffer count = 0). Otherwise they'll be set to VAR_NULL.
Instance* newInstance(PKVM* vm, Class* ty, bool initialize);
Instance* newInstance(PKVM* vm, Class* cls, bool initialize);
// Allocate new native instance and with [data] as the native type handle and
// return Instance*. The [id] is the unique id of the instance, this would be

View File

@ -683,8 +683,8 @@ L_vm_main_loop:
OPCODE(PUSH_CONSTANT):
{
uint16_t index = READ_SHORT();
ASSERT_INDEX(index, script->literals.count);
PUSH(script->literals.data[index]);
ASSERT_INDEX(index, script->constants.count);
PUSH(script->constants.data[index]);
DISPATCH();
}