mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 14:47:37 +03:00
Compare commits
6 Commits
13d66e0f48
...
06f545e65e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06f545e65e | ||
|
|
e5c0ddc9fa | ||
|
|
b1dcb7733b | ||
|
|
0d82b03981 | ||
|
|
5a97334ace | ||
|
|
49d2c5eba8 |
14
README.md
14
README.md
@ -95,6 +95,20 @@ Connect your Xteink X4 to your computer via USB-C and run the following command.
|
||||
```sh
|
||||
pio run --target upload
|
||||
```
|
||||
### Debugging
|
||||
|
||||
After flashing the new features, it’s recommended to capture detailed logs from the serial port.
|
||||
|
||||
First, make sure all required Python packages are installed:
|
||||
|
||||
```python
|
||||
python3 -m pip install serial colorama matplotlib
|
||||
```
|
||||
after that run the script:
|
||||
```sh
|
||||
python3 scripts/debugging_monitor.py
|
||||
```
|
||||
This was tested on Debian and should work on most Linux systems. Minor adjustments may be required for Windows or macOS.
|
||||
|
||||
## Internals
|
||||
|
||||
|
||||
@ -415,13 +415,21 @@ void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const
|
||||
|
||||
std::string GfxRenderer::truncatedText(const int fontId, const char* text, const int maxWidth,
|
||||
const EpdFontFamily::Style style) const {
|
||||
if (!text || maxWidth <= 0) return "";
|
||||
|
||||
std::string item = text;
|
||||
int itemWidth = getTextWidth(fontId, item.c_str(), style);
|
||||
while (itemWidth > maxWidth && item.length() > 8) {
|
||||
item.replace(item.length() - 5, 5, "...");
|
||||
itemWidth = getTextWidth(fontId, item.c_str(), style);
|
||||
const char* ellipsis = "...";
|
||||
int textWidth = getTextWidth(fontId, item.c_str(), style);
|
||||
if (textWidth <= maxWidth) {
|
||||
// Text fits, return as is
|
||||
return item;
|
||||
}
|
||||
return item;
|
||||
|
||||
while (!item.empty() && getTextWidth(fontId, (item + ellipsis).c_str(), style) >= maxWidth) {
|
||||
utf8RemoveLastChar(item);
|
||||
}
|
||||
|
||||
return item.empty() ? ellipsis : item + ellipsis;
|
||||
}
|
||||
|
||||
// Note: Internal driver treats screen in command orientation; this library exposes a logical orientation
|
||||
|
||||
@ -29,3 +29,20 @@ uint32_t utf8NextCodepoint(const unsigned char** string) {
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
size_t utf8RemoveLastChar(std::string& str) {
|
||||
if (str.empty()) return 0;
|
||||
size_t pos = str.size() - 1;
|
||||
while (pos > 0 && (static_cast<unsigned char>(str[pos]) & 0xC0) == 0x80) {
|
||||
--pos;
|
||||
}
|
||||
str.resize(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Truncate string by removing N UTF-8 characters from the end
|
||||
void utf8TruncateChars(std::string& str, const size_t numChars) {
|
||||
for (size_t i = 0; i < numChars && !str.empty(); ++i) {
|
||||
utf8RemoveLastChar(str);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <string>
|
||||
#define REPLACEMENT_GLYPH 0xFFFD
|
||||
|
||||
uint32_t utf8NextCodepoint(const unsigned char** string);
|
||||
// Remove the last UTF-8 codepoint from a std::string and return the new size.
|
||||
size_t utf8RemoveLastChar(std::string& str);
|
||||
// Truncate string by removing N UTF-8 codepoints from the end.
|
||||
void utf8TruncateChars(std::string& str, size_t numChars);
|
||||
|
||||
22
lib/mquickjs/LICENSE
Normal file
22
lib/mquickjs/LICENSE
Normal file
@ -0,0 +1,22 @@
|
||||
Micro QuickJS Javascript Engine
|
||||
|
||||
Copyright (c) 2017-2025 Fabrice Bellard
|
||||
Copyright (c) 2017-2025 Charlie Gordon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
158
lib/mquickjs/Makefile
Normal file
158
lib/mquickjs/Makefile
Normal file
@ -0,0 +1,158 @@
|
||||
#CONFIG_PROFILE=y
|
||||
#CONFIG_X86_32=y
|
||||
#CONFIG_ARM32=y
|
||||
#CONFIG_WIN32=y
|
||||
#CONFIG_SOFTFLOAT=y
|
||||
#CONFIG_ASAN=y
|
||||
#CONFIG_GPROF=y
|
||||
CONFIG_SMALL=y
|
||||
# consider warnings as errors (for development)
|
||||
#CONFIG_WERROR=y
|
||||
|
||||
ifdef CONFIG_ARM32
|
||||
CROSS_PREFIX=arm-linux-gnu-
|
||||
endif
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
ifdef CONFIG_X86_32
|
||||
CROSS_PREFIX?=i686-w64-mingw32-
|
||||
else
|
||||
CROSS_PREFIX?=x86_64-w64-mingw32-
|
||||
endif
|
||||
EXE=.exe
|
||||
else
|
||||
CROSS_PREFIX?=
|
||||
EXE=
|
||||
endif
|
||||
|
||||
HOST_CC=gcc
|
||||
CC=$(CROSS_PREFIX)gcc
|
||||
CFLAGS=-Wall -g -MMD -D_GNU_SOURCE -fno-math-errno -fno-trapping-math
|
||||
HOST_CFLAGS=-Wall -g -MMD -D_GNU_SOURCE -fno-math-errno -fno-trapping-math
|
||||
ifdef CONFIG_WERROR
|
||||
CFLAGS+=-Werror
|
||||
HOST_CFLAGS+=-Werror
|
||||
endif
|
||||
ifdef CONFIG_ARM32
|
||||
CFLAGS+=-mthumb
|
||||
endif
|
||||
ifdef CONFIG_SMALL
|
||||
CFLAGS+=-Os
|
||||
else
|
||||
CFLAGS+=-O2
|
||||
endif
|
||||
#CFLAGS+=-fstack-usage
|
||||
ifdef CONFIG_SOFTFLOAT
|
||||
CFLAGS+=-msoft-float
|
||||
CFLAGS+=-DUSE_SOFTFLOAT
|
||||
endif # CONFIG_SOFTFLOAT
|
||||
HOST_CFLAGS+=-O2
|
||||
LDFLAGS=-g
|
||||
HOST_LDFLAGS=-g
|
||||
ifdef CONFIG_GPROF
|
||||
CFLAGS+=-p
|
||||
LDFLAGS+=-p
|
||||
endif
|
||||
ifdef CONFIG_ASAN
|
||||
CFLAGS+=-fsanitize=address -fno-omit-frame-pointer
|
||||
LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer
|
||||
endif
|
||||
ifdef CONFIG_X86_32
|
||||
CFLAGS+=-m32
|
||||
LDFLAGS+=-m32
|
||||
endif
|
||||
ifdef CONFIG_PROFILE
|
||||
CFLAGS+=-p
|
||||
LDFLAGS+=-p
|
||||
endif
|
||||
|
||||
# when cross compiling from a 64 bit system to a 32 bit system, force
|
||||
# a 32 bit output
|
||||
ifdef CONFIG_X86_32
|
||||
MQJS_BUILD_FLAGS=-m32
|
||||
endif
|
||||
ifdef CONFIG_ARM32
|
||||
MQJS_BUILD_FLAGS=-m32
|
||||
endif
|
||||
|
||||
PROGS=mqjs$(EXE) example$(EXE)
|
||||
TEST_PROGS=dtoa_test libm_test
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
MQJS_OBJS=mqjs.o readline_tty.o readline.o mquickjs.o dtoa.o libm.o cutils.o
|
||||
LIBS=-lm
|
||||
|
||||
mqjs$(EXE): $(MQJS_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
mquickjs.o: mquickjs_atom.h
|
||||
|
||||
mqjs_stdlib: mqjs_stdlib.host.o mquickjs_build.host.o
|
||||
$(HOST_CC) $(HOST_LDFLAGS) -o $@ $^
|
||||
|
||||
mquickjs_atom.h: mqjs_stdlib
|
||||
./mqjs_stdlib -a $(MQJS_BUILD_FLAGS) > $@
|
||||
|
||||
mqjs_stdlib.h: mqjs_stdlib
|
||||
./mqjs_stdlib $(MQJS_BUILD_FLAGS) > $@
|
||||
|
||||
mqjs.o: mqjs_stdlib.h
|
||||
|
||||
# C API example
|
||||
example.o: example_stdlib.h
|
||||
|
||||
example$(EXE): example.o mquickjs.o dtoa.o libm.o cutils.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
example_stdlib: example_stdlib.host.o mquickjs_build.host.o
|
||||
$(HOST_CC) $(HOST_LDFLAGS) -o $@ $^
|
||||
|
||||
example_stdlib.h: example_stdlib
|
||||
./example_stdlib $(MQJS_BUILD_FLAGS) > $@
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
%.host.o: %.c
|
||||
$(HOST_CC) $(HOST_CFLAGS) -c -o $@ $<
|
||||
|
||||
test: mqjs example
|
||||
./mqjs tests/test_closure.js
|
||||
./mqjs tests/test_language.js
|
||||
./mqjs tests/test_loop.js
|
||||
./mqjs tests/test_builtin.js
|
||||
# test bytecode generation and loading
|
||||
./mqjs -o test_builtin.bin tests/test_builtin.js
|
||||
# @sha256sum -c test_builtin.sha256
|
||||
./mqjs -b test_builtin.bin
|
||||
./example tests/test_rect.js
|
||||
|
||||
microbench: mqjs
|
||||
./mqjs tests/microbench.js
|
||||
|
||||
octane: mqjs
|
||||
./mqjs --memory-limit 256M tests/octane/run.js
|
||||
|
||||
size: mqjs
|
||||
size mqjs mqjs.o readline.o cutils.o dtoa.o libm.o mquickjs.o
|
||||
|
||||
dtoa_test: tests/dtoa_test.o dtoa.o cutils.o tests/gay-fixed.o tests/gay-precision.o tests/gay-shortest.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
libm_test: tests/libm_test.o libm.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
rempio2_test: tests/rempio2_test.o libm.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f *.o *.d *~ tests/*.o tests/*.d tests/*~ test_builtin.bin mqjs_stdlib mqjs_stdlib.h mquickjs_build_atoms mquickjs_atom.h mqjs_example example_stdlib example_stdlib.h $(PROGS) $(TEST_PROGS)
|
||||
|
||||
-include $(wildcard *.d)
|
||||
|
||||
|
||||
# ADDED FOR CROSSPOINT
|
||||
mqjs_stdlib.host.o: scripts/crosspoint_stdlib.c
|
||||
$(HOST_CC) $(HOST_CFLAGS) -c -o $@ $<
|
||||
# END OF ADDED PART
|
||||
3344
lib/mquickjs/crosspoint_stdlib.h
Normal file
3344
lib/mquickjs/crosspoint_stdlib.h
Normal file
File diff suppressed because it is too large
Load Diff
178
lib/mquickjs/cutils.c
Normal file
178
lib/mquickjs/cutils.c
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* C utilities
|
||||
*
|
||||
* Copyright (c) 2017 Fabrice Bellard
|
||||
* Copyright (c) 2018 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cutils.h"
|
||||
|
||||
void pstrcpy(char *buf, int buf_size, const char *str)
|
||||
{
|
||||
int c;
|
||||
char *q = buf;
|
||||
|
||||
if (buf_size <= 0)
|
||||
return;
|
||||
|
||||
for(;;) {
|
||||
c = *str++;
|
||||
if (c == 0 || q >= buf + buf_size - 1)
|
||||
break;
|
||||
*q++ = c;
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
/* strcat and truncate. */
|
||||
char *pstrcat(char *buf, int buf_size, const char *s)
|
||||
{
|
||||
int len;
|
||||
len = strlen(buf);
|
||||
if (len < buf_size)
|
||||
pstrcpy(buf + len, buf_size - len, s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int strstart(const char *str, const char *val, const char **ptr)
|
||||
{
|
||||
const char *p, *q;
|
||||
p = str;
|
||||
q = val;
|
||||
while (*q != '\0') {
|
||||
if (*p != *q)
|
||||
return 0;
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
if (ptr)
|
||||
*ptr = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int has_suffix(const char *str, const char *suffix)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
size_t slen = strlen(suffix);
|
||||
return (len >= slen && !memcmp(str + len - slen, suffix, slen));
|
||||
}
|
||||
|
||||
size_t __unicode_to_utf8(uint8_t *buf, unsigned int c)
|
||||
{
|
||||
uint8_t *q = buf;
|
||||
|
||||
if (c < 0x800) {
|
||||
*q++ = (c >> 6) | 0xc0;
|
||||
} else {
|
||||
if (c < 0x10000) {
|
||||
*q++ = (c >> 12) | 0xe0;
|
||||
} else {
|
||||
if (c < 0x00200000) {
|
||||
*q++ = (c >> 18) | 0xf0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
*q++ = ((c >> 12) & 0x3f) | 0x80;
|
||||
}
|
||||
*q++ = ((c >> 6) & 0x3f) | 0x80;
|
||||
}
|
||||
*q++ = (c & 0x3f) | 0x80;
|
||||
return q - buf;
|
||||
}
|
||||
|
||||
int __unicode_from_utf8(const uint8_t *p, size_t max_len, size_t *plen)
|
||||
{
|
||||
size_t len = 1;
|
||||
int c;
|
||||
|
||||
c = p[0];
|
||||
if (c < 0xc0) {
|
||||
goto fail;
|
||||
} else if (c < 0xe0) {
|
||||
if (unlikely(max_len < 2 || (p[1] & 0xc0) != 0x80))
|
||||
goto fail;
|
||||
c = ((p[0] & 0x1f) << 6) | (p[1] & 0x3f);
|
||||
len = 2;
|
||||
if (unlikely(c < 0x80))
|
||||
goto fail;
|
||||
} else if (c < 0xf0) {
|
||||
if (unlikely(max_len < 2 || (p[1] & 0xc0) != 0x80))
|
||||
goto fail;
|
||||
if (unlikely(max_len < 3 || (p[2] & 0xc0) != 0x80)) {
|
||||
len = 2;
|
||||
goto fail;
|
||||
}
|
||||
c = ((p[0] & 0x0f) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f);
|
||||
len = 3;
|
||||
if (unlikely(c < 0x800))
|
||||
goto fail;
|
||||
} else if (c < 0xf8) {
|
||||
if (unlikely(max_len < 2 || (p[1] & 0xc0) != 0x80))
|
||||
goto fail;
|
||||
if (unlikely(max_len < 3 || (p[2] & 0xc0) != 0x80)) {
|
||||
len = 2;
|
||||
goto fail;
|
||||
}
|
||||
if (unlikely(max_len < 4 || (p[3] & 0xc0) != 0x80)) {
|
||||
len = 3;
|
||||
goto fail;
|
||||
}
|
||||
c = ((p[0] & 0x07) << 18) | ((p[1] & 0x3f) << 12) | ((p[2] & 0x3f) << 6) | (p[3] & 0x3f);
|
||||
len = 4;
|
||||
/* We explicitly accept surrogate pairs */
|
||||
if (unlikely(c < 0x10000 || c > 0x10ffff))
|
||||
goto fail;
|
||||
} else {
|
||||
fail:
|
||||
*plen = len;
|
||||
return -1;
|
||||
}
|
||||
*plen = len;
|
||||
return c;
|
||||
}
|
||||
|
||||
int __utf8_get(const uint8_t *p, size_t *plen)
|
||||
{
|
||||
size_t len;
|
||||
int c;
|
||||
|
||||
c = p[0];
|
||||
if (c < 0xc0) {
|
||||
len = 1;
|
||||
} else if (c < 0xe0) {
|
||||
c = ((p[0] & 0x1f) << 6) | (p[1] & 0x3f);
|
||||
len = 2;
|
||||
} else if (c < 0xf0) {
|
||||
c = ((p[0] & 0x0f) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f);
|
||||
len = 3;
|
||||
} else if (c < 0xf8) {
|
||||
c = ((p[0] & 0x07) << 18) | ((p[1] & 0x3f) << 12) | ((p[2] & 0x3f) << 6) | (p[3] & 0x3f);
|
||||
len = 4;
|
||||
} else {
|
||||
len = 1;
|
||||
}
|
||||
*plen = len;
|
||||
return c;
|
||||
}
|
||||
355
lib/mquickjs/cutils.h
Normal file
355
lib/mquickjs/cutils.h
Normal file
@ -0,0 +1,355 @@
|
||||
/*
|
||||
* C utilities
|
||||
*
|
||||
* Copyright (c) 2017 Fabrice Bellard
|
||||
* Copyright (c) 2018 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef CUTILS_H
|
||||
#define CUTILS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/* set if CPU is big endian */
|
||||
#undef WORDS_BIGENDIAN
|
||||
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#define force_inline inline __attribute__((always_inline))
|
||||
#define no_inline __attribute__((noinline))
|
||||
#define __maybe_unused __attribute__((unused))
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
#define stringify(s) tostring(s)
|
||||
#define tostring(s) #s
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
#ifndef countof
|
||||
#define countof(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
/* return the pointer of type 'type *' containing 'ptr' as field 'member' */
|
||||
#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))
|
||||
|
||||
typedef int BOOL;
|
||||
|
||||
#ifndef FALSE
|
||||
enum {
|
||||
FALSE = 0,
|
||||
TRUE = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
void pstrcpy(char *buf, int buf_size, const char *str);
|
||||
char *pstrcat(char *buf, int buf_size, const char *s);
|
||||
int strstart(const char *str, const char *val, const char **ptr);
|
||||
int has_suffix(const char *str, const char *suffix);
|
||||
|
||||
static inline int max_int(int a, int b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline int min_int(int a, int b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline uint32_t max_uint32(uint32_t a, uint32_t b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline uint32_t min_uint32(uint32_t a, uint32_t b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline int64_t max_int64(int64_t a, int64_t b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline int64_t min_int64(int64_t a, int64_t b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline size_t max_size_t(size_t a, size_t b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline size_t min_size_t(size_t a, size_t b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int clz32(unsigned int a)
|
||||
{
|
||||
return __builtin_clz(a);
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int clz64(uint64_t a)
|
||||
{
|
||||
return __builtin_clzll(a);
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int ctz32(unsigned int a)
|
||||
{
|
||||
return __builtin_ctz(a);
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int ctz64(uint64_t a)
|
||||
{
|
||||
return __builtin_ctzll(a);
|
||||
}
|
||||
|
||||
struct __attribute__((packed)) packed_u64 {
|
||||
uint64_t v;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) packed_u32 {
|
||||
uint32_t v;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) packed_u16 {
|
||||
uint16_t v;
|
||||
};
|
||||
|
||||
static inline uint64_t get_u64(const uint8_t *tab)
|
||||
{
|
||||
return ((const struct packed_u64 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline int64_t get_i64(const uint8_t *tab)
|
||||
{
|
||||
return (int64_t)((const struct packed_u64 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline void put_u64(uint8_t *tab, uint64_t val)
|
||||
{
|
||||
((struct packed_u64 *)tab)->v = val;
|
||||
}
|
||||
|
||||
static inline uint32_t get_u32(const uint8_t *tab)
|
||||
{
|
||||
return ((const struct packed_u32 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline int32_t get_i32(const uint8_t *tab)
|
||||
{
|
||||
return (int32_t)((const struct packed_u32 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline void put_u32(uint8_t *tab, uint32_t val)
|
||||
{
|
||||
((struct packed_u32 *)tab)->v = val;
|
||||
}
|
||||
|
||||
static inline uint32_t get_u16(const uint8_t *tab)
|
||||
{
|
||||
return ((const struct packed_u16 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline int32_t get_i16(const uint8_t *tab)
|
||||
{
|
||||
return (int16_t)((const struct packed_u16 *)tab)->v;
|
||||
}
|
||||
|
||||
static inline void put_u16(uint8_t *tab, uint16_t val)
|
||||
{
|
||||
((struct packed_u16 *)tab)->v = val;
|
||||
}
|
||||
|
||||
static inline uint32_t get_u8(const uint8_t *tab)
|
||||
{
|
||||
return *tab;
|
||||
}
|
||||
|
||||
static inline int32_t get_i8(const uint8_t *tab)
|
||||
{
|
||||
return (int8_t)*tab;
|
||||
}
|
||||
|
||||
static inline void put_u8(uint8_t *tab, uint8_t val)
|
||||
{
|
||||
*tab = val;
|
||||
}
|
||||
|
||||
static inline uint16_t bswap16(uint16_t x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
|
||||
static inline uint32_t bswap32(uint32_t v)
|
||||
{
|
||||
return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
|
||||
((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
|
||||
}
|
||||
|
||||
static inline uint64_t bswap64(uint64_t v)
|
||||
{
|
||||
return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
|
||||
((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) |
|
||||
((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) |
|
||||
((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) |
|
||||
((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) |
|
||||
((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) |
|
||||
((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
|
||||
((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));
|
||||
}
|
||||
|
||||
static inline uint32_t get_be32(const uint8_t *d)
|
||||
{
|
||||
return bswap32(get_u32(d));
|
||||
}
|
||||
|
||||
static inline void put_be32(uint8_t *d, uint32_t v)
|
||||
{
|
||||
put_u32(d, bswap32(v));
|
||||
}
|
||||
|
||||
#define UTF8_CHAR_LEN_MAX 4
|
||||
|
||||
size_t __unicode_to_utf8(uint8_t *buf, unsigned int c);
|
||||
int __unicode_from_utf8(const uint8_t *p, size_t max_len, size_t *plen);
|
||||
int __utf8_get(const uint8_t *p, size_t *plen);
|
||||
|
||||
/* Note: at most 21 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes
|
||||
are output. */
|
||||
static inline size_t unicode_to_utf8(uint8_t *buf, unsigned int c)
|
||||
{
|
||||
if (c < 0x80) {
|
||||
buf[0] = c;
|
||||
return 1;
|
||||
} else {
|
||||
return __unicode_to_utf8(buf, c);
|
||||
}
|
||||
}
|
||||
|
||||
/* return -1 in case of error. Surrogates are accepted. max_len must
|
||||
be >= 1. *plen is set in case of error and always >= 1. */
|
||||
static inline int unicode_from_utf8(const uint8_t *buf, size_t max_len, size_t *plen)
|
||||
{
|
||||
if (buf[0] < 0x80) {
|
||||
*plen = 1;
|
||||
return buf[0];
|
||||
} else {
|
||||
return __unicode_from_utf8(buf, max_len, plen);
|
||||
}
|
||||
}
|
||||
|
||||
/* Warning: no error checking is done so the UTF-8 encoding must be
|
||||
validated before. */
|
||||
static force_inline int utf8_get(const uint8_t *buf, size_t *plen)
|
||||
{
|
||||
if (likely(buf[0] < 0x80)) {
|
||||
*plen = 1;
|
||||
return buf[0];
|
||||
} else {
|
||||
return __utf8_get(buf, plen);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int from_hex(int c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline uint64_t float64_as_uint64(double d)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
} u;
|
||||
u.d = d;
|
||||
return u.u64;
|
||||
}
|
||||
|
||||
static inline double uint64_as_float64(uint64_t u64)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
} u;
|
||||
u.u64 = u64;
|
||||
return u.d;
|
||||
}
|
||||
|
||||
typedef union {
|
||||
uint32_t u32;
|
||||
float f;
|
||||
} f32_union;
|
||||
|
||||
static inline uint32_t float_as_uint(float f)
|
||||
{
|
||||
f32_union u;
|
||||
u.f = f;
|
||||
return u.u32;
|
||||
}
|
||||
|
||||
static inline float uint_as_float(uint32_t v)
|
||||
{
|
||||
f32_union u;
|
||||
u.u32 = v;
|
||||
return u.f;
|
||||
}
|
||||
|
||||
#endif /* CUTILS_H */
|
||||
1620
lib/mquickjs/dtoa.c
Normal file
1620
lib/mquickjs/dtoa.c
Normal file
File diff suppressed because it is too large
Load Diff
83
lib/mquickjs/dtoa.h
Normal file
83
lib/mquickjs/dtoa.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Tiny float64 printing and parsing library
|
||||
*
|
||||
* Copyright (c) 2024-2025 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
//#define JS_DTOA_DUMP_STATS
|
||||
|
||||
/* maximum number of digits for fixed and frac formats */
|
||||
#define JS_DTOA_MAX_DIGITS 101
|
||||
|
||||
/* radix != 10 is only supported with flags = JS_DTOA_FORMAT_FREE */
|
||||
/* use as many digits as necessary */
|
||||
#define JS_DTOA_FORMAT_FREE (0 << 0)
|
||||
/* use n_digits significant digits (1 <= n_digits <= JS_DTOA_MAX_DIGITS) */
|
||||
#define JS_DTOA_FORMAT_FIXED (1 << 0)
|
||||
/* force fractional format: [-]dd.dd with n_digits fractional digits.
|
||||
0 <= n_digits <= JS_DTOA_MAX_DIGITS */
|
||||
#define JS_DTOA_FORMAT_FRAC (2 << 0)
|
||||
#define JS_DTOA_FORMAT_MASK (3 << 0)
|
||||
|
||||
/* select exponential notation either in fixed or free format */
|
||||
#define JS_DTOA_EXP_AUTO (0 << 2)
|
||||
#define JS_DTOA_EXP_ENABLED (1 << 2)
|
||||
#define JS_DTOA_EXP_DISABLED (2 << 2)
|
||||
#define JS_DTOA_EXP_MASK (3 << 2)
|
||||
|
||||
#define JS_DTOA_MINUS_ZERO (1 << 4) /* show the minus sign for -0 */
|
||||
|
||||
/* only accepts integers (no dot, no exponent) */
|
||||
#define JS_ATOD_INT_ONLY (1 << 0)
|
||||
/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
|
||||
#define JS_ATOD_ACCEPT_BIN_OCT (1 << 1)
|
||||
/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
|
||||
#define JS_ATOD_ACCEPT_LEGACY_OCTAL (1 << 2)
|
||||
/* accept _ between digits as a digit separator */
|
||||
#define JS_ATOD_ACCEPT_UNDERSCORES (1 << 3)
|
||||
|
||||
typedef struct {
|
||||
uint64_t mem[37];
|
||||
} JSDTOATempMem;
|
||||
|
||||
typedef struct {
|
||||
uint64_t mem[27];
|
||||
} JSATODTempMem;
|
||||
|
||||
/* return a maximum bound of the string length */
|
||||
int js_dtoa_max_len(double d, int radix, int n_digits, int flags);
|
||||
/* return the string length */
|
||||
int js_dtoa(char *buf, double d, int radix, int n_digits, int flags,
|
||||
JSDTOATempMem *tmp_mem);
|
||||
double js_atod(const char *str, const char **pnext, int radix, int flags,
|
||||
JSATODTempMem *tmp_mem);
|
||||
|
||||
#ifdef JS_DTOA_DUMP_STATS
|
||||
void js_dtoa_dump_stats(void);
|
||||
#endif
|
||||
|
||||
/* additional exported functions */
|
||||
size_t u32toa(char *buf, uint32_t n);
|
||||
size_t i32toa(char *buf, int32_t n);
|
||||
size_t u64toa(char *buf, uint64_t n);
|
||||
size_t i64toa(char *buf, int64_t n);
|
||||
size_t u64toa_radix(char *buf, uint64_t n, unsigned int radix);
|
||||
size_t i64toa_radix(char *buf, int64_t n, unsigned int radix);
|
||||
2260
lib/mquickjs/libm.c
Normal file
2260
lib/mquickjs/libm.c
Normal file
File diff suppressed because it is too large
Load Diff
46
lib/mquickjs/libm.h
Normal file
46
lib/mquickjs/libm.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Tiny Math Library
|
||||
*
|
||||
* Copyright (c) 2024 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
double js_scalbn(double x, int n);
|
||||
double js_floor(double x);
|
||||
double js_ceil(double x);
|
||||
double js_trunc(double x);
|
||||
double js_round_inf(double a);
|
||||
double js_fabs(double x);
|
||||
double js_sqrt(double x);
|
||||
int32_t js_lrint(double a);
|
||||
double js_fmod(double x, double y);
|
||||
double js_sin(double x);
|
||||
double js_cos(double x);
|
||||
double js_tan(double x);
|
||||
double js_acos(double x);
|
||||
double js_asin(double x);
|
||||
double js_atan(double x);
|
||||
double js_atan2(double y, double x);
|
||||
double js_exp(double x);
|
||||
double js_log(double x);
|
||||
double js_log2(double x);
|
||||
double js_log10(double x);
|
||||
double js_pow(double x, double y);
|
||||
/* exported only for tests */
|
||||
int js_rem_pio2(double x, double *y);
|
||||
99
lib/mquickjs/list.h
Normal file
99
lib/mquickjs/list.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Linux klist like system
|
||||
*
|
||||
* Copyright (c) 2016-2017 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
#ifndef NULL
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
struct list_head {
|
||||
struct list_head *prev;
|
||||
struct list_head *next;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(el) { &(el), &(el) }
|
||||
|
||||
/* return the pointer of type 'type *' containing 'el' as field 'member' */
|
||||
#define list_entry(el, type, member) container_of(el, type, member)
|
||||
|
||||
static inline void init_list_head(struct list_head *head)
|
||||
{
|
||||
head->prev = head;
|
||||
head->next = head;
|
||||
}
|
||||
|
||||
/* insert 'el' between 'prev' and 'next' */
|
||||
static inline void __list_add(struct list_head *el,
|
||||
struct list_head *prev, struct list_head *next)
|
||||
{
|
||||
prev->next = el;
|
||||
el->prev = prev;
|
||||
el->next = next;
|
||||
next->prev = el;
|
||||
}
|
||||
|
||||
/* add 'el' at the head of the list 'head' (= after element head) */
|
||||
static inline void list_add(struct list_head *el, struct list_head *head)
|
||||
{
|
||||
__list_add(el, head, head->next);
|
||||
}
|
||||
|
||||
/* add 'el' at the end of the list 'head' (= before element head) */
|
||||
static inline void list_add_tail(struct list_head *el, struct list_head *head)
|
||||
{
|
||||
__list_add(el, head->prev, head);
|
||||
}
|
||||
|
||||
static inline void list_del(struct list_head *el)
|
||||
{
|
||||
struct list_head *prev, *next;
|
||||
prev = el->prev;
|
||||
next = el->next;
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
el->prev = NULL; /* fail safe */
|
||||
el->next = NULL; /* fail safe */
|
||||
}
|
||||
|
||||
static inline int list_empty(struct list_head *el)
|
||||
{
|
||||
return el->next == el;
|
||||
}
|
||||
|
||||
#define list_for_each(el, head) \
|
||||
for(el = (head)->next; el != (head); el = el->next)
|
||||
|
||||
#define list_for_each_safe(el, el1, head) \
|
||||
for(el = (head)->next, el1 = el->next; el != (head); \
|
||||
el = el1, el1 = el->next)
|
||||
|
||||
#define list_for_each_prev(el, head) \
|
||||
for(el = (head)->prev; el != (head); el = el->prev)
|
||||
|
||||
#define list_for_each_prev_safe(el, el1, head) \
|
||||
for(el = (head)->prev, el1 = el->prev; el != (head); \
|
||||
el = el1, el1 = el->prev)
|
||||
|
||||
#endif /* LIST_H */
|
||||
18324
lib/mquickjs/mquickjs.c
Normal file
18324
lib/mquickjs/mquickjs.c
Normal file
File diff suppressed because it is too large
Load Diff
382
lib/mquickjs/mquickjs.h
Normal file
382
lib/mquickjs/mquickjs.h
Normal file
@ -0,0 +1,382 @@
|
||||
/*
|
||||
* Micro QuickJS Javascript Engine
|
||||
*
|
||||
* Copyright (c) 2017-2025 Fabrice Bellard
|
||||
* Copyright (c) 2017-2025 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MQUICKJS_H
|
||||
#define MQUICKJS_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define __js_printf_like(f, a) __attribute__((format(printf, f, a)))
|
||||
#else
|
||||
#define __js_printf_like(a, b)
|
||||
#endif
|
||||
|
||||
#if INTPTR_MAX >= INT64_MAX
|
||||
#define JS_PTR64 /* pointers are 64 bit wide instead of 32 bit wide */
|
||||
#endif
|
||||
|
||||
typedef struct JSContext JSContext;
|
||||
|
||||
#ifdef JS_PTR64
|
||||
typedef uint64_t JSWord;
|
||||
typedef uint64_t JSValue;
|
||||
#define JSW 8
|
||||
#define JSValue_PRI PRIo64
|
||||
#define JS_USE_SHORT_FLOAT
|
||||
#else
|
||||
typedef uint32_t JSWord;
|
||||
typedef uint32_t JSValue;
|
||||
#define JSW 4
|
||||
#define JSValue_PRI PRIo32
|
||||
#endif
|
||||
|
||||
#define JS_BOOL int
|
||||
|
||||
enum {
|
||||
JS_TAG_INT = 0, /* 31 bit integer (1 bit) */
|
||||
JS_TAG_PTR = 1, /* pointer (2 bits) */
|
||||
JS_TAG_SPECIAL = 3, /* other special values (2 bits) */
|
||||
JS_TAG_BOOL = JS_TAG_SPECIAL | (0 << 2), /* (5 bits) */
|
||||
JS_TAG_NULL = JS_TAG_SPECIAL | (1 << 2), /* (5 bits) */
|
||||
JS_TAG_UNDEFINED = JS_TAG_SPECIAL | (2 << 2), /* (5 bits) */
|
||||
JS_TAG_EXCEPTION = JS_TAG_SPECIAL | (3 << 2), /* (5 bits) */
|
||||
JS_TAG_SHORT_FUNC = JS_TAG_SPECIAL | (4 << 2), /* (5 bits) */
|
||||
JS_TAG_UNINITIALIZED = JS_TAG_SPECIAL | (5 << 2), /* (5 bits) */
|
||||
JS_TAG_STRING_CHAR = JS_TAG_SPECIAL | (6 << 2), /* (5 bits) */
|
||||
JS_TAG_CATCH_OFFSET = JS_TAG_SPECIAL | (7 << 2), /* (5 bits) */
|
||||
#ifdef JS_USE_SHORT_FLOAT
|
||||
JS_TAG_SHORT_FLOAT = 5, /* 3 bits */
|
||||
#endif
|
||||
};
|
||||
|
||||
#define JS_TAG_SPECIAL_BITS 5
|
||||
|
||||
#define JS_VALUE_GET_INT(v) ((int)(v) >> 1)
|
||||
#define JS_VALUE_GET_SPECIAL_VALUE(v) ((int)(v) >> JS_TAG_SPECIAL_BITS)
|
||||
#define JS_VALUE_GET_SPECIAL_TAG(v) ((v) & ((1 << JS_TAG_SPECIAL_BITS) - 1))
|
||||
#define JS_VALUE_MAKE_SPECIAL(tag, v) ((tag) | ((v) << JS_TAG_SPECIAL_BITS))
|
||||
|
||||
#define JS_NULL JS_VALUE_MAKE_SPECIAL(JS_TAG_NULL, 0)
|
||||
#define JS_UNDEFINED JS_VALUE_MAKE_SPECIAL(JS_TAG_UNDEFINED, 0)
|
||||
#define JS_UNINITIALIZED JS_VALUE_MAKE_SPECIAL(JS_TAG_UNINITIALIZED, 0)
|
||||
#define JS_FALSE JS_VALUE_MAKE_SPECIAL(JS_TAG_BOOL, 0)
|
||||
#define JS_TRUE JS_VALUE_MAKE_SPECIAL(JS_TAG_BOOL, 1)
|
||||
|
||||
#define JS_EX_NORMAL 0 /* all exceptions except not enough memory */
|
||||
#define JS_EX_CALL 1 /* specific exception to generate a tail call. The call flags are added */
|
||||
#define JS_EXCEPTION JS_VALUE_MAKE_SPECIAL(JS_TAG_EXCEPTION, JS_EX_NORMAL)
|
||||
|
||||
typedef enum {
|
||||
JS_CLASS_OBJECT,
|
||||
JS_CLASS_ARRAY,
|
||||
JS_CLASS_C_FUNCTION,
|
||||
JS_CLASS_CLOSURE,
|
||||
JS_CLASS_NUMBER,
|
||||
JS_CLASS_BOOLEAN,
|
||||
JS_CLASS_STRING,
|
||||
JS_CLASS_DATE,
|
||||
JS_CLASS_REGEXP,
|
||||
|
||||
JS_CLASS_ERROR,
|
||||
JS_CLASS_EVAL_ERROR,
|
||||
JS_CLASS_RANGE_ERROR,
|
||||
JS_CLASS_REFERENCE_ERROR,
|
||||
JS_CLASS_SYNTAX_ERROR,
|
||||
JS_CLASS_TYPE_ERROR,
|
||||
JS_CLASS_URI_ERROR,
|
||||
JS_CLASS_INTERNAL_ERROR,
|
||||
|
||||
JS_CLASS_ARRAY_BUFFER,
|
||||
JS_CLASS_TYPED_ARRAY,
|
||||
|
||||
JS_CLASS_UINT8C_ARRAY,
|
||||
JS_CLASS_INT8_ARRAY,
|
||||
JS_CLASS_UINT8_ARRAY,
|
||||
JS_CLASS_INT16_ARRAY,
|
||||
JS_CLASS_UINT16_ARRAY,
|
||||
JS_CLASS_INT32_ARRAY,
|
||||
JS_CLASS_UINT32_ARRAY,
|
||||
JS_CLASS_FLOAT32_ARRAY,
|
||||
JS_CLASS_FLOAT64_ARRAY,
|
||||
|
||||
JS_CLASS_USER, /* user classes start from this value */
|
||||
} JSObjectClassEnum;
|
||||
|
||||
/* predefined functions */
|
||||
typedef enum {
|
||||
JS_CFUNCTION_bound,
|
||||
JS_CFUNCTION_USER, /* user functions start from this value */
|
||||
} JSCFunctionEnum;
|
||||
|
||||
/* temporary buffer to hold C strings */
|
||||
typedef struct {
|
||||
uint8_t buf[5];
|
||||
} JSCStringBuf;
|
||||
|
||||
typedef struct JSGCRef {
|
||||
JSValue val;
|
||||
struct JSGCRef *prev;
|
||||
} JSGCRef;
|
||||
|
||||
/* stack of JSGCRef */
|
||||
JSValue *JS_PushGCRef(JSContext *ctx, JSGCRef *ref);
|
||||
JSValue JS_PopGCRef(JSContext *ctx, JSGCRef *ref);
|
||||
|
||||
#define JS_PUSH_VALUE(ctx, v) do { JS_PushGCRef(ctx, &v ## _ref); v ## _ref.val = v; } while (0)
|
||||
#define JS_POP_VALUE(ctx, v) v = JS_PopGCRef(ctx, &v ## _ref)
|
||||
|
||||
/* list of JSGCRef (they can be removed in any order, slower) */
|
||||
JSValue *JS_AddGCRef(JSContext *ctx, JSGCRef *ref);
|
||||
void JS_DeleteGCRef(JSContext *ctx, JSGCRef *ref);
|
||||
|
||||
JSValue JS_NewFloat64(JSContext *ctx, double d);
|
||||
JSValue JS_NewInt32(JSContext *ctx, int32_t val);
|
||||
JSValue JS_NewUint32(JSContext *ctx, uint32_t val);
|
||||
JSValue JS_NewInt64(JSContext *ctx, int64_t val);
|
||||
|
||||
static inline JS_BOOL JS_IsInt(JSValue v)
|
||||
{
|
||||
return (v & 1) == JS_TAG_INT;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsPtr(JSValue v)
|
||||
{
|
||||
return (v & (JSW - 1)) == JS_TAG_PTR;
|
||||
}
|
||||
|
||||
#ifdef JS_USE_SHORT_FLOAT
|
||||
static inline JS_BOOL JS_IsShortFloat(JSValue v)
|
||||
{
|
||||
return (v & (JSW - 1)) == JS_TAG_SHORT_FLOAT;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline JS_BOOL JS_IsBool(JSValue v)
|
||||
{
|
||||
return JS_VALUE_GET_SPECIAL_TAG(v) == JS_TAG_BOOL;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsNull(JSValue v)
|
||||
{
|
||||
return v == JS_NULL;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsUndefined(JSValue v)
|
||||
{
|
||||
return v == JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsUninitialized(JSValue v)
|
||||
{
|
||||
return v == JS_UNINITIALIZED;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsException(JSValue v)
|
||||
{
|
||||
return v == JS_EXCEPTION;
|
||||
}
|
||||
|
||||
static inline JSValue JS_NewBool(int val)
|
||||
{
|
||||
return JS_VALUE_MAKE_SPECIAL(JS_TAG_BOOL, (val != 0));
|
||||
}
|
||||
|
||||
JS_BOOL JS_IsNumber(JSContext *ctx, JSValue val);
|
||||
JS_BOOL JS_IsString(JSContext *ctx, JSValue val);
|
||||
JS_BOOL JS_IsError(JSContext *ctx, JSValue val);
|
||||
JS_BOOL JS_IsFunction(JSContext *ctx, JSValue val);
|
||||
|
||||
int JS_GetClassID(JSContext *ctx, JSValue val);
|
||||
void JS_SetOpaque(JSContext *ctx, JSValue val, void *opaque);
|
||||
void *JS_GetOpaque(JSContext *ctx, JSValue val);
|
||||
|
||||
typedef JSValue JSCFunction(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv);
|
||||
/* no JS function call be called from a C finalizer */
|
||||
typedef void (*JSCFinalizer)(JSContext *ctx, void *opaque);
|
||||
|
||||
typedef enum JSCFunctionDefEnum { /* XXX: should rename for namespace isolation */
|
||||
JS_CFUNC_generic,
|
||||
JS_CFUNC_generic_magic,
|
||||
JS_CFUNC_constructor,
|
||||
JS_CFUNC_constructor_magic,
|
||||
JS_CFUNC_generic_params,
|
||||
JS_CFUNC_f_f,
|
||||
} JSCFunctionDefEnum;
|
||||
|
||||
typedef union JSCFunctionType {
|
||||
JSCFunction *generic;
|
||||
JSValue (*generic_magic)(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv, int magic);
|
||||
JSCFunction *constructor;
|
||||
JSValue (*constructor_magic)(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv, int magic);
|
||||
JSValue (*generic_params)(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv, JSValue params);
|
||||
double (*f_f)(double f);
|
||||
} JSCFunctionType;
|
||||
|
||||
typedef struct JSCFunctionDef {
|
||||
JSCFunctionType func;
|
||||
JSValue name;
|
||||
uint8_t def_type;
|
||||
uint8_t arg_count;
|
||||
int16_t magic;
|
||||
} JSCFunctionDef;
|
||||
|
||||
typedef struct {
|
||||
const JSWord *stdlib_table;
|
||||
const JSCFunctionDef *c_function_table;
|
||||
const JSCFinalizer *c_finalizer_table;
|
||||
uint32_t stdlib_table_len;
|
||||
uint32_t stdlib_table_align;
|
||||
uint32_t sorted_atoms_offset;
|
||||
uint32_t global_object_offset;
|
||||
uint32_t class_count;
|
||||
} JSSTDLibraryDef;
|
||||
|
||||
typedef void JSWriteFunc(void *opaque, const void *buf, size_t buf_len);
|
||||
/* return != 0 if the JS code needs to be interrupted */
|
||||
typedef int JSInterruptHandler(JSContext *ctx, void *opaque);
|
||||
|
||||
JSContext *JS_NewContext(void *mem_start, size_t mem_size, const JSSTDLibraryDef *stdlib_def);
|
||||
/* if prepare_compilation is true, the context will be used to compile
|
||||
to a binary file. JS_NewContext2() is not expected to be used in
|
||||
the embedded version */
|
||||
JSContext *JS_NewContext2(void *mem_start, size_t mem_size, const JSSTDLibraryDef *stdlib_def, JS_BOOL prepare_compilation);
|
||||
void JS_FreeContext(JSContext *ctx);
|
||||
void JS_SetContextOpaque(JSContext *ctx, void *opaque);
|
||||
void JS_SetInterruptHandler(JSContext *ctx, JSInterruptHandler *interrupt_handler);
|
||||
void JS_SetRandomSeed(JSContext *ctx, uint64_t seed);
|
||||
JSValue JS_GetGlobalObject(JSContext *ctx);
|
||||
JSValue JS_Throw(JSContext *ctx, JSValue obj);
|
||||
JSValue __js_printf_like(3, 4) JS_ThrowError(JSContext *ctx, JSObjectClassEnum error_num,
|
||||
const char *fmt, ...);
|
||||
#define JS_ThrowTypeError(ctx, fmt, ...) JS_ThrowError(ctx, JS_CLASS_TYPE_ERROR, fmt, ##__VA_ARGS__)
|
||||
#define JS_ThrowReferenceError(ctx, fmt, ...) JS_ThrowError(ctx, JS_CLASS_REFERENCE_ERROR, fmt, ##__VA_ARGS__)
|
||||
#define JS_ThrowInternalError(ctx, fmt, ...) JS_ThrowError(ctx, JS_CLASS_INTERNAL_ERROR, fmt, ##__VA_ARGS__)
|
||||
#define JS_ThrowRangeError(ctx, fmt, ...) JS_ThrowError(ctx, JS_CLASS_RANGE_ERROR, fmt, ##__VA_ARGS__)
|
||||
#define JS_ThrowSyntaxError(ctx, fmt, ...) JS_ThrowError(ctx, JS_CLASS_SYNTAX_ERROR, fmt, ##__VA_ARGS__)
|
||||
JSValue JS_ThrowOutOfMemory(JSContext *ctx);
|
||||
JSValue JS_GetPropertyStr(JSContext *ctx, JSValue this_obj, const char *str);
|
||||
JSValue JS_GetPropertyUint32(JSContext *ctx, JSValue obj, uint32_t idx);
|
||||
JSValue JS_SetPropertyStr(JSContext *ctx, JSValue this_obj,
|
||||
const char *str, JSValue val);
|
||||
JSValue JS_SetPropertyUint32(JSContext *ctx, JSValue this_obj,
|
||||
uint32_t idx, JSValue val);
|
||||
JSValue JS_NewObjectClassUser(JSContext *ctx, int class_id);
|
||||
JSValue JS_NewObject(JSContext *ctx);
|
||||
JSValue JS_NewArray(JSContext *ctx, int initial_len);
|
||||
/* create a C function with an object parameter (closure) */
|
||||
JSValue JS_NewCFunctionParams(JSContext *ctx, int func_idx, JSValue params);
|
||||
|
||||
#define JS_EVAL_RETVAL (1 << 0) /* return the last value instead of undefined (slower code) */
|
||||
#define JS_EVAL_REPL (1 << 1) /* implicitly defined global variables in assignments */
|
||||
#define JS_EVAL_STRIP_COL (1 << 2) /* strip column number debug information (save memory) */
|
||||
#define JS_EVAL_JSON (1 << 3) /* parse as JSON and return the object */
|
||||
#define JS_EVAL_REGEXP (1 << 4) /* internal use */
|
||||
#define JS_EVAL_REGEXP_FLAGS_SHIFT 8 /* internal use */
|
||||
JSValue JS_Parse(JSContext *ctx, const char *input, size_t input_len,
|
||||
const char *filename, int eval_flags);
|
||||
JSValue JS_Run(JSContext *ctx, JSValue val);
|
||||
JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
|
||||
const char *filename, int eval_flags);
|
||||
void JS_GC(JSContext *ctx);
|
||||
JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len);
|
||||
JSValue JS_NewString(JSContext *ctx, const char *buf);
|
||||
const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValue val, JSCStringBuf *buf);
|
||||
const char *JS_ToCString(JSContext *ctx, JSValue val, JSCStringBuf *buf);
|
||||
JSValue JS_ToString(JSContext *ctx, JSValue val);
|
||||
int JS_ToInt32(JSContext *ctx, int *pres, JSValue val);
|
||||
int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValue val);
|
||||
int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValue val);
|
||||
int JS_ToNumber(JSContext *ctx, double *pres, JSValue val);
|
||||
|
||||
JSValue JS_GetException(JSContext *ctx);
|
||||
int JS_StackCheck(JSContext *ctx, uint32_t len);
|
||||
void JS_PushArg(JSContext *ctx, JSValue val);
|
||||
#define FRAME_CF_CTOR (1 << 16) /* also ored with argc in
|
||||
C constructors */
|
||||
JSValue JS_Call(JSContext *ctx, int call_flags);
|
||||
|
||||
#define JS_BYTECODE_MAGIC 0xacfb
|
||||
|
||||
typedef struct {
|
||||
uint16_t magic; /* JS_BYTECODE_MAGIC */
|
||||
uint16_t version;
|
||||
uintptr_t base_addr;
|
||||
JSValue unique_strings;
|
||||
JSValue main_func;
|
||||
} JSBytecodeHeader;
|
||||
|
||||
/* only used on the host when compiling to file */
|
||||
void JS_PrepareBytecode(JSContext *ctx,
|
||||
JSBytecodeHeader *hdr,
|
||||
const uint8_t **pdata_buf, uint32_t *pdata_len,
|
||||
JSValue eval_code);
|
||||
/* only used on the host when compiling to file */
|
||||
int JS_RelocateBytecode2(JSContext *ctx, JSBytecodeHeader *hdr,
|
||||
uint8_t *buf, uint32_t buf_len,
|
||||
uintptr_t new_base_addr, JS_BOOL update_atoms);
|
||||
#if JSW == 8
|
||||
typedef struct {
|
||||
uint16_t magic; /* JS_BYTECODE_MAGIC */
|
||||
uint16_t version;
|
||||
uint32_t base_addr;
|
||||
uint32_t unique_strings;
|
||||
uint32_t main_func;
|
||||
} JSBytecodeHeader32;
|
||||
|
||||
/* only used on the host when compiling to file. A 32 bit bytecode is generated on a 64 bit host. */
|
||||
int JS_PrepareBytecode64to32(JSContext *ctx,
|
||||
JSBytecodeHeader32 *hdr,
|
||||
const uint8_t **pdata_buf, uint32_t *pdata_len,
|
||||
JSValue eval_code);
|
||||
#endif
|
||||
|
||||
JS_BOOL JS_IsBytecode(const uint8_t *buf, size_t buf_len);
|
||||
/* Relocate the bytecode in 'buf' so that it can be executed
|
||||
later. Return 0 if OK, != 0 if error */
|
||||
int JS_RelocateBytecode(JSContext *ctx,
|
||||
uint8_t *buf, uint32_t buf_len);
|
||||
/* Load the precompiled bytecode from 'buf'. 'buf' must be allocated
|
||||
as long as the JSContext exists. Use JS_Run() to execute
|
||||
it. warning: the bytecode is not checked so it should come from a
|
||||
trusted source. */
|
||||
JSValue JS_LoadBytecode(JSContext *ctx, const uint8_t *buf);
|
||||
|
||||
/* debug functions */
|
||||
void JS_SetLogFunc(JSContext *ctx, JSWriteFunc *write_func);
|
||||
void JS_PrintValue(JSContext *ctx, JSValue val);
|
||||
#define JS_DUMP_LONG (1 << 0) /* display object/array content */
|
||||
#define JS_DUMP_NOQUOTE (1 << 1) /* strings: no quote for identifiers */
|
||||
/* for low level dumps: don't dump special properties and use specific
|
||||
quotes to distinguish string chars, unique strings and normal
|
||||
strings */
|
||||
#define JS_DUMP_RAW (1 << 2)
|
||||
void JS_PrintValueF(JSContext *ctx, JSValue val, int flags);
|
||||
void JS_DumpValueF(JSContext *ctx, const char *str,
|
||||
JSValue val, int flags);
|
||||
void JS_DumpValue(JSContext *ctx, const char *str,
|
||||
JSValue val);
|
||||
void JS_DumpMemory(JSContext *ctx, JS_BOOL is_long);
|
||||
|
||||
#endif /* MQUICKJS_H */
|
||||
76
lib/mquickjs/mquickjs_atom.h
Normal file
76
lib/mquickjs/mquickjs_atom.h
Normal file
@ -0,0 +1,76 @@
|
||||
#define JS_ATOM_null 0
|
||||
#define JS_ATOM_false 3
|
||||
#define JS_ATOM_true 6
|
||||
#define JS_ATOM_if 9
|
||||
#define JS_ATOM_else 11
|
||||
#define JS_ATOM_return 14
|
||||
#define JS_ATOM_var 17
|
||||
#define JS_ATOM_this 19
|
||||
#define JS_ATOM_delete 22
|
||||
#define JS_ATOM_void 25
|
||||
#define JS_ATOM_typeof 28
|
||||
#define JS_ATOM_new 31
|
||||
#define JS_ATOM_in 33
|
||||
#define JS_ATOM_instanceof 35
|
||||
#define JS_ATOM_do 39
|
||||
#define JS_ATOM_while 41
|
||||
#define JS_ATOM_for 44
|
||||
#define JS_ATOM_break 46
|
||||
#define JS_ATOM_continue 49
|
||||
#define JS_ATOM_switch 53
|
||||
#define JS_ATOM_case 56
|
||||
#define JS_ATOM_default 59
|
||||
#define JS_ATOM_throw 62
|
||||
#define JS_ATOM_try 65
|
||||
#define JS_ATOM_catch 67
|
||||
#define JS_ATOM_finally 70
|
||||
#define JS_ATOM_function 73
|
||||
#define JS_ATOM_debugger 77
|
||||
#define JS_ATOM_with 81
|
||||
#define JS_ATOM_class 84
|
||||
#define JS_ATOM_const 87
|
||||
#define JS_ATOM_enum 90
|
||||
#define JS_ATOM_export 93
|
||||
#define JS_ATOM_extends 96
|
||||
#define JS_ATOM_import 99
|
||||
#define JS_ATOM_super 102
|
||||
#define JS_ATOM_implements 105
|
||||
#define JS_ATOM_interface 109
|
||||
#define JS_ATOM_let 113
|
||||
#define JS_ATOM_package 115
|
||||
#define JS_ATOM_private 118
|
||||
#define JS_ATOM_protected 121
|
||||
#define JS_ATOM_public 125
|
||||
#define JS_ATOM_static 128
|
||||
#define JS_ATOM_yield 131
|
||||
#define JS_ATOM_empty 134
|
||||
#define JS_ATOM_toString 136
|
||||
#define JS_ATOM_valueOf 140
|
||||
#define JS_ATOM_number 143
|
||||
#define JS_ATOM_object 146
|
||||
#define JS_ATOM_undefined 149
|
||||
#define JS_ATOM_string 153
|
||||
#define JS_ATOM_boolean 156
|
||||
#define JS_ATOM__ret_ 159
|
||||
#define JS_ATOM__eval_ 162
|
||||
#define JS_ATOM_eval 165
|
||||
#define JS_ATOM_arguments 168
|
||||
#define JS_ATOM_value 172
|
||||
#define JS_ATOM_get 175
|
||||
#define JS_ATOM_set 177
|
||||
#define JS_ATOM_prototype 179
|
||||
#define JS_ATOM_constructor 183
|
||||
#define JS_ATOM_length 187
|
||||
#define JS_ATOM_target 190
|
||||
#define JS_ATOM_of 193
|
||||
#define JS_ATOM_NaN 195
|
||||
#define JS_ATOM_Infinity 197
|
||||
#define JS_ATOM__Infinity 201
|
||||
#define JS_ATOM_name 205
|
||||
#define JS_ATOM_Error 208
|
||||
#define JS_ATOM___proto__ 211
|
||||
#define JS_ATOM_index 215
|
||||
#define JS_ATOM_input 218
|
||||
|
||||
#define JS_ATOM_END 221
|
||||
|
||||
932
lib/mquickjs/mquickjs_build.c
Normal file
932
lib/mquickjs/mquickjs_build.c
Normal file
@ -0,0 +1,932 @@
|
||||
/*
|
||||
* Micro QuickJS build utility
|
||||
*
|
||||
* Copyright (c) 2017-2025 Fabrice Bellard
|
||||
* Copyright (c) 2017-2025 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "cutils.h"
|
||||
#include "list.h"
|
||||
#include "mquickjs_build.h"
|
||||
|
||||
static unsigned JSW = 4; // override this with -m64
|
||||
|
||||
typedef struct {
|
||||
char *str;
|
||||
int offset;
|
||||
} AtomDef;
|
||||
|
||||
typedef struct {
|
||||
AtomDef *tab;
|
||||
int count;
|
||||
int size;
|
||||
int offset;
|
||||
} AtomList;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int length;
|
||||
char *magic;
|
||||
char *cproto_name;
|
||||
char *cfunc_name;
|
||||
} CFuncDef;
|
||||
|
||||
typedef struct {
|
||||
CFuncDef *tab;
|
||||
int count;
|
||||
int size;
|
||||
} CFuncList;
|
||||
|
||||
typedef struct {
|
||||
struct list_head link;
|
||||
const JSClassDef *class1;
|
||||
int class_idx;
|
||||
char *finalizer_name;
|
||||
char *class_id;
|
||||
} ClassDefEntry;
|
||||
|
||||
typedef struct {
|
||||
AtomList atom_list;
|
||||
CFuncList cfunc_list;
|
||||
int cur_offset;
|
||||
int sorted_atom_table_offset;
|
||||
int global_object_offset;
|
||||
struct list_head class_list;
|
||||
} BuildContext;
|
||||
|
||||
static const char *atoms[] = {
|
||||
#define DEF(a, b) b,
|
||||
/* keywords */
|
||||
DEF(null, "null") /* must be first */
|
||||
DEF(false, "false")
|
||||
DEF(true, "true")
|
||||
DEF(if, "if")
|
||||
DEF(else, "else")
|
||||
DEF(return, "return")
|
||||
DEF(var, "var")
|
||||
DEF(this, "this")
|
||||
DEF(delete, "delete")
|
||||
DEF(void, "void")
|
||||
DEF(typeof, "typeof")
|
||||
DEF(new, "new")
|
||||
DEF(in, "in")
|
||||
DEF(instanceof, "instanceof")
|
||||
DEF(do, "do")
|
||||
DEF(while, "while")
|
||||
DEF(for, "for")
|
||||
DEF(break, "break")
|
||||
DEF(continue, "continue")
|
||||
DEF(switch, "switch")
|
||||
DEF(case, "case")
|
||||
DEF(default, "default")
|
||||
DEF(throw, "throw")
|
||||
DEF(try, "try")
|
||||
DEF(catch, "catch")
|
||||
DEF(finally, "finally")
|
||||
DEF(function, "function")
|
||||
DEF(debugger, "debugger")
|
||||
DEF(with, "with")
|
||||
/* FutureReservedWord */
|
||||
DEF(class, "class")
|
||||
DEF(const, "const")
|
||||
DEF(enum, "enum")
|
||||
DEF(export, "export")
|
||||
DEF(extends, "extends")
|
||||
DEF(import, "import")
|
||||
DEF(super, "super")
|
||||
/* FutureReservedWords when parsing strict mode code */
|
||||
DEF(implements, "implements")
|
||||
DEF(interface, "interface")
|
||||
DEF(let, "let")
|
||||
DEF(package, "package")
|
||||
DEF(private, "private")
|
||||
DEF(protected, "protected")
|
||||
DEF(public, "public")
|
||||
DEF(static, "static")
|
||||
DEF(yield, "yield")
|
||||
#undef DEF
|
||||
|
||||
/* other atoms */
|
||||
"",
|
||||
"toString",
|
||||
"valueOf",
|
||||
"number",
|
||||
"object",
|
||||
"undefined",
|
||||
"string",
|
||||
"boolean",
|
||||
"<ret>",
|
||||
"<eval>",
|
||||
"eval",
|
||||
"arguments",
|
||||
"value",
|
||||
"get",
|
||||
"set",
|
||||
"prototype",
|
||||
"constructor",
|
||||
"length",
|
||||
"target",
|
||||
"of",
|
||||
"NaN",
|
||||
"Infinity",
|
||||
"-Infinity",
|
||||
"name",
|
||||
"Error",
|
||||
"__proto__",
|
||||
"index",
|
||||
"input",
|
||||
};
|
||||
|
||||
|
||||
static char *cvt_name(char *buf, size_t buf_size, const char *str)
|
||||
{
|
||||
size_t i, len = strlen(str);
|
||||
assert(len < buf_size);
|
||||
if (len == 0) {
|
||||
strcpy(buf, "empty");
|
||||
} else {
|
||||
strcpy(buf, str);
|
||||
for(i = 0; i < len; i++) {
|
||||
if (buf[i] == '<' || buf[i] == '>' || buf[i] == '-')
|
||||
buf[i] = '_';
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static BOOL is_ascii_string(const char *buf, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < len; i++) {
|
||||
if ((uint8_t)buf[i] > 0x7f)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL is_numeric_string(const char *buf, size_t len)
|
||||
{
|
||||
return (!strcmp(buf, "NaN") ||
|
||||
!strcmp(buf, "Infinity") ||
|
||||
!strcmp(buf, "-Infinity"));
|
||||
}
|
||||
|
||||
static int find_atom(AtomList *s, const char *str)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < s->count; i++) {
|
||||
if (!strcmp(str, s->tab[i].str))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int add_atom(AtomList *s, const char *str)
|
||||
{
|
||||
int i;
|
||||
AtomDef *e;
|
||||
i = find_atom(s, str);
|
||||
if (i >= 0)
|
||||
return s->tab[i].offset;
|
||||
if ((s->count + 1) > s->size) {
|
||||
s->size = max_int(s->count + 1, s->size * 3 / 2);
|
||||
s->tab = realloc(s->tab, sizeof(s->tab[0]) * s->size);
|
||||
}
|
||||
e = &s->tab[s->count++];
|
||||
e->str = strdup(str);
|
||||
e->offset = s->offset;
|
||||
s->offset += 1 + ((strlen(str) + JSW) / JSW);
|
||||
return s->count - 1;
|
||||
}
|
||||
|
||||
static int add_cfunc(CFuncList *s, const char *name, int length, const char *magic, const char *cproto_name, const char *cfunc_name)
|
||||
{
|
||||
int i;
|
||||
CFuncDef *e;
|
||||
|
||||
for(i = 0; i < s->count; i++) {
|
||||
e = &s->tab[i];
|
||||
if (!strcmp(name, e->name) &&
|
||||
length == e->length &&
|
||||
!strcmp(magic, e->magic) &&
|
||||
!strcmp(cproto_name, e->cproto_name) &&
|
||||
!strcmp(cfunc_name, e->cfunc_name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if ((s->count + 1) > s->size) {
|
||||
s->size = max_int(s->count + 1, s->size * 3 / 2);
|
||||
s->tab = realloc(s->tab, sizeof(s->tab[0]) * s->size);
|
||||
}
|
||||
e = &s->tab[s->count++];
|
||||
e->name = strdup(name);
|
||||
e->magic = strdup(magic);
|
||||
e->length = length;
|
||||
e->cproto_name = strdup(cproto_name);
|
||||
e->cfunc_name = strdup(cfunc_name);
|
||||
return s->count - 1;
|
||||
}
|
||||
|
||||
static void dump_atom_defines(void)
|
||||
{
|
||||
AtomList atom_list_s, *s = &atom_list_s;
|
||||
AtomDef *e;
|
||||
int i;
|
||||
char buf[256];
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
/* add the predefined atoms (they have a corresponding define) */
|
||||
for(i = 0; i < countof(atoms); i++) {
|
||||
add_atom(s, atoms[i]);
|
||||
}
|
||||
|
||||
for(i = 0; i < s->count; i++) {
|
||||
e = &s->tab[i];
|
||||
printf("#define JS_ATOM_%s %d\n",
|
||||
cvt_name(buf, sizeof(buf), e->str), e->offset);
|
||||
}
|
||||
printf("\n");
|
||||
printf("#define JS_ATOM_END %d\n", s->offset);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int atom_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
const AtomDef *a1 = (const AtomDef *)p1;
|
||||
const AtomDef *a2 = (const AtomDef *)p2;
|
||||
return strcmp(a1->str, a2->str);
|
||||
}
|
||||
|
||||
/* js_atom_table must be properly aligned because the property hash
|
||||
table uses the low bits of the atom pointer value */
|
||||
#define ATOM_ALIGN 64
|
||||
|
||||
static void dump_atoms(BuildContext *ctx)
|
||||
{
|
||||
AtomList *s = &ctx->atom_list;
|
||||
int i, j, k, l, len, len1, is_ascii, is_numeric;
|
||||
uint64_t v;
|
||||
const char *str;
|
||||
AtomDef *sorted_atoms;
|
||||
char buf[256];
|
||||
|
||||
sorted_atoms = malloc(sizeof(sorted_atoms[0]) * s->count);
|
||||
memcpy(sorted_atoms, s->tab, sizeof(sorted_atoms[0]) * s->count);
|
||||
qsort(sorted_atoms, s->count, sizeof(sorted_atoms[0]), atom_cmp);
|
||||
|
||||
printf(" /* atom_table */\n");
|
||||
for(i = 0; i < s->count; i++) {
|
||||
str = s->tab[i].str;
|
||||
len = strlen(str);
|
||||
is_ascii = is_ascii_string(str, len);
|
||||
is_numeric = is_numeric_string(str, len);
|
||||
printf(" (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (%d << (JS_MTAG_BITS + 1)) | (%d << (JS_MTAG_BITS + 2)) | (%d << (JS_MTAG_BITS + 3)), /* \"%s\" (offset=%d) */\n",
|
||||
is_ascii, is_numeric, len, str, ctx->cur_offset);
|
||||
len1 = (len + JSW) / JSW;
|
||||
for(j = 0; j < len1; j++) {
|
||||
l = min_uint32(JSW, len - j * JSW);
|
||||
v = 0;
|
||||
for(k = 0; k < l; k++)
|
||||
v |= (uint64_t)(uint8_t)str[j * JSW + k] << (k * 8);
|
||||
printf(" 0x%0*" PRIx64 ",\n", JSW * 2, v);
|
||||
}
|
||||
assert(ctx->cur_offset == s->tab[i].offset);
|
||||
ctx->cur_offset += len1 + 1;
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
ctx->sorted_atom_table_offset = ctx->cur_offset;
|
||||
|
||||
printf(" /* sorted atom table (offset=%d) */\n", ctx->cur_offset);
|
||||
printf(" JS_VALUE_ARRAY_HEADER(%d),\n", s->count);
|
||||
for(i = 0; i < s->count; i++) {
|
||||
AtomDef *e = &sorted_atoms[i];
|
||||
printf(" JS_ROM_VALUE(%d), /* %s */\n",
|
||||
e->offset, cvt_name(buf, sizeof(buf), e->str));
|
||||
}
|
||||
ctx->cur_offset += s->count + 1;
|
||||
printf("\n");
|
||||
|
||||
free(sorted_atoms);
|
||||
}
|
||||
|
||||
static int define_value(BuildContext *s, const JSPropDef *d);
|
||||
|
||||
static uint32_t dump_atom(BuildContext *s, const char *str, BOOL value_only)
|
||||
{
|
||||
int len, idx, i, offset;
|
||||
|
||||
len = strlen(str);
|
||||
for(i = 0; i < len; i++) {
|
||||
if ((uint8_t)str[i] >= 128) {
|
||||
fprintf(stderr, "unicode property names are not supported yet (%s)\n", str);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (len >= 1 && (str[0] >= '0' && str[0] <= '9')) {
|
||||
fprintf(stderr, "numeric property names are not supported yet (%s)\n", str);
|
||||
exit(1);
|
||||
}
|
||||
if (len == 1) {
|
||||
if (value_only) {
|
||||
/* XXX: hardcoded */
|
||||
return ((uint8_t)str[0] << 5) | 0x1b;
|
||||
}
|
||||
printf("JS_VALUE_MAKE_SPECIAL(JS_TAG_STRING_CHAR, %d)",
|
||||
(uint8_t)str[0]);
|
||||
} else {
|
||||
idx = find_atom(&s->atom_list, str);
|
||||
if (idx < 0) {
|
||||
fprintf(stderr, "atom '%s' is undefined\n", str);
|
||||
exit(1);
|
||||
}
|
||||
offset = s->atom_list.tab[idx].offset;
|
||||
if (value_only)
|
||||
return (offset * JSW) + 1; /* correct modulo ATOM_ALIGN */
|
||||
printf("JS_ROM_VALUE(%d)", offset);
|
||||
}
|
||||
printf(" /* %s */", str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_cfuncs(BuildContext *s)
|
||||
{
|
||||
int i;
|
||||
CFuncDef *e;
|
||||
|
||||
printf("static const JSCFunctionDef js_c_function_table[] = {\n");
|
||||
for(i = 0; i < s->cfunc_list.count; i++) {
|
||||
e = &s->cfunc_list.tab[i];
|
||||
printf(" { { .%s = %s },\n", e->cproto_name, e->cfunc_name);
|
||||
printf(" ");
|
||||
dump_atom(s, e->name, FALSE);
|
||||
printf(",\n");
|
||||
printf(" JS_CFUNC_%s, %d, %s },\n",
|
||||
e->cproto_name, e->length, e->magic);
|
||||
}
|
||||
printf("};\n\n");
|
||||
}
|
||||
|
||||
static void dump_cfinalizers(BuildContext *s)
|
||||
{
|
||||
struct list_head *el;
|
||||
ClassDefEntry *e;
|
||||
|
||||
printf("static const JSCFinalizer js_c_finalizer_table[JS_CLASS_COUNT - JS_CLASS_USER] = {\n");
|
||||
list_for_each(el, &s->class_list) {
|
||||
e = list_entry(el, ClassDefEntry, link);
|
||||
if (e->finalizer_name &&
|
||||
strcmp(e->finalizer_name, "NULL") != 0) {
|
||||
printf(" [%s - JS_CLASS_USER] = %s,\n", e->class_id, e->finalizer_name);
|
||||
}
|
||||
}
|
||||
printf("};\n\n");
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
PROPS_KIND_GLOBAL,
|
||||
PROPS_KIND_PROTO,
|
||||
PROPS_KIND_CLASS,
|
||||
PROPS_KIND_OBJECT,
|
||||
} JSPropsKindEnum;
|
||||
|
||||
static inline uint32_t hash_prop(BuildContext *s, const char *name)
|
||||
{
|
||||
/* Compute the hash for a symbol, must be consistent with
|
||||
mquickjs.c implementation.
|
||||
*/
|
||||
uint32_t prop = dump_atom(s, name, TRUE);
|
||||
return (prop / JSW) ^ (prop % JSW); /* XXX: improve */
|
||||
}
|
||||
|
||||
static int define_props(BuildContext *s, const JSPropDef *props_def,
|
||||
JSPropsKindEnum props_kind, const char *class_id_str)
|
||||
{
|
||||
int i, *ident_tab, idx, props_ident, n_props;
|
||||
int prop_idx;
|
||||
const JSPropDef *d;
|
||||
uint32_t *prop_hash;
|
||||
BOOL is_global_object = (props_kind == PROPS_KIND_GLOBAL);
|
||||
static const JSPropDef dummy_props[] = {
|
||||
{ JS_DEF_END },
|
||||
};
|
||||
|
||||
if (!props_def)
|
||||
props_def = dummy_props;
|
||||
|
||||
n_props = 0;
|
||||
for(d = props_def; d->def_type != JS_DEF_END; d++) {
|
||||
n_props++;
|
||||
}
|
||||
if (props_kind == PROPS_KIND_PROTO ||
|
||||
props_kind == PROPS_KIND_CLASS)
|
||||
n_props++;
|
||||
ident_tab = malloc(sizeof(ident_tab[0]) * n_props);
|
||||
|
||||
/* define the various objects */
|
||||
for(d = props_def, i = 0; d->def_type != JS_DEF_END; d++, i++) {
|
||||
ident_tab[i] = define_value(s, d);
|
||||
}
|
||||
|
||||
props_ident = -1;
|
||||
prop_hash = NULL;
|
||||
if (is_global_object) {
|
||||
props_ident = s->cur_offset;
|
||||
printf(" /* global object properties (offset=%d) */\n", props_ident);
|
||||
printf(" JS_VALUE_ARRAY_HEADER(%d),\n", 2 * n_props);
|
||||
s->cur_offset += 2 * n_props + 1;
|
||||
} else {
|
||||
int hash_size_log2;
|
||||
uint32_t hash_size, hash_mask;
|
||||
uint32_t *hash_table, h;
|
||||
|
||||
if (n_props <= 1)
|
||||
hash_size_log2 = 0;
|
||||
else
|
||||
hash_size_log2 = (32 - clz32(n_props - 1)) - 1;
|
||||
hash_size = 1 << hash_size_log2;
|
||||
if (hash_size > ATOM_ALIGN / JSW) {
|
||||
#if !defined __APPLE__
|
||||
// XXX: Cannot request data alignment larger than 64 bytes on Darwin
|
||||
fprintf(stderr, "Too many properties, consider increasing ATOM_ALIGN\n");
|
||||
#endif
|
||||
hash_size = ATOM_ALIGN / JSW;
|
||||
}
|
||||
hash_mask = hash_size - 1;
|
||||
|
||||
hash_table = malloc(sizeof(hash_table[0]) * hash_size);
|
||||
prop_hash = malloc(sizeof(prop_hash[0]) * n_props);
|
||||
/* build the hash table */
|
||||
for(i = 0; i < hash_size; i++)
|
||||
hash_table[i] = 0;
|
||||
prop_idx = 0;
|
||||
for(i = 0, d = props_def; i < n_props; i++, d++) {
|
||||
const char *name;
|
||||
if (d->def_type != JS_DEF_END) {
|
||||
name = d->name;
|
||||
} else {
|
||||
if (props_kind == PROPS_KIND_PROTO)
|
||||
name = "constructor";
|
||||
else
|
||||
name = "prototype";
|
||||
}
|
||||
h = hash_prop(s, name) & hash_mask;
|
||||
prop_hash[prop_idx] = hash_table[h];
|
||||
hash_table[h] = 2 + hash_size + 3 * prop_idx;
|
||||
prop_idx++;
|
||||
}
|
||||
|
||||
props_ident = s->cur_offset;
|
||||
printf(" /* properties (offset=%d) */\n", props_ident);
|
||||
printf(" JS_VALUE_ARRAY_HEADER(%d),\n", 2 + hash_size + n_props * 3);
|
||||
printf(" %d << 1, /* n_props */\n", n_props);
|
||||
printf(" %d << 1, /* hash_mask */\n", hash_mask);
|
||||
for(i = 0; i < hash_size; i++) {
|
||||
printf(" %d << 1,\n", hash_table[i]);
|
||||
}
|
||||
s->cur_offset += hash_size + 3 + 3 * n_props;
|
||||
free(hash_table);
|
||||
}
|
||||
prop_idx = 0;
|
||||
for(d = props_def, i = 0; i < n_props; d++, i++) {
|
||||
const char *name, *prop_type;
|
||||
/* name */
|
||||
printf(" ");
|
||||
if (d->def_type != JS_DEF_END) {
|
||||
name = d->name;
|
||||
} else {
|
||||
if (props_kind == PROPS_KIND_PROTO)
|
||||
name = "constructor";
|
||||
else
|
||||
name = "prototype";
|
||||
}
|
||||
dump_atom(s, name, FALSE);
|
||||
printf(",\n");
|
||||
|
||||
printf(" ");
|
||||
prop_type = "NORMAL";
|
||||
switch(d->def_type) {
|
||||
case JS_DEF_PROP_DOUBLE:
|
||||
if (ident_tab[i] >= 0)
|
||||
goto value_ptr;
|
||||
/* short int */
|
||||
printf("%d << 1,", (int32_t)d->u.f64);
|
||||
break;
|
||||
case JS_DEF_CGETSET:
|
||||
if (is_global_object) {
|
||||
fprintf(stderr, "getter/setter forbidden in global object\n");
|
||||
exit(1);
|
||||
}
|
||||
prop_type = "GETSET";
|
||||
goto value_ptr;
|
||||
case JS_DEF_CLASS:
|
||||
value_ptr:
|
||||
assert(ident_tab[i] >= 0);
|
||||
printf("JS_ROM_VALUE(%d),", ident_tab[i]);
|
||||
break;
|
||||
case JS_DEF_PROP_UNDEFINED:
|
||||
printf("JS_UNDEFINED,");
|
||||
break;
|
||||
case JS_DEF_PROP_NULL:
|
||||
printf("JS_NULL,");
|
||||
break;
|
||||
case JS_DEF_PROP_STRING:
|
||||
dump_atom(s, d->u.str, FALSE);
|
||||
printf(",");
|
||||
break;
|
||||
case JS_DEF_CFUNC:
|
||||
idx = add_cfunc(&s->cfunc_list,
|
||||
d->name,
|
||||
d->u.func.length,
|
||||
d->u.func.magic,
|
||||
d->u.func.cproto_name,
|
||||
d->u.func.func_name);
|
||||
printf("JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, %d),", idx);
|
||||
break;
|
||||
case JS_DEF_END:
|
||||
if (props_kind == PROPS_KIND_PROTO) {
|
||||
/* constructor property */
|
||||
printf("(uint32_t)(-%s - 1) << 1,", class_id_str);
|
||||
} else {
|
||||
/* prototype property */
|
||||
printf("%s << 1,", class_id_str);
|
||||
}
|
||||
prop_type = "SPECIAL";
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
printf("\n");
|
||||
if (!is_global_object) {
|
||||
printf(" (%d << 1) | (JS_PROP_%s << 30),\n",
|
||||
prop_hash[prop_idx], prop_type);
|
||||
}
|
||||
prop_idx++;
|
||||
}
|
||||
|
||||
free(prop_hash);
|
||||
free(ident_tab);
|
||||
return props_ident;
|
||||
}
|
||||
|
||||
static ClassDefEntry *find_class(BuildContext *s, const JSClassDef *d)
|
||||
{
|
||||
struct list_head *el;
|
||||
ClassDefEntry *e;
|
||||
|
||||
list_for_each(el, &s->class_list) {
|
||||
e = list_entry(el, ClassDefEntry, link);
|
||||
if (e->class1 == d)
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void free_class_entries(BuildContext *s)
|
||||
{
|
||||
struct list_head *el, *el1;
|
||||
ClassDefEntry *e;
|
||||
list_for_each_safe(el, el1, &s->class_list) {
|
||||
e = list_entry(el, ClassDefEntry, link);
|
||||
free(e->class_id);
|
||||
free(e->finalizer_name);
|
||||
free(e);
|
||||
}
|
||||
init_list_head(&s->class_list);
|
||||
}
|
||||
|
||||
static int define_class(BuildContext *s, const JSClassDef *d)
|
||||
{
|
||||
int ctor_func_idx = -1, class_props_idx = -1, proto_props_idx = -1;
|
||||
int ident, parent_class_idx = -1;
|
||||
ClassDefEntry *e;
|
||||
|
||||
/* check if the class is already defined */
|
||||
e = find_class(s, d);
|
||||
if (e)
|
||||
return e->class_idx;
|
||||
|
||||
if (d->parent_class)
|
||||
parent_class_idx = define_class(s, d->parent_class);
|
||||
|
||||
if (d->func_name) {
|
||||
ctor_func_idx = add_cfunc(&s->cfunc_list,
|
||||
d->name,
|
||||
d->length,
|
||||
d->class_id,
|
||||
d->cproto_name,
|
||||
d->func_name);
|
||||
}
|
||||
|
||||
if (ctor_func_idx >= 0) {
|
||||
class_props_idx = define_props(s, d->class_props, PROPS_KIND_CLASS, d->class_id);
|
||||
proto_props_idx = define_props(s, d->proto_props, PROPS_KIND_PROTO, d->class_id);
|
||||
} else {
|
||||
if (d->class_props)
|
||||
class_props_idx = define_props(s, d->class_props, PROPS_KIND_OBJECT, d->class_id);
|
||||
}
|
||||
|
||||
ident = s->cur_offset;
|
||||
printf(" /* class (offset=%d) */\n", ident);
|
||||
printf(" JS_MB_HEADER_DEF(JS_MTAG_OBJECT),\n");
|
||||
if (class_props_idx >= 0)
|
||||
printf(" JS_ROM_VALUE(%d),\n", class_props_idx);
|
||||
else
|
||||
printf(" JS_NULL,\n");
|
||||
printf(" %d,\n", ctor_func_idx);
|
||||
if (proto_props_idx >= 0)
|
||||
printf(" JS_ROM_VALUE(%d),\n", proto_props_idx);
|
||||
else
|
||||
printf(" JS_NULL,\n");
|
||||
if (parent_class_idx >= 0) {
|
||||
printf(" JS_ROM_VALUE(%d),\n", parent_class_idx);
|
||||
} else {
|
||||
printf(" JS_NULL,\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
s->cur_offset += 5;
|
||||
|
||||
e = malloc(sizeof(*e));
|
||||
memset(e, 0, sizeof(*e));
|
||||
e->class_idx = ident;
|
||||
e->class1 = d;
|
||||
if (ctor_func_idx >= 0) {
|
||||
e->class_id = strdup(d->class_id);
|
||||
e->finalizer_name = strdup(d->finalizer_name);
|
||||
}
|
||||
list_add_tail(&e->link, &s->class_list);
|
||||
return ident;
|
||||
}
|
||||
|
||||
#define JS_SHORTINT_MIN (-(1 << 30))
|
||||
#define JS_SHORTINT_MAX ((1 << 30) - 1)
|
||||
|
||||
static BOOL is_short_int(double d)
|
||||
{
|
||||
return (d >= JS_SHORTINT_MIN && d <= JS_SHORTINT_MAX && (int32_t)d == d);
|
||||
}
|
||||
|
||||
static int define_value(BuildContext *s, const JSPropDef *d)
|
||||
{
|
||||
int ident;
|
||||
ident = -1;
|
||||
switch(d->def_type) {
|
||||
case JS_DEF_PROP_DOUBLE:
|
||||
{
|
||||
uint64_t v;
|
||||
if (!is_short_int(d->u.f64)) {
|
||||
ident = s->cur_offset;
|
||||
printf(" /* float64 (offset=%d) */\n", ident);
|
||||
printf(" JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),\n");
|
||||
v = float64_as_uint64(d->u.f64);
|
||||
if (JSW == 8) {
|
||||
printf(" 0x%016zx,\n", (size_t)v);
|
||||
printf("\n");
|
||||
s->cur_offset += 2;
|
||||
} else {
|
||||
/* XXX: little endian assumed */
|
||||
printf(" 0x%08x,\n", (uint32_t)v);
|
||||
printf(" 0x%08x,\n", (uint32_t)(v >> 32));
|
||||
printf("\n");
|
||||
s->cur_offset += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JS_DEF_CLASS:
|
||||
ident = define_class(s, d->u.class1);
|
||||
break;
|
||||
case JS_DEF_CGETSET:
|
||||
{
|
||||
int get_idx = -1, set_idx = -1;
|
||||
char buf[256];
|
||||
if (strcmp(d->u.getset.get_func_name, "NULL") != 0) {
|
||||
snprintf(buf, sizeof(buf), "get %s", d->name);
|
||||
get_idx = add_cfunc(&s->cfunc_list,
|
||||
buf,
|
||||
0, /* length */
|
||||
d->u.getset.magic,
|
||||
d->u.getset.cproto_name,
|
||||
d->u.getset.get_func_name);
|
||||
}
|
||||
if (strcmp(d->u.getset.set_func_name, "NULL") != 0) {
|
||||
snprintf(buf, sizeof(buf), "set %s", d->name);
|
||||
set_idx = add_cfunc(&s->cfunc_list,
|
||||
buf,
|
||||
1, /* length */
|
||||
d->u.getset.magic,
|
||||
d->u.getset.cproto_name,
|
||||
d->u.getset.set_func_name);
|
||||
}
|
||||
ident = s->cur_offset;
|
||||
printf(" /* getset (offset=%d) */\n", ident);
|
||||
printf(" JS_VALUE_ARRAY_HEADER(2),\n");
|
||||
if (get_idx >= 0)
|
||||
printf(" JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, %d),\n", get_idx);
|
||||
else
|
||||
printf(" JS_UNDEFINED,\n");
|
||||
if (set_idx >= 0)
|
||||
printf(" JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, %d),\n", set_idx);
|
||||
else
|
||||
printf(" JS_UNDEFINED,\n");
|
||||
printf("\n");
|
||||
s->cur_offset += 3;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ident;
|
||||
}
|
||||
|
||||
static void define_atoms_props(BuildContext *s, const JSPropDef *props_def, JSPropsKindEnum props_kind);
|
||||
|
||||
static void define_atoms_class(BuildContext *s, const JSClassDef *d)
|
||||
{
|
||||
ClassDefEntry *e;
|
||||
/* check if the class is already defined */
|
||||
e = find_class(s, d);
|
||||
if (e)
|
||||
return;
|
||||
if (d->parent_class)
|
||||
define_atoms_class(s, d->parent_class);
|
||||
if (d->func_name)
|
||||
add_atom(&s->atom_list, d->name);
|
||||
if (d->class_props)
|
||||
define_atoms_props(s, d->class_props, d->func_name ? PROPS_KIND_CLASS : PROPS_KIND_OBJECT);
|
||||
if (d->proto_props)
|
||||
define_atoms_props(s, d->proto_props, PROPS_KIND_PROTO);
|
||||
}
|
||||
|
||||
static void define_atoms_props(BuildContext *s, const JSPropDef *props_def, JSPropsKindEnum props_kind)
|
||||
{
|
||||
const JSPropDef *d;
|
||||
for(d = props_def; d->def_type != JS_DEF_END; d++) {
|
||||
add_atom(&s->atom_list, d->name);
|
||||
switch(d->def_type) {
|
||||
case JS_DEF_PROP_STRING:
|
||||
add_atom(&s->atom_list, d->u.str);
|
||||
break;
|
||||
case JS_DEF_CLASS:
|
||||
define_atoms_class(s, d->u.class1);
|
||||
break;
|
||||
case JS_DEF_CGETSET:
|
||||
{
|
||||
char buf[256];
|
||||
if (strcmp(d->u.getset.get_func_name, "NULL") != 0) {
|
||||
snprintf(buf, sizeof(buf), "get %s", d->name);
|
||||
add_atom(&s->atom_list, buf);
|
||||
}
|
||||
if (strcmp(d->u.getset.set_func_name, "NULL") != 0) {
|
||||
snprintf(buf, sizeof(buf), "set %s", d->name);
|
||||
add_atom(&s->atom_list, buf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int usage(const char *name)
|
||||
{
|
||||
fprintf(stderr, "usage: %s {-m32 | -m64} [-a]\n", name);
|
||||
fprintf(stderr,
|
||||
" create a ROM file for the mquickjs standard library\n"
|
||||
"--help list options\n"
|
||||
"-m32 force generation for a 32 bit target\n"
|
||||
"-m64 force generation for a 64 bit target\n"
|
||||
"-a generate the mquickjs_atom.h header\n"
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int build_atoms(const char *stdlib_name, const JSPropDef *global_obj,
|
||||
const JSPropDef *c_function_decl, int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
unsigned jsw;
|
||||
BuildContext ss, *s = &ss;
|
||||
BOOL build_atom_defines = FALSE;
|
||||
|
||||
#if INTPTR_MAX >= INT64_MAX
|
||||
jsw = 8;
|
||||
#else
|
||||
jsw = 4;
|
||||
#endif
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-m64")) {
|
||||
jsw = 8;
|
||||
} else if (!strcmp(argv[i], "-m32")) {
|
||||
jsw = 4;
|
||||
} else if (!strcmp(argv[i], "-a")) {
|
||||
build_atom_defines = TRUE;
|
||||
} else if (!strcmp(argv[i], "--help")) {
|
||||
return usage(argv[0]);
|
||||
} else {
|
||||
fprintf(stderr, "invalid argument '%s'\n", argv[i]);
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
JSW = jsw;
|
||||
|
||||
if (build_atom_defines) {
|
||||
dump_atom_defines();
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
init_list_head(&s->class_list);
|
||||
|
||||
/* add the predefined atoms (they have a corresponding define) */
|
||||
for(i = 0; i < countof(atoms); i++) {
|
||||
add_atom(&s->atom_list, atoms[i]);
|
||||
}
|
||||
|
||||
/* add the predefined functions */
|
||||
if (c_function_decl) {
|
||||
const JSPropDef *d;
|
||||
for(d = c_function_decl; d->def_type != JS_DEF_END; d++) {
|
||||
if (d->def_type != JS_DEF_CFUNC) {
|
||||
fprintf(stderr, "only C functions are allowed in c_function_decl[]\n");
|
||||
exit(1);
|
||||
}
|
||||
add_atom(&s->atom_list, d->name);
|
||||
add_cfunc(&s->cfunc_list,
|
||||
d->name,
|
||||
d->u.func.length,
|
||||
d->u.func.magic,
|
||||
d->u.func.cproto_name,
|
||||
d->u.func.func_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* first pass to define the atoms */
|
||||
define_atoms_props(s, global_obj, PROPS_KIND_GLOBAL);
|
||||
free_class_entries(s);
|
||||
|
||||
printf("/* this file is automatically generated - do not edit */\n\n");
|
||||
printf("#include \"mquickjs_priv.h\"\n\n");
|
||||
|
||||
printf("static const uint%u_t __attribute((aligned(%d))) js_stdlib_table[] = {\n",
|
||||
JSW * 8, ATOM_ALIGN);
|
||||
|
||||
dump_atoms(s);
|
||||
|
||||
s->global_object_offset = define_props(s, global_obj, PROPS_KIND_GLOBAL, NULL);
|
||||
|
||||
printf("};\n\n");
|
||||
|
||||
dump_cfuncs(s);
|
||||
|
||||
printf("#ifndef JS_CLASS_COUNT\n"
|
||||
"#define JS_CLASS_COUNT JS_CLASS_USER /* total number of classes */\n"
|
||||
"#endif\n\n");
|
||||
|
||||
dump_cfinalizers(s);
|
||||
|
||||
free_class_entries(s);
|
||||
|
||||
printf("const JSSTDLibraryDef %s = {\n", stdlib_name);
|
||||
printf(" js_stdlib_table,\n");
|
||||
printf(" js_c_function_table,\n");
|
||||
printf(" js_c_finalizer_table,\n");
|
||||
printf(" %d,\n", s->cur_offset);
|
||||
printf(" %d,\n", ATOM_ALIGN);
|
||||
printf(" %d,\n", s->sorted_atom_table_offset);
|
||||
printf(" %d,\n", s->global_object_offset);
|
||||
printf(" JS_CLASS_COUNT,\n");
|
||||
printf("};\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
97
lib/mquickjs/mquickjs_build.h
Normal file
97
lib/mquickjs/mquickjs_build.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Micro QuickJS build utility
|
||||
*
|
||||
* Copyright (c) 2017-2025 Fabrice Bellard
|
||||
* Copyright (c) 2017-2025 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MQUICKJS_BUILD_H
|
||||
#define MQUICKJS_BUILD_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
enum {
|
||||
JS_DEF_END,
|
||||
JS_DEF_CFUNC,
|
||||
JS_DEF_CGETSET,
|
||||
JS_DEF_PROP_DOUBLE,
|
||||
JS_DEF_PROP_UNDEFINED,
|
||||
JS_DEF_PROP_STRING,
|
||||
JS_DEF_PROP_NULL,
|
||||
JS_DEF_CLASS,
|
||||
};
|
||||
|
||||
typedef struct JSClassDef JSClassDef;
|
||||
|
||||
typedef struct JSPropDef {
|
||||
int def_type;
|
||||
const char *name;
|
||||
union {
|
||||
struct {
|
||||
uint8_t length;
|
||||
const char *magic;
|
||||
const char *cproto_name;
|
||||
const char *func_name;
|
||||
} func;
|
||||
struct {
|
||||
const char *magic;
|
||||
const char *cproto_name;
|
||||
const char *get_func_name;
|
||||
const char *set_func_name;
|
||||
} getset;
|
||||
double f64;
|
||||
const JSClassDef *class1;
|
||||
const char *str;
|
||||
} u;
|
||||
} JSPropDef;
|
||||
|
||||
typedef struct JSClassDef {
|
||||
const char *name;
|
||||
int length;
|
||||
const char *cproto_name;
|
||||
const char *func_name;
|
||||
const char *class_id;
|
||||
const JSPropDef *class_props; /* NULL if none */
|
||||
const JSPropDef *proto_props; /* NULL if none */
|
||||
const JSClassDef *parent_class; /* NULL if none */
|
||||
const char *finalizer_name; /* "NULL" if none */
|
||||
} JSClassDef;
|
||||
|
||||
#define JS_PROP_END { JS_DEF_END }
|
||||
#define JS_CFUNC_DEF(name, length, func_name) { JS_DEF_CFUNC, name, { .func = { length, "0", "generic", #func_name } } }
|
||||
#define JS_CFUNC_MAGIC_DEF(name, length, func_name, magic) { JS_DEF_CFUNC, name, { .func = { length, #magic, "generic_magic", #func_name } } }
|
||||
#define JS_CFUNC_SPECIAL_DEF(name, length, proto, func_name) { JS_DEF_CFUNC, name, { .func = { length, "0", #proto, #func_name } } }
|
||||
#define JS_CGETSET_DEF(name, get_name, set_name) { JS_DEF_CGETSET, name, { .getset = { "0", "generic", #get_name, #set_name } } }
|
||||
#define JS_CGETSET_MAGIC_DEF(name, get_name, set_name, magic) { JS_DEF_CGETSET, name, { .getset = { #magic, "generic_magic", #get_name, #set_name } } }
|
||||
#define JS_PROP_CLASS_DEF(name, cl) { JS_DEF_CLASS, name, { .class1 = cl } }
|
||||
#define JS_PROP_DOUBLE_DEF(name, val, flags) { JS_DEF_PROP_DOUBLE, name, { .f64 = val } }
|
||||
#define JS_PROP_UNDEFINED_DEF(name, flags) { JS_DEF_PROP_UNDEFINED, name }
|
||||
#define JS_PROP_NULL_DEF(name, flags) { JS_DEF_PROP_NULL, name }
|
||||
#define JS_PROP_STRING_DEF(name, cstr, flags) { JS_DEF_PROP_STRING, name, { .str = cstr } }
|
||||
|
||||
#define JS_CLASS_DEF(name, length, func_name, class_id, class_props, proto_props, parent_class, finalizer_name) { name, length, "constructor", #func_name, #class_id, class_props, proto_props, parent_class, #finalizer_name }
|
||||
#define JS_CLASS_MAGIC_DEF(name, length, func_name, class_id, class_props, proto_props, parent_class, finalizer_name) { name, length, "constructor_magic", #func_name, #class_id, class_props, proto_props, parent_class, #finalizer_name }
|
||||
#define JS_OBJECT_DEF(name, obj_props) { name, 0, NULL, NULL, NULL, obj_props, NULL, NULL, NULL }
|
||||
|
||||
int build_atoms(const char *stdlib_name, const JSPropDef *global_obj,
|
||||
const JSPropDef *c_function_decl, int argc, char **argv);
|
||||
|
||||
#endif /* MQUICKJS_BUILD_H */
|
||||
264
lib/mquickjs/mquickjs_opcode.h
Normal file
264
lib/mquickjs/mquickjs_opcode.h
Normal file
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Micro QuickJS opcode definitions
|
||||
*
|
||||
* Copyright (c) 2017-2025 Fabrice Bellard
|
||||
* Copyright (c) 2017-2025 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifdef FMT
|
||||
FMT(none)
|
||||
FMT(none_int)
|
||||
FMT(none_loc)
|
||||
FMT(none_arg)
|
||||
FMT(none_var_ref)
|
||||
FMT(u8)
|
||||
FMT(i8)
|
||||
FMT(loc8)
|
||||
FMT(const8)
|
||||
FMT(label8)
|
||||
FMT(u16)
|
||||
FMT(i16)
|
||||
FMT(label16)
|
||||
FMT(npop)
|
||||
FMT(npopx)
|
||||
FMT(loc)
|
||||
FMT(arg)
|
||||
FMT(var_ref)
|
||||
FMT(u32)
|
||||
FMT(i32)
|
||||
FMT(const16)
|
||||
FMT(label)
|
||||
FMT(value)
|
||||
#undef FMT
|
||||
#endif /* FMT */
|
||||
|
||||
#ifdef DEF
|
||||
|
||||
#ifndef def
|
||||
#define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f)
|
||||
#endif
|
||||
|
||||
DEF(invalid, 1, 0, 0, none) /* never emitted */
|
||||
|
||||
/* push values */
|
||||
DEF( push_value, 5, 0, 1, value)
|
||||
DEF( push_const, 3, 0, 1, const16)
|
||||
DEF( fclosure, 3, 0, 1, const16)
|
||||
DEF( undefined, 1, 0, 1, none)
|
||||
DEF( null, 1, 0, 1, none)
|
||||
DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */
|
||||
DEF( push_false, 1, 0, 1, none)
|
||||
DEF( push_true, 1, 0, 1, none)
|
||||
DEF( object, 3, 0, 1, u16)
|
||||
DEF( this_func, 1, 0, 1, none)
|
||||
DEF( arguments, 1, 0, 1, none)
|
||||
DEF( new_target, 1, 0, 1, none)
|
||||
|
||||
DEF( drop, 1, 1, 0, none) /* a -> */
|
||||
DEF( nip, 1, 2, 1, none) /* a b -> b */
|
||||
//DEF( nip1, 1, 3, 2, none) /* a b c -> b c */
|
||||
DEF( dup, 1, 1, 2, none) /* a -> a a */
|
||||
DEF( dup1, 1, 2, 3, none) /* a b -> a a b */
|
||||
DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */
|
||||
//DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */
|
||||
DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */
|
||||
DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */
|
||||
//DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */
|
||||
DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */
|
||||
DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */
|
||||
//DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */
|
||||
DEF( swap, 1, 2, 2, none) /* a b -> b a */
|
||||
//DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */
|
||||
DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */
|
||||
//DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */
|
||||
//DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */
|
||||
//DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */
|
||||
|
||||
DEF(call_constructor, 3, 1, 1, npop) /* func args... -> ret (arguments are not counted in n_pop) */
|
||||
DEF( call, 3, 1, 1, npop) /* func args... -> ret (arguments are not counted in n_pop) */
|
||||
DEF( call_method, 3, 2, 1, npop) /* this func args.. -> ret (arguments are not counted in n_pop) */
|
||||
DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */
|
||||
DEF( return, 1, 1, 0, none)
|
||||
DEF( return_undef, 1, 0, 0, none)
|
||||
DEF( throw, 1, 1, 0, none)
|
||||
DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a bytecode string */
|
||||
|
||||
DEF( get_field, 3, 1, 1, const16) /* obj -> val */
|
||||
DEF( get_field2, 3, 1, 2, const16) /* obj -> obj val */
|
||||
DEF( put_field, 3, 2, 0, const16) /* obj val -> */
|
||||
DEF( get_array_el, 1, 2, 1, none) /* obj prop -> val */
|
||||
DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */
|
||||
DEF( put_array_el, 1, 3, 0, none) /* obj prop val -> */
|
||||
DEF( get_length, 1, 1, 1, none) /* obj -> val */
|
||||
DEF( get_length2, 1, 1, 2, none) /* obj -> obj val */
|
||||
DEF( define_field, 3, 2, 1, const16) /* obj val -> obj */
|
||||
DEF( define_getter, 3, 2, 1, const16) /* obj val -> obj */
|
||||
DEF( define_setter, 3, 2, 1, const16) /* obj val -> obj */
|
||||
DEF( set_proto, 1, 2, 1, none) /* obj proto -> obj */
|
||||
|
||||
DEF( get_loc, 3, 0, 1, loc)
|
||||
DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */
|
||||
DEF( get_arg, 3, 0, 1, arg)
|
||||
DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */
|
||||
DEF( get_var_ref, 3, 0, 1, var_ref)
|
||||
DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */
|
||||
DEF(get_var_ref_nocheck, 3, 0, 1, var_ref)
|
||||
DEF(put_var_ref_nocheck, 3, 1, 0, var_ref)
|
||||
DEF( if_false, 5, 1, 0, label)
|
||||
DEF( if_true, 5, 1, 0, label) /* must come after if_false */
|
||||
DEF( goto, 5, 0, 0, label) /* must come after if_true */
|
||||
DEF( catch, 5, 0, 1, label)
|
||||
DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */
|
||||
DEF( ret, 1, 1, 0, none) /* used to return from the finally block */
|
||||
|
||||
DEF( for_in_start, 1, 1, 1, none) /* obj -> iter */
|
||||
DEF( for_of_start, 1, 1, 1, none) /* obj -> iter */
|
||||
DEF( for_of_next, 1, 1, 3, none) /* iter -> iter val done */
|
||||
|
||||
/* arithmetic/logic operations */
|
||||
DEF( neg, 1, 1, 1, none)
|
||||
DEF( plus, 1, 1, 1, none)
|
||||
DEF( dec, 1, 1, 1, none)
|
||||
DEF( inc, 1, 1, 1, none)
|
||||
DEF( post_dec, 1, 1, 2, none)
|
||||
DEF( post_inc, 1, 1, 2, none)
|
||||
DEF( not, 1, 1, 1, none)
|
||||
DEF( lnot, 1, 1, 1, none)
|
||||
DEF( typeof, 1, 1, 1, none)
|
||||
DEF( delete, 1, 2, 1, none) /* obj prop -> ret */
|
||||
|
||||
DEF( mul, 1, 2, 1, none)
|
||||
DEF( div, 1, 2, 1, none)
|
||||
DEF( mod, 1, 2, 1, none)
|
||||
DEF( add, 1, 2, 1, none)
|
||||
DEF( sub, 1, 2, 1, none)
|
||||
DEF( pow, 1, 2, 1, none)
|
||||
DEF( shl, 1, 2, 1, none)
|
||||
DEF( sar, 1, 2, 1, none)
|
||||
DEF( shr, 1, 2, 1, none)
|
||||
DEF( lt, 1, 2, 1, none)
|
||||
DEF( lte, 1, 2, 1, none)
|
||||
DEF( gt, 1, 2, 1, none)
|
||||
DEF( gte, 1, 2, 1, none)
|
||||
DEF( instanceof, 1, 2, 1, none)
|
||||
DEF( in, 1, 2, 1, none)
|
||||
DEF( eq, 1, 2, 1, none)
|
||||
DEF( neq, 1, 2, 1, none)
|
||||
DEF( strict_eq, 1, 2, 1, none)
|
||||
DEF( strict_neq, 1, 2, 1, none)
|
||||
DEF( and, 1, 2, 1, none)
|
||||
DEF( xor, 1, 2, 1, none)
|
||||
DEF( or, 1, 2, 1, none)
|
||||
/* must be the last non short and non temporary opcode */
|
||||
DEF( nop, 1, 0, 0, none)
|
||||
|
||||
DEF( push_minus1, 1, 0, 1, none_int)
|
||||
DEF( push_0, 1, 0, 1, none_int)
|
||||
DEF( push_1, 1, 0, 1, none_int)
|
||||
DEF( push_2, 1, 0, 1, none_int)
|
||||
DEF( push_3, 1, 0, 1, none_int)
|
||||
DEF( push_4, 1, 0, 1, none_int)
|
||||
DEF( push_5, 1, 0, 1, none_int)
|
||||
DEF( push_6, 1, 0, 1, none_int)
|
||||
DEF( push_7, 1, 0, 1, none_int)
|
||||
DEF( push_i8, 2, 0, 1, i8)
|
||||
DEF( push_i16, 3, 0, 1, i16)
|
||||
DEF( push_const8, 2, 0, 1, const8)
|
||||
DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */
|
||||
DEF(push_empty_string, 1, 0, 1, none)
|
||||
|
||||
DEF( get_loc8, 2, 0, 1, loc8)
|
||||
DEF( put_loc8, 2, 1, 0, loc8) /* must follow get_loc8 */
|
||||
|
||||
DEF( get_loc0, 1, 0, 1, none_loc)
|
||||
DEF( get_loc1, 1, 0, 1, none_loc)
|
||||
DEF( get_loc2, 1, 0, 1, none_loc)
|
||||
DEF( get_loc3, 1, 0, 1, none_loc)
|
||||
DEF( put_loc0, 1, 1, 0, none_loc) /* must follow get_loc */
|
||||
DEF( put_loc1, 1, 1, 0, none_loc)
|
||||
DEF( put_loc2, 1, 1, 0, none_loc)
|
||||
DEF( put_loc3, 1, 1, 0, none_loc)
|
||||
DEF( get_arg0, 1, 0, 1, none_arg)
|
||||
DEF( get_arg1, 1, 0, 1, none_arg)
|
||||
DEF( get_arg2, 1, 0, 1, none_arg)
|
||||
DEF( get_arg3, 1, 0, 1, none_arg)
|
||||
DEF( put_arg0, 1, 1, 0, none_arg) /* must follow get_arg */
|
||||
DEF( put_arg1, 1, 1, 0, none_arg)
|
||||
DEF( put_arg2, 1, 1, 0, none_arg)
|
||||
DEF( put_arg3, 1, 1, 0, none_arg)
|
||||
#if 0
|
||||
DEF( if_false8, 2, 1, 0, label8)
|
||||
DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */
|
||||
DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */
|
||||
DEF( goto16, 3, 0, 0, label16)
|
||||
|
||||
DEF( call0, 1, 1, 1, npopx)
|
||||
DEF( call1, 1, 1, 1, npopx)
|
||||
DEF( call2, 1, 1, 1, npopx)
|
||||
DEF( call3, 1, 1, 1, npopx)
|
||||
#endif
|
||||
|
||||
#undef DEF
|
||||
#undef def
|
||||
#endif /* DEF */
|
||||
|
||||
#ifdef REDEF
|
||||
|
||||
/* regular expression bytecode */
|
||||
REDEF(invalid, 1) /* never used */
|
||||
REDEF(char1, 2)
|
||||
REDEF(char2, 3)
|
||||
REDEF(char3, 4)
|
||||
REDEF(char4, 5)
|
||||
REDEF(dot, 1)
|
||||
REDEF(any, 1) /* same as dot but match any character including line terminator */
|
||||
REDEF(space, 1)
|
||||
REDEF(not_space, 1) /* must come after */
|
||||
REDEF(line_start, 1)
|
||||
REDEF(line_start_m, 1)
|
||||
REDEF(line_end, 1)
|
||||
REDEF(line_end_m, 1)
|
||||
REDEF(goto, 5)
|
||||
REDEF(split_goto_first, 5)
|
||||
REDEF(split_next_first, 5)
|
||||
REDEF(match, 1)
|
||||
REDEF(lookahead_match, 1)
|
||||
REDEF(negative_lookahead_match, 1) /* must come after */
|
||||
REDEF(save_start, 2) /* save start position */
|
||||
REDEF(save_end, 2) /* save end position, must come after saved_start */
|
||||
REDEF(save_reset, 3) /* reset save positions */
|
||||
REDEF(loop, 6) /* decrement the top the stack and goto if != 0 */
|
||||
REDEF(loop_split_goto_first, 10) /* loop and then split */
|
||||
REDEF(loop_split_next_first, 10)
|
||||
REDEF(loop_check_adv_split_goto_first, 10) /* loop and then check advance and split */
|
||||
REDEF(loop_check_adv_split_next_first, 10)
|
||||
REDEF(set_i32, 6) /* store the immediate value to a register */
|
||||
REDEF(word_boundary, 1)
|
||||
REDEF(not_word_boundary, 1)
|
||||
REDEF(back_reference, 2)
|
||||
REDEF(back_reference_i, 2)
|
||||
REDEF(range8, 2) /* variable length */
|
||||
REDEF(range, 3) /* variable length */
|
||||
REDEF(lookahead, 5)
|
||||
REDEF(negative_lookahead, 5) /* must come after */
|
||||
REDEF(set_char_pos, 2) /* store the character position to a register */
|
||||
REDEF(check_advance, 2) /* check that the register is different from the character position */
|
||||
|
||||
#endif /* REDEF */
|
||||
268
lib/mquickjs/mquickjs_priv.h
Normal file
268
lib/mquickjs/mquickjs_priv.h
Normal file
@ -0,0 +1,268 @@
|
||||
/* microj private definitions */
|
||||
#ifndef MICROJS_PRIV_H
|
||||
#define MICROJS_PRIV_H
|
||||
|
||||
#include "mquickjs.h"
|
||||
#include "libm.h"
|
||||
|
||||
#define JS_DUMP /* 2.6 kB */
|
||||
//#define DUMP_EXEC
|
||||
//#define DUMP_FUNC_BYTECODE /* dump the bytecode of each compiled function */
|
||||
//#define DUMP_REOP /* dump regexp bytecode */
|
||||
//#define DUMP_GC
|
||||
//#define DUMP_TOKEN /* dump parsed tokens */
|
||||
/* run GC before at each malloc() and modify the allocated data pointers */
|
||||
//#define DEBUG_GC
|
||||
#if defined(DUMP_FUNC_BYTECODE) || defined(DUMP_EXEC)
|
||||
#define DUMP_BYTECODE /* include the dump_byte_code() function */
|
||||
#endif
|
||||
|
||||
#define JS_VALUE_TO_PTR(v) (void *)((uintptr_t)(v) - 1)
|
||||
#define JS_VALUE_FROM_PTR(ptr) (JSWord)((uintptr_t)(ptr) + 1)
|
||||
|
||||
#define JS_IS_ROM_PTR(ctx, ptr) ((uintptr_t)(ptr) < (uintptr_t)ctx || (uintptr_t)(ptr) >= (uintptr_t)ctx->stack_top)
|
||||
|
||||
enum {
|
||||
JS_MTAG_FREE,
|
||||
/* javascript values */
|
||||
JS_MTAG_OBJECT,
|
||||
JS_MTAG_FLOAT64,
|
||||
JS_MTAG_STRING,
|
||||
/* other special memory blocks */
|
||||
JS_MTAG_FUNCTION_BYTECODE,
|
||||
JS_MTAG_VALUE_ARRAY,
|
||||
JS_MTAG_BYTE_ARRAY,
|
||||
JS_MTAG_VARREF,
|
||||
|
||||
JS_MTAG_COUNT,
|
||||
};
|
||||
|
||||
/* JS_MTAG_BITS bits are reserved at the start of every memory block */
|
||||
#define JS_MTAG_BITS 4
|
||||
|
||||
#define JS_MB_HEADER \
|
||||
JSWord gc_mark: 1; \
|
||||
JSWord mtag: (JS_MTAG_BITS - 1)
|
||||
|
||||
typedef enum {
|
||||
JS_PROP_NORMAL,
|
||||
JS_PROP_GETSET, /* value is a two element JSValueArray */
|
||||
JS_PROP_VARREF, /* value is a JSVarRef (used for global variables) */
|
||||
JS_PROP_SPECIAL, /* for the prototype and constructor properties in ROM */
|
||||
} JSPropTypeEnum;
|
||||
|
||||
#define JS_MB_HEADER_DEF(tag) ((tag) << 1)
|
||||
#define JS_VALUE_ARRAY_HEADER(size) (JS_MB_HEADER_DEF(JS_MTAG_VALUE_ARRAY) | ((size) << JS_MTAG_BITS))
|
||||
|
||||
#define JS_ROM_VALUE(offset) JS_VALUE_FROM_PTR(&js_stdlib_table[offset])
|
||||
|
||||
/* runtime helpers */
|
||||
JSValue js_function_constructor(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_function_get_prototype(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_function_set_prototype(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_function_get_length_name(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int is_name);
|
||||
JSValue js_function_toString(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_function_call(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_function_apply(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_function_bind(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_function_bound(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, JSValue params);
|
||||
|
||||
JSValue js_array_get_length(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_array_set_length(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
|
||||
JSValue js_number_constructor(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_number_toString(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_number_toFixed(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_number_toExponential(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_number_toPrecision(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_number_parseInt(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_number_parseFloat(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
|
||||
JSValue js_boolean_constructor(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
|
||||
JSValue js_string_get_length(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_string_set_length(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_string_slice(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_string_substring(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
enum {
|
||||
magic_internalAt,
|
||||
magic_charAt,
|
||||
magic_charCodeAt,
|
||||
magic_codePointAt,
|
||||
};
|
||||
JSValue js_string_charAt(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int magic);
|
||||
JSValue js_string_concat(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_string_indexOf(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int lastIndexOf);
|
||||
JSValue js_string_match(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_string_replace(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int is_replaceAll);
|
||||
JSValue js_string_search(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_string_split(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_string_toLowerCase(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int to_lower);
|
||||
JSValue js_string_trim(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int magic);
|
||||
JSValue js_string_toString(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_string_repeat(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
|
||||
JSValue js_object_constructor(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_object_defineProperty(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_object_getPrototypeOf(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_object_setPrototypeOf(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_object_create(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_object_keys(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_object_hasOwnProperty(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_object_toString(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
|
||||
JSValue js_string_constructor(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_string_fromCharCode(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int is_fromCodePoint);
|
||||
|
||||
JSValue js_error_constructor(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int magic);
|
||||
JSValue js_error_toString(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_error_get_message(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int magic);
|
||||
|
||||
JSValue js_array_constructor(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_array_push(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int is_unshift);
|
||||
JSValue js_array_pop(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_array_shift(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_array_join(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_array_toString(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_array_isArray(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_array_reverse(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_array_concat(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_array_indexOf(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int is_lastIndexOf);
|
||||
JSValue js_array_slice(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_array_splice(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_array_sort(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
|
||||
#define js_special_every 0
|
||||
#define js_special_some 1
|
||||
#define js_special_forEach 2
|
||||
#define js_special_map 3
|
||||
#define js_special_filter 4
|
||||
|
||||
JSValue js_array_every(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int special);
|
||||
|
||||
#define js_special_reduce 0
|
||||
#define js_special_reduceRight 1
|
||||
|
||||
JSValue js_array_reduce(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int special);
|
||||
|
||||
JSValue js_math_min_max(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int magic);
|
||||
double js_math_sign(double a);
|
||||
double js_math_fround(double a);
|
||||
JSValue js_math_imul(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_math_clz32(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_math_atan2(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_math_pow(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_math_random(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
|
||||
JSValue js_array_buffer_constructor(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_array_buffer_get_byteLength(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_typed_array_base_constructor(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_typed_array_constructor(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int magic);
|
||||
JSValue js_typed_array_get_length(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int magic);
|
||||
JSValue js_typed_array_subarray(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_typed_array_set(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
|
||||
JSValue js_date_constructor(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
|
||||
JSValue js_global_eval(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_global_isNaN(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_global_isFinite(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
|
||||
JSValue js_json_parse(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_json_stringify(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
|
||||
JSValue js_regexp_constructor(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_regexp_get_lastIndex(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_regexp_set_lastIndex(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_regexp_get_source(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_regexp_get_flags(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv);
|
||||
JSValue js_regexp_exec(JSContext *ctx, JSValue *this_val,
|
||||
int argc, JSValue *argv, int is_test);
|
||||
|
||||
#endif /* MICROJS_PRIV_H */
|
||||
18
lib/mquickjs/scripts/build.sh
Executable file
18
lib/mquickjs/scripts/build.sh
Executable file
@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
cd $SCRIPT_DIR/.. # mquickjs directory
|
||||
|
||||
make clean
|
||||
|
||||
CONFIG_X86_32=1 CONFIG_SOFTFLOAT=1 make mqjs_stdlib.h
|
||||
CONFIG_X86_32=1 CONFIG_SOFTFLOAT=1 make mquickjs_atom.h
|
||||
|
||||
mv mqjs_stdlib.h crosspoint_stdlib.h
|
||||
|
||||
mv mquickjs_atom.h crosspoint_atom.h # avoid being deleted in the next step
|
||||
make clean
|
||||
mv crosspoint_atom.h mquickjs_atom.h
|
||||
566
lib/mquickjs/scripts/crosspoint_stdlib.c
Normal file
566
lib/mquickjs/scripts/crosspoint_stdlib.c
Normal file
@ -0,0 +1,566 @@
|
||||
/*
|
||||
* Micro QuickJS REPL library
|
||||
*
|
||||
* Copyright (c) 2017-2025 Fabrice Bellard
|
||||
* Copyright (c) 2017-2025 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mquickjs_build.h"
|
||||
|
||||
/* defined in mqjs_example.c */
|
||||
//#define CONFIG_CLASS_EXAMPLE
|
||||
|
||||
static const JSPropDef js_object_proto[] = {
|
||||
JS_CFUNC_DEF("hasOwnProperty", 1, js_object_hasOwnProperty),
|
||||
JS_CFUNC_DEF("toString", 0, js_object_toString),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSPropDef js_object[] = {
|
||||
JS_CFUNC_DEF("defineProperty", 3, js_object_defineProperty),
|
||||
JS_CFUNC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf),
|
||||
JS_CFUNC_DEF("setPrototypeOf", 2, js_object_setPrototypeOf),
|
||||
JS_CFUNC_DEF("create", 2, js_object_create),
|
||||
JS_CFUNC_DEF("keys", 1, js_object_keys),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_object_class =
|
||||
JS_CLASS_DEF("Object", 1, js_object_constructor, JS_CLASS_OBJECT,
|
||||
js_object, js_object_proto, NULL, NULL);
|
||||
|
||||
static const JSPropDef js_function_proto[] = {
|
||||
JS_CGETSET_DEF("prototype", js_function_get_prototype, js_function_set_prototype ),
|
||||
JS_CFUNC_DEF("call", 1, js_function_call ),
|
||||
JS_CFUNC_DEF("apply", 2, js_function_apply ),
|
||||
JS_CFUNC_DEF("bind", 1, js_function_bind ),
|
||||
JS_CFUNC_DEF("toString", 0, js_function_toString ),
|
||||
JS_CGETSET_MAGIC_DEF("length", js_function_get_length_name, NULL, 0 ),
|
||||
JS_CGETSET_MAGIC_DEF("name", js_function_get_length_name, NULL, 1 ),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_function_class =
|
||||
JS_CLASS_DEF("Function", 1, js_function_constructor, JS_CLASS_CLOSURE, NULL, js_function_proto, NULL, NULL);
|
||||
|
||||
static const JSPropDef js_number_proto[] = {
|
||||
JS_CFUNC_DEF("toExponential", 1, js_number_toExponential ),
|
||||
JS_CFUNC_DEF("toFixed", 1, js_number_toFixed ),
|
||||
JS_CFUNC_DEF("toPrecision", 1, js_number_toPrecision ),
|
||||
JS_CFUNC_DEF("toString", 1, js_number_toString ),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSPropDef js_number[] = {
|
||||
JS_CFUNC_DEF("parseInt", 2, js_number_parseInt ),
|
||||
JS_CFUNC_DEF("parseFloat", 1, js_number_parseFloat ),
|
||||
JS_PROP_DOUBLE_DEF("MAX_VALUE", 1.7976931348623157e+308, 0 ),
|
||||
JS_PROP_DOUBLE_DEF("MIN_VALUE", 5e-324, 0 ),
|
||||
JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
|
||||
JS_PROP_DOUBLE_DEF("NEGATIVE_INFINITY", -INFINITY, 0 ),
|
||||
JS_PROP_DOUBLE_DEF("POSITIVE_INFINITY", INFINITY, 0 ),
|
||||
JS_PROP_DOUBLE_DEF("EPSILON", 2.220446049250313e-16, 0 ), /* ES6 */
|
||||
JS_PROP_DOUBLE_DEF("MAX_SAFE_INTEGER", 9007199254740991.0, 0 ), /* ES6 */
|
||||
JS_PROP_DOUBLE_DEF("MIN_SAFE_INTEGER", -9007199254740991.0, 0 ), /* ES6 */
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_number_class =
|
||||
JS_CLASS_DEF("Number", 1, js_number_constructor, JS_CLASS_NUMBER, js_number, js_number_proto, NULL, NULL);
|
||||
|
||||
static const JSClassDef js_boolean_class =
|
||||
JS_CLASS_DEF("Boolean", 1, js_boolean_constructor, JS_CLASS_BOOLEAN, NULL, NULL, NULL, NULL);
|
||||
|
||||
static const JSPropDef js_string_proto[] = {
|
||||
JS_CGETSET_DEF("length", js_string_get_length, js_string_set_length ),
|
||||
JS_CFUNC_MAGIC_DEF("charAt", 1, js_string_charAt, magic_charAt ),
|
||||
JS_CFUNC_MAGIC_DEF("charCodeAt", 1, js_string_charAt, magic_charCodeAt ),
|
||||
JS_CFUNC_MAGIC_DEF("codePointAt", 1, js_string_charAt, magic_codePointAt ),
|
||||
JS_CFUNC_DEF("slice", 2, js_string_slice ),
|
||||
JS_CFUNC_DEF("substring", 2, js_string_substring ),
|
||||
JS_CFUNC_DEF("concat", 1, js_string_concat ),
|
||||
JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0 ),
|
||||
JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1 ),
|
||||
JS_CFUNC_DEF("match", 1, js_string_match ),
|
||||
JS_CFUNC_MAGIC_DEF("replace", 2, js_string_replace, 0 ),
|
||||
JS_CFUNC_MAGIC_DEF("replaceAll", 2, js_string_replace, 1 ),
|
||||
JS_CFUNC_DEF("search", 1, js_string_search ),
|
||||
JS_CFUNC_DEF("split", 2, js_string_split ),
|
||||
JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ),
|
||||
JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ),
|
||||
JS_CFUNC_MAGIC_DEF("trim", 0, js_string_trim, 3 ),
|
||||
JS_CFUNC_MAGIC_DEF("trimEnd", 0, js_string_trim, 2 ),
|
||||
JS_CFUNC_MAGIC_DEF("trimStart", 0, js_string_trim, 1 ),
|
||||
JS_CFUNC_DEF("toString", 0, js_string_toString ),
|
||||
JS_CFUNC_DEF("repeat", 1, js_string_repeat ),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSPropDef js_string[] = {
|
||||
JS_CFUNC_MAGIC_DEF("fromCharCode", 1, js_string_fromCharCode, 0 ),
|
||||
JS_CFUNC_MAGIC_DEF("fromCodePoint", 1, js_string_fromCharCode, 1 ),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_string_class =
|
||||
JS_CLASS_DEF("String", 1, js_string_constructor, JS_CLASS_STRING, js_string, js_string_proto, NULL, NULL);
|
||||
|
||||
static const JSPropDef js_array_proto[] = {
|
||||
JS_CFUNC_DEF("concat", 1, js_array_concat ),
|
||||
JS_CGETSET_DEF("length", js_array_get_length, js_array_set_length ),
|
||||
JS_CFUNC_MAGIC_DEF("push", 1, js_array_push, 0 ),
|
||||
JS_CFUNC_DEF("pop", 0, js_array_pop ),
|
||||
JS_CFUNC_DEF("join", 1, js_array_join ),
|
||||
JS_CFUNC_DEF("toString", 0, js_array_toString ),
|
||||
JS_CFUNC_DEF("reverse", 0, js_array_reverse ),
|
||||
JS_CFUNC_DEF("shift", 0, js_array_shift ),
|
||||
JS_CFUNC_DEF("slice", 2, js_array_slice ),
|
||||
JS_CFUNC_DEF("splice", 2, js_array_splice ),
|
||||
JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ),
|
||||
JS_CFUNC_MAGIC_DEF("indexOf", 1, js_array_indexOf, 0 ),
|
||||
JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_array_indexOf, 1 ),
|
||||
JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, js_special_every ),
|
||||
JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, js_special_some ),
|
||||
JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, js_special_forEach ),
|
||||
JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, js_special_map ),
|
||||
JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, js_special_filter ),
|
||||
JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, js_special_reduce ),
|
||||
JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, js_special_reduceRight ),
|
||||
JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, js_special_reduce ),
|
||||
JS_CFUNC_DEF("sort", 1, js_array_sort ),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSPropDef js_array[] = {
|
||||
JS_CFUNC_DEF("isArray", 1, js_array_isArray ),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_array_class =
|
||||
JS_CLASS_DEF("Array", 1, js_array_constructor, JS_CLASS_ARRAY, js_array, js_array_proto, NULL, NULL);
|
||||
|
||||
static const JSPropDef js_error_proto[] = {
|
||||
JS_CFUNC_DEF("toString", 0, js_error_toString ),
|
||||
JS_PROP_STRING_DEF("name", "Error", 0 ),
|
||||
JS_CGETSET_MAGIC_DEF("message", js_error_get_message, NULL, 0 ),
|
||||
JS_CGETSET_MAGIC_DEF("stack", js_error_get_message, NULL, 1 ),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_error_class =
|
||||
JS_CLASS_MAGIC_DEF("Error", 1, js_error_constructor, JS_CLASS_ERROR, NULL, js_error_proto, NULL, NULL);
|
||||
|
||||
#define ERROR_DEF(cname, name, class_id) \
|
||||
static const JSPropDef js_ ## cname ## _proto[] = { \
|
||||
JS_PROP_STRING_DEF("name", name, 0 ), \
|
||||
JS_PROP_END, \
|
||||
}; \
|
||||
static const JSClassDef js_ ## cname ## _class = \
|
||||
JS_CLASS_MAGIC_DEF(name, 1, js_error_constructor, class_id, NULL, js_ ## cname ## _proto, &js_error_class, NULL);
|
||||
|
||||
ERROR_DEF(eval_error, "EvalError", JS_CLASS_EVAL_ERROR)
|
||||
ERROR_DEF(range_error, "RangeError", JS_CLASS_RANGE_ERROR)
|
||||
ERROR_DEF(reference_error, "ReferenceError", JS_CLASS_REFERENCE_ERROR)
|
||||
ERROR_DEF(syntax_error, "SyntaxError", JS_CLASS_SYNTAX_ERROR)
|
||||
ERROR_DEF(type_error, "TypeError", JS_CLASS_TYPE_ERROR)
|
||||
ERROR_DEF(uri_error, "URIError", JS_CLASS_URI_ERROR)
|
||||
ERROR_DEF(internal_error, "InternalError", JS_CLASS_INTERNAL_ERROR)
|
||||
|
||||
static const JSPropDef js_math[] = {
|
||||
JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
|
||||
JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
|
||||
JS_CFUNC_SPECIAL_DEF("sign", 1, f_f, js_math_sign ),
|
||||
JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, js_fabs ),
|
||||
JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, js_floor ),
|
||||
JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, js_ceil ),
|
||||
JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_round_inf ),
|
||||
JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, js_sqrt ),
|
||||
|
||||
JS_PROP_DOUBLE_DEF("E", 2.718281828459045, 0 ),
|
||||
JS_PROP_DOUBLE_DEF("LN10", 2.302585092994046, 0 ),
|
||||
JS_PROP_DOUBLE_DEF("LN2", 0.6931471805599453, 0 ),
|
||||
JS_PROP_DOUBLE_DEF("LOG2E", 1.4426950408889634, 0 ),
|
||||
JS_PROP_DOUBLE_DEF("LOG10E", 0.4342944819032518, 0 ),
|
||||
JS_PROP_DOUBLE_DEF("PI", 3.141592653589793, 0 ),
|
||||
JS_PROP_DOUBLE_DEF("SQRT1_2", 0.7071067811865476, 0 ),
|
||||
JS_PROP_DOUBLE_DEF("SQRT2", 1.4142135623730951, 0 ),
|
||||
|
||||
JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, js_sin ),
|
||||
JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, js_cos ),
|
||||
JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, js_tan ),
|
||||
JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, js_asin ),
|
||||
JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, js_acos ),
|
||||
JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, js_atan ),
|
||||
JS_CFUNC_DEF("atan2", 2, js_math_atan2 ),
|
||||
JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, js_exp ),
|
||||
JS_CFUNC_SPECIAL_DEF("log", 1, f_f, js_log ),
|
||||
JS_CFUNC_DEF("pow", 2, js_math_pow ),
|
||||
JS_CFUNC_DEF("random", 0, js_math_random ),
|
||||
|
||||
/* some ES6 functions */
|
||||
JS_CFUNC_DEF("imul", 2, js_math_imul ),
|
||||
JS_CFUNC_DEF("clz32", 1, js_math_clz32 ),
|
||||
JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround ),
|
||||
JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, js_trunc ),
|
||||
JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, js_log2 ),
|
||||
JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, js_log10 ),
|
||||
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_math_obj =
|
||||
JS_OBJECT_DEF("Math", js_math);
|
||||
|
||||
static const JSPropDef js_json[] = {
|
||||
JS_CFUNC_DEF("parse", 2, js_json_parse ),
|
||||
JS_CFUNC_DEF("stringify", 3, js_json_stringify ),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_json_obj =
|
||||
JS_OBJECT_DEF("JSON", js_json);
|
||||
|
||||
/* typed arrays */
|
||||
static const JSPropDef js_array_buffer_proto[] = {
|
||||
JS_CGETSET_DEF("byteLength", js_array_buffer_get_byteLength, NULL ),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_array_buffer_class =
|
||||
JS_CLASS_DEF("ArrayBuffer", 1, js_array_buffer_constructor, JS_CLASS_ARRAY_BUFFER, NULL, js_array_buffer_proto, NULL, NULL);
|
||||
|
||||
static const JSPropDef js_typed_array_base_proto[] = {
|
||||
JS_CGETSET_MAGIC_DEF("length", js_typed_array_get_length, NULL, 0 ),
|
||||
JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_length, NULL, 1 ),
|
||||
JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_length, NULL, 2 ),
|
||||
JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_length, NULL, 3 ),
|
||||
JS_CFUNC_DEF("join", 1, js_array_join ),
|
||||
JS_CFUNC_DEF("toString", 0, js_array_toString ),
|
||||
JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray ),
|
||||
JS_CFUNC_DEF("set", 1, js_typed_array_set ),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_typed_array_base_class =
|
||||
JS_CLASS_DEF("TypedArray", 0, js_typed_array_base_constructor, JS_CLASS_TYPED_ARRAY, NULL, js_typed_array_base_proto, NULL, NULL);
|
||||
|
||||
#define TA_DEF(name, class_name, bpe)\
|
||||
static const JSPropDef js_ ## name [] = {\
|
||||
JS_PROP_DOUBLE_DEF("BYTES_PER_ELEMENT", bpe, 0),\
|
||||
JS_PROP_END,\
|
||||
};\
|
||||
static const JSPropDef js_ ## name ## _proto[] = {\
|
||||
JS_PROP_DOUBLE_DEF("BYTES_PER_ELEMENT", bpe, 0),\
|
||||
JS_PROP_END,\
|
||||
};\
|
||||
static const JSClassDef js_ ## name ## _class =\
|
||||
JS_CLASS_MAGIC_DEF(#name, 3, js_typed_array_constructor, class_name, js_ ## name, js_ ## name ## _proto, &js_typed_array_base_class, NULL);
|
||||
|
||||
TA_DEF(Uint8ClampedArray, JS_CLASS_UINT8C_ARRAY, 1)
|
||||
TA_DEF(Int8Array, JS_CLASS_INT8_ARRAY, 1)
|
||||
TA_DEF(Uint8Array, JS_CLASS_UINT8_ARRAY, 1)
|
||||
TA_DEF(Int16Array, JS_CLASS_INT16_ARRAY, 2)
|
||||
TA_DEF(Uint16Array, JS_CLASS_UINT16_ARRAY, 2)
|
||||
TA_DEF(Int32Array, JS_CLASS_INT32_ARRAY, 4)
|
||||
TA_DEF(Uint32Array, JS_CLASS_UINT32_ARRAY, 4)
|
||||
TA_DEF(Float32Array, JS_CLASS_FLOAT32_ARRAY, 4)
|
||||
TA_DEF(Float64Array, JS_CLASS_FLOAT64_ARRAY, 8)
|
||||
|
||||
/* regexp */
|
||||
|
||||
static const JSPropDef js_regexp_proto[] = {
|
||||
JS_CGETSET_DEF("lastIndex", js_regexp_get_lastIndex, js_regexp_set_lastIndex ),
|
||||
JS_CGETSET_DEF("source", js_regexp_get_source, NULL ),
|
||||
JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ),
|
||||
JS_CFUNC_MAGIC_DEF("exec", 1, js_regexp_exec, 0 ),
|
||||
JS_CFUNC_MAGIC_DEF("test", 1, js_regexp_exec, 1 ),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_regexp_class =
|
||||
JS_CLASS_DEF("RegExp", 2, js_regexp_constructor, JS_CLASS_REGEXP, NULL, js_regexp_proto, NULL, NULL);
|
||||
|
||||
/* other objects */
|
||||
|
||||
static const JSPropDef js_date[] = {
|
||||
JS_CFUNC_DEF("now", 0, js_date_now),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_date_class =
|
||||
JS_CLASS_DEF("Date", 7, js_date_constructor, JS_CLASS_DATE, js_date, NULL, NULL, NULL);
|
||||
|
||||
static const JSPropDef js_console[] = {
|
||||
JS_CFUNC_DEF("log", 1, js_print),
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_console_obj =
|
||||
JS_OBJECT_DEF("Console", js_console);
|
||||
|
||||
static const JSPropDef js_performance[] = {
|
||||
JS_CFUNC_DEF("now", 0, js_performance_now),
|
||||
JS_PROP_END,
|
||||
};
|
||||
static const JSClassDef js_performance_obj =
|
||||
JS_OBJECT_DEF("Performance", js_performance);
|
||||
|
||||
// Crosspoint-specific functions (will invoke native C++ code)
|
||||
#define JS_PROP_INT_DEF(name, val, flags) { JS_DEF_PROP_DOUBLE, name, { .f64 = val } }
|
||||
static const JSPropDef js_cp[] = {
|
||||
JS_PROP_STRING_DEF("FAST_REFRESH", "F", 0),
|
||||
JS_PROP_STRING_DEF("HALF_REFRESH", "H", 0),
|
||||
JS_PROP_STRING_DEF("FULL_REFRESH", "A", 0),
|
||||
|
||||
JS_PROP_STRING_DEF("FONT_UI_10", "UI10", 0),
|
||||
JS_PROP_STRING_DEF("FONT_UI_12", "UI12", 0),
|
||||
JS_PROP_STRING_DEF("FONT_SMALL", "SM", 0),
|
||||
|
||||
JS_PROP_STRING_DEF("TEXT_REGULAR", "R", 0),
|
||||
JS_PROP_STRING_DEF("TEXT_BOLD", "B", 0),
|
||||
JS_PROP_STRING_DEF("TEXT_ITALIC", "I", 0),
|
||||
JS_PROP_STRING_DEF("TEXT_BOLD_ITALIC", "J", 0),
|
||||
|
||||
JS_PROP_STRING_DEF("BTN_BACK", "B", 0),
|
||||
JS_PROP_STRING_DEF("BTN_CONFIRM", "C", 0),
|
||||
JS_PROP_STRING_DEF("BTN_LEFT", "L", 0),
|
||||
JS_PROP_STRING_DEF("BTN_RIGHT", "R", 0),
|
||||
JS_PROP_STRING_DEF("BTN_UP", "U", 0),
|
||||
JS_PROP_STRING_DEF("BTN_DOWN", "D", 0),
|
||||
|
||||
/**
|
||||
* @brief Get the number of milliseconds since the device was powered on
|
||||
* @return {number} Milliseconds since power on
|
||||
*/
|
||||
JS_CFUNC_DEF("millis", 0, js_millis),
|
||||
|
||||
/**
|
||||
* @brief Check if a button is currently pressed
|
||||
* @param {string} buttonId The ID of the button to check (e.g., CP.BTN_BACK, CP.BTN_CONFIRM, etc.)
|
||||
* @return {boolean} True if the button is pressed, false otherwise
|
||||
*/
|
||||
JS_CFUNC_DEF("btnIsPressed", 0, js_btnIsPressed),
|
||||
|
||||
/**
|
||||
* @brief Get screen width, ben changed based on orientation
|
||||
* @return {number} Screen width in pixels
|
||||
*/
|
||||
JS_CFUNC_DEF("getScreenWidth", 0, js_getScreenWidth),
|
||||
|
||||
/**
|
||||
* @brief Get screen height, ben changed based on orientation
|
||||
* @return {number} Screen height in pixels
|
||||
*/
|
||||
JS_CFUNC_DEF("getScreenHeight", 0, js_getScreenHeight),
|
||||
|
||||
/**
|
||||
* @brief Clear the screen buffer
|
||||
* @param {number} color The color to clear the screen to (0-255, where 0 = black, 255 = white)
|
||||
* @return {void}
|
||||
*/
|
||||
JS_CFUNC_DEF("clearScreen", 1, js_clearScreen),
|
||||
|
||||
/**
|
||||
* @brief Display the screen buffer
|
||||
* @param {string} refreshMode The refresh mode to use (0 = CP.FAST_REFRESH, 1 = CP.FULL_REFRESH, etc.)
|
||||
* @return {void}
|
||||
*/
|
||||
JS_CFUNC_DEF("displayBuffer", 1, js_displayBuffer),
|
||||
|
||||
|
||||
/**
|
||||
* @brief Draws a line from (x1, y1) to (x2, y2).
|
||||
* @param x1 {number} The x-coordinate of the starting point.
|
||||
* @param y1 {number} The y-coordinate of the starting point.
|
||||
* @param x2 {number} The x-coordinate of the ending point.
|
||||
* @param y2 {number} The y-coordinate of the ending point.
|
||||
* @param state {boolean} The state to set the pixels to (true for on, false for off). Defaults to true.
|
||||
*/
|
||||
JS_CFUNC_DEF("drawLine", 5, js_drawLine),
|
||||
|
||||
/**
|
||||
* @brief Draws the outline of a rectangle at the specified position with the given dimensions.
|
||||
* @param x {number} The x-coordinate of the top-left corner of the rectangle.
|
||||
* @param y {number} The y-coordinate of the top-left corner of the rectangle.
|
||||
* @param width {number} The width of the rectangle.
|
||||
* @param height {number} The height of the rectangle.
|
||||
* @param state {boolean} The state to set the pixels to (true for on, false for off). Defaults to true.
|
||||
*/
|
||||
JS_CFUNC_DEF("drawRect", 5, js_drawRect),
|
||||
|
||||
/**
|
||||
* @brief Fills a rectangle at the specified position with the given dimensions.
|
||||
* @param x {number} The x-coordinate of the top-left corner of the rectangle.
|
||||
* @param y {number} The y-coordinate of the top-left corner of the rectangle.
|
||||
* @param width {number} The width of the rectangle.
|
||||
* @param height {number} The height of the rectangle.
|
||||
* @param state {boolean} The state to set the pixels to (true for on, false for off). Defaults to true.
|
||||
*/
|
||||
JS_CFUNC_DEF("fillRect", 5, js_fillRect),
|
||||
|
||||
/**
|
||||
* @brief Draws a bitmap image at the specified position with the given dimensions.
|
||||
* @param bitmap {ArrayBuffer} The array of bytes representing the bitmap data, 1bpp, must have total size of (width * height) / 8.
|
||||
* @param x {number} The x-coordinate of the top-left corner where the image will be drawn.
|
||||
* @param y {number} The y-coordinate of the top-left corner where the image will be drawn.
|
||||
* @param width {number} The width of the image.
|
||||
* @param height {number} The height of the image.
|
||||
*/
|
||||
JS_CFUNC_DEF("drawImage", 5, js_drawImage),
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the width in pixels of the text.
|
||||
* @param fontId {string} The ID of the font to use (e.g., CP.FONT_UI_10, CP.FONT_SMALL, etc.)
|
||||
* @param text {string} The text to measure.
|
||||
* @param style {string} The style of the font (CP.TEXT_REGULAR, CP.TEXT_BOLD, etc.)
|
||||
*/
|
||||
JS_CFUNC_DEF("getTextWidth", 3, js_getTextWidth),
|
||||
|
||||
/**
|
||||
* @brief Draws centered text at the specified y-coordinate (non-wrapped).
|
||||
* @param fontId {string} The ID of the font to use (e.g., CP.FONT_UI_10, CP.FONT_SMALL, etc.)
|
||||
* @param y {number} The y-coordinate where the text will be drawn.
|
||||
* @param text {string} The text to draw.
|
||||
* @param black {boolean} Whether to draw the text in black (true) or white (false).
|
||||
* @param style {string} The style of the font (CP.TEXT_REGULAR, CP.TEXT_BOLD, etc.)
|
||||
*/
|
||||
JS_CFUNC_DEF("drawCenteredText", 5, js_drawCenteredText),
|
||||
|
||||
/**
|
||||
* @brief Draws text at the specified position (non-wrapped).
|
||||
* @param fontId {string} The ID of the font to use (e.g., CP.FONT_UI_10, CP.FONT_SMALL, etc.)
|
||||
* @param x {number} The x-coordinate where the text will be drawn.
|
||||
* @param y {number} The y-coordinate where the text will be drawn.
|
||||
* @param text {string} The text to draw.
|
||||
* @param black {boolean} Whether to draw the text in black (true) or white (false).
|
||||
* @param style {string} The style of the font (CP.TEXT_REGULAR, CP.TEXT_BOLD, etc.)
|
||||
*/
|
||||
JS_CFUNC_DEF("drawText", 6, js_drawText),
|
||||
|
||||
// JS_CFUNC_DEF("drawTextBox", 6, js_drawText), // TODO: implement drawTextBox
|
||||
|
||||
|
||||
/**
|
||||
* @brief Draws button hints at the bottom of the screen.
|
||||
* @param fontId {string} The ID of the font to use (e.g., CP.FONT_UI_10, CP.FONT_SMALL, etc.)
|
||||
* @param btn1Text {string} The text for button 1.
|
||||
* @param btn2Text {string} The text for button 2.
|
||||
* @param btn3Text {string} The text for button 3.
|
||||
* @param btn4Text {string} The text for button 4.
|
||||
*/
|
||||
JS_CFUNC_DEF("drawButtonHints", 5, js_drawButtonHints),
|
||||
|
||||
/**
|
||||
* @brief Draws side button hints on the left and right sides of the screen.
|
||||
* @param fontId {string} The ID of the font to use (e.g., CP.FONT_UI_10, CP.FONT_SMALL, etc.)
|
||||
* @param topBtnText {string} The text for the top side button.
|
||||
* @param bottomBtnText {string} The text for the bottom side button.
|
||||
*/
|
||||
JS_CFUNC_DEF("drawSideButtonHints", 3, js_drawSideButtonHints),
|
||||
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
static const JSClassDef js_cp_obj =
|
||||
JS_OBJECT_DEF("CP", js_cp);
|
||||
// End of Crosspoint-specific functions
|
||||
|
||||
static const JSPropDef js_global_object[] = {
|
||||
JS_PROP_CLASS_DEF("Object", &js_object_class),
|
||||
JS_PROP_CLASS_DEF("Function", &js_function_class),
|
||||
JS_PROP_CLASS_DEF("Number", &js_number_class),
|
||||
JS_PROP_CLASS_DEF("Boolean", &js_boolean_class),
|
||||
JS_PROP_CLASS_DEF("String", &js_string_class),
|
||||
JS_PROP_CLASS_DEF("Array", &js_array_class),
|
||||
JS_PROP_CLASS_DEF("Math", &js_math_obj),
|
||||
JS_PROP_CLASS_DEF("Date", &js_date_class),
|
||||
JS_PROP_CLASS_DEF("JSON", &js_json_obj),
|
||||
JS_PROP_CLASS_DEF("RegExp", &js_regexp_class),
|
||||
|
||||
JS_PROP_CLASS_DEF("Error", &js_error_class),
|
||||
JS_PROP_CLASS_DEF("EvalError", &js_eval_error_class),
|
||||
JS_PROP_CLASS_DEF("RangeError", &js_range_error_class),
|
||||
JS_PROP_CLASS_DEF("ReferenceError", &js_reference_error_class),
|
||||
JS_PROP_CLASS_DEF("SyntaxError", &js_syntax_error_class),
|
||||
JS_PROP_CLASS_DEF("TypeError", &js_type_error_class),
|
||||
JS_PROP_CLASS_DEF("URIError", &js_uri_error_class),
|
||||
JS_PROP_CLASS_DEF("InternalError", &js_internal_error_class),
|
||||
|
||||
JS_PROP_CLASS_DEF("ArrayBuffer", &js_array_buffer_class),
|
||||
JS_PROP_CLASS_DEF("Uint8ClampedArray", &js_Uint8ClampedArray_class),
|
||||
JS_PROP_CLASS_DEF("Int8Array", &js_Int8Array_class),
|
||||
JS_PROP_CLASS_DEF("Uint8Array", &js_Uint8Array_class),
|
||||
JS_PROP_CLASS_DEF("Int16Array", &js_Int16Array_class),
|
||||
JS_PROP_CLASS_DEF("Uint16Array", &js_Uint16Array_class),
|
||||
JS_PROP_CLASS_DEF("Int32Array", &js_Int32Array_class),
|
||||
JS_PROP_CLASS_DEF("Uint32Array", &js_Uint32Array_class),
|
||||
JS_PROP_CLASS_DEF("Float32Array", &js_Float32Array_class),
|
||||
JS_PROP_CLASS_DEF("Float64Array", &js_Float64Array_class),
|
||||
|
||||
JS_CFUNC_DEF("parseInt", 2, js_number_parseInt ),
|
||||
JS_CFUNC_DEF("parseFloat", 1, js_number_parseFloat ),
|
||||
JS_CFUNC_DEF("eval", 1, js_global_eval),
|
||||
JS_CFUNC_DEF("isNaN", 1, js_global_isNaN ),
|
||||
JS_CFUNC_DEF("isFinite", 1, js_global_isFinite ),
|
||||
|
||||
JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ),
|
||||
JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
|
||||
JS_PROP_UNDEFINED_DEF("undefined", 0 ),
|
||||
/* Note: null is expanded as the global object in js_global_object[] */
|
||||
JS_PROP_NULL_DEF("globalThis", 0 ),
|
||||
|
||||
JS_PROP_CLASS_DEF("console", &js_console_obj),
|
||||
JS_PROP_CLASS_DEF("performance", &js_performance_obj),
|
||||
JS_CFUNC_DEF("print", 1, js_print),
|
||||
#ifdef CONFIG_CLASS_EXAMPLE
|
||||
JS_PROP_CLASS_DEF("Rectangle", &js_rectangle_class),
|
||||
JS_PROP_CLASS_DEF("FilledRectangle", &js_filled_rectangle_class),
|
||||
#else
|
||||
JS_CFUNC_DEF("gc", 0, js_gc),
|
||||
JS_CFUNC_DEF("load", 1, js_load),
|
||||
JS_CFUNC_DEF("setTimeout", 2, js_setTimeout),
|
||||
JS_CFUNC_DEF("clearTimeout", 1, js_clearTimeout),
|
||||
#endif
|
||||
|
||||
JS_PROP_CLASS_DEF("CP", &js_cp_obj), // crosspoint-specific object
|
||||
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
/* Additional C function declarations (only useful for C
|
||||
closures). They are always defined first. */
|
||||
static const JSPropDef js_c_function_decl[] = {
|
||||
/* must come first if "bind" is defined */
|
||||
JS_CFUNC_SPECIAL_DEF("bound", 0, generic_params, js_function_bound ),
|
||||
#ifdef CONFIG_CLASS_EXAMPLE
|
||||
JS_CFUNC_SPECIAL_DEF("rectangle_closure_test", 0, generic_params, js_rectangle_closure_test ),
|
||||
#endif
|
||||
JS_PROP_END,
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return build_atoms("js_stdlib", js_global_object, js_c_function_decl, argc, argv);
|
||||
}
|
||||
932
lib/mquickjs/scripts/mquickjs_build.c
Normal file
932
lib/mquickjs/scripts/mquickjs_build.c
Normal file
@ -0,0 +1,932 @@
|
||||
/*
|
||||
* Micro QuickJS build utility
|
||||
*
|
||||
* Copyright (c) 2017-2025 Fabrice Bellard
|
||||
* Copyright (c) 2017-2025 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "cutils.h"
|
||||
#include "list.h"
|
||||
#include "mquickjs_build.h"
|
||||
|
||||
static unsigned JSW = 4; // override this with -m64
|
||||
|
||||
typedef struct {
|
||||
char *str;
|
||||
int offset;
|
||||
} AtomDef;
|
||||
|
||||
typedef struct {
|
||||
AtomDef *tab;
|
||||
int count;
|
||||
int size;
|
||||
int offset;
|
||||
} AtomList;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int length;
|
||||
char *magic;
|
||||
char *cproto_name;
|
||||
char *cfunc_name;
|
||||
} CFuncDef;
|
||||
|
||||
typedef struct {
|
||||
CFuncDef *tab;
|
||||
int count;
|
||||
int size;
|
||||
} CFuncList;
|
||||
|
||||
typedef struct {
|
||||
struct list_head link;
|
||||
const JSClassDef *class1;
|
||||
int class_idx;
|
||||
char *finalizer_name;
|
||||
char *class_id;
|
||||
} ClassDefEntry;
|
||||
|
||||
typedef struct {
|
||||
AtomList atom_list;
|
||||
CFuncList cfunc_list;
|
||||
int cur_offset;
|
||||
int sorted_atom_table_offset;
|
||||
int global_object_offset;
|
||||
struct list_head class_list;
|
||||
} BuildContext;
|
||||
|
||||
static const char *atoms[] = {
|
||||
#define DEF(a, b) b,
|
||||
/* keywords */
|
||||
DEF(null, "null") /* must be first */
|
||||
DEF(false, "false")
|
||||
DEF(true, "true")
|
||||
DEF(if, "if")
|
||||
DEF(else, "else")
|
||||
DEF(return, "return")
|
||||
DEF(var, "var")
|
||||
DEF(this, "this")
|
||||
DEF(delete, "delete")
|
||||
DEF(void, "void")
|
||||
DEF(typeof, "typeof")
|
||||
DEF(new, "new")
|
||||
DEF(in, "in")
|
||||
DEF(instanceof, "instanceof")
|
||||
DEF(do, "do")
|
||||
DEF(while, "while")
|
||||
DEF(for, "for")
|
||||
DEF(break, "break")
|
||||
DEF(continue, "continue")
|
||||
DEF(switch, "switch")
|
||||
DEF(case, "case")
|
||||
DEF(default, "default")
|
||||
DEF(throw, "throw")
|
||||
DEF(try, "try")
|
||||
DEF(catch, "catch")
|
||||
DEF(finally, "finally")
|
||||
DEF(function, "function")
|
||||
DEF(debugger, "debugger")
|
||||
DEF(with, "with")
|
||||
/* FutureReservedWord */
|
||||
DEF(class, "class")
|
||||
DEF(const, "const")
|
||||
DEF(enum, "enum")
|
||||
DEF(export, "export")
|
||||
DEF(extends, "extends")
|
||||
DEF(import, "import")
|
||||
DEF(super, "super")
|
||||
/* FutureReservedWords when parsing strict mode code */
|
||||
DEF(implements, "implements")
|
||||
DEF(interface, "interface")
|
||||
DEF(let, "let")
|
||||
DEF(package, "package")
|
||||
DEF(private, "private")
|
||||
DEF(protected, "protected")
|
||||
DEF(public, "public")
|
||||
DEF(static, "static")
|
||||
DEF(yield, "yield")
|
||||
#undef DEF
|
||||
|
||||
/* other atoms */
|
||||
"",
|
||||
"toString",
|
||||
"valueOf",
|
||||
"number",
|
||||
"object",
|
||||
"undefined",
|
||||
"string",
|
||||
"boolean",
|
||||
"<ret>",
|
||||
"<eval>",
|
||||
"eval",
|
||||
"arguments",
|
||||
"value",
|
||||
"get",
|
||||
"set",
|
||||
"prototype",
|
||||
"constructor",
|
||||
"length",
|
||||
"target",
|
||||
"of",
|
||||
"NaN",
|
||||
"Infinity",
|
||||
"-Infinity",
|
||||
"name",
|
||||
"Error",
|
||||
"__proto__",
|
||||
"index",
|
||||
"input",
|
||||
};
|
||||
|
||||
|
||||
static char *cvt_name(char *buf, size_t buf_size, const char *str)
|
||||
{
|
||||
size_t i, len = strlen(str);
|
||||
assert(len < buf_size);
|
||||
if (len == 0) {
|
||||
strcpy(buf, "empty");
|
||||
} else {
|
||||
strcpy(buf, str);
|
||||
for(i = 0; i < len; i++) {
|
||||
if (buf[i] == '<' || buf[i] == '>' || buf[i] == '-')
|
||||
buf[i] = '_';
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static BOOL is_ascii_string(const char *buf, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < len; i++) {
|
||||
if ((uint8_t)buf[i] > 0x7f)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL is_numeric_string(const char *buf, size_t len)
|
||||
{
|
||||
return (!strcmp(buf, "NaN") ||
|
||||
!strcmp(buf, "Infinity") ||
|
||||
!strcmp(buf, "-Infinity"));
|
||||
}
|
||||
|
||||
static int find_atom(AtomList *s, const char *str)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < s->count; i++) {
|
||||
if (!strcmp(str, s->tab[i].str))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int add_atom(AtomList *s, const char *str)
|
||||
{
|
||||
int i;
|
||||
AtomDef *e;
|
||||
i = find_atom(s, str);
|
||||
if (i >= 0)
|
||||
return s->tab[i].offset;
|
||||
if ((s->count + 1) > s->size) {
|
||||
s->size = max_int(s->count + 1, s->size * 3 / 2);
|
||||
s->tab = realloc(s->tab, sizeof(s->tab[0]) * s->size);
|
||||
}
|
||||
e = &s->tab[s->count++];
|
||||
e->str = strdup(str);
|
||||
e->offset = s->offset;
|
||||
s->offset += 1 + ((strlen(str) + JSW) / JSW);
|
||||
return s->count - 1;
|
||||
}
|
||||
|
||||
static int add_cfunc(CFuncList *s, const char *name, int length, const char *magic, const char *cproto_name, const char *cfunc_name)
|
||||
{
|
||||
int i;
|
||||
CFuncDef *e;
|
||||
|
||||
for(i = 0; i < s->count; i++) {
|
||||
e = &s->tab[i];
|
||||
if (!strcmp(name, e->name) &&
|
||||
length == e->length &&
|
||||
!strcmp(magic, e->magic) &&
|
||||
!strcmp(cproto_name, e->cproto_name) &&
|
||||
!strcmp(cfunc_name, e->cfunc_name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if ((s->count + 1) > s->size) {
|
||||
s->size = max_int(s->count + 1, s->size * 3 / 2);
|
||||
s->tab = realloc(s->tab, sizeof(s->tab[0]) * s->size);
|
||||
}
|
||||
e = &s->tab[s->count++];
|
||||
e->name = strdup(name);
|
||||
e->magic = strdup(magic);
|
||||
e->length = length;
|
||||
e->cproto_name = strdup(cproto_name);
|
||||
e->cfunc_name = strdup(cfunc_name);
|
||||
return s->count - 1;
|
||||
}
|
||||
|
||||
static void dump_atom_defines(void)
|
||||
{
|
||||
AtomList atom_list_s, *s = &atom_list_s;
|
||||
AtomDef *e;
|
||||
int i;
|
||||
char buf[256];
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
/* add the predefined atoms (they have a corresponding define) */
|
||||
for(i = 0; i < countof(atoms); i++) {
|
||||
add_atom(s, atoms[i]);
|
||||
}
|
||||
|
||||
for(i = 0; i < s->count; i++) {
|
||||
e = &s->tab[i];
|
||||
printf("#define JS_ATOM_%s %d\n",
|
||||
cvt_name(buf, sizeof(buf), e->str), e->offset);
|
||||
}
|
||||
printf("\n");
|
||||
printf("#define JS_ATOM_END %d\n", s->offset);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int atom_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
const AtomDef *a1 = (const AtomDef *)p1;
|
||||
const AtomDef *a2 = (const AtomDef *)p2;
|
||||
return strcmp(a1->str, a2->str);
|
||||
}
|
||||
|
||||
/* js_atom_table must be properly aligned because the property hash
|
||||
table uses the low bits of the atom pointer value */
|
||||
#define ATOM_ALIGN 64
|
||||
|
||||
static void dump_atoms(BuildContext *ctx)
|
||||
{
|
||||
AtomList *s = &ctx->atom_list;
|
||||
int i, j, k, l, len, len1, is_ascii, is_numeric;
|
||||
uint64_t v;
|
||||
const char *str;
|
||||
AtomDef *sorted_atoms;
|
||||
char buf[256];
|
||||
|
||||
sorted_atoms = malloc(sizeof(sorted_atoms[0]) * s->count);
|
||||
memcpy(sorted_atoms, s->tab, sizeof(sorted_atoms[0]) * s->count);
|
||||
qsort(sorted_atoms, s->count, sizeof(sorted_atoms[0]), atom_cmp);
|
||||
|
||||
printf(" /* atom_table */\n");
|
||||
for(i = 0; i < s->count; i++) {
|
||||
str = s->tab[i].str;
|
||||
len = strlen(str);
|
||||
is_ascii = is_ascii_string(str, len);
|
||||
is_numeric = is_numeric_string(str, len);
|
||||
printf(" (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (%d << (JS_MTAG_BITS + 1)) | (%d << (JS_MTAG_BITS + 2)) | (%d << (JS_MTAG_BITS + 3)), /* \"%s\" (offset=%d) */\n",
|
||||
is_ascii, is_numeric, len, str, ctx->cur_offset);
|
||||
len1 = (len + JSW) / JSW;
|
||||
for(j = 0; j < len1; j++) {
|
||||
l = min_uint32(JSW, len - j * JSW);
|
||||
v = 0;
|
||||
for(k = 0; k < l; k++)
|
||||
v |= (uint64_t)(uint8_t)str[j * JSW + k] << (k * 8);
|
||||
printf(" 0x%0*" PRIx64 ",\n", JSW * 2, v);
|
||||
}
|
||||
assert(ctx->cur_offset == s->tab[i].offset);
|
||||
ctx->cur_offset += len1 + 1;
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
ctx->sorted_atom_table_offset = ctx->cur_offset;
|
||||
|
||||
printf(" /* sorted atom table (offset=%d) */\n", ctx->cur_offset);
|
||||
printf(" JS_VALUE_ARRAY_HEADER(%d),\n", s->count);
|
||||
for(i = 0; i < s->count; i++) {
|
||||
AtomDef *e = &sorted_atoms[i];
|
||||
printf(" JS_ROM_VALUE(%d), /* %s */\n",
|
||||
e->offset, cvt_name(buf, sizeof(buf), e->str));
|
||||
}
|
||||
ctx->cur_offset += s->count + 1;
|
||||
printf("\n");
|
||||
|
||||
free(sorted_atoms);
|
||||
}
|
||||
|
||||
static int define_value(BuildContext *s, const JSPropDef *d);
|
||||
|
||||
static uint32_t dump_atom(BuildContext *s, const char *str, BOOL value_only)
|
||||
{
|
||||
int len, idx, i, offset;
|
||||
|
||||
len = strlen(str);
|
||||
for(i = 0; i < len; i++) {
|
||||
if ((uint8_t)str[i] >= 128) {
|
||||
fprintf(stderr, "unicode property names are not supported yet (%s)\n", str);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (len >= 1 && (str[0] >= '0' && str[0] <= '9')) {
|
||||
fprintf(stderr, "numeric property names are not supported yet (%s)\n", str);
|
||||
exit(1);
|
||||
}
|
||||
if (len == 1) {
|
||||
if (value_only) {
|
||||
/* XXX: hardcoded */
|
||||
return ((uint8_t)str[0] << 5) | 0x1b;
|
||||
}
|
||||
printf("JS_VALUE_MAKE_SPECIAL(JS_TAG_STRING_CHAR, %d)",
|
||||
(uint8_t)str[0]);
|
||||
} else {
|
||||
idx = find_atom(&s->atom_list, str);
|
||||
if (idx < 0) {
|
||||
fprintf(stderr, "atom '%s' is undefined\n", str);
|
||||
exit(1);
|
||||
}
|
||||
offset = s->atom_list.tab[idx].offset;
|
||||
if (value_only)
|
||||
return (offset * JSW) + 1; /* correct modulo ATOM_ALIGN */
|
||||
printf("JS_ROM_VALUE(%d)", offset);
|
||||
}
|
||||
printf(" /* %s */", str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_cfuncs(BuildContext *s)
|
||||
{
|
||||
int i;
|
||||
CFuncDef *e;
|
||||
|
||||
printf("static const JSCFunctionDef js_c_function_table[] = {\n");
|
||||
for(i = 0; i < s->cfunc_list.count; i++) {
|
||||
e = &s->cfunc_list.tab[i];
|
||||
printf(" { { .%s = %s },\n", e->cproto_name, e->cfunc_name);
|
||||
printf(" ");
|
||||
dump_atom(s, e->name, FALSE);
|
||||
printf(",\n");
|
||||
printf(" JS_CFUNC_%s, %d, %s },\n",
|
||||
e->cproto_name, e->length, e->magic);
|
||||
}
|
||||
printf("};\n\n");
|
||||
}
|
||||
|
||||
static void dump_cfinalizers(BuildContext *s)
|
||||
{
|
||||
struct list_head *el;
|
||||
ClassDefEntry *e;
|
||||
|
||||
printf("static const JSCFinalizer js_c_finalizer_table[JS_CLASS_COUNT - JS_CLASS_USER] = {\n");
|
||||
list_for_each(el, &s->class_list) {
|
||||
e = list_entry(el, ClassDefEntry, link);
|
||||
if (e->finalizer_name &&
|
||||
strcmp(e->finalizer_name, "NULL") != 0) {
|
||||
printf(" [%s - JS_CLASS_USER] = %s,\n", e->class_id, e->finalizer_name);
|
||||
}
|
||||
}
|
||||
printf("};\n\n");
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
PROPS_KIND_GLOBAL,
|
||||
PROPS_KIND_PROTO,
|
||||
PROPS_KIND_CLASS,
|
||||
PROPS_KIND_OBJECT,
|
||||
} JSPropsKindEnum;
|
||||
|
||||
static inline uint32_t hash_prop(BuildContext *s, const char *name)
|
||||
{
|
||||
/* Compute the hash for a symbol, must be consistent with
|
||||
mquickjs.c implementation.
|
||||
*/
|
||||
uint32_t prop = dump_atom(s, name, TRUE);
|
||||
return (prop / JSW) ^ (prop % JSW); /* XXX: improve */
|
||||
}
|
||||
|
||||
static int define_props(BuildContext *s, const JSPropDef *props_def,
|
||||
JSPropsKindEnum props_kind, const char *class_id_str)
|
||||
{
|
||||
int i, *ident_tab, idx, props_ident, n_props;
|
||||
int prop_idx;
|
||||
const JSPropDef *d;
|
||||
uint32_t *prop_hash;
|
||||
BOOL is_global_object = (props_kind == PROPS_KIND_GLOBAL);
|
||||
static const JSPropDef dummy_props[] = {
|
||||
{ JS_DEF_END },
|
||||
};
|
||||
|
||||
if (!props_def)
|
||||
props_def = dummy_props;
|
||||
|
||||
n_props = 0;
|
||||
for(d = props_def; d->def_type != JS_DEF_END; d++) {
|
||||
n_props++;
|
||||
}
|
||||
if (props_kind == PROPS_KIND_PROTO ||
|
||||
props_kind == PROPS_KIND_CLASS)
|
||||
n_props++;
|
||||
ident_tab = malloc(sizeof(ident_tab[0]) * n_props);
|
||||
|
||||
/* define the various objects */
|
||||
for(d = props_def, i = 0; d->def_type != JS_DEF_END; d++, i++) {
|
||||
ident_tab[i] = define_value(s, d);
|
||||
}
|
||||
|
||||
props_ident = -1;
|
||||
prop_hash = NULL;
|
||||
if (is_global_object) {
|
||||
props_ident = s->cur_offset;
|
||||
printf(" /* global object properties (offset=%d) */\n", props_ident);
|
||||
printf(" JS_VALUE_ARRAY_HEADER(%d),\n", 2 * n_props);
|
||||
s->cur_offset += 2 * n_props + 1;
|
||||
} else {
|
||||
int hash_size_log2;
|
||||
uint32_t hash_size, hash_mask;
|
||||
uint32_t *hash_table, h;
|
||||
|
||||
if (n_props <= 1)
|
||||
hash_size_log2 = 0;
|
||||
else
|
||||
hash_size_log2 = (32 - clz32(n_props - 1)) - 1;
|
||||
hash_size = 1 << hash_size_log2;
|
||||
if (hash_size > ATOM_ALIGN / JSW) {
|
||||
#if !defined __APPLE__
|
||||
// XXX: Cannot request data alignment larger than 64 bytes on Darwin
|
||||
fprintf(stderr, "Too many properties, consider increasing ATOM_ALIGN\n");
|
||||
#endif
|
||||
hash_size = ATOM_ALIGN / JSW;
|
||||
}
|
||||
hash_mask = hash_size - 1;
|
||||
|
||||
hash_table = malloc(sizeof(hash_table[0]) * hash_size);
|
||||
prop_hash = malloc(sizeof(prop_hash[0]) * n_props);
|
||||
/* build the hash table */
|
||||
for(i = 0; i < hash_size; i++)
|
||||
hash_table[i] = 0;
|
||||
prop_idx = 0;
|
||||
for(i = 0, d = props_def; i < n_props; i++, d++) {
|
||||
const char *name;
|
||||
if (d->def_type != JS_DEF_END) {
|
||||
name = d->name;
|
||||
} else {
|
||||
if (props_kind == PROPS_KIND_PROTO)
|
||||
name = "constructor";
|
||||
else
|
||||
name = "prototype";
|
||||
}
|
||||
h = hash_prop(s, name) & hash_mask;
|
||||
prop_hash[prop_idx] = hash_table[h];
|
||||
hash_table[h] = 2 + hash_size + 3 * prop_idx;
|
||||
prop_idx++;
|
||||
}
|
||||
|
||||
props_ident = s->cur_offset;
|
||||
printf(" /* properties (offset=%d) */\n", props_ident);
|
||||
printf(" JS_VALUE_ARRAY_HEADER(%d),\n", 2 + hash_size + n_props * 3);
|
||||
printf(" %d << 1, /* n_props */\n", n_props);
|
||||
printf(" %d << 1, /* hash_mask */\n", hash_mask);
|
||||
for(i = 0; i < hash_size; i++) {
|
||||
printf(" %d << 1,\n", hash_table[i]);
|
||||
}
|
||||
s->cur_offset += hash_size + 3 + 3 * n_props;
|
||||
free(hash_table);
|
||||
}
|
||||
prop_idx = 0;
|
||||
for(d = props_def, i = 0; i < n_props; d++, i++) {
|
||||
const char *name, *prop_type;
|
||||
/* name */
|
||||
printf(" ");
|
||||
if (d->def_type != JS_DEF_END) {
|
||||
name = d->name;
|
||||
} else {
|
||||
if (props_kind == PROPS_KIND_PROTO)
|
||||
name = "constructor";
|
||||
else
|
||||
name = "prototype";
|
||||
}
|
||||
dump_atom(s, name, FALSE);
|
||||
printf(",\n");
|
||||
|
||||
printf(" ");
|
||||
prop_type = "NORMAL";
|
||||
switch(d->def_type) {
|
||||
case JS_DEF_PROP_DOUBLE:
|
||||
if (ident_tab[i] >= 0)
|
||||
goto value_ptr;
|
||||
/* short int */
|
||||
printf("%d << 1,", (int32_t)d->u.f64);
|
||||
break;
|
||||
case JS_DEF_CGETSET:
|
||||
if (is_global_object) {
|
||||
fprintf(stderr, "getter/setter forbidden in global object\n");
|
||||
exit(1);
|
||||
}
|
||||
prop_type = "GETSET";
|
||||
goto value_ptr;
|
||||
case JS_DEF_CLASS:
|
||||
value_ptr:
|
||||
assert(ident_tab[i] >= 0);
|
||||
printf("JS_ROM_VALUE(%d),", ident_tab[i]);
|
||||
break;
|
||||
case JS_DEF_PROP_UNDEFINED:
|
||||
printf("JS_UNDEFINED,");
|
||||
break;
|
||||
case JS_DEF_PROP_NULL:
|
||||
printf("JS_NULL,");
|
||||
break;
|
||||
case JS_DEF_PROP_STRING:
|
||||
dump_atom(s, d->u.str, FALSE);
|
||||
printf(",");
|
||||
break;
|
||||
case JS_DEF_CFUNC:
|
||||
idx = add_cfunc(&s->cfunc_list,
|
||||
d->name,
|
||||
d->u.func.length,
|
||||
d->u.func.magic,
|
||||
d->u.func.cproto_name,
|
||||
d->u.func.func_name);
|
||||
printf("JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, %d),", idx);
|
||||
break;
|
||||
case JS_DEF_END:
|
||||
if (props_kind == PROPS_KIND_PROTO) {
|
||||
/* constructor property */
|
||||
printf("(uint32_t)(-%s - 1) << 1,", class_id_str);
|
||||
} else {
|
||||
/* prototype property */
|
||||
printf("%s << 1,", class_id_str);
|
||||
}
|
||||
prop_type = "SPECIAL";
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
printf("\n");
|
||||
if (!is_global_object) {
|
||||
printf(" (%d << 1) | (JS_PROP_%s << 30),\n",
|
||||
prop_hash[prop_idx], prop_type);
|
||||
}
|
||||
prop_idx++;
|
||||
}
|
||||
|
||||
free(prop_hash);
|
||||
free(ident_tab);
|
||||
return props_ident;
|
||||
}
|
||||
|
||||
static ClassDefEntry *find_class(BuildContext *s, const JSClassDef *d)
|
||||
{
|
||||
struct list_head *el;
|
||||
ClassDefEntry *e;
|
||||
|
||||
list_for_each(el, &s->class_list) {
|
||||
e = list_entry(el, ClassDefEntry, link);
|
||||
if (e->class1 == d)
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void free_class_entries(BuildContext *s)
|
||||
{
|
||||
struct list_head *el, *el1;
|
||||
ClassDefEntry *e;
|
||||
list_for_each_safe(el, el1, &s->class_list) {
|
||||
e = list_entry(el, ClassDefEntry, link);
|
||||
free(e->class_id);
|
||||
free(e->finalizer_name);
|
||||
free(e);
|
||||
}
|
||||
init_list_head(&s->class_list);
|
||||
}
|
||||
|
||||
static int define_class(BuildContext *s, const JSClassDef *d)
|
||||
{
|
||||
int ctor_func_idx = -1, class_props_idx = -1, proto_props_idx = -1;
|
||||
int ident, parent_class_idx = -1;
|
||||
ClassDefEntry *e;
|
||||
|
||||
/* check if the class is already defined */
|
||||
e = find_class(s, d);
|
||||
if (e)
|
||||
return e->class_idx;
|
||||
|
||||
if (d->parent_class)
|
||||
parent_class_idx = define_class(s, d->parent_class);
|
||||
|
||||
if (d->func_name) {
|
||||
ctor_func_idx = add_cfunc(&s->cfunc_list,
|
||||
d->name,
|
||||
d->length,
|
||||
d->class_id,
|
||||
d->cproto_name,
|
||||
d->func_name);
|
||||
}
|
||||
|
||||
if (ctor_func_idx >= 0) {
|
||||
class_props_idx = define_props(s, d->class_props, PROPS_KIND_CLASS, d->class_id);
|
||||
proto_props_idx = define_props(s, d->proto_props, PROPS_KIND_PROTO, d->class_id);
|
||||
} else {
|
||||
if (d->class_props)
|
||||
class_props_idx = define_props(s, d->class_props, PROPS_KIND_OBJECT, d->class_id);
|
||||
}
|
||||
|
||||
ident = s->cur_offset;
|
||||
printf(" /* class (offset=%d) */\n", ident);
|
||||
printf(" JS_MB_HEADER_DEF(JS_MTAG_OBJECT),\n");
|
||||
if (class_props_idx >= 0)
|
||||
printf(" JS_ROM_VALUE(%d),\n", class_props_idx);
|
||||
else
|
||||
printf(" JS_NULL,\n");
|
||||
printf(" %d,\n", ctor_func_idx);
|
||||
if (proto_props_idx >= 0)
|
||||
printf(" JS_ROM_VALUE(%d),\n", proto_props_idx);
|
||||
else
|
||||
printf(" JS_NULL,\n");
|
||||
if (parent_class_idx >= 0) {
|
||||
printf(" JS_ROM_VALUE(%d),\n", parent_class_idx);
|
||||
} else {
|
||||
printf(" JS_NULL,\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
s->cur_offset += 5;
|
||||
|
||||
e = malloc(sizeof(*e));
|
||||
memset(e, 0, sizeof(*e));
|
||||
e->class_idx = ident;
|
||||
e->class1 = d;
|
||||
if (ctor_func_idx >= 0) {
|
||||
e->class_id = strdup(d->class_id);
|
||||
e->finalizer_name = strdup(d->finalizer_name);
|
||||
}
|
||||
list_add_tail(&e->link, &s->class_list);
|
||||
return ident;
|
||||
}
|
||||
|
||||
#define JS_SHORTINT_MIN (-(1 << 30))
|
||||
#define JS_SHORTINT_MAX ((1 << 30) - 1)
|
||||
|
||||
static BOOL is_short_int(double d)
|
||||
{
|
||||
return (d >= JS_SHORTINT_MIN && d <= JS_SHORTINT_MAX && (int32_t)d == d);
|
||||
}
|
||||
|
||||
static int define_value(BuildContext *s, const JSPropDef *d)
|
||||
{
|
||||
int ident;
|
||||
ident = -1;
|
||||
switch(d->def_type) {
|
||||
case JS_DEF_PROP_DOUBLE:
|
||||
{
|
||||
uint64_t v;
|
||||
if (!is_short_int(d->u.f64)) {
|
||||
ident = s->cur_offset;
|
||||
printf(" /* float64 (offset=%d) */\n", ident);
|
||||
printf(" JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),\n");
|
||||
v = float64_as_uint64(d->u.f64);
|
||||
if (JSW == 8) {
|
||||
printf(" 0x%016zx,\n", (size_t)v);
|
||||
printf("\n");
|
||||
s->cur_offset += 2;
|
||||
} else {
|
||||
/* XXX: little endian assumed */
|
||||
printf(" 0x%08x,\n", (uint32_t)v);
|
||||
printf(" 0x%08x,\n", (uint32_t)(v >> 32));
|
||||
printf("\n");
|
||||
s->cur_offset += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JS_DEF_CLASS:
|
||||
ident = define_class(s, d->u.class1);
|
||||
break;
|
||||
case JS_DEF_CGETSET:
|
||||
{
|
||||
int get_idx = -1, set_idx = -1;
|
||||
char buf[256];
|
||||
if (strcmp(d->u.getset.get_func_name, "NULL") != 0) {
|
||||
snprintf(buf, sizeof(buf), "get %s", d->name);
|
||||
get_idx = add_cfunc(&s->cfunc_list,
|
||||
buf,
|
||||
0, /* length */
|
||||
d->u.getset.magic,
|
||||
d->u.getset.cproto_name,
|
||||
d->u.getset.get_func_name);
|
||||
}
|
||||
if (strcmp(d->u.getset.set_func_name, "NULL") != 0) {
|
||||
snprintf(buf, sizeof(buf), "set %s", d->name);
|
||||
set_idx = add_cfunc(&s->cfunc_list,
|
||||
buf,
|
||||
1, /* length */
|
||||
d->u.getset.magic,
|
||||
d->u.getset.cproto_name,
|
||||
d->u.getset.set_func_name);
|
||||
}
|
||||
ident = s->cur_offset;
|
||||
printf(" /* getset (offset=%d) */\n", ident);
|
||||
printf(" JS_VALUE_ARRAY_HEADER(2),\n");
|
||||
if (get_idx >= 0)
|
||||
printf(" JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, %d),\n", get_idx);
|
||||
else
|
||||
printf(" JS_UNDEFINED,\n");
|
||||
if (set_idx >= 0)
|
||||
printf(" JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, %d),\n", set_idx);
|
||||
else
|
||||
printf(" JS_UNDEFINED,\n");
|
||||
printf("\n");
|
||||
s->cur_offset += 3;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ident;
|
||||
}
|
||||
|
||||
static void define_atoms_props(BuildContext *s, const JSPropDef *props_def, JSPropsKindEnum props_kind);
|
||||
|
||||
static void define_atoms_class(BuildContext *s, const JSClassDef *d)
|
||||
{
|
||||
ClassDefEntry *e;
|
||||
/* check if the class is already defined */
|
||||
e = find_class(s, d);
|
||||
if (e)
|
||||
return;
|
||||
if (d->parent_class)
|
||||
define_atoms_class(s, d->parent_class);
|
||||
if (d->func_name)
|
||||
add_atom(&s->atom_list, d->name);
|
||||
if (d->class_props)
|
||||
define_atoms_props(s, d->class_props, d->func_name ? PROPS_KIND_CLASS : PROPS_KIND_OBJECT);
|
||||
if (d->proto_props)
|
||||
define_atoms_props(s, d->proto_props, PROPS_KIND_PROTO);
|
||||
}
|
||||
|
||||
static void define_atoms_props(BuildContext *s, const JSPropDef *props_def, JSPropsKindEnum props_kind)
|
||||
{
|
||||
const JSPropDef *d;
|
||||
for(d = props_def; d->def_type != JS_DEF_END; d++) {
|
||||
add_atom(&s->atom_list, d->name);
|
||||
switch(d->def_type) {
|
||||
case JS_DEF_PROP_STRING:
|
||||
add_atom(&s->atom_list, d->u.str);
|
||||
break;
|
||||
case JS_DEF_CLASS:
|
||||
define_atoms_class(s, d->u.class1);
|
||||
break;
|
||||
case JS_DEF_CGETSET:
|
||||
{
|
||||
char buf[256];
|
||||
if (strcmp(d->u.getset.get_func_name, "NULL") != 0) {
|
||||
snprintf(buf, sizeof(buf), "get %s", d->name);
|
||||
add_atom(&s->atom_list, buf);
|
||||
}
|
||||
if (strcmp(d->u.getset.set_func_name, "NULL") != 0) {
|
||||
snprintf(buf, sizeof(buf), "set %s", d->name);
|
||||
add_atom(&s->atom_list, buf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int usage(const char *name)
|
||||
{
|
||||
fprintf(stderr, "usage: %s {-m32 | -m64} [-a]\n", name);
|
||||
fprintf(stderr,
|
||||
" create a ROM file for the mquickjs standard library\n"
|
||||
"--help list options\n"
|
||||
"-m32 force generation for a 32 bit target\n"
|
||||
"-m64 force generation for a 64 bit target\n"
|
||||
"-a generate the mquickjs_atom.h header\n"
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int build_atoms(const char *stdlib_name, const JSPropDef *global_obj,
|
||||
const JSPropDef *c_function_decl, int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
unsigned jsw;
|
||||
BuildContext ss, *s = &ss;
|
||||
BOOL build_atom_defines = FALSE;
|
||||
|
||||
#if INTPTR_MAX >= INT64_MAX
|
||||
jsw = 8;
|
||||
#else
|
||||
jsw = 4;
|
||||
#endif
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-m64")) {
|
||||
jsw = 8;
|
||||
} else if (!strcmp(argv[i], "-m32")) {
|
||||
jsw = 4;
|
||||
} else if (!strcmp(argv[i], "-a")) {
|
||||
build_atom_defines = TRUE;
|
||||
} else if (!strcmp(argv[i], "--help")) {
|
||||
return usage(argv[0]);
|
||||
} else {
|
||||
fprintf(stderr, "invalid argument '%s'\n", argv[i]);
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
JSW = jsw;
|
||||
|
||||
if (build_atom_defines) {
|
||||
dump_atom_defines();
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
init_list_head(&s->class_list);
|
||||
|
||||
/* add the predefined atoms (they have a corresponding define) */
|
||||
for(i = 0; i < countof(atoms); i++) {
|
||||
add_atom(&s->atom_list, atoms[i]);
|
||||
}
|
||||
|
||||
/* add the predefined functions */
|
||||
if (c_function_decl) {
|
||||
const JSPropDef *d;
|
||||
for(d = c_function_decl; d->def_type != JS_DEF_END; d++) {
|
||||
if (d->def_type != JS_DEF_CFUNC) {
|
||||
fprintf(stderr, "only C functions are allowed in c_function_decl[]\n");
|
||||
exit(1);
|
||||
}
|
||||
add_atom(&s->atom_list, d->name);
|
||||
add_cfunc(&s->cfunc_list,
|
||||
d->name,
|
||||
d->u.func.length,
|
||||
d->u.func.magic,
|
||||
d->u.func.cproto_name,
|
||||
d->u.func.func_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* first pass to define the atoms */
|
||||
define_atoms_props(s, global_obj, PROPS_KIND_GLOBAL);
|
||||
free_class_entries(s);
|
||||
|
||||
printf("/* this file is automatically generated - do not edit */\n\n");
|
||||
printf("#include \"mquickjs_priv.h\"\n\n");
|
||||
|
||||
printf("static const uint%u_t __attribute((aligned(%d))) js_stdlib_table[] = {\n",
|
||||
JSW * 8, ATOM_ALIGN);
|
||||
|
||||
dump_atoms(s);
|
||||
|
||||
s->global_object_offset = define_props(s, global_obj, PROPS_KIND_GLOBAL, NULL);
|
||||
|
||||
printf("};\n\n");
|
||||
|
||||
dump_cfuncs(s);
|
||||
|
||||
printf("#ifndef JS_CLASS_COUNT\n"
|
||||
"#define JS_CLASS_COUNT JS_CLASS_USER /* total number of classes */\n"
|
||||
"#endif\n\n");
|
||||
|
||||
dump_cfinalizers(s);
|
||||
|
||||
free_class_entries(s);
|
||||
|
||||
printf("const JSSTDLibraryDef %s = {\n", stdlib_name);
|
||||
printf(" js_stdlib_table,\n");
|
||||
printf(" js_c_function_table,\n");
|
||||
printf(" js_c_finalizer_table,\n");
|
||||
printf(" %d,\n", s->cur_offset);
|
||||
printf(" %d,\n", ATOM_ALIGN);
|
||||
printf(" %d,\n", s->sorted_atom_table_offset);
|
||||
printf(" %d,\n", s->global_object_offset);
|
||||
printf(" JS_CLASS_COUNT,\n");
|
||||
printf("};\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
97
lib/mquickjs/scripts/mquickjs_build.h
Normal file
97
lib/mquickjs/scripts/mquickjs_build.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Micro QuickJS build utility
|
||||
*
|
||||
* Copyright (c) 2017-2025 Fabrice Bellard
|
||||
* Copyright (c) 2017-2025 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MQUICKJS_BUILD_H
|
||||
#define MQUICKJS_BUILD_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
enum {
|
||||
JS_DEF_END,
|
||||
JS_DEF_CFUNC,
|
||||
JS_DEF_CGETSET,
|
||||
JS_DEF_PROP_DOUBLE,
|
||||
JS_DEF_PROP_UNDEFINED,
|
||||
JS_DEF_PROP_STRING,
|
||||
JS_DEF_PROP_NULL,
|
||||
JS_DEF_CLASS,
|
||||
};
|
||||
|
||||
typedef struct JSClassDef JSClassDef;
|
||||
|
||||
typedef struct JSPropDef {
|
||||
int def_type;
|
||||
const char *name;
|
||||
union {
|
||||
struct {
|
||||
uint8_t length;
|
||||
const char *magic;
|
||||
const char *cproto_name;
|
||||
const char *func_name;
|
||||
} func;
|
||||
struct {
|
||||
const char *magic;
|
||||
const char *cproto_name;
|
||||
const char *get_func_name;
|
||||
const char *set_func_name;
|
||||
} getset;
|
||||
double f64;
|
||||
const JSClassDef *class1;
|
||||
const char *str;
|
||||
} u;
|
||||
} JSPropDef;
|
||||
|
||||
typedef struct JSClassDef {
|
||||
const char *name;
|
||||
int length;
|
||||
const char *cproto_name;
|
||||
const char *func_name;
|
||||
const char *class_id;
|
||||
const JSPropDef *class_props; /* NULL if none */
|
||||
const JSPropDef *proto_props; /* NULL if none */
|
||||
const JSClassDef *parent_class; /* NULL if none */
|
||||
const char *finalizer_name; /* "NULL" if none */
|
||||
} JSClassDef;
|
||||
|
||||
#define JS_PROP_END { JS_DEF_END }
|
||||
#define JS_CFUNC_DEF(name, length, func_name) { JS_DEF_CFUNC, name, { .func = { length, "0", "generic", #func_name } } }
|
||||
#define JS_CFUNC_MAGIC_DEF(name, length, func_name, magic) { JS_DEF_CFUNC, name, { .func = { length, #magic, "generic_magic", #func_name } } }
|
||||
#define JS_CFUNC_SPECIAL_DEF(name, length, proto, func_name) { JS_DEF_CFUNC, name, { .func = { length, "0", #proto, #func_name } } }
|
||||
#define JS_CGETSET_DEF(name, get_name, set_name) { JS_DEF_CGETSET, name, { .getset = { "0", "generic", #get_name, #set_name } } }
|
||||
#define JS_CGETSET_MAGIC_DEF(name, get_name, set_name, magic) { JS_DEF_CGETSET, name, { .getset = { #magic, "generic_magic", #get_name, #set_name } } }
|
||||
#define JS_PROP_CLASS_DEF(name, cl) { JS_DEF_CLASS, name, { .class1 = cl } }
|
||||
#define JS_PROP_DOUBLE_DEF(name, val, flags) { JS_DEF_PROP_DOUBLE, name, { .f64 = val } }
|
||||
#define JS_PROP_UNDEFINED_DEF(name, flags) { JS_DEF_PROP_UNDEFINED, name }
|
||||
#define JS_PROP_NULL_DEF(name, flags) { JS_DEF_PROP_NULL, name }
|
||||
#define JS_PROP_STRING_DEF(name, cstr, flags) { JS_DEF_PROP_STRING, name, { .str = cstr } }
|
||||
|
||||
#define JS_CLASS_DEF(name, length, func_name, class_id, class_props, proto_props, parent_class, finalizer_name) { name, length, "constructor", #func_name, #class_id, class_props, proto_props, parent_class, #finalizer_name }
|
||||
#define JS_CLASS_MAGIC_DEF(name, length, func_name, class_id, class_props, proto_props, parent_class, finalizer_name) { name, length, "constructor_magic", #func_name, #class_id, class_props, proto_props, parent_class, #finalizer_name }
|
||||
#define JS_OBJECT_DEF(name, obj_props) { name, 0, NULL, NULL, NULL, obj_props, NULL, NULL, NULL }
|
||||
|
||||
int build_atoms(const char *stdlib_name, const JSPropDef *global_obj,
|
||||
const JSPropDef *c_function_decl, int argc, char **argv);
|
||||
|
||||
#endif /* MQUICKJS_BUILD_H */
|
||||
970
lib/mquickjs/softfp_template.h
Normal file
970
lib/mquickjs/softfp_template.h
Normal file
@ -0,0 +1,970 @@
|
||||
/*
|
||||
* SoftFP Library
|
||||
*
|
||||
* Copyright (c) 2016 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#if F_SIZE == 32
|
||||
#define F_UINT uint32_t
|
||||
#define F_ULONG uint64_t
|
||||
#define MANT_SIZE 23
|
||||
#define EXP_SIZE 8
|
||||
#elif F_SIZE == 64
|
||||
#define F_UHALF uint32_t
|
||||
#define F_UINT uint64_t
|
||||
#ifdef HAVE_INT128
|
||||
#define F_ULONG uint128_t
|
||||
#endif
|
||||
#define MANT_SIZE 52
|
||||
#define EXP_SIZE 11
|
||||
#elif F_SIZE == 128
|
||||
#define F_UHALF uint64_t
|
||||
#define F_UINT uint128_t
|
||||
#define MANT_SIZE 112
|
||||
#define EXP_SIZE 15
|
||||
#else
|
||||
#error unsupported F_SIZE
|
||||
#endif
|
||||
|
||||
#define EXP_MASK ((1 << EXP_SIZE) - 1)
|
||||
#define MANT_MASK (((F_UINT)1 << MANT_SIZE) - 1)
|
||||
#define SIGN_MASK ((F_UINT)1 << (F_SIZE - 1))
|
||||
#define IMANT_SIZE (F_SIZE - 2) /* internal mantissa size */
|
||||
#define RND_SIZE (IMANT_SIZE - MANT_SIZE)
|
||||
#define QNAN_MASK ((F_UINT)1 << (MANT_SIZE - 1))
|
||||
#define EXP_BIAS ((1 << (EXP_SIZE - 1)) - 1)
|
||||
|
||||
/* quiet NaN */
|
||||
#define F_QNAN glue(F_QNAN, F_SIZE)
|
||||
#define clz glue(clz, F_SIZE)
|
||||
#define pack_sf glue(pack_sf, F_SIZE)
|
||||
#define unpack_sf glue(unpack_sf, F_SIZE)
|
||||
#define rshift_rnd glue(rshift_rnd, F_SIZE)
|
||||
#define round_pack_sf glue(roundpack_sf, F_SIZE)
|
||||
#define normalize_sf glue(normalize_sf, F_SIZE)
|
||||
#define normalize2_sf glue(normalize2_sf, F_SIZE)
|
||||
#define issignan_sf glue(issignan_sf, F_SIZE)
|
||||
#define isnan_sf glue(isnan_sf, F_SIZE)
|
||||
#define add_sf glue(add_sf, F_SIZE)
|
||||
#define mul_sf glue(mul_sf, F_SIZE)
|
||||
#define fma_sf glue(fma_sf, F_SIZE)
|
||||
#define div_sf glue(div_sf, F_SIZE)
|
||||
#define sqrt_sf glue(sqrt_sf, F_SIZE)
|
||||
#define normalize_subnormal_sf glue(normalize_subnormal_sf, F_SIZE)
|
||||
#define divrem_u glue(divrem_u, F_SIZE)
|
||||
#define sqrtrem_u glue(sqrtrem_u, F_SIZE)
|
||||
#define mul_u glue(mul_u, F_SIZE)
|
||||
#define cvt_sf32_sf glue(cvt_sf32_sf, F_SIZE)
|
||||
#define cvt_sf64_sf glue(cvt_sf64_sf, F_SIZE)
|
||||
|
||||
static const F_UINT F_QNAN = (((F_UINT)EXP_MASK << MANT_SIZE) | ((F_UINT)1 << (MANT_SIZE - 1)));
|
||||
|
||||
static inline F_UINT pack_sf(uint32_t a_sign, uint32_t a_exp, F_UINT a_mant)
|
||||
{
|
||||
return ((F_UINT)a_sign << (F_SIZE - 1)) |
|
||||
((F_UINT)a_exp << MANT_SIZE) |
|
||||
(a_mant & MANT_MASK);
|
||||
}
|
||||
|
||||
static inline F_UINT unpack_sf(uint32_t *pa_sign, int32_t *pa_exp,
|
||||
F_UINT a)
|
||||
{
|
||||
*pa_sign = a >> (F_SIZE - 1);
|
||||
*pa_exp = (a >> MANT_SIZE) & EXP_MASK;
|
||||
return a & MANT_MASK;
|
||||
}
|
||||
|
||||
static F_UINT rshift_rnd(F_UINT a, int d)
|
||||
{
|
||||
F_UINT mask;
|
||||
if (d != 0) {
|
||||
if (d >= F_SIZE) {
|
||||
a = (a != 0);
|
||||
} else {
|
||||
mask = ((F_UINT)1 << d) - 1;
|
||||
a = (a >> d) | ((a & mask) != 0);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
#if F_USE_FFLAGS
|
||||
#define FFLAGS_PARAM , uint32_t *pfflags
|
||||
#define FFLAGS_ARG , pfflags
|
||||
#else
|
||||
#define FFLAGS_PARAM
|
||||
#define FFLAGS_ARG
|
||||
#endif
|
||||
|
||||
/* a_mant is considered to have its MSB at F_SIZE - 2 bits */
|
||||
static F_UINT round_pack_sf(uint32_t a_sign, int a_exp, F_UINT a_mant,
|
||||
RoundingModeEnum rm FFLAGS_PARAM)
|
||||
{
|
||||
int diff;
|
||||
uint32_t addend, rnd_bits;
|
||||
|
||||
switch(rm) {
|
||||
case RM_RNE:
|
||||
case RM_RMM:
|
||||
addend = (1 << (RND_SIZE - 1));
|
||||
break;
|
||||
case RM_RTZ:
|
||||
addend = 0;
|
||||
break;
|
||||
default:
|
||||
case RM_RDN:
|
||||
case RM_RUP:
|
||||
// printf("s=%d rm=%d m=%x\n", a_sign, rm, a_mant);
|
||||
if (a_sign ^ (rm & 1))
|
||||
addend = (1 << RND_SIZE) - 1;
|
||||
else
|
||||
addend = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* potentially subnormal */
|
||||
if (a_exp <= 0) {
|
||||
BOOL is_subnormal;
|
||||
/* Note: we set the underflow flag if the rounded result
|
||||
is subnormal and inexact */
|
||||
is_subnormal = (a_exp < 0 ||
|
||||
(a_mant + addend) < ((F_UINT)1 << (F_SIZE - 1)));
|
||||
diff = 1 - a_exp;
|
||||
a_mant = rshift_rnd(a_mant, diff);
|
||||
rnd_bits = a_mant & ((1 << RND_SIZE ) - 1);
|
||||
if (is_subnormal && rnd_bits != 0) {
|
||||
#if F_USE_FFLAGS
|
||||
*pfflags |= FFLAG_UNDERFLOW;
|
||||
#endif
|
||||
}
|
||||
a_exp = 1;
|
||||
} else {
|
||||
rnd_bits = a_mant & ((1 << RND_SIZE ) - 1);
|
||||
}
|
||||
#if F_USE_FFLAGS
|
||||
if (rnd_bits != 0)
|
||||
*pfflags |= FFLAG_INEXACT;
|
||||
#endif
|
||||
a_mant = (a_mant + addend) >> RND_SIZE;
|
||||
/* half way: select even result */
|
||||
if (rm == RM_RNE && rnd_bits == (1 << (RND_SIZE - 1)))
|
||||
a_mant &= ~1;
|
||||
/* Note the rounding adds at least 1, so this is the maximum
|
||||
value */
|
||||
a_exp += a_mant >> (MANT_SIZE + 1);
|
||||
if (a_mant <= MANT_MASK) {
|
||||
/* denormalized or zero */
|
||||
a_exp = 0;
|
||||
} else if (a_exp >= EXP_MASK) {
|
||||
/* overflow */
|
||||
if (addend == 0) {
|
||||
a_exp = EXP_MASK - 1;
|
||||
a_mant = MANT_MASK;
|
||||
} else {
|
||||
/* infinity */
|
||||
a_exp = EXP_MASK;
|
||||
a_mant = 0;
|
||||
}
|
||||
#if F_USE_FFLAGS
|
||||
*pfflags |= FFLAG_OVERFLOW | FFLAG_INEXACT;
|
||||
#endif
|
||||
}
|
||||
return pack_sf(a_sign, a_exp, a_mant);
|
||||
}
|
||||
|
||||
/* a_mant is considered to have at most F_SIZE - 1 bits */
|
||||
static F_UINT normalize_sf(uint32_t a_sign, int a_exp, F_UINT a_mant,
|
||||
RoundingModeEnum rm FFLAGS_PARAM)
|
||||
{
|
||||
int shift;
|
||||
shift = clz(a_mant) - (F_SIZE - 1 - IMANT_SIZE);
|
||||
assert(shift >= 0);
|
||||
a_exp -= shift;
|
||||
a_mant <<= shift;
|
||||
return round_pack_sf(a_sign, a_exp, a_mant, rm FFLAGS_ARG);
|
||||
}
|
||||
|
||||
static inline F_UINT normalize_subnormal_sf(int32_t *pa_exp, F_UINT a_mant)
|
||||
{
|
||||
int shift;
|
||||
shift = MANT_SIZE - ((F_SIZE - 1 - clz(a_mant)));
|
||||
*pa_exp = 1 - shift;
|
||||
return a_mant << shift;
|
||||
}
|
||||
|
||||
#if F_USE_FFLAGS
|
||||
F_STATIC BOOL issignan_sf(F_UINT a)
|
||||
{
|
||||
uint32_t a_exp1;
|
||||
F_UINT a_mant;
|
||||
a_exp1 = (a >> (MANT_SIZE - 1)) & ((1 << (EXP_SIZE + 1)) - 1);
|
||||
a_mant = a & MANT_MASK;
|
||||
return (a_exp1 == (2 * EXP_MASK) && a_mant != 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef F_NORMALIZE_ONLY
|
||||
|
||||
F_STATIC BOOL isnan_sf(F_UINT a)
|
||||
{
|
||||
uint32_t a_exp;
|
||||
F_UINT a_mant;
|
||||
a_exp = (a >> MANT_SIZE) & EXP_MASK;
|
||||
a_mant = a & MANT_MASK;
|
||||
return (a_exp == EXP_MASK && a_mant != 0);
|
||||
}
|
||||
|
||||
|
||||
F_STATIC F_UINT add_sf(F_UINT a, F_UINT b, RoundingModeEnum rm FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign, b_sign, a_exp, b_exp;
|
||||
F_UINT tmp, a_mant, b_mant;
|
||||
|
||||
/* swap so that abs(a) >= abs(b) */
|
||||
if ((a & ~SIGN_MASK) < (b & ~SIGN_MASK)) {
|
||||
tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
a_sign = a >> (F_SIZE - 1);
|
||||
b_sign = b >> (F_SIZE - 1);
|
||||
a_exp = (a >> MANT_SIZE) & EXP_MASK;
|
||||
b_exp = (b >> MANT_SIZE) & EXP_MASK;
|
||||
a_mant = (a & MANT_MASK) << 3;
|
||||
b_mant = (b & MANT_MASK) << 3;
|
||||
if (unlikely(a_exp == EXP_MASK)) {
|
||||
if (a_mant != 0) {
|
||||
/* NaN result */
|
||||
#if F_USE_FFLAGS
|
||||
if (!(a_mant & (QNAN_MASK << 3)) || issignan_sf(b))
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
#endif
|
||||
return F_QNAN;
|
||||
} else if (b_exp == EXP_MASK && a_sign != b_sign) {
|
||||
#if F_USE_FFLAGS
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
#endif
|
||||
return F_QNAN;
|
||||
} else {
|
||||
/* infinity */
|
||||
return a;
|
||||
}
|
||||
}
|
||||
if (a_exp == 0) {
|
||||
a_exp = 1;
|
||||
} else {
|
||||
a_mant |= (F_UINT)1 << (MANT_SIZE + 3);
|
||||
}
|
||||
if (b_exp == 0) {
|
||||
b_exp = 1;
|
||||
} else {
|
||||
b_mant |= (F_UINT)1 << (MANT_SIZE + 3);
|
||||
}
|
||||
b_mant = rshift_rnd(b_mant, a_exp - b_exp);
|
||||
if (a_sign == b_sign) {
|
||||
/* same signs : add the absolute values */
|
||||
a_mant += b_mant;
|
||||
} else {
|
||||
/* different signs : subtract the absolute values */
|
||||
a_mant -= b_mant;
|
||||
if (a_mant == 0) {
|
||||
/* zero result : the sign needs a specific handling */
|
||||
a_sign = (rm == RM_RDN);
|
||||
}
|
||||
}
|
||||
a_exp += (RND_SIZE - 3);
|
||||
return normalize_sf(a_sign, a_exp, a_mant, rm FFLAGS_ARG);
|
||||
}
|
||||
|
||||
F_STATIC F_UINT glue(sub_sf, F_SIZE)(F_UINT a, F_UINT b, RoundingModeEnum rm FFLAGS_PARAM)
|
||||
{
|
||||
return add_sf(a, b ^ SIGN_MASK, rm FFLAGS_ARG);
|
||||
}
|
||||
|
||||
#ifdef F_ULONG
|
||||
|
||||
static F_UINT mul_u(F_UINT *plow, F_UINT a, F_UINT b)
|
||||
{
|
||||
F_ULONG r;
|
||||
r = (F_ULONG)a * (F_ULONG)b;
|
||||
*plow = r;
|
||||
return r >> F_SIZE;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define FH_SIZE (F_SIZE / 2)
|
||||
|
||||
static F_UINT mul_u(F_UINT *plow, F_UINT a, F_UINT b)
|
||||
{
|
||||
F_UHALF a0, a1, b0, b1, r0, r1, r2, r3;
|
||||
F_UINT r00, r01, r10, r11, c;
|
||||
a0 = a;
|
||||
a1 = a >> FH_SIZE;
|
||||
b0 = b;
|
||||
b1 = b >> FH_SIZE;
|
||||
|
||||
r00 = (F_UINT)a0 * (F_UINT)b0;
|
||||
r01 = (F_UINT)a0 * (F_UINT)b1;
|
||||
r10 = (F_UINT)a1 * (F_UINT)b0;
|
||||
r11 = (F_UINT)a1 * (F_UINT)b1;
|
||||
|
||||
r0 = r00;
|
||||
c = (r00 >> FH_SIZE) + (F_UHALF)r01 + (F_UHALF)r10;
|
||||
r1 = c;
|
||||
c = (c >> FH_SIZE) + (r01 >> FH_SIZE) + (r10 >> FH_SIZE) + (F_UHALF)r11;
|
||||
r2 = c;
|
||||
r3 = (c >> FH_SIZE) + (r11 >> FH_SIZE);
|
||||
|
||||
*plow = ((F_UINT)r1 << FH_SIZE) | r0;
|
||||
return ((F_UINT)r3 << FH_SIZE) | r2;
|
||||
}
|
||||
|
||||
#undef FH_SIZE
|
||||
|
||||
#endif
|
||||
|
||||
F_STATIC F_UINT mul_sf(F_UINT a, F_UINT b, RoundingModeEnum rm FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign, b_sign, r_sign;
|
||||
int32_t a_exp, b_exp, r_exp;
|
||||
F_UINT a_mant, b_mant, r_mant, r_mant_low;
|
||||
|
||||
a_sign = a >> (F_SIZE - 1);
|
||||
b_sign = b >> (F_SIZE - 1);
|
||||
r_sign = a_sign ^ b_sign;
|
||||
a_exp = (a >> MANT_SIZE) & EXP_MASK;
|
||||
b_exp = (b >> MANT_SIZE) & EXP_MASK;
|
||||
a_mant = a & MANT_MASK;
|
||||
b_mant = b & MANT_MASK;
|
||||
if (a_exp == EXP_MASK || b_exp == EXP_MASK) {
|
||||
if (isnan_sf(a) || isnan_sf(b)) {
|
||||
#if F_USE_FFLAGS
|
||||
if (issignan_sf(a) || issignan_sf(b)) {
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
}
|
||||
#endif
|
||||
return F_QNAN;
|
||||
} else {
|
||||
/* infinity */
|
||||
if ((a_exp == EXP_MASK && (b_exp == 0 && b_mant == 0)) ||
|
||||
(b_exp == EXP_MASK && (a_exp == 0 && a_mant == 0))) {
|
||||
#if F_USE_FFLAGS
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
#endif
|
||||
return F_QNAN;
|
||||
} else {
|
||||
return pack_sf(r_sign, EXP_MASK, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (a_exp == 0) {
|
||||
if (a_mant == 0)
|
||||
return pack_sf(r_sign, 0, 0); /* zero */
|
||||
a_mant = normalize_subnormal_sf(&a_exp, a_mant);
|
||||
} else {
|
||||
a_mant |= (F_UINT)1 << MANT_SIZE;
|
||||
}
|
||||
if (b_exp == 0) {
|
||||
if (b_mant == 0)
|
||||
return pack_sf(r_sign, 0, 0); /* zero */
|
||||
b_mant = normalize_subnormal_sf(&b_exp, b_mant);
|
||||
} else {
|
||||
b_mant |= (F_UINT)1 << MANT_SIZE;
|
||||
}
|
||||
r_exp = a_exp + b_exp - (1 << (EXP_SIZE - 1)) + 2;
|
||||
|
||||
r_mant = mul_u(&r_mant_low,a_mant << RND_SIZE, b_mant << (RND_SIZE + 1));
|
||||
r_mant |= (r_mant_low != 0);
|
||||
return normalize_sf(r_sign, r_exp, r_mant, rm FFLAGS_ARG);
|
||||
}
|
||||
|
||||
#ifdef F_ULONG
|
||||
|
||||
static F_UINT divrem_u(F_UINT *pr, F_UINT ah, F_UINT al, F_UINT b)
|
||||
{
|
||||
F_ULONG a;
|
||||
a = ((F_ULONG)ah << F_SIZE) | al;
|
||||
*pr = a % b;
|
||||
return a / b;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* XXX: optimize */
|
||||
static F_UINT divrem_u(F_UINT *pr, F_UINT a1, F_UINT a0, F_UINT b)
|
||||
{
|
||||
int i, qb, ab;
|
||||
|
||||
assert(a1 < b);
|
||||
for(i = 0; i < F_SIZE; i++) {
|
||||
ab = a1 >> (F_SIZE - 1);
|
||||
a1 = (a1 << 1) | (a0 >> (F_SIZE - 1));
|
||||
if (ab || a1 >= b) {
|
||||
a1 -= b;
|
||||
qb = 1;
|
||||
} else {
|
||||
qb = 0;
|
||||
}
|
||||
a0 = (a0 << 1) | qb;
|
||||
}
|
||||
*pr = a1;
|
||||
return a0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
F_STATIC F_UINT div_sf(F_UINT a, F_UINT b, RoundingModeEnum rm FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign, b_sign, r_sign;
|
||||
int32_t a_exp, b_exp, r_exp;
|
||||
F_UINT a_mant, b_mant, r_mant, r;
|
||||
|
||||
a_sign = a >> (F_SIZE - 1);
|
||||
b_sign = b >> (F_SIZE - 1);
|
||||
r_sign = a_sign ^ b_sign;
|
||||
a_exp = (a >> MANT_SIZE) & EXP_MASK;
|
||||
b_exp = (b >> MANT_SIZE) & EXP_MASK;
|
||||
a_mant = a & MANT_MASK;
|
||||
b_mant = b & MANT_MASK;
|
||||
if (a_exp == EXP_MASK) {
|
||||
if (a_mant != 0 || isnan_sf(b)) {
|
||||
#if F_USE_FFLAGS
|
||||
if (issignan_sf(a) || issignan_sf(b)) {
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
}
|
||||
#endif
|
||||
return F_QNAN;
|
||||
} else if (b_exp == EXP_MASK) {
|
||||
#if F_USE_FFLAGS
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
#endif
|
||||
return F_QNAN;
|
||||
} else {
|
||||
return pack_sf(r_sign, EXP_MASK, 0);
|
||||
}
|
||||
} else if (b_exp == EXP_MASK) {
|
||||
if (b_mant != 0) {
|
||||
#if F_USE_FFLAGS
|
||||
if (issignan_sf(a) || issignan_sf(b)) {
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
}
|
||||
#endif
|
||||
return F_QNAN;
|
||||
} else {
|
||||
return pack_sf(r_sign, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (b_exp == 0) {
|
||||
if (b_mant == 0) {
|
||||
/* zero */
|
||||
if (a_exp == 0 && a_mant == 0) {
|
||||
#if F_USE_FFLAGS
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
#endif
|
||||
return F_QNAN;
|
||||
} else {
|
||||
#if F_USE_FFLAGS
|
||||
*pfflags |= FFLAG_DIVIDE_ZERO;
|
||||
#endif
|
||||
return pack_sf(r_sign, EXP_MASK, 0);
|
||||
}
|
||||
}
|
||||
b_mant = normalize_subnormal_sf(&b_exp, b_mant);
|
||||
} else {
|
||||
b_mant |= (F_UINT)1 << MANT_SIZE;
|
||||
}
|
||||
if (a_exp == 0) {
|
||||
if (a_mant == 0)
|
||||
return pack_sf(r_sign, 0, 0); /* zero */
|
||||
a_mant = normalize_subnormal_sf(&a_exp, a_mant);
|
||||
} else {
|
||||
a_mant |= (F_UINT)1 << MANT_SIZE;
|
||||
}
|
||||
r_exp = a_exp - b_exp + (1 << (EXP_SIZE - 1)) - 1;
|
||||
r_mant = divrem_u(&r, a_mant, 0, b_mant << 2);
|
||||
if (r != 0)
|
||||
r_mant |= 1;
|
||||
return normalize_sf(r_sign, r_exp, r_mant, rm FFLAGS_ARG);
|
||||
}
|
||||
|
||||
#ifdef F_ULONG
|
||||
|
||||
/* compute sqrt(a) with a = ah*2^F_SIZE+al and a < 2^(F_SIZE - 2)
|
||||
return true if not exact square. */
|
||||
static int sqrtrem_u(F_UINT *pr, F_UINT ah, F_UINT al)
|
||||
{
|
||||
F_ULONG a, u, s;
|
||||
int l, inexact;
|
||||
|
||||
/* 2^l >= a */
|
||||
if (ah != 0) {
|
||||
l = 2 * F_SIZE - clz(ah - 1);
|
||||
} else {
|
||||
if (al == 0) {
|
||||
*pr = 0;
|
||||
return 0;
|
||||
}
|
||||
l = F_SIZE - clz(al - 1);
|
||||
}
|
||||
a = ((F_ULONG)ah << F_SIZE) | al;
|
||||
u = (F_ULONG)1 << ((l + 1) / 2);
|
||||
for(;;) {
|
||||
s = u;
|
||||
u = ((a / s) + s) / 2;
|
||||
if (u >= s)
|
||||
break;
|
||||
}
|
||||
inexact = (a - s * s) != 0;
|
||||
*pr = s;
|
||||
return inexact;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int sqrtrem_u(F_UINT *pr, F_UINT a1, F_UINT a0)
|
||||
{
|
||||
int l, inexact;
|
||||
F_UINT u, s, r, q, sq0, sq1;
|
||||
|
||||
/* 2^l >= a */
|
||||
if (a1 != 0) {
|
||||
l = 2 * F_SIZE - clz(a1 - 1);
|
||||
} else {
|
||||
if (a0 == 0) {
|
||||
*pr = 0;
|
||||
return 0;
|
||||
}
|
||||
l = F_SIZE - clz(a0 - 1);
|
||||
}
|
||||
u = (F_UINT)1 << ((l + 1) / 2);
|
||||
for(;;) {
|
||||
s = u;
|
||||
q = divrem_u(&r, a1, a0, s);
|
||||
u = (q + s) / 2;
|
||||
if (u >= s)
|
||||
break;
|
||||
}
|
||||
sq1 = mul_u(&sq0, s, s);
|
||||
inexact = (sq0 != a0 || sq1 != a1);
|
||||
*pr = s;
|
||||
return inexact;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
F_STATIC F_UINT sqrt_sf(F_UINT a, RoundingModeEnum rm FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign;
|
||||
int32_t a_exp;
|
||||
F_UINT a_mant;
|
||||
|
||||
a_sign = a >> (F_SIZE - 1);
|
||||
a_exp = (a >> MANT_SIZE) & EXP_MASK;
|
||||
a_mant = a & MANT_MASK;
|
||||
if (a_exp == EXP_MASK) {
|
||||
if (a_mant != 0) {
|
||||
#if F_USE_FFLAGS
|
||||
if (issignan_sf(a)) {
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
}
|
||||
#endif
|
||||
return F_QNAN;
|
||||
} else if (a_sign) {
|
||||
goto neg_error;
|
||||
} else {
|
||||
return a; /* +infinity */
|
||||
}
|
||||
}
|
||||
if (a_sign) {
|
||||
if (a_exp == 0 && a_mant == 0)
|
||||
return a; /* -zero */
|
||||
neg_error:
|
||||
#if F_USE_FFLAGS
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
#endif
|
||||
return F_QNAN;
|
||||
}
|
||||
if (a_exp == 0) {
|
||||
if (a_mant == 0)
|
||||
return pack_sf(0, 0, 0); /* zero */
|
||||
a_mant = normalize_subnormal_sf(&a_exp, a_mant);
|
||||
} else {
|
||||
a_mant |= (F_UINT)1 << MANT_SIZE;
|
||||
}
|
||||
a_exp -= EXP_MASK / 2;
|
||||
/* simpler to handle an even exponent */
|
||||
if (a_exp & 1) {
|
||||
a_exp--;
|
||||
a_mant <<= 1;
|
||||
}
|
||||
a_exp = (a_exp >> 1) + EXP_MASK / 2;
|
||||
a_mant <<= (F_SIZE - 4 - MANT_SIZE);
|
||||
if (sqrtrem_u(&a_mant, a_mant, 0))
|
||||
a_mant |= 1;
|
||||
return normalize_sf(a_sign, a_exp, a_mant, rm FFLAGS_ARG);
|
||||
}
|
||||
|
||||
/* comparisons */
|
||||
|
||||
F_STATIC int glue(eq_quiet_sf, F_SIZE)(F_UINT a, F_UINT b FFLAGS_PARAM)
|
||||
{
|
||||
if (isnan_sf(a) || isnan_sf(b)) {
|
||||
#if F_USE_FFLAGS
|
||||
if (issignan_sf(a) || issignan_sf(b)) {
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((F_UINT)((a | b) << 1) == 0)
|
||||
return 1; /* zero case */
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
F_STATIC int glue(le_sf, F_SIZE)(F_UINT a, F_UINT b FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign, b_sign;
|
||||
|
||||
if (isnan_sf(a) || isnan_sf(b)) {
|
||||
#if F_USE_FFLAGS
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
a_sign = a >> (F_SIZE - 1);
|
||||
b_sign = b >> (F_SIZE - 1);
|
||||
if (a_sign != b_sign) {
|
||||
return (a_sign || ((F_UINT)((a | b) << 1) == 0));
|
||||
} else {
|
||||
if (a_sign) {
|
||||
return (a >= b);
|
||||
} else {
|
||||
return (a <= b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
F_STATIC int glue(lt_sf, F_SIZE)(F_UINT a, F_UINT b FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign, b_sign;
|
||||
|
||||
if (isnan_sf(a) || isnan_sf(b)) {
|
||||
#if F_USE_FFLAGS
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
a_sign = a >> (F_SIZE - 1);
|
||||
b_sign = b >> (F_SIZE - 1);
|
||||
if (a_sign != b_sign) {
|
||||
return (a_sign && ((F_UINT)((a | b) << 1) != 0));
|
||||
} else {
|
||||
if (a_sign) {
|
||||
return (a > b);
|
||||
} else {
|
||||
return (a < b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* return -1 (a < b), 0 (a = b), 1 (a > b) or 2 (a = nan or b =
|
||||
nan) */
|
||||
F_STATIC int glue(cmp_sf, F_SIZE)(F_UINT a, F_UINT b FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign, b_sign;
|
||||
|
||||
if (isnan_sf(a) || isnan_sf(b)) {
|
||||
#if F_USE_FFLAGS
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
#endif
|
||||
return 2;
|
||||
}
|
||||
|
||||
a_sign = a >> (F_SIZE - 1);
|
||||
b_sign = b >> (F_SIZE - 1);
|
||||
if (a_sign != b_sign) {
|
||||
if ((F_UINT)((a | b) << 1) != 0)
|
||||
return 1 - 2 * a_sign;
|
||||
else
|
||||
return 0; /* -0 = +0 */
|
||||
} else {
|
||||
if (a < b)
|
||||
return 2 * a_sign - 1;
|
||||
else if (a > b)
|
||||
return 1 - 2 * a_sign;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* conversions between floats */
|
||||
|
||||
#if F_SIZE >= 64
|
||||
|
||||
F_STATIC F_UINT cvt_sf32_sf(uint32_t a FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign;
|
||||
int32_t a_exp;
|
||||
F_UINT a_mant;
|
||||
|
||||
a_mant = unpack_sf32(&a_sign, &a_exp, a);
|
||||
if (a_exp == 0xff) {
|
||||
if (a_mant != 0) {
|
||||
/* NaN */
|
||||
#if F_USE_FFLAGS
|
||||
if (issignan_sf32(a)) {
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
}
|
||||
#endif
|
||||
return F_QNAN;
|
||||
} else {
|
||||
/* infinity */
|
||||
return pack_sf(a_sign, EXP_MASK, 0);
|
||||
}
|
||||
}
|
||||
if (a_exp == 0) {
|
||||
if (a_mant == 0)
|
||||
return pack_sf(a_sign, 0, 0); /* zero */
|
||||
a_mant = normalize_subnormal_sf32(&a_exp, a_mant);
|
||||
}
|
||||
/* convert the exponent value */
|
||||
a_exp = a_exp - 0x7f + (EXP_MASK / 2);
|
||||
/* shift the mantissa */
|
||||
a_mant <<= (MANT_SIZE - 23);
|
||||
/* We assume the target float is large enough to that no
|
||||
normalization is necessary */
|
||||
return pack_sf(a_sign, a_exp, a_mant);
|
||||
}
|
||||
|
||||
F_STATIC uint32_t glue(glue(cvt_sf, F_SIZE), _sf32)(F_UINT a, RoundingModeEnum rm FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign;
|
||||
int32_t a_exp;
|
||||
F_UINT a_mant;
|
||||
|
||||
a_mant = unpack_sf(&a_sign, &a_exp, a);
|
||||
if (a_exp == EXP_MASK) {
|
||||
if (a_mant != 0) {
|
||||
/* NaN */
|
||||
#if F_USE_FFLAGS
|
||||
if (issignan_sf(a)) {
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
}
|
||||
#endif
|
||||
return F_QNAN32;
|
||||
} else {
|
||||
/* infinity */
|
||||
return pack_sf32(a_sign, 0xff, 0);
|
||||
}
|
||||
}
|
||||
if (a_exp == 0) {
|
||||
if (a_mant == 0)
|
||||
return pack_sf32(a_sign, 0, 0); /* zero */
|
||||
normalize_subnormal_sf(&a_exp, a_mant);
|
||||
} else {
|
||||
a_mant |= (F_UINT)1 << MANT_SIZE;
|
||||
}
|
||||
/* convert the exponent value */
|
||||
a_exp = a_exp - (EXP_MASK / 2) + 0x7f;
|
||||
/* shift the mantissa */
|
||||
a_mant = rshift_rnd(a_mant, MANT_SIZE - (32 - 2));
|
||||
return normalize_sf32(a_sign, a_exp, a_mant, rm FFLAGS_ARG);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if F_SIZE >= 128
|
||||
|
||||
F_STATIC F_UINT cvt_sf64_sf(uint64_t a FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign;
|
||||
int32_t a_exp;
|
||||
F_UINT a_mant;
|
||||
|
||||
a_mant = unpack_sf64(&a_sign, &a_exp, a);
|
||||
|
||||
if (a_exp == 0x7ff) {
|
||||
if (a_mant != 0) {
|
||||
/* NaN */
|
||||
#if F_USE_FFLAGS
|
||||
if (issignan_sf64(a)) {
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
}
|
||||
#endif
|
||||
return F_QNAN;
|
||||
} else {
|
||||
/* infinity */
|
||||
return pack_sf(a_sign, EXP_MASK, 0);
|
||||
}
|
||||
}
|
||||
if (a_exp == 0) {
|
||||
if (a_mant == 0)
|
||||
return pack_sf(a_sign, 0, 0); /* zero */
|
||||
a_mant = normalize_subnormal_sf64(&a_exp, a_mant);
|
||||
}
|
||||
/* convert the exponent value */
|
||||
a_exp = a_exp - 0x3ff + (EXP_MASK / 2);
|
||||
/* shift the mantissa */
|
||||
a_mant <<= (MANT_SIZE - 52);
|
||||
return pack_sf(a_sign, a_exp, a_mant);
|
||||
}
|
||||
|
||||
F_STATIC uint64_t glue(glue(cvt_sf, F_SIZE), _sf64)(F_UINT a, RoundingModeEnum rm FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign;
|
||||
int32_t a_exp;
|
||||
F_UINT a_mant;
|
||||
|
||||
a_mant = unpack_sf(&a_sign, &a_exp, a);
|
||||
if (a_exp == EXP_MASK) {
|
||||
if (a_mant != 0) {
|
||||
/* NaN */
|
||||
#if F_USE_FFLAGS
|
||||
if (issignan_sf(a)) {
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
}
|
||||
#endif
|
||||
return F_QNAN64;
|
||||
} else {
|
||||
/* infinity */
|
||||
return pack_sf64(a_sign, 0x7ff, 0);
|
||||
}
|
||||
}
|
||||
if (a_exp == 0) {
|
||||
if (a_mant == 0)
|
||||
return pack_sf64(a_sign, 0, 0); /* zero */
|
||||
normalize_subnormal_sf(&a_exp, a_mant);
|
||||
} else {
|
||||
a_mant |= (F_UINT)1 << MANT_SIZE;
|
||||
}
|
||||
/* convert the exponent value */
|
||||
a_exp = a_exp - (EXP_MASK / 2) + 0x3ff;
|
||||
/* shift the mantissa */
|
||||
a_mant = rshift_rnd(a_mant, MANT_SIZE - (64 - 2));
|
||||
return normalize_sf64(a_sign, a_exp, a_mant, rm, pfflags);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#undef clz
|
||||
|
||||
#define ICVT_SIZE 32
|
||||
#include "softfp_template_icvt.h"
|
||||
|
||||
#define ICVT_SIZE 64
|
||||
#include "softfp_template_icvt.h"
|
||||
|
||||
/* additional libm functions */
|
||||
|
||||
/* return a mod b (exact) */
|
||||
F_STATIC F_UINT glue(fmod_sf, F_SIZE)(F_UINT a, F_UINT b FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign;
|
||||
int32_t a_exp, b_exp, n;
|
||||
F_UINT a_mant, b_mant, a_abs, b_abs;
|
||||
|
||||
a_abs = a & ~SIGN_MASK;
|
||||
b_abs = b & ~SIGN_MASK;
|
||||
if (b_abs == 0 ||
|
||||
a_abs >= ((F_UINT)EXP_MASK << MANT_SIZE) ||
|
||||
b_abs > ((F_UINT)EXP_MASK << MANT_SIZE)) {
|
||||
/* XXX: flags */
|
||||
return F_QNAN;
|
||||
}
|
||||
if (a_abs < b_abs) {
|
||||
return a; /* |a| < |b| return a */
|
||||
} else if (a_abs == b_abs) {
|
||||
return a & SIGN_MASK; /* |a| = |b| return copy_sign(0, a) */
|
||||
}
|
||||
|
||||
a_sign = a >> (F_SIZE - 1);
|
||||
a_exp = (a >> MANT_SIZE) & EXP_MASK;
|
||||
b_exp = (b >> MANT_SIZE) & EXP_MASK;
|
||||
a_mant = (a & MANT_MASK);
|
||||
b_mant = (b & MANT_MASK);
|
||||
|
||||
if (a_exp == 0) {
|
||||
a_mant = normalize_subnormal_sf(&a_exp, a_mant);
|
||||
} else {
|
||||
a_mant |= (F_UINT)1 << MANT_SIZE;
|
||||
}
|
||||
if (b_exp == 0) {
|
||||
b_mant = normalize_subnormal_sf(&b_exp, b_mant);
|
||||
} else {
|
||||
b_mant |= (F_UINT)1 << MANT_SIZE;
|
||||
}
|
||||
n = a_exp - b_exp;
|
||||
if (a_mant >= b_mant)
|
||||
a_mant -= b_mant;
|
||||
/* here a_mant < b_mant and n >= 0 */
|
||||
/* multiply a_mant by 2^n */
|
||||
/* XXX: do it faster */
|
||||
while (n != 0) {
|
||||
a_mant <<= 1;
|
||||
if (a_mant >= b_mant)
|
||||
a_mant -= b_mant;
|
||||
n--;
|
||||
}
|
||||
/* Note: the rounding mode does not matter because the result is
|
||||
exact */
|
||||
return normalize_sf(a_sign, b_exp, a_mant << RND_SIZE, RM_RNE FFLAGS_ARG);
|
||||
}
|
||||
#endif /* F_NORMALIZE_ONLY */
|
||||
|
||||
#undef F_SIZE
|
||||
#undef F_UINT
|
||||
#undef F_ULONG
|
||||
#undef F_UHALF
|
||||
#undef MANT_SIZE
|
||||
#undef EXP_SIZE
|
||||
#undef EXP_MASK
|
||||
#undef MANT_MASK
|
||||
#undef SIGN_MASK
|
||||
#undef IMANT_SIZE
|
||||
#undef RND_SIZE
|
||||
#undef QNAN_MASK
|
||||
#undef F_QNAN
|
||||
#undef F_NORMALIZE_ONLY
|
||||
#undef EXP_BIAS
|
||||
|
||||
#undef pack_sf
|
||||
#undef unpack_sf
|
||||
#undef rshift_rnd
|
||||
#undef round_pack_sf
|
||||
#undef normalize_sf
|
||||
#undef normalize2_sf
|
||||
#undef issignan_sf
|
||||
#undef isnan_sf
|
||||
#undef add_sf
|
||||
#undef mul_sf
|
||||
#undef fma_sf
|
||||
#undef div_sf
|
||||
#undef sqrt_sf
|
||||
#undef normalize_subnormal_sf
|
||||
#undef divrem_u
|
||||
#undef sqrtrem_u
|
||||
#undef mul_u
|
||||
#undef cvt_sf32_sf
|
||||
#undef cvt_sf64_sf
|
||||
172
lib/mquickjs/softfp_template_icvt.h
Normal file
172
lib/mquickjs/softfp_template_icvt.h
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* SoftFP Library
|
||||
*
|
||||
* Copyright (c) 2016 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#if ICVT_SIZE == 32
|
||||
#define ICVT_UINT uint32_t
|
||||
#define ICVT_INT int32_t
|
||||
#elif ICVT_SIZE == 64
|
||||
#define ICVT_UINT uint64_t
|
||||
#define ICVT_INT int64_t
|
||||
#elif ICVT_SIZE == 128
|
||||
#define ICVT_UINT uint128_t
|
||||
#define ICVT_INT int128_t
|
||||
#else
|
||||
#error unsupported icvt
|
||||
#endif
|
||||
|
||||
/* conversions between float and integers */
|
||||
static ICVT_INT glue(glue(glue(internal_cvt_sf, F_SIZE), _i), ICVT_SIZE)(F_UINT a, RoundingModeEnum rm,
|
||||
BOOL is_unsigned FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign, addend, rnd_bits;
|
||||
int32_t a_exp;
|
||||
F_UINT a_mant;
|
||||
ICVT_UINT r, r_max;
|
||||
|
||||
a_sign = a >> (F_SIZE - 1);
|
||||
a_exp = (a >> MANT_SIZE) & EXP_MASK;
|
||||
a_mant = a & MANT_MASK;
|
||||
if (a_exp == EXP_MASK && a_mant != 0)
|
||||
a_sign = 0; /* NaN is like +infinity */
|
||||
if (a_exp == 0) {
|
||||
a_exp = 1;
|
||||
} else {
|
||||
a_mant |= (F_UINT)1 << MANT_SIZE;
|
||||
}
|
||||
a_mant <<= RND_SIZE;
|
||||
a_exp = a_exp - (EXP_MASK / 2) - MANT_SIZE;
|
||||
|
||||
if (is_unsigned)
|
||||
r_max = (ICVT_UINT)a_sign - 1;
|
||||
else
|
||||
r_max = ((ICVT_UINT)1 << (ICVT_SIZE - 1)) - (ICVT_UINT)(a_sign ^ 1);
|
||||
if (a_exp >= 0) {
|
||||
if (a_exp <= (ICVT_SIZE - 1 - MANT_SIZE)) {
|
||||
r = (ICVT_UINT)(a_mant >> RND_SIZE) << a_exp;
|
||||
if (r > r_max)
|
||||
goto overflow;
|
||||
} else {
|
||||
overflow:
|
||||
#if F_USE_FFLAGS
|
||||
*pfflags |= FFLAG_INVALID_OP;
|
||||
#endif
|
||||
return r_max;
|
||||
}
|
||||
} else {
|
||||
a_mant = rshift_rnd(a_mant, -a_exp);
|
||||
|
||||
switch(rm) {
|
||||
case RM_RNE:
|
||||
case RM_RMM:
|
||||
addend = (1 << (RND_SIZE - 1));
|
||||
break;
|
||||
case RM_RTZ:
|
||||
addend = 0;
|
||||
break;
|
||||
default:
|
||||
case RM_RDN:
|
||||
case RM_RUP:
|
||||
if (a_sign ^ (rm & 1))
|
||||
addend = (1 << RND_SIZE) - 1;
|
||||
else
|
||||
addend = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
rnd_bits = a_mant & ((1 << RND_SIZE ) - 1);
|
||||
a_mant = (a_mant + addend) >> RND_SIZE;
|
||||
/* half way: select even result */
|
||||
if (rm == RM_RNE && rnd_bits == (1 << (RND_SIZE - 1)))
|
||||
a_mant &= ~1;
|
||||
if (a_mant > r_max)
|
||||
goto overflow;
|
||||
r = a_mant;
|
||||
#if F_USE_FFLAGS
|
||||
if (rnd_bits != 0)
|
||||
*pfflags |= FFLAG_INEXACT;
|
||||
#endif
|
||||
}
|
||||
if (a_sign)
|
||||
r = -r;
|
||||
return r;
|
||||
}
|
||||
|
||||
F_STATIC ICVT_INT __maybe_unused glue(glue(glue(cvt_sf, F_SIZE), _i), ICVT_SIZE)(F_UINT a, RoundingModeEnum rm FFLAGS_PARAM)
|
||||
{
|
||||
return glue(glue(glue(internal_cvt_sf, F_SIZE), _i), ICVT_SIZE)(a, rm,
|
||||
FALSE FFLAGS_ARG);
|
||||
}
|
||||
|
||||
F_STATIC ICVT_UINT __maybe_unused glue(glue(glue(cvt_sf, F_SIZE), _u), ICVT_SIZE)(F_UINT a, RoundingModeEnum rm FFLAGS_PARAM)
|
||||
{
|
||||
return glue(glue(glue(internal_cvt_sf, F_SIZE), _i), ICVT_SIZE) (a, rm,
|
||||
TRUE FFLAGS_ARG);
|
||||
}
|
||||
|
||||
/* conversions between float and integers */
|
||||
static F_UINT glue(glue(glue(internal_cvt_i, ICVT_SIZE), _sf), F_SIZE)(ICVT_INT a,
|
||||
RoundingModeEnum rm,
|
||||
BOOL is_unsigned FFLAGS_PARAM)
|
||||
{
|
||||
uint32_t a_sign;
|
||||
int32_t a_exp;
|
||||
F_UINT a_mant;
|
||||
ICVT_UINT r, mask;
|
||||
int l;
|
||||
|
||||
if (!is_unsigned && a < 0) {
|
||||
a_sign = 1;
|
||||
r = -(ICVT_UINT)a;
|
||||
} else {
|
||||
a_sign = 0;
|
||||
r = a;
|
||||
}
|
||||
a_exp = (EXP_MASK / 2) + F_SIZE - 2;
|
||||
/* need to reduce range before generic float normalization */
|
||||
l = ICVT_SIZE - glue(clz, ICVT_SIZE)(r) - (F_SIZE - 1);
|
||||
if (l > 0) {
|
||||
mask = r & (((ICVT_UINT)1 << l) - 1);
|
||||
r = (r >> l) | ((r & mask) != 0);
|
||||
a_exp += l;
|
||||
}
|
||||
a_mant = r;
|
||||
return normalize_sf(a_sign, a_exp, a_mant, rm FFLAGS_ARG);
|
||||
}
|
||||
|
||||
F_STATIC F_UINT __maybe_unused glue(glue(glue(cvt_i, ICVT_SIZE), _sf), F_SIZE)(ICVT_INT a,
|
||||
RoundingModeEnum rm
|
||||
FFLAGS_PARAM)
|
||||
{
|
||||
return glue(glue(glue(internal_cvt_i, ICVT_SIZE), _sf), F_SIZE)(a, rm, FALSE FFLAGS_ARG);
|
||||
}
|
||||
|
||||
F_STATIC F_UINT __maybe_unused glue(glue(glue(cvt_u, ICVT_SIZE), _sf), F_SIZE)(ICVT_UINT a,
|
||||
RoundingModeEnum rm
|
||||
FFLAGS_PARAM)
|
||||
{
|
||||
return glue(glue(glue(internal_cvt_i, ICVT_SIZE), _sf), F_SIZE)(a, rm, TRUE FFLAGS_ARG);
|
||||
}
|
||||
|
||||
#undef ICVT_SIZE
|
||||
#undef ICVT_INT
|
||||
#undef ICVT_UINT
|
||||
@ -30,6 +30,8 @@ build_flags =
|
||||
-std=c++2a
|
||||
# Enable UTF-8 long file names in SdFat
|
||||
-DUSE_UTF8_LONG_NAMES=1
|
||||
# Ignore error for mquickjs
|
||||
-Wno-narrowing
|
||||
|
||||
; Board configuration
|
||||
board_build.flash_mode = dio
|
||||
|
||||
214
scripts/debugging_monitor.py
Executable file
214
scripts/debugging_monitor.py
Executable file
@ -0,0 +1,214 @@
|
||||
import sys
|
||||
import argparse
|
||||
import re
|
||||
import threading
|
||||
from datetime import datetime
|
||||
from collections import deque
|
||||
import time
|
||||
|
||||
# Try to import potentially missing packages
|
||||
try:
|
||||
import serial
|
||||
from colorama import init, Fore, Style
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.animation as animation
|
||||
except ImportError as e:
|
||||
missing_package = e.name
|
||||
print("\n" + "!" * 50)
|
||||
print(f" Error: The required package '{missing_package}' is not installed.")
|
||||
print("!" * 50)
|
||||
|
||||
print(f"\nTo fix this, please run the following command in your terminal:\n")
|
||||
|
||||
install_cmd = "pip install "
|
||||
packages = []
|
||||
if 'serial' in str(e): packages.append("pyserial")
|
||||
if 'colorama' in str(e): packages.append("colorama")
|
||||
if 'matplotlib' in str(e): packages.append("matplotlib")
|
||||
|
||||
print(f" {install_cmd}{' '.join(packages)}")
|
||||
|
||||
print("\nExiting...")
|
||||
sys.exit(1)
|
||||
|
||||
# --- Global Variables for Data Sharing ---
|
||||
# Store last 50 data points
|
||||
MAX_POINTS = 50
|
||||
time_data = deque(maxlen=MAX_POINTS)
|
||||
free_mem_data = deque(maxlen=MAX_POINTS)
|
||||
total_mem_data = deque(maxlen=MAX_POINTS)
|
||||
data_lock = threading.Lock() # Prevent reading while writing
|
||||
|
||||
# Initialize colors
|
||||
init(autoreset=True)
|
||||
|
||||
def get_color_for_line(line):
|
||||
"""
|
||||
Classify log lines by type and assign appropriate colors.
|
||||
"""
|
||||
line_upper = line.upper()
|
||||
|
||||
if any(keyword in line_upper for keyword in ["ERROR", "[ERR]", "[SCT]", "FAILED", "WARNING"]):
|
||||
return Fore.RED
|
||||
if "[MEM]" in line_upper or "FREE:" in line_upper:
|
||||
return Fore.CYAN
|
||||
if any(keyword in line_upper for keyword in ["[GFX]", "[ERS]", "DISPLAY", "RAM WRITE", "RAM COMPLETE", "REFRESH", "POWERING ON", "FRAME BUFFER", "LUT"]):
|
||||
return Fore.MAGENTA
|
||||
if any(keyword in line_upper for keyword in ["[EBP]", "[BMC]", "[ZIP]", "[PARSER]", "[EHP]", "LOADING EPUB", "CACHE", "DECOMPRESSED", "PARSING"]):
|
||||
return Fore.GREEN
|
||||
if "[ACT]" in line_upper or "ENTERING ACTIVITY" in line_upper or "EXITING ACTIVITY" in line_upper:
|
||||
return Fore.YELLOW
|
||||
if any(keyword in line_upper for keyword in ["RENDERED PAGE", "[LOOP]", "DURATION", "WAIT COMPLETE"]):
|
||||
return Fore.BLUE
|
||||
if any(keyword in line_upper for keyword in ["[CPS]", "SETTINGS", "[CLEAR_CACHE]"]):
|
||||
return Fore.LIGHTYELLOW_EX
|
||||
if any(keyword in line_upper for keyword in ["ESP-ROM", "BUILD:", "RST:", "BOOT:", "SPIWP:", "MODE:", "LOAD:", "ENTRY", "[SD]", "STARTING CROSSPOINT", "VERSION"]):
|
||||
return Fore.LIGHTBLACK_EX
|
||||
if "[RBS]" in line_upper:
|
||||
return Fore.LIGHTCYAN_EX
|
||||
if "[KRS]" in line_upper:
|
||||
return Fore.LIGHTMAGENTA_EX
|
||||
if any(keyword in line_upper for keyword in ["EINKDISPLAY:", "STATIC FRAME", "INITIALIZING", "SPI INITIALIZED", "GPIO PINS", "RESETTING", "SSD1677", "E-INK"]):
|
||||
return Fore.LIGHTMAGENTA_EX
|
||||
if any(keyword in line_upper for keyword in ["[FNS]", "FOOTNOTE"]):
|
||||
return Fore.LIGHTGREEN_EX
|
||||
if any(keyword in line_upper for keyword in ["[CHAP]", "[OPDS]", "[COF]"]):
|
||||
return Fore.LIGHTYELLOW_EX
|
||||
|
||||
return Fore.WHITE
|
||||
|
||||
def parse_memory_line(line):
|
||||
"""
|
||||
Extracts Free and Total bytes from the specific log line.
|
||||
Format: [MEM] Free: 196344 bytes, Total: 226412 bytes, Min Free: 112620 bytes
|
||||
"""
|
||||
# Regex to find 'Free: <digits>' and 'Total: <digits>'
|
||||
match = re.search(r"Free:\s*(\d+).*Total:\s*(\d+)", line)
|
||||
if match:
|
||||
try:
|
||||
free_bytes = int(match.group(1))
|
||||
total_bytes = int(match.group(2))
|
||||
return free_bytes, total_bytes
|
||||
except ValueError:
|
||||
return None, None
|
||||
return None, None
|
||||
|
||||
def serial_worker(port, baud):
|
||||
"""
|
||||
Runs in a background thread. Handles reading serial, printing to console,
|
||||
and updating the data lists.
|
||||
"""
|
||||
print(f"{Fore.CYAN}--- Opening {port} at {baud} baud ---{Style.RESET_ALL}")
|
||||
|
||||
try:
|
||||
ser = serial.Serial(port, baud, timeout=0.1)
|
||||
ser.dtr = False
|
||||
ser.rts = False
|
||||
except serial.SerialException as e:
|
||||
print(f"{Fore.RED}Error opening port: {e}{Style.RESET_ALL}")
|
||||
return
|
||||
|
||||
try:
|
||||
while True:
|
||||
try:
|
||||
raw_data = ser.readline().decode('utf-8', errors='replace')
|
||||
|
||||
if not raw_data:
|
||||
continue
|
||||
|
||||
clean_line = raw_data.strip()
|
||||
if not clean_line:
|
||||
continue
|
||||
|
||||
# Add PC timestamp
|
||||
pc_time = datetime.now().strftime("%H:%M:%S")
|
||||
formatted_line = re.sub(r"^\[\d+\]", f"[{pc_time}]", clean_line)
|
||||
|
||||
# Check for Memory Line
|
||||
if "[MEM]" in formatted_line:
|
||||
free_val, total_val = parse_memory_line(formatted_line)
|
||||
if free_val is not None:
|
||||
with data_lock:
|
||||
time_data.append(pc_time)
|
||||
free_mem_data.append(free_val / 1024) # Convert to KB
|
||||
total_mem_data.append(total_val / 1024) # Convert to KB
|
||||
|
||||
# Print to console
|
||||
line_color = get_color_for_line(formatted_line)
|
||||
print(f"{line_color}{formatted_line}")
|
||||
|
||||
except OSError:
|
||||
print(f"{Fore.RED}Device disconnected.{Style.RESET_ALL}")
|
||||
break
|
||||
except Exception as e:
|
||||
# If thread is killed violently (e.g. main exit), silence errors
|
||||
pass
|
||||
finally:
|
||||
if 'ser' in locals() and ser.is_open:
|
||||
ser.close()
|
||||
|
||||
def update_graph(frame):
|
||||
"""
|
||||
Called by Matplotlib animation to redraw the chart.
|
||||
"""
|
||||
with data_lock:
|
||||
if not time_data:
|
||||
return
|
||||
|
||||
# Convert deques to lists for plotting
|
||||
x = list(time_data)
|
||||
y_free = list(free_mem_data)
|
||||
y_total = list(total_mem_data)
|
||||
|
||||
plt.cla() # Clear axis
|
||||
|
||||
# Plot Total RAM
|
||||
plt.plot(x, y_total, label='Total RAM (KB)', color='red', linestyle='--')
|
||||
|
||||
# Plot Free RAM
|
||||
plt.plot(x, y_free, label='Free RAM (KB)', color='green', marker='o')
|
||||
|
||||
# Fill area under Free RAM
|
||||
plt.fill_between(x, y_free, color='green', alpha=0.1)
|
||||
|
||||
plt.title("ESP32 Memory Monitor")
|
||||
plt.ylabel("Memory (KB)")
|
||||
plt.xlabel("Time")
|
||||
plt.legend(loc='upper left')
|
||||
plt.grid(True, linestyle=':', alpha=0.6)
|
||||
|
||||
# Rotate date labels
|
||||
plt.xticks(rotation=45, ha='right')
|
||||
plt.tight_layout()
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="ESP32 Monitor with Graph")
|
||||
parser.add_argument("port", nargs="?", default="/dev/ttyACM0", help="Serial port")
|
||||
parser.add_argument("--baud", type=int, default=115200, help="Baud rate")
|
||||
args = parser.parse_args()
|
||||
|
||||
# 1. Start the Serial Reader in a separate thread
|
||||
# Daemon=True means this thread dies when the main program closes
|
||||
t = threading.Thread(target=serial_worker, args=(args.port, args.baud), daemon=True)
|
||||
t.start()
|
||||
|
||||
# 2. Set up the Graph (Main Thread)
|
||||
try:
|
||||
plt.style.use('light_background')
|
||||
except:
|
||||
pass
|
||||
|
||||
fig = plt.figure(figsize=(10, 6))
|
||||
|
||||
# Update graph every 1000ms
|
||||
ani = animation.FuncAnimation(fig, update_graph, interval=1000)
|
||||
|
||||
try:
|
||||
print(f"{Fore.YELLOW}Starting Graph Window... (Close window to exit){Style.RESET_ALL}")
|
||||
plt.show()
|
||||
except KeyboardInterrupt:
|
||||
print(f"\n{Fore.YELLOW}Exiting...{Style.RESET_ALL}")
|
||||
plt.close('all') # Force close any lingering plot windows
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
251
src/activities/app/AppActivity.cpp
Normal file
251
src/activities/app/AppActivity.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
#include "AppActivity.h"
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
#include <MappedInputManager.h>
|
||||
#include <SDCardManager.h>
|
||||
|
||||
#include "../../util/StringUtils.h"
|
||||
#include "fontIds.h"
|
||||
|
||||
void AppActivity::taskTrampoline(void* param) {
|
||||
auto* self = static_cast<AppActivity*>(param);
|
||||
self->displayTaskLoop();
|
||||
}
|
||||
|
||||
void AppActivity::taskAppTrampoline(void* param) {
|
||||
auto* self = static_cast<AppActivity*>(param);
|
||||
self->appTaskLoop();
|
||||
}
|
||||
|
||||
void AppActivity::onEnter() {
|
||||
Activity::onEnter();
|
||||
renderingMutex = xSemaphoreCreateMutex();
|
||||
|
||||
selectedIdx = 0;
|
||||
programs.clear();
|
||||
|
||||
// load available applications from /apps directory
|
||||
FsFile dir = SdMan.open("/apps");
|
||||
if (dir && dir.isDirectory()) {
|
||||
dir.rewindDirectory();
|
||||
for (FsFile file = dir.openNextFile(); file; file = dir.openNextFile()) {
|
||||
char name[256];
|
||||
file.getName(name, sizeof(name));
|
||||
std::string filename(name);
|
||||
// only accept .js files
|
||||
if (StringUtils::checkFileExtension(filename, ".js")) {
|
||||
programs.emplace_back(std::move(filename));
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
dir.close();
|
||||
|
||||
// Trigger first update
|
||||
updateRequired = true;
|
||||
|
||||
xTaskCreate(&AppActivity::taskTrampoline, "AppActivityTask",
|
||||
4096, // Stack size
|
||||
this, // Parameters
|
||||
1, // Priority
|
||||
&displayTaskHandle // Task handle
|
||||
);
|
||||
}
|
||||
|
||||
void AppActivity::onExit() {
|
||||
Activity::onExit();
|
||||
|
||||
auto& runner = AppRunner::getInstance();
|
||||
runner.reset();
|
||||
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
if (displayTaskHandle) {
|
||||
vTaskDelete(displayTaskHandle);
|
||||
displayTaskHandle = nullptr;
|
||||
}
|
||||
vSemaphoreDelete(renderingMutex);
|
||||
renderingMutex = nullptr;
|
||||
}
|
||||
|
||||
void AppActivity::loop() {
|
||||
auto& runner = AppRunner::getInstance();
|
||||
if (runner.running) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (runner.exited) {
|
||||
if (appTaskHandle) {
|
||||
vTaskDelete(appTaskHandle);
|
||||
appTaskHandle = nullptr;
|
||||
}
|
||||
runner.reset();
|
||||
updateRequired = true;
|
||||
// give back rendering control
|
||||
xSemaphoreGive(renderingMutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
|
||||
// delegate rendering to the app
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
startProgram(programs[selectedIdx]); // TODO: handle errors
|
||||
return;
|
||||
}
|
||||
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Back)) {
|
||||
onGoHome();
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle navigation
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Up) ||
|
||||
mappedInput.wasPressed(MappedInputManager::Button::Left)) {
|
||||
// Move selection up (with wrap-around)
|
||||
selectedIdx = (selectedIdx > 0) ? (selectedIdx - 1) : (programs.size() - 1);
|
||||
updateRequired = true;
|
||||
} else if (mappedInput.wasPressed(MappedInputManager::Button::Down) ||
|
||||
mappedInput.wasPressed(MappedInputManager::Button::Right)) {
|
||||
// Move selection down (with wrap around)
|
||||
selectedIdx = (selectedIdx + 1) % programs.size();
|
||||
updateRequired = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AppActivity::displayTaskLoop() {
|
||||
while (true) {
|
||||
if (updateRequired) { //&& !subActivity) {
|
||||
updateRequired = false;
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
render();
|
||||
xSemaphoreGive(renderingMutex);
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void AppActivity::render() const {
|
||||
renderer.clearScreen();
|
||||
|
||||
const auto pageWidth = renderer.getScreenWidth();
|
||||
const auto pageHeight = renderer.getScreenHeight();
|
||||
|
||||
// Draw header
|
||||
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Applications", true, EpdFontFamily::BOLD);
|
||||
|
||||
if (programs.empty()) {
|
||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2, "No applications found", true);
|
||||
} else {
|
||||
// Draw selection
|
||||
renderer.fillRect(0, 60 + selectedIdx * 30 - 2, pageWidth - 1, 30);
|
||||
|
||||
// Draw all programs
|
||||
for (int i = 0; i < programs.size(); i++) {
|
||||
const int programY = 60 + i * 30; // 30 pixels between programs
|
||||
|
||||
// Draw program name
|
||||
renderer.drawText(UI_10_FONT_ID, 20, programY, programs[i].c_str(), i != selectedIdx);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw help text
|
||||
const auto labels = mappedInput.mapLabels("« Back", "Select", "", "");
|
||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
|
||||
// Always use standard refresh for settings screen
|
||||
renderer.displayBuffer();
|
||||
}
|
||||
|
||||
//
|
||||
// APP RUNNER
|
||||
//
|
||||
|
||||
// singleton for now
|
||||
AppActivity* instance = nullptr;
|
||||
|
||||
int fontIdFromString(const std::string& fontStr) {
|
||||
if (fontStr == "BOOKERLY_12") return BOOKERLY_12_FONT_ID;
|
||||
if (fontStr == "BOOKERLY_14") return BOOKERLY_14_FONT_ID;
|
||||
if (fontStr == "BOOKERLY_16") return BOOKERLY_16_FONT_ID;
|
||||
if (fontStr == "BOOKERLY_18") return BOOKERLY_18_FONT_ID;
|
||||
if (fontStr == "NOTOSANS_12") return NOTOSANS_12_FONT_ID;
|
||||
if (fontStr == "NOTOSANS_14") return NOTOSANS_14_FONT_ID;
|
||||
if (fontStr == "NOTOSANS_16") return NOTOSANS_16_FONT_ID;
|
||||
if (fontStr == "NOTOSANS_18") return NOTOSANS_18_FONT_ID;
|
||||
if (fontStr == "OPENDYSLEXIC_8") return OPENDYSLEXIC_8_FONT_ID;
|
||||
if (fontStr == "OPENDYSLEXIC_10") return OPENDYSLEXIC_10_FONT_ID;
|
||||
if (fontStr == "OPENDYSLEXIC_12") return OPENDYSLEXIC_12_FONT_ID;
|
||||
if (fontStr == "OPENDYSLEXIC_14") return OPENDYSLEXIC_14_FONT_ID;
|
||||
if (fontStr == "UI_10") return UI_10_FONT_ID;
|
||||
if (fontStr == "UI_12") return UI_12_FONT_ID;
|
||||
if (fontStr == "SMALL") return SMALL_FONT_ID;
|
||||
return -1;
|
||||
}
|
||||
|
||||
EpdFontFamily::Style styleFromString(const std::string& styleStr) {
|
||||
if (styleStr == "REGULAR") return EpdFontFamily::REGULAR;
|
||||
if (styleStr == "BOLD") return EpdFontFamily::BOLD;
|
||||
if (styleStr == "ITALIC") return EpdFontFamily::ITALIC;
|
||||
if (styleStr == "BOLD_ITALIC") return EpdFontFamily::BOLD_ITALIC;
|
||||
return EpdFontFamily::REGULAR;
|
||||
}
|
||||
|
||||
void AppActivity::startProgram(std::string programName) {
|
||||
std::string fullPath = "/apps/" + programName;
|
||||
FsFile file = SdMan.open(fullPath.c_str(), O_RDONLY);
|
||||
assert(file && file.isOpen());
|
||||
size_t fileSize = file.size();
|
||||
|
||||
if (fileSize == 0 || fileSize > AppRunner::MAX_PROG_SIZE) {
|
||||
// TODO: show as a dialog message
|
||||
Serial.printf("[%lu] [APP] Invalid program size: %u bytes, max supported = %u\n", millis(), (unsigned)fileSize,
|
||||
(unsigned)AppRunner::MAX_PROG_SIZE);
|
||||
file.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// prepare runner
|
||||
auto& runner = AppRunner::getInstance();
|
||||
runner.reset();
|
||||
|
||||
// load program code
|
||||
runner.prog.resize(fileSize + 1);
|
||||
size_t bytesRead = file.read(&runner.prog[0], fileSize);
|
||||
assert(bytesRead == fileSize);
|
||||
runner.prog[fileSize] = '\0';
|
||||
file.close();
|
||||
Serial.printf("[%lu] [APP] Starting program: %s (%u bytes)\n", millis(), programName.c_str(),
|
||||
(unsigned)runner.prog.size());
|
||||
|
||||
// clear screen before running
|
||||
renderer.clearScreen();
|
||||
renderer.displayBuffer();
|
||||
|
||||
// start new task
|
||||
runner.running = true;
|
||||
xTaskCreate(&AppActivity::taskAppTrampoline, "AppRuntimeTask",
|
||||
4096, // Stack size
|
||||
this, // Parameters
|
||||
1, // Priority
|
||||
&appTaskHandle // Task handle
|
||||
);
|
||||
|
||||
Serial.printf("[%lu] [APP] Program started\n", millis());
|
||||
}
|
||||
|
||||
void AppActivity::appTaskLoop() {
|
||||
auto& runner = AppRunner::getInstance();
|
||||
assert(runner.running && "program not running");
|
||||
|
||||
// run program code
|
||||
runner.run(&renderer, &mappedInput);
|
||||
|
||||
// program ended
|
||||
Serial.printf("[%lu] [APP] Program ended\n", millis());
|
||||
runner.running = false;
|
||||
runner.exited = true;
|
||||
|
||||
// keep task alive until main loop cleans up
|
||||
while (true) {
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
39
src/activities/app/AppActivity.h
Normal file
39
src/activities/app/AppActivity.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include <EpdFontFamily.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../../activities/Activity.h"
|
||||
#include "AppRunner.h"
|
||||
|
||||
class AppActivity final : public Activity {
|
||||
TaskHandle_t displayTaskHandle = nullptr;
|
||||
TaskHandle_t appTaskHandle = nullptr;
|
||||
SemaphoreHandle_t renderingMutex = nullptr;
|
||||
bool updateRequired = false;
|
||||
const std::function<void()> onGoHome;
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
static void taskAppTrampoline(void* param);
|
||||
[[noreturn]] void displayTaskLoop();
|
||||
[[noreturn]] void appTaskLoop();
|
||||
void render() const;
|
||||
void startProgram(std::string programName);
|
||||
|
||||
public:
|
||||
explicit AppActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, const std::function<void()>& onGoHome)
|
||||
: Activity("Settings", renderer, mappedInput), onGoHome(onGoHome) {}
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void loop() override;
|
||||
|
||||
GfxRenderer& getRenderer() { return renderer; }
|
||||
MappedInputManager& getMappedInput() { return mappedInput; }
|
||||
|
||||
// state
|
||||
std::vector<std::string> programs;
|
||||
size_t selectedIdx = 0;
|
||||
};
|
||||
331
src/activities/app/AppRunner.cpp
Normal file
331
src/activities/app/AppRunner.cpp
Normal file
@ -0,0 +1,331 @@
|
||||
|
||||
#include "AppRunner.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../../fontIds.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <mquickjs.h>
|
||||
|
||||
static JSValue js_print(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
int i;
|
||||
JSValue v;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (i != 0) Serial.write(' ');
|
||||
v = argv[i];
|
||||
if (JS_IsString(ctx, v)) {
|
||||
JSCStringBuf buf;
|
||||
const char* str;
|
||||
size_t len;
|
||||
str = JS_ToCStringLen(ctx, &len, v, &buf);
|
||||
Serial.write((const uint8_t*)str, len);
|
||||
} else {
|
||||
JS_PrintValueF(ctx, argv[i], JS_DUMP_LONG);
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_date_now(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return JS_NewInt64(ctx, (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000));
|
||||
}
|
||||
|
||||
static JSValue js_performance_now(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
return JS_ThrowInternalError(ctx, "js_performance_now not implemented");
|
||||
}
|
||||
|
||||
static JSValue js_gc(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
return JS_ThrowInternalError(ctx, "js_gc not implemented");
|
||||
}
|
||||
|
||||
static JSValue js_load(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
return JS_ThrowInternalError(ctx, "js_load not implemented");
|
||||
}
|
||||
|
||||
static JSValue js_setTimeout(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
return JS_ThrowInternalError(ctx, "js_setTimeout not implemented");
|
||||
}
|
||||
|
||||
static JSValue js_clearTimeout(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
return JS_ThrowInternalError(ctx, "js_clearTimeout not implemented");
|
||||
}
|
||||
|
||||
// Crosspoint-specific functions
|
||||
|
||||
AppRunner& appInstance() { return AppRunner::getInstance(); }
|
||||
|
||||
const char* argc_err_msg = "Expected at least %d arguments, but got %d";
|
||||
#define CHECK_ARGC(minArgs) \
|
||||
if (argc < minArgs) { \
|
||||
return JS_ThrowTypeError(ctx, argc_err_msg, minArgs, argc); \
|
||||
}
|
||||
|
||||
#define GET_STRING_ARG(index, varName) \
|
||||
JSCStringBuf varName##Buf; \
|
||||
size_t varName##Len; \
|
||||
const char* varName; \
|
||||
varName = JS_ToCStringLen(ctx, &varName##Len, argv[index], &varName##Buf);
|
||||
|
||||
static JSValue js_millis(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
return JS_NewInt64(ctx, millis());
|
||||
}
|
||||
|
||||
static JSValue js_btnIsPressed(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
CHECK_ARGC(1);
|
||||
GET_STRING_ARG(0, buttonStr);
|
||||
if (!buttonStr) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
MappedInputManager::Button button;
|
||||
if (strcmp(buttonStr, "B") == 0) {
|
||||
button = MappedInputManager::Button::Back;
|
||||
} else if (strcmp(buttonStr, "C") == 0) {
|
||||
button = MappedInputManager::Button::Confirm;
|
||||
} else if (strcmp(buttonStr, "L") == 0) {
|
||||
button = MappedInputManager::Button::Left;
|
||||
} else if (strcmp(buttonStr, "R") == 0) {
|
||||
button = MappedInputManager::Button::Right;
|
||||
} else if (strcmp(buttonStr, "U") == 0) {
|
||||
button = MappedInputManager::Button::Up;
|
||||
} else if (strcmp(buttonStr, "D") == 0) {
|
||||
button = MappedInputManager::Button::Down;
|
||||
} else {
|
||||
return JS_ThrowRangeError(ctx, "invalid button id '%s'", buttonStr);
|
||||
}
|
||||
bool isPressed = appInstance().mappedInput->isPressed(button);
|
||||
return JS_NewBool(isPressed);
|
||||
}
|
||||
|
||||
static JSValue js_getScreenWidth(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
return appInstance().renderer->getScreenWidth();
|
||||
}
|
||||
|
||||
static JSValue js_getScreenHeight(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
return appInstance().renderer->getScreenHeight();
|
||||
}
|
||||
|
||||
static JSValue js_clearScreen(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
CHECK_ARGC(1);
|
||||
int color;
|
||||
if (JS_ToInt32(ctx, &color, argv[0])) return JS_EXCEPTION;
|
||||
if (color < 0 || color > 255) {
|
||||
return JS_ThrowRangeError(ctx, "color must be between 0 and 255");
|
||||
}
|
||||
appInstance().renderer->clearScreen((uint8_t)color);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_displayBuffer(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
CHECK_ARGC(1);
|
||||
int refreshMode = HalDisplay::FAST_REFRESH;
|
||||
if (JS_ToInt32(ctx, &refreshMode, argv[0])) return JS_EXCEPTION;
|
||||
appInstance().renderer->displayBuffer((HalDisplay::RefreshMode)refreshMode);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_drawLine(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
CHECK_ARGC(5);
|
||||
int x1, y1, x2, y2, state;
|
||||
if (JS_ToInt32(ctx, &x1, argv[0]) || JS_ToInt32(ctx, &y1, argv[1]) || JS_ToInt32(ctx, &x2, argv[2]) ||
|
||||
JS_ToInt32(ctx, &y2, argv[3]) || JS_ToInt32(ctx, &state, argv[4])) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
appInstance().renderer->drawLine(x1, y1, x2, y2, state != 0);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_drawRect(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
CHECK_ARGC(5);
|
||||
int x, y, width, height, state;
|
||||
if (JS_ToInt32(ctx, &x, argv[0]) || JS_ToInt32(ctx, &y, argv[1]) || JS_ToInt32(ctx, &width, argv[2]) ||
|
||||
JS_ToInt32(ctx, &height, argv[3]) || JS_ToInt32(ctx, &state, argv[4])) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
appInstance().renderer->drawRect(x, y, width, height, state != 0);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_fillRect(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
CHECK_ARGC(5);
|
||||
int x, y, width, height, state;
|
||||
if (JS_ToInt32(ctx, &x, argv[0]) || JS_ToInt32(ctx, &y, argv[1]) || JS_ToInt32(ctx, &width, argv[2]) ||
|
||||
JS_ToInt32(ctx, &height, argv[3]) || JS_ToInt32(ctx, &state, argv[4])) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
appInstance().renderer->fillRect(x, y, width, height, state != 0);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_drawImage(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
CHECK_ARGC(5);
|
||||
JSCStringBuf buf;
|
||||
size_t len; // unused for now
|
||||
const char* bitmapData = JS_ToCStringLen(ctx, &len, argv[0], &buf);
|
||||
int x, y, width, height;
|
||||
if (!bitmapData || JS_ToInt32(ctx, &x, argv[1]) || JS_ToInt32(ctx, &y, argv[2]) || JS_ToInt32(ctx, &width, argv[3]) ||
|
||||
JS_ToInt32(ctx, &height, argv[4])) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
appInstance().renderer->drawImage((const uint8_t*)bitmapData, x, y, width, height);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static int fontIdFromString(const char* fontIdStr) {
|
||||
if (strcmp(fontIdStr, "UI10") == 0) {
|
||||
return UI_10_FONT_ID;
|
||||
} else if (strcmp(fontIdStr, "UI12") == 0) {
|
||||
return UI_12_FONT_ID;
|
||||
} else if (strcmp(fontIdStr, "SM") == 0) {
|
||||
return SMALL_FONT_ID;
|
||||
}
|
||||
return UI_10_FONT_ID; // default
|
||||
}
|
||||
|
||||
static EpdFontFamily::Style textStyleFromString(const char* styleStr) {
|
||||
EpdFontFamily::Style style = EpdFontFamily::REGULAR;
|
||||
if (strcmp(styleStr, "B") == 0) {
|
||||
style = EpdFontFamily::BOLD;
|
||||
} else if (strcmp(styleStr, "I") == 0) {
|
||||
style = EpdFontFamily::ITALIC;
|
||||
} else if (strcmp(styleStr, "J") == 0) {
|
||||
style = EpdFontFamily::BOLD_ITALIC;
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
static JSValue js_getTextWidth(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
CHECK_ARGC(3);
|
||||
GET_STRING_ARG(0, fontIdStr);
|
||||
GET_STRING_ARG(1, text);
|
||||
GET_STRING_ARG(2, styleStr);
|
||||
if (!fontIdStr || !text || !styleStr) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
int fontId = fontIdFromString(fontIdStr);
|
||||
EpdFontFamily::Style style = textStyleFromString(styleStr);
|
||||
int width = appInstance().renderer->getTextWidth(fontId, text, style);
|
||||
return JS_NewInt32(ctx, width);
|
||||
}
|
||||
|
||||
static JSValue js_drawCenteredText(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
CHECK_ARGC(5);
|
||||
int y, black;
|
||||
GET_STRING_ARG(0, fontIdStr);
|
||||
GET_STRING_ARG(2, text);
|
||||
GET_STRING_ARG(4, styleStr);
|
||||
if (!fontIdStr || JS_ToInt32(ctx, &y, argv[1]) || !text || JS_ToInt32(ctx, &black, argv[3]) || !styleStr) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
int fontId = fontIdFromString(fontIdStr);
|
||||
EpdFontFamily::Style style = textStyleFromString(styleStr);
|
||||
appInstance().renderer->drawCenteredText(fontId, y, text, black != 0, style);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_drawText(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
CHECK_ARGC(6);
|
||||
int x, y, black;
|
||||
GET_STRING_ARG(0, fontIdStr);
|
||||
GET_STRING_ARG(3, text);
|
||||
GET_STRING_ARG(5, styleStr);
|
||||
if (!fontIdStr || JS_ToInt32(ctx, &y, argv[2]) || !text || JS_ToInt32(ctx, &black, argv[4]) || !styleStr) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
int fontId = fontIdFromString(fontIdStr);
|
||||
EpdFontFamily::Style style = textStyleFromString(styleStr);
|
||||
appInstance().renderer->drawText(fontId, x, y, text, black != 0, style);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_drawButtonHints(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
CHECK_ARGC(5);
|
||||
GET_STRING_ARG(0, fontIdStr);
|
||||
GET_STRING_ARG(1, btn1Text);
|
||||
GET_STRING_ARG(2, btn2Text);
|
||||
GET_STRING_ARG(3, btn3Text);
|
||||
GET_STRING_ARG(4, btn4Text);
|
||||
if (!fontIdStr || !btn1Text || !btn2Text || !btn3Text || !btn4Text) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
int fontId = fontIdFromString(fontIdStr);
|
||||
appInstance().renderer->drawButtonHints(fontId, btn1Text, btn2Text, btn3Text, btn4Text);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_drawSideButtonHints(JSContext* ctx, JSValue* this_val, int argc, JSValue* argv) {
|
||||
CHECK_ARGC(3);
|
||||
GET_STRING_ARG(0, fontIdStr);
|
||||
GET_STRING_ARG(1, topBtnText);
|
||||
GET_STRING_ARG(2, bottomBtnText);
|
||||
if (!fontIdStr || !topBtnText || !bottomBtnText) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
int fontId = fontIdFromString(fontIdStr);
|
||||
appInstance().renderer->drawSideButtonHints(fontId, topBtnText, bottomBtnText);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
#include <crosspoint_stdlib.h>
|
||||
}
|
||||
|
||||
AppRunner AppRunner::instance;
|
||||
|
||||
static void dump_error(JSContext* jsCtx) {
|
||||
JSValue obj = JS_GetException(jsCtx);
|
||||
JS_PrintValueF(jsCtx, obj, JS_DUMP_LONG);
|
||||
}
|
||||
|
||||
static void serial_log_write_func(void* opaque, const void* buf, size_t buf_len) {
|
||||
Serial.printf("[%lu] [MJS] %.*s", millis(), (int)buf_len, (const char*)buf);
|
||||
Serial.write((const uint8_t*)buf, buf_len);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void AppRunner::run(GfxRenderer* renderer, MappedInputManager* mappedInput) {
|
||||
this->renderer = renderer;
|
||||
this->mappedInput = mappedInput;
|
||||
|
||||
this->mem.resize(MAX_MEM_SIZE);
|
||||
this->jsCtx = JS_NewContext(mem.data(), mem.size(), &js_stdlib);
|
||||
JS_SetLogFunc(jsCtx, serial_log_write_func);
|
||||
|
||||
JSValue val;
|
||||
|
||||
if (JS_IsBytecode((const uint8_t*)prog.data(), prog.size())) {
|
||||
Serial.printf("[%lu] [APP] Loading bytecode...\n", millis());
|
||||
if (JS_RelocateBytecode(jsCtx, (uint8_t*)prog.data(), prog.size())) {
|
||||
Serial.printf("[%lu] [APP] Failed to relocate bytecode\n", millis());
|
||||
}
|
||||
val = JS_LoadBytecode(jsCtx, (const uint8_t*)prog.data());
|
||||
} else {
|
||||
Serial.printf("[%lu] [APP] Parsing program from source...\n", millis());
|
||||
int parse_flags = 0;
|
||||
val = JS_Parse(jsCtx, prog.data(), prog.size(), "app", parse_flags);
|
||||
}
|
||||
|
||||
if (JS_IsException(val)) {
|
||||
dump_error(jsCtx);
|
||||
Serial.printf("[%lu] [APP] Got exception on parsing program\n", millis());
|
||||
return;
|
||||
}
|
||||
|
||||
val = JS_Run(jsCtx, val);
|
||||
|
||||
if (JS_IsException(val)) {
|
||||
dump_error(jsCtx);
|
||||
Serial.printf("[%lu] [APP] Program exited with exception\n", millis());
|
||||
return;
|
||||
}
|
||||
|
||||
// normal exit
|
||||
}
|
||||
42
src/activities/app/AppRunner.h
Normal file
42
src/activities/app/AppRunner.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
#include <MappedInputManager.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
#include <mquickjs.h>
|
||||
}
|
||||
|
||||
class AppRunner {
|
||||
public:
|
||||
static constexpr size_t MAX_PROG_SIZE = 32 * 1024; // 32KB
|
||||
static constexpr size_t MAX_MEM_SIZE = 64 * 1024; // 64KB
|
||||
|
||||
bool running = false;
|
||||
bool exited = false;
|
||||
std::vector<char> prog; // need to be alloc and set before run()
|
||||
std::vector<char> mem;
|
||||
JSContext* jsCtx = nullptr;
|
||||
|
||||
GfxRenderer* renderer = nullptr;
|
||||
MappedInputManager* mappedInput = nullptr;
|
||||
|
||||
void reset() {
|
||||
this->running = false;
|
||||
this->exited = false;
|
||||
this->prog.clear();
|
||||
this->mem.clear();
|
||||
this->jsCtx = nullptr;
|
||||
}
|
||||
|
||||
void run(GfxRenderer* renderer, MappedInputManager* mappedInput);
|
||||
|
||||
// need to be singleton so that the binded JS functions can access it
|
||||
static AppRunner& getInstance() { return instance; }
|
||||
|
||||
private:
|
||||
static AppRunner instance;
|
||||
};
|
||||
@ -4,6 +4,7 @@
|
||||
#include <Epub.h>
|
||||
#include <GfxRenderer.h>
|
||||
#include <SDCardManager.h>
|
||||
#include <Utf8.h>
|
||||
#include <Xtc.h>
|
||||
|
||||
#include <cstring>
|
||||
@ -174,6 +175,7 @@ void HomeActivity::loop() {
|
||||
const int continueIdx = hasContinueReading ? idx++ : -1;
|
||||
const int myLibraryIdx = idx++;
|
||||
const int opdsLibraryIdx = hasOpdsUrl ? idx++ : -1;
|
||||
const int appsIdx = idx++;
|
||||
const int fileTransferIdx = idx++;
|
||||
const int settingsIdx = idx;
|
||||
|
||||
@ -183,6 +185,8 @@ void HomeActivity::loop() {
|
||||
onMyLibraryOpen();
|
||||
} else if (selectorIndex == opdsLibraryIdx) {
|
||||
onOpdsBrowserOpen();
|
||||
} else if (selectorIndex == appsIdx) {
|
||||
onAppsOpen();
|
||||
} else if (selectorIndex == fileTransferIdx) {
|
||||
onFileTransferOpen();
|
||||
} else if (selectorIndex == settingsIdx) {
|
||||
@ -366,7 +370,7 @@ void HomeActivity::render() {
|
||||
while (!lines.back().empty() && renderer.getTextWidth(UI_12_FONT_ID, lines.back().c_str()) > maxLineWidth) {
|
||||
// Remove "..." first, then remove one UTF-8 char, then add "..." back
|
||||
lines.back().resize(lines.back().size() - 3); // Remove "..."
|
||||
StringUtils::utf8RemoveLastChar(lines.back());
|
||||
utf8RemoveLastChar(lines.back());
|
||||
lines.back().append("...");
|
||||
}
|
||||
break;
|
||||
@ -375,7 +379,7 @@ void HomeActivity::render() {
|
||||
int wordWidth = renderer.getTextWidth(UI_12_FONT_ID, i.c_str());
|
||||
while (wordWidth > maxLineWidth && !i.empty()) {
|
||||
// Word itself is too long, trim it (UTF-8 safe)
|
||||
StringUtils::utf8RemoveLastChar(i);
|
||||
utf8RemoveLastChar(i);
|
||||
// Check if we have room for ellipsis
|
||||
std::string withEllipsis = i + "...";
|
||||
wordWidth = renderer.getTextWidth(UI_12_FONT_ID, withEllipsis.c_str());
|
||||
@ -428,7 +432,7 @@ void HomeActivity::render() {
|
||||
if (!lastBookAuthor.empty()) {
|
||||
std::string trimmedAuthor = lastBookAuthor;
|
||||
while (renderer.getTextWidth(UI_10_FONT_ID, trimmedAuthor.c_str()) > maxLineWidth && !trimmedAuthor.empty()) {
|
||||
StringUtils::utf8RemoveLastChar(trimmedAuthor);
|
||||
utf8RemoveLastChar(trimmedAuthor);
|
||||
}
|
||||
if (renderer.getTextWidth(UI_10_FONT_ID, trimmedAuthor.c_str()) <
|
||||
renderer.getTextWidth(UI_10_FONT_ID, lastBookAuthor.c_str())) {
|
||||
@ -462,14 +466,14 @@ void HomeActivity::render() {
|
||||
// Trim author if too long (UTF-8 safe)
|
||||
bool wasTrimmed = false;
|
||||
while (renderer.getTextWidth(UI_10_FONT_ID, trimmedAuthor.c_str()) > maxLineWidth && !trimmedAuthor.empty()) {
|
||||
StringUtils::utf8RemoveLastChar(trimmedAuthor);
|
||||
utf8RemoveLastChar(trimmedAuthor);
|
||||
wasTrimmed = true;
|
||||
}
|
||||
if (wasTrimmed && !trimmedAuthor.empty()) {
|
||||
// Make room for ellipsis
|
||||
while (renderer.getTextWidth(UI_10_FONT_ID, (trimmedAuthor + "...").c_str()) > maxLineWidth &&
|
||||
!trimmedAuthor.empty()) {
|
||||
StringUtils::utf8RemoveLastChar(trimmedAuthor);
|
||||
utf8RemoveLastChar(trimmedAuthor);
|
||||
}
|
||||
trimmedAuthor.append("...");
|
||||
}
|
||||
@ -503,7 +507,7 @@ void HomeActivity::render() {
|
||||
|
||||
// --- Bottom menu tiles ---
|
||||
// Build menu items dynamically
|
||||
std::vector<const char*> menuItems = {"My Library", "File Transfer", "Settings"};
|
||||
std::vector<const char*> menuItems = {"My Library", "Applications", "File Transfer", "Settings"};
|
||||
if (hasOpdsUrl) {
|
||||
// Insert OPDS Browser after My Library
|
||||
menuItems.insert(menuItems.begin() + 1, "OPDS Browser");
|
||||
|
||||
@ -26,6 +26,7 @@ class HomeActivity final : public Activity {
|
||||
const std::function<void()> onSettingsOpen;
|
||||
const std::function<void()> onFileTransferOpen;
|
||||
const std::function<void()> onOpdsBrowserOpen;
|
||||
const std::function<void()> onAppsOpen;
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
[[noreturn]] void displayTaskLoop();
|
||||
@ -39,13 +40,14 @@ class HomeActivity final : public Activity {
|
||||
explicit HomeActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||
const std::function<void()>& onContinueReading, const std::function<void()>& onMyLibraryOpen,
|
||||
const std::function<void()>& onSettingsOpen, const std::function<void()>& onFileTransferOpen,
|
||||
const std::function<void()>& onOpdsBrowserOpen)
|
||||
const std::function<void()>& onOpdsBrowserOpen, const std::function<void()>& onAppsOpen)
|
||||
: Activity("Home", renderer, mappedInput),
|
||||
onContinueReading(onContinueReading),
|
||||
onMyLibraryOpen(onMyLibraryOpen),
|
||||
onSettingsOpen(onSettingsOpen),
|
||||
onFileTransferOpen(onFileTransferOpen),
|
||||
onOpdsBrowserOpen(onOpdsBrowserOpen) {}
|
||||
onOpdsBrowserOpen(onOpdsBrowserOpen),
|
||||
onAppsOpen(onAppsOpen) {}
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void loop() override;
|
||||
|
||||
@ -570,8 +570,8 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in
|
||||
availableTitleSpace = rendererableScreenWidth - titleMarginLeft - titleMarginRight;
|
||||
titleMarginLeftAdjusted = titleMarginLeft;
|
||||
}
|
||||
while (titleWidth > availableTitleSpace && title.length() > 11) {
|
||||
title.replace(title.length() - 8, 8, "...");
|
||||
if (titleWidth > availableTitleSpace) {
|
||||
title = renderer.truncatedText(SMALL_FONT_ID, title.c_str(), availableTitleSpace);
|
||||
titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,8 +533,8 @@ void TxtReaderActivity::renderStatusBar(const int orientedMarginRight, const int
|
||||
|
||||
std::string title = txt->getTitle();
|
||||
int titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str());
|
||||
while (titleWidth > availableTextWidth && title.length() > 11) {
|
||||
title.replace(title.length() - 8, 8, "...");
|
||||
if (titleWidth > availableTextWidth) {
|
||||
title = renderer.truncatedText(SMALL_FONT_ID, title.c_str(), availableTextWidth);
|
||||
titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str());
|
||||
}
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#include "KOReaderCredentialStore.h"
|
||||
#include "MappedInputManager.h"
|
||||
#include "RecentBooksStore.h"
|
||||
#include "activities/app/AppActivity.h"
|
||||
#include "activities/boot_sleep/BootActivity.h"
|
||||
#include "activities/boot_sleep/SleepActivity.h"
|
||||
#include "activities/browser/OpdsBookBrowserActivity.h"
|
||||
@ -236,10 +237,15 @@ void onGoToBrowser() {
|
||||
enterNewActivity(new OpdsBookBrowserActivity(renderer, mappedInputManager, onGoHome));
|
||||
}
|
||||
|
||||
void onGoToApps() {
|
||||
exitActivity();
|
||||
enterNewActivity(new AppActivity(renderer, mappedInputManager, onGoHome));
|
||||
}
|
||||
|
||||
void onGoHome() {
|
||||
exitActivity();
|
||||
enterNewActivity(new HomeActivity(renderer, mappedInputManager, onContinueReading, onGoToMyLibrary, onGoToSettings,
|
||||
onGoToFileTransfer, onGoToBrowser));
|
||||
onGoToFileTransfer, onGoToBrowser, onGoToApps));
|
||||
}
|
||||
|
||||
void setupDisplayAndFonts() {
|
||||
|
||||
@ -61,23 +61,4 @@ bool checkFileExtension(const String& fileName, const char* extension) {
|
||||
return localFile.endsWith(localExtension);
|
||||
}
|
||||
|
||||
size_t utf8RemoveLastChar(std::string& str) {
|
||||
if (str.empty()) return 0;
|
||||
size_t pos = str.size() - 1;
|
||||
// Walk back to find the start of the last UTF-8 character
|
||||
// UTF-8 continuation bytes start with 10xxxxxx (0x80-0xBF)
|
||||
while (pos > 0 && (static_cast<unsigned char>(str[pos]) & 0xC0) == 0x80) {
|
||||
--pos;
|
||||
}
|
||||
str.resize(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Truncate string by removing N UTF-8 characters from the end
|
||||
void utf8TruncateChars(std::string& str, const size_t numChars) {
|
||||
for (size_t i = 0; i < numChars && !str.empty(); ++i) {
|
||||
utf8RemoveLastChar(str);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace StringUtils
|
||||
|
||||
@ -19,10 +19,4 @@ std::string sanitizeFilename(const std::string& name, size_t maxLength = 100);
|
||||
bool checkFileExtension(const std::string& fileName, const char* extension);
|
||||
bool checkFileExtension(const String& fileName, const char* extension);
|
||||
|
||||
// UTF-8 safe string truncation - removes one character from the end
|
||||
// Returns the new size after removing one UTF-8 character
|
||||
size_t utf8RemoveLastChar(std::string& str);
|
||||
|
||||
// Truncate string by removing N UTF-8 characters from the end
|
||||
void utf8TruncateChars(std::string& str, size_t numChars);
|
||||
} // namespace StringUtils
|
||||
|
||||
Loading…
Reference in New Issue
Block a user