Module: Yadriggy::Py

Defined in:
lib/yadriggy/py.rb,
lib/yadriggy/py/import.rb,
lib/yadriggy/py/python.rb,
lib/yadriggy/py/syntax.rb,
lib/yadriggy/py/codegen.rb,
lib/yadriggy/py/py_typechecker.rb

Overview

Python language embedded in Ruby

Defined Under Namespace

Modules: PyImport Classes: CodeGen, Import, PyTypeChecker

Constant Summary collapse

Syntax =
Yadriggy.define_syntax do
  expr  = Name | Number | Super | Binary | Unary | ternary |
          StringLiteral | Lambda |
          ArrayLiteral | Paren | lambda_call | with_call | fun_call |
          ArrayRef | HashLiteral
  stmnt = Return | ForLoop | Loop | if_stmnt | Break |
             BeginEnd | Def | ModuleDef
  exprs = Exprs | stmnt | expr

  Name = { name: String }
  Number     = { value: Numeric }
  VariableCall     = Name
  InstanceVariable = nil
  GlobalVariable   = nil
  Reserved   = Name
  Const      = Name
  Binary     = { left: expr, op: Symbol, right: expr }
  ArrayRef   = { array: expr, indexes: expr }
  ArrayRefField  = ArrayRef
  Assign     = { left: [expr] | expr, op: Symbol,
                 right: [expr] | expr }
  Dots       = Binary
  Unary      = { op: Symbol, operand: expr }
  StringLiteral  = { value: String }
  ArrayLiteral   = { elements: ForLoop | [ expr ] }
  Paren      = { expression: expr }
  HashLiteral    = { pairs: [ (expr|Label|SymbolLiteral) * expr ] }
  Return     = { values: [ expr ] }
  ForLoop    = {vars: [ Identifier ], set: expr, body: exprs }
  Loop       = { op: :while, cond: expr, body: exprs }
  Break      = { values: nil }
  if_stmnt   = Conditional + { op: :if, cond: expr, then: exprs,
                  all_elsif: [expr * exprs], else: (exprs) }
  ternary    = Conditional + { op: :ifop, cond: expr, then: expr,
                  all_elsif: nil, else: expr }
  Parameters = { params: [ Identifier ],
                 optionals: [ Identifier * expr ],
                 rest_of_params: (Identifier),
                 params_after_rest: [ Identifier ],
                 keywords: [ Label * expr ],
                 rest_of_keywords: (Identifier),
                 block_param: (Identifier) }
  Block      = Parameters + { body: exprs }
  Lambda     = Block + { body: expr }  # -> (x) { x + 1 }
  lambda_name = { name: "lambda" }
  lambda_call = Call + { receiver: nil, op: nil, name: lambda_name,
                 args: nil, block_arg: nil, block: Block }
  with_name  = { name: "with" }
  with_call  = Call + { receiver: nil, op: nil, name: with_name,
                        args: HashLiteral, block_arg: nil, block: Block }
  fun_call   = Call + { receiver: (expr), op: (Symbol), name: Identifier,
                 args: [ expr ], block_arg: nil, block: nil }
  Command    = fun_call
  Exprs      = { expressions: [ exprs ] }
  Rescue     = { types: [ Const | ConstPathRef ],
                 parameter: (Identifier),
                 body: (exprs), nested_rescue: (Rescue),
                 else: (exprs), ensure: (exprs) }
  BeginEnd   = { body: exprs, rescue: (Rescue) }
  Def        = Parameters +
               { singular: (expr), name: Identifier, body: exprs,
                 rescue: (Rescue) }
  ModuleDef  = { name: Const | ConstPathRef, body: exprs,
                 rescue: (Rescue) }
  ClassDef   = ModuleDef +
               { superclass: (Const | ConstPathRef) }
end

Class Method Summary collapse

Class Method Details

.expr_or_subtype(ast) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/yadriggy/py/python.rb', line 53

def self.expr_or_subtype(ast)
  if ast.nil? || ast.is_a?(Assign)
    false
  else
    usertype = ast.usertype
    if usertype == :fun_call
      ast.name.name != 'print'
    else
      usertype == :expr || usertype == :lambda_call || usertype == :ternary
    end
  end
end

.generate_except_last(ast, gen) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/yadriggy/py/python.rb', line 38

def self.generate_except_last(ast, gen)
  if expr_or_subtype(ast)
    ast
  elsif ast.is_a?(Exprs) && expr_or_subtype(ast.expressions[-1])
    ast.expressions[0...-1].each do |e|
      gen.print(e)
      gen.newline
    end
    ast.expressions[-1]
  else
    gen.print(ast)
    nil
  end
end

.init_free_variables(checker) ⇒ Object



28
29
30
31
32
33
34
35
36
# File 'lib/yadriggy/py/python.rb', line 28

def self.init_free_variables(checker)
  unless checker.references.empty?
    gen = CodeGen.new(Printer.new, checker)
    args = gen.print_free_vars_initializer
    PyCall.exec(gen.printer.output)
    f = PyCall.eval(CodeGen::FreeVarInitName)
    f.call(args)
  end
end

.run(&blk) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/yadriggy/py/python.rb', line 12

def self.run(&blk)
  ast = Yadriggy::reify(blk)
  Syntax.raise_error unless Syntax.check(ast.tree)
  checker = PyTypeChecker.new
  checker.typecheck(ast.tree.body)
  PyCall.exec(Import.source)
  init_free_variables(checker)
  gen = CodeGen.new(Printer.new, checker)
  ast.astrees.each {|t| gen.print(t) unless t == ast }
  last_expr = generate_except_last(ast.tree.body, gen)
  PyCall.exec(gen.printer.output)
  unless last_expr.nil?
    PyCall.eval(CodeGen.new(Printer.new, checker).print(last_expr).printer.output)
  end
end