Skip to content

Commit c79ee2c

Browse files
committed
Readme + small edits
1 parent 75d3b4e commit c79ee2c

File tree

9 files changed

+54
-108
lines changed

9 files changed

+54
-108
lines changed

README.md

+7-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ as outlined by Don Yessick for CS403 at the University of Alabama
66
This interpreter is feature complete for the language as defined by Yessick
77
Notes on choices made:
88

9-
```true``` is the truth value
9+
```true``` for truthy values
1010

11-
```nil``` used for false/nil value
11+
```nil``` for falsey/nil values
1212

1313
```=``` used for equality checking
1414

@@ -39,6 +39,9 @@ First, move into the ```golisp``` directory that was just created
3939

4040
From here, you can use the ```make``` command to compile the interpreter into the executable ```./main``` in the current directory.
4141

42+
For submission purposes, ```make``` also runs ```/test/tester.lsp```, which tests every implemented feature in the language
43+
and outputs the checking to the console
44+
4245
Alternatively, you can compile an executable ```./main``` in the current directory.
4346
```
4447
$ go build cmd/main.go
@@ -55,3 +58,5 @@ $ ./main file.lsp
5558
```
5659
to run ```file.lsp```
5760

61+
# About the project
62+
This project was my second ever project in Go after writing my Lox interpreter. I have to say I enjoyed the language just as much as I did the first go around, and I was again glad I had chosen a language that was both so simple to pick up and so powerful. My largest problems that I ran into in this implementation mainly revolved around working through the underlying workings of the Lisp language that I had not considered before. Once I figured out that everything in the language was either a list or an atom/symbol, it became much easier to work through the implementation. I'll admit that I may not have done everything the most optimally (see my giant switch statements in interpreter/visitExpr.go) but I worked through most things multiple times in order to make it work as intended. An example would be the functions, which I initially attempted to detect at runtime, meaning I just parsed the definition and calls as lists, and tried to work those into definition or call statements at runtime. This nearly broke my brain and produced some code very reminiscent of spaghetti, but after trashing all of my changes and starting over, I managed to make definitions and calls into special cases in the parser that far simplified the process, as I could borrow a lot of the interpretation logic from the Lox interpreter. Other than functions, most of the project was fairly smooth sailing and I'm pretty proud of my ability to bang out a working interpreter without having to follow the guidance of a textbook.

pkg/interpreter/callable.go

+1-29
Original file line numberDiff line numberDiff line change
@@ -34,32 +34,4 @@ func (l LispFunction) Call(i *Interpreter, arguments []interface{}) (interface{}
3434
}
3535

3636
return i.evaluateFunction(l.Declaration.Body, env)
37-
}
38-
39-
// type clock struct{}
40-
41-
// func (c *clock) Arity() int {
42-
// return 0
43-
// }
44-
45-
// func (c *clock) Call(i *Interpreter, arguments []interface{}) (interface{}, error) {
46-
// return float64(time.Now().UnixMilli()) / 1000, nil
47-
// }
48-
49-
// func (c clock) String() string {
50-
// return "<native fn>"
51-
// }
52-
53-
// type toStr struct{}
54-
55-
// func (t *toStr) Arity() int {
56-
// return 1
57-
// }
58-
59-
// func (t *toStr) Call(i *Interpreter, arguments []interface{}) (interface{}, error) {
60-
// return fmt.Sprintf("%v", arguments[0]), nil
61-
// }
62-
63-
// func (t toStr) String() string {
64-
// return "<native fn>"
65-
// }
37+
}

pkg/interpreter/helpers.go

+1-18
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,4 @@ func checkNumberOperands(operator scanner.Token, left interface{}, right interfa
4141
return nil
4242
}
4343
return &RuntimeError{Token: operator, Message: "Operators must be numbers"}
44-
}
45-
46-
// func (i *Interpreter) cdr(k parser.Keyword) (interface{}, error) {
47-
// var elems []parser.Expression
48-
// for _, elem := range k.Args {
49-
// newExpr, err := i.evaluate(elem)
50-
// if err != nil {
51-
// return nil, err
52-
// }
53-
// if expr, ok := newExpr.(parser.Expression); ok {
54-
// elems = append(elems, expr)
55-
// } else {
56-
// return nil, &RuntimeError{Message: "type assertion failed, expected parser.Expression"}
57-
// }
58-
// }
59-
// fmt.Println(elems)
60-
// return parser.ListExpr{Head: elems[1], Tail: elems[2:]}, nil
61-
// }
44+
}

