scopes.go 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. package glisp
  2. import (
  3. "errors"
  4. "fmt"
  5. )
  6. type Scope map[int]Sexp
  7. func (s Scope) IsStackElem() {}
  8. func (stack *Stack) PushScope() {
  9. stack.Push(Scope(make(map[int]Sexp)))
  10. }
  11. func (stack *Stack) PopScope() error {
  12. _, err := stack.Pop()
  13. return err
  14. }
  15. func (stack *Stack) lookupSymbol(sym SexpSymbol, minFrame int) (Sexp, error) {
  16. if !stack.IsEmpty() {
  17. for i := 0; i <= stack.tos-minFrame; i++ {
  18. elem, err := stack.Get(i)
  19. if err != nil {
  20. return SexpNull, err
  21. }
  22. scope := map[int]Sexp(elem.(Scope))
  23. expr, ok := scope[sym.number]
  24. if ok {
  25. return expr, nil
  26. }
  27. }
  28. }
  29. return SexpNull, errors.New(fmt.Sprint("symbol ", sym, " not found"))
  30. }
  31. func (stack *Stack) LookupSymbol(sym SexpSymbol) (Sexp, error) {
  32. return stack.lookupSymbol(sym, 0)
  33. }
  34. // LookupSymbolNonGlobal - closures use this to only find symbols below the global scope, to avoid copying globals it'll always be-able to ref
  35. func (stack *Stack) LookupSymbolNonGlobal(sym SexpSymbol) (Sexp, error) {
  36. return stack.lookupSymbol(sym, 1)
  37. }
  38. func (stack *Stack) BindSymbol(sym SexpSymbol, expr Sexp) error {
  39. if stack.IsEmpty() {
  40. return errors.New("no scope available")
  41. }
  42. stack.elements[stack.tos].(Scope)[sym.number] = expr
  43. return nil
  44. }