MyL é minha proposta de linguagem para aplicativos comerciais. Reúne conceitos de linguagens consagradas, conceitos de linguagens modernas e novas propostas.

MyL segue o paradigma imperativo com orientação a objetos. Mas a POO implementada em MyL possui várias diferenças em relação aos padrões de mercado para linguagens compiladas. Acredito que essas diferenças tragam maior produtividade e clareza ao código escrito.

MyL não é uma linguagem de script. É uma linguagem compilada e fortemente tipada, ainda assim, bastante versátil.

MyL NÃO é case-sensitive.

A implementação atual do compilador MyL possui um parser, um otimizador e um gerador de código.

O compilador de MyL não gera byte-code ou código nativo. Gera código-fonte em uma linguagem intermediária.

Uma implementação do compilador pode ser livremente baixada no SourceForge.

 

Programas em MyL

Um arquivo fonte de um programa escrito em MyL possui a extensão ".myl". Sua estrutura divide-se basicamente entre declarações e instruções, antes e após a palavra reservada do.

As declarações podem ser classificadas quanto à sua visibilidade. A visibilidade é definida em seções, e não individualmente como em Java.

 
public:
// Várias declarações públicas...

protected:
// Várias declarações protegidas...

private:
// Várias declarações privadas...

 

do

// Várias instruções imperativas...

 

 

As declarações são públicas por padrão, se nenhuma visibilidade tiver sido indicada.

O menor programa escrito em MyL (Hello World) começa com a instrução do.

 

do Writeln(‘Hello World’);

 

 

Características da Linguagem MyL

Assertivas

As assertivas servem para garantir pré-condições ou para escrever testes unitários em MyL.

Uma exceção é disparada quando a condição não é satisfeita. Essa exceção contém uma descrição textual da expressão que foi avaliada com seus valores. Opcionalmente pode ser fornecida uma mensagem (else).

 

assert 1 + 1 = 2;

assert 11 * 34 = 374;

assert Valor > 10 else ‘Valor fora da faixa’;

 

 

Matrizes e Arrays

Matrizes e arrays são declaradas usando colchetes. O tipo do vetor é dado pelos seus elementos. Um que contém elementos inteiros é um int[].

No exemplo a seguir, Z é um array de inteiros com dois elementos e A é uma matriz de 3 linhas e 3 colunas, com exceção da última linha que tem 4.

 

var z := [1, 2];

assert Length(z) = 2;

 

z[1] := 7;

 

var a := [[1, 2, 3], [3, 44, 2], [5, 66, 7, 8]];

assert Length(a) = 3;

 

var b: int[];

b := [1, 2, 3, 4];

 

 

Tipos básicos de dados

MyL suporta uma série de tipos básicos para valores inteiros, ponto-flutuante, caracteres etc.

 

// Tipo inteiro de 32 bits (-2147483648 a 2147483647)

var it1: int;

var it3: int = -1;

 

// Tipo inteiro grande de 64 bits (-2^63 a 2^63-1)

var bi1: bigint;

 

// Inteiro não sinalizado de 16 bits (0 a 65535)

var wd1: word;

 

// Inteiro não sinalizado de 32 bits (0 a 4294967295)

var ca3: card = MaxCard;

                  

// Inteiro não sinalizado de 8 bits (0 a 255)

var bt1: byte;

 

// Tipo lógico booleano (True ou False)

var bo1: bool = false;

 

// Valor de ponto flutuante (5.0*10^-324 a 1.7*10^308)

var fl1: float = 0;

 

// Data, Hora ou Data/Hora

var ti1: time = 2008.1.1;

 

// Um caractere

var ch1: char = 'a';

 

// Uma cadeia de caracteres

var st1: string = 'aaa';

 

// Tipo variante, que é compatível com qualquer outro tipo básico

var an1: any = 0;

an1 := 'teste';

an1 := 1900.1.1;

an1 := true;

 

 

Literais String multilinha

As constantes strings podem ser declaradas sem necessariamente terminar na mesma linha, sem emendas. As quebras de texto do editor são incluídas na string.

 

var S: string = 'Uma literal string em MyL pode

ocupar várias linhas do arquivo. Nesse caso,

ela irá incluir as quebras de linha, espaços

e tabulações do editor de texto.

Isso é interessante para escrever instruções

SQL, por exemplo.';

 

 

Literais para Data e Hora

MyL possui uma sintaxe própria para definir literais de tempo. Em outras linguagens é necessário utilizar alguma função ou método de construção.

O tempo é um tipo básico de dados distinto, não é um ponto-flutuante como em Delphi. Suporta operações básicas de adição de dias, diferença entre datas etc.

 

