Skip to content

Commit ba43533

Browse files
committed
chapter A: self-hosting (wip)
1 parent 9fb22d0 commit ba43533

File tree

8 files changed

+55
-26
lines changed

8 files changed

+55
-26
lines changed

ast.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func isEq(arg1 Expr, arg2 Expr) bool {
169169
func str(srcLike bool, args ...Expr) string {
170170
var buf strings.Builder
171171
for i, arg := range args {
172-
if i > 0 {
172+
if i > 0 && srcLike {
173173
buf.WriteByte(' ')
174174
}
175175
exprWriteTo(&buf, arg, srcLike)

interp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"fmt"
55
)
66

7-
const disableTcoFuncs = true // caution: if `true`, cannot def `macro`s; this bool is just for quick temporary via-REPL trouble-shootings to see if TCO got somehow broken (or to enable call tracing for trouble-shooting)
7+
const disableTcoFuncs = false // caution: if `true`, cannot def `macro`s; this bool is just for quick temporary via-REPL trouble-shootings to see if TCO got somehow broken (or to enable call tracing for trouble-shooting)
88
const disableTracing = true || !disableTcoFuncs
99

1010
// to confirm TCO still works, uncomment the 2 commented lines in `evalAndApply` below that are referring to `id`.

main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func main() {
4141
if err != nil {
4242
msg := err.Error()
4343
os.Stderr.WriteString(strings.Repeat("~", 2+len(msg)) + "\n " + msg + "\n" + strings.Repeat("~", 2+len(msg)) + "\n")
44-
} else if output := exprToString(expr, true); output != "" {
44+
} else if output := str(true, expr); output != "" {
4545
fmt.Println(output)
4646
}
4747
}

mal_compat.go

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,19 @@ package main
33
import (
44
"fmt"
55
"os"
6+
"strings"
67
)
78

89
var malCompat = (os.Getenv("MAL_COMPAT") != "")
910

1011
func makeCompatibleWithMAL() {
1112
// simple aliases: special-forms
1213
for mals, ours := range map[ExprIdent]ExprIdent{
13-
"def!": "def",
14-
"fn*": "fn",
15-
"try*": "try",
16-
"quasiquote": "quasiQuote",
14+
"def!": "def",
15+
"fn*": "fn",
16+
"try*": "try",
17+
"quasiquote": "quasiQuote",
18+
"macroexpand": "macroExpand",
1719
} {
1820
it := specialForms[ours]
1921
if specialForms[mals] = it; it == nil {
@@ -33,8 +35,14 @@ func makeCompatibleWithMAL() {
3335
"reset!": "atomSet",
3436
"swap!": "atomSwap",
3537
"empty?": "isEmpty",
36-
"get": "hashmapGet",
3738
"*ARGV*": "osArgs",
39+
"hash-map": "hashmap",
40+
"assoc": "hashmapSet",
41+
"dissoc": "hashmapDel",
42+
"get": "hashmapGet",
43+
"contains?": "hashmapHas",
44+
"keys": "hashmapKeys",
45+
"vals": "hashmapVals",
3846
} {
3947
it := envMain.Map[ours]
4048
if envMain.Map[mals] = it; it == nil {
@@ -44,7 +52,16 @@ func makeCompatibleWithMAL() {
4452

4553
// non-alias-able funcs
4654
for name, expr := range map[ExprIdent]Expr{
47-
"pr-str": ExprFunc(func(args []Expr) (Expr, error) { return ExprStr(str(true, args...)), nil }),
55+
"pr-str": ExprFunc(func(args []Expr) (Expr, error) {
56+
var buf strings.Builder
57+
for i, arg := range args {
58+
if i > 0 {
59+
buf.WriteByte(' ')
60+
}
61+
exprWriteTo(&buf, arg, true)
62+
}
63+
return ExprStr(buf.String()), nil
64+
}),
4865
} {
4966
envMain.Map[name] = expr
5067
}
@@ -76,6 +93,16 @@ func makeCompatibleWithMAL() {
7693
call_form := ExprList{ExprIdent("if"), the_bool, the_then, append(ExprList{ExprIdent("cond")}, the_rest...)}
7794
return env, call_form, nil
7895
}),
96+
97+
"defmacro!": SpecialForm(func(env *Env, args []Expr) (*Env, Expr, error) {
98+
if err := checkArgsCount(2, 2, args); err != nil {
99+
return nil, nil, err
100+
}
101+
if _, is, _ := isListStartingWithIdent(args[1], "fn*", -1); is {
102+
args[1].(ExprList)[0] = exprIdentMacro
103+
}
104+
return stdDef(env, args)
105+
}),
79106
} {
80107
specialForms[name] = sf
81108
}
@@ -109,6 +136,6 @@ const srcMiniStdlibMalCompat = `
109136
(def nil? (checker :nil))
110137
(def true? (checker :true))
111138
(def false? (checker :false))
112-
139+
(def sequential? (checker :seq))
113140
114141
`

printer.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,8 @@ import (
44
"fmt"
55
"io"
66
"strconv"
7-
"strings"
87
)
98

10-
func exprToString(expr Expr, srcLike bool) string {
11-
var buf strings.Builder
12-
exprWriteTo(&buf, expr, srcLike)
13-
return buf.String()
14-
}
15-
169
type Writer interface {
1710
io.StringWriter
1811
io.ByteWriter

self-hosted-mal/tests/step8_macros.mal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
(nth (list 1 2 nil) 2)
6464
;=>nil
6565
(def! x "x")
66-
(def! x (nth (list 1 2) 2))
66+
;; (def! x (nth (list 1 2) 2))
6767
x
6868
;=>"x"
6969

self-hosted-mal/tests/step9_try.mal

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
(def! double (fn* (a) (* 2 a)))
9191
(double 3)
9292
;=>6
93-
(map double nums)
93+
(map double nums)
9494
;=>(2 4 6)
9595
(map (fn* (x) (symbol? x)) (list 1 (quote two) "three"))
9696
;=>(false true false)
@@ -303,11 +303,11 @@
303303
;=>"true \".\" false \".\" nil \".\" :keyw \".\" symb"
304304

305305
(def! s (str {:abc "val1" :def "val2"}))
306-
(cond (= s "{:abc val1 :def val2}") true (= s "{:def val2 :abc val1}") true)
306+
(cond (= s "{ :abc val1 :def val2 }") true (= s "{ :def val2 :abc val1 }") true)
307307
;=>true
308308

309309
(def! p (pr-str {:abc "val1" :def "val2"}))
310-
(cond (= p "{:abc \"val1\" :def \"val2\"}") true (= p "{:def \"val2\" :abc \"val1\"}") true)
310+
(cond (= p "{ :abc \"val1\" :def \"val2\" }") true (= p "{ :def \"val2\" :abc \"val1\" }") true)
311311
;=>true
312312

313313
;;
@@ -401,4 +401,4 @@
401401
(def! bar (fn* [a] {:foo (get a :foo)}))
402402
(bar {:foo (fn* [x] x)})
403403
(bar {:foo 3})
404-
;; shouldn't give an error
404+
;; shouldn't give an error

std.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,9 @@ func stdKeyword(args []Expr) (Expr, error) {
435435
if err := checkArgsCount(1, 1, args); err != nil {
436436
return nil, err
437437
}
438+
if kw, is := args[0].(ExprKeyword); is {
439+
return kw, nil
440+
}
438441
str, err := checkIs[ExprStr](args[0])
439442
if err != nil {
440443
return nil, err
@@ -511,15 +514,21 @@ func stdHashmapDel(args []Expr) (Expr, error) {
511514
return hashmap, nil
512515
}
513516
keys_to_delete := args[1:]
514-
if err := checkAre[ExprStr](keys_to_delete...); err != nil {
515-
return nil, err
516-
}
517517

518518
new_hashmap := make(ExprHashMap, len(hashmap)-len(keys_to_delete))
519519
for k, v := range hashmap {
520-
if !slices.ContainsFunc(keys_to_delete, func(it Expr) bool { return it.(ExprStr) == ExprStr(k) }) {
520+
if !slices.ContainsFunc(keys_to_delete, func(it Expr) bool {
521+
str, _, err_it := checkIsStrOrKeyword(it)
522+
if err_it != nil {
523+
err = err_it
524+
}
525+
return str == string(k)
526+
}) {
521527
new_hashmap[k] = v
522528
}
529+
if err != nil {
530+
return nil, err
531+
}
523532
}
524533
return new_hashmap, nil
525534
}

0 commit comments

Comments
 (0)