klayout/scripts/mkqtdecl_common/cpp_parser_classes.rb

475 lines
9.6 KiB
Ruby

#
# Copyright (C) 2006-2020 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
class Treetop::Runtime::SyntaxNode
# An alias which can be used inside a derived cpp implementation
# The default implementation collects all objects emitted by the subnodes.
def get_cpp
a = elements && elements.collect { |e| e.cpp }.select { |e| e }.flatten
(a && !a.empty?) ? a : nil
end
# Returns the CPP objects emitted by this node.
# This method delivers CPP objects or arrays of CPP objects.
def cpp
get_cpp
end
# Returns the single CPP object or nil
def cpp_reduced
a = self.cpp
if a.is_a?(Array)
a.size == 1 || raise("Internal error: more than one syntax tree node")
a = a[0]
end
a
end
# Note: this method is required because curly braces cannot be put
# into parser conditions (treetop syntax flaw?)
def text_value_ends_with_curly_brace
text_value =~ /\}$/
end
end
# These are a couple of emitter extensions to SyntaxNode which produce the definition syntax tree
# through the "cpp" method:
module PTypeOf
def cpp
CPPTypeOf::new(qid.cpp)
end
end
def extract_signed(t)
if t =~ /unsigned/
:unsigned
elsif t =~ /signed/
:signed
else
nil
end
end
def extract_length(t)
if t =~ /long long/
:longlong
elsif t =~ /long/
:long
elsif t =~ /short/
:short
else
nil
end
end
module PIntType
def cpp
CPPPOD::new(extract_signed(text_value), extract_length(text_value), :int)
end
end
module PCharType
def cpp
CPPPOD::new(extract_signed(text_value), nil, :char)
end
end
module PBoolType
def cpp
CPPPOD::new(nil, nil, :bool)
end
end
module PSpecialType
def cpp
# the special type produces an ID
CPPQualifiedId::new(false, [ CPPId::new(id.text_value, nil) ])
end
end
module PFloatType
def cpp
kind = text_value =~ /double/ ? :double : :float
CPPPOD::new(nil, extract_length(text_value), kind)
end
end
module PVoidType
def cpp
CPPPOD::new(nil, nil, :void)
end
end
module PEnumSpec
def cpp
CPPEnumSpec::new(id.text_value, initspec.nonterminal? ? initspec.init.text_value : nil)
end
end
module PEnumType
def cpp
name = id ? id.text_value : nil
specs = bodyspec.nonterminal? ? bodyspec.body.cpp : nil
CPPEnum::new(name, specs)
end
end
module PConst
def cpp
CPPConst::new(text_value)
end
end
module PTemplateArgs
def cpp
decl = self.get_cpp
decl ? CPPTemplateArgs::new(decl) : nil
end
end
module PId
def cpp
CPPId::new(id.text_value, taspec.nonterminal? ? taspec.ta.cpp_reduced : nil)
end
end
module PQualifiedId
def cpp
CPPQualifiedId::new(globalspec.nonterminal?, self.get_cpp)
end
end
module PBaseClass
def cpp
visibility = nil
virtual = false
at = attr.text_value
if at =~ /private/
visibility = :private
elsif at =~ /public/
visibility = :public
elsif at =~ /protected/
visibility = :protected
end
if at =~ /virtual/
virtual = true
end
CPPBaseClass::new(visibility, virtual, cid.cpp_reduced)
end
end
module PStructOrClassType
def cpp
kind = :class
if stype.text_value == "struct"
kind = :struct
elsif stype.text_value == "union"
kind = :union
end
id = idspec.nonterminal? ? idspec.id.cpp_reduced : nil
base_classes = bcspec.nonterminal? ? bcspec.bc.cpp : nil
body_decl = bodyspec.nonterminal? ? bodyspec.body.cpp : nil
CPPStruct::new(kind, id, base_classes, body_decl)
end
end
module PCV
def to_symbol
return self.text_value == "const" ? :const : :volatile
end
end
module PFriendDecl
def cpp
CPPFriendDecl::new(t.cpp)
end
end
module PPointer
def cpp
CPPCV::wrap(cvspec.nonterminal? && cvspec.cv.to_symbol, CPPPointer::new(itspec.nonterminal? ? itspec.it.cpp_reduced : CPPAnonymousId::new))
end
end
module PReference
def cpp
CPPCV::wrap(cvspec.nonterminal? && cvspec.cv.to_symbol, CPPReference::new(itspec.nonterminal? ? itspec.it.cpp_reduced : CPPAnonymousId::new))
end
end
module PMemberPointer
def cpp
CPPMemberPointer::new(cspec.qid.cpp, itspec.nonterminal? ? itspec.it.cpp_reduced : CPPAnonymousId::new, cvspec.nonterminal? && cvspec.cv.to_symbol)
end
end
module PArraySpec
def cpp
CPPArray::new(nil)
end
end
module PFuncArgPart
def cpp
t.cpp_reduced
end
end
module PFuncSpec
def cpp
CPPFunc::new(nil, (fa.nonterminal? && fa.text_value != "void") ? (fa.a.cpp || []) : [], cvspec.nonterminal? && cvspec.cv.to_symbol)
end
end
module PInnerTypeWithCV
def cpp
CPPCV::wrap(cvspec.to_symbol, it.cpp_reduced)
end
end
module PInnerType
def cpp
if pfx.nonterminal?
pfx.elements.inject(it.cpp_reduced) do |r,e|
ee = e.spec.cpp_reduced
ee.inner = r
ee
end
else
it.cpp
end
end
end
module PStorageClass
def cpp
if text_value =~ /^static/
return CPPAttr::new(:static)
elsif text_value =~ /^extern/
return CPPAttr::new(:extern)
else
return nil
end
end
end
module PVirtual
def cpp
return CPPAttr::new(:virtual)
end
end
module PInline
def cpp
return CPPAttr::new(:inline)
end
end
module PType
def cpp
# This is the class/struct/union/enum declaration if there is one
d = ct.cpp
if d.is_a?(Array)
r = d.select { |i| i.is_a?(CPPStruct) || i.is_a?(CPPEnum) }
elsif d.is_a?(CPPStruct) || d.is_a?(CPPEnum)
r = [d]
else
r = []
end
# Create each declaration
ot = CPPCV::wrap(cvspec.nonterminal? && cvspec.cv.to_symbol, ct.cpp_reduced)
if il.nonterminal?
r << CPPType::new(ot, il.t1.cpp_reduced, il.i1.nonterminal? ? il.i1.is1.text_value : nil)
il.tt.elements.each do |t|
r << CPPType::new(ot, t.t2.cpp_reduced, t.i2.nonterminal? ? t.i2.is2.text_value : nil)
end
else
r << CPPType::new(ot, CPPAnonymousId::new, pi.nonterminal? ? pi.is.text_value : nil)
end
r
end
end
module PEllipsis
def cpp
CPPEllipsis::new
end
end
module PTypeWoComma
def cpp
ot = CPPCV::wrap(cvspec.nonterminal? && cvspec.cv.to_symbol, ct.cpp_reduced)
if il.nonterminal?
CPPType::new(ot, il.t.cpp_reduced, il.i.nonterminal? ? il.i.is.text_value : nil)
else
CPPType::new(ot, CPPAnonymousId::new, pi.nonterminal? ? pi.is.text_value : nil)
end
end
end
module PTypeForTemplate
def cpp
ot = CPPCV::wrap(cvspec.nonterminal? && cvspec.cv.to_symbol, ct.cpp_reduced)
CPPType::new(ot, il.nonterminal? ? il.t.cpp_reduced : CPPAnonymousId::new, nil)
end
end
module PUsing
def cpp
CPPUsingSpec::new(id.cpp_reduced, :default)
end
end
module PTypedef
def cpp
t.cpp.collect do |d|
if d.is_a?(CPPStruct)
CPPStructDeclaration::new(d, nil, :default)
elsif d.is_a?(CPPEnum)
CPPEnumDeclaration::new(d, :default)
else
CPPTypedef::new(d, :default)
end
end
end
end
module PPrivateClassStructBodyDeclarations
def cpp
decl = d.cpp
decl && decl.collect do |d|
if d.respond_to?(:visibility)
d.visibility = :private
end
d
end
end
end
module PProtectedClassStructBodyDeclarations
def cpp
decl = d.cpp
decl && decl.collect do |d|
if d.respond_to?(:visibility)
d.visibility = :protected
end
d
end
end
end
module PPublicClassStructBodyDeclarations
def cpp
decl = d.cpp
decl && decl.collect do |d|
if d.respond_to?(:visibility)
d.visibility = :public
end
d
end
end
end
module PTemplateDecl
def cpp
CPPTemplateDecl::new(self.get_cpp)
end
end
module PClassTemplateArg
def cpp
CPPClassTemplateArg::new(id.text_value, dtspec.nonterminal? ? dtspec.cpp : nil)
end
end
module PDirectTemplateArg
def cpp
CPPDirectTemplateArg::new(t.cpp, initspec.nonterminal? ? initspec.text_value : nil)
end
end
module PDeclaration
def cpp
td = nil
if template.nonterminal?
td = template.d.cpp
end
storage_class = nil
virtual = nil
inline = nil
if attr.nonterminal? && attr.cpp
attr.cpp.each do |d|
if d.attr == :virtual
virtual = true
elsif d.attr == :inline
inline = true
elsif d.attr == :static
storage_class = :static
elsif d.attr == :extern
storage_class = :extern
end
end
end
# TODO: abstract declaration determination should be based on initializers on the
# inner types
t.cpp.collect do |d|
if d.is_a?(CPPStruct)
CPPStructDeclaration::new(d, td, :default)
elsif d.is_a?(CPPEnum)
CPPEnumDeclaration::new(d, :default)
else
CPPDeclaration::new(d, td, :default, storage_class, virtual, inline)
end
end
end
end
module PExternBlock
def cpp
self.get_cpp.collect do |d|
if d.is_a?(CPPDeclaration)
d.storage_class = :extern
end
d
end
end
end
module PNamespace
def cpp
CPPNamespace::new(n.text_value, decls.cpp || [])
end
end
module PModule
def cpp
CPPModule::new(self.get_cpp)
end
end