| 1 | module builtin |
| 2 | |
| 3 | // used to generate JS throw statements. |
| 4 | |
| 5 | $if js_node { |
| 6 | #var $fs = require('fs'); |
| 7 | } |
| 8 | |
| 9 | @[noreturn] |
| 10 | pub fn js_throw(s any) { |
| 11 | #throw s |
| 12 | |
| 13 | for {} |
| 14 | } |
| 15 | |
| 16 | #let globalPrint, globalWrite; |
| 17 | $if js_freestanding { |
| 18 | #globalPrint = globalThis.print |
| 19 | #globalWrite = (typeof globalThis.write === 'function')? write: globalThis.print |
| 20 | } |
| 21 | |
| 22 | pub fn flush_stdout() { |
| 23 | // needed for parity with builtin.c.v |
| 24 | } |
| 25 | |
| 26 | pub fn flush_stderr() { |
| 27 | // needed for parity with builtin.c.v |
| 28 | } |
| 29 | |
| 30 | pub fn println(s string) { |
| 31 | $if js_freestanding { |
| 32 | #globalPrint(s.str) |
| 33 | } $else { |
| 34 | #console.log(s.str) |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | pub fn print(s string) { |
| 39 | $if js_node { |
| 40 | #$process.stdout.write(s.str) |
| 41 | } $else $if js_freestanding { |
| 42 | #globalWrite(s.str) |
| 43 | } $else { |
| 44 | panic('Cannot `print` in a browser, use `println` instead') |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | pub fn eprintln(s string) { |
| 49 | $if js_freestanding { |
| 50 | #globalPrint(s.str) |
| 51 | } $else { |
| 52 | #console.error(s.str) |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | pub fn eprint(s string) { |
| 57 | $if js_node { |
| 58 | #$process.stderr.write(s.str) |
| 59 | } $else { |
| 60 | panic('Cannot `eprint` in a browser, use `println` instead') |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | // input_character gives back a single character, read from the standard input. |
| 65 | // It returns -1 on error (when the input is finished (EOF), on a broken pipe etc). |
| 66 | pub fn input_character() int { |
| 67 | $if js_node { |
| 68 | mut ch := -1 |
| 69 | #try { |
| 70 | #const read_buffer = Buffer.alloc(1) |
| 71 | #const nbytes = $fs.readSync(0, read_buffer, 0, 1, null) |
| 72 | #if (nbytes > 0) { ch.val = read_buffer[0] } |
| 73 | #} catch (e) {} |
| 74 | |
| 75 | return ch |
| 76 | } $else { |
| 77 | return -1 |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | // print_character writes the single character `ch` to the standard output. |
| 82 | // It returns the written character value, or panics if the active JS runtime |
| 83 | // does not support stdout writes. |
| 84 | pub fn print_character(ch u8) int { |
| 85 | print(ch.ascii_str()) |
| 86 | return ch |
| 87 | } |
| 88 | |
| 89 | // Exits the process in node, and halts execution in the browser |
| 90 | // because `process.exit` is undefined. Workaround for not having |
| 91 | // a 'real' way to exit in the browser. |
| 92 | @[noreturn] |
| 93 | pub fn exit(c int) { |
| 94 | JS.process.exit(c) |
| 95 | js_throw('exit(${c})') |
| 96 | } |
| 97 | |
| 98 | fn opt_ok(data voidptr, option Option) { |
| 99 | #option.state = 0 |
| 100 | #option.err = none__ |
| 101 | #option.data = data |
| 102 | } |
| 103 | |
| 104 | pub fn unwrap(opt string) string { |
| 105 | mut o := Option{} |
| 106 | #o = opt |
| 107 | if o.state != 0 { |
| 108 | js_throw(o.err) |
| 109 | } |
| 110 | |
| 111 | mut res := '' |
| 112 | #res = opt.data |
| 113 | |
| 114 | return res |
| 115 | } |
| 116 | |
| 117 | fn js_stacktrace() string { |
| 118 | stacktrace := '' |
| 119 | #let err = new TypeError(); |
| 120 | #err.name = 'stacktrace: ' |
| 121 | #stacktrace.str = err.stack |
| 122 | |
| 123 | return stacktrace |
| 124 | } |
| 125 | |
| 126 | // v_clone_value preserves standalone JS semantics for V clone methods. |
| 127 | #function v_clone_value(value) { |
| 128 | #if (value === null || value === undefined) return value; |
| 129 | #if (value instanceof $ref) return new $ref(v_clone_value(value.val)); |
| 130 | #if (value instanceof array) return array_clone(value); |
| 131 | #if (value instanceof map) { |
| 132 | #let cloned = {} |
| 133 | #for (const key in value.map) cloned[key] = { key: v_clone_value(value.map[key].key), val: v_clone_value(value.map[key].val) } |
| 134 | #return new map(cloned); |
| 135 | #} |
| 136 | #if (typeof value !== 'object') return value; |
| 137 | #if (typeof value.$toJS === 'function') { |
| 138 | #let cloned = Object.create(Object.getPrototypeOf(value) || Object.prototype); |
| 139 | #for (const key of Object.keys(value)) cloned[key] = v_clone_value(value[key]); |
| 140 | #return cloned; |
| 141 | #} |
| 142 | #let cloned; |
| 143 | #try { |
| 144 | #cloned = typeof value.constructor === 'function' ? new value.constructor({}) : Object.create(Object.getPrototypeOf(value)); |
| 145 | #} catch (e) { |
| 146 | #cloned = Object.create(Object.getPrototypeOf(value) || Object.prototype); |
| 147 | #} |
| 148 | #for (const key of Object.keys(value)) cloned[key] = v_clone_value(value[key]); |
| 149 | #return cloned; |
| 150 | #} |
| 151 | |
| 152 | pub fn print_backtrace() { |
| 153 | println(js_stacktrace()) |
| 154 | } |
| 155 | |
| 156 | pub fn (a array) clone() array { |
| 157 | mut res := empty_array() |
| 158 | #const source = a instanceof $ref ? a.val : a |
| 159 | #const cloned = source.arr.arr.slice(source.arr.index_start.valueOf(), source.arr.index_start.valueOf() + source.len.valueOf()).map(v_clone_value) |
| 160 | #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)})) |
| 161 | |
| 162 | return res |
| 163 | } |
| 164 | |
| 165 | // Check for nil value |
| 166 | pub fn isnil(val voidptr) bool { |
| 167 | res := false |
| 168 | // This one is kinda weird. In C and native backend we can cast booleans and integers to pointers |
| 169 | // so we just check *for* all possible NULL-like values here. |
| 170 | #if (typeof val == 'function') { res.val = false; } else { |
| 171 | #val = val instanceof voidptr ? val.valueOf().val : val; |
| 172 | #res.val = val === null || val === undefined || val === false || val === 0 || val === BigInt(0) || (val instanceof int ? val.val == 0 : false) |
| 173 | #} |
| 174 | |
| 175 | return res |
| 176 | } |
| 177 | |
| 178 | pub fn (f float_literal) str() string { |
| 179 | res := '' |
| 180 | #res.str += f.valueOf() |
| 181 | |
| 182 | return res |
| 183 | } |
| 184 | |