|
|
+++
|
|
|
title = "§5 Setting Up the Project"
|
|
|
priority = 5
|
|
|
status = "done"
|
|
|
ticket_type = "task"
|
|
|
dependencies = []
|
|
|
+++
|
|
|
|
|
|
## §5 Setting Up the Project — Stub to fill
|
|
|
|
|
|
File: `edu/src/lisp-compiler.md`, section `### 5. Setting Up the Project`
|
|
|
|
|
|
Replace the stub line with full content. Target 400–600 words. This is a pure hands-on section: create the project, add dependencies, lay out modules, verify it compiles.
|
|
|
|
|
|
## Learning objectives
|
|
|
|
|
|
- Know exactly which dependencies to add and why
|
|
|
- Have the module skeleton in place before any parsing logic is written
|
|
|
- Understand the release profile settings required by the project conventions
|
|
|
|
|
|
## Content to write
|
|
|
|
|
|
### Create the project
|
|
|
|
|
|
```sh
|
|
|
cargo new minilisp --bin
|
|
|
cd minilisp
|
|
|
```
|
|
|
|
|
|
### Dependencies (`Cargo.toml`)
|
|
|
|
|
|
```toml
|
|
|
[package]
|
|
|
name = "minilisp"
|
|
|
version = "0.1.0"
|
|
|
edition = "2021"
|
|
|
|
|
|
[dependencies]
|
|
|
nom = "8"
|
|
|
|
|
|
[profile.release]
|
|
|
opt-level = "z"
|
|
|
lto = true
|
|
|
strip = true
|
|
|
codegen-units = 1
|
|
|
```
|
|
|
|
|
|
Explain each dependency:
|
|
|
- `nom = "8"` — the parser combinator library. Pinned to major version 8 because nom 8 introduced breaking API changes from nom 7. If the reader sees different combinator signatures in other resources, they may be looking at nom 7 documentation.
|
|
|
|
|
|
### Module skeleton
|
|
|
|
|
|
Create the following files with stub content (empty public functions or empty modules):
|
|
|
|
|
|
**`src/main.rs`**
|
|
|
```rust
|
|
|
mod ast;
|
|
|
mod parser;
|
|
|
mod analyser;
|
|
|
mod codegen;
|
|
|
mod error;
|
|
|
|
|
|
fn main() {
|
|
|
// §16: wire up the CLI here
|
|
|
println!("MiniLisp compiler");
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**`src/error.rs`**
|
|
|
```rust
|
|
|
#[derive(Debug)]
|
|
|
pub enum CompileError {
|
|
|
ParseError(String),
|
|
|
SemanticError(String),
|
|
|
}
|
|
|
|
|
|
impl std::fmt::Display for CompileError {
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
match self {
|
|
|
CompileError::ParseError(msg) => write!(f, "parse error: {}", msg),
|
|
|
CompileError::SemanticError(msg) => write!(f, "semantic error: {}", msg),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**`src/ast.rs`** — stub (§7 will fill this in):
|
|
|
```rust
|
|
|
// Defined in §7
|
|
|
```
|
|
|
|
|
|
**`src/parser.rs`** — stub:
|
|
|
```rust
|
|
|
// Defined in §8–9
|
|
|
```
|
|
|
|
|
|
**`src/analyser.rs`** — stub:
|
|
|
```rust
|
|
|
// Defined in §10–11
|
|
|
```
|
|
|
|
|
|
**`src/codegen.rs`** — stub:
|
|
|
```rust
|
|
|
// Defined in §12–15
|
|
|
```
|
|
|
|
|
|
### Verify it compiles
|
|
|
|
|
|
```sh
|
|
|
cargo check
|
|
|
```
|
|
|
|
|
|
Should produce no errors (warnings about unused items are expected).
|
|
|
|
|
|
### Run the validation suite
|
|
|
|
|
|
Introduce the four commands from the repo conventions that must pass before any commit:
|
|
|
```sh
|
|
|
cargo fmt
|
|
|
cargo check
|
|
|
cargo clippy
|
|
|
cargo test
|
|
|
```
|
|
|
|
|
|
Explain that `cargo test` will report zero tests at this stage — that is fine. As modules are filled in, the test count will grow.
|
|
|
|
|
|
## Style notes
|
|
|
|
|
|
- Show the complete `Cargo.toml` up front — readers frequently have version issues if they pick the wrong nom major version
|
|
|
- Keep the module stubs minimal — just enough for `cargo check` to pass
|
|
|
- End with a checkpoint: "you should now have a project that compiles" — sets a clear success criterion
|