getLuaArch() (hell)

This commit is contained in:
2026-05-28 21:52:10 -03:00
parent a80b3f1ebe
commit cca07e5557
13 changed files with 4012 additions and 2 deletions

4
.gitmodules vendored
View File

@@ -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

View File

@@ -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 $@

View File

@@ -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();
}

View File

@@ -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");
}

View File

@@ -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
View File

@@ -0,0 +1,3 @@
#include "neonucleus.h"
nn_Architecture getLuaArch();

View File

@@ -3,6 +3,7 @@
#include "neonucleus.h"
#include "ncomplib.h"
#include <jni.h>
#include "luaarch.h"
#include "carbon.hpp"
@@ -175,4 +176,9 @@ JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1getCom
nn_Computer* nnPC = (nn_Computer*) Carbon::PointerBacked::GetPointer(env, computer);
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());
}

View File

@@ -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
View 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)

870
src/tla-static/luaarch.c Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff