[Question]
  [
# Inspired by, and in memory of, our beloved genius,
[![John Scholes, 1948-2019](https://i.stack.imgur.com/lIqGd.png "John Scholes, 1948-2019")](https://www.dyalog.com/news/131/420/John-Scholes.htm)
# [R.I.P.](http://johnscholes.rip/)
He [invented](https://dyalog.tv/Dyalog18/?v=y33XDD6ANt0 "Dfns - Past, Present and Future") and implemented [dfns](http://dfns.dyalog.com/ "D-functions") — his magnum opus and the subject of the challenge.
For the interested: [latest full dfns documentation](http://help.dyalog.com/latest/index_Left.htm#CSHID=Language%2FDefined%2520Functions%2520and%2520Operators%2FDynamicFunctions%2FDynamic%2520Functions%2520and%2520Operators.htm%7CStartTopic=Content%2FLanguage%2FDefined%2520Functions%2520and%2520Operators%2FDynamicFunctions%2FDynamic%2520Functions%2520and%2520Operators.htm) and [videos with John](http://johnscholes.rip/video/).
## Task
Given an ASCII source code, answer in which of the following four categories it belongs:
1. Dyadic dop
2. Monadic dop
3. Dfn
4. Other
You may return any four consistent values, but please state your mapping if it isn't obvious.
### Details
You may assume that the source code always begins with an opening curly brace `{` and ends with a closing curly brace `}`.
Recursively nested braces can occur (e.g. `{{{}}}`), but categories 1–3 can never have brace nesting depth go below 1 (so `{}{}` is "Other") and all braces must be balanced (so `{{}` is "Other").
Characters in the following contexts on a line are ignored:
1. To the right of `#` (a comment): `significant#ignored`
2. Enclosed in single quotes `'`…`'` (i.e. in a string): `significant'ignored'significant` (This applies to `#` too: `'#'significant`)
3. To the right of an unpaired quote `'` (pairing quotes from the left): `significant'ignored`
In curly brace level one (i.e. excluding nested braces):
* Dyadic dops contain the uninterrupted phrase `ww`
* Monadic dops do not contain `ww`, but do contain `aa`
* Dfns contain neither `ww` nor `aa`
## Test cases
### Dyadic dops
```
{ww}
```
```
{
    www
}
```
```
{
''ww'
}
```
```
{aa
ww}
```
```
{'#''#'ww?aa}
```
### Monadic dops
```
{aa}
```
```
{aaaa}
```
```
{aa{ww}'ww'}
```
```
{w#w'
aa'
}
```
```
{aaw*w}
```
```
{w'\'aa\''}
```
### Dfns
```
{}
```
```
{a a}
```
```
{aA}
```
```
{
{aa}
}
```
```
{w
w''w#
w}
```
```
{{
}}
```
```
{w\'aa\'}
```
### Other
```
{}{}
```
```
{{}
```
```
{}}
```
```
{ww}}
```
```
{}
{}
```
```
{ww}{}
```
```
{#}
```
```
{'
'}
```
  
[Answer]
# JavaScript (ES6), ~~145 ... 138~~ 136 bytes
Returns \$0\$ for *dyadic dops*, \$1\$ for *monadic dops*, \$2\$ for *dfns* and \$3\$ for *other*.
```
s=>[...s].map(c=>s=(n=`
aw}{#'`.indexOf(c))?n>5?i^=2:i?0:n>4?i=1:n>3?d++:n>2?x+=!d--:(o|=n<0|d|s!=c?0:n,c):i=0,o=i=0,x=d=-1)|x|~d?3:2>>o
```
[Try it online!](https://tio.run/##fZLPTsMwDMbve4ptPaSla7U/cCm4EdKuaA9AQYuSFoJGUi0TKWrLq5cUhAQiXg6x5M@2fl@cF/bGDD/K@pQoLcqhgsFAfp@mqXlIX1kdcsgNhAr2E2b7NiD7VCpRNrsq5FFEVX5F5SOsM0mXmcovqYSVixsq4tjFNW1imIkkyULdgbpZdqIzM@Bj8YJHmYTlQsN4NyAgWUVd030IusnWea4HrpXRhzI96KeQbN@ZkHwqdG1IdD35rVXhvLW2n0eefKGm7lhrC4UVEGItwWTGClUobDoJXC9l7Fv9I5M7rc4S/3T9z@PKaHOk9es2GH0wdsaMvbA@1m2lvIzImCkGeIu98egWo3KrsW4HgQv@Atff@6h3p@fy6MVGwJF0j3BZRHBOWrQFUQLkA7nv96UMnw "JavaScript (Node.js) – Try It Online")
## Alternate versions
* [**131 bytes**](https://tio.run/##hZLPTsMwDMbve4qxHtKytdofuBTcCGlXtAegoEVJC0HDmdYJF63l1UsqEAJp83KII31fHP/svKp3Vemd3e5jdKboSugqyKrkTW1D7Q8QIqwHitpDINaJRVPUqzLUUSQxu5b2CeapldMUsytpYebjQprx2Me5rMdwYeI4DV0DeDttTFNdgO7NEx2lFqYTB/1eg4F4FjV182nkIp1nmeu0w8ptimTjnkOx/FDG6qFx20pEN4O/Whk@JEkyOhC1o8fohJjj0C8iypF1CUEkWI9SOebIPiYCn0Uq9WP55xH3Ds@i/F49Lp6R@070GIyJgp5SqXOodElHIZYlniyeSzhkK79jR9N3hS3Xz5b8/AIfGJfP1B5lWu1fit1JKA6L01quYOJUD3vgL3NywP1P/8@/5e4L) by taking an array of characters as input
* [**132 bytes**](https://tio.run/##fZLRSsMwFIbvfYq5XqR1y1g7hixyGpTdii9QhNC0WpknY5mmss5Xr@lEUMxZL9L0fDnh@5u8qHdly12z3XM0uupr6C3kd291Xe1im8xe1TZGyC0gT@cS@WIlGzkXfrL0X2m2OI1LGZsOdGc5nmCariQCrK5FNsVEtBO41JwLPZmIBlLRPELmJ/OpgWFsQQNPk67tPrVciCzPTV8atGZTzTbmKWbrD6WbcqTN1rLk5uI3q@PxwbnjOAnUCxz5xzlXILWAMecYhZUqsEBqdxb5XqnUN/2D2b3Bs8Y/Xf/rNBliDrZh7qIhh1JnwrgrF3Jd1xh0JLYZUYK31D8e0lJW/micP4PIv8ILfP8xZP2wf652QW1CnCgfCS9HAJ/kQLYQJCIukL9@J9J/AQ) by using *Buffer()* (Node.js)
## How?
The input string is parsed character by character.
### Translation of characters into codes
Each character \$c\$ is translated into a code \$n\$ according to the following table:
```
 character | code | triggered operation
-----------+------+---------------------------------------------------------
    \n     |   0  | i = 0
     a     |   1* | o |= n < 0 | d | s != c ? 0 : n
     w     |   2* | o |= n < 0 | d | s != c ? 0 : n
     }     |   3* | x += !d--
     {     |   4* | d++
     #     |   5* | i = 1
     '     |   6  | i ^= 2
   other   |  -1* | same as 'a' or 'w', but always fails because of 'n < 0'
```
Codes marked with a '\$\*\$' have no effect when \$i\neq 0\$.
### Variables describing the parser state
The following variables are used during the parsing:
* \$o\$: a bitmask keeping track of encountered phrases
	+ bit 0: a valid phrase `aa` has been encountered
	+ bit 1: a valid phrase `ww` has been encountered
* \$i\$: a bitmask telling whether some characters should be ignored
	+ bit 0: we're currently located inside a comment
	+ bit 1: we're currently located inside a string (this bit is still updated within a comment, but this is harmless)
* \$s\$: the result of the previous iteration
* \$d\$: the current depth of nested braces (starting at \$-1\$)
* \$x\$: the number of times we went from depth \$0\$ to depth \$-1\$, minus \$1\$
### Final result
We output \$3\$ if \$x\$ is not equal to \$0\$ or \$d\$ is not equal to \$-1\$. Otherwise, we output \$0\$, \$1\$ or \$2\$ according to the value held in \$o\$.
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), ~~50 48 46~~ 45 [bytes](https://github.com/DennisMitchell/jelly/wiki/Code-page)
```
Ỵµṣ”'m2Kṣ”#Ḣ)KµċⱮƤØ{IF©<-oµ⁾waż¤ẇ€‘Ḅ«5×®¬Ḅ⁼1¤
```
A monadic Link accepting a list of characters which yields:
```
5 - Dyadic dop
4 - Monadic dop
3 - Dfn
0 - Other
```
**[Try it online!](https://tio.run/##y0rNyan8///h7i2Htj7cufhRw1z1XCNvCEv54Y5Fmt6Hth7pfrRx3bElh2dUe7odWmmjm39o66PGfeWJR/ccWvJwV/ujpjWPGmY83NFyaLXp4emH1h1aA2Q/atxjeGjJ////lZSUYriqy7nK1ZXz8ksUEhWS83NzU/NK1MuVYazikqLMvHSFzDwkWRidm1@UqoBFAReXcn5eTiWSANCK6sTE2rT8/OqKiuqqqtrapMQivXL1cqBELdAVAA "Jelly – Try It Online")** Or see a [test-suite](https://tio.run/##VY7PSgMxEMbv8xRLcghKPSh4E8SLIH2E2kMOXqTicZAQaIvgwQewFy@6F3EpCC5ULR5m1fdIXiSdbBubDYH5981vvsuL0egmBPf1TrX7ePbjR3V10F9n0i2edvpU/9z7t/lf2czM2Sm9HO1dU@0n36h/l1S6zzs/rfx45ha39HrYPNCcKs79ZLlPZWja6bQKYTAQBtEKKHpCiHMwUPBDRLBcb7tKIapuT2uAuLpuGSVZcqy1FUPoMTVm7UDrLI3HIiq7iJLJWm/pLMNdTJy0WvxDTnK78U7XFwKyWwnY6Rqwsd4wEzVFu4nsLoNb/skTT5JYZhIFqsUOVw "Jelly – Try It Online").  
uses Python quoting to avoid the possibility of evaluating input as a Python set or dictionary
### How?
```
Ỵµṣ”'m2Kṣ”#Ḣ)KµċⱮƤØ{IF©<-oµ⁾waż¤ẇ€‘Ḅ«5×®¬Ḅ⁼1¤ - Link: list of characters
                                              - breaking long Link up...
Ỵµṣ”'m2Kṣ”#Ḣ)K      - Replace any strings or comments with (single) spaces
Ỵ                   - split at newline characters
 µ          )       - monadic chain for each:
  ṣ”'               -   split at apostrophe characters
     m2             -   modulo 2 slice (i.e. every other part starting with the first
                    -   - that is, non-string code. Will remove strings from within comments)
       K            -   join with spaces
        ṣ”#         -   split at octothorp characters
           Ḣ        -   head (i.e. non-comment code)
             K      - join with spaces
µċⱮƤØ{IF©<-oµ       - Replace characters of code at depth > 1 with the integer 1
µ           µ       - monadic chain, call previous result A:
    Ø{              -   literal ['{','}']
   Ƥ                -   for prefixes of A:
  Ɱ                 -     map across right argument with:
 ċ                  -       count
      I             -   deltas (i.e. [count('}') - count('{')] for each prefix)
       F            -   flatten (i.e. count('}') - count('{') for each prefix)
                    -   -- i.e -1*depth of each character of A; closing braces at depth+1
        ©           -   (copy this list of depths to the register for later use)
         <-         -   less than -1? (vectorises)
           o        -   logical OR with A (vectorises, replacing deep code with 1s)
⁾waż¤ẇ€‘Ḅ«5×®¬Ḅ⁼1¤ - Categorise the result, R
    ¤              - nilad followed by link(s) as a nilad:
⁾wa                -   literal ['w', 'a']
   ż               -   zip with itself = [['w','w'],['a','a']]
     ẇ€            - for €ach: is a sublist of R?  i.e. one of: [0,0] [1,0] [0,1] [1,1]
       ‘           - increment (vectorises)                     [1,1] [2,1] [1,2] [2,2]
        Ḅ          - unbinary                                     3     5     4     6
         «5        - minimum with five                            3     5     4     5
                 ¤ - nilad followed by link(s) as a nilad:
            ®      -   recall depths from the register
             ¬     -   logical NOT (vectorises) (0->1, other depths->0)
              Ḅ    -   unbinary
               ⁼1  -   equal one -- i.e. depths ends with a 0 and contains no other zero 
           ×       - multiply
```
[Answer]
# [Clean](https://github.com/Ourous/curated-clean-linux), ~~309~~ ~~293~~ 284 bytes
We can get away with only using 3 variable names at a time, so we'll call them `a`, `p`, and `l`.
```
import StdEnv,Text,Data.List
a=isInfixOf o zip2[2,2]
@ =['\'']
$p#p=join@[foldl((\[a:p]_|p>[]=a++[';':join@(tl p)]=split['#']a!!0)o split@)l l\\l<-mklines p]
#l=[(?a- ?l,p)\\a<-inits p&[p:l]<-tails p]
|{p\\(a,p)<-l|a<2}<>"{}"=0|a['ww']l=1|a['aa']l=2=3
?l=sum[1\\'{'<-l]-sum[1\\'}'<-l]
```
[Try it online!](https://tio.run/##XZBBb9swDIXP0a9gm2KyV7tNs5tnJRnWHgIUSIEU2EESBiKxO220LcRK3S7JX59nOekw9Ebyfe@J4ooyLNuiWm8pgwJN2ZrCVhsHS7e@K5@jx@zFRbfo8Ore1I6hMPW8zM3LIocKfhs7luNorNkMhOSKc80u7NCKn5UpZzKvaE1BoCQmVn/f24nUAi8vJf/Mk54IHIENtagtGSf5kGs8OxuFFfSDWUhASlEaF7/IlFkNVrMhCRlMMYYpRTZUCtPYlMZ12gdpE9Jp7NBQj@53VqkAOyyNaY/p@JBOzneHczHao@RNwzWJG18i@nIsPrEpiXpbyBul@I53Lh2/tYe@bfNNVcDytXZZcTVfwOlWSTJfRPCUua8/cBNB9ow0X7Clw05r2GAIgSnt1kXQhCA894XIo7VXr69F918sgyCdhP6GIfQ0Gwi4OJXsf0@SwMdv1YbWEE8gkH6oo9MoZO/Su7dX/VJNyAZd4nG3t109sQcPgBDA1Yj3UCD10XBy1//s79I96oGkp3pTu2tYw3kzZM3hzyonfKrbeH7f3r6WWJjVsXkgdHm1Kf4C "Clean – Try It Online")
Defines the function `$ :: [Char] -> Int` and some helpers, giving the mapping:
* `0`: Other
* `1`: Dyadic dop
* `2`: Monadic dop
* `3`: Dfn
Expanded (first version), and with more than 3 variable names:
```
$ s
    # s // remove strings and comments
        = join [';'] [ // join the second argument with semicolons
            limit ( // take the first repeated element of
                iterate // an infinite list of applications of the first argument
                    (
                        (
                            \(p, q) = p ++ case q of // join the first half with a modified second half
                                ['\'\'': q] = [';': q] // replace two quotes with a semicolon
                                [c, _: q] = [c: q] // drop the character after a quote or hash
                                _ = [] // leave unmatched strings unchanged
                        ) o span // split the string on the first occurrence of
                            \c = c <> '\'' && c <> '#' // a quote or hash
                    ) l // applied to l
                )
            \\ l <- mklines s // for line l in s split at newlines
        ]
    # b // generate a map of nesting levels
        = [
            ( // the pair of
                ?i - ?t, // the nesting level
                c // the character c
            ) 
            \\ i <- inits s // for init i of s
            & // synchronously iterated with 
                [c: t] <- tails s // character c at the start of tail [c:t] of s
        ]
    // determine what the code is
    | {c \\(n, c) <- b | n < 2} // if the string made of characters with nesting level of less than 2
        <> "{}" // is not the same as the paired braces at the beginning and end
        = 0 // return zero
    | m ['ww'] b // if there are two consecutive 'w's at nesting level 2
        = 1 // return 1
    | m ['aa'] b // if there are two consecutive 'a's at nesting level 2
        = 2 // return 2
    = 3 // otherwise return 3
```
[Answer]
# [Retina 0.8.2](https://github.com/m-ender/retina/wiki/The-Language/a950ad7d925ec9316e3e2fb2cf5d49fd15d23e3d), 91 bytes
```
m`'.*?('|$)|#.*
¶
s(+`(?!^)\{[^{}]*\}(?!$)
¶
^(?!\{[^{}]*\}$).+
3
^.+ww.+
2
^.+aa.+
1
..+
0
```
[Try it online!](https://tio.run/##RU5JDsIwDDzXryhKkbtIEcsDKv7AjVLFBw4c4ABIPqT5Vh/QjwXHoSKK7JmxZ5LX7XN/Ujy7ZXaFs8tsYVu7ApY5Phzatq9xqprJ2FYkeNedq/vN2Az@MvpwbYcgtGrSbBT0l6vGdnCE0XbMgg4JEQnag5W6i9EzBwAPpRxmBiWIzKiQCPICGpTL3BNlPde1p5hkSoyNmInWAG41gHFAogF1RSdl9p70SU3UPWB53oCaPATVslWd6tWSRxxyoP8x7Ua/DOL4Ag "Retina 0.8.2 – Try It Online") Link includes test suite. Explanation:
```
m`'.*?('|$)|#.*
¶
```
Remove strings and comments.
```
s(+`(?!^)\{[^{}]*\}(?!$)
¶
```
Remove matched brackets, working out from the innermost, but leave the first and last brackets.
```
^(?!\{[^{}]*\}$).+
3
```
If we don't have matched brackets then this is Other.
```
^.+ww.+
2
```
Otherwise if we have `ww` then this is Dyadic Dop.
```
^.+aa.+
1
```
Otherwise if we have `aa` then this is Monadic Dop.
```
..+
0
```
Otherwise if this is anything not covered above then this is Dfn.
]