Ambientes Virtuais de Execução Semestre Inverno 2012/13 Trabalho Final 1 Objectivos Este trabalho tem como objectivo a consolidação de conhecimentos dos mecanismos e construções do sistema de tipos do.net estudados nas aulas teóricas, nomeadamente a utilização de delegates, eventos, genéricos e reflexão. 2 Introdução Com o presente trabalho pretende-se desenvolver uma aplicação Windows Forms com funcionalidades de edição, compilação e execução de programas escritos na linguagem C#. A aplicação deverá suportar os seguintes requisitos: Capacidade de edição de ficheiro contendo código C#. Compilação (modo manual ou modo automático) para EXE ou DLL do ficheiro corrente. Os erros de compilação deverão ser apresentados no editor. Capacidade de Code Completion (funcionalidade equivalente ao Intellisense do Visual Studio), isto é, quando for digitado o caráter. deverá ser apresentada uma lista dos membros do objeto implícito ou, no caso de se tratar de um tipo, a lista de membros estáticos desse tipo. Exemplos: Se for digitado System.Console., deverá ser apresentada a lista de membros estáticos do tipo System.Console. Se for digitado: struct X { int i; X xval; xval. deverá ser apresentada a lista de membros de instância do tipo X; Execução do assembly caso este tenha um entry point (assembly EXE). A figura 1 ilustra o aspeto gráfico da aplicação, e também o resultado da execução de um ficheiro produzido no editor. Na secção 3 serão fornecidos elementos sobre a implementação de cada funcionalidade. 1
3 Descrição 3.1 Editor Figura 1: Aspeto gráfico da aplicação e resultado de selecionar a opção Run.... O editor é composto por quatro componentes: Tool bar Contém componentes para manipular: referências do assembly (combo box Assembly References e botões + e - ), compilar ficheiro fonte e executar assembly resultante (botões Compile... e Run... ), e botões para gestão dos ficheiros (botões New..., Load... e Save... ). Área de edição É utilizado o componente System.Windows.Forms.RichTextBox. Visualização de erros É também utilizado o componente RichTextBox, mas sem capacidade de edição. Status bar Visualização da linha e coluna do cursor no editor e visualização de mensagens de estado (por exemplo: ficheiro foi carregado no editor, o texto presente no editor foi gravado em ficheiro, entre outras). 3.2 Compilação Para compilar o ficheiro fonte C# deverá utilizar o tipo CSharpEditor.CompilerServices.Compiler (disponibilizado no anexo a este documento), que permite invocar programaticamente o compilador de C#. 3.3 Code Completion Como foi referido anteriormente, sempre que for digitado o caráter. deverão ser apresentados os membros do objeto ou tipo implícitos na consulta. Para apresentar esta lista poderá usar o componente ListBox, disponível no namespace System.Windows.Forms. A lista de membros é obtida fazendo introspeção ao código. Para esse efeito, deverá compilar o código ignorando a expressão de consulta presente na linha 2
Figura 2: Utilização da funcionalidade Code completion. corrente (pois está incompleta) e produzir o assembly a partir do restante código; de seguida, deverá obter, via instrospeção ao assembly compilado no passo anterior, os membros do objeto ou tipo. A figura 2 ilustra a utilização da funcionalidade Code completion para obter a lista de membros da variável p, do tipo Test.Program. Assuma que as variáveis locais são declaradas da seguinte forma: cada declaração de variável aparece numa linha distinta e a variável não é iniciada na declaração. Por isso, uma declaração de variável local tem a forma simplificada: <Type identifier> <Variable identifier> ;. Assuma também que a expressão de consulta consiste numa única linha contendo o código <Variable identifier>. ou <Type identifier>.. Além de permitir fazer Code Completion de membros de variáveis locais declaradas da forma enunciada no parágrafo anterior, deve ser dado o suporte de Code Completion sobre nomes que podem ser obtidos por introspeção (parâmetros do método, membros de instância e estáticos e nomes de tipos). Na secção seguinte são apresentados exemplos relativos a este ponto. 3.3.1 Obtenção do tipo das variáveis existente no código fonte Para obter a lista de membros a partir da consulta <Variable identifier>. ou <Type identifier>., terá que determinar o tipo do identificador. No exemplo apresentado anteriormente, struct X { int i; X xval; xval. o tipo da variável local xval é X. Na consulta System.Console. o tipo é System.Console. No caso de instropeção a uma variável local, o tipo é determinado fazendo uma análise sintática (parsing) ao código 3
fonte do método onde a variável foi declarada. Por simplicidade assume-se que as consultas sobre variáveis locais são sempre realizadas no scope onde as variáveis são declaradas. Continuando com o exemplo anterior, outras consultas possíveis incluem: struct X { int i; args. // Apresenta lista de membros do parâmetro args // Ou: Prog.CoordX. // Apresenta lista de membros do campo CoordX // Ou: public void Process() { val. // Apresenta lista de membros do campo this.val 3.3.2 Introspeção do assembly compilado A operação de Code Completion (usando o caráter. sobre uma variável ou tipo) resulta na compilação do ficheiro e posterior análise aos membros do tipo via introspeção do assembly. No entanto, na altura em que é realizado load ao assembly, a aplicação faz lock (Read lock) sobre o assembly, não permitindo atualizações posteriores a este ficheiro decorrentes de novas compilações que venham a ser realizadas. Para solucionar este problema, o código de inspeção do assembly deve ser executado num outro Application Domain, contruído com a opção Shadow copying ativada. Esta opção permite especificar que todos os assemblies presentes na diretoria base do Application Domain sejam copiados para outra diretoria. O troço de código seguinte ilustra a configuração desta opção: var setup = new AppDomainSetup { ApplicationName = "", ApplicationBase = < probing path >, ShadowCopyFiles = " true ", ShadowCopyDirectories = < probing path > [ CachePath = "D :\\ AnyPath \\ " ] ; A string <probing path> especifica a diretoria de onde se quer fazer shadow copying, por exemplo, a diretoria bin\degug da aplicação. O atributo CachePath é opcional na utilização; se não for especificada (opção recomendada), é usada uma cache própria que é gerida automaticamente pelo CLR. Este objecto setup é passado na construção do Application Domain. 3.4 Execução da aplicação Para executar a aplicação compilada, poderá usar o troço de código: var proc = new Process () ; proc. StartInfo. FileName = " something. exe "; proc. Start () ; proc. WaitForExit () ; var exitcode = proc. ExitCode ; proc. Close () ; Se pretender usar a consola, pode usar o seguinte código no evento Load da aplicação windows forms: 4
namespace CSharpEditor { public partial class CSharpEditorForm : Form { [ DllImport (" Kernel32. dll ")] static extern Boolean AllocConsole () ; private void C Shar pedi torf orm_ Loa d ( object sender, EventArgs e) { if (! AllocConsole () ) MessageBox. Show (" Failed to alloc console ");... 4 Código disponibilizado Como anexo a este documento, é disponibilizada uma solução do Visual Studio (VS2010), contendo o projeto: CSharpEditor Projecto onde deverão ser desenvolvidos os tipos que constituem a implementação. É disponibilizado o seguinte código base: interface gráfica da aplicação Windows Forms; deteção do caráter. e apresentação de uma List box na vizinhança do. ; atualização do status bar; implementação do tipo CSharpEditor.CompilerServices.Compiler e exemplos de utilização. 5 Testes Unitários No desenvolvimento do projecto sugere-se a utilização do framework de testes unitários NUnit (http: //www.nunit.org). O NUnit não está integrado no VS2010. Para integrar a execução dos testes sugerese a seguinte opção: Instalar e referenciar no projecto o assembly nunit.framework.dll. Instalar o plugin ReSharper (em http://www.jetbrains.com/resharper/download). Neste caso apenas está disponível uma versão de avaliação com licença para 30 dias. Quem estiver interessado em obter a licença anual atribuída ao ISEL, deverá contatar o docente. 6 Avaliação Na avaliação do trabalho são levados em conta os seguintes aspetos: organização e qualidade da solução; qualidade do relatório; teste dos componentes. 7 Prazo de Entrega O prazo de entrega do trabalho (relatório e código fonte) é o dia 16 de Fevereiro de 2013. 5 ISEL, 14 de Dezembro de 2012.