mirror of
https://github.com/peklaiho/madlisp.git
synced 2024-12-28 17:08:55 +00:00
60 lines
1.9 KiB
Plaintext
60 lines
1.9 KiB
Plaintext
|
|
;;
|
|
;; Simple command line calculator which demonstrates the following concepts:
|
|
;; - command parser with arguments
|
|
;; - readline support with history
|
|
;; - main loop
|
|
;;
|
|
;; This is a barebones example for creating interactive command line scripts.
|
|
;; This script should be executed directly, not inside the repl.
|
|
;;
|
|
|
|
;; Load some utility functions we use
|
|
(load (str __DIR__ "util.mad"))
|
|
|
|
;; Define commands
|
|
(defn cmdAdd (args) (apply + args))
|
|
(defn cmdDiv (args) (apply / args))
|
|
(defn cmdMod (args) (apply % args))
|
|
(defn cmdMul (args) (apply * args))
|
|
(defn cmdSub (args) (apply - args))
|
|
(defn cmdHelp () (str "Available commands: " (apply join ", " (keys cmdMap))))
|
|
(defn cmdQuit () (exit))
|
|
|
|
;; And we define a hash-map for command lookups with minimum number of arguments
|
|
(def cmdMap {
|
|
"add": [cmdAdd 2]
|
|
"div": [cmdDiv 2]
|
|
"mod": [cmdMod 2]
|
|
"mul": [cmdMul 2]
|
|
"sub": [cmdSub 2]
|
|
"help": [cmdHelp 0]
|
|
"quit": [cmdQuit 0]
|
|
})
|
|
|
|
;; Find the first command which starts with the given name, or null
|
|
(defn findCmd (name)
|
|
(if (null? name) null
|
|
(let (matches (filterh (fn (v k) (prefix? k name)) cmdMap))
|
|
(if (empty? matches) null
|
|
(get matches (first (keys matches)))))))
|
|
|
|
;; Split input by spaces, find command that matches the first word
|
|
;; and call it, giving the rest of the words as arguments.
|
|
(defn parseInput (inp)
|
|
(let (words (str-first-rest inp) cname (first words) args (second words) cmd (findCmd cname))
|
|
(if (null? cmd) "Unknown command, try 'help'."
|
|
(if (< (len args) (second cmd)) (str "Give at least 2 arguments to " cname ".")
|
|
((first cmd) args)))))
|
|
|
|
;; Define a file for readline and load it
|
|
(def readlineFile (str HOME "calc_history"))
|
|
(readline-load readlineFile)
|
|
|
|
;; Main loop: Read input from user, add it to readline, and parse it
|
|
(while true
|
|
(let (inp (readline "[calc] "))
|
|
(readline-add inp)
|
|
(readline-save readlineFile)
|
|
(print "⇒ " (parseInput inp) EOL)))
|