Definição de um Subconjunto da Linguagem Java
B.2.2 Comandos C‘skip’ = skip
CD = accum(DD) CE = EE CC1 ‘;’ C2 = seq(CC1, CC2) C‘{’ C ‘}’ = makeBlock(CC)) C‘print’ E = output(EE)
Entre comandos, podem-se encontrar comandos vazios, declarações, blocos, sequências de comandos e comandos de impressão.
C‘while’ E C =makeBlock(
escape( loop(EE, escape(CC, ‘continue’)), ‘break’) )
C‘do’ C ‘while’ =makeBlock(
escape( loop(escape(CC, ‘continue’), EE), ‘break’) )
C‘for’ F C1 E C2 C3 =makeBlock(
escape(
for(CC1, EE, CC2, escape(CC3, ‘continue’)),
‘break’) )
Os laços de Java0 são while, do-while e for. A definição de cada um dos laços especifica os pontos de saída utilizados pelos sequenciadores break e continue.
C‘if’ E ‘then’ C1 ‘else’ C2 = makeBlock(choose(EE, CC1, C2))
C‘switch’ E CaseExps ‘default’ C = escape(
trap(E, SCCaseExps, CC), ‘break’
)
K‘case’ E C CaseExps = [(EE, seq(CC, CCaseExps)) • KCaseExps] K‘case’ E C = (EE, CC)
K = []
C‘case’ E C CaseExps = seq(CC, CCaseExps) C‘case’ E C = CC
Os comandos condicionais de Java0 são if-then-else e switch. A ausência da segunda alternativa daquele ou da alternativa default deste pode ser modelada pelo
uso do comando vazio e, por isso, não é explicitada nas equações semânticas. C‘break’ = throw(‘break’)
C‘continue’ = throw(‘continue’) C‘return’ E = resultIs(EE) C‘return’ = throw(‘return’)
Os sequenciadores de Java0 são break, continue e return.
B.2.3
Declarações
DD1 ‘;’ D2 = accum(elabSeq(DD1, DD2))
DType I = bind(I, ref(getDefault Type), Type) DType I ‘=’ E = bind(I, ref(deref(EE)), Type) DType I‘[]’ = bind(I, ref(getDefault Type), Type ‘[]’) DType I‘[]’ ‘=’ ‘{’ ArrayInitializer ‘}’ =
bind(I, ref(array(0,size values,values)), Type ‘[]’) where values = ADArrayInitializer
ADE ‘,’ ArrayInitializer = [EE • DArrayInitializer] ADE = EE
AD‘{’ ArrayInitializer ‘}’ = array(0,size values,values) where values = ADArrayInitializer
Java0 possui declarações de variáveis. Quando valores não são especificados, o valor default associado ao tipo da variável é armazenado.
Dvoid I ‘(’ DA ‘)’ Block = bind(I, parametrize(arg, escape(CBlock, ‘return’))) where arg = [(ref,‘this’) • DADA]
DType I ‘(’ DA ‘)’ Block = bind(I, parametrize(arg, valof(CBlock))) where arg = [(ref,‘this’) • DADA]
DAType I DA = ((I, value), DADA)
DAType I ‘[]’ FPar = ((I, value), DADA) DA = ()
Procedimentos e funções podem ser declarados. A diferença entre eles está no retorno. Procedimentos podem ser abandonados, enquanto funções retornam valores.
D‘class’ Id ‘{’ D ‘}’ =
ZD (λc o.elabRec(bind(Id, class(elabRec(c), elabRec(o)), static))) skip skip ZD1 ‘;’ D2 q = ZD1; ZD2 q
ZModifier Method q c o = q elabCol(c,DModifier Method) o Z‘static’ Variable q c o = q elabCol(c,D‘static’ Variable) o Z‘’ Variable q c o = q c elabCol(o,D‘’ Variable) o
A declaração de classes exige que as declarações de membros e atributos estáticos sejam separadas das demais.
B.2.4
Expressões
EI = lookup(I) EB = BB BInteger = int(Integer) BBoolean = bool(Boolean) BFloat = float(Float) BDouble = double(Double) B Long = long(Long) BChar = char(Char) BString = string(String) BByte = byte(Byte) BShort = short(Short)As expressões mais simples de Java0 são os literais e os acessos a variáveis.
EE1 O E2 = apply(OO, EE1, EE2)
EE1 O ‘=’ E2 = assign(EE1, apply(OO, EE1, EE2))
EE1‘[’ E2 ‘]’ = index(EE1, EE2)
Operações básicas como soma, subtração e testes de igualdade são realizados por meio do componente apply. Definições das operações são omitidas neste apêndice.
E‘fun’ E ‘.’ Id ‘(’ EA ‘)’ = apply(method, arg) where method = lookup(target, Id)
arg = [target • EAEA] target = EE
E‘static-fun’ E ‘(’ EA ‘)’ = apply(method, arg) where method = lookup(target, Id)
arg = [target • EAEA] target = lookup(EE, ‘class’)
E‘fun’ Id ‘(’ EA ‘)’ = apply(method, arg) where method = lookup(this, Id)
arg = [this • EAEA] this = value(‘this’)
E‘static-fun’ Id ‘(’ EA ‘)’ = apply(method, arg) where method = lookup(class, Id)
arg = [class • EAEA] class = value(‘class’) EAE EA = [EE • EAEA] EA = []
As chamadas de funções estáticas passam a própria classe como primeiro parâmetro. Isso é feito para manter uma certa semelhança com as demais chamadas de funções, as quais passam o próprio objeto target como primeiro parâmetro. No entanto, os bindings necessários para a aplicação das funções estáticas já são conhecidos no momento de sua declaração, logo é desnecessário passar a classe como parâmetro. Caso o método acessado seja redefinido por uma subclasse, no momento da chamada, o método encontrado pelo componente lookup é aquele pertencente à subclasse. Para acessar o método da superclasse, é necessário fazer a busca no pequeno environment que constitui o super.
EE ‘instanceof’ Id = apply(‘=’, getType(EE), string(‘id’)) E‘this’ = lookup(‘this’)
E‘super’ = lookup(lookup(‘this’),‘super’) EE ‘.’ Id = lookup(EE, Id)
Em Java0, é possível checar se um objeto é instância de uma determinada classe. Como toda expressão é avaliada dentro de uma função, o objeto corrente pode ser
acessado por meio do parâmetro this. Já o super, assim como outros atributos, pode ser encontrado no pequeno environment que constitui o objeto corrente.
E‘(’ Type ‘)’ E = cast(EE, string(Type))
where cast (e,t) = choose(apply(‘=’, getType(e), t), e, cast(super e, t)) super e = lookup(e, ‘super’)
A única coerção de tipo permitida em Java0 é o uso de um objeto com o tipo de uma de suas superclasses.
E‘new’ Id ‘{’ D ‘}’ = construct objDef []
where objDef = object(subclass(lookup(Id), ZD λc o.class(elabRec(c), elabRec(o)))) E‘new’ Id ‘(’ EA ‘)’ ‘{’ D ‘}’ = construct objDef EAEA
where objDef = object(subclass(lookup(Id), ZD λc o.class(elabRec(c), elabRec(o)))) E‘new’ Id ‘(’ EA ‘)’ = construct objDef EAEA
where objDef = object(lookup(Id))
construct objDef args = pipe(objDef, λobj.valof(seq(callConstructor, resultis(obj)))) where callConstructor = call(lookup(obj, ‘constructor’), args)
Ao se instanciar objetos, o membro construtor é executado e o resultado da instanciação é o próprio objeto.
E‘new’ Id ArrayIndex = newArray(reverse IArrayIndex 0)
where newArray es v = pipe(hd es, λe.newArray (tl es) (array(0, e, deref(e)))) newArray [] v = v
values n = [undefined • values (n -1)]
E‘new’ B ArrayIndex = newArray(reverse IArrayIndex 0)
where newArray es v = pipe(hd es, λe.newArray (tl es) (array(0, e, deref(e)))) newArray [] v = v
values n = [getDefault B • values (n -1)] I‘[’ E ‘]’ ArrayIndex = [EE • IArrayIndex] I‘[’ E ‘]’ = EE
A instanciação de arranjos exige que cada valor seja criado e armazenado na posi- ção correspondente. Note que é necessário obter o valor de variáveis com o componente derefpara determinar a quantidade de valores a serem passados ao componente array.
getDefault Integer = int(‘0’) getDefault Boolean = bool(‘false’) getDefault Float = float(‘0.0f’) getDefault Double = double(‘0.0d’) getDefault Long = long(‘0L’) getDefault Char = char(‘˘0000’) getDefault String = undefined getDefault Byte = byte(‘’0) getDefault Short = short(‘0’)
Para cada tipo primitivo de Java0 é definido um valor default, em geral o valor 0.
B.3
Exemplos
A Figura B.1 mostra um trecho de um programa Java0 e sua denotação representada por meio de componentes. Neste exemplo, está representada a semântica de dynamic dispatch. A classe A define o método f, cujo valor de retorno é 1. O objeto b é instância de uma subclasse anônima de A, que redefine o método f, cujo resultado passa a ser o valor de f na superclasse mais um. Como os métodos das subclasses prevalecem sobre os métodos da classe no momento da resolução de nomes, o valor impresso por esse trecho é 2.
A Figura B.2 mostra a semântica de uma construção switch em Java0. Neste exemplo, os dois cases são modelados por tuplas cujo primeiro elemento é o valor do case e o segundo é o comando a ser executado. Caso nenhum op tenha um valor diferente de “sum” e “sub”, o comando correspondente ao caso default é executado.
A Figura B.3 mostra a semântica de um exemplo de inner class em Java0. A classe B pode ser acessada como um campo da classe A, o que é feito na instanciação do objeto b. Durante a instanciação, primeiro o objeto é criado por meio da declaração de seus campos e depois o método construtor é chamado. O resultado da instanciação é o próprio objeto criado.
class A { int f () {return 1;} } . . . A b = new A { int f () { return super.f() + 1; } } print b.f(); . . . elabRec(bind(‘A’,
class(elabRec(skip), elabRec(f), static) ))
where f =bind(‘f’, proc(parametrize([], valof(resultIs(int(‘1’))) )))
. . .
bind(‘b’, object(subclass(lookup(‘A’), B)) where f = bind( ‘f’, proc(parametrize([],
valof(resultIs(v)) )), type( ‘A’))
B =class( elabRec(skip), elabRec(f)) v = apply(‘+’,
call(lookup(lookup(‘super’), ‘f’), []), int(‘1’))
output(apply(method, arg))
where method = lookup(target, ‘f’), target = lookup(‘b’)
args = [] . . .
Figura B.1: Exemplo de dynamic dispatch em Java0.
switch(op) { case “sum”: x = a + b; break; case “sub”: x = a - b; break; default: x = a; } escape(
trap(lookup(‘op’), [sum • sub], default) ‘break’
)
where sum = (string(‘sum’),
seq(assign(x, apply(‘+’, a, b)), jump(‘break’))) sub = (string(‘sum’), seq(assign(x, apply(‘-’, a, b)), jump(‘break’)) default = assign(x, b) a = lookup(‘a’) b = lookup(‘b’) x = lookup(‘x’)
class A { class B { . . . } } . . .
A.B b = new A.B()
elabRec(bind(‘A’,
class(elabRec(B), elabRec(skip), static) ))
where B = bind(‘B’,
class(elabRec(. . . ), elabRec(. . . ), static)) . . .
bind(‘b’, build, type(‘A.B’))
where build = pipe(AB, λo.valof(seq(cons, resultIs(o)))) AB = object(lookup(lookup(‘A’), ‘B’))
cons = call(lookup(o, ‘constructor’), []) Figura B.3: Exemplo de inner class em Java0.