Commits

Anonymous committed 8fbb814

Initial commit. S, K, I and apply operator are implemented.

Comments (0)

Files changed (2)

+include $(GOROOT)/src/Make.inc
+
+TARG=unlambda
+GOFILES=unlambda.go
+
+include $(GOROOT)/src/Make.cmd
+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
+		}
+	}
+}