(define (parse-duckyscript input) (define blank '(+ ("\t\v "))) (define number '(+ numeric)) (define string '(+ nonl)) (define mod '(or "WINDOWS" "GUI" "SHIFT" "ALT" "CONTROL" "CTRL" "COMMAND" "OPTION")) (define key '(+ (or upper numeric #\_))) (define char '(~ #\space)) (define comment-cmd `(: bol (or "REM" "//"))) (define default-delay-cmd `(: bol "DEFAULT" (? "_") "DELAY" ,blank)) (define delay-cmd `(: bol "DELAY" ,blank)) (define string-cmd `(: bol "STRING" ,blank)) (define string-delay-cmd `(: bol "STRING_DELAY" ,blank)) (define repeat-cmd `(: bol "REPEAT" ,blank)) (define shortcut-cmd `(: ($ (* (: ,mod (? ,blank)))) ($ (or ,key ,char)))) (define optional-string-arg `(: (? ,blank) ($ (? ,string)))) (define number-arg `($ ,number)) (define string-arg `($ ,string)) (define number-string-arg `(: ($ ,number) ,blank ($ ,string))) (define dashed-modifier `(: bol ,mod "-" ,key (* (: "-" ,key)))) (define (preprocess line) (if (irregex-search dashed-modifier line) (string-translate line "-" " ") line)) (define (command-match line type-rx args-rx) (and-let* (((irregex-search type-rx line)) (rest (irregex-replace type-rx line ""))) (or (irregex-match args-rx rest) (error "Invalid arguments" line)))) (define (parse line) (define $ irregex-match-substring) (define ->int string->number) (let ((line (preprocess line))) (cond ((command-match line comment-cmd optional-string-arg) => (lambda (m) `(comment ,($ m 1)))) ((command-match line default-delay-cmd number-arg) => (lambda (m) `(default-delay ,(->int ($ m 1))))) ((command-match line delay-cmd number-arg) => (lambda (m) `(delay ,(->int ($ m 1))))) ((command-match line string-cmd string-arg) => (lambda (m) `(string ,($ m 1)))) ((command-match line string-delay-cmd number-string-arg) => (lambda (m) `(string-delay ,(->int ($ m 1)) ,($ m 2)))) ((command-match line repeat-cmd number-arg) => (lambda (m) `(repeat ,(->int ($ m 1))))) ((irregex-match shortcut-cmd line) => (lambda (m) `(shortcut ,(irregex-split blank ($ m 1)) ,($ m 2)))) (else (error "Unrecognized line" line))))) (map parse (irregex-split "\r\n|\n" input)))