{"id":3131,"date":"2022-06-24T22:09:44","date_gmt":"2022-06-24T19:09:44","guid":{"rendered":"https:\/\/demensdeum.com\/blog\/?p=3131"},"modified":"2024-12-16T22:32:20","modified_gmt":"2024-12-16T19:32:20","slug":"pattern-interpreter","status":"publish","type":"post","link":"https:\/\/demensdeum.com\/blog\/pt\/2022\/06\/24\/pattern-interpreter\/","title":{"rendered":"Int\u00e9rprete de padr\u00f5es"},"content":{"rendered":"<h3>O que est\u00e1 inclu\u00eddo<\/h3>\n<p>O padr\u00e3o Interpreter refere-se a padr\u00f5es de design comportamentais. Este padr\u00e3o permite implementar sua pr\u00f3pria linguagem de programa\u00e7\u00e3o trabalhando com uma \u00e1rvore AST, cujos v\u00e9rtices s\u00e3o express\u00f5es terminais e n\u00e3o terminais que implementam o m\u00e9todo Interpret, que fornece a funcionalidade da linguagem.<\/p>\n<ul>\n<li>Express\u00e3o terminal &#8211; por exemplo, constante de string &#8211; &#8220;Ol\u00e1, Mundo&#8221;<\/li>\n<li>Express\u00e3o n\u00e3o terminal &#8211; por exemplo Print(&#8220;Hello World&#8221;), cont\u00e9m Print e um argumento da express\u00e3o Terminal &#8220;Hello World&#8221;<\/li>\n<\/ul>\n<p>Qual \u200b\u200b\u00e9 a diferen\u00e7a? A diferen\u00e7a \u00e9 que a interpreta\u00e7\u00e3o termina nas express\u00f5es terminais, mas para as n\u00e3o-terminais ela continua em profundidade em todos os v\u00e9rtices\/argumentos recebidos. Se a \u00e1rvore AST consistisse apenas em express\u00f5es n\u00e3o terminais, o aplicativo nunca seria conclu\u00eddo, porque \u00e9 necess\u00e1ria uma certa finitude de qualquer processo, essa finitude \u00e9 o que s\u00e3o as express\u00f5es terminais, elas geralmente cont\u00eam dados, por exemplo strings.<\/p>\n<p>Um exemplo de \u00e1rvore AST est\u00e1 abaixo:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3143\" src=\"https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2022\/06\/ast.png\" alt=\"\" width=\"512\" height=\"578\" srcset=\"https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2022\/06\/ast.png 512w, https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2022\/06\/ast-266x300.png 266w\" sizes=\"auto, (max-width: 512px) 100vw, 512px\" \/><br \/>\nDcoetzee, CC0, via Wikimedia Commons<\/p>\n<p>Como voc\u00ea pode ver, as express\u00f5es terminais s\u00e3o constantes e vari\u00e1veis, as express\u00f5es n\u00e3o terminais s\u00e3o o resto.<\/p>\n<h3>O que n\u00e3o est\u00e1 inclu\u00eddo<\/h3>\n<p>A implementa\u00e7\u00e3o do Interpretador n\u00e3o inclui a an\u00e1lise da entrada da string de idioma na \u00e1rvore AST. Basta implementar classes de express\u00f5es terminais e n\u00e3o terminais, m\u00e9todos Interpret com o argumento Context na entrada, criar uma \u00e1rvore de express\u00f5es AST e executar o m\u00e9todo Interpret na express\u00e3o raiz. Um contexto pode ser usado para armazenar o estado do aplicativo em tempo de execu\u00e7\u00e3o.<\/p>\n<h3>Implementa\u00e7\u00e3o<\/h3>\n<p>O padr\u00e3o envolve:<\/p>\n<ul>\n<li>Cliente \u2013 retorna a \u00e1rvore AST e executa Interpret(context) para o n\u00f3 raiz (Cliente)<\/li>\n<li>Contexto \u2013 cont\u00e9m o estado da aplica\u00e7\u00e3o, passado para express\u00f5es quando interpretado (Contexto)<\/li>\n<li>Express\u00e3o abstrata \u2013 uma classe abstrata contendo o m\u00e9todo Interpret(context) (Expression)<\/li>\n<li>A express\u00e3o terminal \u00e9 uma express\u00e3o final, descendente de uma express\u00e3o abstrata (TerminalExpression)<\/li>\n<li>Uma express\u00e3o n\u00e3o terminal n\u00e3o \u00e9 uma express\u00e3o finita; ela cont\u00e9m ponteiros para v\u00e9rtices profundos na \u00e1rvore AST. Os v\u00e9rtices subordinados geralmente afetam o resultado da interpreta\u00e7\u00e3o da express\u00e3o n\u00e3o terminal (NonTerminalExpression).<\/li>\n<\/ul>\n<p>Exemplo de cliente em C#<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>        static void Main(string[] args)\n        {\n            var context = new Context();\n            var initialProgram = new PerformExpression(\n                new IExpression[] {\n                    new SetExpression(\"alpha\", \"1\"),\n                    new GetExpression(\"alpha\"),\n                    new PrintExpression(\n                        new IExpression[] {\n                            new ConstantExpression(\"Hello Interpreter Pattern\")\n                        }\n                    )\n                }\n            );\n            System.Console.WriteLine(initialProgram.interpret(context));\n        }\n}\n<\/code><\/pre>\n<\/div>\n<p>Exemplo de express\u00e3o abstrata em C#<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>{\n    String interpret(Context context);\n}\n<\/code><\/pre>\n<\/div>\n<p>Exemplo de express\u00e3o terminal em C# (String Constant)<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>{\n    private String constant;\n\n    public ConstantExpression(String constant) {\n        this.constant = constant;\n    }\n\n    override public String interpret(Context context) {\n        return constant;\n    }\n}\n<\/code><\/pre>\n<\/div>\n<p>Exemplo de express\u00e3o n\u00e3o terminal em C# (Iniciando e concatenando os resultados de v\u00e9rtices subordinados, utilizando o delimitador \u201c;\u201d<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>{\n    public PerformExpression(IExpression[] leafs) : base(leafs) {\n        this.leafs = leafs;\n    }\n    \n    override public String interpret(Context context) {\n        var output = \"\";\n        foreach (var leaf in leafs) {\n            output += leaf.interpret(context) + \";\";\n        }\n        return output;\n    }\n}\n<\/code><\/pre>\n<\/div>\n<h3>Voc\u00ea consegue fazer isso funcionalmente?<\/h3>\n<p>Como \u00e9 sabido, todas as linguagens Turing-completas s\u00e3o equivalentes. \u00c9 poss\u00edvel transferir o padr\u00e3o Orientado a Objetos para a linguagem de programa\u00e7\u00e3o Funcional?<\/p>\n<p>Para um experimento, vamos usar uma linguagem FP para a web chamada Elm. N\u00e3o h\u00e1 classes no Elm, mas existem registros e tipos, portanto, os seguintes registros e tipos est\u00e3o envolvidos na implementa\u00e7\u00e3o:<\/p>\n<ul>\n<li>Express\u00e3o \u2013 listando todas as express\u00f5es de linguagem poss\u00edveis (Express\u00e3o)<\/li>\n<li>Express\u00e3o subordinada \u2013 uma express\u00e3o subordinada \u00e0 express\u00e3o n\u00e3o terminal (ExpressionLeaf)<\/li>\n<li>Contexto \u2013 um registro que armazena o estado do aplicativo (Contexto)<\/li>\n<li>Fun\u00e7\u00f5es que implementam m\u00e9todos Interpret(context) &#8211; todas as fun\u00e7\u00f5es necess\u00e1rias que implementam a funcionalidade de express\u00f5es terminais e n\u00e3o terminais<\/li>\n<li>Registros auxiliares do estado do Int\u00e9rprete &#8211; necess\u00e1rios para o correto funcionamento do Int\u00e9rprete, armazenam o estado do Int\u00e9rprete, contexto<\/li>\n<\/ul>\n<p>Um exemplo de fun\u00e7\u00e3o que implementa a interpreta\u00e7\u00e3o para todo o conjunto de express\u00f5es poss\u00edveis no Elm:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>  case input.expression of\n    Constant text -&gt;\n      { \n        output = text, \n        context = input.context \n      }\n    Perform leafs -&gt;\n      let inputs = List.map (\\leaf -&gt; { expressionLeaf = leaf, context = input.context } ) leafs in\n        let startLeaf = { expressionLeaf = (Node (Constant \"\")), context = { variables = Dict.empty } } in\n          let outputExpressionInput = List.foldl mergeContextsAndRunLeafs startLeaf inputs in\n            {\n              output = (runExpressionLeaf outputExpressionInput).output,\n              context = input.context\n            }\n    Print printExpression -&gt;\n      run \n      { \n        expression = printExpression, \n        context = input.context \n      }\n    Set key value -&gt;\n      let variables = Dict.insert key value input.context.variables in\n      {\n        output = \"OK\",\n        context = { variables = variables }\n      }\n    Get key -&gt;\n      {\n        output = Maybe.withDefault (\"No value for key: \" ++ key) (Dict.get key input.context.variables),\n        context = input.context\n      }\n<\/code><\/pre>\n<\/div>\n<h3>E quanto \u00e0 an\u00e1lise?<\/h3>\n<p>A an\u00e1lise do c\u00f3digo-fonte em uma \u00e1rvore AST n\u00e3o est\u00e1 inclu\u00edda no padr\u00e3o Interpreter, existem v\u00e1rias abordagens para an\u00e1lise do c\u00f3digo-fonte, mas falaremos mais sobre isso em outro momento.<br \/>Na implementa\u00e7\u00e3o do Interpreter for Elm, escrevi um analisador simples na \u00e1rvore AST, consistindo em duas fun\u00e7\u00f5es &#8211; an\u00e1lise de um v\u00e9rtice, an\u00e1lise de v\u00e9rtices subordinados.<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>parseLeafs state =\n    let tokensQueue = state.tokensQueue in\n        let popped = pop state.tokensQueue in\n            let tokensQueueTail = tail state.tokensQueue in\n                if popped == \"Nothing\" then\n                    state\n                else if popped == \"Perform(\" then\n                    {\n                        tokensQueue = tokensQueue,\n                        result = (state.result ++ [Node (parse tokensQueue)])\n                    }\n                else if popped == \")\" then\n                    parseLeafs {\n                        tokensQueue = tokensQueueTail,\n                        result = state.result\n                    }\n                else if popped == \"Set\" then\n                    let key = pop tokensQueueTail in\n                        let value = pop (tail tokensQueueTail) in\n                            parseLeafs {\n                                tokensQueue = tail (tail tokensQueueTail),\n                                result = (state.result ++ [Node (Set key value)])\n                            }\n                else if popped == \"Get\" then\n                    let key = pop tokensQueueTail in\n                        parseLeafs {\n                            tokensQueue = tail tokensQueueTail,\n                            result = (state.result ++ [Node (Get key)])\n                        }\n                else \n                    parseLeafs {\n                        tokensQueue = tokensQueueTail,\n                        result = (state.result ++ [Node (Constant popped)])\n                    }\n\nparse tokensQueue =\n    let popped = pop tokensQueue in\n        let tokensQueueTail = tail tokensQueue in\n            if popped == \"Perform(\" then\n                Perform (\n                    parseLeafs {\n                        tokensQueue = tokensQueueTail, \n                        result = []\n                    }\n                ).result\n            else if popped == \"Set\" then\n                let key = pop tokensQueueTail in\n                    let value = pop (tail tokensQueueTail) in\n                        Set key value\n            else if popped == \"Print\" then\n                Print (parse tokensQueueTail)\n            else\n                Constant popped\n<\/code><\/pre>\n<\/div>\n<h3>Links<\/h3>\n<p><a href=\"https:\/\/gitlab.com\/demensdeum\/patterns\/-\/tree\/master\/interpreter\/elm\" target=\"_blank\" rel=\"noopener\">https:\/\/gitlab.com\/demensdeum \/patterns\/-\/tree\/master\/interpreter\/elm<\/a><br \/><a href=\"https:\/\/gitlab.com\/demensdeum\/patterns\/-\/tree\/master\/interpreter\/csharp\" target=\"_blank\" rel=\"noopener\">https:\/\/gitlab.com\/demensdeum\/patterns\/-\/tree\/master\/interpreter\/csharp<\/a><\/p>\n<h3>Fontes<\/h3>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Interpreter_pattern\" target=\"_blank\" rel=\"noopener\">https:\/\/en.wikipedia.org\/wiki\/Interpreter_pattern<\/a> <br \/><a href=\"https:\/\/elm-lang.org\/\" target=\"_blank\" rel=\"noopener\">https:\/\/elm-lang.org\/<\/a><br \/>\n<a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/\" target=\"_blank\" rel=\"noopener\">https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>O que est\u00e1 inclu\u00eddo O padr\u00e3o Interpreter refere-se a padr\u00f5es de design comportamentais. Este padr\u00e3o permite implementar sua pr\u00f3pria linguagem de programa\u00e7\u00e3o trabalhando com uma \u00e1rvore AST, cujos v\u00e9rtices s\u00e3o express\u00f5es terminais e n\u00e3o terminais que implementam o m\u00e9todo Interpret, que fornece a funcionalidade da linguagem. Express\u00e3o terminal &#8211; por exemplo, constante de string &#8211;<a class=\"more-link\" href=\"https:\/\/demensdeum.com\/blog\/pt\/2022\/06\/24\/pattern-interpreter\/\">Continue reading <span class=\"screen-reader-text\">&#8220;Int\u00e9rprete de padr\u00f5es&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[61,52],"tags":[95],"class_list":["post-3131","post","type-post","status-publish","format-standard","hentry","category-techie","category-tutorials","tag-patterns","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"pt","enabled_languages":["en","ru","zh","de","fr","ja","pt","hi"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"ru":{"title":true,"content":true,"excerpt":false},"zh":{"title":true,"content":true,"excerpt":false},"de":{"title":true,"content":true,"excerpt":false},"fr":{"title":true,"content":true,"excerpt":false},"ja":{"title":true,"content":true,"excerpt":false},"pt":{"title":true,"content":true,"excerpt":false},"hi":{"title":false,"content":false,"excerpt":false}}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/3131","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=3131"}],"version-history":[{"count":15,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/3131\/revisions"}],"predecessor-version":[{"id":3886,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/3131\/revisions\/3886"}],"wp:attachment":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=3131"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=3131"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=3131"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}