Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ serde_json = "1.0"
# CLI
clap = { version = "4", features = ["derive"] }
rustyline = "14"
glob = "0.3"

# Async runtime (for runtime system)
tokio = { version = "1.37", features = ["full"] }
Expand Down
200 changes: 200 additions & 0 deletions GETTING_STARTED.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
# Getting Started with Eclexia

Eclexia is an "Economics-as-Code" programming language that brings resource-aware computing to software development. This guide will help you get up and running quickly.

## Installation

### Prerequisites

- Rust 1.75 or later
- Cargo (comes with Rust)

### Building from Source

```bash
git clone https://github.com/hyperpolymath/eclexia.git
cd eclexia
cargo build --release
```

The binary will be available at `target/release/eclexia`.

## Quick Start

### 1. Create a New Project

```bash
eclexia init my-project
cd my-project
```

This creates a new Eclexia project with:
- `eclexia.toml` - Project configuration
- `src/main.ecl` - Entry point

### 2. Write Your First Program

Edit `src/main.ecl`:

```eclexia
// A simple hello world program
def main() -> Unit {
println("Hello, Economics-as-Code!")
}
```

### 3. Run Your Program

```bash
eclexia run src/main.ecl
```

## Core Concepts

### Adaptive Functions

Eclexia's key innovation is **adaptive functions** - functions with multiple implementations that the runtime selects based on resource constraints.

```eclexia
// Define helper functions
def efficient_fib(n: Int) -> Int {
fib_helper(n, 0, 1)
}

def fib_helper(n: Int, a: Int, b: Int) -> Int {
if n <= 0 { a } else { fib_helper(n - 1, b, a + b) }
}

def simple_fib(n: Int) -> Int {
if n <= 1 { n } else { simple_fib(n - 1) + simple_fib(n - 2) }
}

// Adaptive function with multiple solutions
adaptive def fibonacci(n: Int) -> Int
@requires: energy < 100J
@optimize: minimize energy
{
@solution "efficient":
@when: true
@provides: energy: 5J, latency: 10ms, carbon: 1gCO2e
{
efficient_fib(n)
}

@solution "naive":
@when: true
@provides: energy: 50J, latency: 50ms, carbon: 5gCO2e
{
simple_fib(n)
}
}
```

The runtime uses **shadow prices** to select the optimal solution based on:
- Energy consumption (Joules)
- Latency (milliseconds)
- Carbon emissions (gCO2e)

### Resource Annotations

Functions can declare resource constraints:

```eclexia
def process_data() -> Unit
@requires: energy < 10J
@requires: carbon < 5gCO2e
{
// Implementation
}
```

### Dimensional Types

Eclexia supports SI units at the type level:

```eclexia
let energy: Float<J> = 5.0J // Joules
let power: Float<W> = 100.0W // Watts
let carbon: Float<gCO2e> = 2.5gCO2e // Carbon emissions
```

## CLI Commands

| Command | Description |
|---------|-------------|
| `eclexia run <file>` | Execute an Eclexia program |
| `eclexia build <file>` | Compile a program |
| `eclexia check <file>` | Type-check without running |
| `eclexia init [name]` | Create a new project |
| `eclexia fmt <files>` | Format source files |
| `eclexia repl` | Start interactive REPL |

### Run Options

```bash
# Run with shadow price observation
eclexia run src/main.ecl --observe-shadow

# Run with carbon report
eclexia run src/main.ecl --carbon-report
```

## Example: Adaptive Fibonacci

See `examples/fibonacci.ecl` for a complete example:

```bash
eclexia run examples/fibonacci.ecl
```

Output:
```
Eclexia Adaptive Fibonacci Demo
================================
[adaptive] Selected solution 'efficient' for fibonacci

fibonacci(10) = 55

The runtime selected the best solution based on shadow prices:
efficient: cost = 5 + 10 + 1 = 16
naive: cost = 50 + 50 + 5 = 105
```

## Project Configuration

The `eclexia.toml` file configures your project:

```toml
[package]
name = "my-project"
version = "0.1.0"
edition = "2025"

[dependencies]
# Add dependencies here

[resources]
default-energy-budget = "1000J"
default-carbon-budget = "100gCO2e"
```

## Error Messages

Eclexia provides helpful error messages with source locations:

```
Type errors:
3:16: type mismatch: expected Int, found String
```

## Next Steps

- Read the [Specification](SPECIFICATION.md) for language details
- Explore the [Theory](THEORY.md) for the economics foundation
- Check the [Implementation Roadmap](IMPLEMENTATION_ROADMAP.md) for upcoming features
- Browse `examples/` for more code samples

## Getting Help

