diff --git a/src/component.c b/src/component.c index 05f5f79..8c45753 100644 --- a/src/component.c +++ b/src/component.c @@ -71,6 +71,10 @@ nn_componentTable *nn_getComponentTable(nn_component *component) { return component->table; } +const char *nn_getComponentType(nn_componentTable *table) { + return table->name; +} + void *nn_getComponentUserdata(nn_component *component) { return component->statePtr; } diff --git a/src/computer.c b/src/computer.c index d3c8457..5d212f5 100644 --- a/src/computer.c +++ b/src/computer.c @@ -41,6 +41,9 @@ nn_computer *nn_newComputer(nn_universe *universe, nn_address address, nn_archit c->userdata = userdata; c->memoryTotal = memoryLimit; c->tmpAddress = NULL; + c->temperature = 30; + c->roomTemperature = 30; + c->temperatureCoefficient = 1; // Setup Architecture c->archState = c->arch->setup(c, c->arch->userdata); @@ -242,6 +245,46 @@ void nn_addEnergy(nn_computer *computer, size_t amount) { computer->energy += amount; } +double nn_getTemperature(nn_computer *computer) { + return computer->temperature; +} + +double nn_getThermalCoefficient(nn_computer *computer) { + return computer->temperatureCoefficient; +} + +double nn_getRoomTemperature(nn_computer *computer) { + return computer->roomTemperature; +} + +void nn_setTemperature(nn_computer *computer, double temperature) { + computer->temperature = temperature; + if(computer->temperature < computer->roomTemperature) computer->temperature = computer->roomTemperature; +} + +void nn_setTemperatureCoefficient(nn_computer *computer, double coefficient) { + computer->temperatureCoefficient = coefficient; +} + +void nn_setRoomTemperature(nn_computer *computer, double roomTemperature) { + computer->roomTemperature = roomTemperature; + if(computer->temperature < computer->roomTemperature) computer->temperature = computer->roomTemperature; +} + +void nn_addHeat(nn_computer *computer, double heat) { + computer->temperature += heat * computer->temperatureCoefficient; + if(computer->temperature < computer->roomTemperature) computer->temperature = computer->roomTemperature; +} + +void nn_removeHeat(nn_computer *computer, double heat) { + computer->temperature -= heat * computer->temperatureCoefficient; + if(computer->temperature < computer->roomTemperature) computer->temperature = computer->roomTemperature; +} + +bool nn_isOverheating(nn_computer *computer) { + return computer->temperature > NN_OVERHEAT_MIN; +} + const char *nn_getError(nn_computer *computer) { return computer->err; } @@ -272,7 +315,32 @@ void nn_setCError(nn_computer *computer, const char *err) { computer->allocatedError = false; } -nn_component *nn_newComponent(nn_computer *computer, nn_address address, int slot, nn_componentTable *table, void *userdata); +nn_component *nn_newComponent(nn_computer *computer, nn_address address, int slot, nn_componentTable *table, void *userdata) { + nn_component *c = NULL; + for(size_t i = 0; i < computer->componentLen; i++) { + if(computer->components[i].address == NULL) { + c = computer->components + i; + break; + } + } + if(c == NULL) { + if(computer->componentLen == computer->componentCap) return NULL; // too many + c = computer->components + computer->componentLen; + computer->componentLen++; + } + + c->address = nn_strdup(address); + if(c->address == NULL) return NULL; + c->table = table; + c->slot = slot; + c->computer = computer; + if(table->constructor == NULL) { + c->statePtr = NULL; + } else { + c->statePtr = table->constructor(table->userdata); + } + return c; +} void nn_removeComponent(nn_computer *computer, nn_address address) { for(size_t i = 0; i < computer->componentLen; i++) { @@ -299,6 +367,21 @@ nn_component *nn_findComponent(nn_computer *computer, nn_address address) { return NULL; } +nn_component **nn_listComponent(nn_computer *computer, size_t *len) { + nn_component **c = nn_malloc(sizeof(nn_component *) * computer->componentLen); + if(c == NULL) return NULL; + size_t j = 0; + for(size_t i = 0; i < computer->componentLen; i++) { + nn_component *component = computer->components + i; + if(component->address != NULL) { + c[j] = component; + j++; + } + } + *len = j; + return c; +} + void nn_resetCall(nn_computer *computer) { for(size_t i = 0; i < computer->argc; i++) { nn_values_drop(computer->args[i]); diff --git a/src/computer.h b/src/computer.h index a9322e4..1e4ed8b 100644 --- a/src/computer.h +++ b/src/computer.h @@ -37,6 +37,9 @@ typedef struct nn_computer { size_t memoryTotal; nn_address address; nn_address tmpAddress; + double temperature; + double temperatureCoefficient; + double roomTemperature; } nn_computer; #endif diff --git a/src/emulator.c b/src/emulator.c index c4e5e78..5fbcdff 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -1,8 +1,18 @@ #include #include +#include #include "neonucleus.h" #include "testLuaArch.h" +void emulator_debugPrint(void *componentUserdata, void *methodUserdata, nn_component *component, nn_computer *computer) { + nn_value msg = nn_getArgument(computer, 0); + const char *m = nn_toCString(msg); + printf("[DEBUG] %s\n", m); + nn_return(computer, nn_values_cstring(m)); + nn_return(computer, nn_values_cstring(m)); + nn_return(computer, nn_values_cstring(m)); +} + int main() { printf("Setting up universe\n"); nn_universe *universe = nn_newUniverse(); @@ -14,7 +24,23 @@ int main() { nn_computer *computer = nn_newComputer(universe, "testMachine", arch, NULL, 1*1024*1024, 16); nn_setEnergyInfo(computer, 5000, 5000); nn_addSupportedArchitecture(computer, arch); + + nn_componentTable *t = nn_newComponentTable("debugPrint", NULL, NULL, NULL); + nn_defineMethod(t, "log", false, emulator_debugPrint, NULL, "logs stuff"); + + nn_newComponent(computer, "debugPrint", -1, t, NULL); + + double lastTime = nn_realTime(); while(true) { + double now = nn_realTime(); + double dt = now - lastTime; + if(dt == 0) dt = 1.0/60; + lastTime = now; + + // remove some heat per second + nn_removeHeat(computer, dt * (rand() % 12)); + if(nn_isOverheating(computer)) continue; + int state = nn_tickComputer(computer); if(state == NN_STATE_SWITCH) { nn_architecture *nextArch = nn_getNextArchitecture(computer); diff --git a/src/neonucleus.h b/src/neonucleus.h index 22e9795..bb1a195 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -57,6 +57,7 @@ #define NN_MAX_USERDATA 1024 #define NN_MAX_USER_SIZE 128 #define NN_MAX_SIGNAL_SIZE 8192 +#define NN_OVERHEAT_MIN 100 typedef struct nn_guard nn_guard; typedef struct nn_universe nn_universe; @@ -178,37 +179,33 @@ void nn_lockComputer(nn_computer *computer); void nn_unlockComputer(nn_computer *computer); /// This means the computer has not yet started. -/// This is used to determine whether newComponent and removeComponent should emit signals. #define NN_STATE_SETUP 0 /// This means the computer is running. There is no matching off-state, as the computer is /// only off when it is deleted. #define NN_STATE_RUNNING 1 -/// This means a call budget exceeded, and the sandbox should make the computer yield. -#define NN_STATE_OVERUSED 2 - /// This means a component's invocation could not be done due to a crucial resource being busy. /// The sandbox should yield, then *invoke the component method again.* -#define NN_STATE_BUSY 3 +#define NN_STATE_BUSY 2 /// This state occurs when a call to removeEnergy has consumed all the energy left. /// The sandbox should yield, and the runner should shut down the computer. /// No error is set, the sandbox can set it if it wanted to. -#define NN_STATE_BLACKOUT 4 +#define NN_STATE_BLACKOUT 3 /// This state only indicates that the runner should turn off the computer, but not due to a blackout. /// The runner need not bring it back. -#define NN_STATE_CLOSING 5 +#define NN_STATE_CLOSING 4 /// This state indicates that the runner should turn off the computer, but not due to a blackout. /// The runner should bring it back. /// By "bring it back", we mean delete the computer, then recreate the entire state. -#define NN_STATE_REPEAT 6 +#define NN_STATE_REPEAT 5 /// This state indciates that the runner should turn off the computer, to switch architectures. /// The architecture is returned by getNextArchitecture. -#define NN_STATE_SWITCH 7 +#define NN_STATE_SWITCH 6 int nn_getState(nn_computer *computer); void nn_setState(nn_computer *computer, int state); @@ -219,6 +216,17 @@ size_t nn_getMaxEnergy(nn_computer *computer); void nn_removeEnergy(nn_computer *computer, size_t energy); void nn_addEnergy(nn_computer *computer, size_t amount); +double nn_getTemperature(nn_computer *computer); +double nn_getThermalCoefficient(nn_computer *computer); +double nn_getRoomTemperature(nn_computer *computer); +void nn_setTemperature(nn_computer *computer, double temperature); +void nn_setTemperatureCoefficient(nn_computer *computer, double coefficient); +void nn_setRoomTemperature(nn_computer *computer, double roomTemperature); +void nn_addHeat(nn_computer *computer, double heat); +void nn_removeHeat(nn_computer *computer, double heat); +/* Checks against NN_OVERHEAT_MIN */ +bool nn_isOverheating(nn_computer *computer); + // NULL if there is no error. const char *nn_getError(nn_computer *computer); void nn_clearError(nn_computer *computer); @@ -243,8 +251,11 @@ nn_computer *nn_getComputerOfComponent(nn_component *component); nn_address nn_getComponentAddress(nn_component *component); int nn_getComponentSlot(nn_component *component); nn_componentTable *nn_getComponentTable(nn_component *component); +const char *nn_getComponentType(nn_componentTable *table); void *nn_getComponentUserdata(nn_component *component); nn_component *nn_findComponent(nn_computer *computer, nn_address address); +/* RESULT SHOULD BE NN_FREE()'D OR ELSE MEMORY IS LEAKED */ +nn_component **nn_listComponent(nn_computer *computer, size_t *len); // Component VTable stuff diff --git a/src/sandbox.lua b/src/sandbox.lua index 5187d43..d926c43 100644 --- a/src/sandbox.lua +++ b/src/sandbox.lua @@ -1,5 +1,7 @@ -print(string.format("%d / %d", computer.usedMemory(), computer.totalMemory())) -print(string.format("Computer Address: %q, Tmp Address: %q", computer.address(), computer.tmpAddress())) +print(component.doc("debugPrint", "log")) +local a, b, c = component.invoke("debugPrint", "log", "Absolute cinema") +print(a, b, c) -print(computer.getArchitecture()) -print(table.unpack(computer.getArchitectures())) +computer.pushSignal("stuff", 123, "b", false, nil) + +print(computer.popSignal()) diff --git a/src/testLuaArch.c b/src/testLuaArch.c index f5daf68..37e32db 100644 --- a/src/testLuaArch.c +++ b/src/testLuaArch.c @@ -43,6 +43,78 @@ nn_computer *testLuaArch_getComputer(lua_State *L) { return testLuaArch_get(L)->computer; } +static nn_value testLuaArch_getValue(lua_State *L, int index) { + if(lua_isinteger(L, index)) { + return nn_values_integer(lua_tointeger(L, index)); + } + if(lua_isnumber(L, index)) { + return nn_values_number(lua_tonumber(L, index)); + } + if(lua_isboolean(L, index)) { + return nn_values_boolean(lua_toboolean(L, index)); + } + if(lua_isnoneornil(L, index)) { + return nn_values_nil(); + } + if(lua_isstring(L, index)) { + size_t l = 0; + const char *s = lua_tolstring(L, index, &l); + return nn_values_string(s, l); + } + //TODO: bring it back once I make everything else not leak memory + //luaL_argcheck(L, false, index, luaL_typename(L, index)); + return nn_values_nil(); +} + +static void testLuaArch_pushValue(lua_State *L, nn_value val) { + int t = nn_values_getType(val); + if(t == NN_VALUE_NIL) { + lua_pushnil(L); + return; + } + if(t == NN_VALUE_INT) { + lua_pushinteger(L, val.integer); + return; + } + if(t == NN_VALUE_NUMBER) { + lua_pushnumber(L, val.number); + return; + } + if(t == NN_VALUE_BOOL) { + lua_pushboolean(L, val.boolean); + return; + } + if(t == NN_VALUE_STR) { + lua_pushlstring(L, val.string->data, val.string->len); + return; + } + if(t == NN_VALUE_CSTR) { + lua_pushstring(L, val.cstring); + return; + } + if(t == NN_VALUE_ARRAY) { + nn_array *arr = val.array; + lua_createtable(L, arr->len, 0); + int luaVal = lua_gettop(L); + for(size_t i = 0; i < arr->len; i++) { + testLuaArch_pushValue(L, arr->values[i]); + lua_seti(L, luaVal, i+1); + } + return; + } + if(t == NN_VALUE_TABLE) { + nn_table *tbl = val.table; + lua_createtable(L, 0, tbl->len); + int luaVal = lua_gettop(L); + for(size_t i = 0; i < tbl->len; i++) { + testLuaArch_pushValue(L, tbl->pairs[i].key); + testLuaArch_pushValue(L, tbl->pairs[i].val); + lua_settable(L, luaVal); + } + return; + } +} + static int testLuaArch_computer_usedMemory(lua_State *L) { testLuaArch *s = testLuaArch_get(L); lua_pushinteger(L, s->memoryUsed); @@ -133,6 +205,123 @@ static int testLuaArch_computer_setArchitecture(lua_State *L) { return 0; } +static int testLuaArch_computer_isOverheating(lua_State *L) { + nn_computer *c = testLuaArch_getComputer(L); + lua_pushboolean(L, nn_isOverheating(c)); + return 1; +} + +static int testLuaArch_computer_getTemperature(lua_State *L) { + nn_computer *c = testLuaArch_getComputer(L); + lua_pushnumber(L, nn_getTemperature(c)); + return 1; +} + +static int testLuaArch_computer_addHeat(lua_State *L) { + nn_computer *c = testLuaArch_getComputer(L); + double n = luaL_checknumber(L, 1); + nn_addHeat(c, n); + return 0; +} + +static int testLuaArch_computer_pushSignal(lua_State *L) { + nn_computer *c = testLuaArch_getComputer(L); + luaL_checkstring(L, 1); + int argc = lua_gettop(L); + if(argc > NN_MAX_ARGS) luaL_error(L, "too many arguments"); + nn_value args[argc]; + for(size_t i = 0; i < argc; i++) { + args[i] = testLuaArch_getValue(L, i+1); + } + const char *err = nn_pushSignal(c, args, argc); + if(err != NULL) { + for(size_t i = 0; i < argc; i++) { + nn_values_drop(args[i]); + } + luaL_error(L, "%s", err); + return 0; + } + return 0; +} + +static int testLuaArch_computer_popSignal(lua_State *L) { + nn_computer *c = testLuaArch_getComputer(L); + size_t retc = nn_signalSize(c); + for(size_t i = 0; i < retc; i++) { + testLuaArch_pushValue(L, nn_fetchSignalValue(c, i)); + } + nn_popSignal(c); + return retc; +} + +static int testLuaArch_component_list(lua_State *L) { + nn_computer *c = testLuaArch_getComputer(L); + size_t len = 0; + nn_component **components = nn_listComponent(c, &len); + lua_createtable(L, 0, len); + int list = lua_gettop(L); + for(size_t i = 0; i < len; i++) { + nn_component *component = components[i]; + nn_componentTable *table = nn_getComponentTable(component); + nn_address addr = nn_getComponentAddress(component); + const char *type = nn_getComponentType(table); + + lua_pushstring(L, type); + lua_setfield(L, list, addr); + } + nn_free(components); + return 1; +} + +static int testLuaArch_component_doc(lua_State *L) { + nn_computer *c = testLuaArch_getComputer(L); + const char *addr = luaL_checkstring(L, 1); + const char *method = luaL_checkstring(L, 2); + nn_component *component = nn_findComponent(c, (char *)addr); + if(component == NULL) { + lua_pushnil(L); + lua_pushstring(L, "no such component"); + return 2; + } + const char *doc = nn_methodDoc(nn_getComponentTable(component), method); + if(doc == NULL) { + lua_pushnil(L); + } else { + lua_pushstring(L, doc); + } + return 1; +} + + +static int testLuaArch_component_invoke(lua_State *L) { + nn_computer *c = testLuaArch_getComputer(L); + const char *addr = luaL_checkstring(L, 1); + const char *method = luaL_checkstring(L, 2); + int argc = lua_gettop(L) - 2; + nn_component *component = nn_findComponent(c, (char *)addr); + if(component == NULL) { + lua_pushnil(L); + lua_pushstring(L, "no such component"); + return 2; + } + nn_resetCall(c); + for(size_t i = 0; i < argc; i++) { + nn_addArgument(c, testLuaArch_getValue(L, 2 + argc)); + } + if(!nn_invokeComponentMethod(component, method)) { + nn_resetCall(c); + lua_pushnil(L); + lua_pushstring(L, "no such method"); + return 2; + } + size_t retc = nn_getReturnCount(c); + for(size_t i = 0; i < retc; i++) { + testLuaArch_pushValue(L, nn_getReturn(c, i)); + } + nn_resetCall(c); + return retc; +} + void testLuaArch_loadEnv(lua_State *L) { lua_createtable(L, 0, 10); int computer = lua_gettop(L); @@ -148,6 +337,8 @@ void testLuaArch_loadEnv(lua_State *L) { lua_setfield(L, computer, "tmpAddress"); lua_pushcfunction(L, testLuaArch_computer_uptime); lua_setfield(L, computer, "uptime"); + lua_pushcfunction(L, testLuaArch_computer_beep); + lua_setfield(L, computer, "beep"); lua_pushcfunction(L, testLuaArch_computer_energy); lua_setfield(L, computer, "energy"); lua_pushcfunction(L, testLuaArch_computer_maxEnergy); @@ -158,7 +349,23 @@ void testLuaArch_loadEnv(lua_State *L) { lua_setfield(L, computer, "getArchitectures"); lua_pushcfunction(L, testLuaArch_computer_setArchitecture); lua_setfield(L, computer, "setArchitecture"); + lua_pushcfunction(L, testLuaArch_computer_isOverheating); + lua_setfield(L, computer, "isOverheating"); + lua_pushcfunction(L, testLuaArch_computer_getTemperature); + lua_setfield(L, computer, "getTemperature"); + lua_pushcfunction(L, testLuaArch_computer_addHeat); + lua_setfield(L, computer, "addHeat"); lua_setglobal(L, "computer"); + + lua_createtable(L, 0, 10); + int component = lua_gettop(L); + lua_pushcfunction(L, testLuaArch_component_list); + lua_setfield(L, component, "list"); + lua_pushcfunction(L, testLuaArch_component_doc); + lua_setfield(L, component, "doc"); + lua_pushcfunction(L, testLuaArch_component_invoke); + lua_setfield(L, component, "invoke"); + lua_setglobal(L, "component"); } testLuaArch *testLuaArch_setup(nn_computer *computer, void *_) { diff --git a/src/utils.c b/src/utils.c index 1fbf7a8..fe2539c 100644 --- a/src/utils.c +++ b/src/utils.c @@ -44,7 +44,6 @@ double nn_realTime() { #else - double nn_realTime() { LARGE_INTEGER frequency = {0}; if(!QueryPerformanceFrequency(&frequency)) return 0; diff --git a/src/value.c b/src/value.c index d10da19..f1ca324 100644 --- a/src/value.c +++ b/src/value.c @@ -155,6 +155,47 @@ nn_pair nn_values_getPair(nn_value obj, size_t idx) { return obj.table->pairs[idx]; } +intptr_t nn_toInt(nn_value val) { + if(val.tag == NN_VALUE_INT) return val.integer; + if(val.tag == NN_VALUE_NUMBER) return val.number; + return 0; +} + +double nn_toNumber(nn_value val) { + if(val.tag == NN_VALUE_INT) return val.integer; + if(val.tag == NN_VALUE_NUMBER) return val.number; + return 0; +} + +bool nn_toBoolean(nn_value val) { + if(val.tag == NN_VALUE_NIL) return false; + if(val.tag == NN_VALUE_BOOL) return val.boolean; + return true; +} + +const char *nn_toCString(nn_value val) { + if(val.tag == NN_VALUE_CSTR) return val.cstring; + if(val.tag == NN_VALUE_STR) return val.string->data; + return NULL; +} + +const char *nn_toString(nn_value val, size_t *len) { + size_t l = 0; + const char *c = NULL; + + if(val.tag == NN_VALUE_CSTR) { + c = val.cstring; + l = strlen(c); + } + if(val.tag == NN_VALUE_STR) { + c = val.string->data; + l = val.string->len; + } + + if(len == NULL) *len = l; + return c; +} + size_t nn_measurePacketSize(nn_value *vals, size_t len) { size_t size = 0; for(size_t i = 0; i < len; i++) {