diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..4233e08 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,98 @@ +# HypnoScript Copilot Instructions + +## Architecture Overview + +HypnoScript is a hypnotically-themed programming language with a pure Rust implementation (Rust 2024 edition). The compilation pipeline flows: + +``` +Source (.hyp) → Lexer → Tokens → Parser → AST → TypeChecker → Interpreter/Compiler +``` + +**Workspace crates (dependency order):** + +| Crate | Purpose | Key Exports | +| -------------------------- | --------------------------- | ------------------------------------------------------------------------ | +| `hypnoscript-core` | Type system foundation | `HypnoType`, `HypnoBaseType`, `SymbolTable` | +| `hypnoscript-lexer-parser` | Tokenization & AST | `Lexer`, `Parser`, `AstNode`, `Token` | +| `hypnoscript-runtime` | 180+ builtins (20+ modules) | `MathBuiltins`, `StringBuiltins`, `ArrayBuiltins`, etc. | +| `hypnoscript-compiler` | All backends | `Interpreter`, `TypeChecker`, `WasmCodeGenerator`, `NativeCodeGenerator` | +| `hypnoscript-cli` | CLI + package manager | Commands: `exec`, `lex`, `parse`, `check`, `compile-wasm` | + +## Essential Commands + +```bash +# Development cycle +cargo build --all # Debug build +cargo run -p hypnoscript-cli -- exec file.hyp # Run .hyp file +cargo run -p hypnoscript-cli -- exec file.hyp --debug # Interactive debugger + +# Testing (185+ tests, run on Windows/Linux/macOS in CI) +cargo test --all # All tests +cargo test --package hypnoscript-compiler -- --nocapture # Single crate with output +cargo test --package hypnoscript-runtime test_math # Specific test + +# Pre-commit quality checks (enforced by CI) +cargo fmt --all -- --check +cargo clippy --all-targets --all-features -- -D warnings + +# Release build (LTO enabled, stripped) +cargo build --all --release +``` + +## Language Syntax Quick Reference + +HypnoScript uses hypnotic-themed keywords. See [token.rs](hypnoscript-lexer-parser/src/token.rs) for complete list. + +| HypnoScript | Equivalent | Example | +| ---------------------------- | ---------- | ---------------------------------------------------------------- | +| `Focus { } Relax` | program | `Focus { observe "hi"; } Relax` | +| `induce`/`freeze` | let/const | `induce x: number = 42;` | +| `suggestion` | function | `suggestion add(a: number, b: number): number { awaken a + b; }` | +| `session` | class | `session Counter { expose count: number = 0; }` | +| `observe`/`whisper` | print | `observe "Hello";` (with newline) | +| `awaken` | return | `awaken result;` | +| `entrain`/`when`/`otherwise` | match | `entrain x { when 0 => "zero" otherwise => "other" }` | +| `yourEyesAreGettingHeavy` | >= | `if (x yourEyesAreGettingHeavy 10) deepFocus { }` | +| `lucidFallback` | ?? | `maybeNull lucidFallback 100` | + +## Adding New Builtin Functions + +1. **Create module** in `hypnoscript-runtime/src/` (e.g., `my_builtins.rs`) +2. **Implement trait** `BuiltinModule` from [builtin_trait.rs](hypnoscript-runtime/src/builtin_trait.rs): + ```rust + impl BuiltinModule for MyBuiltins { + fn module_name() -> &'static str { "My" } + fn description() -> &'static str { "My builtin functions" } + fn function_names() -> &'static [&'static str] { &["MyFunc1", "MyFunc2"] } + } + ``` +3. **Export** in `hypnoscript-runtime/src/lib.rs` +4. **Register** in [interpreter.rs](hypnoscript-compiler/src/interpreter.rs) - add match arms in `call_builtin_function()` +5. **Add tests** as inline `#[cfg(test)] mod tests { }` at file end + +## Code Conventions + +- **Error handling**: Use `thiserror` with `#[derive(Error)]`. User-facing errors support i18n via `LocalizedMessage` (EN, DE, FR, ES) +- **AST nodes**: All constructs map to variants in `AstNode` enum ([ast.rs](hypnoscript-lexer-parser/src/ast.rs)) +- **Tests**: Inline modules at file end with `#[cfg(test)]`. Test `.hyp` files in `hypnoscript-tests/` +- **Workspace deps**: Shared dependencies defined in root `Cargo.toml` under `[workspace.dependencies]` + +## Package Manager (trance.json) + +HypnoScript projects use themed manifest keys: + +- `ritualName` → package name, `mantra` → version +- `anchors`/`deepAnchors` → dependencies/devDependencies +- `suggestions` → npm-style scripts + +See [package.rs](hypnoscript-cli/src/package.rs) for schema. + +## Key Files Reference + +| File | Purpose | +| ------------------------------------------------------------ | -------------------------------------------- | +| [interpreter.rs](hypnoscript-compiler/src/interpreter.rs) | Main runtime (3400+ lines), builtin dispatch | +| [ast.rs](hypnoscript-lexer-parser/src/ast.rs) | All 30+ AST node variants | +| [token.rs](hypnoscript-lexer-parser/src/token.rs) | Token types & hypnotic keyword mappings | +| [types.rs](hypnoscript-core/src/types.rs) | `HypnoType` enum, type inference | +| [builtin_trait.rs](hypnoscript-runtime/src/builtin_trait.rs) | `BuiltinModule` trait for extending runtime | diff --git a/.github/labeler.yml b/.github/labeler.yml index 5f8bf71..ac930f1 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,4 +1,4 @@ -# Labeler-Konfiguration für HypnoScript +# Labeler configuration for HypnoScript # See https://github.com/actions/labeler for configuration format. 'area:core': diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 29f6d48..5fb60da 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -35,7 +35,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - fetch-depth: 0 # Für VitePress lastUpdated-Feature + fetch-depth: 0 # For VitePress lastUpdated feature - name: Setup Rust uses: actions-rust-lang/setup-rust-toolchain@v1 diff --git a/.github/workflows/rust-build-and-release.yml b/.github/workflows/rust-build-and-release.yml index d1e213f..0c2983f 100644 --- a/.github/workflows/rust-build-and-release.yml +++ b/.github/workflows/rust-build-and-release.yml @@ -189,11 +189,11 @@ jobs: ## Installation - ### Automatisches Setup (Linux/macOS) + ### Automatic setup (Linux/macOS) ```bash curl -fsSL https://kink-development-group.github.io/hyp-runtime/install.sh | bash ``` - Das Skript erkennt System & Architektur, verifiziert Checksums und aktualisiert vorhandene Installationen. + The script detects system & architecture, verifies checksums, and updates existing installations. ### Linux/macOS ```bash diff --git a/CHANGELOG.md b/CHANGELOG.md index df0dc9e..d857ea0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,60 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/). +## [1.2.0] - 2026-01-22 + +### Added + +- **Complete Debugging Infrastructure** with interactive step-through execution: + - New `hypnoscript-compiler/src/debug.rs` module with `DebugState`, `StepMode`, `CallFrame`, `WatchExpression`, and `PauseReason` types + - Breakpoint management (set, remove, clear, list) + - Step modes: Step Into, Step Over, Step Out, Continue + - Call stack tracking with function name, line number, and local variables + - Watch expressions for monitoring values during debugging + - Source code display with breakpoint markers + +- **Debug REPL** (`hypnoscript-cli/src/debug_repl.rs`) for interactive debugging sessions: + - Commands: `break`, `delete`, `continue`, `step`, `next`, `out`, `print`, `locals`, `stack`, `watch`, `list`, `where`, `help`, `quit` + - Expression evaluation in current scope + - Variable inspection (locals, globals, all variables) + - Configurable via `DebugConfig` with initial breakpoints and watches + +- **Debug Builtins** (`hypnoscript-runtime/src/debug_builtins.rs`): + - `inspect(value)` - Returns value with type information + - `typeOf(value)` - Returns the type name + - `stackTrace()` - Returns formatted call stack + - `dump(value)` - Prints detailed value representation + - `assertEqual()`, `assertNotEqual()`, `assertTruthy()`, `assertFalsy()`, `assertNull()`, `assertNotNull()` - Assertions with messages + - `time(label)`, `timeEnd(label)`, `measureTime(fn)` - Performance timing + - `log()`, `warn()`, `error()`, `trace()` - Debug output levels + - `breakpoint()` - Programmatic breakpoint + +- **Extended CLI Debug Options** for the `exec` command: + - `--debug` / `-d` - Enable interactive debug mode + - `--breakpoints ` - Set initial breakpoints (comma-separated line numbers) + - `--watch ` - Set initial watch expressions (comma-separated) + - `--trace-file ` - Output trace information to file + +- **Interpreter Debug Integration**: + - `enable_debug_mode()` / `disable_debug_mode()` methods + - `set_breakpoint()`, `remove_breakpoint()`, `has_breakpoint()`, `clear_breakpoints()` + - `set_step_mode()`, `step_mode()` for stepping control + - `add_watch()`, `remove_watch()` for watch expressions + - `debug_locals()`, `debug_globals()`, `debug_all_variables()` for variable inspection + - `debug_call_stack()`, `debug_source_context()` for execution context + +### Changed + +- Extended `Interpreter` struct with optional `debug_state` field +- Updated CLI `exec` command to support debug mode with REPL integration + +### Tests + +- Added 9 new debug mode tests in `interpreter.rs` +- Added comprehensive unit tests for `DebugState`, `DebugCommand`, `CallFrame` +- Added unit tests for `DebugBuiltins` (assertions, timing, inspection) +- Added unit tests for `DebugSession` and `DebugConfig` + ## [1.0.0] - 2025-11-15 ### Added @@ -30,3 +84,4 @@ All notable changes to this project will be documented in this file. The format - Successfully completed `cargo deny check` with cleaned-up license and advisory checks. [1.0.0]: https://github.com/Kink-Development-Group/hyp-runtime/releases/tag/1.0.0 +[1.2.0]: https://github.com/Kink-Development-Group/hyp-runtime/releases/tag/1.2.0 diff --git a/Cargo.toml b/Cargo.toml index 4d6017b..c28071e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ ] [workspace.package] -version = "1.0.0" +version = "1.2.0" edition = "2024" authors = ["Kink Development Group"] license = "MIT" @@ -18,11 +18,11 @@ repository = "https://github.com/Kink-Development-Group/hyp-runtime" [workspace.dependencies] # Core dependencies shared across workspace anyhow = "1.0" -thiserror = "1.0" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -reqwest = { version = "0.11", default-features = false, features = ["json", "blocking", "rustls-tls"] } -csv = "1.3" +thiserror = "2.0.18" +serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.149" +reqwest = { version = "0.13.1", default-features = false, features = ["json", "blocking", "query", "rustls"] } +csv = "1.4.0" [profile.release] opt-level = 3 diff --git a/IMPLEMENTATION_SUMMARY_PACKAGE_MANAGER.md b/IMPLEMENTATION_SUMMARY_PACKAGE_MANAGER.md deleted file mode 100644 index faebbd7..0000000 --- a/IMPLEMENTATION_SUMMARY_PACKAGE_MANAGER.md +++ /dev/null @@ -1,247 +0,0 @@ -# Package Manager Implementation Summary - -## Overview - -This implementation adds a complete package manager to the HypnoScript CLI, providing npm/bun-like functionality with hypnotic theming. - -## What Was Implemented - -### 1. Data Structures (`hypnoscript-cli/src/package.rs`) - -#### TranceManifest -The main manifest structure with all fields from the specification: -- `ritualName`: Package name -- `mantra`: Version (semver) -- `intent`: Project type (cli, library) -- `induction`: Package metadata (description, entry point, keywords, license) -- `hypnotists`: Authors/contributors -- `auras`: Links and resources (repository, homepage, documentation, support) -- `suggestions`: Runnable scripts (like npm scripts) -- `anchors`: Production dependencies -- `deepAnchors`: Development dependencies -- `channels`: Binary/CLI configuration -- `triggers`: Lifecycle hooks - -#### TranceLock -Lock file for reproducible builds: -- `lockVersion`: Lock file format version -- `lockedAnchors`: Resolved dependencies with versions, sources, and integrity hashes - -### 2. CLI Commands - -All commands integrated into the main CLI: - -| Command | Description | Example | -|---------|-------------|---------| -| `init` | Initialize new project | `hypnoscript init --template cli` | -| `add` | Add a dependency | `hypnoscript add pkg --version "^1.0.0"` | -| `remove` | Remove a dependency | `hypnoscript remove pkg` | -| `install` | Install all dependencies | `hypnoscript install` | -| `list` | List dependencies | `hypnoscript list` | -| `validate` | Validate manifest | `hypnoscript validate` | -| `run` | Run a script | `hypnoscript run test` | - -### 3. Templates - -#### CLI Template -For command-line applications: -- Binary configuration -- Default scripts (focus, test) -- Multi-platform targets -- Telemetry configuration - -#### Library Template -For reusable libraries: -- Library-focused structure -- Build and test scripts -- Entry point at `src/lib.hyp` - -### 4. Features - -✅ **Manifest Creation**: Initialize projects with different templates -✅ **Dependency Management**: Add, remove, and track dependencies -✅ **Lock Files**: Generate lock files for reproducible builds -✅ **Validation**: Validate manifest structure and semver versions -✅ **Scripts**: Define and reference runnable scripts -✅ **Metadata**: Track authors, licenses, keywords, and links -✅ **Binary Config**: Configure CLI applications with entry points and targets -✅ **Lifecycle Hooks**: Define pre/post execution scripts - -### 5. Testing - -Comprehensive test suite covering: -- Template generation (CLI and library) -- Manifest initialization and persistence -- Dependency addition and removal -- Lock file generation -- Manifest serialization/deserialization - -All 6 tests pass successfully. - -### 6. Documentation - -- **PACKAGE_MANAGER.md**: Complete usage guide with examples -- **README.md**: Updated with package manager section -- **examples/trance.json**: Full example showing all fields -- Inline code documentation with rustdoc comments - -## Example Usage - -### Initialize a New CLI Project - -```bash -hypnoscript init --name my-cli --template cli -``` - -Creates: -```json -{ - "ritualName": "my-cli", - "mantra": "0.1.0", - "intent": "cli", - "induction": { - "description": "A HypnoScript CLI application: my-cli", - "entryScript": "src/main.hyp", - "keywords": ["hypnoscript", "cli"], - "license": "MIT" - }, - "suggestions": { - "focus": "hypnoscript exec src/main.hyp", - "test": "hypnoscript exec tests/smoke.hyp" - }, - "anchors": {}, - "deepAnchors": {}, - "channels": { - "binary": "my-cli", - "entry": "focus", - "targets": ["windows-x64", "linux-x64", "macos-universal"], - "telemetry": { - "enabled": false, - "endpoint": null - } - } -} -``` - -### Add Dependencies - -```bash -# Production dependency -hypnoscript add hypnoscript-runtime --version "^1.0.0" - -# Development dependency -hypnoscript add @hypno/testing-lab --version "^0.3.0" --dev -``` - -### Install All Dependencies - -```bash -hypnoscript install -``` - -Creates `trance-lock.json`: -```json -{ - "lockVersion": "1.0.0", - "lockedAnchors": { - "hypnoscript-runtime": { - "version": "^1.0.0", - "source": "registry", - "integrity": null, - "dependencies": {} - } - } -} -``` - -### List Dependencies - -```bash -hypnoscript list -``` - -Output: -``` -📦 my-cli v0.1.0 - -Anchors (dependencies): - hypnoscript-runtime @ ^1.0.0 - -Deep Anchors (devDependencies): - @hypno/testing-lab @ ^0.3.0 -``` - -## Architecture - -### Module Organization -- `package.rs`: Core package manager implementation -- `main.rs`: CLI command integration -- Modular design allows easy extension - -### Design Decisions - -1. **Hypnotic Terminology**: Maintains thematic consistency with HypnoScript -2. **npm-like Interface**: Familiar workflow for developers -3. **Semver Support**: Standard version specification -4. **Template System**: Quick project scaffolding -5. **Validation**: Early error detection -6. **Lock Files**: Reproducible builds - -## Future Enhancements - -The current implementation provides the foundation for: - -1. **Package Registry**: Server-side package hosting -2. **Dependency Resolution**: Automatic transitive dependency management -3. **Publishing**: Upload packages to registry -4. **Workspaces**: Monorepo support -5. **Audit**: Security vulnerability scanning -6. **Update**: Smart dependency updates -7. **Link**: Local package development - -## Integration Points - -The package manager is designed to integrate with: -- **Formatter**: Use dependency information for formatting -- **Linter**: Check against declared dependencies -- **Compiler**: Resolve module imports from dependencies -- **Build System**: Manage build artifacts - -## Code Quality - -✅ All tests pass (6/6) -✅ Clippy warnings resolved -✅ Code formatted with rustfmt -✅ No security issues detected -✅ Comprehensive error handling -✅ Well-documented public APIs - -## Files Changed - -1. `hypnoscript-cli/src/package.rs` (new, 654 lines) -2. `hypnoscript-cli/src/main.rs` (modified, +67 lines) -3. `README.md` (modified, added package manager section) -4. `PACKAGE_MANAGER.md` (new, complete usage guide) -5. `examples/trance.json` (new, example manifest) - -## Compatibility - -- Works on all platforms (Linux, macOS, Windows) -- No breaking changes to existing CLI -- Backwards compatible with existing projects -- Self-contained, no external dependencies - -## Summary - -The package manager implementation successfully delivers all requirements from the issue: - -✅ Client-side package manager as part of CLI -✅ trance.json manifest following specified schema -✅ trance-lock.json for dependency locking -✅ npm/bun-like command interface -✅ Template support (CLI, library) -✅ Efficient and fast implementation -✅ Integration-ready for formatter/linter -✅ Comprehensive testing and documentation - -The implementation is production-ready and provides a solid foundation for future server-side registry development. diff --git a/PACKAGE_MANAGER.md b/PACKAGE_MANAGER.md index acca1ee..7d3c170 100644 --- a/PACKAGE_MANAGER.md +++ b/PACKAGE_MANAGER.md @@ -121,19 +121,19 @@ The `trance.json` file follows the HypnoScript theming with hypnotic terminology ### Field Descriptions -| Field | Description | npm Equivalent | -|-------|-------------|----------------| -| `ritualName` | Package name | `name` | -| `mantra` | Package version (semver) | `version` | -| `intent` | Project type (cli, library) | N/A | -| `induction` | Package metadata | Combined from multiple fields | -| `hypnotists` | Contributors/authors | `contributors` | -| `auras` | Links and resources | `repository`, `homepage`, etc. | -| `suggestions` | Runnable scripts | `scripts` | -| `anchors` | Production dependencies | `dependencies` | -| `deepAnchors` | Development dependencies | `devDependencies` | -| `channels` | Binary/CLI configuration | `bin` | -| `triggers` | Lifecycle hooks | `scripts` (lifecycle) | +| Field | Description | npm Equivalent | +| ------------- | --------------------------- | ------------------------------ | +| `ritualName` | Package name | `name` | +| `mantra` | Package version (semver) | `version` | +| `intent` | Project type (cli, library) | N/A | +| `induction` | Package metadata | Combined from multiple fields | +| `hypnotists` | Contributors/authors | `contributors` | +| `auras` | Links and resources | `repository`, `homepage`, etc. | +| `suggestions` | Runnable scripts | `scripts` | +| `anchors` | Production dependencies | `dependencies` | +| `deepAnchors` | Development dependencies | `devDependencies` | +| `channels` | Binary/CLI configuration | `bin` | +| `triggers` | Lifecycle hooks | `scripts` (lifecycle) | ## The trance-lock.json Lock File @@ -141,10 +141,10 @@ The lock file ensures reproducible builds by capturing exact dependency versions ```json { - "lockVersion": "1.0.0", + "lockVersion": "1.2.0", "lockedAnchors": { "hypnoscript-runtime": { - "version": "^1.0.0", + "version": "^1.2.0", "source": "registry", "integrity": null, "dependencies": {} @@ -164,6 +164,7 @@ hypnoscript init --template cli ``` Creates a project with: + - Binary configuration in `channels` - Default scripts for running and testing - CLI-specific metadata @@ -177,6 +178,7 @@ hypnoscript init --template library ``` Creates a project with: + - Library-focused structure - Build and test scripts - Entry point at `src/lib.hyp` @@ -224,3 +226,5 @@ The package manager is part of the HypnoScript CLI. To contribute: ## License MIT License - Same as HypnoScript Runtime + +MIT License - Same as HypnoScript Runtime diff --git a/README.md b/README.md index 8589a43..183005b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ -# HypnoScript – Rust Implementation +# HypnoScript **HypnoScript** is a hypnotically-inspired programming language with its own syntax (`Focus { ... } Relax`). -The complete runtime environment, compiler, and command-line tools were ported from C# to Rust -and are exclusively developed in Rust from version 1.0 onwards. +The complete runtime environment, compiler, and command-line tools are exclusively developed in Rust from version 1.0 onwards. --- diff --git a/deny.toml b/deny.toml index 379716a..eadc474 100644 --- a/deny.toml +++ b/deny.toml @@ -120,7 +120,8 @@ exceptions = [ # list #{ allow = ["Zlib"], crate = "adler32" }, { crate = "android_system_properties", allow = ["Apache-2.0", "MIT"] }, - { crate = "webpki-roots", allow = ["MPL-2.0"] }, + # aws-lc-sys is a dependency of rustls-webpki and uses a combination of licenses + { crate = "aws-lc-sys", allow = ["ISC", "MIT", "Apache-2.0", "OpenSSL"] }, ] # Some crates don't have (easily) machine readable licensing information, diff --git a/examples/trance.json b/examples/trance.json index d123fc2..27c679e 100644 --- a/examples/trance.json +++ b/examples/trance.json @@ -29,8 +29,8 @@ "test": "hypnoscript exec tests/smoke.hyp" }, "anchors": { - "hypnoscript-runtime": "^1.0.0", - "hypnoscript-cli": "^1.0.0" + "hypnoscript-runtime": "^1.2.0", + "hypnoscript-cli": "^1.2.0" }, "deepAnchors": { "@hypno/testing-lab": "^0.3.0" diff --git a/hypnoscript-cli/Cargo.toml b/hypnoscript-cli/Cargo.toml index 582a5cd..7595902 100644 --- a/hypnoscript-cli/Cargo.toml +++ b/hypnoscript-cli/Cargo.toml @@ -26,6 +26,6 @@ clap = { version = "4.5", features = ["derive"] } semver = "1.0" serde = { workspace = true } serde_json = { workspace = true } -ureq = { version = "2.9", features = ["json"] } -tempfile = "3.10" +ureq = { version = "3.1.4", features = ["json"] } +tempfile = "3.24.0" shlex = "1.3" diff --git a/hypnoscript-cli/src/debug_repl.rs b/hypnoscript-cli/src/debug_repl.rs new file mode 100644 index 0000000..2dae2f8 --- /dev/null +++ b/hypnoscript-cli/src/debug_repl.rs @@ -0,0 +1,658 @@ +//! Debug REPL for interactive HypnoScript debugging. +//! +//! This module provides an interactive debugging session that allows users to: +//! - Set and remove breakpoints +//! - Step through code execution +//! - Inspect variables and the call stack +//! - Evaluate expressions +//! - Watch expressions +//! +//! # Usage +//! +//! The debug REPL is invoked when running a HypnoScript file with the `--debug` flag: +//! +//! ```bash +//! hypnoscript exec myfile.hyp --debug +//! ``` +//! +//! This enters an interactive session where users can use debug commands +//! before and during program execution. + +use anyhow::{Result, anyhow}; +use hypnoscript_compiler::{DebugCommand, Interpreter, StepMode, debug_help}; +use hypnoscript_lexer_parser::{Lexer, Parser as HypnoParser}; +use std::collections::HashSet; +use std::io::{self, Write}; + +/// Configuration for a debug session. +#[derive(Debug, Clone, Default)] +pub struct DebugConfig { + /// Initial breakpoints to set (line numbers) + pub breakpoints: Vec, + /// Initial watch expressions + pub watch_expressions: Vec, + /// Whether to enable verbose output + pub verbose: bool, + /// Path to trace output file (if any) + pub trace_file: Option, +} + +impl DebugConfig { + /// Creates a new debug configuration. + pub fn new() -> Self { + Self::default() + } + + /// Adds initial breakpoints. + pub fn with_breakpoints(mut self, breakpoints: Vec) -> Self { + self.breakpoints = breakpoints; + self + } + + /// Adds initial watch expressions. + pub fn with_watches(mut self, watches: Vec) -> Self { + self.watch_expressions = watches; + self + } + + /// Enables verbose output. + pub fn with_verbose(mut self, verbose: bool) -> Self { + self.verbose = verbose; + self + } + + /// Sets the trace output file. + pub fn with_trace_file(mut self, trace_file: Option) -> Self { + self.trace_file = trace_file; + self + } +} + +/// Result of executing a debug command. +#[derive(Debug)] +#[allow(dead_code)] +pub enum CommandResult { + /// Continue running until next pause + Continue, + /// Step to next statement + Step(StepMode), + /// Quit the debug session + Quit, + /// Output to display to user + Output(String), + /// No action needed + None, +} + +/// Interactive debug session. +pub struct DebugSession { + /// The interpreter instance + interpreter: Interpreter, + /// Source code being debugged + source: String, + /// Parsed AST + ast: Option, + /// Configuration + config: DebugConfig, + /// Whether the session has started + started: bool, + /// Whether execution has finished + finished: bool, + /// Current execution state + execution_state: ExecutionState, +} + +/// State of the debug execution. +#[derive(Debug, Clone, PartialEq, Eq)] +#[allow(dead_code)] +enum ExecutionState { + /// Before execution started + NotStarted, + /// Running (not paused) + Running, + /// Paused at a breakpoint or step + Paused, + /// Execution completed + Finished, +} + +impl DebugSession { + /// Creates a new debug session for the given source file. + pub fn new(source: String, config: DebugConfig) -> Result { + let mut interpreter = Interpreter::new(); + interpreter.enable_debug_mode(&source); + + // Set initial breakpoints + for &line in &config.breakpoints { + interpreter.set_breakpoint(line); + } + + // Add initial watch expressions + for expr in &config.watch_expressions { + interpreter.add_watch(expr.clone()); + } + + Ok(Self { + interpreter, + source, + ast: None, + config, + started: false, + finished: false, + execution_state: ExecutionState::NotStarted, + }) + } + + /// Parses the source code. + pub fn parse(&mut self) -> Result<()> { + let mut lexer = Lexer::new(&self.source); + let tokens = lexer.lex().map_err(|e| anyhow!("Lexer error: {}", e))?; + + let mut parser = HypnoParser::new(tokens); + let ast = parser + .parse_program() + .map_err(|e| anyhow!("Parser error: {}", e))?; + + self.ast = Some(ast); + Ok(()) + } + + /// Runs the interactive debug session. + pub fn run(&mut self) -> Result<()> { + // Parse if not already done + if self.ast.is_none() { + self.parse()?; + } + + self.print_welcome(); + self.print_source_info(); + + // Enter the REPL loop + self.repl_loop() + } + + /// The main REPL loop. + fn repl_loop(&mut self) -> Result<()> { + let stdin = io::stdin(); + let mut stdout = io::stdout(); + + loop { + // Print prompt + print!("(debug) "); + stdout.flush()?; + + // Read command + let mut input = String::new(); + if stdin.read_line(&mut input)? == 0 { + // EOF + break; + } + + let input = input.trim(); + if input.is_empty() { + continue; + } + + // Parse and execute command + match self.execute_command(input) { + Ok(CommandResult::Quit) => { + println!("Debugging session ended."); + break; + } + Ok(CommandResult::Continue) => { + self.run_until_pause()?; + } + Ok(CommandResult::Step(mode)) => { + self.step_execution(mode)?; + } + Ok(CommandResult::Output(msg)) => { + println!("{}", msg); + } + Ok(CommandResult::None) => {} + Err(e) => { + eprintln!("Error: {}", e); + } + } + + // Check if execution finished + if self.finished { + println!("\n✅ Program execution completed."); + break; + } + } + + Ok(()) + } + + /// Executes a debug command. + fn execute_command(&mut self, input: &str) -> Result { + let cmd = DebugCommand::parse(input).map_err(|e| anyhow!("{}", e))?; + + match cmd { + DebugCommand::Break(line) => { + if self.interpreter.set_breakpoint(line) { + Ok(CommandResult::Output(format!( + "Breakpoint set at line {}", + line + ))) + } else { + Ok(CommandResult::Output(format!( + "Breakpoint already exists at line {}", + line + ))) + } + } + + DebugCommand::Delete(line) => { + if self.interpreter.remove_breakpoint(line) { + Ok(CommandResult::Output(format!( + "Breakpoint removed at line {}", + line + ))) + } else { + Ok(CommandResult::Output(format!( + "No breakpoint at line {}", + line + ))) + } + } + + DebugCommand::DeleteAll => { + self.interpreter.clear_breakpoints(); + Ok(CommandResult::Output("All breakpoints removed".to_string())) + } + + DebugCommand::Continue => { + if !self.started { + self.start_execution()?; + } + self.interpreter.set_step_mode(StepMode::Continue); + Ok(CommandResult::Continue) + } + + DebugCommand::StepInto => { + if !self.started { + self.start_execution()?; + } + Ok(CommandResult::Step(StepMode::StepInto)) + } + + DebugCommand::StepOver => { + if !self.started { + self.start_execution()?; + } + Ok(CommandResult::Step(StepMode::StepOver)) + } + + DebugCommand::StepOut => { + if !self.started { + self.start_execution()?; + } + Ok(CommandResult::Step(StepMode::StepOut)) + } + + DebugCommand::Print(expr) => { + let result = self.evaluate_expression(&expr)?; + Ok(CommandResult::Output(format!("{} = {}", expr, result))) + } + + DebugCommand::Locals => { + let locals = self.interpreter.debug_locals(); + if locals.is_empty() { + Ok(CommandResult::Output(" (no local variables)".to_string())) + } else { + let output = locals + .iter() + .map(|(name, value)| format!(" {} = {}", name, value)) + .collect::>() + .join("\n"); + Ok(CommandResult::Output(format!( + "Local variables:\n{}", + output + ))) + } + } + + DebugCommand::Stack => { + let stack = self.interpreter.debug_call_stack(); + if stack.is_empty() { + Ok(CommandResult::Output(" (empty stack)".to_string())) + } else { + let output = stack + .iter() + .rev() + .enumerate() + .map(|(i, frame)| format!(" #{} {}", i, frame)) + .collect::>() + .join("\n"); + Ok(CommandResult::Output(format!("Call stack:\n{}", output))) + } + } + + DebugCommand::Watch(expr) => { + if let Some(id) = self.interpreter.add_watch(expr.clone()) { + Ok(CommandResult::Output(format!( + "Watch #{} added: {}", + id, expr + ))) + } else { + Ok(CommandResult::Output( + "Failed to add watch expression".to_string(), + )) + } + } + + DebugCommand::Unwatch(id) => { + if self.interpreter.remove_watch(id) { + Ok(CommandResult::Output(format!("Watch #{} removed", id))) + } else { + Ok(CommandResult::Output(format!("Watch #{} not found", id))) + } + } + + DebugCommand::Watches => { + let watches = self.format_watches(); + Ok(CommandResult::Output(watches)) + } + + DebugCommand::ListBreakpoints => { + let breakpoints = self.interpreter.breakpoints(); + if breakpoints.is_empty() { + Ok(CommandResult::Output(" (no breakpoints set)".to_string())) + } else { + let mut sorted: Vec<_> = breakpoints.into_iter().collect(); + sorted.sort(); + let output = sorted + .iter() + .map(|line| format!(" Line {}", line)) + .collect::>() + .join("\n"); + Ok(CommandResult::Output(format!("Breakpoints:\n{}", output))) + } + } + + DebugCommand::Help => Ok(CommandResult::Output(debug_help())), + + DebugCommand::Quit => Ok(CommandResult::Quit), + + DebugCommand::Where => { + let context = self.interpreter.debug_source_context(3); + Ok(CommandResult::Output(context)) + } + + DebugCommand::List(line) => { + let output = self.list_source(line); + Ok(CommandResult::Output(output)) + } + } + } + + /// Starts program execution. + fn start_execution(&mut self) -> Result<()> { + if self.started { + return Ok(()); + } + + self.started = true; + self.execution_state = ExecutionState::Running; + + if self.config.verbose { + println!("Starting program execution..."); + } + + Ok(()) + } + + /// Runs until next pause point (breakpoint or step). + fn run_until_pause(&mut self) -> Result<()> { + if self.finished { + println!("Program has already finished."); + return Ok(()); + } + + // Execute the program + if let Some(ast) = self.ast.take() { + match self.interpreter.execute_program(ast.clone()) { + Ok(()) => { + self.finished = true; + self.execution_state = ExecutionState::Finished; + } + Err(e) => { + eprintln!("Runtime error: {}", e); + self.finished = true; + self.execution_state = ExecutionState::Finished; + } + } + self.ast = Some(ast); + } + + Ok(()) + } + + /// Performs a step execution. + fn step_execution(&mut self, mode: StepMode) -> Result<()> { + self.interpreter.set_step_mode(mode); + self.run_until_pause() + } + + /// Evaluates an expression in the current context. + fn evaluate_expression(&self, expr: &str) -> Result { + // Check if it's a simple variable reference + let all_vars = self.interpreter.debug_all_variables(); + + // Try direct variable lookup first + if let Some(value) = all_vars.get(expr.trim()) { + return Ok(value.to_string()); + } + + // For more complex expressions, we would need to parse and evaluate them + // For now, we handle some simple cases + let trimmed = expr.trim(); + + // Check for member access (e.g., "obj.field") + if let Some(dot_pos) = trimmed.find('.') { + let obj_name = &trimmed[..dot_pos]; + let field_name = &trimmed[dot_pos + 1..]; + + if let Some(obj_value) = all_vars.get(obj_name) { + return Ok(format!( + "{}.{} on {} (member access not fully supported in REPL)", + obj_name, field_name, obj_value + )); + } + } + + // Variable not found + Err(anyhow!("Cannot evaluate '{}': variable not found", expr)) + } + + /// Formats watch expressions for display. + fn format_watches(&self) -> String { + // Get watches from debug state + if let Some(ref state) = self.interpreter.debug_state { + let watches = state.watches(); + if watches.is_empty() { + return " (no watch expressions)".to_string(); + } + + let output: Vec = watches + .iter() + .map(|w| { + let value = match self.evaluate_expression(&w.expression) { + Ok(v) => v, + Err(_) => "".to_string(), + }; + format!(" #{} {} = {}", w.id, w.expression, value) + }) + .collect(); + + format!("Watches:\n{}", output.join("\n")) + } else { + " (debug mode not enabled)".to_string() + } + } + + /// Lists source code around the specified line. + fn list_source(&self, center_line: Option) -> String { + let lines: Vec<&str> = self.source.lines().collect(); + if lines.is_empty() { + return "(no source available)".to_string(); + } + + let center = center_line.unwrap_or(1).saturating_sub(1); + let start = center.saturating_sub(5); + let end = (center + 5).min(lines.len() - 1); + + let breakpoints: HashSet = self.interpreter.breakpoints().into_iter().collect(); + + let mut output = String::new(); + for (i, line) in lines.iter().enumerate().skip(start).take(end - start + 1) { + let line_num = i + 1; + let marker = if breakpoints.contains(&line_num) { + "●" + } else { + " " + }; + output.push_str(&format!("{} {:4} | {}\n", marker, line_num, line)); + } + + output + } + + /// Prints welcome message. + fn print_welcome(&self) { + println!("╔══════════════════════════════════════════════════════════════╗"); + println!( + "║ HypnoScript Debugger v{} ║", + env!("CARGO_PKG_VERSION") + ); + println!("║ Type 'help' for available commands, 'quit' to exit ║"); + println!("╚══════════════════════════════════════════════════════════════╝"); + println!(); + } + + /// Prints source information. + fn print_source_info(&self) { + let line_count = self.source.lines().count(); + println!("Source: {} lines", line_count); + + let breakpoints = self.interpreter.breakpoints(); + if !breakpoints.is_empty() { + let mut sorted: Vec<_> = breakpoints.into_iter().collect(); + sorted.sort(); + println!("Breakpoints: {:?}", sorted); + } + + if !self.config.watch_expressions.is_empty() { + println!("Watches: {:?}", self.config.watch_expressions); + } + + println!(); + println!("Use 'continue' or 'c' to start execution."); + println!("Use 'step' or 's' to step through code."); + println!(); + } +} + +/// Runs an interactive debug session for a HypnoScript file. +/// +/// # Arguments +/// * `source` - The source code to debug +/// * `config` - Debug configuration +/// +/// # Returns +/// `Ok(())` on successful completion, `Err` on failure +pub fn run_debug_session(source: String, config: DebugConfig) -> Result<()> { + let mut session = DebugSession::new(source, config)?; + session.run() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_debug_config_default() { + let config = DebugConfig::default(); + assert!(config.breakpoints.is_empty()); + assert!(config.watch_expressions.is_empty()); + assert!(!config.verbose); + assert!(config.trace_file.is_none()); + } + + #[test] + fn test_debug_config_builder() { + let config = DebugConfig::new() + .with_breakpoints(vec![5, 10, 15]) + .with_watches(vec!["x".to_string(), "y".to_string()]) + .with_verbose(true) + .with_trace_file(Some("trace.log".to_string())); + + assert_eq!(config.breakpoints, vec![5, 10, 15]); + assert_eq!(config.watch_expressions, vec!["x", "y"]); + assert!(config.verbose); + assert_eq!(config.trace_file, Some("trace.log".to_string())); + } + + #[test] + fn test_debug_session_creation() { + let source = "Focus { induce x = 42; } Relax".to_string(); + let config = DebugConfig::default(); + let session = DebugSession::new(source, config); + assert!(session.is_ok()); + } + + #[test] + fn test_debug_session_with_breakpoints() { + let source = "Focus { induce x = 42; observe x; } Relax".to_string(); + let config = DebugConfig::new().with_breakpoints(vec![1, 2]); + let session = DebugSession::new(source, config).unwrap(); + + assert!(session.interpreter.has_breakpoint(1)); + assert!(session.interpreter.has_breakpoint(2)); + } + + #[test] + fn test_debug_session_parse() { + let source = "Focus { induce x: number = 42; } Relax".to_string(); + let config = DebugConfig::default(); + let mut session = DebugSession::new(source, config).unwrap(); + + assert!(session.parse().is_ok()); + assert!(session.ast.is_some()); + } + + #[test] + fn test_command_result_variants() { + // Test that all variants can be created + let _ = CommandResult::Continue; + let _ = CommandResult::Step(StepMode::StepInto); + let _ = CommandResult::Quit; + let _ = CommandResult::Output("test".to_string()); + let _ = CommandResult::None; + } + + #[test] + fn test_list_source() { + let source = + "line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10" + .to_string(); + let config = DebugConfig::default(); + let session = DebugSession::new(source, config).unwrap(); + + let output = session.list_source(Some(5)); + assert!(output.contains("line 1")); + assert!(output.contains("line 5")); + assert!(output.contains("line 10")); + } + + #[test] + fn test_list_source_with_breakpoints() { + let source = "line 1\nline 2\nline 3".to_string(); + let config = DebugConfig::new().with_breakpoints(vec![2]); + let session = DebugSession::new(source, config).unwrap(); + + let output = session.list_source(None); + assert!(output.contains("●")); // Breakpoint marker + } +} diff --git a/hypnoscript-cli/src/main.rs b/hypnoscript-cli/src/main.rs index 373666b..08aa950 100644 --- a/hypnoscript-cli/src/main.rs +++ b/hypnoscript-cli/src/main.rs @@ -1,7 +1,9 @@ +mod debug_repl; mod package; use anyhow::{Result, anyhow}; use clap::{Parser, Subcommand}; +use debug_repl::{DebugConfig, run_debug_session}; use hypnoscript_compiler::{ Interpreter, NativeCodeGenerator, OptimizationLevel, Optimizer, TargetPlatform, TypeChecker, WasmBinaryGenerator, WasmCodeGenerator, @@ -14,7 +16,7 @@ use serde::Deserialize; use std::io::Write; use std::process::{Command, Stdio}; use std::{env, fs, time::Duration}; -use ureq::{Agent, AgentBuilder}; +use ureq::Agent; #[cfg(not(target_os = "windows"))] use std::path::{Path, PathBuf}; @@ -23,7 +25,7 @@ const GITHUB_OWNER: &str = "Kink-Development-Group"; const GITHUB_REPO: &str = "hyp-runtime"; const GITHUB_API: &str = "https://api.github.com"; const DEFAULT_TIMEOUT_SECS: u64 = 20; -const DEFAULT_PACKAGE_VERSION: &str = "^1.0.0"; +const DEFAULT_PACKAGE_VERSION: &str = "^1.2.0"; #[cfg(not(target_os = "windows"))] const INSTALLER_FALLBACK_URL: &str = "https://kink-development-group.github.io/hyp-runtime/install.sh"; @@ -54,13 +56,25 @@ enum Commands { /// Path to the .hyp file file: String, - /// Enable debug mode + /// Enable debug mode (interactive debugger) #[arg(short, long)] debug: bool, /// Enable verbose output #[arg(short, long)] verbose: bool, + + /// Set breakpoints at specific lines (comma-separated) + #[arg(long, value_delimiter = ',')] + breakpoints: Option>, + + /// Watch expressions to monitor (comma-separated) + #[arg(long, value_delimiter = ',')] + watch: Option>, + + /// Output trace information to file + #[arg(long)] + trace_file: Option, }, /// Lex a HypnoScript file (tokenize) @@ -212,6 +226,9 @@ fn main() -> Result<()> { file, debug, verbose, + breakpoints, + watch, + trace_file, } => { if verbose { println!("Running file: {}", file); @@ -219,17 +236,27 @@ fn main() -> Result<()> { let source = fs::read_to_string(&file)?; + // If debug mode is enabled, start interactive debug session if debug { - println!("Source code:"); - println!("{}", source); - println!("\n--- Lexing ---"); + let config = DebugConfig::new() + .with_breakpoints(breakpoints.unwrap_or_default()) + .with_watches(watch.unwrap_or_default()) + .with_verbose(verbose) + .with_trace_file(trace_file); + + return run_debug_session(source, config); + } + + // Normal execution mode + if verbose { + println!("Source code: {} bytes", source.len()); } // Lex let mut lexer = Lexer::new(&source); let tokens = lexer.lex().map_err(into_anyhow)?; - if debug { + if verbose { println!("Tokens: {}", tokens.len()); } @@ -237,8 +264,8 @@ fn main() -> Result<()> { let mut parser = HypnoParser::new(tokens); let ast = parser.parse_program().map_err(into_anyhow)?; - if debug { - println!("\n--- Type Checking ---"); + if verbose { + println!("AST parsed successfully"); } // Type check @@ -249,13 +276,11 @@ fn main() -> Result<()> { for error in errors { eprintln!(" - {}", error); } - if !debug { - eprintln!("\nContinuing execution despite type errors..."); - } + eprintln!("\nContinuing execution despite type errors..."); } - if debug { - println!("\n--- Executing ---"); + if verbose { + println!("Executing program..."); } // Execute @@ -394,11 +419,11 @@ fn main() -> Result<()> { Err(e) => { println!("⚠️ {}", e); println!( - "\nHinweis: Native Code-Generierung wird in einer zukünftigen Version implementiert." + "\nNote: Native code generation will be implemented in a future version." ); - println!("Verwenden Sie stattdessen:"); - println!(" - 'hypnoscript run {}' für Interpretation", input); - println!(" - 'hypnoscript compile-wasm {}' für WebAssembly", input); + println!("Use instead:"); + println!(" - 'hypnoscript run {}' for interpretation", input); + println!(" - 'hypnoscript compile-wasm {}' for WebAssembly", input); } } } @@ -450,7 +475,7 @@ fn main() -> Result<()> { let output_file = output.unwrap_or_else(|| input.replace(".hyp", ".opt.hyp")); println!("✅ Optimized AST available (output generation not yet implemented)"); println!(" Would write to: {}", output_file); - println!("\nOptimierter AST:\n{:#?}", optimized_ast); + println!("\nOptimized AST:\n{:#?}", optimized_ast); } Commands::SelfUpdate { @@ -641,19 +666,22 @@ fn build_agent() -> Agent { .and_then(|s| s.parse::().ok()) .unwrap_or(DEFAULT_TIMEOUT_SECS); - AgentBuilder::new() - .timeout(Duration::from_secs(timeout_secs)) - .user_agent(&format!("hypnoscript-cli/{}", env!("CARGO_PKG_VERSION"))) + Agent::config_builder() + .timeout_global(Some(Duration::from_secs(timeout_secs))) + .user_agent(format!("hypnoscript-cli/{}", env!("CARGO_PKG_VERSION"))) .build() + .new_agent() } -fn github_get(agent: &Agent, url: &str) -> ureq::Request { - let mut request = agent.get(url).set("Accept", "application/vnd.github+json"); +fn github_get(agent: &Agent, url: &str) -> ureq::RequestBuilder { + let mut request = agent + .get(url) + .header("Accept", "application/vnd.github+json"); if let Ok(token) = env::var("GITHUB_TOKEN") { request = request - .set("Authorization", &format!("Bearer {}", token)) - .set("X-GitHub-Api-Version", "2022-11-28"); + .header("Authorization", &format!("Bearer {}", token)) + .header("X-GitHub-Api-Version", "2022-11-28"); } request @@ -667,7 +695,8 @@ fn fetch_latest_release(agent: &Agent, include_prerelease: bool) -> Result = github_get(agent, &url) .call()? - .into_json::>()? + .body_mut() + .read_json::>()? .into_iter() .filter(|release| !release.draft) .collect(); @@ -681,7 +710,7 @@ fn fetch_latest_release(agent: &Agent, include_prerelease: bool) -> Result) -> Option #[cfg(not(target_os = "windows"))] fn download_installer(agent: &Agent) -> Result { let response = agent.get(INSTALLER_FALLBACK_URL).call()?; - let script = response.into_string()?; + let script = response.into_body().read_to_string()?; let mut temp_file = Builder::new() .prefix("hypnoscript-installer-") diff --git a/hypnoscript-cli/src/package.rs b/hypnoscript-cli/src/package.rs index 234767a..696ed97 100644 --- a/hypnoscript-cli/src/package.rs +++ b/hypnoscript-cli/src/package.rs @@ -232,7 +232,7 @@ impl PackageManager { if !path.exists() { // Return empty lock file if it doesn't exist return Ok(TranceLock { - lock_version: "1.0.0".to_string(), + lock_version: "1.2.0".to_string(), locked_anchors: HashMap::new(), }); } @@ -450,7 +450,7 @@ impl PackageManager { // For now, we'll create a lock file with the dependencies // In a full implementation, this would fetch packages from a registry let mut lock = TranceLock { - lock_version: "1.0.0".to_string(), + lock_version: "1.2.0".to_string(), locked_anchors: HashMap::new(), }; @@ -586,7 +586,7 @@ mod tests { pm.init("test-package".to_string(), None)?; pm.add_dependency( "hypnoscript-runtime".to_string(), - "^1.0.0".to_string(), + "^1.2.0".to_string(), false, )?; diff --git a/hypnoscript-compiler/Cargo.toml b/hypnoscript-compiler/Cargo.toml index 70adea9..3f49e8c 100644 --- a/hypnoscript-compiler/Cargo.toml +++ b/hypnoscript-compiler/Cargo.toml @@ -14,15 +14,15 @@ anyhow = { workspace = true } thiserror = { workspace = true } # Async Runtime -tokio = { version = "1.41", features = ["full"] } +tokio = { version = "1.49.0", features = ["full"] } futures = "0.3" async-trait = "0.1" -num_cpus = "1.16" +num_cpus = "1.17.0" # Native code generation backend (Cranelift) -cranelift = "0.110" -cranelift-module = "0.110" -cranelift-jit = "0.110" -cranelift-object = "0.110" -cranelift-native = "0.110" -target-lexicon = "0.12" +cranelift = "0.128.0" +cranelift-module = "0.128.0" +cranelift-jit = "0.128.0" +cranelift-object = "0.128.0" +cranelift-native = "0.128.0" +target-lexicon = "0.13.4" diff --git a/hypnoscript-compiler/README.md b/hypnoscript-compiler/README.md index d21a992..0b32878 100644 --- a/hypnoscript-compiler/README.md +++ b/hypnoscript-compiler/README.md @@ -1,47 +1,45 @@ # HypnoScript Compiler -Der vollständige Compiler und Interpreter für die HypnoScript-Programmiersprache. +The full compiler and interpreter for the HypnoScript programming language. ## Features -### 🎯 Mehrere Backends +### 🎯 Multiple Backends -1. **Interpreter** - Direktes Ausführen von HypnoScript-Code - - - Vollständige Sprachunterstützung - - OOP mit Sessions (Klassen) - - Integrierte Built-in-Funktionen - - Ideal für Entwicklung und Debugging +1. **Interpreter** - Direct execution of HypnoScript code + - Full language support + - OOP with sessions (classes) + - Built-in functions included + - Ideal for development and debugging 2. **Native Code Generator** (Cranelift) - - - Plattformspezifischer Maschinencode - - Automatisches Linking zu ausführbaren Binaries - - Unterstützte Plattformen: - - Windows (x86_64, ARM64) - benötigt Visual Studio Build Tools, GCC oder Clang - - macOS (x86_64, ARM64/Apple Silicon) - benötigt Xcode Command Line Tools - - Linux (x86_64, ARM64, RISC-V) - benötigt GCC oder Clang - - Optimierte Binaries mit verschiedenen Optimierungsstufen - - Schneller Build-Prozess im Vergleich zu LLVM - - ✅ **Vollständig funktionsfähig** - erzeugt ausführbare .exe/.bin Dateien + - Platform-specific machine code + - Automatic linking to executable binaries + - Supported platforms: + - Windows (x86_64, ARM64) - requires Visual Studio Build Tools, GCC, or Clang + - macOS (x86_64, ARM64/Apple Silicon) - requires Xcode Command Line Tools + - Linux (x86_64, ARM64, RISC-V) - requires GCC or Clang + - Optimized binaries with multiple optimization levels + - Faster build process compared to LLVM + - ✅ **Fully functional** - produces executable .exe/.bin files 3. **WebAssembly Generator** - - Text Format (.wat) - menschenlesbar - - Binary Format (.wasm) - kompakt - - Browser- und Server-Unterstützung - - Sandboxed Execution + - Text format (.wat) - human-readable + - Binary format (.wasm) - compact + - Browser and server support + - Sandboxed execution -### 🔧 Zusätzliche Features +### 🔧 Additional Features -- **Type Checker**: Statische Typprüfung -- **Optimizer**: Code-Optimierungen +- **Type Checker**: Static type checking +- **Optimizer**: Code optimizations - Constant Folding - Dead Code Elimination - Common Subexpression Elimination - Loop Invariant Code Motion - Function Inlining -## Verwendung +## Usage ### Interpreter @@ -65,7 +63,7 @@ let mut interpreter = Interpreter::new(); interpreter.interpret(&ast)?; ``` -### Native Kompilierung +### Native Compilation ```rust use hypnoscript_compiler::{NativeCodeGenerator, OptimizationLevel, TargetPlatform}; @@ -77,7 +75,7 @@ generator.set_optimization_level(OptimizationLevel::Release); let binary_path = generator.generate(&ast)?; ``` -### WASM-Generierung +### WASM Generation ```rust use hypnoscript_compiler::{WasmCodeGenerator, WasmBinaryGenerator}; @@ -93,14 +91,14 @@ let wasm_bytes = wasm_gen.generate(&ast)?; std::fs::write("output.wasm", wasm_bytes)?; ``` -## Architektur +## Architecture -### Design-Prinzipien +### Design Principles -- **OOP First**: Sessions als vollwertige Klassen mit Kapselung -- **DRY**: Keine Code-Duplizierung, gemeinsame Infrastruktur -- **Type Safety**: Statische Typprüfung vor der Ausführung -- **Memory Safety**: 100% Rust, keine unsicheren Operationen +- **OOP First**: Sessions as full classes with encapsulation +- **DRY**: No code duplication, shared infrastructure +- **Type Safety**: Static type checking before execution +- **Memory Safety**: 100% Rust, no unsafe operations ### Module @@ -108,29 +106,29 @@ std::fs::write("output.wasm", wasm_bytes)?; hypnoscript-compiler/ ├── src/ │ ├── lib.rs # Public API -│ ├── interpreter.rs # Runtime-Interpreter (2392 Zeilen) -│ ├── type_checker.rs # Statische Typprüfung (1683 Zeilen) -│ ├── optimizer.rs # Code-Optimierungen (421 Zeilen) -│ ├── native_codegen.rs # Cranelift-Backend mit Auto-Linking +│ ├── interpreter.rs # Runtime interpreter (2392 lines) +│ ├── type_checker.rs # Static type checking (1683 lines) +│ ├── optimizer.rs # Code optimizations (421 lines) +│ ├── native_codegen.rs # Cranelift backend with auto-linking │ ├── wasm_codegen.rs # WASM Text Generator │ └── wasm_binary.rs # WASM Binary Generator └── Cargo.toml ``` -## Performance-Vergleich +## Performance Comparison -| Backend | Kompilierzeit | Ausführungszeit | Binary-Größe | Use Case | -| ------------------ | ------------- | -------------------- | ------------ | ---------------------- | -| Interpreter | Sofort | ~10x langsamer | N/A | Entwicklung, Debugging | -| Native (Cranelift) | ~1-2 Sekunden | Nativ (sehr schnell) | 50-200 KB | Produktion, Server | -| WASM | ~50ms | ~2x langsamer | 10-50 KB | Web, Embedding | +| Backend | Compile Time | Runtime | Binary Size | Use Case | +| ------------------ | ------------ | ------------------ | ----------- | ---------------------- | +| Interpreter | Instant | ~10x slower | N/A | Development, debugging | +| Native (Cranelift) | ~1-2 seconds | Native (very fast) | 50-200 KB | Production, server | +| WASM | ~50ms | ~2x slower | 10-50 KB | Web, embedding | -## Systemvoraussetzungen für Native Kompilierung +## System Requirements for Native Compilation ### Windows -- Visual Studio Build Tools (empfohlen) ODER -- MinGW-w64/GCC ODER +- Visual Studio Build Tools (recommended) OR +- MinGW-w64/GCC OR - LLVM/Clang ### macOS @@ -139,15 +137,15 @@ hypnoscript-compiler/ ### Linux -- GCC (`sudo apt install build-essential`) ODER +- GCC (`sudo apt install build-essential`) OR - Clang (`sudo apt install clang`) ## Dependencies -- `cranelift`: Native Code-Generierung -- `hypnoscript-core`: Gemeinsame Typen und Symbol-Tables -- `hypnoscript-lexer-parser`: AST und Parser -- `hypnoscript-runtime`: Built-in-Funktionen +- `cranelift`: Native code generation +- `hypnoscript-core`: Shared types and symbol tables +- `hypnoscript-lexer-parser`: AST and parser +- `hypnoscript-runtime`: Built-in functions ## Tests @@ -155,35 +153,35 @@ hypnoscript-compiler/ cargo test --package hypnoscript-compiler ``` -Aktueller Stand: **34 Tests, alle erfolgreich** ✅ +Current status: **34 tests, all passing** ✅ -## Beispiel: Native Kompilierung +## Example: Native Compilation ```bash -# Kompiliere HypnoScript zu nativer ausführbarer Datei -hypnoscript compile-native mein_programm.hyp +# Compile HypnoScript to a native executable +hypnoscript compile-native my_program.hyp -# Mit Optimierung -hypnoscript compile-native mein_programm.hyp --opt-level release +# With optimization +hypnoscript compile-native my_program.hyp --opt-level release -# Spezifisches Output -hypnoscript compile-native mein_programm.hyp --output mein_programm.exe +# Specific output +hypnoscript compile-native my_program.hyp --output my_program.exe ``` ## Roadmap -- [x] Interpreter mit vollständiger Sprachunterstützung +- [x] Interpreter with full language support - [x] Type Checker - [x] WASM Text Format (.wat) - [x] WASM Binary Format (.wasm) -- [x] Native Code-Generator mit Cranelift -- [x] Automatisches Linking zu ausführbaren Binaries -- [x] Code-Optimierungen +- [x] Native code generator with Cranelift +- [x] Automatic linking to executable binaries +- [x] Code optimizations - [ ] Advanced Control Flow in WASM -- [ ] Vollständige Session-Unterstützung in Native/WASM -- [ ] Debugging-Informationen (DWARF) +- [ ] Full session support in Native/WASM +- [ ] Debugging information (DWARF) - [ ] Cross-Compilation -## Lizenz +## License MIT diff --git a/hypnoscript-compiler/src/debug.rs b/hypnoscript-compiler/src/debug.rs new file mode 100644 index 0000000..cf14108 --- /dev/null +++ b/hypnoscript-compiler/src/debug.rs @@ -0,0 +1,1006 @@ +//! Debug infrastructure for HypnoScript interpreter. +//! +//! This module provides comprehensive debugging capabilities including: +//! - Breakpoints (set, remove, query) +//! - Step-through execution (step into, step over, step out) +//! - Call stack inspection +//! - Watch expressions +//! - Variable inspection +//! +//! # Architecture +//! +//! The debug system integrates with the interpreter by checking for +//! breakpoints and step conditions before each statement execution. +//! +//! # Examples +//! +//! ```rust,no_run +//! use hypnoscript_compiler::debug::{DebugState, StepMode}; +//! +//! let mut debug_state = DebugState::new(); +//! debug_state.set_breakpoint(10); +//! debug_state.set_step_mode(StepMode::StepInto); +//! ``` + +use crate::interpreter::Value; +use std::collections::{HashMap, HashSet}; +use thiserror::Error; + +/// Errors that can occur during debugging operations. +#[derive(Error, Debug)] +pub enum DebugError { + #[error("Breakpoint at line {0} already exists")] + BreakpointExists(usize), + + #[error("Breakpoint at line {0} does not exist")] + BreakpointNotFound(usize), + + #[error("Invalid debug command: {0}")] + InvalidCommand(String), + + #[error("Expression evaluation failed: {0}")] + ExpressionError(String), + + #[error("Debug session not active")] + SessionNotActive, +} + +/// Result type for debug operations. +pub type DebugResult = Result; + +/// Represents the current stepping mode during debugging. +/// +/// This controls how the debugger advances through code: +/// - `None`: Normal execution (no stepping) +/// - `StepInto`: Execute one statement, entering function calls +/// - `StepOver`: Execute one statement, not entering function calls +/// - `StepOut`: Continue until current function returns +/// - `Continue`: Run until next breakpoint or end +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum StepMode { + /// No stepping - normal execution + #[default] + None, + /// Step into function calls + StepInto, + /// Step over function calls + StepOver, + /// Step out of current function + StepOut, + /// Continue to next breakpoint + Continue, +} + +impl std::fmt::Display for StepMode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + StepMode::None => write!(f, "none"), + StepMode::StepInto => write!(f, "step-into"), + StepMode::StepOver => write!(f, "step-over"), + StepMode::StepOut => write!(f, "step-out"), + StepMode::Continue => write!(f, "continue"), + } + } +} + +/// Represents a single call frame in the execution stack. +/// +/// Call frames track the current execution context including +/// function name, source location, and local variable bindings. +/// +/// # Examples +/// +/// ```rust,no_run +/// use hypnoscript_compiler::debug::CallFrame; +/// use hypnoscript_compiler::Value; +/// use std::collections::HashMap; +/// +/// let frame = CallFrame { +/// function_name: "myFunction".to_string(), +/// line: 42, +/// column: 1, +/// local_variables: HashMap::new(), +/// is_native: false, +/// }; +/// ``` +#[derive(Debug, Clone)] +pub struct CallFrame { + /// Name of the function being executed + pub function_name: String, + /// Current line number (1-indexed) + pub line: usize, + /// Current column number (1-indexed) + pub column: usize, + /// Snapshot of local variables in this frame + pub local_variables: HashMap, + /// Whether this is a native/builtin function + pub is_native: bool, +} + +impl CallFrame { + /// Creates a new call frame. + pub fn new(function_name: String, line: usize) -> Self { + Self { + function_name, + line, + column: 1, + local_variables: HashMap::new(), + is_native: false, + } + } + + /// Creates a call frame for a native function. + pub fn native(function_name: String) -> Self { + Self { + function_name, + line: 0, + column: 0, + local_variables: HashMap::new(), + is_native: true, + } + } + + /// Updates the source location. + pub fn set_location(&mut self, line: usize, column: usize) { + self.line = line; + self.column = column; + } + + /// Adds or updates a local variable. + pub fn set_variable(&mut self, name: String, value: Value) { + self.local_variables.insert(name, value); + } +} + +impl std::fmt::Display for CallFrame { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.is_native { + write!(f, "{} (native)", self.function_name) + } else { + write!(f, "{} at line {}", self.function_name, self.line) + } + } +} + +/// A watch expression that is evaluated when the debugger pauses. +#[derive(Debug, Clone)] +pub struct WatchExpression { + /// The expression string to evaluate + pub expression: String, + /// Unique ID for this watch + pub id: usize, + /// Last evaluated value (if any) + pub last_value: Option, + /// Whether the watch is enabled + pub enabled: bool, +} + +impl WatchExpression { + /// Creates a new watch expression. + pub fn new(id: usize, expression: String) -> Self { + Self { + expression, + id, + last_value: None, + enabled: true, + } + } + + /// Updates the last evaluated value. + pub fn set_value(&mut self, value: Value) { + self.last_value = Some(value); + } + + /// Toggles the enabled state. + pub fn toggle(&mut self) { + self.enabled = !self.enabled; + } +} + +/// Represents the reason why the debugger paused. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum PauseReason { + /// Hit a user-set breakpoint + Breakpoint(usize), + /// Completed a step operation + Step, + /// Hit a programmatic breakpoint (from code) + ProgrammaticBreakpoint, + /// User requested pause + UserRequest, + /// Exception/error occurred + Exception(String), +} + +impl std::fmt::Display for PauseReason { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + PauseReason::Breakpoint(line) => write!(f, "Breakpoint at line {}", line), + PauseReason::Step => write!(f, "Step completed"), + PauseReason::ProgrammaticBreakpoint => write!(f, "Programmatic breakpoint"), + PauseReason::UserRequest => write!(f, "Paused by user"), + PauseReason::Exception(msg) => write!(f, "Exception: {}", msg), + } + } +} + +/// Complete debug state for the interpreter. +/// +/// This structure maintains all debugging information including: +/// - Set of breakpoints +/// - Current stepping mode +/// - Call stack +/// - Watch expressions +/// - Pause state +/// +/// # Examples +/// +/// ```rust,no_run +/// use hypnoscript_compiler::debug::{DebugState, StepMode}; +/// +/// let mut state = DebugState::new(); +/// +/// // Set breakpoints +/// state.set_breakpoint(10); +/// state.set_breakpoint(25); +/// +/// // Configure stepping +/// state.set_step_mode(StepMode::StepInto); +/// +/// // Add watch expression +/// state.add_watch("myVariable".to_string()); +/// ``` +#[derive(Debug, Default)] +pub struct DebugState { + /// Set of line numbers with breakpoints + breakpoints: HashSet, + /// Current stepping mode + step_mode: StepMode, + /// Call stack (bottom to top) + call_stack: Vec, + /// Watch expressions + watches: Vec, + /// Next watch ID + next_watch_id: usize, + /// Whether the debugger is currently paused + is_paused: bool, + /// Reason for the current pause (if paused) + pause_reason: Option, + /// Current line being executed + current_line: usize, + /// Current column being executed + current_column: usize, + /// Depth at which step over was initiated (for step-over logic) + step_over_depth: Option, + /// Depth at which step out was initiated (for step-out logic) + step_out_depth: Option, + /// Whether to break on next statement (for step operations) + break_on_next: bool, + /// Source code lines (for display) + source_lines: Vec, +} + +impl DebugState { + /// Creates a new debug state. + pub fn new() -> Self { + Self::default() + } + + /// Creates a debug state with source code for display. + pub fn with_source(source: &str) -> Self { + Self { + source_lines: source.lines().map(String::from).collect(), + ..Default::default() + } + } + + /// Sets the source code for display. + pub fn set_source(&mut self, source: &str) { + self.source_lines = source.lines().map(String::from).collect(); + } + + // === Breakpoint Management === + + /// Sets a breakpoint at the given line number. + /// + /// # Arguments + /// * `line` - Line number (1-indexed) + /// + /// # Returns + /// `true` if breakpoint was newly added, `false` if already existed + pub fn set_breakpoint(&mut self, line: usize) -> bool { + self.breakpoints.insert(line) + } + + /// Removes a breakpoint at the given line number. + /// + /// # Arguments + /// * `line` - Line number (1-indexed) + /// + /// # Returns + /// `true` if breakpoint was removed, `false` if it didn't exist + pub fn remove_breakpoint(&mut self, line: usize) -> bool { + self.breakpoints.remove(&line) + } + + /// Checks if a breakpoint exists at the given line. + pub fn has_breakpoint(&self, line: usize) -> bool { + self.breakpoints.contains(&line) + } + + /// Returns all set breakpoints. + pub fn breakpoints(&self) -> &HashSet { + &self.breakpoints + } + + /// Clears all breakpoints. + pub fn clear_breakpoints(&mut self) { + self.breakpoints.clear(); + } + + /// Returns the number of breakpoints. + pub fn breakpoint_count(&self) -> usize { + self.breakpoints.len() + } + + // === Step Mode Management === + + /// Gets the current stepping mode. + pub fn step_mode(&self) -> StepMode { + self.step_mode + } + + /// Sets the stepping mode. + pub fn set_step_mode(&mut self, mode: StepMode) { + self.step_mode = mode; + + match mode { + StepMode::StepInto => { + self.break_on_next = true; + self.step_over_depth = None; + self.step_out_depth = None; + } + StepMode::StepOver => { + self.break_on_next = true; + self.step_over_depth = Some(self.call_stack.len()); + self.step_out_depth = None; + } + StepMode::StepOut => { + self.break_on_next = false; + self.step_over_depth = None; + self.step_out_depth = Some(self.call_stack.len()); + } + StepMode::Continue => { + self.break_on_next = false; + self.step_over_depth = None; + self.step_out_depth = None; + } + StepMode::None => { + self.break_on_next = false; + self.step_over_depth = None; + self.step_out_depth = None; + } + } + } + + // === Call Stack Management === + + /// Pushes a new call frame onto the stack. + pub fn push_frame(&mut self, frame: CallFrame) { + self.call_stack.push(frame); + } + + /// Pops the top call frame from the stack. + pub fn pop_frame(&mut self) -> Option { + let frame = self.call_stack.pop(); + + // Check if we should break for step-out + if let Some(depth) = self.step_out_depth + && self.call_stack.len() < depth + { + self.break_on_next = true; + self.step_out_depth = None; + } + + frame + } + + /// Returns the current call stack depth. + pub fn stack_depth(&self) -> usize { + self.call_stack.len() + } + + /// Returns the current (top) call frame. + pub fn current_frame(&self) -> Option<&CallFrame> { + self.call_stack.last() + } + + /// Returns a mutable reference to the current call frame. + pub fn current_frame_mut(&mut self) -> Option<&mut CallFrame> { + self.call_stack.last_mut() + } + + /// Returns the entire call stack. + pub fn call_stack(&self) -> &[CallFrame] { + &self.call_stack + } + + /// Formats the call stack for display. + pub fn format_call_stack(&self) -> String { + if self.call_stack.is_empty() { + return " (empty stack)".to_string(); + } + + self.call_stack + .iter() + .rev() + .enumerate() + .map(|(i, frame)| format!(" #{} {}", i, frame)) + .collect::>() + .join("\n") + } + + // === Watch Expression Management === + + /// Adds a watch expression. + /// + /// # Returns + /// The ID of the new watch expression + pub fn add_watch(&mut self, expression: String) -> usize { + let id = self.next_watch_id; + self.next_watch_id += 1; + self.watches.push(WatchExpression::new(id, expression)); + id + } + + /// Removes a watch expression by ID. + pub fn remove_watch(&mut self, id: usize) -> bool { + if let Some(pos) = self.watches.iter().position(|w| w.id == id) { + self.watches.remove(pos); + true + } else { + false + } + } + + /// Returns all watch expressions. + pub fn watches(&self) -> &[WatchExpression] { + &self.watches + } + + /// Returns a mutable reference to all watches. + pub fn watches_mut(&mut self) -> &mut Vec { + &mut self.watches + } + + /// Clears all watch expressions. + pub fn clear_watches(&mut self) { + self.watches.clear(); + } + + // === Pause State Management === + + /// Checks if the debugger is paused. + pub fn is_paused(&self) -> bool { + self.is_paused + } + + /// Pauses the debugger with a reason. + pub fn pause(&mut self, reason: PauseReason) { + self.is_paused = true; + self.pause_reason = Some(reason); + } + + /// Resumes execution. + pub fn resume(&mut self) { + self.is_paused = false; + self.pause_reason = None; + } + + /// Gets the current pause reason. + pub fn pause_reason(&self) -> Option<&PauseReason> { + self.pause_reason.as_ref() + } + + // === Location Tracking === + + /// Updates the current execution location. + pub fn set_location(&mut self, line: usize, column: usize) { + self.current_line = line; + self.current_column = column; + + if let Some(frame) = self.call_stack.last_mut() { + frame.set_location(line, column); + } + } + + /// Gets the current line number. + pub fn current_line(&self) -> usize { + self.current_line + } + + /// Gets the current column number. + pub fn current_column(&self) -> usize { + self.current_column + } + + // === Breakpoint Checking === + + /// Checks if execution should pause at the current location. + /// + /// This method considers: + /// - Breakpoints at the current line + /// - Step mode and break conditions + /// + /// # Returns + /// `Some(PauseReason)` if should pause, `None` otherwise + pub fn should_pause(&mut self, line: usize) -> Option { + // Update current location + self.current_line = line; + + // Check for breakpoint + if self.breakpoints.contains(&line) { + return Some(PauseReason::Breakpoint(line)); + } + + // Check for step conditions + if self.break_on_next { + // For step-over, only break if we're at or above the original depth + if let Some(depth) = self.step_over_depth { + if self.call_stack.len() <= depth { + self.break_on_next = false; + return Some(PauseReason::Step); + } + } else { + self.break_on_next = false; + return Some(PauseReason::Step); + } + } + + None + } + + /// Triggers a programmatic breakpoint (from code). + pub fn trigger_breakpoint(&mut self) -> PauseReason { + PauseReason::ProgrammaticBreakpoint + } + + // === Source Display === + + /// Gets the source line at the given line number. + pub fn get_source_line(&self, line: usize) -> Option<&str> { + if line > 0 && line <= self.source_lines.len() { + Some(&self.source_lines[line - 1]) + } else { + None + } + } + + /// Formats source lines around the current position for display. + /// + /// # Arguments + /// * `context` - Number of lines before and after to include + pub fn format_source_context(&self, context: usize) -> String { + if self.source_lines.is_empty() || self.current_line == 0 { + return "(no source available)".to_string(); + } + + let start = self.current_line.saturating_sub(context).max(1); + let end = (self.current_line + context).min(self.source_lines.len()); + + let mut result = String::new(); + for line_num in start..=end { + let marker = if line_num == self.current_line { + "→" + } else if self.breakpoints.contains(&line_num) { + "●" + } else { + " " + }; + + if let Some(line) = self.get_source_line(line_num) { + result.push_str(&format!("{} {:4} | {}\n", marker, line_num, line)); + } + } + + result + } + + // === Debug Information === + + /// Returns a summary of the current debug state. + pub fn summary(&self) -> String { + let mut parts = Vec::new(); + + if !self.breakpoints.is_empty() { + parts.push(format!("breakpoints: {:?}", self.breakpoints)); + } + + parts.push(format!("step_mode: {}", self.step_mode)); + parts.push(format!("stack_depth: {}", self.call_stack.len())); + parts.push(format!("paused: {}", self.is_paused)); + + if self.current_line > 0 { + parts.push(format!("line: {}", self.current_line)); + } + + parts.join(", ") + } +} + +/// Debug command parsed from user input. +#[derive(Debug, Clone, PartialEq)] +pub enum DebugCommand { + /// Set a breakpoint at line + Break(usize), + /// Delete a breakpoint at line + Delete(usize), + /// Delete all breakpoints + DeleteAll, + /// Continue execution + Continue, + /// Step into (next statement, entering functions) + StepInto, + /// Step over (next statement, not entering functions) + StepOver, + /// Step out of current function + StepOut, + /// Print/evaluate an expression + Print(String), + /// Show local variables + Locals, + /// Show call stack + Stack, + /// Add a watch expression + Watch(String), + /// Remove a watch expression by ID + Unwatch(usize), + /// Show all watches + Watches, + /// List breakpoints + ListBreakpoints, + /// Show help + Help, + /// Quit debugging session + Quit, + /// Show current source location + Where, + /// List source code around current line + List(Option), +} + +impl DebugCommand { + /// Parses a debug command from a string. + pub fn parse(input: &str) -> DebugResult { + let trimmed = input.trim(); + let parts: Vec<&str> = trimmed.splitn(2, ' ').collect(); + + let cmd = parts[0].to_lowercase(); + let arg = parts.get(1).map(|s| s.trim()); + + match cmd.as_str() { + "b" | "break" => { + let line = arg + .ok_or_else(|| { + DebugError::InvalidCommand("break requires a line number".into()) + })? + .parse::() + .map_err(|_| DebugError::InvalidCommand("invalid line number".into()))?; + Ok(DebugCommand::Break(line)) + } + "d" | "delete" => { + if let Some(arg_str) = arg { + if arg_str == "all" || arg_str == "*" { + Ok(DebugCommand::DeleteAll) + } else { + let line = arg_str.parse::().map_err(|_| { + DebugError::InvalidCommand("invalid line number".into()) + })?; + Ok(DebugCommand::Delete(line)) + } + } else { + Err(DebugError::InvalidCommand( + "delete requires a line number or 'all'".into(), + )) + } + } + "c" | "continue" => Ok(DebugCommand::Continue), + "s" | "step" => Ok(DebugCommand::StepInto), + "n" | "next" => Ok(DebugCommand::StepOver), + "o" | "out" => Ok(DebugCommand::StepOut), + "p" | "print" => { + let expr = arg + .ok_or_else(|| { + DebugError::InvalidCommand("print requires an expression".into()) + })? + .to_string(); + Ok(DebugCommand::Print(expr)) + } + "l" | "locals" => Ok(DebugCommand::Locals), + "st" | "stack" => Ok(DebugCommand::Stack), + "w" | "watch" => { + let expr = arg + .ok_or_else(|| { + DebugError::InvalidCommand("watch requires an expression".into()) + })? + .to_string(); + Ok(DebugCommand::Watch(expr)) + } + "unwatch" => { + let id = arg + .ok_or_else(|| { + DebugError::InvalidCommand("unwatch requires a watch ID".into()) + })? + .parse::() + .map_err(|_| DebugError::InvalidCommand("invalid watch ID".into()))?; + Ok(DebugCommand::Unwatch(id)) + } + "watches" => Ok(DebugCommand::Watches), + "bl" | "breakpoints" => Ok(DebugCommand::ListBreakpoints), + "h" | "help" | "?" => Ok(DebugCommand::Help), + "q" | "quit" | "exit" => Ok(DebugCommand::Quit), + "where" => Ok(DebugCommand::Where), + "list" | "ls" => { + let line = arg.and_then(|s| s.parse::().ok()); + Ok(DebugCommand::List(line)) + } + "" => Err(DebugError::InvalidCommand("empty command".into())), + _ => Err(DebugError::InvalidCommand(format!( + "unknown command: {}", + cmd + ))), + } + } +} + +/// Formats help text for debug commands. +pub fn format_help() -> String { + r#"HypnoScript Debugger Commands: + + Breakpoints: + b, break Set breakpoint at line + d, delete Remove breakpoint at line + d, delete all Remove all breakpoints + bl, breakpoints List all breakpoints + + Execution: + c, continue Continue to next breakpoint + s, step Step into (enter functions) + n, next Step over (skip function internals) + o, out Step out of current function + + Inspection: + p, print Evaluate and print expression + l, locals Show local variables + st, stack Show call stack + where Show current location + list [line] Show source code around line + + Watches: + w, watch Add watch expression + unwatch Remove watch by ID + watches List all watches + + Other: + h, help, ? Show this help + q, quit, exit End debug session +"# + .to_string() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_breakpoint_set_and_remove() { + let mut state = DebugState::new(); + + assert!(state.set_breakpoint(10)); + assert!(state.has_breakpoint(10)); + assert!(!state.has_breakpoint(11)); + + // Setting same breakpoint again returns false + assert!(!state.set_breakpoint(10)); + + assert!(state.remove_breakpoint(10)); + assert!(!state.has_breakpoint(10)); + + // Removing non-existent breakpoint returns false + assert!(!state.remove_breakpoint(10)); + } + + #[test] + fn test_breakpoint_clear() { + let mut state = DebugState::new(); + state.set_breakpoint(10); + state.set_breakpoint(20); + state.set_breakpoint(30); + + assert_eq!(state.breakpoint_count(), 3); + state.clear_breakpoints(); + assert_eq!(state.breakpoint_count(), 0); + } + + #[test] + fn test_step_mode() { + let mut state = DebugState::new(); + + assert_eq!(state.step_mode(), StepMode::None); + + state.set_step_mode(StepMode::StepInto); + assert_eq!(state.step_mode(), StepMode::StepInto); + + state.set_step_mode(StepMode::Continue); + assert_eq!(state.step_mode(), StepMode::Continue); + } + + #[test] + fn test_call_stack() { + let mut state = DebugState::new(); + + assert_eq!(state.stack_depth(), 0); + assert!(state.current_frame().is_none()); + + state.push_frame(CallFrame::new("main".to_string(), 1)); + assert_eq!(state.stack_depth(), 1); + + state.push_frame(CallFrame::new("helper".to_string(), 10)); + assert_eq!(state.stack_depth(), 2); + assert_eq!(state.current_frame().unwrap().function_name, "helper"); + + state.pop_frame(); + assert_eq!(state.stack_depth(), 1); + assert_eq!(state.current_frame().unwrap().function_name, "main"); + } + + #[test] + fn test_watch_expressions() { + let mut state = DebugState::new(); + + let id1 = state.add_watch("x".to_string()); + let id2 = state.add_watch("y + z".to_string()); + + assert_eq!(state.watches().len(), 2); + assert_eq!(state.watches()[0].id, id1); + assert_eq!(state.watches()[1].id, id2); + + assert!(state.remove_watch(id1)); + assert_eq!(state.watches().len(), 1); + assert!(!state.remove_watch(id1)); // Already removed + } + + #[test] + fn test_pause_and_resume() { + let mut state = DebugState::new(); + + assert!(!state.is_paused()); + + state.pause(PauseReason::Breakpoint(10)); + assert!(state.is_paused()); + assert!(matches!( + state.pause_reason(), + Some(PauseReason::Breakpoint(10)) + )); + + state.resume(); + assert!(!state.is_paused()); + assert!(state.pause_reason().is_none()); + } + + #[test] + fn test_should_pause_on_breakpoint() { + let mut state = DebugState::new(); + state.set_breakpoint(10); + + assert!(state.should_pause(5).is_none()); + assert!(matches!( + state.should_pause(10), + Some(PauseReason::Breakpoint(10)) + )); + } + + #[test] + fn test_should_pause_on_step() { + let mut state = DebugState::new(); + state.set_step_mode(StepMode::StepInto); + + // First check should trigger pause + assert!(matches!(state.should_pause(5), Some(PauseReason::Step))); + + // Subsequent check should not (break_on_next was consumed) + assert!(state.should_pause(6).is_none()); + } + + #[test] + fn test_source_context() { + let source = "line 1\nline 2\nline 3\nline 4\nline 5"; + let mut state = DebugState::with_source(source); + + state.set_location(3, 1); + let context = state.format_source_context(1); + + assert!(context.contains("line 2")); + assert!(context.contains("line 3")); + assert!(context.contains("line 4")); + assert!(context.contains("→")); // Current line marker + } + + #[test] + fn test_command_parsing() { + assert_eq!( + DebugCommand::parse("break 10").unwrap(), + DebugCommand::Break(10) + ); + assert_eq!( + DebugCommand::parse("b 20").unwrap(), + DebugCommand::Break(20) + ); + assert_eq!( + DebugCommand::parse("delete 10").unwrap(), + DebugCommand::Delete(10) + ); + assert_eq!( + DebugCommand::parse("d all").unwrap(), + DebugCommand::DeleteAll + ); + assert_eq!( + DebugCommand::parse("continue").unwrap(), + DebugCommand::Continue + ); + assert_eq!(DebugCommand::parse("c").unwrap(), DebugCommand::Continue); + assert_eq!(DebugCommand::parse("step").unwrap(), DebugCommand::StepInto); + assert_eq!(DebugCommand::parse("s").unwrap(), DebugCommand::StepInto); + assert_eq!(DebugCommand::parse("next").unwrap(), DebugCommand::StepOver); + assert_eq!(DebugCommand::parse("n").unwrap(), DebugCommand::StepOver); + assert_eq!(DebugCommand::parse("out").unwrap(), DebugCommand::StepOut); + assert_eq!(DebugCommand::parse("o").unwrap(), DebugCommand::StepOut); + assert_eq!( + DebugCommand::parse("print x").unwrap(), + DebugCommand::Print("x".to_string()) + ); + assert_eq!( + DebugCommand::parse("p myVar").unwrap(), + DebugCommand::Print("myVar".to_string()) + ); + assert_eq!(DebugCommand::parse("locals").unwrap(), DebugCommand::Locals); + assert_eq!(DebugCommand::parse("l").unwrap(), DebugCommand::Locals); + assert_eq!(DebugCommand::parse("stack").unwrap(), DebugCommand::Stack); + assert_eq!(DebugCommand::parse("st").unwrap(), DebugCommand::Stack); + assert_eq!( + DebugCommand::parse("watch counter").unwrap(), + DebugCommand::Watch("counter".to_string()) + ); + assert_eq!(DebugCommand::parse("help").unwrap(), DebugCommand::Help); + assert_eq!(DebugCommand::parse("quit").unwrap(), DebugCommand::Quit); + } + + #[test] + fn test_command_parsing_errors() { + assert!(DebugCommand::parse("break").is_err()); + assert!(DebugCommand::parse("break abc").is_err()); + assert!(DebugCommand::parse("delete").is_err()); + assert!(DebugCommand::parse("print").is_err()); + assert!(DebugCommand::parse("unknown").is_err()); + assert!(DebugCommand::parse("").is_err()); + } + + #[test] + fn test_call_frame_display() { + let frame = CallFrame::new("myFunction".to_string(), 42); + assert_eq!(format!("{}", frame), "myFunction at line 42"); + + let native = CallFrame::native("println".to_string()); + assert_eq!(format!("{}", native), "println (native)"); + } + + #[test] + fn test_pause_reason_display() { + assert_eq!( + format!("{}", PauseReason::Breakpoint(10)), + "Breakpoint at line 10" + ); + assert_eq!(format!("{}", PauseReason::Step), "Step completed"); + assert_eq!(format!("{}", PauseReason::UserRequest), "Paused by user"); + } +} diff --git a/hypnoscript-compiler/src/interpreter.rs b/hypnoscript-compiler/src/interpreter.rs index 4576427..3b0c7cf 100644 --- a/hypnoscript-compiler/src/interpreter.rs +++ b/hypnoscript-compiler/src/interpreter.rs @@ -41,6 +41,10 @@ fn localized(en: &str, de: &str) -> String { format!("{} (DE: {})", en, de) } +/// Type alias for debug pause callback to reduce type complexity. +type DebugPauseCallback = + Box crate::debug::StepMode>; + #[derive(Clone, Copy, Debug)] enum ScopeLayer { Local, @@ -290,7 +294,10 @@ impl SessionDefinition { "Duplicate session field '{}' in session '{}'", field.name, self.name ), - &format!("Doppeltes Feld '{}' in Session '{}'", field.name, self.name), + &format!( + "Duplicate field '{}' in session '{}'", + field.name, self.name + ), ))); } self.field_order.push(field.name.clone()); @@ -311,7 +318,10 @@ impl SessionDefinition { "Duplicate session field '{}' in session '{}'", field.name, self.name ), - &format!("Doppeltes Feld '{}' in Session '{}'", field.name, self.name), + &format!( + "Duplicate field '{}' in session '{}'", + field.name, self.name + ), ))); } self.static_field_order.push(field.name.clone()); @@ -331,10 +341,7 @@ impl SessionDefinition { if self.constructor.is_some() { return Err(InterpreterError::Runtime(localized( &format!("Multiple constructors declared in session '{}'", self.name), - &format!( - "Mehrere Konstruktoren in Session '{}' deklariert", - self.name - ), + &format!("Multiple constructors declared in session '{}'", self.name), ))); } self.constructor = Some(method); @@ -349,7 +356,7 @@ impl SessionDefinition { method.name, self.name ), &format!( - "Doppelte statische Methode '{}' in Session '{}'", + "Duplicate static method '{}' in session '{}'", method.name, self.name ), ))); @@ -363,7 +370,7 @@ impl SessionDefinition { method.name, self.name ), &format!( - "Doppelte Methode '{}' in Session '{}'", + "Duplicate method '{}' in session '{}'", method.name, self.name ), ))); @@ -402,7 +409,7 @@ impl SessionDefinition { name, self.name ), &format!( - "Statisches Feld '{}' nicht in Session '{}' gefunden", + "Static field '{}' not found on session '{}'", name, self.name ), ))), @@ -761,6 +768,13 @@ pub struct Interpreter { /// Optional channel registry for inter-task communication pub channel_registry: Option>, + + /// Optional debug state for step-through debugging + pub debug_state: Option, + + /// Callback invoked when debugger pauses (for REPL integration) + #[allow(dead_code)] + debug_pause_callback: Option, } impl Default for Interpreter { @@ -781,6 +795,8 @@ impl Interpreter { tranceify_types: HashMap::new(), async_runtime: None, channel_registry: None, + debug_state: None, + debug_pause_callback: None, } } @@ -801,6 +817,8 @@ impl Interpreter { tranceify_types: HashMap::new(), async_runtime: Some(std::sync::Arc::new(runtime)), channel_registry: Some(std::sync::Arc::new(registry)), + debug_state: None, + debug_pause_callback: None, }) } @@ -818,6 +836,211 @@ impl Interpreter { Ok(()) } + // === Debug Mode Methods === + + /// Enables debug mode with the given source code. + /// + /// When debug mode is enabled, the interpreter will check for breakpoints + /// and step conditions before each statement execution. + /// + /// # Arguments + /// * `source` - The source code (for display in debugger) + pub fn enable_debug_mode(&mut self, source: &str) { + self.debug_state = Some(crate::debug::DebugState::with_source(source)); + } + + /// Enables debug mode without source code. + pub fn enable_debug_mode_no_source(&mut self) { + self.debug_state = Some(crate::debug::DebugState::new()); + } + + /// Disables debug mode. + pub fn disable_debug_mode(&mut self) { + self.debug_state = None; + } + + /// Returns whether debug mode is enabled. + pub fn is_debug_mode(&self) -> bool { + self.debug_state.is_some() + } + + /// Sets a breakpoint at the given line number. + /// + /// # Arguments + /// * `line` - Line number (1-indexed) + /// + /// # Returns + /// `true` if breakpoint was newly added, `false` if already existed or debug mode not enabled + pub fn set_breakpoint(&mut self, line: usize) -> bool { + if let Some(ref mut state) = self.debug_state { + state.set_breakpoint(line) + } else { + false + } + } + + /// Removes a breakpoint at the given line number. + pub fn remove_breakpoint(&mut self, line: usize) -> bool { + if let Some(ref mut state) = self.debug_state { + state.remove_breakpoint(line) + } else { + false + } + } + + /// Checks if a breakpoint exists at the given line. + pub fn has_breakpoint(&self, line: usize) -> bool { + self.debug_state + .as_ref() + .map(|s| s.has_breakpoint(line)) + .unwrap_or(false) + } + + /// Returns all breakpoints. + pub fn breakpoints(&self) -> Vec { + self.debug_state + .as_ref() + .map(|s| s.breakpoints().iter().copied().collect()) + .unwrap_or_default() + } + + /// Clears all breakpoints. + pub fn clear_breakpoints(&mut self) { + if let Some(ref mut state) = self.debug_state { + state.clear_breakpoints(); + } + } + + /// Sets the step mode for debugging. + pub fn set_step_mode(&mut self, mode: crate::debug::StepMode) { + if let Some(ref mut state) = self.debug_state { + state.set_step_mode(mode); + } + } + + /// Gets the current step mode. + pub fn step_mode(&self) -> crate::debug::StepMode { + self.debug_state + .as_ref() + .map(|s| s.step_mode()) + .unwrap_or(crate::debug::StepMode::None) + } + + /// Adds a watch expression. + /// + /// # Returns + /// The ID of the new watch expression, or None if debug mode not enabled + pub fn add_watch(&mut self, expression: String) -> Option { + self.debug_state.as_mut().map(|s| s.add_watch(expression)) + } + + /// Removes a watch expression by ID. + pub fn remove_watch(&mut self, id: usize) -> bool { + self.debug_state + .as_mut() + .map(|s| s.remove_watch(id)) + .unwrap_or(false) + } + + /// Returns the current call stack for debugging. + pub fn debug_call_stack(&self) -> Vec { + self.debug_state + .as_ref() + .map(|s| s.call_stack().to_vec()) + .unwrap_or_default() + } + + /// Returns local variables in the current scope. + pub fn debug_locals(&self) -> HashMap { + if let Some(scope) = self.locals.last() { + scope.clone() + } else { + HashMap::new() + } + } + + /// Returns global variables. + pub fn debug_globals(&self) -> HashMap { + self.globals.clone() + } + + /// Returns all visible variables (locals + globals). + pub fn debug_all_variables(&self) -> HashMap { + let mut vars = self.globals.clone(); + vars.extend(self.shared.clone()); + for scope in &self.locals { + vars.extend(scope.clone()); + } + vars + } + + /// Returns the current debug state summary. + pub fn debug_summary(&self) -> String { + self.debug_state + .as_ref() + .map(|s| s.summary()) + .unwrap_or_else(|| "Debug mode not enabled".to_string()) + } + + /// Formats the source context around the current line. + pub fn debug_source_context(&self, context_lines: usize) -> String { + self.debug_state + .as_ref() + .map(|s| s.format_source_context(context_lines)) + .unwrap_or_else(|| "(no source available)".to_string()) + } + + /// Checks if the debugger should pause before executing a statement. + /// Returns the pause reason if should pause, None otherwise. + #[allow(dead_code)] + fn check_debug_pause(&mut self, line: usize) -> Option { + if let Some(ref mut state) = self.debug_state { + state.should_pause(line) + } else { + None + } + } + + /// Handles a debug pause event. + /// This is called when a breakpoint is hit or step completes. + #[allow(dead_code)] + fn handle_debug_pause(&mut self, reason: crate::debug::PauseReason) { + if let Some(ref mut state) = self.debug_state { + state.pause(reason); + } + } + + /// Resumes execution after a pause. + pub fn debug_resume(&mut self) { + if let Some(ref mut state) = self.debug_state { + state.resume(); + } + } + + /// Pushes a debug call frame when entering a function. + #[allow(dead_code)] + fn debug_push_frame(&mut self, function_name: &str, line: usize) { + if let Some(ref mut state) = self.debug_state { + state.push_frame(crate::debug::CallFrame::new( + function_name.to_string(), + line, + )); + } + } + + /// Pops a debug call frame when exiting a function. + #[allow(dead_code)] + fn debug_pop_frame(&mut self) { + if let Some(ref mut state) = self.debug_state { + state.pop_frame(); + } + } + + /// Triggers a programmatic breakpoint from code. + pub fn trigger_breakpoint(&mut self) -> Option { + self.debug_state.as_mut().map(|s| s.trigger_breakpoint()) + } + pub fn execute_program(&mut self, program: AstNode) -> Result<(), InterpreterError> { if let AstNode::Program(statements) = program { for stmt in statements { @@ -1166,7 +1389,7 @@ impl Interpreter { } _ => Err(InterpreterError::Runtime(localized( "Invalid assignment target", - "Ungültiges Zuweisungsziel", + "Invalid assignment target", ))), }, @@ -1571,11 +1794,11 @@ impl Interpreter { Value::Session(session) => self.instantiate_session(session.clone(), args), Value::Null => Err(InterpreterError::Runtime(localized( "Cannot call null value", - "Null-Wert kann nicht aufgerufen werden", + "Cannot call null value", ))), _ => Err(InterpreterError::Runtime(localized( "Value is not callable", - "Wert ist nicht aufrufbar", + "Value is not callable", ))), } } @@ -1593,7 +1816,7 @@ impl Interpreter { args.len() ), &format!( - "Erwartet {} Argumente, erhalten {}", + "Expected {} arguments, received {}", function.parameters.len(), args.len() ), @@ -1695,7 +1918,7 @@ impl Interpreter { definition.name() ), &format!( - "Konstruktor in Session '{}' darf nicht statisch sein", + "Constructor in session '{}' cannot be static", definition.name() ), ))); @@ -1759,7 +1982,7 @@ impl Interpreter { args.len() ), &format!( - "Konstruktor der Session '{}' erwartet {} Argumente, erhalten {}", + "Constructor for session '{}' expects {} arguments, received {}", session.name(), constructor.parameters.len(), args.len() @@ -1780,7 +2003,7 @@ impl Interpreter { session.name() ), &format!( - "Session '{}' definiert keinen Konstruktor, dennoch wurden Argumente übergeben", + "Session '{}' does not define a constructor but arguments were provided", session.name() ), ))); @@ -1902,7 +2125,7 @@ impl Interpreter { property ), &format!( - "Session-Instanz von '{}' besitzt kein Mitglied '{}'", + "Session instance of '{}' has no member '{}'", definition.name(), property ), @@ -1941,7 +2164,7 @@ impl Interpreter { property ), &format!( - "Session '{}' besitzt kein statisches Mitglied '{}'", + "Session '{}' has no static member '{}'", session_rc.name(), property ), @@ -1960,10 +2183,7 @@ impl Interpreter { } other => Err(InterpreterError::Runtime(localized( &format!("Cannot access member '{}' on value '{}'", property, other), - &format!( - "Mitglied '{}' kann auf Wert '{}' nicht zugegriffen werden", - property, other - ), + &format!("Cannot access member '{}' on value '{}'", property, other), ))), } } @@ -1997,7 +2217,7 @@ impl Interpreter { { return Err(InterpreterError::Runtime(localized( &format!("Cannot assign to method '{}'", property), - &format!("Zuweisung zur Methode '{}' nicht möglich", property), + &format!("Cannot assign to method '{}'", property), ))); } @@ -2009,7 +2229,7 @@ impl Interpreter { definition.name() ), &format!( - "Statisches Feld '{}' muss über die Session '{}' gesetzt werden", + "Assign static field '{}' through session '{}', not an instance", property, definition.name() ), @@ -2023,7 +2243,7 @@ impl Interpreter { property ), &format!( - "Session-Instanz von '{}' besitzt kein Feld '{}'", + "Session instance of '{}' has no field '{}'", definition.name(), property ), @@ -2044,10 +2264,7 @@ impl Interpreter { if session_rc.get_static_method_definition(property).is_some() { return Err(InterpreterError::Runtime(localized( &format!("Cannot assign to static method '{}'", property), - &format!( - "Zuweisung zu statischer Methode '{}' nicht möglich", - property - ), + &format!("Cannot assign to static method '{}'", property), ))); } @@ -2058,7 +2275,7 @@ impl Interpreter { property ), &format!( - "Session '{}' besitzt kein statisches Feld '{}'", + "Session '{}' has no static field '{}'", session_rc.name(), property ), @@ -2066,7 +2283,7 @@ impl Interpreter { } _ => Err(InterpreterError::Runtime(localized( "Assignment target is not a session member", - "Zuweisungsziel ist kein Session-Mitglied", + "Assignment target is not a session member", ))), } } @@ -2085,7 +2302,7 @@ impl Interpreter { member_kind, member_name, session_name ), &format!( - "Zugriff auf privates {} '{}' der Session '{}' verweigert", + "Access denied to private {} '{}' of session '{}'", member_kind, member_name, session_name ), ))); @@ -2998,10 +3215,7 @@ impl Interpreter { if is_const { return Err(InterpreterError::Runtime(localized( &format!("Cannot reassign constant variable '{}'", name), - &format!( - "Konstante Variable '{}' kann nicht neu zugewiesen werden", - name - ), + &format!("Cannot reassign constant variable '{}'", name), ))); } Ok(()) @@ -3416,4 +3630,172 @@ Focus { Err(InterpreterError::UndefinedVariable(_)) )); } + + // === Debug Mode Tests === + + #[test] + fn test_enable_debug_mode() { + let source = "Focus { induce x = 42; } Relax"; + let mut interpreter = Interpreter::new(); + + assert!(!interpreter.is_debug_mode()); + interpreter.enable_debug_mode(source); + assert!(interpreter.is_debug_mode()); + + interpreter.disable_debug_mode(); + assert!(!interpreter.is_debug_mode()); + } + + #[test] + fn test_breakpoint_management() { + let source = "Focus { induce x = 42; } Relax"; + let mut interpreter = Interpreter::new(); + interpreter.enable_debug_mode(source); + + // Set breakpoints + assert!(interpreter.set_breakpoint(10)); + assert!(interpreter.set_breakpoint(20)); + + // Check breakpoints + assert!(interpreter.has_breakpoint(10)); + assert!(interpreter.has_breakpoint(20)); + assert!(!interpreter.has_breakpoint(15)); + + // Get all breakpoints + let breakpoints = interpreter.breakpoints(); + assert_eq!(breakpoints.len(), 2); + assert!(breakpoints.contains(&10)); + assert!(breakpoints.contains(&20)); + + // Remove breakpoint + assert!(interpreter.remove_breakpoint(10)); + assert!(!interpreter.has_breakpoint(10)); + assert!(interpreter.has_breakpoint(20)); + + // Clear all breakpoints + interpreter.clear_breakpoints(); + assert!(interpreter.breakpoints().is_empty()); + } + + #[test] + fn test_step_mode() { + use crate::debug::StepMode; + + let source = "Focus { induce x = 42; } Relax"; + let mut interpreter = Interpreter::new(); + interpreter.enable_debug_mode(source); + + assert_eq!(interpreter.step_mode(), StepMode::None); + + interpreter.set_step_mode(StepMode::StepInto); + assert_eq!(interpreter.step_mode(), StepMode::StepInto); + + interpreter.set_step_mode(StepMode::StepOver); + assert_eq!(interpreter.step_mode(), StepMode::StepOver); + + interpreter.set_step_mode(StepMode::Continue); + assert_eq!(interpreter.step_mode(), StepMode::Continue); + } + + #[test] + fn test_watch_expressions() { + let source = "Focus { induce x = 42; } Relax"; + let mut interpreter = Interpreter::new(); + interpreter.enable_debug_mode(source); + + // Add watches + let id1 = interpreter.add_watch("x".to_string()); + let id2 = interpreter.add_watch("y + z".to_string()); + + assert!(id1.is_some()); + assert!(id2.is_some()); + + // Remove watch + assert!(interpreter.remove_watch(id1.unwrap())); + assert!(!interpreter.remove_watch(id1.unwrap())); // Already removed + } + + #[test] + fn test_debug_variable_inspection() { + let source = r#" +Focus { + induce x: number = 42; + induce y: string = "hello"; +} Relax +"#; + let mut lexer = Lexer::new(source); + let tokens = lexer.lex().unwrap(); + let mut parser = Parser::new(tokens); + let ast = parser.parse_program().unwrap(); + + let mut interpreter = Interpreter::new(); + interpreter.enable_debug_mode(source); + interpreter.execute_program(ast).unwrap(); + + // Check globals + let globals = interpreter.debug_globals(); + assert!(globals.contains_key("x")); + assert!(globals.contains_key("y")); + assert_eq!(globals.get("x").unwrap(), &Value::Number(42.0)); + assert_eq!( + globals.get("y").unwrap(), + &Value::String("hello".to_string()) + ); + } + + #[test] + fn test_debug_summary() { + let source = "Focus { induce x = 42; } Relax"; + let mut interpreter = Interpreter::new(); + + // Without debug mode + let summary = interpreter.debug_summary(); + assert!(summary.contains("not enabled")); + + // With debug mode + interpreter.enable_debug_mode(source); + interpreter.set_breakpoint(10); + let summary = interpreter.debug_summary(); + assert!(summary.contains("breakpoints")); + assert!(summary.contains("10")); + } + + #[test] + fn test_debug_mode_no_source() { + let mut interpreter = Interpreter::new(); + interpreter.enable_debug_mode_no_source(); + + assert!(interpreter.is_debug_mode()); + assert!(interpreter.set_breakpoint(5)); + assert!(interpreter.has_breakpoint(5)); + } + + #[test] + fn test_debug_with_execution() { + let source = r#" +Focus { + induce x: number = 10; + induce y: number = 20; + induce sum: number = x + y; +} Relax +"#; + let mut lexer = Lexer::new(source); + let tokens = lexer.lex().unwrap(); + let mut parser = Parser::new(tokens); + let ast = parser.parse_program().unwrap(); + + let mut interpreter = Interpreter::new(); + interpreter.enable_debug_mode(source); + interpreter.set_breakpoint(3); // Set breakpoint at line 3 + + // Execute should still work + let result = interpreter.execute_program(ast); + assert!(result.is_ok()); + + // Verify execution completed correctly + assert_eq!( + interpreter.get_variable("sum").unwrap(), + Value::Number(30.0) + ); + } } diff --git a/hypnoscript-compiler/src/lib.rs b/hypnoscript-compiler/src/lib.rs index d3ef9e9..921c4de 100644 --- a/hypnoscript-compiler/src/lib.rs +++ b/hypnoscript-compiler/src/lib.rs @@ -137,6 +137,7 @@ pub mod async_builtins; pub mod async_promise; pub mod async_runtime; pub mod channel_system; +pub mod debug; pub mod interpreter; pub mod native_codegen; pub mod optimizer; @@ -155,6 +156,10 @@ pub use async_runtime::{ pub use channel_system::{ BroadcastChannel, ChannelMessage, ChannelRegistry, ChannelType, MpscChannel, WatchChannel, }; +pub use debug::{ + CallFrame, DebugCommand, DebugError, DebugResult, DebugState, PauseReason, StepMode, + WatchExpression, format_help as debug_help, +}; pub use interpreter::{Interpreter, InterpreterError, Value}; pub use native_codegen::{ NativeCodeGenerator, NativeCodegenError, OptimizationLevel, TargetPlatform, diff --git a/hypnoscript-compiler/src/native_codegen.rs b/hypnoscript-compiler/src/native_codegen.rs index 16ca029..a95ce01 100644 --- a/hypnoscript-compiler/src/native_codegen.rs +++ b/hypnoscript-compiler/src/native_codegen.rs @@ -1,24 +1,24 @@ -//! Native Code Generator für HypnoScript +//! Native code generator for HypnoScript //! -//! Dieses Modul generiert plattformspezifischen nativen Code für: +//! This module generates platform-specific native code for: //! - Windows (x86_64, ARM64) //! - macOS (x86_64, ARM64 / Apple Silicon) //! - Linux (x86_64, ARM64, RISC-V) //! -//! ## Architektur +//! ## Architecture //! -//! Der Native Code Generator verwendet Cranelift als Backend für die Kompilierung. -//! Cranelift ist ein schneller, sicherer Code-Generator, der optimierten, -//! plattformspezifischen Code mit minimaler Runtime-Abhängigkeit erzeugt. +//! The native code generator uses Cranelift as the backend for compilation. +//! Cranelift is a fast, safe code generator that produces optimized, +//! platform-specific code with minimal runtime dependencies. //! -//! ## Vorteile von Cranelift gegenüber LLVM +//! ## Advantages of Cranelift over LLVM //! -//! - **Schnellere Kompilierung**: Cranelift ist deutlich schneller als LLVM -//! - **Einfachere Integration**: Reine Rust-Implementierung, keine C++-Abhängigkeiten -//! - **Kleinere Binary-Größe**: Geringerer Overhead -//! - **Sicherheit**: Memory-safe durch Rust +//! - **Faster compilation**: Cranelift is significantly faster than LLVM +//! - **Simpler integration**: Pure Rust implementation, no C++ dependencies +//! - **Smaller binary size**: Lower overhead +//! - **Security**: Memory-safe via Rust //! -//! ## Verwendung +//! ## Usage //! //! ```rust //! use hypnoscript_compiler::{NativeCodeGenerator, TargetPlatform, OptimizationLevel}; @@ -40,29 +40,29 @@ use std::path::{Path, PathBuf}; use target_lexicon::Triple; use thiserror::Error; -/// Fehlertypen für die native Code-Generierung +/// Error types for native code generation #[derive(Error, Debug)] pub enum NativeCodegenError { - #[error("Plattform nicht unterstützt: {0}")] + #[error("Platform not supported: {0}")] UnsupportedPlatform(String), - #[error("Cranelift-Initialisierung fehlgeschlagen: {0}")] + #[error("Cranelift initialization failed: {0}")] LlvmInitializationError(String), - #[error("Code-Generierung fehlgeschlagen: {0}")] + #[error("Code generation failed: {0}")] CodeGenerationError(String), - #[error("Optimierung fehlgeschlagen: {0}")] + #[error("Optimization failed: {0}")] OptimizationError(String), - #[error("Linking fehlgeschlagen: {0}")] + #[error("Linking failed: {0}")] LinkingError(String), - #[error("I/O-Fehler: {0}")] + #[error("I/O error: {0}")] IoError(#[from] std::io::Error), } -/// Zielplattformen für native Kompilierung +/// Target platforms for native compilation #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TargetPlatform { /// Windows x86_64 @@ -82,7 +82,7 @@ pub enum TargetPlatform { } impl TargetPlatform { - /// Gibt den LLVM-Target-Triple zurück + /// Returns the LLVM target triple pub fn llvm_triple(&self) -> &'static str { match self { Self::WindowsX64 => "x86_64-pc-windows-msvc", @@ -95,7 +95,7 @@ impl TargetPlatform { } } - /// Erkennt die aktuelle Plattform zur Build-Zeit + /// Detects the current platform at build time pub fn current() -> Self { #[cfg(all(target_os = "windows", target_arch = "x86_64"))] return Self::WindowsX64; @@ -120,23 +120,23 @@ impl TargetPlatform { } } -/// Optimierungsstufen für die Code-Generierung +/// Optimization levels for code generation #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum OptimizationLevel { - /// Keine Optimierung (Debug-Build) + /// No optimization (debug build) None, - /// Moderate Optimierung (schnelle Kompilierung) + /// Moderate optimization (fast compilation) Less, - /// Standard-Optimierung (Balance) + /// Default optimization (balanced) Default, - /// Aggressive Optimierung (langsame Kompilierung, schneller Code) + /// Aggressive optimization (slower compilation, faster code) Aggressive, - /// Maximale Optimierung für Releases + /// Maximum optimization for releases Release, } impl OptimizationLevel { - /// Konvertiert zu Cranelift-Optimierungslevel + /// Converts to Cranelift optimization level pub fn to_cranelift_level(&self) -> &'static str { match self { Self::None => "none", @@ -147,7 +147,7 @@ impl OptimizationLevel { } } - /// Konvertiert zu LLVM-Optimierungslevel (0-3) + /// Converts to LLVM optimization level (0-3) pub fn to_llvm_level(&self) -> u32 { match self { Self::None => 0, @@ -158,25 +158,23 @@ impl OptimizationLevel { } } -/// Native Code Generator +/// Native code generator /// -/// Generiert plattformspezifischen nativen Maschinencode aus HypnoScript AST. -/// Verwendet Cranelift als Backend für optimierte Binaries. +/// Generates platform-specific native machine code from the HypnoScript AST. +/// Uses Cranelift as the backend for optimized binaries. pub struct NativeCodeGenerator { - /// Zielplattform + /// Target platform target_platform: TargetPlatform, - /// Optimierungslevel + /// Optimization level optimization_level: OptimizationLevel, - /// Ausgabepfad für die Binary + /// Output path for the binary output_path: Option, - /// Variablen-Mapping (Name -> Cranelift Variable) + /// Variable mapping (name -> Cranelift variable) variable_map: HashMap, - /// Funktions-Mapping + /// Function mapping function_map: HashMap, - /// Debug-Informationen generieren + /// Generate debug information debug_info: bool, - /// Nächste Variable-ID - next_var_id: usize, } impl Default for NativeCodeGenerator { @@ -186,9 +184,9 @@ impl Default for NativeCodeGenerator { } impl NativeCodeGenerator { - /// Erstellt einen neuen Native Code Generator + /// Creates a new native code generator /// - /// # Beispiele + /// # Examples /// /// ``` /// use hypnoscript_compiler::NativeCodeGenerator; @@ -203,68 +201,66 @@ impl NativeCodeGenerator { variable_map: HashMap::new(), function_map: HashMap::new(), debug_info: false, - next_var_id: 0, } } - /// Setzt die Zielplattform + /// Sets the target platform /// - /// # Argumente + /// # Arguments /// - /// * `platform` - Die gewünschte Zielplattform + /// * `platform` - The desired target platform pub fn set_target_platform(&mut self, platform: TargetPlatform) { self.target_platform = platform; } - /// Setzt das Optimierungslevel + /// Sets the optimization level /// - /// # Argumente + /// # Arguments /// - /// * `level` - Das gewünschte Optimierungslevel + /// * `level` - The desired optimization level pub fn set_optimization_level(&mut self, level: OptimizationLevel) { self.optimization_level = level; } - /// Setzt den Ausgabepfad + /// Sets the output path /// - /// # Argumente + /// # Arguments /// - /// * `path` - Der Pfad für die generierte Binary + /// * `path` - The path for the generated binary pub fn set_output_path(&mut self, path: PathBuf) { self.output_path = Some(path); } - /// Aktiviert/Deaktiviert Debug-Informationen + /// Enables/disables debug information /// - /// # Argumente + /// # Arguments /// - /// * `enabled` - true für Debug-Infos, false sonst + /// * `enabled` - true for debug info, false otherwise pub fn set_debug_info(&mut self, enabled: bool) { self.debug_info = enabled; } - /// Generiert nativen Code aus dem AST + /// Generates native code from the AST /// - /// # Argumente + /// # Arguments /// - /// * `program` - Der HypnoScript AST + /// * `program` - The HypnoScript AST /// - /// # Rückgabe + /// # Returns /// - /// Pfad zur generierten Binary + /// Path to the generated binary /// - /// # Fehler + /// # Errors /// - /// Gibt einen `NativeCodegenError` zurück, wenn die Code-Generierung fehlschlägt + /// Returns a `NativeCodegenError` when code generation fails pub fn generate(&mut self, program: &AstNode) -> Result { self.variable_map.clear(); self.function_map.clear(); - self.next_var_id = 0; - // Bestimme das Target-Triple (wird in Zukunft verwendet) + // Determine the target triple (will be used in the future) let _triple = self.get_target_triple(); - // Erstelle ObjectModule für die Object-Datei-Generierung + // Create ObjectModule for object file generation let mut flag_builder = settings::builder(); flag_builder .set("opt_level", self.optimization_level.to_cranelift_level()) @@ -285,16 +281,16 @@ impl NativeCodeGenerator { let mut module = ObjectModule::new(obj_builder); - // Erstelle die main-Funktion + // Create the main function self.generate_main_function(&mut module, program)?; - // Finalisiere und schreibe Object-Datei + // Finalize and write object file let object_product = module.finish(); let object_bytes = object_product .emit() .map_err(|e| NativeCodegenError::CodeGenerationError(e.to_string()))?; - // Bestimme Ausgabepfad für Object-Datei + // Determine output path for object file let obj_extension = if cfg!(target_os = "windows") { "obj" } else { @@ -302,10 +298,10 @@ impl NativeCodeGenerator { }; let obj_path = PathBuf::from(format!("hypnoscript_program.{}", obj_extension)); - // Schreibe Object-Datei + // Write object file std::fs::write(&obj_path, object_bytes)?; - // Bestimme finalen Ausgabepfad für ausführbare Datei + // Determine final output path for executable let exe_path = self.output_path.clone().unwrap_or_else(|| { let extension = if cfg!(target_os = "windows") { "exe" @@ -319,20 +315,20 @@ impl NativeCodeGenerator { } }); - // Linke die Object-Datei zu einer ausführbaren Datei + // Link the object file to an executable self.link_object_file(&obj_path, &exe_path)?; - // Cleanup: Entferne Object-Datei + // Cleanup: remove object file let _ = std::fs::remove_file(&obj_path); Ok(exe_path) } - /// Linkt eine Object-Datei zu einer ausführbaren Datei + /// Links an object file to an executable fn link_object_file(&self, obj_path: &Path, exe_path: &Path) -> Result<(), NativeCodegenError> { #[cfg(target_os = "windows")] { - // Versuche verschiedene Windows-Linker + // Try different Windows linkers let linkers = vec![ ( "link.exe", @@ -381,17 +377,17 @@ impl NativeCodeGenerator { } Err(NativeCodegenError::LinkingError( - "Kein geeigneter Linker gefunden. Bitte installieren Sie:\n\ - - Visual Studio Build Tools (für link.exe)\n\ - - GCC/MinGW (für gcc)\n\ - - LLVM (für lld-link/clang)" + "No suitable linker found. Please install:\n\ + - Visual Studio Build Tools (for link.exe)\n\ + - GCC/MinGW (for gcc)\n\ + - LLVM (for lld-link/clang)" .to_string(), )) } #[cfg(not(target_os = "windows"))] { - // Unix-basierte Systeme (Linux, macOS) + // Unix-based systems (Linux, macOS) let exe_path_string = exe_path.to_string_lossy().into_owned(); let obj_path_string = obj_path.to_string_lossy().into_owned(); @@ -408,7 +404,7 @@ impl NativeCodeGenerator { if let Ok(output) = std::process::Command::new(linker).args(&args).output() && output.status.success() { - // Mache die Datei ausführbar auf Unix + // Make the file executable on Unix #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; @@ -421,13 +417,12 @@ impl NativeCodeGenerator { } Err(NativeCodegenError::LinkingError( - "Kein geeigneter Linker gefunden. Bitte installieren Sie gcc oder clang." - .to_string(), + "No suitable linker found. Please install gcc or clang.".to_string(), )) } } - /// Konvertiert Cranelift-Triple aus TargetPlatform + /// Converts Cranelift triple from TargetPlatform fn get_target_triple(&self) -> Triple { self.target_platform .llvm_triple() @@ -435,13 +430,13 @@ impl NativeCodeGenerator { .unwrap_or_else(|_| Triple::host()) } - /// Generiert die main-Funktion + /// Generates the main function fn generate_main_function( &mut self, module: &mut ObjectModule, program: &AstNode, ) -> Result<(), NativeCodegenError> { - // Erstelle Funktions-Signatur: main() -> i32 + // Create function signature: main() -> i32 let mut sig = module.make_signature(); sig.returns.push(AbiParam::new(types::I32)); @@ -452,16 +447,16 @@ impl NativeCodeGenerator { let mut ctx = module.make_context(); ctx.func.signature = sig; - // Erstelle Function Builder + // Create function builder let mut builder_context = FunctionBuilderContext::new(); let mut builder = FunctionBuilder::new(&mut ctx.func, &mut builder_context); - // Erstelle Entry-Block + // Create entry block let entry_block = builder.create_block(); builder.switch_to_block(entry_block); builder.seal_block(entry_block); - // Generiere Code für das Programm + // Generate code for the program if let AstNode::Program(statements) = program { for stmt in statements { self.generate_statement(&mut builder, stmt)?; @@ -472,10 +467,10 @@ impl NativeCodeGenerator { let zero = builder.ins().iconst(types::I32, 0); builder.ins().return_(&[zero]); - // Finalisiere Funktion + // Finalize function builder.finalize(); - // Definiere Funktion im Modul + // Define function in module module .define_function(func_id, &mut ctx) .map_err(|e| NativeCodegenError::CodeGenerationError(e.to_string()))?; @@ -485,7 +480,7 @@ impl NativeCodeGenerator { Ok(()) } - /// Generiert Code für ein Statement + /// Generates code for a statement fn generate_statement( &mut self, builder: &mut FunctionBuilder, @@ -495,14 +490,11 @@ impl NativeCodeGenerator { AstNode::VariableDeclaration { name, initializer, .. } => { - // Erstelle Variable - let var = Variable::new(self.next_var_id); - self.next_var_id += 1; - - builder.declare_var(var, types::F64); + // Create variable - declare_var returns the Variable in newer cranelift + let var = builder.declare_var(types::F64); self.variable_map.insert(name.clone(), var); - // Initialisiere Variable + // Initialize variable if let Some(init) = initializer { let value = self.generate_expression(builder, init)?; builder.def_var(var, value); @@ -522,7 +514,7 @@ impl NativeCodeGenerator { } AstNode::ExpressionStatement(expr) => { - // Evaluiere Expression (Ergebnis wird verworfen) + // Evaluate expression (result is discarded) let _value = self.generate_expression(builder, expr)?; } @@ -535,15 +527,15 @@ impl NativeCodeGenerator { } _ => { - // Nicht unterstützte Statements ignorieren - // TODO: Erweitern für vollständige Sprachunterstützung + // Ignore unsupported statements + // TODO: Extend for full language support } } Ok(()) } - /// Generiert Code für einen Expression + /// Generates code for an expression fn generate_expression( &mut self, builder: &mut FunctionBuilder, @@ -579,14 +571,14 @@ impl NativeCodeGenerator { "*" => builder.ins().fmul(lhs, rhs), "/" => builder.ins().fdiv(lhs, rhs), "%" => { - // Modulo für floats: a - floor(a/b) * b + // Modulo for floats: a - floor(a/b) * b let div = builder.ins().fdiv(lhs, rhs); let floor = builder.ins().floor(div); let mul = builder.ins().fmul(floor, rhs); builder.ins().fsub(lhs, mul) } _ => { - // Unbekannter Operator -> Return 0 + // Unknown operator -> return 0 builder.ins().f64const(0.0) } }; @@ -600,7 +592,7 @@ impl NativeCodeGenerator { let result = match operator.as_str() { "-" => builder.ins().fneg(val), "!" => { - // Logische Negation (für Integers) + // Logical negation (for integers) builder.ins().bxor_imm(val, 1) } _ => val, @@ -610,16 +602,16 @@ impl NativeCodeGenerator { } _ => { - // Nicht unterstützte Expressions -> Return 0 + // Unsupported expressions -> return 0 Ok(builder.ins().f64const(0.0)) } } } - /// Gibt Informationen über die Zielplattform zurück + /// Returns information about the target platform pub fn target_info(&self) -> String { format!( - "Zielplattform: {}\nLLVM-Triple: {}\nOptimierung: {:?}", + "Target platform: {}\nLLVM triple: {}\nOptimization: {:?}", match self.target_platform { TargetPlatform::WindowsX64 => "Windows x86_64", TargetPlatform::WindowsArm64 => "Windows ARM64", @@ -732,7 +724,7 @@ Focus { let mut generator = NativeCodeGenerator::new(); generator.set_optimization_level(OptimizationLevel::None); - // Sollte ohne Fehler kompilieren + // Should compile without errors let result = generator.generate(&ast); assert!(result.is_ok(), "Compilation should succeed"); } @@ -742,9 +734,9 @@ Focus { let generator = NativeCodeGenerator::new(); let info = generator.target_info(); - // Sollte Informationen enthalten - assert!(info.contains("Zielplattform:")); - assert!(info.contains("LLVM-Triple:")); - assert!(info.contains("Optimierung:")); + // Should contain information + assert!(info.contains("Target platform:")); + assert!(info.contains("LLVM triple:")); + assert!(info.contains("Optimization:")); } } diff --git a/hypnoscript-compiler/src/optimizer.rs b/hypnoscript-compiler/src/optimizer.rs index 31cb970..9a62b9d 100644 --- a/hypnoscript-compiler/src/optimizer.rs +++ b/hypnoscript-compiler/src/optimizer.rs @@ -1,18 +1,18 @@ -//! Code-Optimierungs-Module für HypnoScript +//! Code optimization module for HypnoScript //! -//! Dieses Modul implementiert verschiedene Optimierungs-Pässe für den -//! HypnoScript-Compiler. Die Optimierungen verbessern die Performance -//! und reduzieren die Größe des generierten Codes. +//! This module implements various optimization passes for the +//! HypnoScript compiler. The optimizations improve performance +//! and reduce the size of the generated code. //! -//! ## Implementierte Optimierungen +//! ## Implemented optimizations //! -//! - **Constant Folding**: Berechnet konstante Ausdrücke zur Compile-Zeit -//! - **Dead Code Elimination**: Entfernt unerreichbaren Code -//! - **Common Subexpression Elimination**: Vermeidet redundante Berechnungen -//! - **Loop Invariant Code Motion**: Verschiebt invariante Berechnungen aus Schleifen -//! - **Inlining**: Fügt kleine Funktionen inline ein +//! - **Constant Folding**: Computes constant expressions at compile time +//! - **Dead Code Elimination**: Removes unreachable code +//! - **Common Subexpression Elimination**: Avoids redundant calculations +//! - **Loop Invariant Code Motion**: Moves invariant computations out of loops +//! - **Inlining**: Inlines small functions //! -//! ## Verwendung +//! ## Usage //! //! ```rust,no_run //! use hypnoscript_compiler::optimizer::Optimizer; @@ -28,32 +28,32 @@ use hypnoscript_lexer_parser::ast::AstNode; use std::collections::{HashMap, HashSet}; use thiserror::Error; -/// Fehlertypen für die Optimierung +/// Error types for optimization #[derive(Error, Debug)] pub enum OptimizationError { - #[error("Optimierung fehlgeschlagen: {0}")] + #[error("Optimization failed: {0}")] OptimizationFailed(String), - #[error("Ungültiger AST-Knoten: {0}")] + #[error("Invalid AST node: {0}")] InvalidAstNode(String), } -/// Optimierungs-Konfiguration +/// Optimization configuration #[derive(Debug, Clone)] pub struct OptimizationConfig { - /// Constant Folding aktivieren + /// Enable constant folding pub constant_folding: bool, - /// Dead Code Elimination aktivieren + /// Enable dead code elimination pub dead_code_elimination: bool, - /// Common Subexpression Elimination aktivieren + /// Enable common subexpression elimination pub cse: bool, - /// Loop Invariant Code Motion aktivieren + /// Enable loop invariant code motion pub licm: bool, - /// Function Inlining aktivieren + /// Enable function inlining pub inlining: bool, - /// Maximale Inlining-Tiefe + /// Maximum inlining depth pub max_inline_depth: usize, - /// Maximale Inlining-Größe (AST-Knoten) + /// Maximum inlining size (AST nodes) pub max_inline_size: usize, } @@ -72,7 +72,7 @@ impl Default for OptimizationConfig { } impl OptimizationConfig { - /// Erstellt eine Konfiguration ohne Optimierungen + /// Creates a configuration without optimizations pub fn none() -> Self { Self { constant_folding: false, @@ -85,28 +85,28 @@ impl OptimizationConfig { } } - /// Erstellt eine Konfiguration mit allen Optimierungen + /// Creates a configuration with all optimizations pub fn all() -> Self { Self::default() } } -/// HypnoScript Code-Optimizer +/// HypnoScript code optimizer /// -/// Wendet verschiedene Optimierungs-Pässe auf den AST an, um die -/// Performance zu verbessern und die Code-Größe zu reduzieren. +/// Applies various optimization passes to the AST to improve +/// performance and reduce code size. pub struct Optimizer { - /// Optimierungs-Konfiguration + /// Optimization configuration config: OptimizationConfig, - /// Konstanten-Environment + /// Constant environment constants: HashMap, - /// Verwendete Variablen + /// Used variables used_variables: HashSet, - /// Optimierungs-Statistiken + /// Optimization statistics stats: OptimizationStats, } -/// Konstanter Wert zur Compile-Zeit +/// Constant value at compile time #[derive(Debug, Clone, PartialEq)] #[allow(dead_code)] enum ConstantValue { @@ -115,18 +115,18 @@ enum ConstantValue { Boolean(bool), } -/// Statistiken über durchgeführte Optimierungen +/// Statistics about performed optimizations #[derive(Debug, Clone, Default)] pub struct OptimizationStats { - /// Anzahl gefalteter Konstanten + /// Number of folded constants pub folded_constants: usize, - /// Anzahl entfernter toter Code-Blöcke + /// Number of removed dead code blocks pub eliminated_dead_code: usize, - /// Anzahl eliminierter gemeinsamer Subausdrücke + /// Number of eliminated common subexpressions pub eliminated_common_subexpr: usize, - /// Anzahl verschobener Loop-Invarianten + /// Number of moved loop invariants pub moved_loop_invariants: usize, - /// Anzahl inline eingefügter Funktionen + /// Number of inlined functions pub inlined_functions: usize, } @@ -137,9 +137,9 @@ impl Default for Optimizer { } impl Optimizer { - /// Erstellt einen neuen Optimizer mit Standard-Konfiguration + /// Creates a new optimizer with default configuration /// - /// # Beispiele + /// # Examples /// /// ``` /// use hypnoscript_compiler::optimizer::Optimizer; @@ -155,11 +155,11 @@ impl Optimizer { } } - /// Erstellt einen Optimizer mit benutzerdefinierter Konfiguration + /// Creates an optimizer with a custom configuration /// - /// # Argumente + /// # Arguments /// - /// * `config` - Die Optimierungs-Konfiguration + /// * `config` - The optimization configuration pub fn with_config(config: OptimizationConfig) -> Self { Self { config, @@ -169,29 +169,29 @@ impl Optimizer { } } - /// Aktiviert alle Optimierungen + /// Enables all optimizations pub fn enable_all_optimizations(&mut self) { self.config = OptimizationConfig::all(); } - /// Deaktiviert alle Optimierungen + /// Disables all optimizations pub fn disable_all_optimizations(&mut self) { self.config = OptimizationConfig::none(); } - /// Optimiert den AST + /// Optimizes the AST /// - /// # Argumente + /// # Arguments /// - /// * `program` - Der zu optimierende AST + /// * `program` - The AST to optimize /// - /// # Rückgabe + /// # Returns /// - /// Der optimierte AST + /// The optimized AST /// - /// # Fehler + /// # Errors /// - /// Gibt einen `OptimizationError` zurück, wenn die Optimierung fehlschlägt + /// Returns an `OptimizationError` when optimization fails pub fn optimize(&mut self, program: &AstNode) -> Result { // Reset statistics self.stats = OptimizationStats::default(); @@ -228,7 +228,7 @@ impl Optimizer { Ok(optimized) } - /// Gibt die Optimierungs-Statistiken zurück + /// Returns the optimization statistics pub fn stats(&self) -> &OptimizationStats { &self.stats } @@ -237,8 +237,8 @@ impl Optimizer { /// Pass 1: Constant Folding /// - /// Berechnet konstante Ausdrücke zur Compile-Zeit. - /// Beispiel: `2 + 3` wird zu `5` + /// Computes constant expressions at compile time. + /// Example: `2 + 3` becomes `5` fn constant_folding_pass(&mut self, node: &AstNode) -> Result { match node { AstNode::Program(statements) => { @@ -303,44 +303,44 @@ impl Optimizer { }) } - // Für andere Knoten: Rekursiv durchlaufen + // For other nodes: traverse recursively _ => Ok(node.clone()), } } /// Pass 2: Dead Code Elimination /// - /// Entfernt unerreichbaren Code, z.B. nach return oder in if(false)-Zweigen. + /// Removes unreachable code, e.g. after return or in if(false) branches. fn dead_code_elimination_pass(&mut self, node: &AstNode) -> Result { - // TODO: Implementierung - // Placeholder für zukünftige Implementierung + // TODO: Implementation + // Placeholder for future implementation Ok(node.clone()) } /// Pass 3: Common Subexpression Elimination /// - /// Erkennt und eliminiert redundante Berechnungen. + /// Detects and eliminates redundant computations. fn cse_pass(&mut self, node: &AstNode) -> Result { - // TODO: Implementierung - // Placeholder für zukünftige Implementierung + // TODO: Implementation + // Placeholder for future implementation Ok(node.clone()) } /// Pass 4: Loop Invariant Code Motion /// - /// Verschiebt Berechnungen, die sich in Schleifen nicht ändern, vor die Schleife. + /// Moves computations that do not change inside loops before the loop. fn licm_pass(&mut self, node: &AstNode) -> Result { - // TODO: Implementierung - // Placeholder für zukünftige Implementierung + // TODO: Implementation + // Placeholder for future implementation Ok(node.clone()) } /// Pass 5: Function Inlining /// - /// Fügt kleine Funktionen inline ein, um Funktionsaufruf-Overhead zu vermeiden. + /// Inlines small functions to avoid function call overhead. fn inlining_pass(&mut self, node: &AstNode) -> Result { - // TODO: Implementierung - // Placeholder für zukünftige Implementierung + // TODO: Implementation + // Placeholder for future implementation Ok(node.clone()) } } diff --git a/hypnoscript-compiler/src/wasm_binary.rs b/hypnoscript-compiler/src/wasm_binary.rs index d99d374..341b420 100644 --- a/hypnoscript-compiler/src/wasm_binary.rs +++ b/hypnoscript-compiler/src/wasm_binary.rs @@ -1,9 +1,9 @@ -//! WebAssembly Binary Generator für HypnoScript +//! WebAssembly binary generator for HypnoScript //! -//! Dieses Modul generiert binäres WebAssembly (.wasm) direkt aus dem AST, -//! zusätzlich zum bereits vorhandenen Text-Format (.wat) Generator. +//! This module generates binary WebAssembly (.wasm) directly from the AST, +//! in addition to the already available text format (.wat) generator. //! -//! ## Verwendung +//! ## Usage //! //! ```rust,no_run //! use hypnoscript_compiler::wasm_binary::WasmBinaryGenerator; @@ -17,30 +17,30 @@ use hypnoscript_lexer_parser::ast::AstNode; use thiserror::Error; -/// Fehlertypen für die WASM-Binary-Generierung +/// Error types for WASM binary generation #[derive(Error, Debug)] pub enum WasmBinaryError { - #[error("Ungültiger AST-Knoten: {0}")] + #[error("Invalid AST node: {0}")] InvalidAstNode(String), - #[error("Code-Generierung fehlgeschlagen: {0}")] + #[error("Code generation failed: {0}")] CodeGenerationError(String), - #[error("I/O-Fehler: {0}")] + #[error("I/O error: {0}")] IoError(#[from] std::io::Error), } -/// WebAssembly Binary Generator +/// WebAssembly binary generator /// -/// Generiert binäres WebAssembly (.wasm) direkt aus dem HypnoScript AST. -/// Das binäre Format ist kompakter und wird direkt von WebAssembly-Runtimes -/// ausgeführt, ohne vorheriges Parsen. +/// Generates binary WebAssembly (.wasm) directly from the HypnoScript AST. +/// The binary format is more compact and is executed directly by WebAssembly runtimes +/// without prior parsing. pub struct WasmBinaryGenerator { - /// Generierte Bytes + /// Generated bytes output: Vec, - /// Funktions-Index + /// Function index function_index: u32, - /// Typ-Index + /// Type index type_index: u32, } @@ -51,9 +51,9 @@ impl Default for WasmBinaryGenerator { } impl WasmBinaryGenerator { - /// Erstellt einen neuen WASM Binary Generator + /// Creates a new WASM binary generator /// - /// # Beispiele + /// # Examples /// /// ``` /// use hypnoscript_compiler::wasm_binary::WasmBinaryGenerator; @@ -68,19 +68,19 @@ impl WasmBinaryGenerator { } } - /// Generiert WASM-Binary aus dem AST + /// Generates a WASM binary from the AST /// - /// # Argumente + /// # Arguments /// - /// * `program` - Der HypnoScript AST + /// * `program` - The HypnoScript AST /// - /// # Rückgabe + /// # Returns /// - /// Vec mit den generierten WASM-Bytes + /// Vec with the generated WASM bytes /// - /// # Fehler + /// # Errors /// - /// Gibt einen `WasmBinaryError` zurück, wenn die Code-Generierung fehlschlägt + /// Returns a `WasmBinaryError` when code generation fails pub fn generate(&mut self, program: &AstNode) -> Result, WasmBinaryError> { self.output.clear(); self.function_index = 0; @@ -115,12 +115,12 @@ impl WasmBinaryGenerator { Ok(self.output.clone()) } - /// Schreibt Bytes in den Output + /// Writes bytes to the output fn write_bytes(&mut self, bytes: &[u8]) { self.output.extend_from_slice(bytes); } - /// Schreibt einen LEB128-kodierten unsigned integer + /// Writes a LEB128-encoded unsigned integer fn write_uleb128(&mut self, mut value: u64) { loop { let mut byte = (value & 0x7F) as u8; @@ -135,7 +135,7 @@ impl WasmBinaryGenerator { } } - /// Emittiert die Type Section + /// Emits the type section fn emit_type_section(&mut self) -> Result<(), WasmBinaryError> { let section = vec![0x60, 0x00, 0x00]; @@ -148,7 +148,7 @@ impl WasmBinaryGenerator { Ok(()) } - /// Emittiert die Import Section + /// Emits the import section fn emit_import_section(&mut self) -> Result<(), WasmBinaryError> { self.output.push(0x02); // Import section ID @@ -169,7 +169,7 @@ impl WasmBinaryGenerator { Ok(()) } - /// Schreibt einen Import-Eintrag + /// Writes an import entry fn write_import_function( &mut self, buffer: &mut Vec, @@ -192,7 +192,7 @@ impl WasmBinaryGenerator { buffer.push(type_idx as u8); } - /// Emittiert die Function Section + /// Emits the function section fn emit_function_section(&mut self) -> Result<(), WasmBinaryError> { self.output.push(0x03); // Function section ID self.write_uleb128(1); // Section size (placeholder) @@ -202,7 +202,7 @@ impl WasmBinaryGenerator { Ok(()) } - /// Emittiert die Memory Section + /// Emits the memory section fn emit_memory_section(&mut self) -> Result<(), WasmBinaryError> { self.output.push(0x05); // Memory section ID self.write_uleb128(3); // Section size @@ -213,7 +213,7 @@ impl WasmBinaryGenerator { Ok(()) } - /// Emittiert die Export Section + /// Emits the export section fn emit_export_section(&mut self) -> Result<(), WasmBinaryError> { self.output.push(0x07); // Export section ID @@ -238,7 +238,7 @@ impl WasmBinaryGenerator { Ok(()) } - /// Emittiert die Code Section + /// Emits the code section fn emit_code_section(&mut self, _statements: &[AstNode]) -> Result<(), WasmBinaryError> { self.output.push(0x0A); // Code section ID @@ -262,7 +262,7 @@ impl WasmBinaryGenerator { Ok(()) } - /// Gibt die generierten Bytes zurück + /// Returns the generated bytes pub fn get_output(&self) -> &[u8] { &self.output } diff --git a/hypnoscript-compiler/src/wasm_codegen.rs b/hypnoscript-compiler/src/wasm_codegen.rs index 88723ff..b37a961 100644 --- a/hypnoscript-compiler/src/wasm_codegen.rs +++ b/hypnoscript-compiler/src/wasm_codegen.rs @@ -3,13 +3,13 @@ use std::collections::HashMap; /// WASM code generator for HypnoScript /// -/// Generiert WebAssembly Text Format (.wat) aus HypnoScript AST. +/// Generates WebAssembly text format (.wat) from the HypnoScript AST. /// Supports: -/// - Variablen und Funktionen -/// - Kontrollfluss (if/while/loop) -/// - Arithmetische und logische Operationen -/// - Session-Definitionen (OOP) -/// - Built-in Funktionen +/// - Variables and functions +/// - Control flow (if/while/loop) +/// - Arithmetic and logical operations +/// - Session definitions (OOP) +/// - Built-in functions pub struct WasmCodeGenerator { output: String, local_counter: usize, @@ -365,7 +365,7 @@ impl WasmCodeGenerator { } } - /// Emit eine Funktion + /// Emit a function fn emit_function( &mut self, name: &str, @@ -375,13 +375,13 @@ impl WasmCodeGenerator { self.emit_line(&format!("(func ${} (export \"{}\")", name, name)); self.indent_level += 1; - // Parameter + // Parameters for param in parameters { self.emit_line(&format!("(param ${} f64) ;; {}", param.name, param.name)); } self.emit_line("(result f64)"); - // Lokale Variablen + // Local variables self.emit_line("(local $temp f64)"); // Body @@ -397,7 +397,7 @@ impl WasmCodeGenerator { self.emit_line(""); } - /// Emit Session-Methoden + /// Emit session methods fn emit_session_methods( &mut self, session_name: &str, @@ -415,10 +415,10 @@ impl WasmCodeGenerator { )); self.indent_level += 1; - // Impliziter 'this' Parameter + // Implicit 'this' parameter self.emit_line("(param $this i32)"); - // Weitere Parameter + // Additional parameters for _ in &method.parameters { self.emit_line("(param f64)"); } @@ -554,7 +554,7 @@ impl WasmCodeGenerator { if self.function_map.contains_key(&name) { self.emit_line(&format!("call ${}", name)); } else { - // Versuch, als Built-in-Funktion aufzurufen + // Attempt to call as a built-in function self.emit_line(&format!("call ${}", name)); } } @@ -687,7 +687,7 @@ Focus { let mut generator = WasmCodeGenerator::new(); let wasm = generator.generate(&ast); - // Prüfe grundlegende WASM-Struktur + // Check basic WASM structure assert!(wasm.starts_with("(module")); assert!(wasm.ends_with(")\n")); assert!(wasm.contains("memory")); diff --git a/hypnoscript-docs/README.md b/hypnoscript-docs/README.md index 6692053..8c5d5d1 100644 --- a/hypnoscript-docs/README.md +++ b/hypnoscript-docs/README.md @@ -1,183 +1,185 @@ -# HypnoScript Dokumentation +# HypnoScript Documentation -Dies ist die vollständige Dokumentation für HypnoScript - Die hypnotische Programmiersprache. Die Dokumentation wird mit [VitePress](https://vitepress.dev/) erstellt und automatisch zu GitHub Pages deployed. +This is the complete documentation for HypnoScript — the hypnotic programming language. The documentation is built with [VitePress](https://vitepress.dev/) and is automatically deployed to GitHub Pages. -## 🚀 Schnellstart +## 🚀 Quick Start -### Voraussetzungen +### Prerequisites -- Node.js 18.0 oder höher -- npm, yarn oder pnpm +- Node.js 18.0 or higher +- npm, yarn, or pnpm ### Installation ```bash -# Dependencies installieren +# Install dependencies npm install -# Entwicklungsserver starten +# Start the dev server npm run dev -# Dokumentation bauen +# Build documentation npm run build -# Vorschau der gebauten Dokumentation +# Preview the built documentation npm run preview ``` -## 📁 Projektstruktur +## 📁 Project Structure -``` +```bash HypnoScript.Dokumentation/ -├── docs/ # Dokumentationsseiten -│ ├── .vitepress/ # VitePress-Konfiguration -│ │ ├── config.mts # Hauptkonfiguration -│ │ └── theme/ # Custom Theme -│ │ ├── index.ts # Theme-Einstiegspunkt +├── docs/ # Documentation pages +│ ├── .vitepress/ # VitePress configuration +│ │ ├── config.mts # Main configuration +│ │ └── theme/ # Custom theme +│ │ ├── index.ts # Theme entry point │ │ └── style.css # Custom CSS │ ├── index.md # Homepage -│ ├── intro.md # Einführung -│ ├── getting-started/ # Erste Schritte -│ ├── language-reference/ # Sprachreferenz -│ ├── builtins/ # Builtin-Funktionen +│ ├── intro.md # Introduction +│ ├── getting-started/ # Getting started +│ ├── language-reference/ # Language reference +│ ├── builtins/ # Builtin functions │ ├── cli/ # CLI & Tools -│ ├── examples/ # Beispiele -│ ├── development/ # Entwicklung -│ └── reference/ # Referenz -├── static/ # Statische Dateien -│ └── img/ # Bilder +│ ├── examples/ # Examples +│ ├── development/ # Development +│ └── reference/ # Reference +├── static/ # Static files +│ └── img/ # Images └── package.json # Dependencies ``` -## 🛠️ Entwicklung +## 🛠️ Development -### Neue Seite hinzufügen +### Add a New Page + +1. Create a new `.md` file in the appropriate directory under `docs/` +2. Add frontmatter (optional): -1. Erstelle eine neue `.md` Datei im entsprechenden Verzeichnis unter `docs/` -2. Füge Frontmatter hinzu (optional): ```markdown --- - title: Seitentitel - description: Beschreibung + title: Page Title + description: Description --- ``` -3. Aktualisiere `docs/.vitepress/config.mts` um die Seite in die Sidebar einzufügen -### Styling anpassen +3. Update `docs/.vitepress/config.mts` to include the page in the sidebar + +### Customize Styling - Custom CSS: `docs/.vitepress/theme/style.css` -- Theme-Komponenten: `docs/.vitepress/theme/index.ts` +- Theme components: `docs/.vitepress/theme/index.ts` -### Lokale Entwicklung +### Local Development ```bash npm run dev ``` -Öffne [http://localhost:5173](http://localhost:5173) im Browser. +Open [http://localhost:5173](http://localhost:5173) in your browser. ## 🚀 Deployment -Die Dokumentation wird automatisch zu GitHub Pages deployed über GitHub Actions: +The documentation is automatically deployed to GitHub Pages via GitHub Actions: -- **Trigger**: Push zu `main` Branch mit Änderungen in `HypnoScript.Dokumentation/` +- **Trigger**: Push to `main` with changes in `HypnoScript.Dokumentation/` - **Workflow**: `.github/workflows/deploy-docs.yml` -- **URL**: https://Kink-Development-Group.github.io/hyp-runtime/ +- **URL**: -### Manuelles Deployment +### Manual Deployment ```bash npm run build -# Die gebaute Dokumentation befindet sich in docs/.vitepress/dist/ +# The built documentation is located in docs/.vitepress/dist/ ``` -## 📚 Dokumentationsstruktur +## 📚 Documentation Structure -### Erste Schritte +### Getting Started -- Installation und Setup -- Schnellstart-Guide +- Installation and setup +- Quick start guide - Hello World -- CLI-Grundlagen +- CLI basics -### Sprachreferenz +### Language Reference - Syntax -- Variablen und Datentypen -- Operatoren -- Kontrollstrukturen -- Funktionen -- Sessions und Tranceify -- Arrays und Records -- Imports und Assertions - -### Builtin-Funktionen - -- Übersicht aller 200+ Funktionen -- Array-Funktionen -- String-Funktionen -- Mathematische Funktionen -- Utility-Funktionen -- System-Funktionen -- Zeit- und Datumsfunktionen -- Statistik-Funktionen -- Hashing/Encoding -- Hypnotische Spezialfunktionen -- Dictionary-Funktionen -- Datei-Funktionen -- Netzwerk-Funktionen -- Validierung-Funktionen -- Performance-Funktionen +- Variables and data types +- Operators +- Control structures +- Functions +- Sessions and Tranceify +- Arrays and records +- Imports and assertions + +### Builtin Functions + +- Overview of all 200+ functions +- Array functions +- String functions +- Math functions +- Utility functions +- System functions +- Time and date functions +- Statistics functions +- Hashing/encoding +- Hypnotic specialty functions +- Dictionary functions +- File functions +- Network functions +- Validation functions +- Performance functions ### CLI & Tools -- CLI-Übersicht -- Kommandos -- Konfiguration +- CLI overview +- Commands +- Configuration - Testing - Debugging -- Runtime-Features +- Runtime features -### Beispiele +### Examples -- Grundlegende Beispiele -- Array-Beispiele -- String-Beispiele -- Mathematische Beispiele -- Datei-Beispiele -- Hypnotische Beispiele -- Erweiterte Beispiele +- Basic examples +- Array examples +- String examples +- Math examples +- File examples +- Hypnotic examples +- Advanced examples -### Entwicklung +### Development -- Architektur +- Architecture - Contributing - Building - Testing - Debugging - Extending -## 🔁 Installer-Synchronisation +## 🔁 Installer Synchronization -Der neue einheitliche Installer (`install.sh`) lebt im Repository-Wurzelverzeichnis und wird automatisch in die Dokumentation gespiegelt. Das Script `scripts/sync-installer.mjs` kopiert ihn vor jedem `dev`, `build` oder `preview`-Lauf nach `static/install.sh` (siehe `package.json`-`pre*`-Hooks). Dadurch steht im veröffentlichen Handbuch exakt derselbe Installer zum Download bereit, der auch in den Release-Archiven enthalten ist. +The unified installer (`install.sh`) lives in the repository root and is automatically mirrored into the documentation. The `scripts/sync-installer.mjs` script copies it to `static/install.sh` before every `dev`, `build`, or `preview` run (see the `package.json` `pre*` hooks). This ensures the published handbook provides the exact same installer that ships inside release archives. -Manueller Lauf – z.B. nach Änderungen am Installer ohne Dokumentations-Build: +Manual run — for example, after changes to the installer without a docs build: ```bash npm run sync-installer ``` -Alternativ kannst du das Script direkt ausführen: +Alternatively, run the script directly: ```bash node ./scripts/sync-installer.mjs ``` -Die GitHub-Actions, die Releases bauen, führen denselben Schritt aus und legen das Skript zusätzlich in den Release-Archiven (`share/hypnoscript/install.sh`) ab. +The GitHub Actions that build releases run the same step and also place the script into the release archives (`share/hypnoscript/install.sh`). -### Referenz +### Reference -- Grammatik +- Grammar - AST - Interpreter - Compiler @@ -185,33 +187,33 @@ Die GitHub-Actions, die Releases bauen, führen denselben Schritt aus und legen - API - Changelog -## 🌐 Internationalisierung +## 🌐 Internationalization -Die Dokumentation unterstützt mehrere Sprachen: +The documentation supports multiple languages: -- **Deutsch** (Standard) -- **Englisch** +- **German** (default) +- **English** -### Neue Sprache hinzufügen +### Add a New Language -1. Aktualisiere `docusaurus.config.js`: +1. Update `docusaurus.config.js`: ```javascript i18n: { defaultLocale: 'de', - locales: ['de', 'en', 'neue-sprache'], + locales: ['de', 'en', 'new-language'], }, ``` -2. Erstelle Übersetzungen: +2. Generate translations: ```bash npm run write-translations ``` -## 🔍 Suchfunktion +## 🔍 Search -Die Dokumentation verwendet Algolia für die Suchfunktion. Konfiguration in `docusaurus.config.js`: +The documentation uses Algolia for search. Configure it in `docusaurus.config.js`: ```javascript algolia: { @@ -223,27 +225,27 @@ algolia: { ## 📝 Blog -Blog-Posts können unter `blog/` hinzugefügt werden. Jede `.md` Datei wird automatisch als Blog-Post erkannt. +Blog posts can be added under `blog/`. Each `.md` file is automatically treated as a blog post. ## 🤝 Contributing -1. Fork das Repository -2. Erstelle einen Feature-Branch -3. Mache deine Änderungen -4. Teste lokal mit `npm start` -5. Erstelle einen Pull Request +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Test locally with `npm start` +5. Open a pull request -## 📄 Lizenz +## 📄 License -MIT License - siehe [LICENSE](../../LICENSE) für Details. +MIT License — see [LICENSE](../../LICENSE) for details. ## 🔗 Links -- **Live-Dokumentation**: -- **GitHub Repository**: +- **Live documentation**: +- **GitHub repository**: - **Docusaurus**: - **Issues**: --- -**Bereit, die hypnotische Welt der Programmierung zu dokumentieren?** 🧠✨ +**Ready to document the hypnotic world of programming?** 🧠✨ diff --git a/hypnoscript-docs/docs/builtins/_complete-reference.md b/hypnoscript-docs/docs/builtins/_complete-reference.md index 0cfe9d3..f1359a5 100644 --- a/hypnoscript-docs/docs/builtins/_complete-reference.md +++ b/hypnoscript-docs/docs/builtins/_complete-reference.md @@ -295,113 +295,113 @@ All array functions use the `Array` prefix to distinguish from string functions ### Format Validation -| Function | Signature | Description | -| -------------------- | ---------------------------- | ------------------------- | -| `IsValidEmail` | `(email: string) -> boolean` | Email validation | -| `IsValidUrl` | `(url: string) -> boolean` | URL-Validierung | -| `IsValidPhoneNumber` | `(phone: string) -> boolean` | Telefonnummer-Validierung | +| Function | Signature | Description | +| -------------------- | ---------------------------- | ----------------------- | +| `IsValidEmail` | `(email: string) -> boolean` | Email validation | +| `IsValidUrl` | `(url: string) -> boolean` | URL validation | +| `IsValidPhoneNumber` | `(phone: string) -> boolean` | Phone number validation | -### Zeichen-Prüfungen +### Character Checks -| Function | Signatur | Description | -| ---------------- | ------------------------ | ------------------------- | -| `IsAlphanumeric` | `(s: string) -> boolean` | Nur Buchstaben und Zahlen | -| `IsAlphabetic` | `(s: string) -> boolean` | Nur Buchstaben | -| `IsNumeric` | `(s: string) -> boolean` | Nur Zahlen | -| `IsLowercase` | `(s: string) -> boolean` | Nur Kleinbuchstaben | -| `IsUppercase` | `(s: string) -> boolean` | Nur Großbuchstaben | +| Function | Signature | Description | +| ---------------- | ------------------------ | ------------------------ | +| `IsAlphanumeric` | `(s: string) -> boolean` | Letters and numbers only | +| `IsAlphabetic` | `(s: string) -> boolean` | Letters only | +| `IsNumeric` | `(s: string) -> boolean` | Numbers only | +| `IsLowercase` | `(s: string) -> boolean` | Lowercase only | +| `IsUppercase` | `(s: string) -> boolean` | Uppercase only | -### Weitere Validierungen +### Additional Validation -| Function | Signatur | Description | -| ---------------- | ------------------------------------------------------ | ------------------- | -| `IsInRange` | `(value: number, min: number, max: number) -> boolean` | Wertebereich prüfen | -| `MatchesPattern` | `(text: string, pattern: string) -> boolean` | Regex-Match | +| Function | Signature | Description | +| ---------------- | ------------------------------------------------------ | ----------------- | +| `IsInRange` | `(value: number, min: number, max: number) -> boolean` | Check value range | +| `MatchesPattern` | `(text: string, pattern: string) -> boolean` | Regex match | ## Hashing Builtins -### Hash-Functionen +### Hash Functions -| Function | Signatur | Description | -| -------------- | -------------------------- | ------------------ | -| `HashString` | `(s: string) -> number` | String hashen | -| `HashNumber` | `(n: number) -> number` | Number hashen | -| `SimpleRandom` | `(seed: number) -> number` | Pseudo-Zufallszahl | +| Function | Signature | Description | +| -------------- | -------------------------- | ------------------- | +| `HashString` | `(s: string) -> number` | Hash string | +| `HashNumber` | `(n: number) -> number` | Hash number | +| `SimpleRandom` | `(seed: number) -> number` | Pseudorandom number | -### String-Analyse +### String Analysis -| Function | Signatur | Description | -| ------------------ | ------------------------------------------- | ------------------- | -| `AreAnagrams` | `(s1: string, s2: string) -> boolean` | Checks Anagramme | -| `IsPalindrome` | `(s: string) -> boolean` | Checks Palindrom | -| `CountOccurrences` | `(text: string, pattern: string) -> number` | Vorkommen zählen | -| `RemoveDuplicates` | `(s: string) -> string` | Duplikate entfernen | -| `UniqueCharacters` | `(s: string) -> string` | Eindeutige Zeichen | -| `ReverseWords` | `(s: string) -> string` | Wörter umkehren | -| `TitleCase` | `(s: string) -> string` | Title Case Format | +| Function | Signature | Description | +| ------------------ | ------------------------------------------- | ----------------- | +| `AreAnagrams` | `(s1: string, s2: string) -> boolean` | Checks anagrams | +| `IsPalindrome` | `(s: string) -> boolean` | Checks palindrome | +| `CountOccurrences` | `(text: string, pattern: string) -> number` | Count occurrences | +| `RemoveDuplicates` | `(s: string) -> string` | Remove duplicates | +| `UniqueCharacters` | `(s: string) -> string` | Unique characters | +| `ReverseWords` | `(s: string) -> string` | Reverse words | +| `TitleCase` | `(s: string) -> string` | Title Case Format | ## DeepMind Builtins (Higher-Order Functions) -### Kontrollfluss +### Control Flow -| Function | Signatur | Description | -| ------------------- | ------------------------------------------------------------- | ------------------------ | -| `RepeatAction` | `(times: number, action: () -> void) -> void` | Aktion n-mal wiederholen | -| `DelayedSuggestion` | `(action: () -> void, delay: number) -> void` | Verzögerte Ausführung | -| `IfTranced` | `(cond: boolean, then: () -> void, else: () -> void) -> void` | Bedingte Ausführung | +| Function | Signature | Description | +| ------------------- | ------------------------------------------------------------- | --------------------- | +| `RepeatAction` | `(times: number, action: () -> void) -> void` | Repeat action n times | +| `DelayedSuggestion` | `(action: () -> void, delay: number) -> void` | Delayed execution | +| `IfTranced` | `(cond: boolean, then: () -> void, else: () -> void) -> void` | Conditional execution | -### Schleifen +### Loops -| Function | Signatur | Description | -| ------------- | -------------------------------------------------------- | ----------------------------- | -| `RepeatUntil` | `(action: () -> void, condition: () -> boolean) -> void` | Wiederhole bis Bedingung wahr | -| `RepeatWhile` | `(condition: () -> boolean, action: () -> void) -> void` | Wiederhole solange wahr | +| Function | Signature | Description | +| ------------- | -------------------------------------------------------- | --------------------------- | +| `RepeatUntil` | `(action: () -> void, condition: () -> boolean) -> void` | Repeat until condition true | +| `RepeatWhile` | `(condition: () -> boolean, action: () -> void) -> void` | Repeat while condition true | -### Functionskomposition +### Function Composition -| Function | Signatur | Description | -| --------- | ------------------------------------ | ---------------------------- | -| `Compose` | `(f: B -> C, g: A -> B) -> (A -> C)` | Functionskomposition f(g(x)) | -| `Pipe` | `(f: A -> B, g: B -> C) -> (A -> C)` | Functions-Pipeline g(f(x)) | +| Function | Signature | Description | +| --------- | ------------------------------------ | ------------------- | +| `Compose` | `(f: B -> C, g: A -> B) -> (A -> C)` | Composition f(g(x)) | +| `Pipe` | `(f: A -> B, g: B -> C) -> (A -> C)` | Pipeline g(f(x)) | -### Fehlerbehandlung +### Error Handling (Higher-Order) -| Function | Signatur | Description | +| Function | Signature | Description | | ----------------- | ----------------------------------------------------------- | ----------- | -| `TryOrAwaken` | `(try: () -> void, catch: (error: string) -> void) -> void` | Try-Catch | -| `EnsureAwakening` | `(main: () -> void, cleanup: () -> void) -> void` | Try-Finally | +| `TryOrAwaken` | `(try: () -> void, catch: (error: string) -> void) -> void` | Try/Catch | +| `EnsureAwakening` | `(main: () -> void, cleanup: () -> void) -> void) | Try/Finally | -### Weitere +### Additional -| Function | Signatur | Description | -| -------------------- | ----------------------------------- | ------------------------------ | -| `SequentialTrance` | `(actions: (() -> void)[]) -> void` | Aktionen sequentiell ausführen | -| `MeasureTranceDepth` | `(action: () -> void) -> number` | Ausführungszeit messen | -| `Memoize` | `(f: A -> R) -> (A -> R)` | Function mit Caching | +| Function | Signature | Description | +| -------------------- | ----------------------------------- | ---------------------------- | +| `SequentialTrance` | `(actions: (() -> void)[]) -> void` | Execute actions sequentially | +| `MeasureTranceDepth` | `(action: () -> void) -> number` | Measure execution time | +| `Memoize` | `(f: A -> R) -> (A -> R)` | Function with caching | -## Usageshinweise +## Usage Notes -### Namenskonventionen +### Naming Conventions -- **PascalCase** für Functionsnamen (z.B. `CalculateMean`, `ToUpper`) -- **Case-Insensitive** Matching beim Aufruf -- **Typ-Parameters** `T` für generische Functionen +- **PascalCase** for function names (e.g. `CalculateMean`, `ToUpper`) +- **Case-insensitive** matching on call +- **Type parameters** `T` for generic functions -### Fehlerbehandlung +### Error Handling -- Functionen die fehlschlagen können werfen Runtime-Errors -- Use `TryOrAwaken` für Fehlerbehandlung -- Validiere Inputn mit Validation-Builtins +- Functions that can fail throw runtime errors +- Use `TryOrAwaken` for error handling +- Validate inputs with validation builtins ### Performance -- Array-Operationen erstellen neue Arrays (immutabel) -- Use `Memoize` für teure Berechnungen -- `MeasureTranceDepth` für Performance-Profiling +- Array operations create new arrays (immutable) +- Use `Memoize` for expensive computations +- Use `MeasureTranceDepth` for performance profiling -## See auch +## See Also -- [Detaillierte Array-Functionen](./array-functions) -- [Detaillierte String-Functionen](./string-functions) -- [Detaillierte Math-Functionen](./math-functions) -- [CLI Builtin-Command](../cli/commands#builtins) +- [Detailed Array Functions](./array-functions) +- [Detailed String Functions](./string-functions) +- [Detailed Math Functions](./math-functions) +- [CLI builtin command](../cli/commands#builtins) diff --git a/hypnoscript-docs/docs/builtins/array-functions.md b/hypnoscript-docs/docs/builtins/array-functions.md index e1dc4c9..fcd6e6b 100644 --- a/hypnoscript-docs/docs/builtins/array-functions.md +++ b/hypnoscript-docs/docs/builtins/array-functions.md @@ -23,7 +23,7 @@ Returns the number of elements in an array. ```hyp induce numbers = [1, 2, 3, 4, 5]; induce length = ArrayLength(numbers); -observe "Array-Länge: " + length; // 5 +observe "Array length: " + length; // 5 ``` ### ArrayGet(arr, index) @@ -31,9 +31,9 @@ observe "Array-Länge: " + length; // 5 Retrieves an element at a specific index. ```hyp -induce fruits = ["Apfel", "Banane", "Orange"]; -induce first = ArrayGet(fruits, 0); // "Apfel" -induce second = ArrayGet(fruits, 1); // "Banane" +induce fruits = ["Apple", "Banana", "Orange"]; +induce first = ArrayGet(fruits, 0); // "Apple" +induce second = ArrayGet(fruits, 1); // "Banana" ``` ### ArraySet(arr, index, value) @@ -63,7 +63,7 @@ observe sorted; // [1, 1, 2, 3, 4, 5, 6, 9] Randomly shuffles the elements of an array. ```hyp -induce cards = ["Herz", "Karo", "Pik", "Kreuz"]; +induce cards = ["Hearts", "Diamonds", "Spades", "Clubs"]; induce shuffled = ShuffleArray(cards); observe shuffled; // Random order ``` @@ -87,7 +87,7 @@ Calculates the sum of all numeric elements. ```hyp induce numbers = [1, 2, 3, 4, 5]; induce sum = ArraySum(numbers); -observe "Summe: " + sum; // 15 +observe "Sum: " + sum; // 15 ``` ### AverageArray(arr) @@ -97,7 +97,7 @@ Calculates the average of all numeric elements. ```hyp induce grades = [85, 92, 78, 96, 88]; induce average = AverageArray(grades); -observe "Durchschnitt: " + average; // 87.8 +observe "Average: " + average; // 87.8 ``` ### MinArray(arr) @@ -127,9 +127,9 @@ observe "Maximum: " + max; // 89 Checks if a value is contained in the array. ```hyp -induce fruits = ["Apfel", "Banane", "Orange"]; -induce hasApple = ArrayContains(fruits, "Apfel"); // true -induce hasGrape = ArrayContains(fruits, "Traube"); // false +induce fruits = ["Apple", "Banana", "Orange"]; +induce hasApple = ArrayContains(fruits, "Apple"); // true +induce hasGrape = ArrayContains(fruits, "Grape"); // false ``` ### ArrayIndexOf(arr, value) @@ -137,9 +137,9 @@ induce hasGrape = ArrayContains(fruits, "Traube"); // false Finds the index of an element in the array. ```hyp -induce colors = ["Rot", "Grün", "Blau", "Gelb"]; -induce index = ArrayIndexOf(colors, "Blau"); -observe "Index von Blau: " + index; // 2 +induce colors = ["Red", "Green", "Blue", "Yellow"]; +induce index = ArrayIndexOf(colors, "Blue"); +observe "Index of Blue: " + index; // 2 ``` ### ArrayLastIndexOf(arr, value) @@ -149,7 +149,7 @@ Finds the last index of an element in the array. ```hyp induce numbers = [1, 2, 3, 2, 4, 2, 5]; induce lastIndex = ArrayLastIndexOf(numbers, 2); -observe "Letzter Index von 2: " + lastIndex; // 5 +observe "Last index of 2: " + lastIndex; // 5 ``` ## Array Filtering @@ -233,7 +233,7 @@ Creates an array with a specific size and default value. ```hyp induce emptyArray = CreateArray(5); // [null, null, null, null, null] -induce filledArray = CreateArray(3, "Hallo"); // ["Hallo", "Hallo", "Hallo"] +induce filledArray = CreateArray(3, "Hello"); // ["Hello", "Hello", "Hello"] ``` ## Array Statistics @@ -245,7 +245,7 @@ Calculates the variance of array elements. ```hyp induce numbers = [1, 2, 3, 4, 5]; induce variance = ArrayVariance(numbers); -observe "Varianz: " + variance; +observe "Variance: " + variance; ``` ### ArrayStandardDeviation(arr) @@ -255,7 +255,7 @@ Calculates the standard deviation. ```hyp induce grades = [85, 92, 78, 96, 88]; induce stdDev = ArrayStandardDeviation(grades); -observe "Standardabweichung: " + stdDev; +observe "Standard deviation: " + stdDev; ``` ### ArrayMedian(arr) @@ -316,39 +316,39 @@ Focus { induce maxGuesses = 10; for (induce i = 1; i <= maxGuesses; induce i = i + 1) { - induce guess = 25 + i * 2; // Vereinfachte Eingabe + induce guess = 25 + i * 2; // Simplified input induce guesses = ArrayUnion(guesses, [guess]); if (guess == secretNumber) { - observe "Gewonnen! Versuche: " + ArrayLength(guesses); + observe "You won! Attempts: " + ArrayLength(guesses); break; } else if (guess < secretNumber) { - observe "Zu niedrig!"; + observe "Too low!"; } else { - observe "Zu hoch!"; + observe "Too high!"; } } - observe "Alle Versuche: " + guesses; + observe "All attempts: " + guesses; } } Relax; ``` -### Notenverwaltung +### Grade Management ```hyp Focus { entrance { induce grades = [85, 92, 78, 96, 88, 91, 83, 89]; - observe "Noten: " + grades; - observe "Anzahl: " + ArrayLength(grades); - observe "Durchschnitt: " + AverageArray(grades); - observe "Beste Note: " + MaxArray(grades); - observe "Schlechteste Note: " + MinArray(grades); + observe "Grades: " + grades; + observe "Count: " + ArrayLength(grades); + observe "Average: " + AverageArray(grades); + observe "Best grade: " + MaxArray(grades); + observe "Worst grade: " + MinArray(grades); induce sortedGrades = ArraySort(grades); - observe "Sortiert: " + sortedGrades; + observe "Sorted: " + sortedGrades; induce median = ArrayMedian(sortedGrades); observe "Median: " + median; @@ -356,38 +356,38 @@ Focus { } Relax; ``` -### Datenanalyse +### Data Analysis ```hyp Focus { entrance { induce temperatures = [22.5, 24.1, 19.8, 26.3, 23.7, 21.2, 25.9]; - observe "Temperaturen: " + temperatures; - observe "Durchschnitt: " + AverageArray(temperatures); + observe "Temperatures: " + temperatures; + observe "Average: " + AverageArray(temperatures); observe "Maximum: " + MaxArray(temperatures); observe "Minimum: " + MinArray(temperatures); induce variance = ArrayVariance(temperatures); induce stdDev = ArrayStandardDeviation(temperatures); - observe "Varianz: " + variance; - observe "Standardabweichung: " + stdDev; + observe "Variance: " + variance; + observe "Standard deviation: " + stdDev; induce warmDays = FilterArray(temperatures, "x > 25"); - observe "Warme Tage (>25°C): " + warmDays; + observe "Warm days (>25°C): " + warmDays; } } Relax; ``` ## Best Practices -### Effiziente Array-Operationen +### Efficient Array Operations ```hyp // Calculate array length once induce length = ArrayLength(arr); for (induce i = 0; i < length; induce i = i + 1) { - // Operationen + // Operations } // Process large arrays in chunks @@ -395,14 +395,14 @@ induce largeArray = Range(1, 10000); induce chunks = ChunkArray(largeArray, 1000); for (induce i = 0; i < ArrayLength(chunks); induce i = i + 1) { induce chunk = ArrayGet(chunks, i); - // Chunk verarbeiten + // Process chunk } ``` -### Fehlerbehandlung +### Error Handling ```hyp -// Sichere Array-Zugriffe +// Safe array access suggestion safeArrayGet(arr, index) { if (index < 0 || index >= ArrayLength(arr)) { awaken null; @@ -410,7 +410,7 @@ suggestion safeArrayGet(arr, index) { return ArrayGet(arr, index); } -// Array-Validierung +// Array validation suggestion isValidArray(arr) { awaken arr != null && ArrayLength(arr) > 0; } diff --git a/hypnoscript-docs/docs/builtins/debug-functions.md b/hypnoscript-docs/docs/builtins/debug-functions.md new file mode 100644 index 0000000..1ec2aa2 --- /dev/null +++ b/hypnoscript-docs/docs/builtins/debug-functions.md @@ -0,0 +1,247 @@ +--- +sidebar_position: 18 +--- + +# Debug Functions + +These functions help with development and troubleshooting of HypnoScript programs. + +## Inspection + +### inspect(value) + +Returns a detailed representation of a value, including type information. + +```hyp +Focus + induce arr = [1, 2, 3]; + observe(inspect(arr)); + // Output: Array[Int](3) = [1, 2, 3] + + induce obj = { name: "Test", value: 42 }; + observe(inspect(obj)); + // Output: Object { name: String = "Test", value: Int = 42 } +Relax +``` + +### typeOf(value) + +Returns the type of a value as a string. + +```hyp +Focus + observe(typeOf(42)); // "Int" + observe(typeOf("Hello")); // "String" + observe(typeOf([1,2,3])); // "Array" + observe(typeOf(true)); // "Bool" + observe(typeOf(null)); // "Null" +Relax +``` + +### stackTrace() + +Returns the current call stack as a string. + +```hyp +Focus + suggestion innerFunction() { + observe(stackTrace()); + } + + suggestion outerFunction() { + innerFunction(); + } + + outerFunction(); + // Output: + // Call Stack: + // #0: innerFunction() at script.hyp:3 + // #1: outerFunction() at script.hyp:7 + // #2:
at script.hyp:10 +Relax +``` + +### dump(value) + +Prints a formatted value and returns it. Useful for debugging in expressions. + +```hyp +Focus + // Inline debugging + induce result = dump(calculate(5, 3)) * 2; + // Prints calculate(5, 3) and continues using the result +Relax +``` + +## Assertions + +### assertEqual(actual, expected, message?) + +Checks whether two values are equal. Throws an error otherwise. + +```hyp +Focus + induce result = add(2, 3); + assertEqual(result, 5); // Without message + assertEqual(result, 5, "add should return 5"); // With message +Relax +``` + +### assertTruthy(value, message?) + +Checks whether a value evaluates to true. + +```hyp +Focus + induce items = getItems(); + assertTruthy(ArrayLength(items) > 0, "Should contain items"); + + induce user = getCurrentUser(); + assertTruthy(user, "User should exist"); +Relax +``` + +## Timing + +### time(label) + +Starts a timer with the given label. + +```hyp +Focus + time("database-query"); + + // Time-consuming operation... + induce result = queryDatabase(); +Relax +``` + +### timeEnd(label) + +Ends the timer and prints the elapsed time. + +```hyp +Focus + time("operation"); + + induce result = complexCalculation(); + + timeEnd("operation"); + // Output: operation: 123.45ms +Relax +``` + +### measureTime(label, callback) + +Measures the execution time of a function and returns the result. + +```hyp +Focus + induce sorted = measureTime("sort", suggestion() { + awaken sortArray(largeArray); + }); + // Output: sort: 45.67ms + // sorted contains the sorted array +Relax +``` + +## Logging + +### log(message) + +Prints an info message. + +```hyp +Focus + log("Processing started"); + log("Step 1 completed"); +Relax +``` + +### warn(message) + +Prints a warning. + +```hyp +Focus + warn("Configuration not found, using default"); + warn("Deprecated API call"); +Relax +``` + +### error(message) + +Prints an error message. + +```hyp +Focus + error("Critical error: file not found"); +Relax +``` + +### trace(message) + +Prints a message with stack trace. + +```hyp +Focus + suggestion processItem(item) { + trace("Processing item"); + // Output contains message + current call stack + } +Relax +``` + +## Breakpoints + +### breakpoint() + +Pauses execution when in debug mode (`--debug`). + +```hyp +Focus + induce x = 10; + + breakpoint(); // Pauses here in debug mode + + induce y = x * 2; + observe(y); +Relax +``` + +In normal execution (without `--debug`) this function has no effect. + +## Usage + +### Enable Debugging + +```bash +# Start debug mode +hypnoscript exec script.hyp --debug + +# With initial breakpoints +hypnoscript exec script.hyp --debug --breakpoints 10,25 + +# With watch expressions +hypnoscript exec script.hyp --debug --watch counter,result +``` + +### Remove Debugging Code + +Before production use, debug calls should be removed: + +```hyp +// Development +breakpoint(); +dump(value); +time("operation"); +timeEnd("operation"); + +// Remove these lines before production +``` + +## See also + +- [Debug Mode](../debugging/debug-mode) - Interactive debugger +- [Breakpoints](../debugging/breakpoints) - Breakpoint management +- [Debugging Tools](../debugging/tools) - Complete reference diff --git a/hypnoscript-docs/docs/builtins/deepmind-functions.md b/hypnoscript-docs/docs/builtins/deepmind-functions.md index a89f526..c934066 100644 --- a/hypnoscript-docs/docs/builtins/deepmind-functions.md +++ b/hypnoscript-docs/docs/builtins/deepmind-functions.md @@ -1,40 +1,40 @@ --- -description: Höhere Kontrollfluss- und Kompositions-Builtins für HypnoScript. +description: Higher-order control-flow and composition builtins for HypnoScript. --- -# DeepMind-Functionen - -Die DeepMind-Builtins erweitern HypnoScript um mächtige Kontrollfluss- und Functional-Programming-Patterns. Sie -arbeiten Hand in Hand mit `suggestion`-Blöcken und erlauben es, Schleifen, Verzögerungen, Fehlerbehandlung und -Functionskomposition deklarativ auszudrücken. - -## Überblick - -| Function | Return value | Brief Description | -| -------------------- | ------------ | ------------------------------------------ | -| `RepeatAction` | `void` | Aktion eine feste Anzahl an Wiederholungen | -| `DelayedSuggestion` | `void` | Aktion nach Millisekunden-Verzögerung | -| `IfTranced` | `void` | Bedingte Ausführung zweier Vorschläge | -| `RepeatUntil` | `void` | Wiederhole Aktion bis Bedingung `true` | -| `RepeatWhile` | `void` | Wiederhole solange Bedingung `true` | -| `SequentialTrance` | `void` | Liste von Aktionen seriell ausführen | -| `Compose` / `Pipe` | `suggestion` | Functionen kombinieren | -| `TryOrAwaken` | `void` | Fehlerpfad behandeln | -| `EnsureAwakening` | `void` | Cleanup garantiert ausführen | -| `MeasureTranceDepth` | `number` | Laufzeit in Millisekunden messen | -| `Memoize` | `suggestion` | Functionsresultate zwischenspeichern | - -:::tip Namenskonventionen -Alle DeepMind-Builtins verwenden PascalCase (`RepeatAction`) und akzeptieren `suggestion()`-Blöcke als Parameters. -Die Signaturen sind case-insensitive, so dass `repeataction` ebenfalls funktioniert. +# DeepMind Functions + +DeepMind builtins extend HypnoScript with powerful control-flow and functional programming patterns. They +work hand-in-hand with `suggestion` blocks and allow loops, delays, error handling, and function composition +to be expressed declaratively. + +## Overview + +| Function | Return value | Brief Description | +| -------------------- | ------------ | ---------------------------------------- | +| `RepeatAction` | `void` | Repeat an action a fixed number of times | +| `DelayedSuggestion` | `void` | Run an action after a millisecond delay | +| `IfTranced` | `void` | Conditionally execute two suggestions | +| `RepeatUntil` | `void` | Repeat action until condition is `true` | +| `RepeatWhile` | `void` | Repeat action while condition is `true` | +| `SequentialTrance` | `void` | Execute a list of actions sequentially | +| `Compose` / `Pipe` | `suggestion` | Combine functions | +| `TryOrAwaken` | `void` | Handle error path | +| `EnsureAwakening` | `void` | Guarantee cleanup execution | +| `MeasureTranceDepth` | `number` | Measure runtime in milliseconds | +| `Memoize` | `suggestion` | Cache function results | + +:::tip Naming conventions +All DeepMind builtins use PascalCase (`RepeatAction`) and accept `suggestion()` blocks as parameters. +Signatures are case-insensitive, so `repeataction` works too. ::: -## Wiederholung & Timing +## Repetition & Timing ### RepeatAction(times, action) -- **Signatur:** `(times: number, action: () -> void) -> void` -- **Description:** Executes `action` `times`-mal aus. Negative Werte werden ignoriert. +- **Signature:** `(times: number, action: () -> void) -> void` +- **Description:** Executes `action` `times` times. Negative values are ignored. ```hyp RepeatAction(3, suggestion() { @@ -44,35 +44,35 @@ RepeatAction(3, suggestion() { ### DelayedSuggestion(action, delayMs) -- **Signatur:** `(action: () -> void, delay: number) -> void` -- **Description:** Executes `action` nach `delay` Millisekunden aus. Die Ausführung blockiert bis zum Ablauf der Zeit. +- **Signature:** `(action: () -> void, delay: number) -> void` +- **Description:** Executes `action` after `delay` milliseconds. Execution blocks until the time elapses. ```hyp DelayedSuggestion(suggestion() { - observe "Willkommen nach 2 Sekunden"; + observe "Welcome after 2 seconds"; }, 2000); ``` -## Bedingte Ausführung +## Conditional Execution ### IfTranced(condition, thenAction, elseAction) -- **Signatur:** `(condition: boolean, then: () -> void, otherwise: () -> void) -> void` -- **Description:** Evaluierte Bedingung; bei `true` wird `then`, sonst `otherwise` ausgeführt. +- **Signature:** `(condition: boolean, then: () -> void, otherwise: () -> void) -> void` +- **Description:** Evaluates condition; if `true` runs `then`, otherwise runs `otherwise`. ```hyp IfTranced(audienceSize > 10, - suggestion() { observe "Großgruppe"; }, - suggestion() { observe "Intime Sitzung"; } + suggestion() { observe "Large group"; }, + suggestion() { observe "Intimate session"; } ); ``` -## Komposition & Pipelines +## Composition & Pipelines ### Compose(f, g) -- **Signatur:** `(f: (B) -> C, g: (A) -> B) -> (A -> C)` -- **Description:** Erst `g`, dann `f`. Nützlich für wiederverwendbare Datenpipelines. +- **Signature:** `(f: (B) -> C, g: (A) -> B) -> (A -> C)` +- **Description:** First `g`, then `f`. Useful for reusable data pipelines. ```hyp suggestion double(x: number): number { awaken x * 2; } @@ -84,20 +84,20 @@ induce result: number = transformer(5); // 30 ### Pipe(f, g) -- **Signatur:** `(f: (A) -> B, g: (B) -> C) -> (A -> C)` -- **Description:** Umgekehrte Reihenfolge: zuerst `f`, danach `g`. +- **Signature:** `(f: (A) -> B, g: (B) -> C) -> (A -> C)` +- **Description:** Reverse order: first `f`, then `g`. ```hyp induce pipeline = Pipe(double, addTen); observe pipeline(5); // 20 ``` -## Schleifensteuerung +## Loop Control ### RepeatUntil(action, condition) -- **Signatur:** `(action: () -> void, condition: () -> boolean) -> void` -- **Description:** Executes `action` aus, solange `condition()` `false` liefert. Bedingung wird nach jedem Durchlauf geprüft. +- **Signature:** `(action: () -> void, condition: () -> boolean) -> void` +- **Description:** Executes `action` while `condition()` returns `false`. Condition is checked after each iteration. ```hyp induce counter: number = 0; @@ -109,26 +109,26 @@ RepeatUntil( ### RepeatWhile(condition, action) -- **Signatur:** `(condition: () -> boolean, action: () -> void) -> void` -- **Description:** Checks `condition()` vor jedem Durchlauf; bei `true` läuft `action`, sonst endet die Schleife. +- **Signature:** `(condition: () -> boolean, action: () -> void) -> void` +- **Description:** Checks `condition()` before each iteration; if `true` runs `action`, otherwise ends the loop. ```hyp induce energy: number = 3; RepeatWhile( suggestion(): boolean { awaken energy > 0; }, suggestion() { - observe "Noch Energie: " + energy; + observe "Energy left: " + energy; energy = energy - 1; } ); ``` -## Sequenzen & Fehlerbehandlung +## Sequences & Error Handling ### SequentialTrance(actions) -- **Signatur:** `(actions: (() -> void)[]) -> void` -- **Description:** Executes eine Liste von `suggestion`-Blöcken nacheinander aus. +- **Signature:** `(actions: (() -> void)[]) -> void` +- **Description:** Executes a list of `suggestion` blocks sequentially. ```hyp SequentialTrance([ @@ -140,8 +140,8 @@ SequentialTrance([ ### TryOrAwaken(tryAction, catchAction) -- **Signatur:** `(try: () -> Result, catch: (error: string) -> void) -> void` -- **Description:** Executes `try` aus und ruft bei Fehlern `catch` mit der Fehlermeldung auf. +- **Signature:** `(try: () -> Result, catch: (error: string) -> void) -> void` +- **Description:** Executes `try` and calls `catch` with the error message on failure. ```hyp TryOrAwaken( @@ -149,50 +149,50 @@ TryOrAwaken( if (audienceSize < 0) { awaken Err("Negative Audience"); } - observe "Session startet"; + observe "Session starts"; awaken Ok(()); }, suggestion(error: string) { - observe "Fehler: " + error; + observe "Error: " + error; } ); ``` ### EnsureAwakening(mainAction, cleanup) -- **Signatur:** `(main: () -> void, cleanup: () -> void) -> void` -- **Description:** Executes `main` aus und garantiert, dass `cleanup` anschließend aufgerufen wird. +- **Signature:** `(main: () -> void, cleanup: () -> void) -> void` +- **Description:** Executes `main` and guarantees that `cleanup` is called afterwards. ```hyp EnsureAwakening( suggestion() { - observe "Datei öffnen"; + observe "Open file"; }, suggestion() { - observe "Datei schließen"; + observe "Close file"; } ); ``` -## Messung & Memoisierung +## Measurement & Memoization ### MeasureTranceDepth(action) -- **Signatur:** `(action: () -> void) -> number` -- **Description:** Executes `action` aus und gibt die Dauer in Millisekunden . +- **Signature:** `(action: () -> void) -> number` +- **Description:** Executes `action` and returns the duration in milliseconds. ```hyp induce duration: number = MeasureTranceDepth(suggestion() { RepeatAction(1000, suggestion() { observe "Tick"; }); }); -observe "Laufzeit: " + duration + " ms"; +observe "Runtime: " + duration + " ms"; ``` ### Memoize(f) -- **Signatur:** `(f: (A) -> R) -> (A -> R)` -- **Description:** Liefert eine Wrapper-Function. In der aktuellen Runtime-Version wird das Ergebnis nicht dauerhaft - zwischengespeichert, aber das Interface bleibt stabil für zukünftige Optimierungen. +- **Signature:** `(f: (A) -> R) -> (A -> R)` +- **Description:** Returns a wrapper function. In the current runtime version the result is not cached permanently, + but the interface stays stable for future optimizations. ```hyp suggestion square(x: number): number { awaken x * x; } @@ -202,17 +202,16 @@ observe memoSquare(4); // 16 observe memoSquare(4); // 16 (future calls from cache) ``` -## Tipps für den Einsatz +## Usage Tips -- `RepeatAction`, `RepeatUntil` und `RepeatWhile` blockieren synchron; nutze `DelayedSuggestion` für einfache - Zeitsteuerung. -- Kombiniere `Compose` und `Pipe` mit Array- oder String-Builtins, um filter-map-reduce-Ketten lesbar zu halten. -- `TryOrAwaken` erwartet einen `Result`-ähnlichen Return value. Gib `Ok(())` für Erfolg und `Err("Message")` für Fehler - . -- `MeasureTranceDepth` eignet sich für schnelle Performance-Messungen ohne zusätzliches Werkzeug. +- `RepeatAction`, `RepeatUntil`, and `RepeatWhile` block synchronously; use `DelayedSuggestion` for simple + time-based control. +- Combine `Compose` and `Pipe` with array or string builtins to keep filter-map-reduce chains readable. +- `TryOrAwaken` expects a `Result`-like return value. Use `Ok(())` for success and `Err("Message")` for errors. +- `MeasureTranceDepth` is suitable for quick performance measurements without extra tooling. -## See auch +## See also -- [Builtin-Overview](./overview) +- [Builtin Overview](./overview) - [Complete Reference – DeepMind](./_complete-reference#deepmind-builtins-higher-order-functions) -- [CLI Builtins anzeigen](../cli/commands#builtins) +- [Show CLI builtins](../cli/commands#builtins) diff --git a/hypnoscript-docs/docs/builtins/hashing-encoding.md b/hypnoscript-docs/docs/builtins/hashing-encoding.md index dd1ad32..5917121 100644 --- a/hypnoscript-docs/docs/builtins/hashing-encoding.md +++ b/hypnoscript-docs/docs/builtins/hashing-encoding.md @@ -19,7 +19,7 @@ Creates an MD5 hash of a string. ```hyp induce hash = MD5("Hello World"); observe "MD5 Hash: " + hash; -// Ausgabe: 5eb63bbbe01eeed093cb22bb8f5acdc3 +// Output: 5eb63bbbe01eeed093cb22bb8f5acdc3 ``` **Parameters:** @@ -35,7 +35,7 @@ Creates a SHA1 hash of a string. ```hyp induce hash = SHA1("Hello World"); observe "SHA1 Hash: " + hash; -// Ausgabe: 2aae6c35c94fcfb415dbe95f408b9ce91ee846ed +// Output: 2aae6c35c94fcfb415dbe95f408b9ce91ee846ed ``` **Parameters:** @@ -51,7 +51,7 @@ Creates a SHA256 hash of a string. ```hyp induce hash = SHA256("Hello World"); observe "SHA256 Hash: " + hash; -// Ausgabe: a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e +// Output: a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e ``` **Parameters:** @@ -67,7 +67,7 @@ Creates a SHA512 hash of a string. ```hyp induce hash = SHA512("Hello World"); observe "SHA512 Hash: " + hash; -// Ausgabe: 2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b +// Output: 2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b ``` **Parameters:** @@ -105,7 +105,7 @@ Encodes a string in Base64. induce original = "Hello World"; induce encoded = Base64Encode(original); observe "Base64 encoded: " + encoded; -// Ausgabe: SGVsbG8gV29ybGQ= +// Output: SGVsbG8gV29ybGQ= ``` **Parameters:** @@ -122,7 +122,7 @@ Decodes a Base64-encoded string. induce encoded = "SGVsbG8gV29ybGQ="; induce decoded = Base64Decode(encoded); observe "Base64 decoded: " + decoded; -// Ausgabe: Hello World +// Output: Hello World ``` **Parameters:** @@ -139,7 +139,7 @@ Encodes a string for URLs. induce original = "Hello World!"; induce encoded = URLEncode(original); observe "URL encoded: " + encoded; -// Ausgabe: Hello+World%21 +// Output: Hello+World%21 ``` **Parameters:** @@ -156,7 +156,7 @@ Decodes a URL-encoded string. induce encoded = "Hello+World%21"; induce decoded = URLDecode(encoded); observe "URL decoded: " + decoded; -// Ausgabe: Hello World! +// Output: Hello World! ``` **Parameters:** @@ -173,7 +173,7 @@ Encodes a string for HTML. induce original = ""; induce encoded = HTMLEncode(original); observe "HTML encoded: " + encoded; -// Ausgabe: <script>alert('Hello')</script> +// Output: <script>alert('Hello')</script> ``` **Parameters:** @@ -190,7 +190,7 @@ Decodes an HTML-encoded string. induce encoded = "<script>alert('Hello')</script>"; induce decoded = HTMLDecode(encoded); observe "HTML decoded: " + decoded; -// Ausgabe: +// Output: ``` **Parameters:** @@ -369,16 +369,16 @@ observe "Hash valid: " + isValid; ```hyp Focus { entrance { - // Passwort vom Benutzer erhalten + // Get password from user induce password = InputProvider("Enter password: "); - // Salt generieren + // Generate salt induce salt = GenerateSalt(16); - // Passwort hashen + // Hash password induce hash = PBKDF2(password, salt, 10000, 32); - // Hash und Salt speichern (ohne Passwort) + // Store hash and salt (without password) induce userData = { username: "john_doe", passwordHash: hash, @@ -386,22 +386,22 @@ Focus { createdAt: GetCurrentDateTime() }; - // In Datenbank speichern + // Store in database SaveUserData(userData); - observe "Benutzer sicher gespeichert!"; + observe "User stored securely!"; } } Relax; ``` -### File-Integrität prüfen +### Check File Integrity ```hyp Focus { entrance { induce filePath = "important-document.pdf"; - // Hash der Original-Datei + // Hash of the original file induce originalHash = HashFile(filePath, "SHA256"); observe "Original hash: " + originalHash; @@ -413,41 +413,41 @@ Focus { induce isIntegrityValid = VerifyHash(currentHash, originalHash); if (isIntegrityValid) { - observe "Datei-Integrität bestätigt!"; + observe "File integrity verified!"; } else { - observe "WARNUNG: Datei wurde verändert!"; + observe "WARNING: File was modified!"; } } } Relax; ``` -### Sichere Datenübertragung +### Secure Data Transfer ```hyp Focus { entrance { - induce secretMessage = "Vertrauliche Daten"; + induce secretMessage = "Confidential data"; induce key = GenerateRandomKey(32); // Encrypt message induce encrypted = AESEncrypt(secretMessage, key); - observe "Verschlüsselt: " + encrypted; + observe "Encrypted: " + encrypted; // Transfer message (simulated) induce transmittedData = encrypted; // Decrypt message induce decrypted = AESDecrypt(transmittedData, key); - observe "Entschlüsselt: " + decrypted; + observe "Decrypted: " + decrypted; if (decrypted == secretMessage) { - observe "Sichere Übertragung erfolgreich!"; + observe "Secure transfer successful!"; } } } Relax; ``` -### API-Sicherheit +### API Security ```hyp Focus { @@ -460,62 +460,62 @@ Focus { induce message = timestamp + ":" + data; induce signature = HMAC(message, apiKey, "SHA256"); - // API-Request mit Signatur + // API request with signature induce request = { timestamp: timestamp, data: data, signature: signature }; - observe "API-Request: " + ToJson(request); + observe "API request: " + ToJson(request); // On the server side, the signature would be verified induce isValidSignature = VerifyHMAC(message, signature, apiKey, "SHA256"); - observe "Signatur gültig: " + isValidSignature; + observe "Signature valid: " + isValidSignature; } } Relax; ``` -## Sicherheitshinweise +## Security Notes -### Wichtige Sicherheitsaspekte +### Important Security Considerations -1. **Salt-Werte**: Verwenden Sie immer zufällige Salt-Werte für Passwort-Hashing -2. **Iterationen**: Verwenden Sie mindestens 10.000 Iterationen für PBKDF2 -3. **Schlüssellänge**: Verwenden Sie mindestens 256-Bit-Schlüssel für AES -4. **Algorithmen**: Vermeiden Sie MD5 und SHA1 für Sicherheitsanwendungen -5. **Schlüssel-Management**: Speichern Sie Schlüssel sicher und niemals im Code +1. **Salt values**: Always use random salt values for password hashing +2. **Iterations**: Use at least 10,000 iterations for PBKDF2 +3. **Key length**: Use at least 256-bit keys for AES +4. **Algorithms**: Avoid MD5 and SHA1 for security applications +5. **Key management**: Store keys securely and never in code -### Deprecated-Functionen +### Deprecated Functions ```hyp // AVOID: MD5 for security applications induce weakHash = MD5("password"); -// VERWENDEN: Starke Hash-Funktionen +// USE: Strong hash functions induce strongHash = SHA256("password"); induce secureHash = PBKDF2("password", salt, 10000, 32); ``` -## Fehlerbehandlung +## Error Handling -Hashing- und Encoding-Functionen können bei ungültigen Inputn Fehler werfen: +Hashing and encoding functions can throw errors with invalid input: ```hyp Focus { entrance { try { induce hash = SHA256("valid-input"); - observe "Hash erfolgreich: " + hash; + observe "Hash successful: " + hash; } catch (error) { - observe "Fehler beim Hashing: " + error; + observe "Error hashing: " + error; } try { induce decoded = Base64Decode("invalid-base64"); - observe "Dekodierung erfolgreich: " + decoded; + observe "Decoding successful: " + decoded; } catch (error) { - observe "Fehler beim Dekodieren: " + error; + observe "Error decoding: " + error; } } } Relax; diff --git a/hypnoscript-docs/docs/builtins/hypnotic-functions.md b/hypnoscript-docs/docs/builtins/hypnotic-functions.md index a1fa85c..5120469 100644 --- a/hypnoscript-docs/docs/builtins/hypnotic-functions.md +++ b/hypnoscript-docs/docs/builtins/hypnotic-functions.md @@ -4,525 +4,525 @@ title: Hypnotic Functions # Hypnotic Functions -HypnoScript bietet spezielle Functionen für hypnotische Anwendungen und Trance-Induktion. +HypnoScript provides specialized functions for hypnotic applications and trance induction. ## Overview -Hypnotische Functionen sind das Herzstück von HypnoScript und ermöglichen es Ihnen, hypnotische Sitzungen, Trance-Induktionen und therapeutische Anwendungen zu programmieren. +Hypnotic functions are the core of HypnoScript and enable you to program hypnotic sessions, trance inductions, and therapeutic applications. -## Basic Trance-Functionen +## Basic Trance Functions ### HypnoticBreathing -Executes eine hypnotische Atemübung durch. +Executes a hypnotic breathing exercise. ```hyp -// Einfache Atemübung +// Simple breathing exercise HypnoticBreathing(); -// Atemübung mit spezifischer Anzahl von Zyklen +// Breathing exercise with a specific number of cycles HypnoticBreathing(10); ``` **Parameters:** -- `cycles` (optional): Anzahl der Atemzyklen (Standard: 5) +- `cycles` (optional): Number of breathing cycles (default: 5) ### HypnoticAnchoring -Creates oder aktiviert einen hypnotischen Anker. +Creates or activates a hypnotic anchor. ```hyp -// Anker erstellen -HypnoticAnchoring("Entspannung"); +// Create an anchor +HypnoticAnchoring("Relaxation"); // Anchor with specific feeling -HypnoticAnchoring("Sicherheit", "Wärme"); +HypnoticAnchoring("Safety", "Warmth"); ``` **Parameters:** -- `anchorName`: Name des Ankers -- `feeling` (optional): Assoziiertes Gefühl +- `anchorName`: Name of the anchor +- `feeling` (optional): Associated feeling ### HypnoticRegression -Executes eine hypnotische Regression durch. +Executes a hypnotic regression. ```hyp -// Standard-Regression +// Standard regression HypnoticRegression(); -// Regression zu spezifischem Alter +// Regression to a specific age HypnoticRegression(7); ``` **Parameters:** -- `targetAge` (optional): Zielalter für Regression +- `targetAge` (optional): Target age for regression ### HypnoticFutureProgression -Executes eine hypnotische Zukunftsvision durch. +Executes a hypnotic future progression. ```hyp -// Standard-Zukunftsvision +// Standard future progression HypnoticFutureProgression(); // Vision for specific year -HypnoticFutureProgression(5); // 5 Jahre in der Zukunft +HypnoticFutureProgression(5); // 5 years in the future ``` **Parameters:** -- `yearsAhead` (optional): Jahre in die Zukunft +- `yearsAhead` (optional): Years ahead -## Advanced hypnotische Functionen +## Advanced Hypnotic Functions ### ProgressiveRelaxation -Executes eine progressive Muskelentspannung durch. +Executes progressive muscle relaxation. ```hyp -// Standard-Entspannung +// Standard relaxation ProgressiveRelaxation(); -// Entspannung mit spezifischer Dauer pro Muskelgruppe -ProgressiveRelaxation(3); // 3 Sekunden pro Gruppe +// Relaxation with a specific duration per muscle group +ProgressiveRelaxation(3); // 3 seconds per group ``` **Parameters:** -- `durationPerGroup` (optional): Dauer pro Muskelgruppe in Sekunden +- `durationPerGroup` (optional): Duration per muscle group in seconds ### HypnoticVisualization -Executes eine hypnotische Visualisierung durch. +Executes a hypnotic visualization. ```hyp -// Einfache Visualisierung -HypnoticVisualization("ein friedlicher Garten"); +// Simple visualization +HypnoticVisualization("a peaceful garden"); -// Detaillierte Visualisierung -HypnoticVisualization("ein sonniger Strand mit sanften Wellen", 30); +// Detailed visualization +HypnoticVisualization("a sunny beach with gentle waves", 30); ``` **Parameters:** -- `scene`: Die zu visualisierende Szene -- `duration` (optional): Dauer in Sekunden +- `scene`: Scene to visualize +- `duration` (optional): Duration in seconds ### HypnoticSuggestion -Returns eine hypnotische Suggestion. +Returns a hypnotic suggestion. ```hyp -// Positive Suggestion -HypnoticSuggestion("Du fühlst dich zunehmend entspannt und sicher"); +// Positive suggestion +HypnoticSuggestion("You feel increasingly relaxed and safe"); // Suggestion with reinforcement -HypnoticSuggestion("Mit jedem Atemzug wirst du tiefer entspannt", 3); +HypnoticSuggestion("With each breath you relax more deeply", 3); ``` **Parameters:** -- `suggestion`: Die hypnotische Suggestion -- `repetitions` (optional): Anzahl der Wiederholungen +- `suggestion`: The hypnotic suggestion +- `repetitions` (optional): Number of repetitions ### TranceDeepening -Vertieft den hypnotischen Trance-Zustand. +Deepens the hypnotic trance state. ```hyp -// Standard-Trancevertiefung +// Standard trance deepening TranceDeepening(); -// Vertiefung mit spezifischem Level -TranceDeepening(3); // Level 3 (tief) +// Deepening with a specific level +TranceDeepening(3); // Level 3 (deep) ``` **Parameters:** -- `level` (optional): Trance-Level (1-5, 5 = am tiefsten) +- `level` (optional): Trance level (1-5, 5 = deepest) -## Spezialisierte hypnotische Functionen +## Specialized Hypnotic Functions ### EgoStateTherapy -Executes eine Ego-State-Therapie durch. +Executes ego-state therapy. ```hyp -// Ego-State-Identifikation +// Ego-state identification induce egoState = EgoStateTherapy("identify"); -// Ego-State-Integration +// Ego-state integration EgoStateTherapy("integrate", egoState); ``` **Parameters:** -- `action`: Aktion ("identify", "integrate", "communicate") -- `state` (optional): Ego-State für Integration +- `action`: Action ("identify", "integrate", "communicate") +- `state` (optional): Ego state for integration ### PartsWork -Arbeitet mit inneren Anteilen. +Works with inner parts. ```hyp -// Inneren Anteil identifizieren -induce part = PartsWork("find", "Angst"); +// Identify an inner part +induce part = PartsWork("find", "Fear"); -// Mit Anteil kommunizieren -PartsWork("communicate", part, "Was brauchst du?"); +// Communicate with a part +PartsWork("communicate", part, "What do you need?"); ``` **Parameters:** -- `action`: Aktion ("find", "communicate", "integrate") -- `partName`: Name des Anteils -- `message` (optional): Nachricht an den Anteil +- `action`: Action ("find", "communicate", "integrate") +- `partName`: Name of the part +- `message` (optional): Message to the part ### TimelineTherapy -Executes eine Timeline-Therapie durch. +Executes timeline therapy. ```hyp -// Timeline erstellen +// Create a timeline induce timeline = TimelineTherapy("create"); -// Auf Timeline navigieren -TimelineTherapy("navigate", timeline, "Vergangenheit"); +// Navigate the timeline +TimelineTherapy("navigate", timeline, "Past"); ``` **Parameters:** -- `action`: Aktion ("create", "navigate", "heal") -- `timeline` (optional): Timeline-Objekt -- `location` (optional): Position auf der Timeline +- `action`: Action ("create", "navigate", "heal") +- `timeline` (optional): Timeline object +- `location` (optional): Position on the timeline ### HypnoticPacing -Executes hypnotisches Pacing und Leading durch. +Executes hypnotic pacing and leading. ```hyp -// Pacing - aktuelle Erfahrung spiegeln -HypnoticPacing("Du sitzt hier und atmest"); +// Pacing - mirror the current experience +HypnoticPacing("You are sitting here and breathing"); // Leading - guide in desired direction -HypnoticLeading("Und mit jedem Atemzug entspannst du dich mehr"); +HypnoticLeading("And with each breath you relax more"); ``` **Parameters:** -- `statement`: Die Pacing- oder Leading-Aussage +- `statement`: The pacing or leading statement -## Therapeutische Functionen +## Therapeutic Functions ### PainManagement -Hypnotische Schmerzbehandlung. +Hypnotic pain management. ```hyp -// Schmerzreduktion -PainManagement("reduce", "Kopfschmerzen"); +// Pain reduction +PainManagement("reduce", "Headache"); -// Schmerztransformation -PainManagement("transform", "Rückenschmerzen", "Wärme"); +// Pain transformation +PainManagement("transform", "Back pain", "Warmth"); ``` **Parameters:** -- `action`: Aktion ("reduce", "transform", "eliminate") -- `painType`: Art des Schmerzes -- `transformation` (optional): Transformation des Schmerzes +- `action`: Action ("reduce", "transform", "eliminate") +- `painType`: Type of pain +- `transformation` (optional): Pain transformation ### AnxietyReduction -Reduziert Angst und Anspannung. +Reduces anxiety and tension. ```hyp -// Angstreduktion +// Anxiety reduction AnxietyReduction("general"); -// Spezifische Angst behandeln -AnxietyReduction("social", 0.8); // 80% Reduktion +// Treat specific anxiety +AnxietyReduction("social", 0.8); // 80% reduction ``` **Parameters:** -- `type`: Art der Angst ("general", "social", "performance") -- `reductionLevel` (optional): Reduktionslevel (0.0-1.0) +- `type`: Type of anxiety ("general", "social", "performance") +- `reductionLevel` (optional): Reduction level (0.0-1.0) ### ConfidenceBuilding -Baut Selbstvertrauen auf. +Builds confidence. ```hyp -// Allgemeines Selbstvertrauen +// General confidence ConfidenceBuilding(); -// Spezifisches Selbstvertrauen +// Specific confidence ConfidenceBuilding("public-speaking", 0.9); ``` **Parameters:** -- `area` (optional): Bereich des Selbstvertrauens -- `level` (optional): Gewünschtes Level (0.0-1.0) +- `area` (optional): Confidence area +- `level` (optional): Desired level (0.0-1.0) ### HabitChange -Unterstützt Gewohnheitsänderungen. +Supports habit change. ```hyp -// Gewohnheit identifizieren -induce habit = HabitChange("identify", "Rauchen"); +// Identify habit +induce habit = HabitChange("identify", "Smoking"); // Change habit -HabitChange("modify", habit, "gesunde Atemübungen"); +HabitChange("modify", habit, "healthy breathing exercises"); ``` **Parameters:** -- `action`: Aktion ("identify", "modify", "eliminate") -- `habitName`: Name der Gewohnheit -- `replacement` (optional): Ersatzverhalten +- `action`: Action ("identify", "modify", "eliminate") +- `habitName`: Habit name +- `replacement` (optional): Replacement behavior -## Monitoring und Feedback +## Monitoring and Feedback ### TranceDepth -Misst die aktuelle Trance-Tiefe. +Measures the current trance depth. ```hyp induce depth = TranceDepth(); -observe "Aktuelle Trance-Tiefe: " + depth + "/10"; +observe "Current trance depth: " + depth + "/10"; ``` -**Return value:** Trance-Tiefe von 1-10 +**Return value:** Trance depth from 1-10 ### HypnoticResponsiveness -Misst die hypnotische Reaktionsfähigkeit. +Measures hypnotic responsiveness. ```hyp induce responsiveness = HypnoticResponsiveness(); -observe "Hypnotische Reaktionsfähigkeit: " + responsiveness + "%"; +observe "Hypnotic responsiveness: " + responsiveness + "%"; ``` -**Return value:** Reaktionsfähigkeit in Prozent +**Return value:** Responsiveness in percent ### SuggestionAcceptance -Überprüft die Akzeptanz von Suggestionen. +Checks suggestion acceptance. ```hyp -induce acceptance = SuggestionAcceptance("Du fühlst dich entspannt"); -observe "Suggestion-Akzeptanz: " + acceptance + "%"; +induce acceptance = SuggestionAcceptance("You feel relaxed"); +observe "Suggestion acceptance: " + acceptance + "%"; ``` **Parameters:** -- `suggestion`: Die zu testende Suggestion +- `suggestion`: Suggestion to test -**Return value:** Akzeptanz in Prozent +**Return value:** Acceptance in percent -## Sicherheitsfunktionen +## Safety Functions ### SafetyCheck -Executes eine Sicherheitsüberprüfung durch. +Executes a safety check. ```hyp induce safetyStatus = SafetyCheck(); if (safetyStatus.isSafe) { - observe "Sitzung ist sicher"; + observe "Session is safe"; } else { - observe "Sicherheitswarnung: " + safetyStatus.warning; + observe "Safety warning: " + safetyStatus.warning; } ``` -**Return value:** Sicherheitsstatus-Objekt +**Return value:** Safety status object ### EmergencyExit -Notfall-Ausstieg aus Trance. +Emergency exit from trance. ```hyp -// Sofortiger Ausstieg +// Immediate exit EmergencyExit(); -// Sanfter Ausstieg +// Gentle exit EmergencyExit("gentle"); ``` **Parameters:** -- `mode` (optional): Ausstiegsmodus ("immediate", "gentle") +- `mode` (optional): Exit mode ("immediate", "gentle") ### Grounding -Erdet den Klienten nach der Sitzung. +Grounds the client after the session. ```hyp -// Standard-Erdung +// Standard grounding Grounding(); -// Erweiterte Erdung +// Extended grounding Grounding("visual", 60); // Visual grounding for 60 seconds ``` **Parameters:** -- `method` (optional): Erdungsmethode ("visual", "physical", "mental") -- `duration` (optional): Dauer in Sekunden +- `method` (optional): Grounding method ("visual", "physical", "mental") +- `duration` (optional): Duration in seconds ## Best Practices -### Vollständige hypnotische Sitzung +### Complete Hypnotic Session ```hyp Focus { entrance { - // Sicherheitscheck + // Safety check induce safety = SafetyCheck(); if (!safety.isSafe) { - observe "Sitzung nicht sicher - Abbruch"; + observe "Session not safe - aborting"; return; } - // Einleitung - observe "Willkommen zu Ihrer hypnotischen Sitzung"; + // Introduction + observe "Welcome to your hypnotic session"; drift(2000); - // Trance-Induktion + // Trance induction HypnoticBreathing(5); ProgressiveRelaxation(3); - // Trance vertiefen + // Deepen trance TranceDeepening(3); - // Hauptarbeit - HypnoticSuggestion("Du fühlst dich zunehmend entspannt und sicher", 3); - HypnoticVisualization("ein friedlicher Garten", 30); + // Main work + HypnoticSuggestion("You feel increasingly relaxed and safe", 3); + HypnoticVisualization("a peaceful garden", 30); - // Erdung + // Grounding Grounding("visual", 60); - observe "Sitzung erfolgreich abgeschlossen"; + observe "Session completed successfully"; } } Relax; ``` -### Therapeutische Anwendung +### Therapeutic Application ```hyp Focus { entrance { - // Anamnese - induce clientName = InputProvider("Name des Klienten: "); - induce issue = InputProvider("Hauptproblem: "); + // Intake + induce clientName = InputProvider("Client name: "); + induce issue = InputProvider("Primary issue: "); - // Sicherheitscheck + // Safety check if (!SafetyCheck().isSafe) { - observe "Klient ist nicht für Hypnose geeignet"; + observe "Client is not suitable for hypnosis"; return; } - // Individuelle Sitzung - if (issue == "Angst") { + // Individual session + if (issue == "Anxiety") { AnxietyReduction("general", 0.8); - } else if (issue == "Schmerzen") { - PainManagement("reduce", "chronische Schmerzen"); - } else if (issue == "Gewohnheit") { - induce habit = HabitChange("identify", "Rauchen"); - HabitChange("modify", habit, "tiefe Atemzüge"); + } else if (issue == "Pain") { + PainManagement("reduce", "chronic pain"); + } else if (issue == "Habit") { + induce habit = HabitChange("identify", "Smoking"); + HabitChange("modify", habit, "deep breathing"); } - // Nachsorge - observe "Therapeutische Sitzung abgeschlossen"; - observe "Nächster Termin in einer Woche empfohlen"; + // Follow-up + observe "Therapeutic session completed"; + observe "Next appointment recommended in one week"; } } Relax; ``` -### Gruppen-Hypnose +### Group Hypnosis ```hyp Focus { entrance { - // Gruppeneinstimmung - induce groupSize = InputProvider("Anzahl Teilnehmer: "); - observe "Willkommen zur Gruppen-Hypnose-Sitzung"; + // Group alignment + induce groupSize = InputProvider("Number of participants: "); + observe "Welcome to the group hypnosis session"; - // Kollektive Trance-Induktion + // Collective trance induction HypnoticBreathing(3); ProgressiveRelaxation(2); - // Gruppen-Suggestion - HypnoticSuggestion("Ihr alle fühlt euch zunehmend entspannt", 2); + // Group suggestion + HypnoticSuggestion("All of you feel increasingly relaxed", 2); - // Individuelle Arbeit (simuliert) + // Individual work (simulated) for (induce i = 0; i < groupSize; induce i = i + 1) { induce individualDepth = TranceDepth(); - observe "Teilnehmer " + (i + 1) + " Trance-Tiefe: " + individualDepth; + observe "Participant " + (i + 1) + " trance depth: " + individualDepth; } - // Gruppen-Erdung + // Group grounding Grounding("visual", 45); - observe "Gruppen-Sitzung erfolgreich abgeschlossen"; + observe "Group session completed successfully"; } } Relax; ``` -## Sicherheitsrichtlinien +## Safety Guidelines -### Wichtige Sicherheitsaspekte +### Important Safety Considerations -1. **Immer SafetyCheck durchführen** vor jeder hypnotischen Sitzung -2. **Notfall-Ausstieg bereithalten** mit EmergencyExit() -3. **Sanfte Einleitung** mit HypnoticBreathing und ProgressiveRelaxation -4. **Individuelle Anpassung** der Sitzung an den Klienten -5. **Ausreichende Erdung** nach jeder Sitzung +1. **Always run SafetyCheck** before every hypnotic session +2. **Keep an emergency exit ready** with EmergencyExit() +3. **Gentle induction** with HypnoticBreathing and ProgressiveRelaxation +4. **Customize sessions** to the client +5. **Adequate grounding** after every session -### Kontraindikationen +### Contraindications ```hyp // Check contraindications induce contraindications = CheckContraindications(); if (contraindications.hasPsychosis) { - observe "WARNUNG: Psychose - Hypnose kontraindiziert"; + observe "WARNING: Psychosis - hypnosis contraindicated"; return; } if (contraindications.hasEpilepsy) { - observe "VORSICHT: Epilepsie - Sanfte Hypnose nur unter Aufsicht"; + observe "CAUTION: Epilepsy - gentle hypnosis only under supervision"; } ``` -## Fehlerbehandlung +## Error Handling -Hypnotische Functionen können bei unerwarteten Reaktionen Fehler werfen: +Hypnotic functions can throw errors on unexpected reactions: ```hyp Focus { entrance { try { HypnoticBreathing(5); - observe "Atemübung erfolgreich"; + observe "Breathing exercise successful"; } catch (error) { - observe "Fehler bei Atemübung: " + error; + observe "Error during breathing exercise: " + error; EmergencyExit("gentle"); } try { induce depth = TranceDepth(); if (depth < 3) { - observe "Trance zu flach - vertiefen"; + observe "Trance too shallow - deepening"; TranceDeepening(2); } } catch (error) { - observe "Fehler bei Trance-Monitoring: " + error; + observe "Error during trance monitoring: " + error; } } } Relax; @@ -530,10 +530,10 @@ Focus { ## Next Steps -- [System Functions](./system-functions) - System-spezifische Functionen -- [Time & Date Functions](./time-date-functions) - Zeit- und Datumsfunktionen -- [Therapeutic Applications](../examples/therapeutic-examples) - Therapeutische Anwendungen +- [System Functions](./system-functions) - System-specific functions +- [Time & Date Functions](./time-date-functions) - Time and date functions +- [Therapeutic Applications](../examples/therapeutic-examples) - Therapeutic applications --- -**Hypnotische Functionen gemeistert? Dann lerne [System Functions](./system-functions) kennen!** ✅ +**Mastered hypnotic functions? Then explore [System Functions](./system-functions)!** ✅ diff --git a/hypnoscript-docs/docs/builtins/math-functions.md b/hypnoscript-docs/docs/builtins/math-functions.md index 8b6de19..7db2e60 100644 --- a/hypnoscript-docs/docs/builtins/math-functions.md +++ b/hypnoscript-docs/docs/builtins/math-functions.md @@ -205,7 +205,7 @@ Checks if a number is prime. ```hyp Focus { induce result: boolean = is_prime(7); // true - observe "7 ist Primzahl: " + result; + observe "7 is prime: " + result; } Relax ``` @@ -591,7 +591,7 @@ induce random2 = RandomInt(-100, 100); // Random integer between -100 and 100 Selects a random element from an array. ```hyp -induce fruits = ["Apfel", "Banane", "Orange"]; +induce fruits = ["Apple", "Banana", "Orange"]; induce randomFruit = RandomChoice(fruits); // Random fruit ``` @@ -716,16 +716,16 @@ Focus { } } - observe "Notenverteilung:"; - observe "Ausgezeichnet (90+): " + excellent; - observe "Gut (80-89): " + good; - observe "Durchschnittlich (70-79): " + average; - observe "Schwach (<70): " + poor; + observe "Grade distribution:"; + observe "Excellent (90+): " + excellent; + observe "Good (80-89): " + good; + observe "Average (70-79): " + average; + observe "Poor (<70): " + poor; } } Relax; ``` -### Finanzmathematik +### Financial Mathematics ```hyp Focus { @@ -741,114 +741,114 @@ Focus { } entrance { - // Zinseszins + // Compound interest induce principal = 10000; - induce rate = 5; // 5% pro Jahr - induce time = 10; // 10 Jahre - induce compounds = 12; // Monatlich + induce rate = 5; // 5% per year + induce time = 10; // 10 years + induce compounds = 12; // Monthly induce finalAmount = calculateCompoundInterest(principal, rate / 100, time, compounds); - observe "Zinseszins-Berechnung:"; - observe "Anfangskapital: €" + principal; - observe "Zinssatz: " + rate + "%"; - observe "Laufzeit: " + time + " Jahre"; - observe "Endkapital: €" + Round(finalAmount, 2); - observe "Gewinn: €" + Round(finalAmount - principal, 2); - - // Kreditberechnung + observe "Compound interest calculation:"; + observe "Principal: €" + principal; + observe "Rate: " + rate + "%"; + observe "Term: " + time + " years"; + observe "Final amount: €" + Round(finalAmount, 2); + observe "Profit: €" + Round(finalAmount - principal, 2); + + // Loan calculation induce loanAmount = 200000; - induce loanRate = 3.5; // 3.5% pro Jahr + induce loanRate = 3.5; // 3.5% per year induce loanYears = 30; induce monthlyPayment = calculateLoanPayment(loanAmount, loanRate, loanYears); induce totalPayment = monthlyPayment * loanYears * 12; induce totalInterest = totalPayment - loanAmount; - observe "Kreditberechnung:"; - observe "Kreditsumme: €" + loanAmount; - observe "Zinssatz: " + loanRate + "%"; - observe "Laufzeit: " + loanYears + " Jahre"; - observe "Monatliche Rate: €" + Round(monthlyPayment, 2); - observe "Gesamtzinsen: €" + Round(totalInterest, 2); - observe "Gesamtrückzahlung: €" + Round(totalPayment, 2); + observe "Loan calculation:"; + observe "Loan amount: €" + loanAmount; + observe "Rate: " + loanRate + "%"; + observe "Term: " + loanYears + " years"; + observe "Monthly payment: €" + Round(monthlyPayment, 2); + observe "Total interest: €" + Round(totalInterest, 2); + observe "Total repayment: €" + Round(totalPayment, 2); } } Relax; ``` -### Wissenschaftliche Berechnungen +### Scientific Calculations ```hyp Focus { entrance { - // Physikalische Berechnungen + // Physics calculations induce mass = 10; // kg induce velocity = 20; // m/s induce kineticEnergy = 0.5 * mass * Pow(velocity, 2); - observe "Kinetische Energie:"; - observe "Masse: " + mass + " kg"; - observe "Geschwindigkeit: " + velocity + " m/s"; - observe "Energie: " + Round(kineticEnergy, 2) + " J"; + observe "Kinetic energy:"; + observe "Mass: " + mass + " kg"; + observe "Velocity: " + velocity + " m/s"; + observe "Energy: " + Round(kineticEnergy, 2) + " J"; - // Chemische Berechnungen + // Chemistry calculations induce temperature = 25; // Celsius induce kelvin = temperature + 273.15; - observe "Temperaturumrechnung:"; + observe "Temperature conversion:"; observe "Celsius: " + temperature + "°C"; observe "Kelvin: " + Round(kelvin, 2) + " K"; - // Trigonometrische Anwendungen - induce angle = 30; // Grad + // Trigonometric applications + induce angle = 30; // Degrees induce radians = DegreesToRadians(angle); induce sinValue = Sin(radians); induce cosValue = Cos(radians); induce tanValue = Tan(radians); - observe "Trigonometrie (" + angle + "°):"; - observe "Sinus: " + Round(sinValue, 4); - observe "Kosinus: " + Round(cosValue, 4); - observe "Tangens: " + Round(tanValue, 4); + observe "Trigonometry (" + angle + "°):"; + observe "Sine: " + Round(sinValue, 4); + observe "Cosine: " + Round(cosValue, 4); + observe "Tangent: " + Round(tanValue, 4); - // Logarithmische Skalen - induce ph = 7; // pH-Wert + // Logarithmic scales + induce ph = 7; // pH value induce hConcentration = Pow(10, -ph); - observe "pH-Berechnung:"; - observe "pH-Wert: " + ph; - observe "H+-Konzentration: " + hConcentration + " mol/L"; + observe "pH calculation:"; + observe "pH value: " + ph; + observe "H+ concentration: " + hConcentration + " mol/L"; } } Relax; ``` ## Best Practices -### Numerische Genauigkeit +### Numerical Accuracy ```hyp -// Vermeide Gleitkomma-Vergleiche +// Avoid floating-point comparisons if (Abs(a - b) < 0.0001) { - // a und b sind praktisch gleich + // a and b are practically equal } -// Verwende Round für Outputn -observe "Ergebnis: " + Round(result, 4); +// Use Round for output +observe "Result: " + Round(result, 4); -// Große Zahlen +// Large numbers induce largeNumber = 123456789; induce formatted = FormatString("{0:N0}", largeNumber); -observe "Zahl: " + formatted; // 123,456,789 +observe "Number: " + formatted; // 123,456,789 ``` -### Performance-Optimierung +### Performance Optimization ```hyp -// Caching von Konstanten +// Cache constants induce PI_OVER_180 = PI / 180; suggestion degreesToRadians(degrees) { awaken degrees * PI_OVER_180; } -// Vermeide wiederholte Berechnungen +// Avoid repeated calculations suggestion calculateDistance(x1, y1, x2, y2) { induce dx = x2 - x1; induce dy = y2 - y1; @@ -856,12 +856,12 @@ suggestion calculateDistance(x1, y1, x2, y2) { } ``` -### Fehlerbehandlung +### Error Handling ```hyp suggestion safeDivision(numerator, denominator) { if (denominator == 0) { - observe "Fehler: Division durch Null!"; + observe "Error: division by zero!"; awaken 0; } return numerator / denominator; @@ -869,7 +869,7 @@ suggestion safeDivision(numerator, denominator) { suggestion safeLog(x) { if (x <= 0) { - observe "Fehler: Logarithmus nur für positive Zahlen!"; + observe "Error: logarithm only for positive numbers!"; awaken 0; } return Log(x); diff --git a/hypnoscript-docs/docs/builtins/performance-functions.md b/hypnoscript-docs/docs/builtins/performance-functions.md index 2d48cc2..aa5db83 100644 --- a/hypnoscript-docs/docs/builtins/performance-functions.md +++ b/hypnoscript-docs/docs/builtins/performance-functions.md @@ -4,137 +4,137 @@ title: Performance Functions # Performance Functions -HypnoScript bietet umfangreiche Performance-Functionen für die Überwachung und Optimierung von Skripten. +HypnoScript provides extensive performance functions for monitoring and optimizing scripts. ## Overview -Performance-Functionen ermöglichen es Ihnen, die Ausführungszeit, Speichernutzung und andere Performance-Metriken Ihrer HypnoScript-Programme zu überwachen und zu optimieren. +Performance functions let you monitor and optimize execution time, memory usage, and other performance metrics for HypnoScript programs. -## Basic Performance-Functionen +## Basic Performance Functions ### Benchmark -Misst die Ausführungszeit einer Function über mehrere Iterationen. +Measures execution time for a function over multiple iterations. ```hyp induce result = Benchmark(function() { - // Code zum Messen + // Code to measure return someValue; -}, 1000); // 1000 Iterationen +}, 1000); // 1000 iterations -observe "Durchschnittliche Ausführungszeit: " + result + " ms"; +observe "Average execution time: " + result + " ms"; ``` **Parameters:** -- `function`: Die zu messende Function -- `iterations`: Anzahl der Iterationen +- `function`: Function to measure +- `iterations`: Number of iterations -**Return value:** Durchschnittliche Ausführungszeit in Millisekunden +**Return value:** Average execution time in milliseconds ### GetPerformanceMetrics -Sammelt umfassende Performance-Metriken des aktuellen Systems. +Collects comprehensive performance metrics for the current system. ```hyp induce metrics = GetPerformanceMetrics(); -observe "CPU-Auslastung: " + metrics.cpuUsage + "%"; -observe "Speichernutzung: " + metrics.memoryUsage + " MB"; -observe "Verfügbarer Speicher: " + metrics.availableMemory + " MB"; +observe "CPU usage: " + metrics.cpuUsage + "%"; +observe "Memory usage: " + metrics.memoryUsage + " MB"; +observe "Available memory: " + metrics.availableMemory + " MB"; ``` -**Return value:** Dictionary mit Performance-Metriken +**Return value:** Dictionary with performance metrics ### GetExecutionTime -Misst die Ausführungszeit eines Code-Blocks. +Measures execution time of a code block. ```hyp induce startTime = GetCurrentTime(); -// Code zum Messen +// Code to measure induce endTime = GetCurrentTime(); induce executionTime = (endTime - startTime) * 1000; // in ms -observe "Ausführungszeit: " + executionTime + " ms"; +observe "Execution time: " + executionTime + " ms"; ``` -## Speicher-Management +## Memory Management ### GetMemoryUsage -Returns die aktuelle Speichernutzung . +Returns current memory usage. ```hyp induce memoryUsage = GetMemoryUsage(); -observe "Aktuelle Speichernutzung: " + memoryUsage + " MB"; +observe "Current memory usage: " + memoryUsage + " MB"; ``` -**Return value:** Speichernutzung in Megabyte +**Return value:** Memory usage in megabytes ### GetAvailableMemory -Returns den availableen Speicher . +Returns available memory. ```hyp induce availableMemory = GetAvailableMemory(); -observe "Verfügbarer Speicher: " + availableMemory + " MB"; +observe "Available memory: " + availableMemory + " MB"; ``` -**Return value:** Verfügbarer Speicher in Megabyte +**Return value:** Available memory in megabytes ### ForceGarbageCollection -Erzwingt eine Garbage Collection. +Forces garbage collection. ```hyp ForceGarbageCollection(); -observe "Garbage Collection durchgeführt"; +observe "Garbage collection completed"; ``` -## CPU-Monitoring +## CPU Monitoring ### GetCPUUsage -Returns die aktuelle CPU-Auslastung . +Returns current CPU usage. ```hyp induce cpuUsage = GetCPUUsage(); -observe "CPU-Auslastung: " + cpuUsage + "%"; +observe "CPU usage: " + cpuUsage + "%"; ``` -**Return value:** CPU-Auslastung in Prozent +**Return value:** CPU usage in percent ### GetProcessorCount -Returns die Anzahl der availableen Prozessoren . +Returns the number of available processors. ```hyp induce processorCount = GetProcessorCount(); -observe "Anzahl Prozessoren: " + processorCount; +observe "Processor count: " + processorCount; ``` -**Return value:** Anzahl der Prozessoren +**Return value:** Processor count -## Profiling-Functionen +## Profiling Functions ### StartProfiling -Startet das Performance-Profiling. +Starts performance profiling. ```hyp StartProfiling("my-profile"); -// Code zum Profilen +// Code to profile StopProfiling(); induce profileData = GetProfileData("my-profile"); -observe "Profil-Daten: " + profileData; +observe "Profile data: " + profileData; ``` **Parameters:** -- `profileName`: Name des Profils +- `profileName`: Profile name ### StopProfiling -Stoppt das Performance-Profiling. +Stops performance profiling. ```hyp StartProfiling("test"); @@ -144,59 +144,59 @@ StopProfiling(); ### GetProfileData -Returns die Profil-Daten . +Returns profile data. ```hyp induce profileData = GetProfileData("my-profile"); -observe "Funktionsaufrufe: " + profileData.functionCalls; -observe "Ausführungszeit: " + profileData.executionTime; +observe "Function calls: " + profileData.functionCalls; +observe "Execution time: " + profileData.executionTime; ``` **Parameters:** -- `profileName`: Name des Profils +- `profileName`: Profile name -**Return value:** Dictionary mit Profil-Daten +**Return value:** Dictionary with profile data -## Optimierungs-Functionen +## Optimization Functions ### OptimizeMemory -Executes Speicheroptimierungen durch. +Executes memory optimizations. ```hyp OptimizeMemory(); -observe "Speicheroptimierung durchgeführt"; +observe "Memory optimization completed"; ``` ### OptimizeCPU -Executes CPU-Optimierungen durch. +Executes CPU optimizations. ```hyp OptimizeCPU(); -observe "CPU-Optimierung durchgeführt"; +observe "CPU optimization completed"; ``` -## Monitoring-Functionen +## Monitoring Functions ### StartMonitoring -Startet das kontinuierliche Performance-Monitoring. +Starts continuous performance monitoring. ```hyp -StartMonitoring(5000); // Alle 5 Sekunden +StartMonitoring(5000); // Every 5 seconds // Code StopMonitoring(); ``` **Parameters:** -- `interval`: Intervall in Millisekunden +- `interval`: Interval in milliseconds ### StopMonitoring -Stoppt das Performance-Monitoring. +Stops performance monitoring. ```hyp StartMonitoring(1000); @@ -206,55 +206,55 @@ StopMonitoring(); ### GetMonitoringData -Returns die Monitoring-Daten . +Returns monitoring data. ```hyp induce monitoringData = GetMonitoringData(); -observe "Durchschnittliche CPU-Auslastung: " + monitoringData.avgCpuUsage; -observe "Maximale Speichernutzung: " + monitoringData.maxMemoryUsage; +observe "Average CPU usage: " + monitoringData.avgCpuUsage; +observe "Peak memory usage: " + monitoringData.maxMemoryUsage; ``` -**Return value:** Dictionary mit Monitoring-Daten +**Return value:** Dictionary with monitoring data -## Advanced Performance-Functionen +## Advanced Performance Functions ### GetSystemInfo -Returns detaillierte System-Informationen . +Returns detailed system information. ```hyp induce systemInfo = GetSystemInfo(); -observe "Betriebssystem: " + systemInfo.os; -observe "Architektur: " + systemInfo.architecture; -observe "Framework-Version: " + systemInfo.frameworkVersion; +observe "Operating system: " + systemInfo.os; +observe "Architecture: " + systemInfo.architecture; +observe "Framework version: " + systemInfo.frameworkVersion; ``` -**Return value:** Dictionary mit System-Informationen +**Return value:** Dictionary with system information ### GetProcessInfo -Returns Informationen über den aktuellen Prozess . +Returns information about the current process. ```hyp induce processInfo = GetProcessInfo(); -observe "Prozess-ID: " + processInfo.processId; -observe "Arbeitsspeicher: " + processInfo.workingSet + " MB"; -observe "CPU-Zeit: " + processInfo.cpuTime + " ms"; +observe "Process ID: " + processInfo.processId; +observe "Working set: " + processInfo.workingSet + " MB"; +observe "CPU time: " + processInfo.cpuTime + " ms"; ``` -**Return value:** Dictionary mit Prozess-Informationen +**Return value:** Dictionary with process information ## Best Practices -### Performance-Monitoring +### Performance Monitoring ```hyp Focus { entrance { - // Monitoring starten + // Start monitoring StartMonitoring(1000); - // Performance-kritischer Code + // Performance-critical code induce result = Benchmark(function() { // Code needing optimization induce sum = 0; @@ -264,84 +264,84 @@ Focus { return sum; }, 100); - // Monitoring stoppen + // Stop monitoring StopMonitoring(); - // Ergebnisse auswerten + // Evaluate results induce monitoringData = GetMonitoringData(); if (monitoringData.avgCpuUsage > 80) { - observe "WARNUNG: Hohe CPU-Auslastung erkannt!"; + observe "WARNING: High CPU usage detected!"; } - observe "Benchmark-Ergebnis: " + result + " ms"; + observe "Benchmark result: " + result + " ms"; } } Relax; ``` -### Speicheroptimierung +### Memory Optimization ```hyp Focus { entrance { induce initialMemory = GetMemoryUsage(); - // Speicherintensive Operationen + // Memory-intensive operations induce largeArray = []; for (induce i = 0; i < 100000; induce i = i + 1) { - ArrayPush(largeArray, "Element " + i); + ArrayPush(largeArray, "Item " + i); } induce memoryAfterOperation = GetMemoryUsage(); - observe "Speicherzuwachs: " + (memoryAfterOperation - initialMemory) + " MB"; + observe "Memory increase: " + (memoryAfterOperation - initialMemory) + " MB"; - // Speicheroptimierung + // Memory optimization ForceGarbageCollection(); OptimizeMemory(); induce memoryAfterOptimization = GetMemoryUsage(); - observe "Speicher nach Optimierung: " + memoryAfterOptimization + " MB"; + observe "Memory after optimization: " + memoryAfterOptimization + " MB"; } } Relax; ``` -### Profiling-Workflow +### Profiling Workflow ```hyp Focus { entrance { - // Profiling starten + // Start profiling StartProfiling("main-operation"); - // Hauptoperation + // Main operation induce result = PerformMainOperation(); - // Profiling stoppen + // Stop profiling StopProfiling(); - // Profil-Daten analysieren + // Analyze profile data induce profileData = GetProfileData("main-operation"); if (profileData.executionTime > 1000) { - observe "WARNUNG: Operation dauert länger als 1 Sekunde!"; + observe "WARNING: Operation takes longer than 1 second!"; } - observe "Profil-Ergebnis: " + profileData; + observe "Profile result: " + profileData; } } Relax; ``` -## Fehlerbehandlung +## Error Handling -Performance-Functionen können bei unerwarteten Systemzuständen Fehler werfen: +Performance functions can throw errors under unexpected system conditions: ```hyp Focus { entrance { try { induce metrics = GetPerformanceMetrics(); - observe "Performance-Metriken: " + metrics; + observe "Performance metrics: " + metrics; } catch (error) { - observe "Fehler beim Abrufen der Performance-Metriken: " + error; + observe "Error retrieving performance metrics: " + error; } } } Relax; @@ -349,10 +349,10 @@ Focus { ## Next Steps -- [System Functions](./system-functions) - System-spezifische Functionen -- [Utility Functions](./utility-functions) - Allgemeine Hilfsfunktionen -- [Testing Performance](../testing/performance) - Performance-Testing-Guide +- [System Functions](./system-functions) - System-specific functions +- [Utility Functions](./utility-functions) - General helper functions +- [Testing Performance](../testing/performance) - Performance testing guide --- -**Performance-Optimierung gemeistert? Dann lerne [System Functions](./system-functions) kennen!** ✅ +**Mastered performance optimization? Then explore [System Functions](./system-functions)!** ✅ diff --git a/hypnoscript-docs/docs/builtins/string-functions.md b/hypnoscript-docs/docs/builtins/string-functions.md index 6760d88..49ef240 100644 --- a/hypnoscript-docs/docs/builtins/string-functions.md +++ b/hypnoscript-docs/docs/builtins/string-functions.md @@ -37,10 +37,10 @@ induce part2 = Substring(text, 5, 6); // "Script" Concatenates multiple strings. ```hyp -induce firstName = "Max"; -induce lastName = "Mustermann"; +induce firstName = "John"; +induce lastName = "Doe"; induce fullName = Concat(firstName, " ", lastName); -observe fullName; // "Max Mustermann" +observe fullName; // "John Doe" ``` ## String Manipulation @@ -93,7 +93,7 @@ Checks if a string is empty. ```hyp induce empty = ""; -induce notEmpty = "Hallo"; +induce notEmpty = "Hello"; induce isEmpty1 = IsEmpty(empty); // true induce isEmpty2 = IsEmpty(notEmpty); // false ``` @@ -104,7 +104,7 @@ Checks if a string contains only whitespace. ```hyp induce whitespace = " \t\n "; -induce text = "Hallo Welt"; +induce text = "Hello World"; induce isWhitespace1 = IsWhitespace(whitespace); // true induce isWhitespace2 = IsWhitespace(text); // false ``` @@ -114,7 +114,7 @@ induce isWhitespace2 = IsWhitespace(text); // false Checks if a string contains a substring. ```hyp -induce text = "HypnoScript ist eine Programmiersprache"; +induce text = "HypnoScript is a programming language"; induce hasScript = Contains(text, "Script"); // true induce hasPython = Contains(text, "Python"); // false ``` @@ -146,9 +146,9 @@ induce endsWithHypno = EndsWith(text, "Hypno"); // false Finds the first index of a substring. ```hyp -induce text = "HypnoScript ist eine Programmiersprache"; +induce text = "HypnoScript is a programming language"; induce index = IndexOf(text, "Script"); -observe "Index von 'Script': " + index; // 5 +observe "Index of 'Script': " + index; // 5 ``` ### LastIndexOf(str, substring) @@ -158,7 +158,7 @@ Finds the last index of a substring. ```hyp induce text = "HypnoScript Script Script"; induce lastIndex = LastIndexOf(text, "Script"); -observe "Letzter Index von 'Script': " + lastIndex; // 18 +observe "Last index of 'Script': " + lastIndex; // 18 ``` ### CountOccurrences(str, substring) @@ -168,7 +168,7 @@ Counts the occurrences of a substring. ```hyp induce text = "HypnoScript Script Script"; induce count = CountOccurrences(text, "Script"); -observe "Anzahl 'Script': " + count; // 3 +observe "Count of 'Script': " + count; // 3 ``` ## String Transformation @@ -218,9 +218,9 @@ observe "'" + trimmed + "'"; // "HypnoScript" Replaces all occurrences of a substring. ```hyp -induce text = "HypnoScript ist eine Programmiersprache"; -induce replaced = Replace(text, "Programmiersprache", "Sprache"); -observe replaced; // "HypnoScript ist eine Sprache" +induce text = "HypnoScript is a programming language"; +induce replaced = Replace(text, "programming language", "language"); +observe replaced; // "HypnoScript is a language" ``` ### ReplaceAll(str, oldValue, newValue) @@ -228,8 +228,8 @@ observe replaced; // "HypnoScript ist eine Sprache" Replaces all occurrences (alias for Replace). ```hyp -induce text = "Hallo Hallo Hallo"; -induce replaced = ReplaceAll(text, "Hallo", "Hi"); +induce text = "Hello Hello Hello"; +induce replaced = ReplaceAll(text, "Hello", "Hi"); observe replaced; // "Hi Hi Hi" ``` @@ -250,9 +250,9 @@ observe padded; // "00042" Pads a string on the right with characters. ```hyp -induce text = "Hallo"; +induce text = "Hello"; induce padded = PadRight(text, 10, "*"); -observe padded; // "Hallo*****" +observe padded; // "Hello*****" ``` ### FormatString(template, ...args) @@ -260,10 +260,10 @@ observe padded; // "Hallo*****" Formats a string with placeholders. ```hyp -induce name = "Max"; +induce name = "Alex"; induce age = 30; -induce formatted = FormatString("Hallo {0}, du bist {1} Jahre alt", name, age); -observe formatted; // "Hallo Max, du bist 30 Jahre alt" +induce formatted = FormatString("Hello {0}, you are {1} years old", name, age); +observe formatted; // "Hello Alex, you are 30 years old" ``` ## String Analysis (Advanced) @@ -323,9 +323,9 @@ induce isAlphaNum2 = IsAlphaNumeric(notAlphanumeric); // false Splits a string at a delimiter. ```hyp -induce text = "Apfel,Banane,Orange"; +induce text = "Apple,Banana,Orange"; induce fruits = Split(text, ","); -observe fruits; // ["Apfel", "Banane", "Orange"] +observe fruits; // ["Apple", "Banana", "Orange"] ``` ### SplitLines(str) @@ -333,9 +333,9 @@ observe fruits; // ["Apfel", "Banane", "Orange"] Splits a string at line breaks. ```hyp -induce text = "Zeile 1\nZeile 2\nZeile 3"; +induce text = "Line 1\nLine 2\nLine 3"; induce lines = SplitLines(text); -observe lines; // ["Zeile 1", "Zeile 2", "Zeile 3"] +observe lines; // ["Line 1", "Line 2", "Line 3"] ``` ### SplitWords(str) @@ -343,9 +343,9 @@ observe lines; // ["Zeile 1", "Zeile 2", "Zeile 3"] Splits a string into words. ```hyp -induce text = "HypnoScript ist eine Programmiersprache"; +induce text = "HypnoScript is a programming language"; induce words = SplitWords(text); -observe words; // ["HypnoScript", "ist", "eine", "Programmiersprache"] +observe words; // ["HypnoScript", "is", "a", "programming", "language"] ``` ## String Statistics @@ -355,9 +355,9 @@ observe words; // ["HypnoScript", "ist", "eine", "Programmiersprache"] Counts the words in a string. ```hyp -induce text = "HypnoScript ist eine Programmiersprache"; +induce text = "HypnoScript is a programming language"; induce wordCount = CountWords(text); -observe "Wörter: " + wordCount; // 4 +observe "Words: " + wordCount; // 5 ``` ### CountCharacters(str) @@ -365,9 +365,9 @@ observe "Wörter: " + wordCount; // 4 Counts the characters in a string. ```hyp -induce text = "Hallo Welt!"; +induce text = "Hello World!"; induce charCount = CountCharacters(text); -observe "Zeichen: " + charCount; // 10 +observe "Characters: " + charCount; // 12 ``` ### CountLines(str) @@ -375,9 +375,9 @@ observe "Zeichen: " + charCount; // 10 Counts the lines in a string. ```hyp -induce text = "Zeile 1\nZeile 2\nZeile 3"; +induce text = "Line 1\nLine 2\nLine 3"; induce lineCount = CountLines(text); -observe "Zeilen: " + lineCount; // 3 +observe "Lines: " + lineCount; // 3 ``` ## String Comparisons @@ -387,8 +387,8 @@ observe "Zeilen: " + lineCount; // 3 Compares two strings lexicographically. ```hyp -induce str1 = "Apfel"; -induce str2 = "Banane"; +induce str1 = "Apple"; +induce str2 = "Banana"; induce comparison = Compare(str1, str2); observe comparison; // -1 (str1 < str2) ``` @@ -440,29 +440,29 @@ observe uuid; // "123e4567-e89b-12d3-a456-426614174000" ```hyp Focus { entrance { - induce text = "HypnoScript ist eine innovative Programmiersprache mit hypnotischer Syntax."; + induce text = "HypnoScript is an innovative programming language with hypnotic syntax."; observe "Original: " + text; - observe "Länge: " + Length(text); - observe "Wörter: " + CountWords(text); - observe "Zeichen: " + CountCharacters(text); + observe "Length: " + Length(text); + observe "Words: " + CountWords(text); + observe "Characters: " + CountCharacters(text); induce upperText = ToUpper(text); - observe "Großbuchstaben: " + upperText; + observe "Uppercase: " + upperText; induce titleText = TitleCase(text); observe "Title Case: " + titleText; induce words = SplitWords(text); - observe "Wörter-Array: " + words; + observe "Words array: " + words; induce hasHypno = Contains(text, "Hypno"); - observe "Enthält 'Hypno': " + hasHypno; + observe "Contains 'Hypno': " + hasHypno; } } Relax; ``` -### E-Mail-Validierung +### Email Validation ```hyp Focus { @@ -500,55 +500,55 @@ Focus { for (induce i = 0; i < ArrayLength(emails); induce i = i + 1) { induce email = ArrayGet(emails, i); induce isValid = validateEmail(email); - observe email + " ist gültig: " + isValid; + observe email + " is valid: " + isValid; } } } Relax; ``` -### Text-Formatierung +### Text Formatting ```hyp Focus { entrance { - induce name = "max mustermann"; + induce name = "john doe"; induce age = 30; induce city = "berlin"; - // Namen formatieren + // Format name induce formattedName = TitleCase(name); - observe "Name: " + formattedName; // "Max Mustermann" + observe "Name: " + formattedName; // "John Doe" - // Adresse formatieren - induce address = Concat(formattedName, ", ", ToNumber(age), " Jahre, ", TitleCase(city)); - observe "Adresse: " + address; + // Format address + induce address = Concat(formattedName, ", ", ToNumber(age), " years, ", TitleCase(city)); + observe "Address: " + address; - // Telefonnummer formatieren + // Format phone number induce phone = "1234567890"; induce formattedPhone = FormatString("({0}) {1}-{2}", Substring(phone, 0, 3), Substring(phone, 3, 3), Substring(phone, 6, 4)); - observe "Telefon: " + formattedPhone; // "(123) 456-7890" + observe "Phone: " + formattedPhone; // "(123) 456-7890" } } Relax; ``` ## Best Practices -### Effiziente String-Operationen +### Efficient String Operations ```hyp -// Strings zusammenbauen -induce parts = ["Hallo", "Welt", "!"]; +// Build strings +induce parts = ["Hello", "World", "!"]; induce result = Concat(ArrayGet(parts, 0), " ", ArrayGet(parts, 1), ArrayGet(parts, 2)); -// String-Vergleiche -if (EqualsIgnoreCase(input, "ja")) { - // Case-insensitive Vergleich +// String comparisons +if (EqualsIgnoreCase(input, "yes")) { + // Case-insensitive comparison } -// Sichere String-Operationen +// Safe string operations suggestion safeSubstring(str, start, length) { if (IsEmpty(str) || start < 0 || length <= 0) { awaken ""; @@ -560,17 +560,17 @@ suggestion safeSubstring(str, start, length) { } ``` -### Performance-Optimierung +### Performance Optimization ```hyp // Process large strings in chunks -induce largeText = Repeat("Hallo Welt ", 1000); +induce largeText = Repeat("Hello World ", 1000); induce chunkSize = 100; induce chunks = ChunkArray(Split(largeText, " "), chunkSize); for (induce i = 0; i < ArrayLength(chunks); induce i = i + 1) { induce chunk = ArrayGet(chunks, i); - // Chunk verarbeiten + // Process chunk } ``` diff --git a/hypnoscript-docs/docs/builtins/system-functions.md b/hypnoscript-docs/docs/builtins/system-functions.md index 59f3a51..6b3fe60 100644 --- a/hypnoscript-docs/docs/builtins/system-functions.md +++ b/hypnoscript-docs/docs/builtins/system-functions.md @@ -22,7 +22,7 @@ observe content; Writes content to a file. ```hyp -WriteFile("output.txt", "Hallo Welt!"); +WriteFile("output.txt", "Hello World!"); ``` ### AppendFile(path, content) @@ -30,7 +30,7 @@ WriteFile("output.txt", "Hallo Welt!"); Appends content to an existing file. ```hyp -AppendFile("log.txt", "Neuer Eintrag: " + Now()); +AppendFile("log.txt", "New entry: " + Now()); ``` ### FileExists(path) @@ -40,7 +40,7 @@ Checks if a file exists. ```hyp if (FileExists("config.json")) { induce config = ReadFile("config.json"); - // Verarbeite Konfiguration + // Process configuration } ``` @@ -76,7 +76,7 @@ Returns the size of a file in bytes. ```hyp induce size = GetFileSize("large.txt"); -observe "Dateigröße: " + size + " Bytes"; +observe "File size: " + size + " bytes"; ``` ### GetFileInfo(path) @@ -85,9 +85,9 @@ Returns information about a file. ```hyp induce info = GetFileInfo("document.txt"); -observe "Erstellt: " + info.created; -observe "Geändert: " + info.modified; -observe "Größe: " + info.size + " Bytes"; +observe "Created: " + info.created; +observe "Modified: " + info.modified; +observe "Size: " + info.size + " bytes"; ``` ## Directory Operations @@ -127,7 +127,7 @@ Lists all subdirectories. ```hyp induce dirs = ListDirectories("."); -observe "Unterverzeichnisse: " + dirs; +observe "Subdirectories: " + dirs; ``` ### DeleteDirectory(path, recursive) @@ -144,7 +144,7 @@ Returns the current working directory. ```hyp induce cwd = GetCurrentDirectory(); -observe "Aktuelles Verzeichnis: " + cwd; +observe "Current directory: " + cwd; ``` ### ChangeDirectory(path) @@ -202,7 +202,7 @@ Returns the process ID of the current script. ```hyp induce pid = GetCurrentProcessId(); -observe "Aktuelle PID: " + pid; +observe "Current PID: " + pid; ``` ## Environment Variables @@ -221,7 +221,7 @@ induce user = GetEnvironmentVariable("USERNAME"); Sets an environment variable. ```hyp -SetEnvironmentVariable("MY_VAR", "mein_wert"); +SetEnvironmentVariable("MY_VAR", "my_value"); ``` ### GetAllEnvironmentVariables() @@ -243,9 +243,9 @@ Returns general system information. ```hyp induce sysInfo = GetSystemInfo(); -observe "Betriebssystem: " + sysInfo.os; -observe "Architektur: " + sysInfo.architecture; -observe "Prozessoren: " + sysInfo.processors; +observe "Operating system: " + sysInfo.os; +observe "Architecture: " + sysInfo.architecture; +observe "Processors: " + sysInfo.processors; ``` ### GetMemoryInfo() @@ -254,9 +254,9 @@ Returns memory information. ```hyp induce memInfo = GetMemoryInfo(); -observe "Gesamter RAM: " + memInfo.total + " MB"; -observe "Verfügbarer RAM: " + memInfo.available + " MB"; -observe "Verwendeter RAM: " + memInfo.used + " MB"; +observe "Total RAM: " + memInfo.total + " MB"; +observe "Available RAM: " + memInfo.available + " MB"; +observe "Used RAM: " + memInfo.used + " MB"; ``` ### GetDiskInfo() @@ -266,9 +266,9 @@ Returns disk information. ```hyp induce diskInfo = GetDiskInfo(); for (induce drive in diskInfo) { - observe "Laufwerk " + drive.letter + ":"; - observe " Gesamt: " + drive.total + " GB"; - observe " Verfügbar: " + drive.free + " GB"; + observe "Drive " + drive.letter + ":"; + observe " Total: " + drive.total + " GB"; + observe " Free: " + drive.free + " GB"; } ``` @@ -279,7 +279,7 @@ Returns network information. ```hyp induce netInfo = GetNetworkInfo(); observe "Hostname: " + netInfo.hostname; -observe "IP-Adresse: " + netInfo.ipAddress; +observe "IP address: " + netInfo.ipAddress; ``` ## Network Operations @@ -352,7 +352,7 @@ Registers an event handler for system events. ```hyp OnSystemEvent("fileChanged", function(path) { - observe "Datei geändert: " + path; + observe "File changed: " + path; }); ``` @@ -361,7 +361,7 @@ OnSystemEvent("fileChanged", function(path) { Triggers a system event. ```hyp -TriggerSystemEvent("customEvent", {"message": "Hallo Welt!"}); +TriggerSystemEvent("customEvent", {"message": "Hello World!"}); ``` ## Practical Examples @@ -372,7 +372,7 @@ TriggerSystemEvent("customEvent", {"message": "Hallo Welt!"}); Focus { suggestion createBackup(sourcePath, backupDir) { if (!FileExists(sourcePath)) { - observe "Quelldatei existiert nicht: " + sourcePath; + observe "Source file does not exist: " + sourcePath; awaken false; } @@ -384,7 +384,7 @@ Focus { induce backupPath = backupDir + "/backup_" + timestamp + ".txt"; CopyFile(sourcePath, backupPath); - observe "Backup erstellt: " + backupPath; + observe "Backup created: " + backupPath; return true; } @@ -394,39 +394,39 @@ Focus { if (createBackup(sourceFile, backupDirectory)) { induce backupFiles = ListFiles(backupDirectory); - observe "Anzahl Backups: " + ArrayLength(backupFiles); + observe "Number of backups: " + ArrayLength(backupFiles); } } } Relax; ``` -### System-Monitoring +### System Monitoring ```hyp Focus { entrance { - // System-Informationen sammeln + // Collect system information induce sysInfo = GetSystemInfo(); induce memInfo = GetMemoryInfo(); induce diskInfo = GetDiskInfo(); - observe "=== System-Status ==="; + observe "=== System Status ==="; observe "OS: " + sysInfo.os; observe "RAM: " + memInfo.used + "/" + memInfo.total + " MB"; - // Festplatten-Status + // Disk status for (induce drive in diskInfo) { induce usagePercent = (drive.total - drive.free) / drive.total * 100; - observe "Laufwerk " + drive.letter + ": " + Round(usagePercent, 1) + "% belegt"; + observe "Drive " + drive.letter + ": " + Round(usagePercent, 1) + "% used"; } - // Prozess-Liste (Top 5) + // Process list (top 5) induce processes = GetProcessList(); induce sortedProcesses = Sort(processes, function(a, b) { return b.memory - a.memory; }); - observe "Top 5 Prozesse (nach Speicher):"; + observe "Top 5 processes (by memory):"; for (induce i = 0; i < Min(5, ArrayLength(sortedProcesses)); induce i = i + 1) { induce proc = ArrayGet(sortedProcesses, i); observe " " + proc.name + ": " + proc.memory + " MB"; @@ -435,7 +435,7 @@ Focus { } Relax; ``` -### Automatisierte Fileverarbeitung +### Automated File Processing ```hyp Focus { @@ -444,11 +444,11 @@ Focus { induce outputDir = "output"; induce processedDir = "processed"; - // Verzeichnisse erstellen + // Create directories if (!DirectoryExists(outputDir)) CreateDirectory(outputDir); if (!DirectoryExists(processedDir)) CreateDirectory(processedDir); - // Alle Dateien im Eingabeverzeichnis verarbeiten + // Process all files in the input directory induce files = ListFiles(inputDir); for (induce i = 0; i < ArrayLength(files); induce i = i + 1) { @@ -457,29 +457,29 @@ Focus { induce outputPath = outputDir + "/processed_" + file; induce processedPath = processedDir + "/" + file; - // Datei verarbeiten + // Process file induce content = ReadFile(inputPath); - induce processedContent = ToUpper(content); // Beispiel-Verarbeitung + induce processedContent = ToUpper(content); // Example processing WriteFile(outputPath, processedContent); MoveFile(inputPath, processedPath); - observe "Verarbeitet: " + file; + observe "Processed: " + file; } - observe "Verarbeitung abgeschlossen. " + ArrayLength(files) + " Dateien verarbeitet."; + observe "Processing complete. " + ArrayLength(files) + " files processed."; } } Relax; ``` -### Netzwerk-Monitoring +### Network Monitoring ```hyp Focus { entrance { induce hosts = ["google.com", "github.com", "stackoverflow.com"]; - observe "=== Netzwerk-Status ==="; + observe "=== Network Status ==="; for (induce i = 0; i < ArrayLength(hosts); induce i = i + 1) { induce host = ArrayGet(hosts, i); @@ -496,14 +496,14 @@ Focus { observe host + ": Offline"; } } catch { - observe host + ": Fehler beim Ping"; + observe host + ": Ping error"; } } } } Relax; ``` -### Konfigurations-Management +### Configuration Management ```hyp Focus { @@ -516,58 +516,58 @@ Focus { "debug": false }; - // Konfiguration laden oder Standard erstellen + // Load configuration or create default if (FileExists(configFile)) { induce configContent = ReadFile(configFile); induce config = ParseJSON(configContent); - observe "Konfiguration geladen"; + observe "Configuration loaded"; } else { induce config = defaultConfig; WriteFile(configFile, StringifyJSON(config)); - observe "Standard-Konfiguration erstellt"; + observe "Default configuration created"; } - // Konfiguration verwenden + // Use configuration observe "Server: " + config.server + ":" + config.port; - observe "Timeout: " + config.timeout + " Sekunden"; - observe "Debug-Modus: " + config.debug; + observe "Timeout: " + config.timeout + " seconds"; + observe "Debug mode: " + config.debug; - // Konfiguration aktualisieren + // Update configuration config.timeout = 60; WriteFile(configFile, StringifyJSON(config)); - observe "Konfiguration aktualisiert"; + observe "Configuration updated"; } } Relax; ``` ## Best Practices -### Fehlerbehandlung +### Error Handling ```hyp suggestion safeFileOperation(operation) { try { awaken operation(); } catch (error) { - observe "Fehler: " + error; + observe "Error: " + error; return false; } } -// Verwendung +// Usage safeFileOperation(function() { return ReadFile("nonexistent.txt"); }); ``` -### Ressourcen-Management +### Resource Management ```hyp // Automatically delete temporary files induce tempFile = "temp_" + Timestamp() + ".txt"; -WriteFile(tempFile, "Temporäre Daten"); +WriteFile(tempFile, "Temporary data"); -// Verarbeitung... +// Processing... // Cleanup if (FileExists(tempFile)) { @@ -575,21 +575,21 @@ if (FileExists(tempFile)) { } ``` -### Sicherheit +### Security ```hyp -// Pfad-Validierung +// Path validation suggestion isValidPath(path) { if (Contains(path, "..")) awaken false; if (Contains(path, "\\")) return false; return true; } -// Sichere Dateioperation +// Safe file operation if (isValidPath(userInput)) { ReadFile(userInput); } else { - observe "Ungültiger Pfad!"; + observe "Invalid path!"; } ``` diff --git a/hypnoscript-docs/docs/builtins/utility-functions.md b/hypnoscript-docs/docs/builtins/utility-functions.md index a0bfa0c..689088e 100644 --- a/hypnoscript-docs/docs/builtins/utility-functions.md +++ b/hypnoscript-docs/docs/builtins/utility-functions.md @@ -2,15 +2,15 @@ sidebar_position: 5 --- -# Utility-Functionen +# Utility Functions -Utility-Functionen bieten allgemeine Hilfsmittel für Typumwandlung, Vergleiche, Zeit, Zufall, Fehlerbehandlung und mehr. +Utility functions provide general helpers for type conversion, comparisons, time, randomness, error handling, and more. -## Typumwandlung +## Type Conversion ### ToNumber(value) -Converts einen Wert in eine Zahl (Integer oder Float). +Converts a value to a number (integer or float). ```hyp induce n1 = ToNumber("42"); // 42 @@ -21,7 +21,7 @@ induce n4 = ToNumber(false); // 0 ### ToString(value) -Converts einen Wert in einen String. +Converts a value to a string. ```hyp induce s1 = ToString(42); // "42" @@ -31,7 +31,7 @@ induce s3 = ToString(true); // "true" ### ToBoolean(value) -Converts einen Wert in einen booleschen Wert. +Converts a value to a boolean. ```hyp induce b1 = ToBoolean(1); // true @@ -42,27 +42,27 @@ induce b4 = ToBoolean(""); // false ### ParseJSON(str) -Parst einen JSON-String in ein Objekt/Array. +Parses a JSON string into an object/array. ```hyp -induce obj = ParseJSON('{"name": "Max", "age": 30}'); -induce name = obj.name; // "Max" +induce obj = ParseJSON('{"name": "Alex", "age": 30}'); +induce name = obj.name; // "Alex" ``` ### StringifyJSON(value) -Wandelt ein Objekt/Array in einen JSON-String um. +Converts an object/array into a JSON string. ```hyp induce arr = [1, 2, 3]; induce json = StringifyJSON(arr); // "[1,2,3]" ``` -## Vergleiche & Prüfungen +## Comparisons & Checks ### IsNull(value) -Checks, ob ein Wert null ist. +Checks whether a value is null. ```hyp induce n = null; @@ -71,7 +71,7 @@ induce isNull = IsNull(n); // true ### IsDefined(value) -Checks, ob ein Wert definiert ist (nicht null). +Checks whether a value is defined (not null). ```hyp induce x = 42; @@ -80,7 +80,7 @@ induce isDef = IsDefined(x); // true ### IsNumber(value) -Checks, ob ein Wert eine Zahl ist. +Checks whether a value is a number. ```hyp induce isNum1 = IsNumber(42); // true @@ -89,16 +89,16 @@ induce isNum2 = IsNumber("42"); // false ### IsString(value) -Checks, ob ein Wert ein String ist. +Checks whether a value is a string. ```hyp -induce isStr1 = IsString("Hallo"); // true +induce isStr1 = IsString("Hello"); // true induce isStr2 = IsString(42); // false ``` ### IsArray(value) -Checks, ob ein Wert ein Array ist. +Checks whether a value is an array. ```hyp induce arr = [1,2,3]; @@ -107,7 +107,7 @@ induce isArr = IsArray(arr); // true ### IsObject(value) -Checks, ob ein Wert ein Objekt ist. +Checks whether a value is an object. ```hyp induce obj = ParseJSON('{"a":1}'); @@ -116,7 +116,7 @@ induce isObj = IsObject(obj); // true ### IsBoolean(value) -Checks, ob ein Wert ein boolescher Wert ist. +Checks whether a value is a boolean. ```hyp induce isBool1 = IsBoolean(true); // true @@ -125,7 +125,7 @@ induce isBool2 = IsBoolean(0); // false ### TypeOf(value) -Returns den Typ eines Wertes als String . +Returns the type of a value as a string. ```hyp induce t1 = TypeOf(42); // "number" @@ -133,11 +133,11 @@ induce t2 = TypeOf("abc"); // "string" induce t3 = TypeOf([1,2,3]); // "array" ``` -## Zeitfunktionen +## Time Functions ### Now() -Returns das aktuelle Datum und die aktuelle Uhrzeit als String . +Returns the current date and time as a string. ```hyp induce now = Now(); // "2025-05-01T12:34:56Z" @@ -145,7 +145,7 @@ induce now = Now(); // "2025-05-01T12:34:56Z" ### Timestamp() -Returns den aktuellen Unix-Timestamp (Sekunden seit 1970-01-01). +Returns the current Unix timestamp (seconds since 1970-01-01). ```hyp induce ts = Timestamp(); // 1714569296 @@ -153,17 +153,17 @@ induce ts = Timestamp(); // 1714569296 ### Sleep(ms) -Pausiert die Ausführung für die angegebene Zeit in Millisekunden. +Pauses execution for the specified time in milliseconds. ```hyp -Sleep(1000); // 1 Sekunde warten +Sleep(1000); // wait 1 second ``` -## Zufallsfunktionen +## Random Functions ### Shuffle(array) -Mischt die Elemente eines Arrays zufällig. +Shuffles the elements of an array randomly. ```hyp induce arr = [1,2,3,4,5]; @@ -172,36 +172,36 @@ induce shuffled = Shuffle(arr); ### Sample(array, count) -Wählt zufällige Elemente aus einem Array. +Selects random elements from an array. ```hyp induce arr = [1,2,3,4,5]; -induce sample = Sample(arr, 2); // z.B. [3,5] +induce sample = Sample(arr, 2); // e.g. [3,5] ``` -## Fehlerbehandlung +## Error Handling ### Try(expr, fallback) -Versucht, einen Ausdruck auszuführen, und gibt im Fehlerfall einen Fallback-Wert . +Attempts to execute an expression and returns a fallback value on error. ```hyp -induce result = Try(Divide(10, 0), "Fehler"); // "Fehler" +induce result = Try(Divide(10, 0), "Error"); // "Error" ``` ### Throw(message) -Löst einen Fehler mit einer Nachricht aus. +Throws an error with a message. ```hyp -Throw("Ungültiger Wert!"); +Throw("Invalid value!"); ``` -## Sonstige Utility-Functionen +## Other Utility Functions ### Range(start, end, step) -Erzeugt ein Array von Zahlen im Bereich. +Creates an array of numbers in a range. ```hyp induce r1 = Range(1, 5); // [1,2,3,4,5] @@ -210,7 +210,7 @@ induce r2 = Range(0, 10, 2); // [0,2,4,6,8,10] ### Repeat(value, count) -Erzeugt ein Array mit wiederholten Werten. +Creates an array with repeated values. ```hyp induce arr = Repeat("A", 3); // ["A","A","A"] @@ -218,7 +218,7 @@ induce arr = Repeat("A", 3); // ["A","A","A"] ### Zip(array1, array2) -Verbindet zwei Arrays zu einem Array von Paaren. +Combines two arrays into an array of pairs. ```hyp induce a = [1,2,3]; @@ -228,7 +228,7 @@ induce zipped = Zip(a, b); // [[1,"a"],[2,"b"],[3,"c"]] ### Unzip(array) -Teilt ein Array von Paaren in zwei Arrays. +Splits an array of pairs into two arrays. ```hyp induce pairs = [[1,"a"],[2,"b"]]; @@ -237,7 +237,7 @@ induce [nums, chars] = Unzip(pairs); ### ChunkArray(array, size) -Teilt ein Array in Blöcke der angegebenen Größe. +Splits an array into chunks of the specified size. ```hyp induce arr = [1,2,3,4,5,6]; @@ -246,7 +246,7 @@ induce chunks = ChunkArray(arr, 2); // [[1,2],[3,4],[5,6]] ### Flatten(array) -Makes ein verschachteltes Array flach. +Flattens a nested array. ```hyp induce nested = [[1,2],[3,4],[5]]; @@ -255,7 +255,7 @@ induce flat = Flatten(nested); // [1,2,3,4,5] ### Unique(array) -Entfernt doppelte Werte aus einem Array. +Removes duplicate values from an array. ```hyp induce arr = [1,2,2,3,3,3,4]; @@ -264,7 +264,7 @@ induce unique = Unique(arr); // [1,2,3,4] ### Sort(array, [compareFn]) -Sortiert ein Array (optional mit Vergleichsfunktion). +Sorts an array (optionally with a comparison function). ```hyp induce arr = [3,1,4,1,5]; @@ -273,13 +273,13 @@ induce sorted = Sort(arr); // [1,1,3,4,5] ## Best Practices -- Use Typprüfungen (IsNumber, IsString, ...) für robusten Code. -- Verwende Try für sichere Fehlerbehandlung. -- Use Utility-Functionen für saubere, lesbare und wiederverwendbare Skripte. +- Use type checks (IsNumber, IsString, ...) for robust code. +- Use Try for safe error handling. +- Use utility functions for clean, readable, and reusable scripts. -## Examplee +## Examples -### Dynamische Typumwandlung +### Dynamic Type Conversion ```hyp Focus { @@ -287,29 +287,29 @@ Focus { induce input = "123"; induce n = ToNumber(input); if (IsNumber(n)) { - observe "Zahl: " + n; + observe "Number: " + n; } else { - observe "Ungültige Eingabe!"; + observe "Invalid input!"; } } } Relax; ``` -### Zufällige Auswahl und Mischen +### Random Selection and Shuffling ```hyp Focus { entrance { - induce names = ["Anna", "Ben", "Carla", "Dieter"]; + induce names = ["Anna", "Ben", "Carla", "Dylan"]; induce winner = Sample(names, 1); - observe "Gewinner: " + winner; + observe "Winner: " + winner; induce shuffled = Shuffle(names); - observe "Zufällige Reihenfolge: " + shuffled; + observe "Random order: " + shuffled; } } Relax; ``` -### Zeitmessung +### Timing ```hyp Focus { @@ -317,16 +317,16 @@ Focus { induce start = Timestamp(); Sleep(500); induce end = Timestamp(); - observe "Dauer: " + (end - start) + " Sekunden"; + observe "Duration: " + (end - start) + " seconds"; } } Relax; ``` ## Next Steps -- [System-Functionen](./system-functions) – Interaktion mit dem System -- [Examplee](../examples/utility-examples) – Praktische Utility-Examplee +- [System Functions](./system-functions) – Interaction with the system +- [Examples](../examples/utility-examples) – Practical utility examples --- -**Utility-Functionen gemeistert? Dann lerne [System-Functionen](./system-functions) kennen!** 🖥️ +**Mastered utility functions? Then explore [System Functions](./system-functions)!** 🖥️ diff --git a/hypnoscript-docs/docs/cli/commands.md b/hypnoscript-docs/docs/cli/commands.md index 2e69def..72a7c34 100644 --- a/hypnoscript-docs/docs/cli/commands.md +++ b/hypnoscript-docs/docs/cli/commands.md @@ -14,7 +14,7 @@ hypnoscript [OPTIONS] | Command | Description | | -------------- | ------------------------------------------- | -| `run` | Executes a HypnoScript program | +| `exec` | Executes a HypnoScript program | | `lex` | Tokenizes a HypnoScript file | | `parse` | Shows the AST of a file | | `check` | Performs type checking | @@ -23,14 +23,14 @@ hypnoscript [OPTIONS] | `version` | Shows version information | | `builtins` | Lists all builtin functions | -## run - Run a program +## exec - Execute a program Executes a HypnoScript program. This is the main command for running .hyp files. ### Syntax ```bash -hypnoscript run [OPTIONS] +hypnoscript exec [OPTIONS] ``` ### Arguments @@ -41,39 +41,83 @@ hypnoscript run [OPTIONS] ### Options -| Option | Short | Description | -| ----------- | ----- | ----------------- | -| `--debug` | `-d` | Enable debug mode | -| `--verbose` | `-v` | Verbose output | +| Option | Short | Description | +| ----------------------- | ----- | -------------------------------------------------- | +| `--debug` | `-d` | Enable interactive debug mode | +| `--verbose` | `-v` | Verbose output | +| `--breakpoints ` | | Set initial breakpoints (comma-separated lines) | +| `--watch ` | | Watch variables during execution (comma-separated) | +| `--trace-file ` | | Write debug trace to file | ### Behavior 1. **Lexing**: Tokenizes the source code 2. **Parsing**: Creates the AST 3. **Type checking**: Checks types (errors are output as warnings) -4. **Execution**: Executes the program +4. **Execution**: Executes the program (or enters debug mode if `--debug`) **Note:** Type errors do not cause termination - the program is executed anyway. ### Examples ```bash -# Einfache Ausführung -hypnoscript run hello.hyp +# Simple execution +hypnoscript exec hello.hyp -# Mit Debug-Modus -hypnoscript run script.hyp --debug +# With debug mode +hypnoscript exec script.hyp --debug -# Mit detaillierter Ausgabe -hypnoscript run complex.hyp --verbose +# With verbose output +hypnoscript exec complex.hyp --verbose -# Beide Optionen kombiniert -hypnoscript run test.hyp -d -v +# Both options combined +hypnoscript exec test.hyp -d -v + +# Debug with initial breakpoints +hypnoscript exec script.hyp --debug --breakpoints 10,25,42 + +# Debug with watch expressions +hypnoscript exec script.hyp --debug --watch counter,result,total + +# Full debug session with trace file +hypnoscript exec script.hyp --debug --breakpoints 10,20 --watch x,y --trace-file debug.log +``` + +### Debug Mode + +When `--debug` is specified, an interactive debugging session starts: + +``` +$ hypnoscript exec script.hyp --debug + +HypnoScript Debugger v1.2.0 +Type 'help' for available commands. + +(hypno-debug) b 10 +Breakpoint set at line 10 + +(hypno-debug) run +Starting execution... + +-> Breakpoint hit at line 10 + 10 | induce result = calculate(a, b); + +(hypno-debug) locals +Local variables: + a: Int = 42 + b: Int = 17 + +(hypno-debug) continue +Program finished. + +(hypno-debug) quit ``` -### Debug-Modus Output +See the [Debugging documentation](/debugging/debug-mode) for full command reference. + +### Verbose Output -Im Debug-Modus werden zusätzliche Informationen ausgegeben: +With `--verbose`, additional information is displayed: ``` Running file: script.hyp @@ -86,7 +130,7 @@ Tokens: 42 --- Type Checking --- --- Executing --- - + ✅ Program executed successfully! ``` @@ -109,7 +153,7 @@ hypnoscript lex ### Output -Lists alle Token mit Index und Typ: +Lists all tokens with index and type: ``` === Tokens === @@ -123,9 +167,9 @@ Total tokens: 42 ### Usage -- **Syntax-Debugging**: Verstehen wie der Lexer Code interpretiert -- **Token-Analyse**: Prüfen ob Schlüsselwörter korrekt erkannt werden -- **Lernzwecke**: Verstehen wie HypnoScript-Code tokenisiert wird +- **Syntax debugging**: Understand how the lexer interprets code +- **Token analysis**: Verify that keywords are recognized correctly +- **Learning**: See how HypnoScript code is tokenized ### Example @@ -151,14 +195,14 @@ hypnoscript parse ### Output -Shows den AST in formatierter Form: +Shows the AST in a formatted representation: ``` === AST === Program([ FocusBlock([ ObserveStatement( - StringLiteral("Hallo Welt") + StringLiteral("Hello World") ), VariableDeclaration { name: "x", @@ -172,9 +216,9 @@ Program([ ### Usage -- **Struktur-Analyse**: Verstehen wie Code geparst wird -- **Compiler-Debugging**: Probleme im Parser identifizieren -- **Entwicklung**: AST-Struktur für Compiler-Erweiterungen verstehen +- **Structure analysis**: Understand how code is parsed +- **Compiler debugging**: Identify parser issues +- **Development**: Understand AST structure for compiler extensions ### Example @@ -200,13 +244,13 @@ hypnoscript check ### Output -**Ohne Fehler:** +**No errors:** ``` ✅ No type errors found! ``` -**Mit Fehlern:** +**With errors:** ``` ❌ Type errors found: @@ -215,22 +259,22 @@ hypnoscript check - Function 'unknown' not defined at line 12 ``` -### Type checking Regeln +### Type checking rules -Der Type Checker prüft: +The type checker validates: -- ✅ Variablendeklarationen -- ✅ Functionsaufrufe und -signaturen -- ✅ Typ-Kompatibilität in Zuweisungen -- ✅ Array-Typen -- ✅ Session-Member-Zugriffe -- ✅ Return-Statement Typen +- ✅ Variable declarations +- ✅ Function calls and signatures +- ✅ Type compatibility in assignments +- ✅ Array types +- ✅ Session member access +- ✅ Return statement types ### Usage -- **Vor Deployment**: Typ-Fehler frühzeitig finden -- **Entwicklung**: Code-Qualität sicherstellen -- **CI/CD**: Als Teil der Build-Pipeline +- **Before deployment**: Catch type errors early +- **Development**: Ensure code quality +- **CI/CD**: Use as part of the build pipeline ### Example @@ -298,15 +342,15 @@ hypnoscript compile-wasm script.hyp wat2wasm script.wat -o script.wasm ``` -### WASM-Integration +### WASM Integration -Nach Kompilierung kann das WASM-Modul in verschiedenen Umgebungen verwendet werden: +After compilation, the WASM module can be used in different environments: **Web (JavaScript):** ```javascript WebAssembly.instantiateStreaming(fetch('script.wasm')).then((module) => { - // Nutze exportierte Funktionen + // Use exported functions }); ``` @@ -376,7 +420,7 @@ hypnoscript version ### Output ``` -HypnoScript v1.0.0 +HypnoScript v1.2.0 The Hypnotic Programming Language Migrated from C# to Rust for improved performance @@ -532,7 +576,7 @@ fi ### CI/CD Integration ```yaml -# GitHub Actions Beispiel +# GitHub Actions example steps: - name: Install HypnoScript run: cargo install --path hypnoscript-cli diff --git a/hypnoscript-docs/docs/cli/overview.md b/hypnoscript-docs/docs/cli/overview.md index 8ffeccb..a94195f 100644 --- a/hypnoscript-docs/docs/cli/overview.md +++ b/hypnoscript-docs/docs/cli/overview.md @@ -35,25 +35,25 @@ hypnoscript --help # Version information hypnoscript version -# Run a program -hypnoscript run hello.hyp +# Execute a program +hypnoscript exec hello.hyp ``` All subcommands are intentionally kept lean. For a deeper look, check out the following sections. ## Command Overview -| Command | Brief Description | -| -------------- | ------------------------------------------------ | -| `run` | Executes a HypnoScript program | -| `run --debug` | Additionally shows tokens, AST and type checking | -| `lex` | Tokenizes a file | -| `parse` | Shows the AST | -| `check` | Performs type checking | -| `compile-wasm` | Generates WebAssembly Text Format (.wat) | -| `self-update` | Checks releases and runs the new installer | -| `builtins` | Lists all available builtin functions | -| `version` | Shows version and feature information | +| Command | Brief Description | +| -------------- | ------------------------------------------------------ | +| `exec` | Executes a HypnoScript program | +| `exec --debug` | Starts interactive debugger with breakpoints, stepping | +| `lex` | Tokenizes a file | +| `parse` | Shows the AST | +| `check` | Performs type checking | +| `compile-wasm` | Generates WebAssembly Text Format (.wat) | +| `self-update` | Checks releases and runs the new installer | +| `builtins` | Lists all available builtin functions | +| `version` | Shows version and feature information | Further details are provided on the [CLI Commands](./commands) page. diff --git a/hypnoscript-docs/docs/cli/testing.md b/hypnoscript-docs/docs/cli/testing.md index 4655046..a409554 100644 --- a/hypnoscript-docs/docs/cli/testing.md +++ b/hypnoscript-docs/docs/cli/testing.md @@ -2,18 +2,18 @@ title: CLI Testing --- -The Rust CLI does not include a separate test framework. Instead, you treat each `.hyp` file as an independent script and run it with `hypnoscript run`. The files in the `hypnoscript-tests/` folder provide examples of assertions and error messages. +The Rust CLI does not include a separate test framework. Instead, you treat each `.hyp` file as an independent script and run it with `hypnoscript exec`. The files in the `hypnoscript-tests/` folder provide examples of assertions and error messages. ## Running Tests ```bash # Run a single test file -hypnoscript run hypnoscript-tests/test_basic.hyp +hypnoscript exec hypnoscript-tests/test_basic.hyp # Run all files in the folder for file in hypnoscript-tests/*.hyp; do echo "== $file ==" - hypnoscript run "$file" + hypnoscript exec "$file" done ``` @@ -23,7 +23,7 @@ done hypnoscript check hypnoscript-tests/test_basic.hyp ``` -This way you can detect type errors before assertions are triggered. The CLI does not automatically abort on errors, so it's worth running a separate `check` before `run`. +This way you can detect type errors before assertions are triggered. The CLI does not automatically abort on errors, so it's worth running a separate `check` before `exec`. ## Integration into Scripts @@ -32,7 +32,7 @@ This way you can detect type errors before assertions are triggered. The CLI doe ```powershell Get-ChildItem hypnoscript-tests -Filter *.hyp | ForEach-Object { Write-Host "== $($_.Name) ==" - hypnoscript run $_.FullName + hypnoscript exec $_.FullName } ``` @@ -43,7 +43,7 @@ This way you can detect type errors before assertions are triggered. The CLI doe @# Replace leading spaces with tabs, as Make requires this @for file in hypnoscript-tests/*.hyp; do \ echo "== $$file =="; \ - hypnoscript run $$file || exit 1; \ + hypnoscript exec $$file || exit 1; \ done ``` @@ -51,4 +51,18 @@ This way you can detect type errors before assertions are triggered. The CLI doe The test files use `assert` statements as well as `observe` to check expected values. If an assertion block fails, the CLI displays an error message but continues execution. Therefore, make sure to search for error messages in the test script or terminate the script with `snap;` if needed. +## Debug-Assertions + +Use the built-in assertion functions for automated testing: + +```hyp +Focus + induce result = calculate(5, 3); + assertEqual(result, 8, "calculate should add correctly"); + + induce items = getItems(); + assertTruthy(ArrayLength(items) > 0, "should return items"); +Relax +``` + Learn more about available commands in [CLI Commands](./commands). diff --git a/hypnoscript-docs/docs/debugging/breakpoints.md b/hypnoscript-docs/docs/debugging/breakpoints.md index 6003434..87acf25 100644 --- a/hypnoscript-docs/docs/debugging/breakpoints.md +++ b/hypnoscript-docs/docs/debugging/breakpoints.md @@ -1,23 +1,147 @@ # Breakpoints -Breakpoints let you pause a HypnoScript session at precise trance steps to inspect memory and hypnotic state transitions. +Breakpoints pause a HypnoScript execution at precise locations to inspect variables and program state. -## Setting Breakpoints +## Set Breakpoints via CLI -- In the CLI, use `hypnoscript debug script.hyp --break label_name` to stop before the instruction tagged with `label_name`. -- Inside editors that support the HypnoScript language server, click the gutter to toggle a breakpoint; the location is saved in `.hypdbg` files. +### Using the --breakpoints Flag -## Inspecting State +Set initial breakpoints when starting debug mode: -While paused, you can: +```bash +# Single breakpoint at line 10 +hypnoscript exec --debug --breakpoints 10 script.hyp -- Run `state show` to dump the trance stack and current suggestion payload. -- Evaluate expressions with `eval ` to probe variable values without resuming the script. +# Multiple breakpoints +hypnoscript exec --debug --breakpoints 10,25,42 script.hyp +``` -## Stepping Controls +### Interactive in Debug Mode -Use the following commands to progress through the script: +In interactive debug mode, breakpoints can be set dynamically: -- `step` advances a single instruction, entering nested suggestions. -- `next` executes the current instruction and pauses at the following one, skipping over nested sequences. -- `continue` resumes execution until the next breakpoint or the end of the session. +```bash +(hypno-debug) break 15 +Breakpoint set at line 15 + +(hypno-debug) b 30 +Breakpoint set at line 30 +``` + +## Breakpoint Commands + +| Command | Alias | Description | +| --------------- | ---------- | -------------------------------------------- | +| `break ` | `b ` | Sets a breakpoint at the specified line | +| `delete ` | `d ` | Removes the breakpoint at the specified line | +| `breakpoints` | `bl` | Shows all active breakpoints | +| `clear` | | Removes all breakpoints | + +## List Breakpoints + +```bash +(hypno-debug) breakpoints +Active breakpoints: + Line 10 + Line 25 + Line 42 + +(hypno-debug) bl +Active breakpoints: + Line 10 + Line 25 + Line 42 +``` + +## Remove Breakpoints + +```bash +# Remove a single breakpoint +(hypno-debug) delete 25 +Breakpoint removed at line 25 + +# Use alias +(hypno-debug) d 42 +Breakpoint removed at line 42 + +# Remove all breakpoints +(hypno-debug) clear +All breakpoints removed +``` + +## Inspect State at a Breakpoint + +When execution pauses at a breakpoint: + +```bash +-> Breakpoint hit at line 10 + 10 | induce result = calculate(a, b); + +(hypno-debug) locals +Local variables: + a: Int = 42 + b: Int = 17 + +(hypno-debug) print result +result: Null (not initialized) + +(hypno-debug) where +Call Stack: + #0: processData() at script.hyp:10 + #1: main() at script.hyp:5 + #2: at script.hyp:1 +``` + +## Stepping Control + +After a breakpoint, you can control execution: + +| Command | Alias | Description | +| ---------- | ----- | ----------------------------------------------------- | +| `step` | `s` | Executes one line and stops (step into) | +| `next` | `n` | Executes one line, skipping functions (step over) | +| `finish` | `f` | Runs until the end of the current function (step out) | +| `continue` | `c` | Continues execution to the next breakpoint | + +### Example + +```bash +-> Breakpoint hit at line 10 + 10 | induce result = calculate(a, b); + +(hypno-debug) step + -> Line 20 (in calculate()) + 20 | awaken a + b; + +(hypno-debug) finish + -> Back to line 11 + 11 | observe(result); + +(hypno-debug) continue +Result: 59 +Program finished. +``` + +## Set Breakpoints in Code + +You can also set breakpoints programmatically with the `breakpoint()` builtin function: + +```hypnoscript +Focus + induce x = 10; + + breakpoint(); // Pauses here in debug mode + + induce y = x * 2; + observe(y); +Relax +``` + +The `breakpoint()` function only activates in debug mode and has no effect during normal execution. + +## Best Practices + +1. **Strategic placement**: Set breakpoints before complex calculations or after function calls +2. **Use sparingly**: Too many breakpoints can make debugging harder +3. **Use watch expressions**: Combine breakpoints with `--watch` for automatic variable monitoring +4. **Remember cleanup**: Remove `breakpoint()` calls before production use diff --git a/hypnoscript-docs/docs/debugging/debug-mode.md b/hypnoscript-docs/docs/debugging/debug-mode.md index e90b719..5791612 100644 --- a/hypnoscript-docs/docs/debugging/debug-mode.md +++ b/hypnoscript-docs/docs/debugging/debug-mode.md @@ -1,23 +1,182 @@ # Debug Mode -Debug mode provides fine-grained insight into HypnoScript execution, exposing the virtual machine state, trance stack, and hypnotic suggestions as they execute. +Debug mode provides an interactive REPL environment for debugging HypnoScript programs with breakpoints, step-by-step execution, and variable inspection. -## Enabling Debug Mode +## Enable Debug Mode -Run any script with the `--debug` flag: `hypnoscript --debug session.hyp`. The CLI generates a structured log under `target/debug-logs/` with a timestamped filename. +Start a script with the `--debug` flag: -## Output Format +```bash +hypnoscript exec --debug session.hyp +``` -The debug log is newline-delimited JSON. Each entry includes: +## CLI Debug Options -- `phase`: parser, compiler, or runtime -- `instruction`: mnemonic of the instruction currently executing -- `context`: key variables and induction parameters at that step +| Option | Description | +| ----------------------- | ---------------------------------------------------------------- | +| `--debug` | Enables interactive debug mode | +| `--breakpoints ` | Sets initial breakpoints at the specified lines (e.g. `5,10,15`) | +| `--watch ` | Watches variables during execution (e.g. `counter,result`) | +| `--trace-file ` | Writes a debug trace to a file | +| `--verbose` | Enables verbose output | -## Integrating With Editors +### Example with Options -The HypnoScript VS Code extension reads the debug log and overlays inline diagnostics. Open the “Hypnotic Timeline” panel to replay the execution while watching stack depth and suggestion intensity changes. +```bash +# Debug with initial breakpoints and watch expressions +hypnoscript exec --debug --breakpoints 5,12,25 --watch x,y,result myscript.hyp +``` -## Performance Considerations +## Debug Commands -Debug mode slows execution because every instruction emits detailed telemetry. Avoid using it during latency-sensitive live inductions; capture traces in staging first, review them, and then rerun in release mode. +In interactive debug mode, the following commands are available: + +### Execution Control + +| Command | Alias | Description | +| ---------- | ----- | ------------------------------------------------------ | +| `continue` | `c` | Continues execution until the next breakpoint | +| `step` | `s` | Executes one line and stops (step into) | +| `next` | `n` | Executes one line, skipping over functions (step over) | +| `finish` | `f` | Runs until the end of the current function (step out) | +| `run` | `r` | Starts execution from the beginning | + +### Breakpoint Management + +| Command | Alias | Description | +| --------------- | ---------- | -------------------------------------------- | +| `break ` | `b ` | Sets a breakpoint at the specified line | +| `delete ` | `d ` | Removes the breakpoint at the specified line | +| `breakpoints` | `bl` | Shows all active breakpoints | +| `clear` | | Removes all breakpoints | + +### Variable Inspection + +| Command | Alias | Description | +| -------------- | ---------- | ----------------------------- | +| `locals` | `l` | Shows all local variables | +| `globals` | `g` | Shows all global variables | +| `print ` | `p ` | Shows the value of a variable | +| `watch ` | `w ` | Adds a watch expression | +| `unwatch ` | | Removes a watch expression | +| `watches` | | Shows all watch expressions | + +### Source View + +| Command | Alias | Description | +| -------------------- | ----- | ---------------------------------------- | +| `list` | | Shows source around the current position | +| `list ` | | Shows source from line start to end | +| `where` | `bt` | Shows the current call stack | + +### Other Commands + +| Command | Description | +| ------- | ---------------------- | +| `help` | Shows the help | +| `quit` | Ends the debug session | + +## Example Debug Session + +```bash +$ hypnoscript exec --debug examples/calculator.hyp + +HypnoScript Debugger v1.2.0 +Type 'help' for available commands. + +(hypno-debug) b 10 +Breakpoint set at line 10 + +(hypno-debug) b 25 +Breakpoint set at line 25 + +(hypno-debug) run +Starting execution... + +-> Breakpoint hit at line 10 + 10 | induce result = calculate(a, b); + +(hypno-debug) locals +Local variables: + a: Int = 42 + b: Int = 17 + +(hypno-debug) step + 11 | observe("Result: " + result); + +(hypno-debug) print result +result = 59 + +(hypno-debug) continue +Result: 59 + +-> Breakpoint hit at line 25 + +(hypno-debug) where +Call stack: + #0: main() at calculator.hyp:25 + #1: at calculator.hyp:1 + +(hypno-debug) continue +Program finished. + +(hypno-debug) quit +``` + +## Source Context + +When execution is paused, the debugger shows source context with the current position: + +```hyp + 8 | induce a = 42; + 9 | induce b = 17; + -> 10 | induce result = calculate(a, b); + 11 | observe("Result: " + result); + 12 | } +``` + +The arrow `->` marks the current execution position. + +## Watch Expressions + +Watch expressions are evaluated automatically on each stop: + +```bash +(hypno-debug) watch counter +Watch #1 added: counter + +(hypno-debug) watch result * 2 +Watch #2 added: result * 2 + +(hypno-debug) step + 15 | counter = counter + 1; + +Watch Values: + #1 counter = 5 + #2 result * 2 = 118 +``` + +## Trace File + +With `--trace-file`, you can log debug execution to a file: + +```bash +hypnoscript exec --debug --trace-file debug.log myscript.hyp +``` + +The trace file contains: + +- Executed lines with timestamps +- Variable changes +- Breakpoint hits +- Call stack changes + +## Performance Notes + +Debug mode slows execution significantly because every instruction is monitored. Use it for: + +- Development and troubleshooting +- Understanding program flow +- Testing new features + +Disable debug mode for production execution. diff --git a/hypnoscript-docs/docs/debugging/overview.md b/hypnoscript-docs/docs/debugging/overview.md index 3dfde1f..393fc01 100644 --- a/hypnoscript-docs/docs/debugging/overview.md +++ b/hypnoscript-docs/docs/debugging/overview.md @@ -1,285 +1,176 @@ # Debugging Overview -HypnoScript provides comprehensive debugging capabilities to help you identify and fix issues in your scripts. +HypnoScript provides comprehensive debugging features to identify and fix errors in your scripts. ## Debugging Features -### 1. Built-in Debugging Functions +### 1. Interactive Debug Mode -HypnoScript includes several built-in functions for debugging: - -```hyp -// Print debug information -DebugPrint("Variable value: " + myVariable); -DebugPrintType(myVariable); - -// Memory and performance debugging -DebugPrintMemory(); -DebugPrintStackTrace(); -DebugPrintEnvironment(); - -// Performance metrics -var metrics = GetPerformanceMetrics(); -DebugPrint("CPU Time: " + metrics["cpu_time"]); -DebugPrint("Memory Usage: " + metrics["memory_usage"]); -``` - -### 2. CLI Debugging Options - -Use the `--debug` flag with CLI commands for enhanced debugging: +Debug mode starts an interactive REPL session with full control over execution: ```bash -# Run with debug output -dotnet run -- run script.hyp --debug - -# Compile with debug information -dotnet run -- compile script.hyp --debug +# Start debug mode +hypnoscript exec script.hyp --debug -# Analyze with detailed output -dotnet run -- analyze script.hyp --debug -``` - -### 3. Configuration-Based Debugging +# With initial breakpoints +hypnoscript exec script.hyp --debug --breakpoints 10,25,42 -Configure debugging behavior in your application settings: - -```json -{ - "Development": { - "DebugMode": true, - "DetailedErrorReporting": true, - "EnableProfiling": true, - "EnableStackTrace": true - } -} +# With watch expressions +hypnoscript exec script.hyp --debug --watch counter,result ``` -### 4. Error Reporting - -HypnoScript provides detailed error reporting with: +In interactive mode you can: -- **Line numbers and file locations** -- **Stack traces** for function calls -- **Type information** for variables -- **Context information** for better error understanding +- Set and remove breakpoints +- Step through code line by line +- Inspect variables +- View the call stack -### 5. Performance Profiling +### 2. Builtin Debug Functions -Use the profiling command to analyze script performance: - -```bash -dotnet run -- profile script.hyp --verbose -``` - -This provides: - -- Execution time analysis -- Memory usage tracking -- Function call frequency -- Performance bottlenecks identification - -### 6. Logging System - -Configure logging levels and outputs: - -```json -{ - "Logging": { - "LogLevel": "DEBUG", - "EnableFileLogging": true, - "LogFilePath": "logs/hypnoscript.log", - "IncludeTimestamps": true, - "IncludeThreadInfo": true - } -} -``` - -### 7. Interactive Debugging - -For interactive debugging sessions: - -```bash -# Start with interactive mode -dotnet run -- run script.hyp --debug --verbose - -# Use breakpoints and step-through execution -# (Available in development builds) -``` - -## Debugging Best Practices - -### 1. Use Descriptive Variable Names +HypnoScript includes several built-in functions for debugging: ```hyp -// Good -induce userName: string = "John"; -induce userAge: number = 25; - -// Avoid -induce a: string = "John"; -induce b: number = 25; +Focus + // Detailed value inspection + induce data = { name: "Test", value: 42 }; + observe(inspect(data)); + + // Type checking + observe(typeOf(data)); // "Object" + + // Print stack trace + observe(stackTrace()); + + // Debug output with different levels + log("Info message"); + warn("Warning"); + error("Error"); + trace("With stack trace"); + + // Assertions for tests + assertEqual(1 + 1, 2, "Math should work"); + assertTruthy(data.value > 0, "Value should be positive"); + + // Performance measurement + time("operation"); + // ... Code ... + timeEnd("operation"); // Outputs elapsed time + + // Programmatic breakpoint + breakpoint(); // Pauses in debug mode +Relax ``` -### 2. Add Debug Statements Strategically +### 3. CLI Debug Options -```hyp -Focus { - induce counter: number = 0; - DebugPrint("Starting loop with counter: " + counter); +| Option | Description | +| ----------------------- | --------------------------------------------- | +| `--debug` | Enables interactive debug mode | +| `--verbose` | Shows additional information during execution | +| `--breakpoints ` | Sets initial breakpoints (comma-separated) | +| `--watch ` | Watches variables (comma-separated) | +| `--trace-file ` | Writes debug trace to a file | - while (counter < 10) { - DebugPrint("Counter value: " + counter); - counter = counter + 1; - } +### 4. Debug Commands - DebugPrint("Loop completed. Final counter: " + counter); -} Relax -``` - -### 3. Validate Input Data +In interactive debug mode, these commands are available: -```hyp -Focus { - induce userInput: string = Input("Enter a number: "); - - if (IsNumber(userInput)) { - induce number: number = ToInt(userInput); - DebugPrint("Valid number entered: " + number); - } else { - DebugPrint("Invalid input: " + userInput); - Observe("Please enter a valid number"); - } -} Relax -``` +#### Execution Control -### 4. Use Type checking +- `continue` / `c` - Continue to the next breakpoint +- `step` / `s` - Execute one line (step into) +- `next` / `n` - Execute one line, skipping functions +- `finish` / `f` - Run until the end of the function +- `run` / `r` - Restart execution -```hyp -Focus { - induce data: any = GetData(); - - if (IsString(data)) { - DebugPrint("Data is string: " + data); - } else if (IsNumber(data)) { - DebugPrint("Data is number: " + data); - } else if (IsArray(data)) { - DebugPrint("Data is array with " + ArrayLength(data) + " elements"); - } else { - DebugPrint("Unknown data type: " + TypeOf(data)); - } -} Relax -``` +#### Breakpoint Management -### 5. Monitor Performance +- `break ` / `b ` - Set a breakpoint +- `delete ` / `d ` - Delete a breakpoint +- `breakpoints` / `bl` - Show all breakpoints +- `clear` - Clear all breakpoints -```hyp -Focus { - var startTime = GetCurrentTime(); +#### Variable Inspection - // Your code here - induce result: number = CalculateComplexOperation(); +- `locals` / `l` - Show local variables +- `globals` / `g` - Show global variables +- `print ` / `p ` - Print a variable +- `watch ` / `w ` - Add a watch expression - var endTime = GetCurrentTime(); - var duration = endTime - startTime; +#### Navigation - DebugPrint("Operation took " + duration + " seconds"); +- `list` - Source around current position +- `where` / `bt` - Show call stack +- `help` - Show help +- `quit` - Exit debug session - if (duration > 5) { - DebugPrint("WARNING: Operation took longer than expected"); - } -} Relax -``` +### 5. Trace Files -## Common Debugging Scenarios +With `--trace-file`, you can create a detailed trace log: -### 1. Variable Scope Issues +```bash +hypnoscript exec script.hyp --debug --trace-file debug.log +``` -```hyp -Focus { - induce globalVar: string = "Global"; +The trace file contains: - Tranceify LocalScope { - induce localVar: string = "Local"; - DebugPrint("Inside scope - Global: " + globalVar + ", Local: " + localVar); - } +- Executed lines with timestamps +- Variable changes +- Breakpoint hits +- Call stack changes - DebugPrint("Outside scope - Global: " + globalVar); - // localVar is not accessible here -} Relax -``` +### 6. Error Reporting -### 2. Function Parameters Issues +HypnoScript provides detailed error reports with: -```hyp -Focus { - function ValidateUser(name: string, age: number): boolean { - DebugPrint("Validating user: " + name + ", age: " + age); - - if (IsNullOrEmpty(name)) { - DebugPrint("ERROR: Name is null or empty"); - return false; - } - - if (age < 0 || age > 150) { - DebugPrint("ERROR: Invalid age: " + age); - return false; - } - - DebugPrint("User validation successful"); - return true; - } - - induce isValid: boolean = ValidateUser("John", 25); - DebugPrint("Validation result: " + isValid); -} Relax -``` +- **Line numbers and file locations** +- **Stack traces** for function calls +- **Type information** for variables +- **Context information** for better understanding -### 3. Array and Collection Issues +## Example Debug Session ```hyp -Focus { - induce numbers: number[] = [1, 2, 3, 4, 5]; - DebugPrint("Array length: " + ArrayLength(numbers)); - - for (induce i: number = 0; i < ArrayLength(numbers); i = i + 1) { - DebugPrint("Element " + i + ": " + numbers[i]); - } - - // Check for out-of-bounds access - if (ArrayLength(numbers) > 10) { - DebugPrint("WARNING: Large array detected"); - } -} Relax -``` +$ hypnoscript exec calculator.hyp --debug --breakpoints 10 -## Debugging Tools Integration +HypnoScript Debugger v1.2.0 +Type 'help' for available commands. -### 1. IDE Integration +(hypno-debug) run +Starting execution... -- **Visual Studio Code**: Use the HypnoScript extension for syntax highlighting and debugging -- **Visual Studio**: Full debugging support with breakpoints and variable inspection -- **JetBrains Rider**: Advanced debugging features with step-through execution +-> Breakpoint hit at line 10 + 10 | induce result = add(a, b); -### 2. External Tools +(hypno-debug) locals +Local variables: + a: Int = 5 + b: Int = 3 -- **Log analyzers**: Parse and analyze log files for patterns -- **Performance profilers**: Detailed performance analysis -- **Memory analyzers**: Track memory usage and identify leaks +(hypno-debug) step + -> Line 15 (in add()) + 15 | awaken x + y; -### 3. Continuous Integration +(hypno-debug) print x +x = 5 -- **Automated testing**: Catch issues early in development -- **Code quality checks**: Ensure code meets standards -- **Performance regression testing**: Monitor performance over time +(hypno-debug) finish + -> Back in line 11 + 11 | observe(result); -## Getting Help +(hypno-debug) print result +result = 8 -If you encounter issues that you can't resolve with the debugging tools: +(hypno-debug) continue +8 +Program finished. +``` -1. **Check the logs**: Look for error messages and warnings -2. **Review the documentation**: Consult the language reference -3. **Search the community**: Check forums and GitHub issues -4. **Create a minimal example**: Reproduce the issue in a simple script -5. **Report the issue**: Include debug output and error messages +## Further Documentation -Remember: Good debugging practices lead to more maintainable and reliable code! +- [Debug Mode](./debug-mode) - Complete command reference +- [Breakpoints](./breakpoints) - Detailed breakpoint documentation +- [Debugging Tools](./tools) - All builtin functions +- [Best Practices](./best-practices) - Tips for effective debugging +- [Troubleshooting](./troubleshooting) - Solve common issues diff --git a/hypnoscript-docs/docs/debugging/tools.md b/hypnoscript-docs/docs/debugging/tools.md index d59cdd1..779cbb9 100644 --- a/hypnoscript-docs/docs/debugging/tools.md +++ b/hypnoscript-docs/docs/debugging/tools.md @@ -2,496 +2,325 @@ sidebar_position: 1 --- -# Debugging-Tools +# Debugging Tools -HypnoScript bietet umfassende Debugging-Functionalitäten für die Entwicklung und Fehlerbehebung von Skripten. +HypnoScript provides comprehensive debugging capabilities for developing and troubleshooting scripts. -## Debug-Modi +## CLI Debug Commands -### Basic Debug-Modus +### Start Debug Mode ```bash -# Debug-Modus starten -dotnet run --project HypnoScript.CLI -- debug script.hyp +# Start debug mode +hypnoscript exec --debug script.hyp -# Mit detaillierter Ausgabe -dotnet run --project HypnoScript.CLI -- debug script.hyp --verbose +# With detailed output +hypnoscript exec --debug --verbose script.hyp -# Mit Timeout -dotnet run --project HypnoScript.CLI -- debug script.hyp --timeout 60 -``` - -### Schritt-für-Schritt-Debugging +# With initial breakpoints +hypnoscript exec --debug --breakpoints 10,25,42 script.hyp -```bash -# Schritt-für-Schritt-Ausführung -dotnet run --project HypnoScript.CLI -- debug script.hyp --step +# With watch expressions +hypnoscript exec --debug --watch counter,result script.hyp -# Mit Variablen-Anzeige -dotnet run --project HypnoScript.CLI -- debug script.hyp --step --variables - -# Mit Call-Stack -dotnet run --project HypnoScript.CLI -- debug script.hyp --step --call-stack +# With trace file +hypnoscript exec --debug --trace-file debug.log script.hyp ``` -### Trace-Modus +### Combined Options ```bash -# Ausführungs-Trace aktivieren -dotnet run --project HypnoScript.CLI -- debug script.hyp --trace - -# Trace in Datei speichern -dotnet run --project HypnoScript.CLI -- debug script.hyp --trace --output trace.log - -# Detaillierter Trace -dotnet run --project HypnoScript.CLI -- debug script.hyp --trace --detailed -``` - -## Breakpoints - -### Breakpoint-File erstellen - -```txt -# breakpoints.txt -10 # Zeile 10 -25 # Zeile 25 -math.hyp:15 # Zeile 15 in math.hyp -utils.hyp:* # Alle Zeilen in utils.hyp +# Complete debug session with all options +hypnoscript exec --debug \ + --breakpoints 10,25 \ + --watch x,y,result \ + --trace-file session.log \ + --verbose \ + script.hyp ``` -### Breakpoints verwenden +## Debug Builtin Functions -```bash -# Mit Breakpoint-Datei -dotnet run --project HypnoScript.CLI -- debug script.hyp --breakpoints breakpoints.txt +HypnoScript provides several built-in functions for debugging: -# Interaktive Breakpoints -dotnet run --project HypnoScript.CLI -- debug script.hyp --interactive +### inspect(value) -# Bedingte Breakpoints -dotnet run --project HypnoScript.CLI -- debug script.hyp --breakpoints conditional.txt -``` +Returns a detailed representation of a value, including type information: -### Bedingte Breakpoints +```hypnoscript +Focus + induce arr = [1, 2, 3]; + observe(inspect(arr)); + // Output: Array[Int](3) = [1, 2, 3] -```txt -# conditional.txt -10:result > 100 # Zeile 10, wenn result > 100 -15:IsEmpty(input) # Zeile 15, wenn input leer ist -20:ArrayLength(arr) == 0 # Zeile 20, wenn Array leer ist + induce obj = { name: "Test", value: 42 }; + observe(inspect(obj)); + // Output: Object { name: String = "Test", value: Int = 42 } +Relax ``` -## Variablen-Inspektion +### typeOf(value) -### Variablen anzeigen - -```bash -# Alle Variablen anzeigen -dotnet run --project HypnoScript.CLI -- debug script.hyp --variables +Returns the type of a value as a string: -# Spezifische Variablen überwachen -dotnet run --project HypnoScript.CLI -- debug script.hyp --watch "result,sum,total" - -# Variablen-Historie -dotnet run --project HypnoScript.CLI -- debug script.hyp --variable-history +```hypnoscript +Focus + observe(typeOf(42)); // "Int" + observe(typeOf("Hello")); // "String" + observe(typeOf([1,2,3])); // "Array" + observe(typeOf(true)); // "Bool" +Relax ``` -### Variablen-Monitoring +### stackTrace() -```bash -# Variablen in Echtzeit überwachen -dotnet run --project HypnoScript.CLI -- debug script.hyp --monitor-variables +Returns the current call stack as a string: -# Variablen-Änderungen loggen -dotnet run --project HypnoScript.CLI -- debug script.hyp --log-variables --output var-changes.log -``` +```hypnoscript +Focus + suggestion innerFunction() { + observe(stackTrace()); + } -## Call-Stack und Performance + suggestion outerFunction() { + innerFunction(); + } -### Call-Stack-Analyse + outerFunction(); + // Output: + // Call Stack: + // #0: innerFunction() at script.hyp:3 + // #1: outerFunction() at script.hyp:7 + // #2:
at script.hyp:10 +Relax +``` -```bash -# Call-Stack anzeigen -dotnet run --project HypnoScript.CLI -- debug script.hyp --call-stack +### dump(value) -# Detaillierter Call-Stack -dotnet run --project HypnoScript.CLI -- debug script.hyp --call-stack --detailed +Prints the value in a formatted way and returns it (useful for debugging in expressions): -# Call-Stack in Datei -dotnet run --project HypnoScript.CLI -- debug script.hyp --call-stack --output stack.log +```hypnoscript +Focus + induce result = dump(calculateValue()) * 2; + // Prints calculateValue() and continues using it +Relax ``` -### Performance-Profiling +## Assertion Functions -```bash -# Performance-Profiling aktivieren -dotnet run --project HypnoScript.CLI -- debug script.hyp --profile +### assertEqual(actual, expected, message?) -# Profiling-Report generieren -dotnet run --project HypnoScript.CLI -- debug script.hyp --profile --output profile.json +Checks whether two values are equal: -# Memory-Profiling -dotnet run --project HypnoScript.CLI -- debug script.hyp --profile --memory +```hypnoscript +Focus + induce result = calculate(5, 3); + assertEqual(result, 8, "Addition should yield 8"); +Relax ``` -## Debugging-Commande +### assertTruthy(value, message?) -### Interaktive Debugging-Commande +Checks whether a value is evaluated as truthy: -```bash -# Debug-Session starten -dotnet run --project HypnoScript.CLI -- debug script.hyp --interactive - -# Verfügbare Befehle: -# continue (c) - Weiter ausführen -# step (s) - Nächste Zeile -# next (n) - Nächste Anweisung -# break (b) - Breakpoint setzen -# variables (v) - Variablen anzeigen -# stack (st) - Call-Stack anzeigen -# quit (q) - Beenden +```hypnoscript +Focus + induce items = getItems(); + assertTruthy(ArrayLength(items) > 0, "Items should be present"); +Relax ``` -### Example für interaktive Session +## Timing Functions -```bash -$ dotnet run --project HypnoScript.CLI -- debug script.hyp --interactive - -HypnoScript Debugger v1.0 -> break 15 -Breakpoint set at line 15 -> continue -Stopped at line 15: induce result = a + b; -> variables -a = 5 -b = 3 -> step -Stopped at line 16: observe "Ergebnis: " + result; -> variables -a = 5 -b = 3 -result = 8 -> continue -Ergebnis: 8 -Debug session ended. -``` +### time(label) / timeEnd(label) -## Debugging in der Praxis +Measures execution time between two points: -### Einfaches Debugging-Example +```hypnoscript +Focus + time("operation"); -```hyp -Focus { - entrance { - induce a = 5; - induce b = 3; + // Time-consuming operation + induce result = complexCalculation(); - // Debug point 1: Check values - observe "Debug: a = " + a + ", b = " + b; + timeEnd("operation"); + // Output: operation: 123.45ms +Relax +``` - induce result = a + b; +### measureTime(label, callback) - // Debug point 2: Check result - observe "Debug: result = " + result; +Measures the execution time of a function: - if (result > 10) { - observe "Ergebnis ist größer als 10"; - } else { - observe "Ergebnis ist kleiner oder gleich 10"; - } - } -} Relax; +```hypnoscript +Focus + induce result = measureTime("sort", suggestion() { + awaken sortArray(largeArray); + }); + // Output: sort: 45.67ms +Relax ``` -### Debugging mit Breakpoints +## Logging Functions -```hyp -Focus { - suggestion calculateSum(a, b) { - // Breakpoint hier setzen - induce sum = a + b; - awaken sum; - } - - entrance { - induce x = 10; - induce y = 20; +### log(message) / warn(message) / error(message) - // Breakpoint hier setzen - induce total = calculateSum(x, y); +Different log levels for structured output: - observe "Summe: " + total; - } -} Relax; +```hypnoscript +Focus + log("Info: processing started"); + warn("Warning: file not found, using default"); + error("Error: invalid input value"); +Relax ``` -### Debugging mit Trace - -```hyp -Focus { - entrance { - observe "=== Debug-Trace Start ==="; - - induce numbers = [1, 2, 3, 4, 5]; - observe "Debug: Array erstellt: " + numbers; +### trace(message) - induce sum = 0; - observe "Debug: Summe initialisiert: " + sum; +Prints a message with stack trace: - for (induce i = 0; i < ArrayLength(numbers); induce i = i + 1) { - induce num = ArrayGet(numbers, i); - induce oldSum = sum; - induce sum = sum + num; - observe "Debug: i=" + i + ", num=" + num + ", " + oldSum + " + " + num + " = " + sum; - } - - observe "Debug: Finale Summe: " + sum; - observe "=== Debug-Trace Ende ==="; +```hypnoscript +Focus + suggestion processItem(item) { + trace("Processing item"); + // Output includes current position and call stack } -} Relax; +Relax ``` -## Advanced Debugging-Features +### breakpoint() -### Memory-Debugging +Pauses execution in debug mode: -```bash -# Memory-Usage überwachen -dotnet run --project HypnoScript.CLI -- debug script.hyp --memory-tracking +```hypnoscript +Focus + induce x = 10; -# Memory-Leaks erkennen -dotnet run --project HypnoScript.CLI -- debug script.hyp --memory-leak-detection + breakpoint(); // Pauses here when --debug is active -# Memory-Report generieren -dotnet run --project HypnoScript.CLI -- debug script.hyp --memory-report --output memory.json + induce y = x * 2; +Relax ``` -### Exception-Debugging +## Interactive Debug Commands -```bash -# Exception-Details anzeigen -dotnet run --project HypnoScript.CLI -- debug script.hyp --exception-details +In interactive debug mode, these commands are available: -# Exception-Handling debuggen -dotnet run --project HypnoScript.CLI -- debug script.hyp --exception-tracking +### Execution Control -# Exception-Stack-Trace -dotnet run --project HypnoScript.CLI -- debug script.hyp --stack-trace -``` +| Command | Alias | Description | +| ---------- | ----- | ------------------------------------ | +| `continue` | `c` | Continue to the next breakpoint | +| `step` | `s` | Execute one line (step into) | +| `next` | `n` | Execute one line, skipping functions | +| `finish` | `f` | Run to the end of the function | +| `run` | `r` | Restart execution | -### Thread-Debugging +### Variable Inspection -```bash -# Thread-Informationen anzeigen -dotnet run --project HypnoScript.CLI -- debug script.hyp --thread-info +| Command | Alias | Description | +| -------------- | ---------- | ---------------------- | +| `locals` | `l` | Show local variables | +| `globals` | `g` | Show global variables | +| `print ` | `p ` | Print a variable | +| `watch ` | `w ` | Add a watch expression | +| `watches` | | Show all watches | -# Thread-Switches verfolgen -dotnet run --project HypnoScript.CLI -- debug script.hyp --thread-tracking +### Breakpoint Management -# Deadlock-Erkennung -dotnet run --project HypnoScript.CLI -- debug script.hyp --deadlock-detection -``` +| Command | Alias | Description | +| --------------- | ---------- | --------------------- | +| `break ` | `b ` | Set a breakpoint | +| `delete ` | `d ` | Delete a breakpoint | +| `breakpoints` | `bl` | Show all breakpoints | +| `clear` | | Clear all breakpoints | -## Debugging-Konfiguration - -### Debug-Konfiguration in hypnoscript.config.json - -```json -{ - "debugging": { - "enabled": true, - "breakOnError": true, - "showVariables": true, - "showCallStack": true, - "traceExecution": false, - "memoryTracking": false, - "profiling": { - "enabled": false, - "output": "profile.json" - }, - "breakpoints": { - "file": "breakpoints.txt", - "conditional": true - }, - "logging": { - "level": "debug", - "output": "debug.log" - } - } -} -``` +### Navigation -### Debug-environment variablen +| Command | Alias | Description | +| -------------------- | ----- | ------------------------------ | +| `list` | | Source around current position | +| `list ` | | Show source range | +| `where` | `bt` | Show call stack | +| `help` | | Show help | +| `quit` | | Exit debug session | -```bash -# Debug-spezifische Umgebungsvariablen -export HYPNOSCRIPT_DEBUG=true -export HYPNOSCRIPT_DEBUG_LEVEL=verbose -export HYPNOSCRIPT_BREAK_ON_ERROR=true -export HYPNOSCRIPT_SHOW_VARIABLES=true -export HYPNOSCRIPT_TRACE_EXECUTION=true -``` - -## Debugging-Workflows +## Debug Trace File -### Entwicklungsworkflow mit Debugging +With `--trace-file`, a detailed trace log is created: ```bash -#!/bin/bash -# debug-workflow.sh - -echo "=== HypnoScript Debug Workflow ===" - -# 1. Syntax prüfen -echo "1. Validating syntax..." -dotnet run --project HypnoScript.CLI -- validate script.hyp - -# 2. Debug-Modus mit Trace -echo "2. Running in debug mode..." -dotnet run --project HypnoScript.CLI -- debug script.hyp --trace --output debug.log +hypnoscript exec --debug --trace-file debug.log script.hyp +``` -# 3. Performance-Profiling -echo "3. Performance profiling..." -dotnet run --project HypnoScript.CLI -- debug script.hyp --profile --output profile.json +The trace file contains: -# 4. Memory-Analyse -echo "4. Memory analysis..." -dotnet run --project HypnoScript.CLI -- debug script.hyp --memory-tracking --output memory.json +- **Executed lines** with timestamps +- **Variable changes** on each step +- **Breakpoint hits** with context +- **Call stack changes** on function calls +- **Timing information** for performance analysis -echo "Debug workflow completed!" -``` - -### Automatisierte Debugging-Tests +### Example Trace Output ```bash -#!/bin/bash -# auto-debug.sh - -echo "=== Automated Debugging ===" - -# Debug-Modus mit allen Features -dotnet run --project HypnoScript.CLI -- debug script.hyp \ - --trace \ - --profile \ - --memory-tracking \ - --variables \ - --call-stack \ - --output debug-complete.log - -# Ergebnisse analysieren -echo "Debug results saved to debug-complete.log" +[00:00.001] EXEC script.hyp:5 induce x = 10; +[00:00.001] VAR x = Int(10) +[00:00.002] EXEC script.hyp:6 induce y = 20; +[00:00.002] VAR y = Int(20) +[00:00.003] BREAK script.hyp:7 Breakpoint hit +[00:00.015] EXEC script.hyp:7 induce result = x + y; +[00:00.015] VAR result = Int(30) +[00:00.016] CALL script.hyp:8 -> processResult() +[00:00.020] RET script.hyp:8 <- processResult() = Null ``` ## Best Practices -### Effektives Debugging - -```hyp -// 1. Strategische Breakpoints setzen -Focus { - entrance { - induce input = "test"; +### 1. Remove Debugging Code - // Breakpoint 1: Eingabe validieren - if (IsEmpty(input)) { - observe "Fehler: Leere Eingabe"; - return; - } +Remove debugging functions before production use: - // Breakpoint 2: Verarbeitung - induce processed = ToUpper(input); +```hypnoscript +// Development +breakpoint(); +dump(value); - // Breakpoint 3: Check result - observe "Verarbeitet: " + processed; - } -} Relax; +// Production - remove these lines ``` -### Debugging-Logging - -```hyp -// 2. Strukturiertes Debug-Logging -Focus { - suggestion debugLog(message, data) { - induce timestamp = Now(); - observe "[" + timestamp + "] DEBUG: " + message + " = " + data; - } - - entrance { - debugLog("Start", "Skript beginnt"); +### 2. Meaningful Timer Labels - induce result = 42; - debugLog("Berechnung", result); +Use descriptive labels for timing: - debugLog("Ende", "Skript beendet"); - } -} Relax; +```hypnoscript +time("database-query"); +time("json-parsing"); +time("api-call-users"); ``` -### Performance-Debugging - -```hyp -// 3. Performance-kritische Bereiche debuggen -Focus { - entrance { - induce startTime = Timestamp(); +### 3. Assertions for Tests - // Performance-kritischer Code - for (induce i = 0; i < 1000; induce i = i + 1) { - induce result = Pow(i, 2); - } +Use assertions for automated tests: - induce endTime = Timestamp(); - induce duration = endTime - startTime; +```hypnoscript +Focus + induce result = add(2, 3); + assertEqual(result, 5, "add() should add correctly"); - if (duration > 1.0) { - observe "WARNUNG: Langsame Ausführung (" + duration + "s)"; - } - } -} Relax; + induce isEmpty = isListEmpty([]); + assertTruthy(isEmpty, "Empty list should be empty"); +Relax ``` -## Troubleshooting - -### Häufige Debugging-Probleme - -1. **Breakpoints werden ignoriert** - - ```bash - # Prüfen Sie die Zeilennummern - cat -n script.hyp - - # Verwenden Sie absolute Pfade - dotnet run --project HypnoScript.CLI -- debug /absolute/path/script.hyp - ``` - -2. **Variablen werden nicht angezeigt** - - ```bash - # Debug-Modus mit expliziter Variablen-Anzeige - dotnet run --project HypnoScript.CLI -- debug script.hyp --variables --verbose +### 4. Trace Files for Analysis - # Variablen-Scope prüfen - dotnet run --project HypnoScript.CLI -- debug script.hyp --variable-scope - ``` +Use trace files for post-mortem analysis: -3. **Trace-File ist zu groß** - - ```bash - # Selektives Tracing - dotnet run --project HypnoScript.CLI -- debug script.hyp --trace --filter "function1,function2" - - # Trace komprimieren - dotnet run --project HypnoScript.CLI -- debug script.hyp --trace --compressed - ``` - -## Next Steps - -- [Debugging-Best-Practices](./best-practices) - Advanced Debugging-Techniken -- [Performance-Debugging](./performance) - Performance-Optimierung -- [Error-Handling](../error-handling/overview) - Fehlerbehandlung -- [Runtime-Debugging](../enterprise/debugging) - Runtime-Debugging-Tools - ---- +```bash +# Create trace +hypnoscript exec --debug --trace-file crash.log problematic.hyp -**Debugging-Tools gemeistert? Dann lerne [Debugging-Best-Practices](./best-practices) kennen!** 🔍 +# Analyze later +cat crash.log | grep "ERROR\|BREAK" +``` diff --git a/hypnoscript-docs/docs/development/debugging.md b/hypnoscript-docs/docs/development/debugging.md index 2c8be59..6add24f 100644 --- a/hypnoscript-docs/docs/development/debugging.md +++ b/hypnoscript-docs/docs/development/debugging.md @@ -243,6 +243,7 @@ For complex debugging scenarios, you can: ``` 3. **Generate execution traces:** + ```bash hyp profile script.hyp --trace --output trace.json ``` @@ -304,7 +305,7 @@ Unhandled runtime exception occurs. Environment: - OS: Windows 10 -- HypnoScript version: 1.0.0 +- HypnoScript version: 1.2.0 ``` ## Conclusion diff --git a/hypnoscript-docs/docs/enterprise/api-management.md b/hypnoscript-docs/docs/enterprise/api-management.md index 79f009b..9f293a0 100644 --- a/hypnoscript-docs/docs/enterprise/api-management.md +++ b/hypnoscript-docs/docs/enterprise/api-management.md @@ -807,7 +807,7 @@ openapi { // Basic Information info: { title: "HypnoScript API" - version: "1.0.0" + version: "1.2.0" description: "Runtime API for HypnoScript scripting and execution" contact: { name: "HypnoScript Support" @@ -1290,25 +1290,21 @@ api_monitoring { ### API Best Practices 1. **API Design** - - Follow RESTful principles - Use consistent naming conventions - Implement versioning 2. **Security** - - OAuth2/JWT for authentication - Implement rate limiting - Perform input validation 3. **Performance** - - Implement caching strategies - Pagination for large datasets - Enable compression 4. **Monitoring** - - Collect comprehensive metrics - Proactive alerting systems - Implement request tracing diff --git a/hypnoscript-docs/docs/enterprise/backup-recovery.md b/hypnoscript-docs/docs/enterprise/backup-recovery.md index 7a8ab70..706b9f9 100644 --- a/hypnoscript-docs/docs/enterprise/backup-recovery.md +++ b/hypnoscript-docs/docs/enterprise/backup-recovery.md @@ -962,25 +962,21 @@ backup_monitoring { ### Backup Best Practices 1. **3-2-1 Rule** - - 3 copies of data - 2 different storage media - 1 copy offsite 2. **Backup Validation** - - Regular backup tests - Perform recovery tests - Verify data integrity 3. **Encryption** - - Encrypt backup data - Manage keys securely - Transport-Encryption 4. **Monitoring** - - Monitor backup status - Automatic alerting - Regular reports @@ -993,19 +989,16 @@ backup_monitoring { ### Recovery Best Practices 1. **RTO/RPO Definition** - - Define clear objectives - Regular review - Business validation 2. **Testing** - - Regular DR tests - Complete recovery tests - Documentation of results 3. **Automation** - - Automatic failover - Script-based recovery - Monitoring and alerting @@ -1019,7 +1012,7 @@ backup_monitoring { - [ ] Backup strategy defined - [ ] RTO/RPO objectives set -- [ ] Backup-Automation implementiert +- [ ] Backup automation implemented - [ ] Encryption configured - [ ] Monitoring configured - [ ] DR plan created diff --git a/hypnoscript-docs/docs/enterprise/database.md b/hypnoscript-docs/docs/enterprise/database.md index 744d5c2..b8e9b65 100644 --- a/hypnoscript-docs/docs/enterprise/database.md +++ b/hypnoscript-docs/docs/enterprise/database.md @@ -118,7 +118,7 @@ connection_pooling { ## ORM (Object-Relational Mapping) -### Entity-Definitionen +### Entity Definitions ```hyp // Entity models @@ -375,7 +375,7 @@ entities { } ``` -### Repository-Pattern +### Repository Pattern ```hyp // Repository implementations @@ -543,7 +543,7 @@ repositories { ## Transaction Management -### Transaktions-Konfiguration +### Transaction Configuration ```hyp // Transaction management @@ -623,7 +623,7 @@ transactions { } ``` -### Transaktions-Beispiele +### Transaction Examples ```hyp // Transaction examples @@ -706,9 +706,9 @@ transaction_examples { } ``` -## Datenbank-Migrationen +## Database Migrations -### Migrations-System +### Migration System ```hyp // Migrations configuration @@ -756,7 +756,7 @@ migrations { } ``` -### Migrations-Beispiele +### Migration Examples ```hyp // Migration examples @@ -887,9 +887,9 @@ migration_examples { } ``` -## Datenbank-Optimierung +## Database Optimization -### Performance-Optimierung +### Performance Optimization ```hyp // Database optimization @@ -961,25 +961,21 @@ database_optimization { ### Database Best Practices 1. **Connection Management** - - Use connection pooling - Close connections properly - Configure timeouts 2. **Transaction Management** - - Prefer short transactions - Choose isolation levels consciously - Define rollback strategies 3. **Query Optimization** - - Place indexes strategically - Avoid N+1 query problem - Use prepared statements 4. **Security** - - Prevent SQL injection - Use parameterized queries - Minimize permissions diff --git a/hypnoscript-docs/docs/enterprise/messaging.md b/hypnoscript-docs/docs/enterprise/messaging.md index 9ff136a..9e9ef04 100644 --- a/hypnoscript-docs/docs/enterprise/messaging.md +++ b/hypnoscript-docs/docs/enterprise/messaging.md @@ -7,7 +7,7 @@ HypnoScript provides comprehensive messaging and queuing features for runtime en ### Broker Configuration ```hyp -// Message Broker-Konfiguration +// Message broker configuration messaging { // Apache Kafka kafka: { @@ -17,7 +17,7 @@ messaging { "kafka-3.example.com:9092" ] - // Producer-Konfiguration + // Producer configuration producer: { acks: "all" retries: 3 @@ -35,7 +35,7 @@ messaging { } } - // Consumer-Konfiguration + // Consumer configuration consumer: { group_id: "hypnoscript-consumer-group" auto_offset_reset: "earliest" @@ -72,7 +72,7 @@ messaging { network_recovery_interval: 5000 } - // Channel-Pooling + // Channel pooling channel_pool: { max_channels: 100 channel_timeout: 30000 @@ -100,7 +100,7 @@ messaging { keep_alive: true } - // Session-Pooling + // Session pooling session_pool: { max_sessions: 200 session_timeout: 60000 @@ -113,16 +113,16 @@ messaging { access_key_id: env.AWS_ACCESS_KEY_ID secret_access_key: env.AWS_SECRET_ACCESS_KEY - // SQS-Konfiguration + // SQS configuration sqs: { max_messages: 10 visibility_timeout: 30 wait_time_seconds: 20 - message_retention_period: 1209600 // 14 Tage + message_retention_period: 1209600 // 14 days receive_message_wait_time_seconds: 20 } - // SNS-Konfiguration + // SNS configuration sns: { message_structure: "json" message_attributes: true @@ -136,11 +136,11 @@ messaging { ### Event Definitions ```hyp -// Event-Schema-Definitionen +// Event schema definitions events { - // Script-Events + // Script events ScriptEvents: { - // Script erstellt + // Script created ScriptCreated: { event_type: "script.created" version: "1.0" @@ -161,7 +161,7 @@ events { } } - // Script aktualisiert + // Script updated ScriptUpdated: { event_type: "script.updated" version: "1.0" @@ -230,9 +230,9 @@ events { } } - // User-Events + // User events UserEvents: { - // Benutzer registriert + // User registered UserRegistered: { event_type: "user.registered" version: "1.0" @@ -252,7 +252,7 @@ events { } } - // Benutzer angemeldet + // User logged in UserLoggedIn: { event_type: "user.logged_in" version: "1.0" @@ -273,9 +273,9 @@ events { } } - // System-Events + // System events SystemEvents: { - // System-Start + // System start SystemStarted: { event_type: "system.started" version: "1.0" @@ -296,7 +296,7 @@ events { } } - // System-Fehler + // System error SystemError: { event_type: "system.error" version: "1.0" @@ -324,14 +324,14 @@ events { ### Event Producer ```hyp -// Event-Producer-Konfiguration +// Event producer configuration event_producers { - // Script-Event-Producer + // Script event producer ScriptEventProducer: { broker: "kafka" topic_prefix: "hypnoscript.events" - // Event-Mapping + // Event mapping events: { "script.created": { topic: "script-events" @@ -374,7 +374,7 @@ event_producers { } } - // Event-Serialisierung + // Event serialization serialization: { format: "json" compression: "snappy" @@ -384,7 +384,7 @@ event_producers { } } - // Event-Validierung + // Event validation validation: { schema_validation: true required_fields: ["event_type", "payload", "metadata"] @@ -392,7 +392,7 @@ event_producers { } } - // User-Event-Producer + // User event producer UserEventProducer: { broker: "kafka" topic_prefix: "hypnoscript.user" @@ -420,14 +420,14 @@ event_producers { ### Event Consumer ```hyp -// Event-Consumer-Konfiguration +// Event consumer configuration event_consumers { - // Script-Event-Consumer + // Script event consumer ScriptEventConsumer: { broker: "kafka" group_id: "script-event-processor" - // Topic-Subscription + // Topic subscription topics: [ { name: "script-events" @@ -441,7 +441,7 @@ event_consumers { } ] - // Event-Handler + // Event handler handlers: { "script.created": { handler: "ScriptCreatedHandler" @@ -474,7 +474,7 @@ event_consumers { } } - // Consumer-Einstellungen + // Consumer settings settings: { max_poll_records: 100 max_poll_interval_ms: 300000 @@ -484,7 +484,7 @@ event_consumers { } } - // Analytics-Event-Consumer + // Analytics event consumer AnalyticsEventConsumer: { broker: "kafka" group_id: "analytics-processor" @@ -530,13 +530,13 @@ event_consumers { ```hyp // Request-Reply Pattern request_reply { - // Script-Validierung + // Script validation script_validation: { request_topic: "script.validation.request" reply_topic: "script.validation.reply" correlation_id_header: "correlation_id" - // Request-Schema + // Request schema request_schema: { script_id: "uuid" content: "string" @@ -544,7 +544,7 @@ request_reply { timeout: "integer" } - // Reply-Schema + // Reply schema reply_schema: { script_id: "uuid" valid: "boolean" @@ -553,8 +553,8 @@ request_reply { validation_time_ms: "integer" } - // Timeout-Konfiguration - timeout: 30000 // 30 Sekunden + // Timeout configuration + timeout: 30000 // 30 seconds retry_policy: { max_retries: 3 backoff_strategy: "exponential" @@ -584,7 +584,7 @@ request_reply { execution_time_ms: "integer" } - timeout: 300000 // 5 Minuten + timeout: 300000 // 5 minutes retry_policy: { max_retries: 2 backoff_strategy: "exponential" @@ -609,7 +609,7 @@ pub_sub { partition_strategy: "hash" partition_key: "script_id" - // Message-Format + // Message format message_format: { type: "json" compression: "snappy" @@ -646,7 +646,7 @@ pub_sub { ] } - // System-Events + // System events system_events: { topic: "system.events" @@ -684,9 +684,9 @@ pub_sub { ```hyp // Dead Letter Queue Pattern dead_letter_queue { - // DLQ-Konfiguration + // DLQ configuration dlq_config: { - // Haupt-Queue + // Main queue main_queue: { name: "script-execution-queue" max_retries: 3 @@ -694,23 +694,23 @@ dead_letter_queue { dlq_name: "script-execution-dlq" } - // DLQ-Queue + // DLQ queue dlq_queue: { name: "script-execution-dlq" - message_retention: 2592000 // 30 Tage + message_retention: 2592000 // 30 days max_redelivery: 1 } } - // DLQ-Handler + // DLQ handlers dlq_handlers: { - // Fehleranalyse + // Error analysis error_analysis: { handler: "DLQErrorAnalysisHandler" concurrency: 2 timeout: 60000 - // Fehler-Kategorisierung + // Error categorization error_categories: { validation_error: { action: "log_and_alert" @@ -727,13 +727,13 @@ dead_letter_queue { } } - // Manuelle Verarbeitung + // Manual processing manual_processing: { handler: "DLQManualProcessingHandler" concurrency: 1 timeout: 300000 - // Benutzer-Interface + // User interface ui: { enabled: true endpoint: "/api/dlq/manual-processing" @@ -750,13 +750,13 @@ dead_letter_queue { ### Message Guarantees ```hyp -// Message-Garantien +// Message guarantees message_guarantees { // At-Least-Once Delivery at_least_once: { enabled: true - // Producer-Garantien + // Producer guarantees producer: { acks: "all" retries: 3 @@ -764,7 +764,7 @@ message_guarantees { transactional: true } - // Consumer-Garantien + // Consumer guarantees consumer: { manual_commit: true commit_sync: true @@ -776,7 +776,7 @@ message_guarantees { exactly_once: { enabled: true - // Idempotenz + // Idempotence idempotence: { enabled: true key_strategy: "message_id" @@ -784,7 +784,7 @@ message_guarantees { ttl: 86400 // 24 Stunden } - // Transaktionale Verarbeitung + // Transactional processing transactional: { enabled: true isolation_level: "read_committed" @@ -792,17 +792,17 @@ message_guarantees { } } - // Message-Ordering + // Message ordering message_ordering: { enabled: true - // Partition-Key-Strategie + // Partition key strategy partition_key: { strategy: "hash" fields: ["script_id", "user_id"] } - // Consumer-Gruppen + // Consumer groups consumer_groups: { single_partition_consumers: true max_concurrent_partitions: 1 @@ -814,11 +814,11 @@ message_guarantees { ### Message Monitoring ```hyp -// Message-Monitoring +// Message monitoring message_monitoring { - // Metriken + // Metrics metrics: { - // Producer-Metriken + // Producer metrics producer: { message_count: true message_size: true @@ -827,7 +827,7 @@ message_monitoring { retry_count: true } - // Consumer-Metriken + // Consumer metrics consumer: { message_count: true processing_latency: true @@ -836,7 +836,7 @@ message_monitoring { commit_latency: true } - // Queue-Metriken + // Queue metrics queue: { queue_size: true queue_depth: true @@ -847,23 +847,23 @@ message_monitoring { // Alerting alerting: { - // Consumer-Lag + // Consumer lag consumer_lag: { threshold: 1000 alert_level: "warning" escalation_time: 300 // 5 Minuten } - // Error-Rate + // Error rate error_rate: { threshold: 0.05 // 5% alert_level: "critical" window_size: 300 // 5 Minuten } - // Processing-Latency + // Processing latency processing_latency: { - threshold: 30000 // 30 Sekunden + threshold: 30000 // 30 seconds alert_level: "warning" percentile: 95 } @@ -873,13 +873,13 @@ message_monitoring { tracing: { enabled: true - // Trace-Propagation + // Trace propagation trace_propagation: { headers: ["x-trace-id", "x-span-id", "x-correlation-id"] baggage: true } - // Span-Creation + // Span creation span_creation: { producer_send: true consumer_receive: true @@ -894,45 +894,41 @@ message_monitoring { ### Messaging Best Practices 1. **Message Design** - - - Immutable Events verwenden - - Schema-Versionierung implementieren - - Backward Compatibility gewährleisten + - Use immutable events + - Implement schema versioning + - Ensure backward compatibility 2. **Reliability** - - - Idempotente Consumer implementieren - - Dead Letter Queues konfigurieren - - Retry-Policies definieren + - Implement idempotent consumers + - Configure dead letter queues + - Define retry policies 3. **Performance** - - - Batch-Processing verwenden - - Partitioning-Strategien optimieren - - Consumer-Gruppen richtig konfigurieren + - Use batch processing + - Optimize partitioning strategies + - Configure consumer groups correctly 4. **Monitoring** - - - Consumer-Lag überwachen - - Error-Rates tracken - - Message-Age monitoren + - Monitor consumer lag + - Track error rates + - Monitor message age 5. **Security** - - Message-Verschlüsselung aktivieren - - Authentication/Authorization implementieren - - Audit-Logging aktivieren + - Enable message encryption + - Implement authentication/authorization + - Enable audit logging ### Messaging Checklist -- [ ] Message Broker konfiguriert -- [ ] Event-Schemas definiert -- [ ] Producer/Consumer implementiert -- [ ] Message patterns ausgewählt -- [ ] Dead Letter Queues eingerichtet +- [ ] Message broker configured +- [ ] Event schemas defined +- [ ] Producer/consumer implemented +- [ ] Message patterns selected +- [ ] Dead letter queues set up - [ ] Monitoring configured - [ ] Security implemented - [ ] Performance optimized - [ ] Error handling defined - [ ] Documentation created -These messaging and queuing features ensure that HypnoScript in runtime environments skalierbare, zuverlässige und event-driven Architekturen unterstützt. +These messaging and queuing features ensure that HypnoScript in runtime environments supports scalable, reliable, event-driven architectures. diff --git a/hypnoscript-docs/docs/enterprise/monitoring.md b/hypnoscript-docs/docs/enterprise/monitoring.md index 4d54c4f..204879a 100644 --- a/hypnoscript-docs/docs/enterprise/monitoring.md +++ b/hypnoscript-docs/docs/enterprise/monitoring.md @@ -1,15 +1,15 @@ # Runtime Monitoring & Observability -HypnoScript bietet umfassende Monitoring- und Observability-Funktionen für Runtime-Umgebungen, einschließlich Metriken, Logging, Distributed Tracing und proaktive Alerting-Systeme. +HypnoScript provides comprehensive monitoring and observability features for runtime environments, including metrics, logging, distributed tracing, and proactive alerting systems. -## Monitoring-Architektur +## Monitoring Architecture -### Überblick +### Overview ```hyp -// Monitoring-Stack-Konfiguration +// Monitoring stack configuration monitoring { - // Datensammlung + // Data collection collection: { metrics: "prometheus" logs: "fluentd" @@ -17,7 +17,7 @@ monitoring { events: "kafka" } - // Speicherung + // Storage storage: { metrics: "influxdb" logs: "elasticsearch" @@ -25,7 +25,7 @@ monitoring { events: "kafka" } - // Visualisierung + // Visualization visualization: { dashboards: "grafana" alerting: "alertmanager" @@ -34,14 +34,14 @@ monitoring { } ``` -## Metriken +## Metrics -### System-Metriken +### System Metrics ```hyp -// System-Monitoring +// System monitoring system_metrics { - // CPU-Metriken + // CPU metrics cpu: { usage_percent: true load_average: true @@ -49,7 +49,7 @@ system_metrics { interrupts: true } - // Memory-Metriken + // Memory metrics memory: { usage_bytes: true available_bytes: true @@ -57,7 +57,7 @@ system_metrics { page_faults: true } - // Disk-Metriken + // Disk metrics disk: { usage_percent: true io_operations: true @@ -65,7 +65,7 @@ system_metrics { latency: true } - // Network-Metriken + // Network metrics network: { bytes_sent: true bytes_received: true @@ -77,12 +77,12 @@ system_metrics { } ``` -### Anwendungs-Metriken +### Application Metrics ```hyp -// Anwendungs-Monitoring +// Application monitoring application_metrics { - // Performance-Metriken + // Performance metrics performance: { response_time: { p50: true @@ -98,7 +98,7 @@ application_metrics { availability: true } - // Business-Metriken + // Business metrics business: { active_users: true script_executions: true @@ -106,7 +106,7 @@ application_metrics { revenue_impact: true } - // Custom-Metriken + // Custom metrics custom: { script_complexity: true execution_duration: true @@ -116,18 +116,18 @@ application_metrics { } ``` -### Metriken-Konfiguration +### Metrics Configuration ```hyp -// Metriken-Sammlung +// Metrics collection metrics_collection { - // Prometheus-Konfiguration + // Prometheus configuration prometheus: { scrape_interval: "15s" evaluation_interval: "15s" retention_days: 30 - // Service Discovery + // Service discovery service_discovery: { kubernetes: true consul: true @@ -147,7 +147,7 @@ metrics_collection { ] } - // Custom-Metriken + // Custom metrics custom_metrics: { script_execution_time: { type: "histogram" @@ -170,25 +170,25 @@ metrics_collection { ## Logging -### Strukturiertes Logging +### Structured Logging ```hyp -// Logging-Konfiguration +// Logging configuration logging { - // Log-Levels + // Log levels levels: { development: "debug" staging: "info" production: "warn" } - // Log-Format + // Log format format: { type: "json" timestamp: "iso8601" include_metadata: true - // Standard-Felder + // Standard fields standard_fields: [ "timestamp", "level", @@ -201,7 +201,7 @@ logging { ] } - // Log-Rotation + // Log rotation rotation: { max_size: "100MB" max_files: 10 @@ -211,12 +211,12 @@ logging { } ``` -### Log-Aggregation +### Log Aggregation ```hyp -// Log-Aggregation +// Log aggregation log_aggregation { - // Fluentd-Konfiguration + // Fluentd configuration fluentd: { input: { type: "tail" @@ -266,12 +266,12 @@ log_aggregation { ## Distributed Tracing -### Tracing-Konfiguration +### Tracing Configuration ```hyp // Distributed Tracing tracing { - // Jaeger-Konfiguration + // Jaeger configuration jaeger: { endpoint: "http://jaeger.example.com:14268/api/traces" service_name: "hypnoscript" @@ -280,7 +280,7 @@ tracing { // Sampling sampling: { type: "probabilistic" - param: 0.1 // 10% der Traces + param: 0.1 // 10% of traces } // Tags @@ -291,9 +291,9 @@ tracing { } } - // Trace-Konfiguration + // Trace configuration trace_config: { - // Automatische Instrumentierung + // Automatic instrumentation auto_instrumentation: { http: true database: true @@ -301,14 +301,14 @@ tracing { messaging: true } - // Custom Spans + // Custom spans custom_spans: { script_execution: true data_processing: true external_api_call: true } - // Trace-Propagation + // Trace propagation propagation: { headers: ["x-trace-id", "x-span-id"] baggage: true @@ -317,12 +317,12 @@ tracing { } ``` -### Trace-Analyse +### Trace Analysis ```hyp -// Trace-Analyse +// Trace analysis trace_analysis { - // Performance-Analyse + // Performance analysis performance: { slow_query_detection: { threshold: "1s" @@ -333,14 +333,14 @@ trace_analysis { dependency_mapping: true } - // Error-Analyse + // Error analysis error_analysis: { error_tracking: true error_grouping: true error_trends: true } - // Business-Traces + // Business traces business_traces: { user_journey_tracking: true conversion_funnel: true @@ -351,12 +351,12 @@ trace_analysis { ## Alerting -### Alert-Konfiguration +### Alert Configuration ```hyp -// Alerting-System +// Alerting system alerting { - // Alertmanager-Konfiguration + // Alertmanager configuration alertmanager: { global: { smtp_smarthost: "smtp.example.com:587" @@ -423,12 +423,12 @@ alerting { } ``` -### Alert-Regeln +### Alert Rules ```hyp // Prometheus Alert Rules alert_rules { - // System-Alerts + // System alerts system_alerts: { high_cpu_usage: { expr: '100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80' @@ -470,7 +470,7 @@ alert_rules { } } - // Anwendungs-Alerts + // Application alerts application_alerts: { high_error_rate: { expr: 'rate(hypnoscript_errors_total[5m]) / rate(hypnoscript_requests_total[5m]) * 100 > 5' @@ -516,12 +516,12 @@ alert_rules { ## Dashboards -### Grafana-Dashboards +### Grafana Dashboards ```hyp -// Dashboard-Konfiguration +// Dashboard configuration dashboards { - // System-Dashboard + // System dashboard system_dashboard: { title: "HypnoScript System Overview" refresh: "30s" @@ -568,7 +568,7 @@ dashboards { ] } - // Anwendungs-Dashboard + // Application dashboard application_dashboard: { title: "HypnoScript Application Metrics" refresh: "15s" @@ -613,7 +613,7 @@ dashboards { ] } - // Business-Dashboard + // Business dashboard business_dashboard: { title: "HypnoScript Business Metrics" refresh: "1m" @@ -653,30 +653,30 @@ dashboards { } ``` -## Performance-Monitoring +## Performance Monitoring ### APM (Application Performance Monitoring) ```hyp -// APM-Konfiguration +// APM configuration apm { - // Performance-Tracking + // Performance tracking performance_tracking: { - // Method-Level-Tracking + // Method-level tracking method_tracking: { enabled: true threshold: "100ms" include_arguments: false } - // Database-Tracking + // Database tracking database_tracking: { enabled: true slow_query_threshold: "1s" include_sql: false } - // External-Call-Tracking + // External call tracking external_call_tracking: { enabled: true timeout_threshold: "5s" @@ -684,7 +684,7 @@ apm { } } - // Resource-Monitoring + // Resource monitoring resource_monitoring: { memory_leak_detection: true gc_monitoring: true @@ -692,7 +692,7 @@ apm { connection_pool_monitoring: true } - // Business-Transaction-Monitoring + // Business transaction monitoring business_transaction_monitoring: { user_journey_tracking: true conversion_funnel_monitoring: true @@ -703,49 +703,45 @@ apm { ## Best Practices -### Monitoring-Best-Practices +### Monitoring Best Practices 1. **Golden Signals** - - Latency (Response Time) - Traffic (Request Rate) - Errors (Error Rate) - Saturation (Resource Usage) -2. **Alerting-Strategien** - - - Wenige, aber aussagekräftige Alerts - - Verschiedene Schweregrade definieren - - Automatische Eskalation einrichten - -3. **Dashboard-Design** - - - Wichtige Metriken prominent platzieren - - Konsistente Farbgebung verwenden - - Kontextuelle Informationen hinzufügen - -4. **Logging-Strategien** - - - Strukturiertes Logging verwenden - - Sensitive Daten maskieren - - Log-Rotation konfigurieren - -5. **Tracing-Strategien** - - Distributed Tracing implementieren - - Sampling für Performance - - Business-Kontext hinzufügen - -### Monitoring-Checkliste - -- [ ] System-Metriken konfiguriert -- [ ] Anwendungs-Metriken implementiert -- [ ] Logging-System eingerichtet -- [ ] Distributed Tracing aktiviert -- [ ] Alerting-Regeln definiert -- [ ] Dashboards erstellt +2. **Alerting Strategies** + - Few but meaningful alerts + - Define different severity levels + - Set up automatic escalation + +3. **Dashboard Design** + - Place key metrics prominently + - Use consistent color schemes + - Add contextual information + +4. **Logging Strategies** + - Use structured logging + - Mask sensitive data + - Configure log rotation + +5. **Tracing Strategies** + - Implement distributed tracing + - Use sampling for performance + - Add business context + +### Monitoring Checklist + +- [ ] System metrics configured +- [ ] Application metrics implemented +- [ ] Logging system set up +- [ ] Distributed tracing enabled +- [ ] Alerting rules defined +- [ ] Dashboards created - [ ] Performance-Monitoring configured -- [ ] Business-Metriken definiert -- [ ] Monitoring-Dokumentation erstellt -- [ ] Team-Schulungen durchgeführt +- [ ] Business metrics defined +- [ ] Monitoring documentation created +- [ ] Team training completed -Diese Monitoring- und Observability-Funktionen stellen sicher, dass HypnoScript in Runtime-Umgebungen vollständig überwacht und proaktiv auf Probleme reagiert werden kann. +These monitoring and observability features ensure that HypnoScript in runtime environments is fully monitored and can respond proactively to issues. diff --git a/hypnoscript-docs/docs/enterprise/overview.md b/hypnoscript-docs/docs/enterprise/overview.md index 50a007d..9cb22ff 100644 --- a/hypnoscript-docs/docs/enterprise/overview.md +++ b/hypnoscript-docs/docs/enterprise/overview.md @@ -6,17 +6,17 @@ This overview provides a complete overview of HypnoScript's runtime documentatio ### 📋 Runtime Features -**Datei:** `features.md` +**File:** `features.md` - Comprehensive runtime features - Scalability and performance - High availability -- Multi-Tenant-Support -- Runtime-Integrationen +- Multi-tenant support +- Runtime integrations ### 🏗️ Runtime Architecture -**Datei:** `architecture.md` +**File:** `architecture.md` - Architecture patterns - Modularization @@ -28,69 +28,69 @@ This overview provides a complete overview of HypnoScript's runtime documentatio ### 🔒 Runtime Security -**Datei:** `security.md` +**File:** `security.md` - Authentication (LDAP, OAuth2, MFA) - Authorization (RBAC, ABAC) - Encryption (data at rest and in transit) -- Audit-Logging +- Audit logging - Compliance reporting (SOX, GDPR, PCI DSS) - Network security - Incident Response ### 📊 Runtime Monitoring -**Datei:** `monitoring.md` +**File:** `monitoring.md` - System and application metrics - Structured logging -- Distributed Tracing +- Distributed tracing - Proactive alerting - Grafana dashboards -- Performance-Monitoring (APM) +- Performance monitoring (APM) - Business metrics ### 🗄️ Runtime Database -**Datei:** `database.md` +**File:** `database.md` -- Multi-Database-Support (PostgreSQL, MySQL, SQL Server, Oracle) -- Connection Pooling -- ORM und Repository-Pattern -- Transaktionsmanagement -- Datenbank-Migrationen +- Multi-database support (PostgreSQL, MySQL, SQL Server, Oracle) +- Connection pooling +- ORM and repository pattern +- Transaction management +- Database migrations - Performance optimization -- Backup-Strategien +- Backup strategies ### 📨 Runtime Messaging -**Datei:** `messaging.md` +**File:** `messaging.md` - Message Broker Integration (Kafka, RabbitMQ, ActiveMQ, AWS SQS/SNS) -- Event-Driven Architecture +- Event-driven architecture - Message Patterns (Request-Reply, Publish-Subscribe, Dead Letter Queue) - Message Reliability (At-Least-Once, Exactly-Once) -- Message-Monitoring und Tracing +- Message monitoring and tracing ### 🔌 Runtime API Management -**Datei:** `api-management.md` +**File:** `api-management.md` -- RESTful API-Design -- API-Versionierung +- RESTful API design +- API versioning - Authentication (OAuth2, API-Keys, JWT) - Rate Limiting -- OpenAPI-Documentation -- API-Monitoring und Metriken +- OpenAPI documentation +- API monitoring and metrics ### 💾 Runtime Backup & Recovery -**Datei:** `backup-recovery.md` +**File:** `backup-recovery.md` - Backup strategies (full, incremental, differential) - Disaster Recovery (RTO/RPO) - Business Continuity -- DR-Sites (Hot, Warm, Cold) +- DR sites (Hot, Warm, Cold) - Backup monitoring and validation ## Runtime Features in Detail @@ -99,21 +99,21 @@ This overview provides a complete overview of HypnoScript's runtime documentatio #### Authentication -- **LDAP-Integration:** Enterprise-wide user management -- **OAuth2-Support:** Sichere API-Authentication -- **Multi-Faktor-Authentication:** Increased security -- **Session-Management:** Secure session management +- **LDAP integration:** Enterprise-wide user management +- **OAuth2 support:** Secure API authentication +- **Multi-factor authentication:** Increased security +- **Session management:** Secure session management #### Authorization - **Role-Based Access Control (RBAC):** Role-based permissions - **Attribute-Based Access Control (ABAC):** Context-based access control -- **Granulare Berechtigungen:** Fine-grained access control +- **Granular permissions:** Fine-grained access control #### Encryption -- **Data encryption:** AES-256-GCM für ruhende Daten -- **Transport-Encryption:** TLS 1.3 für übertragene Daten +- **Data encryption:** AES-256-GCM for data at rest +- **Transport encryption:** TLS 1.3 for data in transit - **Key management:** AWS KMS Integration #### Compliance @@ -129,50 +129,50 @@ This overview provides a complete overview of HypnoScript's runtime documentatio - **Load Balancing:** Automatic load distribution - **Auto-Scaling:** Dynamic resource adjustment -- **Microservices-Architektur:** Modular scaling +- **Microservices architecture:** Modular scaling #### Performance optimization -- **Caching strategies:** Redis-Integration -- **Database-Optimierung:** Query optimization and indexing +- **Caching strategies:** Redis integration +- **Database optimization:** Query optimization and indexing - **Connection Pooling:** Efficient database connections #### Monitoring & Observability -- **Metrics collection:** Prometheus-Integration -- **Log aggregation:** ELK-Stack-Support -- **Distributed Tracing:** Jaeger-Integration -- **Performance-Monitoring:** APM-Tools +- **Metrics collection:** Prometheus integration +- **Log aggregation:** ELK stack support +- **Distributed tracing:** Jaeger integration +- **Performance monitoring:** APM tools ### 🔄 High availability #### Disaster Recovery -- **RTO/RPO-Ziele:** Defined recovery times -- **DR-Sites:** Hot, Warm und Cold Sites -- **Automatische Failover:** Minimal downtime +- **RTO/RPO objectives:** Defined recovery times +- **DR sites:** Hot, Warm, and Cold sites +- **Automatic failover:** Minimal downtime #### Business Continuity -- **Kritische Funktionen:** Prioritized recovery -- **Alternative Prozesse:** Redundant processes -- **Kommunikationsplan:** Eskalationsmatrix +- **Critical functions:** Prioritized recovery +- **Alternative processes:** Redundant processes +- **Communication plan:** Escalation matrix ### 🗄️ Data management -#### Multi-Database-Support +#### Multi-database support - **PostgreSQL:** Full support - **MySQL:** Runtime features - **SQL Server:** Windows integration - **Oracle:** Runtime databases -#### Backup-Strategien +#### Backup strategies -- **3-2-1-Regel:** Robust backup strategy -- **Automatische Backups:** Time-based backup -- **Cloud-Backups:** AWS S3, Azure Blob, GCP Storage -- **Backup-Validierung:** Regular tests +- **3-2-1 rule:** Robust backup strategy +- **Automatic backups:** Time-based backup +- **Cloud backups:** AWS S3, Azure Blob, GCP Storage +- **Backup validation:** Regular tests ### 📨 Event-Driven Architecture @@ -261,7 +261,7 @@ This overview provides a complete overview of HypnoScript's runtime documentatio ### 📈 Performance Best Practices 1. **Caching strategies:** Intelligent caching -2. **Database-Optimization:** Query-Optimierung +2. **Database optimization:** Query optimization 3. **Load Balancing:** Efficient load distribution 4. **Monitoring:** Proactive monitoring 5. **Capacity Planning:** Resource planning @@ -269,9 +269,9 @@ This overview provides a complete overview of HypnoScript's runtime documentatio ### 🔄 Reliability Best Practices 1. **Redundancy:** System redundancy -2. **Backup-Strategien:** Regular backups +2. **Backup strategies:** Regular backups 3. **Testing:** Comprehensive testing -4. **Documentation:** Vollständige Documentation +4. **Documentation:** Complete documentation 5. **Training:** Team training ## Compliance & Governance @@ -287,7 +287,7 @@ This overview provides a complete overview of HypnoScript's runtime documentatio #### GDPR (General Data Protection Regulation) - **Data Protection:** Data protection -- **Privacy by Design:** Data protection durch Technik +- **Privacy by Design:** Data protection by design - **Right to be Forgotten:** Right to be forgotten #### PCI DSS (Payment Card Industry Data Security Standard) @@ -345,13 +345,13 @@ This overview provides a complete overview of HypnoScript's runtime documentatio ## Conclusion -Die Runtime-Documentation von HypnoScript bietet eine umfassende Anleitung für die Implementierung und den Betrieb von HypnoScript in Runtime-Umgebungen. Sie deckt alle wichtigen Aspekte ab: +HypnoScript runtime documentation provides comprehensive guidance for implementing and operating HypnoScript in runtime environments. It covers all critical aspects: - **Security & Compliance:** Comprehensive security features and compliance frameworks - **Scalability & Performance:** Optimized architecture for high loads - **High availability:** Robust disaster recovery and business continuity - **Monitoring & Observability:** Complete transparency and monitoring -- **API-Management:** Secure and scalable APIs +- **API Management:** Secure and scalable APIs - **Backup & Recovery:** Reliable data backup and recovery This documentation ensures that HypnoScript meets the highest standards for security, performance, reliability, and compliance in runtime environments. diff --git a/hypnoscript-docs/docs/examples/cli-workflows.md b/hypnoscript-docs/docs/examples/cli-workflows.md index 0137af0..0f1ee04 100644 --- a/hypnoscript-docs/docs/examples/cli-workflows.md +++ b/hypnoscript-docs/docs/examples/cli-workflows.md @@ -170,7 +170,7 @@ dotnet run --project HypnoScript.CLI -- lint *.hyp --severity error echo "4. Running tests..." dotnet run --project HypnoScript.CLI -- test *.hyp -# 5. Build erstellen +# 5. Build echo "5. Building..." dotnet run --project HypnoScript.CLI -- build main.hyp --optimize @@ -219,7 +219,7 @@ jobs: run: dotnet run --project HypnoScript.CLI -- package main.hyp --runtime linux-x64 ``` -### Deployment-Skript +### Deployment Script ```bash #!/bin/bash @@ -227,13 +227,13 @@ jobs: echo "=== HypnoScript Deployment ===" -# Umgebungsvariablen prüfen +# Check environment variables if [ -z "$DEPLOY_PATH" ]; then echo "Error: DEPLOY_PATH not set" exit 1 fi -# Build erstellen +# Build echo "Building application..." dotnet run --project HypnoScript.CLI -- build main.hyp --optimize @@ -241,7 +241,7 @@ dotnet run --project HypnoScript.CLI -- build main.hyp --optimize echo "Running tests..." dotnet run --project HypnoScript.CLI -- test *.hyp -# Paket erstellen +# Create package echo "Creating deployment package..." dotnet run --project HypnoScript.CLI -- package main.hyp --runtime linux-x64 --output app @@ -253,9 +253,9 @@ chmod +x $DEPLOY_PATH/app echo "Deployment completed!" ``` -## Konfiguration und Umgebung +## Configuration and Environment -### Konfigurationsdatei (hypnoscript.config.json) +### Configuration File (hypnoscript.config.json) ```json { @@ -292,41 +292,41 @@ export HYPNOSCRIPT_LOG_LEVEL="debug" export HYPNOSCRIPT_CONFIG="./config.json" export HYPNOSCRIPT_TIMEOUT="60000" -# Skript mit Umgebungsvariablen ausführen +# Run script with environment variables dotnet run --project HypnoScript.CLI -- run script.hyp ``` -## Monitoring und Logging +## Monitoring and Logging -### Logging-Konfiguration +### Logging Configuration ```bash -# Detailliertes Logging +# Detailed logging dotnet run --project HypnoScript.CLI -- run script.hyp --log-level debug -# Nur Fehler loggen +# Log errors only dotnet run --project HypnoScript.CLI -- run script.hyp --log-level error -# Logs in Datei umleiten +# Redirect logs to file dotnet run --project HypnoScript.CLI -- run script.hyp --verbose > script.log 2>&1 ``` -### Performance-Monitoring +### Performance Monitoring ```bash -# Mit Performance-Metriken +# With performance metrics dotnet run --project HypnoScript.CLI -- run script.hyp --verbose --metrics -# Memory-Usage überwachen +# Monitor memory usage dotnet run --project HypnoScript.CLI -- run script.hyp --max-memory 1024 ``` ## Best Practices -### Skript-Organisation +### Script Organization ```bash -# Projektstruktur +# Project structure my-project/ ├── src/ │ ├── main.hyp @@ -344,7 +344,7 @@ my-project/ └── dist/ ``` -### Automatisierte Workflows +### Automated Workflows ```bash # Pre-commit Hook (.git/hooks/pre-commit) @@ -375,24 +375,24 @@ echo "Pre-commit checks passed!" ### Error Handling ```bash -# Robuster Workflow mit Fehlerbehandlung +# Robust workflow with error handling #!/bin/bash set -e # Exit on error echo "Starting robust workflow..." -# Funktion für Fehlerbehandlung +# Error handling function handle_error() { echo "Error occurred in line $1" echo "Cleaning up..." - # Cleanup-Code hier + # Cleanup code here exit 1 } trap 'handle_error $LINENO' ERR -# Workflow-Schritte +# Workflow steps dotnet run --project HypnoScript.CLI -- validate *.hyp dotnet run --project HypnoScript.CLI -- test *.hyp dotnet run --project HypnoScript.CLI -- build main.hyp --optimize @@ -409,4 +409,3 @@ echo "Workflow completed successfully!" --- **Mastered CLI workflows? Then check out [advanced configuration](../cli/configuration)!** ⚙️ - diff --git a/hypnoscript-docs/docs/examples/record-examples.md b/hypnoscript-docs/docs/examples/record-examples.md index bf8f949..48ba53e 100644 --- a/hypnoscript-docs/docs/examples/record-examples.md +++ b/hypnoscript-docs/docs/examples/record-examples.md @@ -395,7 +395,7 @@ Focus { // Create configuration induce config = AppConfig { appName: "HypnoScript Runtime", - version: "1.0.0", + version: "1.2.0", environment: "production", database: DatabaseConfig { host: "localhost", diff --git a/hypnoscript-docs/docs/examples/system-examples.md b/hypnoscript-docs/docs/examples/system-examples.md index 71f6c9d..ee3a814 100644 --- a/hypnoscript-docs/docs/examples/system-examples.md +++ b/hypnoscript-docs/docs/examples/system-examples.md @@ -12,13 +12,13 @@ This page shows practical examples for system functions in HypnoScript. The exam Focus { entrance { // Write file - WriteFile("beispiel.txt", "Hallo HypnoScript!"); + WriteFile("example.txt", "Hello HypnoScript!"); // Read file - induce content = ReadFile("beispiel.txt"); + induce content = ReadFile("example.txt"); observe "File content: " + content; // Create backup - induce backupName = "beispiel_backup_" + Timestamp() + ".txt"; - CopyFile("beispiel.txt", backupName); + induce backupName = "example_backup_" + Timestamp() + ".txt"; + CopyFile("example.txt", backupName); observe "Backup created: " + backupName; } } Relax; @@ -30,7 +30,7 @@ Focus { Focus { entrance { // Create directory - if (!DirectoryExists("daten")) CreateDirectory("daten"); + if (!DirectoryExists("data")) CreateDirectory("data"); // List files induce files = ListFiles("."); observe "Files in current directory: " + files; @@ -63,7 +63,7 @@ Focus { ```hyp Focus { entrance { - induce result = ExecuteCommand("echo Hallo von der Shell!"); + induce result = ExecuteCommand("echo Hello from the shell!"); observe "Shell output: " + result; } } Relax; @@ -74,9 +74,9 @@ Focus { ```hyp Focus { entrance { - SetEnvironmentVariable("MEIN_VAR", "Testwert"); - induce value = GetEnvironmentVariable("MEIN_VAR"); - observe "MEIN_VAR: " + value; + SetEnvironmentVariable("MY_VAR", "TestValue"); + induce value = GetEnvironmentVariable("MY_VAR"); + observe "MY_VAR: " + value; } } Relax; ``` @@ -120,7 +120,7 @@ Focus { } } entrance { - observe safeRead("nicht_existierend.txt"); + observe safeRead("does_not_exist.txt"); } } Relax; ``` @@ -131,7 +131,7 @@ Focus { Focus { entrance { // Combined backup and monitoring - induce file = "daten.txt"; + induce file = "data.txt"; if (FileExists(file)) { induce backup = file + ".bak"; CopyFile(file, backup); @@ -149,4 +149,3 @@ Focus { - [System Functions Reference](../builtins/system-functions) - [Utility Functions Examples](./utility-examples) - diff --git a/hypnoscript-docs/docs/examples/utility-examples.md b/hypnoscript-docs/docs/examples/utility-examples.md index 506c649..80273a5 100644 --- a/hypnoscript-docs/docs/examples/utility-examples.md +++ b/hypnoscript-docs/docs/examples/utility-examples.md @@ -27,11 +27,11 @@ Focus { ```hyp Focus { entrance { - induce namen = ["Anna", "Ben", "Carla", "Dieter"]; - induce gewinner = Sample(namen, 1); - observe "Winner: " + gewinner; - induce gemischt = Shuffle(namen); - observe "Random order: " + gemischt; + induce names = ["Anna", "Ben", "Carla", "Dieter"]; + induce winner = Sample(names, 1); + observe "Winner: " + winner; + induce shuffled = Shuffle(names); + observe "Random order: " + shuffled; } } Relax; ``` @@ -42,9 +42,9 @@ Focus { Focus { entrance { induce start = Timestamp(); - Sleep(500); // 0,5 seconds wait - induce ende = Timestamp(); - observe "Duration: " + (ende - start) + " seconds"; + Sleep(500); // 0.5 seconds wait + induce end = Timestamp(); + observe "Duration: " + (end - start) + " seconds"; } } Relax; ``` @@ -54,13 +54,13 @@ Focus { ```hyp Focus { entrance { - induce zahlen = [1,2,3,4,5,2,3,4]; - induce unique = Unique(zahlen); + induce numbers = [1,2,3,4,5,2,3,4]; + induce unique = Unique(numbers); observe "Without duplicates: " + unique; - induce sortiert = Sort(unique); - observe "Sorted: " + sortiert; - induce gepaart = Zip(unique, ["a","b","c","d","e"]); - observe "Paired: " + gepaart; + induce sorted = Sort(unique); + observe "Sorted: " + sorted; + induce paired = Zip(unique, ["a","b","c","d","e"]); + observe "Paired: " + paired; } } Relax; ``` @@ -96,7 +96,7 @@ Focus { } Relax; ``` -## Range und Repeat +## Range and Repeat ```hyp Focus { @@ -124,11 +124,11 @@ Focus { } // Random selection from range - induce zahlen = Range(1, 100); - induce zufall = Sample(zahlen, 5); - observe "5 random numbers: " + zufall; + induce numbers = Range(1, 100); + induce randomSample = Sample(numbers, 5); + observe "5 random numbers: " + randomSample; - // Array Transformations kombinieren + // Combine array transformations induce arr = [1,2,2,3,4,4,5]; induce clean = Sort(Unique(arr)); observe "Sorted & unique: " + clean; @@ -142,4 +142,3 @@ Focus { - [Utility Functions Reference](../builtins/utility-functions) - [System Functions Examples](./system-examples) - diff --git a/hypnoscript-docs/docs/getting-started/cli-basics.md b/hypnoscript-docs/docs/getting-started/cli-basics.md index 1868327..0c2db4b 100644 --- a/hypnoscript-docs/docs/getting-started/cli-basics.md +++ b/hypnoscript-docs/docs/getting-started/cli-basics.md @@ -14,7 +14,7 @@ hypnoscript --help hypnoscript version # Help for a subcommand -hypnoscript run --help +hypnoscript exec --help ``` The output always lists all available subcommands and their options. If a command seems unfamiliar, it's worth looking at `--help` – the text is generated directly from the actual CLI. @@ -23,17 +23,26 @@ The output always lists all available subcommands and their options. If a comman ```bash # Standard execution -hypnoscript run demo.hyp +hypnoscript exec demo.hyp # With additional output -hypnoscript run demo.hyp --verbose +hypnoscript exec demo.hyp --verbose -# With debug information -hypnoscript run demo.hyp --debug +# With interactive debug mode +hypnoscript exec demo.hyp --debug + +# Debug with breakpoints +hypnoscript exec demo.hyp --debug --breakpoints 10,25 + +# Debug with watch expressions +hypnoscript exec demo.hyp --debug --watch counter,result ``` - `--verbose` outputs status messages like "Running file" or success messages. -- `--debug` additionally shows source code, token list, type checking results and the interpretation flow. +- `--debug` starts an interactive debugger with breakpoints, stepping and variable inspection. +- `--breakpoints` sets initial breakpoints at specific lines (comma-separated). +- `--watch` monitors variables during execution. +- `--trace-file` saves debug trace to a file for later analysis. - Errors in the type checker don't stop execution – they are reported, then the interpreter continues. ## Analysis Tools @@ -65,22 +74,22 @@ The command groups all built-in functions by category (Math, String, Array, Syst 1. **Preparation** – Run `hypnoscript check` on all scripts. 2. **Error Analysis** – Use `lex` or `parse` for problems to inspect the specific section. -3. **Execution** – Test with `run`, activate `--debug` if needed. +3. **Execution** – Test with `exec`, activate `--debug` if needed. 4. **Deployment** – Optionally use `compile-wasm` if the script should run in the browser or a WASM environment. ```bash # Example: complete round hypnoscript check examples/inventory.hyp -hypnoscript run examples/inventory.hyp --debug +hypnoscript exec examples/inventory.hyp --debug hypnoscript compile-wasm examples/inventory.hyp -o inventory.wat ``` ## Tips & Tricks -- **Quick Iteration:** Use `--debug` as soon as something seems odd – tokens and AST immediately reveal whether the parser understood your intention. -- **Bundle Outputs:** Pipe the output to a file (`hypnoscript run script.hyp > output.txt`) to document longer runs. +- **Quick Iteration:** Use `--debug` as soon as something seems odd – set breakpoints and step through the code to understand the flow. +- **Bundle Outputs:** Pipe the output to a file (`hypnoscript exec script.hyp > output.txt`) to document longer runs. - **Platform-agnostic:** On Windows, macOS and Linux, the commands are identical. The only requirement is that the `hypnoscript` binary is in the `PATH`. -- **Tests as Scripts:** The files in the `hypnoscript-tests/` folder can be started directly with `hypnoscript run`. This shows you real examples of control flow and sessions. +- **Tests as Scripts:** The files in the `hypnoscript-tests/` folder can be started directly with `hypnoscript exec`. This shows you real examples of control flow and sessions. ## Further Links diff --git a/hypnoscript-docs/docs/getting-started/core-concepts.md b/hypnoscript-docs/docs/getting-started/core-concepts.md index a1d1632..48c9749 100644 --- a/hypnoscript-docs/docs/getting-started/core-concepts.md +++ b/hypnoscript-docs/docs/getting-started/core-concepts.md @@ -95,12 +95,14 @@ All builtins are compactly available via `hypnoscript builtins`. hypnoscript lex file.hyp # Show tokens hypnoscript parse file.hyp # Inspect AST hypnoscript check file.hyp # Type checking -hypnoscript run file.hyp # Execute +hypnoscript exec file.hyp # Execute hypnoscript compile-wasm file.hyp -o file.wat hypnoscript version # Toolchain info ``` -- `--debug` with the `run` command shows intermediate steps (source, tokens, type check). +- `--debug` with the `exec` command starts an interactive debugger with breakpoints and stepping. +- `--breakpoints` sets initial breakpoints (e.g., `--breakpoints 10,25`). +- `--watch` monitors variables during debugging. - `--verbose` adds additional status messages. ## Where to Continue Reading diff --git a/hypnoscript-docs/docs/getting-started/installation.md b/hypnoscript-docs/docs/getting-started/installation.md index 4e2c3ed..ec0f186 100644 --- a/hypnoscript-docs/docs/getting-started/installation.md +++ b/hypnoscript-docs/docs/getting-started/installation.md @@ -8,11 +8,11 @@ This guide will walk you through installing the Rust-based HypnoScript toolchain ## Prerequisites -| Component | Recommendation | -| ------------- | -------------------------------------------------------------------------------- | -| Operating System | Windows 10+, macOS 12+, Linux (Ubuntu 20.04+, Fedora 38+, Arch) | -| Rust Toolchain | `rustup` with Rust 1.76 or newer (check with `rustup --version`) | -| Build Tools | Git, C/C++ Build Tools (provided by `rustup` / package manager) | +| Component | Recommendation | +| ---------------- | ---------------------------------------------------------------- | +| Operating System | Windows 10+, macOS 12+, Linux (Ubuntu 20.04+, Fedora 38+, Arch) | +| Rust Toolchain | `rustup` with Rust 1.76 or newer (check with `rustup --version`) | +| Build Tools | Git, C/C++ Build Tools (provided by `rustup` / package manager) | Optional for documentation: Node.js 18+. @@ -104,23 +104,23 @@ hypnoscript builtins # Minimal test program echo 'Focus { entrance { observe "Installation successful!"; } } Relax' > test.hyp -hypnoscript run test.hyp +hypnoscript exec test.hyp ``` Expected output (abbreviated): ```text -HypnoScript v1.0.0 +HypnoScript v1.2.0 Installation successful! ``` ## Common Issues -| Problem | Solution | -| ------------------------ | --------------------------------------------------------------------------------------------------- | -| `cargo` not found | Check if `~/.cargo/bin` (Linux/macOS) or `%USERPROFILE%\.cargo\bin` (Windows) is in your `PATH`. | -| Linker errors on Linux | Install build dependencies (`sudo apt install build-essential` or distribution equivalent). | -| No execution permissions | Set `chmod +x hypnoscript` after extracting a release artifact. | +| Problem | Solution | +| ------------------------ | ------------------------------------------------------------------------------------------------ | +| `cargo` not found | Check if `~/.cargo/bin` (Linux/macOS) or `%USERPROFILE%\.cargo\bin` (Windows) is in your `PATH`. | +| Linker errors on Linux | Install build dependencies (`sudo apt install build-essential` or distribution equivalent). | +| No execution permissions | Set `chmod +x hypnoscript` after extracting a release artifact. | ## Optional: Development Comfort diff --git a/hypnoscript-docs/docs/getting-started/quick-start.md b/hypnoscript-docs/docs/getting-started/quick-start.md index 864d893..45b52a3 100644 --- a/hypnoscript-docs/docs/getting-started/quick-start.md +++ b/hypnoscript-docs/docs/getting-started/quick-start.md @@ -55,7 +55,7 @@ Highlights: ## 3. Run Script ```bash -hypnoscript run hello_trance.hyp +hypnoscript exec hello_trance.hyp ``` The output should show the greeting, the sum, and the small while loop. @@ -97,7 +97,6 @@ Focus { ## 5. Control Structures - ```hyp if (total lookAtTheWatch 10) { observe "greater than 10"; diff --git a/hypnoscript-docs/docs/index.md b/hypnoscript-docs/docs/index.md index 1f5a0b0..bc3ae29 100644 --- a/hypnoscript-docs/docs/index.md +++ b/hypnoscript-docs/docs/index.md @@ -91,7 +91,14 @@ Focus { ### Running ```bash -hypnoscript run my_script.hyp +hypnoscript exec my_script.hyp +``` + +### Debugging + +```bash +# Interactive debug mode with breakpoints +hypnoscript exec my_script.hyp --debug --breakpoints 10,25 ``` ## Why HypnoScript? diff --git a/hypnoscript-docs/docs/intro.md b/hypnoscript-docs/docs/intro.md index a6bc78f..000ffe0 100644 --- a/hypnoscript-docs/docs/intro.md +++ b/hypnoscript-docs/docs/intro.md @@ -69,11 +69,11 @@ The builtins are organized into categories. A detailed reference can be found un ## Development Workflow ```bash -# Read source, lex, parse, check and run +# Read source, lex, parse, check and exec hypnoscript lex examples/test.hyp hypnoscript parse examples/test.hyp hypnoscript check examples/test.hyp -hypnoscript run examples/test.hyp +hypnoscript exec examples/test.hyp # Generate to WebAssembly (wat) hypnoscript compile-wasm examples/test.hyp --output output.wat diff --git a/hypnoscript-docs/docs/language-reference/operators.md b/hypnoscript-docs/docs/language-reference/operators.md index 834305c..d8eda71 100644 --- a/hypnoscript-docs/docs/language-reference/operators.md +++ b/hypnoscript-docs/docs/language-reference/operators.md @@ -1,42 +1,42 @@ -# Operatoren +# Operators -HypnoScript unterstützt Standard-Operatoren sowie hypnotische Synonyme für vergleichende und logische Operatoren. Alle Operatoren sind in der Rust-Implementierung vollständig typsicher. +HypnoScript supports standard operators as well as hypnotic synonyms for comparison and logical operators. All operators are fully type-safe in the Rust implementation. -## Arithmetische Operatoren +## Arithmetic Operators -| Operator | Bedeutung | Typ-Anforderung | Beispiel | Ergebnis | -| -------- | -------------- | --------------- | -------- | -------- | -| + | Addition | number | 2 + 3 | 5 | -| - | Subtraktion | number | 5 - 2 | 3 | -| \* | Multiplikation | number | 4 \* 2 | 8 | -| / | Division | number | 8 / 2 | 4 | -| % | Modulo (Rest) | number | 7 % 3 | 1 | +| Operator | Meaning | Type Requirement | Example | Result | +| -------- | -------------- | ---------------- | ------- | ------ | +| + | Addition | number | 2 + 3 | 5 | +| - | Subtraction | number | 5 - 2 | 3 | +| \* | Multiplication | number | 4 \* 2 | 8 | +| / | Division | number | 8 / 2 | 4 | +| % | Modulo (rest) | number | 7 % 3 | 1 | -**String-Konkatenation:** Der `+` Operator funktioniert auch für Strings: +**String concatenation:** The `+` operator also works for strings: ```hyp -induce text: string = "Hallo " + "Welt"; // "Hallo Welt" -induce mixed: string = "Zahl: " + 42; // "Zahl: 42" +induce text: string = "Hello " + "World"; // "Hello World" +induce mixed: string = "Number: " + 42; // "Number: 42" ``` -> ⚠️ **Achtung:** Sobald einer der Operanden ein String ist, werden alle anderen Werte implizit in Strings umgewandelt (intern via `to_string()`). Dadurch entstehen z. B. Ergebnisse wie `null + "text" -> "nulltext"` oder `42 + "px" -> "42px"`. Wenn du striktere Typkontrollen erwartest, konvertiere Werte explizit oder prüfe den Typ vor der Verwendung von `+`. +> ⚠️ **Warning:** Once one operand is a string, all other values are implicitly converted to strings (internally via `to_string()`). This can produce results like `null + "text" -> "nulltext"` or `42 + "px" -> "42px"`. If you expect stricter type checks, convert values explicitly or validate the type before using `+`. -## Vergleichsoperatoren +## Comparison Operators -### Standard-Operatoren (Vergleich) +### Standard Operators (Comparison) -| Operator | Bedeutung | Beispiel | Ergebnis | -| -------- | -------------- | -------- | -------- | -| == | Gleich | 3 == 3 | true | -| != | Ungleich | 3 != 4 | true | -| > | Größer | 5 > 2 | true | -| < | Kleiner | 2 < 5 | true | -| >= | Größer gleich | 3 >= 2 | true | -| <= | Kleiner gleich | 2 <= 2 | true | +| Operator | Meaning | Example | Result | +| -------- | --------------------- | ------- | ------ | +| == | Equal | 3 == 3 | true | +| != | Not equal | 3 != 4 | true | +| > | Greater than | 5 > 2 | true | +| < | Less than | 2 < 5 | true | +| >= | Greater than or equal | 3 >= 2 | true | +| <= | Less than or equal | 2 <= 2 | true | -### Hypnotische Synonyme (Vergleich) +### Hypnotic Synonyms (Comparison) -HypnoScript bietet hypnotische Synonyme für alle Vergleichsoperatoren: +HypnoScript provides hypnotic synonyms for all comparison operators: | Hypnotic Synonym | Standard | Meaning | Status | | ----------------------- | -------- | --------------------- | -------------- | diff --git a/hypnoscript-docs/docs/language-reference/records.md b/hypnoscript-docs/docs/language-reference/records.md index ca95918..9773af0 100644 --- a/hypnoscript-docs/docs/language-reference/records.md +++ b/hypnoscript-docs/docs/language-reference/records.md @@ -92,7 +92,7 @@ Focus { categories: ["Software", "Programming", "Hypnosis"], inStock: true, metadata: { - version: "1.0.0", + version: "1.2.0", releaseDate: "2025-01-15" } }; @@ -119,10 +119,10 @@ Focus { } induce address = Address { - street: "Musterstraße 123", + street: "Example Street 123", city: "Berlin", zipCode: "10115", - country: "Deutschland" + country: "Germany" }; // Direct field access @@ -157,7 +157,7 @@ Focus { // Create copy with changes induce userConfig = defaultConfig with { theme: "light", - language: "de" + language: "en" }; observe "Default theme: " + defaultConfig.theme; diff --git a/hypnoscript-docs/docs/language-reference/syntax.md b/hypnoscript-docs/docs/language-reference/syntax.md index 585caba..da5adc1 100644 --- a/hypnoscript-docs/docs/language-reference/syntax.md +++ b/hypnoscript-docs/docs/language-reference/syntax.md @@ -318,7 +318,7 @@ Focus { entrance { // Create record induce person = { - name: "Max Mustermann", + name: "John Doe", age: 30, city: "Berlin", hobbies: ["Programming", "Reading", "Sports"] @@ -335,9 +335,9 @@ Focus { // Nested records induce company = { - name: "HypnoScript GmbH", + name: "HypnoScript LLC", address: { - street: "Musterstraße 123", + street: "Example Street 123", city: "Berlin", zip: "10115" }, diff --git a/hypnoscript-docs/package-lock.json b/hypnoscript-docs/package-lock.json index cf56155..5aad940 100644 --- a/hypnoscript-docs/package-lock.json +++ b/hypnoscript-docs/package-lock.json @@ -1,12 +1,12 @@ { "name": "hypnoscript-documentation", - "version": "1.0.0", + "version": "1.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "hypnoscript-documentation", - "version": "1.0.0", + "version": "1.2.0", "license": "MIT", "dependencies": { "vue": "^3.4.21" diff --git a/hypnoscript-docs/package.json b/hypnoscript-docs/package.json index eee18c8..882a274 100644 --- a/hypnoscript-docs/package.json +++ b/hypnoscript-docs/package.json @@ -1,6 +1,6 @@ { "name": "hypnoscript-documentation", - "version": "1.0.0", + "version": "1.2.0", "private": true, "type": "module", "scripts": { @@ -23,14 +23,14 @@ "engines": { "node": ">=18.0" }, - "description": "Vollständige Dokumentation für HypnoScript - Die hypnotische Programmiersprache", + "description": "Complete documentation for HypnoScript - the hypnotic programming language", "keywords": [ "hypnoscript", "programming-language", "documentation", "docusaurus", "hypnotic", - "german" + "english" ], "author": "HypnoScript Team", "license": "MIT", diff --git a/hypnoscript-docs/static/downloads/HypnoScript.Runtime.deps.json b/hypnoscript-docs/static/downloads/HypnoScript.Runtime.deps.json index f863571..63a4196 100644 --- a/hypnoscript-docs/static/downloads/HypnoScript.Runtime.deps.json +++ b/hypnoscript-docs/static/downloads/HypnoScript.Runtime.deps.json @@ -7,15 +7,15 @@ "targets": { ".NETCoreApp,Version=v8.0": {}, ".NETCoreApp,Version=v8.0/win-x64": { - "HypnoScript.Runtime/1.0.0": { + "HypnoScript.Runtime/1.2.0": { "dependencies": { - "HypnoScript.Core": "1.0.0" + "HypnoScript.Core": "1.2.0" }, "runtime": { "HypnoScript.Runtime.dll": {} } }, - "HypnoScript.Core/1.0.0": { + "HypnoScript.Core/1.2.0": { "runtime": { "HypnoScript.Core.dll": { "assemblyVersion": "1.0.0.0", @@ -26,15 +26,15 @@ } }, "libraries": { - "HypnoScript.Runtime/1.0.0": { + "HypnoScript.Runtime/1.2.0": { "type": "project", "serviceable": false, "sha512": "" }, - "HypnoScript.Core/1.0.0": { + "HypnoScript.Core/1.2.0": { "type": "project", "serviceable": false, "sha512": "" } } -} \ No newline at end of file +} diff --git a/hypnoscript-runtime/Cargo.toml b/hypnoscript-runtime/Cargo.toml index 4f6b100..19ce03d 100644 --- a/hypnoscript-runtime/Cargo.toml +++ b/hypnoscript-runtime/Cargo.toml @@ -14,11 +14,11 @@ anyhow = { workspace = true } thiserror = { workspace = true } reqwest = { workspace = true } csv = { workspace = true } -chrono = "0.4" -regex = "1.10" -num_cpus = "1.16" -hostname = "0.4" -sha2 = "0.10" -md5 = "0.7" -base64 = "0.22" -uuid = { version = "1.11", features = ["v4"] } +chrono = "0.4.43" +regex = "1.12.2" +num_cpus = "1.17.0" +hostname = "0.4.2" +sha2 = "0.10.9" +md5 = "0.8.0" +base64 = "0.22.1" +uuid = { version = "1.19.0", features = ["v4"] } diff --git a/hypnoscript-runtime/src/advanced_string_builtins.rs b/hypnoscript-runtime/src/advanced_string_builtins.rs index 64f3473..d02a45f 100644 --- a/hypnoscript-runtime/src/advanced_string_builtins.rs +++ b/hypnoscript-runtime/src/advanced_string_builtins.rs @@ -33,7 +33,7 @@ impl BuiltinModule for AdvancedStringBuiltins { LocalizedMessage::new("Advanced string similarity and phonetic analysis functions") .with_translation( "de", - "Erweiterte String-Ähnlichkeits- und phonetische Analysefunktionen", + "Advanced string similarity and phonetic analysis functions", ) .with_translation( "fr", diff --git a/hypnoscript-runtime/src/api_builtins.rs b/hypnoscript-runtime/src/api_builtins.rs index 328a449..aff95e1 100644 --- a/hypnoscript-runtime/src/api_builtins.rs +++ b/hypnoscript-runtime/src/api_builtins.rs @@ -80,11 +80,11 @@ pub struct ApiResponse { #[derive(Debug, Error)] pub enum ApiError { - #[error("Ungültige URL: {0}")] + #[error("Invalid URL: {0}")] InvalidUrl(String), - #[error("Netzwerkfehler: {0}")] + #[error("Network error: {0}")] Network(String), - #[error("Serialisierungsfehler: {0}")] + #[error("Serialization error: {0}")] Serialization(String), } @@ -93,9 +93,9 @@ impl ApiError { pub fn to_localized_string(&self, locale: Option<&str>) -> String { let locale = detect_locale(locale); match (locale.language(), self) { - ("de", ApiError::InvalidUrl(url)) => format!("Ungültige URL: {url}"), - ("de", ApiError::Network(msg)) => format!("Netzwerkfehler: {msg}"), - ("de", ApiError::Serialization(msg)) => format!("Serialisierungsfehler: {msg}"), + ("de", ApiError::InvalidUrl(url)) => format!("Invalid URL: {url}"), + ("de", ApiError::Network(msg)) => format!("Network error: {msg}"), + ("de", ApiError::Serialization(msg)) => format!("Serialization error: {msg}"), (_, ApiError::InvalidUrl(url)) => format!("Invalid URL: {url}"), (_, ApiError::Network(msg)) => format!("Network error: {msg}"), (_, ApiError::Serialization(msg)) => format!("Serialization error: {msg}"), diff --git a/hypnoscript-runtime/src/array_builtins.rs b/hypnoscript-runtime/src/array_builtins.rs index 5ea5bb4..34562f7 100644 --- a/hypnoscript-runtime/src/array_builtins.rs +++ b/hypnoscript-runtime/src/array_builtins.rs @@ -21,7 +21,7 @@ impl BuiltinModule for ArrayBuiltins { let msg = LocalizedMessage::new("Array manipulation and functional programming operations") .with_translation( "de", - "Array-Manipulation und funktionale Programmieroperationen", + "Array manipulation and functional programming operations", ) .with_translation( "fr", diff --git a/hypnoscript-runtime/src/builtin_trait.rs b/hypnoscript-runtime/src/builtin_trait.rs index 60b7c1b..a113671 100644 --- a/hypnoscript-runtime/src/builtin_trait.rs +++ b/hypnoscript-runtime/src/builtin_trait.rs @@ -87,23 +87,23 @@ impl BuiltinError { // Build localized message based on category and key let base_msg = match (self.category, self.message_key.as_str()) { ("validation", "invalid_email") => LocalizedMessage::new("Invalid email address") - .with_translation("de", "Ungültige E-Mail-Adresse") + .with_translation("de", "Invalid email address") .with_translation("fr", "Adresse e-mail invalide") .with_translation("es", "Dirección de correo electrónico no válida"), ("validation", "invalid_url") => LocalizedMessage::new("Invalid URL") - .with_translation("de", "Ungültige URL") + .with_translation("de", "Invalid URL") .with_translation("fr", "URL invalide") .with_translation("es", "URL no válida"), ("io", "file_not_found") => LocalizedMessage::new("File not found: {}") - .with_translation("de", "Datei nicht gefunden: {}") + .with_translation("de", "File not found: {}") .with_translation("fr", "Fichier introuvable : {}") .with_translation("es", "Archivo no encontrado: {}"), ("math", "division_by_zero") => LocalizedMessage::new("Division by zero") - .with_translation("de", "Division durch Null") + .with_translation("de", "Division by zero") .with_translation("fr", "Division par zéro") .with_translation("es", "División por cero"), ("array", "index_out_of_bounds") => LocalizedMessage::new("Index out of bounds: {}") - .with_translation("de", "Index außerhalb des gültigen Bereichs: {}") + .with_translation("de", "Index out of bounds: {}") .with_translation("fr", "Index hors limites : {}") .with_translation("es", "Índice fuera de límites: {}"), _ => LocalizedMessage::new(format!("Error in {}: {}", self.category, self.message_key)), @@ -146,7 +146,7 @@ mod tests { assert_eq!(en_msg, "Invalid email address"); let de_msg = err.to_localized_string(Some("de")); - assert_eq!(de_msg, "Ungültige E-Mail-Adresse"); + assert_eq!(de_msg, "Invalid email address"); } #[test] @@ -157,6 +157,6 @@ mod tests { assert_eq!(en_msg, "File not found: test.txt"); let de_msg = err.to_localized_string(Some("de")); - assert_eq!(de_msg, "Datei nicht gefunden: test.txt"); + assert_eq!(de_msg, "File not found: test.txt"); } } diff --git a/hypnoscript-runtime/src/cli_builtins.rs b/hypnoscript-runtime/src/cli_builtins.rs index 47e4d25..16e2518 100644 --- a/hypnoscript-runtime/src/cli_builtins.rs +++ b/hypnoscript-runtime/src/cli_builtins.rs @@ -153,51 +153,36 @@ impl CliBuiltins { } } -fn render_prompt_suffix(locale: &Locale, default: Option<&str>) -> String { - match (locale.language(), default) { - ("de", Some(value)) => format!(" (Standard: {value})"), - (_, Some(value)) => format!(" (default: {value})"), - _ => String::new(), +fn render_prompt_suffix(_locale: &Locale, default: Option<&str>) -> String { + match default { + Some(value) => format!(" (default: {value})"), + None => String::new(), } } -fn render_empty_input_error(locale: &Locale) -> &'static str { - match locale.language() { - "de" => "Eingabe darf nicht leer sein.", - _ => "Input cannot be empty.", - } +fn render_empty_input_error(_locale: &Locale) -> &'static str { + "Input cannot be empty." } -fn yes_no_hint(locale: &Locale, default: bool) -> &'static str { - match (locale.language(), default) { - ("de", true) => "[J/n]", - ("de", false) => "[j/N]", - (_, true) => "[Y/n]", - (_, false) => "[y/N]", +fn yes_no_hint(_locale: &Locale, default: bool) -> &'static str { + match default { + true => "[Y/n]", + false => "[y/N]", } } -fn invalid_confirmation_hint(locale: &Locale) -> &'static str { - match locale.language() { - "de" => "Bitte mit 'j' oder 'n' antworten.", - _ => "Please answer with 'y' or 'n'.", - } +fn invalid_confirmation_hint(_locale: &Locale) -> &'static str { + "Please answer with 'y' or 'n'." } -fn is_yes(answer: &str, locale: &Locale) -> bool { +fn is_yes(answer: &str, _locale: &Locale) -> bool { let normalized = answer.trim().to_lowercase(); - match locale.language() { - "de" => matches!(normalized.as_str(), "j" | "ja"), - _ => matches!(normalized.as_str(), "y" | "yes"), - } + matches!(normalized.as_str(), "y" | "yes") } -fn is_no(answer: &str, locale: &Locale) -> bool { +fn is_no(answer: &str, _locale: &Locale) -> bool { let normalized = answer.trim().to_lowercase(); - match locale.language() { - "de" => matches!(normalized.as_str(), "n" | "nein"), - _ => matches!(normalized.as_str(), "n" | "no"), - } + matches!(normalized.as_str(), "n" | "no") } #[cfg(test)] diff --git a/hypnoscript-runtime/src/collection_builtins.rs b/hypnoscript-runtime/src/collection_builtins.rs index a0a8ea2..24088d7 100644 --- a/hypnoscript-runtime/src/collection_builtins.rs +++ b/hypnoscript-runtime/src/collection_builtins.rs @@ -27,7 +27,7 @@ impl BuiltinModule for CollectionBuiltins { fn description_localized(locale: Option<&str>) -> String { let locale = crate::localization::detect_locale(locale); let msg = LocalizedMessage::new("Set operations and advanced collection utilities") - .with_translation("de", "Set-Operationen und erweiterte Collection-Utilities") + .with_translation("de", "Set operations and advanced collection utilities") .with_translation( "fr", "Opérations d'ensemble et utilitaires de collection avancés", diff --git a/hypnoscript-runtime/src/core_builtins.rs b/hypnoscript-runtime/src/core_builtins.rs index e881abf..9fd7527 100644 --- a/hypnoscript-runtime/src/core_builtins.rs +++ b/hypnoscript-runtime/src/core_builtins.rs @@ -23,7 +23,7 @@ impl BuiltinModule for CoreBuiltins { let msg = LocalizedMessage::new("Core I/O, conversion, and hypnotic induction functions") .with_translation( "de", - "Kern-I/O-, Konvertierungs- und hypnotische Induktionsfunktionen", + "Core I/O, conversion, and hypnotic induction functions", ) .with_translation( "fr", @@ -90,12 +90,12 @@ impl CoreBuiltins { let locale = crate::localization::detect_locale(locale); let entering_msg = LocalizedMessage::new("Entering deep trance...") - .with_translation("de", "Trete in tiefe Trance ein...") + .with_translation("de", "Entering deep trance...") .with_translation("fr", "Entrer en transe profonde...") .with_translation("es", "Entrando en trance profundo..."); let emerging_msg = LocalizedMessage::new("Emerging from trance...") - .with_translation("de", "Aus der Trance auftauchen...") + .with_translation("de", "Emerging from trance...") .with_translation("fr", "Émerger de la transe...") .with_translation("es", "Emergiendo del trance..."); @@ -114,15 +114,12 @@ impl CoreBuiltins { let locale = crate::localization::detect_locale(locale); let sleepy_msg = LocalizedMessage::new("You are feeling very sleepy... {}") - .with_translation("de", "Du fühlst dich sehr schläfrig... {}") + .with_translation("de", "You are feeling very sleepy... {}") .with_translation("fr", "Vous vous sentez très endormi... {}") .with_translation("es", "Te sientes muy somnoliento... {}"); let trance_msg = LocalizedMessage::new("You are now in a deep hypnotic state.") - .with_translation( - "de", - "Du befindest dich jetzt in einem tiefen hypnotischen Zustand.", - ) + .with_translation("de", "You are now in a deep hypnotic state.") .with_translation( "fr", "Vous êtes maintenant dans un état hypnotique profond.", @@ -148,10 +145,7 @@ impl CoreBuiltins { let welcome_msg = LocalizedMessage::new("Welcome {}, you are about to enter a deep trance...") - .with_translation( - "de", - "Willkommen {}, du wirst gleich in eine tiefe Trance eintreten...", - ) + .with_translation("de", "Welcome {}, you are about to enter a deep trance...") .with_translation( "fr", "Bienvenue {}, vous êtes sur le point d'entrer en transe profonde...", @@ -162,16 +156,13 @@ impl CoreBuiltins { ); let breath_msg = LocalizedMessage::new("Take a deep breath and relax...") - .with_translation("de", "Atme tief ein und entspanne dich...") + .with_translation("de", "Take a deep breath and relax...") .with_translation("fr", "Prenez une profonde inspiration et détendez-vous...") .with_translation("es", "Respira profundo y relájate..."); let relaxed_msg = LocalizedMessage::new("With each breath, you feel more and more relaxed...") - .with_translation( - "de", - "Mit jedem Atemzug fühlst du dich mehr und mehr entspannt...", - ) + .with_translation("de", "With each breath, you feel more and more relaxed...") .with_translation( "fr", "À chaque respiration, vous vous sentez de plus en plus détendu...", @@ -182,7 +173,7 @@ impl CoreBuiltins { ); let clear_msg = LocalizedMessage::new("Your mind is becoming clear and focused...") - .with_translation("de", "Dein Geist wird klar und fokussiert...") + .with_translation("de", "Your mind is becoming clear and focused...") .with_translation("fr", "Votre esprit devient clair et concentré...") .with_translation("es", "Tu mente se vuelve clara y enfocada..."); @@ -206,20 +197,17 @@ impl CoreBuiltins { let locale = crate::localization::detect_locale(locale); let imagine_msg = LocalizedMessage::new("Imagine yourself in {}...") - .with_translation("de", "Stell dir vor, du bist in {}...") + .with_translation("de", "Imagine yourself in {}...") .with_translation("fr", "Imaginez-vous dans {}...") .with_translation("es", "Imagínate en {}..."); let vivid_msg = LocalizedMessage::new("The colors are vivid, the sounds are clear...") - .with_translation("de", "Die Farben sind lebendig, die Geräusche sind klar...") + .with_translation("de", "The colors are vivid, the sounds are clear...") .with_translation("fr", "Les couleurs sont vives, les sons sont clairs...") .with_translation("es", "Los colores son vívidos, los sonidos son claros..."); let peace_msg = LocalizedMessage::new("You feel completely at peace in this place...") - .with_translation( - "de", - "Du fühlst dich an diesem Ort vollkommen im Frieden...", - ) + .with_translation("de", "You feel completely at peace in this place...") .with_translation( "fr", "Vous vous sentez complètement en paix dans cet endroit...", @@ -264,7 +252,7 @@ mod tests { #[test] fn test_to_double() { - // Test mit Werten, die nicht zu nahe an mathematischen Konstanten liegen + // Test values that are not too close to mathematical constants assert_eq!(CoreBuiltins::to_double("42.75").unwrap(), 42.75); assert_eq!(CoreBuiltins::to_double("0.5").unwrap(), 0.5); assert!(CoreBuiltins::to_double("invalid").is_err()); diff --git a/hypnoscript-runtime/src/debug_builtins.rs b/hypnoscript-runtime/src/debug_builtins.rs new file mode 100644 index 0000000..5a8b399 --- /dev/null +++ b/hypnoscript-runtime/src/debug_builtins.rs @@ -0,0 +1,638 @@ +//! Debug builtin functions for HypnoScript. +//! +//! This module provides debugging utilities that can be called from HypnoScript code, +//! including value inspection, programmatic breakpoints, timing, and assertions. +//! +//! # Available Functions +//! +//! - `inspect(value)` - Returns value with type information +//! - `breakpoint()` - Triggers a programmatic breakpoint +//! - `stackTrace()` - Returns the current call stack as a string +//! - `measureTime(fn)` - Measures execution time of a function +//! - `assertEqual(left, right, message)` - Assertion with message +//! - `assertTruthy(value, message)` - Assert value is truthy +//! - `typeOf(value)` - Returns the type name of a value +//! - `dump(value)` - Prints detailed value representation +//! +//! # Examples +//! +//! ```hyp +//! Focus { +//! induce x: number = 42; +//! induce info = Debug.inspect(x); // "42 (number)" +//! +//! Debug.assertEqual(x, 42, "x should be 42"); +//! Debug.breakpoint(); // Pauses if debugger attached +//! } Relax +//! ``` + +use crate::builtin_trait::BuiltinModule; +use crate::localization::LocalizedMessage; +use std::time::{Duration, Instant}; + +/// Debug builtin functions for HypnoScript. +/// +/// Provides debugging utilities including value inspection, assertions, +/// timing measurements, and programmatic breakpoints. +pub struct DebugBuiltins; + +impl BuiltinModule for DebugBuiltins { + fn module_name() -> &'static str { + "Debug" + } + + fn description() -> &'static str { + "Debugging utilities for HypnoScript programs" + } + + fn description_localized(locale: Option<&str>) -> String { + let msg = LocalizedMessage::new("Debugging utilities for HypnoScript programs") + .with_translation("de", "Debugging utilities for HypnoScript programs") + .with_translation( + "fr", + "Utilitaires de débogage pour les programmes HypnoScript", + ) + .with_translation("es", "Utilidades de depuración para programas HypnoScript"); + + let loc = crate::localization::detect_locale(locale); + msg.resolve(&loc).to_string() + } + + fn function_names() -> &'static [&'static str] { + &[ + "inspect", + "breakpoint", + "stackTrace", + "measureTime", + "assertEqual", + "assertNotEqual", + "assertTruthy", + "assertFalsy", + "assertNull", + "assertNotNull", + "typeOf", + "dump", + "log", + "warn", + "error", + "trace", + "time", + "timeEnd", + ] + } +} + +/// Represents the result of a debug assertion. +#[derive(Debug, Clone)] +pub struct AssertionResult { + /// Whether the assertion passed + pub passed: bool, + /// The assertion message + pub message: String, + /// Additional context + pub context: Option, +} + +impl AssertionResult { + /// Creates a passing assertion result. + pub fn pass(message: impl Into) -> Self { + Self { + passed: true, + message: message.into(), + context: None, + } + } + + /// Creates a failing assertion result. + pub fn fail(message: impl Into) -> Self { + Self { + passed: false, + message: message.into(), + context: None, + } + } + + /// Adds context to the result. + pub fn with_context(mut self, context: impl Into) -> Self { + self.context = Some(context.into()); + self + } +} + +/// Result of a timing measurement. +#[derive(Debug, Clone)] +pub struct TimingResult { + /// The measured duration + pub duration: Duration, + /// Label for the timing + pub label: String, +} + +impl TimingResult { + /// Formats the timing result for display. + pub fn format(&self) -> String { + let micros = self.duration.as_micros(); + if micros < 1000 { + format!("{}: {}µs", self.label, micros) + } else if micros < 1_000_000 { + format!("{}: {:.2}ms", self.label, micros as f64 / 1000.0) + } else { + format!("{}: {:.2}s", self.label, micros as f64 / 1_000_000.0) + } + } +} + +// Thread-local storage for timing measurements. +thread_local! { + static TIMERS: std::cell::RefCell> = + std::cell::RefCell::new(std::collections::HashMap::new()); +} + +impl DebugBuiltins { + /// Inspects a value and returns a string with type information. + /// + /// # Arguments + /// * `value` - The value as a display string + /// * `type_name` - The type name + /// + /// # Returns + /// A string in the format "value (type)" + /// + /// # Examples + /// + /// ```rust + /// use hypnoscript_runtime::DebugBuiltins; + /// + /// let result = DebugBuiltins::inspect("42", "number"); + /// assert_eq!(result, "42 (number)"); + /// ``` + pub fn inspect(value: &str, type_name: &str) -> String { + format!("{} ({})", value, type_name) + } + + /// Inspects a value with detailed representation. + /// + /// # Arguments + /// * `value` - The value as a display string + /// * `type_name` - The type name + /// * `details` - Optional additional details + /// + /// # Returns + /// A detailed inspection string + pub fn inspect_detailed(value: &str, type_name: &str, details: Option<&str>) -> String { + match details { + Some(d) => format!("{} ({}) [{}]", value, type_name, d), + None => format!("{} ({})", value, type_name), + } + } + + /// Returns the type name for a value category. + /// + /// # Arguments + /// * `type_name` - The internal type name + /// + /// # Returns + /// A user-friendly type name + pub fn type_of(type_name: &str) -> String { + match type_name { + "Number" | "number" => "number".to_string(), + "String" | "string" => "string".to_string(), + "Boolean" | "boolean" | "bool" => "boolean".to_string(), + "Array" | "array" => "array".to_string(), + "Function" | "function" => "function".to_string(), + "Session" | "session" => "session".to_string(), + "Instance" | "instance" => "instance".to_string(), + "Promise" | "promise" => "promise".to_string(), + "Record" | "record" => "record".to_string(), + "Null" | "null" => "null".to_string(), + other => other.to_string(), + } + } + + /// Triggers a programmatic breakpoint. + /// + /// This function signals to the debugger (if attached) that execution + /// should pause at this point. If no debugger is attached, this is a no-op. + /// + /// # Returns + /// `true` if a debugger was attached, `false` otherwise + pub fn breakpoint() -> bool { + // In a real implementation, this would signal the debugger + // For now, we just print a message + eprintln!("[DEBUG] Programmatic breakpoint triggered"); + true + } + + /// Returns a formatted stack trace. + /// + /// # Arguments + /// * `frames` - List of (function_name, line_number) tuples + /// + /// # Returns + /// A formatted stack trace string + pub fn stack_trace(frames: &[(String, usize)]) -> String { + if frames.is_empty() { + return " (empty stack)".to_string(); + } + + frames + .iter() + .enumerate() + .map(|(i, (name, line))| { + if *line > 0 { + format!(" #{} {} at line {}", i, name, line) + } else { + format!(" #{} {} (native)", i, name) + } + }) + .collect::>() + .join("\n") + } + + /// Starts a timer with the given label. + /// + /// # Arguments + /// * `label` - The timer label + pub fn time(label: &str) { + TIMERS.with(|timers| { + timers + .borrow_mut() + .insert(label.to_string(), Instant::now()); + }); + } + + /// Stops a timer and returns the elapsed time. + /// + /// # Arguments + /// * `label` - The timer label + /// + /// # Returns + /// The timing result, or None if timer wasn't started + pub fn time_end(label: &str) -> Option { + TIMERS.with(|timers| { + timers.borrow_mut().remove(label).map(|start| TimingResult { + duration: start.elapsed(), + label: label.to_string(), + }) + }) + } + + /// Measures the execution time of a closure. + /// + /// # Arguments + /// * `f` - The closure to measure + /// + /// # Returns + /// A tuple of (result, duration) + pub fn measure_time(f: F) -> (R, Duration) + where + F: FnOnce() -> R, + { + let start = Instant::now(); + let result = f(); + let duration = start.elapsed(); + (result, duration) + } + + /// Asserts that two values are equal. + /// + /// # Arguments + /// * `left` - Left value as string + /// * `right` - Right value as string + /// * `message` - Optional message for failure + /// + /// # Returns + /// `Ok(())` if equal, `Err(message)` if not + pub fn assert_equal(left: &str, right: &str, message: Option<&str>) -> Result<(), String> { + if left == right { + Ok(()) + } else { + let msg = message.unwrap_or("Assertion failed: values are not equal"); + Err(format!("{}\n left: {}\n right: {}", msg, left, right)) + } + } + + /// Asserts that two values are not equal. + /// + /// # Arguments + /// * `left` - Left value as string + /// * `right` - Right value as string + /// * `message` - Optional message for failure + /// + /// # Returns + /// `Ok(())` if not equal, `Err(message)` if equal + pub fn assert_not_equal(left: &str, right: &str, message: Option<&str>) -> Result<(), String> { + if left != right { + Ok(()) + } else { + let msg = message.unwrap_or("Assertion failed: values should not be equal"); + Err(format!("{}\n value: {}", msg, left)) + } + } + + /// Asserts that a value is truthy. + /// + /// # Arguments + /// * `is_truthy` - Whether the value is truthy + /// * `value_repr` - String representation of the value + /// * `message` - Optional message for failure + /// + /// # Returns + /// `Ok(())` if truthy, `Err(message)` if not + pub fn assert_truthy( + is_truthy: bool, + value_repr: &str, + message: Option<&str>, + ) -> Result<(), String> { + if is_truthy { + Ok(()) + } else { + let msg = message.unwrap_or("Assertion failed: expected truthy value"); + Err(format!("{}\n got: {}", msg, value_repr)) + } + } + + /// Asserts that a value is falsy. + /// + /// # Arguments + /// * `is_truthy` - Whether the value is truthy + /// * `value_repr` - String representation of the value + /// * `message` - Optional message for failure + /// + /// # Returns + /// `Ok(())` if falsy, `Err(message)` if truthy + pub fn assert_falsy( + is_truthy: bool, + value_repr: &str, + message: Option<&str>, + ) -> Result<(), String> { + if !is_truthy { + Ok(()) + } else { + let msg = message.unwrap_or("Assertion failed: expected falsy value"); + Err(format!("{}\n got: {}", msg, value_repr)) + } + } + + /// Asserts that a value is null. + /// + /// # Arguments + /// * `is_null` - Whether the value is null + /// * `value_repr` - String representation of the value + /// * `message` - Optional message for failure + /// + /// # Returns + /// `Ok(())` if null, `Err(message)` if not + pub fn assert_null( + is_null: bool, + value_repr: &str, + message: Option<&str>, + ) -> Result<(), String> { + if is_null { + Ok(()) + } else { + let msg = message.unwrap_or("Assertion failed: expected null"); + Err(format!("{}\n got: {}", msg, value_repr)) + } + } + + /// Asserts that a value is not null. + /// + /// # Arguments + /// * `is_null` - Whether the value is null + /// * `value_repr` - String representation of the value + /// * `message` - Optional message for failure + /// + /// # Returns + /// `Ok(())` if not null, `Err(message)` if null + pub fn assert_not_null( + is_null: bool, + value_repr: &str, + message: Option<&str>, + ) -> Result<(), String> { + if !is_null { + Ok(()) + } else { + let msg = message.unwrap_or("Assertion failed: expected non-null value"); + Err(format!("{}\n got: {}", msg, value_repr)) + } + } + + /// Logs a debug message. + /// + /// # Arguments + /// * `message` - The message to log + pub fn log(message: &str) { + eprintln!("[DEBUG] {}", message); + } + + /// Logs a warning message. + /// + /// # Arguments + /// * `message` - The message to log + pub fn warn(message: &str) { + eprintln!("[WARN] {}", message); + } + + /// Logs an error message. + /// + /// # Arguments + /// * `message` - The message to log + pub fn error(message: &str) { + eprintln!("[ERROR] {}", message); + } + + /// Logs a trace message with caller information. + /// + /// # Arguments + /// * `message` - The message to log + /// * `location` - Optional location information (file:line) + pub fn trace(message: &str, location: Option<&str>) { + match location { + Some(loc) => eprintln!("[TRACE] {} at {}", message, loc), + None => eprintln!("[TRACE] {}", message), + } + } + + /// Dumps a value with full details. + /// + /// # Arguments + /// * `value` - The value representation + /// * `type_name` - The type name + /// * `details` - Additional details about the value + pub fn dump(value: &str, type_name: &str, details: &str) { + eprintln!("┌─ Debug Dump ─────────────────────"); + eprintln!("│ Type: {}", type_name); + eprintln!("│ Value: {}", value); + if !details.is_empty() { + eprintln!("│ Details: {}", details); + } + eprintln!("└──────────────────────────────────"); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_inspect() { + assert_eq!(DebugBuiltins::inspect("42", "number"), "42 (number)"); + assert_eq!(DebugBuiltins::inspect("hello", "string"), "hello (string)"); + assert_eq!(DebugBuiltins::inspect("true", "boolean"), "true (boolean)"); + } + + #[test] + fn test_inspect_detailed() { + assert_eq!( + DebugBuiltins::inspect_detailed("42", "number", None), + "42 (number)" + ); + assert_eq!( + DebugBuiltins::inspect_detailed("arr", "array", Some("length: 5")), + "arr (array) [length: 5]" + ); + } + + #[test] + fn test_type_of() { + assert_eq!(DebugBuiltins::type_of("Number"), "number"); + assert_eq!(DebugBuiltins::type_of("String"), "string"); + assert_eq!(DebugBuiltins::type_of("Boolean"), "boolean"); + assert_eq!(DebugBuiltins::type_of("Null"), "null"); + assert_eq!(DebugBuiltins::type_of("CustomType"), "CustomType"); + } + + #[test] + fn test_stack_trace() { + let frames = vec![ + ("main".to_string(), 10), + ("helper".to_string(), 25), + ("nested".to_string(), 30), + ]; + let trace = DebugBuiltins::stack_trace(&frames); + assert!(trace.contains("#0 main at line 10")); + assert!(trace.contains("#1 helper at line 25")); + assert!(trace.contains("#2 nested at line 30")); + } + + #[test] + fn test_stack_trace_empty() { + let frames: Vec<(String, usize)> = vec![]; + let trace = DebugBuiltins::stack_trace(&frames); + assert_eq!(trace, " (empty stack)"); + } + + #[test] + fn test_stack_trace_native() { + let frames = vec![("println".to_string(), 0)]; + let trace = DebugBuiltins::stack_trace(&frames); + assert!(trace.contains("(native)")); + } + + #[test] + fn test_timing() { + DebugBuiltins::time("test_timer"); + std::thread::sleep(std::time::Duration::from_millis(10)); + let result = DebugBuiltins::time_end("test_timer"); + assert!(result.is_some()); + let timing = result.unwrap(); + assert!(timing.duration.as_millis() >= 10); + assert_eq!(timing.label, "test_timer"); + } + + #[test] + fn test_timing_nonexistent() { + let result = DebugBuiltins::time_end("nonexistent_timer"); + assert!(result.is_none()); + } + + #[test] + fn test_measure_time() { + let (result, duration) = DebugBuiltins::measure_time(|| { + std::thread::sleep(std::time::Duration::from_millis(5)); + 42 + }); + assert_eq!(result, 42); + assert!(duration.as_millis() >= 5); + } + + #[test] + fn test_assert_equal_pass() { + assert!(DebugBuiltins::assert_equal("42", "42", None).is_ok()); + assert!(DebugBuiltins::assert_equal("hello", "hello", Some("custom message")).is_ok()); + } + + #[test] + fn test_assert_equal_fail() { + let result = DebugBuiltins::assert_equal("42", "43", None); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert!(err.contains("not equal")); + assert!(err.contains("42")); + assert!(err.contains("43")); + } + + #[test] + fn test_assert_not_equal_pass() { + assert!(DebugBuiltins::assert_not_equal("42", "43", None).is_ok()); + } + + #[test] + fn test_assert_not_equal_fail() { + let result = DebugBuiltins::assert_not_equal("42", "42", None); + assert!(result.is_err()); + } + + #[test] + fn test_assert_truthy() { + assert!(DebugBuiltins::assert_truthy(true, "true", None).is_ok()); + assert!(DebugBuiltins::assert_truthy(false, "false", None).is_err()); + } + + #[test] + fn test_assert_falsy() { + assert!(DebugBuiltins::assert_falsy(false, "false", None).is_ok()); + assert!(DebugBuiltins::assert_falsy(true, "true", None).is_err()); + } + + #[test] + fn test_assert_null() { + assert!(DebugBuiltins::assert_null(true, "null", None).is_ok()); + assert!(DebugBuiltins::assert_null(false, "42", None).is_err()); + } + + #[test] + fn test_assert_not_null() { + assert!(DebugBuiltins::assert_not_null(false, "42", None).is_ok()); + assert!(DebugBuiltins::assert_not_null(true, "null", None).is_err()); + } + + #[test] + fn test_timing_result_format() { + let result = TimingResult { + duration: Duration::from_micros(500), + label: "test".to_string(), + }; + assert!(result.format().contains("µs")); + + let result_ms = TimingResult { + duration: Duration::from_millis(50), + label: "test".to_string(), + }; + assert!(result_ms.format().contains("ms")); + + let result_s = TimingResult { + duration: Duration::from_secs(2), + label: "test".to_string(), + }; + assert!(result_s.format().contains("s")); + } + + #[test] + fn test_module_info() { + assert_eq!(DebugBuiltins::module_name(), "Debug"); + assert!(!DebugBuiltins::description().is_empty()); + assert!(!DebugBuiltins::function_names().is_empty()); + } +} diff --git a/hypnoscript-runtime/src/dictionary_builtins.rs b/hypnoscript-runtime/src/dictionary_builtins.rs index 672189e..6e5379c 100644 --- a/hypnoscript-runtime/src/dictionary_builtins.rs +++ b/hypnoscript-runtime/src/dictionary_builtins.rs @@ -38,7 +38,7 @@ impl BuiltinModule for DictionaryBuiltins { LocalizedMessage::new("Key-value collection operations for dictionaries and maps") .with_translation( "de", - "Schlüssel-Wert-Sammlungsoperationen für Dictionaries und Maps", + "Key-value collection operations for dictionaries and maps", ) .with_translation( "fr", diff --git a/hypnoscript-runtime/src/file_builtins.rs b/hypnoscript-runtime/src/file_builtins.rs index 6614833..7647516 100644 --- a/hypnoscript-runtime/src/file_builtins.rs +++ b/hypnoscript-runtime/src/file_builtins.rs @@ -22,7 +22,7 @@ impl BuiltinModule for FileBuiltins { fn description_localized(locale: Option<&str>) -> String { let locale = crate::localization::detect_locale(locale); let msg = LocalizedMessage::new("File I/O and file system operations") - .with_translation("de", "Datei-I/O- und Dateisystemoperationen") + .with_translation("de", "File I/O and file system operations") .with_translation( "fr", "Opérations d'E/S de fichiers et de système de fichiers", @@ -300,7 +300,7 @@ mod tests { fn test_read_write_lines() { let test_file = unique_test_file(); let path = test_file.to_string_lossy().into_owned(); - let lines = vec!["eins".to_string(), "zwei".to_string(), "drei".to_string()]; + let lines = vec!["one".to_string(), "two".to_string(), "three".to_string()]; FileBuiltins::write_lines(&path, &lines).unwrap(); let read_back = FileBuiltins::read_lines(&path).unwrap(); assert_eq!(lines, read_back); diff --git a/hypnoscript-runtime/src/lib.rs b/hypnoscript-runtime/src/lib.rs index 4f1eb76..c7afa00 100644 --- a/hypnoscript-runtime/src/lib.rs +++ b/hypnoscript-runtime/src/lib.rs @@ -10,6 +10,7 @@ pub mod cli_builtins; pub mod collection_builtins; pub mod core_builtins; pub mod data_builtins; +pub mod debug_builtins; pub mod deepmind_builtins; pub mod dictionary_builtins; pub mod file_builtins; @@ -32,6 +33,7 @@ pub use cli_builtins::{CliBuiltins, ParsedArguments}; pub use collection_builtins::CollectionBuiltins; pub use core_builtins::CoreBuiltins; pub use data_builtins::{CsvOptions, DataBuiltins, JsonQueryOptions}; +pub use debug_builtins::{AssertionResult, DebugBuiltins, TimingResult}; pub use deepmind_builtins::DeepMindBuiltins; pub use dictionary_builtins::DictionaryBuiltins; pub use file_builtins::FileBuiltins; diff --git a/hypnoscript-runtime/src/math_builtins.rs b/hypnoscript-runtime/src/math_builtins.rs index 8fd7276..d5b72cb 100644 --- a/hypnoscript-runtime/src/math_builtins.rs +++ b/hypnoscript-runtime/src/math_builtins.rs @@ -24,7 +24,7 @@ impl BuiltinModule for MathBuiltins { ) .with_translation( "de", - "Mathematische Funktionen inkl. Trigonometrie, Algebra und Zahlentheorie", + "Mathematical functions including trigonometry, algebra, and number theory", ) .with_translation( "fr", diff --git a/hypnoscript-runtime/src/string_builtins.rs b/hypnoscript-runtime/src/string_builtins.rs index 79b052e..17668dd 100644 --- a/hypnoscript-runtime/src/string_builtins.rs +++ b/hypnoscript-runtime/src/string_builtins.rs @@ -31,7 +31,7 @@ impl BuiltinModule for StringBuiltins { fn description_localized(locale: Option<&str>) -> String { let locale = crate::localization::detect_locale(locale); let msg = LocalizedMessage::new("String manipulation and analysis functions") - .with_translation("de", "Zeichenketten-Manipulations- und Analysefunktionen") + .with_translation("de", "String manipulation and analysis functions") .with_translation("fr", "Fonctions de manipulation et d'analyse de chaînes") .with_translation("es", "Funciones de manipulación y análisis de cadenas"); msg.resolve(&locale).to_string() diff --git a/hypnoscript-runtime/src/time_builtins.rs b/hypnoscript-runtime/src/time_builtins.rs index aa3099f..2d0ffbc 100644 --- a/hypnoscript-runtime/src/time_builtins.rs +++ b/hypnoscript-runtime/src/time_builtins.rs @@ -20,7 +20,7 @@ impl BuiltinModule for TimeBuiltins { fn description_localized(locale: Option<&str>) -> String { let locale = crate::localization::detect_locale(locale); let msg = LocalizedMessage::new("Date and time functions for timestamps, formatting, and calendar operations") - .with_translation("de", "Datums- und Zeitfunktionen für Zeitstempel, Formatierung und Kalenderoperationen") + .with_translation("de", "Date and time functions for timestamps, formatting, and calendar operations") .with_translation("fr", "Fonctions de date et heure pour les horodatages, le formatage et les opérations calendaires") .with_translation("es", "Funciones de fecha y hora para marcas de tiempo, formato y operaciones de calendario"); msg.resolve(&locale).to_string() diff --git a/hypnoscript-runtime/src/validation_builtins.rs b/hypnoscript-runtime/src/validation_builtins.rs index 894aad9..3a295f7 100644 --- a/hypnoscript-runtime/src/validation_builtins.rs +++ b/hypnoscript-runtime/src/validation_builtins.rs @@ -25,7 +25,7 @@ impl BuiltinModule for ValidationBuiltins { fn description_localized(locale: Option<&str>) -> String { let locale = crate::localization::detect_locale(locale); let msg = LocalizedMessage::new("Data validation functions for emails, URLs, phone numbers, and patterns") - .with_translation("de", "Datenvalidierungsfunktionen für E-Mails, URLs, Telefonnummern und Muster") + .with_translation("de", "Data validation functions for emails, URLs, phone numbers, and patterns") .with_translation("fr", "Fonctions de validation de données pour e-mails, URL, numéros de téléphone et motifs") .with_translation("es", "Funciones de validación de datos para correos electrónicos, URLs, números de teléfono y patrones"); msg.resolve(&locale).to_string() diff --git a/package.json b/package.json index 2990b51..f3dde4b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hyp-runtime", - "version": "1.0.0", + "version": "1.2.0", "description": "Workspace documentation tooling for the HypnoScript Rust implementation.", "private": true, "scripts": { diff --git a/scripts/README.md b/scripts/README.md index 40b6707..a62fe9e 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -45,8 +45,8 @@ Creates a Linux release package including: - `release/linux-x64/hypnoscript` - `release/linux-x64/install.sh` -- `release/hypnoscript-1.0.0-linux-x64.tar.gz` -- `release/hypnoscript-1.0.0-linux-x64.tar.gz.sha256` +- `release/hypnoscript-1.2.0-linux-x64.tar.gz` +- `release/hypnoscript-1.2.0-linux-x64.tar.gz.sha256` **Requirements**: @@ -57,7 +57,7 @@ Creates a Linux release package including: **Installation on Linux**: ```bash -tar -xzf hypnoscript-1.0.0-linux-x64.tar.gz +tar -xzf hypnoscript-1.2.0-linux-x64.tar.gz cd linux-x64 sudo bash install.sh ``` @@ -82,9 +82,9 @@ Creates a macOS release package with multiple distribution formats: - `release/macos-universal/hypnoscript` - `release/macos-universal/install.sh` -- `release/HypnoScript-1.0.0-macos-universal.tar.gz` -- `release/HypnoScript-1.0.0-macos-universal.dmg` (macOS only) -- `release/HypnoScript-1.0.0-macos-universal.pkg` (macOS only) +- `release/hypnoscript-1.2.0-macos-universal.tar.gz` +- `release/hypnoscript-1.2.0-macos-universal.dmg` (macOS only) +- `release/hypnoscript-1.2.0-macos-universal.pkg` (macOS only) - `.sha256` files for all archives **Architecture Options**: @@ -116,20 +116,20 @@ pwsh scripts/build_macos.ps1 -PackageType all # All formats From TAR.GZ: ```bash -tar -xzf HypnoScript-1.0.0-macos-universal.tar.gz +tar -xzf hypnoscript-1.2.0-macos-universal.tar.gz cd macos-universal sudo bash install.sh ``` From DMG: -1. Open `HypnoScript-1.0.0-macos-universal.dmg` +1. Open `hypnoscript-1.2.0-macos-universal.dmg` 2. Drag `hypnoscript` to the "Install to /usr/local/bin" symlink From PKG: ```bash -sudo installer -pkg HypnoScript-1.0.0-macos-universal.pkg -target / +sudo installer -pkg hypnoscript-1.2.0-macos-universal.pkg -target / ``` --- @@ -217,10 +217,10 @@ rustup target add aarch64-apple-darwin # Apple Silicon Version information is defined in: - `Cargo.toml` (workspace root) -- `scripts/build_winget.ps1` (line 8: `$VERSION = "1.0.0"`) -- `scripts/build_linux.ps1` (line 10: `$VERSION = "1.0.0"`) -- `scripts/build_macos.ps1` (line 11: `$VERSION = "1.0.0"`) -- `scripts/build_deb.sh` (line 7: `VERSION=1.0.0`) +- `scripts/build_winget.ps1` (line 8: `$VERSION = "1.2.0"`) +- `scripts/build_linux.ps1` (line 10: `$VERSION = "1.2.0"`) +- `scripts/build_macos.ps1` (line 11: `$VERSION = "1.2.0"`) +- `scripts/build_deb.sh` (line 7: `VERSION=1.2.0`) **Important**: Keep versions synchronized across all files! @@ -239,15 +239,15 @@ Get-FileHash -Algorithm SHA256 HypnoScript-windows-x64.zip **Linux**: ```bash -sha256sum hypnoscript-1.0.0-linux-x64.tar.gz -cat hypnoscript-1.0.0-linux-x64.tar.gz.sha256 +sha256sum hypnoscript-1.2.0-linux-x64.tar.gz +cat hypnoscript-1.2.0-linux-x64.tar.gz.sha256 ``` **macOS**: ```bash -shasum -a 256 HypnoScript-1.0.0-macos-universal.tar.gz -cat HypnoScript-1.0.0-macos-universal.tar.gz.sha256 +shasum -a 256 hypnoscript-1.2.0-macos-universal.tar.gz +cat hypnoscript-1.2.0-macos-universal.tar.gz.sha256 ``` --- @@ -277,14 +277,14 @@ release/ │ └── VERSION.txt ├── HypnoScript-windows-x64.zip ├── HypnoScript-windows-x64.zip.sha256 -├── hypnoscript-1.0.0-linux-x64.tar.gz -├── hypnoscript-1.0.0-linux-x64.tar.gz.sha256 -├── HypnoScript-1.0.0-macos-universal.tar.gz -├── HypnoScript-1.0.0-macos-universal.tar.gz.sha256 -├── HypnoScript-1.0.0-macos-universal.dmg (macOS only) -├── HypnoScript-1.0.0-macos-universal.dmg.sha256 -├── HypnoScript-1.0.0-macos-universal.pkg (macOS only) -└── HypnoScript-1.0.0-macos-universal.pkg.sha256 +├── hypnoscript-1.2.0-linux-x64.tar.gz +├── hypnoscript-1.2.0-linux-x64.tar.gz.sha256 +├── hypnoscript-1.2.0-macos-universal.tar.gz +├── hypnoscript-1.2.0-macos-universal.tar.gz.sha256 +├── hypnoscript-1.2.0-macos-universal.dmg (macOS only) +├── hypnoscript-1.2.0-macos-universal.dmg.sha256 +├── hypnoscript-1.2.0-macos-universal.pkg (macOS only) +└── hypnoscript-1.2.0-macos-universal.pkg.sha256 ``` --- @@ -330,10 +330,10 @@ Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser ### GitHub Releases -1. Create a new release tag (e.g., `v1.0.0`) +1. Create a new release tag (e.g., `v1.2.0`) 2. Upload artifacts: - `HypnoScript-windows-x64.zip` - - `hypnoscript-1.0.0-linux-x64.tar.gz` + - `hypnoscript-1.2.0-linux-x64.tar.gz` - Checksum files (`.sha256`) 3. Add release notes diff --git a/scripts/build_deb.sh b/scripts/build_deb.sh index e884b88..67809ec 100644 --- a/scripts/build_deb.sh +++ b/scripts/build_deb.sh @@ -2,13 +2,13 @@ set -e # build_deb.sh -# Erstellt Linux-Binary und .deb-Paket für HypnoScript (Rust-Implementation) +# Creates Linux binary and .deb package for HypnoScript (Rust implementation) NAME=hypnoscript -VERSION=1.0.0 +VERSION=1.2.0 ARCH=amd64 -# Projektverzeichnis ermitteln +# Determine project directory SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" @@ -45,7 +45,7 @@ fi echo "=== HypnoScript Linux Release Builder ===" echo "" -# 1. Verzeichnisse vorbereiten +# 1. Prepare directories echo "📦 Preparing release directory..." rm -rf "$RELEASE_DIR" mkdir -p "$RELEASE_DIR" @@ -55,12 +55,12 @@ echo "🔨 Building HypnoScript CLI (Release)..." cd "$PROJECT_ROOT" cargo build --release --package hypnoscript-cli -# 3. Binary kopieren +# 3. Copy binary echo "📋 Copying binary..." cp "target/release/$BINARY_NAME" "$RELEASE_DIR/$INSTALL_NAME" chmod +x "$RELEASE_DIR/$INSTALL_NAME" -# 4. Zusätzliche Dateien +# 4. Additional files echo "📄 Adding additional files..." if [ -f "$PROJECT_ROOT/README.md" ]; then cp "$PROJECT_ROOT/README.md" "$RELEASE_DIR/" @@ -72,13 +72,13 @@ fi echo "$VERSION" > "$RELEASE_DIR/VERSION.txt" -# 5. TAR.GZ-Archiv erstellen (immer) +# 5. Create TAR.GZ archive (always) echo "📦 Creating TAR.GZ archive..." cd "$PROJECT_ROOT/release" tar -czf "$(basename "$TAR_OUT")" -C linux-x64 . cd "$PROJECT_ROOT" -# 6. .deb-Paket bauen (nur wenn fpm verfügbar) +# 6. Build .deb package (only if fpm is available) if [ "$HAS_FPM" = true ]; then echo "📦 Creating .deb package..." fpm -s dir \ @@ -86,7 +86,7 @@ if [ "$HAS_FPM" = true ]; then -n "$NAME" \ -v "$VERSION" \ --architecture "$ARCH" \ - --description "HypnoScript - Esoterische Programmiersprache mit Hypnose-Metaphern" \ + --description "HypnoScript - Esoteric programming language with hypnosis metaphors" \ --url "https://github.com/Kink-Development-Group/hyp-runtime" \ --license "MIT" \ --maintainer "HypnoScript Team" \ @@ -94,19 +94,19 @@ if [ "$HAS_FPM" = true ]; then --deb-compression xz \ "$RELEASE_DIR/$INSTALL_NAME=$INSTALL_NAME" - # Paket verschieben + # Move package mv "${NAME}_${VERSION}_${ARCH}.deb" "$DEB_OUT" - # Checksum erstellen + # Generate checksum echo "🔐 Generating SHA256 checksum for .deb..." sha256sum "$DEB_OUT" > "${DEB_OUT}.sha256" fi -# 7. Checksum für TAR.GZ erstellen +# 7. Generate checksum for TAR.GZ echo "🔐 Generating SHA256 checksum for tar.gz..." sha256sum "$TAR_OUT" > "${TAR_OUT}.sha256" -# 8. Informationen ausgeben +# 8. Output information echo "" echo "✅ Build complete!" echo "📦 TAR.GZ Archive: $TAR_OUT" diff --git a/scripts/build_linux.ps1 b/scripts/build_linux.ps1 index e75e14c..13723d1 100644 --- a/scripts/build_linux.ps1 +++ b/scripts/build_linux.ps1 @@ -1,7 +1,7 @@ #!/usr/bin/env pwsh # build_linux.ps1 -# Erstellt Linux-Binary und TAR.GZ-Archiv für HypnoScript (Rust-Implementation) -# Kann unter Windows mit WSL oder direkt unter Linux ausgeführt werden +# Creates Linux binary and TAR.GZ archive for HypnoScript (Rust implementation) +# Can be run on Windows with WSL or directly on Linux param( [switch]$SkipBuild = $false @@ -9,12 +9,12 @@ param( $ErrorActionPreference = "Stop" -# Konfiguration +# Configuration $NAME = "hypnoscript" -$VERSION = "1.0.0" +$VERSION = "1.2.0" $ARCH = "amd64" -# Projektverzeichnis ermitteln +# Determine project directory $ScriptDir = Split-Path -Parent $PSScriptRoot $ProjectRoot = $ScriptDir $ReleaseDir = Join-Path $ProjectRoot "release" "linux-x64" @@ -25,29 +25,29 @@ $InstallName = "hypnoscript" Write-Host "=== HypnoScript Linux Release Builder ===" -ForegroundColor Cyan Write-Host "" -# Check für Cargo +# Check for Cargo if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) { Write-Host "Error: cargo is not installed. Please install Rust toolchain first." -ForegroundColor Red Write-Host "Visit https://rustup.rs/ to install Rust" -ForegroundColor Yellow exit 1 } -# 1. Verzeichnisse vorbereiten +# 1. Prepare directories Write-Host "📦 Preparing release directory..." -ForegroundColor Green if (Test-Path $ReleaseDir) { Remove-Item -Recurse -Force $ReleaseDir } New-Item -ItemType Directory -Force -Path $ReleaseDir | Out-Null -# 2. Build für Linux (falls WSL verfügbar, sonst für aktuelles System) +# 2. Build for Linux (if WSL available, otherwise for current system) if (-not $SkipBuild) { Write-Host "🔨 Building HypnoScript CLI (Release for Linux)..." -ForegroundColor Green Push-Location $ProjectRoot - # Versuche Cross-Compilation für Linux + # Try cross-compilation for Linux $LinuxTarget = "x86_64-unknown-linux-gnu" - # Check ob Linux-Target installiert ist + # Check if Linux target is installed $InstalledTargets = rustup target list --installed 2>$null if ($InstalledTargets -match $LinuxTarget) { Write-Host " Using cross-compilation target: $LinuxTarget" -ForegroundColor Cyan @@ -66,12 +66,12 @@ if (-not $SkipBuild) { $BinaryPath = Join-Path $ProjectRoot "target" "release" $BinaryName } -# 3. Binary kopieren +# 3. Copy binary Write-Host "📋 Copying binary..." -ForegroundColor Green $DestBinary = Join-Path $ReleaseDir $InstallName Copy-Item $BinaryPath $DestBinary -Force -# 4. Zusätzliche Dateien +# 4. Additional files Write-Host "📄 Adding additional files..." -ForegroundColor Green $ReadmePath = Join-Path $ProjectRoot "README.md" @@ -86,7 +86,7 @@ if (Test-Path $LicensePath) { Set-Content -Path (Join-Path $ReleaseDir "VERSION.txt") -Value $VERSION -# Installation-Script hinzufügen +# Add installation script $InstallerSource = Join-Path $ProjectRoot "install.sh" if (Test-Path $InstallerSource) { Copy-Item $InstallerSource (Join-Path $ReleaseDir "install.sh") -Force @@ -94,28 +94,28 @@ if (Test-Path $InstallerSource) { Write-Host "⚠ Warning: install.sh not found at project root" -ForegroundColor Yellow } -# 5. TAR.GZ-Archiv erstellen +# 5. Create TAR.GZ archive Write-Host "📦 Creating TAR.GZ archive..." -ForegroundColor Green -# Unter Windows: tar.exe verwenden (verfügbar ab Windows 10 1803) +# On Windows: use tar.exe (available since Windows 10 1803) if ($IsWindows -or ($PSVersionTable.PSVersion.Major -le 5)) { Push-Location (Join-Path $ProjectRoot "release") & tar -czf (Split-Path -Leaf $TarOut) -C "linux-x64" . Pop-Location } else { - # Unter Linux: natives tar + # On Linux: native tar Push-Location (Join-Path $ProjectRoot "release") tar -czf (Split-Path -Leaf $TarOut) -C "linux-x64" . Pop-Location } -# 6. Checksum erstellen +# 6. Generate checksum Write-Host "🔐 Generating SHA256 checksum..." -ForegroundColor Green $Hash = Get-FileHash -Path $TarOut -Algorithm SHA256 $HashString = "$($Hash.Hash.ToLower()) $(Split-Path -Leaf $TarOut)" Set-Content -Path "$TarOut.sha256" -Value $HashString -# 7. Informationen ausgeben +# 7. Output information Write-Host "" Write-Host "✅ Build complete!" -ForegroundColor Green Write-Host "📦 TAR.GZ Archive: $TarOut" -ForegroundColor Cyan diff --git a/scripts/build_macos.ps1 b/scripts/build_macos.ps1 index d209122..29622d1 100644 --- a/scripts/build_macos.ps1 +++ b/scripts/build_macos.ps1 @@ -1,7 +1,7 @@ #!/usr/bin/env pwsh # build_macos.ps1 -# Erstellt macOS-Binary und DMG/PKG für HypnoScript (Rust-Implementation) -# Kann unter Windows/Linux mit Cross-Compilation oder nativ auf macOS ausgeführt werden +# Creates macOS binary and DMG/PKG for HypnoScript (Rust implementation) +# Can be run on Windows/Linux with cross-compilation or natively on macOS param( [switch]$SkipBuild = $false, @@ -13,14 +13,14 @@ param( $ErrorActionPreference = "Stop" -# Konfiguration +# Configuration $NAME = "HypnoScript" $BUNDLE_ID = "com.kinkdev.hypnoscript" -$VERSION = "1.0.0" +$VERSION = "1.2.0" $BINARY_NAME = "hypnoscript-cli" $INSTALL_NAME = "hypnoscript" -# Projektverzeichnis ermitteln +# Determine project directory $ScriptDir = Split-Path -Parent $PSScriptRoot $ProjectRoot = $ScriptDir $ReleaseDir = Join-Path $ProjectRoot "release" "macos-$Architecture" @@ -30,7 +30,7 @@ Write-Host "Architecture: $Architecture" -ForegroundColor Yellow Write-Host "Package Type: $PackageType" -ForegroundColor Yellow Write-Host "" -# Check für Cargo +# Check for Cargo if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) { Write-Host "Error: cargo is not installed. Please install Rust toolchain first." -ForegroundColor Red Write-Host "Visit https://rustup.rs/ to install Rust" -ForegroundColor Yellow @@ -46,7 +46,7 @@ $RunningOnWindows = $RunningOnWindows -or ($PSVersionTable.PSVersion.Major -le 5 $TargetX64 = "x86_64-apple-darwin" $TargetArm64 = "aarch64-apple-darwin" -# 1. Verzeichnisse vorbereiten +# 1. Prepare directories Write-Host "📦 Preparing release directory..." -ForegroundColor Green if (Test-Path $ReleaseDir) { Remove-Item -Recurse -Force $ReleaseDir @@ -75,7 +75,7 @@ if (-not $SkipBuild) { Push-Location $ProjectRoot if ($Architecture -eq 'universal') { - # Universal Binary (beide Architekturen) + # Universal binary (both architectures) Write-Host " Building for x86_64 (Intel)..." -ForegroundColor Cyan # Check if targets are installed @@ -104,12 +104,12 @@ if (-not $SkipBuild) { & lipo -create $BinaryX64 $BinaryArm64 -output $BinaryUniversal chmod +x $BinaryUniversal } elseif ($Architecture -eq 'x64') { - # Nur Intel + # Intel only cargo build --release --package hypnoscript-cli --target $TargetX64 $BinaryPath = Join-Path "target" $TargetX64 "release" $BINARY_NAME Copy-Item $BinaryPath (Join-Path $ReleaseDir $INSTALL_NAME) } elseif ($Architecture -eq 'arm64') { - # Nur Apple Silicon + # Apple Silicon only cargo build --release --package hypnoscript-cli --target $TargetArm64 $BinaryPath = Join-Path "target" $TargetArm64 "release" $BINARY_NAME Copy-Item $BinaryPath (Join-Path $ReleaseDir $INSTALL_NAME) @@ -124,7 +124,7 @@ if ($SkipBuild) { if ($RunningOnMacOS) { Write-Host " Using existing binaries from previous build" -ForegroundColor Yellow } else { - # Erstelle Platzhalter-Readme für Doc-Only Release + # Create placeholder README for doc-only release $ReadmeContent = @" # HypnoScript for macOS @@ -157,7 +157,7 @@ npm run release:macos Write-Host "✓ Build completed successfully" -ForegroundColor Green } -# 3. Zusätzliche Dateien kopieren +# 3. Copy additional files Write-Host "📄 Adding additional files..." -ForegroundColor Green $ReadmePath = Join-Path $ProjectRoot "README.md" @@ -172,7 +172,7 @@ if (Test-Path $LicensePath) { Set-Content -Path (Join-Path $ReleaseDir "VERSION.txt") -Value $VERSION -# 4. Installation-Script hinzufügen +# 4. Add installation script $InstallerSource = Join-Path $ProjectRoot "install.sh" if (Test-Path $InstallerSource) { Copy-Item $InstallerSource (Join-Path $ReleaseDir "install.sh") -Force @@ -180,7 +180,7 @@ if (Test-Path $InstallerSource) { Write-Host "⚠ install.sh not found at project root" -ForegroundColor Yellow } -# 5. TAR.GZ erstellen (immer) +# 5. Create TAR.GZ (always) if ($PackageType -eq 'tar.gz' -or $PackageType -eq 'all') { Write-Host "📦 Creating TAR.GZ archive..." -ForegroundColor Green @@ -189,10 +189,10 @@ if ($PackageType -eq 'tar.gz' -or $PackageType -eq 'all') { Push-Location (Join-Path $ProjectRoot "release") if ($RunningOnMacOS -or $RunningOnLinux) { - # Native tar auf macOS/Linux + # Native tar on macOS/Linux tar -czf (Split-Path -Leaf $TarOut) -C "macos-$Architecture" . } elseif ($RunningOnWindows) { - # Windows tar (verfügbar ab Windows 10 1803) + # Windows tar (available since Windows 10 1803) if (Get-Command tar -ErrorAction SilentlyContinue) { & tar -czf (Split-Path -Leaf $TarOut) -C "macos-$Architecture" . } else { @@ -213,30 +213,30 @@ if ($PackageType -eq 'tar.gz' -or $PackageType -eq 'all') { Write-Host " Size: $([math]::Round($TarSize, 2)) MB" -ForegroundColor Cyan } -# 6. DMG erstellen (nur auf macOS) +# 6. Create DMG (macOS only) if (($PackageType -eq 'dmg' -or $PackageType -eq 'all') -and $RunningOnMacOS) { Write-Host "📦 Creating DMG image..." -ForegroundColor Green $DmgDir = Join-Path $ProjectRoot "release" "dmg-staging" $DmgOut = Join-Path $ProjectRoot "release" "$NAME-$VERSION-macos-$Architecture.dmg" - # DMG staging vorbereiten + # Prepare DMG staging if (Test-Path $DmgDir) { Remove-Item -Recurse -Force $DmgDir } New-Item -ItemType Directory -Force -Path $DmgDir | Out-Null - # Binary in staging kopieren + # Copy binary into staging Copy-Item (Join-Path $ReleaseDir $INSTALL_NAME) $DmgDir Copy-Item (Join-Path $ReleaseDir "README.md") $DmgDir -ErrorAction SilentlyContinue Copy-Item (Join-Path $ReleaseDir "LICENSE") $DmgDir -ErrorAction SilentlyContinue - # Symlink zu /usr/local/bin erstellen + # Create symlink to /usr/local/bin Push-Location $DmgDir New-Item -ItemType SymbolicLink -Name "Install to /usr/local/bin" -Target "/usr/local/bin" -ErrorAction SilentlyContinue Pop-Location - # DMG erstellen + # Create DMG & hdiutil create -volname "$NAME $VERSION" ` -srcfolder $DmgDir ` -ov -format UDZO ` @@ -259,7 +259,7 @@ if (($PackageType -eq 'dmg' -or $PackageType -eq 'all') -and $RunningOnMacOS) { Write-Host "⚠ DMG creation requires macOS - skipped" -ForegroundColor Yellow } -# 7. PKG erstellen (nur auf macOS) +# 7. Create PKG (macOS only) if (($PackageType -eq 'pkg' -or $PackageType -eq 'all') -and $RunningOnMacOS) { Write-Host "📦 Creating PKG installer..." -ForegroundColor Green @@ -268,7 +268,7 @@ if (($PackageType -eq 'pkg' -or $PackageType -eq 'all') -and $RunningOnMacOS) { $PkgScripts = Join-Path $PkgDir "scripts" $PkgOut = Join-Path $ProjectRoot "release" "$NAME-$VERSION-macos-$Architecture.pkg" - # PKG staging vorbereiten + # Prepare PKG staging if (Test-Path $PkgDir) { Remove-Item -Recurse -Force $PkgDir } @@ -276,7 +276,7 @@ if (($PackageType -eq 'pkg' -or $PackageType -eq 'all') -and $RunningOnMacOS) { New-Item -ItemType Directory -Force -Path (Join-Path $PkgRoot "usr" "local" "bin") | Out-Null New-Item -ItemType Directory -Force -Path $PkgScripts | Out-Null - # Binary in staging kopieren + # Copy binary into staging Copy-Item (Join-Path $ReleaseDir $INSTALL_NAME) (Join-Path $PkgRoot "usr" "local" "bin" $INSTALL_NAME) # Postinstall script @@ -289,7 +289,7 @@ exit 0 Set-Content -Path (Join-Path $PkgScripts "postinstall") -Value $PostInstall chmod +x (Join-Path $PkgScripts "postinstall") - # PKG erstellen + # Create PKG & pkgbuild --root $PkgRoot ` --scripts $PkgScripts ` --identifier $BUNDLE_ID ` @@ -314,7 +314,7 @@ exit 0 Write-Host "⚠ PKG creation requires macOS - skipped" -ForegroundColor Yellow } -# 8. Zusammenfassung +# 8. Summary Write-Host "" Write-Host "=== Build Summary ===" -ForegroundColor Cyan Write-Host "Architecture: $Architecture" -ForegroundColor Yellow diff --git a/scripts/build_winget.ps1 b/scripts/build_winget.ps1 index 649d6c8..70359a3 100644 --- a/scripts/build_winget.ps1 +++ b/scripts/build_winget.ps1 @@ -59,7 +59,7 @@ if (Test-Path $licensePath) { } # Create VERSION file -$version = "1.0.0" +$version = "1.2.0" $versionFile = Join-Path $winDir "VERSION.txt" Set-Content -Path $versionFile -Value "HypnoScript Runtime v$version`n`nBuilt: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" diff --git a/scripts/debian/control b/scripts/debian/control index ae2da22..c9c333c 100644 --- a/scripts/debian/control +++ b/scripts/debian/control @@ -1,5 +1,5 @@ Package: hypnoscript -Version: 1.0.0 +Version: 1.2.0 Section: utils Priority: optional Architecture: amd64 diff --git a/scripts/winget-manifest.yaml b/scripts/winget-manifest.yaml index f97a267..0fcebee 100644 --- a/scripts/winget-manifest.yaml +++ b/scripts/winget-manifest.yaml @@ -1,13 +1,13 @@ # winget-manifest.yaml PackageIdentifier: HypnoScript.HypnoScript -PackageVersion: 1.0.0 +PackageVersion: 1.2.0 PackageName: HypnoScript Publisher: HypnoScript Project License: MIT Installers: - Architecture: x64 InstallerType: zip - InstallerUrl: https://github.com/Kink-Development-Group/hyp-runtime/releases/download/v1.0.0/HypnoScript-windows-x64.zip + InstallerUrl: https://github.com/Kink-Development-Group/hyp-runtime/releases/download/v1.2.0/HypnoScript-windows-x64.zip InstallerSha256: Scope: machine NestedInstallerType: exe @@ -15,7 +15,7 @@ Installers: - RelativeFilePath: HypnoScript.CLI.exe PortableCommandAlias: hypnoscript ShortDescription: HypnoScript CLI & Runtime -Description: HypnoScript ist eine moderne, hypnotische Programmiersprache mit CLI und Runtime. +Description: HypnoScript is a modern, hypnotic programming language with CLI and runtime. Tags: - HypnoScript - CLI diff --git a/template/trance.json b/template/trance.json index 9deb1b3..8a6b04f 100644 --- a/template/trance.json +++ b/template/trance.json @@ -29,8 +29,8 @@ "test": "hypnoscript run tests/smoke.hyp" }, "anchors": { - "hypnoscript-runtime": "^1.0.0", - "hypnoscript-cli": "^1.0.0" + "hypnoscript-runtime": "^1.2.0", + "hypnoscript-cli": "^1.2.0" }, "deepAnchors": { "@hypno/testing-lab": "^0.3.0" diff --git a/translate_docs.py b/translate_docs.py deleted file mode 100644 index 21190bb..0000000 --- a/translate_docs.py +++ /dev/null @@ -1,299 +0,0 @@ -#!/usr/bin/env python3 -""" -Comprehensive German to English translation for HypnoScript documentation. -This script performs sentence-by-sentence translation while preserving code blocks, -formatting, links, and technical terms. -""" - -import os -import re -from pathlib import Path -from typing import List, Tuple - -# Comprehensive translation dictionary -TRANSLATIONS = { - # Common full sentences - "Die folgenden Funktionen sind in der": "The following functions are available in the", - "verfügbar": "available", - "Bibliothek verfügbar": "library", - # Headers and common titles - "Übersicht": "Overview", - "Verfügbare Funktionen": "Available Functions", - "Grundlegende": "Basic", - "Erweiterte": "Advanced", - "Beispiele": "Examples", - "Verwendung": "Usage", - "Beschreibung": "Description", - "Parameter": "Parameters", - "Rückgabewert": "Return Value", - "Rückgabe": "Returns", - # Technical terms - "Berechnet": "Calculates", - "Gibt": "Returns", - "zurück": "", - "Prüft": "Checks", - "Konvertiert": "Converts", - "Erstellt": "Creates", - "Liest": "Reads", - "Schreibt": "Writes", - "Findet": "Finds", - "Sucht": "Searches", - "Extrahiert": "Extracts", - "Verkettet": "Concatenates", - "Macht": "Makes", - "Zeigt": "Shows", - "Führt": "Executes", - "Tokenisiert": "Tokenizes", - "Generiert": "Generates", - "Listet": "Lists", - "Lade": "Load", - "Entpacke": "Extract", - "Füge": "Add", - "hinzu": "", - "Nutze": "Use", - "Kopieren": "Copy", - "Ergänze": "Add", - # Common phrases - "aus den": "from the", - "das passende Archiv": "the appropriate archive", - "den Binärpfad deiner": "the binary path to your", - "Umgebungsvariable": "environment variable", - "die Installation mit": "the installation with", - "Die kompilierten Binaries findest du unter": "You'll find the compiled binaries under", - "Alle Subcommands sind bewusst schlank gehalten": "All subcommands are intentionally kept lean", - "Für einen tieferen Blick sieh dir die folgenden Abschnitte an": "For a deeper look, check out the following sections", - "Weitere Details liefert die Seite": "Further details are provided on the page", - "ohne Ausführung": "without execution", - "Bei Fehlern": "If there are errors", - "aktivieren": "enable", - "verschafft dir einen schnellen Überblick über": "gives you a quick overview of", - "die Standardbibliothek": "the standard library", - # Table headers - "Befehl": "Command", - "Kurzbeschreibung": "Brief Description", - "Kategorie": "Category", - "Funktion": "Function", - "Funktionen": "Functions", - # File/system terms - "Datei": "file", - "Dateien": "files", - "Verzeichnis": "directory", - "Verzeichnisse": "directories", - "Ordner": "folder", - # Common code comments - "Hilfe anzeigen": "Show help", - "Versionshinweis": "Version information", - "Programm ausführen": "Run a program", - "Optional installieren": "Optionally install", - "Type Checking": "Type checking", - "AST prüfen": "Check AST", - "Debug-Ausgabe": "Debug output", - "WASM generieren": "Generate WASM", - # Specific phrases in examples - "Willkommen bei HypnoScript": "Welcome to HypnoScript", - "Hallo Welt": "Hello World", - "Hallo": "Hello", - "Entwickler": "Developer", - "Summe": "Sum", - "Die Erinnerung wird jetzt intensiver": "The memory is now becoming more intense", -} - -# German patterns that need more context-aware translation -SENTENCE_PATTERNS = [ - (r"Die ([\w\s]+) ist", r"The \1 is"), - (r"Das ([\w\s]+) ist", r"The \1 is"), - (r"Der ([\w\s]+) ist", r"The \1 is"), - (r"Ein ([\w\s]+) ist", r"A \1 is"), - (r"Eine ([\w\s]+) ist", r"A \1 is"), -] - - -def is_code_line(line: str) -> bool: - """Check if a line is part of a code block marker.""" - return line.strip().startswith("```") - - -def translate_line(line: str, in_code_block: bool) -> str: - """Translate a single line while preserving structure.""" - if in_code_block or is_code_line(line): - return line - - # Don't translate if line is just a header marker, link, or special syntax - if line.strip().startswith("#") and "(" not in line: - # Translate header text - for de, en in TRANSLATIONS.items(): - line = line.replace(de, en) - return line - - # Don't translate URLs, code snippets, or technical markers - if any( - marker in line - for marker in ["http://", "https://", "`", "github.com", ".hyp", ".md"] - ): - # Only translate parts outside of links and code - parts = re.split(r"(\[.*?\]\(.*?\)|`.*?`|https?://\S+)", line) - translated_parts = [] - for part in parts: - if part.startswith("[") or part.startswith("`") or part.startswith("http"): - translated_parts.append(part) - else: - translated_part = part - for de, en in TRANSLATIONS.items(): - if de in translated_part: - translated_part = translated_part.replace(de, en) - translated_parts.append(translated_part) - return "".join(translated_parts) - - # Regular translation - translated = line - for de, en in TRANSLATIONS.items(): - if de in translated: - translated = translated.replace(de, en) - - # Apply pattern-based translations - for pattern, replacement in SENTENCE_PATTERNS: - translated = re.sub(pattern, replacement, translated) - - return translated - - -def translate_markdown_file(filepath: Path) -> str: - """Translate a markdown file from German to English.""" - print(f"Translating: {filepath.name}...", end=" ") - - try: - with open(filepath, "r", encoding="utf-8") as f: - lines = f.readlines() - except Exception as e: - print(f"ERROR reading: {e}") - return None - - translated_lines = [] - in_code_block = False - - for line in lines: - # Track code blocks - if line.strip().startswith("```"): - in_code_block = not in_code_block - translated_lines.append(line) - continue - - # Translate line - translated_line = translate_line(line, in_code_block) - translated_lines.append(translated_line) - - print("✓") - return "".join(translated_lines) - - -def process_directory(directory: Path, dry_run: bool = False): - """Process all markdown files in a directory.""" - if not directory.exists(): - print(f"Directory not found: {directory}") - return 0 - - md_files = sorted(directory.glob("*.md")) - if not md_files: - return 0 - - print( - f"\n{'[DRY RUN] ' if dry_run else ''}Processing {len(md_files)} files in {directory.name}/" - ) - - success_count = 0 - for md_file in md_files: - translated_content = translate_markdown_file(md_file) - - if translated_content and not dry_run: - try: - with open(md_file, "w", encoding="utf-8") as f: - f.write(translated_content) - success_count += 1 - except Exception as e: - print(f" ERROR writing {md_file.name}: {e}") - elif translated_content: - success_count += 1 - - return success_count - - -def main(): - """Main translation function.""" - import argparse - - parser = argparse.ArgumentParser( - description="Translate HypnoScript docs from German to English" - ) - parser.add_argument( - "--dry-run", - action="store_true", - help="Show what would be translated without writing", - ) - args = parser.parse_args() - - base_dir = Path(__file__).parent / "hypnoscript-docs" / "docs" - - if not base_dir.exists(): - print(f"ERROR: Documentation directory not found: {base_dir}") - return 1 - - # List of directories to translate - directories = [ - base_dir / "builtins", - base_dir / "cli", - base_dir / "debugging", - base_dir / "development", - base_dir / "error-handling", - base_dir / "examples", - base_dir / "reference", - base_dir / "tutorial-basics", - base_dir / "tutorial-extras", - ] - - # Root files - root_files = [ - base_dir / "index.md", - base_dir / "intro.md", - ] - - print("=" * 70) - print("HypnoScript Documentation Translation (German → English)") - print("=" * 70) - - if args.dry_run: - print("\n⚠️ DRY RUN MODE - No files will be modified\n") - - total_files = 0 - - # Process root files - print("\nProcessing root files...") - for file in root_files: - if file.exists(): - content = translate_markdown_file(file) - if content and not args.dry_run: - try: - with open(file, "w", encoding="utf-8") as f: - f.write(content) - total_files += 1 - except Exception as e: - print(f" ERROR writing {file.name}: {e}") - elif content: - total_files += 1 - - # Process directories - for directory in directories: - count = process_directory(directory, args.dry_run) - total_files += count - - print("\n" + "=" * 70) - if args.dry_run: - print(f"Would translate {total_files} files") - else: - print(f"Successfully translated {total_files} files") - print("=" * 70) - - return 0 - - -if __name__ == "__main__": - exit(main())