Compare commits

...

14 Commits

Author SHA1 Message Date
Alec Murphy
d4349b4971 deps: Update CFLAGS for openlibm build 2026-03-24 07:47:49 -04:00
Alec Murphy
c00e96e9a4 Bump VERSION to commit 7368c02 2026-03-24 07:45:47 -04:00
Alec Murphy
72d6dccbe8 Bump VERSION to commit 76bd203 2026-03-12 07:29:52 -04:00
Alec Murphy
1bc618fa9a Bump VERSION to commit 32064e1 2026-03-02 09:46:12 -05:00
Alec Murphy
5d216e3e65 Change build settings back to vscodium 2026-01-31 14:23:20 -05:00
Alec Murphy
57872fb45b Update to latest mujs.git commit 05cd646 2025-09-09 10:49:03 -04:00
Alec Murphy
cc4f8dfa51 Add LibTemple/Input functions 2025-06-10 13:34:00 -04:00
Alec Murphy
e6cff10e60 Add Input.mouse_x(), Input.mouse_y(), Input.mouse_lb(), Input.mouse_rb() to jslibtemple.c 2025-06-10 11:28:31 -04:00
Alec Murphy
d8108823b3 Wire up jsB_load, jsB_read to FileRead in mujs 2025-06-10 10:39:34 -04:00
Alec Murphy
9ad75fff5c Update examples/hello.js 2025-06-10 09:30:04 -04:00
Alec Murphy
d97bb83dea Add gmtime, mktime to LibC 2025-06-10 09:26:01 -04:00
Alec Murphy
f1fe3a6a97 Add kludge for sprintf -> npf_snprintf in mujs 2025-06-10 09:25:26 -04:00
Alec Murphy
a25b25984f Initialize interpreter in Adam task 2025-06-10 07:42:11 -04:00
Alec Murphy
b11a59d211 Update scripts/build-all 2025-06-10 07:13:13 -04:00
34 changed files with 441 additions and 348 deletions

View File

@@ -1,47 +0,0 @@
[Buildset]
BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x08\x00m\x00u\x00j\x00s)
[CustomBuildSystem]
CurrentConfiguration=BuildConfig0
[CustomBuildSystem][BuildConfig0]
BuildDir=file:///home/alec/repos/mujs
Title=
[CustomBuildSystem][BuildConfig0][ToolBuild]
Arguments=/home/alec/repos/mujs
Enabled=true
Environment=
Executable=file:///home/alec/repos/mujs/scripts/build-all
Type=0
[CustomBuildSystem][BuildConfig0][ToolClean]
Arguments=
Enabled=false
Environment=
Executable=
Type=3
[CustomBuildSystem][BuildConfig0][ToolConfigure]
Arguments=
Enabled=false
Environment=
Executable=
Type=1
[CustomBuildSystem][BuildConfig0][ToolInstall]
Arguments=
Enabled=false
Environment=
Executable=
Type=2
[CustomBuildSystem][BuildConfig0][ToolPrune]
Arguments=
Enabled=false
Environment=
Executable=
Type=4
[Project]
VersionControlSupport=kdevgit

5
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"jaktLanguageServer.compiler.executablePath": "/home/alec/cloned/jakt/build/bin/jakt",
"git.ignoreLimitWarning": true,
"terminal.integrated.shellIntegration.history": 0
}

1
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1 @@
{"version":"2.0.0","tasks":[{"label":"Build All","type":"shell","command":"${workspaceFolder}/scripts/build-all ${workspaceFolder}","group":{"kind":"build","isDefault":true},"runOptions":{"instanceLimit":1,"instancePolicy":"terminateOldest"},"problemMatcher":[]}]}

9
Run.HC
View File

@@ -1,7 +1,8 @@
XTalkWait(Fs, "Cd(\"M:/System/\");\n");
XTalkWait(Fs, "#include \"M:/System/MakeSystem\";\n");
XTalkWait(Fs, "#include \"M:/MuJS\";\n");
Adam("Cd(\"M:/System/\");\n");
Adam("#include \"M:/System/MakeSystem\";\n");
WinMax;
AutoComplete(0);
XTalkWait(Fs, "Cd(\"M:/\");\n");
XTalkWait(Fs, "mujs(\"examples/hello.js\");\n");

View File

@@ -1,51 +0,0 @@
#define PUSH_SYSV_REGS \
asm {PUSH RCX PUSH RDX PUSH RBX PUSH RBP PUSH RSI PUSH RDI PUSH R8 PUSH R9 PUSH \
R10 PUSH R11 PUSH R12 PUSH R13 PUSH R14 PUSH R15}
#define POP_SYSV_REGS \
p0 = p0; \
p1 = p1; \
p2 = p2; \
p3 = p3; \
p4 = p4; \
p5 = p5; \
asm {POP R15 POP R14 POP R13 POP R12 POP R11 POP R10 POP R9 POP R8 POP RDI POP \
RSI POP RBP POP RBX POP RDX POP RCX}
#define GET_SYSV_ARGS \
asm {PUSH R9 PUSH R8 PUSH RCX PUSH RDX PUSH RSI PUSH RDI} \
I64 reg RDI p0; \
I64 reg RSI p1; \
I64 reg RDX p2; \
I64 reg RCX p3; \
I64 reg R8 p4; \
I64 reg R9 p5; \
asm {POP RDI POP RSI POP RDX POP RCX POP R8 POP R9}
#define MOV_ANS_RAX asm { MOV[&ans], RAX }
#define MOV_PARAM0_RDI asm {MOV [&param0], RDI}
I64 param0;
I64 elf_argc;
U8** elf_argv;
asm {
_ELF_CALL::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RDI,U64 SF_ARG2[RBP]
MOV RSI,U64 SF_ARG3[RBP]
TEST RAX,RAX
JZ @@05
CALL RAX
@@05: POP RBP
RET1 8
}
U0 _main()
{
MOV_PARAM0_RDI
CallInd(_ELF_CALL, param0, elf_argc, elf_argv);
UserTaskCont;
}
//U0 _exit() { UserTaskCont; }

