Compare commits
17 Commits
287e773aa5
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 9eae8e8fd2 | |||
| 80e6682114 | |||
| f2db7450ba | |||
| f71c5493ed | |||
| f7b7605408 | |||
| cfc8abe05c | |||
| 52f335ef5e | |||
| 32e03de3ed | |||
| 8c1fc42867 | |||
| 322aa2178c | |||
| 90506db9a1 | |||
| 7038bebd3d | |||
| 3c904fb657 | |||
| 4fe0701455 | |||
| cca07e5557 | |||
| a80b3f1ebe | |||
| edd4fbed7b |
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,3 +1,7 @@
|
|||||||
[submodule "NeoNucleus"]
|
[submodule "NeoNucleus"]
|
||||||
path = NeoNucleus
|
path = NeoNucleus
|
||||||
url = https://gitea.codersquack.nl/NeoFlock/NeoNucleus.git
|
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
|
||||||
|
|||||||
12
Makefile
12
Makefile
@@ -1,23 +1,25 @@
|
|||||||
CC=gcc
|
CC=gcc
|
||||||
CXX=g++
|
CXX=g++
|
||||||
CFLAGS=-Wall -Wextra
|
CFLAGS=-Wall -Wextra
|
||||||
TARGET=libneonucleusjni.so
|
LD_FLAGS=
|
||||||
|
TARGET=libcarbon.so
|
||||||
|
|
||||||
BASE_PATH=./src/main/org/neoflock/NeoNucleus
|
BASE_PATH=./src/main/org/neoflock/NeoNucleus
|
||||||
JAVA_HOME=/usr/lib/jvm/java-25-openjdk/
|
JAVA_HOME=/usr/lib/jvm/java-25-openjdk/
|
||||||
BASE_NPATH=./src/native/
|
BASE_NPATH=./src/native/
|
||||||
JAVA_SRCS = $(wildcard ./src/main/org/neoflock/NeoNucleus/*.java)
|
JAVA_SRCS = $(wildcard ./src/main/org/neoflock/NeoNucleus/*.java)
|
||||||
JAVA_CLASSES = $(wildcard ./src/main/org/neoflock/NeoNucleus/*.class)
|
JAVA_CLASSES = $(wildcard ./src/main/org/neoflock/NeoNucleus/*.class)
|
||||||
|
TLA_PATH=./src/tla-static
|
||||||
|
|
||||||
CPP_SRCS = $(wildcard ${BASE_NPATH}/*.cpp)
|
CPP_SRCS = $(wildcard ${BASE_NPATH}/*.cpp)
|
||||||
OBJS = $(CPP_SRCS:.cpp=.o)
|
OBJS = $(CPP_SRCS:.cpp=.o)
|
||||||
NATIVE_NAME=main
|
NATIVE_NAME=main
|
||||||
|
|
||||||
all: $(TARGET)
|
all: java $(TARGET)
|
||||||
|
|
||||||
$(TARGET): $(OBJS)
|
$(TARGET): $(OBJS)
|
||||||
g++ -shared -o ${BASE_NPATH}/$(TARGET) \
|
$(CXX) -shared -o ${BASE_NPATH}/$(TARGET) \
|
||||||
$(OBJS) ${BASE_NPATH}/libneonucleus.a -lc
|
$(OBJS) ${BASE_NPATH}/libneonucleus.a $(TLA_PATH)/libtla.a $(TLA_PATH)/foreign/lua54/liblua.a -lc $(LD_FLAGS)
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
$(CXX) -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux $(CFLAGS) \
|
$(CXX) -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux $(CFLAGS) \
|
||||||
$< -o $@
|
$< -o $@
|
||||||
@@ -30,6 +32,6 @@ run: all
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm ${JAVA_CLASSES}
|
rm ${JAVA_CLASSES}
|
||||||
rm $(OBJS) $(TARGET)
|
rm $(OBJS) $(BASE_NPATH)/$(TARGET)
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
Submodule NeoNucleus updated: 3b04fd45c7...7c086f6b8e
@@ -1,4 +1,4 @@
|
|||||||
# Carbon Hydrogen
|
# Carbon Hydrogen
|
||||||
NeoNucleus JNI bindings.
|
NeoNucleus JNI bindings.
|
||||||
### Dev Setup Notes
|
### Dev Setup Notes
|
||||||
Java expects libneonucleusjni.so on the src/native directory. This is the default unless you're not using the Makefile.
|
Java expects libcarbon.so on the src/native directory. This is the default unless you're not using the Makefile. Make *sure* to build NeoNucleus with `make lib MODE=release`, and place the libneonucleus.a on src/native. The same applies for TLA (testLuaArch), which must be built with `make MODE=release`.
|
||||||
@@ -4,7 +4,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
public class NativeBindings {
|
public class NativeBindings {
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("neonucleusjni");
|
System.loadLibrary("carbon");
|
||||||
}
|
}
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
//nn_Context ctx = nn_initContext();
|
//nn_Context ctx = nn_initContext();
|
||||||
@@ -24,19 +24,26 @@ public class NativeBindings {
|
|||||||
eeprom.free();
|
eeprom.free();
|
||||||
nn_Computer computer = nn_createComputer(universe, UUID.randomUUID().toString(), 4096, 100, 100);
|
nn_Computer computer = nn_createComputer(universe, UUID.randomUUID().toString(), 4096, 100, 100);
|
||||||
nn_setCallBudget(computer, 0);
|
nn_setCallBudget(computer, 0);
|
||||||
|
System.out.println("Arch: " + arch.name);
|
||||||
nn_setArchitecture(computer, arch);
|
nn_setArchitecture(computer, arch);
|
||||||
|
System.out.println("past setArch");
|
||||||
nn_addSupportedArchitecture(computer, arch);
|
nn_addSupportedArchitecture(computer, arch);
|
||||||
|
System.out.println("past addSupported");
|
||||||
nn_mountComponent(computer, eepromCard, 0, false);
|
nn_mountComponent(computer, eepromCard, 0, false);
|
||||||
|
System.out.println("past mountComponent");
|
||||||
nn_Exit e = nn_tick(computer);
|
nn_Exit e = nn_tick(computer);
|
||||||
|
System.out.println("ticked");
|
||||||
if (e != nn_Exit.NN_OK) {
|
if (e != nn_Exit.NN_OK) {
|
||||||
System.out.println("NN tick error: " + nn_getError(computer));
|
System.out.println("NN tick error: " + nn_getError(computer));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
System.out.println("sync ticked");
|
||||||
e = nn_tickSynchronized(computer);
|
e = nn_tickSynchronized(computer);
|
||||||
if (e != nn_Exit.NN_OK) {
|
if (e != nn_Exit.NN_OK) {
|
||||||
System.out.println("NN synchronized tick error: " + nn_getError(computer));
|
System.out.println("NN synchronized tick error: " + nn_getError(computer));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
System.out.println("getting state");
|
||||||
nn_ComputerState state = nn_getComputerState(computer);
|
nn_ComputerState state = nn_getComputerState(computer);
|
||||||
if(state == nn_ComputerState.NN_POWEROFF) return;
|
if(state == nn_ComputerState.NN_POWEROFF) return;
|
||||||
if(state == nn_ComputerState.NN_CRASHED) {
|
if(state == nn_ComputerState.NN_CRASHED) {
|
||||||
|
|||||||
@@ -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
|
public nn_Architecture(String name, Function<String, Integer> handler) { // string is a placeholder; please fix
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.handler = handler;
|
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
|
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 allocate();
|
||||||
public native boolean free();
|
public native boolean free();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/main/org/neoflock/NeoNucleus/nn_Beep.java
Normal file
13
src/main/org/neoflock/NeoNucleus/nn_Beep.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package org.neoflock.NeoNucleus;
|
||||||
|
|
||||||
|
public class nn_Beep {
|
||||||
|
public final double frequency;
|
||||||
|
public final double duration;
|
||||||
|
public final double volume;
|
||||||
|
|
||||||
|
public nn_Beep(double frequency, double duration, double volume) {
|
||||||
|
this.frequency = frequency;
|
||||||
|
this.duration = duration;
|
||||||
|
this.volume = volume;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
package org.neoflock.NeoNucleus;
|
package org.neoflock.NeoNucleus;
|
||||||
|
|
||||||
public class nn_Computer {
|
public class nn_Computer extends PointerBackedClass {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
package org.neoflock.NeoNucleus;
|
package org.neoflock.NeoNucleus;
|
||||||
|
|
||||||
public class nn_Environment {
|
import java.util.function.Consumer;
|
||||||
public String a;
|
|
||||||
// TODO
|
// we're gonna start needing java-side userdatas soon....
|
||||||
|
public class nn_Environment extends PointerBackedClass {
|
||||||
|
public final Consumer<nn_EnvironmentRequest> handler;
|
||||||
|
private nn_Environment(Consumer<nn_EnvironmentRequest> handler) {
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/main/org/neoflock/NeoNucleus/nn_EnvironmentAction.java
Normal file
10
src/main/org/neoflock/NeoNucleus/nn_EnvironmentAction.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package org.neoflock.NeoNucleus;
|
||||||
|
|
||||||
|
public enum nn_EnvironmentAction {
|
||||||
|
NN_ENV_DRAWENERGY,
|
||||||
|
NN_ENV_POWERON,
|
||||||
|
NN_ENV_POWEROFF,
|
||||||
|
NN_ENV_CRASHED,
|
||||||
|
NN_ENV_BEEP,
|
||||||
|
NN_ENV_BEEPMORSE,
|
||||||
|
}
|
||||||
21
src/main/org/neoflock/NeoNucleus/nn_EnvironmentRequest.java
Normal file
21
src/main/org/neoflock/NeoNucleus/nn_EnvironmentRequest.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package org.neoflock.NeoNucleus;
|
||||||
|
|
||||||
|
public final class nn_EnvironmentRequest extends PointerBackedClass {
|
||||||
|
public final nn_Computer computer;
|
||||||
|
public final nn_EnvironmentAction action;
|
||||||
|
|
||||||
|
// these three props below can be nullable
|
||||||
|
public final Double energy;
|
||||||
|
public final nn_Beep beep;
|
||||||
|
public final nn_MorseBeep morseBeep;
|
||||||
|
private nn_EnvironmentRequest(
|
||||||
|
nn_Computer computer, nn_EnvironmentAction action,
|
||||||
|
Double energy, nn_Beep beep, nn_MorseBeep morseBeep
|
||||||
|
) {
|
||||||
|
this.computer = computer;
|
||||||
|
this.action = action;
|
||||||
|
this.energy = energy;
|
||||||
|
this.beep = beep;
|
||||||
|
this.morseBeep = morseBeep;
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/main/org/neoflock/NeoNucleus/nn_MorseBeep.java
Normal file
14
src/main/org/neoflock/NeoNucleus/nn_MorseBeep.java
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package org.neoflock.NeoNucleus;
|
||||||
|
|
||||||
|
public class nn_MorseBeep {
|
||||||
|
public final String pattern;
|
||||||
|
public final double frequency;
|
||||||
|
public final double volume;
|
||||||
|
|
||||||
|
public nn_MorseBeep(String pattern, double frequency, double volume) {
|
||||||
|
this.pattern = pattern;
|
||||||
|
this.frequency = frequency;
|
||||||
|
this.volume = volume;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,35 @@
|
|||||||
#include "carbon.hpp"
|
#include "carbon.hpp"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
// redefine it here with the impl
|
// redefine it here with the impl
|
||||||
// theres probably a better way to do this
|
// theres probably a better way to do this
|
||||||
|
#define CARBON_JNI_EXCEPTION_CHECK() if (env->ExceptionCheck()) return NULL;
|
||||||
#define CARBON_EXCEPTION_FUNC(fname, classpath) jint fname(JNIEnv* env, const char* message) { return THROW_EXCEPTION(classpath, message); }
|
#define CARBON_EXCEPTION_FUNC(fname, classpath) jint fname(JNIEnv* env, const char* message) { return THROW_EXCEPTION(classpath, message); }
|
||||||
#define CARBON_MAP_TO_NN_EXIT(enumcase) case enumcase:\
|
#define CARBON_MAP_TO_NN_EXIT(enumcase) case enumcase: {\
|
||||||
jfieldID id = env->GetFieldID(clazz, #enumcase, "Lorg.neoflock.NeoNucleus.nn_Exit;");\
|
jfieldID id = env->GetStaticFieldID(clazz, #enumcase, "Lorg/neoflock/NeoNucleus/nn_Exit;");\
|
||||||
return env->GetStaticObjectField(clazz, id);
|
CARBON_JNI_EXCEPTION_CHECK();\
|
||||||
#define CARBON_MAP_TO_NN_COMPUTERSTATE(enumcase) case enumcase:\
|
jobject obj = env->GetStaticObjectField(clazz, id);\
|
||||||
jfieldID id = env->GetFieldID(clazz, #enumcase, "Lorg.neoflock.NeoNucleus.nn_ComputerState;");\
|
CARBON_JNI_EXCEPTION_CHECK();\
|
||||||
return env->GetStaticObjectField(clazz, id);
|
return obj;\
|
||||||
|
}
|
||||||
|
#define CARBON_MAP_TO_NN_COMPUTERSTATE(enumcase) case enumcase: {\
|
||||||
|
jfieldID id = env->GetFieldID(clazz, #enumcase, "Lorg/neoflock/NeoNucleus/nn_ComputerState;");\
|
||||||
|
CARBON_JNI_EXCEPTION_CHECK()\
|
||||||
|
return env->GetStaticObjectField(clazz, id);\
|
||||||
|
}
|
||||||
|
// EM = enum mapper
|
||||||
|
#define CARBON_EM_DEFINE(classpath) const char* enumClassPath = classpath;\
|
||||||
|
jclass clazz = env->FindClass(enumClassPath);\
|
||||||
|
CARBON_JNI_EXCEPTION_CHECK();
|
||||||
|
#define CARBON_EM_SWITCH(block) switch (a) { block }
|
||||||
|
#define CARBON_EM_CASE(ecase) case ecase: {\
|
||||||
|
jfieldID id = env->GetFieldID(clazz, #ecase, enumClassPath);\
|
||||||
|
CARBON_JNI_EXCEPTION_CHECK();\
|
||||||
|
return env->GetStaticObjectField(clazz, id);\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CARBON_CLASSPATH(jvtype) "Lorg/neoflock/NeoNucleus/" #jvtype
|
||||||
|
#define CARBON_EM_FROM(jvtype) return Carbon_FromEnum<jvtype>(env, CARBON_CLASSPATH(jvtype), a);
|
||||||
|
|
||||||
// codename for NN JNI is Carbon because i needed something better than NN JNI
|
// codename for NN JNI is Carbon because i needed something better than NN JNI
|
||||||
bool Carbon::PointerBacked::SetPointer(JNIEnv * env, jobject obj, void* ptr) {
|
bool Carbon::PointerBacked::SetPointer(JNIEnv * env, jobject obj, void* ptr) {
|
||||||
@@ -64,6 +86,7 @@ nn_Exit Carbon::JNIComponentHandler(nn_ComponentRequest* request) {
|
|||||||
}
|
}
|
||||||
jobject Carbon::Map::To_nn_Exit(JNIEnv* env, nn_Exit a) {
|
jobject Carbon::Map::To_nn_Exit(JNIEnv* env, nn_Exit a) {
|
||||||
jclass clazz = env->FindClass("org/neoflock/NeoNucleus/nn_Exit");
|
jclass clazz = env->FindClass("org/neoflock/NeoNucleus/nn_Exit");
|
||||||
|
CARBON_JNI_EXCEPTION_CHECK();
|
||||||
switch (a) {
|
switch (a) {
|
||||||
CARBON_MAP_TO_NN_EXIT(NN_OK)
|
CARBON_MAP_TO_NN_EXIT(NN_OK)
|
||||||
CARBON_MAP_TO_NN_EXIT(NN_ENOMEM)
|
CARBON_MAP_TO_NN_EXIT(NN_ENOMEM)
|
||||||
@@ -75,7 +98,7 @@ jobject Carbon::Map::To_nn_Exit(JNIEnv* env, nn_Exit a) {
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
nn_Exit From_nn_Exit(JNIEnv* env, jobject a) {
|
nn_Exit Carbon::Map::From_nn_Exit(JNIEnv* env, jobject a) {
|
||||||
jclass clazz = env->FindClass("org/neoflock/NeoNucleus/nn_Exit");
|
jclass clazz = env->FindClass("org/neoflock/NeoNucleus/nn_Exit");
|
||||||
jmethodID ordMID = env->GetMethodID(clazz, "ordinal", "()I");
|
jmethodID ordMID = env->GetMethodID(clazz, "ordinal", "()I");
|
||||||
jint value = env->CallIntMethod(a, ordMID);
|
jint value = env->CallIntMethod(a, ordMID);
|
||||||
@@ -92,12 +115,63 @@ jobject Carbon::Map::To_nn_ComputerState(JNIEnv* env, nn_ComputerState a) {
|
|||||||
CARBON_MAP_TO_NN_COMPUTERSTATE(NN_BLACKOUT)
|
CARBON_MAP_TO_NN_COMPUTERSTATE(NN_BLACKOUT)
|
||||||
CARBON_MAP_TO_NN_COMPUTERSTATE(NN_CHARCH)
|
CARBON_MAP_TO_NN_COMPUTERSTATE(NN_CHARCH)
|
||||||
}
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
nn_Exit From_nn_ComputerState(JNIEnv* env, jobject a) {
|
nn_ComputerState Carbon::Map::From_nn_ComputerState(JNIEnv* env, jobject a) {
|
||||||
jclass clazz = env->FindClass("org/neoflock/NeoNucleus/nn_ComputerState");
|
jclass clazz = env->FindClass("org/neoflock/NeoNucleus/nn_ComputerState");
|
||||||
jmethodID ordMID = env->GetMethodID(clazz, "ordinal", "()I");
|
jmethodID ordMID = env->GetMethodID(clazz, "ordinal", "()I");
|
||||||
jint value = env->CallIntMethod(a, ordMID);
|
jint value = env->CallIntMethod(a, ordMID);
|
||||||
return (nn_Exit) value;
|
return (nn_ComputerState) 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);
|
||||||
|
jobject obj = env->NewObject(clazz, consMID, str);
|
||||||
|
printf("malloc\n");
|
||||||
|
nn_Architecture* data = (nn_Architecture*) malloc(sizeof(nn_Architecture));
|
||||||
|
if (data == NULL) {
|
||||||
|
printf("null data\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
printf("memcpy\n");
|
||||||
|
memcpy(data, &a, sizeof(nn_Architecture));
|
||||||
|
printf("setptr\n");
|
||||||
|
if (!Carbon::PointerBacked::SetPointer(env, obj, data)) {
|
||||||
|
printf("SetPointer is false");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
printf("return\n");
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobject Carbon::Map::To_nn_EnvironmentAction(JNIEnv *env, nn_EnvironmentAction a)
|
||||||
|
{
|
||||||
|
CARBON_EM_DEFINE("Lorg/neoflock/NeoNucleus/nn_EnvironmentAction");
|
||||||
|
CARBON_EM_SWITCH(
|
||||||
|
CARBON_EM_CASE(NN_ENV_DRAWENERGY)
|
||||||
|
CARBON_EM_CASE(NN_ENV_POWERON)
|
||||||
|
CARBON_EM_CASE(NN_ENV_POWEROFF)
|
||||||
|
CARBON_EM_CASE(NN_ENV_CRASHED)
|
||||||
|
CARBON_EM_CASE(NN_ENV_BEEP)
|
||||||
|
CARBON_EM_CASE(NN_ENV_BEEPMORSE)
|
||||||
|
)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T Carbon_FromEnum(JNIEnv* env, const char* classpath, jobject a) {
|
||||||
|
jclass clazz = env->FindClass(classpath);
|
||||||
|
jmethodID ordMID = env->GetMethodID(clazz, "ordinal", "()I");
|
||||||
|
jint value = env->CallIntMethod(a, ordMID);
|
||||||
|
return (T) value;
|
||||||
|
}
|
||||||
|
nn_EnvironmentAction Carbon::Map::From_nn_EnvironmentAction(JNIEnv* env, jobject a)
|
||||||
|
{ CARBON_EM_FROM(nn_EnvironmentAction); }
|
||||||
|
|
||||||
|
jobject Carbon::Map::To_nn_EnvironmentRequest(JNIEnv* env, nn_EnvironmentRequest a) {
|
||||||
|
jclass clazz = env->FindClass(CARBON_CLASSPATH(nn_EnvironmentRequest));
|
||||||
|
jmethodID consMID = env->GetMethodID(clazz, "<init>", "(Lorg/neoflock/NeoNucleus/nn_Computer;Lorg/neoflock/NeoNucleus/nn_EnvironmentAction;Ljava/lang/Double;Lorg/neoflock/NeoNucleus/nn_Beep;Lorg/neoflock/NeoNucleus/nn_MorseBeep;)V");
|
||||||
|
//env->NewObject(clazz, consMID, )
|
||||||
}
|
}
|
||||||
namespace Carbon::Exceptions {
|
namespace Carbon::Exceptions {
|
||||||
CARBON_EXCEPTION_FUNC(ThrowNullPtr, "java/lang/NullPointerException");
|
CARBON_EXCEPTION_FUNC(ThrowNullPtr, "java/lang/NullPointerException");
|
||||||
|
|||||||
@@ -24,10 +24,15 @@ namespace Carbon {
|
|||||||
bool ResetPointer(JNIEnv * env, jobject obj);
|
bool ResetPointer(JNIEnv * env, jobject obj);
|
||||||
}
|
}
|
||||||
namespace Map {
|
namespace Map {
|
||||||
|
//template <typename T> T FromEnum(JNIEnv* env, const char* classpath, T a);
|
||||||
jobject To_nn_Exit(JNIEnv* env, nn_Exit a);
|
jobject To_nn_Exit(JNIEnv* env, nn_Exit a);
|
||||||
nn_Exit From_nn_Exit(JNIEnv* env, jobject a);
|
nn_Exit From_nn_Exit(JNIEnv* env, jobject a);
|
||||||
jobject To_nn_ComputerState(JNIEnv* env, nn_ComputerState a);
|
jobject To_nn_ComputerState(JNIEnv* env, nn_ComputerState a);
|
||||||
nn_ComputerState From_nn_ComputerState(JNIEnv* env, jobject a);
|
nn_ComputerState From_nn_ComputerState(JNIEnv* env, jobject a);
|
||||||
|
jobject To_nn_Architecture(JNIEnv* env, nn_Architecture a);
|
||||||
|
nn_EnvironmentAction From_nn_EnvironmentAction(JNIEnv* env, jobject a);
|
||||||
|
jobject To_nn_EnvironmentAction(JNIEnv* env, nn_EnvironmentAction a);
|
||||||
|
jobject To_nn_EnvironmentRequest(JNIEnv* env, nn_EnvironmentRequest a);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct JavaObjectTarget { // i might lowkey drop this struct
|
typedef struct JavaObjectTarget { // i might lowkey drop this struct
|
||||||
|
|||||||
4
src/native/luaarch.h
Normal file
4
src/native/luaarch.h
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#include "neonucleus.h"
|
||||||
|
extern "C" {
|
||||||
|
nn_Architecture getLuaArch();
|
||||||
|
}
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
#include "org_neoflock_NeoNucleus_NativeBindings.h"
|
#include "org_neoflock_NeoNucleus_NativeBindings.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "neonucleus.h"
|
#include "neonucleus.h"
|
||||||
|
extern "C" {
|
||||||
#include "ncomplib.h"
|
#include "ncomplib.h"
|
||||||
|
}
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
#include "luaarch.h"
|
||||||
|
|
||||||
#include "carbon.hpp"
|
#include "carbon.hpp"
|
||||||
|
|
||||||
@@ -39,13 +42,10 @@
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1initContext
|
JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1initContext
|
||||||
(JNIEnv * env, jclass ogClazz) {
|
(JNIEnv * env, jclass) {
|
||||||
//jclass clazz = env->FindClass("org/neoflock/NeoNucleus/nn_Context");
|
|
||||||
//jmethodID creator = env->GetStaticMethodID(clazz, "createFromPointer", "(J)Lorg/neoflock/NeoNucleus/Context;");
|
|
||||||
jobject obj = Carbon::InstantiateOpaqueClass(env, "org/neoflock/NeoNucleus/nn_Context");
|
jobject obj = Carbon::InstantiateOpaqueClass(env, "org/neoflock/NeoNucleus/nn_Context");
|
||||||
nn_Context * ctx = (nn_Context*)malloc(sizeof(nn_Context));
|
nn_Context * ctx = (nn_Context*)malloc(sizeof(nn_Context));
|
||||||
nn_initContext(ctx);
|
nn_initContext(ctx);
|
||||||
//jobject result = env->CallStaticObjectMethod(clazz, creator, (jlong) ctx);
|
|
||||||
Carbon::PointerBacked::SetPointer(env, obj, ctx);
|
Carbon::PointerBacked::SetPointer(env, obj, ctx);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1setCom
|
|||||||
nMethods[i] = {
|
nMethods[i] = {
|
||||||
.name = env->GetStringUTFChars(nameStr, NULL),
|
.name = env->GetStringUTFChars(nameStr, NULL),
|
||||||
.doc = env->GetStringUTFChars(docStr, NULL),
|
.doc = env->GetStringUTFChars(docStr, NULL),
|
||||||
.flags = (nn_MethodFlags) env->GetByteField(oArr, NULL)
|
.flags = (nn_MethodFlags) flagsByte
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,6 +173,74 @@ JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1create
|
|||||||
JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1getComputerState
|
JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1getComputerState
|
||||||
(JNIEnv * env, jclass, jobject computer) {
|
(JNIEnv * env, jclass, jobject computer) {
|
||||||
nn_Computer* nnPC = (nn_Computer*) Carbon::PointerBacked::GetPointer(env, computer);
|
nn_Computer* nnPC = (nn_Computer*) Carbon::PointerBacked::GetPointer(env, computer);
|
||||||
NULLPTR_CHECK(nnPC, nn_Component);
|
NULLPTR_CHECK(nnPC, nn_Computer);
|
||||||
return Carbon::Map::To_nn_ComputerState(env, nn_getComputerState(nnPC));
|
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());
|
||||||
|
}
|
||||||
|
JNIEXPORT void JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1setCallBudget
|
||||||
|
(JNIEnv * env, jclass, jobject computer, jdouble budget) {
|
||||||
|
nn_Computer* nnPC = (nn_Computer*) Carbon::PointerBacked::GetPointer(env, computer);
|
||||||
|
NULLPTR_CHECKNR(nnPC, nn_Computer);
|
||||||
|
nn_setCallBudget(nnPC, budget);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1setTotalEnergy
|
||||||
|
(JNIEnv * env, jclass, jobject computer, jdouble maxEnergy) {
|
||||||
|
nn_Computer* nnPC = (nn_Computer*) Carbon::PointerBacked::GetPointer(env, computer);
|
||||||
|
NULLPTR_CHECKNR(nnPC, nn_Computer);
|
||||||
|
nn_setTotalEnergy(nnPC, maxEnergy);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1setArchitecture
|
||||||
|
(JNIEnv * env, jclass, jobject computer, jobject arch) {
|
||||||
|
nn_Computer* nnPC = (nn_Computer*) Carbon::PointerBacked::GetPointer(env, computer);
|
||||||
|
nn_Architecture* nnArch = (nn_Architecture*) Carbon::PointerBacked::GetPointer(env, arch);
|
||||||
|
NULLPTR_CHECKNR(nnPC, nn_Computer);
|
||||||
|
NULLPTR_CHECKNR(nnArch, nn_Architecture);
|
||||||
|
|
||||||
|
nn_setArchitecture(nnPC, nnArch);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1addSupportedArchitecture
|
||||||
|
(JNIEnv * env, jclass, jobject computer, jobject arch) {
|
||||||
|
nn_Computer* nnPC = (nn_Computer*) Carbon::PointerBacked::GetPointer(env, computer);
|
||||||
|
nn_Architecture* nnArch = (nn_Architecture*) Carbon::PointerBacked::GetPointer(env, arch);
|
||||||
|
NULLPTR_CHECK(nnPC, nn_Computer);
|
||||||
|
NULLPTR_CHECK(nnArch, nn_Architecture);
|
||||||
|
|
||||||
|
return Carbon::Map::To_nn_Exit(env, nn_addSupportedArchitecture(nnPC, nnArch));
|
||||||
|
//nn_addSupportedArchitecture(nnPC, nnArch);
|
||||||
|
//return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1setTmpAddress
|
||||||
|
(JNIEnv * env, jclass, jobject computer, jstring address) {
|
||||||
|
// TODO
|
||||||
|
nn_Computer* nnPC = (nn_Computer*) Carbon::PointerBacked::GetPointer(env, computer);
|
||||||
|
NULLPTR_CHECK(nnPC, nn_Computer);
|
||||||
|
if (address == NULL) {
|
||||||
|
return Carbon::Map::To_nn_Exit(env, nn_setTmpAddress(nnPC, NULL));
|
||||||
|
}
|
||||||
|
const char * str = env->GetStringUTFChars(address, NULL);
|
||||||
|
nn_Exit exitCode = nn_setTmpAddress(nnPC, str);
|
||||||
|
env->ReleaseStringUTFChars(address, str);
|
||||||
|
return Carbon::Map::To_nn_Exit(env, exitCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1tick
|
||||||
|
(JNIEnv * env, jclass, jobject computer) {
|
||||||
|
nn_Computer* nnPC = (nn_Computer*) Carbon::PointerBacked::GetPointer(env, computer);
|
||||||
|
NULLPTR_CHECK(nnPC, nn_Computer);
|
||||||
|
return Carbon::Map::To_nn_Exit(env, nn_tick(nnPC));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL Java_org_neoflock_NeoNucleus_NativeBindings_nn_1tickSynchronized
|
||||||
|
(JNIEnv * env, jclass, jobject computer) {
|
||||||
|
nn_Computer* nnPC = (nn_Computer*) Carbon::PointerBacked::GetPointer(env, computer);
|
||||||
|
NULLPTR_CHECK(nnPC, nn_Computer);
|
||||||
|
return Carbon::Map::To_nn_Exit(env, nn_tickSynchronized(nnPC));
|
||||||
|
}
|
||||||
|
|||||||
354
src/native/ncomplib.h
Normal file
354
src/native/ncomplib.h
Normal file
@@ -0,0 +1,354 @@
|
|||||||
|
#ifndef NN_COMPLIB
|
||||||
|
#define NN_COMPLIB
|
||||||
|
|
||||||
|
#include "neonucleus.h"
|
||||||
|
|
||||||
|
#define NCL_PREFIX "ncl-"
|
||||||
|
|
||||||
|
#define NCL_EEPROM "ncl-eeprom"
|
||||||
|
#define NCL_FS "ncl-filesystem"
|
||||||
|
#define NCL_DRIVE "ncl-drive"
|
||||||
|
#define NCL_FLASH "ncl-nandflash"
|
||||||
|
#define NCL_GPU "ncl-gpu"
|
||||||
|
#define NCL_SCREEN "ncl-screen"
|
||||||
|
|
||||||
|
#define NCL_TMPFS "ncl-tmpfs"
|
||||||
|
|
||||||
|
// Default file cost.
|
||||||
|
// This is for a normal HDD/floppy.
|
||||||
|
#define NCL_FILECOST_DEFAULT 512
|
||||||
|
|
||||||
|
// File cost on an installer floppy.
|
||||||
|
// In OC, those are backed by a file called ZipFileInputStream.
|
||||||
|
// That class has a different implementation for spaceUsed,
|
||||||
|
// it is almost identical except it does not add the file cost.
|
||||||
|
// For that reason, it is recommended to set it to 0, for parity.
|
||||||
|
#define NCL_FILECOST_INSTALL 0
|
||||||
|
|
||||||
|
#define NCL_MAX_VRAMBUF 128
|
||||||
|
#define NCL_MAX_KEYBOARD 64
|
||||||
|
|
||||||
|
// very low-level actions
|
||||||
|
// some environment have VFSes so
|
||||||
|
// we support wrapping those
|
||||||
|
|
||||||
|
typedef struct ncl_Stat {
|
||||||
|
// whether the entry is a directory
|
||||||
|
bool isDirectory;
|
||||||
|
// the logical size of the entry
|
||||||
|
// as in, for files it is how many bytes are in there.
|
||||||
|
// For directories, it should be 0.
|
||||||
|
// Every entry has a base cost, and thus fear not,
|
||||||
|
// it will not lead to infinite disk usage.
|
||||||
|
// Instead, make their size representative of the
|
||||||
|
// size on disk / number of entries.
|
||||||
|
size_t size;
|
||||||
|
// the real size.
|
||||||
|
// This is for realSpaceUsed, and is a safety mechanism
|
||||||
|
// against disk-hogging.
|
||||||
|
size_t diskSize;
|
||||||
|
// The UNIX timestamp of the last modified date
|
||||||
|
// of the entry.
|
||||||
|
intptr_t lastModified;
|
||||||
|
} ncl_Stat;
|
||||||
|
|
||||||
|
typedef enum ncl_VFSAction {
|
||||||
|
NCL_VFS_OPEN,
|
||||||
|
NCL_VFS_CLOSE,
|
||||||
|
NCL_VFS_READ,
|
||||||
|
NCL_VFS_SEEK,
|
||||||
|
NCL_VFS_WRITE,
|
||||||
|
|
||||||
|
NCL_VFS_OPENDIR,
|
||||||
|
NCL_VFS_CLOSEDIR,
|
||||||
|
NCL_VFS_READDIR,
|
||||||
|
|
||||||
|
// non-recursively remove entry
|
||||||
|
NCL_VFS_REMOVE,
|
||||||
|
// non-recursively make directory
|
||||||
|
NCL_VFS_MKDIR,
|
||||||
|
|
||||||
|
NCL_VFS_STAT,
|
||||||
|
} ncl_VFSAction;
|
||||||
|
|
||||||
|
typedef struct ncl_VFSRequest {
|
||||||
|
void *state;
|
||||||
|
ncl_VFSAction action;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
const char *path;
|
||||||
|
// same r, w and a modes as regular filesystem component
|
||||||
|
const char *mode;
|
||||||
|
void *file;
|
||||||
|
} open;
|
||||||
|
struct {
|
||||||
|
// set to NULL for EoF
|
||||||
|
char *buf;
|
||||||
|
size_t len;
|
||||||
|
void *file;
|
||||||
|
} read;
|
||||||
|
struct {
|
||||||
|
const char *buf;
|
||||||
|
size_t len;
|
||||||
|
void *file;
|
||||||
|
} write;
|
||||||
|
struct {
|
||||||
|
nn_FSWhence whence;
|
||||||
|
int off;
|
||||||
|
void *file;
|
||||||
|
} seek;
|
||||||
|
void *close;
|
||||||
|
struct {
|
||||||
|
const char *path;
|
||||||
|
void *dir;
|
||||||
|
} opendir;
|
||||||
|
struct {
|
||||||
|
// set to NULL for EoF
|
||||||
|
// buffer size is NN_MAX_PATH.
|
||||||
|
// Remember to account for terminator
|
||||||
|
char *name;
|
||||||
|
void *dir;
|
||||||
|
} readdir;
|
||||||
|
void *closedir;
|
||||||
|
const char *remove;
|
||||||
|
const char *mkdir;
|
||||||
|
struct {
|
||||||
|
// set to NULL if missing
|
||||||
|
const char *path;
|
||||||
|
ncl_Stat *stat;
|
||||||
|
} stat;
|
||||||
|
struct {
|
||||||
|
// path of directory that / represents
|
||||||
|
const char *path;
|
||||||
|
// get the estimated amount of space
|
||||||
|
// used up by an empty entry.
|
||||||
|
// Used for enforcing capacity.
|
||||||
|
size_t size;
|
||||||
|
} entrysize;
|
||||||
|
};
|
||||||
|
} ncl_VFSRequest;
|
||||||
|
|
||||||
|
typedef struct ncl_VFS {
|
||||||
|
// the internal state
|
||||||
|
void *state;
|
||||||
|
// the handler.
|
||||||
|
// True on success, false on failure.
|
||||||
|
bool (*handler)(ncl_VFSRequest *request);
|
||||||
|
// the path separator
|
||||||
|
char pathsep;
|
||||||
|
// the assumed cost of a file in spaceUsedIn.
|
||||||
|
size_t fileCost;
|
||||||
|
} ncl_VFS;
|
||||||
|
|
||||||
|
// The default FS.
|
||||||
|
// Uses a basic implementation using POSIX/Windows FS APIs,
|
||||||
|
// or erroring on all operations if baremetal.
|
||||||
|
// Has default file cost (512)
|
||||||
|
extern ncl_VFS ncl_defaultFS;
|
||||||
|
|
||||||
|
// The installer FS.
|
||||||
|
// Same implementation as the default FS,
|
||||||
|
// but has a file cost of 0.
|
||||||
|
// This makes it accurate to ZipFileInputStreams in OC,
|
||||||
|
// which are used for the loot floppy disks.
|
||||||
|
// ENSURE ALL FILESYSTEMS WITH 0 FILE COST
|
||||||
|
// ARE READ-ONLY, OR ELSE YOU CAN BE SPAMMED
|
||||||
|
// ENDLESSLY WITH GIGABYTES OF DISK HOGGING.
|
||||||
|
extern ncl_VFS ncl_installerFS;
|
||||||
|
|
||||||
|
void *ncl_openfile(ncl_VFS vfs, const char *path, const char *mode);
|
||||||
|
void ncl_closefile(ncl_VFS vfs, void *file);
|
||||||
|
// returns false on EoF
|
||||||
|
bool ncl_readfile(ncl_VFS vfs, void *file, char *buf, size_t *len);
|
||||||
|
bool ncl_writefile(ncl_VFS vfs, void *file, const char *data, size_t len);
|
||||||
|
bool ncl_seekfile(ncl_VFS vfs, void *file, nn_FSWhence whence, int *off);
|
||||||
|
bool ncl_stat(ncl_VFS vfs, const char *path, ncl_Stat *stat);
|
||||||
|
|
||||||
|
void *ncl_opendir(ncl_VFS vfs, const char *path);
|
||||||
|
void ncl_closedir(ncl_VFS vfs, void *dir);
|
||||||
|
// returns false on EoF
|
||||||
|
bool ncl_readdir(ncl_VFS vfs, void *dir, char name[NN_MAX_PATH]);
|
||||||
|
size_t ncl_spaceUsedIn(ncl_VFS vfs, const char *path);
|
||||||
|
// gets the real space used
|
||||||
|
size_t ncl_spaceUsedBy(ncl_VFS vfs, const char *path);
|
||||||
|
|
||||||
|
bool ncl_exists(ncl_VFS vfs, const char *path);
|
||||||
|
|
||||||
|
bool ncl_remove(ncl_VFS vfs, const char *path);
|
||||||
|
bool ncl_removeRecursive(ncl_VFS vfs, const char *path);
|
||||||
|
|
||||||
|
bool ncl_mkdir(ncl_VFS vfs, const char *path);
|
||||||
|
bool ncl_mkdirRecursive(ncl_VFS vfs, const char *path);
|
||||||
|
|
||||||
|
bool ncl_copyto(ncl_VFS vfs, const char *from, const char *to);
|
||||||
|
|
||||||
|
typedef struct ncl_EncodedState {
|
||||||
|
char *buf;
|
||||||
|
size_t len;
|
||||||
|
} ncl_EncodedState;
|
||||||
|
|
||||||
|
nn_Exit ncl_encodeComponentState(nn_Universe *universe, nn_Component *comp, ncl_EncodedState *state);
|
||||||
|
void ncl_freeEncodedState(nn_Universe *universe, ncl_EncodedState *state);
|
||||||
|
nn_Exit ncl_loadComponentState(nn_Component *comp, const ncl_EncodedState *state);
|
||||||
|
|
||||||
|
size_t ncl_getLabel(nn_Component *c, char buf[NN_MAX_LABEL]);
|
||||||
|
size_t ncl_setLabel(nn_Component *c, const char *label, size_t len);
|
||||||
|
size_t ncl_setCLabel(nn_Component *c, const char *label);
|
||||||
|
|
||||||
|
nn_Component *ncl_createFilesystem(nn_Universe *universe, const char *address, const char *path, const nn_Filesystem *fs, bool isReadonly);
|
||||||
|
|
||||||
|
// Creates a tmpfs.
|
||||||
|
// This component is mostly treated like a normal filesystem,
|
||||||
|
// except you obviously cannot bind a vfs to it.
|
||||||
|
// Do note, it is illegal to mix encoded state between normal filesystem
|
||||||
|
// and tmpfs.
|
||||||
|
nn_Component *ncl_createTmpFS(nn_Universe *universe, const char *address, const nn_Filesystem *fs, size_t fileCost, bool isReadonly);
|
||||||
|
|
||||||
|
// this drive has its data in RAM.
|
||||||
|
// However, the data is not encoded in its state.
|
||||||
|
// Remember to read the entire drive and save it somewhere before dropping it.
|
||||||
|
nn_Component *ncl_createDrive(nn_Universe *universe, const char *address, const nn_Drive *drive, const char *data, size_t len, bool isReadonly);
|
||||||
|
|
||||||
|
// usable like a drive, but is a nandflash component
|
||||||
|
nn_Component *ncl_createFlash(nn_Universe *universe, const char *address, const nn_NandFlash *flash, const char *data, size_t len, bool isReadonly);
|
||||||
|
|
||||||
|
// data is stored interally
|
||||||
|
nn_Component *ncl_createEEPROM(nn_Universe *universe, const char *address, const nn_EEPROM *eeprom, const char *code, size_t codelen, bool isReadonly);
|
||||||
|
|
||||||
|
// Gets the VFS bound to a filesystem or drive.
|
||||||
|
// Returns the default FS if the component is not recognized.
|
||||||
|
ncl_VFS ncl_getVFS(nn_Component *component);
|
||||||
|
|
||||||
|
// Sets the VFS bound to a filesystem or drive.
|
||||||
|
// This determines the filesystem the operations are run in.
|
||||||
|
// Returns the old VFS.
|
||||||
|
ncl_VFS ncl_setVFS(nn_Component *component, ncl_VFS vfs);
|
||||||
|
|
||||||
|
// TODO, stuff we could implement:
|
||||||
|
// redstone, hologram, oled, ipu, vt, led, tape_drive, cd_drive, serial, colorful_lamp
|
||||||
|
|
||||||
|
typedef struct ncl_Pixel {
|
||||||
|
// 0xRRGGBB format
|
||||||
|
unsigned int fgColor;
|
||||||
|
// 0xRRGGBB format
|
||||||
|
unsigned int bgColor;
|
||||||
|
// the codepoint
|
||||||
|
nn_codepoint codepoint;
|
||||||
|
} ncl_Pixel;
|
||||||
|
|
||||||
|
typedef struct ncl_ScreenState ncl_ScreenState;
|
||||||
|
|
||||||
|
typedef enum ncl_ScreenFlags {
|
||||||
|
NCL_SCREEN_ON = 1<<0,
|
||||||
|
NCL_SCREEN_PRECISE = 1<<1,
|
||||||
|
NCL_SCREEN_TOUCHINVERTED = 1<<2,
|
||||||
|
} ncl_ScreenFlags;
|
||||||
|
|
||||||
|
nn_Component *ncl_createScreen(nn_Universe *universe, const char *address, const nn_ScreenConfig *config);
|
||||||
|
nn_Component *ncl_createGPU(nn_Universe *universe, const char *address, const nn_GPU *gpu);
|
||||||
|
|
||||||
|
typedef struct ncl_ComponentStat {
|
||||||
|
// common ones
|
||||||
|
char label[NN_MAX_LABEL];
|
||||||
|
size_t labellen;
|
||||||
|
// used for indicating usage. If higher than last time, something happened.
|
||||||
|
// This can be used to show a light or play a sound.
|
||||||
|
size_t usageCounter;
|
||||||
|
bool isReadonly;
|
||||||
|
// specific properties
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
const nn_EEPROM *conf;
|
||||||
|
size_t codeUsed;
|
||||||
|
size_t dataUsed;
|
||||||
|
} eeprom;
|
||||||
|
struct {
|
||||||
|
const nn_Filesystem *conf;
|
||||||
|
size_t spaceUsed;
|
||||||
|
size_t realDiskUsage;
|
||||||
|
size_t filesOpen;
|
||||||
|
const char *path;
|
||||||
|
} fs;
|
||||||
|
struct {
|
||||||
|
const nn_Drive *conf;
|
||||||
|
size_t lastSector;
|
||||||
|
} drive;
|
||||||
|
struct {
|
||||||
|
const nn_NandFlash *conf;
|
||||||
|
size_t currentWriteCount;
|
||||||
|
double wearlevel;
|
||||||
|
} flash;
|
||||||
|
struct {
|
||||||
|
const nn_GPU *conf;
|
||||||
|
size_t vramFree;
|
||||||
|
size_t bufferCount;
|
||||||
|
// can be NULL if there is none
|
||||||
|
const char *boundScreen;
|
||||||
|
} gpu;
|
||||||
|
struct {
|
||||||
|
const nn_ScreenConfig *conf;
|
||||||
|
ncl_ScreenState *state;
|
||||||
|
ncl_ScreenFlags flags;
|
||||||
|
int viewportWidth;
|
||||||
|
int viewportHeight;
|
||||||
|
char depth;
|
||||||
|
size_t keyboardCount;
|
||||||
|
} screen;
|
||||||
|
};
|
||||||
|
} ncl_ComponentStat;
|
||||||
|
|
||||||
|
bool ncl_isNCLID(const char *type);
|
||||||
|
bool ncl_isNCLComponent(nn_Component *component);
|
||||||
|
void ncl_statComponent(nn_Component *component, ncl_ComponentStat *stat);
|
||||||
|
// For EEPROMs, filesystems, drives
|
||||||
|
// Returns whether it was successful or not.
|
||||||
|
bool ncl_makeReadonly(nn_Component *component);
|
||||||
|
|
||||||
|
// Returns the amount of data written.
|
||||||
|
// The capacity MUST be at least the data size of the EEPROM.
|
||||||
|
size_t ncl_getEEPROMData(nn_Component *component, char *buf);
|
||||||
|
void ncl_setEEPROMData(nn_Component *component, const char *data, size_t len);
|
||||||
|
|
||||||
|
// Returns the amount of data written.
|
||||||
|
// The capacity MUST be at least the size of the EEPROM.
|
||||||
|
size_t ncl_getEEPROMCode(nn_Component *component, char *buf);
|
||||||
|
void ncl_setEEPROMCode(nn_Component *component, const char *data, size_t len);
|
||||||
|
|
||||||
|
size_t ncl_getEEPROMArch(nn_Component *component, char buf[NN_MAX_ARCHNAME]);
|
||||||
|
void ncl_setEEPROMArch(nn_Component *component, const char *arch, size_t len);
|
||||||
|
|
||||||
|
// Reads part of a drive.
|
||||||
|
// Off is 0-indexed.
|
||||||
|
size_t ncl_readDrive(nn_Component *component, size_t offset, char *buf, size_t len);
|
||||||
|
// Writes to part of a drive.
|
||||||
|
// Off is 0-indexed.
|
||||||
|
void ncl_writeDrive(nn_Component *component, size_t offset, const char *buf, size_t len);
|
||||||
|
// Returns the internal memory buffer with the drive data,
|
||||||
|
// and if len is not NULL, will also write the capacity.
|
||||||
|
// This is in case you do not want to risk OOM while saving the state.
|
||||||
|
char *ncl_getDriveBuffer(nn_Component *component, size_t *len);
|
||||||
|
|
||||||
|
void ncl_lockScreen(ncl_ScreenState *state);
|
||||||
|
void ncl_unlockScreen(ncl_ScreenState *state);
|
||||||
|
void ncl_resetScreen(ncl_ScreenState *state);
|
||||||
|
void ncl_getScreenResolution(const ncl_ScreenState *state, size_t *width, size_t *height);
|
||||||
|
void ncl_setScreenResolution(ncl_ScreenState *state, size_t width, size_t height);
|
||||||
|
void ncl_getScreenMaxResolution(const ncl_ScreenState *state, size_t *width, size_t *height);
|
||||||
|
nn_Exit ncl_setScreenMaxResolution(ncl_ScreenState *state, size_t width, size_t height);
|
||||||
|
void ncl_getScreenViewport(const ncl_ScreenState *state, size_t *width, size_t *height);
|
||||||
|
void ncl_setScreenViewport(ncl_ScreenState *state, size_t width, size_t height);
|
||||||
|
ncl_Pixel ncl_getScreenPixel(const ncl_ScreenState *state, int x, int y);
|
||||||
|
void ncl_setScreenPixel(ncl_ScreenState *state, int x, int y, nn_codepoint codepoint, int fg, int bg, bool isFgPalette, bool isBgPalette);
|
||||||
|
ncl_ScreenFlags ncl_getScreenFlags(const ncl_ScreenState *state);
|
||||||
|
void ncl_setScreenFlags(ncl_ScreenState *state, ncl_ScreenFlags flags);
|
||||||
|
char ncl_getScreenDepth(ncl_ScreenState *state);
|
||||||
|
void ncl_setScreenDepth(ncl_ScreenState *state, char depth);
|
||||||
|
nn_Exit ncl_mountKeyboard(ncl_ScreenState *state, const char *keyboardAddress);
|
||||||
|
void ncl_unmountKeyboard(ncl_ScreenState *state, const char *keyboardAddress);
|
||||||
|
bool ncl_hasKeyboard(ncl_ScreenState *state, const char *keyboardAddress);
|
||||||
|
const char *ncl_getKeyboard(ncl_ScreenState *state, size_t idx);
|
||||||
|
double ncl_getScreenEnergyUsage(ncl_ScreenState *state);
|
||||||
|
double ncl_getScreenBrightness(ncl_ScreenState *state);
|
||||||
|
void ncl_setScreenBrightness(ncl_ScreenState *state, double brightness);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -7,6 +7,14 @@
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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
|
* Class: org_neoflock_NeoNucleus_NativeBindings
|
||||||
* Method: nn_initContext
|
* 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