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. // Add a literal constant to scripts literals and return it's index.
static int compilerAddConstant(Compiler* compiler, Var value) { 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++) { for (uint32_t i = 0; i < constants->count; i++) {
if (isValuesSame(literals->data[i], value)) { if (isValuesSame(constants->data[i], value)) {
return i; return i;
} }
} }
// Add new constant to script. // Add new constant to script.
if (literals->count < MAX_CONSTANTS) { if (constants->count < MAX_CONSTANTS) {
pkVarBufferWrite(literals, compiler->parser.vm, value); pkVarBufferWrite(constants, compiler->parser.vm, value);
} else { } else {
parseError(compiler, "A script should contain at most %d " parseError(compiler, "A script should contain at most %d "
"unique constants.", MAX_CONSTANTS); "unique constants.", MAX_CONSTANTS);
} }
return (int)literals->count - 1; return (int)constants->count - 1;
} }
// Enters inside a block. // Enters inside a block.
@ -2665,12 +2665,12 @@ static void compileRegularImport(Compiler* compiler) {
// If it has a module name use it as binding variable. // 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 // Core libs names are it's module name but for local libs it's optional
// to define a module name for a script. // 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 // Get the variable to bind the imported symbol, if we already have a
// variable with that name override it, otherwise use a new variable. // variable with that name override it, otherwise use a new variable.
const char* name = lib->module->data; const char* name = lib->name->data;
uint32_t length = lib->module->length; uint32_t length = lib->name->length;
int line = compiler->parser.previous.line; int line = compiler->parser.previous.line;
var_index = compilerImportName(compiler, line, name, length); 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 // If the script running a REPL or compiled multiple times by hosting
// application module attribute might already set. In that case make it // application module attribute might already set. In that case make it
// Compile error. // Compile error.
if (script->module != NULL) { if (script->name != NULL) {
parseError(compiler, "Module name already defined."); parseError(compiler, "Module name already defined.");
} else { } else {
consume(compiler, TK_NAME, "Expected a name for the module."); consume(compiler, TK_NAME, "Expected a name for the module.");
const char* name = compiler->parser.previous.start; const char* name = compiler->parser.previous.start;
uint32_t len = compiler->parser.previous.length; uint32_t len = compiler->parser.previous.length;
script->module = newStringLength(vm, name, len); script->name = newStringLength(vm, name, len);
consumeEndStatement(compiler); 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. // Check if function with the same name already exists.
if (scriptGetFunc(script, name, (uint32_t)strlen(name)) != -1) { if (scriptGetFunc(script, name, (uint32_t)strlen(name)) != -1) {
__ASSERT(false, stringFormat(vm, "A function named '$' already esists " __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. // Check if a global variable with the same name already exists.
if (scriptGetGlobals(script, name, (uint32_t)strlen(name)) != -1) { if (scriptGetGlobals(script, name, (uint32_t)strlen(name)) != -1) {
__ASSERT(false, stringFormat(vm, "A global variable named '$' already " __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: case OP_PUSH_CONSTANT:
{ {
int index = READ_SHORT(); int index = READ_SHORT();
ASSERT_INDEX((uint32_t)index, func->owner->literals.count); ASSERT_INDEX((uint32_t)index, func->owner->constants.count);
Var value = func->owner->literals.data[index]; Var value = func->owner->constants.data[index];
// Prints: %5d [val]\n // Prints: %5d [val]\n
PRINT_INT(index); PRINT_INT(index);

View File

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

View File

@ -276,20 +276,36 @@ struct Range {
struct Script { struct Script {
Object _super; 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. // same String objects.
String* module; //< Module name of the script. String* name; //< Module name of the script.
String* path; //< Path of the script. String* path; //< Path of the script.
pkVarBuffer globals; //< Script level global variables. // The constant pool of the module, which contains literal values like
pkUintBuffer global_names; //< Name map to index in globals. // 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. pkFunctionBuffer functions; //< Functions of the script.
pkClassBuffer classes; //< Classes 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. Function* body; //< Script body is an anonymous function.
// When a script has globals, it's body need to be executed to initialize the // 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. const char* name; //< Name in the script [owner] or C literal.
Script* owner; //< Owner script of the function. 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) // 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). // 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 // 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. // 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. // 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 // 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 // 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): OPCODE(PUSH_CONSTANT):
{ {
uint16_t index = READ_SHORT(); uint16_t index = READ_SHORT();
ASSERT_INDEX(index, script->literals.count); ASSERT_INDEX(index, script->constants.count);
PUSH(script->literals.data[index]); PUSH(script->constants.data[index]);
DISPATCH(); DISPATCH();
} }