mirror of
https://github.com/janet-lang/janet
synced 2025-10-18 01:07:40 +00:00
Add macros in compiler.
This commit is contained in:
@@ -1,67 +0,0 @@
|
||||
|
||||
# This file is executed without any macro expansion (macros are not
|
||||
# yet defined). Cannot use macros or anything outside the stl.
|
||||
|
||||
(var macros @{})
|
||||
|
||||
# Helper for macro expansion
|
||||
(def macroexpand (fn recur [x]
|
||||
(def x (ast-unwrap x))
|
||||
(if (= (type x) :tuple)
|
||||
(if (> (length x) 0)
|
||||
(do
|
||||
(def first (get x 0))
|
||||
(def rest (array-slice x 1))
|
||||
(def macro (get macros first))
|
||||
(if macro (recur (apply macro rest)) x))
|
||||
x)
|
||||
x)))
|
||||
|
||||
# Function to create macros
|
||||
(def _defmacro (fn [name f]
|
||||
(set macros name f)
|
||||
f))
|
||||
|
||||
# Make defn
|
||||
(_defmacro "defn" (fn [name &]
|
||||
(tuple 'def name (apply tuple 'fn &))))
|
||||
|
||||
# Make defmacro
|
||||
(_defmacro "defmacro" (fn [name &]
|
||||
(tuple global-macro (string name) (apply tuple 'fn &))))
|
||||
|
||||
# Comment returns nil
|
||||
(_defmacro "comment" (fn [] nil))
|
||||
|
||||
# The source file to read from
|
||||
(var *sourcefile* stdin)
|
||||
|
||||
# The *read* macro gets the next form from the source file, and
|
||||
# returns it. It is a var and therefor can be overwritten.
|
||||
(var *read* (fn []
|
||||
(def b (buffer))
|
||||
(def p (parser))
|
||||
(while (not (parse-hasvalue p))
|
||||
(read *sourcefile* 1 b)
|
||||
(if (= (length b) 0)
|
||||
(error "parse error: unexpected end of source"))
|
||||
(parse-charseq p b)
|
||||
(if (= (parse-status p) :error)
|
||||
(error (string "parse error: " (parse-consume p))))
|
||||
(clear b))
|
||||
(parse-consume p)))
|
||||
|
||||
# Evaluates a form by macro-expanding it, compiling it, and
|
||||
# then executing it.
|
||||
(def eval (fn [x]
|
||||
(def func (compile (macroexpand x)))
|
||||
(if (= :function (type func))
|
||||
(func)
|
||||
(error (string "compiler error: " func)))))
|
||||
|
||||
# A simple repl for testing.
|
||||
(while true
|
||||
(def t (thread (fn []
|
||||
(while true
|
||||
(print (eval (*read*)))))))
|
||||
(print (tran t)))
|
14
test/repl.dst
Normal file
14
test/repl.dst
Normal file
@@ -0,0 +1,14 @@
|
||||
# Bootstrap the language
|
||||
|
||||
# Helper for macro expansion
|
||||
(def macroexpand (fn recur [x]
|
||||
(def y (ast-unwrap x))
|
||||
(if (= (type y) :tuple)
|
||||
(if (> (length y) 0)
|
||||
(do
|
||||
(def first (get y 0))
|
||||
(def rest (array-slice y 1))
|
||||
(def macro (get _env first))
|
||||
(if macro (recur (apply macro rest)) x))
|
||||
x)
|
||||
x)))
|
@@ -1,18 +1,34 @@
|
||||
(def fib (asm '{
|
||||
bytecode [
|
||||
(load-integer 2 2)
|
||||
(less-than 2 0 2)
|
||||
(jump-if-not 2 2)
|
||||
(return 0)
|
||||
(load-self 1)
|
||||
(add-immediate 0 0 -1)
|
||||
(push 0)
|
||||
(call 2 1)
|
||||
(add-immediate 0 0 -1)
|
||||
(push 0)
|
||||
(call 3 1)
|
||||
(add-integer 0 2 3)
|
||||
(return 0)
|
||||
]
|
||||
arity 1
|
||||
}))
|
||||
(def mapnil
|
||||
" (mapnil f a)
|
||||
Map a function over a tuple or array and return nil."
|
||||
(fn [f t]
|
||||
(var i 0)
|
||||
(def len (length t))
|
||||
(while (< i len)
|
||||
(f (get t i))
|
||||
(varset! i (+ i 1)))))
|
||||
|
||||
(def mapt
|
||||
" (mapt f t)
|
||||
Map a function over a tuple or array and produce a new tuple."
|
||||
(fn [f t]
|
||||
(var i 0)
|
||||
(def len (length t))
|
||||
(def accum [])
|
||||
(while (< i len)
|
||||
(array-push accum (f (get t i)))
|
||||
(varset! i (+ i 1)))
|
||||
(apply tuple accum)))
|
||||
|
||||
(def mapa
|
||||
" (mapa f a)
|
||||
Map a function over a tuple or array and produce a new array."
|
||||
(fn [f t]
|
||||
(var i 0)
|
||||
(def len (length t))
|
||||
(def accum [])
|
||||
(while (< i len)
|
||||
(array-push accum (f (get t i)))
|
||||
(varset! i (+ i 1)))
|
||||
accum))
|
||||
|
||||
|
@@ -59,6 +59,7 @@
|
||||
(fn [x] (+ x x))
|
||||
+) "type ordering")
|
||||
|
||||
(assert (= (string (buffer "123" "456")) (string @"123456")) "buffer literal")
|
||||
(assert (= (get {} 1) nil) "get nil from empty struct")
|
||||
(assert (= (get @{} 1) nil) "get nil from empty table")
|
||||
(assert (= (get {:boop :bap} :boop) :bap) "get non nil from struct")
|
||||
@@ -259,6 +260,35 @@
|
||||
(varset! count (+ 1 count)))
|
||||
(assert (= (length syms) 128) "many symbols")))
|
||||
|
||||
# Macros
|
||||
|
||||
(def defmacro macro (fn [name & more]
|
||||
(tuple 'def name 'macro (tuple-prepend (tuple-prepend more name) 'fn))))
|
||||
(defmacro defn
|
||||
[name & more]
|
||||
(tuple
|
||||
'def
|
||||
name
|
||||
(tuple-prepend (tuple-prepend more name) 'fn)))
|
||||
|
||||
(defmacro when [cond & body] (tuple 'if cond (tuple-prepend body 'do)))
|
||||
|
||||
(defn dub [x] (+ x x))
|
||||
(assert (= 2 (dub 1)) "defn macro")
|
||||
(do
|
||||
(defn trip [x] (+ x x x))
|
||||
(assert (= 3 (trip 1)) "defn macro triple"))
|
||||
(do
|
||||
(var i 0)
|
||||
(when true
|
||||
(varset! i (+ i 1))
|
||||
(varset! i (+ i 1))
|
||||
(varset! i (+ i 1))
|
||||
(varset! i (+ i 1))
|
||||
(varset! i (+ i 1))
|
||||
(varset! i (+ i 1)))
|
||||
(assert (= i 6) "when macro"))
|
||||
|
||||
# report
|
||||
|
||||
(print "\n" num-tests-passed " of " num-tests-run " tests passed\n")
|
||||
|
Reference in New Issue
Block a user