View File

@@ -3,6 +3,36 @@
#define ET_EXEC 2
#define ET_DYN 3
U0 @patch_call_rel32(U32 from, U32 to)
{
*(from(U8*)) = 0xE8;
*((from + 1)(I32*)) = to - from - 5;
}
U0 @patch_jmp_rel32(U32 from, U32 to)
{
*(from(U8*)) = 0xE9;
*((from + 1)(I32*)) = to - from - 5;
}
U0 @sse_enable()
{
/* clang-format off */
asm
{
MOV_EAX_CR0
AND AX, 0xFFFB // clear coprocessor emulation CR0.EM
OR AX, 0x2 // set coprocessor monitoring CR0.MP
MOV_CR0_EAX
MOV_EAX_CR4
OR AX, 3 << 9 // set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
MOV_CR4_EAX
}
/* clang-format on */
}
@sse_enable;
U0 @elf64_debug_print(U8 fmt, ...)
{
// FIXME: Remove unnecessary debug_print statements and PrintErr for errors.
@@ -170,11 +200,6 @@ U0 process_elf_rela_dyn_entries(Elf* elf)
entry_name = elf->dynstr + elf->dynsym[(rela_dyn->r_info >> 32)].st_name;
@elf64_debug_print("rela_dyn->r_offset = %08x\n", rela_dyn->r_offset);
@elf64_debug_print("entry name = '%s'\n", entry_name);
if (!StrCmp(entry_name, "__libc_start_main")) {
*(rela_dyn->r_offset)(U64*) = &_main;
@elf64_debug_print("Set value for .rela.dyn entry '%s' to: &_main\n",
entry_name);
}
if (!StrCmp(entry_name, "stdin")) {
*(rela_dyn->r_offset)(U64*) = 0;
@elf64_debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 0);
@@ -249,12 +274,6 @@ U0 process_elf_rela_plt_entries(Elf* elf)
*patch = entry_name;
@patch_jmp_rel32(plt, handler);
@patch_call_rel32(handler + 0x16, &PrintErr);
//@patch_call_rel32(handler + 0x21, &_exit);
if (!StrCmp(entry_name, "__libc_start_main")) {
symbol_exists = TRUE;
@patch_jmp_rel32(plt, &_main);
@elf64_debug_print("Set value for .rela.plt entry '%s' to &_main\n", entry_name);
}
if (get_symbol_address(entry_name)) {
symbol_exists = TRUE;
@patch_jmp_rel32(plt, get_symbol_address(entry_name));
@@ -293,8 +312,4 @@ U0 load_elf(...)
process_elf_section_header_table(&elf);
process_elf_rela_dyn_entries(&elf);
process_elf_rela_plt_entries(&elf);
_start = elf.ehdr->e_entry;
elf_argc = argc;
elf_argv = argv;
}

View File

@@ -1,3 +1,25 @@
#define PUSH_SYSV_REGS \
asm {PUSH RCX PUSH RDX PUSH RBX PUSH RBP PUSH RSI PUSH RDI PUSH R8 PUSH R9 PUSH \
R10 PUSH R11 PUSH R12 PUSH R13 PUSH R14 PUSH R15}
#define POP_SYSV_REGS \
p0 = p0; \
p1 = p1; \
p2 = p2; \
p3 = p3; \
p4 = p4; \
p5 = p5; \
asm {POP R15 POP R14 POP R13 POP R12 POP R11 POP R10 POP R9 POP R8 POP RDI POP \
RSI POP RBP POP RBX POP RDX POP RCX}
#define GET_SYSV_ARGS \
asm {PUSH R9 PUSH R8 PUSH RCX PUSH RDX PUSH RSI PUSH RDI} \
I64 reg RDI p0; \
I64 reg RSI p1; \
I64 reg RDX p2; \
I64 reg RCX p3; \
I64 reg R8 p4; \
I64 reg R9 p5; \
asm {POP RDI POP RSI POP RDX POP RCX POP R8 POP R9}
asm {
_SETJMP::
MOV [RDI], RBX // Store caller saved registers
@@ -29,6 +51,30 @@ _LONGJMP::
_extern _SETJMP U64 _setjmp(U64 jmp_buf);
_extern _LONGJMP U64 longjmp(U64 jmp_buf, U64 ret);
class libc_tm {
I32 tm_sec; /* seconds, range 0 to 59 */
I32 tm_min; /* minutes, range 0 to 59 */
I32 tm_hour; /* hours, range 0 to 23 */
I32 tm_mday; /* day of the month, range 1 to 31 */
I32 tm_mon; /* month, range 0 to 11 */
I32 tm_year; /* The number of years since 1900 */
I32 tm_wday; /* day of the week, range 0 to 6 */
I32 tm_yday; /* day in the year, range 0 to 365 */
I32 tm_isdst; /* daylight saving time */
};
#define NIST_TIME_OFFSET -9488
I64 CDate2Unix(CDate dt)
{ // TempleOS datetime to Unix timestamp.
return ToI64((dt - Str2Date("1/1/1970")) / CDATE_FREQ + NIST_TIME_OFFSET);
}
public CDate Unix2CDate(I64 timestamp)
{//Unix timestamp to TempleOS datetime.
return (timestamp-NIST_TIME_OFFSET)*CDATE_FREQ+Str2Date("1/1/1970");
}
U0 free()
{
PUSH_SYSV_REGS
@@ -60,6 +106,56 @@ U0 localtime()
POP_SYSV_REGS
}
U64 @gmtime(U64* timep)
{
CDateStruct ds;
Date2Struct(&ds, Unix2CDate(*timep));
libc_tm* tm = CAlloc(sizeof(libc_tm));
tm->tm_sec = ds.sec;
tm->tm_min = ds.min;
tm->tm_hour = ds.hour;
tm->tm_mday = ds.day_of_mon;
tm->tm_mon = ds.mon;
tm->tm_year = ds.year;
tm->tm_wday = ds.day_of_week;
return tm;
}
U0 gmtime()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
@gmtime(p0);
POP_SYSV_REGS
}
U64 @mktime(libc_tm* tm)
{
CDateStruct ds;
MemSet(&ds, 0, sizeof(CDateStruct));
if (tm) {
ds.sec = tm->tm_sec;
ds.min = tm->tm_min;
ds.hour = tm->tm_hour;
ds.day_of_mon = tm->tm_mday;
ds.mon = tm->tm_mon;
ds.year = tm->tm_year;
ds.day_of_week = tm->tm_wday;
} else {
Date2Struct(&ds, Now);
}
return CDate2Unix(Struct2Date(&ds));
}
U0 mktime()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
@mktime(p0);
POP_SYSV_REGS
}
I64 @strncmp(U8* s1, U8* s2, I32 n)
{
U64 u1, u2;
@@ -219,7 +315,6 @@ U0 strcmp()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
//"strcmp: '%s', '%s'\n", p0, p1;
StrCmp(p0, p1);
POP_SYSV_REGS
}
@@ -269,14 +364,6 @@ U0 realloc()
POP_SYSV_REGS
}
#define MY_TIME_OFFSET 9488
public
I64 CDate2Unix(CDate dt)
{ // TempleOS datetime to Unix timestamp.
return ToI64((dt - Str2Date("1/1/1970")) / CDATE_FREQ) - MY_TIME_OFFSET;
}
I64 @time(I64* ptr)
{
no_warn ptr;
@@ -363,11 +450,3 @@ U0 strstr()
POP_SYSV_REGS
}
U0 sprintf()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
StrPrint(p0, p1, p2, p3, p4, p5);
POP_SYSV_REGS
}

