WIP: guile support

This commit is contained in:
Dan Frumin 2019-06-02 22:37:26 +02:00
parent 7369fcac75
commit 746b94599a
9 changed files with 297 additions and 6 deletions

View File

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

View File

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

View File

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

205
src/guileapi.c Normal file
View File

@ -0,0 +1,205 @@
#include "machine.h"
//#if defined(TIC_BUILD_WITH_GUILE)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libguile.h>
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) */

View File

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

View File

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

View File

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

View File

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

44
test.scm Normal file
View File

@ -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")))
;; <TILES>
;; 001:efffffffff222222f8888888f8222222f8fffffff8ff0ffff8ff0ffff8ff0fff
;; 002:fffffeee2222ffee88880fee22280feefff80fff0ff80f0f0ff80f0f0ff80f0f
;; 003:efffffffff222222f8888888f8222222f8fffffff8fffffff8ff0ffff8ff0fff
;; 004:fffffeee2222ffee88880fee22280feefff80ffffff80f0f0ff80f0f0ff80f0f
;; 017:f8fffffff8888888f888f888f8888ffff8888888f2222222ff000fffefffffef
;; 018:fff800ff88880ffef8880fee88880fee88880fee2222ffee000ffeeeffffeeee
;; 019:f8fffffff8888888f888f888f8888ffff8888888f2222222ff000fffefffffef
;; 020:fff800ff88880ffef8880fee88880fee88880fee2222ffee000ffeeeffffeeee
;; </TILES>
;; <WAVES>
;; 000:00000000ffffffff00000000ffffffff
;; 001:0123456789abcdeffedcba9876543210
;; 002:0123456789abcdef0123456789abcdef
;; </WAVES>
;; <SFX>
;; 000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000304000000000
;; </SFX>
;; <PALETTE>
;; 000:140c1c44243430346d4e4a4e854c30346524d04648757161597dced27d2c8595a16daa2cd2aa996dc2cadad45edeeed6
;; </PALETTE>