#!/usr/bin/env python ############################################################################# # Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1997, 1998, 1999 # All Rights Reserved. # # The software contained on this media is the property of the DSTC Pty # Ltd. Use of this software is strictly in accordance with the # license agreement in the accompanying LICENSE.HTML file. If your # distribution of this software does not contain a LICENSE.HTML file # then you have no rights to use this software in any manner and # should contact DSTC at the address below to determine an appropriate # licensing arrangement. # # DSTC Pty Ltd # Level 7, GP South # Staff House Road # University of Queensland # St Lucia, 4072 # Australia # Tel: +61 7 3365 4310 # Fax: +61 7 3365 4311 # Email: enquiries@dstc.edu.au # # This software is being provided "AS IS" without warranty of any # kind. In no event shall DSTC Pty Ltd be liable for damage of any # kind arising out of or in connection with the use or performance of # this software. # # Project: Fnorb # File: $Source: /cvsroot/fnorb/fnorb/parser/IDLParser.py,v $ # Version: @(#)$RCSfile: IDLParser.py,v $ $Revision: 1.25 $ # ############################################################################# """ Parser for OMG IDL. """ # Standard/built-in modules. import new, string, sys, types # Fnorb modules. from Fnorb.orb import CORBA, Fixed, Limits, Util # Fnorb extension modules. use_bison = 1 try: import bison except ImportError: use_bison = 0 # YAPPS parser import idl # Parser modules. import Declarator, Prefix, Stack class IDLParser: """ Parser for OMG IDL. This class implements the semantic actions for the IDL parser. The actual parsing engine is implemented in 'C' using 'flex' and 'bison'. """ ######################################################################### # Parser interface. ######################################################################### def parse(self, repository, filename, yyin): """ Parse some IDL! 'repository' is the interface repository (IFR) to be populated. 'filename' is the filename of the top-level IDL file. 'yyin' is an open file object to read the IDL from. """ if use_bison: return self.parse_bison(repository, filename, yyin) else: return self.parse_yapps(repository, filename, yyin) def parse_bison(self, repository, filename, yyin): self.__repository = repository self.__filename = filename # Initialise the various data structures used during parsing. self.__initialise() # Do the parsing! result = bison.yyparse(self, yyin) # Clean up! self.__cleanup() return (result, self.__top_level_definitions) def parse_yapps(self, repository, filename, yyin): """ Parse some IDL! 'repository' is the interface repository (IFR) to be populated. 'filename' is the filename of the top-level IDL file. 'yyin' is an open file object to read the IDL from. """ # Tokenize from a file-like object text = yyin.read()+'$' tokens = idl.IDLScanner(text) tokens.p = self return self._parse_yapps(repository, filename, tokens, text = text) def parse_tokenized(self, repository, filename, preprocessor): # Tokenize from a parser.cpp.Preprocessor import cpp try: tokens = idl.TokenizedScanner(preprocessor) except cpp.SyntaxError, e: print "SyntaxError:" + e.args[0] return (1, None) tokens.p = self return self._parse_yapps(repository, filename, tokens) def _parse_yapps(self, repository, filename, tokens, text = None): self.__repository = repository self.__filename = filename # Initialise the various data structures used during parsing. self.__initialise() # Do the parsing! parser = idl.IDLParser(tokens) parser.p = self global bison bison = tokens # to support bison try: parser.start() result = 0 except idl.SyntaxError,e: line = tokens.yyfileandlineno() if type(line) is types.TupleType: file, line = line else: file = self.__current_file print "%s:%s:%s" % (file, line, e.msg) # Can't rely on e.pos: it is sometimes character position, # sometimes token number # p = e.pos try: p = tokens.tokens[parser._pos][0] except IndexError: p = -1 if p != -1 and type(p) is not types.TupleType and text: left = string.rfind(text, '\n', max(p-80,0),p) right = string.find(text, '\n', p, p+80) line = text[left+1:right] # this takes into account -1 results p = p - left - 1 l1 = line[:p] l2 = line[p:] l1 = string.expandtabs(l1) p = len(l1) line = l1 + l2 while p > 60: # Cut off 10 chars line = "..."+line[10:] p = p - 7 print "> "+line print "> "+" "*p+"^" print "List of nearby tokens",tokens result = 1 # Clean up! self.__cleanup() return (result, self.__top_level_definitions) def yyerror(self, message): """ Error function called from the 'bison' parser. """ sys.stderr.write("Error: %s on line %d of %s\n" % \ (message, bison.yylineno(), self.__current_file)) return def yywarning(self, message): """ Warning function. """ sys.stderr.write("Warning: %s on line %d of %s\n" % \ (message, bison.yylineno(), self.__current_file)) return ######################################################################### # Semantic actions (called from 'grammar.y'). ######################################################################### def specification_start(self): """ specification: """ # The container stack initially contains just the repository. self.__container_stack = Stack.Stack() self.__container_stack.push(self.__repository) return def specification_end(self): """ specification: definition_PLUS """ # Report an error for any interfaces that were 'forward' declared but # not defined! self.__check_forward_interfaces() # Pop the repository from the container stack, and make sure that the # stack really is empty! self.__container_stack.pop() assert(len(self.__container_stack) == 0) return def module_header(self, name): """ MODULE IDENTIFIER """ # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() # Does the container already contain a definition with this name? module = container.lookup(name) # If there is *no* definition with this name then we can safely create # a new module. if module is None: # Currently the version is always "1.0"! version = "1.0" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create a new module definition in the container. module = container.create_module(ifr_id, name, version) # If the module is defined at the global scope of the top-level IDL # file then add it to our list of top-level definitions. if self.__is_a_top_level_definition(module): self.__top_level_definitions.append(module) # Otherwise, a definition with this name already exists. else: # If it is a module definition then we just "re-open" it to allow # more definitions to be added. If it is not a module definition # then it is illegal! if module._get_def_kind() != CORBA.dk_Module: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR # If the module is defined at the global scope of the top-level IDL # file then add it to our list of top-level definitions. # # We have to do this here as the first occurence of the module may # have been in a file that was '#included'. if self.__is_a_top_level_definition(module): self.__top_level_definitions.append(module) # fixme: Check for ID compatability in the case of '#pragma ID'? pass # Push the module onto the container stack. self.__container_stack.push(module) # Push the new prefix onto the prefix stack. self.__prefix_stack.push(self.__create_prefix(prefix, name)) return def module_body(self): """ '{' definition_STAR '}' """ # Pop the container and prefix from the stacks. self.__container_stack.pop() self.__prefix_stack.pop() return def interface_dcl_header(self, (abstract, name), base_interfaces): """ [ABSTRACT|LOCAL] INTERFACE IDENTIFIER interface_inheritance_spec_OPT """ assert abstract is None # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() # Does the container already contain a definition with this name? interface = container.lookup(name) # If there is *no* definition with this name then we can safely create # a new interface. if interface is None: # Currently the version is always "1.0"! version = "1.0" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create a new interface definition in the container. interface = container.create_interface(ifr_id, name, version, []) # If the interface is defined at the global scope of the top-level # IDL file then add it to our list of top-level definitions. if self.__is_a_top_level_definition(interface): self.__top_level_definitions.append(interface) # Otherwise, a definition with this name already exists. else: # If it is *not* an interface definition then it is definitely # illegal! if interface._get_def_kind() != CORBA.dk_Interface: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR # If it *is* an interface definition then it must be a forward # declaration. If not then it is also illegal! if interface._get_version() != 'forward': self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR # fixme: Check for ID compatability in the case of '#pragma ID'? pass # 'Move' the interface definition to the same container (this has # the side-effect of placing it last in the containers list of # contents ;^) interface.move(container, name, "1.0") # Delete the interface from the dictionary containing forward # declared but undefined interfaces, del self.__forward_interfaces[interface._get_id()] # Check the base interfaces. for base in base_interfaces: # Make sure that the base interface is not a forward delcaration. if base._get_version() == 'forward': self.yyerror("Interface '%s' not defined" % base._get_name()) raise bison.YYERROR # Make sure that some poor shmuck is not attempting to make the # interface inherit from itself! # # fixme: Will this work in the presence of '#pragma ID'? if base._get_id() == interface._get_id(): self.yyerror("Interface '%s' inherits from itself!" % name) raise bison.YYERROR # Update the list of base interfaces. interface._set_base_interfaces(base_interfaces) # Push the interface onto the container stack. self.__container_stack.push(interface) # Push a new prefix onto the prefix stack. self.__prefix_stack.push(self.__create_prefix(prefix, name)) return interface def interface_dcl_body(self, interface): """ '{' export_STAR '}' """ # Get the interface description. description = interface.describe_interface() # Get the names of all of the interface's operations and attributes. names = map(lambda o: o.name, description.operations) names = names + map(lambda a: a.name, description.attributes) # Add the interface to the interface dictionary. self.__interfaces[interface._get_id()] = names # Get the names of all inherited operations and attributes. inherited = self.__get_inherited_operations(interface, []) # Make sure there are no clashes! if len(inherited) > 0: for name in names: if name in inherited: self.yyerror("Overloaded operation/attribute '%s'" % name) raise bison.YYERROR # Pop the container and prefix from the stacks. self.__container_stack.pop() self.__prefix_stack.pop() return def foward_dcl(self, (abstract, name)): """ forward_dcl: [ABSTRACT|LOCAL] INTERFACE IDENTIFIER """ assert abstract is None # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() # Does the container already contain a definition with this name? interface = container.lookup(name) # If there is *no* definition with this name then we can safely create # a new interface. if interface is None: # Currently the version is always "1.0"! version = "1.0" # Generate a repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create a new interface definition in the container and tag it # with a version of "forward". interface = container.create_interface(ifr_id, name, "forward", []) # If the interface is defined at the global scope of the top-level # IDL file then add it to our list of top-level definitions. if self.__is_a_top_level_definition(interface): self.__top_level_definitions.append(interface) # Add the interface to the dictionary of forward declared but # undefined interfaces. self.__forward_interfaces[ifr_id] = (interface, bison.yylineno()) # Otherwise, a definition with this name already exists. else: # If it is *not* an interface definition then it is illegal! if interface._get_def_kind() != CORBA.dk_Interface: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR # fixme: Check for ID compatability in the case of '#pragma ID'? pass return def interface_inheritance_spec_empty(self): """ interface_inheritance_spec: /* empty */ """ return [] # [InterfaceDef] def interface_inheritance_spec_full(self, scoped_names): """ interface_inheritance_spec: ':' scoped_name_CSV_PLUS """ # Get the container from the stack. container = self.__container_stack.get() # Find the interface definition for each scoped name. base_interfaces = [] for scoped_name in scoped_names: # Lookup the definition. interface = self.__find_scoped_name(container, scoped_name) if interface is None: raise bison.YYERROR # If it is *not* an interface definition then it is illegal! if interface._get_def_kind() != CORBA.dk_Interface: self.yyerror("'%s' is not an interface" % scoped_name) raise bison.YYERROR base_interfaces.append(interface) return base_interfaces def value_dcl_header(self, (abstract, name), (base_values, supported_interface_names)): """ [ABSTRACT|CUSTOM] INTERFACE IDENTIFIER value_inheritance_spec """ # could be "abstract", "custom", or None is_abstract = abstract == "abstract" is_custom = abstract == "custom" # Don't know the initializers yet initializers = [] # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() # could be None, or (truncatable, base_values) if base_values is None: is_truncatable = CORBA.FALSE base_value = None base_values = [] abstract_base_values = [] else: is_truncatable, bases = base_values base_values = [] for scoped_name in bases: # Lookup the definition. value = self.__find_scoped_name(container, scoped_name) if value is None: raise bison.YYERROR # If it is not a value then it is illegal! if value._get_def_kind() != CORBA.dk_Value: self.yyerror("'%s' is not a valuetype" % scoped_name) raise bison.YYERROR base_values.append(value) if not base_values[0]._get_is_abstract(): # the first base might be concrete base_value = base_values[0] abstract_base_values = base_values[1:] else: base_value = None abstract_base_values = base_values if is_truncatable: self.yyerror("'%s' has an abstract truncatable base" % scoped_name) raise bison.YYERROR # make sure bases are abstract for value in abstract_base_values: if not value._get_is_abstract(): self.yyerror("'%s' is not abstract" % value._get_name()) # could be None or list of scoped names if supported_interface_names is None: supported_interface_names = [] supported_interfaces = [] for scoped_name in supported_interface_names: # Lookup the definition. interface = self.__find_scoped_name(container, scoped_name) if value is None: raise bison.YYERROR # If it is not an interface then it is illegal! if value._get_def_kind() != CORBA.dk_Interface: self.yyerror("'%s' is not a valuetype" % scoped_name) raise bison.YYERROR supported_interfaces.append(interface) # Does the container already contain a definition with this name? value = container.lookup(name) # If there is *no* definition with this name then we can safely create # a new valuetype. if value is None: # Currently the version is always "1.0"! version = "1.0" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create a new value definition in the container. value = container.create_value(ifr_id, name, version, is_custom, is_abstract, base_value, is_truncatable, abstract_base_values, supported_interfaces, initializers) # If the value is defined at the global scope of the top-level # IDL file then add it to our list of top-level definitions. if self.__is_a_top_level_definition(value): self.__top_level_definitions.append(value) # Otherwise, a definition with this name already exists. else: # If it is *not* an value definition then it is definitely # illegal! if value._get_def_kind() != CORBA.dk_Value: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR # If it *is* an value definition then it must be a forward # declaration. If not then it is also illegal! if value._get_version() != 'forward': self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR # fixme: Check for ID compatability in the case of '#pragma ID'? pass # 'Move' the value definition to the same container (this has # the side-effect of placing it last in the containers list of # contents ;^) value.move(container, name, "1.0") # Delete the value from the dictionary containing forward # declared but undefined value, del self.__forward_interfaces[value._get_id()] # Check the base values. for base in base_values: # Make sure that the base value is not a forward delcaration. if base._get_version() == 'forward': self.yyerror("Value '%s' not defined" % base._get_name()) raise bison.YYERROR # Make sure that some poor shmuck is not attempting to make the # value inherit from itself! # # fixme: Will this work in the presence of '#pragma ID'? if base._get_id() == value._get_id(): self.yyerror("Value '%s' inherits from itself!" % name) raise bison.YYERROR # Update the list of base interfaces. # XXX already done during creation # interface._set_base_interfaces(base_interfaces) # Push the interface onto the container stack. self.__container_stack.push(value) # Push a new prefix onto the prefix stack. self.__prefix_stack.push(self.__create_prefix(prefix, name)) # Return a the value, and a list to collect initializers in return value, [] def value_dcl_body(self, (value, initializers)): """ '{' export_STAR '}' """ # Get the value description. description = value.describe_value() # Get the names of all of the value's operations and attributes. names = map(lambda o: o.name, description.operations) names = names + map(lambda a: a.name, description.attributes) # XXX check supported interfaces. What constraints? # Add the interface to the interface dictionary. self.__interfaces[value._get_id()] = names # Get the names of all inherited operations and attributes. inherited = self.__get_inherited_operations(value, []) # Make sure there are no clashes! if len(inherited) > 0: for name in names: if name in inherited: self.yyerror("Overloaded operation/attribute '%s'" % name) raise bison.YYERROR # Pop the container and prefix from the stacks. self.__container_stack.pop() self.__prefix_stack.pop() return def value_box_dcl(self, (abstract, name), type_def): """ value_box_dcl: VALUETYPE IDENTIFIER type_spec""" # Verify we are not trying to build an abstract box. if abstract is not None: self.yyerror("'%s' not allowed for value boxes" % abstract) raise bison.YYERROR # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() # Does the container already contain a definition with this name? box = container.lookup(name) # If there is *no* definition with this name then we can safely create # a new valuebox. if box is None: # Currently the version is always "1.0"! version = "1.0" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create a new valuebox definition in the container. box = container.create_value_box(ifr_id, name, version, type_def) # If the valuebox is defined at the global scope of the top-level # IDL file then add it to our list of top-level definitions. if self.__is_a_top_level_definition(box): self.__top_level_definitions.append(box) # Otherwise, a definition with this name already exists. else: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR return box def state_member(self, public, type_def, declarators): """ state_member: [PUBLIC|PRIVATE] type_spec declarators ; """ # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() if public == "public": visibility = CORBA.PUBLIC_MEMBER else: visibility = CORBA.PRIVATE_MEMBER members = [] for declarator in declarators: # If this is an array declarator. if isinstance(declarator, Declarator.ArrayDeclarator): # Get the array dimensions. dimensions = declarator.dimensions() # Create the array type. actual_type_def = self.__create_array(type_def, dimensions) # Otherwise it is a simple declarator. else: actual_type_def = type_def name = declarator.name() # Currently the version is always "1.0"! version = "1.0" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create a new value member in the container. member = container.create_value_member(ifr_id, name, version, actual_type_def, visibility) members.append(member) return members def init_dcl(self, name, params, (value, initializers)): """ init_dcl: FACTORY name ( [init_param_dcls] ) ; """ members = [] for p in params: if p.mode != CORBA.PARAM_IN: self.yyerror("invalid parameter mode in factory") raise bison.YYERROR members.append(CORBA.StructMember(p.name, p.type, p.type_def)) initializers.append(CORBA.Initializer(members, name)) def scoped_name_absolute(self, identifier): """ scoped_name: SCOPE_DELIMITER IDENTIFIER """ return "::" + identifier def scoped_name_relative(self, scoped_name, identifier): """ scoped_name: scoped_name SCOPE_DELIMITER IDENTIFIER """ return scoped_name + "::" + identifier def const_dcl(self, type_def, name, any): """ const_dcl: CONST const_type IDENTIFIER '=' const_expr """ # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() # Does the container already contain a definition with this name? constant = container.lookup(name) # If there is *no* definition with this name then we can safely create # a new constant. if constant is None: # Make sure that the value is of the appropriate type. if not self.__check_constant_type(type_def, any): self.yyerror("Constant '%s' invalid value type" % name) raise bison.YYERROR # Make sure that the value is within the limits of the type, and # coerce it if necessary. (result, value) = self.__check_limits(type_def, any) if not result: self.yyerror("Constant '%s' out of range" % name) raise bison.YYERROR # Wrap the coerced value back in an 'Any' of the appropriate type. any = CORBA.Any(type_def._get_type(), value) # Currently the version is always "1.0"! version = "1.0" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create a new constant definition in the container. constant = container.create_constant(ifr_id, name, version, type_def, any) # If the constant is defined at the global scope of the top-level # IDL file then add it to our list of top-level definitions. if self.__is_a_top_level_definition(constant): self.__top_level_definitions.append(constant) # Otherwise, a definition with this name already exists. else: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR return constant # Valid types for constant expressions. __CONST_TYPES = [CORBA.pk_short, CORBA.pk_long, CORBA.pk_ushort, CORBA.pk_ulong, CORBA.pk_char, CORBA.pk_boolean, CORBA.pk_float, CORBA.pk_double, CORBA.pk_string, CORBA.pk_longlong, CORBA.pk_ulonglong, CORBA.pk_longdouble, CORBA.pk_wchar, CORBA.pk_wstring] def const_type_scoped_name(self, scoped_name): """ const_type: scoped_name """ # Get the container from the stack. container = self.__container_stack.get() # Lookup the definition referenced by the scoped name. definition = self.__find_scoped_name(container, scoped_name) # Unwind any 'typedef' chain. definition = self.__unwind_typedef_chain(definition) # Make sure that the definition is either:- # # 1) One of the following primitive types:- # # integer, char, wchar, boolean, floating point, string, wstring # # 2) Of type 'fixed'. if definition._get_def_kind() == CORBA.dk_Primitive \ and definition._get_kind() in IDLParser.__CONST_TYPES: pass elif definition._get_def_kind() == CORBA.dk_Fixed: pass else: self.yyerror("Invalid constant type '%s'" % scoped_name) raise bison.YYERROR return definition # The arguments to constant expression operators are 'Any's, and the # operations are implemented in the 'Any' module. def or_expr(self, x, y): """ or_expr: or_expr '|' xor_expr """ return x | y def xor_expr(self, x, y): """ xor_expr: xor_expr '^' and_expr """ return x ^ y def and_expr(self, x, y): """ and_expr: and_expr '&' shift_expr """ return x & y def shift_expr_right(self, x, y): """ shift_expr: shift_expr RIGHT_SHIFT add_expr """ return x >> y def shift_expr_left(self, x, y): """ shift_expr: shift_expr LEFT_SHIFT add_expr """ return x << y def add_expr_add(self, x, y): """ add_expr: add_expr '+' mult_expr """ return x + y def add_expr_subtract(self, x, y): """ add_expr: add_expr '-' mult_expr """ return x - y def mult_expr_multiply(self, x, y): """ mult_expr: mult_expr '*' unary_expr """ return x * y def mult_expr_divide(self, x, y): """ mult_expr: mult_expr '/' unary_expr """ return x / y def mult_expr_mod(self, x, y): """ mult_expr: mult_expr '%' unary_expr """ return x % y def unary_expr_neg(self, x): """ unary_expr: '-' primary_expr """ return -x def unary_expr_pos(self, x): """ unary_expr: '+' primary_expr """ return +x def unary_expr_invert(self, x): """ unary_expr: '~' primary_expr """ return ~x def primary_expr_scoped_name(self, scoped_name): """ primary_expr: scoped_name """ # Get the container from the stack. container = self.__container_stack.get() # Lookup the definition referenced by the scoped name. definition = self.__find_scoped_name(container, scoped_name) if definition is None: raise bison.YYERROR # If it is not a constant definition then it is illegal! if definition._get_def_kind() != CORBA.dk_Constant: self.yyerror("'%s' is not a constant expression" % scoped_name) raise bison.YYERROR # Return the constant's value (an 'Any'). return definition._get_value() def literal_integer_literal(self, value): """ literal: INTEGER_LITERAL """ # We get integer literals as the raw string token from the lexer. # # fixme: Should we do this for floating point literals as well? # All integer literals are converted to Python *long* integers and then # coerced back as appropriate. return CORBA.Any(CORBA.TC_longlong, eval(value + "L")) def literal_string_literal(self, value): """ literal: STRING_LITERAL """ # Evaluate the string containing the string! return CORBA.Any(CORBA.TC_string, eval(value)) def literal_character_literal(self, value): """ literal: CHARACTER_LITERAL """ # Evaluate the string containing the character! return CORBA.Any(CORBA.TC_char, eval(value)) def literal_fixed_pt_literal(self, value): """ literal: FIXED_PT_LITERAL """ # Fixed point values are instances of the 'Fixed' class. fixed = new.instance(Fixed.Fixed, {}) # Initialise the instance from the literal. fixed._fnorb_from_literal(value) return CORBA.Any(fixed._fnorb_typecode(), fixed) def literal_floating_pt_literal(self, value): """ literal: FLOATING_PT_LITERAL """ return CORBA.Any(CORBA.TC_double, value) def boolean_literal_true(self): """ boolean_literal: TRUE """ return CORBA.Any(CORBA.TC_boolean, 1) def boolean_literal_false(self): """ boolean_literal: FALSE """ return CORBA.Any(CORBA.TC_boolean, 0) def positive_int_const(self, any): """ positive_int_const: const_expr """ # Get the typecode's 'kind'. kind = any.typecode().kind() # Make sure that it really is a positive, integer ;^) if kind not in IDLParser.__TK_INT or any.value() < 0: self.yyerror("Positive integer value required") raise bison.YYERROR # Extract the value from the 'Any'. return any.value() def type_declarator(self, type_def, declarators): """ type_declarator: type_spec declarators """ # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() # Create a 'typedef' definition for each declarator. for declarator in declarators: # Get the name of the declarator. name = declarator.name() # Does the container already contain a definition with this name? definition = container.lookup(name) # If there is *no* definition with this name then we can safely # create a new 'typedef' definition. if definition is None: # Currently the version is always "1.0"! version = "1.0" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # If this is an array declarator. if isinstance(declarator, Declarator.ArrayDeclarator): # Get the array dimensions. dimensions = declarator.dimensions() # Create the array type. actual_type_def = self.__create_array(type_def, dimensions) # Otherwise it is a simple declarator. else: actual_type_def = type_def # Create a new 'typedef' definition in the container. definition = container.create_alias(ifr_id, name, version, actual_type_def) # If the 'typedef' is defined at the global scope of the # top-level IDL file then add it to our list of top-level # definitions. if self.__is_a_top_level_definition(definition): self.__top_level_definitions.append(definition) # Otherwise, a definition with this name already exists. else: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR return def simple_declarator(self, name): """ simple_declarator: IDENTIFIER """ return Declarator.SimpleDeclarator(name) def float_type(self): """ floating_pt_type: FLOAT """ return self.__repository.get_primitive(CORBA.pk_float) def double_type(self): """ floating_pt_type: DOUBLE """ return self.__repository.get_primitive(CORBA.pk_double) def longdouble_type(self): """ floating_pt_type: LONG DOUBLE """ return self.__repository.get_primitive(CORBA.pk_longdouble) def signed_short_int(self): """ signed_short_int: SHORT """ return self.__repository.get_primitive(CORBA.pk_short) def signed_long_int(self): """ signed_long_int: LONG """ return self.__repository.get_primitive(CORBA.pk_long) def signed_longlong_int(self): """ signed_longlong_int: LONG LONG""" return self.__repository.get_primitive(CORBA.pk_longlong) def unsigned_short_int(self): """ unsigned_short_int: UNSIGNED SHORT """ return self.__repository.get_primitive(CORBA.pk_ushort) def unsigned_long_int(self): """ unsigned_long_int: UNSIGNED LONG """ return self.__repository.get_primitive(CORBA.pk_ulong) def unsigned_longlong_int(self): """ unsigned_longlong_int: UNSIGNED LONG LONG""" return self.__repository.get_primitive(CORBA.pk_ulonglong) def char_type(self): """ char_type: CHAR """ return self.__repository.get_primitive(CORBA.pk_char) def wide_char_type(self): """ wide_char_type: WCHAR """ return self.__repository.get_primitive(CORBA.pk_wchar) def boolean_type(self): """ boolean_type: BOOLEAN """ return self.__repository.get_primitive(CORBA.pk_boolean) def octet_type(self): """ octet_type: OCTET """ return self.__repository.get_primitive(CORBA.pk_octet) def any_type(self): """ any_type: IDL_ANY """ return self.__repository.get_primitive(CORBA.pk_any) def object_type(self): """ object_type: OBJECT """ return self.__repository.get_primitive(CORBA.pk_objref) def struct_type_header(self, name): """ struct_type: STRUCT IDENTIFIER """ # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() # Does the container already contain a definition with this name? struct = container.lookup(name) # If there is *no* definition with this name then we can safely create # a new structure definition. if struct is None: # Set the version to "wip" (for Work In Progress) to allow the # detection of recursive types. version = "wip" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create a new structure definition in the container. struct = container.create_struct(ifr_id, name, version, []) # If the structure is defined at the global scope of the top-level # IDL file then add it to our list of top-level definitions. if self.__is_a_top_level_definition(struct): self.__top_level_definitions.append(struct) # Otherwise, a definition with this name already exists. else: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR # Push the structure onto the container stack. self.__container_stack.push(struct) # Push a new prefix onto the prefix stack. self.__prefix_stack.push(self.__create_prefix(prefix, name)) return struct def struct_type_body(self, struct, members): """ struct_type: '{' member_PLUS '}' """ # Make sure that all member names are unique. dict = {} for member in members: if dict.has_key(member.name): self.yyerror("Duplicate member name '%s'" % name) raise bison.YYERROR dict[member.name] = None # Check for recursive members. if self.__is_recursive_member(member.type_def): # Get the repository id of the recursive structure. ifr_id = member.type_def._get_element_type_def()._get_id() # Find out how deep the recursion is. offset = self.__get_recursion_depth(struct, ifr_id) # Get the bound of the sequence type. length = member.type.length() # Replace the sequence typecode with a recursive sequence # typecode. member.type = CORBA.RecursiveSequenceTypeCode(length, offset) # Fixup the version. struct._set_version("1.0") # Update the structure definition. struct._set_members(members) # Pop the container and prefix from the stacks. self.__container_stack.pop() self.__prefix_stack.pop() return struct def member(self, type_def, declarators): """ member: type_spec declarators """ members = [] for declarator in declarators: # If this is an array declarator. if isinstance(declarator, Declarator.ArrayDeclarator): # Get the array dimensions. dimensions = declarator.dimensions() # Create the array type. actual_type_def = self.__create_array(type_def, dimensions) # Otherwise it is a simple declarator. else: actual_type_def = type_def # Create a 'StructMember' instance. members.append(CORBA.StructMember(declarator.name(), actual_type_def._get_type(), actual_type_def)) return members def union_type_header(self, name, type_def): """ union_type: UNION IDENTIFIER SWITCH '(' switch_type_spec ')' """ # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() # Does the container already contain a definition with this name? union = container.lookup(name) # If there is *no* definition with this name then we can safely create # a new union. if union is None: # Set the version to "wip" (for Work In Progress) to allow the # detection of recursive types. version = "wip" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create a new union definition in the container. union = container.create_union(ifr_id, name, version, type_def, []) # If the union is defined at the global scope of the top-level IDL # file then add it to our list of top-level definitions. if self.__is_a_top_level_definition(union): self.__top_level_definitions.append(union) # Otherwise, a definition with this name already exists. else: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR # Push the union onto the container stack. self.__container_stack.push(union) # Push a new prefix onto the prefix stack. self.__prefix_stack.push(self.__create_prefix(prefix, name)) return union def union_type_body(self, union, elements): """ union_type: '{' switch_body '}' """ # First we break out each pair of (labels, element) into # (label, element) pairs ie flattening the label lists. # This is also the right place to check for duplicates, as # after the "flattening" we can't know which are duplicates # and which just happened to have multiple labels members = [] names_seen = [] # All the element names we've processed for element in elements: labels, type_def, declarator = element typecode = type_def._get_type() name = declarator.name() if name in names_seen: self.yyerror("Duplicate member name '%s'" % name) raise bison.YYERROR names_seen.append(name) for label in labels: members.append(CORBA.UnionMember(name, label, typecode, type_def)) # Get the union's discrimintator (aka switch) typecode and type # definition. typecode = union._get_discriminator_type() type_def = union._get_discriminator_type_def() # Make sure that all member names and label values are unique. This # could take some time if some idiot has used, say an unsigned long as # the discriminator type and a couple of billion cases ;^) name_dict = {} label_dict = {} default_used = 0 for member in members: # Ignore the default case. if member.label.typecode().kind() == CORBA.tk_octet: default_used = 1 else: # Get the label value. value = member.label.value() # Make sure the label is the same type as the discriminant # (or coercable to it). if not self.__check_label_type(type_def, member.label): self.yyerror("Invalid label value %s" % str(value)) raise bison.YYERROR # Make sure that the value is within the limits of the type, # and coerce it if necessary. (result, value) = self.__check_limits(type_def, member.label) if not result: self.yyerror("Label value '%s' out of range" % str(value)) raise bison.YYERROR # Wrap the coerced value back in an 'Any' of the appropriate # type. member.label = CORBA.Any(typecode, value) name_dict[member.name] = None # Label check. if label_dict.has_key(value): self.yyerror("Duplicate case label %s" % str(value)) raise bison.YYERROR label_dict[value] = None # Check for recursive members. if self.__is_recursive_member(member.type_def): # Get the repository id of the recursive structure. ifr_id = member.type_def._get_element_type_def()._get_id() # Find out how deep the recursion is. offset = self.__get_recursion_depth(union, ifr_id) # Get the bound of the sequence type. length = member.type.length() # Replace the sequence typecode with a recursive sequence # typecode. member.type = CORBA.RecursiveSequenceTypeCode(length, offset) # If a default case has been specified, then make sure that the # case labels for the specified type haven't been exhausted. if default_used: # Get the typecode kind. kind = typecode.kind() if kind == CORBA.tk_enum: limit = typecode.member_count() elif kind == CORBA.tk_short \ or typecode.kind() == CORBA.tk_ushort: limit = 65536 # 2 ^ 16 elif kind == CORBA.tk_long \ or typecode.kind() == CORBA.tk_ulong: limit = 4294967296L # 2 ^ 32 elif kind == CORBA.tk_longlong \ or typecode.kind() == CORBA.tk_ulonglong: limit = 18446744073709551616L # 2 ^ 64 elif kind == CORBA.tk_char: limit = 256 # 2 ^ 8 elif kind == CORBA.tk_boolean: limit = 2 # 2 ;^) if len(members) - 1 >= limit: self.yyerror("All case labels exhausted") raise bison.YYERROR # Fixup the version. union._set_version("1.0") # Update the union definition. union._set_members(members) # Pop the container and prefix from the stacks. self.__container_stack.pop() self.__prefix_stack.pop() return union # Valid types for union switch specifications. __SWITCH_TYPES = [CORBA.pk_short, CORBA.pk_long, CORBA.pk_longlong, CORBA.pk_ushort, CORBA.pk_ulong, CORBA.pk_ulonglong, CORBA.pk_char, CORBA.pk_boolean] def switch_type_spec_scoped_name(self, scoped_name): """ switch_type_spec: scoped_name """ # Get the container from the stack. container = self.__container_stack.get() # Lookup the definition referenced by the scoped name. definition = self.__find_scoped_name(container, scoped_name) # Unwind any 'typedef' chain. definition = self.__unwind_typedef_chain(definition) # Make sure the definition type is either integer, char, boolean, or # an enumeration. if definition._get_def_kind() == CORBA.dk_Primitive: if definition._get_kind() not in IDLParser.__SWITCH_TYPES: self.yyerror("Invalid switch type '%s'" % scoped_name) raise bison.YYERROR elif definition._get_def_kind() != CORBA.dk_Enum: self.yyerror("Invalid switch type '%s'" % scoped_name) raise bison.YYERROR return definition def case(self, labels, (type_def, declarator)): """ case: case_label_PLUS element_spec ';' """ typecode = type_def._get_type() name = declarator.name() members = [ (labels, type_def, declarator) ] return members def case_label_default(self): """ case_label: DEFAULT ':' """ return CORBA.Any(CORBA.TC_octet, 0) def element_spec(self, type_def, declarator): """ element_spec: type_def declarator """ return (type_def, declarator) def enum_type_header(self, name): """ enum_type: ENUM IDENTIFIER """ # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() # Does the container already contain a definition with this name? enum = container.lookup(name) # If there is *no* definition with this name then we can safely create # a new enumeration. if enum is None: # Currently the version is always "1.0"! version = "1.0" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create a new enumeration definition in the container. enum = container.create_enum(ifr_id, name, version, []) # If the enumeration is defined at the global scope of the # top-level IDL file then add it to our list of top-level # definitions. if self.__is_a_top_level_definition(enum): self.__top_level_definitions.append(enum) # Otherwise, a definition with this name already exists. else: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR return enum def enum_type_body(self, enum, members): """ enum_type: '{' enumerators '}' """ # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() # Create temporary constant definitions for each member. for i in range(len(members)): # Get the name of the member. name = members[i] # Does the container already contain a definition with this name? constant = container.lookup(name) # If there is *no* definition with this name then we can safely # create a new constant. if constant is None: # Tag the enum member with a distinctive version ;^) version = "Delete Me!" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create an Enum member instance. any = CORBA.Any(enum._get_type(), Util.EnumMember(name, i)) # Create a new constant definition in the container. constant = container.create_constant(ifr_id, name, version, enum, any) # Add the definition to our list of enumeration members to # be cleaned up at the end. self.__enum_members.append(constant) # Otherwise, a definition with this name already exists. else: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR # Update the enumeration definition. enum._set_members(members) return enum def native_type_dcl(self, identifier): """ type_dcl: NATIVE simple_declarator """ self.yywarning('No native types specified in the language mapping') return def sequence_type(self, element_type_def, bound=0): """ sequence_type: SEQUENCE '<' simple_type_spec ',' positive_int_const '>' | SEQUENCE '<' simple_type_spec '>' """ return self.__repository.create_sequence(bound, element_type_def) def string_type(self, bound=0): """ string_type: STRING '<' positive_int_const '>' | STRING """ if bound == 0: definition = self.__repository.get_primitive(CORBA.pk_string) else: definition = self.__repository.create_string(bound) return definition def wide_string_type(self, bound=0): """ wide_string_type: WSTRING '<' positive_int_const '>' | WSTRING """ if bound == 0: definition = self.__repository.get_primitive(CORBA.pk_wstring) else: definition = self.__repository.create_wstring(bound) return definition def array_declarator(self, name, dimensions): """ array_declarator: IDENTIFIER fixed_array_size_PLUS """ return Declarator.ArrayDeclarator(name, dimensions) def fixed_array_size(self, dimension): """ fixed_array_size: '[' positive_int_const ']' """ return dimension def attr_dcl(self, mode, type_def, declarators): """ attr_dcl: readonly_OPT ATTRIBUTE param_type_spec simple_declarators """ # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() for declarator in declarators: # Get the name of the declarator. name = declarator.name() # Does the container already contain a definition with this name? attribute = container.lookup(name) # If there is *no* definition with this name then we can safely # create a new attribute. if attribute is None: # Currently the version is always "1.0"! version = "1.0" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create a new attribute definition in the container. attribute = container.create_attribute(ifr_id, name, version, type_def, mode) # Otherwise, a definition with this name already exists. else: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR return def readonly_OPT_normal(self): """ readonly_OPT: /* empty */ """ return CORBA.ATTR_NORMAL def readonly_OPT_readonly(self): """ readonly_OPT: READONLY """ return CORBA.ATTR_READONLY def except_dcl_header(self, name): """ EXCEPTION IDENTIFIER """ # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() # Does the container already contain a definition with this name? exception = container.lookup(name) # If there is *no* definition with this name then we can safely create # a new exception. if exception is None: # Currently the version is always "1.0"! version = "1.0" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create a new exception definition in the container. exception = container.create_exception(ifr_id, name, version, []) # If the exception is defined at the global scope of the top-level # IDL file then add it to our list of top-level definitions. if self.__is_a_top_level_definition(exception): self.__top_level_definitions.append(exception) # Otherwise, a definition with this name already exists. else: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR # Push the exception onto the container stack. self.__container_stack.push(exception) # Push a new prefix onto the prefix stack. self.__prefix_stack.push(self.__create_prefix(prefix, name)) return exception def except_dcl_body(self, exception, members): """ except_dcl: '{' member_STAR '}' """ # The same as for structure definitions! self.struct_type_body(exception, members) return def op_dcl_header(self, mode, result_type_def, name): """ op_dcl: op_attribute_OPT op_type_spec IDENTIFER """ # Get the container and prefix from the stacks. container = self.__container_stack.get() prefix = self.__prefix_stack.get() # Does the container already contain a definition with this name? operation = container.lookup(name) # If there is *no* definition with this name then we can safely create # a new operation. if operation is None: # Currently the version is always "1.0"! version = "1.0" # Generate an interface repository id. ifr_id = self.__create_ifr_id(prefix, name, version) # Create a new operation definition in the container. operation = container.create_operation(ifr_id, name, version, result_type_def, mode, [], # Parameters. [], # Exceptions. []) # Contexts. # Otherwise, a definition with this name already exists. else: self.yyerror("Redefinition of name '%s'" % name) raise bison.YYERROR return operation def op_dcl_body(self, operation, params, exceptions, contexts): """ op_dcl: op_attribute_OPT op_type_spec IDENTIFER """ # Make sure that the parameter names are unique. dict = {} for param in params: if dict.has_key(param.name): self.yyerror("Duplicate parameter name '%s'" % param.name) raise bison.YYERROR dict[param.name] = None # Update the operation definition. operation._set_params(params) operation._set_exceptions(exceptions) operation._set_contexts(contexts) return def op_attribute_OPT_empty(self): """ op_attribute_OPT: /* empty */ """ return CORBA.OP_NORMAL def op_attribute_OPT_oneway(self): """ op_attribute_OPT: ONEWAY """ return CORBA.OP_ONEWAY def op_type_spec_void(self): """ op_type_spec: VOID """ return self.__repository.get_primitive(CORBA.pk_void) def parameter_dcls_empty(self): """ parameter_dcls: '(' ')' """ return [] def param_dcl(self, mode, type_def, declarator): """ param_dcl: param_attribute param_type_spec simple_declarator """ return CORBA.ParameterDescription(declarator.name(), type_def._get_type(), type_def, mode) def param_attribute_in(self): """ param_attribute: IN """ return CORBA.PARAM_IN def param_attribute_out(self): """ param_attribute: OUT """ return CORBA.PARAM_OUT def param_attribute_inout(self): """ param_attribute: INOUT """ return CORBA.PARAM_INOUT def raises_expr_OPT_empty(self): """ raises_expr_OPT: /* empty */ """ return [] def raises_expr(self, scoped_names): """ raises_expr: RAISES '(' scoped_name_CSV_PLUS ')' """ # Get the container and prefix from the stacks. container = self.__container_stack.get() # Make sure that all of the names refer to exceptions! exceptions = [] for scoped_name in scoped_names: # Lookup the definition referenced by the scoped name. definition = self.__find_scoped_name(container, scoped_name) if definition is None: raise bison.YYERROR # Make sure that it is an exception definition. if definition._get_def_kind() != CORBA.dk_Exception: self.yyerror("'%s' is not an exception" % scoped_name) raise bison.YYERROR exceptions.append(definition) return exceptions def context_expr_OPT_empty(self): """ context_expr_OPT: /* empty */ """ return [] def context_expr(self, string_literals): """ context_expr: CONTEXT '(' string_literal_CSV_PLUS ')' """ # fixme: Fnorb does not support contexts! for string_literal in string_literals: self.yywarning("%s context ignored" % string_literal) return [] def fixed_pt_type(self, digits, scale): """ fixed_pt_type: FIXED '<' positive_int_const ',' integer_literal '>' The fixed point type is not yet implemented. """ self.yywarning("'fixed' not supported by Fnorb runtime") # 'digits' is a positive integer constant and is returned as a Python # long, and ;scale' is an integer literal which is returned as an # 'Any'. return self.__repository.create_fixed(digits, scale.value()) def fixed_pt_const_type(self): """ fixed_pt_const_type: FIXED """ self.yywarning("'fixed' constants not supported by Fnorb runtime") return self.__repository.create_fixed(0, 0) # # '#pragma' directives. # def pragma(self, yytext): """ PRAGMA """ # Split the text of the directive on spaces. components = string.split(yytext) # Ignore any malformed directives. if len(components) == 3: if components[1] == 'prefix': try: # The prefix must be a quoted string. pragma_prefix = eval(components[2]) if type(pragma_prefix) != types.StringType: raise TypeError # Get the current prefix from the stack. prefix = self.__prefix_stack.get() # Update the 'pragma' portion of the prefix. prefix.set_pragma(pragma_prefix) # Ignore any errors. except: self.yywarning("Malformed #pragma prefix") elif len(components) == 4: if components[1] == 'ID': try: # Get the name of the definition. name = components[2] # The id must be a quoted string. ifr_id = eval(components[3]) if type(ifr_id) != types.StringType: raise TypeError # Get the container from the stacks. container = self.__container_stack.get() # Lookup the definition referenced by the scoped name. definition = self.__find_scoped_name(container, name) if definition is None: raise bison.YYERROR # Update the definition's interface repository id. definition._set_id(ifr_id) # Ignore any errors. except: self.yywarning("Malformed #pragma ID") elif components[1] == 'version': try: # Get the name of the definition. name = components[2] # The version is used as a string, but must be in the # format . version = components[3] if type(eval(version)) != types.FloatType: raise TypeError # Get the container from the stacks. container = self.__container_stack.get() # Lookup the definition referenced by the scoped name. definition = self.__find_scoped_name(container, name) if definition is None: raise bison.YYERROR # Update the definition's version. definition._set_version(version) # Ignore any errors. except: self.yywarning("Malformed #pragma version") return def line_directive(self, yytext): """ Parse line/file pre-processor directives. This method is called from the lexer (see the file 'lexer.l'). """ line = None file = None # Split the text on spaces. components = string.split(yytext) # If this a '# line' directive. if components[1] == 'line': # e.g. '# line 1' line = eval(components[2]) # e.g. '# line 1 "filename.idl" if len(components) >= 4: file = eval(components[3]) # Otherwise this is a pre-processor inserted line. else: # e.g. '# 1' line = eval(components[1]) # e.g. '# 1 "filename.idl"', but not '# 1 ""' if len(components) >= 3 and components[2][:2] != '"<': file = eval(components[2]) # Update the line number. if line is not None: bison.yylineno(line) # Update the file. if file is not None: # Get the prefix stack for this file. try: self.__prefix_stack = self.__prefix_stacks[file] # If there is no prefix stack for this file then create one! except KeyError: # The prefix stack initially contains just an empty prefix. self.__prefix_stack = Stack.Stack() self.__prefix_stack.push(Prefix.Prefix()) self.__prefix_stacks[file] = self.__prefix_stack # Update the current filename. self.__current_file = file return # # Generic actions. # def list_empty(self): """ Generic empty list. """ return [] def list_insert(self, item, list): """ Generic list insert. """ if type(item) == types.ListType: list = item + list else: list.insert(0, item) return list def idl_type_scoped_name(self, scoped_name): """ Check that the scoped name references an IDL type definition. """ # Get the container from the stack. container = self.__container_stack.get() # Lookup the definition referenced by the scoped name. definition = self.__find_scoped_name(container, scoped_name) if definition is None: raise bison.YYERROR # If it is not an 'IDLType' definition then it is illegal. if not definition._is_a("IDL:omg.org/CORBA/IDLType:1.0"): self.yyerror("'%s' is not a type name" % scoped_name) raise bison.YYERROR return definition ######################################################################### # Private interface. ######################################################################### def __initialise(self): """ Initialise the various data structures used during parsing. """ # The name of the IDL file currently being parsed. self.__current_file = self.__filename # A dictionary of prefix stacks - keyed on filename. self.__prefix_stacks = {} # {Filename: Stack} # The prefix stack initially contains just an empty prefix. self.__prefix_stack = Stack.Stack() self.__prefix_stack.push(Prefix.Prefix()) self.__prefix_stacks[self.__filename] = self.__prefix_stack # A list of all definitions at the global scope of the top-level IDL # file. self.__top_level_definitions = [] # A dictionary of all interfaces along with the names of their # operations and attributes. self.__interfaces = {} # {RepositoryId: [NamesofOpsAndAttributes]} # A dictionary of forward declared but undefined interfaces. self.__forward_interfaces = {} # {RepositoryId: (InterfaceDef, LineNo)} # A list of the temporary constant definitions created for members of # enumerations. self.__enum_members = [] return def __cleanup(self): """ Cleanup after parsing. """ # Get rid of the temporary contant definitions created for members of # enumerations. for enum_member in self.__enum_members: enum_member.destroy() return def __create_prefix(self, prefix, name): """ Create a new prefix. """ new_prefix = "%s%s/" % (prefix.get_prefix(), name) return Prefix.Prefix(prefix.get_pragma(), new_prefix) def __create_ifr_id(self, prefix, name, version): """ Create an interface repository id. """ return "IDL:%s%s:%s" % (str(prefix), name, version) def __find_scoped_name(self, container, scoped_name): """ Find the definition for the scoped name. """ if scoped_name == "TypeCode": definition = self.__repository.get_primitive(CORBA.pk_TypeCode) elif scoped_name == "Principal": definition = self.__repository.get_primitive(CORBA.pk_Principal) else: # If the container is an interface then we look first in # the interface itself, and then recursively through its base # interfaces. if container._get_def_kind() == CORBA.dk_Interface: definition = self.__find_inherited(container, scoped_name) # Otherwise, we start by searching the current container, and then # its enclosing scopes. else: definition = container.lookup(scoped_name) # While the definition is not found. while definition is None: # Is the container also 'contained'? if container._is_a("IDL:omg.org/CORBA/Contained:1.0"): # Get the container's container ;^) container = container._get_defined_in() # Look in there! definition = container.lookup(scoped_name) else: self.yyerror("Undeclared scoped name '%s'" % scoped_name) break return definition def __find_inherited(self, container, scoped_name): """ Find the definition for the scoped name. """ # Lookup the name in the interface first. definition = container.lookup(scoped_name) if definition is None: # Look through all base interfaces. for base in container._get_base_interfaces(): # Lookup the name in the base's base interfaces! definition = self.__find_inherited(base, scoped_name) if definition is not None: break return definition def __create_array(self, type_def, dims): """ Create an array type definition. """ # Single dimension if len(dims) == 1: array_type_def = self.__repository.create_array(dims[0], type_def) # Multi-dimension else: # Create the 'slice' type. slice_type_def = self.__repository.create_array(dims[-1], type_def) # Recursively create the array type. array_type_def = self.__create_array(slice_type_def, dims[:-1]) return array_type_def def __is_a_top_level_definition(self, definition): """ Is the defn at the global scope of the top-level IDL file? """ if self.__current_file == self.__filename \ and definition._get_defined_in() == self.__repository: result = 1 else: # Include any global scope definitions that are not modules! if definition._get_defined_in() == self.__repository \ and definition._get_def_kind() != CORBA.dk_Module: result = 1 else: result = 0 return result # Integer typecode kinds. __TK_INT = [CORBA.tk_short, CORBA.tk_long, CORBA.tk_longlong, CORBA.tk_ushort, CORBA.tk_ulong, CORBA.tk_ulonglong] # Floating point typecode kinds. __TK_FP = [CORBA.tk_float, CORBA.tk_double, CORBA.tk_longdouble] def __check_constant_type(self, type_def, any): """ Make sure that the value is of the specified type. """ # Get the typecode 'kind's. type_def_kind = type_def._get_type().kind() any_kind = any.typecode().kind() if type_def_kind in IDLParser.__TK_INT \ and any_kind in IDLParser.__TK_INT: result = 1 elif type_def_kind in IDLParser.__TK_FP \ and any_kind in IDLParser.__TK_FP + IDLParser.__TK_INT: result = 1 elif type_def_kind == any_kind: result = 1 else: result = 0 return result def __check_limits(self, type_def, any): """ Make sure that the value is within the limits of the type. """ # Get the typecode 'kind'. type_def_kind = type_def._get_type().kind() # Get the value out of the any. value = any.value() if type_def_kind == CORBA.tk_short: if value < Limits.MIN_SHORT or value > Limits.MAX_SHORT: result = 0 else: result = 1 value = int(value) elif type_def_kind == CORBA.tk_ushort: if value < Limits.MIN_USHORT or value > Limits.MAX_USHORT: result = 0 else: result = 1 value = int(value) elif type_def_kind == CORBA.tk_long: if value < Limits.MIN_LONG or value > Limits.MAX_LONG: result = 0 else: result = 1 value = int(value) elif type_def_kind == CORBA.tk_ulong: if value < Limits.MIN_ULONG or value > Limits.MAX_ULONG: result = 0 else: result = 1 elif type_def_kind == CORBA.tk_longlong: if value < Limits.MIN_LONGLONG or value > Limits.MAX_LONGLONG: result = 0 else: result = 1 elif type_def_kind == CORBA.tk_ulonglong: if value < Limits.MIN_ULONGLONG or value > Limits.MAX_ULONGLONG: result = 0 else: result = 1 elif type_def_kind in IDLParser.__TK_FP: # Coerce integer constants to floating point values # FIXME: IDL expressions are meant to have the type # of the constant they are assigned to right from the # beginning value = float(value) result = 1 # fixme: This should not be here!!! elif type_def_kind == CORBA.tk_fixed: any_typecode = any.typecode() type_def._set_digits(any_typecode.fixed_digits()) type_def._set_scale(any_typecode.fixed_scale()) result = 1 else: result = 1 return (result, value) def __check_label_type(self, type_def, any): """ Make sure that the value is of the specified type. """ # Get the typecode 'kind's. type_def_kind = type_def._get_type().kind() any_kind = any.typecode().kind() if type_def_kind in IDLParser.__TK_INT \ and any_kind in IDLParser.__TK_INT: result = 1 elif type_def_kind == any_kind: # If the union is switched on an enumeration then make sure that # the value is a valid element of the same enumeration! if type_def_kind == CORBA.tk_enum: if type_def._get_type().id() == any.typecode().id(): result = 1 else: result = 0 else: result = 1 else: result = 0 return result def __check_forward_interfaces(self): """ Make sure that all forward declared interfaces were defined. """ if len(self.__forward_interfaces) > 0: for (interface, yylineno) in self.__forward_interfaces.values(): # Set the line number for error reporting. bison.yylineno(yylineno) # Report the error. self.yyerror("Interface '%s' declared but not defined" % \ interface._get_name()) raise bison.YYERROR return def __get_bases(self, interface): if interface._get_def_kind() == CORBA.dk_Interface: return interface._get_base_interfaces() elif interface._get_def_kind() == CORBA.dk_Value: base = interface._get_base_value() abases = interface._get_abstract_base_values() if base: return [base] + abases else: return abases raise NotImplementedError def __get_inherited_operations(self, interface, visited): """ Get all operations and attributes inherited by an interface. """ names = [] for base in self.__get_bases(interface): # Get the interface repository id of the interface. ifr_id = base._get_id() # Only include the operations and attributes for the interface # once! if ifr_id not in visited: # Add the interface's operations and attributes to the list. names = names + self.__interfaces[ifr_id] # Add the interface repository id of the interface to the list # of those already visited. visited.append(ifr_id) # Do it recursively! names = names + self.__get_inherited_operations(base, visited) # Check for duplicates! tmp = {} for name in names: if tmp.has_key(name): self.yyerror("Overloaded operation/attribute '%s'" % name) raise bison.YYERROR else: tmp[name] = None return names def __unwind_typedef_chain(self, definition): """ Unwind any 'typedef' chain! """ # fixme: Which will it be? dk_Typedef or dk_Alias?!?!?!?!?! My bet is # on dk_Alias! while definition._get_def_kind() == CORBA.dk_Typedef \ or definition._get_def_kind() == CORBA.dk_Alias: definition = definition._get_original_type_def() return definition def __is_recursive_member(self, type_def): """ Determine whether or not this is a recursive member. """ if type_def._get_def_kind() == CORBA.dk_Sequence: element_type_def = type_def._get_element_type_def() if element_type_def._get_def_kind() == CORBA.dk_Struct or \ element_type_def._get_def_kind() == CORBA.dk_Union: if element_type_def._get_version() == "wip": return 1 return 0 def __get_recursion_depth(self, type_def, ifr_id, depth=1): """ Find the depth (or 'offset') of a recursive type. """ if type_def._get_id() == ifr_id: return depth else: return self.__get_recursion_depth(type_def._get_defined_in(), ifr_id, depth + 1) return #############################################################################