docs: add project guide for Claude #1

Closed
mvhutz wants to merge 16 commits from docs/claude-guide into main
10 changed files with 197 additions and 193 deletions

3
.gitignore vendored
View File

@@ -9,6 +9,9 @@
*.so
*.dylib
# Build artifacts
lambda
# Test binary, built with `go test -c`
*.test

View File

@@ -1,230 +1,83 @@
---
# golangci-lint configuration file made by @ccoVeille
# Source: https://github.com/ccoVeille/golangci-lint-config-examples/
# Author: @ccoVeille
# License: MIT
# Variant: 03-safe
# Version: v2.0.0
#
version: "2"
formatters:
enable:
# format the code
- gofmt
# format the block of imports
- gci
settings:
# format the code with Go standard library
gofmt:
# simplify the code
# https://pkg.go.dev/cmd/gofmt#hdr-The_simplify_command
simplify: true
rewrite-rules:
# replace `interface{}` with `any` in the code on format
- pattern: 'interface{}'
replacement: 'any'
# make sure imports are always in a deterministic order
# https://github.com/daixiang0/gci/
gci: # define the section orders for imports
gci:
sections:
# Standard section: captures all standard packages.
- standard
# Default section: catchall that is not standard or custom
- default
# linters that related to local tool, so they should be separated
- localmodule
linters:
exclusions:
# these presets where present in the v1 version of golangci-lint
# it's interesting to keep them when migrating, but removing them should be the goal
presets:
# exclude check on comments format in godoc
# These are common false positives in poor code
# you should not use this on recent code you write from scratch
# More information: https://golangci-lint.run/usage/false-positives/#comments
#
# Please uncomment the following line if your code is not using the godoc format
- comments
# Common false positives
# feel free to remove this if you don't have any false positives
# More information: https://golangci-lint.run/usage/false-positives/#common-false-positives
- common-false-positives
# Legacy preset is not recommended anymore
# More information: https://golangci-lint.run/usage/false-positives/#legacy
- legacy
# std-error-handling is a set of rules that avoid reporting unhandled errors on common functions/methods
# More information: https://golangci-lint.run/usage/false-positives/#std-error-handling
- std-error-handling
# some linters are enabled by default
# https://golangci-lint.run/usage/linters/
#
# enable some extra linters
enable:
# Errcheck is a program for checking for unchecked errors in Go code.
- errcheck
# Vet examines Go source code and reports suspicious constructs.
- govet
# Detects when assignments to existing variables are not used.
- ineffassign
# It's a set of rules from staticcheck. See https://staticcheck.io/
- staticcheck
# Checks Go code for unused constants, variables, functions and types.
- unused
# Fast, configurable, extensible, flexible, and beautiful linter for Go.
# Drop-in replacement of golint.
- revive
# make sure to use t.Helper() when needed
- thelper
# mirror suggests rewrites to avoid unnecessary []byte/string conversion
- mirror
# detect the possibility to use variables/constants from the Go standard library.
- usestdlibvars
# Finds commonly misspelled English words.
- misspell
# Checks for duplicate words in the source code.
- dupword
# linter to detect errors invalid key values count
- loggercheck
# detect when a package or method could be replaced by one from the standard library
- exptostd
# detects nested contexts in loops or function literals
- fatcontext
# Reports uses of functions with replacement inside the testing package.
- usetesting
settings:
revive:
rules:
# these are the default revive rules
# you can remove the whole "rules" node if you want
# BUT
# ! /!\ they all need to be present when you want to add more rules than the default ones
# otherwise, you won't have the default rules, but only the ones you define in the "rules" node
# Blank import should be only in a main or test package, or have a comment justifying it.
- name: blank-imports
# context.Context() should be the first parameter of a function when provided as argument.
- name: context-as-argument
arguments:
- allowTypesBefore: "*testing.T"
# Basic types should not be used as a key in `context.WithValue`
- name: context-keys-type
# Importing with `.` makes the programs much harder to understand
- name: dot-imports
# Empty blocks make code less readable and could be a symptom of a bug or unfinished refactoring.
- name: empty-block
# for better readability, variables of type `error` must be named with the prefix `err`.
- name: error-naming
# for better readability, the errors should be last in the list of returned values by a function.
- name: error-return
# for better readability, error messages should not be capitalized or end with punctuation or a newline.
- name: error-strings
# report when replacing `errors.New(fmt.Sprintf())` with `fmt.Errorf()` is possible
- name: errorf
# check naming and commenting conventions on exported symbols.
- name: exported
arguments:
# make error messages clearer
- "sayRepetitiveInsteadOfStutters"
# incrementing an integer variable by 1 is recommended to be done using the `++` operator
- name: increment-decrement
# highlights redundant else-blocks that can be eliminated from the code
# - name: indent-error-flow
# This rule suggests a shorter way of writing ranges that do not use the second value.
- name: range
# receiver names in a method should reflect the struct name (p for Person, for example)
- name: receiver-naming
# redefining built in names (true, false, append, make) can lead to bugs very difficult to detect.
- name: redefines-builtin-id
# redundant else-blocks that can be eliminated from the code.
# - name: superfluous-else
# prevent confusing name for variables when using `time` package
- name: time-naming
# warns when an exported function or method returns a value of an un-exported type.
- name: unexported-return
# spots and proposes to remove unreachable code. also helps to spot errors
- name: unreachable-code
# Functions or methods with unused parameters can be a symptom of an unfinished refactoring or a bug.
- name: unused-parameter
# report when a variable declaration can be simplified
- name: var-declaration
# warns when initialism, variable or package naming conventions are not followed.
- name: var-naming
misspell:
# Correct spellings using locale preferences for US or UK.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
# Default ("") is to use a neutral variety of English.
locale: US
# List of words to ignore
# among the one defined in https://github.com/golangci/misspell/blob/master/words.go
ignore-rules: []
# - valor
# - and
# Extra word corrections.
extra-words: []
# - typo: "whattever"
# correction: "whatever"
output:
# Order to use when sorting results.
# Possible values: `file`, `linter`, and `severity`.
#
# If the severity values are inside the following list, they are ordered in this order:
# 1. error
# 2. warning
# 3. high
# 4. medium
# 5. low
# Either they are sorted alphabetically.
#
# Default: ["file"]
sort-order:
- linter
- severity
- file # filepath, line, and column.
- file

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"makefile.configureOnOpen": false
}