var D: time = 2008.1.1;

 

var T := 10:20:0;

 

var DT := 2008.09.06+08:14:00;
 

 

Tipos implícitos

O tipo da variável pode ser omitido na sua declaração se houver um valor inicial. Isso não quer dizer que a variável não tenha um tipo, ou que seja um variante. Significa que o tipo é inferido a partir do valor atribuído. O compilador na verdade escolhe o melhor tipo para a variável que possa conter o valor atribuído.

A linguagem continua sendo fortemente tipada, pois não é possível alterar o tipo da variável nem atribuir outros tipos de valores. Essa flexibilidade só existe no momento da declaração.

 

// Valores na faixa de MinInt a MaxInt são Int32

var ait1 := 0;

var ait2 := -1;

var ait5 := ait1 + ait2;

 

// Valores fora da faixa de MinInt a MaxInt sao Int64

var abi1 := 60011 * 1024 * 1024 * 1024;

var abi2 := -6 * 1024 * 1024 * 1024;

 

// Lógicos

var abo1 := true;

var abo2 := false;

var abo3 := 1 = 1;

 

// Valores reais

var afl1 := 10 / 3;

var afl2 := afl1 * 3;

 

// Data, Hora e Data/Hora

var ati1 := 002000.002.028;

var ati2 := 1:1:1;

 

// String

var ast1 := '123'#65#66'.';

 

 

Pontos de extensão

Os pontos de extensão permitem aumentar a utilidade de tipos de dados já existentes. É possível criar novos métodos para outras classes sem interferir na declaração original.

Até mesmo tipos primários sem métodos podem passar a tê-los.

 

extension MinhaString for string as

  Maiusculo(this) return UpperCase(this);

end;

 

do

var s := 'teste';

assert s.Maiusculo() = 'TESTE';

 

assert 'aBc'.Maiusculo() = 'ABC';

 

 

Operadores de bit (Bitwise)

Os operadores lógicos podem usados também como operadores bit-a-bit.

 

assert (1 and 3) = 1;

assert (1 and 2) = 0;

assert (1 or 3) = 3;

assert (1 or 2) = 3;

 

var B: byte = 255;

assert not B = 0;

 

 

Conversões de tipos (Type casts)

Usam-se os tipos básicos como funções de conversão de tipos em MyL. As operações de conversão são seguras. Conversões impossíveis causam exceções de tempo de compilação ou execução, como no caso da conversão de objetos de classes incompatíveis.

 

// Com tipos básicos

assert char(65) = 'A';

assert int('A') = 65;

assert float('A') = 65;

