SlideShare uma empresa Scribd logo
Criando sua própria
linguagem de programação
Dev In Sampa
São Paulo, 28 de novembro de 2009
Por quê?


Cada nova linguagem é um campo aberto para
livre experimentação

Compilação é uma arena em que todas as suas
habilidades são necessárias
A verdade verdadeira

“Por que escrever um programa se você pode
escrever um programa para escrever um
programa?”

                          — Autor desconhecido



A verdade verdadeira é que é divertido ;)
Na prática

Você pode usar um parser mais sofisticado para
suas DSLs

Você pode resolver problemas de portar código de
um domínio para outro com um tradutor

Você pode usar um interpretador para construir
geradores mais sofisticados
Na pior das hipóteses...


“Se uma linguagem não é capaz de afetar o modo
como você pensa sobre programação, não vale a
pena aprendê-la”

                                  — Alan Perlis
Um pouco de conceitos
Linguagem


“Uma notação para escrever programas, que são
especificações para a computação de uma
algoritmo”

                                  — Wikipedia
Elementos


Sintaxe: o que é escrito, descrita em uma
gramática formal

Semântica: o que isso significa, especificado em
termos de formalizações de compilação e
execução
Gramáticas formais


Value ← [0-9]+ / '(' Expr ')'
Product ← Value (('*' / '/') Value)*
Sum ← Product (('+' / '-') Product)*
Expr ← Sum
Do texto à execução
  CÓDIGO FONTE              SAÍDA

              PARSING

 ANÁLISE LÉXICA           COMPILADOR
                        INTERPRETADOR
                           TRADUTOR
     TOKENS



ANÁLISE SINTÁTICA           AST
Introduzindo “Mirror”
Inspiração

Sintaxe baseada em Smalltalk e IO

Slot-based como Self

Forte e dinamicamente tipada

Interpretada, via bytecodes
Mirror
World mirrorInto: "Fib".


Fib set: "of:" to: [ n |
     n <= 2
       ifTrue: [ 1. ]
       ifFalse: [ (of: n - 1) + (of: n - 2). ].
].


(Fib of: 10) transcribeAndBreak.
Análise

Via Treetop, um packrat parser em Ruby

  PEGs

  Análise versus geração

  Sem ambigüidades

Gera uma árvore sintática que é compilada para
uma representação em bytecodes
AST #1


(Fib of: 2 + 3)
  transcribeAndBreak.
AST #2


(Fib of: 2 + 3)
  transcribeAndBreak.
Bytecode

push 3
push 2
send +
load Fib
send of:
send transcribeAndBreak
pop
A gramática
Blocos básicos
grammar Mirror


  rule statements
      (spaces? statement spaces? "." spaces?)* <Statements>
  end


  rule statement
      message_expression
  end


  rule message_expression
      keyword_expression / binary_expression / unary_expression
  end


  # ...


end
Keywords

grammar Mirror


  rule keyword_expression
      variable:binary_expression?
        keywords:(spaces? keyword spaces expression:binary_expression)+
          <KeywordExpression>
  end


  # Account deposit: 100 from: user.
  # ...


end
Expressões binárias
grammar Mirror


  rule binary_expression
      variable:unary_expression spaces?
        selector:binary_selector spaces?
        expression:binary_expression <BinaryExpression> /
      unary_expression
  end


  # 2 + 3 * (account balance).
  # ...


end
Expressões unárias
grammar Mirror


  rule unary_expression
        variable:primary
          selectors:(spaces selector:identifier !colon)+
            <UnaryExpression> /
        primary
  end


  # (Account current balance) transcribeAndBreak.
  # ...


end
Juntando as peças
irb> MirrorParser.new.parse('2 + 3.')