12
System/LibTemple/Input.HC Normal file
View File

@@ -0,0 +1,12 @@
Bool @input_key_down(I64 sc)
{
return Bt(kbd.down_bitmap, sc);
}
U0 input_key_down()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
@input_key_down(p0);
POP_SYSV_REGS
}

View File

@@ -1,44 +1,13 @@
/* clang-format off */
WinMax;
AutoComplete(0);
U0 @patch_call_rel32(U32 from, U32 to)
{
*(from(U8*)) = 0xE8;
*((from + 1)(I32*)) = to - from - 5;
}
U0 @patch_jmp_rel32(U32 from, U32 to)
{
*(from(U8*)) = 0xE9;
*((from + 1)(I32*)) = to - from - 5;
}
U0 @sse_enable()
{
/* clang-format off */
asm
{
MOV_EAX_CR0
AND AX, 0xFFFB // clear coprocessor emulation CR0.EM
OR AX, 0x2 // set coprocessor monitoring CR0.MP
MOV_CR0_EAX
MOV_EAX_CR4
OR AX, 3 << 9 // set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
MOV_CR4_EAX
}
/* clang-format on */
}
@sse_enable;
// FFI support files
#include "FFI/Base";
#include "FFI/LibC";
#include "FFI/ELF64";
// LibTemple support files
#include "LibTemple/Input";
#include "LibTemple/OS";
#include "MuJS";
/* clang-format on */

View File

@@ -1,3 +1,3 @@
print("Hello, TempleOS, from MuJS!")
print("Current date and time is: " + JSON.stringify(new Date()))
print("Type mujs; with no arguments for a REPL, or mujs(\"path/to/file.js\"); to run a program.")
print("Current date and time is: " + new Date().toString());
print("Type mujs; for a REPL, or mujs(\"path/to/file.js\"); to run a program.");

View File

@@ -1,4 +0,0 @@
[Project]
CreatedFrom=
Manager=KDevCustomBuildSystem
Name=mujs

View File

@@ -26,6 +26,9 @@ templeos_iso_file = home_path + 'iso/TempleOS.ISO'
qemu_run_cmd = qemu_bin_path + ' ' + qemu_display + ' -enable-kvm -m 1024 -cdrom ' + qemu_slipstream_iso_file + ' -audiodev pa,id=snd0 -machine pcspk-audiodev=snd0 -debugcon stdio -boot d'
def kill_running_qemu_processes():
os.system('killall -e "' + qemu_bin_path + '"')
def clang_format_src_files():
print("build-all: clang-format-src-files")
exclude_paths = ["mujs", "openlibm", ".iso.c"]
@@ -115,7 +118,7 @@ def generate_iso_c_file():
# Fixup addresses for MuJS
mujs_bin_path = redsea_path + '/build/bin/mujs'
mujs_hc_path = redsea_path + '/MuJS.HC'
mujs_hc_path = redsea_path + '/System/MuJS.HC'
hc_fixup('MUJS_MAIN', 'main', mujs_bin_path, mujs_hc_path)
exit_fixup(mujs_bin_path, mujs_hc_path)
@@ -140,6 +143,7 @@ def run():
raise ValueError("build-all: step 'run' failed, error code " + str(res))
def build_all():
kill_running_qemu_processes()
clang_format_src_files()
refresh_build_path()
build_libtemple()

1
src/libtemple/input.h Normal file
View File

@@ -0,0 +1 @@
uint64_t input_key_down(uint64_t sc);

