Skip to content

Commit 7c9ca73

Browse files
committed
chapter A self-hosting (wip)
1 parent aad3035 commit 7c9ca73

File tree

8 files changed

+100
-8
lines changed

8 files changed

+100
-8
lines changed

hello.lisp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
; run with: `rlwrap go run *.go hello.lisp` or `rlwrap go run *.go hello.lisp World`
2+
; — or load this in a REPL session started with `rlwrap go run *.go` by calling `(loadFile "hello.lisp")`
23

34
(def greet
45
(fn (name)
@@ -7,7 +8,7 @@
78
(if (= "" name)
89
(set repeat :false)
910
(println "Hello, " name "!"))
10-
(if repeat (greet :nil) :nil)))
11+
(if repeat (greet :nil))))
1112

1213
(if (isEmpty osArgs)
1314
(greet :nil)

main.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,10 @@ const srcMiniStdlibNonMacros = `
9191
()
9292
(cons (func (first list)) (map func (rest list))))))
9393
94-
94+
(def condBrokenUseCaseOf
95+
(macro (& xs)
96+
(if (> (count xs) 0)
97+
(list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw "odd number of forms to cond")) (cons 'cond (rest (rest xs)))))))
9598
`
9699

97100
const srcMiniStdlibMacros = `

self-hosted/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
All adapted from https://github.com/kanaka/mal/blob/master/impls/mal/

self-hosted/step0_repl.lisp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
;; read
2+
(def READ (fn [strng]
3+
strng))
4+
5+
;; eval
6+
(def EVAL (fn [ast]
7+
ast))
8+
9+
;; print
10+
(def PRINT (fn [exp] exp))
11+
12+
;; repl
13+
(def rep (fn [strng]
14+
(PRINT (EVAL (READ strng)))))
15+
16+
;; repl loop
17+
(def repl-loop (fn [line]
18+
(if line
19+
(do
20+
(if (not (= "" line))
21+
(println (rep line)))
22+
(repl-loop (readLine "mal-user> "))))))
23+
24+
;; main
25+
(repl-loop "")

self-hosted/step1_read_print.lisp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
;; read
2+
(def READ readExpr)
3+
4+
5+
;; eval
6+
(def EVAL (fn [ast]
7+
ast))
8+
9+
;; print
10+
(def PRINT str)
11+
12+
;; repl
13+
(def rep (fn [strng]
14+
(PRINT (EVAL (READ strng)))))
15+
16+
;; repl loop
17+
(def repl-loop (fn [line]
18+
(if line
19+
(do
20+
(if (not (= "" line))
21+
(try
22+
(println (rep line))
23+
(catch exc
24+
(println "Uncaught exception:" exc))))
25+
(repl-loop (readLine "mal-user> "))))))
26+
27+
;; main
28+
(repl-loop "")

special_forms.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ func init() { // in here, instead of above, to avoid "initialization cycle" erro
3030
}
3131
}
3232

33+
// like the funcs in `std.go`, the special-forms return an `Expr, error`. but:
34+
// in addition, they also return an `*Env`. if that is `nil`, the returned Expr
35+
// is a complete result, just like with the std funcs. but if not, the TCO loop
36+
// in `evalAndApply` goes through another iteration with the returned Expr.
37+
3338
func stdDef(env *Env, args []Expr) (*Env, Expr, error) {
3439
return defOrSet(true, env, args)
3540
}
@@ -123,15 +128,18 @@ func stdLet(env *Env, args []Expr) (*Env, Expr, error) {
123128
}
124129

125130
func stdIf(env *Env, args []Expr) (*Env, Expr, error) {
126-
if err := checkArgsCount(3, 3, args); err != nil {
131+
if err := checkArgsCount(2, 3, args); err != nil {
127132
return nil, nil, err
128133
}
134+
if len(args) < 3 {
135+
args = append(args, exprNil)
136+
}
129137
expr, err := evalAndApply(env, args[0])
130138
if err != nil {
131139
return nil, nil, err
132140
}
133141
idx := 1
134-
if isEq(expr, exprFalse) || isEq(expr, exprNil) {
142+
if isNilOrFalse(expr) {
135143
idx = 2
136144
}
137145
return env, args[idx], nil

std.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package main
22

33
import (
4-
"errors"
54
"fmt"
65
"io"
76
"os"
@@ -667,21 +666,27 @@ func stdReadLine(args []Expr) (Expr, error) {
667666
func stdQuit(args []Expr) (Expr, error) {
668667
var exit_code ExprNum
669668
if len(args) > 0 {
670-
exit_code, _ = args[0].(ExprNum)
669+
var is_num bool
670+
if exit_code, is_num = args[0].(ExprNum); (!is_num) || (exit_code > 255) {
671+
exit_code = 255
672+
}
671673
}
672674
os.Exit(int(exit_code))
673675
return exprNil, nil
674676
}
675677

676678
func stdTimeMs(args []Expr) (Expr, error) {
679+
if err := checkArgsCount(0, 0, args); err != nil {
680+
return nil, err
681+
}
677682
return ExprNum(time.Now().UnixMilli()), nil
678683
}
679684

680685
func stdBool(args []Expr) (Expr, error) {
681686
if err := checkArgsCount(1, 1, args); err != nil {
682687
return nil, err
683688
}
684-
return exprBool((!isEq(exprFalse, args[0])) && !isEq(exprNil, args[0])), nil
689+
return exprBool(!isNilOrFalse(args[0])), nil
685690
}
686691

687692
func stdSeq(args []Expr) (Expr, error) {
@@ -717,5 +722,22 @@ func stdSeq(args []Expr) (Expr, error) {
717722
}
718723

719724
func stdConj(args []Expr) (Expr, error) {
720-
return nil, errors.New("TODO")
725+
if err := checkArgsCount(2, -1, args); err != nil {
726+
return nil, err
727+
}
728+
_, is_vec := args[0].(ExprVec)
729+
seq, err := checkIsSeq(args[0])
730+
if err != nil {
731+
return nil, err
732+
}
733+
if is_vec {
734+
seq = append(seq, args[1:]...)
735+
return (ExprVec)(seq), nil
736+
} else {
737+
new_list := make(ExprList, 0, (len(args)-1)+len(seq))
738+
for i := len(args) - 1; i > 0; i-- {
739+
new_list = append(new_list, args[i])
740+
}
741+
return (ExprList)(append(new_list, seq...)), nil
742+
}
721743
}

util.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import (
44
"io"
55
)
66

7+
func isNilOrFalse(expr Expr) bool {
8+
return isEq(exprNil, expr) || isEq(exprFalse, expr)
9+
}
10+
711
func readUntil(r io.Reader, until byte, initialBufCapacity int) (string, error) {
812
buf := make([]byte, 0, initialBufCapacity)
913
var b [1]byte

0 commit comments

Comments
 (0)