Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

+645
View File
@@ -0,0 +1,645 @@
module builtin
import strings
/// Internal representation of `array` type. It is used to implement slices and to make slices behave correctly
/// it simply stores reference to original array and to index them properly it does index array relative to `index_start`.
struct array_buffer {
arr JS.Array
index_start int
len int
cap int
has_slice bool
}
fn (mut a array_buffer) make_copy() {
if a.index_start != 0 || a.has_slice {
mut new_arr := JS.makeEmptyJSArray()
for i in 0 .. a.len {
#new_arr.push(a.val.get(i))
mut x := i
x = x
}
new_arr = new_arr
#a.val.arr = new_arr
#a.val.index_start = new int(0)
#a.val.has_slice = new bool(false)
}
}
#array_buffer.prototype.make_copy = function() { return array_buffer_make_copy(this) }
// TODO(playX): Should this be implemented fully in JS, use generics or just voidptr?
fn (a array_buffer) get(ix int) voidptr {
mut res := unsafe { nil }
#res = a.arr[a.index_start.val + ix.val];
return res
}
fn (mut a array_buffer) set(ix int, val voidptr) {
#a.val.arr[a.val.index_start.valueOf() + ix.valueOf()] = val;
}
#array_buffer.prototype.get = function(ix) { return array_buffer_get(this,ix);}
#array_buffer.prototype.set = function(ix,val) { array_buffer_set(this,ix,val); }
struct array {
pub mut:
arr array_buffer
len int
cap int
}
fn v_sort(mut arr array, comparator fn (voidptr, voidptr) int) {
mut need_iter := true
for need_iter {
need_iter = false
for i := 1; i < arr.len; i++ {
if comparator(arr[i], arr[i - 1]) != 1 {
tmp := arr[i]
arr[i] = arr[i - 1]
arr[i - 1] = tmp
need_iter = true
}
}
}
}
// trim trims the array length to "index" without modifying the allocated data. If "index" is greater than len nothing will be changed.
pub fn (mut a array) trim(index int) {
if index < a.len {
a.len = index
}
}
#function flatIntoArray(target, source, sourceLength, targetIndex, depth) {
#"use strict";
#
#for (var sourceIndex = 0; sourceIndex < sourceLength; ++sourceIndex) {
#if (sourceIndex in source) {
#var element = source[sourceIndex];
#if (depth > 0 && Array.isArray(element))
#targetIndex = flatIntoArray(target, element, element.length, targetIndex, depth - 1);
#else {
#target[targetIndex] = element;
#++targetIndex;
#}
#}
#}
#return targetIndex;
#}
#function flatArray(target,depth) {
#var array = target
#var length = array.length;
#var depthNum = 1;
#
#if (depth !== undefined)
#depthNum = +depth
#
#var result = []
#
#flatIntoArray(result, array, length, 0, depthNum);
#return result;
#}
@[unsafe]
pub fn (a array) repeat_to_depth(count int, depth int) array {
if count < 0 {
panic('array.repeat: count is negative: ${count}')
}
mut arr := empty_array()
if a.len > 0 {
for _ in 0 .. count {
for i in 0 .. a.len {
if depth > 0 {
// TODO
} else {
arr.push(a.arr.get(i))
}
}
}
}
return arr
}
// last returns the last element of the array.
pub fn (a array) last() voidptr {
mut res := unsafe { nil }
#res = a.arr.get(new int(a.len-1));
return res
}
fn (a array) get(ix int) voidptr {
if ix < 0 || ix >= a.len {
return unsafe { nil }
}
mut result := unsafe { nil }
#result = a.arr.get(ix)
return result
}
pub fn (a array) repeat(count int) array {
unsafe {
return a.repeat_to_depth(count, 0)
}
}
#function makeEmptyArray() { return new array(new array_buffer({ arr: [], len: new int(0), index_start: new int(0), cap: new int(0) })); }
#function makeEmptyJSArray() { return new Array(); }
fn JS.makeEmptyArray() array
fn JS.makeEmptyJSArray() JS.Array
fn empty_array() array {
return JS.makeEmptyArray()
}
#function v_clone_for_array_value(value) {
#if (value instanceof $ref || value instanceof voidptr || typeof value === 'function') return value;
#return v_clone_value(value);
#}
fn (a &array) set_len(i int) {
#a.arr.arr.length=i
}
pub fn (mut a array) sort_with_compare(compare voidptr) {
#v_sort(a, compare instanceof voidptr ? compare.val : compare)
}
pub fn (mut a array) sort_with_compare_old(compare voidptr) {
#a.val.arr.arr.sort(compare instanceof voidptr ? compare.val : compare)
}
pub fn (mut a array) sort() {
#a.val.arr.arr.sort($sortComparator)
}
pub fn (a array) index(v string) int {
for i in 0 .. a.len {
#if (a.arr.get(i).toString() == v.toString())
{
return i
}
}
return -1
}
pub fn (a array) last_index(v string) int {
for i := a.len - 1; i >= 0; i-- {
#if (a.arr.get(i).toString() == v.toString())
{
return i
}
}
return -1
}
pub fn (a array) slice(start int, end int) array {
mut result := a
#let slice = a.arr.arr.slice(start,end)
#result = new array(new array_buffer({arr: a.arr.arr, len: new int(slice.length),cap: new int(slice.length),index_start: new int(start),has_slice: new bool(true)}))
#a.arr.has_slice = true
//#v_makeSlice(result)
return result
}
pub fn (mut a array) insert(i int, val voidptr) {
#a.val.arr.make_copy()
#a.val.arr.arr.splice(i,0,v_clone_for_array_value(val))
#a.val.arr.len.val = a.val.arr.arr.length
}
pub fn (mut a array) insert_many(i int, val voidptr, size int) {
#a.val.arr.make_copy()
#a.val.arr.arr.splice(i,0,...val.arr.slice(0,+size).map(v_clone_for_array_value))
#a.val.arr.len.val = a.val.arr.arr.length
}
fn (mut a array) push(val voidptr) {
#a.val.arr.make_copy()
#if (arguments[2] && arguments[2].valueOf()) {a.val.arr.arr.push(...val.map(v_clone_for_array_value))} else {
#a.val.arr.arr.push(v_clone_for_array_value(val))
#}
#a.val.arr.len.val = a.val.arr.arr.length
}
fn v_filter(arr array, callback fn (voidptr) bool) array {
mut filtered := empty_array()
for i := 0; i < arr.arr.len; i++ {
if callback(arr.arr.get(i)) {
filtered.push(arr.arr.get(i))
}
}
return filtered
}
fn v_map(arr array, callback fn (voidptr) voidptr) array {
mut mapped := empty_array()
for i := 0; i < arr.arr.len; i++ {
mapped.push(callback(arr.arr.get(i)))
}
return mapped
}
struct array_iterator {
ix int
end int
arr JS.Array
}
#array_iterator.prototype.next = function () {
#if (this.ix.val < this.end.val) {
#this.ix.val++;
#return {done: false, value: this.arr.arr.get(new int(this.ix.val-1))}
#} else {
#return {done: true, value: undefined}
#}
#}
#array_iterator.prototype[Symbol.iterator] = function () { return this; }
#array.prototype[Symbol.iterator] = function () { return new array_iterator({ix: new int(0),end: new int(this.arr.len),arr: this}); }
#array.prototype.entries = function () { let result = []; for (let key = this.arr.index_start.val;key < this.arr.len.val;key++) { result.push([new int(key), this.arr.get(new int(key))]); } return result[Symbol.iterator](); }
#array.prototype.map = function(callback) { return v_map(this,callback); }
#array.prototype.filter = function(callback) { return v_filter(this,callback); }
#Object.defineProperty(array.prototype,'cap',{ get: function () { return this.len; } })
#array.prototype.any = function (value) {
#let val ;if (typeof value == 'function') { val = function (x) { return value(x); } } else { val = function (x) { return vEq(x,value); } }
#for (let i = 0;i < this.arr.arr.length;i++)
#if (val(this.arr.get(i)))
#return true;
#
#return false;
#}
#array.prototype.all = function (value) {
#let val ;if (typeof value == 'function') { val = function (x) { return value(x); } } else { val = function (x) { return vEq(x,value); } }
#for (let i = 0;i < this.arr.arr.length;i++)
#if (!val(this.arr.get(i)))
#return false;
#
#return true;
#}
//#Object.defineProperty(array_buffer.prototype,"len", { get: function() {return new int(this.arr.length);}, set: function(l) { this.arr.length = l.valueOf(); } })
//#Object.defineProperty(array_buffer.prototype,"cap", { get: function() {return new int(this.arr.length);}, set: function(l) { this.arr.length = l.valueOf(); } })
#
#
#function v_makeSlice(array) { Object.defineProperty(array,'len', {get: function() { return this.arr.len; }, set: function(l) { this.arr.len = l; }}) }
// delete deletes array element at index `i`.
pub fn (mut a array) delete(i int) {
a.delete_many(i, 1)
}
fn arr_copy(mut dst array, src array, count int) {
for i := 0; i < count; i++ {
dst.arr.set(i, src.arr.get(i))
}
}
// delete_many deletes `size` elements beginning with index `i`.
pub fn (mut a array) delete_many(i int, size int) {
#a.val.arr.make_copy()
#a.val.arr.arr.splice(i.valueOf(),size.valueOf())
#a.val.arr.len.val = a.val.arr.arr.length
}
// prepend prepends one value to the array.
pub fn (mut a array) prepend(val voidptr) {
a.insert(0, val)
}
// prepend_many prepends another array to this array.
@[unsafe]
pub fn (mut a array) prepend_many(val voidptr, size int) {
unsafe { a.insert_many(0, val, size) }
}
pub fn (a array) reverse() array {
mut res := empty_array()
#res.arr.arr = Array.from(a.arr).reverse()
return res
}
pub fn (mut a array) reverse_in_place() {
#a.val.arr.arr.reverse()
}
#array.prototype.$includes = function (elem) { return this.arr.arr.find(function(e) { return vEq(elem,e); }) !== undefined;}
pub fn (mut a array) clear() {
#a.val.arr.make_copy()
#a.val.arr.arr.length = 0
#a.val.arr.len.val = 0
}
// reduce executes a given reducer function on each element of the array, resulting in a single output value.
pub fn (a array) reduce(iter fn (int, int) int, accum_start int) int {
mut accum_ := accum_start
/*#for (let i = 0;i < a.arr.length;i++) {
#accum_ = iter(accum_, a.arr[i])
#}*/
for i in 0 .. a.len {
accum_ = iter(accum_, a.get(i))
}
return accum_
}
pub fn (mut a array) pop() voidptr {
mut res := unsafe { nil }
#a.val.arr.make_copy()
#res = a.val.arr.arr.pop()
#a.val.arr.len.val = a.val.arr.arr.length
return res
}
pub fn (a array) first() voidptr {
mut res := unsafe { nil }
#res = a.arr.get(new int(0))
return res
}
#array.prototype.toString = function () {
#let res = "["
#for (let i = 0; i < this.arr.arr.length;i++) {
#res += this.arr.get(i).toString();
#if (i != this.arr.arr.length-1)
#res += ', '
#}
#res += ']'
#return res;
#
#}
pub fn (a array) contains(key voidptr) bool
// delete_last effectively removes last element of an array.
pub fn (mut a array) delete_last() {
#a.val.arr.arr.pop();
}
@[unsafe]
pub fn (a &array) free() {
}
// todo: once (a []u8) will work rewrite this
pub fn (a array) bytestr() string {
res := ''
#for (let i = 0;i < a.arr.len.valueOf();i++) res.str += String.fromCharCode(a.arr.get(new int(i)))
return res
}
pub fn (a []string) str() string {
mut sb := strings.new_builder(a.len * 3)
sb.write_string('[')
for i in 0 .. a.len {
val := a[i]
sb.write_string("'")
sb.write_string(val)
sb.write_string("'")
if i < a.len - 1 {
sb.write_string(', ')
}
}
sb.write_string(']')
res := sb.str()
return res
}
pub fn (a array) to_js_array() JS.Array {
tmp := JS.Array.prototype.constructor()
for i in 0 .. a.len {
tmp.push(a.arr.get(i))
}
return tmp
}
pub fn (a array) to_number_array() JS.Array {
tmp := JS.Array.prototype.constructor()
for i in 0 .. a.len {
elem := a.arr.get(i)
_ := elem
#tmp.push(Number(elem.valueOf()));
}
return tmp
}
// push_many - appends multiple values to the end of the array.
pub fn (mut a array) push_many(val voidptr, size int) {
a.insert_many(a.len, val, size)
}
type EveryFn = fn (JS.Number, JS.Number) JS.Boolean
type BigEveryFn = fn (JS.BigInt, JS.Number) JS.Boolean
pub interface JS.TypedArray {
mut:
byteLength JS.Number
byteOffset JS.Number
length JS.Number
}
pub interface JS.Uint8Array {
JS.TypedArray
at(index JS.Number) JS.Number
every(JS.EveryFn) JS.Boolean
}
pub interface JS.Uint16Array {
JS.TypedArray
at(index JS.Number) JS.Number
every(JS.EveryFn) JS.Boolean
}
pub interface JS.Uint32Array {
JS.TypedArray
at(index JS.Number) JS.Number
every(JS.EveryFn) JS.Boolean
}
pub interface JS.BigUint64Array {
JS.TypedArray
at(index JS.Number) JS.BigInt
every(JS.BigEveryFn) JS.Boolean
}
pub interface JS.Int8Array {
JS.TypedArray
at(index JS.Number) JS.Number
every(JS.EveryFn) JS.Boolean
}
pub interface JS.Int16Array {
JS.TypedArray
at(index JS.Number) JS.Number
every(JS.EveryFn) JS.Boolean
}
pub interface JS.Int32Array {
JS.TypedArray
at(index JS.Number) JS.Number
every(JS.EveryFn) JS.Boolean
}
pub interface JS.BigInt64Array {
JS.TypedArray
at(index JS.Number) JS.BigInt
every(JS.BigEveryFn) JS.Boolean
}
pub interface JS.Float32Array {
JS.TypedArray
at(index JS.Number) JS.Number
every(JS.EveryFn) JS.Boolean
}
pub interface JS.Float64Array {
JS.TypedArray
at(index JS.Number) JS.Number
every(JS.EveryFn) JS.Boolean
}
pub fn uint8_array(arr []u8) JS.Uint8Array {
#let tmp = new Array();
for elem in arr {
_ := elem
#tmp.push(elem.val)
}
mut uint_arr := JS.Uint8Array{}
#uint_arr = new Uint8Array(tmp)
return uint_arr
}
pub fn uint16_array(arr []u16) JS.Uint16Array {
#let tmp = new Array();
for elem in arr {
_ := elem
#tmp.push(elem.val)
}
mut uint_arr := JS.Uint16Array{}
#uint_arr = new Uint16Array(tmp)
return uint_arr
}
pub fn uint32_array(arr []u32) JS.Uint32Array {
#let tmp = new Array();
for elem in arr {
_ := elem
#tmp.push(elem.val)
}
mut uint_arr := JS.Uint32Array{}
#uint_arr = new Uint32Array(tmp)
return uint_arr
}
pub fn int8_array(arr []i8) JS.Int8Array {
#let tmp = new Array();
for elem in arr {
_ := elem
#tmp.push(elem.val)
}
mut int_arr := JS.Int8Array{}
#int_arr = new Int8Array(tmp)
return int_arr
}
pub fn int16_array(arr []i16) JS.Int16Array {
#let tmp = new Array();
for elem in arr {
_ := elem
#tmp.push(elem.val)
}
mut int_arr := JS.Int16Array{}
#int_arr = new Int16Array(tmp)
return int_arr
}
pub fn int32_array(arr []int) JS.Int32Array {
#let tmp = new Array();
for elem in arr {
_ := elem
#tmp.push(elem.val)
}
mut int_arr := JS.Int32Array{}
#int_arr = new Int32Array(tmp)
return int_arr
}
pub fn int64_array(arr []i64) JS.BigInt64Array {
#let tmp = new Array();
for elem in arr {
_ := elem
#tmp.push(elem.val)
}
mut int_arr := JS.BigInt64Array{}
#int_arr = new BigInt64Array(tmp)
return int_arr
}
pub fn uint64_array(arr []u64) JS.BigUint64Array {
#let tmp = new Array();
for elem in arr {
_ := elem
#tmp.push(elem.val)
}
mut int_arr := JS.BigUint64Array{}
#int_arr = new BigUint64Array(tmp)
return int_arr
}
pub fn float32_array(arr []f32) JS.Float32Array {
#let tmp = new Array();
for elem in arr {
_ := elem
#tmp.push(elem.val)
}
mut float_arr := JS.Float32Array{}
#float_arr = new Float32Array(tmp)
return float_arr
}
pub fn float64_array(arr []f64) JS.Float64Array {
#let tmp = new Array();
for elem in arr {
_ := elem
#tmp.push(elem.val)
}
mut float_arr := JS.Float64Array{}
#float_arr = new Float64Array(tmp)
return float_arr
}
File diff suppressed because it is too large. Load diff
+183
View File
@@ -0,0 +1,183 @@
module builtin
// used to generate JS throw statements.
$if js_node {
#var $fs = require('fs');
}
@[noreturn]
pub fn js_throw(s any) {
#throw s
for {}
}
#let globalPrint, globalWrite;
$if js_freestanding {
#globalPrint = globalThis.print
#globalWrite = (typeof globalThis.write === 'function')? write: globalThis.print
}
pub fn flush_stdout() {
// needed for parity with builtin.c.v
}
pub fn flush_stderr() {
// needed for parity with builtin.c.v
}
pub fn println(s string) {
$if js_freestanding {
#globalPrint(s.str)
} $else {
#console.log(s.str)
}
}
pub fn print(s string) {
$if js_node {
#$process.stdout.write(s.str)
} $else $if js_freestanding {
#globalWrite(s.str)
} $else {
panic('Cannot `print` in a browser, use `println` instead')
}
}
pub fn eprintln(s string) {
$if js_freestanding {
#globalPrint(s.str)
} $else {
#console.error(s.str)
}
}
pub fn eprint(s string) {
$if js_node {
#$process.stderr.write(s.str)
} $else {
panic('Cannot `eprint` in a browser, use `println` instead')
}
}
// input_character gives back a single character, read from the standard input.
// It returns -1 on error (when the input is finished (EOF), on a broken pipe etc).
pub fn input_character() int {
$if js_node {
mut ch := -1
#try {
#const read_buffer = Buffer.alloc(1)
#const nbytes = $fs.readSync(0, read_buffer, 0, 1, null)
#if (nbytes > 0) { ch.val = read_buffer[0] }
#} catch (e) {}
return ch
} $else {
return -1
}
}
// print_character writes the single character `ch` to the standard output.
// It returns the written character value, or panics if the active JS runtime
// does not support stdout writes.
pub fn print_character(ch u8) int {
print(ch.ascii_str())
return ch
}
// Exits the process in node, and halts execution in the browser
// because `process.exit` is undefined. Workaround for not having
// a 'real' way to exit in the browser.
@[noreturn]
pub fn exit(c int) {
JS.process.exit(c)
js_throw('exit(${c})')
}
fn opt_ok(data voidptr, option Option) {
#option.state = 0
#option.err = none__
#option.data = data
}
pub fn unwrap(opt string) string {
mut o := Option{}
#o = opt
if o.state != 0 {
js_throw(o.err)
}
mut res := ''
#res = opt.data
return res
}
fn js_stacktrace() string {
stacktrace := ''
#let err = new TypeError();
#err.name = 'stacktrace: '
#stacktrace.str = err.stack
return stacktrace
}
// v_clone_value preserves standalone JS semantics for V clone methods.
#function v_clone_value(value) {
#if (value === null || value === undefined) return value;
#if (value instanceof $ref) return new $ref(v_clone_value(value.val));
#if (value instanceof array) return array_clone(value);
#if (value instanceof map) {
#let cloned = {}
#for (const key in value.map) cloned[key] = { key: v_clone_value(value.map[key].key), val: v_clone_value(value.map[key].val) }
#return new map(cloned);
#}
#if (typeof value !== 'object') return value;
#if (typeof value.$toJS === 'function') {
#let cloned = Object.create(Object.getPrototypeOf(value) || Object.prototype);
#for (const key of Object.keys(value)) cloned[key] = v_clone_value(value[key]);
#return cloned;
#}
#let cloned;
#try {
#cloned = typeof value.constructor === 'function' ? new value.constructor({}) : Object.create(Object.getPrototypeOf(value));
#} catch (e) {
#cloned = Object.create(Object.getPrototypeOf(value) || Object.prototype);
#}
#for (const key of Object.keys(value)) cloned[key] = v_clone_value(value[key]);
#return cloned;
#}
pub fn print_backtrace() {
println(js_stacktrace())
}
pub fn (a array) clone() array {
mut res := empty_array()
#const source = a instanceof $ref ? a.val : a
#const cloned = source.arr.arr.slice(source.arr.index_start.valueOf(), source.arr.index_start.valueOf() + source.len.valueOf()).map(v_clone_value)
#res = new array(new array_buffer({arr: cloned, len: new int(cloned.length), cap: new int(cloned.length), index_start: new int(0), has_slice: new bool(false)}))
return res
}
// Check for nil value
pub fn isnil(val voidptr) bool {
res := false
// This one is kinda weird. In C and native backend we can cast booleans and integers to pointers
// so we just check *for* all possible NULL-like values here.
#if (typeof val == 'function') { res.val = false; } else {
#val = val instanceof voidptr ? val.valueOf().val : val;
#res.val = val === null || val === undefined || val === false || val === 0 || val === BigInt(0) || (val instanceof int ? val.val == 0 : false)
#}
return res
}
pub fn (f float_literal) str() string {
res := ''
#res.str += f.valueOf()
return res
}
+157
View File
@@ -0,0 +1,157 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module builtin
fn (a any) toString()
// panic prints an error message, then exits the process with exit code of 1.
@[noreturn]
pub fn panic(s string) {
eprintln('V panic: ' + s)
eprintln(js_stacktrace())
exit(1)
}
// panic_n prints an error message, followed by the given number, then exits the process with exit code of 1.
@[noreturn]
pub fn panic_n(s string, n i64) {
eprintln('V panic: ' + s)
eprintln(js_stacktrace())
exit(1)
}
// IError holds information about an error instance.
pub interface IError {
msg() string
code() int
}
// str returns the message of IError.
pub fn (err IError) str() string {
return match err {
None__ {
'none'
}
Error {
err.msg()
}
MessageError {
err.str()
}
else {
'${err.type_name()}: ${err.msg()}'
}
}
}
// Error is the empty default implementation of `IError`.
pub struct Error {}
// msg returns the message of Error.
pub fn (err Error) msg() string {
return ''
}
// code returns the code of Error.
pub fn (err Error) code() int {
return 0
}
// MessageError is the default implementation of the `IError` interface that is returned by the `error()` function.
struct MessageError {
pub:
msg string
code int
}
// str returns the message and code of the MessageError.
pub fn (err MessageError) str() string {
return err.msg
}
// msg returns the message of the MessageError.
pub fn (err MessageError) msg() string {
return err.msg
}
// code returns the code of MessageError.
pub fn (err MessageError) code() int {
return err.code
}
pub const none__ = IError(&None__{})
struct None__ {
Error
}
fn (_ None__) str() string {
return 'none'
}
pub struct Option {
state u8
err IError = none__
}
// str returns the Option type: ok, none, or error.
pub fn (o Option) str() string {
if o.state == 0 {
return 'Option{ ok }'
}
if o.state == 1 {
return 'Option{ none }'
}
return 'Option{ error: "${o.err}" }'
}
pub struct _option {
state u8
err IError = none__
}
// str returns the Option type: ok, none, or error.
pub fn (o _option) str() string {
if o.state == 0 {
return 'Option{ ok }'
}
if o.state == 1 {
return 'Option{ none }'
}
return 'Option{ error: "${o.err}" }'
}
// trace_error prints to stderr a string and a backtrace of the error.
fn trace_error(x string) {
eprintln('> ${@FN} | ${x}')
}
// error returns a default error instance containing the error given in `message`.
// Example: if ouch { return error('an error occurred') }
@[inline]
pub fn error(message string) IError {
// trace_error(message)
return &MessageError{
msg: message
}
}
// error_with_code returns a default error instance containing the given `message` and error `code`.
// Example: if ouch { return error_with_code('an error occurred', 1) }
@[inline]
pub fn error_with_code(message string, code int) IError {
// trace_error('${message} | code: ${code}')
return &MessageError{
msg: message
code: code
}
}
// free allows for manually freeing memory allocated at the address `ptr`.
// However, this is a no-op on JS backend
@[unsafe]
pub fn free(ptr voidptr) {
_ := ptr
}
+101
View File
@@ -0,0 +1,101 @@
module builtin
pub fn (b u8) is_space() bool {
mut result := false
#result.val = /^\s*$/.test(String.fromCharCode(b))
return result
}
pub fn (c u8) str() string {
res := ''
#res.str = c.val.toString()
return res
}
pub fn (c u8) ascii_str() string {
res := ''
#res.str = String.fromCharCode(c.val)
return res
}
pub fn (c u8) repeat(count int) string {
mut res := ''
for _ in 0 .. count {
res += c.ascii_str()
}
return res
}
@[inline]
pub fn (c u8) is_digit() bool {
return c >= `0` && c <= `9`
}
// is_hex_digit returns `true` if the byte is either in range 0-9, a-f or A-F and `false` otherwise.
// Example: assert u8(`F`) == true
@[inline]
pub fn (c u8) is_hex_digit() bool {
return c.is_digit() || (c >= `a` && c <= `f`) || (c >= `A` && c <= `F`)
}
// is_oct_digit returns `true` if the byte is in range 0-7 and `false` otherwise.
// Example: assert u8(`7`) == true
@[inline]
pub fn (c u8) is_oct_digit() bool {
return c >= `0` && c <= `7`
}
// is_bin_digit returns `true` if the byte is a binary digit (0 or 1) and `false` otherwise.
// Example: assert u8(`0`) == true
@[inline]
pub fn (c u8) is_bin_digit() bool {
return c == `0` || c == `1`
}
// is_letter returns `true` if the byte is in range a-z or A-Z and `false` otherwise.
// Example: assert u8(`V`) == true
@[inline]
pub fn (c u8) is_letter() bool {
return (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`)
}
// is_alnum returns `true` if the byte is in range a-z, A-Z, 0-9 and `false` otherwise.
// Example: assert u8(`V`) == true
@[inline]
pub fn (c u8) is_alnum() bool {
return (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) || (c >= `0` && c <= `9`)
}
// is_capital returns `true`, if the byte is a Latin capital letter.
// Example: assert `H`.is_capital() == true
// Example: assert `h`.is_capital() == false
@[inline]
pub fn (c u8) is_capital() bool {
return c >= `A` && c <= `Z`
}
// str_escaped returns the contents of `byte` as an escaped `string`.
// Example: assert u8(0).str_escaped() == r'`\0`'
pub fn (b u8) str_escaped() string {
mut str := ''
match b {
0 { str = r'`\0`' }
7 { str = r'`\a`' }
8 { str = r'`\b`' }
9 { str = r'`\t`' }
10 { str = r'`\n`' }
11 { str = r'`\v`' }
12 { str = r'`\f`' }
13 { str = r'`\r`' }
27 { str = r'`\e`' }
32...126 { str = b.ascii_str() }
else { str = '0x' + b.hex() }
}
return str
}
+15
View File
@@ -0,0 +1,15 @@
module builtin
pub fn (x f32) str() string {
res := ''
#res.str = x.val + ''
return res
}
pub fn (x f64) str() string {
res := ''
#res.str = x.val + ''
return res
}
+224
View File
@@ -0,0 +1,224 @@
module builtin
pub type byte = u8
pub const min_i8 = i8(-128)
pub const max_i8 = i8(127)
pub const min_i16 = i16(-32768)
pub const max_i16 = i16(32767)
pub const min_i32 = i32(-2147483648)
pub const max_i32 = i32(2147483647)
// -9223372036854775808 is wrong, because C compilers parse literal values
// without sign first, and 9223372036854775808 overflows i64, hence the
// consecutive subtraction by 1
pub const min_i64 = i64(-9223372036854775807 - 1)
pub const max_i64 = i64(9223372036854775807)
pub const min_int = $if new_int ? && x64 { int(min_i64) } $else { int(min_i32) }
pub const max_int = $if new_int ? && x64 { int(max_i64) } $else { int(max_i32) }
pub const min_u8 = u8(0)
pub const max_u8 = u8(255)
pub const min_u16 = u16(0)
pub const max_u16 = u16(65535)
pub const min_u32 = u32(0)
pub const max_u32 = u32(4294967295)
pub const min_u64 = u64(0)
pub const max_u64 = u64(18446744073709551615)
pub fn (i i8) str() string {
mut res := ''
#res.str = i.val.toString()
return res
}
pub fn (i i16) str() string {
mut res := ''
#res.str = i.val.toString()
return res
}
pub fn (i u16) str() string {
mut res := ''
#res.str = i.val.toString()
return res
}
pub fn (i int) str() string {
mut res := ''
#res = new string( i+'' )
return res
}
pub fn (i i64) str() string {
mut res := ''
#res = new string( i + '')
return res
}
pub fn (i u32) str() string {
mut res := ''
#res = new string( i + '')
return res
}
pub fn (i u64) str() string {
mut res := ''
#res = new string( i + '')
return res
}
pub fn (i bool) str() string {
mut res := ''
#res = new string( i + '')
return res
}
pub fn (i any) str() string {
mut res := ''
#res = new string( i.toString() )
return res
}
pub fn (i int_literal) str() string {
res := ''
#res.str = i.val.toString()
return res
}
pub fn (x u64) hex() string {
res := ''
#res.str = x.val.toString(16)
return res
}
pub fn (x u64) hex_full() string {
res := ''
#res.str = x.val.toString(16)
return res
}
pub fn (x i64) hex() string {
res := ''
#res.str = x.val.toString(16)
return res
}
pub fn (x u32) hex() string {
res := ''
#res.str = x.val.toString(16)
return res
}
pub fn (x u16) hex() string {
res := ''
#res.str = x.val.toString(16)
return res
}
pub fn (x i8) hex() string {
mut res := ''
#res.str = x.val.toString(16)
if res.len < 2 {
res = '0' + res
}
return res
}
pub fn (x i16) hex() string {
res := ''
#res.str = x.val.toString(16)
return res
}
pub fn (x int) hex() string {
res := ''
#res.str = x.val.toString(16)
return res
}
pub fn (x int_literal) hex() string {
res := ''
#res.str = x.val.toString(16)
return res
}
pub fn (x u8) hex() string {
mut res := ''
#res.str = x.val.toString(16)
if res.len < 2 {
res = '0' + res
}
return res
}
// hex returns a string with the hexadecimal representation of the byte elements of the array.
pub fn (b []u8) hex() string {
mut hex := ''
for i in b {
mut z := i
z = z
#let n0 = i.val >> 4
#hex.str += n0 < 10 ? String.fromCharCode(n0) : String.fromCharCode(n0 + 87)
#let n1 = i.val & 0xF
#hex.str += n1 < 10 ? String.fromCharCode(n1) : String.fromCharCode(n1 + 87)
}
return hex
}
pub fn (i int) hex2() string {
return '0x' + i.hex()
}
pub fn (i i8) hex2() string {
return '0x' + i.hex()
}
pub fn (i i16) hex2() string {
return '0x' + i.hex()
}
pub fn (i i64) hex2() string {
return '0x' + i.hex()
}
pub fn (i u8) hex2() string {
return '0x' + i.hex()
}
pub fn (i u16) hex2() string {
return '0x' + i.hex()
}
pub fn (i u32) hex2() string {
return '0x' + i.hex()
}
pub fn (i u64) hex2() string {
return '0x' + i.hex()
}
+246
View File
@@ -0,0 +1,246 @@
// vtest retry: 3
// vtest build: present_node?
const a = 3
const u = u64(1)
fn test_const() {
b := (true && true) || false
assert b == true
assert a == 3
assert u == u64(1)
assert u == 1 // make sure this works without the cast
}
fn test_str_methods() {
assert i8(1).str() == '1'
assert i8(-1).str() == '-1'
assert i16(1).str() == '1'
assert i16(-1).str() == '-1'
assert int(1).str() == '1'
assert int(-1).str() == '-1'
assert int(2147483647).str() == '2147483647'
// todo: overflow check for integers
// assert int(2147483648).str() == '-2147483648'
// assert int(-2147483648).str() == '-2147483648'
assert i64(1).str() == '1'
assert i64(-1).str() == '-1'
assert u16(1).str() == '1'
// assert u16(-1).str() == '65535'
assert u32(1).str() == '1'
// assert u32(-1).str() == '4294967295'
assert u64(1).str() == '1'
// assert u64(-1).str() == '18446744073709551615'
}
fn test_and_precedence() {
assert (2 & 0 == 0) == ((2 & 0) == 0)
assert (2 & 0 != 0) == ((2 & 0) != 0)
assert (0 & 0 >= 0) == ((0 & 0) >= 0)
assert (0 & 0 <= 0) == ((0 & 0) <= 0)
assert (0 & 0 < 1) == ((0 & 0) < 1)
assert (1 & 2 > 0) == ((1 & 2) > 0)
}
fn test_or_precedence() {
assert (1 | 0 == 0) == ((1 | 0) == 0)
assert (1 | 0 != 1) == ((1 | 0) != 1)
assert (1 | 0 >= 2) == ((1 | 0) >= 2)
assert (1 | 0 <= 0) == ((1 | 0) <= 0)
assert (1 | 0 < 0) == ((1 | 0) < 0)
assert (1 | 0 > 1) == ((1 | 0) > 1)
}
fn test_xor_precedence() {
assert (1 ^ 0 == 2) == ((1 ^ 0) == 2)
assert (1 ^ 0 != 2) == ((1 ^ 0) != 2)
assert (1 ^ 0 >= 0) == ((1 ^ 0) >= 0)
assert (1 ^ 0 <= 1) == ((1 ^ 0) <= 1)
assert (1 ^ 0 < 0) == ((1 ^ 0) < 0)
assert (1 ^ 0 > 1) == ((1 ^ 0) > 1)
}
fn test_left_shift_precedence() {
assert (2 << 4 | 3) == ((2 << 4) | 3)
assert (2 << 4 | 3) != (2 << (4 | 3))
}
fn test_right_shift_precedence() {
assert (256 >> 4 | 3) == ((256 >> 4) | 3)
assert (256 >> 4 | 3) != (256 >> (4 | 3))
}
fn test_i8_print() {
b := i8(0)
println(b)
c := i16(7)
println(c)
d := u16(6)
println(d)
assert true
}
/*
fn test_cmp() {
assert 1 ≠ 2
assert 1 ⩽ 2
assert 1 ⩾ 0
}
*/
type MyInt = int
fn test_int_alias() {
i := MyInt(2)
assert i + 10 == 12
}
fn test_hex() {
x := u64(10)
assert x.hex() == 'a'
b := 1234
assert b.hex() == '4d2'
b1 := -1
println(b1)
// assert b1.hex() == 'ffffffff'
// unsigned tests
// assert u8(12).hex() == '0c'
// assert u8(255).hex() == 'ff'
assert u16(65535).hex() == 'ffff'
// assert u32(-1).hex() == 'ffffffff'
// assert u64(-1).hex() == 'ffffffffffffffff'
// signed tests
// assert i8(-1).hex() == 'ff'
assert i8(12).hex() == '0c'
assert i16(32767).hex() == '7fff'
assert int(2147483647).hex() == '7fffffff'
assert i64(9223372036854775807).hex() == '7fffffffffffffff'
}
fn test_bin() {
x1 := 0b10
assert x1 == 2
x2 := 0b10101010
assert x2 == 0xAA
x3 := -0b0000001
assert x3 == -1
x4 := 0b11111111
assert x4 == 255
x5 := u8(0b11111111)
assert x5 == 255
x6 := char(0b11111111)
assert int(x6) == -1
x7 := 0b0
assert x7 == 0
x8 := -0b0
assert x8 == 0
}
fn test_oct() {
x1 := 0o12
assert x1 == 10
x2 := 0o350
assert x2 == 232
x3 := 0o00073
assert x3 == 59
x4 := 0
assert x4 == 0
x5 := 195
assert x5 == 195
x6 := -0o744
assert x6 == -484
x7 := -0o000042
assert x7 == -34
x8 := -112
assert x8 == -112
x9 := -0
assert x9 == 0
}
fn test_num_separator() {
// int
assert 100_000_0 == 1000000
assert -2_23_4_6 == -22346
// bin
assert 0b0_11 == 3
assert -0b0_100 == -4
// oct
assert 0o1_73 == 123
assert -0o17_5 == -125
assert -0o175 == -125
// hex
assert 0xFF == 255
assert 0xF_F == 255
// f32 or f64
assert 312_2.55 == 3122.55
assert 312_2.55 == 3122.55
}
fn test_int_decl() {
x1 := 0
x2 := 1333
x3 := -88955
x4 := 2000000000
x5 := -1999999999
assert typeof(x1).name == 'int'
assert typeof(x2).name == 'int'
assert typeof(x3).name == 'int'
assert typeof(x4).name == 'int'
assert typeof(x5).name == 'int'
x7 := u64(-321314588900011)
assert typeof(x7).name == 'u64'
}
fn test_int_to_hex() {
// array hex
/*
st := [u8(`V`), `L`, `A`, `N`, `G`]
assert st.hex() == '564c414e47'
assert st.hex().len == 10
st1 := [u8(0x41)].repeat(100)
assert st1.hex() == '41'.repeat(100)*/
// --- int to hex tests
c := 12
// 8Bit
assert u8(0).hex() == '00'
assert u8(c).hex() == '0c'
assert i8(c).hex() == '0c'
assert u8(127).hex() == '7f'
assert i8(127).hex() == '7f'
assert u8(255).hex() == 'ff'
// assert u8(-1).hex() == 'ff'
// 16bit
assert u16(0).hex() == '0'
assert i16(c).hex() == 'c'
assert u16(c).hex() == 'c'
assert i16(32767).hex() == '7fff'
assert u16(32767).hex() == '7fff'
// assert i16(-1).hex() == 'ffff'
assert u16(65535).hex() == 'ffff'
// 32bit
assert u32(0).hex() == '0'
assert c.hex() == 'c'
assert u32(c).hex() == 'c'
assert 2147483647.hex() == '7fffffff'
assert u32(2147483647).hex() == '7fffffff'
// assert (-1).hex() == 'ffffffffffffffff'
// assert u32(4294967295).hex() == 'ffffffff'
// 64 bit
assert u64(0).hex() == '0'
assert i64(c).hex() == 'c'
assert u64(c).hex() == 'c'
assert i64(9223372036854775807).hex() == '7fffffffffffffff'
assert u64(9223372036854775807).hex() == '7fffffffffffffff'
// assert i64(-1).hex() == 'ffffffffffffffff'
assert u64(18446744073709551615).hex() == 'ffffffffffffffff'
}
fn test_repeat() {
b := u8(`V`)
assert b.repeat(5) == 'VVVVV'
assert b.repeat(1) == b.ascii_str()
assert b.repeat(0) == ''
}
+192
View File
@@ -0,0 +1,192 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
// This file contains JS functions present in both node and the browser.
// They have been ported from their TypeScript definitions.
module builtin
pub interface JS.Object {}
@[single_impl]
pub interface JS.BigInt {
JS.Any
}
@[single_impl]
pub interface JS.Number {
JS.Any
}
pub interface JS.RegExp {
JS.Any
}
pub type SplitSeparator = JS.RegExp | JS.String
@[single_impl]
pub interface JS.String {
JS.Any
length JS.Number
charAt(index JS.Number) JS.String
charCodeAt(index JS.Number) JS.Number
toUpperCase() JS.String
toLowerCase() JS.String
concat(a JS.String) JS.String
includes(substr JS.String) JS.Boolean
endsWith(substr JS.String) JS.Boolean
startsWith(substr JS.String) JS.Boolean
slice(a JS.Number, b JS.Number) JS.String
split(delim SplitSeparator) JS.Array
indexOf(needle JS.String) JS.Number
lastIndexOf(needle JS.String) JS.Number
}
@[single_impl]
pub interface JS.Boolean {
JS.Any
length JS.Number
}
pub interface JS.Map {
JS.Any
size JS.Number
clear()
delete(key JS.Any) JS.Boolean
get(key JS.Any) JS.Any
has(key JS.Any) JS.Any
set(key JS.Any, val JS.Any)
}
#function Any(val) { return val; }
pub interface JS.Any {}
pub fn js_is_null(x JS.Any) bool {
res := false
#res.val = x === null
return res
}
pub fn js_is_undefined(x JS.Any) bool {
res := false
#res.val = x === undefined
return res
}
pub fn js_null() JS.Any {
mut obj := JS.Any{}
#obj = null;
return obj
}
pub fn js_undefined() JS.Any {
mut obj := JS.Any{}
#obj = undefined;
return obj
}
pub interface JS.Array {
JS.Any // map(fn (JS.Any) JS.Any) JS.Array
map(JS.Any) JS.Array
push(JS.Any) JS.Any
pop() JS.Any
at(JS.Number) JS.Any
mut:
length JS.Number
}
pub fn JS.Array.prototype.constructor(...any) JS.Array
// browser: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Error
// node: https://nodejs.org/api/errors.html#errors_class_error
pub struct JS.Error {
pub:
name string
message string
stack string
}
// Type prototype functions
fn (v JS.String) toString() JS.String
fn (v JS.Number) toString() JS.String
fn (v JS.Boolean) toString() JS.String
fn (v JS.Array) toString() JS.String
fn (v JS.Map) toString() JS.String
// Hack for "`[]JS.String` is not a struct" when returning arr.length or arr.len
// TODO: Fix []JS.String not a struct error
fn native_str_arr_len(arr []JS.String) int {
mut len := 0
#len = arr.length
return len
}
// Top level functions
fn JS.eval(JS.String) JS.Any
fn JS.parseInt(JS.String, f64) JS.Number
fn JS.parseFloat(JS.String) JS.Number
fn JS.isNaN(f64) bool
fn JS.isFinite(f64) bool
fn JS.decodeURI(JS.String) JS.String
fn JS.decodeURIComponent(JS.String) JS.String
fn JS.encodeURI(JS.String) JS.String
type EncodeURIComponentArg = JS.String | bool | f64
fn JS.encodeURIComponent(EncodeURIComponentArg) JS.String
fn JS.escape(JS.String) JS.String
fn JS.unescape(JS.String) JS.String
// console
fn JS.console.assert(bool, ...any)
fn JS.console.clear()
fn JS.console.count(JS.String)
fn JS.console.countReset(JS.String)
fn JS.console.debug(...any)
fn JS.console.dir(any, any)
fn JS.console.dirxml(...any)
fn JS.console.error(...any)
fn JS.console.exception(string, ...any)
fn JS.console.group(...any)
fn JS.console.groupCollapsed(...any)
fn JS.console.groupEnd()
fn JS.console.info(...any)
fn JS.console.log(...any)
fn JS.console.table(any, []string)
fn JS.console.time(JS.String)
fn JS.console.timeEnd(JS.String)
fn JS.console.timeLog(string, ...any)
fn JS.console.timeStamp(string)
fn JS.console.trace(...any)
fn JS.console.warn(...any)
// Math
fn JS.Math.abs(f64) f64
fn JS.Math.acos(f64) f64
fn JS.Math.asin(f64) f64
fn JS.Math.atan(f64) f64
fn JS.Math.atan2(f64, f64) f64
fn JS.Math.ceil(f64) f64
fn JS.Math.cos(f64) f64
fn JS.Math.exp(f64) f64
fn JS.Math.floor(f64) f64
fn JS.Math.log(f64) f64
fn JS.Math.max(...f64) f64
fn JS.Math.min(...f64) f64
fn JS.Math.pow(f64, f64) f64
fn JS.Math.random() f64
fn JS.Math.round(f64) f64
fn JS.Math.sin(f64) f64
fn JS.Math.sqrt(f64) f64
fn JS.Math.tan(f64) f64
// JSON
fn JS.JSON.stringify(any) JS.String
fn JS.JSON.parse(string) any
@@ -0,0 +1,59 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
// This file contains JS functions only present in the browser.
// They have been ported from their TypeScript definitions.
module builtin
// Window
fn JS.atob(string) string
fn JS.btoa(string) string
fn JS.clearInterval(int)
fn JS.clearTimeout(int)
// fn JS.createImageBitmap(ImageBitmapSource, ImageBitmapOptions) Promise<ImageBitmap>
// fn JS.createImageBitmap(ImageBitmapSource, int, int, int, int, ImageBitmapOptions) Promise<ImageBitmap>
// TODO: js async attribute
// [js_async]
// fn JS.fetch(RequestInfo, RequestInit) Promise<Response>
fn JS.queueMicrotask(fn ())
fn JS.setInterval(any, int, ...any) int
fn JS.setTimeout(any, int, ...any) int
fn JS.alert(any)
fn JS.blur()
fn JS.captureEvents()
fn JS.close()
fn JS.confirm(string) bool
// fn JS.departFocus(NavigationReason, FocusNavigationOrigin)
fn JS.focus()
// fn JS.getComputedStyle(Element, string | null) CSSStyleDeclaration
// fn JS.getMatchedCSSRules(Element, string | null) CSSRuleList
// fn JS.getSelection() Selection | null
// fn JS.matchMedia(string) MediaQueryList
fn JS.moveBy(int, int)
fn JS.moveTo(int, int)
fn JS.msWriteProfilerMark(string)
// fn JS.open(string, string, string, bool)?Window
// fn JS.postMessage(any, string, []Transferable)
fn JS.print()
fn JS.prompt(string, string) ?string
fn JS.releaseEvents()
fn JS.resizeBy(int, int)
fn JS.resizeTo(int, int)
// fn JS.scroll(ScrollToOptions)
fn JS.scroll(int, int)
// fn JS.scrollBy(ScrollToOptions)
fn JS.scrollBy(int, int)
// fn JS.scrollTo(ScrollToOptions)
fn JS.scrollTo(int, int)
fn JS.stop()
+31
View File
@@ -0,0 +1,31 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
// This file contains JS functions only present in node.js.
// They have been ported from their TypeScript definitions.
module builtin
pub struct JS.node_process {
pub:
arch string
argsv []string
env []string
platform string
version string
// TODO: add all properties
}
// hack to access process properties
pub fn js_node_process() JS.node_process {
#return process
return JS.node_process{}
}
fn JS.process.exit(int)
fn JS.process.stdout.write(string) bool
fn JS.process.stdout.writeln(string) bool
fn JS.process.stderr.write(string) bool
fn JS.process.stderr.writeln(string) bool
+94
View File
@@ -0,0 +1,94 @@
module builtin
struct map {
m JS.Map
pub:
len int
}
fn (mut m map) internal_set(key JS.Any, val JS.Any) {
//$if es5 {
#let skey = key;
#if (key != null && typeof key.$toJS === 'function') key = key.$toJS();
#if (!(key in m.val.map)) {
#m.val.length++;
#m.val.map[key] = { key: skey, val: val };
#} else {
#m.val.map[key].val = val
#}
/*} $else {
# if (key.hasOwnProperty('$toJS')) key = key.$toJS();
# m.val.m.set(key,val);
}*/
_ := key
_ := val
}
fn (mut m map) internal_get(key JS.Any) JS.Any {
mut val := JS.Any(unsafe { nil })
//$if es5 {
#if (typeof key != "string" && key != null && typeof key.$toJS === 'function') key = key.$toJS();
#if (key in m.val.map) {
#val = m.val.map[key].val
#} else {
#val = js_undefined()
#}
/*} $else {
# if (key.hasOwnProperty('$toJS')) key = key.$toJS();
# val = m.val.m.get(key)
}*/
_ := key
return val
}
#map.prototype.get = function (key) { return map_internal_get(this,key); }
#map.prototype.set = function(key,val) { map_internal_set(this,key,val); }
#map.prototype.has = function (key) { if (typeof key != "string" && key != null && typeof key.$toJS === 'function') { key = key.$toJS() } return key in this.map; }
// Removes the mapping of a particular key from the map.
@[unsafe]
pub fn (mut m map) delete(key JS.Any) {
#let k = key != null && typeof key.$toJS === 'function' ? key.$toJS() : key;
#if (k in m.val.map) {
#delete m.val.map[k];
#m.val.length--;
#}
_ := key
}
pub fn (m map) clone() map {
mut res := m
#res = v_clone_value(m)
return res
}
pub fn (m &map) free() {}
pub fn (m map) keys() array {
ret := JS.makeEmptyArray()
#for (var key in m.map) array_push(ret,m.map[key].key,false)
return ret
}
pub fn (m map) values() array {
ret := JS.makeEmptyArray()
#for (var key in m.map) array_push(ret,m.map[key].val,false);
return ret
}
//#Object.defineProperty(map.prototype,"len",{get: function() { return this.map.size; }})
#map.prototype.toString = function () {
#function fmtKey(key) { return typeof key == 'string' ? '\'' + key + '\'' : key}
#let res = '{'
#for (const entry of this) {
#res += fmtKey(entry[0]) + ': ' + entry[0];
#}
#res += '}'
#return res;
#}
#map.prototype.getOrSet = function (key, init) { const skey = key; if (typeof key != "string" && key != null && typeof key.$toJS === 'function') { key = key.$toJS() } if (key in this.map) { return this.map[key].val; } this.length++; this.map[key] = { key: skey, val: init }; return this.map[key].val; }
+972
View File
@@ -0,0 +1,972 @@
// vtest retry: 3
// vtest build: present_node?
import rand
const test_strings = unique_strings(200, 10)
fn unique_strings(arr_len int, str_len int) []string {
mut arr := []string{cap: arr_len}
for arr.len < arr_len {
str := rand.string(str_len)
if str !in arr {
arr << str
}
}
return arr
}
fn test_get_and_set_many() {
mut m := map[string]int{}
for i, s in test_strings {
m[s] = i
assert m[s] == i
assert m.len == i + 1
}
for i, s in test_strings {
assert m[s] == i
}
assert m.len == test_strings.len
}
fn test_for_in_many() {
mut m := map[string]int{}
for i, s in test_strings {
m[s] = i
}
for k, v in m {
assert m[k] == v
}
}
fn test_keys_many() {
mut m := map[string]int{}
for i, s in test_strings {
m[s] = i
}
keys := m.keys()
assert keys.len == test_strings.len
assert keys.len == m.len
assert keys == test_strings
}
fn test_deletes_many() {
mut m := map[string]int{}
for i, s in test_strings {
m[s] = i
}
for i, s in test_strings {
m.delete(s)
assert m[s] == 0
assert m.len == test_strings.len - (i + 1)
}
assert m.len == 0
assert m.keys().len == 0
}
struct User {
mut:
name string
}
struct Aaa {
mut:
m map[string]int
users map[string]User
}
fn (mut a Aaa) set(key string, val int) {
a.m[key] = val
}
fn test_map() {
mut m := map[string]int{}
assert m.len == 0
m['hi'] = 80
m['hello'] = 101
assert m['hi'] == 80
assert m['hello'] == 101
assert m.len == 2
assert 'hi' in m
mut sum := 0
// Test `for in`
for _, val in m {
sum += val
}
assert sum == 80 + 101
// Test `.keys()`
keys := m.keys()
assert keys.len == 2
assert 'hi' in keys
assert 'hello' in keys
m.delete('hi')
assert m.len == 1
m.delete('aloha')
assert m.len == 1
assert m['hi'] == 0
assert m.keys().len == 1
assert m.keys()[0] == 'hello'
// //
mut users := map[string]User{}
users['1'] = User{'Peter'}
peter := users['1']
assert peter.name == 'Peter'
mut a := Aaa{
m: map[string]int{}
users: map[string]User{}
}
a.users['Bob'] = User{'Bob'}
q := a.users['Bob']
assert q.name == 'Bob'
// test struct field change
a.users['Bob'].name = 'bob'
q2 := a.users['Bob']
assert q2.name == 'bob'
a.m['one'] = 1
a.set('two', 2)
assert a.m['one'] == 1
assert a.m['two'] == 2
}
fn test_map_init() {
one := 'one'
three := 'three'
m := {
one: 1
'two': 2
three: 1 + 2
}
assert m['one'] == 1
assert m['two'] == 2
assert m['three'] == 3
assert m['unknown'] == 0
}
fn test_string_map() {
// m := map[string]Fn
}
fn test_large_map() {
// ticks := time.ticks()
mut nums := map[string]int{}
n := 30 * 1000
for i in 0 .. n {
key := i.str()
nums[key] = i
}
assert nums['1'] == 1
assert nums['999'] == 999
assert nums['1000000'] == 0
// println(time.ticks() - ticks)
}
fn test_various_map_value() {
mut m1 := map[string]int{}
m1['test'] = 1
assert m1['test'] == 1
mut m2 := map[string]string{}
m2['test'] = 'test'
assert m2['test'] == 'test'
mut m3 := map[string]i8{}
m3['test'] = i8(0)
assert m3['test'] == i8(0)
mut m4 := map[string]i16{}
m4['test'] = i16(0)
assert m4['test'] == i16(0)
mut m7 := map[string]u16{}
m7['test'] = u16(0)
assert m7['test'] == u16(0)
mut m8 := map[string]u32{}
m8['test'] = u32(0)
assert m8['test'] == u32(0)
mut m9 := map[string]bool{}
m9['test'] = true
assert m9['test'] == true
mut m10 := map[string]u8{}
m10['test'] = u8(0)
assert m10['test'] == u8(0)
mut m11 := map[string]f32{}
m11['test'] = f32(0.0)
assert m11['test'] == f32(0.0)
mut m12 := map[string]f64{}
m12['test'] = f64(0.0)
assert m12['test'] == f64(0.0)
// mut m13 := map[string]rune
// m13['test'] = rune(0)
// assert m13['test'] == rune(0)
// todo(playX): pointer equality does not work yet
/*
mut m14 := map[string]voidptr{}
m14['test'] = voidptr(0)
assert m14['test'] == voidptr(0)
mut m15 := map[string]&byte{}
m15['test'] = &u8(unsafe { nil })
assert m15['test'] == &u8(unsafe { nil })
mut m16 := map[string]i64{}
m16['test'] = i64(0)
assert m16['test'] == i64(0)
mut m17 := map[string]u64{}
m17['test'] = u64(0)
assert m17['test'] == u64(0)
mut m18 := map[string]&int{}
m18['test'] = &int(0)
assert m18['test'] == &int(0)*/
}
fn test_string_arr() {
mut m := map[string][]string{}
m['a'] = ['one', 'two']
assert m['a'].len == 2
assert m['a'][0] == 'one'
assert m['a'][1] == 'two'
}
fn mut_map(mut m map[string]int) {
m['a'] = 10
}
fn test_mut_arg() {
mut m := map[string]int{}
mut_map(mut m)
a := m['a']
assert a == 10
}
fn test_delete() {
mut m := map[string]int{}
m['one'] = 1
m['two'] = 2
println(m['two']) // => "2"
m.delete('two')
println(m['two'].str()) // => 0
assert ('two' in m) == false
println('two' in m) // => true, on Linux and Windows <-- wrong !
}
fn test_delete_size() {
arr := ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
mut m := map[string]int{}
for _ in 0 .. 10 {
for i in 0 .. 10 {
m[arr[i]] = i
}
assert m.len == 10
println(m.len)
for i in 0 .. 10 {
m.delete(arr[i])
}
}
}
fn test_nested_for_in() {
mut m := map[string]int{}
for i in 0 .. 1000 {
m[i.str()] = i
}
mut i := 0
for key1, _ in m {
assert key1 == i.str()
i++
mut j := 0
for key2, _ in m {
assert key2 == j.str()
j++
}
}
}
fn test_delete_in_for_in() {
mut m := map[string]string{}
for i in 0 .. 1000 {
m[i.str()] = i.str()
}
mut i := 0
for key, _ in m {
assert key == i.str()
m.delete(key)
i++
}
assert m.str() == '{}'
assert m.len == 0
}
// TODO: for in loop does not work as expected there
/*
fn test_set_in_for_in() {
mut m := map[string]string{}
for i in 0 .. 10 {
m[i.str()] = i.str()
}
mut last_key := ''
mut i := 0
for key, _ in m {
m['10'] = '10'
assert key == i.str()
last_key = key
i++
}
assert last_key == '10'
}
*/
fn test_delete_and_set_in_for_in() {
mut m := map[string]string{}
for i in 0 .. 1000 {
m[i.str()] = i.str()
}
mut i := 0
for key, _ in m {
assert key == i.str()
m.delete(key)
m[key] = i.str()
if i == 999 {
break
}
i++
}
assert m.len == 1000
i = 0
for key, _ in m {
assert m[key] == i.str()
i++
}
assert i == 1000
}
struct Mstruct1 {
pub mut:
mymap map[string]int
}
struct Mstruct2 {
pub mut:
mymap map[string]f64
}
struct Mstruct3 {
pub mut:
mymap map[string]u16
}
fn test_map_assign() {
mut a := map[string]f64{}
mut b := map[string]int{}
mut c := map[string]u16{}
a = {
'x': 12.4
'y': 3
}
b = {
'u': -13
'v': 12
}
c = {
's': u16(5)
't': 3
}
_ := Mstruct1{{
'p': 12
}}
_ := Mstruct2{{
'q': 1.7
}}
_ := Mstruct3{{
'r': u16(6)
's': 5
}}
println(a)
println(b)
println(c)
}
fn test_postfix_op_directly() {
mut a := map[string]int{}
a['aaa']++
assert a['aaa'] == 1
a['aaa']++
assert a['aaa'] == 2
a['bbb']--
assert a['bbb'] == -1
a['bbb']--
assert a['bbb'] == -2
}
fn test_map_push_directly() {
mut a := map[string][]string{}
a['aaa'] = []string{}
a['aaa'] << ['a', 'b', 'c']
assert a['aaa'].len == 3
assert a['aaa'] == ['a', 'b', 'c']
}
fn test_map_push_missing_key_does_not_insert() {
mut a := map[string][]string{}
a['aaa'] << 'a'
assert a == map[string][]string{}
}
fn test_assign_directly() {
mut a := map[string]int{}
a['aaa'] += 4
assert a['aaa'] == 4
a['aaa'] -= 2
assert a['aaa'] == 2
}
fn test_map_in_directly() {
for k, v in {
'aa': 1
} {
assert k == 'aa'
assert v == 1
}
}
fn test_plus_assign_string() {
mut m := {
'one': ''
}
m['one'] += '1'
assert m.len == 1
assert m['one'] == '1'
}
fn test_map_keys_to_array() {
m := {
'a': 'b'
'c': 'd'
}
mut arr := []string{}
for k, _ in m {
arr << k
}
sarr := arr.str()
println(sarr)
assert sarr == "['a', 'c']"
}
fn map_in_mut(mut m map[string]int) {
if 'one' in m {
m['one'] = 2
}
}
fn test_map_in_mut() {
mut m := {
'one': 1
}
map_in_mut(mut m)
assert m['one'] == 2
}
fn test_map_in() {
m := {
'Foo': 'bar'
}
if 'foo'.capitalize() in m {
println('ok')
} else {
assert false
}
}
fn mut_map_with_relation_op_in_fn(mut m map[string]int) {
if m['one'] == 1 {
m['three'] = 3
}
if m['two'] != 1 {
m['four'] = 4
}
if m['one'] > 0 {
m['five'] = 5
}
if m['one'] < 2 {
m['six'] = 6
}
if m['two'] >= 2 {
m['seven'] = 7
}
if m['two'] <= 2 {
m['eight'] = 8
}
}
fn test_mut_map_with_relation_op_in_fn() {
mut m := {
'one': 1
'two': 2
}
mut_map_with_relation_op_in_fn(mut m)
assert 'three' in m
assert 'four' in m
assert 'five' in m
assert 'six' in m
assert 'seven' in m
assert 'eight' in m
}
fn test_map_str_after_delete() {
mut m := {
'first': 1
'second': 2
'third': 3
}
osm := '${m}'
m.delete('second')
nsm := '${m}'
println('m: ${m}')
assert osm == "{'first': 1, 'second': 2, 'third': 3}"
assert nsm == "{'first': 1, 'third': 3}"
}
fn test_modify_map_value() {
mut m1 := {
'foo': 3
'bar': -7
}
m1['foo'] += 5
m1['bar'] *= -2
assert m1['foo'] == 8
assert m1['bar'] == 14
}
fn test_map_clone() {
mut nums := {
'foo': 1
'bar': 2
}
mut nums2 := nums.clone()
nums2['foo']++
nums2['bar'] *= 4
assert nums['foo'] == 1
assert nums['bar'] == 2
assert nums2['foo'] == 2
assert nums2['bar'] == 8
}
struct MValue {
name string
misc map[string]string
}
fn test_map_default_zero() {
m := map[string]MValue{}
v := m['unknown']
x := v.misc['x']
println(x)
assert x == ''
}
fn test_map_or() {
m := {
'first': 1
'second': 2
'third': 3
}
_ = m
// num := m['first'] or { return }
}
fn test_int_keys() {
mut m := map[int]int{}
m[3] = 9
m[4] = 16
assert m.len == 2
assert m[3] == 9
assert m[4] == 16
m[5] += 24
m[5]++
assert m[5] == 25
mut m2 := {
3: 9
4: 16
5: 25
}
four := 4
m2.delete(3)
m2.delete(four)
m2.delete(5)
assert m2.len == 0
assert m2[3] == 0
assert m2[4] == 0
assert m2[5] == 0
assert m2.keys() == []
m2 = {
3: 9
4: 16
5: 25
}
assert m2.len == 3
// clone
mc := m.clone()
same := mc == m
assert same
assert mc.len == 3
assert mc.keys() == [3, 4, 5]
mut all := []int{}
for k, v in mc {
assert m[k] == v
all << k
all << v
}
assert all == [3, 9, 4, 16, 5, 25]
mut m3 := {
1: 'one'
2: 'two'
}
assert m3[1] == 'one'
m3.delete(1)
}
enum Color {
red
green
blue
}
type ColorAlias = Color
fn test_alias_enum() {
mut m := map[ColorAlias]string{}
m[Color.red] = 'hi'
assert m[Color.red] == 'hi'
}
fn test_enum_in_map() {
mut m := map[Color]string{}
m[Color.red] = 'hi'
assert Color.red in m
assert Color.green !in m
assert Color.blue !in m
}
fn test_voidptr_keys() {
mut m := map[voidptr]string{}
v := 5
m[&v] = 'var'
m[&m] = 'map'
assert m[&v] == 'var'
assert m[&m] == 'map'
assert m.len == 2
}
fn test_rune_keys() {
mut m := {
`!`: 2
`%`: 3
}
assert typeof(m).name == 'map[rune]int'
assert m[`!`] == 2
m[`@`] = 7
assert m.len == 3
println(m)
assert '${m}' == '{`!`: 2, `%`: 3, `@`: 7}'
/*
mut a := []rune{}
for k, v in m {
a << k
a << rune(v) + `0`
}
assert a == [`!`, `2`, `%`, `3`, `@`, `7`]*/
}
fn test_eq() {
a := {
'a': 1
'b': 2
}
assert a == {
'a': 1
'b': 2
}
b := {
'a': [[1]]
'b': [[2]]
}
assert b == {
'a': [[1]]
'b': [[2]]
}
c := {
'a': {
'11': 1
}
'b': {
'22': 2
}
}
assert c == {
'a': {
'11': 1
}
'b': {
'22': 2
}
}
d := {
'a': MValue{
name: 'aa'
misc: {
'11': '1'
}
}
'b': MValue{
name: 'bb'
misc: {
'22': '2'
}
}
}
assert d == {
'a': MValue{
name: 'aa'
misc: {
'11': '1'
}
}
'b': MValue{
name: 'bb'
misc: {
'22': '2'
}
}
}
}
fn test_non_string_key_map_str() {
assert {
23: 4
}.str() == '{23: 4}'
// TODO: Make runes behave the same as in ES6 for new map impl
/*
assert {
`a`: 12
`b`: 13
}.str() == '{`a`: 12, `b`: 13}'*/
assert {
23: 'foo'
25: 'bar'
}.str() == "{23: 'foo', 25: 'bar'}"
}
fn test_map_assign_empty_map_init() {
mut a := {
'one': 1
}
a = {}
println(a)
assert a == map[string]int{}
assert '${a}' == '{}'
}
fn test_in_map_literal() {
assert 1 in {
1: 'one'
}
}
fn test_in_int_keyed_map_var() {
my_map := {
1: 'A'
}
assert 1 in my_map
assert 2 !in my_map
}
fn test_byte_keys() {
mut m := map[u8]u8{}
byte_max := u8(255)
for i in u8(0) .. byte_max {
m[i] = i
assert m[i] == i
}
for k, v in m {
assert k == v
}
for i in u8(0) .. 100 {
m[i]++
assert m[i] == i + 1
}
assert m.len == byte_max
keys := m.keys()
for i in u8(0) .. byte_max {
assert keys[i] == i
}
for i in u8(0) .. byte_max {
m.delete(i)
assert m[i] == 0
}
assert m.len == 0
}
fn test_i16_keys() {
mut m := map[i16]i16{}
end := i16(1000)
for i in i16(0) .. end {
m[i] = i
assert m[i] == i
}
for k, v in m {
assert k == v
}
for i in i16(0) .. 500 {
m[i]++
assert m[i] == i + 1
}
assert m.len == end
keys := m.keys()
for i in i16(0) .. end {
assert keys[i] == i
}
for i in i16(0) .. end {
m.delete(i)
assert m[i] == 0
}
assert m.len == 0
}
fn test_u16_keys() {
mut m := map[u16]u16{}
end := u16(1000)
for i in u16(0) .. end {
m[i] = i
assert m[i] == i
}
for k, v in m {
assert k == v
}
for i in u16(0) .. 500 {
m[i]++
assert m[i] == i + 1
}
assert m.len == end
keys := m.keys()
for i in u16(0) .. end {
assert keys[i] == i
}
for i in u16(0) .. end {
m.delete(i)
assert m[i] == 0
}
assert m.len == 0
}
fn test_u32_keys() {
mut m := map[u32]u32{}
end := u32(1000)
for i in u32(0) .. end {
m[i] = i
assert m[i] == i
}
for k, v in m {
assert k == v
}
for i in u32(0) .. 500 {
m[i]++
assert m[i] == i + 1
}
assert m.len == end
keys := m.keys()
for i in u32(0) .. end {
assert keys[i] == i
}
for i in u32(0) .. end {
m.delete(i)
assert m[i] == 0
}
assert m.len == 0
}
fn test_int_keys2() {
mut m := map[int]int{}
end := 1000
for i in int(0) .. end {
m[i] = i
assert m[i] == i
}
for k, v in m {
assert k == v
}
for i in int(0) .. 500 {
m[i]++
assert m[i] == i + 1
}
assert m.len == end
keys := m.keys()
for i in int(0) .. end {
assert keys[i] == i
}
for i in int(0) .. end {
m.delete(i)
assert m[i] == 0
}
assert m.len == 0
}
fn test_i64_keys() {
mut m := map[i64]i64{}
end := i64(1000)
for i in i64(0) .. end {
m[i] = i
assert m[i] == i
}
for k, v in m {
assert k == v
}
for i in i64(0) .. 500 {
m[i]++
assert m[i] == i + 1
}
assert m.len == end
keys := m.keys()
for i in i64(0) .. end {
assert keys[int(i)] == i
}
for i in i64(0) .. end {
m.delete(i)
assert m[i] == 0
}
assert m.len == 0
}
fn test_u64_keys() {
mut m := map[u64]u64{}
end := u64(1000)
for i in u64(0) .. end {
m[i] = i
assert m[i] == i
}
for k, v in m {
assert k == v
}
for i in u64(0) .. 500 {
m[i]++
assert m[i] == i + 1
}
assert u64(m.len) == end
keys := m.keys()
for i in u64(0) .. end {
assert keys[int(i)] == i
}
for i in u64(0) .. end {
m.delete(i)
assert m[i] == 0
}
assert m.len == 0
}
fn test_map_set_fixed_array_variable() {
mut m := map[string][2]f64{}
m['A'] = [1.1, 2.2]!
println(m)
assert '${m}' == "{'A': [1.1, 2.2]}"
mut m2 := map[string][2]f64{}
arr := [1.1, 2.2]!
m2['A'] = arr
println(m2)
assert '${m2}' == "{'A': [1.1, 2.2]}"
}
+79
View File
@@ -0,0 +1,79 @@
module builtin
pub interface JS.Promise {
then(onFullfiled JS.Any, onRejected JS.Any)
catch(onCatch JS.Any) JS.Promise
finally(callback JS.Any) JS.Promise
}
@[use_new]
pub fn JS.Promise.prototype.constructor(JS.Any) JS.Promise
pub fn JS.Promise.reject(JS.Any) JS.Promise
pub fn JS.Promise.resolve(JS.Any) JS.Promise
pub fn JS.Promise.race(JS.Array) JS.Promise
// Promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
pub struct Promise[T] {
pub mut:
promise JS.Promise @[noinit]
}
pub fn promise_new[T](executor fn (resolve fn (T), reject fn (JS.Any))) Promise[T] {
promise := JS.Promise.prototype.constructor(executor)
return Promise[T]{promise}
}
pub fn (p Promise[T]) then(on_fulfilled fn (T), on_rejected fn (JS.Any)) {
p.promise.then(on_fulfilled, on_rejected)
}
// catch returns a Promise and deals with rejected cases only.
pub fn (p Promise[T]) catch(callback fn (error JS.Any)) Promise[T] {
promise := p.promise.catch(callback)
return Promise[T]{promise}
}
pub fn (p Promise[T]) finally[U](callback fn ()) Promise[JS.Any] {
promise := p.promise.finally(callback)
return Promise[JS.Any]{promise}
}
// promise_reject returns promise which was rejected because of specified error.
pub fn promise_reject(error JS.Any) Promise[JS.Any] {
promise := JS.Promise.reject(error)
return Promise[JS.Any]{promise}
}
// resolve returns promise which was resolved with specified value.
pub fn promise_resolve[T](result T) Promise[T] {
promise := JS.Promise.resolve(result)
return Promise[T]{promise}
}
// promise_race returns a promise, that fulfills or rejects, as soon as one of the promises in an iterable fulfills or rejects.
// It returns the value or reason from that first promise.
pub fn promise_race[T](promises []Promise[T]) Promise[T] {
promises_ := JS.Array.prototype.constructor()
for elem in promises {
promises_.push(elem.promise)
}
promise := JS.Promise.race(promises_)
return Promise[T]{promise}
}
pub fn JS.Promise.all(JS.Array) JS.Promise
pub fn JS.Promise.allSettled(JS.Array) JS.Promise
/*
pub type JsAny = JS.Any
// all takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises.
pub fn all(array []JS.Promise) Promise<JS.Array, js.promise.JsAny> {
mut promise := JS.Promise(JS.Any(voidptr(0)))
#promise = Promise.all(array.arr.arr);
return Promise<JS.Array,JsAny>{promise}
}
*/
+29
View File
@@ -0,0 +1,29 @@
module builtin
import strings
pub fn (ra []rune) string() string {
mut sb := strings.new_builder(ra.len)
sb.write_runes(ra)
res := sb.str()
return res
}
pub fn (c rune) repeat(count int) string {
if count <= 0 {
return ''
} else if count == 1 {
return c.str()
}
res := ''
#res.str = String.fromCharCode(Number(c.val))
return res.repeat(count)
}
pub fn (c rune) str() string {
res := ''
#res.str = String.fromCharCode(Number(c.val))
return res
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+17
View File
@@ -0,0 +1,17 @@
module builtin
pub fn utf8_str_visible_length(s string) int {
// todo: proper implementation
res := 0
#res.val = s.str.length;
return res
}
pub fn utf8_str_len(s string) int {
return s.len
}
pub fn utf8_char_len(b u8) int {
return ((0xe5000000 >> ((b >> 3) & 0x1e)) & 3) + 1
}