View File

@@ -1,3 +1,5 @@
unsigned long input_key_down(unsigned long sc) { return 0; }
unsigned long os_call_ext_str(char const* func) { return 0; }
unsigned long os_call_ext_str_1(char const* func, unsigned long arg1) { return 0; }

1
src/mujs/VERSION Normal file
View File

@@ -0,0 +1 @@
commit 7368c02b4409107ed64aea19a1c32e6852c76d66

View File

@@ -240,7 +240,7 @@ static void Ap_slice(js_State *J)
static int Ap_sort_cmp(js_State *J, int idx_a, int idx_b)
{
js_Object *obj = js_tovalue(J, 0)->u.object;
if (obj->u.a.simple) {
if (obj->u.a.simple && idx_b < obj->u.a.flat_length) {
js_Value *val_a = &obj->u.a.array[idx_a];
js_Value *val_b = &obj->u.a.array[idx_b];
int und_a = val_a->t.type == JS_TUNDEFINED;
@@ -326,7 +326,7 @@ static int Ap_sort_cmp(js_State *J, int idx_a, int idx_b)
static void Ap_sort_swap(js_State *J, int idx_a, int idx_b)
{
js_Object *obj = js_tovalue(J, 0)->u.object;
if (obj->u.a.simple) {
if (obj->u.a.simple && idx_b < obj->u.a.flat_length) {
js_Value tmp = obj->u.a.array[idx_a];
obj->u.a.array[idx_a] = obj->u.a.array[idx_b];
obj->u.a.array[idx_b] = tmp;
@@ -354,7 +354,7 @@ static int Ap_sort_leaf(js_State *J, int i, int end)
int lc = (j << 1) + 1; /* left child */
int rc = (j << 1) + 2; /* right child */
while (rc < end) {
if (Ap_sort_cmp(J, rc, lc) > 0)
if (Ap_sort_cmp(J, lc, rc) <= 0)
j = rc;
else
j = lc;
@@ -369,8 +369,9 @@ static int Ap_sort_leaf(js_State *J, int i, int end)
static void Ap_sort_sift(js_State *J, int i, int end)
{
int j = Ap_sort_leaf(J, i, end);
while (Ap_sort_cmp(J, i, j) > 0)
while (j > i && Ap_sort_cmp(J, i, j) > 0) {
j = (j - 1) >> 1; /* parent */
}
while (j > i) {
Ap_sort_swap(J, i, j);
j = (j - 1) >> 1; /* parent */

View File

@@ -323,7 +323,7 @@ static char *fmtdate(char *buf, double t)
int d = DateFromTime(t);
if (!isfinite(t))
return "Invalid Date";
sprintf(buf, "%04d-%02d-%02d", y, m+1, d);
npf_snprintf(buf, 1024, "%04d-%02d-%02d", y, m+1, d);
return buf;
}
@@ -338,11 +338,11 @@ static char *fmttime(char *buf, double t, double tza)
if (!isfinite(t))
return "Invalid Date";
if (tza == 0)
sprintf(buf, "%02d:%02d:%02d.%03dZ", H, M, S, ms);
npf_snprintf(buf, 1024, "%02d:%02d:%02d.%03dZ", H, M, S, ms);
else if (tza < 0)
sprintf(buf, "%02d:%02d:%02d.%03d-%02d:%02d", H, M, S, ms, tzh, tzm);
npf_snprintf(buf, 1024, "%02d:%02d:%02d.%03d-%02d:%02d", H, M, S, ms, tzh, tzm);
else
sprintf(buf, "%02d:%02d:%02d.%03d+%02d:%02d", H, M, S, ms, tzh, tzm);
npf_snprintf(buf, 1024, "%02d:%02d:%02d.%03d+%02d:%02d", H, M, S, ms, tzh, tzm);
return buf;
}
@@ -353,7 +353,7 @@ static char *fmtdatetime(char *buf, double t, double tza)
return "Invalid Date";
fmtdate(dbuf, t);
fmttime(tbuf, t, tza);
sprintf(buf, "%sT%s", dbuf, tbuf);
npf_snprintf(buf, 1024, "%sT%s", dbuf, tbuf);
return buf;
}

View File

@@ -53,6 +53,13 @@ static void Ep_toString(js_State *J)
}
}
static void Ep_get_stack(js_State *J)
{
Ep_toString(J);
js_getproperty(J, 0, "stackTrace");
js_concat(J);
}
static int jsB_ErrorX(js_State *J, js_Object *prototype)
{
js_pushobject(J, jsV_newobject(J, JS_CERROR, prototype));
@@ -105,8 +112,13 @@ void jsB_initerror(js_State *J)
{
js_pushobject(J, J->Error_prototype);
{
jsB_props(J, "name", "Error");
jsB_propf(J, "Error.prototype.toString", Ep_toString, 0);
jsB_props(J, "name", "Error");
jsB_propf(J, "Error.prototype.toString", Ep_toString, 0);
jsB_props(J, "message", "");
js_newcfunction(J, Ep_get_stack, "stack", 0);
js_pushnull(J);
js_defaccessor(J, -3, "stack", JS_READONLY | JS_DONTENUM | JS_DONTCONF);
}
js_newcconstructor(J, jsB_Error, jsB_Error, "Error", 1);
js_defglobal(J, "Error", JS_DONTENUM);

View File

@@ -270,6 +270,9 @@ struct js_State
js_Object *gcroot; /* gc scan list */
int runlimit;
int memlimit;
/* environments on the call stack but currently not in scope */
int envtop;
js_Environment *envstack[JS_ENVLIMIT];

View File

@@ -102,7 +102,7 @@ static int jsY_findkeyword(js_State *J, const char *s)
J->text = keywords[i];
return TK_BREAK + i; /* first keyword + i */
}
J->text = js_intern(J, s);
J->text = s;
return TK_IDENTIFIER;
}
@@ -204,14 +204,15 @@ static void textinit(js_State *J)
static void textpush(js_State *J, Rune c)
{
int n;
int n, newcap;
if (c == EOF)
n = 1;
else
n = runelen(c);
if (J->lexbuf.len + n > J->lexbuf.cap) {
J->lexbuf.cap = J->lexbuf.cap * 2;
newcap = J->lexbuf.cap * 2;
J->lexbuf.text = js_realloc(J, J->lexbuf.text, J->lexbuf.cap);
J->lexbuf.cap = newcap;
}
if (c == EOF)
J->lexbuf.text[J->lexbuf.len++] = 0;
@@ -449,7 +450,7 @@ static int lexstring(js_State *J)
s = textend(J);
J->text = js_intern(J, s);
J->text = s;
return TK_STRING;
}
@@ -476,7 +477,7 @@ static int isregexpcontext(int last)
static int lexregexp(js_State *J)
{
const char *s;
int g, m, i;
int g, m, i, flags;
int inclass = 0;
/* already consumed initial '/' */
@@ -523,11 +524,13 @@ static int lexregexp(js_State *J)
if (g > 1 || i > 1 || m > 1)
jsY_error(J, "duplicated flag in regular expression");
J->text = js_intern(J, s);
J->number = 0;
if (g) J->number += JS_REGEXP_G;
if (i) J->number += JS_REGEXP_I;
if (m) J->number += JS_REGEXP_M;
J->text = s;
flags = 0;
if (g) flags |= JS_REGEXP_G;
if (i) flags |= JS_REGEXP_I;
if (m) flags |= JS_REGEXP_M;
J->number = flags;
return TK_REGEXP;
}
@@ -828,7 +831,7 @@ static int lexjsonstring(js_State *J)
s = textend(J);
J->text = js_intern(J, s);
J->text = s;
return TK_STRING;
}

View File

@@ -1,6 +1,7 @@
#include <stdbool.h>
#include <inttypes.h>
#include "../libtemple/input.h"
#include "../libtemple/os.h"
#define value_or_number(v, x) js_isundefined(J, x) ? v : js_tonumber(J, x)
@@ -157,6 +158,84 @@ void jsLT_initgr(js_State *J)
js_defglobal(J, "Gr", JS_DONTENUM);
}
/** Input **/
uint64_t get_glbl_var_addr(char* name)
{
// 0x100300 + 0x3d0: adam_task + offset(CTask.hash_table)
// 0x8: HTT_GLBL_VAR
// 0x78: offset(CHashGlblVar.data_addr)
uint64_t addr = os_call_ext_str_4("HashFind", (uint64_t)name, *(uint64_t*)(0x100300 + 0x3d0), 8, 1);
return addr ? *(uint64_t*)(addr + 0x78) : 0;
}
void Input_get_char(js_State *J)
{
js_pushnumber(J, os_call_ext_str_3("GetChar", 0, 0, 0));
}
void Input_get_string(js_State *J)
{
char* res = (char*)os_call_ext_str_3("GetStr", js_isundefined(J, 1) ? 0 : (uint64_t)js_tostring(J, 1), 0, 0);
if (!res) {
js_pushundefined(J);
return;
}
js_pushstring(J, res);
free(res);
}
void Input_mouse_x(js_State *J)
{
uint64_t* res = (uint64_t*)get_glbl_var_addr("ms");
js_pushnumber(J, res[0]); // offset(CMsStateGlbls.pos.x)
}
void Input_mouse_y(js_State *J)
{
uint64_t* res = (uint64_t*)get_glbl_var_addr("ms");
js_pushnumber(J, res[1]); // offset(CMsStateGlbls.pos.y)
}
void Input_mouse_lb(js_State *J)
{
uint8_t* res = (uint8_t*)get_glbl_var_addr("ms");
js_pushboolean(J, res[0xa0]); // offset(CMsStateGlbls.lb)
}
void Input_mouse_rb(js_State *J)
{
uint8_t* res = (uint8_t*)get_glbl_var_addr("ms");
js_pushboolean(J, res[0xa1]); // offset(CMsStateGlbls.rb)
}
void Input_key_down(js_State *J)
{
js_pushboolean(J, input_key_down(js_tonumber(J, 1)));
}
void Input_press_a_key(js_State *J)
{
js_pushnumber(J, os_call_ext_str("PressAKey"));
}
void jsLT_initinput(js_State *J)
{
js_pushobject(J, jsV_newobject(J, -1, J->Object_prototype));
{
jsB_propf(J, "Input.get_char", Input_get_char, 0);
jsB_propf(J, "Input.get_string", Input_get_string, 1);
jsB_propf(J, "Input.mouse_x", Input_mouse_x, 0);
jsB_propf(J, "Input.mouse_y", Input_mouse_y, 0);
jsB_propf(J, "Input.mouse_lb", Input_mouse_lb, 0);
jsB_propf(J, "Input.mouse_rb", Input_mouse_rb, 0);
jsB_propf(J, "Input.press_a_key", Input_press_a_key, 0);
jsB_propf(J, "Input.key_down", Input_key_down, 1);
}
js_defglobal(J, "Input", JS_DONTENUM);
js_dostring(J, "Input.key_up = function(sc) { return !Input.key_down(sc) }");
}
/** OS **/
// U0 Beep(I8 ona=62,Bool busy=FALSE)
@@ -214,8 +293,9 @@ void OS_read_file_as_string(js_State *J)
return;
}
const char* filename = js_tostring(J, 1);
long file_as_string = os_call_ext_str_3("FileRead", (uint64_t)filename, 0, 0);
js_pushstring(J, file_as_string ? (char*)file_as_string : "");
char* file_as_string = (char*)os_call_ext_str_3("FileRead", (uint64_t)filename, 0, 0);
js_pushstring(J, file_as_string ? file_as_string : "");
free(file_as_string);
}
// U0 Reboot()
@@ -276,5 +356,6 @@ void js_initlibtemple(js_State *J)
{
jsLT_initdc(J);
jsLT_initgr(J);
jsLT_initinput(J);
jsLT_initos(J);
}

