this repo has no description
1// MIT License
2
3// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com
4
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23#include "core/core.h"
24#include "luaapi.h"
25
26static const char _ms_loadstring[] = "_ms_loadstring";
27
28static inline bool isalnum_(char c) {return isalnum(c) || c == '_';}
29
30#include "moonscript.h"
31
32#define MOON_CODE(...) #__VA_ARGS__
33
34static const char* execute_moonscript_src = MOON_CODE(
35 local fn, err = require('moonscript.base').loadstring(...)
36
37 if not fn then
38 error(err)
39 end
40 return fn()
41);
42
43static void setloaded(lua_State* l, char* name)
44{
45 s32 top = lua_gettop(l);
46 lua_getglobal(l, "package");
47 lua_getfield(l, -1, "loaded");
48 lua_getfield(l, -1, name);
49 if (lua_isnil(l, -1)) {
50 lua_pop(l, 1);
51 lua_pushvalue(l, top);
52 lua_setfield(l, -2, name);
53 }
54
55 lua_settop(l, top);
56}
57
58static void evalMoonscript(tic_mem* tic, const char* code) {
59 tic_core* core = (tic_core*)tic;
60 lua_State* lua = core->currentVM;
61
62 lua_getglobal(lua, _ms_loadstring);
63
64 lua_pushstring(lua, code);
65 if (lua_pcall(lua, 1, 1, 0) != LUA_OK)
66 {
67 const char* msg = lua_tostring(lua, -1);
68 if (msg)
69 {
70 core->data->error(core->data->data, msg);
71 }
72 }
73}
74
75extern s32 luaopen_lpeg(lua_State *lua);
76
77static bool initMoonscript(tic_mem* tic, const char* code)
78{
79 tic_core* core = (tic_core*)tic;
80 luaapi_close(tic);
81
82 lua_State* lua = core->currentVM = luaL_newstate();
83 luaapi_open(lua);
84
85 luaopen_lpeg(lua);
86 setloaded(lua, "lpeg");
87
88 luaapi_init(core);
89
90 {
91 lua_State* moon = lua;
92
93 lua_settop(moon, 0);
94
95 if (luaL_loadbuffer(moon, (const char *)moonscript_lua, moonscript_lua_len, "moonscript.lua") != LUA_OK)
96 {
97 core->data->error(core->data->data, "failed to load moonscript.lua");
98 return false;
99 }
100
101 lua_call(moon, 0, 0);
102
103 if (luaL_loadbuffer(moon, execute_moonscript_src, strlen(execute_moonscript_src), "execute_moonscript") != LUA_OK)
104 {
105 core->data->error(core->data->data, "failed to load moonscript compiler");
106 return false;
107 }
108
109 lua_setglobal(lua, _ms_loadstring);
110 lua_getglobal(lua, _ms_loadstring);
111
112 lua_pushstring(moon, code);
113 if (lua_pcall(moon, 1, 1, 0) != LUA_OK)
114 {
115 const char* msg = lua_tostring(moon, -1);
116
117 if (msg)
118 {
119 core->data->error(core->data->data, msg);
120 return false;
121 }
122 }
123 }
124
125 return true;
126}
127
128static const char* const MoonKeywords [] =
129{
130 "false", "true", "nil", "local", "return",
131 "break", "continue", "for", "while",
132 "if", "else", "elseif", "unless", "switch",
133 "when", "and", "or", "in", "do",
134 "not", "super", "try", "catch",
135 "with", "export", "import", "then",
136 "from", "class", "extends", "new", "using",
137};
138
139static const tic_outline_item* getMoonOutline(const char* code, s32* size)
140{
141 enum{Size = sizeof(tic_outline_item)};
142
143 *size = 0;
144
145 static tic_outline_item* items = NULL;
146
147 if(items)
148 {
149 free(items);
150 items = NULL;
151 }
152
153 const char* ptr = code;
154
155 while(true)
156 {
157 static const char FuncString[] = "=->";
158
159 ptr = strstr(ptr, FuncString);
160
161 if(ptr)
162 {
163 const char* end = ptr;
164
165 ptr += sizeof FuncString - 1;
166
167 while(end >= code && !isalnum_(*end)) end--;
168
169 const char* start = end;
170
171 for (const char* val = start-1; val >= code && (isalnum_(*val)); val--, start--);
172
173 if(end > start)
174 {
175 items = realloc(items, (*size + 1) * Size);
176
177 items[*size].pos = start;
178 items[*size].size = (s32)(end - start + 1);
179
180 (*size)++;
181 }
182 }
183 else break;
184 }
185
186 return items;
187}
188
189static const u8 DemoRom[] =
190{
191 #include "../build/assets/moondemo.tic.dat"
192};
193
194static const u8 MarkRom[] =
195{
196 #include "../build/assets/moonmark.tic.dat"
197};
198
199TIC_EXPORT const tic_script EXPORT_SCRIPT(Moon) =
200{
201 .id = 13,
202 .name = "moon",
203 .fileExtension = ".moon",
204 .projectComment = "--",
205 {
206 .init = initMoonscript,
207 .close = luaapi_close,
208 .tick = luaapi_tick,
209 .boot = luaapi_boot,
210
211 .callback =
212 {
213 .scanline = luaapi_scn,
214 .border = luaapi_bdr,
215 .menu = luaapi_menu,
216 },
217 },
218
219 .getOutline = getMoonOutline,
220 .eval = evalMoonscript,
221
222 .blockCommentStart = NULL,
223 .blockCommentEnd = NULL,
224 .blockCommentStart2 = NULL,
225 .blockCommentEnd2 = NULL,
226 .blockStringStart = NULL,
227 .blockStringEnd = NULL,
228 .singleComment = "--",
229 .blockEnd = NULL,
230
231 .keywords = MoonKeywords,
232 .keywordsCount = COUNT_OF(MoonKeywords),
233
234 .demo = {DemoRom, sizeof DemoRom},
235 .mark = {MarkRom, sizeof MarkRom, "moonmark.tic"},
236};