helix/dna/mds/
schema.rs

1use std::path::PathBuf;
2use clap::ValueEnum;
3use anyhow::{Result, Context};
4use crate::dna::mds::loader::BinaryLoader;
5use crate::dna::compiler::Compiler;
6use crate::dna::mds::optimizer::OptimizationLevel;
7
8#[derive(Clone, ValueEnum, Debug)]
9pub enum Language {
10    Rust,
11    Python,
12    JavaScript,
13    CSharp,
14    Java,
15    Go,
16    Ruby,
17    Php,
18}
19
20pub fn schema_command(
21    target: PathBuf,
22    lang: Language,
23    output: Option<PathBuf>,
24    verbose: bool,
25) -> Result<(), Box<dyn std::error::Error>> {
26    if verbose {
27        println!("🔧 Generating SDK schema...");
28        println!("  Target: {}", target.display());
29        println!("  Language: {:?}", lang);
30        println!("  Output: {:?}", output);
31    }
32
33    // Load and parse the Helix file
34    let source = std::fs::read_to_string(&target)
35        .context(format!("Failed to read Helix file: {}", target.display()))?;
36
37    let tokens = crate::dna::atp::lexer::tokenize(&source)
38        .map_err(|e| anyhow::anyhow!("Failed to tokenize Helix file: {} - {}", target.display(), e))?;
39    let ast = crate::dna::atp::parser::parse(tokens)
40        .map_err(|e| anyhow::anyhow!("Failed to parse Helix file: {} - {}", target.display(), e))?;
41
42    // Validation is done through the AST parsing and semantic analysis
43    // let _ = crate::dna::mds::semantic::validate(&ast)
44    //     .map_err(|e| format!("Invalid Helix configuration: {} - {:?}", target.display(), e))?;
45
46    // Determine output file path
47    let output_path = output.unwrap_or_else(|| {
48        let stem = target.file_stem().unwrap_or_default().to_string_lossy();
49        let extension = match lang {
50            Language::Rust => "rs",
51            Language::Python => "py",
52            Language::JavaScript => "js",
53            Language::CSharp => "cs",
54            Language::Java => "java",
55            Language::Go => "go",
56            Language::Ruby => "rb",
57            Language::Php => "php",
58        };
59        target.with_file_name(format!("{}_schema.{}", stem, extension))
60    });
61
62    // Generate schema based on language
63    let schema_code = generate_schema_code(&ast, &lang)?;
64
65    // Write the schema file
66    std::fs::write(&output_path, schema_code)
67        .context(format!("Failed to write schema file: {}", output_path.display()))?;
68
69    println!("✅ Schema generated successfully: {}", output_path.display());
70
71    if verbose {
72        println!("  Language: {:?}", lang);
73        println!("  Sections: {}", ast.declarations.len());
74    }
75
76    Ok(())
77}
78pub fn generate_schema_code(ast: &crate::dna::atp::ast::HelixAst, lang: &Language) -> Result<String, Box<dyn std::error::Error>> {
79    match lang {
80        Language::Rust => generate_rust_schema(ast),
81        Language::Python => generate_python_schema(ast),
82        Language::JavaScript => generate_javascript_schema(ast),
83        Language::CSharp => generate_csharp_schema(ast),
84        Language::Java => generate_java_schema(ast),
85        Language::Go => generate_go_schema(ast),
86        Language::Ruby => generate_ruby_schema(ast),
87        Language::Php => generate_php_schema(ast),
88    }
89}
90pub fn generate_rust_schema(_ast: &crate::dna::atp::ast::HelixAst) -> Result<String, Box<dyn std::error::Error>> {
91    let code = String::from("// Auto-generated Helix SDK for Rust
92use std::collections::HashMap;
93
94pub struct HelixConfig {
95    data: HashMap<String, serde_json::Value>,
96}
97
98impl HelixConfig {
99    pub pub fn new() -> Self {
100        Self {
101            data: HashMap::new(),
102        }
103    }
104
105    pub pub fn from_file(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
106        let content = std::fs::read_to_string(path)?;
107        Self::from_string(&content)
108    }
109
110    pub pub fn from_string(content: &str) -> Result<Self, Box<dyn std::error::Error>> {
111        let data: HashMap<String, serde_json::Value> = serde_json::from_str(content)?;
112        Ok(Self { data })
113    }
114
115    pub pub fn get(&self, key: &str) -> Option<&serde_json::Value> {
116        self.data.get(key)
117    }
118
119    pub pub fn set(&mut self, key: &str, value: serde_json::Value) {
120        self.data.insert(key.to_string(), value);
121    }
122
123    pub pub fn process(&self) -> Result<(), Box<dyn std::error::Error>> {
124        // Process the configuration
125        println!(\"Processing Helix configuration...\");
126        Ok(())
127    }
128
129    pub pub fn compile(&self) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
130        // Compile the configuration
131        println!(\"Compiling Helix configuration...\");
132        let json = serde_json::to_vec(&self.data)?;
133        Ok(json)
134    }
135}
136
137impl std::ops::Index<&str> for HelixConfig {
138    type Output = serde_json::Value;
139
140    pub fn index(&self, key: &str) -> &Self::Output {
141        self.data.get(key).unwrap_or(&serde_json::Value::Null)
142    }
143}
144");
145    Ok(code)
146}
147pub fn generate_python_schema(_ast: &crate::dna::atp::ast::HelixAst) -> Result<String, Box<dyn std::error::Error>> {
148    let code = String::from("# Auto-generated Helix SDK for Python
149
150import json
151from typing import Dict, Any, Optional
152
153class HelixConfig:
154    def __init__(self):
155        self.data: Dict[str, Any] = {}
156
157    @classmethod
158    def from_file(cls, path: str) -> 'HelixConfig':
159        with open(path, 'r') as f:
160            content = f.read()
161        return cls.from_string(content)
162
163    @classmethod
164    def from_string(cls, content: str) -> 'HelixConfig':
165        instance = cls()
166        instance.data = json.loads(content)
167        return instance
168
169    def get(self, key: str) -> Any:
170        return self.data.get(key)
171
172    def set(self, key: str, value: Any):
173        self.data[key] = value
174
175    def __getitem__(self, key: str) -> Any:
176        return self.data.get(key, None)
177
178    def __setitem__(self, key: str, value: Any):
179        self.data[key] = value
180
181    def process(self):
182        \"\"\"Process the configuration\"\"\"
183        print(\"Processing Helix configuration...\")
184
185    def compile(self) -> bytes:
186        \"\"\"Compile the configuration\"\"\"
187        print(\"Compiling Helix configuration...\")
188        return json.dumps(self.data).encode('utf-8')
189");
190    Ok(code)
191}
192pub fn generate_javascript_schema(_ast: &crate::dna::atp::ast::HelixAst) -> Result<String, Box<dyn std::error::Error>> {
193    let code = String::from("// Auto-generated Helix SDK for JavaScript
194
195class HelixConfig {
196    constructor() {
197        this.data = {};
198    }
199
200    static fromFile(path) {
201        const fs = require('fs');
202        const content = fs.readFileSync(path, 'utf8');
203        return HelixConfig.fromString(content);
204    }
205
206    static fromString(content) {
207        const instance = new HelixConfig();
208        instance.data = JSON.parse(content);
209        return instance;
210    }
211
212    get(key) {
213        return this.data[key];
214    }
215
216    set(key, value) {
217        this.data[key] = value;
218    }
219
220    process() {
221        console.log('Processing Helix configuration...');
222    }
223
224    compile() {
225        console.log('Compiling Helix configuration...');
226        return Buffer.from(JSON.stringify(this.data));
227    }
228}
229
230// Bracket notation access
231HelixConfig.prototype.__defineGetter__('hlx', function() {
232    return this;
233});
234
235module.exports = HelixConfig;
236");
237    Ok(code)
238}
239pub fn generate_csharp_schema(_ast: &crate::dna::atp::ast::HelixAst) -> Result<String, Box<dyn std::error::Error>> {
240    let code = String::from("// Auto-generated Helix SDK for C#
241
242using System;
243using System.Collections.Generic;
244using System.IO;
245using Newtonsoft.Json;
246
247public class HelixConfig
248{
249    private Dictionary<string, object> data = new Dictionary<string, object>();
250
251    public static HelixConfig FromFile(string path)
252    {
253        string content = File.ReadAllText(path);
254        return FromString(content);
255    }
256
257    public static HelixConfig FromString(string content)
258    {
259        var instance = new HelixConfig();
260        instance.data = JsonConvert.DeserializeObject<Dictionary<string, object>>(content);
261        return instance;
262    }
263
264    public object Get(string key)
265    {
266        return data.ContainsKey(key) ? data[key] : null;
267    }
268
269    public void Set(string key, object value)
270    {
271        data[key] = value;
272    }
273
274    public object this[string key]
275    {
276        get { return Get(key); }
277        set { Set(key, value); }
278    }
279
280    public void Process()
281    {
282        Console.WriteLine(\"Processing Helix configuration...\");
283    }
284
285    public byte[] Compile()
286    {
287        Console.WriteLine(\"Compiling Helix configuration...\");
288        string json = JsonConvert.SerializeObject(data);
289        return System.Text.Encoding.UTF8.GetBytes(json);
290    }
291}
292");
293    Ok(code)
294}
295pub fn generate_java_schema(_ast: &crate::dna::atp::ast::HelixAst) -> Result<String, Box<dyn std::error::Error>> {
296    let code = String::from("// Auto-generated Helix SDK for Java
297
298import com.fasterxml.jackson.databind.ObjectMapper;
299import java.io.File;
300import java.io.IOException;
301import java.util.HashMap;
302import java.util.Map;
303
304public class HelixConfig {
305    private Map<String, Object> data = new HashMap<>();
306    private static final ObjectMapper mapper = new ObjectMapper();
307
308    public static HelixConfig fromFile(String path) throws IOException {
309        String content = new String(java.nio.file.Files.readAllBytes(new File(path).toPath()));
310        return fromString(content);
311    }
312
313    public static HelixConfig fromString(String content) throws IOException {
314        HelixConfig instance = new HelixConfig();
315        instance.data = mapper.readValue(content, Map.class);
316        return instance;
317    }
318
319    public Object get(String key) {
320        return data.get(key);
321    }
322
323    public void set(String key, Object value) {
324        data.put(key, value);
325    }
326
327    public void process() {
328        System.out.println(\"Processing Helix configuration...\");
329    }
330
331    public byte[] compile() throws IOException {
332        System.out.println(\"Compiling Helix configuration...\");
333        String json = mapper.writeValueAsString(data);
334        return json.getBytes();
335    }
336}
337");
338    Ok(code)
339}
340pub fn generate_go_schema(_ast: &crate::dna::atp::ast::HelixAst) -> Result<String, Box<dyn std::error::Error>> {
341    let code = String::from("// Auto-generated Helix SDK for Go
342
343package helix
344
345import (
346    \"encoding/json\"
347    \"fmt\"
348    \"io/ioutil\"
349    \"log\"
350)
351
352type HelixConfig struct {
353    Data map[string]interface{} `json:\"data\"`
354}
355
356func NewHelixConfig() *HelixConfig {
357    return &HelixConfig{
358        Data: make(map[string]interface{}),
359    }
360}
361
362func FromFile(path string) (*HelixConfig, error) {
363    content, err := ioutil.ReadFile(path)
364    if err != nil {
365        return nil, err
366    }
367    return FromString(string(content))
368}
369
370func FromString(content string) (*HelixConfig, error) {
371    var data map[string]interface{}
372    if err := json.Unmarshal([]byte(content), &data); err != nil {
373        return nil, err
374    }
375    return &HelixConfig{Data: data}, nil
376}
377
378func (h *HelixConfig) Get(key string) interface{} {
379    return h.Data[key]
380}
381
382func (h *HelixConfig) Set(key string, value interface{}) {
383    h.Data[key] = value
384}
385
386func (h *HelixConfig) Process() {
387    fmt.Println(\"Processing Helix configuration...\")
388}
389
390func (h *HelixConfig) Compile() ([]byte, error) {
391    fmt.Println(\"Compiling Helix configuration...\")
392    return json.Marshal(h.Data)
393}
394");
395    Ok(code)
396}
397pub fn generate_ruby_schema(_ast: &crate::dna::atp::ast::HelixAst) -> Result<String, Box<dyn std::error::Error>> {
398    let code = String::from("# Auto-generated Helix SDK for Ruby
399
400require 'json'
401
402class HelixConfig
403  attr_accessor :data
404
405  def initialize
406    @data = {}
407  end
408
409  def self.from_file(path)
410    content = File.read(path)
411    from_string(content)
412  end
413
414  def self.from_string(content)
415    instance = new
416    instance.data = JSON.parse(content)
417    instance
418  end
419
420  def get(key)
421    @data[key]
422  end
423
424  def set(key, value)
425    @data[key] = value
426  end
427
428  def [](key)
429    get(key)
430  end
431
432  def []=(key, value)
433    set(key, value)
434  end
435
436  def process
437    puts 'Processing Helix configuration...'
438  end
439
440  def compile
441    puts 'Compiling Helix configuration...'
442    JSON.dump(@data).bytes
443  end
444end
445");
446    Ok(code)
447}
448pub fn generate_php_schema(_ast: &crate::dna::atp::ast::HelixAst) -> Result<String, Box<dyn std::error::Error>> {
449    let code = String::from("<?php
450// Auto-generated Helix SDK for PHP
451
452class HelixConfig {
453    private $data = [];
454
455    public static function fromFile(string $path): self {
456        $content = file_get_contents($path);
457        return self::fromString($content);
458    }
459
460    public static function fromString(string $content): self {
461        $instance = new self();
462        $instance->data = json_decode($content, true);
463        return $instance;
464    }
465
466    public function get(string $key) {
467        return $this->data[$key] ?? null;
468    }
469
470    public function set(string $key, $value): void {
471        $this->data[$key] = $value;
472    }
473
474    public function __get(string $key) {
475        return $this->get($key);
476    }
477
478    public function __set(string $key, $value): void {
479        $this->set($key, $value);
480    }
481
482    public function process(): void {
483        echo \"Processing Helix configuration...\\n\";
484    }
485
486    public function compile(): string {
487        echo \"Compiling Helix configuration...\\n\";
488        return json_encode($this->data);
489    }
490}
491");
492    Ok(code)
493}
494pub fn decompile_command(
495    input: PathBuf,
496    output: Option<PathBuf>,
497    verbose: bool,
498) -> Result<(), Box<dyn std::error::Error>> {
499    let output_path = output
500        .unwrap_or_else(|| {
501            let mut path = input.clone();
502            path.set_extension("hlx");
503            path
504        });
505    if verbose {
506        println!("🔄 Decompiling: {}", input.display());
507    }
508    let loader = BinaryLoader::new();
509    let binary = loader.load_file(&input)?;
510    let compiler = Compiler::new(OptimizationLevel::Zero);
511    let source = compiler.decompile(&binary)?;
512    std::fs::write(&output_path, source)?;
513    println!("✅ Decompiled successfully: {}", output_path.display());
514    Ok(())
515}
516pub fn validate_command(
517    file: PathBuf,
518    detailed: bool,
519) -> Result<(), Box<dyn std::error::Error>> {
520    let extension = file.extension().and_then(|s| s.to_str());
521    match extension {
522        Some("hlx") => {
523            let source = std::fs::read_to_string(&file)?;
524            let tokens = crate::dna::atp::lexer::tokenize(&source)
525                .map_err(|e| anyhow::anyhow!("Failed to tokenize: {}", e))?;
526            let ast = crate::dna::atp::parser::parse(tokens)?;
527            // Validation is done through the AST parsing
528            // crate::dna::ops::validation::validate(&ast)?;
529            println!("✅ Valid HELIX file: {}", file.display());
530            if detailed {
531                println!("  Declarations: {}", ast.declarations.len());
532            }
533        }
534        Some("hlxb") => {
535            let loader = BinaryLoader::new();
536            let binary = loader.load_file(&file)?;
537            binary.validate()?;
538            println!("✅ Valid HLXB file: {}", file.display());
539            if detailed {
540                println!("  Version: {}", binary.version);
541                println!("  Sections: {}", binary.data_sections.len());
542                println!("  Checksum: {:x}", binary.checksum);
543            }
544        }
545        _ => {
546            return Err("Unknown file type (expected .hlx or .hlxb)".into());
547        }
548    }
549    Ok(())
550}