v2 / vlib / builtin / js / builtin.js.v
183 lines · 154 sloc · 4.49 KB · 8bd5cf064bb488e9f92986ab20ac30bd468ccf2e
Raw
1module builtin
2
3// used to generate JS throw statements.
4
5$if js_node {
6 #var $fs = require('fs');
7}
8
9@[noreturn]
10pub 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
22pub fn flush_stdout() {
23 // needed for parity with builtin.c.v
24}
25
26pub fn flush_stderr() {
27 // needed for parity with builtin.c.v
28}
29
30pub fn println(s string) {
31 $if js_freestanding {
32 #globalPrint(s.str)
33 } $else {
34 #console.log(s.str)
35 }
36}
37
38pub 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
48pub fn eprintln(s string) {
49 $if js_freestanding {
50 #globalPrint(s.str)
51 } $else {
52 #console.error(s.str)
53 }
54}
55
56pub 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).
66pub 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.
84pub 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]
93pub fn exit(c int) {
94 JS.process.exit(c)
95 js_throw('exit(${c})')
96}
97
98fn opt_ok(data voidptr, option Option) {
99 #option.state = 0
100 #option.err = none__
101 #option.data = data
102}
103
104pub 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
117fn 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
152pub fn print_backtrace() {
153 println(js_stacktrace())
154}
155
156pub 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
166pub 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
178pub fn (f float_literal) str() string {
179 res := ''
180 #res.str += f.valueOf()
181
182 return res
183}
184