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; } public class Prog {
public static double CoordX = 12.3; private int val;
public static void Main(String[] args) { X xval;
xval. }
}
deverá ser apresentada a lista de membros de instância do tipoX; 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 pro-duzido no editor. Na secção 3 serão fornecidos elementos sobre a implementação de cada funcionalidade.
Figura 1: Aspeto gráfico da aplicação e resultado de selecionar a opção “Run...”.
3
Descrição
3.1 Editor
O editor é composto por quatro componentes:
Tool bar Contém componentes para manipular: referências do assembly (combo box “Assembly Referen-ces” 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 componenteSystem.Windows.Forms.RichTextBox.
Visualização de erros É também utilizado o componenteRichTextBox, 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
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ávelp, 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 enun-ciada 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; } public class Prog {
public static double CoordX = 12.3; private int val;
public static void Main(String[] args) { X xval;
xval. }
}
o tipo da variável localxval é 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
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; } public class Prog {
public static double CoordX = 12.3; private int val;
public static void Main(String[] args) {
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 Ap-plication 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 atributoCachePath é 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 ();
namespace CSharpEditor {
public partial class CSharpEditorForm : Form { [ DllImport (" Kernel32 . dll ")]
static extern Boolean AllocConsole ();
private void CSharpEditorForm_Load ( 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; implemen-tação do tipoCSharpEditor.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 sugere-se a sugere-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.