mirror of
https://github.com/CPunch/Cosmo.git
synced 2025-10-20 07:50:37 +00:00
Compare commits
82 Commits
e7b2d7d833
...
error-hand
Author | SHA1 | Date | |
---|---|---|---|
bfde2d25cf | |||
97d40765ce | |||
37e4653d40 | |||
1ae473383d | |||
6ed5589513 | |||
1408a07b23 | |||
27818b3788 | |||
37e42eb60b | |||
cd3047c271 | |||
f26376e6f5 | |||
409937c1fa | |||
1d2ba217af | |||
e28ffe1c6c | |||
9c5270124d | |||
5fc9af5564 | |||
a1c58647ba | |||
5c3e24fc39 | |||
dcf6a09dae | |||
e0faa14b35 | |||
861607d6a8 | |||
10c9f92a06 | |||
8dfd7744c2 | |||
7f7bc7c6ad | |||
5169aca6d0 | |||
c34c5850e2 | |||
07ba4c731e | |||
788911130d | |||
c464a76849 | |||
8c6ba18848 | |||
93a09698a9 | |||
be49ec5af5 | |||
4fe437ea4e | |||
e854c5dbb3 | |||
c945c56482 | |||
89d443d767 | |||
54a959438b | |||
355842989b | |||
45f36e6e87 | |||
819e76b711 | |||
f116efa02c | |||
465f4d5e4a | |||
3efee51224 | |||
2836de090b | |||
8e278e3a7d | |||
c8cae03604 | |||
5d805e258b | |||
8df4cc65e3 | |||
7279623e24 | |||
517b0b9532 | |||
1df2e212cb | |||
![]() |
84ec5d2aee | ||
6859ec98ad | |||
057716e0d4 | |||
b9e9dedac6 | |||
1813bbeb1b | |||
471589d379 | |||
70f931df18 | |||
c13db54d7d | |||
da85d640ce | |||
6bc4ec6b04 | |||
f92ffcecbd | |||
66d77bc54b | |||
afac75753f | |||
92b2db9678 | |||
![]() |
b30616bb3c | ||
![]() |
9e6c6038f1 | ||
![]() |
1200e2d512 | ||
2050359d2f | |||
47051575cb | |||
7c7a2ed8d9 | |||
d1ea5c9703 | |||
7c6c075c2a | |||
14539057aa | |||
461e1d0c15 | |||
2e07715a7d | |||
bc43eaaa75 | |||
43a278e12d | |||
![]() |
44f1674b09 | ||
![]() |
27aedd2969 | ||
![]() |
7caa696aa2 | ||
![]() |
2e395065f8 | ||
![]() |
5b8dc30bb8 |
45
.github/workflows/check_build.yaml
vendored
45
.github/workflows/check_build.yaml
vendored
@@ -1,45 +0,0 @@
|
|||||||
name: Check Builds
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- src/**
|
|
||||||
- util/**
|
|
||||||
- main.c
|
|
||||||
- Makefile
|
|
||||||
- CMakeLists.txt
|
|
||||||
- .github/workflows/check_build.yaml
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ubuntu-build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
- name: CMake
|
|
||||||
run: cmake -B build -DCMAKE_BUILD_TYPE=Release
|
|
||||||
- name: Build
|
|
||||||
run: cmake --build build --config Release
|
|
||||||
- name: Upload build artifact
|
|
||||||
uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: Cosmo-Ubuntu
|
|
||||||
path: build/bin
|
|
||||||
|
|
||||||
windows-build:
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
- name: Create CMake build files
|
|
||||||
run: cmake -B build -DCMAKE_BUILD_TYPE=MinSizeRel
|
|
||||||
- name: Check compilation
|
|
||||||
run: cmake --build build --config MinSizeRel
|
|
||||||
- name: Upload build artifact
|
|
||||||
uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: Cosmo-Windows
|
|
||||||
path: build/bin
|
|
@@ -16,7 +16,7 @@ set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT c
|
|||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
file(GLOB sources CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/src/*.c)
|
file(GLOB sources CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/src/*.c)
|
||||||
add_executable(${PROJECT_NAME} main.c ${PROJECT_SOURCE_DIR}/util/linenoise.c)
|
add_executable(${PROJECT_NAME} main.c)
|
||||||
target_sources(${PROJECT_NAME} PRIVATE ${sources})
|
target_sources(${PROJECT_NAME} PRIVATE ${sources})
|
||||||
|
|
||||||
IF (NOT WIN32)
|
IF (NOT WIN32)
|
||||||
|
4
Makefile
4
Makefile
@@ -1,7 +1,7 @@
|
|||||||
# make clean && make && ./bin/cosmo
|
# make clean && make && ./bin/cosmo
|
||||||
|
|
||||||
CC=clang
|
CC=clang
|
||||||
CFLAGS=-fPIE -Wall -Isrc -O3 #-g -fsanitize=address
|
CFLAGS=-fPIE -Wall -Isrc -O3 -std=c99 #-g -fsanitize=address
|
||||||
LDFLAGS=-lm #-fsanitize=address
|
LDFLAGS=-lm #-fsanitize=address
|
||||||
OUT=bin/cosmo
|
OUT=bin/cosmo
|
||||||
|
|
||||||
@@ -21,7 +21,6 @@ CHDR=\
|
|||||||
src/cbaselib.h\
|
src/cbaselib.h\
|
||||||
src/cdump.h\
|
src/cdump.h\
|
||||||
src/cundump.h\
|
src/cundump.h\
|
||||||
util/linenoise.h\
|
|
||||||
|
|
||||||
CSRC=\
|
CSRC=\
|
||||||
src/cchunk.c\
|
src/cchunk.c\
|
||||||
@@ -38,7 +37,6 @@ CSRC=\
|
|||||||
src/cbaselib.c\
|
src/cbaselib.c\
|
||||||
src/cdump.c\
|
src/cdump.c\
|
||||||
src/cundump.c\
|
src/cundump.c\
|
||||||
util/linenoise.c\
|
|
||||||
main.c\
|
main.c\
|
||||||
|
|
||||||
COBJ=$(CSRC:.c=.o)
|
COBJ=$(CSRC:.c=.o)
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
# Cosmo
|
# Cosmo
|
||||||
[](https://github.com/CPunch/Cosmo/actions/workflows/check_build.yaml)
|
[](https://ci.appveyor.com/project/CPunch/Cosmo)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
33
appveyor.yml
Normal file
33
appveyor.yml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
version: 'cosmo-0.1.{build}'
|
||||||
|
|
||||||
|
# we compile every commit under all branches
|
||||||
|
#branch:
|
||||||
|
# only:
|
||||||
|
# - main
|
||||||
|
|
||||||
|
# only run CI if we changed actual code
|
||||||
|
only_commits:
|
||||||
|
files:
|
||||||
|
- src/
|
||||||
|
- main.c
|
||||||
|
- Makefile
|
||||||
|
- CMakeLists.txt
|
||||||
|
- appveyor.yml
|
||||||
|
|
||||||
|
# images we're using
|
||||||
|
image:
|
||||||
|
- Ubuntu2004
|
||||||
|
|
||||||
|
platform:
|
||||||
|
- x64
|
||||||
|
|
||||||
|
install:
|
||||||
|
- sudo apt install clang cmake -y
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- make && ./bin/cosmo examples/testsuite.cosmo -s examples/getters_setters.cosmo
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
- path: bin
|
||||||
|
name: ubuntu20_04-bin-x64
|
||||||
|
type: zip
|
@@ -59,14 +59,7 @@ Includes functions that interact with the operating system.
|
|||||||
|
|
||||||
| Name | Type | Behavior | Example |
|
| Name | Type | Behavior | Example |
|
||||||
| ------------ | ------------------------------------------------ | ------------------------------------------------------------------------ | ------------------------ |
|
| ------------ | ------------------------------------------------ | ------------------------------------------------------------------------ | ------------------------ |
|
||||||
| 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.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.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'
|
|
||||||
|
@@ -1,6 +0,0 @@
|
|||||||
local err, file = os.open("LICENSE.md")
|
|
||||||
if err then
|
|
||||||
print("failed to open file")
|
|
||||||
end
|
|
||||||
|
|
||||||
print(file:read("a"))
|
|
@@ -1,6 +0,0 @@
|
|||||||
local err, file = os.open("test.md", "w")
|
|
||||||
if err then
|
|
||||||
print("failed to open file")
|
|
||||||
end
|
|
||||||
|
|
||||||
file:write("hello world")
|
|
15
main.c
15
main.c
@@ -8,8 +8,6 @@
|
|||||||
#include "cundump.h"
|
#include "cundump.h"
|
||||||
#include "cvm.h"
|
#include "cvm.h"
|
||||||
|
|
||||||
#include "util/linenoise.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -65,7 +63,7 @@ static bool interpret(CState *state, const char *script, const char *mod)
|
|||||||
|
|
||||||
static void repl(CState *state)
|
static void repl(CState *state)
|
||||||
{
|
{
|
||||||
char *line;
|
char line[1024];
|
||||||
_ACTIVE = true;
|
_ACTIVE = true;
|
||||||
|
|
||||||
// add our custom REPL functions
|
// add our custom REPL functions
|
||||||
@@ -75,16 +73,17 @@ static void repl(CState *state)
|
|||||||
cosmoV_pushString(state, "input");
|
cosmoV_pushString(state, "input");
|
||||||
cosmoV_pushCFunction(state, cosmoB_input);
|
cosmoV_pushCFunction(state, cosmoB_input);
|
||||||
|
|
||||||
cosmoV_addGlobals(state, 2);
|
cosmoV_register(state, 2);
|
||||||
|
|
||||||
while (_ACTIVE) {
|
while (_ACTIVE) {
|
||||||
if (!(line = linenoise("> "))) { // better than gets()
|
printf("> ");
|
||||||
|
|
||||||
|
if (!fgets(line, sizeof(line), stdin)) { // better than gets()
|
||||||
|
printf("\n> ");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
linenoiseHistoryAdd(line);
|
|
||||||
interpret(state, line, "REPL");
|
interpret(state, line, "REPL");
|
||||||
free(line);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +129,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_addGlobals(state, 1);
|
cosmoV_register(state, 1);
|
||||||
|
|
||||||
ret = interpret(state, script, fileName);
|
ret = interpret(state, script, fileName);
|
||||||
|
|
||||||
|
272
src/cbaselib.c
272
src/cbaselib.c
@@ -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
|
||||||
cosmoV_insert(state, 0, cosmoV_newBoolean(res));
|
cosmo_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, "");
|
||||||
|
|
||||||
cosmoV_insert(state, 0, cosmoV_newBoolean(res));
|
cosmo_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_addGlobals(state, i);
|
cosmoV_register(state, i);
|
||||||
|
|
||||||
// load other libraries
|
// load other libraries
|
||||||
cosmoB_loadObjLib(state);
|
cosmoB_loadObjLib(state);
|
||||||
@@ -168,43 +168,8 @@ 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);
|
||||||
|
|
||||||
if (!IS_REF(args[0])) {
|
cosmoV_pushRef(state, (CObj *)cosmoV_readObject(args[0])->_obj.proto); // just return the proto
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,9 +194,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", "keys"};
|
const char *identifiers[] = {"ischild"};
|
||||||
|
|
||||||
CosmoCFunction objLib[] = {cosmoB_oisChild, cosmoB_ogetKeys};
|
CosmoCFunction objLib[] = {cosmoB_oisChild};
|
||||||
|
|
||||||
// make object library object
|
// make object library object
|
||||||
cosmoV_pushString(state, "object");
|
cosmoV_pushString(state, "object");
|
||||||
@@ -239,7 +204,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 pairs
|
// key & value pair
|
||||||
cosmoV_pushString(state, "__proto"); // key
|
cosmoV_pushString(state, "__proto"); // key
|
||||||
cosmoV_pushCFunction(state, cosmoB_ogetProto); // value
|
cosmoV_pushCFunction(state, cosmoB_ogetProto); // value
|
||||||
|
|
||||||
@@ -265,176 +230,52 @@ 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_addGlobals(state, 1);
|
cosmoV_register(state, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================================================ [OS.*]
|
// ================================================================ [OS.*]
|
||||||
|
|
||||||
int fileB_read(CState *state, int nargs, CValue *args)
|
// os.read()
|
||||||
{
|
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, "file:read() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "os.read() expected 1 argument, got %d!", nargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cosmoV_isValueUserType(state, args[0], COSMO_USER_FILE)) {
|
|
||||||
cosmoV_typeError(state, "file:__gc()", "<file>", "%s", cosmoV_typeStr(args[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
CObjObject *fileObj = cosmoV_readObject(args[0]);
|
|
||||||
FILE *file = cosmoO_getUserP(fileObj);
|
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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])) {
|
if (!IS_STRING(args[0])) {
|
||||||
cosmoV_typeError(state, "os.open()", "<string>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "os.read()", "<string>", "%s", cosmoV_typeStr(args[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nargs == 2) {
|
CObjString *str = cosmoV_readString(args[0]);
|
||||||
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]);
|
// open file
|
||||||
} else if (nargs != 1) {
|
FILE *file = fopen(str->str, "rb");
|
||||||
cosmoV_error(state, "os.open() expected 1 or 2 arguments, got %d!", nargs);
|
char *buf;
|
||||||
}
|
size_t size, bRead;
|
||||||
} 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) {
|
||||||
cosmoV_pushBoolean(state, true);
|
// return nil, file doesn't exist
|
||||||
cosmoV_pushFString(state, "Failed to open %s!", filePath);
|
return 0;
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushBoolean(state, false);
|
// grab the size of the file
|
||||||
pushFileObj(state, file);
|
fseek(file, 0L, SEEK_END);
|
||||||
return 2;
|
size = ftell(file);
|
||||||
|
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()
|
||||||
@@ -468,8 +309,9 @@ 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[] = {"open", "time", "system"};
|
const char *identifiers[] = {"read", "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");
|
||||||
|
|
||||||
@@ -480,30 +322,7 @@ COSMO_API void cosmoB_loadOS(CState *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_makeObject(state, i);
|
cosmoV_makeObject(state, i);
|
||||||
cosmoV_addGlobals(state, 1); // register the os.* object to the global table
|
cosmoV_register(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.*]
|
||||||
@@ -727,9 +546,8 @@ 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';
|
||||||
@@ -760,7 +578,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_addGlobals(state, 1);
|
cosmoV_register(state, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================================================ [MATH]
|
// ================================================================ [MATH]
|
||||||
@@ -955,7 +773,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_addGlobals(state, 1);
|
cosmoV_register(state, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================================================ [VM.*]
|
// ================================================================ [VM.*]
|
||||||
@@ -1106,5 +924,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_addGlobals(state, 1);
|
cosmoV_register(state, 1);
|
||||||
}
|
}
|
||||||
|
@@ -3,13 +3,6 @@
|
|||||||
|
|
||||||
#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
|
||||||
|
@@ -5,9 +5,8 @@
|
|||||||
|
|
||||||
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)
|
||||||
|
84
src/cmem.c
84
src/cmem.c
@@ -6,7 +6,6 @@
|
|||||||
#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)
|
||||||
@@ -57,7 +56,7 @@ void *cosmoM_reallocate(CState *state, void *buf, size_t oldSize, size_t newSize
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (newBuf == NULL) {
|
if (newBuf == NULL) {
|
||||||
printf("[ERROR] failed to allocate memory!");
|
CERROR("failed to allocate memory!");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,9 +164,8 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -231,11 +229,11 @@ static void traceGrays(CState *state)
|
|||||||
|
|
||||||
static void sweep(CState *state)
|
static void sweep(CState *state)
|
||||||
{
|
{
|
||||||
CObj *prev = NULL, *object = state->objects;
|
CObj *prev = NULL;
|
||||||
|
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; // reset to white
|
object->isMarked = false; // rest to white
|
||||||
prev = object;
|
prev = object;
|
||||||
object = object->next;
|
object = object->next;
|
||||||
} else { // free it!
|
} else { // free it!
|
||||||
@@ -248,22 +246,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
|
||||||
@@ -284,15 +282,14 @@ 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]);
|
||||||
}
|
|
||||||
|
|
||||||
markTable(state, &state->registry);
|
// mark the user defined roots
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
@@ -326,3 +323,44 @@ 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,6 +67,13 @@ 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)
|
||||||
{
|
{
|
||||||
|
38
src/cobj.c
38
src/cobj.c
@@ -15,9 +15,8 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -32,6 +31,7 @@ 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 *objObj = (CObjObject *)obj;
|
CObjObject *objTbl = (CObjObject *)obj;
|
||||||
cosmoT_clearTable(state, &objObj->tbl);
|
cosmoT_clearTable(state, &objTbl->tbl);
|
||||||
cosmoM_free(state, CObjObject, objObj);
|
cosmoM_free(state, CObjObject, objTbl);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COBJ_TABLE: {
|
case COBJ_TABLE: {
|
||||||
@@ -237,9 +237,8 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -398,7 +397,7 @@ bool cosmoO_isDescendant(CObj *obj, CObjObject *proto)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// returns false if error thrown
|
// returns false if error thrown
|
||||||
void cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *val, CObj *obj)
|
bool 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
|
||||||
@@ -408,17 +407,18 @@ void 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// maybe the field is defined in the proto?
|
if (proto->_obj.proto != NULL &&
|
||||||
if (proto->_obj.proto != NULL) {
|
cosmoO_getRawObject(state, proto->_obj.proto, key, val, obj))
|
||||||
cosmoO_getRawObject(state, proto->_obj.proto, key, val, obj);
|
return true;
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val)
|
bool 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,12 +527,15 @@ void 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue val)
|
bool cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue val)
|
||||||
{
|
{
|
||||||
CValue ret; // return value for cosmoO_getIString
|
CValue ret; // return value for cosmoO_getIString
|
||||||
|
|
||||||
@@ -542,9 +545,12 @@ void 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)
|
||||||
|
@@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
#include "cosmo.h"
|
#include "cosmo.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
typedef enum CObjType
|
typedef enum CObjType
|
||||||
{
|
{
|
||||||
COBJ_STRING,
|
COBJ_STRING,
|
||||||
@@ -34,6 +32,7 @@ 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
|
||||||
@@ -173,10 +172,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *val, CObj *obj);
|
bool 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);
|
||||||
void cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val);
|
bool cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val);
|
||||||
void cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue val);
|
bool 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
|
||||||
|
@@ -64,4 +64,6 @@ typedef int (*cosmo_Writer)(CState *state, const void *data, size_t size, const
|
|||||||
#define UNNAMEDCHUNK "_main"
|
#define UNNAMEDCHUNK "_main"
|
||||||
#define COSMOASSERT(x) assert(x)
|
#define COSMOASSERT(x) assert(x)
|
||||||
|
|
||||||
|
#define CERROR(err) printf("%s : %s\n", "[ERROR]", err)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -592,6 +592,8 @@ 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);
|
||||||
|
67
src/cstate.c
67
src/cstate.c
@@ -12,7 +12,6 @@ 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;
|
||||||
|
|
||||||
@@ -33,7 +32,7 @@ CState *cosmoV_newState()
|
|||||||
CState *state = malloc(sizeof(CState));
|
CState *state = malloc(sizeof(CState));
|
||||||
|
|
||||||
if (state == NULL) {
|
if (state == NULL) {
|
||||||
printf("[ERROR] failed to allocate memory!");
|
CERROR("failed to allocate memory!");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +41,7 @@ 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,22 +54,18 @@ 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);
|
||||||
@@ -89,9 +85,8 @@ 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;
|
||||||
@@ -118,15 +113,12 @@ 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);
|
||||||
|
|
||||||
@@ -140,7 +132,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_addGlobals(CState *state, int pairs)
|
void cosmoV_register(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);
|
||||||
@@ -153,51 +145,6 @@ void cosmoV_addGlobals(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");
|
||||||
|
20
src/cstate.h
20
src/cstate.h
@@ -18,7 +18,6 @@ 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
|
||||||
@@ -47,7 +46,6 @@ 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
|
||||||
@@ -57,7 +55,6 @@ 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
|
||||||
|
|
||||||
@@ -65,12 +62,14 @@ struct CState
|
|||||||
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;
|
||||||
|
|
||||||
size_t allocatedBytes;
|
|
||||||
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 freezeGC; // when > 0, GC events will be ignored (for internal use)
|
||||||
int frameCount;
|
int frameCount;
|
||||||
|
size_t allocatedBytes;
|
||||||
|
size_t nextGC; // when allocatedBytes reaches this threshhold, trigger a GC event
|
||||||
};
|
};
|
||||||
|
|
||||||
CPanic *cosmoV_newPanic(CState *state);
|
CPanic *cosmoV_newPanic(CState *state);
|
||||||
@@ -80,16 +79,7 @@ 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_addGlobals(CState *state, int pairs);
|
COSMO_API void cosmoV_register(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);
|
||||||
|
|
||||||
|
@@ -87,9 +87,8 @@ 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
|
||||||
|
156
src/cvm.c
156
src/cvm.c
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#define cosmoV_protect(panic) setjmp(panic->jmp) == 0
|
#define cosmoV_protect(panic) setjmp(panic->jmp) == 0
|
||||||
|
|
||||||
void cosmoV_pushFString(CState *state, const char *format, ...)
|
COSMO_API void cosmoV_pushFString(CState *state, const char *format, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
@@ -21,20 +21,19 @@ 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
|
||||||
void cosmoV_insert(CState *state, int indx, CValue val)
|
COSMO_API void cosmo_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++;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cosmoV_undump(CState *state, cosmo_Reader reader, const void *ud)
|
COSMO_API bool cosmoV_undump(CState *state, cosmo_Reader reader, const void *ud)
|
||||||
{
|
{
|
||||||
CObjFunction *func;
|
CObjFunction *func;
|
||||||
|
|
||||||
@@ -55,7 +54,7 @@ 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
|
||||||
bool cosmoV_compileString(CState *state, const char *src, const char *name)
|
COSMO_API 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);
|
||||||
@@ -78,7 +77,7 @@ bool cosmoV_compileString(CState *state, const char *src, const char *name)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoV_printError(CState *state, CObjError *err)
|
COSMO_API void cosmoV_printError(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++) {
|
||||||
@@ -123,7 +122,6 @@ 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 {
|
||||||
@@ -269,9 +267,8 @@ 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());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -329,9 +326,8 @@ 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
|
||||||
@@ -380,9 +376,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
|
||||||
// -1 since the we already pushed the important value
|
for (int i = 0; i < nresults - 1;
|
||||||
for (int i = 0; i < nresults - 1; i++) {
|
i++) { // -1 since the we already pushed the important value
|
||||||
cosmoV_pushValue(state, cosmoV_newNil());
|
cosmoV_pushValue(state, cosmoV_newNil());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -418,10 +414,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);
|
||||||
return false;
|
return false;
|
||||||
@@ -443,7 +438,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));
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjObject *cosmoV_makeObject(CState *state, int pairs)
|
COSMO_API CObjObject *cosmoV_makeObject(CState *state, int pairs)
|
||||||
{
|
{
|
||||||
StkPtr key, val;
|
StkPtr key, val;
|
||||||
CObjObject *newObj = cosmoO_newObject(state);
|
CObjObject *newObj = cosmoO_newObject(state);
|
||||||
@@ -464,7 +459,7 @@ CObjObject *cosmoV_makeObject(CState *state, int pairs)
|
|||||||
return newObj;
|
return newObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cosmoV_registerProtoObject(CState *state, CObjType objType, CObjObject *obj)
|
COSMO_API 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;
|
||||||
@@ -473,7 +468,7 @@ bool cosmoV_registerProtoObject(CState *state, CObjType objType, CObjObject *obj
|
|||||||
CObj *curr = state->objects;
|
CObj *curr = state->objects;
|
||||||
while (curr != NULL) {
|
while (curr != NULL) {
|
||||||
// update the proto
|
// update the proto
|
||||||
if (curr != (CObj *)obj && curr->type == objType && curr->proto != NULL) {
|
if (curr->type == objType && curr->proto != NULL) {
|
||||||
curr->proto = obj;
|
curr->proto = obj;
|
||||||
}
|
}
|
||||||
curr = curr->next;
|
curr = curr->next;
|
||||||
@@ -482,7 +477,7 @@ bool cosmoV_registerProtoObject(CState *state, CObjType objType, CObjObject *obj
|
|||||||
return replaced;
|
return replaced;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoV_makeTable(CState *state, int pairs)
|
COSMO_API void cosmoV_makeTable(CState *state, int pairs)
|
||||||
{
|
{
|
||||||
StkPtr key, val;
|
StkPtr key, val;
|
||||||
CObjTable *newObj = cosmoO_newTable(state);
|
CObjTable *newObj = cosmoO_newTable(state);
|
||||||
@@ -502,7 +497,7 @@ void cosmoV_makeTable(CState *state, int pairs)
|
|||||||
cosmoV_pushRef(state, (CObj *)newObj);
|
cosmoV_pushRef(state, (CObj *)newObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoV_rawget(CState *state, CObj *_obj, CValue key, CValue *val)
|
bool cosmoV_rawget(CState *state, CObj *_obj, CValue key, CValue *val)
|
||||||
{
|
{
|
||||||
CObjObject *object = cosmoO_grabProto(_obj);
|
CObjObject *object = cosmoO_grabProto(_obj);
|
||||||
|
|
||||||
@@ -511,16 +506,23 @@ void 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);
|
||||||
cosmoO_getRawObject(state, object, key, val, _obj);
|
if (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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoV_rawset(CState *state, CObj *_obj, CValue key, CValue val)
|
bool cosmoV_rawset(CState *state, CObj *_obj, CValue key, CValue val)
|
||||||
{
|
{
|
||||||
CObjObject *object = cosmoO_grabProto(_obj);
|
CObjObject *object = cosmoO_grabProto(_obj);
|
||||||
|
|
||||||
@@ -529,12 +531,14 @@ void 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoV_get(CState *state)
|
COSMO_API bool 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
|
||||||
@@ -542,17 +546,20 @@ void 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_rawget(state, cosmoV_readRef(*obj), *key, &val);
|
if (!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
|
||||||
void cosmoV_set(CState *state)
|
COSMO_API bool 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
|
||||||
@@ -560,17 +567,21 @@ void 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_rawset(state, cosmoV_readRef(*obj), *key, *val);
|
if (!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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val)
|
COSMO_API bool cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val)
|
||||||
{
|
{
|
||||||
cosmoV_rawget(state, obj, key, val);
|
if (!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)) {
|
||||||
@@ -580,18 +591,6 @@ void cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
@@ -697,7 +696,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!"); \
|
CERROR("unknown opcode!"); \
|
||||||
exit(0)
|
exit(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -850,15 +849,18 @@ 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 = cosmoV_newNil(); // to hold our value
|
CValue val; // to hold our value
|
||||||
|
|
||||||
if (proto != NULL) {
|
if (proto != NULL) {
|
||||||
// check for __index metamethod
|
// check for __index metamethod
|
||||||
cosmoO_indexObject(state, proto, *key, &val);
|
if (!cosmoO_indexObject(state, proto, *key,
|
||||||
|
&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;
|
||||||
|
|
||||||
@@ -866,6 +868,7 @@ 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
|
||||||
@@ -880,13 +883,17 @@ 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) {
|
||||||
cosmoO_newIndexObject(state, proto, *key, *value);
|
if (!cosmoO_newIndexObject(
|
||||||
|
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);
|
||||||
@@ -895,6 +902,7 @@ 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
|
||||||
@@ -913,11 +921,13 @@ int cosmoV_execute(CState *state)
|
|||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (IS_REF(*temp)) {
|
if (IS_REF(*temp)) {
|
||||||
cosmoV_rawset(state, cosmoV_readRef(*temp), constants[ident], *value);
|
if (!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
|
||||||
@@ -925,17 +935,19 @@ int cosmoV_execute(CState *state)
|
|||||||
}
|
}
|
||||||
CASE(OP_GETOBJECT) :
|
CASE(OP_GETOBJECT) :
|
||||||
{
|
{
|
||||||
CValue val = cosmoV_newNil(); // to hold our value
|
CValue val; // 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)) {
|
||||||
cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val);
|
if (!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
|
||||||
@@ -943,18 +955,20 @@ int cosmoV_execute(CState *state)
|
|||||||
}
|
}
|
||||||
CASE(OP_GETMETHOD) :
|
CASE(OP_GETMETHOD) :
|
||||||
{
|
{
|
||||||
CValue val = cosmoV_newNil(); // to hold our value
|
CValue val; // 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)) {
|
||||||
cosmoV_getMethod(state, cosmoV_readRef(*temp), constants[ident], &val);
|
if (!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
|
||||||
@@ -971,12 +985,14 @@ 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
|
||||||
cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val);
|
if (!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) :
|
||||||
@@ -986,6 +1002,7 @@ 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);
|
||||||
@@ -1009,6 +1026,7 @@ 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
|
||||||
@@ -1016,6 +1034,7 @@ 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;
|
||||||
@@ -1040,6 +1059,7 @@ 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) :
|
||||||
@@ -1051,6 +1071,7 @@ 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);
|
||||||
@@ -1093,6 +1114,7 @@ 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) :
|
||||||
@@ -1106,6 +1128,7 @@ 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) :
|
||||||
@@ -1121,6 +1144,7 @@ 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) :
|
||||||
@@ -1129,6 +1153,7 @@ 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));
|
||||||
@@ -1153,6 +1178,7 @@ 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) :
|
||||||
@@ -1168,6 +1194,7 @@ 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) :
|
||||||
@@ -1182,6 +1209,7 @@ 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) :
|
||||||
@@ -1193,6 +1221,7 @@ 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);
|
||||||
@@ -1201,23 +1230,27 @@ 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) {
|
||||||
cosmoO_indexObject(state, proto, *key, &val);
|
if (cosmoO_indexObject(state, proto, *key, &val)) {
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushValue(state, val); // pushes old value onto the stack :)
|
cosmoV_pushValue(state, val); // pushes old value onto the stack :)
|
||||||
|
|
||||||
// call __newindex
|
// call __newindex
|
||||||
cosmoO_newIndexObject(state, proto, *key,
|
if (!cosmoO_newIndexObject(state, proto, *key,
|
||||||
cosmoV_newNumber(cosmoV_readNumber(val) + inc));
|
cosmoV_newNumber(cosmoV_readNumber(val) + inc)))
|
||||||
|
return -1;
|
||||||
|
} else
|
||||||
|
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
|
||||||
@@ -1227,6 +1260,7 @@ 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) :
|
||||||
@@ -1241,7 +1275,8 @@ int cosmoV_execute(CState *state)
|
|||||||
CObj *obj = cosmoV_readRef(*temp);
|
CObj *obj = cosmoV_readRef(*temp);
|
||||||
CValue val;
|
CValue val;
|
||||||
|
|
||||||
cosmoV_rawget(state, obj, ident, &val);
|
if (!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);
|
||||||
@@ -1249,13 +1284,16 @@ 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 :)
|
||||||
cosmoV_rawset(state, obj, ident,
|
if (!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) :
|
||||||
|
24
src/cvm.h
24
src/cvm.h
@@ -36,7 +36,7 @@ COSMO_API void cosmoV_pushFString(CState *state, const char *format, ...);
|
|||||||
COSMO_API void cosmoV_printError(CState *state, CObjError *err);
|
COSMO_API void cosmoV_printError(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 cosmoV_insert(CState *state, int indx, CValue val);
|
COSMO_API void cosmo_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
|
||||||
@@ -67,21 +67,27 @@ 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. pops the key & object and pushes the value
|
expects object to be pushed, then the key.
|
||||||
|
|
||||||
|
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 void cosmoV_get(CState *state);
|
COSMO_API bool cosmoV_get(CState *state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
expects object to be pushed, then the key, and finally the new value. pops the object, key &
|
expects object to be pushed, then the key, and finally the new value.
|
||||||
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 void cosmoV_set(CState *state);
|
COSMO_API bool 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 void cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val);
|
COSMO_API bool cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val);
|
||||||
|
|
||||||
// check if the value at the top of the stack is a <obj> user type
|
// clears the stack, callstack and restores the state into a usable state after a calloverflow or
|
||||||
COSMO_API bool cosmoV_isValueUserType(CState *state, CValue val, int userType);
|
// another hard to recover error (keeps the global table intact)
|
||||||
|
COSMO_API bool cosmoV_restore(CState *state);
|
||||||
|
|
||||||
// nice to have wrappers
|
// nice to have wrappers
|
||||||
|
|
||||||
|
@@ -1,379 +0,0 @@
|
|||||||
|
|
||||||
/* this code is not standalone
|
|
||||||
* it is included into linenoise.c
|
|
||||||
* for windows.
|
|
||||||
* It is deliberately kept separate so that
|
|
||||||
* applications that have no need for windows
|
|
||||||
* support can omit this
|
|
||||||
*/
|
|
||||||
static DWORD orig_consolemode = 0;
|
|
||||||
|
|
||||||
static int flushOutput(struct current *current);
|
|
||||||
static void outputNewline(struct current *current);
|
|
||||||
|
|
||||||
static void refreshStart(struct current *current)
|
|
||||||
{
|
|
||||||
(void)current;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void refreshEnd(struct current *current)
|
|
||||||
{
|
|
||||||
(void)current;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void refreshStartChars(struct current *current)
|
|
||||||
{
|
|
||||||
assert(current->output == NULL);
|
|
||||||
/* We accumulate all output here */
|
|
||||||
current->output = sb_alloc();
|
|
||||||
#ifdef USE_UTF8
|
|
||||||
current->ubuflen = 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void refreshNewline(struct current *current)
|
|
||||||
{
|
|
||||||
DRL("<nl>");
|
|
||||||
outputNewline(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void refreshEndChars(struct current *current)
|
|
||||||
{
|
|
||||||
assert(current->output);
|
|
||||||
flushOutput(current);
|
|
||||||
sb_free(current->output);
|
|
||||||
current->output = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int enableRawMode(struct current *current) {
|
|
||||||
DWORD n;
|
|
||||||
INPUT_RECORD irec;
|
|
||||||
|
|
||||||
current->outh = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
current->inh = GetStdHandle(STD_INPUT_HANDLE);
|
|
||||||
|
|
||||||
if (!PeekConsoleInput(current->inh, &irec, 1, &n)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (getWindowSize(current) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (GetConsoleMode(current->inh, &orig_consolemode)) {
|
|
||||||
SetConsoleMode(current->inh, ENABLE_PROCESSED_INPUT);
|
|
||||||
}
|
|
||||||
#ifdef USE_UTF8
|
|
||||||
/* XXX is this the right thing to do? */
|
|
||||||
SetConsoleCP(65001);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void disableRawMode(struct current *current)
|
|
||||||
{
|
|
||||||
SetConsoleMode(current->inh, orig_consolemode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void linenoiseClearScreen(void)
|
|
||||||
{
|
|
||||||
/* XXX: This is ugly. Should just have the caller pass a handle */
|
|
||||||
struct current current;
|
|
||||||
|
|
||||||
current.outh = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
|
|
||||||
if (getWindowSize(¤t) == 0) {
|
|
||||||
COORD topleft = { 0, 0 };
|
|
||||||
DWORD n;
|
|
||||||
|
|
||||||
FillConsoleOutputCharacter(current.outh, ' ',
|
|
||||||
current.cols * current.rows, topleft, &n);
|
|
||||||
FillConsoleOutputAttribute(current.outh,
|
|
||||||
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN,
|
|
||||||
current.cols * current.rows, topleft, &n);
|
|
||||||
SetConsoleCursorPosition(current.outh, topleft);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cursorToLeft(struct current *current)
|
|
||||||
{
|
|
||||||
COORD pos;
|
|
||||||
DWORD n;
|
|
||||||
|
|
||||||
pos.X = 0;
|
|
||||||
pos.Y = (SHORT)current->y;
|
|
||||||
|
|
||||||
FillConsoleOutputAttribute(current->outh,
|
|
||||||
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, current->cols, pos, &n);
|
|
||||||
current->x = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_UTF8
|
|
||||||
static void flush_ubuf(struct current *current)
|
|
||||||
{
|
|
||||||
COORD pos;
|
|
||||||
DWORD nwritten;
|
|
||||||
pos.Y = (SHORT)current->y;
|
|
||||||
pos.X = (SHORT)current->x;
|
|
||||||
SetConsoleCursorPosition(current->outh, pos);
|
|
||||||
WriteConsoleW(current->outh, current->ubuf, current->ubuflen, &nwritten, 0);
|
|
||||||
current->x += current->ubufcols;
|
|
||||||
current->ubuflen = 0;
|
|
||||||
current->ubufcols = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_ubuf(struct current *current, int ch)
|
|
||||||
{
|
|
||||||
/* This code originally by: Author: Mark E. Davis, 1994. */
|
|
||||||
static const int halfShift = 10; /* used for shifting by 10 bits */
|
|
||||||
|
|
||||||
static const DWORD halfBase = 0x0010000UL;
|
|
||||||
static const DWORD halfMask = 0x3FFUL;
|
|
||||||
|
|
||||||
#define UNI_SUR_HIGH_START 0xD800
|
|
||||||
#define UNI_SUR_HIGH_END 0xDBFF
|
|
||||||
#define UNI_SUR_LOW_START 0xDC00
|
|
||||||
#define UNI_SUR_LOW_END 0xDFFF
|
|
||||||
|
|
||||||
#define UNI_MAX_BMP 0x0000FFFF
|
|
||||||
|
|
||||||
if (ch > UNI_MAX_BMP) {
|
|
||||||
/* convert from unicode to utf16 surrogate pairs
|
|
||||||
* There is always space for one extra word in ubuf
|
|
||||||
*/
|
|
||||||
ch -= halfBase;
|
|
||||||
current->ubuf[current->ubuflen++] = (WORD)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
|
||||||
current->ubuf[current->ubuflen++] = (WORD)((ch & halfMask) + UNI_SUR_LOW_START);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
current->ubuf[current->ubuflen++] = ch;
|
|
||||||
}
|
|
||||||
current->ubufcols += utf8_width(ch);
|
|
||||||
if (current->ubuflen >= UBUF_MAX_CHARS) {
|
|
||||||
flush_ubuf(current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int flushOutput(struct current *current)
|
|
||||||
{
|
|
||||||
const char *pt = sb_str(current->output);
|
|
||||||
int len = sb_len(current->output);
|
|
||||||
|
|
||||||
#ifdef USE_UTF8
|
|
||||||
/* convert utf8 in current->output into utf16 in current->ubuf
|
|
||||||
*/
|
|
||||||
while (len) {
|
|
||||||
int ch;
|
|
||||||
int n = utf8_tounicode(pt, &ch);
|
|
||||||
|
|
||||||
pt += n;
|
|
||||||
len -= n;
|
|
||||||
|
|
||||||
add_ubuf(current, ch);
|
|
||||||
}
|
|
||||||
flush_ubuf(current);
|
|
||||||
#else
|
|
||||||
DWORD nwritten;
|
|
||||||
COORD pos;
|
|
||||||
|
|
||||||
pos.Y = (SHORT)current->y;
|
|
||||||
pos.X = (SHORT)current->x;
|
|
||||||
|
|
||||||
SetConsoleCursorPosition(current->outh, pos);
|
|
||||||
WriteConsoleA(current->outh, pt, len, &nwritten, 0);
|
|
||||||
|
|
||||||
current->x += len;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sb_clear(current->output);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int outputChars(struct current *current, const char *buf, int len)
|
|
||||||
{
|
|
||||||
if (len < 0) {
|
|
||||||
len = strlen(buf);
|
|
||||||
}
|
|
||||||
assert(current->output);
|
|
||||||
|
|
||||||
sb_append_len(current->output, buf, len);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void outputNewline(struct current *current)
|
|
||||||
{
|
|
||||||
/* On the last row output a newline to force a scroll */
|
|
||||||
if (current->y + 1 == current->rows) {
|
|
||||||
outputChars(current, "\n", 1);
|
|
||||||
}
|
|
||||||
flushOutput(current);
|
|
||||||
current->x = 0;
|
|
||||||
current->y++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setOutputHighlight(struct current *current, const int *props, int nprops)
|
|
||||||
{
|
|
||||||
int colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
|
|
||||||
int bold = 0;
|
|
||||||
int reverse = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < nprops; i++) {
|
|
||||||
switch (props[i]) {
|
|
||||||
case 0:
|
|
||||||
colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
|
|
||||||
bold = 0;
|
|
||||||
reverse = 0;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
bold = FOREGROUND_INTENSITY;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
reverse = 1;
|
|
||||||
break;
|
|
||||||
case 30:
|
|
||||||
colour = 0;
|
|
||||||
break;
|
|
||||||
case 31:
|
|
||||||
colour = FOREGROUND_RED;
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
colour = FOREGROUND_GREEN;
|
|
||||||
break;
|
|
||||||
case 33:
|
|
||||||
colour = FOREGROUND_RED | FOREGROUND_GREEN;
|
|
||||||
break;
|
|
||||||
case 34:
|
|
||||||
colour = FOREGROUND_BLUE;
|
|
||||||
break;
|
|
||||||
case 35:
|
|
||||||
colour = FOREGROUND_RED | FOREGROUND_BLUE;
|
|
||||||
break;
|
|
||||||
case 36:
|
|
||||||
colour = FOREGROUND_BLUE | FOREGROUND_GREEN;
|
|
||||||
break;
|
|
||||||
case 37:
|
|
||||||
colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flushOutput(current);
|
|
||||||
|
|
||||||
if (reverse) {
|
|
||||||
SetConsoleTextAttribute(current->outh, BACKGROUND_INTENSITY);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SetConsoleTextAttribute(current->outh, colour | bold);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void eraseEol(struct current *current)
|
|
||||||
{
|
|
||||||
COORD pos;
|
|
||||||
DWORD n;
|
|
||||||
|
|
||||||
pos.X = (SHORT) current->x;
|
|
||||||
pos.Y = (SHORT) current->y;
|
|
||||||
|
|
||||||
FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setCursorXY(struct current *current)
|
|
||||||
{
|
|
||||||
COORD pos;
|
|
||||||
|
|
||||||
pos.X = (SHORT) current->x;
|
|
||||||
pos.Y = (SHORT) current->y;
|
|
||||||
|
|
||||||
SetConsoleCursorPosition(current->outh, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void setCursorPos(struct current *current, int x)
|
|
||||||
{
|
|
||||||
current->x = x;
|
|
||||||
setCursorXY(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cursorUp(struct current *current, int n)
|
|
||||||
{
|
|
||||||
current->y -= n;
|
|
||||||
setCursorXY(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cursorDown(struct current *current, int n)
|
|
||||||
{
|
|
||||||
current->y += n;
|
|
||||||
setCursorXY(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fd_read(struct current *current)
|
|
||||||
{
|
|
||||||
while (1) {
|
|
||||||
INPUT_RECORD irec;
|
|
||||||
DWORD n;
|
|
||||||
if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!ReadConsoleInputW(current->inh, &irec, 1, &n)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (irec.EventType == KEY_EVENT) {
|
|
||||||
KEY_EVENT_RECORD *k = &irec.Event.KeyEvent;
|
|
||||||
if (k->bKeyDown || k->wVirtualKeyCode == VK_MENU) {
|
|
||||||
if (k->dwControlKeyState & ENHANCED_KEY) {
|
|
||||||
switch (k->wVirtualKeyCode) {
|
|
||||||
case VK_LEFT:
|
|
||||||
return SPECIAL_LEFT;
|
|
||||||
case VK_RIGHT:
|
|
||||||
return SPECIAL_RIGHT;
|
|
||||||
case VK_UP:
|
|
||||||
return SPECIAL_UP;
|
|
||||||
case VK_DOWN:
|
|
||||||
return SPECIAL_DOWN;
|
|
||||||
case VK_INSERT:
|
|
||||||
return SPECIAL_INSERT;
|
|
||||||
case VK_DELETE:
|
|
||||||
return SPECIAL_DELETE;
|
|
||||||
case VK_HOME:
|
|
||||||
return SPECIAL_HOME;
|
|
||||||
case VK_END:
|
|
||||||
return SPECIAL_END;
|
|
||||||
case VK_PRIOR:
|
|
||||||
return SPECIAL_PAGE_UP;
|
|
||||||
case VK_NEXT:
|
|
||||||
return SPECIAL_PAGE_DOWN;
|
|
||||||
case VK_RETURN:
|
|
||||||
return k->uChar.UnicodeChar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Note that control characters are already translated in AsciiChar */
|
|
||||||
else if (k->wVirtualKeyCode == VK_CONTROL)
|
|
||||||
continue;
|
|
||||||
else {
|
|
||||||
return k->uChar.UnicodeChar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getWindowSize(struct current *current)
|
|
||||||
{
|
|
||||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
|
||||||
if (!GetConsoleScreenBufferInfo(current->outh, &info)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
current->cols = info.dwSize.X;
|
|
||||||
current->rows = info.dwSize.Y;
|
|
||||||
if (current->cols <= 0 || current->rows <= 0) {
|
|
||||||
current->cols = 80;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
current->y = info.dwCursorPosition.Y;
|
|
||||||
current->x = info.dwCursorPosition.X;
|
|
||||||
return 0;
|
|
||||||
}
|
|
2786
util/linenoise.c
2786
util/linenoise.c
File diff suppressed because it is too large
Load Diff
152
util/linenoise.h
152
util/linenoise.h
@@ -1,152 +0,0 @@
|
|||||||
/* linenoise.h -- guerrilla line editing library against the idea that a
|
|
||||||
* line editing lib needs to be 20,000 lines of C code.
|
|
||||||
*
|
|
||||||
* See linenoise.c for more information.
|
|
||||||
*
|
|
||||||
* ------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
|
||||||
* Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are
|
|
||||||
* met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __LINENOISE_H
|
|
||||||
#define __LINENOISE_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifndef NO_COMPLETION
|
|
||||||
typedef struct linenoiseCompletions {
|
|
||||||
size_t len;
|
|
||||||
char **cvec;
|
|
||||||
} linenoiseCompletions;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The callback type for tab completion handlers.
|
|
||||||
*/
|
|
||||||
typedef void(linenoiseCompletionCallback)(const char *prefix, linenoiseCompletions *comp, void *userdata);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sets the current tab completion handler and returns the previous one, or NULL
|
|
||||||
* if no prior one has been set.
|
|
||||||
*/
|
|
||||||
linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *comp, void *userdata);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Adds a copy of the given string to the given completion list. The copy is owned
|
|
||||||
* by the linenoiseCompletions object.
|
|
||||||
*/
|
|
||||||
void linenoiseAddCompletion(linenoiseCompletions *comp, const char *str);
|
|
||||||
|
|
||||||
typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold, void *userdata);
|
|
||||||
typedef void(linenoiseFreeHintsCallback)(void *hint, void *userdata);
|
|
||||||
void linenoiseSetHintsCallback(linenoiseHintsCallback *callback, void *userdata);
|
|
||||||
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *callback);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prompts for input using the given string as the input
|
|
||||||
* prompt. Returns when the user has tapped ENTER or (on an empty
|
|
||||||
* line) EOF (Ctrl-D on Unix, Ctrl-Z on Windows). Returns either
|
|
||||||
* a copy of the entered string (for ENTER) or NULL (on EOF). The
|
|
||||||
* caller owns the returned string and must eventually free() it.
|
|
||||||
*/
|
|
||||||
char *linenoise(const char *prompt);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Like linenoise() but starts with an initial buffer.
|
|
||||||
*/
|
|
||||||
char *linenoiseWithInitial(const char *prompt, const char *initial);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear the screen.
|
|
||||||
*/
|
|
||||||
void linenoiseClearScreen(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Adds a copy of the given line of the command history.
|
|
||||||
*/
|
|
||||||
int linenoiseHistoryAdd(const char *line);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sets the maximum length of the command history, in lines.
|
|
||||||
* If the history is currently longer, it will be trimmed,
|
|
||||||
* retaining only the most recent entries. If len is 0 or less
|
|
||||||
* then this function does nothing.
|
|
||||||
*/
|
|
||||||
int linenoiseHistorySetMaxLen(int len);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the current maximum length of the history, in lines.
|
|
||||||
*/
|
|
||||||
int linenoiseHistoryGetMaxLen(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Saves the current contents of the history to the given file.
|
|
||||||
* Returns 0 on success.
|
|
||||||
*/
|
|
||||||
int linenoiseHistorySave(const char *filename);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Replaces the current history with the contents
|
|
||||||
* of the given file. Returns 0 on success.
|
|
||||||
*/
|
|
||||||
int linenoiseHistoryLoad(const char *filename);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Frees all history entries, clearing the history.
|
|
||||||
*/
|
|
||||||
void linenoiseHistoryFree(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns a pointer to the list of history entries, writing its
|
|
||||||
* length to *len if len is not NULL. The memory is owned by linenoise
|
|
||||||
* and must not be freed.
|
|
||||||
*/
|
|
||||||
char **linenoiseHistory(int *len);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the number of display columns in the current terminal.
|
|
||||||
*/
|
|
||||||
int linenoiseColumns(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable or disable multiline mode (disabled by default)
|
|
||||||
*/
|
|
||||||
void linenoiseSetMultiLine(int enableml);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LINENOISE_H */
|
|
Reference in New Issue
Block a user