From 012d3273212df75e00491a226e28a6a460ade994 Mon Sep 17 00:00:00 2001 From: Chris Foster Date: Mon, 10 Jun 2019 13:41:50 +1000 Subject: [PATCH] Implement include_lisp to eval multiple top level exprs from file. --- src/LispSyntax.jl | 25 ++++++++++++++++++++++++- src/parser.jl | 2 ++ test/lisp.clj | 9 +++++++++ test/runtests.jl | 11 +++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 test/lisp.clj diff --git a/src/LispSyntax.jl b/src/LispSyntax.jl index 4aa8a1b..39f3340 100644 --- a/src/LispSyntax.jl +++ b/src/LispSyntax.jl @@ -1,7 +1,7 @@ module LispSyntax include("parser.jl") -export sx, desx, codegen, @lisp, @lisp_str, assign_reader_dispatch +export sx, desx, codegen, @lisp, @lisp_str, assign_reader_dispatch, include_lisp # Internal types mutable struct s_expr @@ -154,4 +154,27 @@ macro lisp_str(str) return esc(lisp_eval_helper(str)) end + +""" + include_lisp(mod, source) + +Parse expressions from `source` (which may be an `IO` or file name) and +evaluate them sequentially as top level code in module `mod`. +""" +function include_lisp(mod::Module, filename::AbstractString) + open(filename) do io + include_lisp(mod, io) + end +end + +function include_lisp(mod::Module, io::IO) + content = Base.read(io, String) + res = nothing + for sxpr in parse_one(content, top_level) + ex = codegen(desx(sxpr)) + res = Base.eval(mod, ex) + end + res +end + end # module diff --git a/src/parser.jl b/src/parser.jl index ac1a8b4..3505b11 100644 --- a/src/parser.jl +++ b/src/parser.jl @@ -37,6 +37,8 @@ expr.matcher = doubley | floaty | inty | uchary | achary | chary | stringy | boo macrosymy | dispatchy | sexpr | hashy | curly | bracket | quot | quasi | tildeseq | tilde +top_level = Repeat(~opt_ws + expr) + ~opt_ws + Eos() + function read(str) x = parse_one(str, expr) x[1] diff --git a/test/lisp.clj b/test/lisp.clj new file mode 100644 index 0000000..74eeed9 --- /dev/null +++ b/test/lisp.clj @@ -0,0 +1,9 @@ +; File containing top level Clojure-syntax code + +(defn func_in_clj_file [x y] (string "x = " x "; y = " y)) + +(def some_global 1.23f) + +; Following should be the return value of include_lisp +(let [not_a_global 10] + (* not_a_global not_a_global)) diff --git a/test/runtests.jl b/test/runtests.jl index 3fc2972..2ad1304 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -255,6 +255,17 @@ lisp"(do (@incr_global r) (@incr_global number))" lisp"(import ParserCombinator)" @test lisp"(@E_str \"S\")" == E"S" +#------------------------------------------------------------------------------- +@testset "Include from file" begin + # Return value is value of last expression + @test include_lisp(@__MODULE__, "lisp.clj") == 100 + # Test objects defined in lisp.clj + @test func_in_clj_file(1, 2) == "x = 1; y = 2" + @test func_in_clj_file(10, 20) == "x = 10; y = 20" + @test some_global === 1.23f0 + @test !isdefined(@__MODULE__, :not_a_global) +end + # ---------------------------------------------------------------------------------------------------------------------- # Bug reports # ----------------------------------------------------------------------------------------------------------------------