123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752 |
- package glisp
- import (
- "errors"
- "fmt"
- )
- type Generator struct {
- env *Glisp
- funcname string
- tail bool
- scopes int
- instructions []Instruction
- }
- type Loop struct {
- stmtname SexpSymbol
- loopStart int
- loopLen int
- breakOffset int // i.e. relative to loopStart
- continueOffset int // i.e. relative to loopStart
- }
- func (loop *Loop) IsStackElem() {}
- func NewGenerator(env *Glisp) *Generator {
- gen := new(Generator)
- gen.env = env
- gen.instructions = make([]Instruction, 0)
- // tail marks whether or not we are in the tail position
- gen.tail = false
- // scopes is the number of extra (non-function) scopes we've created
- gen.scopes = 0
- return gen
- }
- func (gen *Generator) AddInstructions(instr []Instruction) {
- gen.instructions = append(gen.instructions, instr...)
- }
- func (gen *Generator) AddInstruction(instr Instruction) {
- gen.instructions = append(gen.instructions, instr)
- }
- func (gen *Generator) GenerateBegin(expressions []Sexp) error {
- size := len(expressions)
- oldtail := gen.tail
- gen.tail = false
- if size == 0 {
- return errors.New("No expressions found")
- }
- for _, expr := range expressions[:size-1] {
- err := gen.Generate(expr)
- if err != nil {
- return err
- }
- // insert pops after all but the last instruction
- // that way the stack remains clean
- gen.AddInstruction(PopInstr(0))
- }
- gen.tail = oldtail
- return gen.Generate(expressions[size-1])
- }
- func buildSexpFun(env *Glisp, name string, funcargs SexpArray,
- funcbody []Sexp) (SexpFunction, error) {
- gen := NewGenerator(env)
- gen.tail = true
- if len(name) == 0 {
- gen.funcname = env.GenSymbol("__anon").name
- } else {
- gen.funcname = name
- }
- argsyms := make([]SexpSymbol, len(funcargs))
- for i, expr := range funcargs {
- switch t := expr.(type) {
- case SexpSymbol:
- argsyms[i] = t
- default:
- return MissingFunction,
- errors.New("function argument must be symbol")
- }
- }
- varargs := false
- nargs := len(funcargs)
- if len(argsyms) >= 2 && argsyms[len(argsyms)-2].name == "&" {
- argsyms[len(argsyms)-2] = argsyms[len(argsyms)-1]
- argsyms = argsyms[0 : len(argsyms)-1]
- varargs = true
- nargs = len(argsyms) - 1
- }
- for i := len(argsyms) - 1; i >= 0; i-- {
- gen.AddInstruction(PutInstr{argsyms[i]})
- }
- err := gen.GenerateBegin(funcbody)
- if err != nil {
- return MissingFunction, err
- }
- gen.AddInstruction(ReturnInstr{nil})
- newfunc := GlispFunction(gen.instructions)
- return MakeFunction(gen.funcname, nargs, varargs, newfunc), nil
- }
- func (gen *Generator) GenerateFn(args []Sexp) error {
- if len(args) < 2 {
- return errors.New("malformed function definition")
- }
- var funcargs SexpArray
- switch expr := args[0].(type) {
- case SexpArray:
- funcargs = expr
- default:
- return errors.New("function arguments must be in vector")
- }
- funcbody := args[1:]
- sfun, err := buildSexpFun(gen.env, "", funcargs, funcbody)
- if err != nil {
- return err
- }
- gen.AddInstruction(PushInstrClosure{sfun})
- return nil
- }
- func (gen *Generator) GenerateDef(args []Sexp) error {
- if len(args) != 2 {
- return errors.New("Wrong number of arguments to def")
- }
- var sym SexpSymbol
- switch expr := args[0].(type) {
- case SexpSymbol:
- sym = expr
- default:
- return errors.New("Definition name must by symbol")
- }
- gen.tail = false
- err := gen.Generate(args[1])
- if err != nil {
- return err
- }
- gen.AddInstruction(PutInstr{sym})
- gen.AddInstruction(PushInstr{SexpNull})
- return nil
- }
- func (gen *Generator) GenerateDefn(args []Sexp) error {
- if len(args) < 3 {
- return errors.New("Wrong number of arguments to defn")
- }
- var funcargs SexpArray
- switch expr := args[1].(type) {
- case SexpArray:
- funcargs = expr
- default:
- return errors.New("function arguments must be in vector")
- }
- var sym SexpSymbol
- switch expr := args[0].(type) {
- case SexpSymbol:
- sym = expr
- default:
- return errors.New("Definition name must by symbol")
- }
- sfun, err := buildSexpFun(gen.env, sym.name, funcargs, args[2:])
- if err != nil {
- return err
- }
- gen.AddInstruction(PushInstr{sfun})
- gen.AddInstruction(PutInstr{sym})
- gen.AddInstruction(PushInstr{SexpNull})
- return nil
- }
- func (gen *Generator) GenerateDefmac(args []Sexp) error {
- if len(args) < 3 {
- return errors.New("Wrong number of arguments to defmac")
- }
- var funcargs SexpArray
- switch expr := args[1].(type) {
- case SexpArray:
- funcargs = expr
- default:
- return errors.New("function arguments must be in vector")
- }
- var sym SexpSymbol
- switch expr := args[0].(type) {
- case SexpSymbol:
- sym = expr
- default:
- return errors.New("Definition name must by symbol")
- }
- sfun, err := buildSexpFun(gen.env, sym.name, funcargs, args[2:])
- if err != nil {
- return err
- }
- gen.env.macros[sym.number] = sfun
- gen.AddInstruction(PushInstr{SexpNull})
- return nil
- }
- func (gen *Generator) GenerateMacexpand(args []Sexp) error {
- if len(args) != 1 {
- return WrongNargs
- }
- var list SexpPair
- var islist bool
- var ismacrocall bool
- switch t := args[0].(type) {
- case SexpPair:
- if IsList(t.tail) {
- list = t
- islist = true
- }
- default:
- islist = false
- }
- var macro SexpFunction
- if islist {
- switch t := list.head.(type) {
- case SexpSymbol:
- macro, ismacrocall = gen.env.macros[t.number]
- default:
- ismacrocall = false
- }
- }
- if !ismacrocall {
- gen.AddInstruction(PushInstr{args[0]})
- return nil
- }
- macargs, err := ListToArray(list.tail)
- if err != nil {
- return err
- }
- env := gen.env.Duplicate()
- expr, err := env.Apply(macro, macargs)
- if err != nil {
- return err
- }
- gen.AddInstruction(PushInstr{expr})
- return nil
- }
- func (gen *Generator) GenerateShortCircuit(or bool, args []Sexp) error {
- size := len(args)
- subgen := NewGenerator(gen.env)
- subgen.scopes = gen.scopes
- subgen.tail = gen.tail
- subgen.funcname = gen.funcname
- subgen.Generate(args[size-1])
- instructions := subgen.instructions
- for i := size - 2; i >= 0; i-- {
- subgen = NewGenerator(gen.env)
- subgen.Generate(args[i])
- subgen.AddInstruction(DupInstr(0))
- subgen.AddInstruction(BranchInstr{or, len(instructions) + 2})
- subgen.AddInstruction(PopInstr(0))
- instructions = append(subgen.instructions, instructions...)
- }
- gen.AddInstructions(instructions)
- return nil
- }
- func (gen *Generator) GenerateCond(args []Sexp) error {
- if len(args)%2 == 0 {
- return errors.New("missing default case")
- }
- subgen := NewGenerator(gen.env)
- subgen.tail = gen.tail
- subgen.scopes = gen.scopes
- subgen.funcname = gen.funcname
- err := subgen.Generate(args[len(args)-1])
- if err != nil {
- return err
- }
- instructions := subgen.instructions
- for i := len(args)/2 - 1; i >= 0; i-- {
- subgen.Reset()
- err := subgen.Generate(args[2*i])
- if err != nil {
- return err
- }
- pred_code := subgen.instructions
- subgen.Reset()
- subgen.tail = gen.tail
- subgen.scopes = gen.scopes
- subgen.funcname = gen.funcname
- err = subgen.Generate(args[2*i+1])
- if err != nil {
- return err
- }
- body_code := subgen.instructions
- subgen.Reset()
- subgen.AddInstructions(pred_code)
- subgen.AddInstruction(BranchInstr{false, len(body_code) + 2})
- subgen.AddInstructions(body_code)
- subgen.AddInstruction(JumpInstr{len(instructions) + 1})
- subgen.AddInstructions(instructions)
- instructions = subgen.instructions
- }
- gen.AddInstructions(instructions)
- return nil
- }
- func (gen *Generator) GenerateQuote(args []Sexp) error {
- for _, expr := range args {
- gen.AddInstruction(PushInstr{expr})
- }
- return nil
- }
- func (gen *Generator) GenerateLet(name string, args []Sexp) error {
- if len(args) < 2 {
- return errors.New("malformed let statement")
- }
- lstatements := make([]SexpSymbol, 0)
- rstatements := make([]Sexp, 0)
- var bindings []Sexp
- switch expr := args[0].(type) {
- case SexpArray:
- bindings = []Sexp(expr)
- default:
- return errors.New("let bindings must be in array")
- }
- if len(bindings)%2 != 0 {
- return errors.New("uneven let binding list")
- }
- for i := 0; i < len(bindings)/2; i++ {
- switch t := bindings[2*i].(type) {
- case SexpSymbol:
- lstatements = append(lstatements, t)
- default:
- return errors.New("cannot bind to non-symbol")
- }
- rstatements = append(rstatements, bindings[2*i+1])
- }
- gen.AddInstruction(AddScopeInstr(0))
- gen.scopes++
- if name == "let*" {
- for i, rs := range rstatements {
- err := gen.Generate(rs)
- if err != nil {
- return err
- }
- gen.AddInstruction(PutInstr{lstatements[i]})
- }
- } else if name == "let" {
- for _, rs := range rstatements {
- err := gen.Generate(rs)
- if err != nil {
- return err
- }
- }
- for i := len(lstatements) - 1; i >= 0; i-- {
- gen.AddInstruction(PutInstr{lstatements[i]})
- }
- }
- err := gen.GenerateBegin(args[1:])
- if err != nil {
- return err
- }
- gen.AddInstruction(RemoveScopeInstr(0))
- gen.scopes--
- return nil
- }
- func (gen *Generator) GenerateAssert(args []Sexp) error {
- if len(args) != 1 {
- return WrongNargs
- }
- err := gen.Generate(args[0])
- if err != nil {
- return err
- }
- reterrmsg := fmt.Sprintf("Assertion failed: %s\n",
- args[0].SexpString())
- gen.AddInstruction(BranchInstr{true, 2})
- gen.AddInstruction(ReturnInstr{errors.New(reterrmsg)})
- gen.AddInstruction(PushInstr{SexpNull})
- return nil
- }
- func (gen *Generator) GenerateInclude(args []Sexp) error {
- if len(args) < 1 {
- return WrongNargs
- }
- var err error
- var exps []Sexp
- var sourceItem func(item Sexp) error
- sourceItem = func(item Sexp) error {
- switch t := item.(type) {
- case SexpArray:
- for _, v := range t {
- if err := sourceItem(v); err != nil {
- return err
- }
- }
- case SexpPair:
- expr := item
- for expr != SexpNull {
- list := expr.(SexpPair)
- if err := sourceItem(list.head); err != nil {
- return err
- }
- expr = list.tail
- }
- case SexpStr:
- exps, err = gen.env.ParseFile(string(t))
- if err != nil {
- return err
- }
- err = gen.GenerateBegin(exps)
- if err != nil {
- return err
- }
- default:
- return fmt.Errorf("include: Expected `string`, `list`, `array` given type %T val %v", item, item)
- }
- return nil
- }
- for _, v := range args {
- err = sourceItem(v)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (gen *Generator) GenerateCallBySymbol(sym SexpSymbol, args []Sexp) error {
- switch sym.name {
- case "and":
- return gen.GenerateShortCircuit(false, args)
- case "or":
- return gen.GenerateShortCircuit(true, args)
- case "cond":
- return gen.GenerateCond(args)
- case "quote":
- return gen.GenerateQuote(args)
- case "def":
- return gen.GenerateDef(args)
- case "fn":
- return gen.GenerateFn(args)
- case "defn":
- return gen.GenerateDefn(args)
- case "begin":
- return gen.GenerateBegin(args)
- case "let":
- return gen.GenerateLet("let", args)
- case "let*":
- return gen.GenerateLet("let*", args)
- case "assert":
- return gen.GenerateAssert(args)
- case "defmac":
- return gen.GenerateDefmac(args)
- case "macexpand":
- return gen.GenerateMacexpand(args)
- case "syntax-quote":
- return gen.GenerateSyntaxQuote(args)
- case "include":
- return gen.GenerateInclude(args)
- }
- macro, found := gen.env.macros[sym.number]
- if found {
- // calling Apply on the current environment will screw up
- // the stack, creating a duplicate environment is safer
- env := gen.env.Duplicate()
- expr, err := env.Apply(macro, args)
- if err != nil {
- return err
- }
- return gen.Generate(expr)
- }
- oldtail := gen.tail
- gen.tail = false
- err := gen.GenerateAll(args)
- if err != nil {
- return err
- }
- if oldtail && sym.name == gen.funcname {
- // to do a tail call
- // pop off all the extra scopes
- // then jump to beginning of function
- for i := 0; i < gen.scopes; i++ {
- gen.AddInstruction(RemoveScopeInstr(0))
- }
- gen.AddInstruction(GotoInstr{0})
- } else {
- gen.AddInstruction(CallInstr{sym, len(args)})
- }
- gen.tail = oldtail
- return nil
- }
- func (gen *Generator) GenerateDispatch(fun Sexp, args []Sexp) error {
- gen.GenerateAll(args)
- gen.Generate(fun)
- gen.AddInstruction(DispatchInstr{len(args)})
- return nil
- }
- func (gen *Generator) GenerateCall(expr SexpPair) error {
- arr, _ := ListToArray(expr.tail)
- switch head := expr.head.(type) {
- case SexpSymbol:
- return gen.GenerateCallBySymbol(head, arr)
- }
- return gen.GenerateDispatch(expr.head, arr)
- }
- func (gen *Generator) GenerateArray(arr SexpArray) error {
- err := gen.GenerateAll(arr)
- if err != nil {
- return err
- }
- gen.AddInstruction(CallInstr{gen.env.MakeSymbol("array"), len(arr)})
- return nil
- }
- func (gen *Generator) Generate(expr Sexp) error {
- switch e := expr.(type) {
- case SexpSymbol:
- gen.AddInstruction(GetInstr{e})
- return nil
- case SexpPair:
- if IsList(e) {
- err := gen.GenerateCall(e)
- if err != nil {
- return errors.New(
- fmt.Sprintf("Error generating %s:\n%v",
- expr.SexpString(), err))
- }
- return nil
- } else {
- gen.AddInstruction(PushInstr{expr})
- }
- case SexpArray:
- return gen.GenerateArray(e)
- default:
- gen.AddInstruction(PushInstr{expr})
- return nil
- }
- return nil
- }
- func (gen *Generator) GenerateAll(expressions []Sexp) error {
- for _, expr := range expressions {
- err := gen.Generate(expr)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (gen *Generator) Reset() {
- gen.instructions = make([]Instruction, 0)
- gen.tail = false
- gen.scopes = 0
- }
- // side-effect (or main effect) has to be pushing an expression on the top of
- // the datastack that represents the expanded and substituted expression
- func (gen *Generator) GenerateSyntaxQuote(args []Sexp) error {
- if len(args) != 1 {
- return errors.New("syntax-quote takes exactly one argument")
- }
- arg := args[0]
- // need to handle arrays, since they can have unquotes
- // in them too.
- switch arg.(type) {
- case SexpArray:
- gen.generateSyntaxQuoteArray(arg)
- return nil
- case SexpPair:
- if !IsList(arg) {
- break
- }
- gen.generateSyntaxQuoteList(arg)
- return nil
- case SexpHash:
- gen.generateSyntaxQuoteHash(arg)
- return nil
- }
- gen.AddInstruction(PushInstr{arg})
- return nil
- }
- func (gen *Generator) generateSyntaxQuoteList(arg Sexp) error {
- switch a := arg.(type) {
- case SexpPair:
- //good, required here
- default:
- return fmt.Errorf("arg to generateSyntaxQuoteList() must be list; got %T", a)
- }
- // things that need unquoting end up as
- // (unquote mysym)
- // i.e. a pair
- // list of length 2 exactly, with first atom
- // being "unquote" and second being the symbol
- // to substitute.
- quotebody, _ := ListToArray(arg)
- if len(quotebody) == 2 {
- var issymbol bool
- var sym SexpSymbol
- switch t := quotebody[0].(type) {
- case SexpSymbol:
- sym = t
- issymbol = true
- default:
- issymbol = false
- }
- if issymbol {
- if sym.name == "unquote" {
- gen.Generate(quotebody[1])
- return nil
- } else if sym.name == "unquote-splicing" {
- gen.Generate(quotebody[1])
- gen.AddInstruction(ExplodeInstr(0))
- return nil
- }
- }
- }
- gen.AddInstruction(PushInstr{SexpMarker})
- for _, expr := range quotebody {
- gen.GenerateSyntaxQuote([]Sexp{expr})
- }
- gen.AddInstruction(SquashInstr(0))
- return nil
- }
- func (gen *Generator) generateSyntaxQuoteArray(arg Sexp) error {
- var arr SexpArray
- switch a := arg.(type) {
- case SexpArray:
- //good, required here
- arr = a
- default:
- return fmt.Errorf("arg to generateSyntaxQuoteArray() must be an array; got %T", a)
- }
- gen.AddInstruction(PushInstr{SexpMarker})
- for _, expr := range arr {
- gen.AddInstruction(PushInstr{SexpMarker})
- gen.GenerateSyntaxQuote([]Sexp{expr})
- gen.AddInstruction(SquashInstr(0))
- gen.AddInstruction(ExplodeInstr(0))
- }
- gen.AddInstruction(VectorizeInstr(0))
- return nil
- }
- func (gen *Generator) generateSyntaxQuoteHash(arg Sexp) error {
- var hash SexpHash
- switch a := arg.(type) {
- case SexpHash:
- //good, required here
- hash = a
- default:
- return fmt.Errorf("arg to generateSyntaxQuoteHash() must be a hash; got %T", a)
- }
- n := HashCountKeys(hash)
- gen.AddInstruction(PushInstr{SexpMarker})
- for i := 0; i < n; i++ {
- // must reverse order here to preserve order on rebuild
- key := (*hash.KeyOrder)[(n-i)-1]
- val, err := hash.HashGet(key)
- if err != nil {
- return err
- }
- // value first, since value comes second on rebuild
- gen.AddInstruction(PushInstr{SexpMarker})
- gen.GenerateSyntaxQuote([]Sexp{val})
- gen.AddInstruction(SquashInstr(0))
- gen.AddInstruction(ExplodeInstr(0))
- gen.AddInstruction(PushInstr{SexpMarker})
- gen.GenerateSyntaxQuote([]Sexp{key})
- gen.AddInstruction(SquashInstr(0))
- gen.AddInstruction(ExplodeInstr(0))
- }
- gen.AddInstruction(HashizeInstr{
- HashLen: n,
- TypeName: *(hash.TypeName),
- })
- return nil
- }
|