42
CLAUDE.md Normal file
View File

@@ -0,0 +1,42 @@
# Guide To `lambda`
## Coding Styles
### Conventional Commits
Use conventional commit format: `<type>: <description>`.
**Types**: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `perf`
**Examples**:
- `feat: add explanation mode flag to CLI`
- `fix: correct variable renaming in nested abstractions`
- `docs: update Makefile documentation`
### Branch Names
Use format: `<type>/<description>` with kebab-case.
**Types**: Same as commits: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `perf`
**Examples**:
- `feat/explanation-mode`
- `fix/variable-renaming`
- `docs/makefile-improvements`
- `refactor/silent-directive`
## Pull Request Management
Use the `tea` CLI (Gitea command-line tool) for PR operations instead of `gh`.
**Common commands**:
- `tea pr create` - Create a new pull request
- `tea pr list` - List pull requests
- `tea pr checkout <number>` - Check out a PR locally
- `tea pr close <number>` - Close a pull request
- `tea pr merge <number>` - Merge a pull request
**Creating PRs**: Always create PRs to the `main` branch unless specified otherwise

View File

@@ -1,21 +1,40 @@
BINARY_NAME=lambda.exe
it:
@ go build -o ${BINARY_NAME} ./cmd/lambda
@ chmod +x ${BINARY_NAME}
BINARY_NAME=lambda
TEST=simple
.DEFAULT_GOAL := help
.SILENT:
.PHONY: help it run profile explain graph clean
help:
echo "Available targets:"
echo " it - Build the lambda binary"
echo " run - Build and run with sample input (default: simple.txt)"
echo " profile - Build and run with CPU profiling enabled"
echo " explain - Run with explanation mode and profiling"
echo " graph - Generate CPU profile visualization"
echo " clean - Remove build artifacts"
echo ""
echo "Usage: make run TEST=<sample-name>"
it:
go build -o ${BINARY_NAME} ./cmd/lambda
run: it
@ ./lambda.exe - < ./samples/$(TEST).txt > program.out
./lambda - < ./samples/$(TEST).txt > program.out
profile: it
@ ./lambda.exe -p profile/cpu.prof - < ./samples/$(TEST).txt > program.out
mkdir -p profile
./lambda -p profile/cpu.prof - < ./samples/$(TEST).txt > program.out
explain: it
@ ./lambda.exe -x -p profile/cpu.prof - < ./samples/$(TEST).txt > program.out
mkdir -p profile
./lambda -x -p profile/cpu.prof - < ./samples/$(TEST).txt > program.out
graph:
@ go tool pprof -raw -output=profile/cpu.raw profile/cpu.prof
@ go tool pprof -svg profile/cpu.prof > profile/cpu.svg
@ open profile/cpu.svg
graph: profile
go tool pprof -raw -output=profile/cpu.raw profile/cpu.prof
go tool pprof -svg profile/cpu.prof > profile/cpu.svg
echo "Profile graph saved to 'file://profile/cpu.svg'"
clean:
rm -f ${BINARY_NAME} program.out
rm -rf profile/