View File

@@ -116,11 +116,11 @@ static void numtostr(js_State *J, const char *fmt, int w, double n)
{
/* buf needs to fit printf("%.20f", 1e20) */
char buf[50], *e;
sprintf(buf, fmt, w, n);
npf_snprintf(buf, 1024, fmt, w, n);
e = strchr(buf, 'e');
if (e) {
int exp = atoi(e+1);
sprintf(e, "e%+d", exp);
npf_snprintf(e, 1024, "e%+d", exp);
}
js_pushstring(J, buf);
}

View File

@@ -280,51 +280,59 @@ static void O_defineProperty(js_State *J)
js_copy(J, 1);
}
static void O_defineProperties_walk(js_State *J, js_Property *ref)
static int O_defineProperties_walk(js_State *J, js_Property *ref, int i)
{
if (ref->left->level)
O_defineProperties_walk(J, ref->left);
i = O_defineProperties_walk(J, ref->left, i);
if (!(ref->atts & JS_DONTENUM)) {
js_pushvalue(J, ref->value);
ToPropertyDescriptor(J, js_toobject(J, 1), ref->name, js_toobject(J, -1));
js_pop(J, 1);
if (ref->value.t.type != JS_TOBJECT)
js_typeerror(J, "not an object");
js_pushstring(J, ref->name);
js_setindex(J, -2, i++);
}
if (ref->right->level)
O_defineProperties_walk(J, ref->right);
i = O_defineProperties_walk(J, ref->right, i);
return i;
}
static void O_defineProperties_imp(js_State *J, js_Object *obj)
{
js_Object *props;
const char *name;
int i, n;
if (!js_isobject(J, 2)) js_typeerror(J, "not an object");
props = js_toobject(J, 2);
if (props->properties->level) {
js_newarray(J);
n = O_defineProperties_walk(J, props->properties, 0);
for (i = 0; i < n; ++i) {
js_getindex(J, -1, i);
name = js_tostring(J, -1);
if (js_hasproperty(J, 2, name)) {
ToPropertyDescriptor(J, obj, name, js_toobject(J, -1));
js_pop(J, 1);
}
js_pop(J, 1);
}
js_pop(J, 1);
}
}
static void O_defineProperties(js_State *J)
{
js_Object *props;
js_Object *obj;
if (!js_isobject(J, 1)) js_typeerror(J, "not an object");
if (!js_isobject(J, 2)) js_typeerror(J, "not an object");
props = js_toobject(J, 2);
if (props->properties->level)
O_defineProperties_walk(J, props->properties);
obj = js_toobject(J, 1);
O_defineProperties_imp(J, obj);
js_copy(J, 1);
}
static void O_create_walk(js_State *J, js_Object *obj, js_Property *ref)
{
if (ref->left->level)
O_create_walk(J, obj, ref->left);
if (!(ref->atts & JS_DONTENUM)) {
if (ref->value.t.type != JS_TOBJECT)
js_typeerror(J, "not an object");
ToPropertyDescriptor(J, obj, ref->name, ref->value.u.object);
}
if (ref->right->level)
O_create_walk(J, obj, ref->right);
}
static void O_create(js_State *J)
{
js_Object *obj;
js_Object *proto;
js_Object *props;
if (js_isobject(J, 1))
proto = js_toobject(J, 1);
@@ -337,11 +345,7 @@ static void O_create(js_State *J)
js_pushobject(J, obj);
if (js_isdefined(J, 2)) {
if (!js_isobject(J, 2))
js_typeerror(J, "not an object");
props = js_toobject(J, 2);
if (props->properties->level)
O_create_walk(J, obj, props->properties);
O_defineProperties_imp(J, obj);
}
}

