Closes #26 - Added -i flag to select interpreter (lambda or debruijn) - Created debruijn package with Expression interface - Variable contains index and optional label - Abstraction contains only body (no parameter) - Application structure remains similar - Implemented De Bruijn reduction without variable renaming - Shift operation handles index adjustments - Substitute replaces by index instead of name - Abstracted Engine into interface with two implementations - LambdaEngine: original named variable engine - DeBruijnEngine: new index-based engine - Added conversion functions between representations - LambdaToDeBruijn: converts named to indexed - DeBruijnToLambda: converts indexed back to named - SaccharineToDeBruijn: direct saccharine to De Bruijn - Updated main to switch engines based on -i flag - All test samples pass with both engines Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
69 lines
1.1 KiB
Go
69 lines
1.1 KiB
Go
package debruijn
|
|
|
|
type Iterator struct {
|
|
trace []*Expression
|
|
}
|
|
|
|
func NewIterator(expr *Expression) *Iterator {
|
|
return &Iterator{[]*Expression{expr}}
|
|
}
|
|
|
|
func (i *Iterator) Done() bool {
|
|
return len(i.trace) == 0
|
|
}
|
|
|
|
func (i *Iterator) Current() *Expression {
|
|
if i.Done() {
|
|
return nil
|
|
}
|
|
|
|
return i.trace[len(i.trace)-1]
|
|
}
|
|
|
|
func (i *Iterator) Parent() *Expression {
|
|
if len(i.trace) < 2 {
|
|
return nil
|
|
}
|
|
|
|
return i.trace[len(i.trace)-2]
|
|
}
|
|
|
|
func (i *Iterator) Swap(with Expression) {
|
|
current := i.Current()
|
|
if current != nil {
|
|
*current = with
|
|
}
|
|
}
|
|
|
|
func (i *Iterator) Back() bool {
|
|
if i.Done() {
|
|
return false
|
|
}
|
|
|
|
i.trace = i.trace[:len(i.trace)-1]
|
|
return true
|
|
}
|
|
|
|
func (i *Iterator) Next() {
|
|
switch typed := (*i.Current()).(type) {
|
|
case *Abstraction:
|
|
i.trace = append(i.trace, &typed.body)
|
|
case *Application:
|
|
i.trace = append(i.trace, &typed.abstraction)
|
|
case *Variable:
|
|
for len(i.trace) > 1 {
|
|
if app, ok := (*i.Parent()).(*Application); ok {
|
|
if app.abstraction == *i.Current() {
|
|
i.Back()
|
|
i.trace = append(i.trace, &app.argument)
|
|
return
|
|
}
|
|
}
|
|
|
|
i.Back()
|
|
}
|
|
|
|
i.trace = []*Expression{}
|
|
}
|
|
}
|