- [GitHub Issues](https://github.com/hyperpolymath/eclexia/issues)
- [Contributing Guide](CONTRIBUTING.md)
11 changes: 6 additions & 5 deletions STATE.scm
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

(define current-position
'((phase . "v0.2 - Core Development")
(overall-completion . 45)
(overall-completion . 55)
(components ((rsr-compliance ((status . "complete") (completion . 100)))
(security-docs ((status . "complete") (completion . 100)))
(scm-files ((status . "complete") (completion . 100)))
Expand All @@ -21,12 +21,12 @@
(compiler-lexer ((status . "complete") (completion . 100)))
(compiler-parser ((status . "complete") (completion . 100)))
(compiler-ast ((status . "complete") (completion . 100)))
(compiler-typeck ((status . "in-progress") (completion . 20)))
(compiler-typeck ((status . "in-progress") (completion . 60)))
(compiler-hir ((status . "not-started") (completion . 0)))
(compiler-mir ((status . "not-started") (completion . 0)))
(compiler-codegen ((status . "not-started") (completion . 0)))
(interpreter ((status . "complete") (completion . 100)))
(shadow-prices ((status . "complete") (completion . 80)))
(shadow-prices ((status . "complete") (completion . 100)))
(carbon-api-research ((status . "complete") (completion . 100)))
(runtime ((status . "not-started") (completion . 5)))
(cli ((status . "complete") (completion . 100)))
Expand All @@ -44,7 +44,8 @@
((date . "2025-12-31") (session . "academic-proofs") (notes . "Added comprehensive academic documentation: WHITEPAPER.md, PROOFS.md, SPECIFICATION.md, FORMAL_VERIFICATION.md, THEORY.md, ALGORITHMS.md, BIBLIOGRAPHY.md"))
((date . "2025-12-31") (session . "implementation-planning") (notes . "Added EXTENDED_PROOFS.md with complete academic proofs; added IMPLEMENTATION_ROADMAP.md with full technology stack and phased development plan"))
((date . "2025-12-31") (session . "compiler-phase1") (notes . "Implemented Phase 1 of compiler: lexer with dimensional literals, recursive descent parser, AST with dimensional types, basic type checker scaffolding, CLI with build/run/check/fmt commands, interactive REPL. All 14 tests passing."))
((date . "2025-12-31") (session . "interpreter-phase") (notes . "Implemented tree-walking interpreter with shadow price-based solution selection. Adaptive fibonacci demo works end-to-end: runtime selects efficient solution based on cost = energy + latency + carbon. Created CARBON_APIS.md with comprehensive API research for future carbon-aware scheduling.")))))
((date . "2025-12-31") (session . "interpreter-phase") (notes . "Implemented tree-walking interpreter with shadow price-based solution selection. Adaptive fibonacci demo works end-to-end: runtime selects efficient solution based on cost = energy + latency + carbon. Created CARBON_APIS.md with comprehensive API research for future carbon-aware scheduling."))
((date . "2025-12-31") (session . "compiler-improvements") (notes . "Major improvements: 1) Basic type checking with Hindley-Milner inference, 2) Line:column in errors, 3) GETTING_STARTED.md documentation, 4) Lambda body execution fixed, 5) @when clause evaluation, 6) Path sanitization in init, 7) REPL expression evaluation, 8) fmt/test/bench commands, 9) Runtime error source locations. All tests passing.")))))

(define state-summary
'((project . "eclexia") (completion . 45) (blockers . 0) (updated . "2025-12-31")))
'((project . "eclexia") (completion . 55) (blockers . 0) (updated . "2025-12-31")))
65 changes: 65 additions & 0 deletions compiler/eclexia-ast/src/span.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,71 @@ impl From<std::ops::Range<u32>> for Span {
}
}

/// Line and column position in source code (1-indexed).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LineCol {
/// Line number (1-indexed)
pub line: u32,
/// Column number (1-indexed)
pub col: u32,
}

impl LineCol {
/// Create a new line:column position.
pub const fn new(line: u32, col: u32) -> Self {
Self { line, col }
}
}

impl std::fmt::Display for LineCol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.line, self.col)
}
}

impl Span {
/// Convert a byte offset to line:column position.
///
/// Returns (1,1) for position 0, and properly handles newlines.
pub fn offset_to_linecol(source: &str, offset: u32) -> LineCol {
let offset = offset as usize;
let mut line = 1u32;
let mut col = 1u32;
let mut pos = 0;

for ch in source.chars() {
if pos >= offset {
break;
}
if ch == '\n' {
line += 1;
col = 1;
} else {
col += 1;
}
pos += ch.len_utf8();
}

LineCol::new(line, col)
}

/// Get the line:column of the start of this span.
pub fn start_linecol(&self, source: &str) -> LineCol {
Self::offset_to_linecol(source, self.start)
}

/// Get the line:column of the end of this span.
pub fn end_linecol(&self, source: &str) -> LineCol {
Self::offset_to_linecol(source, self.end)
}

/// Format this span as "line:col" for the start position.
pub fn format_location(&self, source: &str) -> String {
let lc = self.start_linecol(source);
format!("{}:{}", lc.line, lc.col)
}
}

/// A value with an associated source span.
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand Down
Loading
Loading