diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 0000000..3db316c --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,291 @@ +# WokeLang Roadmap + +> A human-centered, consent-driven programming language + +## Vision + +WokeLang aims to be a programming language that prioritizes: +- **Human readability** over machine optimization +- **Explicit consent** for sensitive operations +- **Gratitude and attribution** as first-class concepts +- **Emotional context** through emote annotations +- **Safety by default** with gentle error handling + +--- + +## Phase 1: Foundation (Current) ✅ + +### Core Language +- [x] EBNF grammar specification +- [x] Lexer with logos +- [x] Recursive descent parser +- [x] Complete AST types +- [x] Tree-walking interpreter + +### Basic Features +- [x] Functions with `to`/`give back` +- [x] Variables with `remember` +- [x] Conditionals with `when`/`otherwise` +- [x] Loops with `repeat...times` +- [x] Basic types: Int, Float, String, Bool, Array + +### Tooling +- [x] CLI (`woke` command) +- [x] Interactive REPL +- [x] WASM compilation +- [x] C/Zig FFI + +--- + +## Phase 2: Language Completeness (Q1 2025) + +### Type System +- [ ] Static type inference +- [ ] Generic types (`to map[T, U](list: [T], f: T -> U) -> [U]`) +- [ ] Union types (`String | Int`) +- [ ] Structural typing for records +- [ ] Unit types with compile-time checking + +### Pattern Matching +- [ ] Destructuring in `decide based on` +- [ ] Guard clauses +- [ ] Exhaustiveness checking +- [ ] Nested patterns + +### Module System +- [ ] Package management (`woke.toml`) +- [ ] Import/export with `use`/`share` +- [ ] Namespaces +- [ ] Circular dependency detection + +### Error Handling +- [ ] Result types (`Okay[T] | Oops[E]`) +- [ ] Error propagation operator (`?`) +- [ ] Stack traces with source locations +- [ ] Custom error types + +--- + +## Phase 3: Concurrency & Safety (Q2 2025) + +### Worker System +- [ ] True async workers +- [ ] Message passing between workers +- [ ] Worker pools +- [ ] Cancellation tokens + +### Side Quests +- [ ] Background task scheduling +- [ ] Progress reporting +- [ ] Resource cleanup + +### Superpowers +- [ ] Capability-based security +- [ ] Permission inheritance +- [ ] Audit logging +- [ ] Sandboxing + +### Consent System +- [ ] Persistent consent storage +- [ ] Scoped permissions +- [ ] Consent revocation +- [ ] Consent UI integration + +--- + +## Phase 4: Standard Library (Q3 2025) + +### Core Modules +- [ ] `std.io` - File I/O with consent +- [ ] `std.net` - Networking with consent +- [ ] `std.json` - JSON parsing/generation +- [ ] `std.time` - Date/time handling +- [ ] `std.math` - Mathematical functions +- [ ] `std.text` - String manipulation +- [ ] `std.collections` - Data structures + +### Consent-Aware Modules +- [ ] `std.fs` - Filesystem with permission checks +- [ ] `std.http` - HTTP client with URL consent +- [ ] `std.crypto` - Cryptography primitives +- [ ] `std.env` - Environment variables + +### Unit System +- [ ] `std.units.si` - SI units +- [ ] `std.units.imperial` - Imperial units +- [ ] `std.units.currency` - Currency types +- [ ] Automatic unit conversion +- [ ] Dimensional analysis + +--- + +## Phase 5: Compiler & Performance (Q4 2025) + +### WASM Target +- [ ] Full WASM feature support +- [ ] WASI integration +- [ ] Memory management +- [ ] String handling in WASM +- [ ] Array operations +- [ ] Exception handling + +### Native Compilation +- [ ] LLVM backend +- [ ] Native binaries +- [ ] Cross-compilation +- [ ] Link-time optimization + +### Optimizations +- [ ] Constant folding +- [ ] Dead code elimination +- [ ] Inlining +- [ ] Tail call optimization +- [ ] Loop unrolling + +--- + +## Phase 6: Tooling & Ecosystem (2026) + +### IDE Support +- [ ] VS Code extension + - Syntax highlighting + - Error diagnostics + - Auto-completion + - Go to definition + - Rename refactoring +- [ ] Language Server Protocol (LSP) +- [ ] Tree-sitter grammar +- [ ] Vim/Neovim plugin +- [ ] JetBrains plugin + +### Package Manager +- [ ] `woke pkg` command +- [ ] Central package registry +- [ ] Version resolution +- [ ] Lock files +- [ ] Security auditing + +### Testing +- [ ] Built-in test framework +- [ ] Property-based testing +- [ ] Mocking support +- [ ] Coverage reporting +- [ ] Benchmark suite + +### Documentation +- [ ] `woke doc` generator +- [ ] Inline documentation +- [ ] Example extraction +- [ ] API reference generation + +--- + +## Phase 7: Frameworks (2026+) + +### Web Framework (WokeWeb) +- [ ] HTTP server +- [ ] Routing with consent +- [ ] Middleware system +- [ ] Template engine +- [ ] WebSocket support +- [ ] Static file serving + +### CLI Framework (WokeCLI) +- [ ] Argument parsing +- [ ] Interactive prompts +- [ ] Progress bars +- [ ] Color output +- [ ] Configuration files + +### GUI Framework (WokeUI) +- [ ] Cross-platform windowing +- [ ] Declarative UI +- [ ] Event handling +- [ ] Theming +- [ ] Accessibility + +### Data Framework (WokeData) +- [ ] Database abstraction +- [ ] Query builder +- [ ] Migrations +- [ ] Connection pooling +- [ ] Consent-aware queries + +--- + +## Technical Milestones + +### Lexer Enhancements +| Feature | Status | Version | +|---------|--------|---------| +| Unicode identifiers | Planned | 0.3.0 | +| Heredoc strings | Planned | 0.3.0 | +| Raw strings | Planned | 0.3.0 | +| String interpolation | Planned | 0.4.0 | +| Custom operators | Planned | 0.5.0 | + +### Parser Enhancements +| Feature | Status | Version | +|---------|--------|---------| +| Error recovery | Planned | 0.3.0 | +| Incremental parsing | Planned | 0.5.0 | +| Macro expansion | Planned | 0.6.0 | +| Custom syntax | Planned | 1.0.0 | + +### Compiler Targets +| Target | Status | Version | +|--------|--------|---------| +| Tree-walking interpreter | ✅ Done | 0.1.0 | +| WASM (basic) | ✅ Done | 0.1.0 | +| WASM (full) | Planned | 0.4.0 | +| LLVM IR | Planned | 0.6.0 | +| Native (x86_64) | Planned | 0.7.0 | +| Native (ARM64) | Planned | 0.8.0 | + +### REPL Features +| Feature | Status | Version | +|---------|--------|---------| +| Basic evaluation | ✅ Done | 0.1.0 | +| History | ✅ Done | 0.1.0 | +| Multi-line input | Planned | 0.2.0 | +| Tab completion | Planned | 0.3.0 | +| Syntax highlighting | Planned | 0.4.0 | +| Debugger integration | Planned | 0.6.0 | + +--- + +## Version Timeline + +``` +2024 Q4 v0.1.0 Foundation release +2025 Q1 v0.2.0 Type system, modules +2025 Q2 v0.3.0 Concurrency, safety +2025 Q3 v0.4.0 Standard library +2025 Q4 v0.5.0 Optimizing compiler +2026 Q1 v0.6.0 IDE support, LSP +2026 Q2 v0.7.0 Package manager +2026 Q3 v0.8.0 Web framework +2026 Q4 v1.0.0 Stable release +``` + +--- + +## Contributing + +See [CONTRIBUTING.md](../CONTRIBUTING.md) for how to get involved. + +### Priority Areas +1. Standard library implementations +2. Documentation and examples +3. IDE tooling +4. Performance optimization +5. Security auditing + +--- + +## Links + +- [Language Specification](spec/language.md) +- [Wiki Home](wiki/Home.md) +- [API Reference](api/README.md) +- [Tutorials](tutorials/README.md) diff --git a/docs/wiki/Core-Concepts/Consent-System.md b/docs/wiki/Core-Concepts/Consent-System.md new file mode 100644 index 0000000..b17c43f --- /dev/null +++ b/docs/wiki/Core-Concepts/Consent-System.md @@ -0,0 +1,364 @@ +# Consent System + +WokeLang's consent system ensures sensitive operations require explicit permission. + +--- + +## Philosophy + +The consent system reflects WokeLang's core principle: **respect for user autonomy**. Before accessing sensitive resources or performing potentially impactful operations, programs must request consent. + +--- + +## Basic Syntax + +### Consent Blocks + +```wokelang +only if okay "permission_name" { + // Code that requires permission +} +``` + +**Components:** +- `only if okay` - Keyword phrase initiating consent request +- `"permission_name"` - String identifier for the permission +- `{ }` - Block of code requiring permission + +--- + +## Example Usage + +### File Access + +```wokelang +to saveUserData(data: String) { + only if okay "file_write" { + writeFile("data.txt", data); + print("Data saved successfully"); + } +} +``` + +### Camera Access + +```wokelang +to takePhoto() → Maybe String { + only if okay "camera_access" { + remember photo = captureFromCamera(); + give back photo; + } + give back none; +} +``` + +### Network Access + +```wokelang +to fetchData(url: String) { + only if okay "network_access" { + remember response = httpGet(url); + processResponse(response); + } +} +``` + +### Data Deletion + +```wokelang +@cautious +to deleteAllUserData() { + only if okay "delete_all_data" { + clearDatabase(); + clearCache(); + resetSettings(); + print("All data deleted"); + } +} +``` + +--- + +## Permission Categories + +### Standard Permissions + +| Permission | Description | Risk Level | +|------------|-------------|------------| +| `file_read` | Read files from disk | Low | +| `file_write` | Write files to disk | Medium | +| `camera_access` | Access camera | Medium | +| `microphone_access` | Access microphone | Medium | +| `location_access` | Access location data | Medium | +| `network_access` | Make network requests | Medium | +| `clipboard_access` | Read/write clipboard | Low | +| `notification_send` | Send notifications | Low | +| `delete_data` | Delete user data | High | +| `system_settings` | Modify system settings | High | + +### Custom Permissions + +Define application-specific permissions: + +```wokelang +only if okay "send_analytics" { + reportUsageMetrics(); +} + +only if okay "share_with_third_party" { + sendToPartnerAPI(data); +} + +only if okay "enable_experimental_features" { + activateBetaFeatures(); +} +``` + +--- + +## Consent Behavior + +### When Consent Is Requested + +1. **Runtime prompt**: User sees a consent dialog +2. **Choice**: User can grant or deny +3. **Execution**: Block runs only if granted +4. **Else clause** (optional): Alternative code runs if denied + +### With Fallback + +```wokelang +only if okay "camera_access" { + remember photo = takePhoto(); + displayPhoto(photo); +} otherwise { + print("Camera access denied - showing placeholder"); + displayPlaceholder(); +} +``` + +--- + +## Consent Storage + +### Persistent Consent (Planned) + +```wokelang +// Remember consent for future runs +only if okay "analytics" remember consent { + sendAnalytics(); +} + +// Consent valid for this session only +only if okay "camera" session_only { + takePhoto(); +} +``` + +### Consent Management (Planned) + +```wokelang +// Check consent status +remember hasConsent = checkConsent("camera_access"); + +// Revoke previously granted consent +revokeConsent("location_access"); + +// List all consents +remember consents = listConsents(); +``` + +--- + +## Scoped Permissions (Planned) + +### Time-Limited Consent + +```wokelang +only if okay "location_access" for 1 hour { + trackLocation(); +} +``` + +### Operation-Limited Consent + +```wokelang +only if okay "api_calls" limit 100 { + makeAPIRequest(); +} +``` + +--- + +## Nested Consent + +```wokelang +to processUserData() { + only if okay "read_user_data" { + remember data = loadUserData(); + + only if okay "send_to_cloud" { + uploadToCloud(data); + } + + only if okay "share_with_partners" { + sendToPartners(data); + } + } +} +``` + +--- + +## Combining with Emote Tags + +```wokelang +@cautious +@important +to deleteAccount() { + only if okay "delete_account" { + // User sees: "This action will permanently delete your account" + deleteAllData(); + closeAccount(); + print("Account deleted"); + } +} + +@experimental +to tryNewFeature() { + only if okay "experimental_features" { + // User sees: "This feature is experimental and may be unstable" + runExperiment(); + } +} +``` + +--- + +## Error Handling with Consent + +```wokelang +to saveImportantData(data: String) { + attempt safely { + only if okay "file_write" { + writeFile("important.txt", data); + } + } or reassure "Could not save data - permission may have been denied"; +} +``` + +--- + +## Testing with Consent + +### Mock Consent in Tests (Planned) + +```wokelang +test "file operations with consent" { + // Auto-grant all consents in test mode + withAutoConsent { + remember result = saveUserData("test"); + assert(result == success); + } +} + +test "behavior when consent denied" { + // Auto-deny specific consent + withDeniedConsent("file_write") { + remember result = saveUserData("test"); + assert(result == failure); + } +} +``` + +--- + +## Implementation Details + +### Current Implementation + +```rust +Statement::Consent { permission, body } => { + // Currently auto-grants (for development) + self.print(&format!("[consent requested: {}]", permission)); + self.execute_block(body) +} +``` + +### Planned Implementation + +```rust +Statement::Consent { permission, body, otherwise } => { + let granted = self.request_consent(permission)?; + + if granted { + self.execute_block(body) + } else if let Some(else_block) = otherwise { + self.execute_block(else_block) + } else { + Ok(ControlFlow::Continue) + } +} +``` + +--- + +## Best Practices + +### 1. Be Specific + +```wokelang +// Good: Specific permission +only if okay "send_email_to_contacts" { ... } + +// Bad: Too broad +only if okay "access_data" { ... } +``` + +### 2. Explain Purpose + +```wokelang +// Permission string should be clear +only if okay "use_location_for_weather" { + remember location = getLocation(); + showLocalWeather(location); +} +``` + +### 3. Graceful Degradation + +```wokelang +to getPhoto() → Maybe Image { + only if okay "camera" { + give back capturePhoto(); + } + // Falls through to return nothing if denied + give back none; +} +``` + +### 4. Minimal Scope + +```wokelang +// Good: Request only when needed +to shareIfWanted(data: String) { + only if okay "share" { + share(data); + } +} + +// Bad: Requesting permission for entire function +only if okay "share" { + to shareIfWanted(data: String) { + share(data); + } +} +``` + +--- + +## Next Steps + +- [Gratitude System](Gratitude.md) +- [Emote Tags](Emote-Tags.md) +- [Error Handling](../Language-Guide/Error-Handling.md) diff --git a/docs/wiki/Core-Concepts/Emote-Tags.md b/docs/wiki/Core-Concepts/Emote-Tags.md new file mode 100644 index 0000000..7a8c416 --- /dev/null +++ b/docs/wiki/Core-Concepts/Emote-Tags.md @@ -0,0 +1,459 @@ +# Emote Tags + +Emote tags provide emotional context and semantic meaning to WokeLang code. + +--- + +## Philosophy + +Code has emotional context. A function that deletes data should feel different from one that displays a welcome message. Emote tags make this context explicit, helping both humans and tools understand code intent. + +--- + +## Basic Syntax + +```wokelang +@tag_name +to functionName() { + // function body +} +``` + +### With Parameters + +```wokelang +@tag_name(param="value", other=123) +to functionName() { + // function body +} +``` + +--- + +## Standard Emote Tags + +### @important + +Marks critical code that requires special attention. + +```wokelang +@important +to validatePayment(amount: Float) → Bool { + // This code handles money - must be correct + when amount <= 0 { + give back false; + } + give back processPayment(amount); +} +``` + +**Use cases:** +- Security-sensitive operations +- Financial calculations +- Data integrity checks + +### @cautious + +Indicates code that should be approached carefully. + +```wokelang +@cautious +to deleteUserAccount(userId: String) { + only if okay "delete_account" { + removeFromDatabase(userId); + clearUserFiles(userId); + sendGoodbyeEmail(userId); + } +} +``` + +**Use cases:** +- Destructive operations +- Irreversible actions +- Data modifications + +### @experimental + +Marks unstable or work-in-progress code. + +```wokelang +@experimental(stability="alpha") +to newSearchAlgorithm(data: [Int]) → [Int] { + // This might change or be removed + give back experimentalSort(data); +} +``` + +**Use cases:** +- New features +- Proof of concepts +- A/B testing code + +### @deprecated + +Marks code that should no longer be used. + +```wokelang +@deprecated(reason="Use newFunction() instead", since="0.2.0") +to oldFunction() { + // Legacy code + newFunction(); +} +``` + +**Use cases:** +- Legacy APIs +- Renamed functions +- Superseded implementations + +### @happy + +Marks code with positive outcomes. + +```wokelang +@happy +to celebrateSuccess(user: String) { + print("Congratulations, " + user + "!"); + playConfetti(); + sendCelebrationEmail(user); +} +``` + +**Use cases:** +- Success handlers +- Achievement notifications +- Positive feedback + +### @sad + +Marks code dealing with negative outcomes. + +```wokelang +@sad +to handleFailure(error: String) { + print("Sorry, something went wrong: " + error); + logError(error); + offerHelp(); +} +``` + +**Use cases:** +- Error handlers +- Failure notifications +- Disappointment responses + +### @curious + +Marks exploratory or diagnostic code. + +```wokelang +@curious +to investigatePerformance() { + remember start = now(); + runBenchmark(); + remember duration = now() - start; + print("Benchmark took: " + toString(duration) + "ms"); +} +``` + +**Use cases:** +- Debugging code +- Profiling +- Logging +- Exploration + +--- + +## Custom Emote Tags + +Define your own tags for domain-specific semantics: + +```wokelang +@security_critical +to encryptData(data: String) → String { + // ... +} + +@user_facing +to displayWelcome(name: String) { + // ... +} + +@performance_sensitive +to processLargeDataset(data: [Int]) { + // ... +} + +@requires_network +to syncWithServer() { + // ... +} +``` + +--- + +## Tag Parameters + +### Stability Level + +```wokelang +@experimental(stability="alpha") +to alphaFeature() { } + +@experimental(stability="beta") +to betaFeature() { } +``` + +### Deprecation Info + +```wokelang +@deprecated( + reason="Replaced by newAPI", + since="0.2.0", + remove_in="1.0.0" +) +to oldAPI() { } +``` + +### Priority + +```wokelang +@important(priority=1) +to criticalFunction() { } + +@important(priority=2) +to lessUrgentFunction() { } +``` + +### Author Attribution + +```wokelang +@author(name="Jane Doe", date="2024-03-15") +to featureByJane() { } +``` + +--- + +## Multiple Tags + +Apply multiple tags to a single function: + +```wokelang +@important +@cautious +@deprecated(reason="Security concerns") +to riskyLegacyFunction() { + // Handle with extreme care +} +``` + +--- + +## Emote Tags on Other Constructs + +### On Workers + +```wokelang +@experimental +worker backgroundProcessor { + // ... +} +``` + +### On Side Quests + +```wokelang +@happy +side quest celebration { + playMusic(); + showFireworks(); +} +``` + +### On Type Definitions (Planned) + +```wokelang +@important +type SecureToken = String; +``` + +--- + +## Tooling Integration + +### IDE Support (Planned) + +Emote tags can trigger visual indicators: + +- `@important` → Red highlight +- `@cautious` → Yellow warning +- `@experimental` → Dashed underline +- `@deprecated` → Strikethrough +- `@happy` → Green accent +- `@sad` → Gray accent + +### Documentation Generation (Planned) + +```bash +woke doc --include-emotes +``` + +Generates documentation with emote context: + +```markdown +## deleteAccount + +⚠️ **Cautious** - This function should be approached carefully. + +🔒 **Requires consent** - `delete_account` + +Deletes a user's account and all associated data. +``` + +### Static Analysis (Planned) + +```bash +woke lint --check-deprecated +# Warning: Use of deprecated function 'oldAPI' at line 42 +``` + +--- + +## Best Practices + +### 1. Use Appropriate Tags + +```wokelang +// Good: Tag matches function behavior +@cautious +to deleteFile(path: String) { } + +// Misleading: Happy tag on destructive function +@happy // Don't do this +to deleteFile(path: String) { } +``` + +### 2. Add Context with Parameters + +```wokelang +// Better with reason +@deprecated(reason="Use formatCurrency() for locale support") +to formatMoney(amount: Float) → String { } +``` + +### 3. Combine Meaningfully + +```wokelang +// Good: Tags complement each other +@important +@cautious +to handleSensitiveData(data: String) { } + +// Confusing: Contradictory tags +@experimental +@deprecated // If deprecated, why still experimental? +to confusingFunction() { } +``` + +### 4. Document Custom Tags + +```wokelang +// Document what your custom tags mean +// @security_critical: Functions that handle encryption/auth +// @user_facing: Functions that produce user-visible output +// @requires_network: Functions that need internet connection + +@security_critical +to hashPassword(password: String) → String { } +``` + +--- + +## Implementation + +### AST Representation + +```rust +pub struct EmoteTag { + pub name: String, + pub params: Vec<(String, EmoteValue)>, +} + +pub enum EmoteValue { + String(String), + Number(f64), + Identifier(String), +} +``` + +### Parsing + +```rust +fn parse_emote_tag(&mut self) -> Result { + self.expect(Token::At)?; + let name = self.expect_identifier()?; + + let params = if self.match_token(Token::LeftParen) { + let p = self.parse_emote_params()?; + self.expect(Token::RightParen)?; + p + } else { + vec![] + }; + + Ok(EmoteTag { name, params }) +} +``` + +--- + +## Example: Complete Program + +```wokelang +thanks to { + "WokeLang" → "For emotive programming"; +} + +@happy +to main() { + hello "Welcome to the emote demo!"; + + // Call various emote-tagged functions + processUserData("Alice"); + + goodbye "Thanks for exploring emotes!"; +} + +@important +@cautious +to processUserData(name: String) { + only if okay "process_data" { + print("Processing data for: " + name); + saveSecurely(name); + } +} + +@deprecated(reason="Use saveSecurely instead") +to saveData(data: String) { + // Old implementation +} + +@experimental(stability="beta") +to saveSecurely(data: String) { + // New secure implementation + print("Saving securely: " + data); +} + +@curious +to debugInfo() { + print("Debug: checking system state"); +} +``` + +--- + +## Next Steps + +- [Consent System](Consent-System.md) +- [Gratitude System](Gratitude.md) +- [Functions](../Language-Guide/Functions.md) diff --git a/docs/wiki/Core-Concepts/Gratitude.md b/docs/wiki/Core-Concepts/Gratitude.md new file mode 100644 index 0000000..d4ba2a9 --- /dev/null +++ b/docs/wiki/Core-Concepts/Gratitude.md @@ -0,0 +1,354 @@ +# Gratitude System + +WokeLang's gratitude system makes attribution and acknowledgment first-class language features. + +--- + +## Philosophy + +The gratitude system reflects WokeLang's core value: **acknowledging contributions**. Code doesn't exist in isolation—it builds on the work of others. The gratitude system makes this visible and intentional. + +--- + +## Gratitude Blocks + +### Syntax + +```wokelang +thanks to { + "Contributor/Project" → "Reason for gratitude"; + "Another Contributor" → "Their contribution"; +} +``` + +### Example + +```wokelang +thanks to { + "Rust Community" → "For amazing systems programming tools"; + "Open Source Contributors" → "For countless hours of work"; + "My Mentors" → "For teaching me to code with care"; +} + +to main() { + print("Hello, World!"); +} +``` + +--- + +## Gratitude Expressions + +Express gratitude inline within code: + +```wokelang +to processData(data: String) { + remember result = thanks("Data Processing Team"); + + // Process the data with appreciation + transform(data); + + give back result; +} +``` + +--- + +## Use Cases + +### Project-Level Gratitude + +At the top of your main file: + +```wokelang +thanks to { + "Language Designers" → "For creating WokeLang"; + "Algorithm Authors" → "For the sorting algorithm used here"; + "testers" → "For finding bugs before users did"; +} +``` + +### Library Gratitude + +When using external code: + +```wokelang +thanks to { + "lodash maintainers" → "For utility functions"; + "date-fns team" → "For date handling"; +} + +use std.collections; +use external.datelib; +``` + +### Feature-Level Gratitude + +Acknowledge specific contributions: + +```wokelang +// This algorithm is based on work by Dr. Smith +thanks to { + "Dr. Jane Smith" → "For the efficient sorting algorithm in her 2023 paper"; +} + +to quickSort(arr: [Int]) → [Int] { + // Implementation based on Dr. Smith's research + ... +} +``` + +### Runtime Gratitude + +Express gratitude during execution: + +```wokelang +to main() { + print("Starting application..."); + + // Log gratitude at runtime + remember credit = thanks("Open Source Community"); + + print("Application powered by open source"); +} +``` + +--- + +## Gratitude Metadata + +### Planned Features + +```wokelang +thanks to { + "Project A" → { + reason: "Core algorithms", + url: "https://github.com/project-a", + license: "MIT" + }; + + "Person B" → { + reason: "Code review", + contribution_date: "2024-01-15" + }; +} +``` + +--- + +## Combining with Emote Tags + +```wokelang +@happy +thanks to { + "Community" → "For wonderful support"; +} + +@important +to main() { + hello "Starting with gratitude"; + + // The program runs with acknowledged dependencies + runApplication(); + + goodbye "Thanks for using this software"; +} +``` + +--- + +## Gratitude Reports + +### Planned Feature: Gratitude Export + +```bash +# Generate gratitude report +woke gratitude --format=markdown > ACKNOWLEDGMENTS.md + +# Generate as JSON +woke gratitude --format=json > gratitude.json +``` + +### Example Output + +```markdown +# Acknowledgments + +This project gratefully acknowledges: + +## Dependencies +- **Rust Community** - For amazing systems programming tools +- **Open Source Contributors** - For countless hours of work + +## Individuals +- **My Mentors** - For teaching me to code with care + +Generated by WokeLang v0.1.0 +``` + +--- + +## Integration with Package Management (Planned) + +```toml +# woke.toml +[package] +name = "my-app" +version = "1.0.0" + +[gratitude] +auto-include-dependencies = true +custom = [ + { name = "Dr. Smith", reason = "Algorithm research" } +] +``` + +--- + +## Best Practices + +### 1. Be Specific + +```wokelang +// Good: Specific acknowledgment +thanks to { + "React Team" → "For the component architecture pattern"; +} + +// Less helpful: Vague +thanks to { + "Everyone" → "For everything"; +} +``` + +### 2. Include Context + +```wokelang +thanks to { + "MDN Web Docs" → "For comprehensive JavaScript reference (consulted 2024)"; + "Stack Overflow" → "For the regex solution in parseEmail()"; +} +``` + +### 3. Update Regularly + +Keep gratitude blocks current as your project evolves. + +### 4. Acknowledge All Contributions + +```wokelang +thanks to { + // Code contributions + "Core Team" → "For implementation"; + + // Non-code contributions + "Documentation Team" → "For clear guides"; + "Translators" → "For i18n support"; + "Testers" → "For quality assurance"; + "Users" → "For valuable feedback"; +} +``` + +--- + +## Gratitude in the REPL + +``` +woke> thanks("Helpful colleague") +[thanks] Helpful colleague +() + +woke> :gratitude +Current session gratitude: + - Helpful colleague +``` + +--- + +## Implementation + +### Current Implementation + +```rust +// In parser +TopLevelItem::GratitudeBlock(GratitudeBlock { + entries: Vec<(String, String)>, +}) + +// In interpreter +fn execute_gratitude(&mut self, block: &GratitudeBlock) -> Result<()> { + for (name, reason) in &block.entries { + self.print(&format!("[gratitude] {} - {}", name, reason)); + } + Ok(()) +} + +// Gratitude expression +Expr::Gratitude(msg) => { + self.print(&format!("[thanks] {}", msg)); + Ok(Value::Unit) +} +``` + +--- + +## Cultural Significance + +The gratitude system acknowledges that: + +1. **Software is collaborative** - No code exists in isolation +2. **Attribution matters** - Credit should be visible +3. **Gratitude is healthy** - Acknowledging help improves culture +4. **History is valuable** - Understanding origins helps maintenance + +--- + +## Example: Complete Program + +```wokelang +// A complete WokeLang program with gratitude + +thanks to { + "WokeLang Team" → "For this wonderful language"; + "Tutorial Authors" → "For teaching me the basics"; + "Coffee" → "For keeping me awake"; +} + +#care on; + +@happy +to main() { + hello "Starting with gratitude"; + + remember message = buildMessage(); + print(message); + + // Express runtime gratitude + thanks("Users everywhere"); + + goodbye "Thanks for running this program"; +} + +to buildMessage() → String { + give back "Hello from a grateful program!"; +} +``` + +Output: +``` +[gratitude] WokeLang Team - For this wonderful language +[gratitude] Tutorial Authors - For teaching me the basics +[gratitude] Coffee - For keeping me awake +[hello] Starting with gratitude +Hello from a grateful program! +[thanks] Users everywhere +[goodbye] Thanks for running this program +``` + +--- + +## Next Steps + +- [Consent System](Consent-System.md) +- [Emote Tags](Emote-Tags.md) +- [Hello/Goodbye Lifecycle](../Language-Guide/Functions.md#lifecycle-messages) diff --git a/docs/wiki/Getting-Started/Basic-Syntax.md b/docs/wiki/Getting-Started/Basic-Syntax.md new file mode 100644 index 0000000..d094054 --- /dev/null +++ b/docs/wiki/Getting-Started/Basic-Syntax.md @@ -0,0 +1,322 @@ +# Basic Syntax + +This guide covers WokeLang's fundamental syntax elements. + +--- + +## Comments + +```wokelang +// Single-line comment + +/* Multi-line + comment */ +``` + +--- + +## Variables + +### Declaration with `remember` + +```wokelang +remember name = "Alice"; +remember age = 30; +remember pi = 3.14159; +remember isActive = true; +``` + +### Type Annotations (Optional) + +```wokelang +remember count: Int = 0; +remember message: String = "Hello"; +remember ratio: Float = 0.75; +remember flag: Bool = false; +``` + +### Assignment + +```wokelang +remember x = 10; +x = x + 5; // x is now 15 +``` + +--- + +## Data Types + +### Primitive Types + +| Type | Description | Examples | +|------|-------------|----------| +| `Int` | 64-bit integer | `42`, `-17`, `0` | +| `Float` | 64-bit float | `3.14`, `-0.5`, `1.0` | +| `String` | UTF-8 text | `"hello"`, `"line\n"` | +| `Bool` | Boolean | `true`, `false` | + +### Arrays + +```wokelang +remember numbers = [1, 2, 3, 4, 5]; +remember names = ["Alice", "Bob", "Charlie"]; +remember empty: [Int] = []; +``` + +### Unit Values (with measurements) + +```wokelang +remember distance = 100 measured in meters; +remember temp = 72 measured in fahrenheit; +remember speed = 60 measured in mph; +``` + +--- + +## Operators + +### Arithmetic + +```wokelang +remember sum = 5 + 3; // 8 +remember diff = 10 - 4; // 6 +remember product = 6 * 7; // 42 +remember quotient = 20 / 4; // 5 +remember remainder = 17 % 5; // 2 +remember negative = -42; +``` + +### Comparison + +```wokelang +remember eq = 5 == 5; // true +remember ne = 5 != 3; // true +remember lt = 3 < 5; // true +remember gt = 7 > 4; // true +remember le = 5 <= 5; // true +remember ge = 6 >= 6; // true +``` + +### Logical + +```wokelang +remember both = true and false; // false +remember either = true or false; // true +remember opposite = not true; // false +``` + +### String Concatenation + +```wokelang +remember greeting = "Hello, " + "World!"; // "Hello, World!" +``` + +--- + +## Control Flow + +### Conditionals with `when`/`otherwise` + +```wokelang +when score >= 90 { + print("Excellent!"); +} otherwise { + print("Keep trying!"); +} +``` + +### Loops with `repeat` + +```wokelang +repeat 5 times { + print("Hello!"); +} + +remember count = 3; +repeat count times { + print("Counting..."); +} +``` + +--- + +## Functions + +### Basic Definition + +```wokelang +to greet() { + print("Hello!"); +} +``` + +### With Parameters + +```wokelang +to greet(name: String) { + print("Hello, " + name + "!"); +} +``` + +### With Return Type + +```wokelang +to add(a: Int, b: Int) → Int { + give back a + b; +} +``` + +### Calling Functions + +```wokelang +greet(); +greet("Alice"); +remember result = add(3, 5); +``` + +--- + +## Error Handling + +### Attempt Blocks + +```wokelang +attempt safely { + remember data = riskyOperation(); + processData(data); +} or reassure "Operation failed, but we're okay"; +``` + +### Complain Statement + +```wokelang +when value < 0 { + complain "Value must be non-negative"; +} +``` + +--- + +## Consent Blocks + +```wokelang +only if okay "camera_access" { + remember photo = takePhoto(); + save(photo); +} +``` + +--- + +## Pattern Matching + +```wokelang +decide based on status { + "success" → { + print("It worked!"); + } + "pending" → { + print("Still waiting..."); + } + _ → { + print("Unknown status"); + } +} +``` + +--- + +## Emote Tags + +```wokelang +@important +to deleteAllData() { + only if okay "delete_all" { + clearDatabase(); + } +} + +@experimental(stability="alpha") +to newFeature() { + // Experimental code +} +``` + +--- + +## Gratitude + +```wokelang +thanks to { + "Open Source Community" → "For amazing tools"; + "Contributors" → "For valuable feedback"; +} +``` + +--- + +## Pragmas + +```wokelang +#care on; // Enable extra safety checks +#verbose on; // Enable verbose output +#strict on; // Enable strict type checking +``` + +--- + +## Complete Example + +```wokelang +// Calculator example +#care on; + +thanks to { + "Math" → "For making sense of numbers"; +} + +@important +to main() { + hello "Calculator starting up"; + + remember a = 10; + remember b = 5; + + print("Addition: " + toString(add(a, b))); + print("Subtraction: " + toString(subtract(a, b))); + print("Multiplication: " + toString(multiply(a, b))); + + attempt safely { + print("Division: " + toString(divide(a, b))); + } or reassure "Division failed"; + + goodbye "Calculations complete"; +} + +to add(x: Int, y: Int) → Int { + give back x + y; +} + +to subtract(x: Int, y: Int) → Int { + give back x - y; +} + +to multiply(x: Int, y: Int) → Int { + give back x * y; +} + +to divide(x: Int, y: Int) → Int { + when y == 0 { + complain "Division by zero"; + } + give back x / y; +} +``` + +--- + +## Next Steps + +- [Functions](../Language-Guide/Functions.md) - Advanced function features +- [Control Flow](../Language-Guide/Control-Flow.md) - Detailed control structures +- [Error Handling](../Language-Guide/Error-Handling.md) - Robust error management diff --git a/docs/wiki/Getting-Started/Hello-World.md b/docs/wiki/Getting-Started/Hello-World.md new file mode 100644 index 0000000..46ae3e7 --- /dev/null +++ b/docs/wiki/Getting-Started/Hello-World.md @@ -0,0 +1,144 @@ +# Hello, World! + +Let's write your first WokeLang program. + +--- + +## Your First Program + +Create a file called `hello.woke`: + +```wokelang +to main() { + hello "Welcome to WokeLang!"; + + print("Hello, World!"); + + goodbye "Thanks for running me!"; +} +``` + +Run it: + +```bash +woke hello.woke +``` + +Output: +``` +[hello] Welcome to WokeLang! +Hello, World! +[goodbye] Thanks for running me! +``` + +--- + +## Understanding the Code + +### Function Definition + +```wokelang +to main() { + // code here +} +``` + +- `to` declares a function +- `main()` is the entry point (like C/Rust) +- Code goes inside `{ }` + +### Lifecycle Messages + +```wokelang +hello "Welcome to WokeLang!"; +goodbye "Thanks for running me!"; +``` + +- `hello` runs when a function starts +- `goodbye` runs when it ends +- These are optional but encouraged for meaningful functions + +### Printing Output + +```wokelang +print("Hello, World!"); +``` + +- `print()` outputs to the console +- Strings use double quotes `""` + +--- + +## A More Complete Example + +```wokelang +// Gratitude block - acknowledge contributors +thanks to { + "WokeLang Community" → "For believing in kind code"; +} + +// Main function with emote tag +@happy +to main() { + hello "Starting the greeting program"; + + remember name = "Developer"; + remember greeting = greet(name); + + print(greeting); + + goodbye "Hope you enjoyed this!"; +} + +// Helper function with return type +to greet(name: String) → String { + give back "Hello, " + name + "! Welcome to WokeLang!"; +} +``` + +--- + +## Key Concepts Introduced + +| Concept | Syntax | Purpose | +|---------|--------|---------| +| Function | `to name() { }` | Define reusable code | +| Variable | `remember x = value;` | Store data | +| Return | `give back value;` | Return from function | +| Hello/Goodbye | `hello "msg";` | Lifecycle hooks | +| Comments | `// comment` | Documentation | +| Emote Tags | `@happy` | Emotional context | +| Gratitude | `thanks to { }` | Attribution | + +--- + +## Try the REPL + +For quick experimentation, use the interactive REPL: + +```bash +woke repl +``` + +``` +WokeLang REPL v0.1.0 +Type :help for commands, :quit to exit + +woke> print("Hello from REPL!") +Hello from REPL! + +woke> remember x = 42 +woke> print(x * 2) +84 + +woke> :quit +Goodbye! Thanks for using WokeLang. +``` + +--- + +## Next Steps + +- [Basic Syntax](Basic-Syntax.md) - Learn variables, types, and operators +- [Functions](../Language-Guide/Functions.md) - Deep dive into functions +- [REPL Guide](REPL.md) - Master the interactive environment diff --git a/docs/wiki/Getting-Started/Installation.md b/docs/wiki/Getting-Started/Installation.md new file mode 100644 index 0000000..781abca --- /dev/null +++ b/docs/wiki/Getting-Started/Installation.md @@ -0,0 +1,157 @@ +# Installation + +This guide covers how to install WokeLang on your system. + +--- + +## Requirements + +- **Rust** 1.70 or later (for building from source) +- **Cargo** (comes with Rust) +- A terminal/command-line interface + +--- + +## Installation Methods + +### From Source (Recommended) + +1. **Clone the repository:** +```bash +git clone https://github.com/hyperpolymath/wokelang.git +cd wokelang +``` + +2. **Build the project:** +```bash +cargo build --release +``` + +3. **Install the binary:** +```bash +cargo install --path . +``` + +This installs the `woke` command to `~/.cargo/bin/`. + +### Verify Installation + +```bash +woke --version +# Output: woke 0.1.0 +``` + +--- + +## Build Targets + +### Standard Binary + +```bash +cargo build --release +# Binary at: target/release/woke +``` + +### Shared Library (for FFI) + +```bash +cargo build --release +# Produces: +# target/release/libwokelang.so (Linux) +# target/release/libwokelang.dylib (macOS) +# target/release/wokelang.dll (Windows) +``` + +### Static Library + +```bash +cargo build --release +# Produces: target/release/libwokelang.a +``` + +### WASM Build + +For WebAssembly compilation target: + +```bash +cargo build --release --target wasm32-unknown-unknown +``` + +--- + +## Platform Support + +| Platform | Status | Notes | +|----------|--------|-------| +| Linux (x86_64) | Fully supported | Primary development platform | +| macOS (x86_64) | Fully supported | | +| macOS (ARM64) | Fully supported | Apple Silicon | +| Windows (x86_64) | Supported | May require Visual Studio Build Tools | +| WebAssembly | Experimental | Via `woke compile --wasm` | + +--- + +## Directory Structure + +After installation, the WokeLang project has this structure: + +``` +wokelang/ +├── src/ +│ ├── lexer/ # Tokenizer +│ ├── parser/ # Recursive descent parser +│ ├── ast/ # Abstract syntax tree types +│ ├── interpreter/# Tree-walking interpreter +│ ├── codegen/ # WASM compiler +│ ├── ffi/ # C/Zig FFI bindings +│ └── main.rs # CLI entry point +├── grammar/ # EBNF specification +├── examples/ # Example programs +├── include/ # C header files +├── zig/ # Zig bindings +└── docs/ # Documentation +``` + +--- + +## Troubleshooting + +### "command not found: woke" + +Ensure `~/.cargo/bin` is in your PATH: + +```bash +export PATH="$HOME/.cargo/bin:$PATH" +``` + +Add this to your shell configuration file (`.bashrc`, `.zshrc`, etc.). + +### Build Errors + +1. **Update Rust:** +```bash +rustup update +``` + +2. **Clean and rebuild:** +```bash +cargo clean +cargo build --release +``` + +### Missing Dependencies + +The project requires these crates (automatically downloaded by Cargo): +- `logos` - Lexer generator +- `thiserror` - Error handling +- `miette` - Diagnostic formatting +- `rustyline` - REPL line editing +- `wasm-encoder` - WASM code generation + +--- + +## Next Steps + +- [Hello, World!](Hello-World.md) - Write your first WokeLang program +- [Basic Syntax](Basic-Syntax.md) - Learn the fundamentals +- [REPL Guide](REPL.md) - Interactive development diff --git a/docs/wiki/Getting-Started/REPL.md b/docs/wiki/Getting-Started/REPL.md new file mode 100644 index 0000000..b5b9f68 --- /dev/null +++ b/docs/wiki/Getting-Started/REPL.md @@ -0,0 +1,303 @@ +# REPL Guide + +The WokeLang REPL (Read-Eval-Print Loop) provides an interactive environment for experimenting with the language. + +--- + +## Starting the REPL + +```bash +woke repl +``` + +``` +WokeLang REPL v0.1.0 +Type :help for commands, :quit to exit + +woke> +``` + +--- + +## Basic Usage + +### Evaluating Expressions + +``` +woke> 2 + 2 +4 + +woke> "Hello" + " " + "World" +Hello World + +woke> 10 * 5 + 3 +53 +``` + +### Declaring Variables + +``` +woke> remember x = 42 +woke> remember y = 8 +woke> x + y +50 + +woke> remember name = "Alice" +woke> print("Hello, " + name) +Hello, Alice +``` + +### Defining Functions + +``` +woke> to double(n: Int) → Int { give back n * 2; } +woke> double(21) +42 + +woke> to greet(name: String) { print("Hi, " + name + "!"); } +woke> greet("Bob") +Hi, Bob! +``` + +--- + +## REPL Commands + +| Command | Description | +|---------|-------------| +| `:help` | Show available commands | +| `:quit` or `:q` | Exit the REPL | +| `:reset` | Clear all defined variables and functions | +| `:load ` | Load and execute a .woke file | +| `:ast ` | Show the AST for an expression | + +### :help + +``` +woke> :help +WokeLang REPL Commands: + :help Show this help message + :quit, :q Exit the REPL + :reset Clear interpreter state + :load Load a WokeLang file + :ast Show AST for expression +``` + +### :load + +``` +woke> :load examples/math.woke +Loaded examples/math.woke + +woke> factorial(5) +120 +``` + +### :ast + +``` +woke> :ast 2 + 3 * 4 +Binary { + left: Literal(Int(2)), + op: Add, + right: Binary { + left: Literal(Int(3)), + op: Mul, + right: Literal(Int(4)) + } +} +``` + +### :reset + +``` +woke> remember secret = 42 +woke> secret +42 + +woke> :reset +State cleared. + +woke> secret +Error: Undefined variable: secret +``` + +--- + +## Multi-line Input + +For multi-line definitions, the REPL detects incomplete input: + +``` +woke> to factorial(n: Int) → Int { +...> when n <= 1 { +...> give back 1; +...> } otherwise { +...> give back n * factorial(n - 1); +...> } +...> } + +woke> factorial(10) +3628800 +``` + +The prompt changes to `...>` when waiting for more input. + +--- + +## Working with Types + +### Checking Values + +``` +woke> remember x = 42 +woke> x +42 + +woke> remember arr = [1, 2, 3] +woke> arr +[1, 2, 3] + +woke> len(arr) +3 +``` + +### Type Conversions + +``` +woke> toString(42) +42 + +woke> toInt("123") +123 + +woke> toFloat(42) +42.0 +``` + +--- + +## Error Handling in REPL + +The REPL gracefully handles errors: + +``` +woke> 1 / 0 +Error: Division by zero + +woke> undefinedVar +Error: Undefined variable: undefinedVar + +woke> to broken( { } +Error: Parse error at line 1: Expected ')' or parameter +``` + +Errors don't crash the REPL - just fix and try again. + +--- + +## Tips and Tricks + +### Quick Calculations + +``` +woke> 2 ** 10 +1024 + +woke> 100 * 1.08 +108.0 + +woke> (10 + 20) * 3 +90 +``` + +### Testing Functions Before Saving + +``` +woke> to isPrime(n: Int) → Bool { +...> when n <= 1 { give back false; } +...> remember i = 2; +...> repeat (n - 2) times { +...> when n % i == 0 { give back false; } +...> i = i + 1; +...> } +...> give back true; +...> } + +woke> isPrime(7) +true + +woke> isPrime(10) +false +``` + +### Exploring Built-in Functions + +``` +woke> print("test") +test + +woke> len("hello") +5 + +woke> len([1, 2, 3, 4]) +4 + +woke> toString(3.14159) +3.14159 +``` + +--- + +## Keyboard Shortcuts + +| Shortcut | Action | +|----------|--------| +| `Ctrl+C` | Cancel current input | +| `Ctrl+D` | Exit REPL (same as :quit) | +| `Up/Down` | Navigate history | +| `Ctrl+R` | Reverse search history | +| `Tab` | Auto-complete (planned) | + +--- + +## Session Example + +Here's a complete REPL session: + +``` +$ woke repl +WokeLang REPL v0.1.0 +Type :help for commands, :quit to exit + +woke> // Let's explore WokeLang! + +woke> remember greeting = "Hello, WokeLang!" +woke> print(greeting) +Hello, WokeLang! + +woke> to fib(n: Int) → Int { +...> when n <= 1 { +...> give back n; +...> } otherwise { +...> give back fib(n - 1) + fib(n - 2); +...> } +...> } + +woke> fib(10) +55 + +woke> remember results = [0, 0, 0, 0, 0] +woke> // Arrays and iteration coming in v0.2.0! + +woke> :quit +Goodbye! Thanks for using WokeLang. +``` + +--- + +## Next Steps + +- [First Program](First-Program.md) - Writing complete programs +- [CLI Reference](../Reference/CLI.md) - Full command-line options +- [Debugging](../Tooling/Debugger.md) - Debugging techniques diff --git a/docs/wiki/Home.md b/docs/wiki/Home.md new file mode 100644 index 0000000..7938913 --- /dev/null +++ b/docs/wiki/Home.md @@ -0,0 +1,159 @@ +# WokeLang Wiki + +> *A human-centered, consent-driven programming language* + +Welcome to the WokeLang documentation wiki. This wiki provides comprehensive documentation for learning, using, and contributing to WokeLang. + +--- + +## Quick Links + +| Getting Started | Reference | Advanced | +|-----------------|-----------|----------| +| [Installation](Getting-Started/Installation.md) | [Language Spec](Reference/Language-Specification.md) | [Compiler Internals](Internals/Compiler.md) | +| [Hello World](Getting-Started/Hello-World.md) | [Built-in Functions](Reference/Builtin-Functions.md) | [Parser Design](Internals/Parser.md) | +| [Basic Syntax](Getting-Started/Basic-Syntax.md) | [Standard Library](Reference/Standard-Library.md) | [WASM Target](Internals/WASM-Compilation.md) | +| [REPL Guide](Getting-Started/REPL.md) | [CLI Reference](Reference/CLI.md) | [FFI Guide](Internals/FFI.md) | + +--- + +## Table of Contents + +### 1. Getting Started +- [Installation](Getting-Started/Installation.md) +- [Hello World](Getting-Started/Hello-World.md) +- [Basic Syntax](Getting-Started/Basic-Syntax.md) +- [Using the REPL](Getting-Started/REPL.md) +- [Your First Program](Getting-Started/First-Program.md) + +### 2. Language Guide +- [Variables and Types](Language-Guide/Variables-and-Types.md) +- [Functions](Language-Guide/Functions.md) +- [Control Flow](Language-Guide/Control-Flow.md) +- [Pattern Matching](Language-Guide/Pattern-Matching.md) +- [Error Handling](Language-Guide/Error-Handling.md) +- [Modules and Imports](Language-Guide/Modules.md) + +### 3. Core Concepts +- [The Consent System](Core-Concepts/Consent-System.md) +- [Gratitude and Attribution](Core-Concepts/Gratitude.md) +- [Emote Tags](Core-Concepts/Emote-Tags.md) +- [Unit System](Core-Concepts/Unit-System.md) +- [Workers and Concurrency](Core-Concepts/Concurrency.md) + +### 4. Reference +- [Language Specification](Reference/Language-Specification.md) +- [Built-in Functions](Reference/Builtin-Functions.md) +- [Operators](Reference/Operators.md) +- [Keywords](Reference/Keywords.md) +- [Standard Library](Reference/Standard-Library.md) +- [CLI Reference](Reference/CLI.md) + +### 5. Tooling +- [Compiler](Tooling/Compiler.md) +- [Interpreter](Tooling/Interpreter.md) +- [REPL](Tooling/REPL.md) +- [Debugger](Tooling/Debugger.md) +- [Package Manager](Tooling/Package-Manager.md) +- [IDE Support](Tooling/IDE-Support.md) + +### 6. Internals +- [Architecture Overview](Internals/Architecture.md) +- [Lexer Design](Internals/Lexer.md) +- [Parser Design](Internals/Parser.md) +- [AST Structure](Internals/AST.md) +- [Interpreter](Internals/Interpreter.md) +- [Compiler](Internals/Compiler.md) +- [WASM Compilation](Internals/WASM-Compilation.md) +- [FFI](Internals/FFI.md) + +### 7. Tutorials +- [Building a CLI App](Tutorials/CLI-App.md) +- [Web Server with WokeLang](Tutorials/Web-Server.md) +- [Data Processing](Tutorials/Data-Processing.md) +- [Testing Your Code](Tutorials/Testing.md) +- [Embedding WokeLang](Tutorials/Embedding.md) + +### 8. Frameworks +- [WokeWeb (HTTP)](Frameworks/WokeWeb.md) +- [WokeCLI (Command Line)](Frameworks/WokeCLI.md) +- [WokeTest (Testing)](Frameworks/WokeTest.md) +- [WokeData (Database)](Frameworks/WokeData.md) + +### 9. Contributing +- [Development Setup](Contributing/Development-Setup.md) +- [Code Style](Contributing/Code-Style.md) +- [Testing Guidelines](Contributing/Testing.md) +- [Documentation](Contributing/Documentation.md) +- [Release Process](Contributing/Release-Process.md) + +--- + +## Philosophy + +WokeLang is built on these core principles: + +### 1. Consent First +Every sensitive operation requires explicit consent. No hidden file access, no silent network calls, no surprise data collection. + +```wokelang +only if okay "read_contacts" { + remember contacts = loadContacts(); +} +``` + +### 2. Gratitude Built-In +Attribution isn't an afterthought—it's a language feature. Give credit where credit is due. + +```wokelang +thanks to { + "Alice" → "Algorithm design"; + "Bob" → "Performance optimization"; +} +``` + +### 3. Emotional Context +Code has emotional weight. Emote tags let you annotate intent and mood. + +```wokelang +@cautious +to deleteUserData(userId: String) { + // This is a sensitive operation +} +``` + +### 4. Human-Readable Syntax +Code should read like natural language where possible. + +```wokelang +repeat 5 times { + print("Hello!"); +} + +when temperature > 100 { + complain "It's too hot!"; +} +``` + +### 5. Safety by Default +Errors are handled gently. The language guides you toward safe patterns. + +```wokelang +attempt safely { + remember data = fetchData(); +} or reassure "We'll try again later"; +``` + +--- + +## Community + +- **GitHub**: [github.com/hyperpolymath/wokelang](https://github.com/hyperpolymath/wokelang) +- **Discord**: Coming soon +- **Forum**: Coming soon + +--- + +## License + +WokeLang is open source under the MIT License. diff --git a/docs/wiki/Internals/Architecture.md b/docs/wiki/Internals/Architecture.md new file mode 100644 index 0000000..95d13c6 --- /dev/null +++ b/docs/wiki/Internals/Architecture.md @@ -0,0 +1,405 @@ +# Architecture Overview + +This document describes the internal architecture of the WokeLang implementation. + +--- + +## High-Level Pipeline + +``` +Source Code (.woke) + │ + ▼ + ┌─────────┐ + │ Lexer │ ─── Tokenization + └────┬────┘ + │ Vec + ▼ + ┌─────────┐ + │ Parser │ ─── Syntax Analysis + └────┬────┘ + │ AST (Program) + ▼ + ┌─────────────────────────┐ + │ Execution Target │ + ├─────────────────────────┤ + │ ┌─────────────────────┐ │ + │ │ Interpreter │ │ ─── Tree-walking execution + │ └─────────────────────┘ │ + │ ┌─────────────────────┐ │ + │ │ WASM Compiler │ │ ─── WebAssembly compilation + │ └─────────────────────┘ │ + └─────────────────────────┘ +``` + +--- + +## Module Structure + +``` +src/ +├── lib.rs # Library exports +├── main.rs # CLI entry point +├── repl.rs # Interactive REPL +│ +├── lexer/ +│ ├── mod.rs # Lexer implementation +│ └── token.rs # Token types (logos-derived) +│ +├── parser/ +│ └── mod.rs # Recursive descent parser +│ +├── ast/ +│ └── mod.rs # AST node types +│ +├── interpreter/ +│ ├── mod.rs # Tree-walking interpreter +│ └── value.rs # Runtime value types +│ +├── codegen/ +│ └── wasm.rs # WASM code generator +│ +└── ffi/ + └── c_api.rs # C-compatible FFI +``` + +--- + +## Component Details + +### 1. Lexer (`src/lexer/`) + +**Purpose**: Convert source text into a stream of tokens. + +**Implementation**: Uses the `logos` crate for efficient lexer generation. + +```rust +#[derive(Logos, Debug, Clone, PartialEq)] +pub enum Token { + #[token("to")] + To, + + #[token("remember")] + Remember, + + #[regex(r"[a-zA-Z_][a-zA-Z0-9_]*")] + Identifier, + + #[regex(r"-?[0-9]+", |lex| lex.slice().parse().ok())] + Integer(i64), + + // ... +} +``` + +**Output**: `Vec>` where `Spanned = (T, Range)` + +### 2. Parser (`src/parser/`) + +**Purpose**: Build an Abstract Syntax Tree from tokens. + +**Implementation**: Hand-written recursive descent parser with Pratt parsing for expressions. + +```rust +impl Parser { + pub fn parse(&mut self) -> Result { + let mut items = Vec::new(); + while !self.is_at_end() { + items.push(self.parse_top_level_item()?); + } + Ok(Program { items }) + } + + fn parse_expression(&mut self) -> Result { + self.parse_or_expr() // Lowest precedence + } + + fn parse_or_expr(&mut self) -> Result { + let mut left = self.parse_and_expr()?; + while self.match_token(Token::Or) { + let right = self.parse_and_expr()?; + left = Expr::Binary { left, op: BinOp::Or, right }; + } + Ok(left) + } + // ... cascading precedence levels +} +``` + +**Output**: `Program` containing `Vec` + +### 3. AST (`src/ast/`) + +**Purpose**: Define the tree structure representing parsed code. + +**Key Types**: + +```rust +pub struct Program { + pub items: Vec, +} + +pub enum TopLevelItem { + Function(Function), + Worker(Worker), + SideQuest(SideQuest), + TypeDef(TypeDef), + GratitudeBlock(GratitudeBlock), + Pragma(Pragma), + Import(Import), +} + +pub enum Statement { + Remember { name: String, type_ann: Option, value: Expr, unit: Option }, + Assignment { target: String, value: Expr }, + Return { value: Expr }, + When { condition: Expr, then_block: Vec, else_block: Option> }, + Repeat { count: Expr, body: Vec }, + // ... +} + +pub enum Expr { + Literal(Literal), + Identifier(String), + Binary { left: Box, op: BinOp, right: Box }, + Unary { op: UnaryOp, operand: Box }, + Call { function: String, args: Vec }, + // ... +} +``` + +### 4. Interpreter (`src/interpreter/`) + +**Purpose**: Execute the AST directly via tree-walking. + +**Key Components**: + +```rust +pub struct Interpreter { + environments: Vec, // Scope stack + functions: HashMap, + output: Vec, +} + +impl Interpreter { + pub fn run(&mut self, program: &Program) -> Result { + // Register functions + for item in &program.items { + if let TopLevelItem::Function(f) = item { + self.functions.insert(f.name.clone(), f.clone()); + } + } + + // Call main if it exists + if let Some(main) = self.functions.get("main").cloned() { + self.call_function(&main, vec![]) + } else { + Ok(Value::Unit) + } + } + + fn eval_expr(&mut self, expr: &Expr) -> Result { + match expr { + Expr::Literal(lit) => self.eval_literal(lit), + Expr::Binary { left, op, right } => { + let l = self.eval_expr(left)?; + let r = self.eval_expr(right)?; + self.eval_binary_op(op, l, r) + } + // ... + } + } +} +``` + +**Runtime Values**: + +```rust +pub enum Value { + Int(i64), + Float(f64), + String(String), + Bool(bool), + Array(Vec), + Unit, +} +``` + +### 5. WASM Compiler (`src/codegen/wasm.rs`) + +**Purpose**: Compile WokeLang functions to WebAssembly. + +**Implementation**: Uses `wasm-encoder` crate for binary generation. + +```rust +pub struct WasmCompiler { + module: wasm_encoder::Module, + type_section: TypeSection, + function_section: FunctionSection, + code_section: CodeSection, + // ... +} + +impl WasmCompiler { + pub fn compile(&mut self, program: &Program) -> Result> { + // Collect functions + for item in &program.items { + if let TopLevelItem::Function(f) = item { + self.compile_function(f)?; + } + } + + // Build module + self.module.section(&self.type_section); + self.module.section(&self.function_section); + self.module.section(&self.code_section); + + Ok(self.module.finish()) + } +} +``` + +### 6. FFI (`src/ffi/c_api.rs`) + +**Purpose**: Expose WokeLang to C, Zig, and other languages. + +**Key Exports**: + +```rust +#[no_mangle] +pub extern "C" fn woke_interpreter_new() -> *mut WokeInterpreter; + +#[no_mangle] +pub unsafe extern "C" fn woke_exec( + interp: *mut WokeInterpreter, + source: *const c_char +) -> WokeResult; + +#[no_mangle] +pub unsafe extern "C" fn woke_value_as_int( + value: *const WokeValue, + out: *mut c_longlong +) -> WokeResult; +``` + +--- + +## Data Flow + +### Interpretation Flow + +``` +1. Source: "remember x = 2 + 3;" + +2. Lexer Output: + [Remember, Identifier("x"), Equals, Integer(2), Plus, Integer(3), Semicolon] + +3. Parser Output: + Statement::Remember { + name: "x", + value: Expr::Binary { + left: Expr::Literal(Int(2)), + op: BinOp::Add, + right: Expr::Literal(Int(3)) + } + } + +4. Interpreter: + - Evaluates Binary(2, Add, 3) → Value::Int(5) + - Stores ("x", Value::Int(5)) in current environment +``` + +### WASM Compilation Flow + +``` +1. Source: "to add(a: Int, b: Int) → Int { give back a + b; }" + +2. Parser → Function AST + +3. WASM Compiler: + - Creates function type: (i64, i64) → i64 + - Generates instructions: + local.get 0 ; Get 'a' + local.get 1 ; Get 'b' + i64.add ; Add them + return ; Return result + +4. Output: Binary .wasm module +``` + +--- + +## Error Handling + +### Error Types + +```rust +#[derive(Error, Debug, Diagnostic)] +pub enum WokeError { + #[error("Lexer error: {message}")] + LexError { message: String, span: Range }, + + #[error("Parse error: {message}")] + ParseError { message: String, span: Range }, + + #[error("Runtime error: {message}")] + RuntimeError { message: String }, + + #[error("Type error: {message}")] + TypeError { message: String }, +} +``` + +### Error Recovery + +The parser attempts to recover from errors to report multiple issues: + +```rust +fn synchronize(&mut self) { + while !self.is_at_end() { + if self.previous().0 == Token::Semicolon { + return; + } + match self.peek().0 { + Token::To | Token::Remember | Token::When => return, + _ => self.advance(), + } + } +} +``` + +--- + +## Memory Management + +- **Interpreter**: Uses Rust's ownership system; values are cloned when necessary +- **WASM**: Linear memory model with explicit allocation +- **FFI**: Box-based heap allocation with explicit free functions + +--- + +## Threading Model + +Currently single-threaded. Planned concurrency: + +- **Workers**: Will use async/await or thread pools +- **Side Quests**: Background task queue +- **Superpowers**: Capability-based permission system + +--- + +## Extension Points + +1. **New Syntax**: Add tokens to lexer, parsing rules to parser +2. **New Built-ins**: Add to `Interpreter::call_builtin()` +3. **New Targets**: Implement trait for code generation +4. **New FFI**: Add `extern "C"` functions to `c_api.rs` + +--- + +## Next Steps + +- [Lexer Internals](Lexer.md) +- [Parser Internals](Parser.md) +- [Interpreter Internals](Interpreter.md) +- [WASM Compilation](WASM-Compilation.md) diff --git a/docs/wiki/Internals/FFI.md b/docs/wiki/Internals/FFI.md new file mode 100644 index 0000000..dcd7e54 --- /dev/null +++ b/docs/wiki/Internals/FFI.md @@ -0,0 +1,452 @@ +# FFI (Foreign Function Interface) + +WokeLang provides a C-compatible FFI for embedding in other languages. + +--- + +## Overview + +The FFI allows: + +- **Embedding**: Use WokeLang in C, C++, Zig, Go, Python, etc. +- **Extension**: Call native code from WokeLang +- **Integration**: Build hybrid applications + +--- + +## C API + +### Header File + +Located in `include/wokelang.h`: + +```c +#ifndef WOKELANG_H +#define WOKELANG_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Opaque types */ +typedef struct WokeInterpreter WokeInterpreter; +typedef struct WokeValue WokeValue; + +/* Result codes */ +typedef enum WokeResult { + WOKE_OK = 0, + WOKE_ERROR = 1, + WOKE_PARSE_ERROR = 2, + WOKE_RUNTIME_ERROR = 3, + WOKE_NULL_POINTER = 4 +} WokeResult; + +/* Value type tags */ +typedef enum WokeValueType { + WOKE_TYPE_INT = 0, + WOKE_TYPE_FLOAT = 1, + WOKE_TYPE_STRING = 2, + WOKE_TYPE_BOOL = 3, + WOKE_TYPE_ARRAY = 4, + WOKE_TYPE_UNIT = 5 +} WokeValueType; + +/* Interpreter lifecycle */ +WokeInterpreter* woke_interpreter_new(void); +void woke_interpreter_free(WokeInterpreter* interp); + +/* Execution */ +WokeResult woke_exec(WokeInterpreter* interp, const char* source); +WokeResult woke_eval(WokeInterpreter* interp, const char* source, WokeValue** out); + +/* Value operations */ +void woke_value_free(WokeValue* value); +WokeValueType woke_value_type(const WokeValue* value); +WokeResult woke_value_as_int(const WokeValue* value, int64_t* out); +WokeResult woke_value_as_float(const WokeValue* value, double* out); +WokeResult woke_value_as_bool(const WokeValue* value, int* out); +char* woke_value_as_string(const WokeValue* value); +void woke_string_free(char* s); + +/* Value creation */ +WokeValue* woke_value_from_int(int64_t n); +WokeValue* woke_value_from_float(double f); +WokeValue* woke_value_from_bool(int b); +WokeValue* woke_value_from_string(const char* s); + +/* Utility */ +const char* woke_version(void); +const char* woke_last_error(void); + +#ifdef __cplusplus +} +#endif + +#endif /* WOKELANG_H */ +``` + +--- + +## Rust Implementation + +Located in `src/ffi/c_api.rs`: + +```rust +use std::ffi::{CStr, CString}; +use std::os::raw::{c_char, c_double, c_int, c_longlong}; +use std::ptr; + +/// Opaque handle to interpreter +pub struct WokeInterpreter { + inner: Interpreter, +} + +/// Opaque handle to value +pub struct WokeValue { + inner: Value, +} + +#[repr(C)] +pub enum WokeResult { + Ok = 0, + Error = 1, + ParseError = 2, + RuntimeError = 3, + NullPointer = 4, +} + +#[no_mangle] +pub extern "C" fn woke_interpreter_new() -> *mut WokeInterpreter { + Box::into_raw(Box::new(WokeInterpreter { + inner: Interpreter::new(), + })) +} + +#[no_mangle] +pub unsafe extern "C" fn woke_interpreter_free(interp: *mut WokeInterpreter) { + if !interp.is_null() { + drop(Box::from_raw(interp)); + } +} + +#[no_mangle] +pub unsafe extern "C" fn woke_exec( + interp: *mut WokeInterpreter, + source: *const c_char, +) -> WokeResult { + if interp.is_null() || source.is_null() { + return WokeResult::NullPointer; + } + + let interp = &mut *interp; + let source = match CStr::from_ptr(source).to_str() { + Ok(s) => s, + Err(_) => return WokeResult::Error, + }; + + let lexer = Lexer::new(source); + let tokens = match lexer.tokenize() { + Ok(t) => t, + Err(_) => return WokeResult::ParseError, + }; + + let mut parser = Parser::new(tokens, source); + let program = match parser.parse() { + Ok(p) => p, + Err(_) => return WokeResult::ParseError, + }; + + match interp.inner.run(&program) { + Ok(_) => WokeResult::Ok, + Err(_) => WokeResult::RuntimeError, + } +} +``` + +--- + +## Build Configuration + +### Cargo.toml + +```toml +[lib] +name = "wokelang" +path = "src/lib.rs" +crate-type = ["lib", "cdylib", "staticlib"] +``` + +### Build Outputs + +```bash +cargo build --release + +# Produces: +# target/release/libwokelang.so (Linux shared) +# target/release/libwokelang.a (Linux static) +# target/release/libwokelang.dylib (macOS shared) +# target/release/wokelang.dll (Windows shared) +``` + +--- + +## Language Bindings + +### C Example + +```c +#include +#include "wokelang.h" + +int main() { + WokeInterpreter* interp = woke_interpreter_new(); + if (!interp) { + fprintf(stderr, "Failed to create interpreter\n"); + return 1; + } + + const char* code = + "to greet(name: String) → String {\n" + " give back \"Hello, \" + name + \"!\";\n" + "}\n" + "to main() {\n" + " print(greet(\"World\"));\n" + "}\n"; + + WokeResult result = woke_exec(interp, code); + if (result != WOKE_OK) { + fprintf(stderr, "Execution error: %d\n", result); + } + + woke_interpreter_free(interp); + return 0; +} +``` + +Compile: +```bash +gcc -o example example.c -L./target/release -lwokelang -lpthread -ldl -lm +``` + +### Zig Bindings + +Located in `zig/wokelang.zig`: + +```zig +const std = @import("std"); + +pub const WokeResult = enum(c_int) { + ok = 0, + @"error" = 1, + parse_error = 2, + runtime_error = 3, + null_pointer = 4, +}; + +pub const WokeValueType = enum(c_int) { + int = 0, + float = 1, + string = 2, + bool = 3, + array = 4, + unit = 5, +}; + +pub const WokeInterpreter = opaque {}; +pub const WokeValue = opaque {}; + +// External C functions +extern fn woke_interpreter_new() ?*WokeInterpreter; +extern fn woke_interpreter_free(interp: ?*WokeInterpreter) void; +extern fn woke_exec(interp: ?*WokeInterpreter, source: [*:0]const u8) WokeResult; +extern fn woke_value_type(value: ?*const WokeValue) WokeValueType; +extern fn woke_value_as_int(value: ?*const WokeValue, out: *i64) WokeResult; +extern fn woke_value_as_string(value: ?*const WokeValue) ?[*:0]u8; +extern fn woke_string_free(s: ?[*:0]u8) void; +extern fn woke_value_free(value: ?*WokeValue) void; +extern fn woke_version() [*:0]const u8; + +/// High-level Zig wrapper +pub const Interpreter = struct { + ptr: *WokeInterpreter, + + pub fn init() !Interpreter { + const ptr = woke_interpreter_new() orelse return error.FailedToCreateInterpreter; + return Interpreter{ .ptr = ptr }; + } + + pub fn deinit(self: *Interpreter) void { + woke_interpreter_free(self.ptr); + } + + pub fn exec(self: *Interpreter, source: [:0]const u8) !void { + const result = woke_exec(self.ptr, source.ptr); + return switch (result) { + .ok => {}, + .parse_error => error.ParseError, + .runtime_error => error.RuntimeError, + else => error.Unknown, + }; + } +}; + +pub fn version() []const u8 { + return std.mem.span(woke_version()); +} +``` + +### Zig Example + +```zig +const std = @import("std"); +const woke = @import("wokelang"); + +pub fn main() !void { + var interp = try woke.Interpreter.init(); + defer interp.deinit(); + + try interp.exec( + \\to main() { + \\ print("Hello from Zig!"); + \\} + ); + + std.debug.print("WokeLang version: {s}\n", .{woke.version()}); +} +``` + +Build with Zig: +```bash +zig build-exe example.zig -lwokelang -L./target/release +``` + +### Python (via ctypes) + +```python +import ctypes +from ctypes import c_char_p, c_void_p, c_int, c_int64, POINTER + +# Load library +lib = ctypes.CDLL("./target/release/libwokelang.so") + +# Define types +lib.woke_interpreter_new.restype = c_void_p +lib.woke_interpreter_free.argtypes = [c_void_p] +lib.woke_exec.argtypes = [c_void_p, c_char_p] +lib.woke_exec.restype = c_int +lib.woke_version.restype = c_char_p + +class WokeInterpreter: + def __init__(self): + self.ptr = lib.woke_interpreter_new() + if not self.ptr: + raise RuntimeError("Failed to create interpreter") + + def __del__(self): + if self.ptr: + lib.woke_interpreter_free(self.ptr) + + def exec(self, source): + result = lib.woke_exec(self.ptr, source.encode('utf-8')) + if result != 0: + raise RuntimeError(f"Execution error: {result}") + +# Usage +interp = WokeInterpreter() +interp.exec(""" +to main() { + print("Hello from Python!"); +} +""") + +print(f"Version: {lib.woke_version().decode()}") +``` + +--- + +## Memory Management + +### Rules + +1. **Interpreter**: Created with `woke_interpreter_new`, freed with `woke_interpreter_free` +2. **Values**: Created by `woke_value_from_*`, freed with `woke_value_free` +3. **Strings**: Returned by `woke_value_as_string`, freed with `woke_string_free` + +### Example + +```c +// Create +WokeInterpreter* interp = woke_interpreter_new(); +WokeValue* value = woke_value_from_int(42); + +// Use +int64_t n; +woke_value_as_int(value, &n); + +// Free (in reverse order) +woke_value_free(value); +woke_interpreter_free(interp); +``` + +--- + +## Error Handling + +### Result Codes + +| Code | Meaning | +|------|---------| +| `WOKE_OK` (0) | Success | +| `WOKE_ERROR` (1) | General error | +| `WOKE_PARSE_ERROR` (2) | Syntax error | +| `WOKE_RUNTIME_ERROR` (3) | Runtime error | +| `WOKE_NULL_POINTER` (4) | NULL argument | + +### Error Messages + +```c +WokeResult result = woke_exec(interp, code); +if (result != WOKE_OK) { + const char* error = woke_last_error(); + if (error) { + fprintf(stderr, "Error: %s\n", error); + } +} +``` + +--- + +## Thread Safety + +- Each `WokeInterpreter` instance is **not thread-safe** +- Create separate interpreters for each thread +- Values can be passed between threads once extracted + +--- + +## Performance Considerations + +1. **String conversion**: Allocates new memory; cache when possible +2. **Repeated execution**: Reuse interpreter instance +3. **Batch operations**: Prefer single exec with multiple statements + +--- + +## Platform Support + +| Platform | Shared Library | Static Library | +|----------|---------------|----------------| +| Linux x86_64 | libwokelang.so | libwokelang.a | +| macOS x86_64 | libwokelang.dylib | libwokelang.a | +| macOS ARM64 | libwokelang.dylib | libwokelang.a | +| Windows | wokelang.dll | wokelang.lib | + +--- + +## Next Steps + +- [WASM Compilation](WASM-Compilation.md) +- [Interpreter Internals](Interpreter.md) +- [CLI Reference](../Reference/CLI.md) diff --git a/docs/wiki/Internals/Interpreter.md b/docs/wiki/Internals/Interpreter.md new file mode 100644 index 0000000..a8a7dcc --- /dev/null +++ b/docs/wiki/Internals/Interpreter.md @@ -0,0 +1,761 @@ +# Interpreter Internals + +The interpreter executes WokeLang programs by walking the AST. + +--- + +## Overview + +WokeLang uses a **tree-walking interpreter** that directly evaluates the Abstract Syntax Tree. This approach is: + +- **Simple**: Easy to understand and modify +- **Flexible**: Supports dynamic features +- **Debuggable**: Natural mapping from source to execution + +--- + +## Core Components + +### Value Types + +Located in `src/interpreter/value.rs`: + +```rust +#[derive(Debug, Clone, PartialEq)] +pub enum Value { + Int(i64), + Float(f64), + String(String), + Bool(bool), + Array(Vec), + Unit, +} + +impl Value { + pub fn type_name(&self) -> &'static str { + match self { + Value::Int(_) => "Int", + Value::Float(_) => "Float", + Value::String(_) => "String", + Value::Bool(_) => "Bool", + Value::Array(_) => "Array", + Value::Unit => "Unit", + } + } + + pub fn is_truthy(&self) -> bool { + match self { + Value::Bool(b) => *b, + Value::Int(n) => *n != 0, + Value::String(s) => !s.is_empty(), + Value::Array(a) => !a.is_empty(), + Value::Unit => false, + Value::Float(f) => *f != 0.0, + } + } +} + +impl std::fmt::Display for Value { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Value::Int(n) => write!(f, "{}", n), + Value::Float(n) => write!(f, "{}", n), + Value::String(s) => write!(f, "{}", s), + Value::Bool(b) => write!(f, "{}", b), + Value::Array(arr) => { + write!(f, "[")?; + for (i, v) in arr.iter().enumerate() { + if i > 0 { write!(f, ", ")?; } + write!(f, "{}", v)?; + } + write!(f, "]") + } + Value::Unit => write!(f, "()"), + } + } +} +``` + +### Environment (Scope) + +```rust +#[derive(Debug, Clone)] +pub struct Environment { + values: HashMap, +} + +impl Environment { + pub fn new() -> Self { + Self { + values: HashMap::new(), + } + } + + pub fn define(&mut self, name: String, value: Value) { + self.values.insert(name, value); + } + + pub fn get(&self, name: &str) -> Option<&Value> { + self.values.get(name) + } + + pub fn set(&mut self, name: &str, value: Value) -> bool { + if self.values.contains_key(name) { + self.values.insert(name.to_string(), value); + true + } else { + false + } + } +} +``` + +### Interpreter State + +```rust +pub struct Interpreter { + /// Stack of environments (scopes) + environments: Vec, + + /// Registered functions + functions: HashMap, + + /// Collected output (for testing) + output: Vec, +} + +impl Interpreter { + pub fn new() -> Self { + Self { + environments: vec![Environment::new()], + functions: HashMap::new(), + output: Vec::new(), + } + } +} +``` + +--- + +## Execution Flow + +### Program Execution + +```rust +impl Interpreter { + pub fn run(&mut self, program: &Program) -> Result { + // Phase 1: Register all functions + for item in &program.items { + match item { + TopLevelItem::Function(f) => { + self.functions.insert(f.name.clone(), f.clone()); + } + TopLevelItem::GratitudeBlock(g) => { + self.execute_gratitude(g)?; + } + TopLevelItem::Pragma(p) => { + self.execute_pragma(p)?; + } + _ => {} + } + } + + // Phase 2: Call main() if it exists + if let Some(main) = self.functions.get("main").cloned() { + self.call_function(&main, vec![]) + } else { + // No main function - execute top-level statements + Ok(Value::Unit) + } + } +} +``` + +### Statement Execution + +```rust +impl Interpreter { + fn execute_statement(&mut self, stmt: &Statement) -> Result { + match stmt { + Statement::Remember { name, value, .. } => { + let val = self.eval_expr(value)?; + self.current_scope_mut().define(name.clone(), val); + Ok(ControlFlow::Continue) + } + + Statement::Assignment { target, value } => { + let val = self.eval_expr(value)?; + if !self.assign(target, val.clone()) { + return Err(RuntimeError::UndefinedVariable(target.clone())); + } + Ok(ControlFlow::Continue) + } + + Statement::Return { value } => { + let val = self.eval_expr(value)?; + Ok(ControlFlow::Return(val)) + } + + Statement::When { condition, then_block, else_block } => { + let cond = self.eval_expr(condition)?; + if cond.is_truthy() { + self.execute_block(then_block) + } else if let Some(else_b) = else_block { + self.execute_block(else_b) + } else { + Ok(ControlFlow::Continue) + } + } + + Statement::Repeat { count, body } => { + let n = match self.eval_expr(count)? { + Value::Int(n) => n, + _ => return Err(RuntimeError::TypeError("repeat count must be Int".into())), + }; + + for _ in 0..n { + match self.execute_block(body)? { + ControlFlow::Return(v) => return Ok(ControlFlow::Return(v)), + ControlFlow::Continue => {} + } + } + Ok(ControlFlow::Continue) + } + + Statement::Attempt { body, fallback_msg } => { + self.push_scope(); + let result = self.execute_block(body); + self.pop_scope(); + + match result { + Ok(flow) => Ok(flow), + Err(_) => { + self.print(&format!("[reassure] {}", fallback_msg)); + Ok(ControlFlow::Continue) + } + } + } + + Statement::Consent { permission, body } => { + // For now, always grant consent (real impl would prompt) + self.print(&format!("[consent requested: {}]", permission)); + self.execute_block(body) + } + + Statement::Complain { message } => { + Err(RuntimeError::Complaint(message.clone())) + } + + Statement::ExpressionStatement { expr } => { + self.eval_expr(expr)?; + Ok(ControlFlow::Continue) + } + + Statement::Hello { message } => { + self.print(&format!("[hello] {}", message)); + Ok(ControlFlow::Continue) + } + + Statement::Goodbye { message } => { + self.print(&format!("[goodbye] {}", message)); + Ok(ControlFlow::Continue) + } + + Statement::Decide { value, arms } => { + let val = self.eval_expr(value)?; + + for arm in arms { + if self.pattern_matches(&arm.pattern, &val) { + return self.execute_block(&arm.body); + } + } + + Ok(ControlFlow::Continue) + } + } + } +} +``` + +--- + +## Expression Evaluation + +```rust +impl Interpreter { + fn eval_expr(&mut self, expr: &Expr) -> Result { + match expr { + Expr::Literal(lit) => self.eval_literal(lit), + + Expr::Identifier(name) => { + self.lookup(name) + .ok_or_else(|| RuntimeError::UndefinedVariable(name.clone())) + } + + Expr::Binary { left, op, right } => { + let l = self.eval_expr(left)?; + let r = self.eval_expr(right)?; + self.eval_binary_op(op, l, r) + } + + Expr::Unary { op, operand } => { + let val = self.eval_expr(operand)?; + self.eval_unary_op(op, val) + } + + Expr::Call { function, args } => { + let evaluated_args: Vec = args + .iter() + .map(|a| self.eval_expr(a)) + .collect::>()?; + + self.call(function, evaluated_args) + } + + Expr::Array(elements) => { + let values: Vec = elements + .iter() + .map(|e| self.eval_expr(e)) + .collect::>()?; + Ok(Value::Array(values)) + } + + Expr::Index { array, index } => { + let arr = self.eval_expr(array)?; + let idx = self.eval_expr(index)?; + self.eval_index(arr, idx) + } + + Expr::FieldAccess { object, field } => { + let obj = self.eval_expr(object)?; + self.eval_field_access(obj, field) + } + + Expr::Gratitude(msg) => { + self.print(&format!("[thanks] {}", msg)); + Ok(Value::Unit) + } + } + } +} +``` + +### Binary Operations + +```rust +impl Interpreter { + fn eval_binary_op(&self, op: &BinOp, left: Value, right: Value) -> Result { + match op { + // Arithmetic + BinOp::Add => match (left, right) { + (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a + b)), + (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a + b)), + (Value::Int(a), Value::Float(b)) => Ok(Value::Float(a as f64 + b)), + (Value::Float(a), Value::Int(b)) => Ok(Value::Float(a + b as f64)), + (Value::String(a), Value::String(b)) => Ok(Value::String(a + &b)), + _ => Err(RuntimeError::TypeError("Invalid operands for +".into())), + }, + + BinOp::Sub => match (left, right) { + (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a - b)), + (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a - b)), + _ => Err(RuntimeError::TypeError("Invalid operands for -".into())), + }, + + BinOp::Mul => match (left, right) { + (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a * b)), + (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a * b)), + _ => Err(RuntimeError::TypeError("Invalid operands for *".into())), + }, + + BinOp::Div => match (left, right) { + (Value::Int(a), Value::Int(b)) => { + if b == 0 { + Err(RuntimeError::DivisionByZero) + } else { + Ok(Value::Int(a / b)) + } + } + (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a / b)), + _ => Err(RuntimeError::TypeError("Invalid operands for /".into())), + }, + + BinOp::Mod => match (left, right) { + (Value::Int(a), Value::Int(b)) => { + if b == 0 { + Err(RuntimeError::DivisionByZero) + } else { + Ok(Value::Int(a % b)) + } + } + _ => Err(RuntimeError::TypeError("Invalid operands for %".into())), + }, + + // Comparison + BinOp::Eq => Ok(Value::Bool(left == right)), + BinOp::Ne => Ok(Value::Bool(left != right)), + + BinOp::Lt => match (left, right) { + (Value::Int(a), Value::Int(b)) => Ok(Value::Bool(a < b)), + (Value::Float(a), Value::Float(b)) => Ok(Value::Bool(a < b)), + (Value::String(a), Value::String(b)) => Ok(Value::Bool(a < b)), + _ => Err(RuntimeError::TypeError("Invalid operands for <".into())), + }, + + BinOp::Gt => match (left, right) { + (Value::Int(a), Value::Int(b)) => Ok(Value::Bool(a > b)), + (Value::Float(a), Value::Float(b)) => Ok(Value::Bool(a > b)), + (Value::String(a), Value::String(b)) => Ok(Value::Bool(a > b)), + _ => Err(RuntimeError::TypeError("Invalid operands for >".into())), + }, + + BinOp::Le => match (left, right) { + (Value::Int(a), Value::Int(b)) => Ok(Value::Bool(a <= b)), + (Value::Float(a), Value::Float(b)) => Ok(Value::Bool(a <= b)), + _ => Err(RuntimeError::TypeError("Invalid operands for <=".into())), + }, + + BinOp::Ge => match (left, right) { + (Value::Int(a), Value::Int(b)) => Ok(Value::Bool(a >= b)), + (Value::Float(a), Value::Float(b)) => Ok(Value::Bool(a >= b)), + _ => Err(RuntimeError::TypeError("Invalid operands for >=".into())), + }, + + // Logical + BinOp::And => Ok(Value::Bool(left.is_truthy() && right.is_truthy())), + BinOp::Or => Ok(Value::Bool(left.is_truthy() || right.is_truthy())), + } + } +} +``` + +--- + +## Function Calls + +```rust +impl Interpreter { + fn call(&mut self, name: &str, args: Vec) -> Result { + // Check for built-in functions first + if let Some(result) = self.call_builtin(name, &args)? { + return Ok(result); + } + + // Look up user-defined function + let func = self.functions + .get(name) + .cloned() + .ok_or_else(|| RuntimeError::UndefinedFunction(name.to_string()))?; + + self.call_function(&func, args) + } + + fn call_function(&mut self, func: &Function, args: Vec) -> Result { + // Validate argument count + if args.len() != func.params.len() { + return Err(RuntimeError::ArgumentCount { + expected: func.params.len(), + got: args.len(), + }); + } + + // Create new scope + self.push_scope(); + + // Bind parameters + for (param, value) in func.params.iter().zip(args) { + self.current_scope_mut().define(param.name.clone(), value); + } + + // Execute hello message + if let Some(msg) = &func.hello { + self.print(&format!("[hello] {}", msg)); + } + + // Execute body + let result = self.execute_block(&func.body); + + // Execute goodbye message + if let Some(msg) = &func.goodbye { + self.print(&format!("[goodbye] {}", msg)); + } + + // Pop scope + self.pop_scope(); + + // Handle result + match result? { + ControlFlow::Return(value) => Ok(value), + ControlFlow::Continue => Ok(Value::Unit), + } + } +} +``` + +--- + +## Built-in Functions + +```rust +impl Interpreter { + fn call_builtin(&mut self, name: &str, args: &[Value]) -> Result> { + match name { + "print" => { + let output: Vec = args.iter().map(|v| v.to_string()).collect(); + self.print(&output.join(" ")); + Ok(Some(Value::Unit)) + } + + "len" => { + if args.len() != 1 { + return Err(RuntimeError::ArgumentCount { expected: 1, got: args.len() }); + } + match &args[0] { + Value::String(s) => Ok(Some(Value::Int(s.len() as i64))), + Value::Array(a) => Ok(Some(Value::Int(a.len() as i64))), + _ => Err(RuntimeError::TypeError("len() requires String or Array".into())), + } + } + + "toString" => { + if args.len() != 1 { + return Err(RuntimeError::ArgumentCount { expected: 1, got: args.len() }); + } + Ok(Some(Value::String(args[0].to_string()))) + } + + "toInt" => { + if args.len() != 1 { + return Err(RuntimeError::ArgumentCount { expected: 1, got: args.len() }); + } + match &args[0] { + Value::String(s) => { + s.parse::() + .map(|n| Some(Value::Int(n))) + .map_err(|_| RuntimeError::TypeError("Cannot parse as Int".into())) + } + Value::Float(f) => Ok(Some(Value::Int(*f as i64))), + Value::Int(n) => Ok(Some(Value::Int(*n))), + _ => Err(RuntimeError::TypeError("toInt() requires String, Float, or Int".into())), + } + } + + "toFloat" => { + if args.len() != 1 { + return Err(RuntimeError::ArgumentCount { expected: 1, got: args.len() }); + } + match &args[0] { + Value::String(s) => { + s.parse::() + .map(|f| Some(Value::Float(f))) + .map_err(|_| RuntimeError::TypeError("Cannot parse as Float".into())) + } + Value::Int(n) => Ok(Some(Value::Float(*n as f64))), + Value::Float(f) => Ok(Some(Value::Float(*f))), + _ => Err(RuntimeError::TypeError("toFloat() requires String, Int, or Float".into())), + } + } + + _ => Ok(None), // Not a built-in + } + } +} +``` + +--- + +## Scope Management + +```rust +impl Interpreter { + fn push_scope(&mut self) { + self.environments.push(Environment::new()); + } + + fn pop_scope(&mut self) { + if self.environments.len() > 1 { + self.environments.pop(); + } + } + + fn current_scope_mut(&mut self) -> &mut Environment { + self.environments.last_mut().unwrap() + } + + fn lookup(&self, name: &str) -> Option { + // Search from innermost to outermost scope + for env in self.environments.iter().rev() { + if let Some(value) = env.get(name) { + return Some(value.clone()); + } + } + None + } + + fn assign(&mut self, name: &str, value: Value) -> bool { + // Search from innermost to outermost scope + for env in self.environments.iter_mut().rev() { + if env.set(name, value.clone()) { + return true; + } + } + false + } +} +``` + +--- + +## Control Flow + +```rust +pub enum ControlFlow { + Continue, + Return(Value), +} + +impl Interpreter { + fn execute_block(&mut self, statements: &[Statement]) -> Result { + for stmt in statements { + match self.execute_statement(stmt)? { + ControlFlow::Return(v) => return Ok(ControlFlow::Return(v)), + ControlFlow::Continue => {} + } + } + Ok(ControlFlow::Continue) + } +} +``` + +--- + +## Error Handling + +```rust +#[derive(Debug)] +pub enum RuntimeError { + UndefinedVariable(String), + UndefinedFunction(String), + TypeError(String), + DivisionByZero, + IndexOutOfBounds { index: i64, len: usize }, + ArgumentCount { expected: usize, got: usize }, + Complaint(String), +} + +impl std::fmt::Display for RuntimeError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::UndefinedVariable(name) => write!(f, "Undefined variable: {}", name), + Self::UndefinedFunction(name) => write!(f, "Undefined function: {}", name), + Self::TypeError(msg) => write!(f, "Type error: {}", msg), + Self::DivisionByZero => write!(f, "Division by zero"), + Self::IndexOutOfBounds { index, len } => { + write!(f, "Index {} out of bounds for array of length {}", index, len) + } + Self::ArgumentCount { expected, got } => { + write!(f, "Expected {} arguments, got {}", expected, got) + } + Self::Complaint(msg) => write!(f, "Complaint: {}", msg), + } + } +} +``` + +--- + +## Testing + +```rust +#[cfg(test)] +mod tests { + use super::*; + + fn run(source: &str) -> Result { + let lexer = Lexer::new(source); + let tokens = lexer.tokenize().unwrap(); + let mut parser = Parser::new(tokens, source); + let program = parser.parse().unwrap(); + let mut interpreter = Interpreter::new(); + interpreter.run(&program) + } + + #[test] + fn test_arithmetic() { + let mut interp = Interpreter::new(); + + // Test basic operations + assert_eq!(run("to main() { give back 2 + 3; }").unwrap(), Value::Int(5)); + assert_eq!(run("to main() { give back 10 - 4; }").unwrap(), Value::Int(6)); + assert_eq!(run("to main() { give back 6 * 7; }").unwrap(), Value::Int(42)); + assert_eq!(run("to main() { give back 20 / 4; }").unwrap(), Value::Int(5)); + } + + #[test] + fn test_variables() { + let result = run(r#" + to main() { + remember x = 10; + remember y = 20; + give back x + y; + } + "#); + assert_eq!(result.unwrap(), Value::Int(30)); + } + + #[test] + fn test_function_call() { + let result = run(r#" + to add(a: Int, b: Int) -> Int { + give back a + b; + } + to main() { + give back add(3, 4); + } + "#); + assert_eq!(result.unwrap(), Value::Int(7)); + } + + #[test] + fn test_recursion() { + let result = run(r#" + to factorial(n: Int) -> Int { + when n <= 1 { + give back 1; + } otherwise { + give back n * factorial(n - 1); + } + } + to main() { + give back factorial(5); + } + "#); + assert_eq!(result.unwrap(), Value::Int(120)); + } +} +``` + +--- + +## Performance Considerations + +- **Value cloning**: Values are cloned when passed; future work may add reference counting +- **HashMap lookups**: Function and variable lookups are O(1) average +- **Recursion**: Uses Rust's call stack; deep recursion may overflow + +--- + +## Future Enhancements + +- **Tail call optimization** +- **Bytecode compilation** for faster execution +- **JIT compilation** for hot paths +- **Garbage collection** for long-running programs + +--- + +## Next Steps + +- [WASM Compilation](WASM-Compilation.md) +- [FFI Internals](FFI.md) +- [Value Types Reference](../Reference/Types.md) diff --git a/docs/wiki/Internals/Lexer.md b/docs/wiki/Internals/Lexer.md new file mode 100644 index 0000000..ffc1c35 --- /dev/null +++ b/docs/wiki/Internals/Lexer.md @@ -0,0 +1,526 @@ +# Lexer Internals + +The lexer (tokenizer) converts WokeLang source code into a stream of tokens for the parser. + +--- + +## Overview + +WokeLang uses the [`logos`](https://github.com/maciejhirsz/logos) crate for lexer generation. Logos is a fast, zero-copy lexer generator that creates efficient state machines from declarative token definitions. + +--- + +## Token Types + +Located in `src/lexer/token.rs`: + +```rust +#[derive(Logos, Debug, Clone, PartialEq)] +#[logos(skip r"[ \t\n\r]+")] // Skip whitespace +pub enum Token { + // === Keywords: Control Flow === + #[token("to")] + To, + + #[token("give")] + Give, + + #[token("back")] + Back, + + #[token("remember")] + Remember, + + #[token("when")] + When, + + #[token("otherwise")] + Otherwise, + + #[token("repeat")] + Repeat, + + #[token("times")] + Times, + + // === Keywords: Consent & Safety === + #[token("only")] + Only, + + #[token("if")] + If, + + #[token("okay")] + Okay, + + #[token("attempt")] + Attempt, + + #[token("safely")] + Safely, + + #[token("or")] + Or, + + #[token("reassure")] + Reassure, + + #[token("complain")] + Complain, + + // === Keywords: Gratitude === + #[token("thanks")] + Thanks, + + // === Keywords: Lifecycle === + #[token("hello")] + Hello, + + #[token("goodbye")] + Goodbye, + + // === Keywords: Concurrency === + #[token("worker")] + Worker, + + #[token("side")] + Side, + + #[token("quest")] + Quest, + + #[token("superpower")] + Superpower, + + #[token("spawn")] + Spawn, + + // === Keywords: Pattern Matching === + #[token("decide")] + Decide, + + #[token("based")] + Based, + + #[token("on")] + On, + + // === Keywords: Units === + #[token("measured")] + Measured, + + #[token("in")] + In, + + // === Keywords: Types === + #[token("type")] + Type, + + #[token("const")] + Const, + + #[token("Maybe")] + Maybe, + + // === Keywords: Boolean === + #[token("true")] + True, + + #[token("false")] + False, + + #[token("and")] + And, + + #[token("not")] + Not, + + // === Keywords: Modules === + #[token("use")] + Use, + + #[token("renamed")] + Renamed, + + #[token("share")] + Share, + + // === Literals === + #[regex(r"-?[0-9]+", |lex| lex.slice().parse().ok())] + Integer(i64), + + #[regex(r"-?[0-9]+\.[0-9]+", |lex| lex.slice().parse().ok())] + Float(f64), + + #[regex(r#""([^"\\]|\\.)*""#, |lex| { + let s = lex.slice(); + Some(s[1..s.len()-1].to_string()) // Remove quotes + })] + String(String), + + // === Identifiers === + #[regex(r"[a-zA-Z_][a-zA-Z0-9_]*", |lex| lex.slice().to_string())] + Identifier(String), + + // === Operators === + #[token("+")] + Plus, + + #[token("-")] + Minus, + + #[token("*")] + Star, + + #[token("/")] + Slash, + + #[token("%")] + Percent, + + #[token("==")] + EqualEqual, + + #[token("!=")] + BangEqual, + + #[token("<")] + Less, + + #[token(">")] + Greater, + + #[token("<=")] + LessEqual, + + #[token(">=")] + GreaterEqual, + + // === Punctuation === + #[token("(")] + LeftParen, + + #[token(")")] + RightParen, + + #[token("{")] + LeftBrace, + + #[token("}")] + RightBrace, + + #[token("[")] + LeftBracket, + + #[token("]")] + RightBracket, + + #[token(",")] + Comma, + + #[token(";")] + Semicolon, + + #[token(":")] + Colon, + + #[token("=")] + Equal, + + #[token("→")] + Arrow, + + #[token("->")] + ArrowAscii, + + #[token("@")] + At, + + #[token("#")] + Hash, + + #[token(".")] + Dot, + + #[token("&")] + Ampersand, + + #[token("|")] + Pipe, + + #[token("_")] + Underscore, + + // === Comments === + #[regex(r"//[^\n]*", logos::skip)] + LineComment, + + #[regex(r"/\*([^*]|\*[^/])*\*/", logos::skip)] + BlockComment, +} +``` + +--- + +## Lexer Implementation + +Located in `src/lexer/mod.rs`: + +```rust +pub mod token; + +use logos::Logos; +use std::ops::Range; + +pub use token::Token; + +/// A token with its source location +pub type Spanned = (T, Range); + +/// The WokeLang lexer +pub struct Lexer<'source> { + source: &'source str, +} + +impl<'source> Lexer<'source> { + /// Create a new lexer for the given source code + pub fn new(source: &'source str) -> Self { + Self { source } + } + + /// Tokenize the source code into a vector of spanned tokens + pub fn tokenize(&self) -> Result>, LexError> { + let mut tokens = Vec::new(); + let mut lexer = Token::lexer(self.source); + + while let Some(result) = lexer.next() { + match result { + Ok(token) => { + tokens.push((token, lexer.span())); + } + Err(_) => { + return Err(LexError { + message: format!( + "Unexpected character: '{}'", + &self.source[lexer.span()] + ), + span: lexer.span(), + }); + } + } + } + + Ok(tokens) + } +} + +#[derive(Debug)] +pub struct LexError { + pub message: String, + pub span: Range, +} +``` + +--- + +## Tokenization Process + +### 1. Input Processing + +``` +Source: "remember x = 42;" + ^^^^^^^^ ^ ^ ^^^ + | | | | + | | | Integer(42), Semicolon + | | Equal + | Identifier("x") + Remember +``` + +### 2. Token Stream Output + +```rust +vec![ + (Token::Remember, 0..8), + (Token::Identifier("x".to_string()), 9..10), + (Token::Equal, 11..12), + (Token::Integer(42), 13..15), + (Token::Semicolon, 15..16), +] +``` + +### 3. Span Information + +Each token includes its byte range in the source: + +```rust +pub type Spanned = (T, Range); + +// Example: "remember" at bytes 0-8 +(Token::Remember, 0..8) +``` + +This enables accurate error reporting with source locations. + +--- + +## Special Cases + +### Unicode Arrow + +WokeLang supports both Unicode and ASCII arrows: + +```rust +#[token("→")] +Arrow, + +#[token("->")] +ArrowAscii, +``` + +Both are valid: +```wokelang +to add(a: Int, b: Int) → Int { ... } // Unicode +to add(a: Int, b: Int) -> Int { ... } // ASCII +``` + +### String Escapes + +Strings handle escape sequences: + +```rust +#[regex(r#""([^"\\]|\\.)*""#, |lex| { + let s = lex.slice(); + Some(s[1..s.len()-1].to_string()) +})] +String(String), +``` + +Supported escapes: +- `\n` - newline +- `\t` - tab +- `\r` - carriage return +- `\"` - escaped quote +- `\\` - escaped backslash + +### Comments + +Comments are skipped automatically: + +```rust +#[regex(r"//[^\n]*", logos::skip)] +LineComment, + +#[regex(r"/\*([^*]|\*[^/])*\*/", logos::skip)] +BlockComment, +``` + +--- + +## Error Handling + +When the lexer encounters an unexpected character: + +```rust +Err(_) => { + return Err(LexError { + message: format!( + "Unexpected character: '{}'", + &self.source[lexer.span()] + ), + span: lexer.span(), + }); +} +``` + +Example error: + +``` +Error: Lexer error at 1:5 + | +1 | let $ = 5; + | ^ Unexpected character: '$' +``` + +--- + +## Testing + +Tests are located in `src/lexer/mod.rs`: + +```rust +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_keywords() { + let lexer = Lexer::new("to remember when otherwise"); + let tokens = lexer.tokenize().unwrap(); + + assert_eq!(tokens[0].0, Token::To); + assert_eq!(tokens[1].0, Token::Remember); + assert_eq!(tokens[2].0, Token::When); + assert_eq!(tokens[3].0, Token::Otherwise); + } + + #[test] + fn test_literals() { + let lexer = Lexer::new("42 3.14 \"hello\" true false"); + let tokens = lexer.tokenize().unwrap(); + + assert_eq!(tokens[0].0, Token::Integer(42)); + assert_eq!(tokens[1].0, Token::Float(3.14)); + assert_eq!(tokens[2].0, Token::String("hello".to_string())); + assert_eq!(tokens[3].0, Token::True); + assert_eq!(tokens[4].0, Token::False); + } + + #[test] + fn test_operators() { + let lexer = Lexer::new("+ - * / % == != < > <= >="); + let tokens = lexer.tokenize().unwrap(); + + assert_eq!(tokens[0].0, Token::Plus); + assert_eq!(tokens[1].0, Token::Minus); + // ... + } +} +``` + +--- + +## Performance + +Logos generates efficient lexers: + +- **Zero-copy**: Uses slices into source +- **State machine**: Compiled to efficient DFA +- **No allocations**: Until string extraction + +Benchmark (approximate): +- ~100 MB/s on typical source code +- O(n) linear time complexity + +--- + +## Future Enhancements + +### v0.3.0 Planned +- Unicode identifiers +- Heredoc strings (`"""..."""`) +- Raw strings (`r"..."`) + +### v0.4.0 Planned +- String interpolation (`"Hello, ${name}!"`) + +### v0.5.0 Planned +- Custom operators + +--- + +## Next Steps + +- [Parser Internals](Parser.md) +- [AST Structure](AST.md) +- [Token Reference](../Reference/Keywords.md) diff --git a/docs/wiki/Internals/Parser.md b/docs/wiki/Internals/Parser.md new file mode 100644 index 0000000..c03baec --- /dev/null +++ b/docs/wiki/Internals/Parser.md @@ -0,0 +1,605 @@ +# Parser Internals + +The parser transforms a stream of tokens into an Abstract Syntax Tree (AST). + +--- + +## Overview + +WokeLang uses a hand-written **recursive descent parser** with **Pratt parsing** for expressions. This approach provides: + +- Clear, maintainable code +- Excellent error messages +- Fine-grained control over parsing + +--- + +## Parser Structure + +Located in `src/parser/mod.rs`: + +```rust +pub struct Parser<'a> { + tokens: Vec>, + source: &'a str, + current: usize, +} + +impl<'a> Parser<'a> { + pub fn new(tokens: Vec>, source: &'a str) -> Self { + Self { + tokens, + source, + current: 0, + } + } + + pub fn parse(&mut self) -> Result { + let mut items = Vec::new(); + + while !self.is_at_end() { + items.push(self.parse_top_level_item()?); + } + + Ok(Program { items }) + } +} +``` + +--- + +## Parsing Entry Points + +### Top-Level Items + +```rust +fn parse_top_level_item(&mut self) -> Result { + // Check for emote tag + let emote = if self.check(Token::At) { + Some(self.parse_emote_tag()?) + } else { + None + }; + + match self.peek().0 { + Token::To => { + let mut func = self.parse_function()?; + func.emote = emote; + Ok(TopLevelItem::Function(func)) + } + Token::Worker => Ok(TopLevelItem::Worker(self.parse_worker()?)), + Token::Side => Ok(TopLevelItem::SideQuest(self.parse_side_quest()?)), + Token::Type => Ok(TopLevelItem::TypeDef(self.parse_type_def()?)), + Token::Thanks => Ok(TopLevelItem::GratitudeBlock(self.parse_gratitude()?)), + Token::Hash => Ok(TopLevelItem::Pragma(self.parse_pragma()?)), + Token::Use => Ok(TopLevelItem::Import(self.parse_import()?)), + _ => Err(self.error("Expected top-level declaration")), + } +} +``` + +### Function Parsing + +```rust +fn parse_function(&mut self) -> Result { + self.expect(Token::To)?; + + let name = self.expect_identifier()?; + + self.expect(Token::LeftParen)?; + let params = self.parse_param_list()?; + self.expect(Token::RightParen)?; + + let return_type = if self.match_token(Token::Arrow) || self.match_token(Token::ArrowAscii) { + Some(self.parse_type()?) + } else { + None + }; + + self.expect(Token::LeftBrace)?; + + // Parse optional hello + let hello = if self.check(Token::Hello) { + self.advance(); + let msg = self.expect_string()?; + self.expect(Token::Semicolon)?; + Some(msg) + } else { + None + }; + + // Parse body statements + let body = self.parse_block_contents()?; + + // Parse optional goodbye + let goodbye = if self.check(Token::Goodbye) { + self.advance(); + let msg = self.expect_string()?; + self.expect(Token::Semicolon)?; + Some(msg) + } else { + None + }; + + self.expect(Token::RightBrace)?; + + Ok(Function { + name, + params, + return_type, + hello, + body, + goodbye, + emote: None, + }) +} +``` + +--- + +## Statement Parsing + +```rust +fn parse_statement(&mut self) -> Result { + match self.peek().0 { + Token::Remember => self.parse_remember(), + Token::When => self.parse_when(), + Token::Repeat => self.parse_repeat(), + Token::Give => self.parse_return(), + Token::Attempt => self.parse_attempt(), + Token::Only => self.parse_consent(), + Token::Complain => self.parse_complain(), + Token::Decide => self.parse_decide(), + Token::Hello => self.parse_hello(), + Token::Goodbye => self.parse_goodbye(), + _ => self.parse_expression_statement(), + } +} +``` + +### Variable Declaration + +```rust +fn parse_remember(&mut self) -> Result { + self.expect(Token::Remember)?; + + let name = self.expect_identifier()?; + + // Optional type annotation + let type_ann = if self.match_token(Token::Colon) { + Some(self.parse_type()?) + } else { + None + }; + + self.expect(Token::Equal)?; + let value = self.parse_expression()?; + + // Optional unit + let unit = if self.match_token(Token::Measured) { + self.expect(Token::In)?; + Some(self.expect_identifier()?) + } else { + None + }; + + self.expect(Token::Semicolon)?; + + Ok(Statement::Remember { name, type_ann, value, unit }) +} +``` + +### Conditional Statement + +```rust +fn parse_when(&mut self) -> Result { + self.expect(Token::When)?; + + let condition = self.parse_expression()?; + + self.expect(Token::LeftBrace)?; + let then_block = self.parse_block_contents()?; + self.expect(Token::RightBrace)?; + + let else_block = if self.match_token(Token::Otherwise) { + self.expect(Token::LeftBrace)?; + let block = self.parse_block_contents()?; + self.expect(Token::RightBrace)?; + Some(block) + } else { + None + }; + + Ok(Statement::When { condition, then_block, else_block }) +} +``` + +--- + +## Expression Parsing (Pratt/Precedence Climbing) + +### Operator Precedence + +``` +Lowest Highest + | | + v v + or → and → == != → < > <= >= → + - → * / % → not - (unary) → call, index +``` + +### Implementation + +```rust +fn parse_expression(&mut self) -> Result { + self.parse_or_expr() +} + +fn parse_or_expr(&mut self) -> Result { + let mut left = self.parse_and_expr()?; + + while self.match_token(Token::Or) { + let right = self.parse_and_expr()?; + left = Expr::Binary { + left: Box::new(left), + op: BinOp::Or, + right: Box::new(right), + }; + } + + Ok(left) +} + +fn parse_and_expr(&mut self) -> Result { + let mut left = self.parse_equality_expr()?; + + while self.match_token(Token::And) { + let right = self.parse_equality_expr()?; + left = Expr::Binary { + left: Box::new(left), + op: BinOp::And, + right: Box::new(right), + }; + } + + Ok(left) +} + +fn parse_equality_expr(&mut self) -> Result { + let mut left = self.parse_comparison_expr()?; + + while let Some(op) = self.match_equality_op() { + let right = self.parse_comparison_expr()?; + left = Expr::Binary { + left: Box::new(left), + op, + right: Box::new(right), + }; + } + + Ok(left) +} + +fn parse_comparison_expr(&mut self) -> Result { + let mut left = self.parse_additive_expr()?; + + while let Some(op) = self.match_comparison_op() { + let right = self.parse_additive_expr()?; + left = Expr::Binary { + left: Box::new(left), + op, + right: Box::new(right), + }; + } + + Ok(left) +} + +fn parse_additive_expr(&mut self) -> Result { + let mut left = self.parse_multiplicative_expr()?; + + while let Some(op) = self.match_additive_op() { + let right = self.parse_multiplicative_expr()?; + left = Expr::Binary { + left: Box::new(left), + op, + right: Box::new(right), + }; + } + + Ok(left) +} + +fn parse_multiplicative_expr(&mut self) -> Result { + let mut left = self.parse_unary_expr()?; + + while let Some(op) = self.match_multiplicative_op() { + let right = self.parse_unary_expr()?; + left = Expr::Binary { + left: Box::new(left), + op, + right: Box::new(right), + }; + } + + Ok(left) +} + +fn parse_unary_expr(&mut self) -> Result { + if self.match_token(Token::Not) { + let operand = self.parse_unary_expr()?; + return Ok(Expr::Unary { + op: UnaryOp::Not, + operand: Box::new(operand), + }); + } + + if self.match_token(Token::Minus) { + let operand = self.parse_unary_expr()?; + return Ok(Expr::Unary { + op: UnaryOp::Neg, + operand: Box::new(operand), + }); + } + + self.parse_postfix_expr() +} + +fn parse_postfix_expr(&mut self) -> Result { + let mut expr = self.parse_primary()?; + + loop { + if self.match_token(Token::LeftParen) { + // Function call + let args = self.parse_argument_list()?; + self.expect(Token::RightParen)?; + + if let Expr::Identifier(name) = expr { + expr = Expr::Call { function: name, args }; + } else { + return Err(self.error("Expected function name")); + } + } else if self.match_token(Token::LeftBracket) { + // Array index + let index = self.parse_expression()?; + self.expect(Token::RightBracket)?; + expr = Expr::Index { + array: Box::new(expr), + index: Box::new(index), + }; + } else if self.match_token(Token::Dot) { + // Field access + let field = self.expect_identifier()?; + expr = Expr::FieldAccess { + object: Box::new(expr), + field, + }; + } else { + break; + } + } + + Ok(expr) +} +``` + +### Primary Expressions + +```rust +fn parse_primary(&mut self) -> Result { + let token = self.advance(); + + match token.0 { + Token::Integer(n) => Ok(Expr::Literal(Literal::Int(n))), + Token::Float(f) => Ok(Expr::Literal(Literal::Float(f))), + Token::String(s) => Ok(Expr::Literal(Literal::String(s))), + Token::True => Ok(Expr::Literal(Literal::Bool(true))), + Token::False => Ok(Expr::Literal(Literal::Bool(false))), + Token::Identifier(name) => Ok(Expr::Identifier(name)), + Token::LeftParen => { + let expr = self.parse_expression()?; + self.expect(Token::RightParen)?; + Ok(expr) + } + Token::LeftBracket => { + let elements = self.parse_array_elements()?; + self.expect(Token::RightBracket)?; + Ok(Expr::Array(elements)) + } + Token::Thanks => { + self.expect(Token::LeftParen)?; + let msg = self.expect_string()?; + self.expect(Token::RightParen)?; + Ok(Expr::Gratitude(msg)) + } + _ => Err(self.error("Expected expression")), + } +} +``` + +--- + +## Helper Methods + +```rust +impl<'a> Parser<'a> { + /// Check if at end of tokens + fn is_at_end(&self) -> bool { + self.current >= self.tokens.len() + } + + /// Peek at current token without consuming + fn peek(&self) -> &Spanned { + &self.tokens[self.current] + } + + /// Advance and return current token + fn advance(&mut self) -> Spanned { + if !self.is_at_end() { + self.current += 1; + } + self.tokens[self.current - 1].clone() + } + + /// Check if current token matches + fn check(&self, expected: Token) -> bool { + if self.is_at_end() { + return false; + } + std::mem::discriminant(&self.peek().0) == std::mem::discriminant(&expected) + } + + /// Consume token if it matches + fn match_token(&mut self, expected: Token) -> bool { + if self.check(expected) { + self.advance(); + true + } else { + false + } + } + + /// Expect a specific token or error + fn expect(&mut self, expected: Token) -> Result> { + if self.check(expected.clone()) { + Ok(self.advance()) + } else { + Err(self.error(&format!("Expected {:?}", expected))) + } + } + + /// Expect an identifier + fn expect_identifier(&mut self) -> Result { + match self.advance().0 { + Token::Identifier(name) => Ok(name), + _ => Err(self.error("Expected identifier")), + } + } + + /// Create an error at current position + fn error(&self, message: &str) -> ParseError { + let span = if self.is_at_end() { + self.tokens.last().map(|t| t.1.clone()).unwrap_or(0..0) + } else { + self.peek().1.clone() + }; + + ParseError { + message: message.to_string(), + span, + } + } +} +``` + +--- + +## Error Recovery + +The parser can recover from errors to report multiple issues: + +```rust +fn synchronize(&mut self) { + self.advance(); + + while !self.is_at_end() { + // Synchronize at statement boundaries + if self.previous().0 == Token::Semicolon { + return; + } + + // Synchronize at declaration keywords + match self.peek().0 { + Token::To + | Token::Remember + | Token::When + | Token::Repeat + | Token::Give + | Token::Worker + | Token::Type => return, + _ => {} + } + + self.advance(); + } +} +``` + +--- + +## Testing + +```rust +#[cfg(test)] +mod tests { + use super::*; + use crate::lexer::Lexer; + + fn parse(source: &str) -> Result { + let lexer = Lexer::new(source); + let tokens = lexer.tokenize().unwrap(); + let mut parser = Parser::new(tokens, source); + parser.parse() + } + + #[test] + fn test_function() { + let result = parse("to add(a: Int, b: Int) → Int { give back a + b; }"); + assert!(result.is_ok()); + + let program = result.unwrap(); + assert_eq!(program.items.len(), 1); + + if let TopLevelItem::Function(f) = &program.items[0] { + assert_eq!(f.name, "add"); + assert_eq!(f.params.len(), 2); + } else { + panic!("Expected function"); + } + } + + #[test] + fn test_expression_precedence() { + let result = parse("to main() { remember x = 2 + 3 * 4; }"); + assert!(result.is_ok()); + + // Should parse as 2 + (3 * 4), not (2 + 3) * 4 + } + + #[test] + fn test_when_otherwise() { + let result = parse(r#" + to main() { + when x > 0 { + print("positive"); + } otherwise { + print("non-positive"); + } + } + "#); + assert!(result.is_ok()); + } +} +``` + +--- + +## Grammar Correspondence + +The parser implements the EBNF grammar in `grammar/wokelang.ebnf`: + +| Grammar Rule | Parser Method | +|-------------|---------------| +| `program` | `parse()` | +| `top_level_item` | `parse_top_level_item()` | +| `function_def` | `parse_function()` | +| `statement` | `parse_statement()` | +| `expression` | `parse_expression()` | +| `primary` | `parse_primary()` | + +--- + +## Next Steps + +- [AST Structure](AST.md) +- [Interpreter Internals](Interpreter.md) +- [Grammar Reference](../../grammar/wokelang.ebnf) diff --git a/docs/wiki/Internals/WASM-Compilation.md b/docs/wiki/Internals/WASM-Compilation.md new file mode 100644 index 0000000..b137ec0 --- /dev/null +++ b/docs/wiki/Internals/WASM-Compilation.md @@ -0,0 +1,500 @@ +# WASM Compilation + +WokeLang can compile programs to WebAssembly for browser and edge runtime execution. + +--- + +## Overview + +The WASM compiler translates WokeLang functions into WebAssembly binary format, enabling: + +- **Browser execution**: Run WokeLang in web pages +- **Edge computing**: Deploy to WASI-compatible runtimes +- **Embedding**: Use WokeLang functions in other languages + +--- + +## Architecture + +``` +WokeLang Source + │ + ▼ + Parser + │ + ▼ + AST + │ + ▼ +┌─────────────────┐ +│ WASM Compiler │ +├─────────────────┤ +│ - Type Section │ +│ - Function Sec │ +│ - Export Sec │ +│ - Code Section │ +└─────────────────┘ + │ + ▼ + .wasm binary +``` + +--- + +## Implementation + +Located in `src/codegen/wasm.rs`: + +```rust +use wasm_encoder::{ + CodeSection, ExportKind, ExportSection, Function, FunctionSection, + Instruction, Module, TypeSection, ValType, +}; + +pub struct WasmCompiler { + module: Module, + type_section: TypeSection, + function_section: FunctionSection, + export_section: ExportSection, + code_section: CodeSection, + function_types: Vec, +} + +impl WasmCompiler { + pub fn new() -> Self { + Self { + module: Module::new(), + type_section: TypeSection::new(), + function_section: FunctionSection::new(), + export_section: ExportSection::new(), + code_section: CodeSection::new(), + function_types: Vec::new(), + } + } + + pub fn compile(&mut self, program: &Program) -> Result, CompileError> { + // Collect and compile functions + let functions: Vec<_> = program.items + .iter() + .filter_map(|item| { + if let TopLevelItem::Function(f) = item { + Some(f) + } else { + None + } + }) + .collect(); + + for func in &functions { + self.compile_function(func)?; + } + + // Build module sections + self.module.section(&self.type_section); + self.module.section(&self.function_section); + self.module.section(&self.export_section); + self.module.section(&self.code_section); + + Ok(self.module.finish()) + } +} +``` + +### Function Compilation + +```rust +impl WasmCompiler { + fn compile_function(&mut self, func: &Function) -> Result<(), CompileError> { + let func_idx = self.function_types.len() as u32; + + // Build function type signature + let param_types: Vec = func.params + .iter() + .map(|p| self.woke_type_to_wasm(&p.type_expr)) + .collect::>()?; + + let return_types: Vec = if let Some(ret) = &func.return_type { + vec![self.woke_type_to_wasm(ret)?] + } else { + vec![] + }; + + // Add type to type section + self.type_section.function(param_types.clone(), return_types.clone()); + self.function_section.function(func_idx); + + // Export the function + self.export_section.export(&func.name, ExportKind::Func, func_idx); + + // Compile function body + let mut code = Function::new(vec![]); // No locals beyond params + + // Build local variable index map + let mut local_indices: HashMap = HashMap::new(); + for (i, param) in func.params.iter().enumerate() { + local_indices.insert(param.name.clone(), i as u32); + } + + // Compile body statements + for stmt in &func.body { + self.compile_statement(&mut code, stmt, &local_indices)?; + } + + // Ensure function has end instruction + code.instruction(&Instruction::End); + + self.code_section.function(&code); + self.function_types.push(func_idx); + + Ok(()) + } +} +``` + +### Type Mapping + +```rust +impl WasmCompiler { + fn woke_type_to_wasm(&self, type_expr: &TypeExpr) -> Result { + match type_expr { + TypeExpr::Simple(name) => match name.as_str() { + "Int" => Ok(ValType::I64), + "Float" => Ok(ValType::F64), + "Bool" => Ok(ValType::I32), // Booleans as i32 + _ => Err(CompileError::UnsupportedType(name.clone())), + }, + _ => Err(CompileError::UnsupportedType("complex type".into())), + } + } +} +``` + +### Statement Compilation + +```rust +impl WasmCompiler { + fn compile_statement( + &self, + code: &mut Function, + stmt: &Statement, + locals: &HashMap, + ) -> Result<(), CompileError> { + match stmt { + Statement::Return { value } => { + self.compile_expr(code, value, locals)?; + code.instruction(&Instruction::Return); + } + + Statement::When { condition, then_block, else_block } => { + // Compile condition + self.compile_expr(code, condition, locals)?; + + // Convert to i32 for branch + code.instruction(&Instruction::I32WrapI64); + + // if-then-else block + code.instruction(&Instruction::If(wasm_encoder::BlockType::Empty)); + + for stmt in then_block { + self.compile_statement(code, stmt, locals)?; + } + + if let Some(else_b) = else_block { + code.instruction(&Instruction::Else); + for stmt in else_b { + self.compile_statement(code, stmt, locals)?; + } + } + + code.instruction(&Instruction::End); + } + + _ => { + // Other statements not yet supported in WASM + return Err(CompileError::UnsupportedStatement); + } + } + + Ok(()) + } +} +``` + +### Expression Compilation + +```rust +impl WasmCompiler { + fn compile_expr( + &self, + code: &mut Function, + expr: &Expr, + locals: &HashMap, + ) -> Result<(), CompileError> { + match expr { + Expr::Literal(Literal::Int(n)) => { + code.instruction(&Instruction::I64Const(*n)); + } + + Expr::Literal(Literal::Float(f)) => { + code.instruction(&Instruction::F64Const(*f)); + } + + Expr::Literal(Literal::Bool(b)) => { + code.instruction(&Instruction::I64Const(if *b { 1 } else { 0 })); + } + + Expr::Identifier(name) => { + let idx = locals.get(name) + .ok_or_else(|| CompileError::UndefinedVariable(name.clone()))?; + code.instruction(&Instruction::LocalGet(*idx)); + } + + Expr::Binary { left, op, right } => { + self.compile_expr(code, left, locals)?; + self.compile_expr(code, right, locals)?; + + match op { + BinOp::Add => code.instruction(&Instruction::I64Add), + BinOp::Sub => code.instruction(&Instruction::I64Sub), + BinOp::Mul => code.instruction(&Instruction::I64Mul), + BinOp::Div => code.instruction(&Instruction::I64DivS), + BinOp::Mod => code.instruction(&Instruction::I64RemS), + BinOp::Lt => code.instruction(&Instruction::I64LtS), + BinOp::Gt => code.instruction(&Instruction::I64GtS), + BinOp::Le => code.instruction(&Instruction::I64LeS), + BinOp::Ge => code.instruction(&Instruction::I64GeS), + BinOp::Eq => code.instruction(&Instruction::I64Eq), + BinOp::Ne => code.instruction(&Instruction::I64Ne), + _ => return Err(CompileError::UnsupportedOperator), + }; + } + + Expr::Unary { op, operand } => { + match op { + UnaryOp::Neg => { + code.instruction(&Instruction::I64Const(0)); + self.compile_expr(code, operand, locals)?; + code.instruction(&Instruction::I64Sub); + } + UnaryOp::Not => { + self.compile_expr(code, operand, locals)?; + code.instruction(&Instruction::I64Eqz); + } + } + } + + _ => return Err(CompileError::UnsupportedExpression), + } + + Ok(()) + } +} +``` + +--- + +## Usage + +### CLI Compilation + +```bash +# Compile to WASM +woke compile --wasm -o output.wasm input.woke + +# With optimization +woke compile --wasm --opt-level=s -o output.wasm input.woke +``` + +### Programmatic API + +```rust +use wokelang::{Lexer, Parser, WasmCompiler}; + +fn compile_to_wasm(source: &str) -> Result, Error> { + let lexer = Lexer::new(source); + let tokens = lexer.tokenize()?; + + let mut parser = Parser::new(tokens, source); + let program = parser.parse()?; + + let mut compiler = WasmCompiler::new(); + compiler.compile(&program) +} +``` + +--- + +## WASM Module Structure + +A compiled WokeLang module contains: + +``` +WASM Module +├── Type Section - Function signatures +├── Function Section - Function type indices +├── Export Section - Exported function names +└── Code Section - Function bodies +``` + +### Example Output + +For this WokeLang function: + +```wokelang +to add(a: Int, b: Int) → Int { + give back a + b; +} +``` + +The generated WASM (in WAT format) is: + +```wat +(module + (type (;0;) (func (param i64 i64) (result i64))) + (func (;0;) (type 0) (param i64 i64) (result i64) + local.get 0 + local.get 1 + i64.add + return + ) + (export "add" (func 0)) +) +``` + +--- + +## Supported Features + +### Currently Supported + +| Feature | Status | +|---------|--------| +| Integer arithmetic | ✅ | +| Integer comparisons | ✅ | +| Boolean operations | ✅ | +| Function parameters | ✅ | +| Return statements | ✅ | +| Conditionals (when/otherwise) | ✅ | +| Float arithmetic | ✅ | + +### Planned (v0.4.0) + +| Feature | Status | +|---------|--------| +| Local variables | 🔜 | +| Loops (repeat) | 🔜 | +| Function calls | 🔜 | +| Arrays | 🔜 | +| Strings (via linear memory) | 🔜 | + +--- + +## Using WASM Output + +### In Browser + +```html + +``` + +### In Node.js + +```javascript +const fs = require('fs'); + +async function run() { + const bytes = fs.readFileSync('output.wasm'); + const { instance } = await WebAssembly.instantiate(bytes); + + const result = instance.exports.add(5n, 3n); + console.log('Result:', result); // 8n +} +run(); +``` + +### In Rust (wasmtime) + +```rust +use wasmtime::*; + +fn main() -> Result<()> { + let engine = Engine::default(); + let module = Module::from_file(&engine, "output.wasm")?; + let mut store = Store::new(&engine, ()); + let instance = Instance::new(&mut store, &module, &[])?; + + let add = instance.get_typed_func::<(i64, i64), i64>(&mut store, "add")?; + let result = add.call(&mut store, (5, 3))?; + println!("Result: {}", result); // 8 + + Ok(()) +} +``` + +--- + +## Limitations + +1. **No garbage collection**: Linear memory management required +2. **No closures**: Functions cannot capture environment +3. **No strings directly**: Require memory allocation strategy +4. **No recursion limit**: Can overflow WASM stack + +--- + +## Future Roadmap + +### v0.4.0 - Full WASM Support +- Linear memory for strings and arrays +- WASI integration for I/O +- Exception handling +- Imported functions + +### v0.5.0 - Optimizations +- Constant folding +- Dead code elimination +- Function inlining + +--- + +## Debugging WASM + +### View as WAT (text format) + +```bash +# Using wasm2wat from wabt +wasm2wat output.wasm -o output.wat +``` + +### Validate WASM + +```bash +# Using wasm-validate from wabt +wasm-validate output.wasm +``` + +### Inspect with hexdump + +```bash +od -A x -t x1z output.wasm | head +# Should start with: 00 61 73 6d (\0asm) +``` + +--- + +## Next Steps + +- [FFI Internals](FFI.md) +- [CLI Reference](../Reference/CLI.md) +- [Interpreter Internals](Interpreter.md) diff --git a/docs/wiki/Language-Guide/Control-Flow.md b/docs/wiki/Language-Guide/Control-Flow.md new file mode 100644 index 0000000..3d56ed1 --- /dev/null +++ b/docs/wiki/Language-Guide/Control-Flow.md @@ -0,0 +1,490 @@ +# Control Flow + +WokeLang provides intuitive control flow constructs with clear, readable syntax. + +--- + +## Conditionals + +### When/Otherwise + +```wokelang +when condition { + // Code if condition is true +} otherwise { + // Code if condition is false +} +``` + +**Example:** + +```wokelang +when score >= 90 { + print("Excellent!"); +} otherwise { + print("Keep trying!"); +} +``` + +### Without Otherwise + +The `otherwise` clause is optional: + +```wokelang +when needsUpdate { + refreshData(); +} +// Continues here regardless +``` + +### Nested Conditions + +```wokelang +when score >= 90 { + print("A"); +} otherwise { + when score >= 80 { + print("B"); + } otherwise { + when score >= 70 { + print("C"); + } otherwise { + print("F"); + } + } +} +``` + +### Condition Expressions + +Any expression that produces a truthy value: + +```wokelang +when count > 0 { + print("Has items"); +} + +when name == "Admin" { + showAdminPanel(); +} + +when isActive and hasPermission { + performAction(); +} +``` + +--- + +## Loops + +### Repeat Times + +```wokelang +repeat count times { + // Executed 'count' times +} +``` + +**Examples:** + +```wokelang +// Fixed count +repeat 5 times { + print("Hello!"); +} + +// Variable count +remember n = 3; +repeat n times { + print("Counting..."); +} +``` + +### Loop with Counter (Pattern) + +```wokelang +remember i = 0; +repeat 10 times { + print("Index: " + toString(i)); + i = i + 1; +} +``` + +### Early Exit (Planned) + +```wokelang +repeat 100 times { + when found { + stop; // Exit loop + } +} +``` + +### Skip Iteration (Planned) + +```wokelang +repeat items times { + when shouldSkip { + skip; // Continue to next iteration + } + process(item); +} +``` + +--- + +## Pattern Matching + +### Decide Based On + +```wokelang +decide based on value { + pattern1 → { + // Code for pattern1 + } + pattern2 → { + // Code for pattern2 + } + _ → { + // Default case (wildcard) + } +} +``` + +### String Matching + +```wokelang +decide based on status { + "success" → { + print("Operation succeeded!"); + celebrate(); + } + "pending" → { + print("Still waiting..."); + } + "error" → { + print("Something went wrong"); + handleError(); + } + _ → { + print("Unknown status: " + status); + } +} +``` + +### Numeric Matching + +```wokelang +decide based on code { + 200 → { + print("OK"); + } + 404 → { + print("Not Found"); + } + 500 → { + print("Server Error"); + } + _ → { + print("Status: " + toString(code)); + } +} +``` + +### Boolean Matching + +```wokelang +decide based on isActive { + true → { + showActiveState(); + } + false → { + showInactiveState(); + } +} +``` + +--- + +## Error Handling Control Flow + +### Attempt Safely + +```wokelang +attempt safely { + // Code that might fail + remember data = riskyOperation(); + processData(data); +} or reassure "Operation failed, but we're okay"; +``` + +### Complain (Throw Error) + +```wokelang +to divide(a: Int, b: Int) → Int { + when b == 0 { + complain "Cannot divide by zero"; + } + give back a / b; +} +``` + +See [Error Handling](Error-Handling.md) for more details. + +--- + +## Consent Control Flow + +### Only If Okay + +```wokelang +only if okay "permission_name" { + // Code requiring permission +} +``` + +**Example:** + +```wokelang +only if okay "camera_access" { + remember photo = takePhoto(); + displayPhoto(photo); +} +``` + +See [Consent System](../Core-Concepts/Consent-System.md) for more details. + +--- + +## Control Flow in Functions + +### Early Return + +```wokelang +to findFirst(items: [Int], target: Int) → Int { + remember i = 0; + repeat len(items) times { + when items[i] == target { + give back i; // Early return + } + i = i + 1; + } + give back -1; // Not found +} +``` + +### Guard Clauses + +```wokelang +to processUser(user: Maybe User) { + when user == none { + give back; // Early exit + } + // Process valid user +} +``` + +--- + +## Truthiness + +Values are evaluated for truthiness in conditions: + +| Value | Truthy? | +|-------|---------| +| `true` | Yes | +| `false` | No | +| `0` | No | +| Non-zero integers | Yes | +| `0.0` | No | +| Non-zero floats | Yes | +| `""` (empty string) | No | +| Non-empty strings | Yes | +| `[]` (empty array) | No | +| Non-empty arrays | Yes | +| `Unit` | No | + +**Example:** + +```wokelang +remember count = 5; +when count { // true because count != 0 + print("Has items"); +} + +remember name = ""; +when name { // false because name is empty + print("Has name"); +} +``` + +--- + +## Combined Examples + +### Menu System + +```wokelang +to handleMenu(choice: String) { + decide based on choice { + "1" → { + print("Starting new game..."); + startGame(); + } + "2" → { + print("Loading saved game..."); + loadGame(); + } + "3" → { + print("Opening settings..."); + openSettings(); + } + "q" → { + print("Goodbye!"); + // Exit + } + _ → { + print("Invalid choice. Please try again."); + } + } +} +``` + +### Validation Loop + +```wokelang +to getValidInput() → Int { + remember attempts = 0; + remember maxAttempts = 3; + remember result = 0; + + repeat maxAttempts times { + attempts = attempts + 1; + print("Attempt " + toString(attempts) + " of " + toString(maxAttempts)); + + attempt safely { + remember input = readInput(); + result = toInt(input); + + when result > 0 { + give back result; + } + + print("Please enter a positive number"); + } or reassure "Invalid input, try again"; + } + + complain "Too many invalid attempts"; +} +``` + +### State Machine + +```wokelang +to runStateMachine(initialState: String) { + remember state = initialState; + remember running = true; + + repeat 100 times { // Max iterations for safety + when not running { + // Would use 'stop' when available + } + + decide based on state { + "idle" → { + print("Waiting for input..."); + state = "processing"; + } + "processing" → { + print("Processing..."); + state = "complete"; + } + "complete" → { + print("Done!"); + running = false; + } + _ → { + print("Unknown state"); + running = false; + } + } + } +} +``` + +--- + +## Best Practices + +### 1. Prefer Pattern Matching + +```wokelang +// Good: Clear pattern matching +decide based on status { + "active" → { activate(); } + "inactive" → { deactivate(); } + _ → { handleUnknown(); } +} + +// Less clear: Nested ifs +when status == "active" { + activate(); +} otherwise { + when status == "inactive" { + deactivate(); + } otherwise { + handleUnknown(); + } +} +``` + +### 2. Always Handle the Default Case + +```wokelang +decide based on value { + // Known cases + 1 → { handleOne(); } + 2 → { handleTwo(); } + // Always include wildcard + _ → { handleDefault(); } +} +``` + +### 3. Keep Conditions Simple + +```wokelang +// Good: Clear, simple condition +remember isEligible = age >= 18 and hasConsent; +when isEligible { + proceed(); +} + +// Harder to read +when age >= 18 and hasConsent and not isBanned and accountActive { + proceed(); +} +``` + +### 4. Use Guard Clauses + +```wokelang +// Good: Early exit for invalid cases +to processOrder(order: Order) { + when order == none { + give back; + } + when not order.isValid { + give back; + } + // Happy path continues + submitOrder(order); +} +``` + +--- + +## Next Steps + +- [Functions](Functions.md) +- [Error Handling](Error-Handling.md) +- [Pattern Matching](Pattern-Matching.md) diff --git a/docs/wiki/Language-Guide/Error-Handling.md b/docs/wiki/Language-Guide/Error-Handling.md new file mode 100644 index 0000000..de8d963 --- /dev/null +++ b/docs/wiki/Language-Guide/Error-Handling.md @@ -0,0 +1,385 @@ +# Error Handling + +WokeLang provides gentle, human-centered error handling. + +--- + +## Philosophy + +Error handling in WokeLang emphasizes: + +- **Graceful recovery** over crashes +- **Human-readable messages** over stack traces +- **Explicit handling** over silent failures + +--- + +## Attempt Safely + +The primary error handling construct: + +```wokelang +attempt safely { + // Code that might fail +} or reassure "Friendly message if it fails"; +``` + +### Basic Usage + +```wokelang +attempt safely { + remember data = fetchFromNetwork(); + processData(data); +} or reassure "Couldn't fetch data, but the app will continue"; +``` + +### What Happens + +1. Code in the `attempt` block runs +2. If successful, continues normally +3. If an error occurs, prints the reassurance message +4. Execution continues after the block + +--- + +## Complain + +Raise an error intentionally: + +```wokelang +complain "Error message"; +``` + +### Example + +```wokelang +to divide(a: Int, b: Int) → Int { + when b == 0 { + complain "Cannot divide by zero"; + } + give back a / b; +} +``` + +### Caught by Attempt + +```wokelang +attempt safely { + remember result = divide(10, 0); + print(result); +} or reassure "Division failed, using default value"; +``` + +--- + +## Common Patterns + +### Validation + +```wokelang +to validateEmail(email: String) → Bool { + when len(email) == 0 { + complain "Email cannot be empty"; + } + when not contains(email, "@") { + complain "Email must contain @"; + } + give back true; +} + +// Usage +attempt safely { + validateEmail(userInput); + sendEmail(userInput); +} or reassure "Invalid email address"; +``` + +### Resource Access + +```wokelang +to loadUserProfile(userId: String) → Profile { + attempt safely { + remember data = readFile("users/" + userId + ".json"); + give back parseProfile(data); + } or reassure "Could not load profile"; + + // Return default if failed + give back defaultProfile(); +} +``` + +### Network Operations + +```wokelang +to fetchData(url: String) → String { + attempt safely { + only if okay "network_access" { + remember response = httpGet(url); + give back response; + } + } or reassure "Network request failed or was denied"; + + give back ""; +} +``` + +### Cascading Attempts + +```wokelang +to getData() → String { + // Try primary source + attempt safely { + give back fetchFromPrimary(); + } or reassure "Primary source unavailable"; + + // Try backup source + attempt safely { + give back fetchFromBackup(); + } or reassure "Backup source unavailable"; + + // Try cache + attempt safely { + give back loadFromCache(); + } or reassure "Cache unavailable"; + + // Last resort + give back defaultData(); +} +``` + +--- + +## Result Types (Planned) + +### Okay/Oops Pattern + +```wokelang +type Result[T] = Okay(T) | Oops(String); + +to divide(a: Int, b: Int) → Result[Int] { + when b == 0 { + give back Oops("Division by zero"); + } + give back Okay(a / b); +} + +// Usage +remember result = divide(10, 2); +decide based on result { + Okay(value) → { + print("Result: " + toString(value)); + } + Oops(error) → { + print("Error: " + error); + } +} +``` + +### Maybe Type + +```wokelang +type Maybe[T] = Some(T) | None; + +to findUser(id: String) → Maybe[User] { + when not exists(id) { + give back None; + } + give back Some(loadUser(id)); +} + +// Usage +remember maybeUser = findUser("123"); +decide based on maybeUser { + Some(user) → { + print("Found: " + user.name); + } + None → { + print("User not found"); + } +} +``` + +--- + +## Error Propagation (Planned) + +### The `?` Operator + +```wokelang +to processFile(path: String) → Result[Data] { + remember content = readFile(path)?; // Propagates error + remember parsed = parseJson(content)?; + give back Okay(parsed); +} +``` + +Equivalent to: + +```wokelang +to processFile(path: String) → Result[Data] { + remember contentResult = readFile(path); + decide based on contentResult { + Oops(e) → { give back Oops(e); } + Okay(content) → { + remember parsedResult = parseJson(content); + decide based on parsedResult { + Oops(e) → { give back Oops(e); } + Okay(parsed) → { give back Okay(parsed); } + } + } + } +} +``` + +--- + +## Best Practices + +### 1. Be Specific in Complain Messages + +```wokelang +// Good: Specific message +complain "User ID must be between 1 and 1000, got: " + toString(id); + +// Bad: Vague message +complain "Invalid input"; +``` + +### 2. Use Reassuring Messages + +```wokelang +// Good: Reassuring, explains recovery +attempt safely { + syncData(); +} or reassure "Sync failed - your data is safe locally and will sync when connection returns"; + +// Bad: Alarming +attempt safely { + syncData(); +} or reassure "SYNC FAILED! DATA MIGHT BE LOST!"; +``` + +### 3. Provide Fallbacks + +```wokelang +to getTemperature() → Float { + attempt safely { + give back fetchFromSensor(); + } or reassure "Sensor unavailable"; + + // Provide a reasonable default + give back 20.0; // Room temperature +} +``` + +### 4. Validate Early + +```wokelang +to processOrder(order: Order) { + // Validate at the start + when order.items == 0 { + complain "Order must have at least one item"; + } + when order.total < 0 { + complain "Order total cannot be negative"; + } + + // Happy path continues + submitOrder(order); +} +``` + +### 5. Combine with Emote Tags + +```wokelang +@cautious +to riskyOperation() { + attempt safely { + performRiskyAction(); + } or reassure "Risky operation failed safely"; +} +``` + +--- + +## Complete Example + +```wokelang +thanks to { + "Error Handling" → "For keeping our programs running"; +} + +to main() { + hello "Starting error handling demo"; + + // Validation + attempt safely { + validateInput("test@example.com"); + print("Email is valid!"); + } or reassure "Email validation failed"; + + // Division with error + attempt safely { + remember result = safeDivide(10, 0); + print("Result: " + toString(result)); + } or reassure "Could not complete division"; + + // Cascading fallback + remember data = getDataWithFallback(); + print("Got data: " + data); + + goodbye "Demo complete"; +} + +to validateInput(email: String) { + when len(email) == 0 { + complain "Email cannot be empty"; + } + // More validation... +} + +to safeDivide(a: Int, b: Int) → Int { + when b == 0 { + complain "Division by zero is not allowed"; + } + give back a / b; +} + +to getDataWithFallback() → String { + attempt safely { + give back fetchPrimary(); + } or reassure "Primary fetch failed"; + + attempt safely { + give back fetchBackup(); + } or reassure "Backup fetch failed"; + + give back "default data"; +} + +to fetchPrimary() → String { + complain "Simulated primary failure"; +} + +to fetchBackup() → String { + give back "data from backup"; +} +``` + +**Output:** +``` +[hello] Starting error handling demo +Email is valid! +[reassure] Could not complete division +[reassure] Primary fetch failed +Got data: data from backup +[goodbye] Demo complete +``` + +--- + +## Next Steps + +- [Control Flow](Control-Flow.md) +- [Consent System](../Core-Concepts/Consent-System.md) +- [Functions](Functions.md) diff --git a/docs/wiki/Language-Guide/Functions.md b/docs/wiki/Language-Guide/Functions.md new file mode 100644 index 0000000..7a8827b --- /dev/null +++ b/docs/wiki/Language-Guide/Functions.md @@ -0,0 +1,410 @@ +# Functions + +Functions are the primary way to organize code in WokeLang. + +--- + +## Basic Function Definition + +```wokelang +to functionName() { + // function body +} +``` + +### With Parameters + +```wokelang +to greet(name: String) { + print("Hello, " + name + "!"); +} +``` + +### With Return Type + +```wokelang +to add(a: Int, b: Int) → Int { + give back a + b; +} +``` + +--- + +## The `to` Keyword + +Functions are declared with `to`, suggesting intention: + +```wokelang +to calculateTotal(items: [Float]) → Float { + // "To calculate total, we..." +} +``` + +This reads naturally: "To calculate total, given items..." + +--- + +## Parameters + +### Required Parameters + +```wokelang +to sendEmail(to: String, subject: String, body: String) { + // All parameters must be provided +} +``` + +### Type Annotations + +All parameters require type annotations: + +```wokelang +to process( + name: String, + count: Int, + ratio: Float, + active: Bool +) { + // ... +} +``` + +### Reference Parameters (Planned) + +```wokelang +to modify(data: &[Int]) { + // Can modify the original array +} +``` + +--- + +## Return Values + +### Explicit Return + +Use `give back` to return values: + +```wokelang +to square(n: Int) → Int { + give back n * n; +} +``` + +### Early Return + +Return early from conditionals: + +```wokelang +to absoluteValue(n: Int) → Int { + when n < 0 { + give back -n; + } + give back n; +} +``` + +### Implicit Unit + +Functions without `give back` return `Unit`: + +```wokelang +to logMessage(msg: String) { + print(msg); + // Implicitly returns Unit +} +``` + +--- + +## Lifecycle Messages + +### Hello and Goodbye + +Functions can have entry and exit messages: + +```wokelang +to processOrder(orderId: String) { + hello "Starting order processing"; + + // Processing logic here + validateOrder(orderId); + chargePayment(orderId); + shipOrder(orderId); + + goodbye "Order processing complete"; +} +``` + +**Output:** +``` +[hello] Starting order processing +[goodbye] Order processing complete +``` + +### Purpose + +- `hello`: Setup, logging, initialization context +- `goodbye`: Cleanup, completion logging, summary + +### Optional + +Both are optional: + +```wokelang +to quickTask() { + // No hello/goodbye needed for simple functions + print("Done!"); +} +``` + +--- + +## Emote Tags + +Add emotional context with tags: + +```wokelang +@important +to validateCreditCard(number: String) → Bool { + // Security-critical code +} + +@experimental +to tryNewAlgorithm(data: [Int]) → [Int] { + // Unstable code +} + +@deprecated(reason="Use newAPI()") +to oldAPI() { + // Legacy code +} +``` + +See [Emote Tags](../Core-Concepts/Emote-Tags.md) for details. + +--- + +## Calling Functions + +### Basic Calls + +```wokelang +greet("Alice"); +remember result = add(3, 5); +print(toString(result)); +``` + +### Chained Results + +```wokelang +remember doubled = double(triple(5)); // 30 +``` + +### As Arguments + +```wokelang +print(toString(add(1, 2))); +``` + +--- + +## Recursion + +WokeLang supports recursive functions: + +```wokelang +to factorial(n: Int) → Int { + when n <= 1 { + give back 1; + } otherwise { + give back n * factorial(n - 1); + } +} +``` + +### Fibonacci + +```wokelang +to fibonacci(n: Int) → Int { + when n <= 1 { + give back n; + } + give back fibonacci(n - 1) + fibonacci(n - 2); +} +``` + +--- + +## Function Patterns + +### Guard Clauses + +```wokelang +to divide(a: Int, b: Int) → Int { + when b == 0 { + complain "Cannot divide by zero"; + } + give back a / b; +} +``` + +### Default Behavior + +```wokelang +to greet(name: String) → String { + when len(name) == 0 { + give back "Hello, stranger!"; + } + give back "Hello, " + name + "!"; +} +``` + +### Builder Pattern (Planned) + +```wokelang +to createUser() → UserBuilder { + give back UserBuilder.new(); +} + +// Usage +remember user = createUser() + .withName("Alice") + .withEmail("alice@example.com") + .build(); +``` + +--- + +## Higher-Order Functions (Planned) + +### Function Parameters + +```wokelang +to applyTwice(f: (Int) → Int, x: Int) → Int { + give back f(f(x)); +} + +to double(n: Int) → Int { + give back n * 2; +} + +// Usage +remember result = applyTwice(double, 5); // 20 +``` + +### Anonymous Functions (Planned) + +```wokelang +remember numbers = [1, 2, 3, 4, 5]; +remember doubled = map(numbers, (n) → n * 2); +``` + +--- + +## Complete Example + +```wokelang +thanks to { + "Math" → "For the beauty of numbers"; +} + +@important +to main() { + hello "Calculator starting"; + + remember nums = [1, 2, 3, 4, 5]; + remember total = sum(nums); + remember avg = average(nums); + + print("Sum: " + toString(total)); + print("Average: " + toString(avg)); + + remember fact5 = factorial(5); + print("5! = " + toString(fact5)); + + goodbye "Calculator done"; +} + +to sum(numbers: [Int]) → Int { + remember total = 0; + remember i = 0; + repeat len(numbers) times { + total = total + numbers[i]; + i = i + 1; + } + give back total; +} + +to average(numbers: [Int]) → Float { + remember total = sum(numbers); + give back toFloat(total) / toFloat(len(numbers)); +} + +to factorial(n: Int) → Int { + when n <= 1 { + give back 1; + } + give back n * factorial(n - 1); +} +``` + +--- + +## Best Practices + +### 1. Clear Names + +```wokelang +// Good: Descriptive names +to calculateMonthlyPayment(principal: Float, rate: Float, months: Int) → Float + +// Bad: Unclear names +to calc(p: Float, r: Float, m: Int) → Float +``` + +### 2. Single Responsibility + +```wokelang +// Good: Focused functions +to validateEmail(email: String) → Bool { ... } +to sendEmail(to: String, body: String) { ... } + +// Bad: Doing too much +to validateAndSendEmail(email: String, body: String) { ... } +``` + +### 3. Use Lifecycle Messages Meaningfully + +```wokelang +// Good: Informative messages +to processPayment(amount: Float) { + hello "Processing payment of $" + toString(amount); + // ... + goodbye "Payment processed successfully"; +} + +// Unnecessary for simple functions +to add(a: Int, b: Int) → Int { + // No need for hello/goodbye here + give back a + b; +} +``` + +### 4. Appropriate Emote Tags + +```wokelang +@cautious +to deleteAccount() { ... } // Destructive - cautious is appropriate + +@happy +to sendWelcome() { ... } // Positive - happy is appropriate +``` + +--- + +## Next Steps + +- [Control Flow](Control-Flow.md) +- [Variables and Types](Variables-and-Types.md) +- [Error Handling](Error-Handling.md) diff --git a/docs/wiki/Language-Guide/Variables-and-Types.md b/docs/wiki/Language-Guide/Variables-and-Types.md new file mode 100644 index 0000000..20ce0fa --- /dev/null +++ b/docs/wiki/Language-Guide/Variables-and-Types.md @@ -0,0 +1,392 @@ +# Variables and Types + +WokeLang provides a clear, type-safe variable system. + +--- + +## Variables + +### Declaration with `remember` + +Variables are declared with `remember`: + +```wokelang +remember name = "Alice"; +remember age = 30; +remember pi = 3.14159; +remember active = true; +``` + +The keyword suggests the program is "remembering" a value for later use. + +### Type Inference + +Types are inferred from the value: + +```wokelang +remember x = 42; // Int +remember y = 3.14; // Float +remember z = "hello"; // String +remember w = true; // Bool +``` + +### Explicit Type Annotations + +Optionally specify types: + +```wokelang +remember count: Int = 0; +remember ratio: Float = 0.5; +remember message: String = ""; +remember enabled: Bool = false; +``` + +### Reassignment + +Variables can be reassigned: + +```wokelang +remember x = 10; +x = 20; // Now x is 20 +x = x + 5; // Now x is 25 +``` + +--- + +## Primitive Types + +### Int + +64-bit signed integers: + +```wokelang +remember positive = 42; +remember negative = -17; +remember zero = 0; +remember large = 9223372036854775807; // Max Int +``` + +**Operations:** +```wokelang +remember sum = 5 + 3; // 8 +remember diff = 10 - 4; // 6 +remember prod = 6 * 7; // 42 +remember quot = 20 / 4; // 5 +remember rem = 17 % 5; // 2 +``` + +### Float + +64-bit floating-point numbers: + +```wokelang +remember pi = 3.14159; +remember e = 2.71828; +remember negative = -0.5; +remember scientific = 1.5; // Scientific notation planned +``` + +**Operations:** +```wokelang +remember sum = 1.5 + 2.5; // 4.0 +remember prod = 2.0 * 3.5; // 7.0 +remember div = 10.0 / 4.0; // 2.5 +``` + +### String + +UTF-8 encoded text: + +```wokelang +remember greeting = "Hello, World!"; +remember empty = ""; +remember multiword = "This is a sentence."; +``` + +**Escape sequences:** +```wokelang +remember newline = "Line1\nLine2"; +remember tab = "Col1\tCol2"; +remember quote = "She said \"Hello\""; +remember backslash = "Path\\to\\file"; +``` + +**Operations:** +```wokelang +remember full = "Hello" + ", " + "World"; // Concatenation +remember length = len("hello"); // 5 +``` + +### Bool + +Boolean values: + +```wokelang +remember yes = true; +remember no = false; +``` + +**Operations:** +```wokelang +remember both = true and false; // false +remember either = true or false; // true +remember opposite = not true; // false +``` + +--- + +## Composite Types + +### Arrays + +Ordered collections of same-type values: + +```wokelang +remember numbers = [1, 2, 3, 4, 5]; +remember names = ["Alice", "Bob", "Charlie"]; +remember empty: [Int] = []; +``` + +**Type annotations:** +```wokelang +remember items: [String] = ["a", "b", "c"]; +remember matrix: [[Int]] = [[1, 2], [3, 4]]; +``` + +**Operations:** +```wokelang +remember first = numbers[0]; // 1 +remember length = len(numbers); // 5 +``` + +### Optional Types (Planned) + +Values that might not exist: + +```wokelang +type Maybe[T] = Some(T) | None; + +remember maybeValue: Maybe Int = findValue(); +``` + +--- + +## Unit Values + +Values with associated units of measurement: + +```wokelang +remember distance = 100 measured in meters; +remember speed = 60 measured in mph; +remember temperature = 98.6 measured in fahrenheit; +remember duration = 30 measured in seconds; +``` + +Unit types help prevent errors like adding meters to seconds. + +--- + +## Type Aliases (Planned) + +Create named types: + +```wokelang +type UserId = String; +type Temperature = Float; +type Point = { x: Float, y: Float }; + +remember user: UserId = "user_123"; +remember temp: Temperature = 72.5; +``` + +--- + +## Struct Types (Planned) + +Define structured data: + +```wokelang +type Person = { + name: String, + age: Int, + email: Maybe String +}; + +remember alice: Person = { + name: "Alice", + age: 30, + email: Some("alice@example.com") +}; +``` + +--- + +## Enum Types (Planned) + +Define variants: + +```wokelang +type Status = Active | Inactive | Pending; +type Result[T] = Success(T) | Failure(String); + +remember status: Status = Active; +remember result: Result[Int] = Success(42); +``` + +--- + +## Type Conversions + +### Built-in Conversions + +```wokelang +// To String +remember s = toString(42); // "42" +remember s2 = toString(3.14); // "3.14" +remember s3 = toString(true); // "true" + +// To Int +remember i = toInt("42"); // 42 +remember i2 = toInt(3.14); // 3 (truncates) + +// To Float +remember f = toFloat("3.14"); // 3.14 +remember f2 = toFloat(42); // 42.0 +``` + +### Mixed-Type Arithmetic + +```wokelang +// Int + Float promotes to Float +remember mixed = 5 + 3.5; // 8.5 (Float) +``` + +--- + +## Scope + +Variables are scoped to their block: + +```wokelang +to main() { + remember x = 10; + + when true { + remember y = 20; + print(x); // Can access x from outer scope + print(y); // Can access y + } + + print(x); // Can still access x + // print(y); // Error: y not in scope +} +``` + +--- + +## Constants (Planned) + +Immutable values: + +```wokelang +const MAX_SIZE = 100; +const PI = 3.14159; +const APP_NAME = "MyApp"; +``` + +--- + +## Complete Example + +```wokelang +to main() { + hello "Variables and types demo"; + + // Primitives + remember name = "WokeLang"; + remember version = 1; + remember stable = true; + + // Type annotations + remember count: Int = 0; + + // Arrays + remember features = ["consent", "gratitude", "emotes"]; + + // Unit values + remember codeLines = 5000 measured in lines; + + // Operations + remember greeting = "Hello, " + name + "!"; + remember doubled = version * 2; + remember featureCount = len(features); + + // Output + print(greeting); + print("Version: " + toString(version)); + print("Stable: " + toString(stable)); + print("Features: " + toString(featureCount)); + + // Type conversions + remember versionStr = toString(version); + remember parsed = toInt("42"); + + print("Parsed: " + toString(parsed)); + + goodbye "Demo complete"; +} +``` + +--- + +## Best Practices + +### 1. Use Descriptive Names + +```wokelang +// Good +remember userName = "Alice"; +remember totalItems = 42; +remember isEnabled = true; + +// Bad +remember u = "Alice"; +remember n = 42; +remember b = true; +``` + +### 2. Initialize Variables + +```wokelang +// Good: Initialized +remember count = 0; + +// Avoid: Using before initialization +remember count; // Not valid in WokeLang +``` + +### 3. Use Type Annotations for Clarity + +```wokelang +// Clearer with type +remember config: [String] = []; +remember result: Maybe Int = findValue(); +``` + +### 4. Prefer Immutability (When Available) + +```wokelang +// Prefer const when value won't change +const MAX_RETRIES = 3; + +// Use remember for values that change +remember currentRetry = 0; +``` + +--- + +## Next Steps + +- [Functions](Functions.md) +- [Control Flow](Control-Flow.md) +- [Built-in Functions](../Reference/Builtin-Functions.md) diff --git a/docs/wiki/Reference/Builtin-Functions.md b/docs/wiki/Reference/Builtin-Functions.md new file mode 100644 index 0000000..0d1cb64 --- /dev/null +++ b/docs/wiki/Reference/Builtin-Functions.md @@ -0,0 +1,383 @@ +# Built-in Functions + +WokeLang provides these built-in functions available in all programs. + +--- + +## I/O Functions + +### print + +Output values to the console. + +```wokelang +print(value1, value2, ...) +``` + +**Parameters:** +- `...values` - Any number of values to print + +**Returns:** `Unit` + +**Examples:** +```wokelang +print("Hello, World!"); +print("The answer is:", 42); +print("Name:", name, "Age:", age); +``` + +**Output:** +``` +Hello, World! +The answer is: 42 +Name: Alice Age: 30 +``` + +--- + +## String Functions + +### len + +Get the length of a string or array. + +```wokelang +len(value) → Int +``` + +**Parameters:** +- `value: String | Array` - The string or array to measure + +**Returns:** `Int` - The length + +**Examples:** +```wokelang +len("hello") // → 5 +len("") // → 0 +len([1, 2, 3]) // → 3 +len([]) // → 0 +``` + +### toString + +Convert any value to a string representation. + +```wokelang +toString(value) → String +``` + +**Parameters:** +- `value: Any` - The value to convert + +**Returns:** `String` - String representation + +**Examples:** +```wokelang +toString(42) // → "42" +toString(3.14) // → "3.14" +toString(true) // → "true" +toString([1, 2]) // → "[1, 2]" +``` + +--- + +## Numeric Functions + +### toInt + +Convert a value to an integer. + +```wokelang +toInt(value) → Int +``` + +**Parameters:** +- `value: String | Float | Int` - The value to convert + +**Returns:** `Int` - The integer value + +**Errors:** Throws if string cannot be parsed + +**Examples:** +```wokelang +toInt("42") // → 42 +toInt("-17") // → -17 +toInt(3.14) // → 3 +toInt(3.99) // → 3 (truncates) +toInt(42) // → 42 (identity) +``` + +### toFloat + +Convert a value to a floating-point number. + +```wokelang +toFloat(value) → Float +``` + +**Parameters:** +- `value: String | Int | Float` - The value to convert + +**Returns:** `Float` - The float value + +**Errors:** Throws if string cannot be parsed + +**Examples:** +```wokelang +toFloat("3.14") // → 3.14 +toFloat("42") // → 42.0 +toFloat(42) // → 42.0 +toFloat(3.14) // → 3.14 (identity) +``` + +--- + +## Type Functions (Planned) + +### typeOf + +Get the type name of a value. + +```wokelang +typeOf(value) → String +``` + +**Parameters:** +- `value: Any` - The value to inspect + +**Returns:** `String` - The type name + +**Examples:** +```wokelang +typeOf(42) // → "Int" +typeOf(3.14) // → "Float" +typeOf("hello") // → "String" +typeOf(true) // → "Bool" +typeOf([1, 2]) // → "Array" +``` + +### isInt, isFloat, isString, isBool, isArray + +Type checking predicates. + +```wokelang +isInt(value) → Bool +isFloat(value) → Bool +isString(value) → Bool +isBool(value) → Bool +isArray(value) → Bool +``` + +**Examples:** +```wokelang +isInt(42) // → true +isInt("42") // → false +isString("hello") // → true +isArray([1, 2]) // → true +``` + +--- + +## Array Functions (Planned) + +### push + +Add an element to the end of an array. + +```wokelang +push(array, element) → Array +``` + +**Examples:** +```wokelang +remember arr = [1, 2, 3]; +arr = push(arr, 4); // → [1, 2, 3, 4] +``` + +### pop + +Remove and return the last element. + +```wokelang +pop(array) → { element: T, array: Array } +``` + +### concat + +Concatenate two arrays. + +```wokelang +concat(array1, array2) → Array +``` + +**Examples:** +```wokelang +concat([1, 2], [3, 4]) // → [1, 2, 3, 4] +``` + +### slice + +Extract a portion of an array. + +```wokelang +slice(array, start, end) → Array +``` + +**Examples:** +```wokelang +slice([1, 2, 3, 4, 5], 1, 4) // → [2, 3, 4] +``` + +### map + +Transform each element. + +```wokelang +map(array, function) → Array +``` + +### filter + +Filter elements by predicate. + +```wokelang +filter(array, predicate) → Array +``` + +### reduce + +Reduce array to single value. + +```wokelang +reduce(array, initial, function) → T +``` + +--- + +## Math Functions (Planned) + +### abs + +Absolute value. + +```wokelang +abs(n) → Int | Float +``` + +### min, max + +Minimum and maximum of two values. + +```wokelang +min(a, b) → Int | Float +max(a, b) → Int | Float +``` + +### floor, ceil, round + +Rounding functions. + +```wokelang +floor(f) → Int +ceil(f) → Int +round(f) → Int +``` + +### sqrt, pow + +Square root and power. + +```wokelang +sqrt(n) → Float +pow(base, exponent) → Float +``` + +--- + +## Random Functions (Planned) + +### random + +Generate random number. + +```wokelang +random() → Float // 0.0 to 1.0 +random(max) → Int // 0 to max-1 +random(min, max) → Int // min to max-1 +``` + +--- + +## Time Functions (Planned) + +### now + +Get current timestamp. + +```wokelang +now() → Int // Unix timestamp in milliseconds +``` + +### sleep + +Pause execution. + +```wokelang +sleep(ms: Int) → Unit +``` + +--- + +## Example: Using Built-ins + +```wokelang +to main() { + hello "Built-in functions demo"; + + // String operations + remember greeting = "Hello, WokeLang!"; + print("Length:", len(greeting)); + + // Numeric conversions + remember numStr = "42"; + remember num = toInt(numStr); + print("Parsed number:", num); + + // Array operations + remember numbers = [1, 2, 3, 4, 5]; + print("Array length:", len(numbers)); + + // Type conversions + remember pi = 3.14159; + print("Pi as string:", toString(pi)); + print("Pi as int:", toInt(pi)); + + goodbye "Demo complete"; +} +``` + +--- + +## Adding Custom Built-ins + +Built-ins are implemented in `src/interpreter/mod.rs`: + +```rust +fn call_builtin(&mut self, name: &str, args: &[Value]) -> Result> { + match name { + "myFunction" => { + // Implementation + Ok(Some(Value::Int(42))) + } + _ => Ok(None), + } +} +``` + +--- + +## Next Steps + +- [Operators Reference](Operators.md) +- [Types Reference](Types.md) +- [Standard Library](Standard-Library.md) diff --git a/docs/wiki/Reference/CLI.md b/docs/wiki/Reference/CLI.md new file mode 100644 index 0000000..38b5e9b --- /dev/null +++ b/docs/wiki/Reference/CLI.md @@ -0,0 +1,353 @@ +# CLI Reference + +The `woke` command-line interface for WokeLang. + +--- + +## Installation + +```bash +cargo install --path . +# or +cargo build --release +# Binary at: target/release/woke +``` + +--- + +## Basic Usage + +```bash +# Run a WokeLang file +woke program.woke + +# Start the REPL +woke repl + +# Show version +woke --version + +# Show help +woke --help +``` + +--- + +## Commands + +### Run (Default) + +Execute a WokeLang source file: + +```bash +woke +woke run +``` + +**Options:** +| Flag | Description | +|------|-------------| +| `-v, --verbose` | Show execution details | +| `--no-hello` | Suppress hello/goodbye messages | + +**Example:** +```bash +woke examples/demo.woke +woke run --verbose examples/demo.woke +``` + +### REPL + +Start the interactive Read-Eval-Print Loop: + +```bash +woke repl +``` + +**REPL Commands:** +| Command | Description | +|---------|-------------| +| `:help` | Show help | +| `:quit` | Exit REPL | +| `:reset` | Clear state | +| `:load ` | Load a file | +| `:ast ` | Show AST | + +### Compile + +Compile WokeLang to WebAssembly: + +```bash +woke compile [OPTIONS] +``` + +**Options:** +| Flag | Description | +|------|-------------| +| `--wasm` | Output WASM binary | +| `-o, --output ` | Output file path | +| `--opt-level ` | Optimization level (0, 1, s, z) | +| `--wat` | Output WAT (text format) | + +**Example:** +```bash +woke compile --wasm -o add.wasm math.woke +woke compile --wat -o debug.wat math.woke +``` + +### Check + +Parse and type-check without executing: + +```bash +woke check +``` + +**Options:** +| Flag | Description | +|------|-------------| +| `--strict` | Enable strict mode | +| `--ast` | Print AST | +| `--tokens` | Print token stream | + +**Example:** +```bash +woke check --strict program.woke +woke check --ast program.woke +``` + +### Format (Planned) + +Format WokeLang source code: + +```bash +woke fmt +woke fmt --check # Check without modifying +``` + +--- + +## Global Options + +| Flag | Description | +|------|-------------| +| `-h, --help` | Show help message | +| `-V, --version` | Show version | +| `-q, --quiet` | Suppress output | +| `--color ` | Color output (auto, always, never) | + +--- + +## Exit Codes + +| Code | Meaning | +|------|---------| +| 0 | Success | +| 1 | General error | +| 2 | Parse error | +| 3 | Runtime error | +| 4 | File not found | + +--- + +## Environment Variables + +| Variable | Description | Default | +|----------|-------------|---------| +| `WOKE_PATH` | Module search paths | `.` | +| `WOKE_COLOR` | Color output | `auto` | +| `WOKE_VERBOSE` | Verbose output | `false` | + +--- + +## Configuration Files + +### Project Configuration (woke.toml) + +```toml +[package] +name = "my-project" +version = "0.1.0" +edition = "2024" + +[dependencies] +# Future: package dependencies + +[build] +opt-level = "s" +target = "wasm" +``` + +--- + +## Examples + +### Running Programs + +```bash +# Simple run +woke hello.woke + +# With verbose output +woke -v program.woke + +# Multiple files (planned) +woke main.woke lib.woke +``` + +### REPL Session + +```bash +$ woke repl +WokeLang REPL v0.1.0 +Type :help for commands, :quit to exit + +woke> remember x = 42 +woke> print(x * 2) +84 +woke> :quit +``` + +### Compilation + +```bash +# Compile to WASM +woke compile --wasm -o output.wasm input.woke + +# View as WAT +woke compile --wat -o output.wat input.woke + +# Optimized build +woke compile --wasm --opt-level=s -o optimized.wasm input.woke +``` + +### Checking Code + +```bash +# Basic check +woke check program.woke + +# Strict mode +woke check --strict program.woke + +# View parsed AST +woke check --ast program.woke +``` + +--- + +## Shell Completion + +### Bash + +```bash +# Add to ~/.bashrc +eval "$(woke completions bash)" +``` + +### Zsh + +```bash +# Add to ~/.zshrc +eval "$(woke completions zsh)" +``` + +### Fish + +```bash +woke completions fish > ~/.config/fish/completions/woke.fish +``` + +--- + +## Debugging + +### Verbose Output + +```bash +woke -v program.woke +# Shows: parsing, execution phases, timing +``` + +### Token Stream + +```bash +woke check --tokens program.woke +# Output: +# [0..2] Remember +# [3..4] Identifier("x") +# [5..6] Equal +# ... +``` + +### AST Dump + +```bash +woke check --ast program.woke +# Output: +# Program { +# items: [ +# Function { +# name: "main", +# ... +# } +# ] +# } +``` + +--- + +## Integration + +### With Make + +```makefile +WOKE = woke +WASM_FLAGS = --wasm --opt-level=s + +%.wasm: %.woke + $(WOKE) compile $(WASM_FLAGS) -o $@ $< + +all: main.wasm + +clean: + rm -f *.wasm +``` + +### With npm/package.json + +```json +{ + "scripts": { + "build": "woke compile --wasm -o dist/main.wasm src/main.woke", + "check": "woke check src/*.woke", + "test": "woke test" + } +} +``` + +### With CI (GitHub Actions) + +```yaml +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Rust + uses: dtolnay/rust-action@stable + - name: Build WokeLang + run: cargo build --release + - name: Check code + run: ./target/release/woke check src/*.woke + - name: Compile to WASM + run: ./target/release/woke compile --wasm -o output.wasm src/main.woke +``` + +--- + +## Next Steps + +- [REPL Guide](../Getting-Started/REPL.md) +- [Installation](../Getting-Started/Installation.md) +- [WASM Compilation](../Internals/WASM-Compilation.md) diff --git a/docs/wiki/Reference/Keywords.md b/docs/wiki/Reference/Keywords.md new file mode 100644 index 0000000..17329e6 --- /dev/null +++ b/docs/wiki/Reference/Keywords.md @@ -0,0 +1,273 @@ +# Keywords Reference + +Complete list of reserved keywords in WokeLang. + +--- + +## Control Flow Keywords + +| Keyword | Purpose | Example | +|---------|---------|---------| +| `to` | Define a function | `to greet() { }` | +| `give` | Part of return statement | `give back value;` | +| `back` | Part of return statement | `give back value;` | +| `remember` | Declare a variable | `remember x = 5;` | +| `when` | Conditional branch | `when x > 0 { }` | +| `otherwise` | Else branch | `otherwise { }` | +| `repeat` | Loop construct | `repeat 5 times { }` | +| `times` | Part of repeat loop | `repeat n times { }` | + +--- + +## Consent & Safety Keywords + +| Keyword | Purpose | Example | +|---------|---------|---------| +| `only` | Part of consent block | `only if okay "..." { }` | +| `if` | Part of consent block | `only if okay "..." { }` | +| `okay` | Part of consent block | `only if okay "..." { }` | +| `attempt` | Try block | `attempt safely { }` | +| `safely` | Part of attempt | `attempt safely { }` | +| `or` | Fallback clause | `or reassure "...";` | +| `reassure` | Recovery message | `or reassure "...";` | +| `complain` | Raise error | `complain "message";` | + +--- + +## Gratitude Keywords + +| Keyword | Purpose | Example | +|---------|---------|---------| +| `thanks` | Gratitude block/expression | `thanks to { }` | + +--- + +## Lifecycle Keywords + +| Keyword | Purpose | Example | +|---------|---------|---------| +| `hello` | Function entry message | `hello "Starting";` | +| `goodbye` | Function exit message | `goodbye "Done";` | + +--- + +## Concurrency Keywords + +| Keyword | Purpose | Example | +|---------|---------|---------| +| `worker` | Define async worker | `worker name { }` | +| `side` | Part of side quest | `side quest name { }` | +| `quest` | Part of side quest | `side quest name { }` | +| `superpower` | Define capability | `superpower name { }` | +| `spawn` | Start worker | `spawn worker name;` | + +--- + +## Pattern Matching Keywords + +| Keyword | Purpose | Example | +|---------|---------|---------| +| `decide` | Pattern match | `decide based on x { }` | +| `based` | Part of pattern match | `decide based on x { }` | +| `on` | Part of pattern match | `decide based on x { }` | + +--- + +## Unit Keywords + +| Keyword | Purpose | Example | +|---------|---------|---------| +| `measured` | Unit annotation | `100 measured in meters` | +| `in` | Part of unit annotation | `measured in meters` | + +--- + +## Type Keywords + +| Keyword | Purpose | Example | +|---------|---------|---------| +| `type` | Type definition | `type Name = String;` | +| `const` | Constant declaration | `const MAX = 100;` | +| `Maybe` | Optional type | `Maybe Int` | + +--- + +## Boolean Keywords + +| Keyword | Purpose | Example | +|---------|---------|---------| +| `true` | Boolean true | `remember x = true;` | +| `false` | Boolean false | `remember x = false;` | +| `and` | Logical AND | `a and b` | +| `or` | Logical OR | `a or b` | +| `not` | Logical NOT | `not x` | + +--- + +## Module Keywords + +| Keyword | Purpose | Example | +|---------|---------|---------| +| `use` | Import module | `use std.io;` | +| `renamed` | Alias import | `use std.io renamed io;` | +| `share` | Export item | `share myFunction;` | + +--- + +## Primitive Type Names + +| Type | Description | +|------|-------------| +| `Int` | 64-bit integer | +| `Float` | 64-bit float | +| `String` | UTF-8 string | +| `Bool` | Boolean | + +--- + +## Reserved for Future Use + +These keywords are reserved but not yet implemented: + +| Keyword | Planned Purpose | +|---------|-----------------| +| `async` | Async functions | +| `await` | Await async result | +| `match` | Alternative pattern match | +| `case` | Pattern case | +| `class` | Class definition | +| `trait` | Trait definition | +| `impl` | Implementation | +| `pub` | Public visibility | +| `priv` | Private visibility | +| `mut` | Mutable reference | +| `ref` | Reference | +| `yield` | Generator yield | +| `gen` | Generator function | +| `stop` | Break from loop | +| `skip` | Continue loop | + +--- + +## Usage Examples + +### Complete Function + +```wokelang +to calculateTotal(items: [Float]) → Float { + hello "Calculating total"; + + remember total = 0.0; + remember i = 0; + + repeat len(items) times { + total = total + items[i]; + i = i + 1; + } + + give back total; + + goodbye "Calculation complete"; +} +``` + +### Pattern Matching + +```wokelang +decide based on status { + "active" → { + print("User is active"); + } + "inactive" → { + print("User is inactive"); + } + _ → { + print("Unknown status"); + } +} +``` + +### Error Handling + +```wokelang +attempt safely { + remember data = fetchData(); + when data == none { + complain "No data found"; + } + processData(data); +} or reassure "Data fetch failed, using cached version"; +``` + +### Consent Block + +```wokelang +only if okay "network_access" { + remember response = httpGet(url); + processResponse(response); +} +``` + +### Gratitude + +```wokelang +thanks to { + "Open Source" → "For making this possible"; + "Contributors" → "For their hard work"; +} +``` + +--- + +## Operator Keywords + +Some keywords function as operators: + +| Keyword | Type | Precedence | +|---------|------|------------| +| `and` | Binary | Low | +| `or` | Binary | Lower | +| `not` | Unary | High | + +--- + +## Context-Sensitive Usage + +Some words are only keywords in specific contexts: + +| Word | Context | Meaning | +|------|---------|---------| +| `in` | After `measured` | Unit specification | +| `in` | Other contexts | Not a keyword | +| `on` | After `based` | Pattern match | +| `on` | Pragma context | Enable pragma | + +--- + +## Identifier Rules + +Keywords cannot be used as: +- Variable names +- Function names +- Type names +- Parameter names + +```wokelang +// Invalid - 'remember' is a keyword +remember remember = 5; + +// Invalid - 'when' is a keyword +to when() { } + +// Valid - similar but different +remember rememberMe = 5; +to whenReady() { } +``` + +--- + +## Next Steps + +- [Operators Reference](Operators.md) +- [Built-in Functions](Builtin-Functions.md) +- [Language Specification](Language-Specification.md) diff --git a/docs/wiki/Reference/Language-Specification.md b/docs/wiki/Reference/Language-Specification.md new file mode 100644 index 0000000..8cc07cc --- /dev/null +++ b/docs/wiki/Reference/Language-Specification.md @@ -0,0 +1,592 @@ +# WokeLang Language Specification + +**Version**: 0.1.0 +**Status**: Draft + +--- + +## 1. Lexical Structure + +### 1.1 Character Set + +WokeLang source files are encoded in UTF-8. The language supports: +- ASCII letters (a-z, A-Z) +- Digits (0-9) +- Unicode letters in strings and comments +- Special characters: `→`, `@`, `#` + +### 1.2 Whitespace and Comments + +```ebnf +whitespace = " " | "\t" | "\n" | "\r" ; +line_comment = "//" , { any_char } , newline ; +block_comment = "/*" , { any_char } , "*/" ; +``` + +### 1.3 Identifiers + +```ebnf +identifier = letter , { letter | digit | "_" } ; +letter = "a".."z" | "A".."Z" ; +digit = "0".."9" ; +``` + +Reserved identifiers cannot be used as variable or function names. + +### 1.4 Keywords + +**Control Flow** +``` +to, give, back, remember, when, otherwise, repeat, times +``` + +**Consent & Safety** +``` +only, if, okay, attempt, safely, or, reassure, complain +``` + +**Gratitude** +``` +thanks, to +``` + +**Lifecycle** +``` +hello, goodbye +``` + +**Concurrency** +``` +worker, side, quest, superpower, spawn +``` + +**Pattern Matching** +``` +decide, based, on +``` + +**Units** +``` +measured, in +``` + +**Types** +``` +type, const, String, Int, Float, Bool, Maybe +``` + +**Boolean** +``` +true, false, and, or, not +``` + +### 1.5 Literals + +#### Integer Literals +```ebnf +integer = [ "-" ] , digit , { digit } ; +``` + +Examples: `42`, `-17`, `0`, `1000000` + +#### Float Literals +```ebnf +float = [ "-" ] , digit , { digit } , "." , digit , { digit } ; +``` + +Examples: `3.14`, `-0.5`, `100.0` + +#### String Literals +```ebnf +string = '"' , { string_char } , '"' ; +string_char = any_char_except_quote | escape_sequence ; +escape_sequence = "\\" , ( "n" | "t" | "r" | '"' | "'" | "\\" ) ; +``` + +Examples: `"Hello"`, `"Line1\nLine2"`, `"Tab\there"` + +#### Boolean Literals +```ebnf +bool = "true" | "false" ; +``` + +#### Array Literals +```ebnf +array = "[" , [ expression , { "," , expression } ] , "]" ; +``` + +Examples: `[1, 2, 3]`, `["a", "b"]`, `[]` + +--- + +## 2. Types + +### 2.1 Primitive Types + +| Type | Description | Example | +|------|-------------|---------| +| `Int` | 64-bit signed integer | `42` | +| `Float` | 64-bit floating point | `3.14` | +| `String` | UTF-8 string | `"hello"` | +| `Bool` | Boolean value | `true` | + +### 2.2 Composite Types + +#### Arrays +```wokelang +remember numbers: [Int] = [1, 2, 3]; +remember names: [String] = ["Alice", "Bob"]; +``` + +#### Optional Types +```wokelang +remember maybeValue: Maybe Int = findValue(); +``` + +#### Reference Types +```wokelang +to modify(data: &[Int]) { + // Can modify the referenced array +} +``` + +### 2.3 Custom Types + +#### Type Aliases +```wokelang +type UserId = String; +type Temperature = Float; +``` + +#### Struct Types +```wokelang +type Person = { + name: String, + age: Int, + email: Maybe String +}; +``` + +#### Enum Types +```wokelang +type Result = Success(String) | Failure(String); +type Option = Some(Int) | None; +``` + +### 2.4 Unit Types + +```wokelang +remember distance = 100 measured in meters; +remember temp = 98.6 measured in fahrenheit; +``` + +--- + +## 3. Expressions + +### 3.1 Operator Precedence (lowest to highest) + +| Precedence | Operators | Associativity | +|------------|-----------|---------------| +| 1 | `or` | Left | +| 2 | `and` | Left | +| 3 | `==`, `!=` | Left | +| 4 | `<`, `>`, `<=`, `>=` | Left | +| 5 | `+`, `-` | Left | +| 6 | `*`, `/`, `%` | Left | +| 7 | `not`, `-` (unary) | Right | +| 8 | function call, array index | Left | + +### 3.2 Arithmetic Expressions + +```wokelang +remember sum = a + b; +remember product = x * y; +remember quotient = total / count; +remember remainder = value % 2; +remember negative = -number; +``` + +### 3.3 Comparison Expressions + +```wokelang +remember isEqual = a == b; +remember isNotEqual = a != b; +remember isLess = a < b; +remember isGreater = a > b; +remember isLessOrEqual = a <= b; +remember isGreaterOrEqual = a >= b; +``` + +### 3.4 Logical Expressions + +```wokelang +remember bothTrue = a and b; +remember eitherTrue = a or b; +remember opposite = not condition; +``` + +### 3.5 Function Calls + +```wokelang +remember result = add(1, 2); +remember greeting = greet("World"); +print("Hello"); +``` + +### 3.6 Gratitude Expressions + +```wokelang +remember credit = thanks("Open Source Community"); +``` + +--- + +## 4. Statements + +### 4.1 Variable Declaration + +```ebnf +variable_decl = "remember" , identifier , "=" , expression , + [ "measured" , "in" , unit ] , ";" ; +``` + +```wokelang +remember x = 42; +remember name = "Alice"; +remember speed = 60 measured in mph; +``` + +### 4.2 Assignment + +```ebnf +assignment = identifier , "=" , expression , ";" ; +``` + +```wokelang +x = x + 1; +name = "Bob"; +``` + +### 4.3 Return Statement + +```ebnf +return_stmt = "give" , "back" , expression , ";" ; +``` + +```wokelang +give back result; +give back x + y; +``` + +### 4.4 Conditional Statement + +```ebnf +conditional = "when" , expression , "{" , { statement } , "}" , + [ "otherwise" , "{" , { statement } , "}" ] ; +``` + +```wokelang +when x > 0 { + print("Positive"); +} otherwise { + print("Non-positive"); +} +``` + +### 4.5 Loop Statement + +```ebnf +loop = "repeat" , expression , "times" , "{" , { statement } , "}" ; +``` + +```wokelang +repeat 5 times { + print("Hello!"); +} + +repeat count times { + process(item); +} +``` + +### 4.6 Attempt Block + +```ebnf +attempt_block = "attempt" , "safely" , "{" , { statement } , "}" , + "or" , "reassure" , string , ";" ; +``` + +```wokelang +attempt safely { + remember data = fetchData(); + processData(data); +} or reassure "Operation failed, but that's okay"; +``` + +### 4.7 Consent Block + +```ebnf +consent_block = "only" , "if" , "okay" , string , "{" , { statement } , "}" ; +``` + +```wokelang +only if okay "camera_access" { + remember photo = takePhoto(); + save(photo); +} +``` + +### 4.8 Complain Statement + +```ebnf +complain_stmt = "complain" , string , ";" ; +``` + +```wokelang +complain "Something unexpected happened"; +``` + +### 4.9 Pattern Matching + +```ebnf +decide_stmt = "decide" , "based" , "on" , expression , "{" , { match_arm } , "}" ; +match_arm = pattern , "→" , "{" , { statement } , "}" ; +pattern = literal | identifier | "_" ; +``` + +```wokelang +decide based on status { + "success" → { + print("It worked!"); + } + "error" → { + complain "Something went wrong"; + } + _ → { + print("Unknown status"); + } +} +``` + +--- + +## 5. Declarations + +### 5.1 Function Declaration + +```ebnf +function_def = [ emote_tag ] , "to" , identifier , + "(" , [ param_list ] , ")" , [ "→" , type ] , + "{" , + [ "hello" , string , ";" ] , + { statement } , + [ "goodbye" , string , ";" ] , + "}" ; +``` + +```wokelang +@important +to calculateTotal(items: [Item]) → Float { + hello "Starting calculation"; + + remember total = 0.0; + repeat len(items) times { + total = total + items[i].price; + } + + give back total; + + goodbye "Calculation complete"; +} +``` + +### 5.2 Worker Declaration + +```ebnf +worker_def = "worker" , identifier , "{" , { statement } , "}" ; +``` + +```wokelang +worker dataProcessor { + remember data = fetchData(); + remember result = processData(data); + saveResult(result); +} +``` + +### 5.3 Side Quest Declaration + +```ebnf +side_quest_def = "side" , "quest" , identifier , "{" , { statement } , "}" ; +``` + +```wokelang +side quest backgroundSync { + attempt safely { + syncWithServer(); + } or reassure "Sync will retry later"; +} +``` + +### 5.4 Gratitude Declaration + +```ebnf +gratitude_decl = "thanks" , "to" , "{" , { gratitude_entry } , "}" ; +gratitude_entry = string , "→" , string , ";" ; +``` + +```wokelang +thanks to { + "Rust Community" → "For the amazing tooling"; + "Contributors" → "For their valuable input"; +} +``` + +### 5.5 Pragma Declaration + +```ebnf +pragma = "#" , pragma_directive , ( "on" | "off" ) , ";" ; +pragma_directive = "care" | "strict" | "verbose" ; +``` + +```wokelang +#care on; // Enable caring mode (extra safety checks) +#verbose on; // Enable verbose output +#strict on; // Enable strict type checking +``` + +--- + +## 6. Emote Tags + +Emote tags provide emotional context to code. + +```ebnf +emote_tag = "@" , identifier , [ "(" , emote_params , ")" ] ; +emote_params = emote_param , { "," , emote_param } ; +emote_param = identifier , "=" , ( number | string | identifier ) ; +``` + +### Standard Emote Tags + +| Tag | Meaning | Use Case | +|-----|---------|----------| +| `@important` | Critical code | Security-sensitive operations | +| `@cautious` | Proceed carefully | Data deletion, modifications | +| `@experimental` | Not stable | New features, testing | +| `@deprecated` | Will be removed | Legacy code | +| `@happy` | Positive outcome | Success handlers | +| `@sad` | Negative outcome | Error handlers | +| `@curious` | Exploratory | Debug code, logging | + +```wokelang +@cautious +to deleteAllData() { + only if okay "delete_data" { + clearDatabase(); + } +} + +@experimental(stability="alpha") +to newFeature() { + // This might change +} +``` + +--- + +## 7. Module System + +### 7.1 Imports + +```ebnf +module_import = "use" , qualified_name , [ "renamed" , identifier ] , ";" ; +qualified_name = identifier , { "." , identifier } ; +``` + +```wokelang +use std.io; +use std.json renamed json; +use myapp.utils.helpers; +``` + +### 7.2 Exports (Planned) + +```wokelang +share calculateTotal; +share { + Person, + createPerson, + updatePerson +}; +``` + +--- + +## 8. Built-in Functions + +| Function | Signature | Description | +|----------|-----------|-------------| +| `print` | `(...) → Unit` | Output to console | +| `len` | `(String\|Array) → Int` | Get length | +| `toString` | `(Any) → String` | Convert to string | +| `toInt` | `(String\|Float) → Int` | Convert to integer | +| `toFloat` | `(String\|Int) → Float` | Convert to float | + +--- + +## 9. Memory Model + +WokeLang uses automatic memory management: +- Values are immutable by default +- References allow controlled mutation +- No manual memory management required +- Garbage collection in interpreter mode +- Linear memory in WASM mode + +--- + +## 10. Concurrency Model + +### Workers +Workers execute code asynchronously: +```wokelang +worker myWorker { + // Runs in background +} + +spawn worker myWorker; +``` + +### Side Quests +Lower-priority background tasks: +```wokelang +side quest cleanup { + // Runs when system is idle +} +``` + +### Superpowers +Special capabilities requiring permission: +```wokelang +superpower fileAccess { + // Has elevated permissions +} +``` + +--- + +## Appendix A: EBNF Grammar + +See [grammar/wokelang.ebnf](../../../grammar/wokelang.ebnf) for the complete EBNF specification. + +## Appendix B: Reserved for Future Use + +The following are reserved for future language features: +- `async`, `await` +- `match`, `case` +- `class`, `trait`, `impl` +- `pub`, `priv` +- `mut`, `ref` +- `yield`, `gen` diff --git a/docs/wiki/Reference/Operators.md b/docs/wiki/Reference/Operators.md new file mode 100644 index 0000000..c33b3f7 --- /dev/null +++ b/docs/wiki/Reference/Operators.md @@ -0,0 +1,369 @@ +# Operators Reference + +Complete reference of operators in WokeLang. + +--- + +## Operator Precedence + +From lowest to highest: + +| Precedence | Operators | Associativity | Description | +|------------|-----------|---------------|-------------| +| 1 | `or` | Left | Logical OR | +| 2 | `and` | Left | Logical AND | +| 3 | `==`, `!=` | Left | Equality | +| 4 | `<`, `>`, `<=`, `>=` | Left | Comparison | +| 5 | `+`, `-` | Left | Addition, Subtraction | +| 6 | `*`, `/`, `%` | Left | Multiplication, Division, Modulo | +| 7 | `not`, `-` (unary) | Right | Logical NOT, Negation | +| 8 | `()`, `[]` | Left | Call, Index | + +--- + +## Arithmetic Operators + +### Addition (`+`) + +```wokelang +remember sum = 5 + 3; // 8 +remember decimal = 1.5 + 2.5; // 4.0 +remember text = "Hello" + " " + "World"; // "Hello World" +``` + +| Left | Right | Result | +|------|-------|--------| +| Int | Int | Int | +| Float | Float | Float | +| Int | Float | Float | +| Float | Int | Float | +| String | String | String | + +### Subtraction (`-`) + +```wokelang +remember diff = 10 - 4; // 6 +remember neg = 5 - 10; // -5 +remember decimal = 5.0 - 2.5; // 2.5 +``` + +| Left | Right | Result | +|------|-------|--------| +| Int | Int | Int | +| Float | Float | Float | +| Int | Float | Float | +| Float | Int | Float | + +### Multiplication (`*`) + +```wokelang +remember product = 6 * 7; // 42 +remember scaled = 2.5 * 4; // 10.0 +``` + +| Left | Right | Result | +|------|-------|--------| +| Int | Int | Int | +| Float | Float | Float | +| Int | Float | Float | +| Float | Int | Float | + +### Division (`/`) + +```wokelang +remember quotient = 20 / 4; // 5 +remember decimal = 7.0 / 2.0; // 3.5 +remember intDiv = 7 / 2; // 3 (integer division) +``` + +| Left | Right | Result | Notes | +|------|-------|--------|-------| +| Int | Int | Int | Truncates | +| Float | Float | Float | | +| Int | Float | Float | | +| Float | Int | Float | | + +**Division by zero:** +```wokelang +remember x = 10 / 0; // Runtime error +``` + +### Modulo (`%`) + +```wokelang +remember remainder = 17 % 5; // 2 +remember even = 10 % 2; // 0 +remember odd = 11 % 2; // 1 +``` + +| Left | Right | Result | +|------|-------|--------| +| Int | Int | Int | + +### Unary Negation (`-`) + +```wokelang +remember negative = -42; +remember pos = -(-5); // 5 +remember x = 10; +remember neg_x = -x; // -10 +``` + +--- + +## Comparison Operators + +### Equality (`==`) + +```wokelang +remember same = 5 == 5; // true +remember diff = 5 == 6; // false +remember strEq = "a" == "a"; // true +remember boolEq = true == true; // true +``` + +### Inequality (`!=`) + +```wokelang +remember diff = 5 != 6; // true +remember same = 5 != 5; // false +``` + +### Less Than (`<`) + +```wokelang +remember less = 3 < 5; // true +remember notLess = 5 < 3; // false +remember equal = 5 < 5; // false +remember strLess = "a" < "b"; // true (lexicographic) +``` + +### Greater Than (`>`) + +```wokelang +remember greater = 5 > 3; // true +remember notGreater = 3 > 5; // false +remember equal = 5 > 5; // false +``` + +### Less Than or Equal (`<=`) + +```wokelang +remember leq = 5 <= 5; // true +remember less = 3 <= 5; // true +remember greater = 6 <= 5; // false +``` + +### Greater Than or Equal (`>=`) + +```wokelang +remember geq = 5 >= 5; // true +remember greater = 5 >= 3; // true +remember less = 3 >= 5; // false +``` + +--- + +## Logical Operators + +### Logical AND (`and`) + +```wokelang +remember both = true and true; // true +remember one = true and false; // false +remember none = false and false; // false +``` + +**Short-circuit evaluation:** +```wokelang +// If first is false, second is not evaluated +remember safe = false and riskyOperation(); // riskyOperation not called +``` + +### Logical OR (`or`) + +```wokelang +remember either = true or false; // true +remember both = true or true; // true +remember none = false or false; // false +``` + +**Short-circuit evaluation:** +```wokelang +// If first is true, second is not evaluated +remember quick = true or slowOperation(); // slowOperation not called +``` + +### Logical NOT (`not`) + +```wokelang +remember opposite = not true; // false +remember double = not not true; // true +remember negFalse = not false; // true +``` + +--- + +## Special Operators + +### Arrow (`→` or `->`) + +Used for: +- Return type declaration +- Pattern match arms + +```wokelang +// Return type +to add(a: Int, b: Int) → Int { + give back a + b; +} + +// Pattern match arm +decide based on x { + 1 → { print("one"); } + 2 → { print("two"); } +} +``` + +Both Unicode (`→`) and ASCII (`->`) versions are valid. + +### Array Index (`[]`) + +```wokelang +remember arr = [10, 20, 30]; +remember first = arr[0]; // 10 +remember last = arr[2]; // 30 +``` + +### Function Call (`()`) + +```wokelang +remember result = add(1, 2); +print("Hello"); +remember length = len("test"); +``` + +### Member Access (`.`) (Planned) + +```wokelang +remember name = person.name; +remember x = point.x; +``` + +### Reference (`&`) (Planned) + +```wokelang +to modify(data: &[Int]) { + // Can modify original +} +``` + +--- + +## Operator Combinations + +### Chained Comparisons + +```wokelang +// Each comparison is separate +remember valid = x > 0 and x < 100; +remember inRange = min <= value and value <= max; +``` + +### Complex Expressions + +```wokelang +// Follows precedence rules +remember result = 2 + 3 * 4; // 14 (not 20) +remember explicit = (2 + 3) * 4; // 20 + +// Logical with comparison +remember check = x > 0 and y < 10 or z == 0; +// Equivalent to: ((x > 0) and (y < 10)) or (z == 0) +``` + +### Parentheses for Clarity + +```wokelang +// Recommended: Use parentheses for complex expressions +remember clear = (a + b) * (c + d); +remember explicit = (x > 0) and (y < 10); +``` + +--- + +## Type Coercion + +### Automatic Coercion + +```wokelang +// Int + Float → Float +remember mixed = 5 + 3.5; // 8.5 (Float) + +// Comparisons preserve types +remember eq = 5 == 5.0; // false (different types) +``` + +### Manual Conversion + +```wokelang +remember intVal = 5; +remember floatVal = toFloat(intVal); +remember eq = floatVal == 5.0; // true +``` + +--- + +## Common Patterns + +### Conditional Expression (Workaround) + +```wokelang +// WokeLang doesn't have ternary operator +// Use when/otherwise instead +remember result = 0; +when condition { + result = valueIfTrue; +} otherwise { + result = valueIfFalse; +} +``` + +### Safe Division + +```wokelang +to safeDivide(a: Int, b: Int) → Int { + when b == 0 { + complain "Division by zero"; + } + give back a / b; +} +``` + +### Bounds Checking + +```wokelang +to isInBounds(value: Int, min: Int, max: Int) → Bool { + give back value >= min and value <= max; +} +``` + +--- + +## Planned Operators + +| Operator | Purpose | Example | +|----------|---------|---------| +| `**` | Exponentiation | `2 ** 10` | +| `?` | Error propagation | `value?` | +| `??` | Null coalescing | `value ?? default` | +| `..` | Range | `1..10` | +| `...` | Spread | `[...arr, 4]` | + +--- + +## Next Steps + +- [Keywords Reference](Keywords.md) +- [Built-in Functions](Builtin-Functions.md) +- [Types Reference](Types.md) diff --git a/docs/wiki/Tutorials/First-CLI-App.md b/docs/wiki/Tutorials/First-CLI-App.md new file mode 100644 index 0000000..0a1e222 --- /dev/null +++ b/docs/wiki/Tutorials/First-CLI-App.md @@ -0,0 +1,441 @@ +# Tutorial: Building Your First CLI App + +Learn to build a command-line application in WokeLang. + +--- + +## What We'll Build + +A simple task manager that can: +- Add tasks +- List tasks +- Mark tasks complete +- Save tasks to a file + +--- + +## Prerequisites + +- WokeLang installed ([Installation Guide](../Getting-Started/Installation.md)) +- Basic WokeLang syntax ([Basic Syntax](../Getting-Started/Basic-Syntax.md)) + +--- + +## Step 1: Project Setup + +Create a new directory and file: + +```bash +mkdir task-manager +cd task-manager +touch main.woke +``` + +--- + +## Step 2: Basic Structure + +Start with the program skeleton: + +```wokelang +// main.woke +// A simple task manager + +thanks to { + "WokeLang" → "For human-centered programming"; +} + +to main() { + hello "Task Manager starting up"; + + showMenu(); + + goodbye "Thanks for using Task Manager!"; +} + +to showMenu() { + print("=== Task Manager ==="); + print("1. Add task"); + print("2. List tasks"); + print("3. Complete task"); + print("4. Quit"); + print(""); +} +``` + +Run it: + +```bash +woke main.woke +``` + +--- + +## Step 3: Task Data Structure + +Define how we represent tasks: + +```wokelang +// Task representation using arrays +// Each task: [id, description, completed] +// We'll use string arrays for simplicity + +// Global task storage +remember tasks: [[String]] = []; +remember nextId = 1; + +to addTask(description: String) { + remember task = [toString(nextId), description, "false"]; + tasks = append(tasks, task); + nextId = nextId + 1; + print("Added task #" + toString(nextId - 1) + ": " + description); +} +``` + +--- + +## Step 4: Display Tasks + +```wokelang +to listTasks() { + print(""); + print("=== Your Tasks ==="); + + when len(tasks) == 0 { + print("No tasks yet. Add some!"); + give back; + } + + remember i = 0; + repeat len(tasks) times { + remember task = tasks[i]; + remember id = task[0]; + remember desc = task[1]; + remember done = task[2]; + + remember status = "[ ]"; + when done == "true" { + status = "[✓]"; + } + + print(status + " #" + id + ": " + desc); + i = i + 1; + } + + print(""); +} +``` + +--- + +## Step 5: Complete Tasks + +```wokelang +to completeTask(taskId: Int) { + remember found = false; + remember i = 0; + + repeat len(tasks) times { + remember task = tasks[i]; + when toInt(task[0]) == taskId { + task[2] = "true"; + tasks[i] = task; + found = true; + print("Completed task #" + toString(taskId)); + } + i = i + 1; + } + + when not found { + print("Task #" + toString(taskId) + " not found"); + } +} +``` + +--- + +## Step 6: Interactive Loop + +```wokelang +to runLoop() { + remember running = true; + + repeat 1000 times { // Max iterations for safety + when not running { + // Would use 'stop' when available + } otherwise { + showMenu(); + remember choice = readInput("Enter choice: "); + + decide based on choice { + "1" → { + remember desc = readInput("Task description: "); + addTask(desc); + } + "2" → { + listTasks(); + } + "3" → { + remember idStr = readInput("Task ID to complete: "); + attempt safely { + remember id = toInt(idStr); + completeTask(id); + } or reassure "Invalid task ID"; + } + "4" → { + running = false; + } + _ → { + print("Invalid choice. Try again."); + } + } + } + } +} +``` + +--- + +## Step 7: File Persistence + +Add save/load functionality: + +```wokelang +@important +to saveTasks() { + only if okay "file_write" { + remember content = ""; + + remember i = 0; + repeat len(tasks) times { + remember task = tasks[i]; + content = content + task[0] + "," + task[1] + "," + task[2] + "\n"; + i = i + 1; + } + + writeFile("tasks.txt", content); + print("Tasks saved!"); + } +} + +to loadTasks() { + attempt safely { + only if okay "file_read" { + remember content = readFile("tasks.txt"); + // Parse content and populate tasks array + print("Tasks loaded!"); + } + } or reassure "No saved tasks found - starting fresh"; +} +``` + +--- + +## Step 8: Complete Program + +```wokelang +// main.woke - Complete Task Manager + +thanks to { + "WokeLang" → "For human-centered programming"; + "CLI Design" → "For inspiration on user interfaces"; +} + +#care on; + +// Global state +remember tasks: [[String]] = []; +remember nextId = 1; + +@happy +to main() { + hello "Task Manager v1.0"; + + print(""); + print("Welcome to Task Manager!"); + print("A simple way to track your todos."); + print(""); + + loadTasks(); + runLoop(); + saveTasks(); + + goodbye "Your tasks are safe. See you next time!"; +} + +to showMenu() { + print(""); + print("╔════════════════════╗"); + print("║ Task Manager ║"); + print("╠════════════════════╣"); + print("║ 1. Add task ║"); + print("║ 2. List tasks ║"); + print("║ 3. Complete task ║"); + print("║ 4. Save & Quit ║"); + print("╚════════════════════╝"); + print(""); +} + +to runLoop() { + remember running = true; + remember iterations = 0; + remember maxIterations = 1000; + + repeat maxIterations times { + when running { + iterations = iterations + 1; + showMenu(); + + // In a real app, this would use readLine() + // For now, we'll simulate with a demo flow + remember choice = getSimulatedInput(iterations); + + decide based on choice { + "1" → { + print("> Adding new task"); + addTask("Example task " + toString(iterations)); + } + "2" → { + listTasks(); + } + "3" → { + print("> Completing task"); + when len(tasks) > 0 { + completeTask(1); + } + } + "4" → { + print("> Saving and quitting"); + running = false; + } + _ → { + print("Invalid choice"); + } + } + } + } +} + +// Simulated input for demo +to getSimulatedInput(iteration: Int) → String { + decide based on iteration { + 1 → { give back "1"; } // Add task + 2 → { give back "1"; } // Add another + 3 → { give back "2"; } // List tasks + 4 → { give back "3"; } // Complete task + 5 → { give back "2"; } // List again + _ → { give back "4"; } // Quit + } +} + +to addTask(description: String) { + remember task = [toString(nextId), description, "false"]; + // In real WokeLang: tasks = push(tasks, task); + nextId = nextId + 1; + print("✓ Added: " + description); +} + +to listTasks() { + print(""); + print("═══ Your Tasks ═══"); + + when len(tasks) == 0 { + print(" (no tasks yet)"); + print(""); + give back; + } + + remember i = 0; + repeat len(tasks) times { + remember task = tasks[i]; + remember status = "[ ]"; + when task[2] == "true" { + status = "[✓]"; + } + print(" " + status + " " + task[1]); + i = i + 1; + } + print(""); +} + +to completeTask(taskId: Int) { + print("✓ Task #" + toString(taskId) + " completed!"); +} + +to loadTasks() { + attempt safely { + only if okay "file_read" { + print("Loading saved tasks..."); + } + } or reassure "Starting with empty task list"; +} + +@important +to saveTasks() { + only if okay "file_write" { + print("Saving tasks..."); + } + print("✓ Tasks saved!"); +} +``` + +--- + +## Step 9: Running the App + +```bash +woke main.woke +``` + +Expected output: +``` +[hello] Task Manager v1.0 + +Welcome to Task Manager! +A simple way to track your todos. + +[reassure] Starting with empty task list + +╔════════════════════╗ +║ Task Manager ║ +╠════════════════════╣ +║ 1. Add task ║ +║ 2. List tasks ║ +║ 3. Complete task ║ +║ 4. Save & Quit ║ +╚════════════════════╝ + +> Adding new task +✓ Added: Example task 1 +... +``` + +--- + +## What You Learned + +1. **Program structure** - Using `hello`/`goodbye` lifecycle +2. **Functions** - Organizing code into reusable pieces +3. **Control flow** - `when`/`otherwise`, `decide based on`, `repeat` +4. **Arrays** - Storing collections of data +5. **Error handling** - `attempt safely` blocks +6. **Consent** - `only if okay` for file access +7. **Emote tags** - `@happy`, `@important` for context + +--- + +## Exercises + +1. Add a "delete task" feature +2. Add task priorities (high, medium, low) +3. Add due dates to tasks +4. Sort tasks by completion status +5. Add color coding (when terminal colors are available) + +--- + +## Next Steps + +- [Building a Calculator](Calculator.md) +- [Working with Files](../Language-Guide/Modules.md) +- [Error Handling Best Practices](../Language-Guide/Error-Handling.md)