mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-06 04:37:47 +08:00
Merge pull request #189 from ThakeeNathees/fn-cls-moved-constants
literals renamed to constants
This commit is contained in:
commit
98643e7fd1
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user