Current section

26 Versions

Jump to

Compare versions

16 files changed
+985 additions
-166 deletions
  @@ -0,0 +1,13 @@
1 + "use strict";
2 +
3 + import ERTS from "../erts.mjs";
4 +
5 + const Elixir_Application = {
6 + // TODO: provide a more complete implementation.
7 + // Simplified temporary implementation - reads from client-side application env storage.
8 + "get_env/3": (app, key, defaultValue) => {
9 + return ERTS.applicationEnv.get(app, key, defaultValue);
10 + },
11 + };
12 +
13 + export default Elixir_Application;
  @@ -1,5 +1,7 @@
1 1 "use strict";
2 2
3 + import Bitstring from "../bitstring.mjs";
4 + import Erlang from "../erlang/erlang.mjs";
3 5 import HologramInterpreterError from "../errors/interpreter_error.mjs";
4 6 import Interpreter from "../interpreter.mjs";
5 7 import Type from "../type.mjs";
  @@ -39,6 +41,32 @@ const Elixir_IO = {
39 41
40 42 return term;
41 43 },
44 +
45 + // Deps: [IO.warn/2]
46 + "warn/1": (message) => {
47 + return Elixir_IO["warn/2"](message, Type.list());
48 + },
49 +
50 + // TODO: provide a more complete implementation.
51 + // Simplified temporary implementation - just prints the message to the console.
52 + // The second argument (stacktrace options) is ignored on the client side.
53 + // Deps: [:erlang.iolist_to_binary/1]
54 + "warn/2": (message, _stacktraceOrOpts) => {
55 + const binary = Erlang["iolist_to_binary/1"](message);
56 + console.warn(Bitstring.toText(binary));
57 +
58 + return Type.atom("ok");
59 + },
60 +
61 + // TODO: provide a more complete implementation.
62 + // Simplified temporary implementation - evaluates the message function and delegates to warn/2.
63 + // Deps: [IO.warn/2]
64 + "warn_once/3": (_key, messageFun, _stacktraceDropLevels) => {
65 + return Elixir_IO["warn/2"](
66 + Interpreter.callAnonymousFunction(messageFun, []),
67 + Type.list(),
68 + );
69 + },
42 70 };
43 71
44 72 export default Elixir_IO;
  @@ -1373,38 +1373,30 @@ const Erlang = {
1373 1373 // End integer_to_list/2
1374 1374 // Deps: []
1375 1375
1376 - // TODO: test
1377 1376 // Start iolist_to_binary/1
1378 1377 "iolist_to_binary/1": (ioListOrBinary) => {
1379 - // TODO: validate arg
1380 -
1381 - if (Type.isBitstring(ioListOrBinary)) {
1378 + if (Type.isBinary(ioListOrBinary)) {
1382 1379 return ioListOrBinary;
1383 1380 }
1384 1381
1385 - const chunks = Erlang_Lists["flatten/1"](ioListOrBinary).data.map(
1386 - (term) => {
1387 - // TODO: validate list item (binary or integer allowed)
1382 + if (!Type.isList(ioListOrBinary)) {
1383 + Interpreter.raiseArgumentError(
1384 + Interpreter.buildArgumentErrorMsg(1, "not an iodata term"),
1385 + );
1386 + }
1388 1387
1389 - if (Type.isBitstring(term)) {
1390 - return term;
1391 - }
1392 -
1393 - const segment = Type.bitstringSegment(term, {
1394 - type: "integer",
1395 - size: Type.integer(8),
1396 - unit: 1n,
1397 - endianness: "big",
1398 - });
1399 -
1400 - return Bitstring.fromSegmentWithIntegerValue(segment);
1401 - },
1402 - );
1403 -
1404 - return Bitstring.concat(chunks);
1388 + // :erlang.list_to_binary/1 raises ArgumentError "not an iolist term" on invalid input.
1389 + // Remap to "not an iodata term" to match OTP's iolist_to_binary/1 behavior.
1390 + try {
1391 + return Erlang["list_to_binary/1"](ioListOrBinary);
1392 + } catch {
1393 + Interpreter.raiseArgumentError(
1394 + Interpreter.buildArgumentErrorMsg(1, "not an iodata term"),
1395 + );
1396 + }
1405 1397 },
1406 1398 // End iolist_to_binary/1
1407 - // Deps: [:lists.flatten/1]
1399 + // Deps: [:erlang.list_to_binary/1]
1408 1400
1409 1401 // Start is_atom/1
1410 1402 "is_atom/1": (term) => {
  @@ -1615,6 +1607,8 @@ const Erlang = {
1615 1607
1616 1608 if (Type.isBinary(tail)) {
1617 1609 chunks.push(tail);
1610 + } else if (Type.isList(tail)) {
1611 + collect(tail);
1618 1612 } else {
1619 1613 Interpreter.raiseArgumentError(
1620 1614 Interpreter.buildArgumentErrorMsg(1, "not an iolist term"),
  @@ -1,5 +1,6 @@
1 1 "use strict";
2 2
3 + import ApplicationEnv from "./erts/application_env.mjs";
3 4 import BinaryPatternRegistry from "./erts/binary_pattern_registry.mjs";
4 5 import NativeObjectRegistry from "./erts/native_object_registry.mjs";
5 6 import NodeTable from "./erts/node_table.mjs";
  @@ -28,6 +29,7 @@ export default class ERTS {
28 29 return $.#initPid;
29 30 }
30 31
32 + static applicationEnv = ApplicationEnv;
31 33 static binaryPatternRegistry = BinaryPatternRegistry;
32 34 static ets = {};
  @@ -0,0 +1,39 @@
1 + "use strict";
2 +
3 + import Type from "../type.mjs";
4 +
5 + export default class ApplicationEnv {
6 + // Nested Map: app_string -> key_string -> value
7 + // Public for easier testing
8 + static data = new Map();
9 +
10 + static clear() {
11 + $.data = new Map();
12 + }
13 +
14 + static get(app, key, defaultValue) {
15 + const encodedApp = Type.encodeMapKey(app);
16 +
17 + if (!$.data.has(encodedApp)) {
18 + return defaultValue;
19 + }
20 +
21 + const appData = $.data.get(encodedApp);
22 + const encodedKey = Type.encodeMapKey(key);
23 +
24 + return appData.has(encodedKey) ? appData.get(encodedKey) : defaultValue;
25 + }
26 +
27 + static put(app, key, value) {
28 + const encodedApp = Type.encodeMapKey(app);
29 +
30 + if (!$.data.has(encodedApp)) {
31 + $.data.set(encodedApp, new Map());
32 + }
33 +
34 + const encodedKey = Type.encodeMapKey(key);
35 + $.data.get(encodedApp).set(encodedKey, value);
36 + }
37 + }
38 +
39 + const $ = ApplicationEnv;
Loading more files…