feat: add async/await keywords, Num/String extensions, and Jinja markdown example
Add `async` and `await` token support to the Wren compiler with scheduler resolution logic, extend `Num` with `e` constant, hyperbolic trig, base conversion, and new methods (`isZero`, `gcd`, `lcm`, `digits`, etc.), extend `String` with `lower`, `upper`, `capitalize`, `title`, and regenerate `wren_core.wren.inc`. Include `Makefile` for multi-platform builds, rewrite `README.md` with updated build instructions, and add `example/await_demo.wren` and `example/jinja_markdown.wren` demonstrating new features.
This commit is contained in:
Vendored
+61
@@ -108,6 +108,8 @@ typedef enum
|
||||
TOKEN_TRUE,
|
||||
TOKEN_VAR,
|
||||
TOKEN_WHILE,
|
||||
TOKEN_ASYNC,
|
||||
TOKEN_AWAIT,
|
||||
|
||||
TOKEN_FIELD,
|
||||
TOKEN_STATIC_FIELD,
|
||||
@@ -619,6 +621,8 @@ static Keyword keywords[] =
|
||||
{"true", 4, TOKEN_TRUE},
|
||||
{"var", 3, TOKEN_VAR},
|
||||
{"while", 5, TOKEN_WHILE},
|
||||
{"async", 5, TOKEN_ASYNC},
|
||||
{"await", 5, TOKEN_AWAIT},
|
||||
{NULL, 0, TOKEN_EOF} // Sentinel to mark the end of the array.
|
||||
};
|
||||
|
||||
@@ -1746,6 +1750,8 @@ static void expression(Compiler* compiler);
|
||||
static void statement(Compiler* compiler);
|
||||
static void definition(Compiler* compiler);
|
||||
static void parsePrecedence(Compiler* compiler, Precedence precedence);
|
||||
static void async_(Compiler* compiler, bool canAssign);
|
||||
static void await_(Compiler* compiler, bool canAssign);
|
||||
|
||||
// Replaces the placeholder argument for a previous CODE_JUMP or CODE_JUMP_IF
|
||||
// instruction with an offset that jumps to the current end of bytecode.
|
||||
@@ -2499,6 +2505,59 @@ static void this_(Compiler* compiler, bool canAssign)
|
||||
loadThis(compiler);
|
||||
}
|
||||
|
||||
static int resolveScheduler(Compiler* compiler)
|
||||
{
|
||||
int symbol = wrenSymbolTableFind(
|
||||
&compiler->parser->module->variableNames,
|
||||
"Scheduler", 9);
|
||||
|
||||
if (symbol == -1)
|
||||
{
|
||||
symbol = wrenDeclareVariable(compiler->parser->vm,
|
||||
compiler->parser->module,
|
||||
"Scheduler", 9,
|
||||
compiler->parser->previous.line);
|
||||
if (symbol == -2)
|
||||
{
|
||||
error(compiler, "Too many module variables defined.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
static void await_(Compiler* compiler, bool canAssign)
|
||||
{
|
||||
int schedulerSymbol = resolveScheduler(compiler);
|
||||
if (schedulerSymbol == -1) return;
|
||||
|
||||
emitShortArg(compiler, CODE_LOAD_MODULE_VAR, schedulerSymbol);
|
||||
|
||||
ignoreNewlines(compiler);
|
||||
expression(compiler);
|
||||
|
||||
callMethod(compiler, 1, "await_(_)", 9);
|
||||
}
|
||||
|
||||
static void async_(Compiler* compiler, bool canAssign)
|
||||
{
|
||||
int schedulerSymbol = resolveScheduler(compiler);
|
||||
if (schedulerSymbol == -1) return;
|
||||
|
||||
emitShortArg(compiler, CODE_LOAD_MODULE_VAR, schedulerSymbol);
|
||||
|
||||
consume(compiler, TOKEN_LEFT_BRACE, "Expect '{' after 'async'.");
|
||||
|
||||
Compiler fnCompiler;
|
||||
initCompiler(&fnCompiler, compiler->parser, compiler, false);
|
||||
fnCompiler.fn->arity = 0;
|
||||
|
||||
finishBody(&fnCompiler);
|
||||
endCompiler(&fnCompiler, "[async]", 7);
|
||||
|
||||
callMethod(compiler, 1, "async_(_)", 9);
|
||||
}
|
||||
|
||||
// Subscript or "array indexing" operator like `foo[bar]`.
|
||||
static void subscript(Compiler* compiler, bool canAssign)
|
||||
{
|
||||
@@ -2799,6 +2858,8 @@ GrammarRule rules[] =
|
||||
/* TOKEN_TRUE */ PREFIX(boolean),
|
||||
/* TOKEN_VAR */ UNUSED,
|
||||
/* TOKEN_WHILE */ UNUSED,
|
||||
/* TOKEN_ASYNC */ PREFIX(async_),
|
||||
/* TOKEN_AWAIT */ PREFIX(await_),
|
||||
/* TOKEN_FIELD */ PREFIX(field),
|
||||
/* TOKEN_STATIC_FIELD */ PREFIX(staticField),
|
||||
/* TOKEN_NAME */ { name, NULL, namedSignature, PREC_NONE, NULL },
|
||||
|
||||
Vendored
+148
@@ -2,6 +2,7 @@
|
||||
#include <errno.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
@@ -647,6 +648,7 @@ DEF_NUM_CONSTANT(smallest, DBL_MIN)
|
||||
|
||||
DEF_NUM_CONSTANT(maxSafeInteger, 9007199254740991.0)
|
||||
DEF_NUM_CONSTANT(minSafeInteger, -9007199254740991.0)
|
||||
DEF_NUM_CONSTANT(e, 2.71828182845904523536)
|
||||
|
||||
// Defines a primitive on Num that calls infix [op] and returns [type].
|
||||
#define DEF_NUM_INFIX(name, op, type) \
|
||||
@@ -704,6 +706,10 @@ DEF_NUM_FN(tan, tan)
|
||||
DEF_NUM_FN(log, log)
|
||||
DEF_NUM_FN(log2, log2)
|
||||
DEF_NUM_FN(exp, exp)
|
||||
DEF_NUM_FN(log10, log10)
|
||||
DEF_NUM_FN(sinh, sinh)
|
||||
DEF_NUM_FN(cosh, cosh)
|
||||
DEF_NUM_FN(tanh, tanh)
|
||||
|
||||
DEF_PRIMITIVE(num_mod)
|
||||
{
|
||||
@@ -843,6 +849,65 @@ DEF_PRIMITIVE(num_truncate)
|
||||
RETURN_NUM(integer);
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(num_toBase)
|
||||
{
|
||||
if (!validateInt(vm, args[1], "Radix")) return false;
|
||||
int radix = (int)AS_NUM(args[1]);
|
||||
if (radix < 2 || radix > 36)
|
||||
{
|
||||
RETURN_ERROR("Radix must be between 2 and 36.");
|
||||
}
|
||||
double raw = AS_NUM(args[0]);
|
||||
if (isnan(raw) || isinf(raw))
|
||||
{
|
||||
RETURN_ERROR("Cannot convert NaN or Infinity to a base string.");
|
||||
}
|
||||
int64_t value = (int64_t)trunc(raw);
|
||||
bool negative = value < 0;
|
||||
if (negative) value = -value;
|
||||
static const char lookup[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
char buf[66];
|
||||
int len = 0;
|
||||
if (value == 0)
|
||||
{
|
||||
buf[len++] = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
while (value > 0)
|
||||
{
|
||||
buf[len++] = lookup[value % radix];
|
||||
value = value / radix;
|
||||
}
|
||||
}
|
||||
if (negative) buf[len++] = '-';
|
||||
for (int i = 0; i < len / 2; i++)
|
||||
{
|
||||
char tmp = buf[i];
|
||||
buf[i] = buf[len - 1 - i];
|
||||
buf[len - 1 - i] = tmp;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
RETURN_VAL(wrenNewStringLength(vm, buf, len));
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(num_format)
|
||||
{
|
||||
if (!validateInt(vm, args[1], "Decimal places")) return false;
|
||||
int decimals = (int)AS_NUM(args[1]);
|
||||
if (decimals < 0 || decimals > 20)
|
||||
{
|
||||
RETURN_ERROR("Decimal places must be between 0 and 20.");
|
||||
}
|
||||
char buf[64];
|
||||
int len = snprintf(buf, sizeof(buf), "%.*f", decimals, AS_NUM(args[0]));
|
||||
if (len < 0 || len >= (int)sizeof(buf))
|
||||
{
|
||||
RETURN_ERROR("Formatting failed.");
|
||||
}
|
||||
RETURN_VAL(wrenNewStringLength(vm, buf, (size_t)len));
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(object_same)
|
||||
{
|
||||
RETURN_BOOL(wrenValuesEqual(args[1], args[2]));
|
||||
@@ -1167,6 +1232,46 @@ DEF_PRIMITIVE(string_plus)
|
||||
RETURN_VAL(wrenStringFormat(vm, "@@", args[0], args[1]));
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(string_lt)
|
||||
{
|
||||
if (!validateString(vm, args[1], "Right operand")) return false;
|
||||
ObjString* left = AS_STRING(args[0]);
|
||||
ObjString* right = AS_STRING(args[1]);
|
||||
uint32_t minLen = left->length < right->length ? left->length : right->length;
|
||||
int cmp = memcmp(left->value, right->value, minLen);
|
||||
RETURN_BOOL(cmp < 0 || (cmp == 0 && left->length < right->length));
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(string_gt)
|
||||
{
|
||||
if (!validateString(vm, args[1], "Right operand")) return false;
|
||||
ObjString* left = AS_STRING(args[0]);
|
||||
ObjString* right = AS_STRING(args[1]);
|
||||
uint32_t minLen = left->length < right->length ? left->length : right->length;
|
||||
int cmp = memcmp(left->value, right->value, minLen);
|
||||
RETURN_BOOL(cmp > 0 || (cmp == 0 && left->length > right->length));
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(string_lte)
|
||||
{
|
||||
if (!validateString(vm, args[1], "Right operand")) return false;
|
||||
ObjString* left = AS_STRING(args[0]);
|
||||
ObjString* right = AS_STRING(args[1]);
|
||||
uint32_t minLen = left->length < right->length ? left->length : right->length;
|
||||
int cmp = memcmp(left->value, right->value, minLen);
|
||||
RETURN_BOOL(cmp < 0 || (cmp == 0 && left->length <= right->length));
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(string_gte)
|
||||
{
|
||||
if (!validateString(vm, args[1], "Right operand")) return false;
|
||||
ObjString* left = AS_STRING(args[0]);
|
||||
ObjString* right = AS_STRING(args[1]);
|
||||
uint32_t minLen = left->length < right->length ? left->length : right->length;
|
||||
int cmp = memcmp(left->value, right->value, minLen);
|
||||
RETURN_BOOL(cmp > 0 || (cmp == 0 && left->length >= right->length));
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(string_subscript)
|
||||
{
|
||||
ObjString* string = AS_STRING(args[0]);
|
||||
@@ -1197,6 +1302,36 @@ DEF_PRIMITIVE(string_toString)
|
||||
RETURN_VAL(args[0]);
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(string_lower)
|
||||
{
|
||||
ObjString* str = AS_STRING(args[0]);
|
||||
char* buf = ALLOCATE_ARRAY(vm, char, str->length + 1);
|
||||
for (uint32_t i = 0; i < str->length; i++)
|
||||
{
|
||||
uint8_t c = (uint8_t)str->value[i];
|
||||
buf[i] = (c >= 'A' && c <= 'Z') ? (char)(c + 32) : (char)c;
|
||||
}
|
||||
buf[str->length] = '\0';
|
||||
Value result = wrenNewStringLength(vm, buf, str->length);
|
||||
DEALLOCATE(vm, buf);
|
||||
RETURN_VAL(result);
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(string_upper)
|
||||
{
|
||||
ObjString* str = AS_STRING(args[0]);
|
||||
char* buf = ALLOCATE_ARRAY(vm, char, str->length + 1);
|
||||
for (uint32_t i = 0; i < str->length; i++)
|
||||
{
|
||||
uint8_t c = (uint8_t)str->value[i];
|
||||
buf[i] = (c >= 'a' && c <= 'z') ? (char)(c - 32) : (char)c;
|
||||
}
|
||||
buf[str->length] = '\0';
|
||||
Value result = wrenNewStringLength(vm, buf, str->length);
|
||||
DEALLOCATE(vm, buf);
|
||||
RETURN_VAL(result);
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(system_clock)
|
||||
{
|
||||
RETURN_NUM((double)clock() / CLOCKS_PER_SEC);
|
||||
@@ -1358,6 +1493,7 @@ void wrenInitializeCore(WrenVM* vm)
|
||||
PRIMITIVE(vm->numClass->obj.classObj, "smallest", num_smallest);
|
||||
PRIMITIVE(vm->numClass->obj.classObj, "maxSafeInteger", num_maxSafeInteger);
|
||||
PRIMITIVE(vm->numClass->obj.classObj, "minSafeInteger", num_minSafeInteger);
|
||||
PRIMITIVE(vm->numClass->obj.classObj, "e", num_e);
|
||||
PRIMITIVE(vm->numClass, "-(_)", num_minus);
|
||||
PRIMITIVE(vm->numClass, "+(_)", num_plus);
|
||||
PRIMITIVE(vm->numClass, "*(_)", num_multiply);
|
||||
@@ -1403,6 +1539,12 @@ void wrenInitializeCore(WrenVM* vm)
|
||||
PRIMITIVE(vm->numClass, "sign", num_sign);
|
||||
PRIMITIVE(vm->numClass, "toString", num_toString);
|
||||
PRIMITIVE(vm->numClass, "truncate", num_truncate);
|
||||
PRIMITIVE(vm->numClass, "log10", num_log10);
|
||||
PRIMITIVE(vm->numClass, "sinh", num_sinh);
|
||||
PRIMITIVE(vm->numClass, "cosh", num_cosh);
|
||||
PRIMITIVE(vm->numClass, "tanh", num_tanh);
|
||||
PRIMITIVE(vm->numClass, "toBase(_)", num_toBase);
|
||||
PRIMITIVE(vm->numClass, "format(_)", num_format);
|
||||
|
||||
// These are defined just so that 0 and -0 are equal, which is specified by
|
||||
// IEEE 754 even though they have different bit representations.
|
||||
@@ -1413,6 +1555,10 @@ void wrenInitializeCore(WrenVM* vm)
|
||||
PRIMITIVE(vm->stringClass->obj.classObj, "fromCodePoint(_)", string_fromCodePoint);
|
||||
PRIMITIVE(vm->stringClass->obj.classObj, "fromByte(_)", string_fromByte);
|
||||
PRIMITIVE(vm->stringClass, "+(_)", string_plus);
|
||||
PRIMITIVE(vm->stringClass, "<(_)", string_lt);
|
||||
PRIMITIVE(vm->stringClass, ">(_)", string_gt);
|
||||
PRIMITIVE(vm->stringClass, "<=(_)", string_lte);
|
||||
PRIMITIVE(vm->stringClass, ">=(_)", string_gte);
|
||||
PRIMITIVE(vm->stringClass, "[_]", string_subscript);
|
||||
PRIMITIVE(vm->stringClass, "byteAt_(_)", string_byteAt);
|
||||
PRIMITIVE(vm->stringClass, "byteCount_", string_byteCount);
|
||||
@@ -1426,6 +1572,8 @@ void wrenInitializeCore(WrenVM* vm)
|
||||
PRIMITIVE(vm->stringClass, "iteratorValue(_)", string_iteratorValue);
|
||||
PRIMITIVE(vm->stringClass, "startsWith(_)", string_startsWith);
|
||||
PRIMITIVE(vm->stringClass, "toString", string_toString);
|
||||
PRIMITIVE(vm->stringClass, "lower_", string_lower);
|
||||
PRIMITIVE(vm->stringClass, "upper_", string_upper);
|
||||
|
||||
vm->listClass = AS_CLASS(wrenFindVariable(vm, coreModule, "List"));
|
||||
PRIMITIVE(vm->listClass->obj.classObj, "filled(_,_)", list_filled);
|
||||
|
||||
Vendored
+281
-2
@@ -2,7 +2,62 @@ class Bool {}
|
||||
class Fiber {}
|
||||
class Fn {}
|
||||
class Null {}
|
||||
class Num {}
|
||||
class Num {
|
||||
isZero { this == 0 }
|
||||
isPositive { this > 0 }
|
||||
isNegative { this < 0 }
|
||||
isFinite { !isInfinity && !isNan }
|
||||
isEven { isInteger && this % 2 == 0 }
|
||||
isOdd { isInteger && this % 2 != 0 }
|
||||
|
||||
isBetween(min, max) { this >= min && this <= max }
|
||||
|
||||
toDegrees { this * 180 / Num.pi }
|
||||
toRadians { this * Num.pi / 180 }
|
||||
|
||||
toChar { String.fromCodePoint(this) }
|
||||
toHex { toBase(16) }
|
||||
toBinary { toBase(2) }
|
||||
toOctal { toBase(8) }
|
||||
|
||||
gcd(other) {
|
||||
var a = this.abs
|
||||
var b = other.abs
|
||||
while (b != 0) {
|
||||
var t = b
|
||||
b = a % b
|
||||
a = t
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
lcm(other) {
|
||||
if (this == 0 && other == 0) return 0
|
||||
return (this * other).abs / gcd(other)
|
||||
}
|
||||
|
||||
digits {
|
||||
if (!isInteger) Fiber.abort("Value must be an integer.")
|
||||
var n = this.abs
|
||||
if (n == 0) {
|
||||
var z = List.new()
|
||||
z.add(0)
|
||||
return z
|
||||
}
|
||||
var result = List.new()
|
||||
while (n > 0) {
|
||||
result.add(n % 10)
|
||||
n = (n / 10).floor
|
||||
}
|
||||
var reversed = List.new()
|
||||
var i = result.count - 1
|
||||
while (i >= 0) {
|
||||
reversed.add(result[i])
|
||||
i = i - 1
|
||||
}
|
||||
return reversed
|
||||
}
|
||||
}
|
||||
|
||||
class Sequence {
|
||||
all(f) {
|
||||
@@ -289,6 +344,230 @@ class String is Sequence {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
lower { lower_ }
|
||||
upper { upper_ }
|
||||
|
||||
capitalize {
|
||||
if (isEmpty) return this
|
||||
return this[0].upper + this[1..-1].lower
|
||||
}
|
||||
|
||||
title {
|
||||
if (isEmpty) return this
|
||||
var result = ""
|
||||
var capitalizeNext = true
|
||||
for (c in this) {
|
||||
if (c == " " || c == "\t" || c == "\n" || c == "\r") {
|
||||
result = result + c
|
||||
capitalizeNext = true
|
||||
} else if (capitalizeNext) {
|
||||
result = result + c.upper
|
||||
capitalizeNext = false
|
||||
} else {
|
||||
result = result + c.lower
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
swapCase {
|
||||
var result = ""
|
||||
for (c in this) {
|
||||
var cp = c.codePoints.toList[0]
|
||||
if (cp >= 65 && cp <= 90) {
|
||||
result = result + c.lower
|
||||
} else if (cp >= 97 && cp <= 122) {
|
||||
result = result + c.upper
|
||||
} else {
|
||||
result = result + c
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
lastIndexOf(search) {
|
||||
var last = -1
|
||||
var index = 0
|
||||
var size = byteCount_
|
||||
var searchSize = search.byteCount_
|
||||
if (searchSize > size) return -1
|
||||
while (index <= size - searchSize) {
|
||||
var found = indexOf(search, index)
|
||||
if (found == -1) break
|
||||
last = found
|
||||
index = found + 1
|
||||
}
|
||||
return last
|
||||
}
|
||||
|
||||
lastIndexOf(search, start) {
|
||||
var last = -1
|
||||
var index = 0
|
||||
var searchSize = search.byteCount_
|
||||
if (searchSize > start + searchSize) return -1
|
||||
while (index <= start) {
|
||||
var found = indexOf(search, index)
|
||||
if (found == -1 || found > start) break
|
||||
last = found
|
||||
index = found + 1
|
||||
}
|
||||
return last
|
||||
}
|
||||
|
||||
isLower {
|
||||
if (isEmpty) return false
|
||||
var hasAlpha = false
|
||||
for (b in bytes) {
|
||||
if (b >= 65 && b <= 90) return false
|
||||
if (b >= 97 && b <= 122) hasAlpha = true
|
||||
}
|
||||
return hasAlpha
|
||||
}
|
||||
|
||||
isUpper {
|
||||
if (isEmpty) return false
|
||||
var hasAlpha = false
|
||||
for (b in bytes) {
|
||||
if (b >= 97 && b <= 122) return false
|
||||
if (b >= 65 && b <= 90) hasAlpha = true
|
||||
}
|
||||
return hasAlpha
|
||||
}
|
||||
|
||||
isDigit {
|
||||
if (isEmpty) return false
|
||||
for (b in bytes) {
|
||||
if (b < 48 || b > 57) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
isAlpha {
|
||||
if (isEmpty) return false
|
||||
for (b in bytes) {
|
||||
if (!((b >= 65 && b <= 90) || (b >= 97 && b <= 122))) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
isAlphaNumeric {
|
||||
if (isEmpty) return false
|
||||
for (b in bytes) {
|
||||
if (!((b >= 65 && b <= 90) || (b >= 97 && b <= 122) || (b >= 48 && b <= 57))) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
isSpace {
|
||||
if (isEmpty) return false
|
||||
for (b in bytes) {
|
||||
if (b != 32 && b != 9 && b != 10 && b != 13 && b != 12 && b != 11) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
isAscii {
|
||||
for (b in bytes) {
|
||||
if (b >= 128) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
reverse {
|
||||
var list = []
|
||||
for (c in this) {
|
||||
list.insert(0, c)
|
||||
}
|
||||
return list.join("")
|
||||
}
|
||||
|
||||
center(width) { center(width, " ") }
|
||||
|
||||
center(width, char) {
|
||||
if (!(width is Num) || !width.isInteger) {
|
||||
Fiber.abort("Width must be an integer.")
|
||||
}
|
||||
if (!(char is String) || char.isEmpty) {
|
||||
Fiber.abort("Fill character must be a non-empty string.")
|
||||
}
|
||||
var len = count
|
||||
if (len >= width) return this
|
||||
var total = width - len
|
||||
var left = (total / 2).floor
|
||||
var right = total - left
|
||||
return (char * (left + 1))[0...left] + this + (char * (right + 1))[0...right]
|
||||
}
|
||||
|
||||
lpad(width, char) {
|
||||
if (!(width is Num) || !width.isInteger) {
|
||||
Fiber.abort("Width must be an integer.")
|
||||
}
|
||||
if (!(char is String) || char.isEmpty) {
|
||||
Fiber.abort("Fill character must be a non-empty string.")
|
||||
}
|
||||
var len = count
|
||||
if (len >= width) return this
|
||||
var pad = width - len
|
||||
return (char * (pad + 1))[0...pad] + this
|
||||
}
|
||||
|
||||
rpad(width, char) {
|
||||
if (!(width is Num) || !width.isInteger) {
|
||||
Fiber.abort("Width must be an integer.")
|
||||
}
|
||||
if (!(char is String) || char.isEmpty) {
|
||||
Fiber.abort("Fill character must be a non-empty string.")
|
||||
}
|
||||
var len = count
|
||||
if (len >= width) return this
|
||||
var pad = width - len
|
||||
return this + (char * (pad + 1))[0...pad]
|
||||
}
|
||||
|
||||
zfill(width) {
|
||||
if (!(width is Num) || !width.isInteger) {
|
||||
Fiber.abort("Width must be an integer.")
|
||||
}
|
||||
var len = count
|
||||
if (len >= width) return this
|
||||
if (startsWith("-") || startsWith("+")) {
|
||||
return this[0] + ("0" * (width - len)) + this[1..-1]
|
||||
}
|
||||
return ("0" * (width - len)) + this
|
||||
}
|
||||
|
||||
removePrefix(prefix) {
|
||||
if (!(prefix is String)) {
|
||||
Fiber.abort("Prefix must be a string.")
|
||||
}
|
||||
if (startsWith(prefix)) return this[prefix.byteCount_..-1]
|
||||
return this
|
||||
}
|
||||
|
||||
removeSuffix(suffix) {
|
||||
if (!(suffix is String)) {
|
||||
Fiber.abort("Suffix must be a string.")
|
||||
}
|
||||
if (endsWith(suffix)) {
|
||||
var end = byteCount_ - suffix.byteCount_ - 1
|
||||
if (end < 0) return ""
|
||||
return this[0..end]
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
splitLines { replace("\r\n", "\n").replace("\r", "\n").split("\n") }
|
||||
|
||||
chars {
|
||||
var result = []
|
||||
for (c in this) {
|
||||
result.add(c)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
toNum { Num.fromString(this) }
|
||||
}
|
||||
|
||||
class StringByteSequence is Sequence {
|
||||
@@ -480,4 +759,4 @@ class ClassAttributes {
|
||||
_methods = methods
|
||||
}
|
||||
toString { "attributes:%(_attributes) methods:%(_methods)" }
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+289
-9
@@ -1,10 +1,67 @@
|
||||
// Generated automatically from src/vm/wren_core.wren. Do not edit.
|
||||
// Please do not edit this file. It has been generated automatically
|
||||
// from `deps/wren/src/vm/wren_core.wren` using `util/wren_to_c_string.py`
|
||||
|
||||
static const char* coreModuleSource =
|
||||
"class Bool {}\n"
|
||||
"class Fiber {}\n"
|
||||
"class Fn {}\n"
|
||||
"class Null {}\n"
|
||||
"class Num {}\n"
|
||||
"class Num {\n"
|
||||
" isZero { this == 0 }\n"
|
||||
" isPositive { this > 0 }\n"
|
||||
" isNegative { this < 0 }\n"
|
||||
" isFinite { !isInfinity && !isNan }\n"
|
||||
" isEven { isInteger && this % 2 == 0 }\n"
|
||||
" isOdd { isInteger && this % 2 != 0 }\n"
|
||||
"\n"
|
||||
" isBetween(min, max) { this >= min && this <= max }\n"
|
||||
"\n"
|
||||
" toDegrees { this * 180 / Num.pi }\n"
|
||||
" toRadians { this * Num.pi / 180 }\n"
|
||||
"\n"
|
||||
" toChar { String.fromCodePoint(this) }\n"
|
||||
" toHex { toBase(16) }\n"
|
||||
" toBinary { toBase(2) }\n"
|
||||
" toOctal { toBase(8) }\n"
|
||||
"\n"
|
||||
" gcd(other) {\n"
|
||||
" var a = this.abs\n"
|
||||
" var b = other.abs\n"
|
||||
" while (b != 0) {\n"
|
||||
" var t = b\n"
|
||||
" b = a % b\n"
|
||||
" a = t\n"
|
||||
" }\n"
|
||||
" return a\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" lcm(other) {\n"
|
||||
" if (this == 0 && other == 0) return 0\n"
|
||||
" return (this * other).abs / gcd(other)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" digits {\n"
|
||||
" if (!isInteger) Fiber.abort(\"Value must be an integer.\")\n"
|
||||
" var n = this.abs\n"
|
||||
" if (n == 0) {\n"
|
||||
" var z = List.new()\n"
|
||||
" z.add(0)\n"
|
||||
" return z\n"
|
||||
" }\n"
|
||||
" var result = List.new()\n"
|
||||
" while (n > 0) {\n"
|
||||
" result.add(n % 10)\n"
|
||||
" n = (n / 10).floor\n"
|
||||
" }\n"
|
||||
" var reversed = List.new()\n"
|
||||
" var i = result.count - 1\n"
|
||||
" while (i >= 0) {\n"
|
||||
" reversed.add(result[i])\n"
|
||||
" i = i - 1\n"
|
||||
" }\n"
|
||||
" return reversed\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class Sequence {\n"
|
||||
" all(f) {\n"
|
||||
@@ -238,11 +295,11 @@ static const char* coreModuleSource =
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" trim() { trim_(\"\t\r\n \", true, true) }\n"
|
||||
" trim() { trim_(\"\\t\\r\\n \", true, true) }\n"
|
||||
" trim(chars) { trim_(chars, true, true) }\n"
|
||||
" trimEnd() { trim_(\"\t\r\n \", false, true) }\n"
|
||||
" trimEnd() { trim_(\"\\t\\r\\n \", false, true) }\n"
|
||||
" trimEnd(chars) { trim_(chars, false, true) }\n"
|
||||
" trimStart() { trim_(\"\t\r\n \", true, false) }\n"
|
||||
" trimStart() { trim_(\"\\t\\r\\n \", true, false) }\n"
|
||||
" trimStart(chars) { trim_(chars, true, false) }\n"
|
||||
"\n"
|
||||
" trim_(chars, trimStart, trimEnd) {\n"
|
||||
@@ -291,6 +348,230 @@ static const char* coreModuleSource =
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" lower { lower_ }\n"
|
||||
" upper { upper_ }\n"
|
||||
"\n"
|
||||
" capitalize {\n"
|
||||
" if (isEmpty) return this\n"
|
||||
" return this[0].upper + this[1..-1].lower\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" title {\n"
|
||||
" if (isEmpty) return this\n"
|
||||
" var result = \"\"\n"
|
||||
" var capitalizeNext = true\n"
|
||||
" for (c in this) {\n"
|
||||
" if (c == \" \" || c == \"\\t\" || c == \"\\n\" || c == \"\\r\") {\n"
|
||||
" result = result + c\n"
|
||||
" capitalizeNext = true\n"
|
||||
" } else if (capitalizeNext) {\n"
|
||||
" result = result + c.upper\n"
|
||||
" capitalizeNext = false\n"
|
||||
" } else {\n"
|
||||
" result = result + c.lower\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" swapCase {\n"
|
||||
" var result = \"\"\n"
|
||||
" for (c in this) {\n"
|
||||
" var cp = c.codePoints.toList[0]\n"
|
||||
" if (cp >= 65 && cp <= 90) {\n"
|
||||
" result = result + c.lower\n"
|
||||
" } else if (cp >= 97 && cp <= 122) {\n"
|
||||
" result = result + c.upper\n"
|
||||
" } else {\n"
|
||||
" result = result + c\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" lastIndexOf(search) {\n"
|
||||
" var last = -1\n"
|
||||
" var index = 0\n"
|
||||
" var size = byteCount_\n"
|
||||
" var searchSize = search.byteCount_\n"
|
||||
" if (searchSize > size) return -1\n"
|
||||
" while (index <= size - searchSize) {\n"
|
||||
" var found = indexOf(search, index)\n"
|
||||
" if (found == -1) break\n"
|
||||
" last = found\n"
|
||||
" index = found + 1\n"
|
||||
" }\n"
|
||||
" return last\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" lastIndexOf(search, start) {\n"
|
||||
" var last = -1\n"
|
||||
" var index = 0\n"
|
||||
" var searchSize = search.byteCount_\n"
|
||||
" if (searchSize > start + searchSize) return -1\n"
|
||||
" while (index <= start) {\n"
|
||||
" var found = indexOf(search, index)\n"
|
||||
" if (found == -1 || found > start) break\n"
|
||||
" last = found\n"
|
||||
" index = found + 1\n"
|
||||
" }\n"
|
||||
" return last\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" isLower {\n"
|
||||
" if (isEmpty) return false\n"
|
||||
" var hasAlpha = false\n"
|
||||
" for (b in bytes) {\n"
|
||||
" if (b >= 65 && b <= 90) return false\n"
|
||||
" if (b >= 97 && b <= 122) hasAlpha = true\n"
|
||||
" }\n"
|
||||
" return hasAlpha\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" isUpper {\n"
|
||||
" if (isEmpty) return false\n"
|
||||
" var hasAlpha = false\n"
|
||||
" for (b in bytes) {\n"
|
||||
" if (b >= 97 && b <= 122) return false\n"
|
||||
" if (b >= 65 && b <= 90) hasAlpha = true\n"
|
||||
" }\n"
|
||||
" return hasAlpha\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" isDigit {\n"
|
||||
" if (isEmpty) return false\n"
|
||||
" for (b in bytes) {\n"
|
||||
" if (b < 48 || b > 57) return false\n"
|
||||
" }\n"
|
||||
" return true\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" isAlpha {\n"
|
||||
" if (isEmpty) return false\n"
|
||||
" for (b in bytes) {\n"
|
||||
" if (!((b >= 65 && b <= 90) || (b >= 97 && b <= 122))) return false\n"
|
||||
" }\n"
|
||||
" return true\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" isAlphaNumeric {\n"
|
||||
" if (isEmpty) return false\n"
|
||||
" for (b in bytes) {\n"
|
||||
" if (!((b >= 65 && b <= 90) || (b >= 97 && b <= 122) || (b >= 48 && b <= 57))) return false\n"
|
||||
" }\n"
|
||||
" return true\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" isSpace {\n"
|
||||
" if (isEmpty) return false\n"
|
||||
" for (b in bytes) {\n"
|
||||
" if (b != 32 && b != 9 && b != 10 && b != 13 && b != 12 && b != 11) return false\n"
|
||||
" }\n"
|
||||
" return true\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" isAscii {\n"
|
||||
" for (b in bytes) {\n"
|
||||
" if (b >= 128) return false\n"
|
||||
" }\n"
|
||||
" return true\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" reverse {\n"
|
||||
" var list = []\n"
|
||||
" for (c in this) {\n"
|
||||
" list.insert(0, c)\n"
|
||||
" }\n"
|
||||
" return list.join(\"\")\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" center(width) { center(width, \" \") }\n"
|
||||
"\n"
|
||||
" center(width, char) {\n"
|
||||
" if (!(width is Num) || !width.isInteger) {\n"
|
||||
" Fiber.abort(\"Width must be an integer.\")\n"
|
||||
" }\n"
|
||||
" if (!(char is String) || char.isEmpty) {\n"
|
||||
" Fiber.abort(\"Fill character must be a non-empty string.\")\n"
|
||||
" }\n"
|
||||
" var len = count\n"
|
||||
" if (len >= width) return this\n"
|
||||
" var total = width - len\n"
|
||||
" var left = (total / 2).floor\n"
|
||||
" var right = total - left\n"
|
||||
" return (char * (left + 1))[0...left] + this + (char * (right + 1))[0...right]\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" lpad(width, char) {\n"
|
||||
" if (!(width is Num) || !width.isInteger) {\n"
|
||||
" Fiber.abort(\"Width must be an integer.\")\n"
|
||||
" }\n"
|
||||
" if (!(char is String) || char.isEmpty) {\n"
|
||||
" Fiber.abort(\"Fill character must be a non-empty string.\")\n"
|
||||
" }\n"
|
||||
" var len = count\n"
|
||||
" if (len >= width) return this\n"
|
||||
" var pad = width - len\n"
|
||||
" return (char * (pad + 1))[0...pad] + this\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" rpad(width, char) {\n"
|
||||
" if (!(width is Num) || !width.isInteger) {\n"
|
||||
" Fiber.abort(\"Width must be an integer.\")\n"
|
||||
" }\n"
|
||||
" if (!(char is String) || char.isEmpty) {\n"
|
||||
" Fiber.abort(\"Fill character must be a non-empty string.\")\n"
|
||||
" }\n"
|
||||
" var len = count\n"
|
||||
" if (len >= width) return this\n"
|
||||
" var pad = width - len\n"
|
||||
" return this + (char * (pad + 1))[0...pad]\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" zfill(width) {\n"
|
||||
" if (!(width is Num) || !width.isInteger) {\n"
|
||||
" Fiber.abort(\"Width must be an integer.\")\n"
|
||||
" }\n"
|
||||
" var len = count\n"
|
||||
" if (len >= width) return this\n"
|
||||
" if (startsWith(\"-\") || startsWith(\"+\")) {\n"
|
||||
" return this[0] + (\"0\" * (width - len)) + this[1..-1]\n"
|
||||
" }\n"
|
||||
" return (\"0\" * (width - len)) + this\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" removePrefix(prefix) {\n"
|
||||
" if (!(prefix is String)) {\n"
|
||||
" Fiber.abort(\"Prefix must be a string.\")\n"
|
||||
" }\n"
|
||||
" if (startsWith(prefix)) return this[prefix.byteCount_..-1]\n"
|
||||
" return this\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" removeSuffix(suffix) {\n"
|
||||
" if (!(suffix is String)) {\n"
|
||||
" Fiber.abort(\"Suffix must be a string.\")\n"
|
||||
" }\n"
|
||||
" if (endsWith(suffix)) {\n"
|
||||
" var end = byteCount_ - suffix.byteCount_ - 1\n"
|
||||
" if (end < 0) return \"\"\n"
|
||||
" return this[0..end]\n"
|
||||
" }\n"
|
||||
" return this\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" splitLines { replace(\"\\r\\n\", \"\\n\").replace(\"\\r\", \"\\n\").split(\"\\n\") }\n"
|
||||
"\n"
|
||||
" chars {\n"
|
||||
" var result = []\n"
|
||||
" for (c in this) {\n"
|
||||
" result.add(c)\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" toNum { Num.fromString(this) }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class StringByteSequence is Sequence {\n"
|
||||
@@ -441,18 +722,18 @@ static const char* coreModuleSource =
|
||||
"\n"
|
||||
"class System {\n"
|
||||
" static print() {\n"
|
||||
" writeString_(\"\n\")\n"
|
||||
" writeString_(\"\\n\")\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(obj) {\n"
|
||||
" writeObject_(obj)\n"
|
||||
" writeString_(\"\n\")\n"
|
||||
" writeString_(\"\\n\")\n"
|
||||
" return obj\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static printAll(sequence) {\n"
|
||||
" for (object in sequence) writeObject_(object)\n"
|
||||
" writeString_(\"\n\")\n"
|
||||
" writeString_(\"\\n\")\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static write(obj) {\n"
|
||||
@@ -483,4 +764,3 @@ static const char* coreModuleSource =
|
||||
" }\n"
|
||||
" toString { \"attributes:%(_attributes) methods:%(_methods)\" }\n"
|
||||
"}\n";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user