mirror of
https://github.com/CPunch/Cosmo.git
synced 2025-10-18 07:00:10 +00:00
Compare commits
116 Commits
5a00d61646
...
main
Author | SHA1 | Date | |
---|---|---|---|
5711ca218e | |||
5cd3049d66 | |||
cd37cfdae5 | |||
e0455902b0 | |||
43d79a456e | |||
105a3d70c3 | |||
93f3ae1106 | |||
4816e64612 | |||
0df56bd42a | |||
e7b2d7d833 | |||
39060a67e9 | |||
5296495e47 | |||
a337e26229 | |||
b7bb0773b1 | |||
7f5e3ae8dc | |||
7a54230cb9 | |||
1a7d6caec6 | |||
1678194941 | |||
3ea653b26d | |||
d3de4c0e66 | |||
d66d4807b3 | |||
1fcb35168f | |||
611162b3be | |||
b3587f48a2 | |||
bf36412699 | |||
6701a63a63 | |||
ffff01e9d1 | |||
89be01aaf6 | |||
cc9eb4a5ec | |||
789c5210b4 | |||
dfdd97e739 | |||
096d80d8df | |||
f7bc8e0471 | |||
fce568addc | |||
f5e75f09b9 | |||
fe136f84b5 | |||
de8cd481c3 | |||
6654c3b91c | |||
21f7ea5c14 | |||
e1591ae3fd | |||
bfdd33e01d | |||
c0893b8a14 | |||
d30bcace9a | |||
6a47c82179 | |||
d41126e75f | |||
9f19fd4f31 | |||
6126b50941 | |||
7fa7eb8d94 | |||
0633e87aa6 | |||
75d27afe2c | |||
3f39211081 | |||
c5e4305ef8 | |||
1a78a9ab5f | |||
2f0f675159 | |||
7c5d2f6b65 | |||
f76f2ffa92 | |||
155e0829fb | |||
2b3825d258 | |||
7bca6927a9 | |||
d3647c161b | |||
d27d94975e | |||
2d0e63f706 | |||
dfcf0c92b5 | |||
447f874eff | |||
7b1bd1c9fc | |||
9537a2c7b8 | |||
c44dc88972 | |||
d581e68166 | |||
2271681cec | |||
cf18bbbe54 | |||
3a872fb83f | |||
4ed1c79b50 | |||
bc6eb9b6dc | |||
635f31863f | |||
49a7f68239 | |||
8efecf71a4 | |||
395f352c6e | |||
65d37838cd | |||
3b13ae1624 | |||
d1a16d990c | |||
0a4d36f2f4 | |||
8ac8085d20 | |||
e335fd95d6 | |||
b902ac90de | |||
6056f8eb5b | |||
88284a0b6e | |||
![]() |
7998c2ab41 | ||
7b5825668d | |||
d13cc398c8 | |||
012d3702bf | |||
d761970f17 | |||
0e730b9c51 | |||
bff2799bb6 | |||
07ca82f968 | |||
b545e8e5e3 | |||
55e6453589 | |||
c83dca2ab2 | |||
3890c9dd1e | |||
40739e9bea | |||
![]() |
1eec23035f | ||
![]() |
c0274d1d77 | ||
![]() |
fec26ac380 | ||
35466f691f | |||
71c8dc7e34 | |||
7a6e00be41 | |||
14b091b691 | |||
5c71efbe40 | |||
1fff6c7fe9 | |||
1a96e411f2 | |||
fdd0d19308 | |||
33da88a18a | |||
![]() |
50b19e9f4f | ||
![]() |
472a0ea4c1 | ||
![]() |
76574c7860 | ||
![]() |
8b931fa4a7 | ||
![]() |
ce844dc110 |
4
.github/workflows/check_build.yaml
vendored
4
.github/workflows/check_build.yaml
vendored
@@ -19,9 +19,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: CMake
|
- name: CMake
|
||||||
run: cmake -B build
|
run: cmake -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build
|
run: cmake --build build --config Release
|
||||||
- name: Upload build artifact
|
- name: Upload build artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
|
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
|||||||
# make clean && make && ./bin/cosmo
|
# make clean && make && ./bin/cosmo
|
||||||
|
|
||||||
CC=clang
|
CC=clang
|
||||||
CFLAGS=-fPIE -Wall -Isrc -O3 -std=c99 #-g -fsanitize=address
|
CFLAGS=-fPIE -Wall -Isrc -O3 #-g -fsanitize=address
|
||||||
LDFLAGS=-lm #-fsanitize=address
|
LDFLAGS=-lm #-fsanitize=address
|
||||||
OUT=bin/cosmo
|
OUT=bin/cosmo
|
||||||
|
|
||||||
|
10
README.md
10
README.md
@@ -1,7 +1,4 @@
|
|||||||
# Cosmo
|
# Cosmo
|
||||||
[](https://github.com/CPunch/Cosmo/actions/workflows/check_build.yaml)
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```
|
```
|
||||||
Usage: ./bin/cosmo [-clsr] [args]
|
Usage: ./bin/cosmo [-clsr] [args]
|
||||||
@@ -13,6 +10,13 @@ available options are:
|
|||||||
-r start the repl
|
-r start the repl
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/CPunch/Cosmo/actions/workflows/check_build.yaml"><img src="https://github.com/CPunch/Cosmo/actions/workflows/check_build.yaml/badge.svg?branch=main" alt="Workflow"></a>
|
||||||
|
<a href="https://github.com/CPunch/Cosmo/blob/main/LICENSE.md"><img src="https://img.shields.io/github/license/CPunch/Cosmo" alt="License"></a>
|
||||||
|
<br>
|
||||||
|
<a href="https://asciinema.org/a/629355" target="_blank"><img src="https://asciinema.org/a/629355.svg" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
## What is a 'cosmo'?
|
## What is a 'cosmo'?
|
||||||
|
|
||||||
Cosmo is a portable scripting language loosely based off of Lua. Cosmo easily allows the user to extend the language through the use of Proto objects, which describe the behavior of Objects. For example the following is a simple Vector Proto which describes behavior for a Vector-like object.
|
Cosmo is a portable scripting language loosely based off of Lua. Cosmo easily allows the user to extend the language through the use of Proto objects, which describe the behavior of Objects. For example the following is a simple Vector Proto which describes behavior for a Vector-like object.
|
||||||
|
@@ -59,7 +59,14 @@ Includes functions that interact with the operating system.
|
|||||||
|
|
||||||
| Name | Type | Behavior | Example |
|
| Name | Type | Behavior | Example |
|
||||||
| ------------ | ------------------------------------------------ | ------------------------------------------------------------------------ | ------------------------ |
|
| ------------ | ------------------------------------------------ | ------------------------------------------------------------------------ | ------------------------ |
|
||||||
| os.read | `(path<string>)` -> `<string>` or `<nil>` | Returns a file's contents or nil if it doesn't exist/an error occurred | `os.read("path")` -> `Hello, World!`|
|
| os.open | `(path<string>[, mode<string>])` -> `<bool>, <obj>` | Opens a file at `path` and returns a file object. Specify mode to be "r" or "w" optionally, defaults to "r". | `os.open("test.txt")` -> `true, <file>` |
|
||||||
| os.time | `()` -> `<number>` | Returns the system time in Epoch format | `os.time()` -> `1.61691e+09` |
|
| os.time | `()` -> `<number>` | Returns the system time in Epoch format | `os.time()` -> `1.61691e+09` |
|
||||||
| os.system | `(cmd<string>)` -> `<number>` | Runs a system command as if it were a terminal and returns the exit code | `os.system("mkdir test")` -> `0` |
|
| os.system | `(cmd<string>)` -> `<number>` | Runs a system command as if it were a terminal and returns the exit code | `os.system("mkdir test")` -> `0` |
|
||||||
> -> means 'returns'
|
> -> means 'returns'
|
||||||
|
|
||||||
|
File objects have the following methods:
|
||||||
|
| Name | Type | Behavior | Example |
|
||||||
|
| ------------ | ------------------------------------------------ | ------------------------------------------------------------------------ | ------------------------ |
|
||||||
|
| file:read | `(amt<number> or "a")` -> `<string>` | Reads `amt` bytes from the file and returns them as a string. If `"a"` is passed, the entire file is read. | `file:read("a")` -> `"Hello world!"` |
|
||||||
|
| file:write | `(data<string>)` -> `<nil>` | Writes `data` to file. | `file:write("hello world!")` -> `<nil>` |
|
||||||
|
> -> means 'returns'
|
||||||
|
6
examples/reader.cosmo
Normal file
6
examples/reader.cosmo
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
local err, file = os.open("LICENSE.md")
|
||||||
|
if err then
|
||||||
|
print("failed to open file")
|
||||||
|
end
|
||||||
|
|
||||||
|
print(file:read("a"))
|
6
examples/writer.cosmo
Normal file
6
examples/writer.cosmo
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
local err, file = os.open("test.md", "w")
|
||||||
|
if err then
|
||||||
|
print("failed to open file")
|
||||||
|
end
|
||||||
|
|
||||||
|
file:write("hello world")
|
29
main.c
29
main.c
@@ -50,13 +50,24 @@ static bool interpret(CState *state, const char *script, const char *mod)
|
|||||||
|
|
||||||
// cosmoV_compileString pushes the result onto the stack (COBJ_ERROR or COBJ_CLOSURE)
|
// cosmoV_compileString pushes the result onto the stack (COBJ_ERROR or COBJ_CLOSURE)
|
||||||
if (cosmoV_compileString(state, script, mod)) {
|
if (cosmoV_compileString(state, script, mod)) {
|
||||||
// 0 args being passed, 0 results expected
|
cosmoG_disassemble(cosmoV_readClosure(*cosmoV_getTop(state, 0)));
|
||||||
if (!cosmoV_pcall(state, 0, 0)) {
|
if (!cosmoV_pcall(state, 0, 1)) {
|
||||||
cosmoV_printError(state, cosmoV_readError(*cosmoV_pop(state)));
|
cosmoV_printBacktrace(state, cosmoV_readError(*cosmoV_pop(state)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the result is nil, we don't print it
|
||||||
|
if (IS_NIL(*cosmoV_getTop(state, 0))) {
|
||||||
|
cosmoV_pop(state);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, we print the result
|
||||||
|
cosmoV_printValue(*cosmoV_getTop(state, 0));
|
||||||
|
printf("\n");
|
||||||
|
cosmoV_pop(state);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_printError(state, cosmoV_readError(*cosmoV_pop(state)));
|
cosmoV_printBacktrace(state, cosmoV_readError(*cosmoV_pop(state)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +86,7 @@ static void repl(CState *state)
|
|||||||
cosmoV_pushString(state, "input");
|
cosmoV_pushString(state, "input");
|
||||||
cosmoV_pushCFunction(state, cosmoB_input);
|
cosmoV_pushCFunction(state, cosmoB_input);
|
||||||
|
|
||||||
cosmoV_register(state, 2);
|
cosmoV_addGlobals(state, 2);
|
||||||
|
|
||||||
while (_ACTIVE) {
|
while (_ACTIVE) {
|
||||||
if (!(line = linenoise("> "))) { // better than gets()
|
if (!(line = linenoise("> "))) { // better than gets()
|
||||||
@@ -130,7 +141,7 @@ static bool runFile(CState *state, const char *fileName)
|
|||||||
cosmoV_pushString(state, "input");
|
cosmoV_pushString(state, "input");
|
||||||
cosmoV_pushCFunction(state, cosmoB_input);
|
cosmoV_pushCFunction(state, cosmoB_input);
|
||||||
|
|
||||||
cosmoV_register(state, 1);
|
cosmoV_addGlobals(state, 1);
|
||||||
|
|
||||||
ret = interpret(state, script, fileName);
|
ret = interpret(state, script, fileName);
|
||||||
|
|
||||||
@@ -158,7 +169,7 @@ void compileScript(CState *state, const char *in, const char *out)
|
|||||||
CObjFunction *func = cosmoV_readClosure(*cosmoV_getTop(state, 0))->function;
|
CObjFunction *func = cosmoV_readClosure(*cosmoV_getTop(state, 0))->function;
|
||||||
cosmoD_dump(state, func, fileWriter, (void *)fout);
|
cosmoD_dump(state, func, fileWriter, (void *)fout);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_printError(state, cosmoV_readError(*cosmoV_pop(state)));
|
cosmoV_printBacktrace(state, cosmoV_readError(*cosmoV_pop(state)));
|
||||||
}
|
}
|
||||||
|
|
||||||
free(script);
|
free(script);
|
||||||
@@ -171,13 +182,13 @@ void loadScript(CState *state, const char *in)
|
|||||||
{
|
{
|
||||||
FILE *file = fopen(in, "rb");
|
FILE *file = fopen(in, "rb");
|
||||||
if (!cosmoV_undump(state, fileReader, file)) {
|
if (!cosmoV_undump(state, fileReader, file)) {
|
||||||
cosmoV_printError(state, cosmoV_readError(*cosmoV_pop(state)));
|
cosmoV_printBacktrace(state, cosmoV_readError(*cosmoV_pop(state)));
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
printf("[!] loaded %s!\n", in);
|
printf("[!] loaded %s!\n", in);
|
||||||
if (!cosmoV_pcall(state, 0, 0))
|
if (!cosmoV_pcall(state, 0, 0))
|
||||||
cosmoV_printError(state, cosmoV_readError(*cosmoV_pop(state)));
|
cosmoV_printBacktrace(state, cosmoV_readError(*cosmoV_pop(state)));
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
276
src/cbaselib.c
276
src/cbaselib.c
@@ -18,7 +18,7 @@ int cosmoB_print(CState *state, int nargs, CValue *args)
|
|||||||
CObjString *str = cosmoV_toString(state, args[i]);
|
CObjString *str = cosmoV_toString(state, args[i]);
|
||||||
printf("%s", cosmoO_readCString(str));
|
printf("%s", cosmoO_readCString(str));
|
||||||
} else { // else, thats pretty expensive for primitives, just print the raw value
|
} else { // else, thats pretty expensive for primitives, just print the raw value
|
||||||
printValue(args[i]);
|
cosmoV_printValue(args[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@@ -69,7 +69,7 @@ int cosmoB_pcall(CState *state, int nargs, CValue *args)
|
|||||||
bool res = cosmoV_pcall(state, nargs - 1, 1);
|
bool res = cosmoV_pcall(state, nargs - 1, 1);
|
||||||
|
|
||||||
// insert false before the result
|
// insert false before the result
|
||||||
cosmo_insert(state, 0, cosmoV_newBoolean(res));
|
cosmoV_insert(state, 0, cosmoV_newBoolean(res));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ int cosmoB_loadstring(CState *state, int nargs, CValue *args)
|
|||||||
CObjString *str = cosmoV_readString(args[0]);
|
CObjString *str = cosmoV_readString(args[0]);
|
||||||
bool res = cosmoV_compileString(state, str->str, "");
|
bool res = cosmoV_compileString(state, str->str, "");
|
||||||
|
|
||||||
cosmo_insert(state, 0, cosmoV_newBoolean(res));
|
cosmoV_insert(state, 0, cosmoV_newBoolean(res));
|
||||||
return 2; // <boolean>, <closure> or <error>
|
return 2; // <boolean>, <closure> or <error>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ void cosmoB_loadLibrary(CState *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// register all the pushed c functions and the strings as globals
|
// register all the pushed c functions and the strings as globals
|
||||||
cosmoV_register(state, i);
|
cosmoV_addGlobals(state, i);
|
||||||
|
|
||||||
// load other libraries
|
// load other libraries
|
||||||
cosmoB_loadObjLib(state);
|
cosmoB_loadObjLib(state);
|
||||||
@@ -168,8 +168,43 @@ int cosmoB_ogetProto(CState *state, int nargs, CValue *args)
|
|||||||
if (nargs != 1)
|
if (nargs != 1)
|
||||||
cosmoV_error(state, "Expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "Expected 1 argument, got %d!", nargs);
|
||||||
|
|
||||||
cosmoV_pushRef(state, (CObj *)cosmoV_readObject(args[0])->_obj.proto); // just return the proto
|
if (!IS_REF(args[0])) {
|
||||||
|
cosmoV_typeError(state, "__getter.__proto", "<object>", "%s", cosmoV_typeStr(args[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
CObj *proto = (CObj *)cosmoV_readRef(args[0])->proto;
|
||||||
|
if (proto == NULL) {
|
||||||
|
cosmoV_pushNil(state);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cosmoV_pushRef(state, proto); // just return the proto
|
||||||
|
return 1; // 1 result
|
||||||
|
}
|
||||||
|
|
||||||
|
int cosmoB_ogetKeys(CState *state, int nargs, CValue *args)
|
||||||
|
{
|
||||||
|
if (nargs != 1)
|
||||||
|
cosmoV_error(state, "Expected 1 argument, got %d!", nargs);
|
||||||
|
|
||||||
|
if (!IS_OBJECT(args[0])) {
|
||||||
|
cosmoV_typeError(state, "object.__keys", "<object>", "%s", cosmoV_typeStr(args[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// push keys
|
||||||
|
CObjObject *obj = cosmoV_readObject(args[0]);
|
||||||
|
int cap = cosmoT_getCapacity(&obj->tbl);
|
||||||
|
int indx = 0;
|
||||||
|
for (int i = 0; i < cap; i++) {
|
||||||
|
CTableEntry *entry = &obj->tbl.table[i];
|
||||||
|
if (IS_NIL(entry->key))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cosmoV_pushNumber(state, indx++);
|
||||||
|
cosmoV_pushValue(state, entry->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
cosmoV_makeTable(state, indx);
|
||||||
return 1; // 1 result
|
return 1; // 1 result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,9 +229,9 @@ int cosmoB_oisChild(CState *state, int nargs, CValue *args)
|
|||||||
|
|
||||||
COSMO_API void cosmoB_loadObjLib(CState *state)
|
COSMO_API void cosmoB_loadObjLib(CState *state)
|
||||||
{
|
{
|
||||||
const char *identifiers[] = {"ischild"};
|
const char *identifiers[] = {"ischild", "keys"};
|
||||||
|
|
||||||
CosmoCFunction objLib[] = {cosmoB_oisChild};
|
CosmoCFunction objLib[] = {cosmoB_oisChild, cosmoB_ogetKeys};
|
||||||
|
|
||||||
// make object library object
|
// make object library object
|
||||||
cosmoV_pushString(state, "object");
|
cosmoV_pushString(state, "object");
|
||||||
@@ -204,7 +239,7 @@ COSMO_API void cosmoB_loadObjLib(CState *state)
|
|||||||
// make __getter object for debug proto
|
// make __getter object for debug proto
|
||||||
cosmoV_pushString(state, "__getter");
|
cosmoV_pushString(state, "__getter");
|
||||||
|
|
||||||
// key & value pair
|
// key & value pairs
|
||||||
cosmoV_pushString(state, "__proto"); // key
|
cosmoV_pushString(state, "__proto"); // key
|
||||||
cosmoV_pushCFunction(state, cosmoB_ogetProto); // value
|
cosmoV_pushCFunction(state, cosmoB_ogetProto); // value
|
||||||
|
|
||||||
@@ -230,52 +265,176 @@ COSMO_API void cosmoB_loadObjLib(CState *state)
|
|||||||
cosmoV_registerProtoObject(state, COBJ_OBJECT, obj);
|
cosmoV_registerProtoObject(state, COBJ_OBJECT, obj);
|
||||||
|
|
||||||
// register "object" to the global table
|
// register "object" to the global table
|
||||||
cosmoV_register(state, 1);
|
cosmoV_addGlobals(state, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================================================ [OS.*]
|
// ================================================================ [OS.*]
|
||||||
|
|
||||||
// os.read()
|
int fileB_read(CState *state, int nargs, CValue *args)
|
||||||
int cosmoB_osRead(CState *state, int nargs, CValue *args)
|
{
|
||||||
|
if (nargs != 2) {
|
||||||
|
cosmoV_error(state, "file:read() expected 2 arguments, got %d!", nargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cosmoV_isValueUserType(state, args[0], COSMO_USER_FILE)) {
|
||||||
|
cosmoV_typeError(state, "file:read()", "<file>, <number> or \"a\"", "%s, %s",
|
||||||
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
CObjObject *fileObj = cosmoV_readObject(args[0]);
|
||||||
|
FILE *file = cosmoO_getUserP(fileObj);
|
||||||
|
|
||||||
|
if (IS_NUMBER(args[1])) {
|
||||||
|
CValue temp;
|
||||||
|
char *buffer;
|
||||||
|
cosmo_Number length = cosmoV_readNumber(args[1]);
|
||||||
|
|
||||||
|
// make sure the length is within the bounds of the file
|
||||||
|
if (length < 0) {
|
||||||
|
cosmoV_error(state, "file:read() expected length to be >= 0, got %d!", length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate a buffer for the read data
|
||||||
|
buffer = cosmoM_xmalloc(state, (size_t)length + 1);
|
||||||
|
|
||||||
|
// read the data
|
||||||
|
fread(buffer, sizeof(char), (size_t)length, file);
|
||||||
|
buffer[(int)length] = '\0'; // write the NULL terminator
|
||||||
|
|
||||||
|
// push the read data
|
||||||
|
temp = cosmoV_newRef(cosmoO_takeString(state, buffer, (size_t)length));
|
||||||
|
cosmoV_pushValue(state, temp);
|
||||||
|
} else if (IS_STRING(args[1])) {
|
||||||
|
if (strcmp(cosmoV_readCString(args[1]), "a") == 0) {
|
||||||
|
CValue temp;
|
||||||
|
char *buffer;
|
||||||
|
long length;
|
||||||
|
|
||||||
|
// get the length of the file
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
length = ftell(file);
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
|
||||||
|
// allocate a buffer for the read data
|
||||||
|
buffer = cosmoM_xmalloc(state, (size_t)length + 1);
|
||||||
|
|
||||||
|
// read the data
|
||||||
|
fread(buffer, sizeof(char), (size_t)length, file);
|
||||||
|
buffer[length] = '\0'; // write the NULL terminator
|
||||||
|
|
||||||
|
// push the read data
|
||||||
|
temp = cosmoV_newRef(cosmoO_takeString(state, buffer, (size_t)length));
|
||||||
|
cosmoV_pushValue(state, temp);
|
||||||
|
} else {
|
||||||
|
cosmoV_error(state, "file:read() expected \"a\" or <number>, got \"%s\"!",
|
||||||
|
cosmoV_readCString(args[1]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cosmoV_typeError(state, "file:read()", "<file>, <number> or \"a\"", "%s, %s",
|
||||||
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fileB_write(CState *state, int nargs, CValue *args)
|
||||||
|
{
|
||||||
|
CObjObject *fileObj;
|
||||||
|
CObjString *str;
|
||||||
|
FILE *file;
|
||||||
|
|
||||||
|
if (nargs != 2) {
|
||||||
|
cosmoV_error(state, "file:write() expected 2 arguments, got %d!", nargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cosmoV_isValueUserType(state, args[0], COSMO_USER_FILE)) {
|
||||||
|
cosmoV_typeError(state, "file:write()", "<file>, <string>", "%s, %s",
|
||||||
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IS_STRING(args[1])) {
|
||||||
|
cosmoV_typeError(state, "file:write()", "<file>, <string>", "%s, %s",
|
||||||
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
fileObj = cosmoV_readObject(args[0]);
|
||||||
|
str = cosmoV_readString(args[1]);
|
||||||
|
|
||||||
|
file = (FILE *)cosmoO_getUserP(fileObj);
|
||||||
|
fwrite(str->str, sizeof(char), str->length, file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fileB_gc(CState *state, int nargs, CValue *args)
|
||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "os.read() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "file:read() expected 1 argument, got %d!", nargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_STRING(args[0])) {
|
if (!cosmoV_isValueUserType(state, args[0], COSMO_USER_FILE)) {
|
||||||
cosmoV_typeError(state, "os.read()", "<string>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "file:__gc()", "<file>", "%s", cosmoV_typeStr(args[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjString *str = cosmoV_readString(args[0]);
|
CObjObject *fileObj = cosmoV_readObject(args[0]);
|
||||||
|
FILE *file = cosmoO_getUserP(fileObj);
|
||||||
|
|
||||||
// open file
|
fclose(file);
|
||||||
FILE *file = fopen(str->str, "rb");
|
return 0;
|
||||||
char *buf;
|
}
|
||||||
size_t size, bRead;
|
|
||||||
|
|
||||||
|
CObjObject *pushFileObj(CState *state, FILE *file)
|
||||||
|
{
|
||||||
|
CObjObject *fileObj = cosmoO_newObject(state);
|
||||||
|
cosmoV_pushRef(state, (CObj *)fileObj);
|
||||||
|
cosmoO_setUserP(fileObj, file);
|
||||||
|
cosmoO_setUserT(fileObj, COSMO_USER_FILE);
|
||||||
|
|
||||||
|
// grab and set proto from the registry
|
||||||
|
cosmoV_pushRef(state, (CObj *)fileObj);
|
||||||
|
cosmoV_pushString(state, "file");
|
||||||
|
cosmoV_getRegistry(state);
|
||||||
|
cosmoV_setProto(state);
|
||||||
|
|
||||||
|
cosmoO_lock(fileObj);
|
||||||
|
return fileObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cosmoB_osOpen(CState *state, int nargs, CValue *args)
|
||||||
|
{
|
||||||
|
const char *filePath, *mode = "rb";
|
||||||
|
FILE *file;
|
||||||
|
|
||||||
|
if (nargs >= 1) {
|
||||||
|
if (!IS_STRING(args[0])) {
|
||||||
|
cosmoV_typeError(state, "os.open()", "<string>", "%s", cosmoV_typeStr(args[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nargs == 2) {
|
||||||
|
if (!IS_STRING(args[1])) {
|
||||||
|
cosmoV_typeError(state, "os.open()", "<string>, <string>", "%s, %s",
|
||||||
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
mode = cosmoV_readCString(args[1]);
|
||||||
|
} else if (nargs != 1) {
|
||||||
|
cosmoV_error(state, "os.open() expected 1 or 2 arguments, got %d!", nargs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cosmoV_error(state, "os.open() expected 1 or 2 arguments, got %d!", nargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath = cosmoV_readCString(args[0]);
|
||||||
|
file = fopen(filePath, mode);
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
// return nil, file doesn't exist
|
cosmoV_pushBoolean(state, true);
|
||||||
return 0;
|
cosmoV_pushFString(state, "Failed to open %s!", filePath);
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// grab the size of the file
|
cosmoV_pushBoolean(state, false);
|
||||||
fseek(file, 0L, SEEK_END);
|
pushFileObj(state, file);
|
||||||
size = ftell(file);
|
return 2;
|
||||||
rewind(file);
|
|
||||||
|
|
||||||
buf = cosmoM_xmalloc(state, size + 1); // +1 for the NULL terminator
|
|
||||||
bRead = fread(buf, sizeof(char), size, file); // read the file into the buffer
|
|
||||||
|
|
||||||
if (bRead < size) {
|
|
||||||
// an error occured! we don't need to really throw an error, returning a nil is good enough
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[bRead] = '\0'; // place the NULL terminator at the end of the buffer
|
|
||||||
|
|
||||||
// push the string to the stack to return
|
|
||||||
cosmoV_pushValue(state, cosmoV_newRef(cosmoO_takeString(state, buf, bRead)));
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// os.time()
|
// os.time()
|
||||||
@@ -309,9 +468,8 @@ int cosmoB_osSystem(CState *state, int nargs, CValue *args)
|
|||||||
|
|
||||||
COSMO_API void cosmoB_loadOS(CState *state)
|
COSMO_API void cosmoB_loadOS(CState *state)
|
||||||
{
|
{
|
||||||
const char *identifiers[] = {"read", "time", "system"};
|
const char *identifiers[] = {"open", "time", "system"};
|
||||||
|
CosmoCFunction osLib[] = {cosmoB_osOpen, cosmoB_osTime, cosmoB_osSystem};
|
||||||
CosmoCFunction osLib[] = {cosmoB_osRead, cosmoB_osTime, cosmoB_osSystem};
|
|
||||||
|
|
||||||
cosmoV_pushString(state, "os");
|
cosmoV_pushString(state, "os");
|
||||||
|
|
||||||
@@ -322,7 +480,30 @@ COSMO_API void cosmoB_loadOS(CState *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_makeObject(state, i);
|
cosmoV_makeObject(state, i);
|
||||||
cosmoV_register(state, 1); // register the os.* object to the global table
|
cosmoV_addGlobals(state, 1); // register the os.* object to the global table
|
||||||
|
|
||||||
|
// make file proto
|
||||||
|
cosmoV_pushString(state, "file");
|
||||||
|
|
||||||
|
CObjObject *fileProto = cosmoO_newObject(state);
|
||||||
|
cosmoV_pushRef(state, (CObj *)fileProto);
|
||||||
|
|
||||||
|
cosmoV_pushRef(state, (CObj *)fileProto);
|
||||||
|
cosmoV_pushString(state, "read");
|
||||||
|
cosmoV_pushCFunction(state, fileB_read);
|
||||||
|
cosmoV_set(state);
|
||||||
|
|
||||||
|
cosmoV_pushRef(state, (CObj *)fileProto);
|
||||||
|
cosmoV_pushString(state, "write");
|
||||||
|
cosmoV_pushCFunction(state, fileB_write);
|
||||||
|
cosmoV_set(state);
|
||||||
|
|
||||||
|
cosmoV_pushRef(state, (CObj *)fileProto);
|
||||||
|
cosmoV_pushString(state, "__gc");
|
||||||
|
cosmoV_pushCFunction(state, fileB_gc);
|
||||||
|
cosmoV_set(state);
|
||||||
|
|
||||||
|
cosmoV_addRegistry(state, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================================================ [STRING.*]
|
// ================================================================ [STRING.*]
|
||||||
@@ -546,8 +727,9 @@ int cosmoB_sRep(CState *state, int nargs, CValue *args)
|
|||||||
char *newStr = cosmoM_xmalloc(state, length + 1); // + 1 for the NULL terminator
|
char *newStr = cosmoM_xmalloc(state, length + 1); // + 1 for the NULL terminator
|
||||||
|
|
||||||
// copy the string over the new buffer
|
// copy the string over the new buffer
|
||||||
for (int i = 0; i < times; i++)
|
for (int i = 0; i < times; i++) {
|
||||||
memcpy(&newStr[i * str->length], str->str, str->length);
|
memcpy(&newStr[i * str->length], str->str, str->length);
|
||||||
|
}
|
||||||
|
|
||||||
// write the NULL terminator
|
// write the NULL terminator
|
||||||
newStr[length] = '\0';
|
newStr[length] = '\0';
|
||||||
@@ -578,7 +760,7 @@ void cosmoB_loadStrLib(CState *state)
|
|||||||
cosmoV_registerProtoObject(state, COBJ_STRING, obj);
|
cosmoV_registerProtoObject(state, COBJ_STRING, obj);
|
||||||
|
|
||||||
// register "string" to the global table
|
// register "string" to the global table
|
||||||
cosmoV_register(state, 1);
|
cosmoV_addGlobals(state, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================================================ [MATH]
|
// ================================================================ [MATH]
|
||||||
@@ -773,7 +955,7 @@ void cosmoB_loadMathLib(CState *state)
|
|||||||
|
|
||||||
// make the object and register it as a global to the state
|
// make the object and register it as a global to the state
|
||||||
cosmoV_makeObject(state, i);
|
cosmoV_makeObject(state, i);
|
||||||
cosmoV_register(state, 1);
|
cosmoV_addGlobals(state, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================================================ [VM.*]
|
// ================================================================ [VM.*]
|
||||||
@@ -924,5 +1106,5 @@ void cosmoB_loadVM(CState *state)
|
|||||||
cosmoV_makeObject(state, 5); // makes the vm object
|
cosmoV_makeObject(state, 5); // makes the vm object
|
||||||
|
|
||||||
// register "vm" to the global table
|
// register "vm" to the global table
|
||||||
cosmoV_register(state, 1);
|
cosmoV_addGlobals(state, 1);
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,13 @@
|
|||||||
|
|
||||||
#include "cstate.h"
|
#include "cstate.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
COSMO_USER_NONE, // CObjObject is not a userdata object
|
||||||
|
COSMO_USER_FILE, // CObjObject is a file object (see cosmoB_osOpen)
|
||||||
|
COSMO_USER_START // the first user type for user-defined userdata
|
||||||
|
};
|
||||||
|
|
||||||
/* loads all of the base library, including:
|
/* loads all of the base library, including:
|
||||||
- base library ("print", "assert", "type", "pcall", "loadstring", etc.)
|
- base library ("print", "assert", "type", "pcall", "loadstring", etc.)
|
||||||
- object library
|
- object library
|
||||||
|
12
src/cdebug.c
12
src/cdebug.c
@@ -5,8 +5,9 @@
|
|||||||
|
|
||||||
void printIndent(int indent)
|
void printIndent(int indent)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < indent; i++)
|
for (int i = 0; i < indent; i++) {
|
||||||
printf("\t");
|
printf("\t");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int simpleInstruction(const char *name, int offset)
|
static int simpleInstruction(const char *name, int offset)
|
||||||
@@ -61,7 +62,7 @@ static int constInstruction(const char *name, CChunk *chunk, int offset)
|
|||||||
printf("%-16s [%05d] - ", name, index);
|
printf("%-16s [%05d] - ", name, index);
|
||||||
CValue val = chunk->constants.values[index];
|
CValue val = chunk->constants.values[index];
|
||||||
|
|
||||||
printValue(val);
|
cosmoV_printValue(val);
|
||||||
|
|
||||||
return offset + 1 + (sizeof(uint16_t) / sizeof(INSTRUCTION)); // consume opcode + uint
|
return offset + 1 + (sizeof(uint16_t) / sizeof(INSTRUCTION)); // consume opcode + uint
|
||||||
}
|
}
|
||||||
@@ -127,7 +128,7 @@ int disasmInstr(CChunk *chunk, int offset, int indent)
|
|||||||
CObjFunction *cobjFunc = (CObjFunction *)cosmoV_readRef(val);
|
CObjFunction *cobjFunc = (CObjFunction *)cosmoV_readRef(val);
|
||||||
offset += 3; // we consumed the opcode + u16
|
offset += 3; // we consumed the opcode + u16
|
||||||
|
|
||||||
printValue(val);
|
cosmoV_printValue(val);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
// list the upvalues/locals that are captured
|
// list the upvalues/locals that are captured
|
||||||
@@ -222,3 +223,8 @@ int disasmInstr(CChunk *chunk, int offset, int indent)
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cosmoG_disassemble(CObjClosure *closure)
|
||||||
|
{
|
||||||
|
disasmChunk(&closure->function->chunk, closure->function->name == NULL ? UNNAMEDCHUNK : closure->function->name->str, 0);
|
||||||
|
}
|
@@ -2,10 +2,13 @@
|
|||||||
#define CDEBUG_H
|
#define CDEBUG_H
|
||||||
|
|
||||||
#include "cchunk.h"
|
#include "cchunk.h"
|
||||||
|
#include "cobj.h"
|
||||||
|
|
||||||
COSMO_API void disasmChunk(CChunk *chunk, const char *name, int indent);
|
COSMO_API void disasmChunk(CChunk *chunk, const char *name, int indent);
|
||||||
COSMO_API int disasmInstr(CChunk *chunk, int offset, int indent);
|
COSMO_API int disasmInstr(CChunk *chunk, int offset, int indent);
|
||||||
|
|
||||||
void printIndent(int indent);
|
void printIndent(int indent);
|
||||||
|
|
||||||
|
COSMO_API void cosmoG_disassemble(CObjClosure *closure);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
82
src/cmem.c
82
src/cmem.c
@@ -6,6 +6,7 @@
|
|||||||
#include "cstate.h"
|
#include "cstate.h"
|
||||||
#include "ctable.h"
|
#include "ctable.h"
|
||||||
#include "cvalue.h"
|
#include "cvalue.h"
|
||||||
|
#include "cvm.h"
|
||||||
|
|
||||||
// realloc wrapper
|
// realloc wrapper
|
||||||
void *cosmoM_reallocate(CState *state, void *buf, size_t oldSize, size_t newSize)
|
void *cosmoM_reallocate(CState *state, void *buf, size_t oldSize, size_t newSize)
|
||||||
@@ -164,8 +165,9 @@ static void blackenObject(CState *state, CObj *obj)
|
|||||||
markValue(state, err->err);
|
markValue(state, err->err);
|
||||||
|
|
||||||
// mark callframes
|
// mark callframes
|
||||||
for (int i = 0; i < err->frameCount; i++)
|
for (int i = 0; i < err->frameCount; i++) {
|
||||||
markObject(state, (CObj *)err->frames[i].closure);
|
markObject(state, (CObj *)err->frames[i].closure);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -229,11 +231,11 @@ static void traceGrays(CState *state)
|
|||||||
|
|
||||||
static void sweep(CState *state)
|
static void sweep(CState *state)
|
||||||
{
|
{
|
||||||
CObj *prev = NULL;
|
CObj *prev = NULL, *object = state->objects;
|
||||||
CObj *object = state->objects;
|
|
||||||
while (object != NULL) {
|
while (object != NULL) {
|
||||||
if (object->isMarked) { // skip over it
|
if (object->isMarked) { // skip over it
|
||||||
object->isMarked = false; // rest to white
|
object->isMarked = false; // reset to white
|
||||||
prev = object;
|
prev = object;
|
||||||
object = object->next;
|
object = object->next;
|
||||||
} else { // free it!
|
} else { // free it!
|
||||||
@@ -246,22 +248,22 @@ static void sweep(CState *state)
|
|||||||
prev->next = object;
|
prev->next = object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// call __gc on the object
|
||||||
|
CObjObject *protoObject = cosmoO_grabProto(oldObj);
|
||||||
|
CValue res;
|
||||||
|
|
||||||
|
// use user-defined __gc
|
||||||
|
if (protoObject != NULL && cosmoO_getIString(state, protoObject, ISTRING_GC, &res)) {
|
||||||
|
cosmoV_pushValue(state, res);
|
||||||
|
cosmoV_pushRef(state, (CObj *)oldObj);
|
||||||
|
cosmoV_call(state, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
cosmoO_free(state, oldObj);
|
cosmoO_free(state, oldObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void markUserRoots(CState *state)
|
|
||||||
{
|
|
||||||
CObj *root = state->userRoots;
|
|
||||||
|
|
||||||
// traverse userRoots and mark all the object
|
|
||||||
while (root != NULL) {
|
|
||||||
markObject(state, root);
|
|
||||||
root = root->nextRoot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void markRoots(CState *state)
|
static void markRoots(CState *state)
|
||||||
{
|
{
|
||||||
// mark all values on the stack
|
// mark all values on the stack
|
||||||
@@ -282,14 +284,15 @@ static void markRoots(CState *state)
|
|||||||
markObject(state, (CObj *)state->globals);
|
markObject(state, (CObj *)state->globals);
|
||||||
|
|
||||||
// mark all internal strings
|
// mark all internal strings
|
||||||
for (int i = 0; i < ISTRING_MAX; i++)
|
for (int i = 0; i < ISTRING_MAX; i++) {
|
||||||
markObject(state, (CObj *)state->iStrings[i]);
|
markObject(state, (CObj *)state->iStrings[i]);
|
||||||
|
}
|
||||||
|
|
||||||
// mark the user defined roots
|
markTable(state, &state->registry);
|
||||||
markUserRoots(state);
|
|
||||||
|
|
||||||
for (int i = 0; i < COBJ_MAX; i++)
|
for (int i = 0; i < COBJ_MAX; i++) {
|
||||||
markObject(state, (CObj *)state->protoObjects[i]);
|
markObject(state, (CObj *)state->protoObjects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
traceGrays(state);
|
traceGrays(state);
|
||||||
}
|
}
|
||||||
@@ -323,44 +326,3 @@ COSMO_API void cosmoM_updateThreshhold(CState *state)
|
|||||||
{
|
{
|
||||||
state->nextGC = state->allocatedBytes * HEAP_GROW_FACTOR;
|
state->nextGC = state->allocatedBytes * HEAP_GROW_FACTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
COSMO_API void cosmoM_addRoot(CState *state, CObj *newRoot)
|
|
||||||
{
|
|
||||||
// first, check and make sure this root doesn't already exist in the list
|
|
||||||
CObj *root = state->userRoots;
|
|
||||||
while (root != NULL) {
|
|
||||||
if (root == newRoot) // found in the list, abort
|
|
||||||
return;
|
|
||||||
|
|
||||||
root = root->nextRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
// adds root to userRoot linked list
|
|
||||||
newRoot->nextRoot = state->userRoots;
|
|
||||||
state->userRoots = newRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
COSMO_API void cosmoM_removeRoot(CState *state, CObj *oldRoot)
|
|
||||||
{
|
|
||||||
CObj *prev = NULL;
|
|
||||||
CObj *root = state->userRoots;
|
|
||||||
|
|
||||||
// traverse the userRoot linked list
|
|
||||||
while (root != NULL) {
|
|
||||||
if (root == oldRoot) { // found root in list
|
|
||||||
|
|
||||||
// remove from the linked list
|
|
||||||
if (prev == NULL) {
|
|
||||||
state->userRoots = root->nextRoot;
|
|
||||||
} else {
|
|
||||||
prev->nextRoot = root->nextRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
root->nextRoot = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
prev = root;
|
|
||||||
root = root->nextRoot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -67,13 +67,6 @@ COSMO_API bool cosmoM_checkGarbage(CState *state,
|
|||||||
COSMO_API void cosmoM_collectGarbage(CState *state);
|
COSMO_API void cosmoM_collectGarbage(CState *state);
|
||||||
COSMO_API void cosmoM_updateThreshhold(CState *state);
|
COSMO_API void cosmoM_updateThreshhold(CState *state);
|
||||||
|
|
||||||
// lets the VM know you are holding a reference to a CObj and to not free it
|
|
||||||
// NOTE: prefer to use the stack when possible
|
|
||||||
COSMO_API void cosmoM_addRoot(CState *state, CObj *newRoot);
|
|
||||||
|
|
||||||
// lets the VM know this root is no longer held in a reference and is able to be freed
|
|
||||||
COSMO_API void cosmoM_removeRoot(CState *state, CObj *oldRoot);
|
|
||||||
|
|
||||||
// wrapper for cosmoM_reallocate so we can track our memory usage
|
// wrapper for cosmoM_reallocate so we can track our memory usage
|
||||||
static inline void *cosmoM_xmalloc(CState *state, size_t sz)
|
static inline void *cosmoM_xmalloc(CState *state, size_t sz)
|
||||||
{
|
{
|
||||||
|
46
src/cobj.c
46
src/cobj.c
@@ -15,8 +15,9 @@ uint32_t hashString(const char *str, size_t sz)
|
|||||||
uint32_t hash = sz;
|
uint32_t hash = sz;
|
||||||
size_t step = (sz >> 5) + 1;
|
size_t step = (sz >> 5) + 1;
|
||||||
|
|
||||||
for (size_t i = sz; i >= step; i -= step)
|
for (size_t i = sz; i >= step; i -= step) {
|
||||||
hash = ((hash << 5) + (hash >> 2)) + str[i - 1];
|
hash = ((hash << 5) + (hash >> 2)) + str[i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
@@ -31,7 +32,6 @@ CObj *cosmoO_allocateBase(CState *state, size_t sz, CObjType type)
|
|||||||
obj->next = state->objects;
|
obj->next = state->objects;
|
||||||
state->objects = obj;
|
state->objects = obj;
|
||||||
|
|
||||||
obj->nextRoot = NULL;
|
|
||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
printf("allocated %s %p\n", cosmoO_typeStr(obj), obj);
|
printf("allocated %s %p\n", cosmoO_typeStr(obj), obj);
|
||||||
#endif
|
#endif
|
||||||
@@ -51,9 +51,9 @@ void cosmoO_free(CState *state, CObj *obj)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COBJ_OBJECT: {
|
case COBJ_OBJECT: {
|
||||||
CObjObject *objTbl = (CObjObject *)obj;
|
CObjObject *objObj = (CObjObject *)obj;
|
||||||
cosmoT_clearTable(state, &objTbl->tbl);
|
cosmoT_clearTable(state, &objObj->tbl);
|
||||||
cosmoM_free(state, CObjObject, objTbl);
|
cosmoM_free(state, CObjObject, objObj);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COBJ_TABLE: {
|
case COBJ_TABLE: {
|
||||||
@@ -237,8 +237,9 @@ CObjError *cosmoO_newError(CState *state, CValue err)
|
|||||||
cerror->parserError = false;
|
cerror->parserError = false;
|
||||||
|
|
||||||
// clone the call frame
|
// clone the call frame
|
||||||
for (int i = 0; i < state->frameCount; i++)
|
for (int i = 0; i < state->frameCount; i++) {
|
||||||
cerror->frames[i] = state->callFrame[i];
|
cerror->frames[i] = state->callFrame[i];
|
||||||
|
}
|
||||||
|
|
||||||
return cerror;
|
return cerror;
|
||||||
}
|
}
|
||||||
@@ -397,7 +398,7 @@ bool cosmoO_isDescendant(CObj *obj, CObjObject *proto)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// returns false if error thrown
|
// returns false if error thrown
|
||||||
bool cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *val, CObj *obj)
|
void cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *val, CObj *obj)
|
||||||
{
|
{
|
||||||
if (!cosmoT_get(state, &proto->tbl, key,
|
if (!cosmoT_get(state, &proto->tbl, key,
|
||||||
val)) { // if the field doesn't exist in the object, check the proto
|
val)) { // if the field doesn't exist in the object, check the proto
|
||||||
@@ -407,18 +408,17 @@ bool cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *v
|
|||||||
cosmoV_pushRef(state, (CObj *)obj); // push object
|
cosmoV_pushRef(state, (CObj *)obj); // push object
|
||||||
cosmoV_call(state, 1, 1); // call the function with the 1 argument
|
cosmoV_call(state, 1, 1); // call the function with the 1 argument
|
||||||
*val = *cosmoV_pop(state); // set value to the return value of __index
|
*val = *cosmoV_pop(state); // set value to the return value of __index
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proto->_obj.proto != NULL &&
|
// maybe the field is defined in the proto?
|
||||||
cosmoO_getRawObject(state, proto->_obj.proto, key, val, obj))
|
if (proto->_obj.proto != NULL) {
|
||||||
return true;
|
cosmoO_getRawObject(state, proto->_obj.proto, key, val, obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
*val = cosmoV_newNil();
|
*val = cosmoV_newNil();
|
||||||
return true; // no protoobject to check against / key not found
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoO_setRawObject(CState *state, CObjObject *proto, CValue key, CValue val, CObj *obj)
|
void cosmoO_setRawObject(CState *state, CObjObject *proto, CValue key, CValue val, CObj *obj)
|
||||||
@@ -519,7 +519,7 @@ bool cosmoO_getIString(CState *state, CObjObject *object, int flag, CValue *val)
|
|||||||
return false; // obj->proto was false, the istring doesn't exist in this object chain
|
return false; // obj->proto was false, the istring doesn't exist in this object chain
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val)
|
void cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val)
|
||||||
{
|
{
|
||||||
if (cosmoO_getIString(state, object, ISTRING_INDEX, val)) {
|
if (cosmoO_getIString(state, object, ISTRING_INDEX, val)) {
|
||||||
cosmoV_pushValue(state, *val); // push function
|
cosmoV_pushValue(state, *val); // push function
|
||||||
@@ -527,15 +527,12 @@ bool cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *v
|
|||||||
cosmoV_pushValue(state, key); // push key
|
cosmoV_pushValue(state, key); // push key
|
||||||
cosmoV_call(state, 2, 1); // call the function with the 2 arguments
|
cosmoV_call(state, 2, 1); // call the function with the 2 arguments
|
||||||
*val = *cosmoV_pop(state); // set value to the return value of __index
|
*val = *cosmoV_pop(state); // set value to the return value of __index
|
||||||
return true;
|
} else { // there's no __index function defined!
|
||||||
} else { // there's no __index function defined!
|
|
||||||
cosmoV_error(state, "Couldn't index object without __index function!");
|
cosmoV_error(state, "Couldn't index object without __index function!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue val)
|
void cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue val)
|
||||||
{
|
{
|
||||||
CValue ret; // return value for cosmoO_getIString
|
CValue ret; // return value for cosmoO_getIString
|
||||||
|
|
||||||
@@ -545,12 +542,9 @@ bool cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue
|
|||||||
cosmoV_pushValue(state, key); // push key & value pair
|
cosmoV_pushValue(state, key); // push key & value pair
|
||||||
cosmoV_pushValue(state, val);
|
cosmoV_pushValue(state, val);
|
||||||
cosmoV_call(state, 3, 0);
|
cosmoV_call(state, 3, 0);
|
||||||
return true;
|
|
||||||
} else { // there's no __newindex function defined
|
} else { // there's no __newindex function defined
|
||||||
cosmoV_error(state, "Couldn't set index on object without __newindex function!");
|
cosmoV_error(state, "Couldn't set index on object without __newindex function!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjString *cosmoO_toString(CState *state, CObj *obj)
|
CObjString *cosmoO_toString(CState *state, CObj *obj)
|
||||||
@@ -721,13 +715,13 @@ void printObject(CObj *o)
|
|||||||
case COBJ_ERROR: {
|
case COBJ_ERROR: {
|
||||||
CObjError *err = (CObjError *)o;
|
CObjError *err = (CObjError *)o;
|
||||||
printf("%p -> ", (void *)o);
|
printf("%p -> ", (void *)o);
|
||||||
printValue(err->err);
|
cosmoV_printValue(err->err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COBJ_METHOD: {
|
case COBJ_METHOD: {
|
||||||
CObjMethod *method = (CObjMethod *)o;
|
CObjMethod *method = (CObjMethod *)o;
|
||||||
printf("%p -> ", (void *)method);
|
printf("%p -> ", (void *)method);
|
||||||
printValue(method->func);
|
cosmoV_printValue(method->func);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COBJ_CLOSURE: {
|
case COBJ_CLOSURE: {
|
||||||
@@ -739,7 +733,7 @@ void printObject(CObj *o)
|
|||||||
case COBJ_UPVALUE: {
|
case COBJ_UPVALUE: {
|
||||||
CObjUpval *upval = (CObjUpval *)o;
|
CObjUpval *upval = (CObjUpval *)o;
|
||||||
printf("%p -> ", (void *)upval->val);
|
printf("%p -> ", (void *)upval->val);
|
||||||
printValue(*upval->val);
|
cosmoV_printValue(*upval->val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
11
src/cobj.h
11
src/cobj.h
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "cosmo.h"
|
#include "cosmo.h"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
typedef enum CObjType
|
typedef enum CObjType
|
||||||
{
|
{
|
||||||
COBJ_STRING,
|
COBJ_STRING,
|
||||||
@@ -32,7 +34,6 @@ typedef int (*CosmoCFunction)(CState *state, int argCount, CValue *args);
|
|||||||
struct CObj
|
struct CObj
|
||||||
{
|
{
|
||||||
struct CObj *next;
|
struct CObj *next;
|
||||||
struct CObj *nextRoot; // for the root linked list
|
|
||||||
struct CObjObject *proto; // protoobject, describes the behavior of the object
|
struct CObjObject *proto; // protoobject, describes the behavior of the object
|
||||||
CObjType type;
|
CObjType type;
|
||||||
bool isMarked; // for the GC
|
bool isMarked; // for the GC
|
||||||
@@ -54,7 +55,7 @@ struct CObjError
|
|||||||
CCallFrame *frames;
|
CCallFrame *frames;
|
||||||
int frameCount;
|
int frameCount;
|
||||||
int line; // reserved for parser errors
|
int line; // reserved for parser errors
|
||||||
bool parserError; // if true, cosmoV_printError will format the error to the lexer
|
bool parserError; // if true, cosmoV_printBacktrace will format the error to the lexer
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CObjObject
|
struct CObjObject
|
||||||
@@ -172,10 +173,10 @@ static inline CObjObject *cosmoO_grabProto(CObj *obj)
|
|||||||
return obj->type == COBJ_OBJECT ? (CObjObject *)obj : obj->proto;
|
return obj->type == COBJ_OBJECT ? (CObjObject *)obj : obj->proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *val, CObj *obj);
|
void cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *val, CObj *obj);
|
||||||
void cosmoO_setRawObject(CState *state, CObjObject *proto, CValue key, CValue val, CObj *obj);
|
void cosmoO_setRawObject(CState *state, CObjObject *proto, CValue key, CValue val, CObj *obj);
|
||||||
bool cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val);
|
void cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val);
|
||||||
bool cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue val);
|
void cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue val);
|
||||||
|
|
||||||
// sets the user-defined pointer, if a user-define integer is already defined it will be over
|
// sets the user-defined pointer, if a user-define integer is already defined it will be over
|
||||||
// written
|
// written
|
||||||
|
47
src/cparse.c
47
src/cparse.c
@@ -102,9 +102,7 @@ static int expressionPrecedence(CParseState *pstate, int needed, Precedence prec
|
|||||||
// returns # of pushed values onto the stack
|
// returns # of pushed values onto the stack
|
||||||
static int expression(CParseState *pstate, int needed, bool forceNeeded);
|
static int expression(CParseState *pstate, int needed, bool forceNeeded);
|
||||||
static void statement(CParseState *pstate);
|
static void statement(CParseState *pstate);
|
||||||
static void declaration(CParseState *pstate);
|
|
||||||
static void parseFunction(CParseState *pstate, FunctionType type);
|
static void parseFunction(CParseState *pstate, FunctionType type);
|
||||||
static void expressionStatement(CParseState *pstate);
|
|
||||||
static ParseRule *getRule(CTokenType type);
|
static ParseRule *getRule(CTokenType type);
|
||||||
static CObjFunction *endCompiler(CParseState *pstate);
|
static CObjFunction *endCompiler(CParseState *pstate);
|
||||||
|
|
||||||
@@ -592,8 +590,6 @@ static void group(CParseState *pstate, bool canAssign, Precedence prec)
|
|||||||
consume(pstate, TOKEN_RIGHT_PAREN, "Expected ')'");
|
consume(pstate, TOKEN_RIGHT_PAREN, "Expected ')'");
|
||||||
}
|
}
|
||||||
|
|
||||||
#define WRITE_GLOBAL_OP(pstate, op, arg)
|
|
||||||
|
|
||||||
static void _etterAB(CParseState *pstate, uint8_t a, int b, bool isGlobal)
|
static void _etterAB(CParseState *pstate, uint8_t a, int b, bool isGlobal)
|
||||||
{
|
{
|
||||||
writeu8(pstate, a);
|
writeu8(pstate, a);
|
||||||
@@ -1101,18 +1097,19 @@ static ParseRule *getRule(CTokenType type)
|
|||||||
// returns true if it got past the first token (aka prefix wasn't null)
|
// returns true if it got past the first token (aka prefix wasn't null)
|
||||||
static bool parsePrecedence(CParseState *pstate, Precedence prec)
|
static bool parsePrecedence(CParseState *pstate, Precedence prec)
|
||||||
{
|
{
|
||||||
|
bool canAssign;
|
||||||
|
ParseFunc prefix, infix;
|
||||||
|
|
||||||
advance(pstate);
|
advance(pstate);
|
||||||
|
if ((prefix = getRule(pstate->previous.type)->prefix) == NULL)
|
||||||
ParseFunc prefix = getRule(pstate->previous.type)->prefix;
|
|
||||||
|
|
||||||
if (prefix == NULL)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool canAssign = prec <= PREC_ASSIGNMENT;
|
canAssign = prec <= PREC_ASSIGNMENT;
|
||||||
prefix(pstate, canAssign, prec);
|
prefix(pstate, canAssign, prec);
|
||||||
|
|
||||||
while (prec <= getRule(pstate->current.type)->level) {
|
while (prec <= getRule(pstate->current.type)->level) {
|
||||||
ParseFunc infix = getRule(pstate->current.type)->infix;
|
if ((infix = getRule(pstate->current.type)->infix) == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
advance(pstate);
|
advance(pstate);
|
||||||
infix(pstate, canAssign, prec);
|
infix(pstate, canAssign, prec);
|
||||||
}
|
}
|
||||||
@@ -1266,7 +1263,7 @@ static void endScope(CParseState *pstate)
|
|||||||
static void block(CParseState *pstate)
|
static void block(CParseState *pstate)
|
||||||
{
|
{
|
||||||
while (!check(pstate, TOKEN_END) && !check(pstate, TOKEN_EOF) && !check(pstate, TOKEN_ERROR)) {
|
while (!check(pstate, TOKEN_END) && !check(pstate, TOKEN_EOF) && !check(pstate, TOKEN_ERROR)) {
|
||||||
declaration(pstate);
|
statement(pstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
consume(pstate, TOKEN_END, "'end' expected to end block.'");
|
consume(pstate, TOKEN_END, "'end' expected to end block.'");
|
||||||
@@ -1323,7 +1320,7 @@ static void ifStatement(CParseState *pstate)
|
|||||||
while (!check(pstate, TOKEN_END) && !check(pstate, TOKEN_ELSE) &&
|
while (!check(pstate, TOKEN_END) && !check(pstate, TOKEN_ELSE) &&
|
||||||
!check(pstate, TOKEN_ELSEIF) && !check(pstate, TOKEN_EOF) &&
|
!check(pstate, TOKEN_ELSEIF) && !check(pstate, TOKEN_EOF) &&
|
||||||
!check(pstate, TOKEN_ERROR)) {
|
!check(pstate, TOKEN_ERROR)) {
|
||||||
declaration(pstate);
|
statement(pstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
endScope(pstate);
|
endScope(pstate);
|
||||||
@@ -1473,10 +1470,10 @@ static void functionDeclaration(CParseState *pstate)
|
|||||||
|
|
||||||
static void returnStatement(CParseState *pstate)
|
static void returnStatement(CParseState *pstate)
|
||||||
{
|
{
|
||||||
if (pstate->compiler->type != FTYPE_FUNCTION && pstate->compiler->type != FTYPE_METHOD) {
|
// if (pstate->compiler->type != FTYPE_FUNCTION && pstate->compiler->type != FTYPE_METHOD) {
|
||||||
error(pstate, "Expected 'return' in function!");
|
// error(pstate, "Expected 'return' in function!");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (blockFollow(pstate->current)) { // does this return have a value
|
if (blockFollow(pstate->current)) { // does this return have a value
|
||||||
writeu8(pstate, OP_NIL);
|
writeu8(pstate, OP_NIL);
|
||||||
@@ -1591,7 +1588,7 @@ static void forLoop(CParseState *pstate)
|
|||||||
|
|
||||||
// parse initializer
|
// parse initializer
|
||||||
if (!match(pstate, TOKEN_EOS)) {
|
if (!match(pstate, TOKEN_EOS)) {
|
||||||
expressionStatement(pstate);
|
statement(pstate);
|
||||||
consume(pstate, TOKEN_EOS, "Expected ';' after initializer");
|
consume(pstate, TOKEN_EOS, "Expected ';' after initializer");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1707,7 +1704,7 @@ static int expression(CParseState *pstate, int needed, bool forceNeeded)
|
|||||||
forceNeeded); // anything above assignments are an expression
|
forceNeeded); // anything above assignments are an expression
|
||||||
}
|
}
|
||||||
|
|
||||||
static void expressionStatement(CParseState *pstate)
|
static void statement(CParseState *pstate)
|
||||||
{
|
{
|
||||||
int savedPushed = pstate->compiler->pushedValues;
|
int savedPushed = pstate->compiler->pushedValues;
|
||||||
|
|
||||||
@@ -1762,16 +1759,6 @@ static void expressionStatement(CParseState *pstate)
|
|||||||
alignStack(pstate, savedPushed);
|
alignStack(pstate, savedPushed);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void statement(CParseState *pstate)
|
|
||||||
{
|
|
||||||
expressionStatement(pstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void declaration(CParseState *pstate)
|
|
||||||
{
|
|
||||||
statement(pstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CObjFunction *endCompiler(CParseState *pstate)
|
static CObjFunction *endCompiler(CParseState *pstate)
|
||||||
{
|
{
|
||||||
popLocals(pstate, pstate->compiler->scopeDepth + 1); // remove the locals from other scopes
|
popLocals(pstate, pstate->compiler->scopeDepth + 1); // remove the locals from other scopes
|
||||||
@@ -1796,7 +1783,7 @@ CObjFunction *cosmoP_compileString(CState *state, const char *source, const char
|
|||||||
advance(&parser);
|
advance(&parser);
|
||||||
|
|
||||||
while (!match(&parser, TOKEN_EOF)) {
|
while (!match(&parser, TOKEN_EOF)) {
|
||||||
declaration(&parser);
|
statement(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
consume(&parser, TOKEN_EOF, "End of file expected!");
|
consume(&parser, TOKEN_EOF, "End of file expected!");
|
||||||
|
67
src/cstate.c
67
src/cstate.c
@@ -12,6 +12,7 @@ CPanic *cosmoV_newPanic(CState *state)
|
|||||||
CPanic *panic = cosmoM_xmalloc(state, sizeof(CPanic));
|
CPanic *panic = cosmoM_xmalloc(state, sizeof(CPanic));
|
||||||
panic->top = state->top;
|
panic->top = state->top;
|
||||||
panic->frameCount = state->frameCount;
|
panic->frameCount = state->frameCount;
|
||||||
|
panic->freezeGC = state->freezeGC;
|
||||||
panic->prev = state->panic;
|
panic->prev = state->panic;
|
||||||
state->panic = panic;
|
state->panic = panic;
|
||||||
|
|
||||||
@@ -41,7 +42,6 @@ CState *cosmoV_newState()
|
|||||||
|
|
||||||
// GC
|
// GC
|
||||||
state->objects = NULL;
|
state->objects = NULL;
|
||||||
state->userRoots = NULL;
|
|
||||||
state->grayStack.count = 0;
|
state->grayStack.count = 0;
|
||||||
state->grayStack.capacity = 2;
|
state->grayStack.capacity = 2;
|
||||||
state->grayStack.array = NULL;
|
state->grayStack.array = NULL;
|
||||||
@@ -54,18 +54,22 @@ CState *cosmoV_newState()
|
|||||||
state->openUpvalues = NULL;
|
state->openUpvalues = NULL;
|
||||||
|
|
||||||
// set default proto objects
|
// set default proto objects
|
||||||
for (int i = 0; i < COBJ_MAX; i++)
|
for (int i = 0; i < COBJ_MAX; i++) {
|
||||||
state->protoObjects[i] = NULL;
|
state->protoObjects[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ISTRING_MAX; i++)
|
for (int i = 0; i < ISTRING_MAX; i++) {
|
||||||
state->iStrings[i] = NULL;
|
state->iStrings[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
cosmoT_initTable(state, &state->strings, 16); // init string table
|
cosmoT_initTable(state, &state->strings, 16); // init string table
|
||||||
|
cosmoT_initTable(state, &state->registry, 16);
|
||||||
|
|
||||||
state->globals = cosmoO_newTable(state); // init global table
|
state->globals = cosmoO_newTable(state); // init global table
|
||||||
|
|
||||||
// setup all strings used by the VM
|
// setup all strings used by the VM
|
||||||
state->iStrings[ISTRING_INIT] = cosmoO_copyString(state, "__init", 6);
|
state->iStrings[ISTRING_INIT] = cosmoO_copyString(state, "__init", 6);
|
||||||
|
state->iStrings[ISTRING_GC] = cosmoO_copyString(state, "__gc", 4);
|
||||||
state->iStrings[ISTRING_TOSTRING] = cosmoO_copyString(state, "__tostring", 10);
|
state->iStrings[ISTRING_TOSTRING] = cosmoO_copyString(state, "__tostring", 10);
|
||||||
state->iStrings[ISTRING_TONUMBER] = cosmoO_copyString(state, "__tonumber", 10);
|
state->iStrings[ISTRING_TONUMBER] = cosmoO_copyString(state, "__tonumber", 10);
|
||||||
state->iStrings[ISTRING_INDEX] = cosmoO_copyString(state, "__index", 7);
|
state->iStrings[ISTRING_INDEX] = cosmoO_copyString(state, "__index", 7);
|
||||||
@@ -85,8 +89,9 @@ CState *cosmoV_newState()
|
|||||||
state->iStrings[ISTRING_RESERVED] = cosmoO_copyString(state, "__reserved", 10);
|
state->iStrings[ISTRING_RESERVED] = cosmoO_copyString(state, "__reserved", 10);
|
||||||
|
|
||||||
// set the IString flags
|
// set the IString flags
|
||||||
for (int i = 0; i < ISTRING_MAX; i++)
|
for (int i = 0; i < ISTRING_MAX; i++) {
|
||||||
state->iStrings[i]->isIString = true;
|
state->iStrings[i]->isIString = true;
|
||||||
|
}
|
||||||
|
|
||||||
state->freezeGC = 0; // unfreeze the state
|
state->freezeGC = 0; // unfreeze the state
|
||||||
return state;
|
return state;
|
||||||
@@ -113,12 +118,15 @@ void cosmoV_freeState(CState *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mark our internal VM strings NULL
|
// mark our internal VM strings NULL
|
||||||
for (int i = 0; i < ISTRING_MAX; i++)
|
for (int i = 0; i < ISTRING_MAX; i++) {
|
||||||
state->iStrings[i] = NULL;
|
state->iStrings[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// free our string table (the string table includes the internal VM strings)
|
// free our string table (the string table includes the internal VM strings)
|
||||||
cosmoT_clearTable(state, &state->strings);
|
cosmoT_clearTable(state, &state->strings);
|
||||||
|
|
||||||
|
cosmoT_clearTable(state, &state->registry);
|
||||||
|
|
||||||
// free our gray stack & finally free the state structure
|
// free our gray stack & finally free the state structure
|
||||||
cosmoM_freeArray(state, CObj *, state->grayStack.array, state->grayStack.capacity);
|
cosmoM_freeArray(state, CObj *, state->grayStack.array, state->grayStack.capacity);
|
||||||
|
|
||||||
@@ -132,7 +140,7 @@ void cosmoV_freeState(CState *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// expects 2*pairs values on the stack, each pair should consist of 1 key and 1 value
|
// expects 2*pairs values on the stack, each pair should consist of 1 key and 1 value
|
||||||
void cosmoV_register(CState *state, int pairs)
|
void cosmoV_addGlobals(CState *state, int pairs)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < pairs; i++) {
|
for (int i = 0; i < pairs; i++) {
|
||||||
StkPtr key = cosmoV_getTop(state, 1);
|
StkPtr key = cosmoV_getTop(state, 1);
|
||||||
@@ -145,12 +153,57 @@ void cosmoV_register(CState *state, int pairs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// expects 2*pairs values on the stack, each pair should consist of 1 key and 1 value
|
||||||
|
void cosmoV_addRegistry(CState *state, int pairs)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < pairs; i++) {
|
||||||
|
StkPtr key = cosmoV_getTop(state, 1);
|
||||||
|
StkPtr val = cosmoV_getTop(state, 0);
|
||||||
|
|
||||||
|
CValue *oldVal = cosmoT_insert(state, &state->registry, *key);
|
||||||
|
*oldVal = *val;
|
||||||
|
|
||||||
|
cosmoV_setTop(state, 2); // pops the 2 values off the stack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// expects 1 key on the stack, pushes result
|
||||||
|
void cosmoV_getRegistry(CState *state)
|
||||||
|
{
|
||||||
|
CValue key = *cosmoV_pop(state);
|
||||||
|
CValue val;
|
||||||
|
|
||||||
|
if (!cosmoT_get(state, &state->registry, key, &val)) {
|
||||||
|
cosmoV_error(state, "failed to grab %s from registry", cosmoV_typeStr(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
cosmoV_pushValue(state, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cosmoV_setProto(CState *state)
|
||||||
|
{
|
||||||
|
StkPtr objVal = cosmoV_getTop(state, 1);
|
||||||
|
StkPtr protoVal = cosmoV_getTop(state, 0);
|
||||||
|
|
||||||
|
if (!IS_REF(*objVal) || !IS_OBJECT(*protoVal)) {
|
||||||
|
cosmoV_error(state, "cannot set %s to proto of type %s", cosmoV_typeStr(*objVal),
|
||||||
|
cosmoV_typeStr(*protoVal));
|
||||||
|
}
|
||||||
|
|
||||||
|
// actually set the protos
|
||||||
|
CObj *obj = cosmoV_readRef(*objVal);
|
||||||
|
CObjObject *proto = cosmoV_readObject(*protoVal);
|
||||||
|
obj->proto = proto;
|
||||||
|
|
||||||
|
cosmoV_setTop(state, 2);
|
||||||
|
}
|
||||||
|
|
||||||
void cosmoV_printStack(CState *state)
|
void cosmoV_printStack(CState *state)
|
||||||
{
|
{
|
||||||
printf("==== [[ stack dump ]] ====\n");
|
printf("==== [[ stack dump ]] ====\n");
|
||||||
for (CValue *top = state->top - 1; top >= state->stack; top--) {
|
for (CValue *top = state->top - 1; top >= state->stack; top--) {
|
||||||
printf("%d: ", (int)(top - state->stack));
|
printf("%d: ", (int)(top - state->stack));
|
||||||
printValue(*top);
|
cosmoV_printValue(*top);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
src/cstate.h
24
src/cstate.h
@@ -18,6 +18,7 @@ struct CCallFrame
|
|||||||
typedef enum IStringEnum
|
typedef enum IStringEnum
|
||||||
{
|
{
|
||||||
ISTRING_INIT, // __init
|
ISTRING_INIT, // __init
|
||||||
|
ISTRING_GC, // __gc
|
||||||
ISTRING_TOSTRING, // __tostring
|
ISTRING_TOSTRING, // __tostring
|
||||||
ISTRING_TONUMBER, // __tonumber
|
ISTRING_TONUMBER, // __tonumber
|
||||||
ISTRING_EQUAL, // __equals
|
ISTRING_EQUAL, // __equals
|
||||||
@@ -46,6 +47,7 @@ typedef struct CPanic
|
|||||||
StkPtr top;
|
StkPtr top;
|
||||||
struct CPanic *prev;
|
struct CPanic *prev;
|
||||||
int frameCount;
|
int frameCount;
|
||||||
|
int freezeGC;
|
||||||
} CPanic;
|
} CPanic;
|
||||||
|
|
||||||
struct CState
|
struct CState
|
||||||
@@ -55,21 +57,20 @@ struct CState
|
|||||||
CObjObject *protoObjects[COBJ_MAX]; // proto object for each COBJ type [NULL = no default proto]
|
CObjObject *protoObjects[COBJ_MAX]; // proto object for each COBJ type [NULL = no default proto]
|
||||||
CObjString *iStrings[ISTRING_MAX]; // strings used internally by the VM, eg. __init, __index
|
CObjString *iStrings[ISTRING_MAX]; // strings used internally by the VM, eg. __init, __index
|
||||||
CTable strings;
|
CTable strings;
|
||||||
|
CTable registry;
|
||||||
ArrayCObj grayStack; // keeps track of which objects *haven't yet* been traversed in our GC, but
|
ArrayCObj grayStack; // keeps track of which objects *haven't yet* been traversed in our GC, but
|
||||||
// *have been* found
|
// *have been* found
|
||||||
|
|
||||||
CObjUpval *openUpvalues; // tracks all of our still open (meaning still on the stack) upvalues
|
CObjUpval *openUpvalues; // tracks all of our still open (meaning still on the stack) upvalues
|
||||||
CObjTable *globals;
|
CObjTable *globals;
|
||||||
CValue *top; // top of the stack
|
CValue *top; // top of the stack
|
||||||
CObj *objects; // tracks all of our allocated objects
|
CObj *objects; // tracks all of our allocated objects
|
||||||
CObj *userRoots; // user definable roots, this holds CObjs that should be considered "roots",
|
|
||||||
// lets the VM know you are holding a reference to a CObj in your code
|
|
||||||
CPanic *panic;
|
CPanic *panic;
|
||||||
|
|
||||||
int freezeGC; // when > 0, GC events will be ignored (for internal use)
|
|
||||||
int frameCount;
|
|
||||||
size_t allocatedBytes;
|
size_t allocatedBytes;
|
||||||
size_t nextGC; // when allocatedBytes reaches this threshhold, trigger a GC event
|
size_t nextGC; // when allocatedBytes reaches this threshhold, trigger a GC event
|
||||||
|
int freezeGC; // when > 0, GC events will be ignored (for internal use)
|
||||||
|
int frameCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
CPanic *cosmoV_newPanic(CState *state);
|
CPanic *cosmoV_newPanic(CState *state);
|
||||||
@@ -79,7 +80,16 @@ COSMO_API CState *cosmoV_newState();
|
|||||||
COSMO_API void cosmoV_freeState(CState *state);
|
COSMO_API void cosmoV_freeState(CState *state);
|
||||||
|
|
||||||
// expects 2*pairs values on the stack, each pair should consist of 1 key and 1 value
|
// expects 2*pairs values on the stack, each pair should consist of 1 key and 1 value
|
||||||
COSMO_API void cosmoV_register(CState *state, int pairs);
|
COSMO_API void cosmoV_addGlobals(CState *state, int pairs);
|
||||||
|
|
||||||
|
// expects 2*pairs values on the stack, each pair should consist of 1 key and 1 value
|
||||||
|
COSMO_API void cosmoV_addRegistry(CState *state, int pairs);
|
||||||
|
|
||||||
|
// expects 1 key on the stack, pushes result
|
||||||
|
COSMO_API void cosmoV_getRegistry(CState *state);
|
||||||
|
|
||||||
|
// expects <object>->proto = <object> (2 total) to be on the stack
|
||||||
|
COSMO_API void cosmoV_setProto(CState *state);
|
||||||
|
|
||||||
COSMO_API void cosmoV_printStack(CState *state);
|
COSMO_API void cosmoV_printStack(CState *state);
|
||||||
|
|
||||||
|
@@ -69,6 +69,8 @@ static uint32_t getObjectHash(CObj *obj)
|
|||||||
switch (obj->type) {
|
switch (obj->type) {
|
||||||
case COBJ_STRING:
|
case COBJ_STRING:
|
||||||
return ((CObjString *)obj)->hash;
|
return ((CObjString *)obj)->hash;
|
||||||
|
case COBJ_CFUNCTION:
|
||||||
|
return (uint32_t)((CObjCFunction *)obj)->cfunc;
|
||||||
default:
|
default:
|
||||||
return (uint32_t)obj; // just "hash" the pointer
|
return (uint32_t)obj; // just "hash" the pointer
|
||||||
}
|
}
|
||||||
@@ -87,8 +89,9 @@ static uint32_t getValueHash(CValue *val)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
memcpy(buf, &num, sizeof(buf));
|
memcpy(buf, &num, sizeof(buf));
|
||||||
for (size_t i = 0; i < sizeof(cosmo_Number) / sizeof(uint32_t); i++)
|
for (size_t i = 0; i < sizeof(cosmo_Number) / sizeof(uint32_t); i++) {
|
||||||
buf[0] += buf[i];
|
buf[0] += buf[i];
|
||||||
|
}
|
||||||
return buf[0];
|
return buf[0];
|
||||||
}
|
}
|
||||||
// TODO: add support for other types
|
// TODO: add support for other types
|
||||||
@@ -285,9 +288,9 @@ void cosmoT_printTable(CTable *tbl, const char *name)
|
|||||||
for (int i = 0; i < cap; i++) {
|
for (int i = 0; i < cap; i++) {
|
||||||
CTableEntry *entry = &tbl->table[i];
|
CTableEntry *entry = &tbl->table[i];
|
||||||
if (!(IS_NIL(entry->key))) {
|
if (!(IS_NIL(entry->key))) {
|
||||||
printValue(entry->key);
|
cosmoV_printValue(entry->key);
|
||||||
printf(" - ");
|
printf(" - ");
|
||||||
printValue(entry->val);
|
cosmoV_printValue(entry->val);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -101,7 +101,7 @@ const char *cosmoV_typeStr(CValue val)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void printValue(CValue val)
|
void cosmoV_printValue(CValue val)
|
||||||
{
|
{
|
||||||
switch (GET_TYPE(val)) {
|
switch (GET_TYPE(val)) {
|
||||||
case COSMO_TNUMBER:
|
case COSMO_TNUMBER:
|
||||||
|
@@ -119,7 +119,7 @@ void initValArray(CState *state, CValueArray *val, size_t startCapacity);
|
|||||||
void cleanValArray(CState *state, CValueArray *array); // cleans array
|
void cleanValArray(CState *state, CValueArray *array); // cleans array
|
||||||
void appendValArray(CState *state, CValueArray *array, CValue val);
|
void appendValArray(CState *state, CValueArray *array, CValue val);
|
||||||
|
|
||||||
void printValue(CValue val);
|
void cosmoV_printValue(CValue val);
|
||||||
COSMO_API bool cosmoV_equal(CState *state, CValue valA, CValue valB);
|
COSMO_API bool cosmoV_equal(CState *state, CValue valA, CValue valB);
|
||||||
COSMO_API CObjString *cosmoV_toString(CState *state, CValue val);
|
COSMO_API CObjString *cosmoV_toString(CState *state, CValue val);
|
||||||
COSMO_API cosmo_Number cosmoV_toNumber(CState *state, CValue val);
|
COSMO_API cosmo_Number cosmoV_toNumber(CState *state, CValue val);
|
||||||
|
170
src/cvm.c
170
src/cvm.c
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#define cosmoV_protect(panic) setjmp(panic->jmp) == 0
|
#define cosmoV_protect(panic) setjmp(panic->jmp) == 0
|
||||||
|
|
||||||
COSMO_API void cosmoV_pushFString(CState *state, const char *format, ...)
|
void cosmoV_pushFString(CState *state, const char *format, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
@@ -21,19 +21,20 @@ COSMO_API void cosmoV_pushFString(CState *state, const char *format, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inserts val at state->top - indx - 1, moving everything else up
|
// inserts val at state->top - indx - 1, moving everything else up
|
||||||
COSMO_API void cosmo_insert(CState *state, int indx, CValue val)
|
void cosmoV_insert(CState *state, int indx, CValue val)
|
||||||
{
|
{
|
||||||
StkPtr tmp = cosmoV_getTop(state, indx);
|
StkPtr tmp = cosmoV_getTop(state, indx);
|
||||||
|
|
||||||
// moves everything up
|
// moves everything up
|
||||||
for (StkPtr i = state->top; i > tmp; i--)
|
for (StkPtr i = state->top; i > tmp; i--) {
|
||||||
*i = *(i - 1);
|
*i = *(i - 1);
|
||||||
|
}
|
||||||
|
|
||||||
*tmp = val;
|
*tmp = val;
|
||||||
state->top++;
|
state->top++;
|
||||||
}
|
}
|
||||||
|
|
||||||
COSMO_API bool cosmoV_undump(CState *state, cosmo_Reader reader, const void *ud)
|
bool cosmoV_undump(CState *state, cosmo_Reader reader, const void *ud)
|
||||||
{
|
{
|
||||||
CObjFunction *func;
|
CObjFunction *func;
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ COSMO_API bool cosmoV_undump(CState *state, cosmo_Reader reader, const void *ud)
|
|||||||
|
|
||||||
// returns false if failed, error will be on the top of the stack. true if successful, closure will
|
// returns false if failed, error will be on the top of the stack. true if successful, closure will
|
||||||
// be on the top of the stack
|
// be on the top of the stack
|
||||||
COSMO_API bool cosmoV_compileString(CState *state, const char *src, const char *name)
|
bool cosmoV_compileString(CState *state, const char *src, const char *name)
|
||||||
{
|
{
|
||||||
CObjFunction *func;
|
CObjFunction *func;
|
||||||
CPanic *panic = cosmoV_newPanic(state);
|
CPanic *panic = cosmoV_newPanic(state);
|
||||||
@@ -77,7 +78,7 @@ COSMO_API bool cosmoV_compileString(CState *state, const char *src, const char *
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
COSMO_API void cosmoV_printError(CState *state, CObjError *err)
|
void cosmoV_printBacktrace(CState *state, CObjError *err)
|
||||||
{
|
{
|
||||||
// print stack trace
|
// print stack trace
|
||||||
for (int i = 0; i < err->frameCount; i++) {
|
for (int i = 0; i < err->frameCount; i++) {
|
||||||
@@ -122,12 +123,13 @@ void cosmoV_throw(CState *state)
|
|||||||
if (state->panic) {
|
if (state->panic) {
|
||||||
state->top = state->panic->top;
|
state->top = state->panic->top;
|
||||||
state->frameCount = state->panic->frameCount;
|
state->frameCount = state->panic->frameCount;
|
||||||
|
state->freezeGC = state->panic->freezeGC;
|
||||||
cosmoV_pushValue(state, val);
|
cosmoV_pushValue(state, val);
|
||||||
longjmp(state->panic->jmp, 1);
|
longjmp(state->panic->jmp, 1);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_pushValue(state, val);
|
cosmoV_pushValue(state, val);
|
||||||
fprintf(stderr, "Unhandled panic! ");
|
fprintf(stderr, "Unhandled panic! ");
|
||||||
cosmoV_printError(state, error);
|
cosmoV_printBacktrace(state, error);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,8 +269,9 @@ static void callCFunction(CState *state, CosmoCFunction cfunc, int args, int nre
|
|||||||
state->top += nres; // and make sure to move state->top to match
|
state->top += nres; // and make sure to move state->top to match
|
||||||
|
|
||||||
// now, if the caller function expected more return values, push nils onto the stack
|
// now, if the caller function expected more return values, push nils onto the stack
|
||||||
for (int i = nres; i < nresults; i++)
|
for (int i = nres; i < nresults; i++) {
|
||||||
cosmoV_pushValue(state, cosmoV_newNil());
|
cosmoV_pushValue(state, cosmoV_newNil());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -326,8 +329,9 @@ static void rawCall(CState *state, CObjClosure *closure, int args, int nresults,
|
|||||||
state->top += nres; // and make sure to move state->top to match
|
state->top += nres; // and make sure to move state->top to match
|
||||||
|
|
||||||
// now, if the caller function expected more return values, push nils onto the stack
|
// now, if the caller function expected more return values, push nils onto the stack
|
||||||
for (int i = nres; i < nresults; i++)
|
for (int i = nres; i < nresults; i++) {
|
||||||
cosmoV_pushValue(state, cosmoV_newNil());
|
cosmoV_pushValue(state, cosmoV_newNil());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true if successful, false if error
|
// returns true if successful, false if error
|
||||||
@@ -336,7 +340,7 @@ void callCValue(CState *state, CValue func, int args, int nresults, int offset)
|
|||||||
#ifdef VM_DEBUG
|
#ifdef VM_DEBUG
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printIndent(state->frameCount - 1);
|
printIndent(state->frameCount - 1);
|
||||||
printValue(func);
|
cosmoV_printValue(func);
|
||||||
printf("(%d args)\n", args);
|
printf("(%d args)\n", args);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -376,9 +380,9 @@ void callCValue(CState *state, CValue func, int args, int nresults, int offset)
|
|||||||
if (nresults > 0) {
|
if (nresults > 0) {
|
||||||
cosmoV_pushRef(state, (CObj *)newObj);
|
cosmoV_pushRef(state, (CObj *)newObj);
|
||||||
|
|
||||||
// push the nils to fill up the expected return values
|
// push the nils to fill up the expected return values.
|
||||||
for (int i = 0; i < nresults - 1;
|
// -1 since the we already pushed the important value
|
||||||
i++) { // -1 since the we already pushed the important value
|
for (int i = 0; i < nresults - 1; i++) {
|
||||||
cosmoV_pushValue(state, cosmoV_newNil());
|
cosmoV_pushValue(state, cosmoV_newNil());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -414,8 +418,9 @@ bool cosmoV_pcall(CState *state, int args, int nresults)
|
|||||||
|
|
||||||
if (nresults > 0) {
|
if (nresults > 0) {
|
||||||
// push other expected results onto the stack
|
// push other expected results onto the stack
|
||||||
for (int i = 0; i < nresults - 1; i++)
|
for (int i = 0; i < nresults - 1; i++) {
|
||||||
cosmoV_pushValue(state, cosmoV_newNil());
|
cosmoV_pushValue(state, cosmoV_newNil());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_freePanic(state);
|
cosmoV_freePanic(state);
|
||||||
@@ -438,7 +443,7 @@ static inline bool isFalsey(StkPtr val)
|
|||||||
return IS_NIL(*val) || (IS_BOOLEAN(*val) && !cosmoV_readBoolean(*val));
|
return IS_NIL(*val) || (IS_BOOLEAN(*val) && !cosmoV_readBoolean(*val));
|
||||||
}
|
}
|
||||||
|
|
||||||
COSMO_API CObjObject *cosmoV_makeObject(CState *state, int pairs)
|
CObjObject *cosmoV_makeObject(CState *state, int pairs)
|
||||||
{
|
{
|
||||||
StkPtr key, val;
|
StkPtr key, val;
|
||||||
CObjObject *newObj = cosmoO_newObject(state);
|
CObjObject *newObj = cosmoO_newObject(state);
|
||||||
@@ -459,7 +464,7 @@ COSMO_API CObjObject *cosmoV_makeObject(CState *state, int pairs)
|
|||||||
return newObj;
|
return newObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
COSMO_API bool cosmoV_registerProtoObject(CState *state, CObjType objType, CObjObject *obj)
|
bool cosmoV_registerProtoObject(CState *state, CObjType objType, CObjObject *obj)
|
||||||
{
|
{
|
||||||
bool replaced = state->protoObjects[objType] != NULL;
|
bool replaced = state->protoObjects[objType] != NULL;
|
||||||
state->protoObjects[objType] = obj;
|
state->protoObjects[objType] = obj;
|
||||||
@@ -468,7 +473,7 @@ COSMO_API bool cosmoV_registerProtoObject(CState *state, CObjType objType, CObjO
|
|||||||
CObj *curr = state->objects;
|
CObj *curr = state->objects;
|
||||||
while (curr != NULL) {
|
while (curr != NULL) {
|
||||||
// update the proto
|
// update the proto
|
||||||
if (curr->type == objType && curr->proto != NULL) {
|
if (curr != (CObj *)obj && curr->type == objType && curr->proto != NULL) {
|
||||||
curr->proto = obj;
|
curr->proto = obj;
|
||||||
}
|
}
|
||||||
curr = curr->next;
|
curr = curr->next;
|
||||||
@@ -477,7 +482,7 @@ COSMO_API bool cosmoV_registerProtoObject(CState *state, CObjType objType, CObjO
|
|||||||
return replaced;
|
return replaced;
|
||||||
}
|
}
|
||||||
|
|
||||||
COSMO_API void cosmoV_makeTable(CState *state, int pairs)
|
void cosmoV_makeTable(CState *state, int pairs)
|
||||||
{
|
{
|
||||||
StkPtr key, val;
|
StkPtr key, val;
|
||||||
CObjTable *newObj = cosmoO_newTable(state);
|
CObjTable *newObj = cosmoO_newTable(state);
|
||||||
@@ -497,7 +502,7 @@ COSMO_API void cosmoV_makeTable(CState *state, int pairs)
|
|||||||
cosmoV_pushRef(state, (CObj *)newObj);
|
cosmoV_pushRef(state, (CObj *)newObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cosmoV_rawget(CState *state, CObj *_obj, CValue key, CValue *val)
|
void cosmoV_rawget(CState *state, CObj *_obj, CValue key, CValue *val)
|
||||||
{
|
{
|
||||||
CObjObject *object = cosmoO_grabProto(_obj);
|
CObjObject *object = cosmoO_grabProto(_obj);
|
||||||
|
|
||||||
@@ -506,23 +511,16 @@ bool cosmoV_rawget(CState *state, CObj *_obj, CValue key, CValue *val)
|
|||||||
CObjString *field = cosmoV_toString(state, key);
|
CObjString *field = cosmoV_toString(state, key);
|
||||||
cosmoV_error(state, "No proto defined! Couldn't get field '%s' from type %s", field->str,
|
cosmoV_error(state, "No proto defined! Couldn't get field '%s' from type %s", field->str,
|
||||||
cosmoO_typeStr(_obj));
|
cosmoO_typeStr(_obj));
|
||||||
*val = cosmoV_newNil();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// push the object onto the stack so the GC can find it
|
// push the object onto the stack so the GC can find it
|
||||||
cosmoV_pushRef(state, (CObj *)object);
|
cosmoV_pushRef(state, (CObj *)object);
|
||||||
if (cosmoO_getRawObject(state, object, key, val, _obj)) {
|
cosmoO_getRawObject(state, object, key, val, _obj);
|
||||||
// *val now equals the response, pop the object
|
|
||||||
cosmoV_pop(state);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cosmoV_pop(state);
|
cosmoV_pop(state);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cosmoV_rawset(CState *state, CObj *_obj, CValue key, CValue val)
|
void cosmoV_rawset(CState *state, CObj *_obj, CValue key, CValue val)
|
||||||
{
|
{
|
||||||
CObjObject *object = cosmoO_grabProto(_obj);
|
CObjObject *object = cosmoO_grabProto(_obj);
|
||||||
|
|
||||||
@@ -531,14 +529,12 @@ bool cosmoV_rawset(CState *state, CObj *_obj, CValue key, CValue val)
|
|||||||
CObjString *field = cosmoV_toString(state, key);
|
CObjString *field = cosmoV_toString(state, key);
|
||||||
cosmoV_error(state, "No proto defined! Couldn't set field '%s' to type %s", field->str,
|
cosmoV_error(state, "No proto defined! Couldn't set field '%s' to type %s", field->str,
|
||||||
cosmoO_typeStr(_obj));
|
cosmoO_typeStr(_obj));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoO_setRawObject(state, object, key, val, _obj);
|
cosmoO_setRawObject(state, object, key, val, _obj);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
COSMO_API bool cosmoV_get(CState *state)
|
void cosmoV_get(CState *state)
|
||||||
{
|
{
|
||||||
CValue val;
|
CValue val;
|
||||||
StkPtr obj = cosmoV_getTop(state, 1); // object was pushed first
|
StkPtr obj = cosmoV_getTop(state, 1); // object was pushed first
|
||||||
@@ -546,20 +542,17 @@ COSMO_API bool cosmoV_get(CState *state)
|
|||||||
|
|
||||||
if (!IS_REF(*obj)) {
|
if (!IS_REF(*obj)) {
|
||||||
cosmoV_error(state, "Couldn't get field from type %s!", cosmoV_typeStr(*obj));
|
cosmoV_error(state, "Couldn't get field from type %s!", cosmoV_typeStr(*obj));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cosmoV_rawget(state, cosmoV_readRef(*obj), *key, &val))
|
cosmoV_rawget(state, cosmoV_readRef(*obj), *key, &val);
|
||||||
return false;
|
|
||||||
|
|
||||||
// pop the obj & key, push the value
|
// pop the obj & key, push the value
|
||||||
cosmoV_setTop(state, 2);
|
cosmoV_setTop(state, 2);
|
||||||
cosmoV_pushValue(state, val);
|
cosmoV_pushValue(state, val);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// yes, this would technically make it possible to set fields of types other than <string>. go crazy
|
// yes, this would technically make it possible to set fields of types other than <string>. go crazy
|
||||||
COSMO_API bool cosmoV_set(CState *state)
|
void cosmoV_set(CState *state)
|
||||||
{
|
{
|
||||||
StkPtr obj = cosmoV_getTop(state, 2); // object was pushed first
|
StkPtr obj = cosmoV_getTop(state, 2); // object was pushed first
|
||||||
StkPtr key = cosmoV_getTop(state, 1); // then the key
|
StkPtr key = cosmoV_getTop(state, 1); // then the key
|
||||||
@@ -567,21 +560,17 @@ COSMO_API bool cosmoV_set(CState *state)
|
|||||||
|
|
||||||
if (!IS_REF(*obj)) {
|
if (!IS_REF(*obj)) {
|
||||||
cosmoV_error(state, "Couldn't set field on type %s!", cosmoV_typeStr(*obj));
|
cosmoV_error(state, "Couldn't set field on type %s!", cosmoV_typeStr(*obj));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cosmoV_rawset(state, cosmoV_readRef(*obj), *key, *val))
|
cosmoV_rawset(state, cosmoV_readRef(*obj), *key, *val);
|
||||||
return false;
|
|
||||||
|
|
||||||
// pop the obj, key & value
|
// pop the obj, key & value
|
||||||
cosmoV_setTop(state, 3);
|
cosmoV_setTop(state, 3);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
COSMO_API bool cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val)
|
void cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val)
|
||||||
{
|
{
|
||||||
if (!cosmoV_rawget(state, obj, key, val))
|
cosmoV_rawget(state, obj, key, val);
|
||||||
return false;
|
|
||||||
|
|
||||||
// if the result is callable, wrap it in an method
|
// if the result is callable, wrap it in an method
|
||||||
if (IS_CALLABLE(*val)) {
|
if (IS_CALLABLE(*val)) {
|
||||||
@@ -591,6 +580,18 @@ COSMO_API bool cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *va
|
|||||||
cosmoV_pop(state); // pop the object
|
cosmoV_pop(state); // pop the object
|
||||||
*val = cosmoV_newRef(method);
|
*val = cosmoV_newRef(method);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cosmoV_isValueUserType(CState *state, CValue val, int userType)
|
||||||
|
{
|
||||||
|
if (!IS_OBJECT(val)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CObjObject *obj = cosmoV_readObject(val);
|
||||||
|
if (obj->userT != userType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -696,7 +697,7 @@ static inline uint16_t READUINT(CCallFrame *frame)
|
|||||||
# define SWITCH switch (READBYTE(frame))
|
# define SWITCH switch (READBYTE(frame))
|
||||||
# define DEFAULT \
|
# define DEFAULT \
|
||||||
default: \
|
default: \
|
||||||
printf("[ERROR] unknown opcode!"); \
|
printf("[ERROR] unknown opcode!"); \
|
||||||
exit(0)
|
exit(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -849,18 +850,15 @@ int cosmoV_execute(CState *state)
|
|||||||
// sanity check
|
// sanity check
|
||||||
if (!IS_REF(*temp)) {
|
if (!IS_REF(*temp)) {
|
||||||
cosmoV_error(state, "Couldn't index type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't index type %s!", cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObj *obj = cosmoV_readRef(*temp);
|
CObj *obj = cosmoV_readRef(*temp);
|
||||||
CObjObject *proto = cosmoO_grabProto(obj);
|
CObjObject *proto = cosmoO_grabProto(obj);
|
||||||
CValue val; // to hold our value
|
CValue val = cosmoV_newNil(); // to hold our value
|
||||||
|
|
||||||
if (proto != NULL) {
|
if (proto != NULL) {
|
||||||
// check for __index metamethod
|
// check for __index metamethod
|
||||||
if (!cosmoO_indexObject(state, proto, *key,
|
cosmoO_indexObject(state, proto, *key, &val);
|
||||||
&val)) // if returns false, cosmoV_error was called
|
|
||||||
return -1;
|
|
||||||
} else if (obj->type == COBJ_TABLE) {
|
} else if (obj->type == COBJ_TABLE) {
|
||||||
CObjTable *tbl = (CObjTable *)obj;
|
CObjTable *tbl = (CObjTable *)obj;
|
||||||
|
|
||||||
@@ -868,7 +866,6 @@ int cosmoV_execute(CState *state)
|
|||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "No proto defined! Couldn't __index from type %s",
|
cosmoV_error(state, "No proto defined! Couldn't __index from type %s",
|
||||||
cosmoV_typeStr(*temp));
|
cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_setTop(state, 2); // pops the table & the key
|
cosmoV_setTop(state, 2); // pops the table & the key
|
||||||
@@ -883,17 +880,13 @@ int cosmoV_execute(CState *state)
|
|||||||
// sanity check
|
// sanity check
|
||||||
if (!IS_REF(*temp)) {
|
if (!IS_REF(*temp)) {
|
||||||
cosmoV_error(state, "Couldn't set index with type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't set index with type %s!", cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObj *obj = cosmoV_readRef(*temp);
|
CObj *obj = cosmoV_readRef(*temp);
|
||||||
CObjObject *proto = cosmoO_grabProto(obj);
|
CObjObject *proto = cosmoO_grabProto(obj);
|
||||||
|
|
||||||
if (proto != NULL) {
|
if (proto != NULL) {
|
||||||
if (!cosmoO_newIndexObject(
|
cosmoO_newIndexObject(state, proto, *key, *value);
|
||||||
state, proto, *key,
|
|
||||||
*value)) // if it returns false, cosmoV_error was called
|
|
||||||
return -1;
|
|
||||||
} else if (obj->type == COBJ_TABLE) {
|
} else if (obj->type == COBJ_TABLE) {
|
||||||
CObjTable *tbl = (CObjTable *)obj;
|
CObjTable *tbl = (CObjTable *)obj;
|
||||||
CValue *newVal = cosmoT_insert(state, &tbl->tbl, *key);
|
CValue *newVal = cosmoT_insert(state, &tbl->tbl, *key);
|
||||||
@@ -902,7 +895,6 @@ int cosmoV_execute(CState *state)
|
|||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "No proto defined! Couldn't __newindex from type %s",
|
cosmoV_error(state, "No proto defined! Couldn't __newindex from type %s",
|
||||||
cosmoV_typeStr(*temp));
|
cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pop everything off the stack
|
// pop everything off the stack
|
||||||
@@ -921,13 +913,11 @@ int cosmoV_execute(CState *state)
|
|||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (IS_REF(*temp)) {
|
if (IS_REF(*temp)) {
|
||||||
if (!cosmoV_rawset(state, cosmoV_readRef(*temp), constants[ident], *value))
|
cosmoV_rawset(state, cosmoV_readRef(*temp), constants[ident], *value);
|
||||||
return -1;
|
|
||||||
} else {
|
} else {
|
||||||
CObjString *field = cosmoV_toString(state, constants[ident]);
|
CObjString *field = cosmoV_toString(state, constants[ident]);
|
||||||
cosmoV_error(state, "Couldn't set field '%s' on type %s!", field->str,
|
cosmoV_error(state, "Couldn't set field '%s' on type %s!", field->str,
|
||||||
cosmoV_typeStr(*temp));
|
cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pop everything off the stack
|
// pop everything off the stack
|
||||||
@@ -935,19 +925,17 @@ int cosmoV_execute(CState *state)
|
|||||||
}
|
}
|
||||||
CASE(OP_GETOBJECT) :
|
CASE(OP_GETOBJECT) :
|
||||||
{
|
{
|
||||||
CValue val; // to hold our value
|
CValue val = cosmoV_newNil(); // to hold our value
|
||||||
StkPtr temp = cosmoV_getTop(state, 0); // that should be the object
|
StkPtr temp = cosmoV_getTop(state, 0); // that should be the object
|
||||||
uint16_t ident = READUINT(frame); // use for the key
|
uint16_t ident = READUINT(frame); // use for the key
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (IS_REF(*temp)) {
|
if (IS_REF(*temp)) {
|
||||||
if (!cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val))
|
cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val);
|
||||||
return -1;
|
|
||||||
} else {
|
} else {
|
||||||
CObjString *field = cosmoV_toString(state, constants[ident]);
|
CObjString *field = cosmoV_toString(state, constants[ident]);
|
||||||
cosmoV_error(state, "Couldn't get field '%s' from type %s!", field->str,
|
cosmoV_error(state, "Couldn't get field '%s' from type %s!", field->str,
|
||||||
cosmoV_typeStr(*temp));
|
cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_setTop(state, 1); // pops the object
|
cosmoV_setTop(state, 1); // pops the object
|
||||||
@@ -955,20 +943,18 @@ int cosmoV_execute(CState *state)
|
|||||||
}
|
}
|
||||||
CASE(OP_GETMETHOD) :
|
CASE(OP_GETMETHOD) :
|
||||||
{
|
{
|
||||||
CValue val; // to hold our value
|
CValue val = cosmoV_newNil(); // to hold our value
|
||||||
StkPtr temp = cosmoV_getTop(state, 0); // that should be the object
|
StkPtr temp = cosmoV_getTop(state, 0); // that should be the object
|
||||||
uint16_t ident = READUINT(frame); // use for the key
|
uint16_t ident = READUINT(frame); // use for the key
|
||||||
|
|
||||||
// this is almost identical to GETOBJECT, however cosmoV_getMethod is used instead
|
// this is almost identical to GETOBJECT, however cosmoV_getMethod is used instead
|
||||||
// of just cosmoV_get
|
// of just cosmoV_get
|
||||||
if (IS_REF(*temp)) {
|
if (IS_REF(*temp)) {
|
||||||
if (!cosmoV_getMethod(state, cosmoV_readRef(*temp), constants[ident], &val))
|
cosmoV_getMethod(state, cosmoV_readRef(*temp), constants[ident], &val);
|
||||||
return -1;
|
|
||||||
} else {
|
} else {
|
||||||
CObjString *field = cosmoV_toString(state, constants[ident]);
|
CObjString *field = cosmoV_toString(state, constants[ident]);
|
||||||
cosmoV_error(state, "Couldn't get field '%s' from type %s!", field->str,
|
cosmoV_error(state, "Couldn't get field '%s' from type %s!", field->str,
|
||||||
cosmoV_typeStr(*temp));
|
cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_setTop(state, 1); // pops the object
|
cosmoV_setTop(state, 1); // pops the object
|
||||||
@@ -985,14 +971,12 @@ int cosmoV_execute(CState *state)
|
|||||||
// sanity check
|
// sanity check
|
||||||
if (IS_REF(*temp)) {
|
if (IS_REF(*temp)) {
|
||||||
// get the field from the object
|
// get the field from the object
|
||||||
if (!cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val))
|
cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val);
|
||||||
return -1;
|
|
||||||
|
|
||||||
// now invoke the method!
|
// now invoke the method!
|
||||||
invokeMethod(state, cosmoV_readRef(*temp), val, args, nres, 1);
|
invokeMethod(state, cosmoV_readRef(*temp), val, args, nres, 1);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE(OP_ITER) :
|
CASE(OP_ITER) :
|
||||||
@@ -1002,7 +986,6 @@ int cosmoV_execute(CState *state)
|
|||||||
if (!IS_REF(*temp)) {
|
if (!IS_REF(*temp)) {
|
||||||
cosmoV_error(state, "Couldn't iterate over non-iterator type %s!",
|
cosmoV_error(state, "Couldn't iterate over non-iterator type %s!",
|
||||||
cosmoV_typeStr(*temp));
|
cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObj *obj = cosmoV_readRef(*temp);
|
CObj *obj = cosmoV_readRef(*temp);
|
||||||
@@ -1026,7 +1009,6 @@ int cosmoV_execute(CState *state)
|
|||||||
"Expected iterable object! '__iter' returned %s, expected "
|
"Expected iterable object! '__iter' returned %s, expected "
|
||||||
"<object>!",
|
"<object>!",
|
||||||
cosmoV_typeStr(*iObj));
|
cosmoV_typeStr(*iObj));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get __next method and place it at the top of the stack
|
// get __next method and place it at the top of the stack
|
||||||
@@ -1034,7 +1016,6 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_newRef(state->iStrings[ISTRING_NEXT]), iObj);
|
cosmoV_newRef(state->iStrings[ISTRING_NEXT]), iObj);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Expected iterable object! '__iter' not defined!");
|
cosmoV_error(state, "Expected iterable object! '__iter' not defined!");
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
} else if (obj->type == COBJ_TABLE) {
|
} else if (obj->type == COBJ_TABLE) {
|
||||||
CObjTable *tbl = (CObjTable *)obj;
|
CObjTable *tbl = (CObjTable *)obj;
|
||||||
@@ -1059,7 +1040,6 @@ int cosmoV_execute(CState *state)
|
|||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "No proto defined! Couldn't get from type %s",
|
cosmoV_error(state, "No proto defined! Couldn't get from type %s",
|
||||||
cosmoO_typeStr(obj));
|
cosmoO_typeStr(obj));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE(OP_NEXT) :
|
CASE(OP_NEXT) :
|
||||||
@@ -1071,7 +1051,6 @@ int cosmoV_execute(CState *state)
|
|||||||
if (!IS_METHOD(*temp)) {
|
if (!IS_METHOD(*temp)) {
|
||||||
cosmoV_error(state, "Expected '__next' to be a method, got type %s!",
|
cosmoV_error(state, "Expected '__next' to be a method, got type %s!",
|
||||||
cosmoV_typeStr(*temp));
|
cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushValue(state, *temp);
|
cosmoV_pushValue(state, *temp);
|
||||||
@@ -1114,7 +1093,6 @@ int cosmoV_execute(CState *state)
|
|||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Expected numbers, got %s and %s!", cosmoV_typeStr(*valA),
|
cosmoV_error(state, "Expected numbers, got %s and %s!", cosmoV_typeStr(*valA),
|
||||||
cosmoV_typeStr(*valB));
|
cosmoV_typeStr(*valB));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE(OP_POW) :
|
CASE(OP_POW) :
|
||||||
@@ -1128,7 +1106,6 @@ int cosmoV_execute(CState *state)
|
|||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Expected numbers, got %s and %s!", cosmoV_typeStr(*valA),
|
cosmoV_error(state, "Expected numbers, got %s and %s!", cosmoV_typeStr(*valA),
|
||||||
cosmoV_typeStr(*valB));
|
cosmoV_typeStr(*valB));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE(OP_NOT) :
|
CASE(OP_NOT) :
|
||||||
@@ -1144,7 +1121,6 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_pushNumber(state, -(cosmoV_readNumber(*val)));
|
cosmoV_pushNumber(state, -(cosmoV_readNumber(*val)));
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE(OP_COUNT) :
|
CASE(OP_COUNT) :
|
||||||
@@ -1153,7 +1129,6 @@ int cosmoV_execute(CState *state)
|
|||||||
|
|
||||||
if (!IS_REF(*temp)) {
|
if (!IS_REF(*temp)) {
|
||||||
cosmoV_error(state, "Expected non-primitive, got %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Expected non-primitive, got %s!", cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = cosmoO_count(state, cosmoV_readRef(*temp));
|
int count = cosmoO_count(state, cosmoV_readRef(*temp));
|
||||||
@@ -1178,7 +1153,6 @@ int cosmoV_execute(CState *state)
|
|||||||
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
|
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE(OP_INCGLOBAL) :
|
CASE(OP_INCGLOBAL) :
|
||||||
@@ -1194,7 +1168,6 @@ int cosmoV_execute(CState *state)
|
|||||||
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
|
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE(OP_INCUPVAL) :
|
CASE(OP_INCUPVAL) :
|
||||||
@@ -1209,7 +1182,6 @@ int cosmoV_execute(CState *state)
|
|||||||
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
|
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE(OP_INCINDEX) :
|
CASE(OP_INCINDEX) :
|
||||||
@@ -1221,7 +1193,6 @@ int cosmoV_execute(CState *state)
|
|||||||
if (!IS_REF(*temp)) {
|
if (!IS_REF(*temp)) {
|
||||||
cosmoV_error(state, "Couldn't index non-indexable type %s!",
|
cosmoV_error(state, "Couldn't index non-indexable type %s!",
|
||||||
cosmoV_typeStr(*temp));
|
cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObj *obj = cosmoV_readRef(*temp);
|
CObj *obj = cosmoV_readRef(*temp);
|
||||||
@@ -1230,27 +1201,23 @@ int cosmoV_execute(CState *state)
|
|||||||
|
|
||||||
// call __index if the proto was found
|
// call __index if the proto was found
|
||||||
if (proto != NULL) {
|
if (proto != NULL) {
|
||||||
if (cosmoO_indexObject(state, proto, *key, &val)) {
|
cosmoO_indexObject(state, proto, *key, &val);
|
||||||
if (!IS_NUMBER(val)) {
|
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cosmoV_pushValue(state, val); // pushes old value onto the stack :)
|
if (!IS_NUMBER(val)) {
|
||||||
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val));
|
||||||
|
}
|
||||||
|
|
||||||
// call __newindex
|
cosmoV_pushValue(state, val); // pushes old value onto the stack :)
|
||||||
if (!cosmoO_newIndexObject(state, proto, *key,
|
|
||||||
cosmoV_newNumber(cosmoV_readNumber(val) + inc)))
|
// call __newindex
|
||||||
return -1;
|
cosmoO_newIndexObject(state, proto, *key,
|
||||||
} else
|
cosmoV_newNumber(cosmoV_readNumber(val) + inc));
|
||||||
return -1; // cosmoO_indexObject failed and threw an error
|
|
||||||
} else if (obj->type == COBJ_TABLE) {
|
} else if (obj->type == COBJ_TABLE) {
|
||||||
CObjTable *tbl = (CObjTable *)obj;
|
CObjTable *tbl = (CObjTable *)obj;
|
||||||
CValue *val = cosmoT_insert(state, &tbl->tbl, *key);
|
CValue *val = cosmoT_insert(state, &tbl->tbl, *key);
|
||||||
|
|
||||||
if (!IS_NUMBER(*val)) {
|
if (!IS_NUMBER(*val)) {
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pops tbl & key from stack
|
// pops tbl & key from stack
|
||||||
@@ -1260,7 +1227,6 @@ int cosmoV_execute(CState *state)
|
|||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "No proto defined! Couldn't __index from type %s",
|
cosmoV_error(state, "No proto defined! Couldn't __index from type %s",
|
||||||
cosmoV_typeStr(*temp));
|
cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE(OP_INCOBJECT) :
|
CASE(OP_INCOBJECT) :
|
||||||
@@ -1275,8 +1241,7 @@ int cosmoV_execute(CState *state)
|
|||||||
CObj *obj = cosmoV_readRef(*temp);
|
CObj *obj = cosmoV_readRef(*temp);
|
||||||
CValue val;
|
CValue val;
|
||||||
|
|
||||||
if (!cosmoV_rawget(state, obj, ident, &val))
|
cosmoV_rawget(state, obj, ident, &val);
|
||||||
return -1;
|
|
||||||
|
|
||||||
// pop the object off the stack
|
// pop the object off the stack
|
||||||
cosmoV_pop(state);
|
cosmoV_pop(state);
|
||||||
@@ -1284,16 +1249,13 @@ int cosmoV_execute(CState *state)
|
|||||||
// check that it's a number value
|
// check that it's a number value
|
||||||
if (IS_NUMBER(val)) {
|
if (IS_NUMBER(val)) {
|
||||||
cosmoV_pushValue(state, val); // pushes old value onto the stack :)
|
cosmoV_pushValue(state, val); // pushes old value onto the stack :)
|
||||||
if (!cosmoV_rawset(state, obj, ident,
|
cosmoV_rawset(state, obj, ident,
|
||||||
cosmoV_newNumber(cosmoV_readNumber(val) + inc)))
|
cosmoV_newNumber(cosmoV_readNumber(val) + inc));
|
||||||
return -1;
|
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp));
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CASE(OP_EQUAL) :
|
CASE(OP_EQUAL) :
|
||||||
|
28
src/cvm.h
28
src/cvm.h
@@ -33,14 +33,14 @@ COSMO_API CObjObject *cosmoV_makeObject(CState *state, int pairs);
|
|||||||
COSMO_API void cosmoV_makeTable(CState *state, int pairs);
|
COSMO_API void cosmoV_makeTable(CState *state, int pairs);
|
||||||
COSMO_API void cosmoV_concat(CState *state, int vals);
|
COSMO_API void cosmoV_concat(CState *state, int vals);
|
||||||
COSMO_API void cosmoV_pushFString(CState *state, const char *format, ...);
|
COSMO_API void cosmoV_pushFString(CState *state, const char *format, ...);
|
||||||
COSMO_API void cosmoV_printError(CState *state, CObjError *err);
|
COSMO_API void cosmoV_printBacktrace(CState *state, CObjError *err);
|
||||||
COSMO_API void cosmoV_throw(CState *state);
|
COSMO_API void cosmoV_throw(CState *state);
|
||||||
COSMO_API void cosmoV_error(CState *state, const char *format, ...);
|
COSMO_API void cosmoV_error(CState *state, const char *format, ...);
|
||||||
COSMO_API void cosmo_insert(CState *state, int indx, CValue val);
|
COSMO_API void cosmoV_insert(CState *state, int indx, CValue val);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Sets the default proto objects for the passed objType. Also walks through the object heap and
|
Sets the default proto objects for the passed objType. Also walks through the object heap and
|
||||||
updates protos for the passed objType if that CObj* has no proto.
|
updates protos for the passed objType if that CObj* has no proto.
|
||||||
|
|
||||||
returns true if replacing a previously registered proto object for this type
|
returns true if replacing a previously registered proto object for this type
|
||||||
*/
|
*/
|
||||||
@@ -67,27 +67,21 @@ COSMO_API bool cosmoV_compileString(CState *state, const char *src, const char *
|
|||||||
COSMO_API bool cosmoV_undump(CState *state, cosmo_Reader reader, const void *ud);
|
COSMO_API bool cosmoV_undump(CState *state, cosmo_Reader reader, const void *ud);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
expects object to be pushed, then the key.
|
expects object to be pushed, then the key. pops the key & object and pushes the value
|
||||||
|
|
||||||
returns false if an error was thrown, returns true if the value was pushed onto the stack and
|
|
||||||
the object and key were popped
|
|
||||||
*/
|
*/
|
||||||
COSMO_API bool cosmoV_get(CState *state);
|
COSMO_API void cosmoV_get(CState *state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
expects object to be pushed, then the key, and finally the new value.
|
expects object to be pushed, then the key, and finally the new value. pops the object, key &
|
||||||
|
value
|
||||||
returns false if an error was thrown, returns true if the value was set and the object key, and
|
|
||||||
value were popped
|
|
||||||
*/
|
*/
|
||||||
COSMO_API bool cosmoV_set(CState *state);
|
COSMO_API void cosmoV_set(CState *state);
|
||||||
|
|
||||||
// wraps the closure into a CObjMethod, so the function is called as an invoked method
|
// wraps the closure into a CObjMethod, so the function is called as an invoked method
|
||||||
COSMO_API bool cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val);
|
COSMO_API void cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val);
|
||||||
|
|
||||||
// clears the stack, callstack and restores the state into a usable state after a calloverflow or
|
// check if the value at the top of the stack is a <obj> user type
|
||||||
// another hard to recover error (keeps the global table intact)
|
COSMO_API bool cosmoV_isValueUserType(CState *state, CValue val, int userType);
|
||||||
COSMO_API bool cosmoV_restore(CState *state);
|
|
||||||
|
|
||||||
// nice to have wrappers
|
// nice to have wrappers
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user