Source

unlambda-go / unlambda.go

Full commit
package main

import (
	"bufio"
	"os"
)

//-------------------------------------------------------------------------

const (
	FUNCTION_S = iota // Three stages of S-function
	FUNCTION_S1
	FUNCTION_S2

	FUNCTION_K        // Two stages of K-function
	FUNCTION_K1

	FUNCTION_I        // Single-stage I-function

	FUNCTION_DOT      // Dot-function performs output
)

type Function struct {
	x    *Function // First operand
	y    *Function // Second operand
	rune int       // Rune to print out (used in dot-function)
	fn   int       // Function operator code
}

// Creates a new function with the given operator code
func NewFunc(code int) (f *Function) {
	f = new(Function)
	f.fn = code
	return
}

// Creates a new dot-function, that will print a given rune
func NewDotFunc(rune int) (f *Function) {
	f = new(Function)
	f.fn = FUNCTION_DOT
	f.rune = rune
	return
}

// Applies function to an operand x
func (f *Function) ApplyTo(x *Function) (res *Function) {
	switch f.fn {

	// I-function just returns its operand
	case FUNCTION_I:
		return x

	// K-function returns its first operant, but takes two of them
	case FUNCTION_K:
		res = new(Function)
		res.x = x
		res.fn = FUNCTION_K1
		return res
	case FUNCTION_K1:
		return f.x

	// S-function takes 3 operands and applies 1st to the 3rd, and 2nd to the 3rd
	case FUNCTION_S:
		res = new(Function)
		res.x = x
		res.fn = FUNCTION_S1
		return res
	case FUNCTION_S1:
		res = new(Function)
		res.x = f.x
		res.y = x
		res.fn = FUNCTION_S2
		return res
	case FUNCTION_S2:
		return f.x.ApplyTo(x).ApplyTo(f.y.ApplyTo(x))

	// Dot-function prints a single rune
	case FUNCTION_DOT:
		print(string(f.rune))
		return x
	}
	panic("Bad function code")
}

//-------------------------------------------------------------------------

const (
	EXPRESSION_APPLY = iota // Application expression
	EXPRESSION_FUNC         // Function expression
)

type Expression struct {
	f   *Expression
	x   *Expression
	fn  *Function
	exp int
}

func NewApplyExp(f *Expression, x *Expression) (e *Expression) {
	e = new(Expression)
	e.f = f
	e.x = x
	e.exp = EXPRESSION_APPLY
	return
}

func NewFuncExp(f *Function) (e *Expression) {
	e = new(Expression)
	e.fn = f
	e.exp = EXPRESSION_FUNC
	return
}

func (e *Expression) Eval() (f *Function) {
	switch e.exp {
	case EXPRESSION_FUNC:
		return e.fn
	case EXPRESSION_APPLY:
		return e.f.Eval().ApplyTo(e.x.Eval())
	}
	panic("Bad expression")
}

//-------------------------------------------------------------------------

func parse(in *bufio.Reader) (exp *Expression, err os.Error) {
	var rune int

	for {
		rune, _, err = in.ReadRune()
		if err != nil {
			return
		}
		if rune != ' ' && rune != '\r' && rune != '\n' && rune != '\t' {
			break
		}
	}

	switch rune {
	case '`':
		var f, x *Expression
		f, err = parse(in)
		if err != nil {
			return
		}
		x, err = parse(in)
		if err != nil {
			return
		}
		exp = NewApplyExp(f, x)
		return exp, nil
	case 's':
		exp = NewFuncExp(NewFunc(FUNCTION_S))
	case 'k':
		exp = NewFuncExp(NewFunc(FUNCTION_K))
	case 'i':
		exp = NewFuncExp(NewFunc(FUNCTION_I))
	case 'r':
		exp = NewFuncExp(NewDotFunc('\n'))
	case '.':
		rune, _, err = in.ReadRune()
		if err != nil {
			return
		}
		exp = NewFuncExp(NewDotFunc(rune))
	default:
		err = os.NewError("Invalid rune: " + string(rune))
		return
	}
	return
}

func main() {
	in := bufio.NewReader(os.Stdin)

	println("Simple Unlambda implementation")
	println("Written in Go by Serge Zaitsev")

	for {
		print("\n>> ")
		e, err := parse(in)
		if err == nil {
			e.Eval()
		} else {
			println("Error: " + err.String())
			break
		}
	}
}