Skip to content

Commit

Permalink
common-lisp/matching-brackets: 1st iteration - passing
Browse files Browse the repository at this point in the history
  • Loading branch information
vpayno committed Jun 25, 2023
1 parent 8499a9b commit 55cef11
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 99 deletions.
44 changes: 22 additions & 22 deletions common-lisp/matching-brackets/matching-brackets-test.lisp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
;; Ensures that matching-brackets.lisp and the testing library are always loaded
(eval-when (:compile-toplevel :load-toplevel :execute)
(load "matching-brackets")
(quicklisp-client:quickload :fiveam))
(load "matching-brackets")
(quicklisp-client:quickload :fiveam))

;; Defines the testing package with symbols from matching-brackets and FiveAM in scope
;; The `run-tests` function is exported for use by both the user and test-runner
Expand All @@ -17,83 +17,83 @@

(test paired-square-brackets
(let ((value "[]"))
(is-true (matching-brackets:pairedp value))))
(is-true (matching-brackets:pairedp value))))

(test empty-string
(let ((value ""))
(is-true (matching-brackets:pairedp value))))
(is-true (matching-brackets:pairedp value))))

(test unpaired-brackets
(let ((value "[["))
(is-false (matching-brackets:pairedp value))))
(is-false (matching-brackets:pairedp value))))

(test wrong-ordered-brackets
(let ((value "}{"))
(is-false (matching-brackets:pairedp value))))
(is-false (matching-brackets:pairedp value))))

(test wrong-closing-bracket
(let ((value "{]"))
(is-false (matching-brackets:pairedp value))))
(is-false (matching-brackets:pairedp value))))

(test paired-with-whitespace
(let ((value "{ }"))
(is-true (matching-brackets:pairedp value))))
(is-true (matching-brackets:pairedp value))))

(test partially-paired-brackets
(let ((value "{[])"))
(is-false (matching-brackets:pairedp value))))
(is-false (matching-brackets:pairedp value))))

(test simple-nested-brackets
(let ((value "{[]}"))
(is-true (matching-brackets:pairedp value))))
(is-true (matching-brackets:pairedp value))))

(test several-paired-brackets
(let ((value "{}[]"))
(is-true (matching-brackets:pairedp value))))
(is-true (matching-brackets:pairedp value))))

(test paired-and-nested-brackets
(let ((value "([{}({}[])])"))
(is-true (matching-brackets:pairedp value))))
(is-true (matching-brackets:pairedp value))))

(test paired-and-wrong-nested-brackets-but-innermost-are-correct
(let ((value "[({}])"))
(is-false (matching-brackets:pairedp value))))
(is-false (matching-brackets:pairedp value))))

(test unopened-closing-brackets
(let ((value "{[)][]}"))
(is-false (matching-brackets:pairedp value))))
(is-false (matching-brackets:pairedp value))))

(test unpaired-and-nested-brackets
(let ((value "([{])"))
(is-false (matching-brackets:pairedp value))))
(is-false (matching-brackets:pairedp value))))

(test paired-and-wrong-nested-brackets
(let ((value "[({]})"))
(is-false (matching-brackets:pairedp value))))
(is-false (matching-brackets:pairedp value))))

(test paired-and-incomplete-brackets
(let ((value "{}["))
(is-false (matching-brackets:pairedp value))))
(is-false (matching-brackets:pairedp value))))

(test too-many-closing-brackets
(let ((value "[]]"))
(is-false (matching-brackets:pairedp value))))
(is-false (matching-brackets:pairedp value))))

(test early-unexpected-brackets
(let ((value ")()"))
(is-false (matching-brackets:pairedp value))))
(is-false (matching-brackets:pairedp value))))

(test early-mismatched-brackets
(let ((value "{)()"))
(is-false (matching-brackets:pairedp value))))
(is-false (matching-brackets:pairedp value))))

(test math-expression
(let ((value "(((185 + 223.85) * 15) - 543)/2"))
(is-true (matching-brackets:pairedp value))))
(is-true (matching-brackets:pairedp value))))

(test complex-latex-expression
(let ((value "\left(\begin{array}{cc} \frac{1}{3} & x\\ \mathrm{e}^{x} &... x^2 \end{array}\right)"))
(is-true (matching-brackets:pairedp value))))
(is-true (matching-brackets:pairedp value))))