114
makefile-improvements.md Normal file
View File

@@ -0,0 +1,114 @@
# Makefile Improvements
This document lists the issues identified in the original Makefile and the improvements that were implemented.
## Issues Fixed
### 1. Hardcoded `.exe` extension on Unix
**Problem**: `BINARY_NAME=lambda.exe` used a Windows extension on macOS/Linux systems.
**Solution**: Changed to `BINARY_NAME=lambda` since Unix executables don't use extensions.
**Commit**: `0d06fac` - fix: remove Windows .exe extension from binary name
---
### 2. Redundant `chmod +x`
**Problem**: The `chmod +x` command was unnecessary since `go build` already sets the executable bit.
**Solution**: Removed the redundant `chmod +x ${BINARY_NAME}` line.
**Commit**: `e0b0b92` - refactor: remove redundant chmod +x command
---
### 3. Missing `.PHONY` declarations
**Problem**: Without `.PHONY`, if files named `run`, `graph`, etc. existed, Make would skip those targets.
**Solution**: Added `.PHONY: help it run profile explain graph clean` declaration.
**Commit**: `e5ceeb2` - feat: add .PHONY declarations for all targets
---
### 4. No `clean` target
**Problem**: No standard way to remove build artifacts.
**Solution**: Added `clean` target to remove binary, output files, and profile directory:
```makefile
clean:
rm -f ${BINARY_NAME} program.out
rm -rf profile/
```
**Commit**: `7927df4` - feat: add clean target to remove build artifacts
---
### 5. Missing `help` or default target
**Problem**: Running `make` with no arguments was unclear about available targets.
**Solution**: Added `help` target documenting all available commands and their usage.
**Commit**: `24fdc1c` - feat: add help target to document available commands
---
### 6. Profile directory not created
**Problem**: The `profile` and `explain` targets wrote to `profile/cpu.prof` but never created the directory, causing failures on first run.
**Solution**: Added `mkdir -p profile` to both `profile` and `explain` targets.
**Commit**: `bb48d07` - fix: ensure profile directory exists before writing
---
### 7. No dependency check on `graph`
**Problem**: The `graph` target assumed `profile/cpu.prof` exists but didn't depend on `profile`.
**Solution**: Changed `graph:` to `graph: profile` to ensure profiling runs first.
**Commit**: `3158c35` - fix: add profile dependency to graph target
---
### 8. Verbose command prefixes
**Problem**: Every command used `@` prefix individually to suppress output, cluttering the file.
**Solution**: Added `.SILENT:` directive at the top and removed all `@` prefixes. Also moved `TEST` variable to top with other variables.
**Commit**: `8f70bfb` - refactor: use .SILENT directive instead of @ prefixes
---
## Additional Suggestions (Not Yet Implemented)
### 9. Missing `lambda` binary in `.gitignore`
**Issue**: The `.gitignore` has `*.exe` but not the actual `lambda` binary name. Since we removed the `.exe` extension, the binary won't be ignored.
**Recommendation**: Add `lambda` to `.gitignore`:
```
# Build artifacts
lambda
```
---
### 10. No explicit default target
**Issue**: While `help` is currently the first target (and thus default), it's not explicitly declared.
**Recommendation**: Add `.DEFAULT_GOAL = help` at the top for clarity:
```makefile
BINARY_NAME=lambda
TEST=simple
.DEFAULT_GOAL := help
.SILENT:
.PHONY: help it run profile explain graph clean
```
---
## Summary
The Makefile has been significantly improved with better organization, proper dependency management, directory creation, helpful documentation, and cleaner syntax. The remaining suggestions are minor quality-of-life improvements that can be addressed as needed.

