kimchilang 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/.github/workflows/ci.yml +66 -0
  2. package/README.md +1547 -0
  3. package/create-kimchi-app/README.md +44 -0
  4. package/create-kimchi-app/index.js +214 -0
  5. package/create-kimchi-app/package.json +22 -0
  6. package/editors/README.md +121 -0
  7. package/editors/sublime/KimchiLang.sublime-syntax +138 -0
  8. package/editors/vscode/README.md +90 -0
  9. package/editors/vscode/kimchilang-1.1.0.vsix +0 -0
  10. package/editors/vscode/language-configuration.json +37 -0
  11. package/editors/vscode/package.json +55 -0
  12. package/editors/vscode/src/extension.js +354 -0
  13. package/editors/vscode/syntaxes/kimchi.tmLanguage.json +215 -0
  14. package/examples/api/client.km +36 -0
  15. package/examples/async_pipe.km +58 -0
  16. package/examples/basic.kimchi +109 -0
  17. package/examples/cli_framework/README.md +92 -0
  18. package/examples/cli_framework/calculator.km +61 -0
  19. package/examples/cli_framework/deploy.km +126 -0
  20. package/examples/cli_framework/greeter.km +26 -0
  21. package/examples/config.static +27 -0
  22. package/examples/config.static.js +10 -0
  23. package/examples/env_test.km +37 -0
  24. package/examples/fibonacci.kimchi +17 -0
  25. package/examples/greeter.km +15 -0
  26. package/examples/hello.js +1 -0
  27. package/examples/hello.kimchi +3 -0
  28. package/examples/js_interop.km +42 -0
  29. package/examples/logger_example.km +34 -0
  30. package/examples/memo_fibonacci.km +17 -0
  31. package/examples/myapp/lib/http.js +14 -0
  32. package/examples/myapp/lib/http.km +16 -0
  33. package/examples/myapp/main.km +16 -0
  34. package/examples/myapp/main_with_mock.km +42 -0
  35. package/examples/myapp/services/api.js +18 -0
  36. package/examples/myapp/services/api.km +18 -0
  37. package/examples/new_features.kimchi +52 -0
  38. package/examples/project_example.static +20 -0
  39. package/examples/readme_examples.km +240 -0
  40. package/examples/reduce_pattern_match.km +85 -0
  41. package/examples/regex_match.km +46 -0
  42. package/examples/sample.js +45 -0
  43. package/examples/sample.km +39 -0
  44. package/examples/secrets.static +35 -0
  45. package/examples/secrets.static.js +30 -0
  46. package/examples/shell-example.mjs +144 -0
  47. package/examples/shell_example.km +19 -0
  48. package/examples/stdlib_test.km +22 -0
  49. package/examples/test_example.km +69 -0
  50. package/examples/testing/README.md +88 -0
  51. package/examples/testing/http_client.km +18 -0
  52. package/examples/testing/math.km +48 -0
  53. package/examples/testing/math.test.km +93 -0
  54. package/examples/testing/user_service.km +29 -0
  55. package/examples/testing/user_service.test.km +72 -0
  56. package/examples/use-config.mjs +141 -0
  57. package/examples/use_config.km +13 -0
  58. package/install.sh +59 -0
  59. package/package.json +29 -0
  60. package/pantry/acorn/index.km +1 -0
  61. package/pantry/is_number/index.km +1 -0
  62. package/pantry/is_odd/index.km +2 -0
  63. package/project.static +6 -0
  64. package/src/cli.js +1245 -0
  65. package/src/generator.js +1241 -0
  66. package/src/index.js +141 -0
  67. package/src/js2km.js +568 -0
  68. package/src/lexer.js +822 -0
  69. package/src/linter.js +810 -0
  70. package/src/package-manager.js +307 -0
  71. package/src/parser.js +1876 -0
  72. package/src/static-parser.js +500 -0
  73. package/src/typechecker.js +950 -0
  74. package/stdlib/array.km +0 -0
  75. package/stdlib/bitwise.km +38 -0
  76. package/stdlib/console.km +49 -0
  77. package/stdlib/date.km +97 -0
  78. package/stdlib/function.km +44 -0
  79. package/stdlib/http.km +197 -0
  80. package/stdlib/http.md +333 -0
  81. package/stdlib/index.km +26 -0
  82. package/stdlib/json.km +17 -0
  83. package/stdlib/logger.js +114 -0
  84. package/stdlib/logger.km +104 -0
  85. package/stdlib/math.km +120 -0
  86. package/stdlib/object.km +41 -0
  87. package/stdlib/promise.km +33 -0
  88. package/stdlib/string.km +93 -0
  89. package/stdlib/testing.md +265 -0
  90. package/test/test.js +599 -0