assert not bool(#0);

assert bool(#1);

 

// Com objetos

var o: object = new Coisa;

Coisa(o).Valor := 0;

assert Coisa(o).Valor = 0;

Coisa(o).Valor := 10;

assert Coisa(o).Valor = 10;

assert o is Coisa;

 

 

Verificação estática e dinâmica de tipos

O tipo dos valores, variáveis e expressões podem ser testados a qualquer momento com o operador is.

Para tipos básicos como valores inteiros, reais e caracteres, o teste indicará se o valor está na faixa suportada pelo tipo.

 

// Verificação estática de tipos

assert 1 is byte;

assert 1 is int;

assert 1 is float;

assert 1 is byte;

assert -1 is int;

assert not (1.1 is int);

assert 'A' is char;

assert 'A' is string;

assert 'AA' is string;

assert not ('AA' is char);

 

// Verificação dinâmica

var i: int = 255;

assert i is byte;

i++;

assert not (i is byte);

assert i is int;

 

 

Enumerados

 

enum Sexo as (Masculino, Feminino, Indefinido);

 

enum EstadoCivil as (Casado: 1, Solteiro: 2, Divorciado: 3);

 

do

var S: Sexo = Sexo.Feminino;

S := Masculino;

var E := EstadoCivil.Casado;

var F := Casado;

var X: (BW, Color, Gray) = Gray;

X := BW;

var Y: (Left, Right, Center) = Center;

Y := Left;

var Z: Sexo;

Z := Feminino;

 

assert Sexo.Min = Masculino;

assert Sexo.Max = Indefinido;

 

assert Z.Next = Indefinido;

Z++;

assert Z = Indefinido;

assert Z.Next = Masculino;

Z++;

assert Z = Masculino;

assert Z.Prior = Indefinido;

Z--;

assert Z = Indefinido;

 

 

Estruturas de controle

 

if <condição> then

  <instrução>;

 

try

  <instruções,...>

except

  <instruções,...>

finally

  <instruções,...>

end;

 

for <iterador> := <primeiro> to <ultimo> do

  <instrução>;

 

break;

exit;

abort;

raise <string>;

continue;

return <valor>;

 

begin

  <instruções,...>

end;

 

while <condição> do

  <instrução>;

 

repeat

  <instruções,...>

until <condição>;

 

case <valor> of

  <alterativas,...>

else

  <instruções,...>

end;

 

foreach var <iterador> in <domínio> do

  <instrução>;

 

 

Operadores lógicos

 

// or, and, xor e eqv 

assert true or false = true;

assert true and false = false;

assert true xor false = true;

assert not true = false;

assert true eqv true = true;

assert true eqv false = false;

 

 

Operadores aritméticos

 

// operações básicas (+, -, *, /)

assert 3 + 5 = 8;

assert 3 - 5 = -2;

assert 3 * 5 = 15;

assert 3 / 5 = 0.6;

 

// divisão inteira

assert 10 div 3 = 3;

 

// resto da divisão

assert 10 mod 3 = 1;

 

// potenciação e radiciação

assert 3 ^ 2 = 9; // 3 elevado ao quadrado

assert 27 \ 3 = 3; // raiz cúbica de 27

 

 

Operador ternário IfThen

A linguagem C/C++ possui um único operador ternário (com 3 operandos) que tem a função especial de resultar um entre dois operandos de acordo com uma condição. Em outras linguagens esse operador foi implementado como uma função de 3 parâmetros que embute uma instrução IF-ELSE que retorna um ou outro valor. A vantagem do operador em C é que apenas o valor correspondente é avaliado. Se os operandos forem funções, apenas uma delas seria executada, poupando recursos de máquina.

MyL declara uma pseudo-função chamada IfThen, que segue o mesmo principio do operador de C.

 

var i := 0;

var a := ifthen(i <> 0, 10 / i, 0);

assert a = 0;

var b := ifthen(i = 0, 1);

assert b = 1;

 

 

Precedência dos operadores

O esquema de precedência de MyL retarda a solução de operações bit-a-bit e prioriza as operações relacionais, permitindo a construção de expressões lógicas com menor recorrência a parênteses.

 

if A and B or C = 3 or (A and 2) = 2 then

  ...

 

 

Permutação de variáveis

 

var I: int = 10;

var J: int = 20;

swap I, J;

 

assert I = 20 and J = 10;

 

 

Classes e Conceitos
Em MyL podemos definir classes puras e conceitos. Esses conceitos constituem um modelo Straight-to-the-point de programação, quer dizer, se você quer escrever um WebService, então declare um WebService, quer um teste, declare um Teste. Esse modelo traz grande produtividade e simplicidade do código.

 
// uma classe qualquer

class Conta as
  Saldo: Float;
  Debita(Valor: Float) do Saldo -= Valor;
end;

// uma classe persistente em banco de dados (entidade)

persistent Estado as
  Sigla: text field: 'UF';
  Nome: text;
end;

// um serviço

webservice Calculadora as
  Soma(A, B: int): int return A + B;
end;

 


WebServices
São simples como os WebServices devem ser. Com toda a demanda por serviços (SOA) e interoperabilidade, escrever WS deve ser uma tarefa simples e rápida. Por isso esse conceito é padrão em MyL.

 
// um serviço de calculadora
webservice Calculadora as
  Soma(A, B: int): int return A + B;
end;

// um serviço para acessar as funcionalidades da classe Cliente
webservice ClienteWS for Cliente;

// a classe persistente Cliente estende a classe Pessoa
persistent Cliente from Pessoa as
public:
  CNPJ: text;
  UltimaCompra: date;
end;

 


Queries

 
query from Pessoa select Nome,count(),max(Ender.Cid.Habitantes)
  where Nome=Ender.Numero group by Nome order by Ender.Numero;

query from P:Pessoa,E:P.Ender select N:P.Nome;

query from Pessoa select nomeuf:Nome, nomecidade:Ender.Cid.Nome;

query from Pessoa select Nome, Nome + '.' + Ender.Cid.Nome;

query from Pessoa select Ender.Cid.Nome;

query from p:Pessoa, a:p.Ender.Cid, b:a.Est lj c:Pessoa on
  c.Ender.Cid.Est=b select nr:1234, f0:p, f1:a, f2:a.Est.Nome,
  f3:b.Nome, f4:c.Ender.Numero, f5:c.Ender.Logradouro;

query update Estado set Nome:='' where Nome='';

persistent Estado as
  Nome: text read 'teste';
end;

persistent Cidade as
  Est: Estado;
  Nome: text;
  Habitantes: int;
end;

persistent Endereco as
  Logradouro: text;
  Numero: text;
  Cid: Cidade;
end;

persistent Pessoa as
  Nome: text;
  Ender: Endereco;
  Telefone: text;
  Nascimento: date hidden;
end
table: 'PES';


Outros exemplos

 
public:

persistent Estado as
  Nome: text read 'teste';
end;

query update Estado set Nome:='' where Nome='';

storage RH url: 'mssql:northwind';

persistent Cidade as
  Est: Estado;
  Nome: text;
  Habitantes: int;
end;

persistent Endereco as
  Logradouro: text;
  Numero: text;
  Cid: Cidade;
end;

persistent Pessoa as
  Nome: text;
  Ender: Endereco;
  Telefone: text;
  Nascimento: date hidden;
end
table: 'PES';

query from Pessoa select Nome,count(),max(Ender.Cid.Habitantes)
  where Nome=Ender.Numero group by Nome order by Ender.Numero;

query from P:Pessoa,E:P.Ender select N:P.Nome;

query from Pessoa select nomeuf:Nome, nomecidade:Ender.Cid.Nome;

query from Pessoa select Nome, Nome + '.' + Ender.Cid.Nome;

query from Pessoa select Ender.Cid.Nome;

query from p:Pessoa, a:p.Ender.Cid, b:a.Est lj c:Pessoa on
  c.Ender.Cid.Est=b select nr:1234, f0:p, f1:a, f2:a.Est.Nome,
  f3:b.Nome, f4:c.Ender.Numero, f5:c.Ender.Logradouro;

// -------------------------------------------

persistent Cliente from Pessoa as
public:
  CNPJ: text;
  UltimaCompra: date;
end;

webservice ClienteWS for Cliente;

webservice Calculadora as
  Soma(A, B: int): int return A + B;
end;

// -------------------------------------------

class Contas as
  JaMexi() abstract;
end;

persistent ContaPagar from Contas as
  Emissao: date required;
  Vencimento: date required field: 'DTVENC';
  Valor: float check: Valor >= 0;
  Credor: Pessoa lookup: Credor.Nome;
  Status: (EmAberto, Quitado, Suspenso) = EmAberto;
  Pagamento: date check: Pagamento >= Emissao;
  Tag: int transient;

  DiaBase: int = 10 static;

  PraLer1: int read DiaBase;
  PraLer2: int read GetDiaBase;

  PraEscrever1: int write SetDiaBase;
  ///PraEscrever2: int write do DiaBase := PraEscrever2 * 2;

  PraLerEscrever: int read GetDiaBase write SetDiaBase;
  ///PraLerEscrever: int read DiaBase / 2 write do DiaBase := PraEscrever2 * 2;

  LerSomente: int = 54 read;
  EscreverSomente: int write;

  Today(): date return 2001.01.01;
  Time(): date return 00:00:00;
  Now(): date return 2001.01.01+00:00:00;

  Vencida(): bool return Status = EmAberto and Vencimento < Today();

  private:
  SetDiaBase(NovoDia: int) do DiaBase := NovoDia;
  GetDiaBase(): int return DiaBase;

  TodasEmAberto(Inicio, Fim: date): ContaPagar[] static
    return nil;///query from ContaPagar where Status = EmAberto and
      Vencimento in [:Inicio .. :Fim];

  TotalEmAberto(): float static
    return nil;///query from ContaPagar select sum(Valor) where Status = EmAberto;

  QuitaTudo(Credor: Pessoa) static do query update ContaPagar
    set Status := Quitado where Credor = :Credor;

  ExpurgaAntigos(AntesDe: date) static do
    query delete ContaPagar where Status in [Quitado, Suspenso] and
      Pagamento < :AntesDe;

  PensaDepois1() virtual abstract;
  PensaDepois2() abstract;

  PodeMexer(): int virtual return Tag;

  Processa(A, B: int): int do
  begin
    var C := A + B;

    a:=0;///

    return C;
  end;

  JaMexi() override do
    Status := EmAberto;
end
table: 'PAG';

query TotalPorUF(UF: text)
from c:Cliente lj p:ContaPagar lj g:ContaPagar lj i:c.Cid
select c.Ender.Numero, c.Cid.Est.Nome, c.UF, sum(p.Valor)
where p.Credor = c group by c.UF;
///query TotalPorUF(UF: text) from c:Cliente lj i:c.Cid;

crud CtaPagar for ContaPagar;

webservice ContaPagarWS for ContaPagar;