diff --git a/config.json b/config.json index ccd2dda..8cbb756 100644 --- a/config.json +++ b/config.json @@ -269,6 +269,14 @@ "prerequisites": [], "difficulty": 1 }, + { + "slug": "matching-brackets", + "name": "Matching Brackets", + "uuid": "01c66794-36f0-4134-a9a9-4d09011beb5a", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, { "slug": "grains", "name": "Grains", diff --git a/exercises/practice/matching-brackets/.docs/instructions.md b/exercises/practice/matching-brackets/.docs/instructions.md new file mode 100644 index 0000000..ea17084 --- /dev/null +++ b/exercises/practice/matching-brackets/.docs/instructions.md @@ -0,0 +1,5 @@ +# Instructions + +Given a string containing brackets `[]`, braces `{}`, parentheses `()`, or any combination thereof, verify that any and all pairs are matched and nested correctly. +Any other characters should be ignored. +For example, `"{what is (42)}?"` is balanced and `"[text}"` is not. diff --git a/exercises/practice/matching-brackets/.docs/introduction.md b/exercises/practice/matching-brackets/.docs/introduction.md new file mode 100644 index 0000000..0618221 --- /dev/null +++ b/exercises/practice/matching-brackets/.docs/introduction.md @@ -0,0 +1,8 @@ +# Introduction + +You're given the opportunity to write software for the Bracketeer™, an ancient but powerful mainframe. +The software that runs on it is written in a proprietary language. +Much of its syntax is familiar, but you notice _lots_ of brackets, braces and parentheses. +Despite the Bracketeer™ being powerful, it lacks flexibility. +If the source code has any unbalanced brackets, braces or parentheses, the Bracketeer™ crashes and must be rebooted. +To avoid such a scenario, you start writing code that can verify that brackets, braces, and parentheses are balanced before attempting to run it on the Bracketeer™. diff --git a/exercises/practice/matching-brackets/.meta/config.json b/exercises/practice/matching-brackets/.meta/config.json new file mode 100644 index 0000000..92a9f2a --- /dev/null +++ b/exercises/practice/matching-brackets/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "erikschierboom" + ], + "files": { + "solution": [ + "matching-brackets.8th" + ], + "test": [ + "test.8th" + ], + "example": [ + ".meta/example.8th" + ] + }, + "blurb": "Make sure the brackets and braces all match.", + "source": "Ginna Baker" +} diff --git a/exercises/practice/matching-brackets/.meta/example.8th b/exercises/practice/matching-brackets/.meta/example.8th new file mode 100644 index 0000000..459877d --- /dev/null +++ b/exercises/practice/matching-brackets/.meta/example.8th @@ -0,0 +1,14 @@ +: paired? \ s -- T + a:new >r + ( + dup '[ n:= if r> '] a:push >r drop ;then + dup '( n:= if r> ') a:push >r drop ;then + dup '{ n:= if r> '} a:push >r drop ;then + dup '] n:= if r> a:len 0 n:= if a:push >r break ;then a:pop swap >r n:= !if r> '] a:push >r break ;then ;then + dup ') n:= if r> a:len 0 n:= if a:push >r break ;then a:pop swap >r n:= !if r> ') a:push >r break ;then ;then + dup '} n:= if r> a:len 0 n:= if a:push >r break ;then a:pop swap >r n:= !if r> '} a:push >r break ;then ;then + drop + ) + s:each! + r> a:len 0 n:= nip +; diff --git a/exercises/practice/matching-brackets/.meta/tests.toml b/exercises/practice/matching-brackets/.meta/tests.toml new file mode 100644 index 0000000..35a98a0 --- /dev/null +++ b/exercises/practice/matching-brackets/.meta/tests.toml @@ -0,0 +1,70 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[81ec11da-38dd-442a-bcf9-3de7754609a5] +description = "paired square brackets" + +[287f0167-ac60-4b64-8452-a0aa8f4e5238] +description = "empty string" + +[6c3615a3-df01-4130-a731-8ef5f5d78dac] +description = "unpaired brackets" + +[9d414171-9b98-4cac-a4e5-941039a97a77] +description = "wrong ordered brackets" + +[f0f97c94-a149-4736-bc61-f2c5148ffb85] +description = "wrong closing bracket" + +[754468e0-4696-4582-a30e-534d47d69756] +description = "paired with whitespace" + +[ba84f6ee-8164-434a-9c3e-b02c7f8e8545] +description = "partially paired brackets" + +[3c86c897-5ff3-4a2b-ad9b-47ac3a30651d] +description = "simple nested brackets" + +[2d137f2c-a19e-4993-9830-83967a2d4726] +description = "several paired brackets" + +[2e1f7b56-c137-4c92-9781-958638885a44] +description = "paired and nested brackets" + +[84f6233b-e0f7-4077-8966-8085d295c19b] +description = "unopened closing brackets" + +[9b18c67d-7595-4982-b2c5-4cb949745d49] +description = "unpaired and nested brackets" + +[a0205e34-c2ac-49e6-a88a-899508d7d68e] +description = "paired and wrong nested brackets" + +[1d5c093f-fc84-41fb-8c2a-e052f9581602] +description = "paired and wrong nested brackets but innermost are correct" + +[ef47c21b-bcfd-4998-844c-7ad5daad90a8] +description = "paired and incomplete brackets" + +[a4675a40-a8be-4fc2-bc47-2a282ce6edbe] +description = "too many closing brackets" + +[a345a753-d889-4b7e-99ae-34ac85910d1a] +description = "early unexpected brackets" + +[21f81d61-1608-465a-b850-baa44c5def83] +description = "early mismatched brackets" + +[99255f93-261b-4435-a352-02bdecc9bdf2] +description = "math expression" + +[8e357d79-f302-469a-8515-2561877256a1] +description = "complex latex expression" diff --git a/exercises/practice/matching-brackets/libs/exercism/test b/exercises/practice/matching-brackets/libs/exercism/test new file mode 100644 index 0000000..77a05f3 --- /dev/null +++ b/exercises/practice/matching-brackets/libs/exercism/test @@ -0,0 +1,162 @@ +needs console/loaded + +\ ----------------------------------------------------------------- + +ns: test + +-1 var, test-count +var tests-passed +var tests-failed +var tests-skipped +true var, run-test + +\ Some utility words + +: array-insens-dot \ x -- \\ removes leading space on stringified arrays + dup >kind ns:a n:= + if + >s s:trim + then + . +; + +: test-passed \ s x x -- \\ test name, expected value, actual value + 2drop + 1 tests-passed n:+! + con:green con:onBlack . space " ... OK" . con:white con:onBlack cr +; + +: test-skipped \ s -- + 1 tests-skipped n:+! + con:cyan con:onBlack . space " ... SKIPPED" . con:white con:onBlack cr +; + +: test-failed \ s x x -- \\ test name, expected value, actual value + 1 tests-failed n:+! + rot + con:red con:onBlack . space " ... FAIL" . con:white con:onBlack cr + " Actual: «" . array-insens-dot "»" . cr + " Expected: «" . array-insens-dot "»" . cr cr +; + +: isword? \ x -- x f + dup >kind ns:w n:= +; + +: run-test? \ -- T + run-test @ if true else "RUN_ALL_TESTS" getenv n:>bool then +; + +\ Num passed + num skipped + num failed should == num tests +: all-tests-run? \ -- T + tests-passed @ tests-skipped @ tests-failed @ n:+ n:+ + test-count @ n:= +; + +\ returns true if x is a date, false otherwise +: date? \ x -- x T + dup >kind ns:d n:= +; + +\ adapted from 8th forum -- https://8th-dev.com/forum/index.php/topic,2745.0.html +: eq? \ x x -- T + \ are the items the same kind? + 2dup >kind swap >kind n:= + !if 2drop false ;then + + \ same kind: try different comparators + number? if n:= ;then + string? if s:= ;then + array? if ' eq? a:= 2nip ;then + map? if ' eq? m:= 2nip ;then + date? if d:= ;then + + \ otherwise fall back to 'lazy evaluation' + l: = +; + +: check-depth \ ... n -- ... + dup>r + n:1+ depth n:= + !if + con:red con:onBlack + "PANIC: expected stack depth to be " . r> . cr + "Stack is:" . cr + .s cr + 255 die + then + rdrop +; + +\ ----------------------------------------------------------------- + +\ status report at end of run +( all-tests-run? + !if con:red con:onBlack "... FAIL - not all tests completed" . con:white con:onBlack cr then +) onexit + +\ Print a summary of the tests run +( con:white con:onBlack + test-count @ . space "tests planned - " . + tests-passed @ . space "passed - " . + tests-skipped @ . space "skipped - " . + tests-failed @ . space "failed" . cr +) onexit + +\ ----------------------------------------------------------------- +\ The public-facing words +\ ----------------------------------------------------------------- + +: equal? \ s x w -- | s w x -- + run-test? !if 2drop test-skipped ;; then + isword? !if swap then + w:exec + 3 check-depth + 2dup \ so test-failed can show actual and expected + eq? if test-passed else test-failed then +; + +: true? \ s w -- + run-test? !if drop test-skipped ;; then + w:exec + 2 check-depth + true swap dup \ so test-failed can show actual and expected + if test-passed else test-failed then +; + +: false? \ s w -- + run-test? !if drop test-skipped ;; then + w:exec + 2 check-depth + false swap dup \ so test-failed can show actual and expected + !if test-passed else test-failed then +; + +: null? \ s w -- + run-test? !if drop test-skipped ;; then + w:exec + 2 check-depth + null swap dup \ so test-failed can show actual and expected + G:null? nip if test-passed else test-failed then +; + +: SKIP-REST-OF-TESTS false run-test ! ; + +: tests \ n -- + test-count ! +; + +\ Set the exit status: +\ 0 = all OK +\ 1 = not all tests were run (some error occurred) +\ 2 = some tests failed +: end-of-tests \ -- + all-tests-run? + if + tests-failed @ 0 n:= if 0 else 2 then + else + 1 + then + die +; + diff --git a/exercises/practice/matching-brackets/matching-brackets.8th b/exercises/practice/matching-brackets/matching-brackets.8th new file mode 100644 index 0000000..ed9bf6e --- /dev/null +++ b/exercises/practice/matching-brackets/matching-brackets.8th @@ -0,0 +1,3 @@ +: paired? \ s -- T + +; diff --git a/exercises/practice/matching-brackets/test.8th b/exercises/practice/matching-brackets/test.8th new file mode 100644 index 0000000..e1baa15 --- /dev/null +++ b/exercises/practice/matching-brackets/test.8th @@ -0,0 +1,89 @@ +"matching-brackets.8th" f:include +needs exercism/test +with: test +20 tests + +"paired square brackets" + ( "[]" paired? ) + true? + +SKIP-REST-OF-TESTS + +"empty string" + ( "" paired? ) + true? + +"unpaired brackets" + ( "[[" paired? ) + false? + +"wrong ordered brackets" + ( "}{" paired? ) + false? + +"wrong closing bracket" + ( "{]" paired? ) + false? + +"paired with whitespace" + ( "{ }" paired? ) + true? + +"partially paired brackets" + ( "{[])" paired? ) + false? + +"simple nested brackets" + ( "{[]}" paired? ) + true? + +"several paired brackets" + ( "{}[]" paired? ) + true? + +"paired and nested brackets" + ( "([{}({}[])])" paired? ) + true? + +"unopened closing brackets" + ( "{[)][]}" paired? ) + false? + +"unpaired and nested brackets" + ( "([{])" paired? ) + false? + +"paired and wrong nested brackets" + ( "[({]})" paired? ) + false? + +"paired and wrong nested brackets but innermost are correct" + ( "[({}])" paired? ) + false? + +"paired and incomplete brackets" + ( "{}[" paired? ) + false? + +"too many closing brackets" + ( "[]]" paired? ) + false? + +"early unexpected brackets" + ( ")()" paired? ) + false? + +"early mismatched brackets" + ( "{)()" paired? ) + false? + +"math expression" + ( "(((185 + 223.85) * 15) - 543)/2" paired? ) + true? + +"complex latex expression" + ( "\left(\begin{array}{cc} \frac{1}{3} & x\\ \mathrm{e}^{x} &... x^2 \end{array}\right)" paired? ) + true? + +end-of-tests +;with