View File

@@ -45,7 +45,6 @@ static void jsonexpect(js_State *J, int t)
static void jsonvalue(js_State *J)
{
int i;
const char *name;
switch (J->lookahead) {
case TK_STRING:
@@ -66,11 +65,12 @@ static void jsonvalue(js_State *J)
do {
if (J->lookahead != TK_STRING)
js_syntaxerror(J, "JSON: unexpected token: %s (expected string)", jsY_tokenstring(J->lookahead));
name = J->text;
js_pushstring(J, J->text);
jsonnext(J);
jsonexpect(J, ':');
jsonvalue(J);
js_setproperty(J, -2, name);
js_setproperty(J, -3, js_tostring(J, -2));
js_pop(J, 1);
} while (jsonaccept(J, ','));
jsonexpect(J, '}');
break;

View File

@@ -99,7 +99,7 @@ static js_Ast *jsP_list(js_Ast *head)
static js_Ast *jsP_newstrnode(js_State *J, enum js_AstType type, const char *s)
{
js_Ast *node = jsP_newnode(J, type, J->lexline, 0, 0, 0, 0);
node->string = s;
node->string = js_intern(J, s);
return node;
}

View File

@@ -35,9 +35,29 @@ static void js_outofmemory(js_State *J)
js_throw(J);
}
static void js_runlimit(js_State *J)
{
STACK[TOP].t.type = JS_TLITSTR;
STACK[TOP].u.litstr = "script ran too long";
++TOP;
js_throw(J);
}
void js_setlimit(js_State *J, int runlimit, int memlimit)
{
J->runlimit = runlimit;
J->memlimit = memlimit;
}
void *js_malloc(js_State *J, int size)
{
void *ptr = J->alloc(J->actx, NULL, size);
void *ptr;
if (J->memlimit > 0) {
if (size >= J->memlimit)
js_outofmemory(J);
J->memlimit -= size;
}
ptr = J->alloc(J->actx, NULL, size);
if (!ptr)
js_outofmemory(J);
return ptr;
@@ -45,6 +65,12 @@ void *js_malloc(js_State *J, int size)
void *js_realloc(js_State *J, void *ptr, int size)
{
if (J->memlimit > 0) {
// TODO: track released memory
if (size >= J->memlimit)
js_outofmemory(J);
J->memlimit -= size;
}
ptr = J->alloc(J->actx, ptr, size);
if (!ptr)
js_outofmemory(J);
@@ -61,6 +87,7 @@ char *js_strdup(js_State *J, const char *s)
void js_free(js_State *J, void *ptr)
{
// TODO: track released memory (J->memlimit)
J->alloc(J->actx, ptr, 0);
}
@@ -919,11 +946,11 @@ const char *js_ref(js_State *J)
s = v->u.boolean ? "_True" : "_False";
break;
case JS_TOBJECT:
sprintf(buf, "%p", (void*)v->u.object);
npf_snprintf(buf, 1024, "%p", (void*)v->u.object);
s = js_intern(J, buf);
break;
default:
sprintf(buf, "%d", J->nextref++);
npf_snprintf(buf, 1024, "%d", J->nextref++);
s = js_intern(J, buf);
break;
}
@@ -1547,7 +1574,7 @@ static int jsR_isindex(js_State *J, int idx, int *k)
static void jsR_run(js_State *J, js_Function *F)
{
js_Function **FT = F->funtab;
const char **VT = F->vartab-1;
const char **VT = F->vartab ? F->vartab - 1 : NULL;
int lightweight = F->lightweight;
js_Instruction *pcstart = F->code;
js_Instruction *pc = F->code;
@@ -1571,6 +1598,12 @@ static void jsR_run(js_State *J, js_Function *F)
pc += sizeof(str) / sizeof(*pc)
while (1) {
if (J->runlimit > 0) {
if (J->runlimit == 1)
js_runlimit(J);
--J->runlimit;
}
if (J->gccounter > J->gcthresh)
js_gc(J, 0);

View File

@@ -288,8 +288,10 @@ static void Sp_slice(js_State *J)
if (s < e)
Sp_substring_imp(J, str, s, e - s);
else
else if (s > e)
Sp_substring_imp(J, str, e, s - e);
else
js_pushliteral(J, "");
}
static void Sp_substring(js_State *J)
@@ -304,8 +306,10 @@ static void Sp_substring(js_State *J)
if (s < e)
Sp_substring_imp(J, str, s, e - s);
else
else if (s > e)
Sp_substring_imp(J, str, e, s - e);
else
js_pushliteral(J, "");
}
static void Sp_toLowerCase(js_State *J)
@@ -543,6 +547,11 @@ static void Sp_replace_regexp(js_State *J)
re->last = 0;
if (js_try(J)) {
js_free(J, sb);
js_throw(J);
}
loop:
s = m.sub[0].sp;
n = m.sub[0].ep - m.sub[0].sp;
@@ -618,10 +627,6 @@ end:
js_puts(J, &sb, s + n);
js_putc(J, &sb, 0);
if (js_try(J)) {
js_free(J, sb);
js_throw(J);
}
js_pushstring(J, sb ? sb->s : "");
js_endtry(J);
js_free(J, sb);
@@ -643,6 +648,11 @@ static void Sp_replace_string(js_State *J)
}
n = strlen(needle);
if (js_try(J)) {
js_free(J, sb);
js_throw(J);
}
if (js_iscallable(J, 2)) {
js_copy(J, 2);
js_pushundefined(J);
@@ -679,10 +689,6 @@ static void Sp_replace_string(js_State *J)
js_putc(J, &sb, 0);
}
if (js_try(J)) {
js_free(J, sb);
js_throw(J);
}
js_pushstring(J, sb ? sb->s : "");
js_endtry(J);
js_free(J, sb);

View File

@@ -170,7 +170,7 @@ const char *js_itoa(char *out, int v)
unsigned int a;
int i = 0;
if (v < 0) {
a = -v;
a = -(unsigned)v; /* cast to avoid -INT_MIN signed overflow UB */
*s++ = '-';
} else {
a = v;

View File

@@ -94,6 +94,53 @@ char *readline(const char *prompt)
#define PS1 "> "
static int eval_file(js_State *J, const char* filename)
{
char* source = (char*)os_call_ext_str_3("FileRead", (uint64_t)filename, 0, 0);
if (!source) {
js_pushundefined(J);
return 1;
}
int res = js_ploadstring(J, filename, source);
free(source);
if (res) {
fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
js_pop(J, 1);
return 1;
}
js_pushundefined(J);
if (js_pcall(J, 0)) {
fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
js_pop(J, 1);
return 1;
}
if (js_isdefined(J, -1)) {
printf("%s\n", js_tryrepr(J, -1, "can't convert to string"));
}
js_pop(J, 1);
return 0;
}
static int eval_print(js_State *J, const char *source)
{
if (js_ploadstring(J, "[stdin]", source)) {
fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
js_pop(J, 1);
return 1;
}
js_pushundefined(J);
if (js_pcall(J, 0)) {
fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
js_pop(J, 1);
return 1;
}
if (js_isdefined(J, -1)) {
printf("%s\n", js_tryrepr(J, -1, "can't convert to string"));
}
js_pop(J, 1);
return 0;
}
static void jsB_gc(js_State *J)
{
int report = js_toboolean(J, 1);
@@ -103,14 +150,7 @@ static void jsB_gc(js_State *J)
static void jsB_load(js_State *J)
{
int i, n = js_gettop(J);
for (i = 1; i < n; ++i) {
js_loadfile(J, js_tostring(J, i));
js_pushundefined(J);
js_call(J, 0);
js_pop(J, 1);
}
js_pushundefined(J);
eval_file(J, js_tostring(J, 1));
}
static void jsB_compile(js_State *J)
@@ -164,49 +204,13 @@ static void jsB_write(js_State *J)
static void jsB_read(js_State *J)
{
const char *filename = js_tostring(J, 1);
FILE *f;
char *s;
int n, t;
f = fopen(filename, "rb");
if (!f) {
js_error(J, "cannot open file '%s': %s", filename, strerror(errno));
}
if (fseek(f, 0, SEEK_END) < 0) {
fclose(f);
js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno));
}
n = ftell(f);
if (n < 0) {
fclose(f);
js_error(J, "cannot tell in file '%s': %s", filename, strerror(errno));
}
if (fseek(f, 0, SEEK_SET) < 0) {
fclose(f);
js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno));
}
s = malloc(n + 1);
char *s = (char*)os_call_ext_str_3("FileRead", (uint64_t)js_tostring(J, 1), 0, 0);
if (!s) {
fclose(f);
js_error(J, "out of memory");
js_pushundefined(J);
return;
}
t = fread(s, 1, n, f);
if (t != n) {
free(s);
fclose(f);
js_error(J, "cannot read data from file '%s': %s", filename, strerror(errno));
}
s[n] = 0;
js_pushstring(J, s);
free(s);
fclose(f);
}
static void jsB_readline(js_State *J)
@@ -258,49 +262,6 @@ static const char *console_js =
"var console = { log: print, debug: print, warn: print, error: print };"
;
static int eval_file(js_State *J, const char* filename)
{
char* source = (char*)os_call_ext_str_3("FileRead", (uint64_t)filename, 0, 0);
int res = js_ploadstring(J, filename, source);
free(source);
if (res) {
fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
js_pop(J, 1);
return 1;
}
js_pushundefined(J);
if (js_pcall(J, 0)) {
fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
js_pop(J, 1);
return 1;
}
if (js_isdefined(J, -1)) {
printf("%s\n", js_tryrepr(J, -1, "can't convert to string"));
}
js_pop(J, 1);
return 0;
}
static int eval_print(js_State *J, const char *source)
{
if (js_ploadstring(J, "[stdin]", source)) {
fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
js_pop(J, 1);
return 1;
}
js_pushundefined(J);
if (js_pcall(J, 0)) {
fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
js_pop(J, 1);
return 1;
}
if (js_isdefined(J, -1)) {
printf("%s\n", js_tryrepr(J, -1, "can't convert to string"));
}
js_pop(J, 1);
return 0;
}
static void usage(void)
{
fprintf(stderr, "Usage: mujs [options] [script [scriptArgs*]]\n");

View File

@@ -9,7 +9,7 @@ extern "C" {
#define JS_VERSION_MAJOR 1
#define JS_VERSION_MINOR 3
#define JS_VERSION_PATCH 5
#define JS_VERSION_PATCH 8
#define JS_VERSION (JS_VERSION_MAJOR * 10000 + JS_VERSION_MINOR * 100 + JS_VERSION_PATCH)
#define JS_CHECKVERSION(x,y,z) (JS_VERSION >= ((x) * 10000 + (y) * 100 + (z)))
@@ -56,6 +56,7 @@ void js_setreport(js_State *J, js_Report report);
js_Panic js_atpanic(js_State *J, js_Panic panic);
void js_freestate(js_State *J);
void js_gc(js_State *J, int report);
void js_setlimit(js_State *J, int runlimit, int memlimit);
int js_dostring(js_State *J, const char *source);
int js_dofile(js_State *J, const char *filename);

View File

@@ -147,7 +147,7 @@ static int nextrune(struct cstate *g)
g->yychar = '0';
return 1;
}
return 0;
return 1;
case 'u':
if (!g->source[0] || !g->source[1] || !g->source[2] || !g->source[3])
die(g, "unterminated escape sequence");
@@ -159,7 +159,7 @@ static int nextrune(struct cstate *g)
g->yychar = '0';
return 1;
}
return 0;
return 1;
case 0:
g->yychar = '0';
return 1;

View File

@@ -37,7 +37,7 @@ endif()
list(APPEND C_ASM_COMPILE_FLAGS "-ffp-contract=off" "-fno-fast-math" "-fno-rounding-math" "-fno-math-errno")
list(APPEND C_ASM_COMPILE_FLAGS "-fPIC" "-std=c99" "-fno-builtin")
list(APPEND C_ASM_COMPILE_FLAGS "-Wall" "-Wno-implicit-function-declaration")
list(APPEND C_ASM_COMPILE_FLAGS "-DASSEMBLER" "-D__BSD_VISIBLE" "-O3")
list(APPEND C_ASM_COMPILE_FLAGS "-DASSEMBLER" "-D__BSD_VISIBLE" "-O0 --mno-red-zone --mno-mmx")
# Compiler-specific compile flags
if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang")

View File

@@ -106,7 +106,7 @@ endif
# If CFLAGS does not contain a -O optimization flag, default to -O3
ifeq ($(findstring -O,$(CFLAGS)),)
CFLAGS_add += -O3
CFLAGS_add += -O0 -mno-red-zone -mno-mmx
endif
ifneq (,$(findstring MINGW,$(OS)))