1
0
Fork 0
Little S-Expression Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sxpf/lookup.go

122 lines
2.9 KiB

//-----------------------------------------------------------------------------
// Copyright (c) 2022 Detlef Stern
//
// This file is part of sxpf.
//
// sxpf is licensed under the latest version of the EUPL // (European Union
// Public License). Please see file LICENSE.txt for your rights and obligations
// under this license.
//-----------------------------------------------------------------------------
package sxpf
import "io"
// SymbolMap maps symbols to values.
type SymbolMap struct {
maker SymbolMaker
parent *SymbolMap
assoc map[*Symbol]Value
}
func NewSymbolMap(smk SymbolMaker, parentMap *SymbolMap) *SymbolMap {
if parentMap != nil {
if parentMap.maker != smk {
panic("using different symbol maker")
}
}
return &SymbolMap{
maker: smk,
parent: parentMap,
assoc: map[*Symbol]Value{},
}
}
// Set a symbol to its associated value.
func (sm *SymbolMap) Set(sym *Symbol, val Value) {
if oldSym := sm.maker.MakeSymbol(sym.String()); oldSym != sym {
panic("symbol is from other maker")
}
sm.assoc[sym] = val
}
// Lookup the value assiated with a given symbol.
func (sm *SymbolMap) Lookup(sym *Symbol) (Value, bool) {
for curSm := sm; curSm != nil; curSm = curSm.parent {
if val, found := curSm.assoc[sym]; found {
return val, true
}
}
return nil, false
}
// LookupForm returns the value associated with the given symbol, if the value
// is a form.
func (sm *SymbolMap) LookupForm(sym *Symbol) (Form, error) {
if val, found := sm.Lookup(sym); found {
if form, ok := val.(Form); ok {
return form, nil
}
}
return nil, ErrNotFormBound(sym)
}
// MustLookupForm returns the form associated with the given symbol.
// Otherwise it will panic
func (sm *SymbolMap) MustLookupForm(sym *Symbol) Form {
form, err := sm.LookupForm(sym)
if err == nil {
return form
}
panic(err)
}
// AsPair returns a pair representation of the symbol map.
func (sm *SymbolMap) AsPair() *Pair {
if sm == nil {
return Nil()
}
var parent *Pair
if sm.parent == nil {
parent = Nil()
} else {
parent = sm.parent.AsPair()
}
parent = NewPair(NewString("parent"), NewPair(parent, nil))
var tail *Pair
for sym, val := range sm.assoc {
tail = NewPair(NewPair(sym, NewPair(val, nil)), tail)
}
return NewPair(NewString("symbol"), NewPair(parent, tail))
}
// Sexpr methods
func (sm *SymbolMap) IsNil() bool { return sm == nil }
func (sm *SymbolMap) Equal(other Value) bool {
if sm == nil || IsNil(other) {
return sm == other
}
o, ok := other.(*SymbolMap)
if !ok {
return false
}
if sm == o {
return true
}
if !sm.parent.Equal(o.parent) || len(sm.assoc) != len(o.assoc) {
return false
}
for sym, val := range sm.assoc {
if oval, found := o.assoc[sym]; !found || !val.Equal(oval) {
return false
}
}
return true
}
func (sm *SymbolMap) Print(w io.Writer) error {
return sm.AsPair().Print(w)
}
func (sm *SymbolMap) String() string { return sm.AsPair().String() }