SyntaxNode+Statements offset=0, "2 + 3." (build):
  SyntaxNode+Statements0 offset=0, "2 + 3." (statement):
    SyntaxNode+BinaryExpression0+BinaryExpression offset=0, "2 + 3":
      SyntaxNode+IntegerLiteral offset=0, "2" (build):
        SyntaxNode offset=0, "2"
      SyntaxNode+Spaces2 offset=1, " ":
      SyntaxNode offset=2, "+":
        SyntaxNode offset=2, "+"
      SyntaxNode+IntegerLiteral offset=4, "3" (build):
        SyntaxNode offset=4, "3"
Convertendo a AST
Blocos básicos
#     rule statements
#         (spaces? statement spaces? "." spaces?)* <Statements>
#     end


module Statements
    def build
       elements.collect do |element|
            Ast::Statement.new(element.statement.build)
       end
    end
end


class Statement
    def initialize(expression)
       @expression = expression
    end
end
Expressões binárias
#     rule binary_expression
#         variable:unary_expression spaces?
#           selector:binary_selector spaces?
#           expression:binary_expression <BinaryExpression> /
#         unary_expression


module BinaryExpression
    def build
       Ast::Message.new(variable.build, selector.text_value, expression.build)
    end
end


class Message
    def initialize(target, selector, *arguments)
       @target = target
       @selector = selector
       @arguments = arguments
    end
end
Juntando as peças

irb> MirrorParser.new.parse('2 + 3.').build