View File

@@ -1,7 +1,5 @@
package deltanet
/** ------------------------------------------------------------------------- */
// A connection between exactly two nodes in a graph.
type Edge struct {
A, B Node
@@ -28,8 +26,6 @@ func (e Edge) IsPrincipleEdge() bool {
return e.A.GetMainPort() == e && e.B.GetMainPort() == e
}
/** ------------------------------------------------------------------------- */
type Node interface {
// Returns the principle port that the node is attached to.
GetMainPort() Edge
@@ -42,8 +38,6 @@ type Node interface {
GetLabel() string
}
/** ------------------------------------------------------------------------- */
type EraserNode struct {
Main Edge
}
@@ -52,8 +46,6 @@ func (n EraserNode) GetLabel() string { return "Ⓧ" }
func (n EraserNode) GetMainPort() Edge { return n.Main }
func (n EraserNode) GetAuxPorts() []Edge { return []Edge{} }
/** ------------------------------------------------------------------------- */
type ReplicatorNode struct {
Main Edge
Level uint
@@ -68,8 +60,6 @@ func (n ReplicatorNode) GetAuxPorts() []Edge { return n.Aux }
// Returns the level of the replicator node.
func (n ReplicatorNode) GetLevel() uint { return n.Level }
/** ------------------------------------------------------------------------- */
type FanNode struct {
Label string
Main Edge
@@ -80,8 +70,6 @@ func (n FanNode) GetLabel() string { return n.Label }
func (n FanNode) GetMainPort() Edge { return n.Main }
func (n FanNode) GetAuxPorts() []Edge { return []Edge{n.Left, n.Right} }
/** ------------------------------------------------------------------------- */
type TerminalNode struct {
Label string
Main Edge
@@ -90,5 +78,3 @@ type TerminalNode struct {
func (n TerminalNode) GetLabel() string { return n.Label }
func (n TerminalNode) GetMainPort() Edge { return n.Main }
func (n TerminalNode) GetAuxPorts() []Edge { return []Edge{} }
/** ------------------------------------------------------------------------- */

View File

@@ -5,8 +5,6 @@ type Expression interface {
Copy() Expression
}
/** ------------------------------------------------------------------------- */
type Abstraction struct {
Parameter string
Body Expression
@@ -24,8 +22,6 @@ func NewAbstraction(parameter string, body Expression) *Abstraction {
return &Abstraction{Parameter: parameter, Body: body}
}
/** ------------------------------------------------------------------------- */
type Application struct {
Abstraction Expression
Argument Expression
@@ -43,8 +39,6 @@ func NewApplication(function Expression, argument Expression) *Application {
return &Application{Abstraction: function, Argument: argument}
}
/** ------------------------------------------------------------------------- */
type Variable struct {
Value string
}
@@ -61,8 +55,6 @@ func NewVariable(name string) *Variable {
return &Variable{Value: name}
}
/** ------------------------------------------------------------------------- */
type Visitor interface {
VisitAbstraction(*Abstraction)
VisitApplication(*Application)

View File

@@ -4,8 +4,6 @@ type Expression interface {
IsExpression()
}
/** ------------------------------------------------------------------------- */
type Abstraction struct {
Parameters []string
Body Expression
@@ -30,8 +28,6 @@ func (Application) IsExpression() {}
func (Atom) IsExpression() {}
func (Clause) IsExpression() {}
/** ------------------------------------------------------------------------- */
func NewAbstraction(parameter []string, body Expression) *Abstraction {
return &Abstraction{Parameters: parameter, Body: body}
}

View File

@@ -4,8 +4,6 @@ type Statement interface {
IsStatement()
}
/** ------------------------------------------------------------------------- */
type LetStatement struct {
Name string
Parameters []string
@@ -19,8 +17,6 @@ type DeclareStatement struct {
func (LetStatement) IsStatement() {}
func (DeclareStatement) IsStatement() {}
/** ------------------------------------------------------------------------- */
func NewLet(name string, parameters []string, body Expression) *LetStatement {
return &LetStatement{Name: name, Parameters: parameters, Body: body}
}