diff --git a/CMakeLists.txt b/CMakeLists.txt index ff42bdb..295f331 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,6 +197,7 @@ set(TIC80CORE_SRC ${TIC80CORE_DIR}/luaapi.c ${TIC80CORE_DIR}/wrenapi.c ${TIC80CORE_DIR}/squirrelapi.c + ${TIC80CORE_DIR}/guileapi.c ${TIC80CORE_DIR}/ext/gif.c 3rd-party/blip-buf/blip_buf.c # TODO: link it as lib? 3rd-party/duktape-2.2.0/src/duktape.c # TODO: link it as lib? @@ -637,3 +638,11 @@ foreach(TIC80_OUTPUT ${TIC80_OUTPUTS}) endif() endforeach() + +# LMAO GUILE +# include_directories(/gnu/store/9alic3caqhay3h8mx4iihpmyj6ymqpcx-guile-2.2.4/include/guile/2.2) +# link_directories(/gnu/store/9alic3caqhay3h8mx4iihpmyj6ymqpcx-guile-2.2.4/include/guile/2.2 /gnu/store/04vqghzmpqzxpd94h1q931xpmazp5s7g-libgc-7.6.6/lib) +include_directories(/usr/include/guile/2.2) +target_link_libraries(tic80core guile-2.2 pthread gc) +SET(CMAKE_C_COMPILER /usr/bin/gcc) +SET(CMAKE_CXX_COMPILER /usr/bin/c++) diff --git a/include/tic80_config.h b/include/tic80_config.h index 8794620..8d6ad16 100644 --- a/include/tic80_config.h +++ b/include/tic80_config.h @@ -26,15 +26,16 @@ !defined(TIC_BUILD_WITH_MOON) && \ !defined(TIC_BUILD_WITH_FENNEL) && \ !defined(TIC_BUILD_WITH_JS) && \ - !defined(TIC_BUILD_WITH_WREN) + !defined(TIC_BUILD_WITH_WREN) && \ + !defined(TIC_BUILD_WITH_GUILE) -#define TIC_BUILD_WITH_LUA 1 +#define TIC_BUILD_WITH_LUA 1 #define TIC_BUILD_WITH_MOON 1 #define TIC_BUILD_WITH_FENNEL 1 -#define TIC_BUILD_WITH_JS 1 +#define TIC_BUILD_WITH_JS 1 #define TIC_BUILD_WITH_WREN 1 #define TIC_BUILD_WITH_SQUIRREL 1 - +#define TIC_BUILD_WITH_GUILE 1 #endif #if defined(__APPLE__) @@ -88,4 +89,4 @@ # else # define TIC80_API # endif -#endif \ No newline at end of file +#endif diff --git a/src/console.c b/src/console.c index ab7c73e..7c02ba3 100644 --- a/src/console.c +++ b/src/console.c @@ -77,6 +77,10 @@ typedef enum SquirrelScript, #endif +#if defined(TIC_BUILD_WITH_GUILE) + Guile, +#endif + } ScriptLang; #if defined(__TIC_WINDOWS__) || defined(__TIC_LINUX__) || defined(__TIC_MACOSX__) @@ -490,6 +494,10 @@ static void* getDemoCart(Console* console, ScriptLang script, s32* size) case JavaScript: strcpy(path, DefaultJSTicPath); break; #endif +#if defined(TIC_BUILD_WITH_GUILE) + case Guile: strcpy(path, DefaultFennelTicPath); break; +#endif + #if defined(TIC_BUILD_WITH_WREN) case WrenScript: strcpy(path, DefaultWrenTicPath); break; #endif @@ -695,6 +703,7 @@ static bool hasProjectExt(const char* name) || hasExt(name, PROJECT_JS_EXT) || hasExt(name, PROJECT_WREN_EXT) || hasExt(name, PROJECT_SQUIRREL_EXT) + || hasExt(name, PROJECT_GUILE_EXT) || hasExt(name, PROJECT_FENNEL_EXT); } @@ -706,7 +715,8 @@ static const char* projectComment(const char* name) || hasExt(name, PROJECT_WREN_EXT) || hasExt(name, PROJECT_SQUIRREL_EXT)) comment = "//"; - else if(hasExt(name, PROJECT_FENNEL_EXT)) + else if(hasExt(name, PROJECT_FENNEL_EXT) + || hasExt(name, PROJECT_GUILE_EXT)) comment = ";;"; else comment = "--"; @@ -1089,6 +1099,9 @@ static void onConsoleLoadCommandConfirmed(Console* console, const char* param) if(!fsExistsFile(console->fs, name)) name = getName(param, PROJECT_FENNEL_EXT); + if(!fsExistsFile(console->fs, name)) + name = getName(param, PROJECT_GUILE_EXT); + if(!fsExistsFile(console->fs, name)) name = getName(param, PROJECT_SQUIRREL_EXT); @@ -1265,6 +1278,14 @@ static void onConsoleNewCommandConfirmed(Console* console, const char* param) #endif /* defined(TIC_BUILD_WITH_LUA) */ +#if defined(TIC_BUILD_WITH_GUILE) + if(strcmp(param, "guile") == 0) + { + loadDemo(console, Guile); + done = true; + } +#endif + #if defined(TIC_BUILD_WITH_JS) if(strcmp(param, "js") == 0 || strcmp(param, "javascript") == 0) { diff --git a/src/guileapi.c b/src/guileapi.c new file mode 100644 index 0000000..1e9e09a --- /dev/null +++ b/src/guileapi.c @@ -0,0 +1,205 @@ +#include "machine.h" + +//#if defined(TIC_BUILD_WITH_GUILE) + +#include +#include +#include +#include + +static const char TicMachine[] = "_TIC80"; + +// this wouldn't work with multiple guile instances +// pls hide this inside the guile interpreter +tic_mem* memory = NULL; + +/* Utils */ +static s32 getGuileNumber(SCM num) +{ + return (s32)scm_to_signed_integer(num, INT_MIN, INT_MAX); +} + +/* Implementing the TIC-80 API */ +static SCM guile_btn(SCM id) +{ + int r = 0; + if (id != SCM_UNDEFINED) + { + u32 c_id = getGuileNumber(id); + r = memory->ram.input.gamepads.data & (1 << c_id); + } + else + { + r = (int)memory->ram.input.gamepads.data; + } + return scm_from_bool(r); +} + +static SCM guile_btnp(SCM id, SCM hold, SCM period) +{ + s32 c_id = -1; + s32 c_hold = -1; + s32 c_period = -1; + + if (id != SCM_UNDEFINED) c_id = getGuileNumber(id); + if (hold != SCM_UNDEFINED) c_hold = getGuileNumber(hold); + if (period != SCM_UNDEFINED) c_period = getGuileNumber(period); + int r = (int)memory->api.btnp(memory, c_id, c_hold, c_period); + return scm_from_bool(r); +} + +static SCM guile_cls(SCM c) +{ + if(c != SCM_UNDEFINED) + memory->api.clear(memory, getGuileNumber(c)); + else + memory->api.clear(memory, 0); + return SCM_UNDEFINED; +} + +static SCM guile_print(SCM text, SCM x, SCM y, SCM color, + SCM fixed, SCM scale, SCM smallfont) +{ + if (text == SCM_UNDEFINED) return scm_from_int(0); + char * c_txt = scm_to_stringn(text,NULL,"UTF-8",SCM_FAILED_CONVERSION_QUESTION_MARK); + s32 c_x = 0; + if (x != SCM_UNDEFINED) c_x = scm_to_int(x); + s32 c_y = 0; + if (y != SCM_UNDEFINED) c_y = scm_to_int(y); + s32 c_color = TIC_PALETTE_SIZE-1; + if (color != SCM_UNDEFINED) c_color = scm_to_int(color) % TIC_PALETTE_SIZE; + bool c_fixed = false; + if (fixed != SCM_UNDEFINED) c_fixed = scm_to_bool(fixed); + s32 c_scale = 1; + if (scale != SCM_UNDEFINED) c_scale = scm_to_int(scale); + bool alt = false; + if (smallfont != SCM_UNDEFINED) alt = scm_to_bool(smallfont); + s32 width = memory->api.text_ex(memory, c_txt ? c_txt : "nil", + c_x, c_y, c_color, c_fixed, c_scale, alt); + return scm_from_int(width); +} + +static SCM guile_rect(SCM x, SCM y, SCM w, SCM h, SCM color) +{ + s32 c_x = -1; + s32 c_y = -1; + s32 c_w = -1; + s32 c_h = -1; + s32 c_color = -1; + if (x != SCM_UNDEFINED) c_x = getGuileNumber(x); + if (y != SCM_UNDEFINED) c_y = getGuileNumber(y); + if (w != SCM_UNDEFINED) c_w = getGuileNumber(w); + if (h != SCM_UNDEFINED) c_h = getGuileNumber(h); + if (color != SCM_UNDEFINED) c_color = getGuileNumber(color); + memory->api.rect(memory, c_x, c_y, c_w, c_h, c_color); + return scm_from_bool(1); +} + + +static void* guile_register_functions(void * data) { + scm_c_define_gsubr("btnp", 0, 3, 0, &guile_btnp); + scm_c_define_gsubr("cls", 0, 1, 0, &guile_cls); + scm_c_define_gsubr("rect", 5, 0, 0, &guile_rect); + scm_c_define_gsubr("print", 1, 6, 0, &guile_print); + return NULL; +} + +// TODO: pre-compilation +// TODO: error handling much? +static void evalGuile(tic_mem* tic, const char* code) +{ + scm_c_eval_string(code); +} + +static bool initGuile(tic_mem* tic, const char* code) +{ + memory = tic; + scm_with_guile (&guile_register_functions, NULL); + evalGuile(tic, code); + return true; +} + +static void closeGuile(tic_mem* tic) +{ +} + +static void callGuileTick(tic_mem* tic) +{ + SCM ticProc = scm_c_eval_string("TIC"); + // TODO, pre-load this in init + if (scm_procedure_p(ticProc)) + { + // TODO: check for errors + scm_call_0(ticProc); + } + else + { + printf("OwO not a procedure heh"); + } +} + +static void callGuileScanline(tic_mem* memory, s32 row, void* data) +{ +} + +static void callGuileOverline(tic_mem* memory, void* data) +{ +} + +static const tic_outline_item* getGuileOutline(const char* code, s32* size) +{ + static tic_outline_item* items = NULL; + + if(items) + { + free(items); + items = NULL; + } + + printf("UwU..\n"); + return items; +} + + +static const char* const GuileKeywords [] = +{ + "do", "values", "if", "when", "each", "for", "fn", "lambda", "partial", + "while", "set", "global", "var", "local", "let", "tset", + "or", "and", "true", "false", "nil", "#", ":", "->", "->>" +}; + +static const char* const ApiKeywords[] = API_KEYWORDS; + +static const tic_script_config GuileSyntaxConfig = +{ + .init = initGuile, + .close = closeGuile, + .tick = callGuileTick, + .scanline = callGuileScanline, + .overline = callGuileOverline, + + .getOutline = getGuileOutline, + .parse = parseCode, + .eval = evalGuile, + + .blockCommentStart = NULL, + .blockCommentEnd = NULL, + .blockStringStart = NULL, + .blockStringEnd = NULL, + .singleComment = ";", + + .keywords = GuileKeywords, + .keywordsCount = COUNT_OF(GuileKeywords), + + .api = ApiKeywords, + .apiCount = COUNT_OF(ApiKeywords), +}; + +const tic_script_config* getGuileConfig() +{ + return &GuileSyntaxConfig; +} + + + +//#endif /* defined(TIC_BUILD_WITH_GUILE) */ diff --git a/src/machine.h b/src/machine.h index 243b37b..913807a 100644 --- a/src/machine.h +++ b/src/machine.h @@ -198,6 +198,10 @@ const tic_script_config* getFennelConfig(); const tic_script_config* getJsScriptConfig(); #endif +#if defined(TIC_BUILD_WITH_GUILE) +const tic_script_config* getGuileConfig(); +#endif + #if defined(TIC_BUILD_WITH_WREN) const tic_script_config* getWrenScriptConfig(); #endif diff --git a/src/studio.h b/src/studio.h index 1ca40d2..41a45f9 100644 --- a/src/studio.h +++ b/src/studio.h @@ -61,6 +61,7 @@ #define PROJECT_WREN_EXT ".wren" #define PROJECT_SQUIRREL_EXT ".nut" #define PROJECT_FENNEL_EXT ".fnl" +#define PROJECT_GUILE_EXT ".scm" typedef enum { diff --git a/src/surf.c b/src/surf.c index 639f3bb..1c1c2a3 100644 --- a/src/surf.c +++ b/src/surf.c @@ -398,6 +398,7 @@ static bool addMenuItem(const char* name, const char* info, s32 id, void* ptr, b || hasExt(name, PROJECT_WREN_EXT) || hasExt(name, PROJECT_FENNEL_EXT) || hasExt(name, PROJECT_SQUIRREL_EXT) + || hasExt(name, PROJECT_GUILE_EXT) #endif ) { diff --git a/src/tic.c b/src/tic.c index 84819c6..e44df99 100644 --- a/src/tic.c +++ b/src/tic.c @@ -1635,6 +1635,11 @@ static const tic_script_config* getScriptConfig(const char* code) return getFennelConfig(); #endif +#if defined(TIC_BUILD_WITH_GUILE) + if(compareMetatag(code, "script", "guile", getGuileConfig()->singleComment)) + return getGuileConfig(); +#endif + #if defined(TIC_BUILD_WITH_JS) if(compareMetatag(code, "script", "js", getJsScriptConfig()->singleComment) || compareMetatag(code, "script", "javascript", getJsScriptConfig()->singleComment)) diff --git a/test.scm b/test.scm new file mode 100644 index 0000000..dc28d62 --- /dev/null +++ b/test.scm @@ -0,0 +1,44 @@ +;; title: game title +;; author: game developer +;; desc: short description +;; script: guile + +(use-modules (srfi srfi-28)) + +(define c 2) +(define (TIC) + (if (btnp 0) + (set! c (+ c 1))) + (if (btnp 1) + (set! c (- c 1))) + (cls c) + (rect 0 0 240 8 0) + (print (string-append + "cls(" (format "~a" c) + ") -- Use Up/Down to change"))) + +;; +;; 001:efffffffff222222f8888888f8222222f8fffffff8ff0ffff8ff0ffff8ff0fff +;; 002:fffffeee2222ffee88880fee22280feefff80fff0ff80f0f0ff80f0f0ff80f0f +;; 003:efffffffff222222f8888888f8222222f8fffffff8fffffff8ff0ffff8ff0fff +;; 004:fffffeee2222ffee88880fee22280feefff80ffffff80f0f0ff80f0f0ff80f0f +;; 017:f8fffffff8888888f888f888f8888ffff8888888f2222222ff000fffefffffef +;; 018:fff800ff88880ffef8880fee88880fee88880fee2222ffee000ffeeeffffeeee +;; 019:f8fffffff8888888f888f888f8888ffff8888888f2222222ff000fffefffffef +;; 020:fff800ff88880ffef8880fee88880fee88880fee2222ffee000ffeeeffffeeee +;; + +;; +;; 000:00000000ffffffff00000000ffffffff +;; 001:0123456789abcdeffedcba9876543210 +;; 002:0123456789abcdef0123456789abcdef +;; + +;; +;; 000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000304000000000 +;; + +;; +;; 000:140c1c44243430346d4e4a4e854c30346524d04648757161597dced27d2c8595a16daa2cd2aa996dc2cadad45edeeed6 +;; +