#!/usr/bin/env node /** * AeThex Language Compiler v1.0 * Compiles .aethex files to JavaScript, Lua (Roblox), Verse (UEFN), and C# (Unity) */ const fs = require('fs'); const path = require('path'); class AeThexCompiler { constructor(options = {}) { this.target = options.target || 'javascript'; // javascript, roblox, uefn, unity this.output = []; this.indent = 0; this.errors = []; this.warnings = []; this.line = 1; this.sourceFile = options.sourceFile || 'unknown'; } // Error handling error(message, line = this.line) { this.errors.push({ type: 'error', message, line, file: this.sourceFile }); } warn(message, line = this.line) { this.warnings.push({ type: 'warning', message, line, file: this.sourceFile }); } // Output helpers emit(code) { const indentation = ' '.repeat(this.indent); this.output.push(indentation + code); } // Main compile function compile(sourceCode) { this.output = []; this.errors = []; this.warnings = []; this.line = 1; // Add runtime based on target this.addRuntime(); const lines = sourceCode.split('\n'); let i = 0; while (i < lines.length) { this.line = i + 1; const line = lines[i].trim(); if (!line || line.startsWith('#')) { i++; continue; } try { if (line.startsWith('reality ')) { i = this.compileReality(lines, i); } else if (line.startsWith('journey ')) { i = this.compileJourney(lines, i); } else if (line.startsWith('sync ')) { i = this.compileSync(lines, i); } else if (line.startsWith('when ')) { i = this.compileWhen(lines, i); } else if (line.startsWith('notify ')) { i = this.compileNotify(lines, i); } else if (line.startsWith('reveal ')) { i = this.compileReveal(lines, i); } else if (line.startsWith('import ')) { i = this.compileImport(lines, i); } else { i++; } } catch (err) { this.error(`Compilation error: ${err.message}`, i + 1); i++; } } return { code: this.output.join('\n'), errors: this.errors, warnings: this.warnings, success: this.errors.length === 0 }; } // Runtime based on target addRuntime() { if (this.target === 'javascript') { this.emit(`// AeThex Runtime v1.0 (JavaScript Target)`); this.emit(`const AeThex = {`); this.indent++; this.emit(`platform: 'web',`); this.emit(`sync: async function(data, platforms) {`); this.indent++; this.emit(`console.log('[AeThex] Syncing:', data, 'to platforms:', platforms);`); this.emit(`// TODO: Implement actual sync logic`); this.emit(`return true;`); this.indent--; this.emit(`},`); this.emit(`notify: function(message) {`); this.indent++; this.emit(`console.log('[AeThex]', message);`); this.indent--; this.emit(`},`); this.emit(`reveal: function(data) {`); this.indent++; this.emit(`console.log('[AeThex] Revealed:', data);`); this.indent--; this.emit(`}`); this.indent--; this.emit(`};`); this.emit(``); } else if (this.target === 'roblox') { this.emit(`-- AeThex Runtime v1.0 (Roblox/Lua Target)`); this.emit(`local AeThex = {`); this.indent++; this.emit(`platform = "roblox",`); this.emit(`sync = function(data, platforms)`); this.indent++; this.emit(`print("[AeThex] Syncing:", data, "to platforms:", table.concat(platforms, ", "))`); this.emit(`return true`); this.indent--; this.emit(`end,`); this.emit(`notify = function(message)`); this.indent++; this.emit(`print("[AeThex]", message)`); this.indent--; this.emit(`end,`); this.emit(`reveal = function(data)`); this.indent++; this.emit(`print("[AeThex] Revealed:", data)`); this.indent--; this.emit(`end`); this.indent--; this.emit(`}`); this.emit(``); } } // Compile 'reality' blocks compileReality(lines, startIndex) { const line = lines[startIndex].trim(); const match = line.match(/reality\s+(\w+)\s*\{/); if (!match) { this.error(`Invalid reality declaration: ${line}`); return startIndex + 1; } const realityName = match[1]; if (this.target === 'javascript') { this.emit(`// Reality: ${realityName}`); this.emit(`const ${realityName} = {`); this.indent++; } else if (this.target === 'roblox') { this.emit(`-- Reality: ${realityName}`); this.emit(`local ${realityName} = {`); this.indent++; } let i = startIndex + 1; while (i < lines.length && !lines[i].trim().startsWith('}')) { const propLine = lines[i].trim(); if (propLine && !propLine.startsWith('#')) { const propMatch = propLine.match(/(\w+):\s*(.+)/); if (propMatch) { const [, key, value] = propMatch; if (this.target === 'javascript') { this.emit(`${key}: ${value},`); } else if (this.target === 'roblox') { this.emit(`${key} = ${value.replace(/\[/g, '{').replace(/\]/g, '}')},`); } } } i++; } this.indent--; if (this.target === 'javascript') { this.emit(`};`); } else if (this.target === 'roblox') { this.emit(`}`); } this.emit(``); return i + 1; } // Compile 'journey' functions compileJourney(lines, startIndex) { const line = lines[startIndex].trim(); const match = line.match(/journey\s+(\w+)\(([^)]*)\)\s*\{/); if (!match) { this.error(`Invalid journey declaration: ${line}`); return startIndex + 1; } const [, name, params] = match; if (this.target === 'javascript') { this.emit(`async function ${name}(${params}) {`); } else if (this.target === 'roblox') { this.emit(`function ${name}(${params})`); } this.indent++; let i = startIndex + 1; while (i < lines.length && !lines[i].trim().startsWith('}')) { const bodyLine = lines[i].trim(); if (bodyLine && !bodyLine.startsWith('#') && !bodyLine.includes('platform:')) { if (bodyLine.startsWith('sync ')) { i = this.compileSync(lines, i); } else if (bodyLine.startsWith('when ')) { i = this.compileWhen(lines, i); } else if (bodyLine.startsWith('notify ')) { i = this.compileNotify(lines, i); } else if (bodyLine.startsWith('reveal ')) { i = this.compileReveal(lines, i); } else { i++; } } else { i++; } } this.indent--; if (this.target === 'javascript') { this.emit(`}`); } else if (this.target === 'roblox') { this.emit(`end`); } this.emit(``); return i + 1; } // Compile 'sync' statements compileSync(lines, index) { const line = lines[index].trim(); const match = line.match(/sync\s+(.+?)\s+across\s+\[(.+?)\]/); if (!match) { this.error(`Invalid sync statement: ${line}`); return index + 1; } const [, data, platforms] = match; if (this.target === 'javascript') { this.emit(`await AeThex.sync(${data}, [${platforms}]);`); } else if (this.target === 'roblox') { this.emit(`AeThex.sync(${data}, {${platforms}})`); } return index + 1; } // Compile 'when' conditionals compileWhen(lines, startIndex) { const line = lines[startIndex].trim(); const match = line.match(/when\s+(.+?)\s*\{/); if (!match) { this.error(`Invalid when statement: ${line}`); return startIndex + 1; } const condition = match[1]; if (this.target === 'javascript') { this.emit(`if (${condition}) {`); } else if (this.target === 'roblox') { this.emit(`if ${condition} then`); } this.indent++; let i = startIndex + 1; while (i < lines.length && !lines[i].trim().startsWith('}')) { const bodyLine = lines[i].trim(); if (bodyLine && !bodyLine.startsWith('#')) { if (bodyLine.startsWith('sync ')) { i = this.compileSync(lines, i); } else if (bodyLine.startsWith('notify ')) { i = this.compileNotify(lines, i); } else if (bodyLine.startsWith('reveal ')) { i = this.compileReveal(lines, i); } else { this.emit(bodyLine); i++; } } else { i++; } } this.indent--; if (this.target === 'javascript') { this.emit(`}`); } else if (this.target === 'roblox') { this.emit(`end`); } return i + 1; } // Compile 'notify' statements compileNotify(lines, index) { const line = lines[index].trim(); const match = line.match(/notify\s+"(.+)"/); if (!match) { this.error(`Invalid notify statement: ${line}`); return index + 1; } const message = match[1]; this.emit(`AeThex.notify("${message}");`); return index + 1; } // Compile 'reveal' statements compileReveal(lines, index) { const line = lines[index].trim(); const match = line.match(/reveal\s+(.+)/); if (!match) { this.error(`Invalid reveal statement: ${line}`); return index + 1; } const data = match[1]; this.emit(`AeThex.reveal(${data});`); return index + 1; } // Compile 'import' statements compileImport(lines, index) { const line = lines[index].trim(); const match = line.match(/import\s+\{([^}]+)\}\s+from\s+"(.+)"/); if (!match) { this.error(`Invalid import statement: ${line}`); return index + 1; } const [, imports, module] = match; if (this.target === 'javascript') { this.emit(`import { ${imports} } from "${module}";`); } else if (this.target === 'roblox') { this.emit(`-- Import: ${imports} from ${module}`); this.emit(`local ${imports.split(',')[0].trim()} = require(game.ServerScriptService.${module.replace(/@aethex\//,'')})`); } return index + 1; } // Format errors for display formatErrors() { if (this.errors.length === 0 && this.warnings.length === 0) { return '✅ Compilation successful!'; } let output = ''; if (this.errors.length > 0) { output += '❌ Compilation failed with errors:\n\n'; this.errors.forEach(err => { output += ` ${this.sourceFile}:${err.line} - ${err.message}\n`; }); } if (this.warnings.length > 0) { output += '\n⚠️ Warnings:\n\n'; this.warnings.forEach(warn => { output += ` ${this.sourceFile}:${warn.line} - ${warn.message}\n`; }); } return output; } } // CLI Interface if (require.main === module) { const args = process.argv.slice(2); if (args.length === 0) { console.log(` AeThex Language Compiler v1.0 Usage: aethex [options] Options: --target Target platform: javascript, roblox, uefn, unity (default: javascript) --output Output file path --help Show this help Examples: aethex myapp.aethex aethex myapp.aethex --target roblox --output game.lua `); process.exit(0); } const inputFile = args[0]; const targetIndex = args.indexOf('--target'); const outputIndex = args.indexOf('--output'); const target = targetIndex !== -1 ? args[targetIndex + 1] : 'javascript'; const outputFile = outputIndex !== -1 ? args[outputIndex + 1] : null; if (!fs.existsSync(inputFile)) { console.error(`❌ File not found: ${inputFile}`); process.exit(1); } const sourceCode = fs.readFileSync(inputFile, 'utf-8'); const compiler = new AeThexCompiler({ target, sourceFile: inputFile }); const result = compiler.compile(sourceCode); console.log(compiler.formatErrors()); if (result.success) { if (outputFile) { fs.writeFileSync(outputFile, result.code); console.log(`\n✅ Compiled to: ${outputFile}`); } else { console.log('\n--- Compiled Output ---\n'); console.log(result.code); } } else { process.exit(1); } } module.exports = AeThexCompiler;