jaelis-node 1.3.1 → 1.4.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.
- package/README.md +72 -2
- package/lib/JAELIS-VM/lib/adapters/evm-adapter.js +454 -0
- package/lib/JAELIS-VM/lib/adapters/index.js +411 -0
- package/lib/JAELIS-VM/lib/adapters/svm-adapter.js +457 -0
- package/lib/JAELIS-VM/lib/compiler/jir-compiler.js +1097 -0
- package/lib/JAELIS-VM/lib/execution/engine.js +1183 -0
- package/lib/JAELIS-VM/lib/index.js +440 -0
- package/lib/JAELIS-VM/lib/integration/jaelis-integration.js +543 -0
- package/lib/JAELIS-VM/lib/serialization/serializer.js +819 -0
- package/lib/JAELIS-VM/lib/state/state-manager.js +1116 -0
- package/lib/JAELIS-VM/lib/translator/bytecode-translator.js +1222 -0
- package/lib/JAELIS-VM/lib/unified/cross-chain-state.js +836 -0
- package/lib/JAELIS-VM/lib/unified/dynamic-contracts.js +1127 -0
- package/lib/JAELIS-VM/lib/unified/index.js +378 -0
- package/lib/JAELIS-VM/lib/unified/jaelis-abi.js +1150 -0
- package/lib/JAELIS-VM/lib/unified/unified-compiler.js +1350 -0
- package/lib/JAELIS-VM/node_modules/.bin/download-cbor-prebuilds +12 -0
- package/lib/JAELIS-VM/node_modules/.bin/download-cbor-prebuilds.cmd +17 -0
- package/lib/JAELIS-VM/node_modules/.bin/download-cbor-prebuilds.ps1 +28 -0
- package/lib/JAELIS-VM/node_modules/.bin/download-msgpackr-prebuilds +12 -0
- package/lib/JAELIS-VM/node_modules/.bin/download-msgpackr-prebuilds.cmd +17 -0
- package/lib/JAELIS-VM/node_modules/.bin/download-msgpackr-prebuilds.ps1 +28 -0
- package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages +12 -0
- package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages-optional +12 -0
- package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages-optional.cmd +17 -0
- package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages-optional.ps1 +28 -0
- package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages-test +12 -0
- package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages-test.cmd +17 -0
- package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages-test.ps1 +28 -0
- package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages.cmd +17 -0
- package/lib/JAELIS-VM/node_modules/.bin/node-gyp-build-optional-packages.ps1 +28 -0
- package/lib/JAELIS-VM/node_modules/.package-lock.json +127 -0
- package/lib/JAELIS-VM/node_modules/@cbor-extract/cbor-extract-win32-x64/README.md +1 -0
- package/lib/JAELIS-VM/node_modules/@cbor-extract/cbor-extract-win32-x64/index.js +0 -0
- package/lib/JAELIS-VM/node_modules/@cbor-extract/cbor-extract-win32-x64/node.abi115.node +0 -0
- package/lib/JAELIS-VM/node_modules/@cbor-extract/cbor-extract-win32-x64/node.napi.node +0 -0
- package/lib/JAELIS-VM/node_modules/@cbor-extract/cbor-extract-win32-x64/package.json +17 -0
- package/lib/JAELIS-VM/node_modules/@msgpackr-extract/msgpackr-extract-win32-x64/README.md +1 -0
- package/lib/JAELIS-VM/node_modules/@msgpackr-extract/msgpackr-extract-win32-x64/index.js +0 -0
- package/lib/JAELIS-VM/node_modules/@msgpackr-extract/msgpackr-extract-win32-x64/node.abi115.node +0 -0
- package/lib/JAELIS-VM/node_modules/@msgpackr-extract/msgpackr-extract-win32-x64/node.napi.node +0 -0
- package/lib/JAELIS-VM/node_modules/@msgpackr-extract/msgpackr-extract-win32-x64/package.json +17 -0
- package/lib/JAELIS-VM/node_modules/cbor-extract/LICENSE +21 -0
- package/lib/JAELIS-VM/node_modules/cbor-extract/README.md +5 -0
- package/lib/JAELIS-VM/node_modules/cbor-extract/bin/download-prebuilds.js +11 -0
- package/lib/JAELIS-VM/node_modules/cbor-extract/binding.gyp +60 -0
- package/lib/JAELIS-VM/node_modules/cbor-extract/index.js +1 -0
- package/lib/JAELIS-VM/node_modules/cbor-extract/package.json +50 -0
- package/lib/JAELIS-VM/node_modules/cbor-extract/src/extract.cpp +198 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/LICENSE +21 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/README.md +380 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/SECURITY.md +11 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/benchmark.md +73 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/browser.js +11 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/decode.d.ts +2 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/decode.js +1300 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/decode-no-eval.cjs +1244 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/decode-no-eval.cjs.map +1 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/index-no-eval.cjs +2509 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/index-no-eval.cjs.map +1 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/index-no-eval.min.js +2 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/index-no-eval.min.js.map +1 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/index.js +2508 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/index.js.map +1 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/index.min.js +2 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/index.min.js.map +1 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/node.cjs +2629 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/node.cjs.map +1 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/test.js +3343 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/dist/test.js.map +1 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/encode.d.ts +1 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/encode.js +1231 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/index.d.ts +79 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/index.js +3 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/iterators.js +85 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/node-index.js +24 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/package.json +94 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/rollup.config.js +88 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/stream.js +61 -0
- package/lib/JAELIS-VM/node_modules/cbor-x/webpack.config.js +19 -0
- package/lib/JAELIS-VM/node_modules/detect-libc/LICENSE +201 -0
- package/lib/JAELIS-VM/node_modules/detect-libc/README.md +163 -0
- package/lib/JAELIS-VM/node_modules/detect-libc/index.d.ts +14 -0
- package/lib/JAELIS-VM/node_modules/detect-libc/lib/detect-libc.js +313 -0
- package/lib/JAELIS-VM/node_modules/detect-libc/lib/elf.js +39 -0
- package/lib/JAELIS-VM/node_modules/detect-libc/lib/filesystem.js +51 -0
- package/lib/JAELIS-VM/node_modules/detect-libc/lib/process.js +24 -0
- package/lib/JAELIS-VM/node_modules/detect-libc/package.json +44 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/LICENSE +21 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/README.md +372 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/SECURITY.md +11 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/benchmark.md +67 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/index-no-eval.cjs +2407 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/index-no-eval.cjs.map +1 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/index-no-eval.min.js +2 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/index-no-eval.min.js.map +1 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/index.js +2406 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/index.js.map +1 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/index.min.js +2 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/index.min.js.map +1 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/node.cjs +3320 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/node.cjs.map +1 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/test.js +4540 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/test.js.map +1 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/unpack-no-eval.cjs +1250 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/dist/unpack-no-eval.cjs.map +1 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/index.d.cts +91 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/index.d.ts +91 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/index.js +5 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/iterators.js +87 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/node-index.js +25 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/pack.d.cts +1 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/pack.d.ts +1 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/pack.js +1141 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/package.json +104 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/rollup.config.js +88 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/stream.js +57 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/struct.js +815 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/test-worker.js +3 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/unpack.d.cts +2 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/unpack.d.ts +2 -0
- package/lib/JAELIS-VM/node_modules/msgpackr/unpack.js +1221 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/LICENSE +21 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/README.md +5 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/bin/download-prebuilds.js +13 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/binding.gyp +63 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/index.js +1 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages +12 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages-optional +12 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages-optional.cmd +17 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages-optional.ps1 +28 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages-test +12 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages-test.cmd +17 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages-test.ps1 +28 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages.cmd +17 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/.bin/node-gyp-build-optional-packages.ps1 +28 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/LICENSE +21 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/README.md +58 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/bin.js +82 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/build-test.js +19 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/index.js +6 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/node-gyp-build.js +236 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/optional.js +7 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages/package.json +32 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/package.json +50 -0
- package/lib/JAELIS-VM/node_modules/msgpackr-extract/src/extract.cpp +274 -0
- package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/LICENSE +21 -0
- package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/README.md +58 -0
- package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/bin.js +77 -0
- package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/build-test.js +19 -0
- package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/index.js +224 -0
- package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/optional.js +7 -0
- package/lib/JAELIS-VM/node_modules/node-gyp-build-optional-packages/package.json +32 -0
- package/lib/JAELIS-VM/package-lock.json +284 -0
- package/lib/JAELIS-VM/package.json +38 -0
- package/lib/JAELIS-VM/test/comprehensive.test.js +267 -0
- package/lib/JAELIS-VM/test/cross-chain-test.js +470 -0
- package/lib/JAELIS-VM/test/unified-vm-test.js +459 -0
- package/lib/JAELIS-VM/test/unified.test.js +166 -0
- package/lib/JAELIS-VM/test/vm.test.js +599 -0
- package/lib/index.js +240 -4
- package/package.json +2 -2
|
@@ -0,0 +1,1350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JAELIS UNIFIED COMPILER
|
|
3
|
+
*
|
|
4
|
+
* THE HOLY GRAIL - One compiler that understands ALL blockchain languages
|
|
5
|
+
* and compiles them to a single unified bytecode format.
|
|
6
|
+
*
|
|
7
|
+
* NO BRIDGES. NO ADAPTERS. NO TRANSLATION.
|
|
8
|
+
*
|
|
9
|
+
* Just... code that works together.
|
|
10
|
+
*
|
|
11
|
+
* How it works:
|
|
12
|
+
* ┌─────────────────────────────────────────────────────────────────┐
|
|
13
|
+
* │ UNIFIED COMPILER │
|
|
14
|
+
* │ │
|
|
15
|
+
* │ Solidity ──┐ │
|
|
16
|
+
* │ Rust ──────┤ │
|
|
17
|
+
* │ Move ──────┼──► UNIFIED AST ──► UNIFIED IR ──► JAELIS BYTECODE │
|
|
18
|
+
* │ FunC ──────┤ │ │ │
|
|
19
|
+
* │ Cairo ─────┘ │ │ │
|
|
20
|
+
* │ ▼ ▼ │
|
|
21
|
+
* │ Shared Type System Shared State Space │
|
|
22
|
+
* │ │
|
|
23
|
+
* └─────────────────────────────────────────────────────────────────┘
|
|
24
|
+
*
|
|
25
|
+
* Key Innovation:
|
|
26
|
+
* - ALL contracts share the SAME memory space
|
|
27
|
+
* - Direct function calls between languages (no bridging!)
|
|
28
|
+
* - Types are unified (uint256 == u256 == felt252)
|
|
29
|
+
* - State is shared (no lock/mint/burn)
|
|
30
|
+
*
|
|
31
|
+
* @version 0.2.0
|
|
32
|
+
* @author Mario Papaleo - JAELIS Foundation
|
|
33
|
+
* @patent PATENT PENDING - Unified Multi-Language Blockchain Compiler
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
const crypto = require('crypto');
|
|
37
|
+
|
|
38
|
+
// ═══════════════════════════════════════════════════════════════
|
|
39
|
+
// UNIFIED TYPE SYSTEM
|
|
40
|
+
// ═══════════════════════════════════════════════════════════════
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Unified types that work across ALL VMs
|
|
44
|
+
*
|
|
45
|
+
* The key insight: ALL blockchain VMs use the same basic types,
|
|
46
|
+
* they just call them different names. Let's unify them.
|
|
47
|
+
*/
|
|
48
|
+
const UNIFIED_TYPES = {
|
|
49
|
+
// Numbers (all VMs have these, just different names)
|
|
50
|
+
U8: { id: 0x01, size: 1, aliases: ['uint8', 'u8', 'byte'] },
|
|
51
|
+
U16: { id: 0x02, size: 2, aliases: ['uint16', 'u16'] },
|
|
52
|
+
U32: { id: 0x03, size: 4, aliases: ['uint32', 'u32'] },
|
|
53
|
+
U64: { id: 0x04, size: 8, aliases: ['uint64', 'u64', 'usize'] },
|
|
54
|
+
U128: { id: 0x05, size: 16, aliases: ['uint128', 'u128'] },
|
|
55
|
+
U256: { id: 0x06, size: 32, aliases: ['uint256', 'u256', 'felt252', 'int'] },
|
|
56
|
+
|
|
57
|
+
I8: { id: 0x11, size: 1, aliases: ['int8', 'i8'] },
|
|
58
|
+
I16: { id: 0x12, size: 2, aliases: ['int16', 'i16'] },
|
|
59
|
+
I32: { id: 0x13, size: 4, aliases: ['int32', 'i32'] },
|
|
60
|
+
I64: { id: 0x14, size: 8, aliases: ['int64', 'i64', 'isize'] },
|
|
61
|
+
I128: { id: 0x15, size: 16, aliases: ['int128', 'i128'] },
|
|
62
|
+
I256: { id: 0x16, size: 32, aliases: ['int256', 'i256'] },
|
|
63
|
+
|
|
64
|
+
// Boolean
|
|
65
|
+
BOOL: { id: 0x20, size: 1, aliases: ['bool', 'boolean'] },
|
|
66
|
+
|
|
67
|
+
// Address (unified across all chains!)
|
|
68
|
+
ADDRESS: { id: 0x30, size: 32, aliases: ['address', 'pubkey', 'AccountId', 'felt252'] },
|
|
69
|
+
|
|
70
|
+
// Bytes
|
|
71
|
+
BYTES32: { id: 0x40, size: 32, aliases: ['bytes32', 'Hash', 'H256'] },
|
|
72
|
+
BYTES: { id: 0x41, size: -1, aliases: ['bytes', 'Vec<u8>', 'vector<u8>', 'slice'] },
|
|
73
|
+
STRING: { id: 0x42, size: -1, aliases: ['string', 'String', 'str'] },
|
|
74
|
+
|
|
75
|
+
// Complex types
|
|
76
|
+
ARRAY: { id: 0x50, size: -1, aliases: ['array', 'Vec', 'vector', 'list'] },
|
|
77
|
+
MAP: { id: 0x51, size: -1, aliases: ['mapping', 'HashMap', 'Table', 'map'] },
|
|
78
|
+
STRUCT: { id: 0x52, size: -1, aliases: ['struct', 'object'] },
|
|
79
|
+
OPTION: { id: 0x53, size: -1, aliases: ['Option', 'optional', 'nullable'] },
|
|
80
|
+
RESULT: { id: 0x54, size: -1, aliases: ['Result', 'result'] },
|
|
81
|
+
|
|
82
|
+
// Blockchain-specific (but unified!)
|
|
83
|
+
TOKEN: { id: 0x60, size: 32, aliases: ['Token', 'Coin', 'Asset'] },
|
|
84
|
+
NFT: { id: 0x61, size: 32, aliases: ['NFT', 'NonFungible', 'Collectible'] }
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Build reverse lookup
|
|
88
|
+
const TYPE_ALIAS_MAP = new Map();
|
|
89
|
+
for (const [typeName, typeInfo] of Object.entries(UNIFIED_TYPES)) {
|
|
90
|
+
TYPE_ALIAS_MAP.set(typeName.toLowerCase(), typeName);
|
|
91
|
+
for (const alias of typeInfo.aliases) {
|
|
92
|
+
TYPE_ALIAS_MAP.set(alias.toLowerCase(), typeName);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ═══════════════════════════════════════════════════════════════
|
|
97
|
+
// UNIFIED AST (Abstract Syntax Tree)
|
|
98
|
+
// ═══════════════════════════════════════════════════════════════
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Unified AST nodes that can represent ANY blockchain language
|
|
102
|
+
*/
|
|
103
|
+
const AST_NODES = {
|
|
104
|
+
// Top level
|
|
105
|
+
PROGRAM: 'Program',
|
|
106
|
+
MODULE: 'Module',
|
|
107
|
+
CONTRACT: 'Contract',
|
|
108
|
+
|
|
109
|
+
// Declarations
|
|
110
|
+
FUNCTION: 'Function',
|
|
111
|
+
VARIABLE: 'Variable',
|
|
112
|
+
CONSTANT: 'Constant',
|
|
113
|
+
STRUCT: 'Struct',
|
|
114
|
+
ENUM: 'Enum',
|
|
115
|
+
EVENT: 'Event',
|
|
116
|
+
ERROR: 'Error',
|
|
117
|
+
|
|
118
|
+
// Statements
|
|
119
|
+
BLOCK: 'Block',
|
|
120
|
+
IF: 'If',
|
|
121
|
+
WHILE: 'While',
|
|
122
|
+
FOR: 'For',
|
|
123
|
+
RETURN: 'Return',
|
|
124
|
+
EMIT: 'Emit',
|
|
125
|
+
REVERT: 'Revert',
|
|
126
|
+
ASSERT: 'Assert',
|
|
127
|
+
|
|
128
|
+
// Expressions
|
|
129
|
+
CALL: 'Call',
|
|
130
|
+
CROSS_CALL: 'CrossCall', // Direct cross-language call!
|
|
131
|
+
BINARY_OP: 'BinaryOp',
|
|
132
|
+
UNARY_OP: 'UnaryOp',
|
|
133
|
+
MEMBER_ACCESS: 'MemberAccess',
|
|
134
|
+
INDEX_ACCESS: 'IndexAccess',
|
|
135
|
+
LITERAL: 'Literal',
|
|
136
|
+
IDENTIFIER: 'Identifier',
|
|
137
|
+
|
|
138
|
+
// Storage
|
|
139
|
+
STORAGE_READ: 'StorageRead',
|
|
140
|
+
STORAGE_WRITE: 'StorageWrite',
|
|
141
|
+
SHARED_READ: 'SharedRead', // Read from ANY contract!
|
|
142
|
+
SHARED_WRITE: 'SharedWrite' // Write to shared state!
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// ═══════════════════════════════════════════════════════════════
|
|
146
|
+
// UNIFIED COMPILER
|
|
147
|
+
// ═══════════════════════════════════════════════════════════════
|
|
148
|
+
|
|
149
|
+
class UnifiedCompiler {
|
|
150
|
+
constructor(config = {}) {
|
|
151
|
+
this.config = config;
|
|
152
|
+
|
|
153
|
+
// Language parsers (all feed into unified AST)
|
|
154
|
+
this.parsers = {
|
|
155
|
+
solidity: new SolidityParser(),
|
|
156
|
+
rust: new RustParser(),
|
|
157
|
+
move: new MoveParser(),
|
|
158
|
+
func: new FunCParser(),
|
|
159
|
+
cairo: new CairoParser(),
|
|
160
|
+
vyper: new VyperParser()
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// Shared symbol table (THIS IS THE KEY!)
|
|
164
|
+
this.globalSymbols = new Map();
|
|
165
|
+
|
|
166
|
+
// Shared type registry
|
|
167
|
+
this.types = new Map();
|
|
168
|
+
|
|
169
|
+
// Cross-contract references
|
|
170
|
+
this.crossReferences = new Map();
|
|
171
|
+
|
|
172
|
+
// Compilation cache
|
|
173
|
+
this.cache = new Map();
|
|
174
|
+
|
|
175
|
+
console.log('[UnifiedCompiler] Initialized - NO BRIDGES, NO ADAPTERS!');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Compile source code from ANY language to unified bytecode
|
|
180
|
+
*
|
|
181
|
+
* The magic: All contracts end up in the SAME bytecode format,
|
|
182
|
+
* can call each other DIRECTLY, share state NATIVELY.
|
|
183
|
+
*/
|
|
184
|
+
async compile(sources) {
|
|
185
|
+
console.log('[UnifiedCompiler] Compiling unified contract bundle...');
|
|
186
|
+
|
|
187
|
+
const startTime = Date.now();
|
|
188
|
+
|
|
189
|
+
// Step 1: Parse all sources to unified AST
|
|
190
|
+
const asts = [];
|
|
191
|
+
for (const source of sources) {
|
|
192
|
+
const ast = await this.parseToUnifiedAST(source.code, source.language);
|
|
193
|
+
ast.originalLanguage = source.language;
|
|
194
|
+
ast.sourceName = source.name;
|
|
195
|
+
asts.push(ast);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Step 2: Build global symbol table (THIS IS KEY!)
|
|
199
|
+
// All contracts can see all other contracts' public interfaces
|
|
200
|
+
this.buildGlobalSymbolTable(asts);
|
|
201
|
+
|
|
202
|
+
// Step 3: Type unification
|
|
203
|
+
// uint256 (Solidity) = u256 (Rust) = felt252 (Cairo)
|
|
204
|
+
this.unifyTypes(asts);
|
|
205
|
+
|
|
206
|
+
// Step 4: Resolve cross-contract calls
|
|
207
|
+
// A Solidity contract can call a Move function DIRECTLY
|
|
208
|
+
this.resolveCrossReferences(asts);
|
|
209
|
+
|
|
210
|
+
// Step 5: Generate unified IR
|
|
211
|
+
const unifiedIR = this.generateUnifiedIR(asts);
|
|
212
|
+
|
|
213
|
+
// Step 6: Optimize
|
|
214
|
+
const optimizedIR = this.optimize(unifiedIR);
|
|
215
|
+
|
|
216
|
+
// Step 7: Generate bytecode
|
|
217
|
+
const bytecode = this.generateBytecode(optimizedIR);
|
|
218
|
+
|
|
219
|
+
const compileTime = Date.now() - startTime;
|
|
220
|
+
|
|
221
|
+
console.log(`[UnifiedCompiler] Compiled ${sources.length} contracts in ${compileTime}ms`);
|
|
222
|
+
console.log(`[UnifiedCompiler] Cross-contract calls: ${this.crossReferences.size}`);
|
|
223
|
+
console.log(`[UnifiedCompiler] Unified bytecode: ${bytecode.length} bytes`);
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
bytecode,
|
|
227
|
+
asts,
|
|
228
|
+
symbols: this.globalSymbols,
|
|
229
|
+
crossReferences: this.crossReferences,
|
|
230
|
+
metadata: {
|
|
231
|
+
compileTime,
|
|
232
|
+
languages: [...new Set(sources.map(s => s.language))],
|
|
233
|
+
contracts: sources.map(s => s.name)
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Parse source code to UNIFIED AST
|
|
240
|
+
*
|
|
241
|
+
* Different languages, same AST structure!
|
|
242
|
+
*/
|
|
243
|
+
async parseToUnifiedAST(code, language) {
|
|
244
|
+
const parser = this.parsers[language];
|
|
245
|
+
if (!parser) {
|
|
246
|
+
throw new Error(`Unsupported language: ${language}`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Parse to language-specific AST
|
|
250
|
+
const nativeAST = parser.parse(code);
|
|
251
|
+
|
|
252
|
+
// Transform to unified AST
|
|
253
|
+
return this.transformToUnifiedAST(nativeAST, language);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Transform language-specific AST to unified AST
|
|
258
|
+
*/
|
|
259
|
+
transformToUnifiedAST(nativeAST, language) {
|
|
260
|
+
const unified = {
|
|
261
|
+
type: AST_NODES.PROGRAM,
|
|
262
|
+
language,
|
|
263
|
+
modules: [],
|
|
264
|
+
contracts: [],
|
|
265
|
+
functions: [],
|
|
266
|
+
structs: [],
|
|
267
|
+
imports: [],
|
|
268
|
+
exports: []
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// Transform based on language
|
|
272
|
+
switch (language) {
|
|
273
|
+
case 'solidity':
|
|
274
|
+
return this.transformSolidityAST(nativeAST, unified);
|
|
275
|
+
case 'rust':
|
|
276
|
+
return this.transformRustAST(nativeAST, unified);
|
|
277
|
+
case 'move':
|
|
278
|
+
return this.transformMoveAST(nativeAST, unified);
|
|
279
|
+
case 'func':
|
|
280
|
+
return this.transformFunCAST(nativeAST, unified);
|
|
281
|
+
case 'cairo':
|
|
282
|
+
return this.transformCairoAST(nativeAST, unified);
|
|
283
|
+
default:
|
|
284
|
+
return unified;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
transformSolidityAST(native, unified) {
|
|
289
|
+
// Transform Solidity contracts to unified format
|
|
290
|
+
for (const contract of native.contracts || []) {
|
|
291
|
+
const unifiedContract = {
|
|
292
|
+
type: AST_NODES.CONTRACT,
|
|
293
|
+
name: contract.name,
|
|
294
|
+
visibility: 'public',
|
|
295
|
+
storage: [],
|
|
296
|
+
functions: [],
|
|
297
|
+
events: [],
|
|
298
|
+
modifiers: []
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
// Transform functions
|
|
302
|
+
for (const func of contract.body || []) {
|
|
303
|
+
if (func.type === 'FunctionDeclaration') {
|
|
304
|
+
unifiedContract.functions.push({
|
|
305
|
+
type: AST_NODES.FUNCTION,
|
|
306
|
+
name: func.name,
|
|
307
|
+
params: func.params.map(p => ({
|
|
308
|
+
name: p.name,
|
|
309
|
+
type: this.unifyType(p.type, 'solidity')
|
|
310
|
+
})),
|
|
311
|
+
returns: func.returns.map(r => this.unifyType(r, 'solidity')),
|
|
312
|
+
visibility: func.visibility || 'public',
|
|
313
|
+
mutability: func.stateMutability,
|
|
314
|
+
body: func.body
|
|
315
|
+
});
|
|
316
|
+
} else if (func.type === 'StateVariableDeclaration') {
|
|
317
|
+
unifiedContract.storage.push({
|
|
318
|
+
name: func.name,
|
|
319
|
+
type: this.unifyType(func.dataType, 'solidity'),
|
|
320
|
+
visibility: func.visibility
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
unified.contracts.push(unifiedContract);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return unified;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
transformRustAST(native, unified) {
|
|
332
|
+
// Transform Rust/Anchor to unified format
|
|
333
|
+
for (const program of native.programs || []) {
|
|
334
|
+
const unifiedContract = {
|
|
335
|
+
type: AST_NODES.CONTRACT,
|
|
336
|
+
name: program.name,
|
|
337
|
+
visibility: 'public',
|
|
338
|
+
storage: [],
|
|
339
|
+
functions: [],
|
|
340
|
+
accounts: [] // Solana account definitions
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
for (const instruction of program.instructions || []) {
|
|
344
|
+
unifiedContract.functions.push({
|
|
345
|
+
type: AST_NODES.FUNCTION,
|
|
346
|
+
name: instruction.name,
|
|
347
|
+
params: [],
|
|
348
|
+
returns: ['Result'],
|
|
349
|
+
visibility: 'public',
|
|
350
|
+
mutability: 'mutable'
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
unified.contracts.push(unifiedContract);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return unified;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
transformMoveAST(native, unified) {
|
|
361
|
+
// Transform Move modules to unified format
|
|
362
|
+
for (const module of native.modules || []) {
|
|
363
|
+
const unifiedContract = {
|
|
364
|
+
type: AST_NODES.MODULE,
|
|
365
|
+
name: module.name,
|
|
366
|
+
visibility: 'public',
|
|
367
|
+
storage: [],
|
|
368
|
+
functions: [],
|
|
369
|
+
resources: [] // Move resources
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
for (const func of module.functions || []) {
|
|
373
|
+
unifiedContract.functions.push({
|
|
374
|
+
type: AST_NODES.FUNCTION,
|
|
375
|
+
name: func.name,
|
|
376
|
+
params: [],
|
|
377
|
+
returns: [],
|
|
378
|
+
visibility: func.visibility || 'public',
|
|
379
|
+
acquires: func.acquires || [] // Move resource acquires
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
for (const struct of module.structs || []) {
|
|
384
|
+
unifiedContract.resources.push({
|
|
385
|
+
type: AST_NODES.STRUCT,
|
|
386
|
+
name: struct.name,
|
|
387
|
+
abilities: ['key', 'store'] // Move abilities
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
unified.contracts.push(unifiedContract);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return unified;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
transformFunCAST(native, unified) {
|
|
398
|
+
// Transform FunC (TON) to unified format
|
|
399
|
+
const unifiedContract = {
|
|
400
|
+
type: AST_NODES.CONTRACT,
|
|
401
|
+
name: 'ton_contract',
|
|
402
|
+
visibility: 'public',
|
|
403
|
+
storage: [],
|
|
404
|
+
functions: []
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
for (const func of native.functions || []) {
|
|
408
|
+
// Use the name field if available, otherwise try to extract from signature
|
|
409
|
+
const funcName = func.name || func.signature?.match(/(\w+)\s*\(/)?.[1] || 'unknown';
|
|
410
|
+
unifiedContract.functions.push({
|
|
411
|
+
type: AST_NODES.FUNCTION,
|
|
412
|
+
name: funcName,
|
|
413
|
+
params: [],
|
|
414
|
+
returns: func.returns ? [func.returns] : [],
|
|
415
|
+
visibility: 'public'
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
unified.contracts.push(unifiedContract);
|
|
420
|
+
return unified;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
transformCairoAST(native, unified) {
|
|
424
|
+
// Transform Cairo (Starknet) to unified format
|
|
425
|
+
for (const contract of native.contracts || []) {
|
|
426
|
+
const unifiedContract = {
|
|
427
|
+
type: AST_NODES.CONTRACT,
|
|
428
|
+
name: contract.name,
|
|
429
|
+
visibility: 'public',
|
|
430
|
+
storage: [],
|
|
431
|
+
functions: []
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
// Transform Cairo functions
|
|
435
|
+
for (const func of contract.functions || []) {
|
|
436
|
+
unifiedContract.functions.push({
|
|
437
|
+
type: AST_NODES.FUNCTION,
|
|
438
|
+
name: func.name,
|
|
439
|
+
params: [],
|
|
440
|
+
returns: [],
|
|
441
|
+
visibility: func.visibility === 'view' ? 'view' : 'public'
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
unified.contracts.push(unifiedContract);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return unified;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Build GLOBAL symbol table
|
|
453
|
+
*
|
|
454
|
+
* THIS IS THE MAGIC: All contracts can see each other!
|
|
455
|
+
*/
|
|
456
|
+
buildGlobalSymbolTable(asts) {
|
|
457
|
+
console.log('[UnifiedCompiler] Building global symbol table...');
|
|
458
|
+
|
|
459
|
+
for (const ast of asts) {
|
|
460
|
+
for (const contract of ast.contracts || []) {
|
|
461
|
+
const contractKey = `${ast.sourceName}::${contract.name}`;
|
|
462
|
+
|
|
463
|
+
// Register contract
|
|
464
|
+
this.globalSymbols.set(contractKey, {
|
|
465
|
+
type: 'contract',
|
|
466
|
+
name: contract.name,
|
|
467
|
+
language: ast.originalLanguage,
|
|
468
|
+
functions: new Map(),
|
|
469
|
+
storage: new Map()
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
const contractSymbol = this.globalSymbols.get(contractKey);
|
|
473
|
+
|
|
474
|
+
// Register all public functions
|
|
475
|
+
for (const func of contract.functions || []) {
|
|
476
|
+
if (func.visibility === 'public' || func.visibility === 'external') {
|
|
477
|
+
const funcKey = `${contractKey}::${func.name}`;
|
|
478
|
+
contractSymbol.functions.set(func.name, {
|
|
479
|
+
name: func.name,
|
|
480
|
+
params: func.params,
|
|
481
|
+
returns: func.returns,
|
|
482
|
+
selector: this.computeSelector(func.name, func.params)
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
// Also register globally for cross-contract calls
|
|
486
|
+
this.globalSymbols.set(funcKey, {
|
|
487
|
+
type: 'function',
|
|
488
|
+
contract: contractKey,
|
|
489
|
+
...func
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Register storage variables
|
|
495
|
+
for (const storage of contract.storage || []) {
|
|
496
|
+
if (storage.visibility === 'public') {
|
|
497
|
+
contractSymbol.storage.set(storage.name, storage);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
console.log(`[UnifiedCompiler] Registered ${this.globalSymbols.size} symbols`);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Unify types across languages
|
|
508
|
+
*
|
|
509
|
+
* uint256 (Solidity) = u256 (Rust) = felt252 (Cairo) = all the same!
|
|
510
|
+
*/
|
|
511
|
+
unifyTypes(asts) {
|
|
512
|
+
console.log('[UnifiedCompiler] Unifying types across languages...');
|
|
513
|
+
|
|
514
|
+
for (const ast of asts) {
|
|
515
|
+
this.unifyASTTypes(ast);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
unifyASTTypes(node) {
|
|
520
|
+
if (!node || typeof node !== 'object') return;
|
|
521
|
+
|
|
522
|
+
// Unify type references
|
|
523
|
+
if (node.type && typeof node.type === 'string') {
|
|
524
|
+
node.unifiedType = this.unifyType(node.type, node.language);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Recurse
|
|
528
|
+
for (const key of Object.keys(node)) {
|
|
529
|
+
if (Array.isArray(node[key])) {
|
|
530
|
+
for (const item of node[key]) {
|
|
531
|
+
this.unifyASTTypes(item);
|
|
532
|
+
}
|
|
533
|
+
} else if (typeof node[key] === 'object') {
|
|
534
|
+
this.unifyASTTypes(node[key]);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
unifyType(typeStr, language) {
|
|
540
|
+
if (!typeStr) return 'U256'; // Default
|
|
541
|
+
|
|
542
|
+
const normalized = typeStr.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
543
|
+
return TYPE_ALIAS_MAP.get(normalized) || 'U256';
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Resolve cross-contract references
|
|
548
|
+
*
|
|
549
|
+
* When a Solidity contract calls a Move function,
|
|
550
|
+
* we resolve it HERE, not at runtime!
|
|
551
|
+
*/
|
|
552
|
+
resolveCrossReferences(asts) {
|
|
553
|
+
console.log('[UnifiedCompiler] Resolving cross-contract references...');
|
|
554
|
+
|
|
555
|
+
for (const ast of asts) {
|
|
556
|
+
this.findCrossReferences(ast, ast.sourceName);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
findCrossReferences(node, currentContract) {
|
|
561
|
+
if (!node || typeof node !== 'object') return;
|
|
562
|
+
|
|
563
|
+
// Look for cross-contract calls
|
|
564
|
+
if (node.type === AST_NODES.CALL) {
|
|
565
|
+
const target = node.callee;
|
|
566
|
+
if (target && target.includes('::')) {
|
|
567
|
+
// Cross-contract call detected!
|
|
568
|
+
const [contractName, funcName] = target.split('::');
|
|
569
|
+
const targetSymbol = this.globalSymbols.get(`${contractName}::${funcName}`);
|
|
570
|
+
|
|
571
|
+
if (targetSymbol) {
|
|
572
|
+
this.crossReferences.set(`${currentContract}::${target}`, {
|
|
573
|
+
from: currentContract,
|
|
574
|
+
to: contractName,
|
|
575
|
+
function: funcName,
|
|
576
|
+
targetSymbol
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
// Convert to unified cross-call
|
|
580
|
+
node.type = AST_NODES.CROSS_CALL;
|
|
581
|
+
node.targetContract = contractName;
|
|
582
|
+
node.targetFunction = funcName;
|
|
583
|
+
node.resolved = true;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// Recurse
|
|
589
|
+
for (const key of Object.keys(node)) {
|
|
590
|
+
if (Array.isArray(node[key])) {
|
|
591
|
+
for (const item of node[key]) {
|
|
592
|
+
this.findCrossReferences(item, currentContract);
|
|
593
|
+
}
|
|
594
|
+
} else if (typeof node[key] === 'object') {
|
|
595
|
+
this.findCrossReferences(node[key], currentContract);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Generate Unified IR
|
|
602
|
+
*
|
|
603
|
+
* All contracts compile to the SAME intermediate representation
|
|
604
|
+
*/
|
|
605
|
+
generateUnifiedIR(asts) {
|
|
606
|
+
const ir = {
|
|
607
|
+
version: [0, 2, 0],
|
|
608
|
+
contracts: [],
|
|
609
|
+
sharedState: [],
|
|
610
|
+
crossCalls: [],
|
|
611
|
+
entryPoints: []
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
for (const ast of asts) {
|
|
615
|
+
for (const contract of ast.contracts || []) {
|
|
616
|
+
const irContract = {
|
|
617
|
+
name: contract.name,
|
|
618
|
+
language: ast.originalLanguage,
|
|
619
|
+
functions: [],
|
|
620
|
+
storage: [],
|
|
621
|
+
events: []
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
// Generate IR for each function
|
|
625
|
+
for (const func of contract.functions || []) {
|
|
626
|
+
irContract.functions.push({
|
|
627
|
+
name: func.name,
|
|
628
|
+
selector: this.computeSelector(func.name, func.params),
|
|
629
|
+
params: func.params,
|
|
630
|
+
returns: func.returns,
|
|
631
|
+
bytecode: this.generateFunctionBytecode(func)
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// Storage layout (unified across all contracts!)
|
|
636
|
+
for (const storage of contract.storage || []) {
|
|
637
|
+
irContract.storage.push({
|
|
638
|
+
name: storage.name,
|
|
639
|
+
slot: this.computeStorageSlot(contract.name, storage.name),
|
|
640
|
+
type: storage.type
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
ir.contracts.push(irContract);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Add cross-call dispatch table
|
|
649
|
+
for (const [key, ref] of this.crossReferences) {
|
|
650
|
+
ir.crossCalls.push({
|
|
651
|
+
key,
|
|
652
|
+
from: ref.from,
|
|
653
|
+
to: ref.to,
|
|
654
|
+
function: ref.function,
|
|
655
|
+
selector: ref.targetSymbol.selector
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
return ir;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Generate function bytecode
|
|
664
|
+
*
|
|
665
|
+
* Compiles unified AST function to JAELIS bytecode
|
|
666
|
+
*/
|
|
667
|
+
generateFunctionBytecode(func) {
|
|
668
|
+
const bytecode = [];
|
|
669
|
+
const locals = new Map(); // Local variable tracking
|
|
670
|
+
let localIndex = 0;
|
|
671
|
+
|
|
672
|
+
// JIR Opcodes (from jir-compiler.js)
|
|
673
|
+
const OP = {
|
|
674
|
+
NOP: 0x00, BLOCK: 0x01, LOOP: 0x02, IF: 0x03, ELSE: 0x04, END: 0x05,
|
|
675
|
+
BR: 0x06, BR_IF: 0x07, RETURN: 0x08, CALL: 0x09, CALL_INDIRECT: 0x0A,
|
|
676
|
+
DROP: 0x10, SELECT: 0x11, LOCAL_GET: 0x12, LOCAL_SET: 0x13, LOCAL_TEE: 0x14,
|
|
677
|
+
GLOBAL_GET: 0x15, GLOBAL_SET: 0x16,
|
|
678
|
+
I32_LOAD: 0x20, I64_LOAD: 0x21, I32_STORE: 0x24, I64_STORE: 0x25,
|
|
679
|
+
I32_CONST: 0x30, I64_CONST: 0x31,
|
|
680
|
+
I32_ADD: 0x34, I32_SUB: 0x35, I32_MUL: 0x36, I32_DIV_S: 0x37,
|
|
681
|
+
I64_ADD: 0x39, I64_SUB: 0x3A, I64_MUL: 0x3B, I64_DIV_S: 0x3C,
|
|
682
|
+
I32_EQ: 0x40, I32_NE: 0x41, I32_LT_S: 0x42, I32_GT_S: 0x44,
|
|
683
|
+
I32_AND: 0x50, I32_OR: 0x51, I32_XOR: 0x52,
|
|
684
|
+
SLOAD: 0x80, SSTORE: 0x81, BALANCE: 0x84, TRANSFER: 0x85,
|
|
685
|
+
CONTRACT_CALL: 0x87, DELEGATE_CALL: 0x88, STATIC_CALL: 0x89,
|
|
686
|
+
CALLER: 0x90, ORIGIN: 0x91, CALLVALUE: 0x92, CALLDATA: 0x93,
|
|
687
|
+
BLOCKHASH: 0xA0, TIMESTAMP: 0xA2, BLOCKNUMBER: 0xA3, CHAINID: 0xA6,
|
|
688
|
+
SHA256: 0xB0, KECCAK256: 0xB1,
|
|
689
|
+
LOG0: 0xC0, LOG1: 0xC1, LOG2: 0xC2, LOG3: 0xC3, LOG4: 0xC4,
|
|
690
|
+
CROSS_VM_CALL: 0xD0, CROSS_VM_TRANSFER: 0xD1,
|
|
691
|
+
REVERT: 0xFE, HALT: 0xFF
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
// Function prologue
|
|
695
|
+
bytecode.push(OP.BLOCK); // Start function block
|
|
696
|
+
bytecode.push(func.params?.length || 0); // Param count
|
|
697
|
+
bytecode.push(func.returns?.length || 0); // Return count
|
|
698
|
+
|
|
699
|
+
// Register parameters as locals
|
|
700
|
+
for (const param of func.params || []) {
|
|
701
|
+
locals.set(param.name, localIndex++);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// Compile function body
|
|
705
|
+
if (func.body && Array.isArray(func.body)) {
|
|
706
|
+
for (const stmt of func.body) {
|
|
707
|
+
this.compileStatement(stmt, bytecode, locals, OP);
|
|
708
|
+
}
|
|
709
|
+
} else if (func.body) {
|
|
710
|
+
// Single expression body
|
|
711
|
+
this.compileExpression(func.body, bytecode, locals, OP);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// Function epilogue
|
|
715
|
+
if (func.returns?.length > 0) {
|
|
716
|
+
bytecode.push(OP.RETURN);
|
|
717
|
+
}
|
|
718
|
+
bytecode.push(OP.END);
|
|
719
|
+
|
|
720
|
+
return Buffer.from(bytecode);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Compile a statement to bytecode
|
|
725
|
+
*/
|
|
726
|
+
compileStatement(stmt, bytecode, locals, OP) {
|
|
727
|
+
if (!stmt) return;
|
|
728
|
+
|
|
729
|
+
switch (stmt.type) {
|
|
730
|
+
case 'Return':
|
|
731
|
+
case AST_NODES.RETURN:
|
|
732
|
+
if (stmt.argument) {
|
|
733
|
+
this.compileExpression(stmt.argument, bytecode, locals, OP);
|
|
734
|
+
}
|
|
735
|
+
bytecode.push(OP.RETURN);
|
|
736
|
+
break;
|
|
737
|
+
|
|
738
|
+
case 'If':
|
|
739
|
+
case AST_NODES.IF:
|
|
740
|
+
// Condition
|
|
741
|
+
this.compileExpression(stmt.condition, bytecode, locals, OP);
|
|
742
|
+
bytecode.push(OP.IF);
|
|
743
|
+
// Then branch
|
|
744
|
+
for (const s of stmt.consequent || []) {
|
|
745
|
+
this.compileStatement(s, bytecode, locals, OP);
|
|
746
|
+
}
|
|
747
|
+
// Else branch
|
|
748
|
+
if (stmt.alternate) {
|
|
749
|
+
bytecode.push(OP.ELSE);
|
|
750
|
+
for (const s of stmt.alternate || []) {
|
|
751
|
+
this.compileStatement(s, bytecode, locals, OP);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
bytecode.push(OP.END);
|
|
755
|
+
break;
|
|
756
|
+
|
|
757
|
+
case 'While':
|
|
758
|
+
case AST_NODES.WHILE:
|
|
759
|
+
bytecode.push(OP.LOOP);
|
|
760
|
+
// Condition
|
|
761
|
+
this.compileExpression(stmt.condition, bytecode, locals, OP);
|
|
762
|
+
bytecode.push(OP.BR_IF);
|
|
763
|
+
bytecode.push(0x00); // Break if false
|
|
764
|
+
// Body
|
|
765
|
+
for (const s of stmt.body || []) {
|
|
766
|
+
this.compileStatement(s, bytecode, locals, OP);
|
|
767
|
+
}
|
|
768
|
+
bytecode.push(OP.BR);
|
|
769
|
+
bytecode.push(0x00); // Continue loop
|
|
770
|
+
bytecode.push(OP.END);
|
|
771
|
+
break;
|
|
772
|
+
|
|
773
|
+
case 'Variable':
|
|
774
|
+
case AST_NODES.VARIABLE:
|
|
775
|
+
// Variable declaration with assignment
|
|
776
|
+
const varIndex = locals.size;
|
|
777
|
+
locals.set(stmt.name, varIndex);
|
|
778
|
+
if (stmt.init) {
|
|
779
|
+
this.compileExpression(stmt.init, bytecode, locals, OP);
|
|
780
|
+
bytecode.push(OP.LOCAL_SET);
|
|
781
|
+
bytecode.push(varIndex);
|
|
782
|
+
}
|
|
783
|
+
break;
|
|
784
|
+
|
|
785
|
+
case 'Assignment':
|
|
786
|
+
this.compileExpression(stmt.value, bytecode, locals, OP);
|
|
787
|
+
if (locals.has(stmt.target)) {
|
|
788
|
+
bytecode.push(OP.LOCAL_SET);
|
|
789
|
+
bytecode.push(locals.get(stmt.target));
|
|
790
|
+
} else {
|
|
791
|
+
// Storage write
|
|
792
|
+
bytecode.push(OP.SSTORE);
|
|
793
|
+
}
|
|
794
|
+
break;
|
|
795
|
+
|
|
796
|
+
case 'Emit':
|
|
797
|
+
case AST_NODES.EMIT:
|
|
798
|
+
// Compile event arguments
|
|
799
|
+
const argCount = stmt.args?.length || 0;
|
|
800
|
+
for (const arg of stmt.args || []) {
|
|
801
|
+
this.compileExpression(arg, bytecode, locals, OP);
|
|
802
|
+
}
|
|
803
|
+
// LOG opcode based on topic count
|
|
804
|
+
bytecode.push(OP.LOG0 + Math.min(argCount, 4));
|
|
805
|
+
break;
|
|
806
|
+
|
|
807
|
+
case 'Revert':
|
|
808
|
+
case AST_NODES.REVERT:
|
|
809
|
+
if (stmt.message) {
|
|
810
|
+
this.compileExpression(stmt.message, bytecode, locals, OP);
|
|
811
|
+
}
|
|
812
|
+
bytecode.push(OP.REVERT);
|
|
813
|
+
break;
|
|
814
|
+
|
|
815
|
+
case 'Assert':
|
|
816
|
+
case AST_NODES.ASSERT:
|
|
817
|
+
this.compileExpression(stmt.condition, bytecode, locals, OP);
|
|
818
|
+
bytecode.push(OP.IF);
|
|
819
|
+
bytecode.push(OP.NOP); // Pass
|
|
820
|
+
bytecode.push(OP.ELSE);
|
|
821
|
+
bytecode.push(OP.REVERT); // Fail
|
|
822
|
+
bytecode.push(OP.END);
|
|
823
|
+
break;
|
|
824
|
+
|
|
825
|
+
case 'Block':
|
|
826
|
+
case AST_NODES.BLOCK:
|
|
827
|
+
bytecode.push(OP.BLOCK);
|
|
828
|
+
for (const s of stmt.body || []) {
|
|
829
|
+
this.compileStatement(s, bytecode, locals, OP);
|
|
830
|
+
}
|
|
831
|
+
bytecode.push(OP.END);
|
|
832
|
+
break;
|
|
833
|
+
|
|
834
|
+
case 'Expression':
|
|
835
|
+
this.compileExpression(stmt.expression, bytecode, locals, OP);
|
|
836
|
+
bytecode.push(OP.DROP); // Discard result
|
|
837
|
+
break;
|
|
838
|
+
|
|
839
|
+
default:
|
|
840
|
+
// Try to compile as expression
|
|
841
|
+
if (stmt.expression || stmt.callee) {
|
|
842
|
+
this.compileExpression(stmt, bytecode, locals, OP);
|
|
843
|
+
bytecode.push(OP.DROP);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
/**
|
|
849
|
+
* Compile an expression to bytecode
|
|
850
|
+
*/
|
|
851
|
+
compileExpression(expr, bytecode, locals, OP) {
|
|
852
|
+
if (!expr) return;
|
|
853
|
+
|
|
854
|
+
switch (expr.type) {
|
|
855
|
+
case 'Literal':
|
|
856
|
+
case AST_NODES.LITERAL:
|
|
857
|
+
const val = expr.value;
|
|
858
|
+
if (typeof val === 'number') {
|
|
859
|
+
if (val <= 0x7FFFFFFF) {
|
|
860
|
+
bytecode.push(OP.I32_CONST);
|
|
861
|
+
this.pushInt32(bytecode, val);
|
|
862
|
+
} else {
|
|
863
|
+
bytecode.push(OP.I64_CONST);
|
|
864
|
+
this.pushInt64(bytecode, val);
|
|
865
|
+
}
|
|
866
|
+
} else if (typeof val === 'bigint') {
|
|
867
|
+
bytecode.push(OP.I64_CONST);
|
|
868
|
+
this.pushInt64(bytecode, val);
|
|
869
|
+
} else if (typeof val === 'boolean') {
|
|
870
|
+
bytecode.push(OP.I32_CONST);
|
|
871
|
+
bytecode.push(val ? 1 : 0);
|
|
872
|
+
bytecode.push(0, 0, 0);
|
|
873
|
+
} else if (typeof val === 'string') {
|
|
874
|
+
// String literal - encode as bytes
|
|
875
|
+
const strBytes = Buffer.from(val, 'utf8');
|
|
876
|
+
bytecode.push(OP.I32_CONST);
|
|
877
|
+
this.pushInt32(bytecode, strBytes.length);
|
|
878
|
+
bytecode.push(...strBytes);
|
|
879
|
+
}
|
|
880
|
+
break;
|
|
881
|
+
|
|
882
|
+
case 'Identifier':
|
|
883
|
+
case AST_NODES.IDENTIFIER:
|
|
884
|
+
const name = expr.name || expr.value;
|
|
885
|
+
if (locals.has(name)) {
|
|
886
|
+
bytecode.push(OP.LOCAL_GET);
|
|
887
|
+
bytecode.push(locals.get(name));
|
|
888
|
+
} else {
|
|
889
|
+
// Assume it's a storage read
|
|
890
|
+
bytecode.push(OP.SLOAD);
|
|
891
|
+
}
|
|
892
|
+
break;
|
|
893
|
+
|
|
894
|
+
case 'BinaryOp':
|
|
895
|
+
case AST_NODES.BINARY_OP:
|
|
896
|
+
this.compileExpression(expr.left, bytecode, locals, OP);
|
|
897
|
+
this.compileExpression(expr.right, bytecode, locals, OP);
|
|
898
|
+
switch (expr.operator) {
|
|
899
|
+
case '+': bytecode.push(OP.I64_ADD); break;
|
|
900
|
+
case '-': bytecode.push(OP.I64_SUB); break;
|
|
901
|
+
case '*': bytecode.push(OP.I64_MUL); break;
|
|
902
|
+
case '/': bytecode.push(OP.I64_DIV_S); break;
|
|
903
|
+
case '==': bytecode.push(OP.I32_EQ); break;
|
|
904
|
+
case '!=': bytecode.push(OP.I32_NE); break;
|
|
905
|
+
case '<': bytecode.push(OP.I32_LT_S); break;
|
|
906
|
+
case '>': bytecode.push(OP.I32_GT_S); break;
|
|
907
|
+
case '&&': bytecode.push(OP.I32_AND); break;
|
|
908
|
+
case '||': bytecode.push(OP.I32_OR); break;
|
|
909
|
+
case '^': bytecode.push(OP.I32_XOR); break;
|
|
910
|
+
default: bytecode.push(OP.NOP);
|
|
911
|
+
}
|
|
912
|
+
break;
|
|
913
|
+
|
|
914
|
+
case 'UnaryOp':
|
|
915
|
+
case AST_NODES.UNARY_OP:
|
|
916
|
+
this.compileExpression(expr.argument, bytecode, locals, OP);
|
|
917
|
+
switch (expr.operator) {
|
|
918
|
+
case '-':
|
|
919
|
+
bytecode.push(OP.I64_CONST);
|
|
920
|
+
this.pushInt64(bytecode, -1n);
|
|
921
|
+
bytecode.push(OP.I64_MUL);
|
|
922
|
+
break;
|
|
923
|
+
case '!':
|
|
924
|
+
bytecode.push(OP.I32_CONST);
|
|
925
|
+
bytecode.push(0, 0, 0, 0);
|
|
926
|
+
bytecode.push(OP.I32_EQ);
|
|
927
|
+
break;
|
|
928
|
+
}
|
|
929
|
+
break;
|
|
930
|
+
|
|
931
|
+
case 'Call':
|
|
932
|
+
case AST_NODES.CALL:
|
|
933
|
+
// Push arguments
|
|
934
|
+
for (const arg of expr.arguments || []) {
|
|
935
|
+
this.compileExpression(arg, bytecode, locals, OP);
|
|
936
|
+
}
|
|
937
|
+
// Function call
|
|
938
|
+
bytecode.push(OP.CALL);
|
|
939
|
+
// Function index would be resolved during linking
|
|
940
|
+
bytecode.push(0x00); // Placeholder
|
|
941
|
+
break;
|
|
942
|
+
|
|
943
|
+
case 'CrossCall':
|
|
944
|
+
case AST_NODES.CROSS_CALL:
|
|
945
|
+
// Cross-contract call - THE KEY INNOVATION!
|
|
946
|
+
// Push target address
|
|
947
|
+
if (expr.targetContract) {
|
|
948
|
+
bytecode.push(OP.I32_CONST);
|
|
949
|
+
const contractHash = crypto.createHash('sha256')
|
|
950
|
+
.update(expr.targetContract)
|
|
951
|
+
.digest();
|
|
952
|
+
bytecode.push(...contractHash.slice(0, 4));
|
|
953
|
+
}
|
|
954
|
+
// Push arguments
|
|
955
|
+
for (const arg of expr.arguments || []) {
|
|
956
|
+
this.compileExpression(arg, bytecode, locals, OP);
|
|
957
|
+
}
|
|
958
|
+
// Cross-VM call opcode
|
|
959
|
+
bytecode.push(OP.CROSS_VM_CALL);
|
|
960
|
+
break;
|
|
961
|
+
|
|
962
|
+
case 'MemberAccess':
|
|
963
|
+
case AST_NODES.MEMBER_ACCESS:
|
|
964
|
+
this.compileExpression(expr.object, bytecode, locals, OP);
|
|
965
|
+
// Handle built-in properties
|
|
966
|
+
if (expr.property === 'sender') {
|
|
967
|
+
bytecode.push(OP.CALLER);
|
|
968
|
+
} else if (expr.property === 'value') {
|
|
969
|
+
bytecode.push(OP.CALLVALUE);
|
|
970
|
+
} else if (expr.property === 'balance') {
|
|
971
|
+
bytecode.push(OP.BALANCE);
|
|
972
|
+
} else if (expr.property === 'timestamp') {
|
|
973
|
+
bytecode.push(OP.TIMESTAMP);
|
|
974
|
+
} else if (expr.property === 'number') {
|
|
975
|
+
bytecode.push(OP.BLOCKNUMBER);
|
|
976
|
+
}
|
|
977
|
+
break;
|
|
978
|
+
|
|
979
|
+
case 'IndexAccess':
|
|
980
|
+
case AST_NODES.INDEX_ACCESS:
|
|
981
|
+
this.compileExpression(expr.object, bytecode, locals, OP);
|
|
982
|
+
this.compileExpression(expr.index, bytecode, locals, OP);
|
|
983
|
+
bytecode.push(OP.I64_ADD); // Compute offset
|
|
984
|
+
bytecode.push(OP.I64_LOAD); // Load value
|
|
985
|
+
break;
|
|
986
|
+
|
|
987
|
+
case 'StorageRead':
|
|
988
|
+
case AST_NODES.STORAGE_READ:
|
|
989
|
+
bytecode.push(OP.SLOAD);
|
|
990
|
+
break;
|
|
991
|
+
|
|
992
|
+
case 'StorageWrite':
|
|
993
|
+
case AST_NODES.STORAGE_WRITE:
|
|
994
|
+
this.compileExpression(expr.value, bytecode, locals, OP);
|
|
995
|
+
bytecode.push(OP.SSTORE);
|
|
996
|
+
break;
|
|
997
|
+
|
|
998
|
+
default:
|
|
999
|
+
// Unknown expression - no-op
|
|
1000
|
+
bytecode.push(OP.NOP);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* Push a 32-bit integer to bytecode (little-endian)
|
|
1006
|
+
*/
|
|
1007
|
+
pushInt32(bytecode, value) {
|
|
1008
|
+
const v = Number(value);
|
|
1009
|
+
bytecode.push(v & 0xFF);
|
|
1010
|
+
bytecode.push((v >> 8) & 0xFF);
|
|
1011
|
+
bytecode.push((v >> 16) & 0xFF);
|
|
1012
|
+
bytecode.push((v >> 24) & 0xFF);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
/**
|
|
1016
|
+
* Push a 64-bit integer to bytecode (little-endian)
|
|
1017
|
+
*/
|
|
1018
|
+
pushInt64(bytecode, value) {
|
|
1019
|
+
const v = BigInt(value);
|
|
1020
|
+
for (let i = 0; i < 8; i++) {
|
|
1021
|
+
bytecode.push(Number((v >> BigInt(i * 8)) & 0xFFn));
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Optimize unified IR
|
|
1027
|
+
*/
|
|
1028
|
+
optimize(ir) {
|
|
1029
|
+
console.log('[UnifiedCompiler] Optimizing unified IR...');
|
|
1030
|
+
|
|
1031
|
+
// Inline small cross-contract calls
|
|
1032
|
+
this.inlineCrossCalls(ir);
|
|
1033
|
+
|
|
1034
|
+
// Deduplicate shared code
|
|
1035
|
+
this.deduplicateCode(ir);
|
|
1036
|
+
|
|
1037
|
+
// Optimize storage access patterns
|
|
1038
|
+
this.optimizeStorage(ir);
|
|
1039
|
+
|
|
1040
|
+
return ir;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
inlineCrossCalls(ir) {
|
|
1044
|
+
// If a cross-call is to a small function, inline it!
|
|
1045
|
+
for (const crossCall of ir.crossCalls) {
|
|
1046
|
+
const targetContract = ir.contracts.find(c => c.name === crossCall.to);
|
|
1047
|
+
if (targetContract) {
|
|
1048
|
+
const targetFunc = targetContract.functions.find(f => f.name === crossCall.function);
|
|
1049
|
+
if (targetFunc && targetFunc.bytecode.length < 50) {
|
|
1050
|
+
crossCall.inline = true;
|
|
1051
|
+
crossCall.inlinedBytecode = targetFunc.bytecode;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
deduplicateCode(ir) {
|
|
1058
|
+
// Find duplicate bytecode sequences across contracts
|
|
1059
|
+
const seen = new Map();
|
|
1060
|
+
for (const contract of ir.contracts) {
|
|
1061
|
+
for (const func of contract.functions) {
|
|
1062
|
+
const hash = crypto.createHash('sha256').update(func.bytecode).digest('hex');
|
|
1063
|
+
if (seen.has(hash)) {
|
|
1064
|
+
func.deduplicatedTo = seen.get(hash);
|
|
1065
|
+
} else {
|
|
1066
|
+
seen.set(hash, `${contract.name}::${func.name}`);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
optimizeStorage(ir) {
|
|
1073
|
+
// Optimize storage access by grouping frequently accessed slots
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
/**
|
|
1077
|
+
* Generate final bytecode
|
|
1078
|
+
*/
|
|
1079
|
+
generateBytecode(ir) {
|
|
1080
|
+
const sections = [];
|
|
1081
|
+
|
|
1082
|
+
// Magic number: "JUNIFIED"
|
|
1083
|
+
sections.push(Buffer.from([0x4A, 0x55, 0x4E, 0x49, 0x46, 0x49, 0x45, 0x44]));
|
|
1084
|
+
|
|
1085
|
+
// Version
|
|
1086
|
+
sections.push(Buffer.from(ir.version));
|
|
1087
|
+
|
|
1088
|
+
// Contract count
|
|
1089
|
+
sections.push(Buffer.from([ir.contracts.length]));
|
|
1090
|
+
|
|
1091
|
+
// Contract table
|
|
1092
|
+
for (const contract of ir.contracts) {
|
|
1093
|
+
// Contract header
|
|
1094
|
+
const nameBytes = Buffer.from(contract.name);
|
|
1095
|
+
sections.push(Buffer.from([nameBytes.length]));
|
|
1096
|
+
sections.push(nameBytes);
|
|
1097
|
+
|
|
1098
|
+
// Function count
|
|
1099
|
+
sections.push(Buffer.from([contract.functions.length]));
|
|
1100
|
+
|
|
1101
|
+
// Functions
|
|
1102
|
+
for (const func of contract.functions) {
|
|
1103
|
+
// Selector (4 bytes)
|
|
1104
|
+
sections.push(func.selector);
|
|
1105
|
+
|
|
1106
|
+
// Bytecode length
|
|
1107
|
+
const lenBuf = Buffer.alloc(2);
|
|
1108
|
+
lenBuf.writeUInt16LE(func.bytecode.length);
|
|
1109
|
+
sections.push(lenBuf);
|
|
1110
|
+
|
|
1111
|
+
// Bytecode
|
|
1112
|
+
sections.push(func.bytecode);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// Cross-call table
|
|
1117
|
+
sections.push(Buffer.from([ir.crossCalls.length]));
|
|
1118
|
+
for (const crossCall of ir.crossCalls) {
|
|
1119
|
+
sections.push(crossCall.selector);
|
|
1120
|
+
// Add target info
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
return Buffer.concat(sections);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/**
|
|
1127
|
+
* Compute function selector (4 bytes)
|
|
1128
|
+
*/
|
|
1129
|
+
computeSelector(name, params) {
|
|
1130
|
+
const signature = `${name}(${(params || []).map(p => p.type || 'uint256').join(',')})`;
|
|
1131
|
+
const hash = crypto.createHash('sha256').update(signature).digest();
|
|
1132
|
+
return hash.slice(0, 4);
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
/**
|
|
1136
|
+
* Compute storage slot (deterministic across all contracts!)
|
|
1137
|
+
*/
|
|
1138
|
+
computeStorageSlot(contractName, varName) {
|
|
1139
|
+
const key = `${contractName}::${varName}`;
|
|
1140
|
+
const hash = crypto.createHash('sha256').update(key).digest();
|
|
1141
|
+
return hash.slice(0, 32);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1146
|
+
// LANGUAGE PARSERS (Stubs - would be full parsers)
|
|
1147
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1148
|
+
|
|
1149
|
+
class SolidityParser {
|
|
1150
|
+
parse(code) {
|
|
1151
|
+
// Use JIR compiler's parser
|
|
1152
|
+
const JIRCompiler = require('../compiler/jir-compiler');
|
|
1153
|
+
const compiler = new JIRCompiler();
|
|
1154
|
+
return compiler._parseEVM(code);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
class RustParser {
|
|
1159
|
+
parse(code) {
|
|
1160
|
+
const JIRCompiler = require('../compiler/jir-compiler');
|
|
1161
|
+
const compiler = new JIRCompiler();
|
|
1162
|
+
return compiler._parseSVM(code);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
class MoveParser {
|
|
1167
|
+
parse(code) {
|
|
1168
|
+
const JIRCompiler = require('../compiler/jir-compiler');
|
|
1169
|
+
const compiler = new JIRCompiler();
|
|
1170
|
+
return compiler._parseMove(code);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
class FunCParser {
|
|
1175
|
+
parse(code) {
|
|
1176
|
+
const JIRCompiler = require('../compiler/jir-compiler');
|
|
1177
|
+
const compiler = new JIRCompiler();
|
|
1178
|
+
return compiler._parseTVM(code);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
class CairoParser {
|
|
1183
|
+
parse(code) {
|
|
1184
|
+
const JIRCompiler = require('../compiler/jir-compiler');
|
|
1185
|
+
const compiler = new JIRCompiler();
|
|
1186
|
+
return compiler._parseCairo(code);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
class VyperParser {
|
|
1191
|
+
parse(code) {
|
|
1192
|
+
// Vyper parser - Python-like syntax for EVM
|
|
1193
|
+
const ast = {
|
|
1194
|
+
type: 'Program',
|
|
1195
|
+
sourceType: 'vyper',
|
|
1196
|
+
body: [],
|
|
1197
|
+
contracts: []
|
|
1198
|
+
};
|
|
1199
|
+
|
|
1200
|
+
// Parse contract interfaces - @external, @internal, @view, @pure
|
|
1201
|
+
const contractMatch = code.match(/#\s*@version\s+[\d.]+/);
|
|
1202
|
+
const contractName = 'VyperContract'; // Vyper files are single contracts
|
|
1203
|
+
|
|
1204
|
+
const contract = {
|
|
1205
|
+
type: 'ContractDeclaration',
|
|
1206
|
+
name: contractName,
|
|
1207
|
+
body: [],
|
|
1208
|
+
storage: [],
|
|
1209
|
+
events: []
|
|
1210
|
+
};
|
|
1211
|
+
|
|
1212
|
+
// Parse state variables (top-level assignments before functions)
|
|
1213
|
+
// Pattern: varname: type = value OR varname: type
|
|
1214
|
+
const stateVarPattern = /^(\w+)\s*:\s*(\w+(?:\[\w+(?:,\s*\w+)*\])?)\s*(?:=\s*[^\n]+)?$/gm;
|
|
1215
|
+
let match;
|
|
1216
|
+
while ((match = stateVarPattern.exec(code)) !== null) {
|
|
1217
|
+
// Skip if inside a function (check if preceded by def)
|
|
1218
|
+
const beforeMatch = code.substring(0, match.index);
|
|
1219
|
+
const lastDef = beforeMatch.lastIndexOf('def ');
|
|
1220
|
+
const lastNewline = beforeMatch.lastIndexOf('\n\n');
|
|
1221
|
+
if (lastDef === -1 || lastNewline > lastDef) {
|
|
1222
|
+
contract.storage.push({
|
|
1223
|
+
type: 'StateVariableDeclaration',
|
|
1224
|
+
name: match[1],
|
|
1225
|
+
dataType: this.mapVyperType(match[2]),
|
|
1226
|
+
visibility: 'public'
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
// Parse functions: @external/@internal/@view/@pure def func_name(params) -> return_type:
|
|
1232
|
+
const funcPattern = /@(external|internal|view|pure)\s*\ndef\s+(\w+)\s*\(([^)]*)\)(?:\s*->\s*(\w+))?\s*:/g;
|
|
1233
|
+
while ((match = funcPattern.exec(code)) !== null) {
|
|
1234
|
+
const visibility = match[1] === 'external' ? 'public' : match[1];
|
|
1235
|
+
const funcName = match[2];
|
|
1236
|
+
const paramsStr = match[3];
|
|
1237
|
+
const returnType = match[4];
|
|
1238
|
+
|
|
1239
|
+
// Parse parameters
|
|
1240
|
+
const params = [];
|
|
1241
|
+
if (paramsStr.trim()) {
|
|
1242
|
+
const paramParts = paramsStr.split(',');
|
|
1243
|
+
for (const part of paramParts) {
|
|
1244
|
+
const paramMatch = part.trim().match(/(\w+)\s*:\s*(\w+(?:\[\w+(?:,\s*\w+)*\])?)/);
|
|
1245
|
+
if (paramMatch) {
|
|
1246
|
+
params.push({
|
|
1247
|
+
name: paramMatch[1],
|
|
1248
|
+
type: this.mapVyperType(paramMatch[2])
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
contract.body.push({
|
|
1255
|
+
type: 'FunctionDeclaration',
|
|
1256
|
+
name: funcName,
|
|
1257
|
+
params: params,
|
|
1258
|
+
returns: returnType ? [this.mapVyperType(returnType)] : [],
|
|
1259
|
+
visibility: visibility,
|
|
1260
|
+
stateMutability: match[1] === 'view' ? 'view' : (match[1] === 'pure' ? 'pure' : null)
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
// Also parse simpler function patterns without decorators
|
|
1265
|
+
const simpleFuncPattern = /def\s+(\w+)\s*\(([^)]*)\)(?:\s*->\s*(\w+))?\s*:/g;
|
|
1266
|
+
const foundFuncs = new Set(contract.body.map(f => f.name));
|
|
1267
|
+
while ((match = simpleFuncPattern.exec(code)) !== null) {
|
|
1268
|
+
if (!foundFuncs.has(match[1])) {
|
|
1269
|
+
const funcName = match[1];
|
|
1270
|
+
const paramsStr = match[2];
|
|
1271
|
+
const returnType = match[3];
|
|
1272
|
+
|
|
1273
|
+
const params = [];
|
|
1274
|
+
if (paramsStr.trim()) {
|
|
1275
|
+
const paramParts = paramsStr.split(',');
|
|
1276
|
+
for (const part of paramParts) {
|
|
1277
|
+
const paramMatch = part.trim().match(/(\w+)\s*:\s*(\w+(?:\[\w+(?:,\s*\w+)*\])?)/);
|
|
1278
|
+
if (paramMatch) {
|
|
1279
|
+
params.push({
|
|
1280
|
+
name: paramMatch[1],
|
|
1281
|
+
type: this.mapVyperType(paramMatch[2])
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
contract.body.push({
|
|
1288
|
+
type: 'FunctionDeclaration',
|
|
1289
|
+
name: funcName,
|
|
1290
|
+
params: params,
|
|
1291
|
+
returns: returnType ? [this.mapVyperType(returnType)] : [],
|
|
1292
|
+
visibility: 'internal',
|
|
1293
|
+
stateMutability: null
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// Parse events: event EventName: ...
|
|
1299
|
+
const eventPattern = /event\s+(\w+)\s*:/g;
|
|
1300
|
+
while ((match = eventPattern.exec(code)) !== null) {
|
|
1301
|
+
contract.events.push({
|
|
1302
|
+
type: 'EventDeclaration',
|
|
1303
|
+
name: match[1]
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
ast.contracts.push(contract);
|
|
1308
|
+
return ast;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
mapVyperType(vyperType) {
|
|
1312
|
+
const typeMap = {
|
|
1313
|
+
'uint256': 'uint256',
|
|
1314
|
+
'uint128': 'uint128',
|
|
1315
|
+
'uint64': 'uint64',
|
|
1316
|
+
'uint32': 'uint32',
|
|
1317
|
+
'uint16': 'uint16',
|
|
1318
|
+
'uint8': 'uint8',
|
|
1319
|
+
'int256': 'int256',
|
|
1320
|
+
'int128': 'int128',
|
|
1321
|
+
'int64': 'int64',
|
|
1322
|
+
'int32': 'int32',
|
|
1323
|
+
'int16': 'int16',
|
|
1324
|
+
'int8': 'int8',
|
|
1325
|
+
'bool': 'bool',
|
|
1326
|
+
'address': 'address',
|
|
1327
|
+
'bytes32': 'bytes32',
|
|
1328
|
+
'Bytes': 'bytes',
|
|
1329
|
+
'String': 'string',
|
|
1330
|
+
'decimal': 'int256' // Vyper decimal maps to int256 (fixed point)
|
|
1331
|
+
};
|
|
1332
|
+
|
|
1333
|
+
// Handle HashMap[K, V] -> mapping
|
|
1334
|
+
if (vyperType.startsWith('HashMap')) {
|
|
1335
|
+
return 'mapping';
|
|
1336
|
+
}
|
|
1337
|
+
// Handle DynArray[T, N] -> array
|
|
1338
|
+
if (vyperType.startsWith('DynArray')) {
|
|
1339
|
+
return 'array';
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
return typeMap[vyperType] || vyperType;
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
module.exports = {
|
|
1347
|
+
UnifiedCompiler,
|
|
1348
|
+
UNIFIED_TYPES,
|
|
1349
|
+
AST_NODES
|
|
1350
|
+
};
|