A distinção é difícil de fazer e depende da linguagem usada. Também é subjetivo.
No clojure, você pode definir APIs que se parecem com uma DSL. Por exemplo, o soluço permite gerar html:
(html [:span {:class "foo"} "bar"])
Isso pode ser considerado como um DSL com uma sintaxe lisp. O fato de html
poder ser uma macro fornece a mesma quantidade de poder, como se você estivesse escrevendo uma biblioteca de modelos html com expressões s (consulte sxml )
Em python, a mesma API pode se parecer com:
html(["span", {"class" : "foo"}, "bar"])
html é uma função. Seu argumento será avaliado primeiro e, em seguida, a chamada da função acontecerá. O fato de a sintaxe python ser mais específica e a semântica python ser mais rigorosa significa que essa expressão é mais difícil de interpretar como uma DSL independente da linguagem.
Uma representação de linguagem clássica é uma árvore como estrutura de dados e uma função eval chamada recursivamente em seus nós. As linguagens LISP tornam essa estrutura em árvore muito aparente, portanto, qualquer chamada de função aninhada é indistinguível de um recurso de linguagem interno. É por isso que a comunidade LISP fala sobre DSLs para quase tudo.
Acredito que a programação é fornecer abstrações úteis. Acho que olhar para tudo o que você constrói (uma biblioteca ou mesmo a interface do usuário do seu aplicativo) como elementos de linguagem, ajudando as pessoas a resolver um problema complexo, é uma maneira eficaz de projetar a maioria das coisas. Com essa perspectiva, afirmo que todas as bibliotecas são DSLs, mas algumas delas são mal projetadas :-)