package/stdlib/http.md ADDED
@@ -0,0 +1,333 @@
1
+ # HTTP Module
2
+
3
+ A promise-based HTTP client wrapper for Node.js http/https modules.
4
+
5
+ ## Import
6
+
7
+ ```kimchi
8
+ as http dep stdlib.http
9
+ ```
10
+
11
+ ## Functions
12
+
13
+ ### `get(url, options)`
14
+
15
+ Make an HTTP GET request.
16
+
17
+ ```kimchi
18
+ dec response = await http.get("https://api.example.com/users")
19
+ print response.body
20
+ ```
21
+
22
+ **Parameters:**
23
+ - `url` - The URL to request
24
+ - `options` - Optional request options (headers, timeout)
25
+
26
+ **Returns:** Response object
27
+
28
+ ---
29
+
30
+ ### `post(url, body, options)`
31
+
32
+ Make an HTTP POST request.
33
+
34
+ ```kimchi
35
+ dec response = await http.post("https://api.example.com/users", {
36
+ name: "Alice",
37
+ email: "alice@example.com"
38
+ })
39
+ print response.body
40
+ ```
41
+
42
+ **Parameters:**
43
+ - `url` - The URL to request
44
+ - `body` - Request body (automatically JSON stringified if object)
45
+ - `options` - Optional request options
46
+
47
+ **Returns:** Response object
48
+
49
+ ---
50
+
51
+ ### `put(url, body, options)`
52
+
53
+ Make an HTTP PUT request.
54
+
55
+ ```kimchi
56
+ dec response = await http.put("https://api.example.com/users/123", {
57
+ name: "Alice Updated"
58
+ })
59
+ ```
60
+
61
+ **Parameters:**
62
+ - `url` - The URL to request
63
+ - `body` - Request body
64
+ - `options` - Optional request options
65
+
66
+ **Returns:** Response object
67
+
68
+ ---
69
+
70
+ ### `patch(url, body, options)`
71
+
72
+ Make an HTTP PATCH request.
73
+
74
+ ```kimchi
75
+ dec response = await http.patch("https://api.example.com/users/123", {
76
+ email: "newemail@example.com"
77
+ })
78
+ ```
79
+
80
+ **Parameters:**
81
+ - `url` - The URL to request
82
+ - `body` - Request body
83
+ - `options` - Optional request options
84
+
85
+ **Returns:** Response object
86
+
87
+ ---
88
+
89
+ ### `del(url, options)`
90
+
91
+ Make an HTTP DELETE request.
92
+
93
+ ```kimchi
94
+ dec response = await http.del("https://api.example.com/users/123")
95
+ if response.ok {
96
+ print "User deleted"
97
+ }
98
+ ```
99
+
100
+ **Parameters:**
101
+ - `url` - The URL to request
102
+ - `options` - Optional request options
103
+
104
+ **Returns:** Response object
105
+
106
+ ---
107
+
108
+ ### `request(url, options)`
109
+
110
+ Generic HTTP request function. All other methods use this internally.
111
+
112
+ ```kimchi
113
+ dec response = await http.request("https://api.example.com/data", {
114
+ method: "POST",
115
+ headers: {
116
+ "Content-Type": "application/json",
117
+ "Authorization": "Bearer token123"
118
+ },
119
+ body: { key: "value" },
120
+ timeout: 5000
121
+ })
122
+ ```
123
+
124
+ **Parameters:**
125
+ - `url` - The URL to request
126
+ - `options` - Request options:
127
+ - `method` - HTTP method (GET, POST, PUT, PATCH, DELETE)
128
+ - `headers` - Request headers object
129
+ - `body` - Request body
130
+ - `timeout` - Request timeout in milliseconds (default: 30000)
131
+
132
+ **Returns:** Response object
133
+
134
+ ---
135
+
136
+ ### `queryString(params)`
137
+
138
+ Build a URL query string from an object.
139
+
140
+ ```kimchi
141
+ dec qs = http.queryString({ page: 1, limit: 10, search: "hello world" })
142
+ // Returns: "page=1&limit=10&search=hello%20world"
143
+ ```
144
+
145
+ **Parameters:**
146
+ - `params` - Object with key-value pairs
147
+
148
+ **Returns:** URL-encoded query string
149
+
150
+ ---
151
+
152
+ ### `buildUrl(baseUrl, params)`
153
+
154
+ Build a complete URL with query parameters.
155
+
156
+ ```kimchi
157
+ dec url = http.buildUrl("https://api.example.com/search", {
158
+ q: "kimchi",
159
+ page: 1
160
+ })
161
+ // Returns: "https://api.example.com/search?q=kimchi&page=1"
162
+ ```
163
+
164
+ **Parameters:**
165
+ - `baseUrl` - Base URL
166
+ - `params` - Query parameters object
167
+
168
+ **Returns:** Complete URL with query string
169
+
170
+ ---
171
+
172
+ ### `createClient(baseOptions)`
173
+
174
+ Create a reusable HTTP client with default options.
175
+
176
+ ```kimchi
177
+ dec api = http.createClient({
178
+ baseUrl: "https://api.example.com",
179
+ headers: {
180
+ "Authorization": "Bearer token123",
181
+ "Accept": "application/json"
182
+ },
183
+ timeout: 10000
184
+ })
185
+
186
+ // Now use the client - paths are relative to baseUrl
187
+ dec users = await api.get("/users")
188
+ dec user = await api.post("/users", { name: "Bob" })
189
+ dec updated = await api.put("/users/123", { name: "Bob Updated" })
190
+ dec patched = await api.patch("/users/123", { email: "bob@new.com" })
191
+ dec deleted = await api.del("/users/123")
192
+ ```
193
+
194
+ **Parameters:**
195
+ - `baseOptions` - Client configuration:
196
+ - `baseUrl` - Base URL prepended to all requests
197
+ - `headers` - Default headers for all requests
198
+ - `timeout` - Default timeout for all requests
199
+
200
+ **Returns:** Client object with `get`, `post`, `put`, `patch`, `del` methods
201
+
202
+ ---
203
+
204
+ ## Response Object
205
+
206
+ All request functions return a response object with the following properties:
207
+
208
+ ```kimchi
209
+ {
210
+ status: 200, // HTTP status code
211
+ statusText: "OK", // HTTP status message
212
+ headers: {...}, // Response headers
213
+ body: {...}, // Response body (auto-parsed if JSON)
214
+ ok: true // true if status is 200-299
215
+ }
216
+ ```
217
+
218
+ ### Checking Response Status
219
+
220
+ ```kimchi
221
+ dec response = await http.get("https://api.example.com/users")
222
+
223
+ if response.ok {
224
+ print "Success: ${response.body}"
225
+ } else {
226
+ print "Error ${response.status}: ${response.statusText}"
227
+ }
228
+ ```
229
+
230
+ ---
231
+
232
+ ## Examples
233
+
234
+ ### Simple GET Request
235
+
236
+ ```kimchi
237
+ as http dep stdlib.http
238
+
239
+ dec response = await http.get("https://jsonplaceholder.typicode.com/posts/1")
240
+ print "Title: ${response.body.title}"
241
+ ```
242
+
243
+ ### POST with JSON Body
244
+
245
+ ```kimchi
246
+ as http dep stdlib.http
247
+
248
+ dec response = await http.post("https://jsonplaceholder.typicode.com/posts", {
249
+ title: "My Post",
250
+ body: "This is the content",
251
+ userId: 1
252
+ })
253
+
254
+ print "Created post with ID: ${response.body.id}"
255
+ ```
256
+
257
+ ### Using Custom Headers
258
+
259
+ ```kimchi
260
+ as http dep stdlib.http
261
+
262
+ dec response = await http.get("https://api.example.com/protected", {
263
+ headers: {
264
+ "Authorization": "Bearer my-token",
265
+ "X-Custom-Header": "custom-value"
266
+ }
267
+ })
268
+ ```
269
+
270
+ ### Creating an API Client
271
+
272
+ ```kimchi
273
+ as http dep stdlib.http
274
+
275
+ // Create a client for a specific API
276
+ dec github = http.createClient({
277
+ baseUrl: "https://api.github.com",
278
+ headers: {
279
+ "Accept": "application/vnd.github.v3+json",
280
+ "Authorization": "token ghp_xxxxxxxxxxxx"
281
+ }
282
+ })
283
+
284
+ // Fetch user info
285
+ dec user = await github.get("/user")
286
+ print "Logged in as: ${user.body.login}"
287
+
288
+ // List repositories
289
+ dec repos = await github.get("/user/repos")
290
+ for repo in repos.body {
291
+ print "- ${repo.name}"
292
+ }
293
+ ```
294
+
295
+ ### Error Handling
296
+
297
+ ```kimchi
298
+ as http dep stdlib.http
299
+
300
+ try {
301
+ dec response = await http.get("https://api.example.com/users/999")
302
+
303
+ |response.status == 404| => {
304
+ print "User not found"
305
+ }
306
+ |response.status == 401| => {
307
+ print "Unauthorized - please log in"
308
+ }
309
+ |response.ok| => {
310
+ print "User: ${response.body.name}"
311
+ }
312
+ |true| => {
313
+ print "Unexpected error: ${response.status}"
314
+ }
315
+ } catch(e) {
316
+ print "Network error: ${e.message}"
317
+ }
318
+ ```
319
+
320
+ ### Building URLs with Query Parameters
321
+
322
+ ```kimchi
323
+ as http dep stdlib.http
324
+
325
+ dec url = http.buildUrl("https://api.example.com/search", {
326
+ q: "kimchi lang",
327
+ page: 1,
328
+ limit: 20
329
+ })
330
+
331
+ dec results = await http.get(url)
332
+ print "Found ${results.body.total} results"
333
+ ```
@@ -0,0 +1,26 @@
1
+ // KimchiLang Standard Library
2
+ // Main entry point
3
+
4
+ expose fn _describe() {
5
+ return "KimchiLang Standard Library - functional utilities for arrays, strings, objects, math, and more"
6
+ }
7
+
8
+ expose fn _help() {
9
+ return "
10
+ Available modules:
11
+ stdlib.array - Array utilities (map, filter, reduce, etc.)
12
+ stdlib.string - String utilities (split, trim, replace, etc.)
13
+ stdlib.object - Object utilities (keys, values, entries, etc.)
14
+ stdlib.math - Math utilities (abs, round, trig, etc.)
15
+ stdlib.json - JSON utilities (parse, stringify, pretty)
16
+ stdlib.console - Console/IO utilities (log, error, table, etc.)
17
+ stdlib.promise - Promise utilities (all, race, delay, etc.)
18
+ stdlib.date - Date/time utilities (now, format, diff, etc.)
19
+ stdlib.function - Function utilities (compose, pipe, etc.)
20
+
21
+ Usage:
22
+ as arr dep stdlib.array
23
+ as str dep stdlib.string
24
+ as math dep stdlib.math
25
+ "
26
+ }
package/stdlib/json.km ADDED
@@ -0,0 +1,17 @@
1
+ // KimchiLang Standard Library - JSON Functions
2
+
3
+ expose fn _describe() {
4
+ return "JSON utilities: parse, stringify, pretty print"
5
+ }
6
+
7
+ expose fn parse(str) {
8
+ return JSON.parse(str)
9
+ }
10
+
11
+ expose fn stringify(obj) {
12
+ return JSON.stringify(obj)
13
+ }
14
+
15
+ expose fn pretty(obj, indent) {
16
+ return JSON.stringify(obj, null, indent || 2)
17
+ }
@@ -0,0 +1,114 @@
1
+ // KimchiLang Logger Module
2
+ // Provides structured JSON logging with log levels
3
+
4
+ const LOG_LEVELS = {
5
+ debug: 0,
6
+ info: 1,
7
+ warn: 2,
8
+ error: 3,
9
+ };
10
+
11
+ function getLogLevel() {
12
+ const level = (process.env.LOG_LEVEL || 'info').toLowerCase();
13
+ return LOG_LEVELS[level] ?? LOG_LEVELS.info;
14
+ }
15
+
16
+ function getCallerInfo() {
17
+ const err = new Error();
18
+ const stack = err.stack.split('\n');
19
+
20
+ // Find the first stack frame outside of logger.js
21
+ for (let i = 2; i < stack.length; i++) {
22
+ const line = stack[i];
23
+ if (!line.includes('logger.js') && !line.includes('node:internal')) {
24
+ // Parse stack frame: " at functionName (file:line:col)" or " at file:line:col"
25
+ const match = line.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?/);
26
+ if (match) {
27
+ const functionName = match[1] || '<anonymous>';
28
+ const filePath = match[2];
29
+ const lineNumber = parseInt(match[3], 10);
30
+
31
+ // Extract module path from file path
32
+ const modulePath = filePath
33
+ .replace(/^file:\/\//, '')
34
+ .replace(/.*\//, '')
35
+ .replace(/\.(js|km)$/, '');
36
+
37
+ return {
38
+ function: functionName,
39
+ module: modulePath,
40
+ line: lineNumber,
41
+ file: filePath,
42
+ };
43
+ }
44
+ }
45
+ }
46
+
47
+ return {
48
+ function: '<unknown>',
49
+ module: '<unknown>',
50
+ line: 0,
51
+ file: '<unknown>',
52
+ };
53
+ }
54
+
55
+ function formatLog(level, message, data = {}) {
56
+ const caller = getCallerInfo();
57
+ const timestamp = new Date().toISOString();
58
+
59
+ const logEntry = {
60
+ timestamp,
61
+ level,
62
+ module: caller.module,
63
+ function: caller.function,
64
+ line: caller.line,
65
+ message,
66
+ ...data,
67
+ };
68
+
69
+ return JSON.stringify(logEntry);
70
+ }
71
+
72
+ function shouldLog(level) {
73
+ const currentLevel = getLogLevel();
74
+ return LOG_LEVELS[level] >= currentLevel;
75
+ }
76
+
77
+ export const logger = {
78
+ debug(message, data) {
79
+ if (shouldLog('debug')) {
80
+ console.log(formatLog('debug', message, data));
81
+ }
82
+ },
83
+
84
+ info(message, data) {
85
+ if (shouldLog('info')) {
86
+ console.log(formatLog('info', message, data));
87
+ }
88
+ },
89
+
90
+ warn(message, data) {
91
+ if (shouldLog('warn')) {
92
+ console.warn(formatLog('warn', message, data));
93
+ }
94
+ },
95
+
96
+ error(message, data) {
97
+ if (shouldLog('error')) {
98
+ console.error(formatLog('error', message, data));
99
+ }
100
+ },
101
+
102
+ // Create a child logger with additional context
103
+ child(context) {
104
+ return {
105
+ debug: (message, data) => logger.debug(message, { ...context, ...data }),
106
+ info: (message, data) => logger.info(message, { ...context, ...data }),
107
+ warn: (message, data) => logger.warn(message, { ...context, ...data }),
108
+ error: (message, data) => logger.error(message, { ...context, ...data }),
109
+ child: (moreContext) => logger.child({ ...context, ...moreContext }),
110
+ };
111
+ },
112
+ };
113
+
114
+ export default logger;
@@ -0,0 +1,104 @@
1
+ // KimchiLang Logger
2
+ // Usage: as log dep stdlib.logger
3
+ // Then: log.info("message"), log.debug("message"), etc.
4
+ // Set LOG_LEVEL environment variable to control output (debug, info, warn, error)
5
+
6
+ env LOG_LEVEL = "info"
7
+
8
+ dec LOG_LEVELS = {
9
+ debug: 0,
10
+ info: 1,
11
+ warn: 2,
12
+ error: 3
13
+ }
14
+
15
+ fn getLogLevel() {
16
+ dec level = LOG_LEVEL.toLowerCase()
17
+ dec numLevel = LOG_LEVELS[level]
18
+ |numLevel == null| => return 1
19
+ return numLevel
20
+ }
21
+
22
+ fn shouldLog(level) {
23
+ return LOG_LEVELS[level] >= getLogLevel()
24
+ }
25
+
26
+ fn getCallerInfo() {
27
+ return js {
28
+ const err = new Error();
29
+ const stack = err.stack.split('\n');
30
+ for (let i = 3; i < stack.length; i++) {
31
+ const line = stack[i];
32
+ if (!line.includes('logger') && !line.includes('node:internal')) {
33
+ const match = line.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?/);
34
+ if (match) {
35
+ return {
36
+ fn: match[1] || '<anonymous>',
37
+ module: match[2].replace(/^file:\/\//, '').replace(/.*\//, '').replace(/\.(js|km)$/, ''),
38
+ line: parseInt(match[3], 10),
39
+ };
40
+ }
41
+ }
42
+ }
43
+ return { fn: '<unknown>', module: '<unknown>', line: 0 };
44
+ }
45
+ }
46
+
47
+ fn formatLog(level, message, data) {
48
+ dec caller = getCallerInfo()
49
+ dec timestamp = js { return new Date().toISOString(); }
50
+
51
+ dec entry = {
52
+ timestamp: timestamp,
53
+ level: level,
54
+ module: caller.module,
55
+ function: caller.fn,
56
+ line: caller.line,
57
+ message: message
58
+ }
59
+
60
+ |data != null| => {
61
+ js(entry, data) {
62
+ Object.assign(entry, data);
63
+ }
64
+ }
65
+
66
+ return js(entry) { return JSON.stringify(entry); }
67
+ }
68
+
69
+ expose fn debug(message, data) {
70
+ |shouldLog("debug")| => {
71
+ dec output = formatLog("debug", message, data)
72
+ js(output) { console.log(output); }
73
+ }
74
+ }
75
+
76
+ expose fn info(message, data) {
77
+ |shouldLog("info")| => {
78
+ dec output = formatLog("info", message, data)
79
+ js(output) { console.log(output); }
80
+ }
81
+ }
82
+
83
+ expose fn warn(message, data) {
84
+ |shouldLog("warn")| => {
85
+ dec output = formatLog("warn", message, data)
86
+ js(output) { console.warn(output); }
87
+ }
88
+ }
89
+
90
+ expose fn error(message, data) {
91
+ |shouldLog("error")| => {
92
+ dec output = formatLog("error", message, data)
93
+ js(output) { console.error(output); }
94
+ }
95
+ }
96
+
97
+ expose fn child(context) {
98
+ return {
99
+ debug: (msg, data) => debug(msg, { ...context, ...data }),
100
+ info: (msg, data) => info(msg, { ...context, ...data }),
101
+ warn: (msg, data) => warn(msg, { ...context, ...data }),
102
+ error: (msg, data) => error(msg, { ...context, ...data })
103
+ }
104
+ }
package/stdlib/math.km ADDED
@@ -0,0 +1,120 @@
1
+ // KimchiLang Standard Library - Math Functions
2
+
3
+ expose fn _describe() {
4
+ return "Math utilities: abs, round, floor, ceil, trigonometry, etc."
5
+ }
6
+
7
+ expose dec PI = Math.PI
8
+ expose dec E = Math.E
9
+
10
+ expose fn abs(x) {
11
+ return Math.abs(x)
12
+ }
13
+
14
+ expose fn sign(x) {
15
+ return Math.sign(x)
16
+ }
17
+
18
+ expose fn round(x) {
19
+ return Math.round(x)
20
+ }
21
+
22
+ expose fn floor(x) {
23
+ return Math.floor(x)
24
+ }
25
+
26
+ expose fn ceil(x) {
27
+ return Math.ceil(x)
28
+ }
29
+
30
+ expose fn trunc(x) {
31
+ return Math.trunc(x)
32
+ }
33
+
34
+ expose fn pow(base, exponent) {
35
+ return Math.pow(base, exponent)
36
+ }
37
+
38
+ expose fn sqrt(x) {
39
+ return Math.sqrt(x)
40
+ }
41
+
42
+ expose fn cbrt(x) {
43
+ return Math.cbrt(x)
44
+ }
45
+
46
+ expose fn exp(x) {
47
+ return Math.exp(x)
48
+ }
49
+
50
+ expose fn log(x) {
51
+ return Math.log(x)
52
+ }
53
+
54
+ expose fn log10(x) {
55
+ return Math.log10(x)
56
+ }
57
+
58
+ expose fn log2(x) {
59
+ return Math.log2(x)
60
+ }
61
+
62
+ expose fn sin(x) {
63
+ return Math.sin(x)
64
+ }
65
+
66
+ expose fn cos(x) {
67
+ return Math.cos(x)
68
+ }
69
+
70
+ expose fn tan(x) {
71
+ return Math.tan(x)
72
+ }
73
+
74
+ expose fn asin(x) {
75
+ return Math.asin(x)
76
+ }
77
+
78
+ expose fn acos(x) {
79
+ return Math.acos(x)
80
+ }
81
+
82
+ expose fn atan(x) {
83
+ return Math.atan(x)
84
+ }
85
+
86
+ expose fn atan2(y, x) {
87
+ return Math.atan2(y, x)
88
+ }
89
+
90
+ expose fn random() {
91
+ return Math.random()
92
+ }
93
+
94
+ expose fn randomInt(minVal, maxVal) {
95
+ return Math.floor(Math.random() * (maxVal - minVal + 1)) + minVal
96
+ }
97
+
98
+ expose fn clamp(value, minVal, maxVal) {
99
+ return Math.min(Math.max(value, minVal), maxVal)
100
+ }
101
+
102
+ expose fn lerp(start, end, t) {
103
+ return start + (end - start) * t
104
+ }
105
+
106
+ expose fn degrees(radians) {
107
+ return radians * 180 / Math.PI
108
+ }
109
+
110
+ expose fn radians(deg) {
111
+ return deg * Math.PI / 180
112
+ }
113
+
114
+ expose fn isEven(n) {
115
+ return n % 2 == 0
116
+ }
117
+
118
+ expose fn isOdd(n) {
119
+ return n % 2 != 0
120
+ }