Module: LazyPP

Defined in:
lib/readable-cpp/nodes.rb,
lib/readable-cpp/parser.rb,
lib/readable-cpp/package.rb,
lib/readable-cpp/program.rb,
lib/readable-cpp/transformer.rb

Overview

class Object

private
def CallerInspect c
  c = c.map  { |x|
    (x =~ /(\/[.\w\/]+):(\d+):in `([^']+)'/) ? 
    [$1,$2.to_i, $3] :
    nil
  }.compact
  files = {}
  c.map { |i| i[0] }.uniq.each { |file|
    warn "reading #{file}"
    files[file] = File.readlines file
  }
  res = c.uniq
  weights = Hash[res.map { |x| [x, c.count(x)] }]
  res.map! { |r|#(f, n, b)|
    [*r, weights[r], files[r[0]][r[1]],
      (r[1] .. [0, r[1]-20].max).map { |n| 
        if files[r[0]][n] =~ /def[\s]+(([A-Za-z_][A-Za-z_0-9]*[\=!?]?)|([+\-*\/<>\[\]@]+))[\s\(]*/
          binding.pry
          $1
        else
          nil
        end
      }.compact
    ]
  }
  binding.pry
  res
end

end

Defined Under Namespace

Classes: BracketStmts, ClassDecl, Node, OperDecl, Package, Parser, Program, RenderState, Unit

Constant Summary collapse

Conditional =
Node.new(:kind, :condition, :body) do
  def scan *args; body.scan(*args) unless body.nil? end
  def kind= val
    val = val.to_s
    @kind = if val =~ /elseif/i; "else if" #               ;)
    else val end
  end

  def to_cpp(rs)
    "#{rs.indentation}#{kind.to_cpp}#{
      "(#{condition.to_cpp rs})" unless condition.nil?
    } {\n#{body.to_cpp(rs.indent)}\n#{rs.indentation}}"
  end
end
RangeForStmt =
Node.new(:var, :container, :body) do
  def scan p; p.set_cpp0x; body.scan p end
  def to_cpp rs
    "#{rs.indentation}for(#{var.to_cpp(rs)} : #{container.to_cpp rs}) {\n"+
    body.to_cpp(rs.indent)+
    "#{rs.indentation}}"
  end
end
ForStmt =
Class.new(Conditional) do
  def scan *args; body.scan(*args); condition.compact.each{|c|c.scan(*args)} end
  def to_cpp rs
    "#{rs.indentation}for(#{last = condition[0].to_cpp(rs)}#{
      ';' unless last[-1] == ';'}#{condition[1].to_cpp rs};#{condition[2].to_cpp rs}) {\n#{
      body.to_cpp(rs.indent)}\n#{rs.indentation}}"
  end
end
NamespaceIdent =
Node.new(:names) do
  def names= val; @names = Array.wrap(val) end
  def to_cpp(rs) names.map{|n|n.to_cpp(rs)}.join '::' end
end
GotoLabel =
Node.new :type, :label do
  def to_cpp rs
    case type
    when :goto; "goto #{label};"
    else "#{label}:"
    end
  end
end
ThrowStmt =

DOUBLE CHECK, maybe

Node.new :expr do ## DOUBLE CHECK, maybe
  def to_cpp rs
    "throw #{expr.to_cpp rs}"
  end
end
DotName =
Node.new(:name) do
  def name= val; @name = Array.wrap(val) end
  def to_cpp(*)
    if caller.size > 500
      c=CallerInspect(caller)
      #binding.pry
    end
    name.map { |n| 
      n.is_a?(Hash) ? n.values : n 
    }.flatten(1).map(&:to_cpp).join
  end
  def prefix name; @name.insert 0, name end
end
Visibility =
Node.new(:v) do
  def to_cpp rs = RenderState.new();   end
  def to_hpp rs=RenderState.new
    raise "visiblity stmt only allowed in a class decl" \
      unless rs.parent.is_a? ClassDecl
    "#{v}:"
  end
end
FuncCall =
Class.new Node.new(:name, :args, :generics) do
  def initialize(n, a, g = nil)
    super n, a, g
  end
  def args= val
    @args = if val == ?! || val == '()'
      nil
    else
      Array.wrap val
    end
  end
  def generics= val
    @generics = Array.wrap_nil val
  end
  def to_cpp(rs)
    name.to_cpp(rs) + "#{"<#{generics.map { |g| g.to_cpp(rs, '') }.join', '}>" unless generics.nil?}(" + (
      args.nil? ? '' : args.map{|a|a.to_cpp rs}.join(', ')) + ')'

      #args != ?! && [*args].map(&:to_cpp).join(', ') || '') << ')'
  end
end
ExprStmt =
Node.new(:expr) do
  def to_cpp(rs); rs.indentation + expr.to_cpp(rs) + ';' end
end
LangSection =
Node.new(:txt)
AutoDecl =
Node.new(:name, :val) do
  def scan p
    p.set_cpp0x
  end
  def to_cpp(rs)
    "#{rs.indentation}auto #{name.to_cpp rs} = #{val.to_cpp rs};"
  end
end
ReturnStmt =
Node.new(:expr) do
  def to_cpp rs
    "#{rs.indentation}return #{expr.to_cpp rs};"
  end
end
StmtList =

Node.new(:stmts) do

Class.new(Array) do #Node.new(:stmts) do 
  #def [](key) stmts[key] end 
  def inspect
    "<#{self.class}(#{size}) #{map { |s| s.inspect }.join(', ') }>"
  end
  def scan p
    each { |s| s.scan p }
  end
  def to_hpp(rs = RenderState.new)
    map { |s| s.to_hpp(rs) }.join"\n"
  end
  def to_cpp(rs = RenderState.new, &discriminator)
    if block_given?
      select(&discriminator).map { |s| 
        s.to_cpp(rs, &discriminator) 
      }
    else
      map { |s| 
        s.to_cpp(rs) 
      }
    end.join("\n")
  end
  def at index; self[index] end
end
Type =
Node.new(:base, :derived, :storage) do
  attr_accessor :constness, :static, :inline
  attr_accessor :specifiers
  def initialize(b, d, s)
    self.base = b
    self.derived = d
    self.specifiers =Set.new
    self.storage = s
  end
  def no_storage()
    Type.new(base, derived, nil)
  end
  def derived= val
    @derived = (val == [''] || val.nil?) ? nil : Array.wrap(val) 
  end
  def base= val; @base = Array.wrap val; end
  def derived_cpp(rs, m = :to_cpp)
    #@derived_cpp ||= ( ##caching bad, this can change between header/src
      res = '%s'
      left = false
      derived.each do |d|
        d = Hash[d] if d.is_a?(Array)
        next if d.empty?

        # if d.has_key? :constness; self.constness = d[:constness].to_s
        # #elsif d.has_key? :static; self.static = d[:static].to_s

        case d 
        when :ptr
          res = "*#{res}"
          left = true
        when :ref
          res = "&#{res}"
          left = true
        when Hash
          #if d.has_key?(:size) || d.has_key?(:array)
          if d.has_key?(:array) || d.has_key?(:array_unsized)
            n = "[#{d[:array] && d[:array].send(m, rs)}]"
            #n = "[#{d[:size] && d[:size].send(m, rs)}]"
            res = if left; left = false; "(#{res})#{n}"
                  else; "#{res}#{n}" end
          elsif d.has_key? :func_sig
            begin
            n = "(#{[*d[:func_sig]].map { |a| a.send(m, rs) % '' }.join', '})"
            res = if left; left = false; "(#{res})#{n}"
                  else; "#{res}#{n}" end
            rescue => e
              binding.pry
            end
          elsif d.has_key? :const
            res = "#{d[:const].to_s.downcase} #{res}"
            left = true
          # elsif d.has_key? :storage
          #   @storage = d[:storage].to_s.downcase unless d[:storage].nil?
          
          else
            ##what the hell is this? :o
            binding.pry
          end
        else
          binding.pry
        end
      end unless derived.nil?
      res
    #)
  end
  def storage_cpp() "#{"#{storage.to_s.downcase} " unless storage.nil?}" end
  def base_hpp rs
    derived_cpp rs
    storage_cpp + base.map{|x|x.to_hpp rs}.join(' ')
  end
  def base_cpp rs
    derived_cpp rs #just to cache it
    storage_cpp + base.map{|x|x.to_cpp rs}.join(' ')
  end
  def to_hpp rs
    base_hpp(rs) << ' ' << derived_cpp(rs)
  end
  def to_cpp rs=RenderState.new, name=nil ##note to self: % format result with the name
    r = base_cpp(rs) << ' ' << derived_cpp(rs)
    (name.nil? ? r : r % name).rstrip
  end
end
TypeDecl =
Node.new(:name, :type) do
  def to_cpp rs
    rs.gen_header? ? '' : to_hpp(rs)
  end
  def to_hpp rs
    "#{rs.indentation}typedef #{type.base_cpp rs} #{type.derived_cpp(rs) % name.to_cpp(rs)};"
  end
end
Expr =
Node.new(:prefix, :expr, :postfix) do
  def to_cpp(rs)
    # prefix.nil? && postfix.nil? ? 
    # expr.to_cpp : 
    # "(#{prefix.to_cpp}#{expr.to_cpp}#{postfix.to_cpp})"
    "#{prefix.to_cpp rs}#{expr.to_cpp rs}#{postfix.to_cpp rs}"
  end
end
DotExpr =
Node.new(:exprs) do
  def to_cpp(rs = RenderState.new) 
    "#{exprs.map{|e|
      e.to_cpp rs
    }.join''}" 
  end
end
AccessExpr =
Node.new(:access, :expr) do
  def to_cpp(rs) "#{access.to_cpp rs}#{expr.to_cpp rs}" end
end
ParenExpr =
Node.new(:expr) do
  def to_cpp(rs) "(#{expr.to_cpp rs})" end
end
CastExpr =
Node.new(:type, :expr) do
  def to_cpp rs
    "(#{type.to_cpp(rs) % ''})(#{expr.to_cpp rs})"
  end
end
CaseStmt =
Node.new(:exprs, :body) do
  def scan(*args) body.each { |b| b.scan *args } end
  def to_cpp(rs)
    i = rs.indentation
    (exprs == :default ? 
      i+"default:\n" : 
      exprs.map { |x| i+"case #{x.to_cpp rs}:\n"}.join('')
    ) + 
    body.to_cpp(rs.indent) +
    "\n#{rs.indent.indentation}break;"
  end
end
SwitchStmt =
Node.new(:expr, :body) do
  def scan(*args) body.each { |b| b.scan *args } end
  def to_cpp(rs)
    "#{rs.indentation}switch(#{expr.to_cpp rs}) {\n" +
    body.map { |s| s.to_cpp(rs) }.join("\n") +
    "\n#{rs.indentation}}"
  end
end
InfixExpr =
Node.new(:left, :infix, :right) do
  def to_cpp rs
    #binding.pry
    "#{left.to_cpp rs
    } #{infix.to_cpp rs
    } #{right.to_cpp rs}"
  end
end
FuncCall2 =
Node.new(:args) do
  def args= v
    @args = Array.wrap_nil(v.to_s == "!" ? nil : v)
  end
  def to_cpp rs
    "(#{args.map{|_|_.to_cpp rs}.join(', ') unless args.nil?})"
  end
end
PostfixExpr =
Node.new(:x, :postfixen) do
  def scan *args
    postfixen.each do |c| c.scan *args end
  end
  def postfixen= v
    @postfixen = Array.wrap(v)
  end
  def to_cpp rs
    "#{x.to_cpp rs}#{postfixen.map{|_|_.to_cpp rs}.join}"
  end
end
TernaryExpr =
Node.new(:cond, :t, :f) do
  def to_cpp rs
    "#{cond.to_cpp rs} ? #{t.to_cpp rs} : #{f.to_cpp rs}"
  end
end
PrefixExpr =
Node.new(:op, :expr) do
  def scan p
    op.scan p
    expr.scan p
  end
  def to_cpp rs
    "#{op}#{expr.to_cpp rs}"
  end
end
BracketExpr =
Node.new(:expr) do
  def to_cpp(rs=RenderState.new)
    "[#{expr.to_cpp(rs)}]"
  end
end
GenericIdent =
Node.new(:ident, :generic) do
  def generic= val
    @generic = Array.wrap(val)
  end
  def to_cpp(rs)
    "#{ident.to_cpp(rs)}<#{generic.map{|n| n.to_cpp(rs, '')}.join', '}>"
  end
end
UnionType =
Node.new(:members) do
  def members= val; @members = Array.wrap val; end
  def to_cpp rs
    "union{#{members.map{|f|f.to_cpp(rs) + ';'}.join' '}}"
  end
end
EnumType =
Node.new(:fields) do
  def fields= val; @fields = Array.wrap val; end
  def to_cpp(rs)
    "enum{#{fields.map{|f|f.to_cpp rs}.join', '}}"
  end
end
EnumDecl =

the other one works for anonymous enum types (var x: enumA,B,C)

Node.new :name, :fields do
  def fields= val; @fields = Array.wrap val; end
  def header_only rs
    unless rs.gen_header?
      to_hpp rs
    else
      ''
    end
  end
  def to_cpp(rs) header_only(rs) end
  def to_hpp rs
    "#{rs.indentation}enum #{name} {#{fields.map{|f|f.to_cpp rs}.join', '}};"
  end
end
StructType =
Node.new(:body) do
  def to_cpp(rs)
    "struct{#{"\n#{body.to_cpp rs.indent}\n#{rs.indentation}" unless body.nil?}}"
  end
end
VarDeclSimple =
Node.new(:name, :type, :val) do
  def scan p
    name.scan p
    type.scan p
    val.scan p
  end
  def to_cpp(rs = RenderState.new())
    # res = type.to_cpp
    # [*names].map { |n| (res + ';') % n }.join('')
    rs.indentation + (type.base_cpp(rs) % '') + ' ' + (type.derived_cpp(rs)%name) + 
      (val && " = #{val.to_cpp(rs)};" || ';')
  end
end
VarDeclInitializer =
Node.new(:names, :type)do
  def to_cpp(rs = RenderState.new())
    derived = type.derived_cpp rs #cpp
    rs.indentation + type.base_cpp(rs) + ' ' + [*names].map { |n| 
      name = derived % n.name rescue binding.pry
      if n.args.nil?
        name
      else
        name + '(' + [*n.args].map{|a|a.to_cpp(rs)}.join(', ') + ')'
      end
    }.join(', ') + ';'
  end
end
ConstructorName =
Node.new(:name, :args)
IdentDef =
Node.new(:names, :type, :default) do
  def names= val; @names = Array.wrap(val) end
  def to_cpp(rs)
    #return to_hpp(rs)  unless rs.gen_header?
    t = type.to_cpp(rs)
    names.map { |n| t % n }.join', '
  end
  def to_hpp(rs)
    t = type.to_hpp(rs)
    names.map { |n|
      res = t % n
      (res << ' = ' << default.to_cpp(rs)) unless default.nil?
      res
    }.join', '
  end
end
ImportStmt =
Node.new(:pkg) do
  attr_reader :p
  def initialize(pkg)
    @p = Package.new(pkg)
  end

  def scan(prog)
    prog.notify self
  end

  def to_cpp(rs)
    @p.includes.map { |i|
      "#include #{i}\n"
    }.join('') unless @p.includes.nil?
  end
end
StringLit =
Node.new(:wchar, :str) do
  def scan p
    str.gsub!(/[^\\]\n/, "\\\n") ##add \ to the ends of multiline strings for c++
  end
  def to_cpp(*); "#{?L if wchar}\"#{str}\"" end
  def str= val; @str = val.to_s end
  extend Forwardable
  def_delegators :@str, :=~, :to_s
end
DefineStmt =
Node.new(:name, :expr) do
  def to_cpp(rs)
    to_hpp(rs) if not rs.gen_header?
  end
  def to_hpp(rs)
    "#define #{name.to_cpp rs} #{expr.to_cpp rs}"
  end
end
StructLit =
Node.new(:x) do
  def x= val; @x = Array(val) end
  def to_cpp(rs)
    "{#{x.map{|_|_.to_cpp rs}.join', '}}"
  end
end
TryStmt =
Node.new(:attempt, :catches) do
  def to_cpp rs
    "#{rs.indentation}try {\n#{attempt.to_cpp rs.indent}\n"\
    "#{rs.indentation}} #{catches.map{|c|c.to_cpp rs}.join''}"
  end
end
CatchStmt =
Node.new(:c, :body) do
  def to_cpp rs
    "#{rs.indentation}catch (#{c.to_cpp rs}) {\n"\
    "#{body.to_cpp rs.indent}\n"\
    "#{rs.indentation}}"
  end
end
IncludeStmt =
Node.new(:file, :type) do
  def file= val
    if file && file.is_a?(StringLit)
      @file.str = val
    else
      @file = val
    end
  end
  def scan p; p.notify self end
  def to_cpp(rs)
    "#include " << (
      type == :std ? 
        '<' << file << '>' : 
        file.to_cpp)
  end
end
UsingStmt =
Node.new(:name) do
  def to_cpp(rs)
    "using #{name.to_cpp rs};"
  end
end
IntLiteral =
Node.new(:value) do
  def to_cpp(*); "#{value}" end
end
CharLiteral =
Node.new(:char) do
  def to_cpp(*); "'#{char}'" end
end
FloatLiteral =
Node.new(:value, :type) do
  def to_cpp(*)
    "#{value}#{type}"
  end
end
LambdaFunc =
Node.new(:captures, :params, :returns, :body) {
  def captures=(val) @captures = Array.wrap_nil val end
  def params=(val) @params = Array.wrap_nil val end
  def to_cpp(rs)
    "[#{
      captures.join(', ') unless captures.nil?
    }](#{
      params.map{|p|p.to_cpp rs}.join', ' unless params.nil?
    })#{
      "->#{returns.to_cpp(rs) % ''}" unless returns.nil?
    }{#{body.to_cpp(rs)}}"
  end
}
Namespace =
Node.new(:name, :body) do
  def to_hpp(rs)
    "namespace #{name.to_hpp rs} {\n" << body.to_hpp(rs.indent) << "\n}"
  end
  def to_cpp(rs, &b)
    "namespace #{name.to_cpp rs} {\n" << body.to_cpp(rs.indent,&b) << "\n}"
  end
end
DtorDecl =
Node.new(:stmts, :specifier) do
  def specifier= val
    @specifier = if val.nil? then ''
    else
      val.to_s + ' '
    end
  end

  def to_cpp rs
    #parent = rs.parent
    pname = rs.parent_names + '::~' + rs.parents.last.name.to_s
    "#{rs.indentation}#{pname}() \n"\
    "#{rs.indentation}{\n"\
    "#{stmts.to_cpp(rs.indent)}\n"\
    "#{rs.indentation}}"
  end
  def to_hpp rs
    "#{rs.indentation}#{
      specifier unless specifier.nil?
    }~#{rs.last_parent}();"
  end
end
AnonDecl =

DOUBLE CHECK THIS

Node.new :type do ## DOUBLE CHECK THIS
  def to_cpp rs
    
  end ## works fine inside structs/class where
  def to_hpp rs ## the header is always generated above the impl
    "#{rs.indentation}#{type.to_cpp(rs) % ''};"
  end
end
CtorDecl =
Node.new(:args, :initializers, :body, :explicit) do
  def explicit= val; @explicit = val.nil? ? nil : val.to_s.chomp+' ' end
  def args= a; @args = Array.wrap a; end
  def initializers= i; @initializers = (i.nil? ? nil : Array.wrap( i)); end
  def scan(*args) body.scan(*args) end
  def to_cpp rs
    Pry.rescue { 
      pname = rs.parent_names
      pname << "::" << rs.parent.last.name.to_s
      <<-LULZ
#{rs.indentation}#{pname}#{#rs.parent.last.name}::#{pname.nil? ?
  #parent.respond_to?(:name) ? 
  #  parent.name : 
  #  (binding.pry;'/*constructor name missing and parent node has no name*/'):
  #pname
}(#{args.map{|a|a.to_cpp rs}.join', '}) #{
  ( ': ' +
    initializers.map{|i|
      i = i[:initializer]
      "#{i[:member].to_cpp rs}(#{[*i[:args]].map{|a|a.to_cpp rs}.join(', ')})"
    }.join(', ')
  ) unless initializers.nil? 
} #{
if body.nil? then ?; 
else "{\n#{body.to_cpp(rs.indent)}\n#{rs.indentation}}" 
end}
      LULZ
    }
  end
  def to_hpp rs
    parent = rs.parent.last
    "#{rs.indentation}#{explicit}#{parent.name.to_hpp(rs)}(#{args.map{|a|a.to_hpp rs}.join', '});"
  end
end
FuncDecl =
Class.new Node.new(:name, :sig, :body, :generics, :specifiers) do
  def initialize(n,s,b,g,ss= nil)
    super
  end
  def specifiers= val; @specifiers = val.nil? ? nil : Array.wrap(val) end
  def generics= val; @generics = val.nil? ? nil : Array.wrap(val) end
  def scan(*args) body.scan(*args) unless body.nil? end
  def to_cpp(rs)
    ## more info on functions returning functions and such at http://www.newty.de/fpt/fpt.html
    prename = ''
    prename = rs.parent_names+'::' unless rs.parents.empty?
    "#{"#{rs.indentation}template <#{generics.map{|x|'typename '+ x.to_cpp(rs)}.join', '}>\n" if generics}" +
    "#{rs.indentation}#{
      if rs.gen_header?
        #remove the storage if headers are generated 
        sig.no_storage.base_cpp(rs)
      else
        sig.base_cpp(rs)
      end} #{
      sig.derived_cpp(rs) % "#{prename}#{name}"}"+
    "#{body == :EQ0 ? 
      ' = 0;' :
      body.nil? ? 
        ';' : 
        "\n#{rs.indentation}{\n#{
          body.to_cpp(rs.indent) }\n"\
        "#{rs.indentation}}"
    }"
  end
  def to_hpp(rs)
    "#{rs.indentation}#{
      specifiers.map{|s|s.to_hpp rs}.join(' ')+' ' if !specifiers.nil?}#{
    sig.base_hpp rs} #{sig.derived_cpp(rs, :to_hpp) % name};"
  end
end
Transform =
Parslet::Transform.new {
  rule(ident: simple(:i)) { i.to_s }
  rule(ident: simple(:i), generics: simple(:g)) {
    GenericIdent.new(i, g)
  }
  rule(ident: simple(:i), generics: sequence(:g)) {
    GenericIdent.new i, g
  }
  rule(expr: simple(:x), generics: simple(:g)) {
    GenericIdent.new x,g
  }
  rule(expr: simple(:x), generics: sequence(:g)) {
    GenericIdent.new x,g
  }
  rule(void: simple(:v)) { 'void' }
  rule(any: simple(:__)) { '...' }
  rule(ptr: simple(:p)) { :ptr }
  rule(ref: simple(:r)) { :ref }
  rule(list_item: simple(:i)){ i }

  rule(ident_eq: { ident: simple(:i), dot_expr: simple(:x) }) {
    InfixExpr.new(i, '=', x)
  }
  rule(ident_eq: simple(:i)) { i }
  rule(stmts: sequence(:s)) {
    StmtList.new s
  }
  rule(stmts: simple(:s)) {
    StmtList.new Array.wrap s
  }
  rule(anon_decl: simple(:ty)) {
    AnonDecl.new ty
  }
  rule(bracket_stmts: sequence(:s)) {
    BracketStmts.new s
  }
  rule(wchar: simple(:w), string: simple(:s)) {
    StringLit.new(w, s.to_s)
  }
  rule(wchar: simple(:w), string: sequence(:s)) {
    StringLit.new(w, s.join(''))
  }
  rule(goto: simple(:l)) { GotoLabel.new :goto, l }
  rule(label: simple(:g)){ GotoLabel.new :label,g }
  # rule(type: {derived: subtree(:d), base: subtree(:b), storage: simple(:s)}){
  #   Type.new(b, Array.wrap(d), s)
  # }
  # rule(type: {derived: subtree(:d), base: subtree(:b)}) {
  #   Type.new b, Array.wrap(d), nil
  # }
  rule(derived: subtree(:d), base: subtree(:b)) {
    Type.new b, d, nil
  }
  rule(derived: subtree(:d), base: subtree(:b), storage: subtree(:s)) {
    Type.new b, d, s
  }
  rule(type: simple(:t)) {t}

  rule(union: { members: subtree(:m) }) {
    UnionType.new(m)
  }
  rule(auto_decl: {name: simple(:n), value: subtree(:v)}) {
    AutoDecl.new(n, v)
  }
  rule(:catch => simple(:c), body: simple(:b)) {
    CatchStmt.new(c, b)
  }
  rule(attempt: simple(:at), catches: sequence(:c)) {
    TryStmt.new(at, c)
  }
  rule(enum: { fields: subtree(:f) }) {
    EnumType.new f
  }
  rule(struct: simple(:body)) {
    StructType.new body
  }
  rule(lang_section: subtree(:l)) {
    #binding.pry
    LangSection.new(l) }
  rule(id_names: sequence(:n), type: simple(:t)) {
    IdentDef.new n, t, nil
  }
  rule(#ident_def: 
  {
    id_names: sequence(:n), type: simple(:t), id_default: simple(:d)}) {
    IdentDef.new n, t, d
  }
  rule(id_names: simple(:n), type: simple(:t)) {
    IdentDef.new n, t, nil
  }
  rule(#ident_def: 
  {
    names: simple(:n), type: simple(:t),
    default: simple(:d)  }) {
    IdentDef.new n, t, d
  }
  rule(ident_def: simple(:i), any: simple(:a)) {[i, '...']}
  rule(type: simple(:t), any: simple(:a)) {[t, '...']}
  rule(ident_def: simple(:_)) {_}
  rule(var_decl: {name: simple(:n), type: simple(:t)}) {
    VarDeclSimple.new(n, t, nil)
  }
  rule(var_decl: {name: simple(:n), type: simple(:t), expr: simple(:x)}){
    VarDeclSimple.new(n, t, x)
  }
  rule(var_decl: {vdi_names: subtree(:n), vdi_type: simple(:t)}) {
    VarDeclInitializer.new n, t
  }
  rule(case_: 'default', body: sequence(:b)) {
    CaseStmt.new :default, b
  }
  rule(case_: simple(:c), body: sequence(:b)) {
    CaseStmt.new [c], b
  }
  rule(case_: sequence(:c), body: sequence(:b)) {
    CaseStmt.new c, b
  }
  rule(switch_stmt: {expr: simple(:x), cases: sequence(:cases)}) {
    SwitchStmt.new x, cases
  }
  rule(name: simple(:n), constructor: subtree(:c)) {
    ConstructorName.new n, c
  }
  rule(import_pkg: subtree(:i)) {
    ImportStmt.new(i)
  }
  rule(define_stmt: {name: simple(:n), expr: simple(:x)}) {
    DefineStmt.new n, x
  }
  rule(include_stmt: { std: simple(:x), file: simple(:f) }) {
    IncludeStmt.new f, :std
  }
  rule(include_stmt: { local: simple(:f) }) {
    IncludeStmt.new f, :local
  }
  rule(include_stmt: sequence(:s)) {
    StmtList.new(s)
  }
  rule(include_stmt: simple(:s)) { s }
  rule(using_stmt: { ns: simple(:ns), using_namespace: simple(:n) }) {
    UsingStmt.new("namespace #{n}")
  }
  # rule(using_stmt: { using_namespace: simple(:n) }) {
  #   UsingStmt.new(n)
  # }
  rule(using_namespace: simple(:n)) { UsingStmt.new n }
  rule(using_stmt: sequence(:s)) { StmtList.new(s) }
  rule(using_stmt: simple(:s)) { s } 
  rule(namespace_decl: {namespace: subtree(:n), body: subtree(:b)}){
    Namespace.new(n, b)
  }
  rule(oper_decl: {
    pos: simple(:pos), name: simple(:name),
    sig: simple(:sig), body: simple(:body) }) { 
    OperDecl.new name, sig, body, pos 
  }
  rule(oper_decl: {
    name: simple(:name), sig: simple(:sig), body: simple(:body)}) {
    OperDecl.new name, sig, body, nil
  }
  rule(func_decl: {
    name: simple(:name),
    generics: simple(:g),
    sig: simple(:sig)  }) { FuncDecl.new name, sig, nil, g }
  rule(func_decl: {
    name: simple(:name), generics: simple(:g),
    sig: simple(:sig), body: simple(:b)}){
    FuncDecl.new name, sig, b, g
  }
  rule(func_decl: {
    name: simple(:name), generics: subtree(:g), specifiers: subtree(:s),
    sig: simple(:sig), body: simple(:b)}) {
    FuncDecl.new name, sig, b, g, s
  }
  rule(func_decl: {
    name: simple(:name), generics: subtree(:g), specifiers: subtree(:s),
    sig: simple(:sig) }) {
    FuncDecl.new name, sig, nil, g, s
  }
  rule(func_decl: {
    name: simple(:name), generics: subtree(:g), specifiers: subtree(:s),
    sig: simple(:sig), eq_0: simple(:eee)}) {
    FuncDecl.new name, sig, :EQ0, g, s
  }
  # rule(func_decl: {
  #   name: simple(:name),
  #   sig: { args: subtree(:args), returns: subtree(:returns) },
  #   body: simple(:b) }) {
  #   FuncDecl.new name, args, returns, b
  # }
  # rule(func_decl: {
  #   name: simple(:name),
  #   sig: { args: subtree(:args), returns: subtree(:returns) }}) {
  #   FuncDecl.new name, args, returns, nil
  # }
  rule(op: simple(:o)) { o.is_a?(Parslet::Slice) ? o.to_s.intern : o }
  rule(float: simple(:f), type: simple(:t)) {
    FloatLiteral.new(f, t)
  }
  rule(cast: { type: simple(:t), expr: simple(:x) }) { CastExpr.new t, x }
  rule(int: simple(:i)) {
    IntLiteral.new i.to_i
  }
  rule(char: simple(:c)) {
    CharLiteral.new c.to_s
  }
  rule(return: simple(:exp)) {
    ReturnStmt.new exp
  }
  rule(ctor_decl: {
    explicit: simple(:e), args: subtree(:args),
    initializers: subtree(:i), body: simple(:b)}) {
    CtorDecl.new args, i, b, e
  }
  rule(dtor_decl: subtree(:d)) {
    DtorDecl.new(d[:body], d[:specifier] || nil)
  }
  rule(parens: simple(:x)) { 
    ParenExpr.new x
  }
  rule(ref: simple(:r), name: simple(:n)) {
    "#{r}#{n}"
  }
  rule(lambda_func: {
    captures: simple(:c), args: subtree(:p), 
    returns: simple(:r), body: simple(:b)
  }) {
    LambdaFunc.new c, p, r, b
  }
  rule(lambda_func: {
    captures: { auto_ref: simple(:___) },
    args: subtree(:p), returns: simple(:r), body: simple(:b)
  }) {
    LambdaFunc.new '&', p, r, b
  }
  rule(lambda_func: {
    captures: {auto_val: simple(:___)},
    args: subtree(:p), returns: simple(:r), body: simple(:b)
  }) {
    LambdaFunc.new '=', p, r, b
  }
  rule(infix: {
    left: simple(:l), op: simple(:o), right: simple(:r)}) {
    InfixExpr.new l, o.to_s, r
  }
  #rule(postfix: sequence(:x)) { PostfixExpr.new x }
  rule(left: simple(:x), access: simple(:a), ident: simple(:i)) {
    PostfixExpr.new x, [a.to_s, i.to_s]
  }
  rule(prefix_op: simple(:o), expr: simple(:x)) {
    PrefixExpr.new o.to_s, x
  }
  rule(ternary: {
    condition: simple(:c), true: simple(:t), false: simple(:f)
  }) {
    TernaryExpr.new c, t, f
  }
  rule(expr: simple(:x), postfix: sequence(:p)) {
    PostfixExpr.new x, p
  }
  rule(expr: simple(:x), postfix: sequence(:p), args: subtree(:a)) {
    PostfixExpr.new x, [*p, FuncCall2.new(a)]
  }
  rule(args: sequence(:a)) {
    FuncCall2.new a
  }
  rule(args: simple(:a)) {
    FuncCall2.new a
  }
  rule(cast: {type: simple(:t), ident: simple(:i)})

  # rule(prefix: simple(:p), expr: simple(:x), postfix: simple(:pp),
  #   args: subtree(:a),    infix: simple(:i), right: simple(:x2)) {
  #   InfixExpr.new FuncCall.new(Expr.new(p, x, nil), a), i.to_s.intern, x2
  # }
  # rule(expr: simple(:x), args: subtree(:a), infix: simple(:i), right: simple(:r)) {
  #   InfixExpr.new FuncCall.new(x, a), i.to_s.intern, r
  # }
  # rule(prefix: simple(:p), expr: simple(:x), args: simple(:a)) {
  #   FuncCall.new(Expr.new(p.to_s, x, nil), a)
  # }
  # rule(
  #   prefix: simple(:p), expr: simple(:x),
  #   infix: simple(:i), right: simple(:x2)) {
  #   InfixExpr.new(Expr.new(p, x, nil), i.to_s, x2)
  # }
  # rule(
  #   prefix: simple(:p), expr: simple(:x), postfix: simple(:pp),
  #   infix: simple(:i), right: simple(:x2)) {
  #   InfixExpr.new(Expr.new(p, x, pp), i.to_s, x2)
  # }
  # rule(
  #   expr: simple(:x), postfix: simple(:pp),
  #   infix: simple(:i), right: simple(:x2)) {
  #   InfixExpr.new(Expr.new(nil, x, pp), i.to_s, x2)
  # }
  # rule(expr: simple(:x)) {
  #   Expr.new(nil, x, nil)
  # }
  # rule(expr: simple(:x), postfix: simple(:pp)) {
  #   Expr.new(nil, x, pp)
  # }
  # rule(expr: simple(:l), infix: simple(:i), right: simple(:r)) {
  #   InfixExpr.new(l, i.to_s, r)
  # }
  rule(expr: simple(:x)) { 
    x.is_a?(Parslet::Slice) ?
      x.to_s : 
      x 
  }
  rule(expr_stmt: simple(:x)) {
    ExprStmt.new(x)
  }
  # rule(expr: simple(:x), args: subtree(:a)) {
  #   FuncCall.new x, a
  # }
  # rule(parens: simple(:x), args: subtree(:a)) {
  #   FuncCall.new x, a
  # }
  # rule(func: simple(:name), args: subtree(:args)) {
  #   FuncCall.new name, Array.wrap(args)
  # }
  # rule(access: simple(:a), func: simple(:name), args: subtree(:args)) {
  #   FuncCall.new name.prefix(a), Array.wrap(args)
  # }
  rule(type_decl: { 
    name: simple(:n),
    type: { 
      class_type: simple(:c),
      parents: subtree(:p),
      body: subtree(:b) }}) {
    ClassDecl.new(n, c, b, p)
  }
  rule(type_decl: {
    name: simple(:n),
    type: {
      class_type: simple(:c),
      body: subtree(:b) }}) {
    ClassDecl.new(n, c, b, nil)
  }
  rule(type_decl: {
    name: simple(:n),
    enum: { fields: subtree(:f) }}) {
    EnumDecl.new n, f
  }
  rule(struct_lit: simple(:x)) { StructLit.new x }
  rule(struct_lit: sequence(:x)) { StructLit.new x }
  rule(type_decl: {
    name: simple(:n),
    type: simple(:t) }) {
    TypeDecl.new(n, t)
  }
  rule(dot_ident: subtree(:d)) {
    DotName.new d
  }
  # rule(dot_ident: simple(:d)) {
  #   DotName.new d
  # }
  rule(namespace: sequence(:n)) {
    NamespaceIdent.new n
  }
  rule(conditional: {
    kind: simple(:k),
    cond: simple(:c),
    body: simple(:b) }) {
    Conditional.new k, c, b
  }
  rule(for_stmt: {
    l: simple(:l),
    m: simple(:m),
    r: simple(:r),
    body: simple(:b) }) {
    ForStmt.new :for, [l, m, r], b
  }
  rule(conditional: {
    kind: simple(:k), ##else
    body: simple(:b) }) {
    Conditional.new k, nil, b
  }
  rule(range_for: { var: simple(:v), range: simple(:container), body: simple(:b)}) {
    RangeForStmt.new v, container, b
  }
  rule(namespaced: simple(:i)) {
    NamespaceIdent.new i
  }
  rule(namespaced: sequence(:i)) {
    NamespaceIdent.new(i)
  }
  rule(namespaced: {left: simple(:l), right: simple(:r)}) {
    NamespaceIdent.new [l, r]
  }
  rule(modifier: simple(:m), namespaced: simple(:n)) { 
    [m, n]
  }
  rule(modifier: simple(:m), namespaced: sequence(:n)) {
    [m, NamespaceIdent.new(n)]
  }
  rule(sq_bracket_expr: simple(:x)) {
    BracketExpr.new x
  }
  rule(visibility_stmt: simple(:v)) {
    Visibility.new v.to_s
  }
  rule(:throw => simple(:x)) { ThrowStmt.new x }
  rule(access: simple(:a), expr: simple(:x)) {
    AccessExpr.new a, x
  }
  rule(access: simple(:a), ident: simple(:i)) {
    DotName.new([a.to_s, i])
  }
  rule(dot_expr: sequence(:x)) {
    DotExpr.new x
  }
  rule(dot_expr: simple(:x)) {
    DotExpr.new [*x]
  }
}