getLuaArch() (hell)
This commit is contained in:
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,3 +1,7 @@
|
||||
[submodule "NeoNucleus"]
|
||||
path = NeoNucleus
|
||||
url = https://gitea.codersquack.nl/NeoFlock/NeoNucleus.git
|
||||
[submodule "src/tla-static/foreign/lua54"]
|
||||
path = src/tla-static/foreign/lua54
|
||||
url = https://github.com/lua/lua
|
||||
branch = v5.4
|
||||
|
||||
3
Makefile
3
Makefile
@@ -8,6 +8,7 @@ JAVA_HOME=/usr/lib/jvm/java-25-openjdk/
|
||||
BASE_NPATH=./src/native/
|
||||
JAVA_SRCS = $(wildcard ./src/main/org/neoflock/NeoNucleus/*.java)
|
||||
JAVA_CLASSES = $(wildcard ./src/main/org/neoflock/NeoNucleus/*.class)
|
||||
TLA_PATH=./src/tla-static
|
||||
|
||||
CPP_SRCS = $(wildcard ${BASE_NPATH}/*.cpp)
|
||||
OBJS = $(CPP_SRCS:.cpp=.o)
|
||||
@@ -17,7 +18,7 @@ all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
g++ -shared -o ${BASE_NPATH}/$(TARGET) \
|
||||
$(OBJS) ${BASE_NPATH}/libneonucleus.a -lc
|
||||
$(OBJS) ${BASE_NPATH}/libneonucleus.a $(TLA_PATH)/libtla.a -lc
|
||||
%.o: %.cpp
|
||||
$(CXX) -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux $(CFLAGS) \
|
||||
$< -o $@
|
||||
|
||||
@@ -9,7 +9,13 @@ public final class nn_Architecture extends PointerBackedClass implements Manuall
|
||||
public nn_Architecture(String name, Function<String, Integer> handler) { // string is a placeholder; please fix
|
||||
this.name = name;
|
||||
this.handler = handler;
|
||||
|
||||
}
|
||||
private nn_Architecture(String name) { // this overload is used by JNI when returning instances of native nn_Architecture(s)
|
||||
this.name = name;
|
||||
this.handler = (String tmp) -> {
|
||||
// maybe in the future we can let this happen idk
|
||||
throw new IllegalCallerException("Calling native architecture handlers from Java is not allowed!");
|
||||
};
|
||||
}
|
||||
|
||||
private int handleNative() { // i aint gonna be trying to call that Function from jni man
|
||||
@@ -18,4 +24,5 @@ public final class nn_Architecture extends PointerBackedClass implements Manuall
|
||||
|
||||
public native boolean allocate();
|
||||
public native boolean free();
|
||||
|
||||
}
|
||||
|
||||
@@ -101,6 +101,12 @@ nn_Exit From_nn_ComputerState(JNIEnv* env, jobject a) {
|
||||
jint value = env->CallIntMethod(a, ordMID);
|
||||
return (nn_Exit) value;
|
||||
}
|
||||
jobject Carbon::Map::To_nn_Architecture(JNIEnv* env, nn_Architecture a) {
|
||||
jclass clazz = env->FindClass("org/neoflock/NeoNucleus/nn_Architecture");
|
||||
jmethodID consMID = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;)V");
|
||||
jstring str = env->NewStringUTF(a.name);
|
||||
return env->NewObject(clazz, consMID, str);
|
||||
}
|
||||
namespace Carbon::Exceptions {
|
||||
CARBON_EXCEPTION_FUNC(ThrowNullPtr, "java/lang/NullPointerException");
|
||||
}
|
||||
@@ -28,6 +28,7 @@ namespace Carbon {
|
||||
nn_Exit From_nn_Exit(JNIEnv* env, jobject a);
|
||||
jobject To_nn_ComputerState(JNIEnv* env, nn_ComputerState a);
|
||||
nn_ComputerState From_nn_ComputerState(JNIEnv* env, jobject a);
|
||||
jobject To_nn_Architecture(JNIEnv* env, nn_Architecture a);
|
||||
}
|
||||
|
||||
typedef struct JavaObjectTarget { // i might lowkey drop this struct
|
||||
|
||||
3
src/native/luaarch.h
Normal file
3
src/native/luaarch.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "neonucleus.h"
|
||||
|
||||
nn_Architecture getLuaArch();
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "neonucleus.h"
|
||||
#include "ncomplib.h"
|
||||
#include <jni.h>
|
||||
#include "luaarch.h"
|
||||
|
||||
#include "carbon.hpp"
|
||||
|
||||
@@ -176,3 +177,8 @@ JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1getCom
|
||||
NULLPTR_CHECK(nnPC, nn_Component);
|
||||
return Carbon::Map::To_nn_ComputerState(env, nn_getComputerState(nnPC));
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_getLuaArch
|
||||
(JNIEnv * env, jclass) {
|
||||
return Carbon::Map::To_nn_Architecture(env, getLuaArch());
|
||||
}
|
||||
@@ -7,6 +7,14 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: org_neoflock_NeoNucleus_NativeBindings
|
||||
* Method: getLuaArch
|
||||
* Signature: ()Lorg/neoflock/NeoNucleus/nn_Architecture;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_getLuaArch
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: org_neoflock_NeoNucleus_NativeBindings
|
||||
* Method: nn_initContext
|
||||
|
||||
85
src/tla-static/Makefile
Normal file
85
src/tla-static/Makefile
Normal file
@@ -0,0 +1,85 @@
|
||||
#BIN=neonucleus
|
||||
#DYNLIB=libneonucleus.so
|
||||
#LIB=libneonucleus.a
|
||||
LIB=libtla.a
|
||||
|
||||
CC=cc
|
||||
LD=$(CC)
|
||||
AR=ar
|
||||
RANLIB=ranlib
|
||||
WARN=-Wall -Werror -Wno-format-truncation
|
||||
|
||||
ifeq ($(MODE), release)
|
||||
OPT=-Oz
|
||||
DEBUG=
|
||||
else ifeq ($(MODE), release-lto)
|
||||
OPT=-Oz -flto
|
||||
DEBUG=
|
||||
else
|
||||
OPT=-O0
|
||||
SANITIZE=undefined,address
|
||||
DEBUG=-g
|
||||
endif
|
||||
|
||||
NN_STD=gnu99
|
||||
EMU_STD=gnu23
|
||||
|
||||
NNFLAGS=
|
||||
|
||||
SANITIZE_FLAGS=
|
||||
|
||||
ifdef SANITIZE
|
||||
SANITIZE_FLAGS += -fsanitize=$(SANITIZE)
|
||||
endif
|
||||
|
||||
# no-omit-frame-pointer so if a crash does happen we can trace it
|
||||
CFLAGS=-fPIC -fno-omit-frame-pointer $(OPT) $(SANITIZE_FLAGS) $(DEBUG) $(NNFLAGS) $(WARN)
|
||||
|
||||
LDFLAGS=$(OPT) $(DEBUG) $(SANITIZE_FLAGS)
|
||||
|
||||
#LINKRAYLIB=-lraylib
|
||||
#INCLUA=-I /usr/include/lua5.4
|
||||
INCLUA=-I ./foreign/lua54
|
||||
LINKLUA=-llua5.4
|
||||
LINKLIBM=-lm
|
||||
LINKLIBC=
|
||||
|
||||
BUILD_DIR=build
|
||||
SRC_DIR=.
|
||||
|
||||
#all: bin lib dynlib
|
||||
all: lib
|
||||
|
||||
#$(BUILD_DIR)/neonucleus.o: $(SRC_DIR)/neonucleus.c $(SRC_DIR)/neonucleus.h
|
||||
# $(CC) -o $(BUILD_DIR)/neonucleus.o -c $(SRC_DIR)/neonucleus.c $(CFLAGS) -std=$(NN_STD)
|
||||
|
||||
#$(BUILD_DIR)/ncomplib.o: $(SRC_DIR)/ncomplib.c $(SRC_DIR)/ncomplib.h
|
||||
# $(CC) -o $(BUILD_DIR)/ncomplib.o -c $(SRC_DIR)/ncomplib.c $(CFLAGS) -std=$(NN_STD)
|
||||
|
||||
#nn: $(BUILD_DIR)/neonucleus.o $(BUILD_DIR)/ncomplib.o
|
||||
|
||||
$(BUILD_DIR)/luaarch.o: $(SRC_DIR)/luaarch.c $(SRC_DIR)/machine.lua
|
||||
$(CC) -o $(BUILD_DIR)/luaarch.o -c $(SRC_DIR)/luaarch.c $(CFLAGS) $(INCLUA) -std=$(EMU_STD)
|
||||
|
||||
#$(BUILD_DIR)/glyphcache.o: $(SRC_DIR)/glyphcache.c $(SRC_DIR)/glyphcache.h
|
||||
# $(CC) -o $(BUILD_DIR)/glyphcache.o -c $(SRC_DIR)/glyphcache.c $(CFLAGS) -std=$(EMU_STD)
|
||||
|
||||
#$(BUILD_DIR)/main.o: $(SRC_DIR)/main.c $(SRC_DIR)/minBIOS.lua
|
||||
# $(CC) -o $(BUILD_DIR)/main.o -c $(SRC_DIR)/main.c $(CFLAGS) $(INCLUA) -std=$(EMU_STD)
|
||||
|
||||
#bin: nn $(BUILD_DIR)/main.o $(BUILD_DIR)/luaarch.o $(BUILD_DIR)/glyphcache.o
|
||||
# $(LD) $(LDFLAGS) -o $(BIN) $(BUILD_DIR)/neonucleus.o $(BUILD_DIR)/ncomplib.o $(BUILD_DIR)/main.o $(BUILD_DIR)/glyphcache.o $(BUILD_DIR)/luaarch.o $(LINKLIBC) $(LINKLIBM) $(LINKRAYLIB) $(LINKLUA)
|
||||
#
|
||||
#lib: nn
|
||||
# $(AR) rc $(LIB) $(BUILD_DIR)/neonucleus.o $(BUILD_DIR)/ncomplib.o
|
||||
# $(RANLIB) $(LIB)
|
||||
|
||||
lib: $(BUILD_DIR)/luaarch.o
|
||||
$(AR) rc $(LIB) $(BUILD_DIR)/luaarch.o
|
||||
$(RANLIB) $(LIB)
|
||||
|
||||
cleancache:
|
||||
rm -rf $(BUILD_DIR)/*.o
|
||||
|
||||
clean:
|
||||
rm -rf $(BIN) $(DYNLIB) $(LIB)
|
||||
1
src/tla-static/foreign/lua54
Submodule
1
src/tla-static/foreign/lua54
Submodule
Submodule src/tla-static/foreign/lua54 added at 934fdd481c
870
src/tla-static/luaarch.c
Normal file
870
src/tla-static/luaarch.c
Normal file
@@ -0,0 +1,870 @@
|
||||
#include "neonucleus.h"
|
||||
#include <lualib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// This architecture is written horrendously.
|
||||
// This code is garbage, and is entirely just for testing.
|
||||
// This architecture has effectively 0 sandboxing.
|
||||
// The error handling in this architecture is effectively nothing.
|
||||
// Also if the total memory available changes during execution, this Lua arch will NOT CARE.
|
||||
|
||||
const char luaArch_machineLua[] = {
|
||||
#embed "machine.lua"
|
||||
,'\0'
|
||||
};
|
||||
|
||||
typedef struct luaArch {
|
||||
nn_Computer *computer;
|
||||
lua_State *L;
|
||||
size_t freeMem;
|
||||
} luaArch;
|
||||
|
||||
void *luaArch_alloc(void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||
luaArch *arch = ud;
|
||||
if(nsize == 0) {
|
||||
free(ptr);
|
||||
arch->freeMem += osize;
|
||||
return NULL;
|
||||
}
|
||||
if(ptr == NULL) {
|
||||
if(arch->freeMem < nsize) return NULL;
|
||||
void *mem = malloc(nsize);
|
||||
if(mem == NULL) return NULL;
|
||||
arch->freeMem -= nsize;
|
||||
return mem;
|
||||
}
|
||||
if(arch->freeMem + osize < nsize) return NULL;
|
||||
void *mem = realloc(ptr, nsize);
|
||||
if(mem == NULL) return NULL;
|
||||
arch->freeMem += osize;
|
||||
arch->freeMem -= nsize;
|
||||
return mem;
|
||||
}
|
||||
|
||||
static luaArch *luaArch_from(lua_State *L) {
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "archPtr");
|
||||
luaArch *arch = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return arch;
|
||||
}
|
||||
|
||||
// pushes an NN value from a Lua stack index
|
||||
static nn_Exit luaArch_luaToNN(luaArch *arch, lua_State *L, int luaIdx) {
|
||||
nn_Computer *C = arch->computer;
|
||||
|
||||
if(lua_isnoneornil(L, luaIdx)) {
|
||||
return nn_pushnull(C);
|
||||
}
|
||||
// lua_isnumber() automatically casts
|
||||
// because the Lua C API designers
|
||||
// were high
|
||||
if(lua_type(L, luaIdx) == LUA_TNUMBER) {
|
||||
return nn_pushnumber(C, lua_tonumber(L, luaIdx));
|
||||
}
|
||||
if(lua_isstring(L, luaIdx)) {
|
||||
size_t len;
|
||||
const char *s = lua_tolstring(L, luaIdx, &len);
|
||||
return nn_pushlstring(C, s, len);
|
||||
}
|
||||
if(lua_isboolean(L, luaIdx)) {
|
||||
return nn_pushbool(C, lua_toboolean(L, luaIdx));
|
||||
}
|
||||
if(lua_isuserdata(L, luaIdx)) {
|
||||
return nn_pushuserdata(C, (size_t)lua_touserdata(L, luaIdx));
|
||||
}
|
||||
luaL_error(L, "bad Lua value: %s", luaL_typename(L, luaIdx));
|
||||
return NN_EBADSTATE;
|
||||
}
|
||||
|
||||
// pushes a Lua value from an NN stack index
|
||||
static void luaArch_nnToLua(luaArch *arch, lua_State *L, size_t nnIdx) {
|
||||
nn_Computer *C = arch->computer;
|
||||
|
||||
if(nn_isnull(C, nnIdx)) {
|
||||
lua_pushnil(L);
|
||||
return;
|
||||
}
|
||||
if(nn_isnumber(C, nnIdx)) {
|
||||
lua_pushnumber(L, nn_tonumber(C, nnIdx));
|
||||
return;
|
||||
}
|
||||
if(nn_isstring(C, nnIdx)) {
|
||||
size_t len;
|
||||
const char *s = nn_tolstring(C, nnIdx, &len);
|
||||
lua_pushlstring(L, s, len);
|
||||
return;
|
||||
}
|
||||
if(nn_isboolean(C, nnIdx)) {
|
||||
lua_pushboolean(L, nn_toboolean(C, nnIdx));
|
||||
return;
|
||||
}
|
||||
if(nn_istable(C, nnIdx)) {
|
||||
size_t start = nn_getstacksize(C);
|
||||
size_t len;
|
||||
nn_dumptable(C, nnIdx, &len);
|
||||
lua_createtable(L, 0, len);
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
luaArch_nnToLua(arch, L, start + i * 2);
|
||||
luaArch_nnToLua(arch, L, start + i * 2 + 1);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
nn_popn(C, len * 2);
|
||||
return;
|
||||
}
|
||||
if(nn_isuserdata(C, nnIdx)) {
|
||||
lua_pushlightuserdata(L, (void *)nn_touserdata(C, nnIdx));
|
||||
return;
|
||||
}
|
||||
|
||||
luaL_error(L, "bad NN value: %s", nn_typenameof(C, nnIdx));
|
||||
}
|
||||
|
||||
static int luaArch_computer_beep(lua_State *L) {
|
||||
if(lua_type(L, 1) == LUA_TSTRING) {
|
||||
nn_MorseBeep beep = {.frequency = 1000, .beepDuration = 200, .volume = 1};
|
||||
beep.pattern = lua_tostring(L, 1);
|
||||
if(lua_isnumber(L, 2)) {
|
||||
beep.frequency = lua_tonumber(L, 2);
|
||||
}
|
||||
if(lua_isnumber(L, 3)) {
|
||||
beep.beepDuration = lua_tonumber(L, 3);
|
||||
}
|
||||
if(lua_isnumber(L, 4)) {
|
||||
beep.volume = lua_tonumber(L, 4);
|
||||
}
|
||||
if(beep.frequency < 20) beep.frequency = 20;
|
||||
if(beep.beepDuration < 0) beep.beepDuration = 0;
|
||||
if(beep.volume < 0) beep.volume = 0;
|
||||
if(beep.frequency > 20000) beep.frequency = 20000;
|
||||
if(beep.beepDuration > 5) beep.beepDuration = 5;
|
||||
if(beep.volume > 1) beep.volume = 1;
|
||||
nn_beepComputerMorse(luaArch_from(L)->computer, beep);
|
||||
return 0;
|
||||
}
|
||||
nn_Beep beep = {.frequency = 1000, .duration = 1, .volume = 1};
|
||||
if(lua_isnumber(L, 1)) {
|
||||
beep.frequency = lua_tonumber(L, 1);
|
||||
}
|
||||
if(lua_isnumber(L, 2)) {
|
||||
beep.duration = lua_tonumber(L, 2);
|
||||
}
|
||||
if(lua_isnumber(L, 3)) {
|
||||
beep.volume = lua_tonumber(L, 3);
|
||||
}
|
||||
if(beep.frequency < 20) beep.frequency = 20;
|
||||
if(beep.duration < 0) beep.duration = 0;
|
||||
if(beep.volume < 0) beep.volume = 0;
|
||||
if(beep.frequency > 20000) beep.frequency = 20000;
|
||||
if(beep.duration > 5) beep.duration = 5;
|
||||
if(beep.volume > 1) beep.volume = 1;
|
||||
nn_beepComputer(luaArch_from(L)->computer, beep);
|
||||
nn_addIdleTime(luaArch_from(L)->computer, beep.duration);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaArch_computer_freeMemory(lua_State *L) {
|
||||
lua_pushinteger(L, nn_getFreeMemory(luaArch_from(L)->computer));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_computer_totalMemory(lua_State *L) {
|
||||
lua_pushinteger(L, nn_getTotalMemory(luaArch_from(L)->computer));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_computer_uptime(lua_State *L) {
|
||||
lua_pushnumber(L, nn_getUptime(luaArch_from(L)->computer));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_computer_address(lua_State *L) {
|
||||
const char *addr = nn_getComputerAddress(luaArch_from(L)->computer);
|
||||
lua_pushstring(L, addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_computer_tmpAddress(lua_State *L) {
|
||||
const char *addr = nn_getTmpAddress(luaArch_from(L)->computer);
|
||||
if(addr == NULL) lua_pushnil(L);
|
||||
else lua_pushstring(L, addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_computer_users(lua_State *L) {
|
||||
nn_Computer *c = luaArch_from(L)->computer;
|
||||
size_t userc = 0;
|
||||
while(1) {
|
||||
const char *user = nn_getUser(c, userc);
|
||||
if(user == NULL) break;
|
||||
lua_pushstring(L, user);
|
||||
userc++;
|
||||
}
|
||||
return userc;
|
||||
}
|
||||
|
||||
static int luaArch_computer_addUser(lua_State *L) {
|
||||
nn_Computer *c = luaArch_from(L)->computer;
|
||||
const char *user = luaL_checkstring(L, 1);
|
||||
nn_Exit err = nn_addUser(c, user);
|
||||
if(err) {
|
||||
nn_setErrorFromExit(c, err);
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, nn_getError(c));
|
||||
return 2;
|
||||
}
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_computer_removeUser(lua_State *L) {
|
||||
nn_Computer *c = luaArch_from(L)->computer;
|
||||
const char *user = luaL_checkstring(L, 1);
|
||||
lua_pushboolean(L, nn_removeUser(c, user));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_computer_energy(lua_State *L) {
|
||||
lua_pushnumber(L, nn_getEnergy(luaArch_from(L)->computer));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_computer_maxEnergy(lua_State *L) {
|
||||
lua_pushnumber(L, nn_getTotalEnergy(luaArch_from(L)->computer));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_computer_getArchitecture(lua_State *L) {
|
||||
lua_pushstring(L, nn_getArchitecture(luaArch_from(L)->computer).name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_computer_setArchitecture(lua_State *L) {
|
||||
nn_Computer *c = luaArch_from(L)->computer;
|
||||
const char *archname = luaL_checkstring(L, 1);
|
||||
nn_Architecture arch = nn_findSupportedArchitecture(c, archname);
|
||||
if(arch.name == NULL) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "unknown architecture");
|
||||
return 2;
|
||||
}
|
||||
nn_setComputerState(c, NN_CHARCH);
|
||||
nn_setDesiredArchitecture(c, &arch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaArch_computer_getArchitectures(lua_State *L) {
|
||||
nn_Computer *c = luaArch_from(L)->computer;
|
||||
size_t len;
|
||||
const nn_Architecture *arch = nn_getSupportedArchitectures(c, &len);
|
||||
lua_createtable(L, len, 0);
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
lua_pushstring(L, arch[i].name);
|
||||
lua_seti(L, -2, i+1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_computer_shutdown(lua_State *L) {
|
||||
nn_Computer *c = luaArch_from(L)->computer;
|
||||
bool restart = lua_toboolean(L, 1);
|
||||
nn_setComputerState(c, restart ? NN_RESTART : NN_POWEROFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaArch_computer_isOverused(lua_State *L) {
|
||||
nn_Computer *c = luaArch_from(L)->computer;
|
||||
lua_pushboolean(L, nn_componentsOverused(c));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_computer_isIdle(lua_State *L) {
|
||||
nn_Computer *c = luaArch_from(L)->computer;
|
||||
lua_pushboolean(L, nn_isComputerIdle(c));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_computer_pushSignal(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
nn_Computer *c = arch->computer;
|
||||
size_t signalCount = lua_gettop(L);
|
||||
nn_Exit err;
|
||||
for(int i = 1; i <= signalCount; i++) {
|
||||
err = luaArch_luaToNN(arch, L, i);
|
||||
if(err) {
|
||||
nn_setErrorFromExit(c, err);
|
||||
luaL_error(L, "%s", nn_getError(c));
|
||||
}
|
||||
}
|
||||
err = nn_pushSignal(c, signalCount);
|
||||
if(err) {
|
||||
nn_setErrorFromExit(c, err);
|
||||
luaL_error(L, "%s", nn_getError(c));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaArch_computer_popSignal(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
nn_Computer *c = arch->computer;
|
||||
// no signals queued
|
||||
if(nn_countSignals(c) == 0) return 0;
|
||||
nn_clearstack(c);
|
||||
size_t signalCount;
|
||||
nn_Exit err = nn_popSignal(c, &signalCount);
|
||||
if(err) goto fail;
|
||||
for(size_t i = 0; i < signalCount; i++) {
|
||||
luaArch_nnToLua(arch, L, i);
|
||||
}
|
||||
nn_clearstack(c);
|
||||
return signalCount;
|
||||
fail:
|
||||
nn_setErrorFromExit(c, err);
|
||||
luaL_error(L, "%s", nn_getError(c));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaArch_computer_getDeviceInfo(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
nn_Computer *C = arch->computer;
|
||||
lua_createtable(L, 0, 0);
|
||||
for(size_t i = 0;; i++) {
|
||||
const char *devAddr = nn_deviceInfoAt(C, i);
|
||||
if(devAddr == NULL) break;
|
||||
size_t len;
|
||||
const nn_DeviceField *fields = nn_getDeviceInfo(C, i, &len);
|
||||
lua_pushstring(L, devAddr);
|
||||
lua_createtable(L, 0, len);
|
||||
for(size_t j = 0; j < len; j++) {
|
||||
lua_pushstring(L, fields[j].name);
|
||||
lua_pushstring(L, fields[j].value);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_component_list(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
lua_createtable(L, 64, 0);
|
||||
size_t len = nn_countComponents(arch->computer);
|
||||
if(len == 0) {
|
||||
lua_createtable(L, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
NN_VLA(const char *, comps, len);
|
||||
nn_getComponents(arch->computer, comps);
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
nn_Component *c = nn_getComponent(arch->computer, comps[i]);
|
||||
if(c != NULL) {
|
||||
lua_pushstring(L, nn_getComponentType(nn_getComponent(arch->computer, comps[i])));
|
||||
lua_setfield(L, -2, comps[i]);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_component_invoke(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
const char *address = luaL_checkstring(L, 1);
|
||||
const char *method = luaL_checkstring(L, 2);
|
||||
size_t argc = lua_gettop(L);
|
||||
|
||||
nn_clearstack(arch->computer);
|
||||
for(size_t i = 3; i <= argc; i++) {
|
||||
luaArch_luaToNN(arch, L, i);
|
||||
}
|
||||
nn_Exit err = nn_invokeComponent(arch->computer, address, method);
|
||||
if(err != NN_OK) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, nn_getError(arch->computer));
|
||||
return 2;
|
||||
}
|
||||
size_t retc = nn_getstacksize(arch->computer);
|
||||
for(size_t i = 0; i < retc; i++) {
|
||||
luaArch_nnToLua(arch, L, i);
|
||||
}
|
||||
nn_clearstack(arch->computer);
|
||||
return retc;
|
||||
}
|
||||
|
||||
static int luaArch_component_type(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
const char *address = luaL_checkstring(L, 1);
|
||||
|
||||
nn_Component *c = nn_getComponent(arch->computer, address);
|
||||
if(c == NULL) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "no such component");
|
||||
return 2;
|
||||
}
|
||||
lua_pushstring(L, nn_getComponentType(c));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_component_doc(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
const char *address = luaL_checkstring(L, 1);
|
||||
const char *method = luaL_checkstring(L, 2);
|
||||
|
||||
nn_Component *c = nn_getComponent(arch->computer, address);
|
||||
if(c == NULL) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "no such component");
|
||||
return 2;
|
||||
}
|
||||
const char *doc = nn_getComponentDoc(c, method);
|
||||
if(doc == NULL) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "no such method");
|
||||
return 2;
|
||||
}
|
||||
lua_pushstring(L, doc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_component_getMethodFlags(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
const char *address = luaL_checkstring(L, 1);
|
||||
const char *method = luaL_checkstring(L, 2);
|
||||
|
||||
nn_Component *c = nn_getComponent(arch->computer, address);
|
||||
if(c == NULL) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "no such component");
|
||||
return 2;
|
||||
}
|
||||
nn_MethodFlags f = nn_getComponentMethodFlags(c, method);
|
||||
lua_createtable(L, 0, 3);
|
||||
lua_pushboolean(L, (f & NN_DIRECT) != 0);
|
||||
lua_setfield(L, -2, "direct");
|
||||
lua_pushboolean(L, (f & NN_GETTER) != 0);
|
||||
lua_setfield(L, -2, "getter");
|
||||
lua_pushboolean(L, (f & NN_SETTER) != 0);
|
||||
lua_setfield(L, -2, "setter");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_component_slot(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
const char *address = luaL_checkstring(L, 1);
|
||||
|
||||
if(nn_getComponent(arch->computer, address) == NULL) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "no such component");
|
||||
return 2;
|
||||
}
|
||||
lua_pushinteger(L, nn_getComponentSlot(arch->computer, address));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_component_methods(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
const char *address = luaL_checkstring(L, 1);
|
||||
|
||||
nn_Component *c = nn_getComponent(arch->computer, address);
|
||||
|
||||
if(c == NULL) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "no such component");
|
||||
return 2;
|
||||
}
|
||||
size_t methodLen = nn_countComponentMethods(c);
|
||||
if(methodLen == 0) {
|
||||
lua_createtable(L, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
NN_VLA(const char *, methods, methodLen);
|
||||
nn_getComponentMethods(c, methods, &methodLen);
|
||||
lua_createtable(L, 0, methodLen);
|
||||
for(size_t i = 0; i < methodLen; i++) {
|
||||
nn_MethodFlags flags = nn_getComponentMethodFlags(c, methods[i]);
|
||||
if(flags & NN_FIELD_MASK) continue; // skip
|
||||
|
||||
lua_pushboolean(L, (flags & NN_DIRECT) != 0);
|
||||
lua_setfield(L, -2, methods[i]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_component_fields(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
const char *address = luaL_checkstring(L, 1);
|
||||
|
||||
nn_Component *c = nn_getComponent(arch->computer, address);
|
||||
|
||||
if(c == NULL) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "no such component");
|
||||
return 2;
|
||||
}
|
||||
size_t methodLen = nn_countComponentMethods(c);
|
||||
if(methodLen == 0) {
|
||||
lua_createtable(L, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
// const char *methods[methodLen];
|
||||
NN_VLA(const char *, methods, methodLen);
|
||||
nn_getComponentMethods(c, methods, &methodLen);
|
||||
lua_createtable(L, 0, methodLen);
|
||||
for(size_t i = 0; i < methodLen; i++) {
|
||||
nn_MethodFlags flags = nn_getComponentMethodFlags(c, methods[i]);
|
||||
if((flags & NN_FIELD_MASK) == 0) continue; // skip
|
||||
|
||||
lua_createtable(L, 0, 3);
|
||||
lua_pushboolean(L, (flags & NN_DIRECT) != 0);
|
||||
lua_setfield(L, -2, "direct");
|
||||
lua_pushboolean(L, (flags & NN_GETTER) != 0);
|
||||
lua_setfield(L, -2, "getter");
|
||||
lua_pushboolean(L, (flags & NN_SETTER) != 0);
|
||||
lua_setfield(L, -2, "setter");
|
||||
lua_setfield(L, -2, methods[i]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_unicode_char(lua_State *L) {
|
||||
size_t argc = lua_gettop(L);
|
||||
size_t len = 0;
|
||||
for(int i = 1; i <= argc; i++) {
|
||||
nn_codepoint codepoint = lua_tointeger(L, i);
|
||||
size_t size = nn_unicode_codepointSize(codepoint);
|
||||
if(size == 0) luaL_error(L, "codepoint #%d out of range", i);
|
||||
len += size;
|
||||
}
|
||||
nn_Context *ctx = nn_getComputerContext(luaArch_from(L)->computer);
|
||||
char *buf = nn_alloc(ctx, len);
|
||||
size_t buflen = len;
|
||||
len = 0;
|
||||
for(int i = 1; i <= argc; i++) {
|
||||
nn_codepoint codepoint = lua_tointeger(L, i);
|
||||
size_t size = nn_unicode_codepointToChar(buf + len, codepoint);
|
||||
len += size;
|
||||
}
|
||||
lua_pushlstring(L, buf, len);
|
||||
nn_free(ctx, buf, buflen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_unicode_len(lua_State *L) {
|
||||
size_t len;
|
||||
const char *s = lua_tolstring(L, 1, &len);
|
||||
len = nn_unicode_lenPermissive(s, len);
|
||||
lua_pushinteger(L, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_unicode_sub(lua_State *L) {
|
||||
size_t slen;
|
||||
const char *s = lua_tolstring(L, 1, &slen);
|
||||
if(lua_gettop(L) < 2) lua_pushinteger(L, 1);
|
||||
if(lua_gettop(L) < 3) lua_pushinteger(L, -1);
|
||||
|
||||
size_t len = nn_unicode_lenPermissive(s, slen);
|
||||
|
||||
// OpenOS does this...
|
||||
if(len == 0) {
|
||||
lua_pushstring(L, "");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int start = lua_tointeger(L, 2);
|
||||
int end = lua_tointeger(L, 3);
|
||||
|
||||
if(end == 0) {
|
||||
lua_pushstring(L, "");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(start > 0) start--;
|
||||
if(start < 0) start = len + start;
|
||||
if(end > 0) end--;
|
||||
if(end < 0) end = len + end;
|
||||
|
||||
if(start < 0) start = 0;
|
||||
if(start >= len) start = len-1;
|
||||
if(end < 0) end = 0;
|
||||
if(end >= len) end = len-1;
|
||||
|
||||
if(start > end) {
|
||||
lua_pushstring(L, "");
|
||||
return 1;
|
||||
}
|
||||
|
||||
nn_Context *ctx = nn_getComputerContext(luaArch_from(L)->computer);
|
||||
nn_codepoint *cp = nn_alloc(ctx, sizeof(*cp) * len);
|
||||
nn_unicode_codepointsPermissive(s, slen, cp);
|
||||
|
||||
size_t substrlen = nn_unicode_countBytes(cp + start, end - start + 1);
|
||||
char *buf = nn_alloc(ctx, substrlen);
|
||||
nn_unicode_writeBytes(buf, cp + start, end - start + 1);
|
||||
lua_pushlstring(L, buf, substrlen);
|
||||
nn_free(ctx, buf, substrlen);
|
||||
nn_free(ctx, cp, sizeof(*cp) * len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_unicode_wlen(lua_State *L) {
|
||||
size_t slen;
|
||||
const char *s = lua_tolstring(L, 1, &slen);
|
||||
size_t len = nn_unicode_wlenPermissive(s, slen);
|
||||
lua_pushinteger(L, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_unicode_wtrunc(lua_State *L) {
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_userdata_free(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
size_t user = (size_t)lua_touserdata(L, 1);
|
||||
nn_freeUserdata(arch->computer, user);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaArch_userdata_methods(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
size_t user = (size_t)lua_touserdata(L, 1);
|
||||
if(!nn_isUserdataValid(arch->computer, user)) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "no such userdata");
|
||||
return 2;
|
||||
}
|
||||
lua_createtable(L, 0, 0);
|
||||
size_t idx = 0;
|
||||
while(true) {
|
||||
nn_Method m;
|
||||
if(nn_getUserdataMethod(arch->computer, user, idx, &m)) break;
|
||||
idx++;
|
||||
if(m.name == NULL) continue;
|
||||
lua_pushstring(L, m.name);
|
||||
lua_createtable(L, 0, 4);
|
||||
|
||||
// the method data
|
||||
{
|
||||
lua_pushstring(L, "doc");
|
||||
if(m.doc == NULL) lua_pushnil(L); else lua_pushstring(L, m.doc);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "direct");
|
||||
lua_pushboolean(L, (m.flags & NN_DIRECT) != 0);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "getter");
|
||||
lua_pushboolean(L, (m.flags & NN_GETTER) != 0);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "setter");
|
||||
lua_pushboolean(L, (m.flags & NN_SETTER) != 0);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_userdata_invoke(lua_State *L) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
size_t user = (size_t)lua_touserdata(L, 1);
|
||||
if(!nn_isUserdataValid(arch->computer, user)) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "no such userdata");
|
||||
return 2;
|
||||
}
|
||||
const char *method = luaL_checkstring(L, 2);
|
||||
size_t argc = lua_gettop(L);
|
||||
|
||||
nn_clearstack(arch->computer);
|
||||
for(size_t i = 3; i <= argc; i++) {
|
||||
luaArch_luaToNN(arch, L, i);
|
||||
}
|
||||
nn_Exit err = nn_invokeUserdata(arch->computer, user, method);
|
||||
if(err != NN_OK) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, nn_getError(arch->computer));
|
||||
return 2;
|
||||
}
|
||||
size_t retc = nn_getstacksize(arch->computer);
|
||||
for(size_t i = 0; i < retc; i++) {
|
||||
luaArch_nnToLua(arch, L, i);
|
||||
}
|
||||
nn_clearstack(arch->computer);
|
||||
return retc;
|
||||
}
|
||||
|
||||
static void luaArch_loadEnv(lua_State *L) {
|
||||
lua_createtable(L, 0, 10);
|
||||
int computer = lua_gettop(L);
|
||||
lua_pushcfunction(L, luaArch_computer_beep);
|
||||
lua_setfield(L, computer, "beep");
|
||||
lua_pushcfunction(L, luaArch_computer_freeMemory);
|
||||
lua_setfield(L, computer, "freeMemory");
|
||||
lua_pushcfunction(L, luaArch_computer_totalMemory);
|
||||
lua_setfield(L, computer, "totalMemory");
|
||||
lua_pushcfunction(L, luaArch_computer_uptime);
|
||||
lua_setfield(L, computer, "uptime");
|
||||
lua_pushcfunction(L, luaArch_computer_address);
|
||||
lua_setfield(L, computer, "address");
|
||||
lua_pushcfunction(L, luaArch_computer_tmpAddress);
|
||||
lua_setfield(L, computer, "tmpAddress");
|
||||
lua_pushcfunction(L, luaArch_computer_users);
|
||||
lua_setfield(L, computer, "users");
|
||||
lua_pushcfunction(L, luaArch_computer_addUser);
|
||||
lua_setfield(L, computer, "addUser");
|
||||
lua_pushcfunction(L, luaArch_computer_removeUser);
|
||||
lua_setfield(L, computer, "removeUser");
|
||||
lua_pushcfunction(L, luaArch_computer_energy);
|
||||
lua_setfield(L, computer, "energy");
|
||||
lua_pushcfunction(L, luaArch_computer_maxEnergy);
|
||||
lua_setfield(L, computer, "maxEnergy");
|
||||
lua_pushcfunction(L, luaArch_computer_getArchitecture);
|
||||
lua_setfield(L, computer, "getArchitecture");
|
||||
lua_pushcfunction(L, luaArch_computer_getArchitectures);
|
||||
lua_setfield(L, computer, "getArchitectures");
|
||||
lua_pushcfunction(L, luaArch_computer_setArchitecture);
|
||||
lua_setfield(L, computer, "setArchitecture");
|
||||
lua_pushcfunction(L, luaArch_computer_shutdown);
|
||||
lua_setfield(L, computer, "shutdown");
|
||||
lua_pushcfunction(L, luaArch_computer_isOverused);
|
||||
lua_setfield(L, computer, "isOverused");
|
||||
lua_pushcfunction(L, luaArch_computer_isIdle);
|
||||
lua_setfield(L, computer, "isIdle");
|
||||
lua_pushcfunction(L, luaArch_computer_pushSignal);
|
||||
lua_setfield(L, computer, "pushSignal");
|
||||
lua_pushcfunction(L, luaArch_computer_popSignal);
|
||||
lua_setfield(L, computer, "popSignal");
|
||||
lua_pushcfunction(L, luaArch_computer_getDeviceInfo);
|
||||
lua_setfield(L, computer, "getDeviceInfo");
|
||||
lua_setglobal(L, "computer");
|
||||
|
||||
lua_createtable(L, 0, 10);
|
||||
int component = lua_gettop(L);
|
||||
lua_pushcfunction(L, luaArch_component_list);
|
||||
lua_setfield(L, component, "list");
|
||||
lua_pushcfunction(L, luaArch_component_invoke);
|
||||
lua_setfield(L, component, "invoke");
|
||||
lua_pushcfunction(L, luaArch_component_doc);
|
||||
lua_setfield(L, component, "doc");
|
||||
lua_pushcfunction(L, luaArch_component_type);
|
||||
lua_setfield(L, component, "type");
|
||||
lua_pushcfunction(L, luaArch_component_getMethodFlags);
|
||||
lua_setfield(L, component, "getMethodFlags");
|
||||
lua_pushcfunction(L, luaArch_component_slot);
|
||||
lua_setfield(L, component, "slot");
|
||||
lua_pushcfunction(L, luaArch_component_methods);
|
||||
lua_setfield(L, component, "methods");
|
||||
lua_pushcfunction(L, luaArch_component_fields);
|
||||
lua_setfield(L, component, "fields");
|
||||
lua_setglobal(L, "component");
|
||||
|
||||
lua_createtable(L, 0, 10);
|
||||
int unicode = lua_gettop(L);
|
||||
lua_pushcfunction(L, luaArch_unicode_char);
|
||||
lua_setfield(L, unicode, "char");
|
||||
lua_pushcfunction(L, luaArch_unicode_len);
|
||||
lua_setfield(L, unicode, "len");
|
||||
lua_pushcfunction(L, luaArch_unicode_sub);
|
||||
lua_setfield(L, unicode, "sub");
|
||||
lua_pushcfunction(L, luaArch_unicode_wlen);
|
||||
lua_setfield(L, unicode, "wlen");
|
||||
lua_pushcfunction(L, luaArch_unicode_wtrunc);
|
||||
lua_setfield(L, unicode, "wtrunc");
|
||||
lua_setglobal(L, "unicode");
|
||||
|
||||
lua_createtable(L, 0, 10);
|
||||
int userdata = lua_gettop(L);
|
||||
lua_pushcfunction(L, luaArch_userdata_free);
|
||||
lua_setfield(L, userdata, "free");
|
||||
lua_pushcfunction(L, luaArch_userdata_methods);
|
||||
lua_setfield(L, userdata, "methods");
|
||||
lua_pushcfunction(L, luaArch_userdata_invoke);
|
||||
lua_setfield(L, userdata, "invoke");
|
||||
lua_setglobal(L, "userdata");
|
||||
}
|
||||
|
||||
static nn_Exit luaArch_handler(nn_ArchitectureRequest *req) {
|
||||
nn_Computer *computer = req->computer;
|
||||
luaArch *arch = req->localState;
|
||||
nn_Context *ctx = nn_getComputerContext(computer);
|
||||
// the memory scale, used to give Lua extra memory in 64-bit systems
|
||||
// due to it also using more memory.
|
||||
double memScale = sizeof(void *) > 4 ? 1.8 : 1;
|
||||
switch(req->action) {
|
||||
case NN_ARCH_FREEMEM:
|
||||
req->freeMemory = arch->freeMem / memScale;
|
||||
return NN_OK;
|
||||
case NN_ARCH_INIT:
|
||||
// wrapped in a block to prevent L from leaking, because L is common in Lua code so it may be used by mistake
|
||||
{
|
||||
arch = nn_alloc(ctx, sizeof(*arch));
|
||||
arch->freeMem = nn_getTotalMemory(computer) * memScale;
|
||||
arch->computer = computer;
|
||||
#if LUA_VERSION_NUM >= 505L
|
||||
lua_State *L = lua_newstate(luaArch_alloc, arch, rand());
|
||||
#else
|
||||
lua_State *L = lua_newstate(luaArch_alloc, arch);
|
||||
#endif
|
||||
arch->L = L;
|
||||
req->localState = arch;
|
||||
luaL_openlibs(L);
|
||||
lua_pushlightuserdata(L, arch);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "archPtr");
|
||||
|
||||
luaArch_loadEnv(L);
|
||||
|
||||
lua_settop(L, 0);
|
||||
luaL_loadbufferx(L, luaArch_machineLua, strlen(luaArch_machineLua), "=machine.lua", "t");
|
||||
}
|
||||
return NN_OK;
|
||||
case NN_ARCH_DEINIT:
|
||||
lua_close(arch->L);
|
||||
nn_free(ctx, arch, sizeof(*arch));
|
||||
return NN_OK;
|
||||
case NN_ARCH_TICK:;
|
||||
lua_pushboolean(arch->L, req->synchronized);
|
||||
lua_setglobal(arch->L, "_SYNCED");
|
||||
lua_settop(arch->L, 1);
|
||||
int ret = 0;
|
||||
#if LUA_VERSION_NUM >= 504L
|
||||
int res = lua_resume(arch->L, NULL, 0, &ret);
|
||||
#else
|
||||
int res = lua_resume(arch->L, NULL, 0);
|
||||
ret = lua_gettop(arch->L);
|
||||
#endif
|
||||
//printf("res: %d\n", res);
|
||||
if(res == LUA_OK) {
|
||||
// halted, fuck
|
||||
lua_pop(arch->L, ret);
|
||||
nn_setError(computer, "machine halted");
|
||||
nn_setComputerState(computer, NN_CRASHED);
|
||||
return NN_OK;
|
||||
} else if(res != LUA_YIELD) {
|
||||
const char *s = lua_tostring(arch->L, -1);
|
||||
nn_setError(computer, s);
|
||||
nn_setComputerState(computer, NN_CRASHED);
|
||||
return NN_OK;
|
||||
}
|
||||
return NN_OK;
|
||||
case NN_ARCH_SERIALIZE:
|
||||
return nn_pushstring(computer, "lua stuff");
|
||||
case NN_ARCH_DESERIALIZE:
|
||||
// do nothing
|
||||
return NN_OK;
|
||||
}
|
||||
return NN_OK;
|
||||
}
|
||||
|
||||
nn_Architecture getLuaArch() {
|
||||
return (nn_Architecture) {
|
||||
.name = LUA_VERSION,
|
||||
.state = NULL,
|
||||
.handler = luaArch_handler,
|
||||
};
|
||||
}
|
||||
581
src/tla-static/machine.lua
Normal file
581
src/tla-static/machine.lua
Normal file
@@ -0,0 +1,581 @@
|
||||
-- The boot-up code of the Lua architecture.
|
||||
-- Extremely bad.
|
||||
-- Do not use in a serious context, you will be hacked.
|
||||
-- There is no sandboxing here.
|
||||
-- NOTE: we implemented method synchronization in here btw
|
||||
|
||||
os.exit = nil
|
||||
os.execute = nil
|
||||
|
||||
local sysyieldobj = {}
|
||||
local coroutine = coroutine
|
||||
|
||||
local resume, yield = coroutine.resume, coroutine.yield
|
||||
|
||||
local function sysyield()
|
||||
yield(sysyieldobj)
|
||||
end
|
||||
|
||||
function coroutine.resume(co, ...)
|
||||
while true do
|
||||
local t = {resume(co, ...)}
|
||||
if t[1] and rawequal(t[2], sysyieldobj) then
|
||||
yield(sysyieldobj)
|
||||
else
|
||||
return table.unpack(t)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function coroutine.wrap(f)
|
||||
local co = coroutine.create(f)
|
||||
return function(...)
|
||||
if coroutine.status(co) ~= "suspended" then return end
|
||||
local t = {coroutine.resume(co, ...)}
|
||||
if t[1] then
|
||||
return table.unpack(t, 2)
|
||||
end
|
||||
error(t[2], 2)
|
||||
end
|
||||
end
|
||||
|
||||
local clist, cinvoke, computer, component, print, unicode = component.list, component.invoke, computer, component, print, unicode
|
||||
debug.print = print
|
||||
debug.sysyield = sysyield
|
||||
|
||||
function component.list(ctype, exact)
|
||||
local list = clist()
|
||||
local desired = {}
|
||||
|
||||
for addr, type in pairs(list) do
|
||||
if ctype then
|
||||
if exact then
|
||||
if ctype == type then desired[addr] = type end
|
||||
else
|
||||
if string.find(type, ctype) then desired[addr] = type end
|
||||
end
|
||||
else
|
||||
desired[addr] = type
|
||||
end
|
||||
end
|
||||
|
||||
local key = nil
|
||||
setmetatable(desired, {__call = function()
|
||||
local val
|
||||
key, val = next(desired, key)
|
||||
return key, val
|
||||
end})
|
||||
return desired
|
||||
end
|
||||
|
||||
local syncedMethodStats
|
||||
|
||||
local function unsandboxValue(val)
|
||||
if type(val) == "table" then
|
||||
local meta = getmetatable(val)
|
||||
if meta then
|
||||
if type(meta.__userdata) == "userdata" then
|
||||
return meta.__userdata
|
||||
end
|
||||
end
|
||||
local nt = {}
|
||||
for sk, sv in pairs(val) do
|
||||
local k, v = unsandboxValue(sk), unsandboxValue(sv)
|
||||
if k ~= nil then nt[k] = v end
|
||||
end
|
||||
return nt
|
||||
end
|
||||
return val
|
||||
end
|
||||
|
||||
local function sandboxValue(val)
|
||||
if type(val) == "table" then
|
||||
local nt = {}
|
||||
for k, v in pairs(val) do
|
||||
local sk, sv = sandboxValue(k), sandboxValue(v)
|
||||
if sk ~= nil then nt[sk] = sv end
|
||||
end
|
||||
return nt
|
||||
end
|
||||
if type(val) == "userdata" then
|
||||
-- This matches how OC wraps it
|
||||
-- TODO: just make our own shi with fields and stuff
|
||||
-- like a component proxy, because this sucks
|
||||
local userMeta = {
|
||||
__gc = function()
|
||||
userdata.free(val)
|
||||
end,
|
||||
__userdata = val,
|
||||
}
|
||||
|
||||
local wrapped = {type = "userdata", userdata = val}
|
||||
for name, m in pairs(userdata.methods(val)) do
|
||||
wrapped[name] = {
|
||||
name = name,
|
||||
proxy = wrapped,
|
||||
}
|
||||
setmetatable(wrapped[name], {
|
||||
__tostring = function() return m.doc or "function" end,
|
||||
__call = function(_, ...)
|
||||
return userdata.invoke(val, name, ...)
|
||||
end,
|
||||
})
|
||||
end
|
||||
return setmetatable(wrapped, userMeta)
|
||||
end
|
||||
return val
|
||||
end
|
||||
|
||||
local function realInvoke(address, method, ...)
|
||||
local args = {...}
|
||||
for i=1,#args do args[i] = unsandboxValue(args[i]) end
|
||||
local t = {pcall(cinvoke, address, method, table.unpack(args))}
|
||||
if not _SYNCED and not os.getenv("NN_FAST") then
|
||||
if computer.energy() <= 0 then sysyield() end -- out of power
|
||||
if computer.isOverused() then sysyield() end -- overused
|
||||
if computer.isIdle() then sysyield() end -- machine idle
|
||||
end
|
||||
|
||||
if component.type(address) == os.getenv("NN_INVDBG") or string.find(os.getenv("NN_METDBG") or "", method, nil, true) then
|
||||
print("invoked", address, method, ...)
|
||||
print(string.format("got %d values", #t), table.unpack(t))
|
||||
end
|
||||
|
||||
for i=1,#t do t[i] = sandboxValue(t[i]) end
|
||||
|
||||
if t[1] then
|
||||
return table.unpack(t, 2)
|
||||
end
|
||||
return nil, t[2]
|
||||
end
|
||||
|
||||
function component.invoke(address, method, ...)
|
||||
if type(address) ~= "string" then return nil, "bad argument #1 (string expected)" end
|
||||
if type(method) ~= "string" then return nil, "bad argument #2 (string expected)" end
|
||||
if component.getMethodFlags(address, method).direct or os.getenv("NN_FAST") then
|
||||
return realInvoke(address, method, ...)
|
||||
else
|
||||
-- must sync
|
||||
syncedMethodStats = {address, method, ...}
|
||||
sysyield()
|
||||
local rets = syncedMethodStats
|
||||
syncedMethodStats = nil
|
||||
return table.unpack(rets)
|
||||
end
|
||||
end
|
||||
|
||||
local componentCallback = {
|
||||
__call = function(self, ...)
|
||||
return component.invoke(self.address, self.name, ...)
|
||||
end,
|
||||
__tostring = function(self)
|
||||
return component.doc(self.address, self.name) or "function"
|
||||
end,
|
||||
}
|
||||
|
||||
local componentProxy = {
|
||||
__index = function(self, key)
|
||||
if self.fields[key] and self.fields[key].getter then
|
||||
return component.invoke(self.address, key)
|
||||
end
|
||||
return rawget(self, key)
|
||||
end,
|
||||
__newindex = function(self, key, value)
|
||||
if self.fields[key] and self.fields[key].setter then
|
||||
return component.invoke(self.address, key, value)
|
||||
end
|
||||
rawset(self, key, value)
|
||||
end,
|
||||
__pairs = function(self)
|
||||
local reachedFields = false
|
||||
local key, val
|
||||
return function()
|
||||
if not reachedFields then
|
||||
key, val = next(self, key)
|
||||
if key == nil then reachedFields = true end
|
||||
end
|
||||
if reachedFields then
|
||||
key = next(self.fields, key)
|
||||
val = self[key]
|
||||
end
|
||||
return key, val
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
local proxyCache = setmetatable({}, {__mode = "v"})
|
||||
|
||||
function component.proxy(address)
|
||||
if proxyCache[address] then return proxyCache[address] end
|
||||
|
||||
local t, err = component.type(address)
|
||||
if not t then return nil, err end
|
||||
local slot, err = component.slot(address)
|
||||
if not slot then return nil, err end
|
||||
|
||||
local proxy = {address = address, type = t, slot = slot}
|
||||
proxy.fields, err = component.fields(address)
|
||||
if not proxy.fields then return nil, err end
|
||||
|
||||
local methods = component.methods(address)
|
||||
for name in pairs(methods) do
|
||||
proxy[name] = setmetatable({address=address,name=name}, componentCallback)
|
||||
end
|
||||
|
||||
setmetatable(proxy, componentProxy)
|
||||
proxyCache[address] = proxy
|
||||
return proxy
|
||||
end
|
||||
|
||||
function computer.getProgramLocations()
|
||||
return {}
|
||||
end
|
||||
|
||||
local shutdown, setArch = computer.shutdown, computer.setArchitecture
|
||||
|
||||
function computer.shutdown(...)
|
||||
shutdown(...)
|
||||
sysyield()
|
||||
end
|
||||
|
||||
function computer.setArchitecture(arch)
|
||||
if arch == computer.getArchitecture() then return end
|
||||
local ok, err = setArch(arch)
|
||||
sysyield()
|
||||
return ok, err
|
||||
end
|
||||
|
||||
function computer.pullSignal(timeout)
|
||||
timeout = timeout or math.huge
|
||||
timeout = math.max(timeout, 0.001)
|
||||
local deadline = computer.uptime() + timeout
|
||||
while true do
|
||||
if computer.uptime() >= deadline then return end
|
||||
local t = {computer.popSignal()}
|
||||
for i=1,#t do t[i] = unsandboxValue(t[i]) end
|
||||
if #t == 0 then
|
||||
sysyield()
|
||||
else
|
||||
return table.unpack(t)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
unicode.upper, unicode.lower = string.upper, string.lower
|
||||
|
||||
unicode.isWide = function(s)
|
||||
local c = unicode.sub(s, 1, 1)
|
||||
return unicode.wlen(c) > unicode.len(c)
|
||||
end
|
||||
|
||||
unicode.wtrunc = function(str,space)
|
||||
space = space - 1
|
||||
return unicode.sub(str, 1, space)
|
||||
end
|
||||
|
||||
unicode.reverse = string.reverse
|
||||
|
||||
unicode.charWidth = function(s)
|
||||
return 1
|
||||
end
|
||||
|
||||
unicode.sub = function(str, a, b)
|
||||
if not b then b = utf8.len(str) end
|
||||
if not a then a = 1 end
|
||||
-- a = math.max(a,1)
|
||||
if a < 0 then
|
||||
-- negative
|
||||
a = utf8.len(str) + a + 1
|
||||
end
|
||||
if b < 0 then
|
||||
b = utf8.len(str) + b + 1
|
||||
end
|
||||
if a > b then return "" end
|
||||
if b >= utf8.len(str) then b = #str else b = utf8.offset(str,b+1)-1 end
|
||||
if a > utf8.len(str) then return "" end
|
||||
a = utf8.offset(str,a)
|
||||
return str:sub(a,b)
|
||||
-- return str:sub(a, b)
|
||||
end
|
||||
|
||||
function checkArg(arg, val, ...)
|
||||
local t = {...}
|
||||
for i=1,#t do
|
||||
if type(val) == t[i] then return end
|
||||
end
|
||||
error("bad argument #" .. arg .. " (" .. table.concat(t, ", ") .. ") expected", 2)
|
||||
end
|
||||
|
||||
if os.getenv("NN_REPL") == "1" then
|
||||
while true do
|
||||
io.write("\x1b[34mlua>\x1b[0m ")
|
||||
io.flush()
|
||||
local l = io.read("l")
|
||||
if not l then break end
|
||||
local f, err = load("return " .. l, "=repl")
|
||||
if f then
|
||||
print(f())
|
||||
else
|
||||
f, err = load(l, "=repl")
|
||||
if f then f() else print(err) end
|
||||
end
|
||||
yield()
|
||||
end
|
||||
io.write("\n")
|
||||
print("exiting repl")
|
||||
end
|
||||
|
||||
-- Save on just a tiny smudgeon of RAM
|
||||
io = nil
|
||||
package = nil
|
||||
|
||||
local sandbox
|
||||
sandbox = {
|
||||
_VERSION = _VERSION,
|
||||
assert = assert,
|
||||
error = error,
|
||||
getmetatable = getmetatable,
|
||||
ipairs = ipairs,
|
||||
load = function(chunk, name, ty, env)
|
||||
return load(chunk, name, ty, env or sandbox)
|
||||
end,
|
||||
next = next,
|
||||
pairs = pairs,
|
||||
pcall = pcall,
|
||||
rawequal = rawequal,
|
||||
rawget = rawget,
|
||||
rawlen = rawlen,
|
||||
rawset = rawset,
|
||||
select = select,
|
||||
setmetatable = function(t, meta)
|
||||
if type(meta) == "table" then
|
||||
-- nope
|
||||
rawset(meta, "__gc", nil)
|
||||
end
|
||||
return setmetatable(t, meta)
|
||||
end,
|
||||
tonumber = tonumber,
|
||||
tostring = tostring,
|
||||
type = type,
|
||||
xpcall = xpcall,
|
||||
collectgarbage = function() collectgarbage("collect") end,
|
||||
|
||||
bit32 = bit32,
|
||||
|
||||
coroutine = {
|
||||
create = coroutine.create,
|
||||
resume = coroutine.resume,
|
||||
running = coroutine.running,
|
||||
status = coroutine.status,
|
||||
wrap = coroutine.wrap,
|
||||
yield = coroutine.yield,
|
||||
isyieldable = coroutine.isyieldable,
|
||||
},
|
||||
|
||||
debug = {
|
||||
getinfo = debug.getinfo,
|
||||
traceback = debug.traceback,
|
||||
getlocal = function(...) return (debug.getlocal(...)) end,
|
||||
getupvalue = function(...) return (debug.getupvalue(...)) end,
|
||||
print = debug.print,
|
||||
},
|
||||
|
||||
math = {
|
||||
abs = math.abs,
|
||||
acos = math.acos,
|
||||
asin = math.asin,
|
||||
atan = math.atan,
|
||||
atan2 = math.atan2,
|
||||
ceil = math.ceil,
|
||||
cos = math.cos,
|
||||
cosh = math.cosh,
|
||||
deg = math.deg,
|
||||
exp = math.exp,
|
||||
floor = math.floor,
|
||||
fmod = math.fmod,
|
||||
frexp = math.frexp,
|
||||
huge = math.huge,
|
||||
ldexp = math.ldexp,
|
||||
log = math.log,
|
||||
max = math.max,
|
||||
min = math.min,
|
||||
modf = math.modf,
|
||||
pi = math.pi,
|
||||
pow = math.pow,
|
||||
rad = math.rad,
|
||||
random = math.random,
|
||||
randomseed = math.randomseed,
|
||||
sin = math.sin,
|
||||
sinh = math.sinh,
|
||||
sqrt = math.sqrt,
|
||||
tan = math.tan,
|
||||
tanh = math.tanh,
|
||||
maxinteger = math.maxinteger,
|
||||
mininteger = math.mininteger,
|
||||
type = math.type,
|
||||
ult = math.ult,
|
||||
},
|
||||
|
||||
os = {
|
||||
clock = os.clock,
|
||||
date = function(a, b, ...)
|
||||
if type(a) == "number" then
|
||||
a = math.floor(a)
|
||||
end
|
||||
if type(b) == "number" then
|
||||
b = math.floor(b)
|
||||
end
|
||||
return os.date(a, b, ...)
|
||||
end,
|
||||
difftime = os.difftime,
|
||||
time = os.time,
|
||||
},
|
||||
|
||||
string = {
|
||||
byte = string.byte,
|
||||
char = string.char,
|
||||
dump = string.dump,
|
||||
find = string.find,
|
||||
format = string.format,
|
||||
gmatch = string.gmatch,
|
||||
gsub = string.gsub,
|
||||
len = string.len,
|
||||
lower = string.lower,
|
||||
match = string.match,
|
||||
rep = string.rep,
|
||||
reverse = string.reverse,
|
||||
sub = string.sub,
|
||||
upper = string.upper,
|
||||
pack = string.pack,
|
||||
unpack = string.unpack,
|
||||
packsize = string.packsize,
|
||||
},
|
||||
|
||||
table = {
|
||||
concat = table.concat,
|
||||
insert = table.insert,
|
||||
pack = table.pack,
|
||||
remove = table.remove,
|
||||
sort = table.sort,
|
||||
unpack = table.unpack,
|
||||
move = table.move,
|
||||
},
|
||||
|
||||
checkArg = checkArg,
|
||||
|
||||
component = {
|
||||
doc = component.doc,
|
||||
fields = component.fields,
|
||||
invoke = component.invoke,
|
||||
list = component.list,
|
||||
methods = component.methods,
|
||||
proxy = component.proxy,
|
||||
slot = component.slot,
|
||||
type = component.type,
|
||||
},
|
||||
|
||||
computer = {
|
||||
address = computer.address,
|
||||
addUser = computer.addUser,
|
||||
beep = computer.beep,
|
||||
energy = computer.energy,
|
||||
freeMemory = computer.freeMemory,
|
||||
getArchitectures = computer.getArchitectures,
|
||||
getArchitecture = computer.getArchitecture,
|
||||
getDeviceInfo = computer.getDeviceInfo,
|
||||
getProgramLocations = computer.getProgramLocations,
|
||||
isRobot = computer.isRobot,
|
||||
maxEnergy = computer.maxEnergy,
|
||||
pullSignal = computer.pullSignal,
|
||||
pushSignal = function(name, ...)
|
||||
checkArg(1, name, "string")
|
||||
local t = {...}
|
||||
for i=1,#t do
|
||||
local v = unsandboxValue(t[i])
|
||||
if type(v) == "userdata" then
|
||||
return nil, "userdata is forbidden"
|
||||
end
|
||||
t[i] = v
|
||||
end
|
||||
return computer.pushSignal(name, table.unpack(t))
|
||||
end,
|
||||
removeUser = computer.removeUser,
|
||||
setArchitecture = computer.setArchitecture,
|
||||
shutdown = computer.shutdown,
|
||||
tmpAddress = computer.tmpAddress,
|
||||
totalMemory = computer.totalMemory,
|
||||
uptime = computer.uptime,
|
||||
users = computer.users,
|
||||
},
|
||||
|
||||
unicode = {
|
||||
len = utf8.len,
|
||||
wlen = utf8.len, -- this can be very wrong.
|
||||
sub = function (str,a,b)
|
||||
if not b then b = utf8.len(str) end
|
||||
if not a then a = 1 end
|
||||
-- a = math.max(a,1)
|
||||
|
||||
if a < 0 then
|
||||
-- negative
|
||||
|
||||
a = utf8.len(str) + a + 1
|
||||
end
|
||||
|
||||
if b < 0 then
|
||||
b = utf8.len(str) + b + 1
|
||||
end
|
||||
|
||||
if a > b then return "" end
|
||||
|
||||
if b >= utf8.len(str) then b = #str else b = utf8.offset(str,b+1)-1 end
|
||||
|
||||
if a > utf8.len(str) then return "" end
|
||||
a = utf8.offset(str,a)
|
||||
|
||||
return str:sub(a,b)
|
||||
-- return str:sub(a, b)
|
||||
end,
|
||||
char = utf8.char,
|
||||
wtrunc = function (str,space)
|
||||
space = space - 1
|
||||
return str:sub(1,(space >= utf8.len(str)) and (#str) or (utf8.offset(str,space+1)-1))
|
||||
end,
|
||||
upper = string.upper, -- these are accurate... sometimes
|
||||
lower = string.lower,
|
||||
isWide = function ()
|
||||
return false
|
||||
end
|
||||
},
|
||||
|
||||
utf8 = utf8,
|
||||
}
|
||||
sandbox._G = sandbox
|
||||
|
||||
local eeprom = component.list("eeprom", true)()
|
||||
assert(eeprom, "missing firmware")
|
||||
|
||||
-- this would automatically reboot us if it needs to be a different architecture
|
||||
local arch = component.invoke(eeprom, "getArchitecture")
|
||||
if arch then computer.setArchitecture(arch) end
|
||||
|
||||
local code = assert(component.invoke(eeprom, "get"))
|
||||
local f = assert(load(code, "=bios", nil, sandbox))
|
||||
local thread = coroutine.create(f)
|
||||
|
||||
while true do
|
||||
collectgarbage("collect")
|
||||
if _SYNCED then
|
||||
if syncedMethodStats then
|
||||
--debug.print("calling synced method")
|
||||
syncedMethodStats = {realInvoke(table.unpack(syncedMethodStats))}
|
||||
end
|
||||
else
|
||||
local ok, err = resume(thread)
|
||||
if not ok then
|
||||
print(debug.traceback(thread, err))
|
||||
end
|
||||
if coroutine.status(thread) == "dead" then break end
|
||||
end
|
||||
yield()
|
||||
end
|
||||
2437
src/tla-static/neonucleus.h
Normal file
2437
src/tla-static/neonucleus.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user