mirror of https://github.com/KLayout/klayout.git
577 lines
12 KiB
Ruby
577 lines
12 KiB
Ruby
|
|
#
|
|
# Copyright (C) 2006-2024 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 CPPObject
|
|
|
|
# Propagate setting of the visibility down to the children
|
|
# (set_visibility will replace the default visibility with public or private)
|
|
def set_visibility
|
|
end
|
|
|
|
# Inject scoped objects (like "class A::B { ... };") into their target
|
|
# scope.
|
|
def inject_scoped
|
|
end
|
|
|
|
# delivers a string representation of the name or nil if the object does not have a name
|
|
# to contribute
|
|
def myself
|
|
nil
|
|
end
|
|
|
|
# delivers a string representation of the "weak" name or nil if the object does not have a name
|
|
# to contribute. "weak names" are such of second order - e.g. forward declarations.
|
|
def myself_weak
|
|
nil
|
|
end
|
|
|
|
# delivers a CPPQualifiedId representation of the object's location or nil if the object
|
|
# does not have a location to contribute
|
|
def myid
|
|
nil
|
|
end
|
|
|
|
# sets the CPPQualifiedId
|
|
def setid(id)
|
|
end
|
|
|
|
# supposed to establish the parent link
|
|
def set_parent(p)
|
|
end
|
|
|
|
# removes a child from our members
|
|
def remove(d)
|
|
end
|
|
|
|
# inserts a child into our members
|
|
def insert(d)
|
|
end
|
|
|
|
end
|
|
|
|
class CPPType
|
|
|
|
def func
|
|
i = self
|
|
while i.respond_to?(:inner)
|
|
if i.is_a?(CPPFunc) && (i.inner.is_a?(CPPQualifiedId) || i.inner.is_a?(CPPAnonymousId))
|
|
return i
|
|
end
|
|
i = i.inner
|
|
end
|
|
nil
|
|
end
|
|
|
|
def return_type
|
|
rt = self.dup
|
|
f = self.func
|
|
if f
|
|
i = self
|
|
idup = rt
|
|
while i.respond_to?(:inner)
|
|
i = i.inner
|
|
if i == f
|
|
idup.inner = CPPAnonymousId::new
|
|
break
|
|
end
|
|
idup.inner = i.dup
|
|
idup = idup.inner
|
|
end
|
|
end
|
|
rt
|
|
end
|
|
|
|
def name_substituted_type(sub)
|
|
rt = self.dup
|
|
i = self
|
|
idup = rt
|
|
while i.respond_to?(:inner)
|
|
ii = i.inner
|
|
if ii.is_a?(CPPQualifiedId) || ii.is_a?(CPPAnonymousId)
|
|
idup.inner = sub
|
|
break
|
|
end
|
|
i = ii
|
|
idup.inner = i.dup
|
|
idup = idup.inner
|
|
end
|
|
rt
|
|
end
|
|
|
|
def anonymous_type
|
|
name_substituted_type(CPPAnonymousId::new)
|
|
end
|
|
|
|
def renamed_type(name)
|
|
name_substituted_type(CPPQualifiedId::new(false, [name]))
|
|
end
|
|
|
|
def name
|
|
i = self
|
|
while i.respond_to?(:inner)
|
|
ii = i.inner
|
|
if ii.is_a?(CPPQualifiedId)
|
|
return ii.to_s
|
|
end
|
|
i = ii
|
|
end
|
|
nil
|
|
end
|
|
|
|
def is_void?
|
|
self.concrete.is_a?(CPPPOD) && self.concrete.to_s == "void" && (self.inner.is_a?(CPPAnonymousId) || self.inner.is_a?(CPPQualifiedId))
|
|
end
|
|
|
|
end
|
|
|
|
module QualifiedNameResolver
|
|
|
|
attr_accessor :parent
|
|
|
|
def global_scope
|
|
o = self
|
|
while o.myself && o.parent
|
|
o = o.parent
|
|
end
|
|
o
|
|
end
|
|
|
|
# requirements
|
|
# - children -> must deliver a list of child objects
|
|
# - myself -> must deliver my name
|
|
|
|
def set_parent(parent = nil)
|
|
self.parent = parent
|
|
@id2obj = {}
|
|
self.children.each do |d|
|
|
d.myself && (@id2obj[d.myself] = d)
|
|
end
|
|
self.children.each do |d|
|
|
d.myself_weak && (@id2obj[d.myself_weak] ||= d)
|
|
end
|
|
self.children.each do |d|
|
|
d.set_parent(self)
|
|
end
|
|
# Add other children, for example contributed by base classes
|
|
if self.respond_to?(:other_children)
|
|
self.other_children.each do |d|
|
|
d.myself && (@id2obj[d.myself] = d)
|
|
end
|
|
end
|
|
end
|
|
|
|
def dump_ids
|
|
@id2obj.keys.sort.each do |k|
|
|
puts("--> #{k}")
|
|
end
|
|
end
|
|
|
|
# by default the objects don't have a weak identity
|
|
def myself_weak
|
|
nil
|
|
end
|
|
|
|
# returns a list of names of child objects
|
|
def ids
|
|
(@id2obj || {}).keys.sort
|
|
end
|
|
|
|
def id2obj(id)
|
|
@id2obj && @id2obj[id]
|
|
end
|
|
|
|
def resolve_qid(qid, stop = nil, include_other = true)
|
|
|
|
qid.is_a?(CPPQualifiedId) || raise("Argument of resolve_qid must be a CPPQualifiedId object")
|
|
|
|
obj = nil
|
|
if qid.global && self.parent
|
|
root = self
|
|
while root.parent
|
|
root = root.parent
|
|
end
|
|
obj = root.resolve_qid(qid, nil, false)
|
|
else
|
|
obj = id2obj(qid.parts[0].id)
|
|
if obj && qid.parts.size > 1
|
|
# The part may be a typedef: resolve it in that case before we proceed
|
|
while obj && obj.is_a?(CPPTypedef)
|
|
obj = obj.type.concrete.is_a?(CPPQualifiedId) && self.resolve_qid(obj.type.concrete, stop, include_other)
|
|
end
|
|
if obj
|
|
qid_new = qid.dup
|
|
qid_new.parts = qid.parts[1 .. -1]
|
|
obj = obj.respond_to?(:resolve_qid) && obj.resolve_qid(qid_new, stop, include_other)
|
|
end
|
|
end
|
|
if ! obj && include_other
|
|
# try base classes
|
|
self.other_children.each do |bc|
|
|
if bc != self && bc.respond_to?(:resolve_qid)
|
|
(obj = bc.resolve_qid(qid, self, false)) && break
|
|
end
|
|
end
|
|
end
|
|
if ! obj && self.parent && self.parent != stop
|
|
obj = self.parent.resolve_qid(qid, stop, include_other)
|
|
end
|
|
end
|
|
|
|
obj
|
|
|
|
end
|
|
|
|
def inject_scoped
|
|
|
|
self.children.each do |d|
|
|
|
|
d.inject_scoped
|
|
|
|
qid = d.myid
|
|
if qid
|
|
|
|
qid.is_a?(CPPQualifiedId) || raise("Argument of resolve_qid must be a CPPQualifiedId object")
|
|
|
|
if qid.parts.size > 1
|
|
|
|
qid = qid.dup
|
|
while qid.parts.size > 1
|
|
obj = id2obj(qid.parts[0].id)
|
|
if obj
|
|
qid.parts = qid.parts[1 .. -1]
|
|
else
|
|
break
|
|
end
|
|
end
|
|
|
|
if obj && qid.parts.size == 1
|
|
# This copies the visibility which is not quite correct, since the injection case
|
|
# is usually used for providing an implementation outside a class. That does not
|
|
# mean the outside implementation will provide the visibility. Instead a forward
|
|
# declaration inside the target scope will do. Since that is lost in our implementation
|
|
# currently that is not possible.
|
|
self.remove(d)
|
|
d.setid(qid)
|
|
obj.insert(d)
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
class CPPDeclaration
|
|
|
|
include QualifiedNameResolver
|
|
|
|
def children
|
|
[]
|
|
end
|
|
|
|
def other_children
|
|
[]
|
|
end
|
|
|
|
def myself
|
|
self.type.name
|
|
end
|
|
|
|
end
|
|
|
|
class CPPEnumDeclaration
|
|
|
|
include QualifiedNameResolver
|
|
|
|
def children
|
|
[]
|
|
end
|
|
|
|
def other_children
|
|
[]
|
|
end
|
|
|
|
def myself
|
|
# exclude forward declarations
|
|
self.enum.specs && self.enum.name.to_s
|
|
end
|
|
|
|
end
|
|
|
|
class CPPEnumSpec
|
|
|
|
include QualifiedNameResolver
|
|
|
|
def children
|
|
[]
|
|
end
|
|
|
|
def other_children
|
|
[]
|
|
end
|
|
|
|
def myself
|
|
self.name.to_s
|
|
end
|
|
|
|
end
|
|
|
|
class CPPStruct
|
|
|
|
attr_accessor :parent
|
|
|
|
def global_scope
|
|
self.parent && self.parent.global_scope
|
|
end
|
|
|
|
def set_visibility
|
|
|
|
(self.body_decl || []).each do |bd|
|
|
if bd.respond_to?(:visibility) && bd.visibility == :default
|
|
if self.kind == :struct || self.kind == :union
|
|
bd.visibility = :public
|
|
else
|
|
bd.visibility = :private
|
|
end
|
|
end
|
|
bd.set_visibility
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
class CPPTypedef
|
|
|
|
include QualifiedNameResolver
|
|
|
|
def myself
|
|
self.type.name
|
|
end
|
|
|
|
def children
|
|
[]
|
|
end
|
|
|
|
def other_children
|
|
[]
|
|
end
|
|
|
|
end
|
|
|
|
class CPPStructDeclaration
|
|
|
|
include QualifiedNameResolver
|
|
|
|
def children
|
|
|
|
# take this chance to set the parent to struct
|
|
self.struct.parent = self
|
|
c = self.struct.body_decl || []
|
|
|
|
# add enum constants (CPPEnumSpec)
|
|
(self.struct.body_decl || []).each do |bd|
|
|
if bd.is_a?(CPPEnumDeclaration) && bd.enum && bd.enum.specs && !bd.enum.is_class
|
|
c += bd.enum.specs
|
|
end
|
|
end
|
|
|
|
c
|
|
|
|
end
|
|
|
|
def remove(d)
|
|
self.struct.body_decl && self.struct.body_decl.delete(d)
|
|
end
|
|
|
|
def insert(d)
|
|
self.struct.body_decl ||= []
|
|
self.struct.body_decl << d
|
|
end
|
|
|
|
def other_children
|
|
|
|
# add base classes both as sub-namespace and individual parts
|
|
# and add self so scoping is possible into ourself
|
|
c = [ self ]
|
|
|
|
(self.struct.base_classes || []).each do |bc|
|
|
# The parent may be null for template base classes which are
|
|
# forward-declared .. we're not interested in this case.
|
|
if self.parent
|
|
bc_obj = self.parent.resolve_qid(bc.class_id, nil, false)
|
|
# NOTE: it may look strange to test whether the base class is the class itself but
|
|
# since we do a half-hearted job of resolving template variants, this may happen
|
|
# if we derive a template specialization from another one (specifically
|
|
# "template<class T> struct is_default_constructible : is_default_constructible<> { .. }"
|
|
if bc_obj != self && bc_obj.is_a?(CPPStructDeclaration)
|
|
c << bc_obj
|
|
c += bc_obj.children
|
|
c += bc_obj.other_children
|
|
end
|
|
end
|
|
end
|
|
|
|
c
|
|
|
|
end
|
|
|
|
def myself_weak
|
|
# the weak identity will also include forward declarations
|
|
self.struct.id.to_s
|
|
end
|
|
|
|
def myself
|
|
# forward declarations (struct.body_decl == nil and no base classes) don't produce a name and
|
|
# will therefore not contribute
|
|
(self.struct.body_decl || self.struct.base_classes) && self.struct.id.to_s
|
|
end
|
|
|
|
def myid
|
|
# forward declarations (struct.body_decl == nil and no base classes) don't produce a name and
|
|
# will therefore not contribute
|
|
(self.struct.body_decl || self.struct.base_classes) && self.struct.id
|
|
end
|
|
|
|
def setid(id)
|
|
self.struct.id = id
|
|
end
|
|
|
|
def set_visibility
|
|
self.struct && self.struct.set_visibility
|
|
end
|
|
|
|
end
|
|
|
|
class CPPNamespace
|
|
|
|
include QualifiedNameResolver
|
|
|
|
def children
|
|
|
|
# take this opportunity to join identical namespaces
|
|
if self.members
|
|
new_members = []
|
|
ns = {}
|
|
self.members.each do |d|
|
|
if d.is_a?(CPPNamespace)
|
|
if !ns[d.myself]
|
|
ns[d.myself] = d
|
|
new_members << d
|
|
else
|
|
ns[d.myself].members += d.members
|
|
end
|
|
else
|
|
new_members << d
|
|
end
|
|
end
|
|
self.members = new_members
|
|
end
|
|
|
|
self.members || []
|
|
|
|
end
|
|
|
|
def other_children
|
|
# add self so scoping is possible into ourself
|
|
[ self ]
|
|
end
|
|
|
|
def myself
|
|
self.name.to_s
|
|
end
|
|
|
|
def remove(d)
|
|
self.members.delete(d)
|
|
end
|
|
|
|
def insert(d)
|
|
self.members << d
|
|
end
|
|
|
|
def set_visibility
|
|
|
|
(self.members || []).each do |m|
|
|
if m.respond_to?(:visibility) && m.visibility == :default
|
|
m.visibility = :public
|
|
end
|
|
m.set_visibility
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
class CPPModule
|
|
|
|
include QualifiedNameResolver
|
|
|
|
def children
|
|
|
|
# take this opportunity to join identical namespaces
|
|
new_decls = []
|
|
ns = {}
|
|
self.decls.each do |d|
|
|
if d.is_a?(CPPNamespace)
|
|
if !ns[d.myself]
|
|
ns[d.myself] = d
|
|
new_decls << d
|
|
else
|
|
ns[d.myself].members += d.members
|
|
end
|
|
else
|
|
new_decls << d
|
|
end
|
|
end
|
|
|
|
self.decls = new_decls
|
|
|
|
end
|
|
|
|
def other_children
|
|
[]
|
|
end
|
|
|
|
def remove(d)
|
|
self.decls.delete(d)
|
|
end
|
|
|
|
def insert(d)
|
|
self.decls << d
|
|
end
|
|
|
|
def myself
|
|
nil
|
|
end
|
|
|
|
def set_visibility
|
|
(self.decls || []).each do |d|
|
|
if d.respond_to?(:visibility) && d.visibility == :default
|
|
d.visibility = :public
|
|
end
|
|
d.set_visibility
|
|
end
|
|
end
|
|
|
|
end
|