application/octet-stream
•
5.18 KB
•
153 lines
;;; Nujel - Copyright (C) 2020-2021 - Benjamin Vincent Schulenburg
;;; This project uses the MIT license, a copy should be included under /LICENSE
;;;
;;; The REPL implementation, also parses command line arguments and determines
;;; which files to load and whether to start a interactive session.
[def *1 #nil]
[def *2 #nil]
[def *3 #nil]
[def repl/executable-name "nujel"]
[def repl/args #nil]
[def repl/parse-args/eval-next-module #f]
[def repl/parse-args/eval-next #f]
[def repl/parse-args/run-repl #t]
[def repl/options @[]]
[def repl/option-map @[]]
[def repl/line-history #nil]
[defn repl/exception-handler [error]
[print/error error]]
[defn repl/welcome []
[require :ansi]
[println [cat [ansi/rainbow "Nujel"] " is ready for business!"]]]
[defn repl/prompt []
"> "]
[defn repl/wasm [line]
"Evaluate LINE in the wasm context"
[string/write [try repl/exception-handler
[eval-in root-closure [cons do [read line]]]]]]
[defn repl/cmd/raw [ctx line]
[try [fn [err]
[if [= [car err] :unmatched-opening-bracket]
[repl/cmd/raw ctx [cat line [readline "... "]]]
[throw err]]]
[def expr [read line]]
[when [equal? '[] expr]
[print "\r"]
[return]]
[try repl/exception-handler
[def result [eval-in ctx [cons do expr]]]
[repl/push-result result]
[println [if [nil? result] "" [string/display result]]]]]]
[defn repl/push-result [result]
[set! *3 *2]
[set! *2 *1]
[set! *1 result]
[return result]]
[defn repl/cmd [ctx]
[def buf ""]
[def line ""]
[while [not= [trim line] "[/cmd]"]
[set! buf [cat buf line]]
[set! line [readline]]]
[def expr [cons do [read buf]]]
[def result [eval-in ctx expr]]
[repl/push-result result]
[println [if [nil? result] "" [string/display result]]]]
[defn repl/readline [ctx]
[def line [readline [repl/prompt]]]
[set! repl/line-history [cons line repl/line-history]]
[when [nil? line]
[println "Adios, cowboy..."]
[exit 0]]
[if [= [trim line] "[cmd]"]
[repl/cmd ctx]
[repl/cmd/raw ctx line]]]
[defn repl []
[repl/welcome]
[while #t
[try repl/exception-handler
[repl/readline root-closure]]]]
[tree/set! repl/option-map 'm
[fn [option]
[set! repl/parse-args/eval-next-module #t]]]
[tree/set! repl/option-map 'h
[fn [option]
[import [main] :help]
[main #nil]
[exit 0]]]
[tree/set! repl/option-map 'no-color
[fn [option]
[require :ansi]
[set! ansi/disable! #t]]]
[tree/set! repl/option-map 'color
[fn [option]
[require :ansi]
[set! ansi/disable! #f]]]
[tree/set! repl/option-map 'x
[fn [option]
[set! repl/parse-args/eval-next #t]
[set! repl/parse-args/run-repl #f]]]
[tree/set! repl/option-map :default
[fn [option]
[tree/set! repl/options option #t]]]
[defn repl/parse-option [option]
[[or [ref repl/option-map option]
[ref repl/option-map :default]] option]]
[defn repl/parse-options [options]
[if [= [buffer/ref options 0] #\-]
[repl/parse-option [string->keyword [cut options 1]]]
[for-each [map [split options ""] string->symbol] repl/parse-option]]]
[defn repl/parse-arg [arg args]
[cond [repl/parse-args/eval-next [try print/error
[eval-in root-closure [cons do [read arg]]]
[set! repl/parse-args/eval-next #f]]]
[repl/parse-args/eval-next-module [try [fn [e]
[print/error e]
[exit 1]]
[when [= [buffer/ref arg 0] #\:]
[set! arg [string/cut 1]]]
[import [main] [string->keyword arg]]
[main [cdr args]]
[exit 0]]]
[[= [buffer/ref arg 0] #\-] [repl/parse-options [string/cut arg 1]]]
[#t [try [fn [e]
[print/error e]
[exit 1]]
[file/eval-module arg [cdr args]]
[exit 0]]
[set! repl/parse-args/run-repl #f]]]]
[defn repl/parse-args [args]
[if args
[do [repl/parse-arg [car args] args]
[repl/parse-args [cdr args]]]
repl/parse-args/run-repl]]
[defn repl/init/wasm [args]
[repl/welcome]]
[defn repl/init/bin [args]
[try repl/exception-handler
[set! repl/executable-name [car args]]
[when [repl/parse-args [cdr args]] [repl]]]]
[defn repl/init args
[set! repl/args args]
[if [= System/Architecture 'wasm]
[repl/init/wasm args]
[repl/init/bin args]]]