[
    #<Ast::Statement
      @expression =
        #<Ast::Message
          @selector = "+",
          @target = #<Ast::Literal @value = "2", @type = :integer>,
          @arguments = [#<Ast::Literal @value = "3", @type = :integer>]>>
]
Geração de código
Double dispatch
class CodeGenerator


  def initialize(ast)
      @ast = ast
  end


  def generate
      @ast.collect { |statement| generate_any(statement) }.flatten
  end


  def generate_any(ast)
      send("generate_#{ast.class.name.demodulize.underscore}", ast)
  end


  # ...


end
Blocos básicos
class CodeGenerator


  def generate_statement(ast)
      ([generate_any(ast.expression)] + [Bytecode::Pop.new]).flatten
  end


  def generate_variable(ast)
      Bytecode::Load.new(ast.name)
  end


  # ...


end
Mensagens
class CodeGenerator


  def generate_message(ast)
      instructions = []
      ast.arguments.reverse.each do |argument|
        instructions += [generate_any(argument)].flatten
      end
      instructions += [generate_any(ast.target)].flatten
      instructions << Bytecode::Message.new(ast.selector)
      instructions
  end


  # ...


end
Bytecodes
class Pop
  def inspect
      "pop"
  end
end


class Message
  def initialize(selector)
      @selector = selector
      @selector_name = get_selector_name(selector)
      @selector_method = get_selector_method(selector)
      @arity = get_selector_arity(selector)
  end
  # ...
end
Juntando as peças

irb> ast = MirrorParser.new.parse('2 + 3.').build


irb> CodeGenerator.new(ast).generate


[
    push 3,
    push 2,
    send +,
    pop
]
Modelo de execução
Containers & Slots
   ACCOUNT

   BALANCE           0

    DEPOSIT:   BLOCK CONTEXT

   WITHDRAW:   BLOCK CONTEXT

     USER          USER
Universe & World
  UNIVERSE         WORLD

   WORLD       MIRRORINTO:

   ERROR           SET: TO:
Detalhes

O envio de mensagens acontece em um contexto
que é gerado para cada mensagem

Blocos geram contextos empilhados

O interpretador percorre os contextos até
encontrar o objeto apropriado para enviar a
mensagem
Máquina virtual
Máquina Virtual
class VM


  def initialize(instructions)
      @instructions = instructions
  end


  def run
      reset_instruction_pointer
      while has_instructions?
        execute(next_instruction)
      end
  end


  # ...


end
Máquina Virtual
class VM


  def execute(instruction)
      case instruction
      when Bytecode::Implicit
        stack_push_and_wrap(current_context)
      when Bytecode::Pop
        stack.pop
      when Bytecode::Push
        stack_push_and_wrap(instruction.value)
      when Bytecode::Load
        stack_push_and_wrap(walk_contexts(instruction.name))
      # ...
      end
  end


end
Juntando as peças

irb> Interpreter.run(true, "World offload: 2 + 2.")


[4]


irb> Interpreter.run(true, "World offload: [ 2 + 2. ] value.")


[4]
Próximos passos
Próximos passos
Arrays

Inlining de mensagens comuns

  Primitivas: + - * / at: at:put:

  ifTrue:ifFalse et al

  to:do et al

Melhor uso de blocos
LLVM

Uma estratégia de compilação

Um conjunto de instruções virtualizado

Uma infra-estrutura de compilação

Um conjunto de ferramentas
LLVM

Efetivamente uma DSL para geração de código
intermediário otimizado e portável

Estático ou JIT

Usado por MacRuby, Rubinius, Unladden
Swallow e outros
LLVM: Uso

Transformar slots de código em funções

Transformar closures em funções quando não
fizer sentido que os mesmos sejam inline

Compilar o próprio interpretador para ser
parcialmente jitted
LLVM: Uso

module = LLVM::Module.new("mirror")
type = Type::function(MACHINE_WORD, [])
function = module.get_or_insert_function("main", type)


entry_block = function.create_block
exit_block_true = function.create_block
exit_block_false = function.create_block


builder = entry_block.builder
cmp = builder.icmp_sgt(-1.llvm, 1.llvm)
builder.cond_br(cmp, exit_block_true, exit_block_false)
LLVM: Uso


builder = exit_block_true.builder
builder.return(1.llvm)


builder = exit_block_false.builder
builder.return(0.llvm)


ExecutionEngine.get(module)
ExecutionEngine.run_autoconvert(function)
Questões?

@rferraz
http://logbr.reflectivesurface.com

Mais conteúdo relacionado

PDF
Como Construir um Compilador cap-1
Maellson Marques
 
PPTX
DSL - Como construir uma linguagem em 5 minutos
Opensoft SA
 
PDF
Como Construir um compilador-cap 2
Maellson Marques
 
PDF
Conhecendo a JSR 223: Scripting for the Java Platform
Milfont Consulting
 
PDF
TechEd Brasil 2011: WEB 302 - Presente e futuro da linguagem de programação J...
Rogério Moraes de Carvalho
 
PDF
Node.JS - Campus Party Brasil 2011
Emerson Macedo
 
PDF
TechEd Brasil 2011: DEV 303 - Atualizando suas habilidades de programação com...
Rogério Moraes de Carvalho
 
PDF
Palestra Ruby
Cássio Marques
 
Como Construir um Compilador cap-1
Maellson Marques
 
DSL - Como construir uma linguagem em 5 minutos
Opensoft SA
 
Como Construir um compilador-cap 2
Maellson Marques
 
Conhecendo a JSR 223: Scripting for the Java Platform
Milfont Consulting
 
TechEd Brasil 2011: WEB 302 - Presente e futuro da linguagem de programação J...
Rogério Moraes de Carvalho
 
Node.JS - Campus Party Brasil 2011
Emerson Macedo
 
TechEd Brasil 2011: DEV 303 - Atualizando suas habilidades de programação com...
Rogério Moraes de Carvalho
 
Palestra Ruby
Cássio Marques
 

Mais procurados (18)

PDF
Introdução a JavaScript
Bruno Catão
 
PDF
BDD: Torne viva a documentação de seus sistemas
Vitor Mattos
 
PPTX
Delphi Parallel Programming Library
Mario Guedes
 
PPTX
Testes com javascript
Laís Lima
 
PDF
Delphi Conference 2012 - Programação Baseado em Regras com RTTI
Mario Guedes
 
PDF
Xdebug seus problemas acabaram - tdc floripa 2017
Vitor Mattos
 
PDF
JavaScript: agora é sério
Luciano Ramalho
 
PPT
Aula2
fkimura
 
PPTX
Processo de Desenvolvimento de Software - Linguagens Imperativas x Declarativas
Natanael Simões
 
PDF
Apostila de Introdução ao C#.net
Andre Nascimento
 
PPTX
Processo de Desenvolvimento de Software - Programação
Natanael Simões
 
PDF
Delphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-Thread
Mario Guedes
 
PDF
O futuro do elephante: as promessas do php para 2019
Cassio Santos
 
PDF
F I C+ + L P 05
t34m0nana
 
ODP
tmn - Introdução ao JavaScript
Claudio Gamboa
 
PDF
Zephir
Luiz Gavinho
 
PDF
Testes unitários como ferramentas de design de código
Paula Grangeiro
 
Introdução a JavaScript
Bruno Catão
 
BDD: Torne viva a documentação de seus sistemas
Vitor Mattos
 
Delphi Parallel Programming Library
Mario Guedes
 
Testes com javascript
Laís Lima
 
Delphi Conference 2012 - Programação Baseado em Regras com RTTI
Mario Guedes
 
Xdebug seus problemas acabaram - tdc floripa 2017
Vitor Mattos
 
JavaScript: agora é sério
Luciano Ramalho
 
Aula2
fkimura
 
Processo de Desenvolvimento de Software - Linguagens Imperativas x Declarativas
Natanael Simões
 
Apostila de Introdução ao C#.net
Andre Nascimento
 
Processo de Desenvolvimento de Software - Programação
Natanael Simões
 
Delphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-Thread
Mario Guedes
 
O futuro do elephante: as promessas do php para 2019
Cassio Santos
 
F I C+ + L P 05
t34m0nana
 
tmn - Introdução ao JavaScript
Claudio Gamboa
 
Zephir
Luiz Gavinho
 
Testes unitários como ferramentas de design de código
Paula Grangeiro
 
Anúncio

Destaque (12)

PDF
Crie sua Linguagem de Programação com XText
Michel Albonico
 
PDF
A linguagem de programação Erlang
elliando dias
 
PPTX
Geração de código linguagem c
Jefferson Bessa
 
PDF
Arquitetura do coprocessador Intel® Xeon Phi™ - Intel Software Conference 2013
Intel Software Brasil
 
PDF
Algoritmos Gulosos - Troco Mínimo
Gabriel Albuquerque
 
PDF
Como criar seu próprio Framework
Hiarison Gigante
 
ODP
Javascript para adultos
Guilherme Blanco
 
PDF
ΟΡΘΟΔΟΞΙΑ ΚΑΙ ΑΙΡΕΣΙΣ - ΕΚΔΟΣΕΙΣ ΠΕΡΙΟΔΙΚΟΥ Ο ΑΓΙΟΡΕΙΤΗΣ - ΑΘΗΝΑΙ 1982
Spyridon Voykalis
 
PDF
Aula 8 - Lógica de Programação - Variáveis, Tipos de dados e Operadores
André Constantino da Silva
 
PDF
JavaFX: A nova biblioteca gráfica da plataforma Java
jesuinoPower
 
PPT
Javascript levado a serio
Jaydson Gomes
 
PPTX
Campanha da fraternidade 2017 cf 2017 biomas brasileiros resumo do texto base
Antonio De Assis Ribeiro
 
Crie sua Linguagem de Programação com XText
Michel Albonico
 
A linguagem de programação Erlang
elliando dias
 
Geração de código linguagem c
Jefferson Bessa
 
Arquitetura do coprocessador Intel® Xeon Phi™ - Intel Software Conference 2013
Intel Software Brasil
 
Algoritmos Gulosos - Troco Mínimo
Gabriel Albuquerque
 
Como criar seu próprio Framework
Hiarison Gigante
 
Javascript para adultos
Guilherme Blanco
 
ΟΡΘΟΔΟΞΙΑ ΚΑΙ ΑΙΡΕΣΙΣ - ΕΚΔΟΣΕΙΣ ΠΕΡΙΟΔΙΚΟΥ Ο ΑΓΙΟΡΕΙΤΗΣ - ΑΘΗΝΑΙ 1982
Spyridon Voykalis
 
Aula 8 - Lógica de Programação - Variáveis, Tipos de dados e Operadores
André Constantino da Silva
 
JavaFX: A nova biblioteca gráfica da plataforma Java
jesuinoPower
 
Javascript levado a serio
Jaydson Gomes
 
Campanha da fraternidade 2017 cf 2017 biomas brasileiros resumo do texto base
Antonio De Assis Ribeiro
 
Anúncio

Semelhante a Criando sua própria linguagem de programação (20)

PDF
O que mudou no Ruby 1.9
Nando Vieira
 
ODP
Palestra cbq
Rildo Pragana
 
ODP
Aula c++ estruturas de dados
Jean Martina
 
KEY
Programação Orientada a Testes
Gregorio Melo
 
PPTX
JS Experience 2017 - WebAssembly na Prática
iMasters
 
PPT
Redes 1 - Sockets em C#
Marcelo Charan
 
PPTX
Introdução ao CMake
Paulo Remoli
 
PDF
Minicurso Ruby on Rails
Maurício Eduardo
 
PDF
SOLID através de BDD: um guia prático para rubistas
lucashungaro
 
PPT
Introdução a conceitos e a Praticas de Programação
FlavioPNascimento
 
PDF
Ruby & Rails
Sergio Henrique
 
PPTX
TypeScript - Campus party 2013
Giovanni Bassi
 
PDF
Escrevendo modulos python com rust
Bruno Rocha
 
PDF
Minicurso Python
guestac3de
 
PDF
Trabalho
carolrazera
 
PDF
Minicurso kotlin no desenvolvimento mobile - UTFPR
Lucas Antonio Ramos Sartori
 
PDF
Minicurso kotlin UTFPR
Rafael Reynoud Benetti
 
PDF
Cool 3 assembly para linux
Luiz Vieira .´. CISSP, OSCE, GXPN, CEH
 
PPTX
Microsoft S2B - C# ASP.NET
philipsoares
 
PPT
Introdução Ruby 1.8.7 + Rails 3
Régis Eduardo Weizenmann Gregol
 
O que mudou no Ruby 1.9
Nando Vieira
 
Palestra cbq
Rildo Pragana
 
Aula c++ estruturas de dados
Jean Martina
 
Programação Orientada a Testes
Gregorio Melo
 
JS Experience 2017 - WebAssembly na Prática
iMasters
 
Redes 1 - Sockets em C#
Marcelo Charan
 
Introdução ao CMake
Paulo Remoli
 
Minicurso Ruby on Rails
Maurício Eduardo
 
SOLID através de BDD: um guia prático para rubistas
lucashungaro
 
Introdução a conceitos e a Praticas de Programação
FlavioPNascimento
 
Ruby & Rails
Sergio Henrique
 
TypeScript - Campus party 2013
Giovanni Bassi
 
Escrevendo modulos python com rust
Bruno Rocha
 
Minicurso Python
guestac3de
 
Trabalho
carolrazera
 
Minicurso kotlin no desenvolvimento mobile - UTFPR
Lucas Antonio Ramos Sartori
 
Minicurso kotlin UTFPR
Rafael Reynoud Benetti
 
Cool 3 assembly para linux
Luiz Vieira .´. CISSP, OSCE, GXPN, CEH
 
Microsoft S2B - C# ASP.NET
philipsoares
 
Introdução Ruby 1.8.7 + Rails 3
Régis Eduardo Weizenmann Gregol
 

Último (16)

PPTX
Computacao-e-Tecnologias-Digitais-Por-Que-Aprender.pptx
RobertaOliveiradaFon1
 
PPTX
aplicativopenseira.pptx Aplicativo que organiza Pensamentos - Peça Publicitária
StelaNorie1
 
PPTX
22 - Lógica de Programação com Portugol.pptx
Anderson Maciel
 
PPTX
Desenvolvimento-de-Produtos-Inovadores.pptx
ssuser1d7565
 
PDF
Explorando o Futuro do Corpo: Implantes Neurais e o Biohacking dos Sentidos
cooperliora
 
PPTX
Curso de Java 1 - (Introdução Geral).pptx
Anderson Maciel
 
PPTX
Curso de Java 6 - (Números, Data e Hora).pptx
Anderson Maciel
 
PPTX
Curso de Java 5 - (Strings) Tipo de Dados.pptx
Anderson Maciel
 
PPTX
Gestão de Mudanças - Os maiores desafios da Gestão de Mudanças e Gestão de Pr...
Gateware Group
 
PPTX
Gestão de Mudanças - Fases do processo de mudança organizacional
Gateware Group
 
PPTX
Curso de Java 4 - (Orientação a Objetos).pptx
Anderson Maciel
 
PPTX
21 - Lógica de Programação com Portugol.pptx
Anderson Maciel
 
PPTX
Curso de Java 7 - (ArrayList, Collections,(Set, List, Queue, Map)).pptx
Anderson Maciel
 
PPTX
Curso de Java 2 - (PrimeiroPrograma, Variáveis, Tipos e Operadores.pptx
Anderson Maciel
 
PPTX
Curso de Java 3 - (Estruturas de Controle, Decisão, Loop, Procedimento).pptx
Anderson Maciel
 
PDF
Certificado em Redes Neurais Artificiais em Python
CaioSilva506151
 
Computacao-e-Tecnologias-Digitais-Por-Que-Aprender.pptx
RobertaOliveiradaFon1
 
aplicativopenseira.pptx Aplicativo que organiza Pensamentos - Peça Publicitária
StelaNorie1
 
22 - Lógica de Programação com Portugol.pptx
Anderson Maciel
 
Desenvolvimento-de-Produtos-Inovadores.pptx
ssuser1d7565
 
Explorando o Futuro do Corpo: Implantes Neurais e o Biohacking dos Sentidos
cooperliora
 
Curso de Java 1 - (Introdução Geral).pptx
Anderson Maciel
 
Curso de Java 6 - (Números, Data e Hora).pptx
Anderson Maciel
 
Curso de Java 5 - (Strings) Tipo de Dados.pptx
Anderson Maciel
 
Gestão de Mudanças - Os maiores desafios da Gestão de Mudanças e Gestão de Pr...
Gateware Group
 
Gestão de Mudanças - Fases do processo de mudança organizacional
Gateware Group
 
Curso de Java 4 - (Orientação a Objetos).pptx
Anderson Maciel
 
21 - Lógica de Programação com Portugol.pptx
Anderson Maciel
 
Curso de Java 7 - (ArrayList, Collections,(Set, List, Queue, Map)).pptx
Anderson Maciel
 
Curso de Java 2 - (PrimeiroPrograma, Variáveis, Tipos e Operadores.pptx
Anderson Maciel
 
Curso de Java 3 - (Estruturas de Controle, Decisão, Loop, Procedimento).pptx
Anderson Maciel
 
Certificado em Redes Neurais Artificiais em Python
CaioSilva506151
 

Criando sua própria linguagem de programação

  • 1. Criando sua própria linguagem de programação Dev In Sampa São Paulo, 28 de novembro de 2009
  • 2. Por quê? Cada nova linguagem é um campo aberto para livre experimentação Compilação é uma arena em que todas as suas habilidades são necessárias
  • 3. A verdade verdadeira “Por que escrever um programa se você pode escrever um programa para escrever um programa?” — Autor desconhecido A verdade verdadeira é que é divertido ;)
  • 4. Na prática Você pode usar um parser mais sofisticado para suas DSLs Você pode resolver problemas de portar código de um domínio para outro com um tradutor Você pode usar um interpretador para construir geradores mais sofisticados
  • 5. Na pior das hipóteses... “Se uma linguagem não é capaz de afetar o modo como você pensa sobre programação, não vale a pena aprendê-la” — Alan Perlis
  • 6. Um pouco de conceitos
  • 7. Linguagem “Uma notação para escrever programas, que são especificações para a computação de uma algoritmo” — Wikipedia
  • 8. Elementos Sintaxe: o que é escrito, descrita em uma gramática formal Semântica: o que isso significa, especificado em termos de formalizações de compilação e execução
  • 9. Gramáticas formais Value ← [0-9]+ / '(' Expr ')' Product ← Value (('*' / '/') Value)* Sum ← Product (('+' / '-') Product)* Expr ← Sum
  • 10. Do texto à execução CÓDIGO FONTE SAÍDA PARSING ANÁLISE LÉXICA COMPILADOR INTERPRETADOR TRADUTOR TOKENS ANÁLISE SINTÁTICA AST
  • 12. Inspiração Sintaxe baseada em Smalltalk e IO Slot-based como Self Forte e dinamicamente tipada Interpretada, via bytecodes
  • 13. Mirror World mirrorInto: "Fib". Fib set: "of:" to: [ n | n <= 2 ifTrue: [ 1. ] ifFalse: [ (of: n - 1) + (of: n - 2). ]. ]. (Fib of: 10) transcribeAndBreak.
  • 14. Análise Via Treetop, um packrat parser em Ruby PEGs Análise versus geração Sem ambigüidades Gera uma árvore sintática que é compilada para uma representação em bytecodes
  • 15. AST #1 (Fib of: 2 + 3) transcribeAndBreak.
  • 16. AST #2 (Fib of: 2 + 3) transcribeAndBreak.
  • 17. Bytecode push 3 push 2 send + load Fib send of: send transcribeAndBreak pop
  • 19. Blocos básicos grammar Mirror rule statements (spaces? statement spaces? "." spaces?)* <Statements> end rule statement message_expression end rule message_expression keyword_expression / binary_expression / unary_expression end # ... end
  • 20. Keywords grammar Mirror rule keyword_expression variable:binary_expression? keywords:(spaces? keyword spaces expression:binary_expression)+ <KeywordExpression> end # Account deposit: 100 from: user. # ... end
  • 21. Expressões binárias grammar Mirror rule binary_expression variable:unary_expression spaces? selector:binary_selector spaces? expression:binary_expression <BinaryExpression> / unary_expression end # 2 + 3 * (account balance). # ... end
  • 22. Expressões unárias grammar Mirror rule unary_expression variable:primary selectors:(spaces selector:identifier !colon)+ <UnaryExpression> / primary end # (Account current balance) transcribeAndBreak. # ... end
  • 23. Juntando as peças irb> MirrorParser.new.parse('2 + 3.') SyntaxNode+Statements offset=0, "2 + 3." (build): SyntaxNode+Statements0 offset=0, "2 + 3." (statement): SyntaxNode+BinaryExpression0+BinaryExpression offset=0, "2 + 3": SyntaxNode+IntegerLiteral offset=0, "2" (build): SyntaxNode offset=0, "2" SyntaxNode+Spaces2 offset=1, " ": SyntaxNode offset=2, "+": SyntaxNode offset=2, "+" SyntaxNode+IntegerLiteral offset=4, "3" (build): SyntaxNode offset=4, "3"
  • 25. Blocos básicos # rule statements # (spaces? statement spaces? "." spaces?)* <Statements> # end module Statements def build elements.collect do |element| Ast::Statement.new(element.statement.build) end end end class Statement def initialize(expression) @expression = expression end end
  • 26. Expressões binárias # rule binary_expression # variable:unary_expression spaces? # selector:binary_selector spaces? # expression:binary_expression <BinaryExpression> / # unary_expression module BinaryExpression def build Ast::Message.new(variable.build, selector.text_value, expression.build) end end class Message def initialize(target, selector, *arguments) @target = target @selector = selector @arguments = arguments end end
  • 27. Juntando as peças irb> MirrorParser.new.parse('2 + 3.').build [ #<Ast::Statement @expression = #<Ast::Message @selector = "+", @target = #<Ast::Literal @value = "2", @type = :integer>, @arguments = [#<Ast::Literal @value = "3", @type = :integer>]>> ]
  • 29. Double dispatch class CodeGenerator def initialize(ast) @ast = ast end def generate @ast.collect { |statement| generate_any(statement) }.flatten end def generate_any(ast) send("generate_#{ast.class.name.demodulize.underscore}", ast) end # ... end
  • 30. Blocos básicos class CodeGenerator def generate_statement(ast) ([generate_any(ast.expression)] + [Bytecode::Pop.new]).flatten end def generate_variable(ast) Bytecode::Load.new(ast.name) end # ... end
  • 31. Mensagens class CodeGenerator def generate_message(ast) instructions = [] ast.arguments.reverse.each do |argument| instructions += [generate_any(argument)].flatten end instructions += [generate_any(ast.target)].flatten instructions << Bytecode::Message.new(ast.selector) instructions end # ... end
  • 32. Bytecodes class Pop def inspect "pop" end end class Message def initialize(selector) @selector = selector @selector_name = get_selector_name(selector) @selector_method = get_selector_method(selector) @arity = get_selector_arity(selector) end # ... end
  • 33. Juntando as peças irb> ast = MirrorParser.new.parse('2 + 3.').build irb> CodeGenerator.new(ast).generate [ push 3, push 2, send +, pop ]
  • 35. Containers & Slots ACCOUNT BALANCE 0 DEPOSIT: BLOCK CONTEXT WITHDRAW: BLOCK CONTEXT USER USER
  • 36. Universe & World UNIVERSE WORLD WORLD MIRRORINTO: ERROR SET: TO:
  • 37. Detalhes O envio de mensagens acontece em um contexto que é gerado para cada mensagem Blocos geram contextos empilhados O interpretador percorre os contextos até encontrar o objeto apropriado para enviar a mensagem
  • 39. Máquina Virtual class VM def initialize(instructions) @instructions = instructions end def run reset_instruction_pointer while has_instructions? execute(next_instruction) end end # ... end
  • 40. Máquina Virtual class VM def execute(instruction) case instruction when Bytecode::Implicit stack_push_and_wrap(current_context) when Bytecode::Pop stack.pop when Bytecode::Push stack_push_and_wrap(instruction.value) when Bytecode::Load stack_push_and_wrap(walk_contexts(instruction.name)) # ... end end end
  • 41. Juntando as peças irb> Interpreter.run(true, "World offload: 2 + 2.") [4] irb> Interpreter.run(true, "World offload: [ 2 + 2. ] value.") [4]
  • 43. Próximos passos Arrays Inlining de mensagens comuns Primitivas: + - * / at: at:put: ifTrue:ifFalse et al to:do et al Melhor uso de blocos
  • 44. LLVM Uma estratégia de compilação Um conjunto de instruções virtualizado Uma infra-estrutura de compilação Um conjunto de ferramentas
  • 45. LLVM Efetivamente uma DSL para geração de código intermediário otimizado e portável Estático ou JIT Usado por MacRuby, Rubinius, Unladden Swallow e outros
  • 46. LLVM: Uso Transformar slots de código em funções Transformar closures em funções quando não fizer sentido que os mesmos sejam inline Compilar o próprio interpretador para ser parcialmente jitted
  • 47. LLVM: Uso module = LLVM::Module.new("mirror") type = Type::function(MACHINE_WORD, []) function = module.get_or_insert_function("main", type) entry_block = function.create_block exit_block_true = function.create_block exit_block_false = function.create_block builder = entry_block.builder cmp = builder.icmp_sgt(-1.llvm, 1.llvm) builder.cond_br(cmp, exit_block_true, exit_block_false)
  • 48. LLVM: Uso builder = exit_block_true.builder builder.return(1.llvm) builder = exit_block_false.builder builder.return(0.llvm) ExecutionEngine.get(module) ExecutionEngine.run_autoconvert(function)