Commit Graph

29 Commits

Author SHA1 Message Date
e17a85e0a3 refactor: use assert throughout tests and require expected files.
Renamed benchmark_test.go to lambda_test.go.
Consolidated helper functions to use single runSample function.
Replaced all error handling with assert for consistency.
Removed optional expected file check to require all test files have corresponding expected files.
2026-01-12 20:09:21 -05:00
4a5c424e54 test: add dynamic test discovery and validity checks.
Modified benchmark_test.go to dynamically discover all .test files in the
tests directory instead of using hardcoded paths.
Added TestSamplesValidity integration test that validates each test file
against its corresponding .expected file.
Added runSampleWithOutput helper function to capture interpreter output.
Added new test cases with expected outputs for validation.
2026-01-12 20:04:00 -05:00
15c904ccc9 feat: improve reduction algorithm with LIFO-based iterator (#15)
## Description

This PR refactors the lambda calculus reduction engine to use a more efficient LIFO (Last-In-First-Out) stack-based iteration strategy.
Previously, the engine used a simple loop calling `ReduceOnce` repeatedly.
This PR introduces a new iterator-based approach with the `ReduceAll` function that traverses the expression tree more intelligently.

Changes include:

- Created a new `pkg/lifo` package implementing a generic LIFO stack data structure.
- Added `pkg/lambda/iterator.go` with an `Iterator` type for traversing lambda expressions.
- Refactored `pkg/lambda/reduce.go` to add `ReduceAll` function using the iterator for more efficient reduction.
- Updated `internal/engine/engine.go` to use `ReduceAll` instead of looping `ReduceOnce`.
- Renamed sample test files from `.txt` to `.test` extension.
- Fixed `.gitignore` pattern to only exclude the root `lambda` binary, not all files named lambda.
- Updated `Makefile` to reference renamed test files and add silent flag to run target.

### Decisions

- Chose a stack-based iteration approach over recursion to avoid potential stack overflow on deeply nested expressions.
- Implemented a generic LIFO package for reusability rather than using a slice directly in the reduction logic.
- Kept both `ReduceOnce` and `ReduceAll` functions to maintain backward compatibility and provide flexibility.

## Performance

Benchmark results comparing main branch vs this PR on Apple M3:

| Test | Before (ms/op) | After (ms/op) | Change |
|------|----------------|---------------|--------|
| Thunk | 0.014 | 0.014 | 0.00% |
| Fast | 1.29 | 1.20 | **-7.04%** |
| Simple | 21.51 | 6.45 | **-70.01%** |
| Church | 157.67 | 43.00 | -76.788% |
| Saccharine | 185.25 | 178.99 | **-3.38%** |

**Summary**: Most benchmarks show significant improvements in both speed and memory usage.
The Church benchmark shows a regression that needs investigation.

## Benefits

- More efficient expression tree traversal with the iterator pattern.
- Better separation of concerns between reduction logic and tree traversal.
- Generic LIFO stack can be reused in other parts of the codebase.
- Cleaner engine implementation with callback-based step emission.

## Checklist

- [x] Code follows conventional commit format.
- [x] Branch follows naming convention (`<type>/<description>`). Always use underscores.
- [ ] Tests pass (if applicable).
- [ ] Documentation updated (if applicable).

Reviewed-on: #15
Co-authored-by: M.V. Hutz <git@maximhutz.me>
Co-committed-by: M.V. Hutz <git@maximhutz.me>
2026-01-12 02:16:07 +00:00
609fe05250 feat: add benchmark target to Makefile (#14)
## Description

This PR adds benchmarking capabilities to the lambda interpreter.
The benchmarks measure performance across all sample files in the samples folder.
This enables consistent performance testing and helps track optimization improvements over time.

Changes in this PR:
- Added new `bench` target to Makefile for running Go benchmarks.
- Created `benchmark_test.go` with sub-benchmarks for each sample file (Church, Fast, Saccharine, Simple, Thunk).
- Used `b.Run` for organizing sample-specific sub-benchmarks and `b.Loop` for efficient iteration.
- Configured benchmarks to use fixed iterations (10x) and 4 CPU cores for reproducible results.

### Decisions

Used `b.Loop()` instead of traditional `for i := 0; i < b.N; i++` pattern.
This is the modern Go benchmarking idiom that provides better performance measurement.

Benchmarks run the full pipeline (parse, compile, execute, stringify) to measure end-to-end performance for each sample.

## Benefits

Provides quantitative performance metrics for the lambda interpreter.
Enables tracking performance improvements or regressions across different sample complexities.
Consistent benchmark configuration (fixed iterations, CPU cores) ensures reproducible results for comparison.

## Checklist

- [x] Code follows conventional commit format.
- [x] Branch follows naming convention (`<type>/<description>`). Always use underscores.
- [x] Tests pass (if applicable).
- [x] Documentation updated (if applicable).

Reviewed-on: #14
Co-authored-by: M.V. Hutz <git@maximhutz.me>
Co-committed-by: M.V. Hutz <git@maximhutz.me>
2026-01-11 22:48:26 +00:00
0eff85f8fa feat: add output flag (#13)
## Description

The lambda CLI previously only wrote output to stdout using shell redirection.
This PR adds support for writing results to files using the `-o` flag.
This is implemented using a new `Destination` interface that mirrors the existing `Source` pattern.

Changes:
- Added `Destination` interface with `StdoutDestination` and `FileDestination` implementations.
- Added `-o` flag to CLI argument parser for output file specification.
- Updated `Config` to use `Destination` instead of direct output handling.
- Refactored main to use `Destination.Write()` for result output.
- Updated Makefile targets (`run`, `profile`, `explain`) to use `-o` flag instead of shell redirection.

### Decisions

The `-o` flag defaults to stdout when not specified or when set to `-`.
This maintains backward compatibility while providing explicit file output capability.

## Benefits

- Cleaner command-line interface without shell redirection.
- Symmetric design with `Source` interface for input.
- More portable across different shells and environments.
- Explicit output handling improves code clarity.

## Checklist

- [x] Code follows conventional commit format.
- [x] Branch follows naming convention (`<type>/<description>`).
- [ ] Tests pass (if applicable).
- [ ] Documentation updated (if applicable).

Reviewed-on: #13
Co-authored-by: M.V. Hutz <git@maximhutz.me>
Co-committed-by: M.V. Hutz <git@maximhutz.me>
2026-01-11 22:14:48 +00:00
Max
2499921679 style: moved functions around 2025-12-30 15:58:14 -05:00
Max
351faa7e08 feat: statistics flag, commented some more 2025-12-29 20:00:29 -05:00
Max
17cf8f86f8 feat: explanation as observer too 2025-12-29 01:31:09 -05:00
Max
a2ce5b6897 feat: rename profiler to performance, typeless event emitter 2025-12-29 01:15:14 -05:00
Max
c2b397a9f6 feat: observer pattern for statistics 2025-12-29 00:51:50 -05:00
Max
e9dc3fe171 feat: added optional profiling 2025-12-28 22:52:10 -05:00
Max
633d4a4d3b fix: no stringify in hot loop 2025-12-28 02:19:48 -05:00
Max
ee9e71d58e fix: no ds store 2025-12-28 02:07:46 -05:00
Max
0945cedf51 feat: only compute all free variables during a-conversion 2025-12-28 02:07:14 -05:00
Max
4d81aca0b2 feat: fun little program 2025-12-28 00:53:43 -05:00
Max
884180de92 feat: error for when there is more source code than parsed 2025-12-27 02:08:18 -05:00
Max
df53409887 fix: parameters converted in opposite order 2025-12-27 01:41:00 -05:00
Max
a05a63627e feat: better recursive descent 2025-12-27 01:18:06 -05:00
Max
e3629acb45 feat: stuff 2025-12-26 03:37:05 -05:00
Max
d427703afe wip: new folder structure, overhaul language 2025-12-26 02:39:15 -05:00
Max
11e7f70625 feat: stuff 2025-12-26 01:59:56 -05:00
Max
3351eaddfc feat: better structured internal 2025-12-25 17:21:16 -05:00
Max
99703c2587 fix: unbound substitutions, explanation tag 2025-12-25 01:55:46 -05:00
Max
a56ec808ec feat: read from std in 2025-12-25 00:46:48 -05:00
Max
88ee4f799e feat: reducer works 2025-12-25 00:40:34 -05:00
Max
d5999e8e1c feat: reducer, but doesn`t work 2025-12-25 00:30:15 -05:00
Max
2c3ce9baf7 feat: wogihrsoiuvjsroirgj 2025-12-24 14:55:33 -05:00
Max
1d8ecba118 feat: parser 2025-12-23 21:54:42 -05:00
Max
61bb622dcd feat: tokenizer 2025-12-23 14:17:43 -05:00