File size: 4,411 Bytes
1d3f990 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | // EmojiCode Parser β Formal Parser for Emoji-based Instructions
// Produces deterministic canonical representation
import crypto from 'crypto';
// Emoji to (Runtime, Verb) mapping
const EMOJI_MAP = {
'β‘': { runtime: 'holyc', verb: 'Execute' },
'π¦': { runtime: 'rust', verb: 'LocExecute' },
'β
': { runtime: 'ada', verb: 'Verify' },
'π±': { runtime: 'haskell', verb: 'ConsCell' },
'π€': { runtime: 'emoji', verb: 'Encode' },
'βοΈ': { runtime: 'rust', verb: 'Configure' },
'π': { runtime: 'python3', verb: 'LogWrite' },
};
/**
* parse(expression: string): Instruction
* Parse emoji expression into canonical instruction object
*
* Syntax: EMOJI ARG1:value1 ARG2:value2 ...
* Example: β‘ fn:FreqAnchor1618 mode:ring0
*/
export function parse(expression) {
const trimmed = expression.trim();
if (!trimmed) {
throw new Error('Empty expression');
}
const tokens = trimmed.split(/\s+/);
const emoji = tokens[0];
if (!EMOJI_MAP[emoji]) {
throw new Error(`Unknown emoji: ${emoji}`);
}
const { runtime, verb } = EMOJI_MAP[emoji];
const args = {};
// Parse key:value arguments
for (let i = 1; i < tokens.length; i++) {
const token = tokens[i];
if (token.includes(':')) {
const [key, value] = token.split(':', 2);
args[key] = parseValue(value);
} else {
throw new Error(`Invalid token format: ${token} (expected key:value)`);
}
}
// Build canonical instruction
const instruction = {
protocol_version: '1.0.0',
symbol: emoji,
target_runtime: runtime,
verb: verb,
arguments: args,
timestamp: Math.floor(Date.now() / 1000),
};
// Compute deterministic hash
const canonical = canonicalize(instruction);
instruction.instruction_hash = hashInstruction(canonical);
instruction.instruction_id = instruction.instruction_hash;
return instruction;
}
/**
* canonicalize(instruction: object): string
* Produce deterministic JSON-LD representation for hashing
*/
function canonicalize(instruction) {
// Sort keys and arguments for determinism
const sorted = {
protocol_version: instruction.protocol_version,
symbol: instruction.symbol,
target_runtime: instruction.target_runtime,
verb: instruction.verb,
arguments: sortObjectKeys(instruction.arguments),
timestamp: instruction.timestamp,
};
return JSON.stringify(sorted);
}
/**
* sortObjectKeys(obj: object): object
* Recursively sort object keys
*/
function sortObjectKeys(obj) {
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
return obj;
}
const sorted = {};
Object.keys(obj)
.sort()
.forEach((key) => {
sorted[key] = sortObjectKeys(obj[key]);
});
return sorted;
}
/**
* hashInstruction(canonical: string): string
* SHA-256 hash of canonical representation
*/
function hashInstruction(canonical) {
return crypto.createHash('sha256').update(canonical).digest('hex');
}
/**
* parseValue(valueStr: string): string | number | boolean
* Parse value string to appropriate type
*/
function parseValue(valueStr) {
if (valueStr === 'true') return true;
if (valueStr === 'false') return false;
if (/^\d+$/.test(valueStr)) return parseInt(valueStr, 10);
if (/^\d+\.\d+$/.test(valueStr)) return parseFloat(valueStr);
return valueStr;
}
/**
* roundTripTest(expression: string): object
* Verify that parse and canonicalize produce deterministic results
*/
export function roundTripTest(expression) {
const instr1 = parse(expression);
const instr2 = parse(expression);
return {
expr: expression,
hash1: instr1.instruction_hash,
hash2: instr2.instruction_hash,
equal: instr1.instruction_hash === instr2.instruction_hash,
instruction: instr1,
};
}
// CLI for testing
if (import.meta.url === `file://${process.argv[1]}`) {
const tests = [
'β‘ fn:FreqAnchor1618',
'π¦ mode:release',
'β
contract:borrow step:3',
'π± cons:car_cdr',
];
console.log('=== EmojiCode Parser Round-trip Tests ===');
for (const test of tests) {
const result = roundTripTest(test);
console.log(`${test:<30} β hash: ${result.hash1.slice(0, 16)}...`);
console.log(` Deterministic: ${result.equal ? 'YES' : 'NO'}`);
}
}
|