pkg/interpreter/visitExpr.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ func (i *Interpreter) VisitKeywordExpr(k parser.Keyword) (interface{}, error) {
134134
return nil, err
135135
}
136136
result := isTruthy(left) || isTruthy(right)
137-
if result == false {
137+
if !result {
138138
return nil, nil
139139
}
140140
return result, nil

pkg/parser/grammar.go

-6
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,10 @@ func (p *Parser) list() (Expression, error) {
2020
}
2121

2222
if funcName, ok := head.(Symbol); ok {
23-
// fmt.Println("function call", funcName.Name.Lexeme)
2423
return p.functionCall(funcName)
2524
}
2625

2726
if kw, ok := head.(Keyword); ok && kw.Keyword.Type == scanner.DEFINE {
28-
// fmt.Println("function definition", kw.Keyword.Lexeme)
2927
return p.functionDefinition()
3028
}
3129

@@ -130,7 +128,6 @@ func (p *Parser) paramList() ([]scanner.Token, error) {
130128
func (p *Parser) atom() (Expression, error) {
131129
if p.isKeyword() {
132130
k := Keyword{Keyword: p.previous()}
133-
// fmt.Println("adding keyword:", scanner.KeywordsReverse[k.Keyword.Type])
134131
return k, nil
135132
}
136133

@@ -144,10 +141,8 @@ func (p *Parser) atom() (Expression, error) {
144141
var err error
145142
switch prevValue.(type) {
146143
case string:
147-
// fmt.Println("String: " + prevValue.(string))
148144
return Atom{Value: prevValue, Type: scanner.STRING}, err
149145
case float64:
150-
// fmt.Println("Number: " + fmt.Sprintf("%f", prevValue.(float64)))
151146
return Atom{Value: prevValue, Type: scanner.NUMBER}, err
152147
default:
153148
// Handle other types or error
@@ -159,7 +154,6 @@ func (p *Parser) atom() (Expression, error) {
159154
}
160155

161156
if p.match(scanner.SYMBOL) {
162-
// fmt.Println("Symbol: " + p.previous().Lexeme)
163157
return Symbol{Name: p.previous()}, nil
164158
}
165159

pkg/parser/parser.go

-6
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,4 @@ func (p *Parser) Parse() ([]Expression, error) {
2828
}
2929

3030
return expressions, nil
31-
32-
// expr, err := p.expr()
33-
// if err != nil {
34-
// return Atom{Value: nil}, err
35-
// }
36-
// return expr, err
3731
}

pkg/parser/stmt.go

-36
This file was deleted.

pkg/parser/visitor.go

-10
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,9 @@ package parser
33
type ExprVisitor interface {
44
VisitListExpr(l ListExpr) (interface{}, error)
55
VisitKeywordExpr(k Keyword) (interface{}, error)
6-
// VisitBinaryExpr(b Binary) (interface{}, error)
76
VisitOperatorExpr(o Operator) (interface{}, error)
87
VisitAtomExpr(l Atom) (interface{}, error)
9-
// VisitCondExpr(c Cond) (interface{}, error)
10-
// VisitUnaryExpr(u Unary) (interface{}, error)
118
VisitSymbolExpr(s Symbol) (interface{}, error)
129
VisitFuncDefinitionExpr(f FuncDefinition) (interface{}, error)
13-
// VisitLogicalExpr(l Logical) (interface{}, error)
1410
VisitCallExpr(c Call) (interface{}, error)
15-
}
16-
17-
type StmtVisitor interface {
18-
VisitExprStmt(e ExprStmt) (interface{}, error)
19-
VisitSetStmt(v SetStmt) (interface{}, error)
20-
VisitFunctionStmt(f FunctionStmt) (interface{}, error)
2111
}

test/testoutput.txt

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
go build -o main cmd/main.go
2+
./main test/tester.lsp
3+
expect ok: ok
4+
expect fail: fail
5+
ok
6+
ok
7+
ok
8+
ok
9+
10+
test arithmetic operations
11+
ok
12+
ok
13+
ok
14+
ok
15+
16+
test comparison operations
17+
ok
18+
ok
19+
ok
20+
21+
test car and cdr on lists
22+
23+
assuming (list 1 2 3) creates a list [1, 2, 3]
24+
ok
25+
ok
26+
27+
test type checking functions
28+
ok
29+
ok
30+
ok
31+
ok
32+
33+
logical operations
34+
ok
35+
ok
36+
37+
function with multiple arguments
38+
ok
39+
40+
more complex recursive function - fibonacci
41+
ok
42+
43+
testing global variable assignment and usage
44+
ok

0 commit comments

Comments
 (0)