Merge pull request #189 from ThakeeNathees/fn-cls-moved-constants

literals renamed to constants
This commit is contained in:
Thakee Nathees 2022-04-10 06:20:26 +05:30 committed by GitHub
commit 98643e7fd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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();
} }