# R.I.P.

He invented and implemented dfns — his magnum opus and the subject of the challenge.

For the interested: latest full dfns documentation and videos with John.

Given an ASCII source code, answer in which of the following four categories it belongs:

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

{ww}

{
www
}

{
''ww'
}

{aa

ww}

{'#''#'ww?aa}


{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}{}

{#}

{'
'}

• @LuisfelipeDejesusMunoz Dfn. If you see a reason to think otherwise, please let me know.
Feb 19 '19 at 13:38
• Can string quotes be escaped, and if so do we need to handle them? (eg: {'#\'ww?aa'} -> other?) Feb 19 '19 at 21:27
• @Οurous No, the spec is as stated: Anything in quotes is insignificant. (Indeed, APL strings have no escape mechanism.) I'll add a case.
Feb 20 '19 at 5:14
• Hm, may we assume that strings will not contain '' (apostrophe in string, can also be parsed as two adjacent strings for this challenge)? Feb 20 '19 at 16:23
• @EriktheOutgolfer It may occur. I'll add a case, but as you say, it doesn't matter whether 'abc''def' is parsed as one or two strings for this challenge.
Feb 20 '19 at 16:57

# 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!

## Alternate versions

• 131 bytes by taking an array of characters as input
• 132 bytes 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\$$.

# Jelly,  50 48 46  45 bytes

Ỵµṣ”'m2Kṣ”#Ḣ)KµċⱮƤØ{IF©<-oµ⁾waż¤ẇ€‘Ḅ«5×®¬Ḅ⁼1¤


5 - Dyadic dop
3 - Dfn
0 - Other


Try it online! Or see a test-suite.
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
Ỵµṣ”'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
⁾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
®      -   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


# Clean, 309293 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! 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  # Retina 0.8.2, 91 bytes m'.*?('|$)|#.*
¶
s(+(?!^)\{[^{}]*\}(?!$) ¶ ^(?!\{[^{}]*\}$).+
3
^.+ww.+
2
^.+aa.+
1
..+
0


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.