(defun run-tests (&optional (test-or-suite 'matching-brackets-suite))
"Provides human readable results of test run. Default to entire suite."
Expand Down
76 changes: 58 additions & 18 deletions common-lisp/matching-brackets/matching-brackets.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@
;;;; push open brackets into list
;;;; when closing bracket found, see if it matches last open bracket

;;; set to t to enable debugging; to nil to disable debugging
(defparameter debug-mode nil)

;;; test to see if closing bracket matches open bracket
(defun bracket-match (open-bracket close-bracket)
(cond
((and (char= #\[ open-bracket) (char= #\] close-bracket)) t)
((and (char= #\( open-bracket) (char= #\) close-bracket)) t)
((and (char= #\{ open-bracket) (char= #\} close-bracket)) t)
(t nil)
)
((and (char= #\[ open-bracket) (char= #\] close-bracket)) t)
((and (char= #\( open-bracket) (char= #\) close-bracket)) t)
((and (char= #\{ open-bracket) (char= #\} close-bracket)) t)
(t nil)
)
) ; => t or nil

;;; test to see if character is an opening bracket
Expand Down Expand Up @@ -45,37 +48,74 @@

;;; pops the last value on the open bracket stack and also return the new stack
(defun pop-last (a)
(let ((result nil))
(values (setq result (last a)) (setq a (butlast a)))
(let ((popped nil))
(values (setq popped (last a)) (setq a (butlast a)))
)
) ; => (G) ; (A B C D E F)

;;; remove the last value on the open bracket stack and also return the new stack
(defun remove-last (a)
(setq a (butlast a))
) ; => (A B C D E F)

;;; let's you peek at the tail of the open bracket stack to see if it's a match
;;; for the closing bracket you just found
(defun peek (a)
(first (last a))
) ; => G or nil

;;; only print debug messages when degugging
(defun debug-format (message)
(if debug-mode
(format t message)
)
) ; nil

;;; look for matching bracket pairs
(defun pairedp (value)
;; fast return on corner cases
(when (= 0 (length value))
(return-from pairedp t)
)

;; using a list as a stack
(let ((bracket-stack ()))
(let ((bracket-stack ()) (result t))
(loop for c across value do
(when (bracket-either c)
(debug-format (format nil "~A" c))
(if (bracket-open c)
(setq bracket-stack (push-last c bracket-stack))
(setq bracket-stack (push-last c bracket-stack))
(if (and (bracket-close c) (= 0 (length bracket-stack)))
(return nil)
(if (bracket-match (peek bracket-stack) c)
(multiple-value-bind
(last-open bracket-stack)
(pop-last bracket-stack)
) ; multiple-value-bind
(return nil)
) ; if closing matches open; else unmatched
(progn
(setq result nil)
(debug-format (format nil "return from close '~A' before open '~A'" c bracket-stack))
(return-from pairedp result)
)
(if (bracket-match (peek bracket-stack) c)
(progn
(setq bracket-stack (remove-last bracket-stack))
(debug-format (format nil "matched, removing last from stack: '~A'~%" bracket-stack))
)
(progn
(setq result nil)
(debug-format (format nil "return from close '~A' doesn't match open '~A' stack:'~A'~%" c (peek bracket-stack) bracket-stack))
(return-from pairedp result)
)
) ; if closing matches open; else unmatched
) ; if open and stack empty; else open and stack not empty
) ; if open; else close
) ; when either
) ; loop
) ; loop
(debug-format (format nil "~%"))
(if (= 0 (length bracket-stack))
(progn
(debug-format (format nil "return from bracket-stack is empty~%"))
(return-from pairedp t)
)
(progn
(debug-format (format nil "return from bracket-stack '~A' is not empty~%" bracket-stack))
(return-from pairedp nil)
)
)
) ; let
) ; => t or nil
83 changes: 24 additions & 59 deletions common-lisp/matching-brackets/run-tests-lisp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ To load "fiveam":


Running test suite MATCHING-BRACKETS-SUITE
Running test COMPLEX-LATEX-EXPRESSION f
Running test MATH-EXPRESSION f
Running test COMPLEX-LATEX-EXPRESSION .
Running test MATH-EXPRESSION .
Running test EARLY-MISMATCHED-BRACKETS .
Running test EARLY-UNEXPECTED-BRACKETS .
Running test TOO-MANY-CLOSING-BRACKETS .
Expand All @@ -21,69 +21,34 @@ Running test suite MATCHING-BRACKETS-SUITE
Running test UNPAIRED-AND-NESTED-BRACKETS .
Running test UNOPENED-CLOSING-BRACKETS .
Running test PAIRED-AND-WRONG-NESTED-BRACKETS-BUT-INNERMOST-ARE-CORRECT .
Running test PAIRED-AND-NESTED-BRACKETS f
Running test SEVERAL-PAIRED-BRACKETS f
Running test SIMPLE-NESTED-BRACKETS f
Running test PAIRED-AND-NESTED-BRACKETS .
Running test SEVERAL-PAIRED-BRACKETS .
Running test SIMPLE-NESTED-BRACKETS .
Running test PARTIALLY-PAIRED-BRACKETS .
Running test PAIRED-WITH-WHITESPACE f
Running test PAIRED-WITH-WHITESPACE .
Running test WRONG-CLOSING-BRACKET .
Running test WRONG-ORDERED-BRACKETS .
Running test UNPAIRED-BRACKETS .
Running test EMPTY-STRING f
Running test PAIRED-SQUARE-BRACKETS f
Running test EMPTY-STRING .
Running test PAIRED-SQUARE-BRACKETS .
Did 20 checks.
Pass: 12 (60%)
Pass: 20 (100%)
Skip: 0 ( 0%)
Fail: 8 (40%)

Failure Details:
--------------------------------
PAIRED-SQUARE-BRACKETS in MATCHING-BRACKETS-SUITE []:
(MATCHING-BRACKETS:PAIREDP VALUE) did not return a true value
--------------------------------
--------------------------------
EMPTY-STRING in MATCHING-BRACKETS-SUITE []:
(MATCHING-BRACKETS:PAIREDP VALUE) did not return a true value
--------------------------------
--------------------------------
PAIRED-WITH-WHITESPACE in MATCHING-BRACKETS-SUITE []:
(MATCHING-BRACKETS:PAIREDP VALUE) did not return a true value
--------------------------------
--------------------------------
SIMPLE-NESTED-BRACKETS in MATCHING-BRACKETS-SUITE []:
(MATCHING-BRACKETS:PAIREDP VALUE) did not return a true value
--------------------------------
--------------------------------
SEVERAL-PAIRED-BRACKETS in MATCHING-BRACKETS-SUITE []:
(MATCHING-BRACKETS:PAIREDP VALUE) did not return a true value
--------------------------------
--------------------------------
PAIRED-AND-NESTED-BRACKETS in MATCHING-BRACKETS-SUITE []:
(MATCHING-BRACKETS:PAIREDP VALUE) did not return a true value
--------------------------------
--------------------------------
MATH-EXPRESSION in MATCHING-BRACKETS-SUITE []:
(MATCHING-BRACKETS:PAIREDP VALUE) did not return a true value
--------------------------------
--------------------------------
COMPLEX-LATEX-EXPRESSION in MATCHING-BRACKETS-SUITE []:
(MATCHING-BRACKETS:PAIREDP VALUE) did not return a true value
--------------------------------


real 0m2.054s
user 0m1.807s
sys 0m0.245s
Fail: 0 ( 0%)


real 0m2.087s
user 0m1.847s
sys 0m0.237s

===============================================================================

sblint -v ./matching-brackets.lisp ./matching-brackets-test.lisp ./run-tests.lisp
[INFO] Lint file matching-brackets.lisp
matching-brackets.lisp:7:0: style-warning: The variable VALUE is defined but never used.

real 0m0.521s
user 0m0.452s
sys 0m0.069s
real 0m0.461s
user 0m0.403s
sys 0m0.057s

===============================================================================

Expand All @@ -95,17 +60,17 @@ Indenting region...done
Indenting region...
Indenting region...done

real 0m0.094s
user 0m0.066s
sys 0m0.029s
real 0m0.096s
user 0m0.068s
sys 0m0.028s

===============================================================================

Running: misspell .

real 0m0.027s
user 0m0.026s
sys 0m0.013s
real 0m0.024s
user 0m0.030s
sys 0m0.010s

===============================================================================

0 comments on commit 55cef11

Please sign in to comment.