Snippets

Patrick Logan AST interfaces and implementations for a Scheme interpreter in Go

Created by Patrick Logan
package nconc

import (
	"fmt"
)

type Conditional struct {
	Test, Yes, No Expression
}

type ConditionalK struct {
	Yes, No Expression
	NextK   Continuation
}

type Sequence []Expression

type SequenceK struct {
	Es    []Expression
	NextK Continuation
}

type Quote struct {
	D Datum
}

type Definition struct {
	Id Datum
	E  Expression
}

type DefinitionK struct {
	Id    Datum
	NextK Continuation
}

type Assignment struct {
	Id Datum
	E  Expression
}

type AssignmentK struct {
	Id    Datum
	NextK Continuation
}

type Combination []Expression

type CombinationK struct {
	Es    []Expression // Execute each expression of a combination via successive CombinationK continuations
	Ds    []Datum      // Collect the data, giving the final expression an Applicationk continuation
	NextK Continuation
}

type Application []Datum // Apply the first datum, a procedure, to the remaining data, the actual arguments

type ApplicationK struct {
	Ds    []Datum // Collect the data from evaluating each element of a combination then apply via Application
	NextK Continuation
}

type GlobalReference string

type LexicalReference struct {
	Frame, Offset int
}

func (k ApplicationK) Invoke(result Datum, rte *RuntimeFrame, interp *Interpreter) (b Bouncer, d Datum, err error) {
	b = Bouncer{E: Application(append(k.Ds, result)), F: rte, K: k.NextK}
	return
}

func (a Application) Execute(rte *RuntimeFrame, rtk Continuation, interp *Interpreter) (b Bouncer, d Datum, err error) {
	if len(a) == 0 {
		err = ImplementationError("An application must have a callable procedure")
		return
	}
	c, ok := a[0].(Callable)
	if !ok {
		err = ProcedureExpectedError{a[0]}
		return
	}
	var actuals []Datum
	if len(a) > 1 {
		actuals = a[1:]
	}
	var values Datum
	b, values, err = c.Call(rte, rtk, interp, actuals...)
	if err != nil {
		return
	}
	if values != nil {
		b, d, err = rtk.Invoke(values, rte, interp)
	}
	return
}

func (k CombinationK) Invoke(result Datum, rte *RuntimeFrame, interp *Interpreter) (b Bouncer, d Datum, err error) {
	switch len(k.Es) {
	case 0:
		err = ImplementationError("A combination continuation must have at least one expression to execute")
		return
	case 1:
		k1 := ApplicationK{Ds: append(k.Ds, result), NextK: k.NextK}
		b = Bouncer{E: k.Es[0], F: rte, K: k1}
		return
	default:
		k1 := CombinationK{Es: k.Es[1:], Ds: append(k.Ds, result), NextK: k.NextK}
		b = Bouncer{E: k.Es[0], F: rte, K: k1}
		return
	}
}

func (c Combination) Execute(rte *RuntimeFrame, rtk Continuation, interp *Interpreter) (b Bouncer, d Datum, err error) {
	switch len(c) {
	case 0:
		err = EmptyListError{}
		return
	case 1:
		k := ApplicationK{NextK: rtk}
		b = Bouncer{E: c[0], F: rte, K: k}
		return
	default:
		k := CombinationK{Es: c[1:], NextK: rtk}
		b = Bouncer{E: c[0], F: rte, K: k}
		return
	}
}

// Currently allows redefinitions, no need to use SET!
func (k DefinitionK) Invoke(result Datum, rte *RuntimeFrame, interp *Interpreter) (b Bouncer, d Datum, err error) {
	var s *Symbol
	s, ok := k.Id.(*Symbol)
	if !ok {
		err = ImplementationError(fmt.Sprintf("Identifier expected, %T", k.Id))
		return
	}
	interp.TopLevel[s] = result
	k.NextK.Invoke(Void{}, rte, interp)
	return
}

func (def Definition) Execute(rte *RuntimeFrame, rtk Continuation, interp *Interpreter) (b Bouncer, d Datum, err error) {
	k := DefinitionK{Id: def.Id, NextK: rtk}
	b = Bouncer{E: def.E, F: rte, K: k}
	return
}

func (k AssignmentK) Invoke(result Datum, rte *RuntimeFrame, interp *Interpreter) (b Bouncer, d Datum, err error) {
	var s *Symbol
	s, ok := k.Id.(*Symbol)
	if !ok {
		err = ImplementationError(fmt.Sprintf("Identifier expected, %T", k.Id))
		return
	}
	interp.TopLevel[s] = result
	b, d, err = k.NextK.Invoke(Void{}, rte, interp)
	return
}

func (def Assignment) Execute(rte *RuntimeFrame, rtk Continuation, interp *Interpreter) (b Bouncer, d Datum, err error) {
	k := AssignmentK{Id: def.Id, NextK: rtk}
	b = Bouncer{E: def.E, F: rte, K: k}
	return
}

func (ref GlobalReference) Execute(rte *RuntimeFrame, rtk Continuation, interp *Interpreter) (b Bouncer, d Datum, err error) {
	s := interp.Intern(string(ref))
	datum, ok := interp.TopLevel[s]
	if !ok {
		err = UnboundVariableError(string(ref))
	}
	b, d, err = rtk.Invoke(datum, rte, interp)
	return
}

func (ref LexicalReference) Execute(rte *RuntimeFrame, rtk Continuation, interp *Interpreter) (b Bouncer, d Datum, err error) {
	var datum Datum
	datum, err = rte.lookup(ref.Frame, ref.Offset)
	if err != nil {
		return
	}
	b, d, err = rtk.Invoke(datum, rte, interp)
	return
}

func (q Quote) Execute(rte *RuntimeFrame, rtk Continuation, interp *Interpreter) (b Bouncer, d Datum, err error) {
	b, d, err = rtk.Invoke(q.D, rte, interp)
	return
}

func (k SequenceK) Invoke(result Datum, rte *RuntimeFrame, interp *Interpreter) (b Bouncer, d Datum, err error) {
	switch len(k.Es) {
	case 0:
		err = ImplementationError("A SequenceK must have at least one expression")
	case 1:
		b = Bouncer{E: k.Es[0], F: rte, K: k.NextK}
	default:
		k1 := SequenceK{Es: k.Es[1:], NextK: k.NextK}
		b = Bouncer{E: k.Es[0], F: rte, K: k1}
	}
	return
}

func (s Sequence) Execute(rte *RuntimeFrame, rtk Continuation, interp *Interpreter) (b Bouncer, d Datum, err error) {
	switch len(s) {
	case 0:
		b, d, err = rtk.Invoke(Void{}, rte, interp) // (begin) => void
	case 1:
		b = Bouncer{E: s[0], F: rte, K: rtk}
	default:
		k := SequenceK{Es: s[1:], NextK: rtk}
		b = Bouncer{E: s[0], F: rte, K: k}
	}
	return
}

func (k ConditionalK) Invoke(result Datum, rte *RuntimeFrame, interp *Interpreter) (b Bouncer, d Datum, err error) {
	var e Expression
	if result.IsFalse() {
		e = k.No
	} else {
		e = k.Yes
	}
	b = Bouncer{E: e, F: rte, K: k.NextK}
	return
}

func (c Conditional) Execute(rte *RuntimeFrame, rtk Continuation, interp *Interpreter) (b Bouncer, d Datum, err error) {
	k := ConditionalK{Yes: c.Yes, No: c.No, NextK: rtk}
	b = Bouncer{E: c.Test, F: rte, K: k}
	return
}

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.