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;