Skip to content

Commit

Permalink
Start creating, printing and testing s-expressions!
Browse files Browse the repository at this point in the history
  • Loading branch information
eigenhombre committed Mar 5, 2022
1 parent a7a0412 commit b3a84e1
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 2 deletions.
5 changes: 3 additions & 2 deletions lexutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ package main
// https://www.youtube.com/watch?v=HxaD_trXwRE
// https://talks.golang.org/2011/lex.slide
//
// Modified by John Jacobsen to work with a user-supplied set of lexemes
// and state functions.
// Slightly modified by John Jacobsen to work with a user-supplied set of
// lexemes and state functions.
// FIXME: Spin this out into a package.
//
// Copyright (c) 2011 The Go Authors. All rights reserved.

Expand Down
64 changes: 64 additions & 0 deletions lisp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package main

import (
"fmt"
"math/big"
)

// sexpr is a general-purpose data structure for representing
// S-expressions; for now, it has String only, but it may have
// evaluable or other methods added later.
type sexpr interface {
String() string
}

// consCell is a cons cell. Use Cons to create one.
type consCell struct {
car sexpr
cdr sexpr
}

// Nil is the empty list / cons cell. Cons with Nil to create a list
// of one item.
var Nil *consCell = nil

func (j *consCell) String() string {
ret := "("
for car := j; car != Nil; car = car.cdr.(*consCell) {
if car.car == Nil {
return ret + ")"
}
ret += car.car.String()
if car.cdr != Nil {
ret += " "
}
}
return ret + ")"
}

// number is a big.Int, but narrower in its string representation.
type number struct {
big.Int
}

// String returns the string representation of the number.
func (n number) String() string {
return n.Text(10)
}

func Num(ob interface{}) number {
var n number
switch s := ob.(type) {
case string:
n.SetString(s, 10)
case int:
n.SetInt64(int64(s))
default:
panic(fmt.Sprintf("Num: unknown type %T\n", ob))
}
return n
}

func Cons(i sexpr, cdr *consCell) *consCell {
return &consCell{i, cdr}
}
52 changes: 52 additions & 0 deletions sexpr_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package main

import (
"fmt"
"testing"
)

func TestNumberStrings(T *testing.T) {
var tests = []struct {
input interface{}
output string
}{
{1, "1"},
{"1", "1"},
{666, "666"},
{"12948712498129877", "12948712498129877"},
}
for _, test := range tests {
fmt.Printf("Checking that %T-valued %v -> %q\n",
test.input, test.input, test.output)
if Num(test.input).String() != test.output {
T.Errorf("Num(%q).String() != %q", test.input, test.output)
}
}
}

func TestSexprStrings(T *testing.T) {
var tests = []struct {
input sexpr
want string
}{
{Nil, "()"},
{Num(1), "1"},
{Num("2"), "2"},
{Cons(Num(1), Cons(Num("2"), Nil)), "(1 2)"},
{Cons(Num(1), Cons(Num("2"), Cons(Num(3), Nil))), "(1 2 3)"},
{Cons(
Cons(
Num(3),
Cons(
Num("1309875618907812098"),
Nil)),
Cons(Num(5), Cons(Num("6"), Nil))), "((3 1309875618907812098) 5 6)"},
}
for _, test := range tests {
fmt.Printf("Checking string representation: %v\n", test.input)
if test.input.String() != test.want {
T.Errorf("%T-valued %v.String() != %s",
test.input, test.input, test.want)
}
}
}

0 comments on commit b3a84e1

Please sign in to comment.