/** * Demonstrates the ADD opcode working with dicts * * ADD now handles dict merging: * - {a: 1} + {b: 2} === {a: 1, b: 2} * - If both operands are dicts, they are merged * - Keys from the second dict overwrite keys from the first on conflict */ import { toBytecode, run } from "#reef" // Basic dict merge const basicMerge = toBytecode([ ["PUSH", "a"], ["PUSH", 1], ["MAKE_DICT", 1], ["PUSH", "b"], ["PUSH", 2], ["MAKE_DICT", 1], ["ADD"], ["HALT"] ]) console.log('Basic dict merge ({a: 1} + {b: 2}):') const result1 = await run(basicMerge) console.log(result1) // Output: { type: 'dict', value: Map { a: 1, b: 2 } } // Merge with overlapping keys const overlapMerge = toBytecode([ ["PUSH", "a"], ["PUSH", 1], ["PUSH", "b"], ["PUSH", 2], ["MAKE_DICT", 2], ["PUSH", "b"], ["PUSH", 99], ["PUSH", "c"], ["PUSH", 3], ["MAKE_DICT", 2], ["ADD"], ["HALT"] ]) console.log('\nMerge with overlapping keys ({a: 1, b: 2} + {b: 99, c: 3}):') const result2 = await run(overlapMerge) console.log(result2) console.log('Note: b is overwritten from 2 to 99') // Output: { type: 'dict', value: Map { a: 1, b: 99, c: 3 } } // Merge multiple dicts in sequence const multipleMerge = toBytecode([ ["PUSH", "a"], ["PUSH", 1], ["MAKE_DICT", 1], ["PUSH", "b"], ["PUSH", 2], ["MAKE_DICT", 1], ["ADD"], ["PUSH", "c"], ["PUSH", 3], ["MAKE_DICT", 1], ["ADD"], ["PUSH", "d"], ["PUSH", 4], ["MAKE_DICT", 1], ["ADD"], ["HALT"] ]) console.log('\nMultiple merges ({a: 1} + {b: 2} + {c: 3} + {d: 4}):') const result3 = await run(multipleMerge) console.log(result3) // Output: { type: 'dict', value: Map { a: 1, b: 2, c: 3, d: 4 } } // Merge dicts with different value types const mixedTypes = toBytecode([ ["PUSH", "num"], ["PUSH", 42], ["PUSH", "str"], ["PUSH", "hello"], ["MAKE_DICT", 2], ["PUSH", "bool"], ["PUSH", true], ["PUSH", "null"], ["PUSH", null], ["MAKE_DICT", 2], ["ADD"], ["HALT"] ]) console.log('\nMerge dicts with different types ({num: 42, str: "hello"} + {bool: true, null: null}):') const result4 = await run(mixedTypes) console.log(result4) // Output: { type: 'dict', value: Map { num: 42, str: 'hello', bool: true, null: null } } // Merge empty dict with non-empty const emptyMerge = toBytecode([ ["MAKE_DICT", 0], ["PUSH", "x"], ["PUSH", 100], ["PUSH", "y"], ["PUSH", 200], ["MAKE_DICT", 2], ["ADD"], ["HALT"] ]) console.log('\nMerge empty dict with {x: 100, y: 200} ({} + {x: 100, y: 200}):') const result5 = await run(emptyMerge) console.log(result5) // Output: { type: 'dict', value: Map { x: 100, y: 200 } } // Merge dicts with nested structures const nestedMerge = toBytecode([ ["PUSH", "data"], ["PUSH", 1], ["PUSH", 2], ["MAKE_ARRAY", 2], ["MAKE_DICT", 1], ["PUSH", "config"], ["PUSH", "debug"], ["PUSH", true], ["MAKE_DICT", 1], ["MAKE_DICT", 1], ["ADD"], ["HALT"] ]) console.log('\nMerge dicts with nested structures:') const result6 = await run(nestedMerge) console.log(result6) // Output: { type: 'dict', value: Map { data: [1, 2], config: { debug: true } } } // Building configuration objects const configBuild = toBytecode([ // Default config ["PUSH", "debug"], ["PUSH", false], ["PUSH", "port"], ["PUSH", 3000], ["PUSH", "host"], ["PUSH", "localhost"], ["MAKE_DICT", 3], // Override with user config ["PUSH", "debug"], ["PUSH", true], ["PUSH", "port"], ["PUSH", 8080], ["MAKE_DICT", 2], ["ADD"], ["HALT"] ]) console.log('\nBuilding config (defaults + overrides):') const result7 = await run(configBuild) console.log(result7) // Output: { type: 'dict', value: Map { debug: true, port: 8080, host: 'localhost' } }