package sexpr
import (
fmt
math/big
)
// SExpr defines the struct of an S-expression.
// 1. If this S-expression is `NIL`: all `atom`, `car` and `cdr` fields should
//be null pointers (Gos `nil`), i.e. `SExpr{}` or verbosely
//`
//SExpr{
//atom: nil,
//car: nil,
//cdr: nil,
//}
//`
// 2. If this S-expression is a non-`NIL` atom, the `atom` field should store
//the corresponding non-null token pointer of token types `tokenNumber` or
//`tokenSymbol`, and both `car` and `cdr` fields should be null pointers
//(Gos `nil`). E.g. `SExpr{atom: mkTokenSymbol(+)}` or verbosely
//`
//SExpr{
//atom: mkTokenSymbol(+),
//car: nil,
//cdr: nil,
//},
//`
// 3. If this S-expression is a non-`NIL` cons cell, the `atom` field should be
//a null pointer (Gos `nil`) and both `car` and `cdr` should be non-null
//SExpr pointers. Remember that `NIL` is represented as `&SExpr{}` but not a
//non-pointer (Gos `nil`). E.g.
//`
//SExpr{
//atom: nil,
//car: &SExpr{atom: mkTokenSymbol(+)},
//cdr: &SExpr{},
//}
//`
type SExpr struct {
atom *token
car*SExpr
cdr*SExpr
}
// Below we provide useful helper functions and you may want to use them to
// create an S-expression or check whether an S-expression is a `NIL`, (symbol
// or number) atom or cons cell. __Do not modify them__. Feel free to write your
// own helper functions __in files we ask you to modify__.
// NIL
//
func mkNil() *SExpr {
return &SExpr{}
}
// Caveat: `expr.car.isNil()` or `expr.cdr.isNil()` will not work as expected
// when `expr.isNil() == true`. Special treatments is required for this case.
func (expr *SExpr) isNil() bool {
return expr.atom == nil && expr.car == nil && expr.cdr == nil
}
// atom
//
func mkAtom(tok *token) *SExpr {
return &SExpr{atom: tok}
}
// Symbol, number or NIL
func (expr *SExpr) isAtom() bool {
return expr.isNil() ||
(expr.atom != nil && expr.car == nil && expr.cdr == nil)
}
// number atom
// Create a number atom of the int `num`
func mkNumber(num *big.Int) *SExpr {
return &SExpr{atom: &token{typ: tokenNumber, num: num}}
}
func (expr *SExpr) isNumber() bool {
return expr.isAtom() && !expr.isNil() && expr.atom.typ == tokenNumber
}
// symbol atom
// Create a symbol atom of the string `lit`
func mkSymbol(lit string) *SExpr {
return &SExpr{atom: mkTokenSymbol(lit)}
}
func (expr *SExpr) isSymbol() bool {
return expr.isAtom() && !expr.isNil() && expr.atom.typ == tokenSymbol
}
// Create a True symbol atom `T`
func mkSymbolTrue() *SExpr {
return mkSymbol(T)
}
// cons cell
//
// Create a cons cell with given `car` and `cdr`
func mkConsCell(car, cdr *SExpr) *SExpr {
return &SExpr{nil, car, cdr}
}
// Cons cell or NIL
func (expr *SExpr) isConsCell() bool {
return expr.isNil() ||
(expr.atom == nil && expr.car != nil && expr.cdr != nil)
}
// Helper functions to serialize an S-expression in different ways.
// SExprString serializes an SExpr into the __DOTTED__ S-expression representation
func (expr *SExpr) SExprString() string {
switch {
case expr.isNil():
return NIL
case expr.isAtom():
return expr.atom.String()
default:
return fmt.Sprintf((%s . %s), expr.car.SExprString(), expr.cdr.SExprString())
}
}
Reviews
There are no reviews yet.