gecko-dev/dom/tools/IdlParser.cpp

1078 строки
30 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/**
IDL syntax
specification = definition < specification > .
definition = ( type_dcl / const_dcl / except_dcl / interface / module ) ";" .
interface = interface_dcl / forward_dcl .
forward_dcl = "interface" identifier .
interface_dcl = interface_header "{" interface_body "}" .
interface_header = "interface" identifier [ inheritance_spec ] .
interface_body = < export > .
export = ( type_dcl / const_dcl / except_dcl / attr_dcl / op_dcl ) ";" .
inheritance_spec = ":" scoped_name < "," scoped_name > .
scoped_name = identifier
/ ( "::" identifier )
/ ( scoped_name "::" identifier ) .
*/
// initialize cout
#ifdef XP_MAC
#include <iostream>
#endif
#include <ostream.h>
#include "IdlParser.h"
#include "IdlScanner.h"
#include "Exceptions.h"
#include "IdlSpecification.h"
#include "IdlInterface.h"
#include "IdlEnum.h"
#include "IdlVariable.h"
#include "IdlAttribute.h"
#include "IdlFunction.h"
#include "IdlParameter.h"
// not defined yet. We don't need this types for now
// so the forward declaration in IdlParser.h is good enough
/*
#include "IdlTypedef.h"
#include "IdlStruct.h"
#include "IdlUnion.h"
#include "IdlConst.h"
#include "IdlException.h"
*/
/**
* constructor
*/
IdlParser::IdlParser()
{
mScanner = new IdlScanner();
}
/**
* destructor
*/
IdlParser::~IdlParser()
{
if (mScanner) {
delete mScanner;
}
}
/**
* specification = definition < specification > .
* definition = ( type_dcl / const_dcl / except_dcl / interface / module ) ";" .
*
* We only understand interfaces so go directly to process interfaces.
* A more complex parsing of specification requires changes in this method
* (or subclassing if you like and you can let this class process the interfaces only)
*/
void IdlParser::Parse(char *aFileName, IdlSpecification &aSpecification)
{
// connect the scanner to the file in input
if (mScanner->Open(aFileName)) {
try {
// read all the interfaces in the idl file
IdlInterface *idlInterface;
while (mScanner->CanReadMoreData()) {
idlInterface = ParseInterface(aSpecification);
if (idlInterface)
aSpecification.AddInterface(idlInterface);
}
} catch (ParserException &exc) {
cout << exc;
throw AbortParser(mScanner->GetFileName(), mScanner->GetLineNumber());
}
}
else {
throw FileNotFoundException(aFileName);
}
}
/**
* interface = interface_dcl / forward_dcl
* forward_dcl = "interface" identifier
* interface_dcl = interface_header "{" interface_body "}"
* interface_header = "interface" identifier [ inheritance_spec ]
* interface_body = < export >
*
* We look for
* "interface" identifier
* and if followed by "{" or ":" we expect a full interface declaration
* otherwise it is just a forward declaration
*
*/
IdlInterface* IdlParser::ParseInterface(IdlSpecification &aSpecification)
{
IdlInterface *interfaceObj = (IdlInterface*)0;
// go through all comments and assume the last one is a comment for the
// interface
Token *token = (Token*)0;
while (mScanner->CanReadMoreData() && COMMENT_TOKEN == mScanner->PeekToken()->id) {
token = mScanner->NextToken();
}
if (token) {
//XXX save last comment somewhere...
}
if (mScanner->CanReadMoreData()) {
try {
// must be "interface" identifier
if (INTERFACE_TOKEN == mScanner->NextToken()->id) {
TrimComments();
token = mScanner->NextToken();
if (IDENTIFIER_TOKEN == token->id) {
interfaceObj = new IdlInterface();
interfaceObj->SetName(token->stringID);
}
else {
throw InterfaceParsingException("Missing identifier. Interface name undefined.");
}
}
else {
throw InterfaceParsingException("Interface expected. We only process interfaces specification.");
}
TrimComments();
// look for ":"
int inheritanceSpec = 0;
token = mScanner->PeekToken();
if (INHERITANCE_SPEC_TOKEN == token->id) {
mScanner->NextToken(); // read ":"
TrimComments();
//XXX we deal only with an interface_header structured as follow
// interface_header = ":" identifier < "," identifier >
token = mScanner->NextToken(); // this must be the base class
while (IDENTIFIER_TOKEN == token->id) {
interfaceObj->InheritsFrom(token->stringID);
TrimComments();
token = mScanner->PeekToken();
if (SEPARATOR_TOKEN == token->id) {
mScanner->NextToken(); // eat ","
TrimComments();
token = mScanner->NextToken(); // this must be the next base class
}
else {
// next token isn't a ","
// we are done with interface_header
inheritanceSpec = 1;
break;
}
}
if (0 == inheritanceSpec) {
delete interfaceObj;
throw InterfaceParsingException("Bad inheritance specification.");
}
}
// got a "{"
if (BEGIN_BLOCK_TOKEN == token->id) {
ParseInterfaceBody(aSpecification, *interfaceObj);
}
else if (inheritanceSpec) {
delete interfaceObj;
// if interface_header was found a interface_body must be defined
throw InterfaceParsingException("Missing interface body.");
}
else {
//XXX it's a forward declaration what do we do?
}
} catch (EndOfFileException &) {
if (interfaceObj != 0) {
delete interfaceObj;
}
// unexpected end of file. Trying to read after a EOF has
// been returned
throw ParserException("Unexpected End of File.");
}
// read the final ";"
token = mScanner->NextToken();
if (TERMINATOR_TOKEN != token->id) {
throw InterfaceParsingException("Missing ';'.");
}
}
return interfaceObj;
}
/**
* interface_body = < export >
* export = ( type_dcl / const_dcl / except_dcl / attr_dcl / op_dcl ) ";"
* type_dcl = "typedef" type_declarator
* / struct_type
* / union_type
* / enum_type
* struct_type = "struct" identifier "{" member_list "}"
* union_type = "union" identifier "switch" "(" switch_type_spec ")"
* "{" switch_body "}"
* enum_type = "enum" identifier "{" enumerator < "," enumerator > "}"
* const_dcl = "const" const_type identifier "=" const_exp
* except_dcl = "exception" identifier "{" < member > "}"
* attr_dcl = [ "readonly" ] [ "xpidl" ] "attribute" param_type_spec identifier
* op_dcl = [ op_attribute ] op_type_spec identifier parameter_dcls
* [ raises_expr ] [ context_expr ]
* op_attribute = "oneway" .
* op_type_spec = param_type_spec / "void"
* param_type_spec = base_type_spec / string_type / scoped_name
* base_type_spec = floating_pt_type
* / integer_type
* / char_type
* / boolean_type
* / octet_type
* / any_type
* scoped_name = identifier
* / ( "::" identifier )
* / ( scoped_name "::" identifier )
*/
void IdlParser::ParseInterfaceBody(IdlSpecification &aSpecification, IdlInterface &aInterface)
{
// eat "{"
mScanner->NextToken();
TrimComments();
// untill "}" parse the interface body
Token *token = (Token*)0;
while (END_BLOCK_TOKEN != mScanner->PeekToken()->id) {
token = mScanner->NextToken();
TrimComments();
// parse the proper valid type
switch (token->id) {
case IID_TOKEN:
aInterface.AddIID(token->stringID);
break;
case TYPEDEF_TOKEN:
aInterface.AddTypedef(ParseTypedef(aSpecification));
break;
case STRUCT_TOKEN:
aInterface.AddStruct(ParseStruct(aSpecification));
break;
case ENUM_TOKEN:
aInterface.AddEnum(ParseEnum(aSpecification));
break;
case UNION_TOKEN:
aInterface.AddUnion(ParseUnion(aSpecification));
break;
case CONST_TOKEN:
aInterface.AddConst(ParseConst(aSpecification));
break;
case EXCEPTION_TOKEN:
aInterface.AddException(ParseException(aSpecification));
break;
case NOSCRIPT_TOKEN:
{
IdlAttribute* attr;
attr = MaybeParseAttribute(aSpecification, token->id);
if (NULL == attr) {
aInterface.AddFunction(ParseFunction(aSpecification, token));
}
else {
aInterface.AddAttribute(attr);
}
}
break;
case READONLY_TOKEN:
case ATTRIBUTE_TOKEN:
case REPLACEABLE_TOKEN:
aInterface.AddAttribute(ParseAttribute(aSpecification, token->id));
break;
default:
// it's either a function or an error
aInterface.AddFunction(ParseFunction(aSpecification, token));
break;
}
TrimComments();
// read the final ";"
if (IID_TOKEN != token->id) {
token = mScanner->NextToken();
if (TERMINATOR_TOKEN != token->id) {
throw InterfaceParsingException("Missing ';'.");
}
TrimComments();
}
}
// eat "}"
mScanner->NextToken();
}
/**
* XXX NOT IMPLEMENTED YET
*/
IdlTypedef* IdlParser::ParseTypedef(IdlSpecification &aSpecification)
{
throw NotImplementedException();
return (IdlTypedef*)0;
}
/**
* XXX NOT IMPLEMENTED YET
*/
IdlStruct* IdlParser::ParseStruct(IdlSpecification &aSpecification)
{
throw NotImplementedException();
return (IdlStruct*)0;
}
/**
* enum_type = "enum" identifier "{" enumerator < "," enumerator > "}"
* enumerator = identifier
*
* We semplify enum's and define them as
* enum_type = "enum" identifier "{" enumerator < "," integer_literal > "}"
* enumerator = identifier
*/
IdlEnum* IdlParser::ParseEnum(IdlSpecification &aSpecification)
{
IdlEnum *enumObj = new IdlEnum();
Token *token;
// can be an identifier
token = mScanner->NextToken();
if (IDENTIFIER_TOKEN == token->id) {
enumObj->SetName(token->stringID);
TrimComments();
token = mScanner->NextToken();
}
// a "{" must be present anyway
if (BEGIN_BLOCK_TOKEN == token->id) {
// untill "}" parse the enum
token = mScanner->PeekToken();
while (END_BLOCK_TOKEN != token->id) {
// must be an identifier
if (IDENTIFIER_TOKEN == token->id) {
IdlVariable* enumerator = new IdlVariable();
enumerator->SetType(TYPE_INT); // it does not really matter which type
enumerator->SetName(mScanner->NextToken()->stringID);
enumObj->AddEnumerator(enumerator);
TrimComments();
// if "=" is specified an integer must follow
// NOTE: this is an ad hoc solution for the w3c dom. Enum can
// be more complex than this
token = mScanner->PeekToken();
if (ASSIGNEMENT_TOKEN == token->id) {
mScanner->NextToken(); // eat "="
TrimComments();
// must be an integer
token = mScanner->NextToken();
if (token->id == INTEGER_CONSTANT) {
enumerator->SetValue(token->value.vLong);
TrimComments();
token = mScanner->PeekToken();
}
else {
delete enumObj;
throw EnumParsingException("The specified enumerator value is not an integer.");
}
}
if (SEPARATOR_TOKEN == token->id) {
mScanner->NextToken(); // eat ","
TrimComments();
token = mScanner->PeekToken();
}
}
else {
delete enumObj;
throw EnumParsingException("Missing identifier in enum body.");
}
}
mScanner->NextToken(); // eat "}"
}
else {
delete enumObj;
throw EnumParsingException("Missing enum body.");
}
return enumObj;
}
/**
* XXX NOT IMPLEMENTED YET
*/
IdlUnion* IdlParser::ParseUnion(IdlSpecification &aSpecification)
{
throw NotImplementedException();
return (IdlUnion*)0;
}
/**
*
*/
IdlVariable* IdlParser::ParseConst(IdlSpecification &aSpecification)
{
IdlVariable *constObj = new IdlVariable();
Token *token;
TrimComments();
token = mScanner->NextToken();
// must be the type
switch(token->id) {
// base type
case BOOLEAN_TOKEN:
constObj->SetType(TYPE_BOOLEAN);
break;
case FLOAT_TOKEN:
constObj->SetType(TYPE_FLOAT);
break;
case DOUBLE_TOKEN:
constObj->SetType(TYPE_DOUBLE);
break;
case LONG_TOKEN:
constObj->SetType(TYPE_LONG);
break;
case LONG_LONG_TOKEN:
constObj->SetType(TYPE_LONG_LONG);
break;
case SHORT_TOKEN:
constObj->SetType(TYPE_SHORT);
break;
case ULONG_TOKEN:
constObj->SetType(TYPE_ULONG);
break;
case ULONG_LONG_TOKEN:
constObj->SetType(TYPE_ULONG_LONG);
break;
case USHORT_TOKEN:
constObj->SetType(TYPE_USHORT);
break;
case CHAR_TOKEN:
constObj->SetType(TYPE_CHAR);
break;
case INT_TOKEN:
constObj->SetType(TYPE_INT);
break;
case UINT_TOKEN:
constObj->SetType(TYPE_UINT);
break;
case JSVAL_TOKEN:
constObj->SetType(TYPE_JSVAL);
break;
// string type
case STRING_TOKEN:
constObj->SetType(TYPE_STRING);
break;
// scoped name
case IDENTIFIER_TOKEN:
//if (aSpecification.ContainInterface(aToken.stringID)) {
constObj->SetType(TYPE_OBJECT);
constObj->SetTypeName(token->stringID);
break;
//}
default:
delete constObj;
throw ConstParsingException("Unknown type.");
}
TrimComments();
token = mScanner->NextToken();
// an identifier must follow
if (IDENTIFIER_TOKEN == token->id) {
constObj->SetName(token->stringID);
}
else {
delete constObj;
throw ConstParsingException("Missing identifire. Const name undefined.");
}
// the "=" sign
TrimComments();
token = mScanner->NextToken();
if (ASSIGNEMENT_TOKEN != token->id) {
delete constObj;
throw ConstParsingException("Missing identifire. Const name undefined.");
}
TrimComments();
token = mScanner->NextToken();
// must be some kind of constant. Constants token ids start at
// position INTEGER_CONSTANT
if (token->id < INTEGER_CONSTANT) {
delete constObj;
throw ConstParsingException("Missing identifier. Const name undefined.");
}
else if (INTEGER_CONSTANT == token->id) {
constObj->SetValue(token->value.vLong);
}
else if (STRING_CONSTANT == token->id) {
constObj->SetValue(token->value.vString);
}
return constObj;
}
/**
* XXX NOT IMPLEMENTED YET
*/
IdlException* IdlParser::ParseException(IdlSpecification &aSpecification)
{
throw NotImplementedException();
return (IdlException*)0;
}
IdlAttribute* IdlParser::MaybeParseAttribute(IdlSpecification &aSpecification, int aTokenID)
{
Token *token;
int isNoScript = 0;
// if it was a noscript keyword check if this is an attribute
if (NOSCRIPT_TOKEN == aTokenID) {
isNoScript = 1;
TrimComments();
token = mScanner->PeekToken();
if ((token->id != READONLY_TOKEN) && (token->id != ATTRIBUTE_TOKEN) && (token->id != REPLACEABLE_TOKEN)) {
return NULL;
}
mScanner->NextToken();
aTokenID = token->id;
}
return ParseAttribute(aSpecification, aTokenID, isNoScript);
}
/**
* attr_dcl = [ "readonly" ] [ "replaceable" ] "attribute" param_type_spec identifier
* param_type_spec = base_type_spec / string_type / scoped_name
*/
IdlAttribute* IdlParser::ParseAttribute(IdlSpecification &aSpecification, int aTokenID, int aIsNoScript)
{
Token *token;
int isReadOnly = 0;
int isReplaceable = 0;
while (aTokenID != ATTRIBUTE_TOKEN) {
// if it was a readonly keyword read the next keyword
if (READONLY_TOKEN == aTokenID) {
isReadOnly = 1;
TrimComments();
token = mScanner->NextToken();
aTokenID = token->id;
}
else if (REPLACEABLE_TOKEN == aTokenID) {
isReplaceable = 1;
TrimComments();
token = mScanner->NextToken();
aTokenID = token->id;
}
else {
throw AttributeParsingException("Unknown attribute specifier.");
}
}
TrimComments();
// create the attribute object
IdlAttribute *attrObj = new IdlAttribute();
attrObj->SetIsNoScript(aIsNoScript);
attrObj->SetReadOnly(isReadOnly);
attrObj->SetReplaceable(isReplaceable);
// this must be the attribute type
token = mScanner->NextToken();
switch(token->id) {
// base type
case BOOLEAN_TOKEN:
attrObj->SetType(TYPE_BOOLEAN);
break;
case FLOAT_TOKEN:
attrObj->SetType(TYPE_FLOAT);
break;
case DOUBLE_TOKEN:
attrObj->SetType(TYPE_DOUBLE);
break;
case LONG_TOKEN:
attrObj->SetType(TYPE_LONG);
break;
case LONG_LONG_TOKEN:
attrObj->SetType(TYPE_LONG_LONG);
break;
case SHORT_TOKEN:
attrObj->SetType(TYPE_SHORT);
break;
case ULONG_TOKEN:
attrObj->SetType(TYPE_ULONG);
break;
case ULONG_LONG_TOKEN:
attrObj->SetType(TYPE_ULONG_LONG);
break;
case USHORT_TOKEN:
attrObj->SetType(TYPE_USHORT);
break;
case CHAR_TOKEN:
attrObj->SetType(TYPE_CHAR);
break;
case INT_TOKEN:
attrObj->SetType(TYPE_INT);
break;
case UINT_TOKEN:
attrObj->SetType(TYPE_UINT);
break;
case JSVAL_TOKEN:
attrObj->SetType(TYPE_JSVAL);
break;
// string type
case STRING_TOKEN:
attrObj->SetType(TYPE_STRING);
break;
case UNKNOWN_TOKEN:
attrObj->SetType(TYPE_UNKNOWN);
break;
// scoped name
case IDENTIFIER_TOKEN:
//if (aSpecification.ContainInterface(token->stringID)) {
attrObj->SetType(TYPE_OBJECT);
attrObj->SetTypeName(token->stringID);
break;
//}
case XPIDL_TOKEN:
token = mScanner->NextToken();
if (IDENTIFIER_TOKEN == token->id) {
attrObj->SetType(TYPE_XPIDL_OBJECT);
attrObj->SetTypeName(token->stringID);
break;
}
default:
delete attrObj;
throw AttributeParsingException("Unknow attribute type.");
}
TrimComments();
// an identifier must follow
token = mScanner->NextToken();
if (IDENTIFIER_TOKEN == token->id) {
attrObj->SetName(token->stringID);
}
else {
delete attrObj;
throw AttributeParsingException("Missing identifire. Attribute name undefined.");
}
return attrObj;
}
IdlFunction* IdlParser::ParseFunction(IdlSpecification &aSpecification, Token *aToken)
{
// NOTE: we don't process the function specifier "oneway"
int isNoScript = 0;
// if it was a readonly keyword read the next keyword
if (NOSCRIPT_TOKEN == aToken->id) {
isNoScript = 1;
TrimComments();
aToken = mScanner->NextToken();
}
IdlFunction *funcObj = new IdlFunction();
funcObj->SetIsNoScript(isNoScript);
// a function name starts with the return value
switch(aToken->id) {
// base type
case BOOLEAN_TOKEN:
funcObj->SetReturnValue(TYPE_BOOLEAN);
break;
case FLOAT_TOKEN:
funcObj->SetReturnValue(TYPE_FLOAT);
break;
case DOUBLE_TOKEN:
funcObj->SetReturnValue(TYPE_DOUBLE);
break;
case LONG_TOKEN:
funcObj->SetReturnValue(TYPE_LONG);
break;
case LONG_LONG_TOKEN:
funcObj->SetReturnValue(TYPE_LONG_LONG);
break;
case SHORT_TOKEN:
funcObj->SetReturnValue(TYPE_SHORT);
break;
case ULONG_TOKEN:
funcObj->SetReturnValue(TYPE_ULONG);
break;
case ULONG_LONG_TOKEN:
funcObj->SetReturnValue(TYPE_ULONG_LONG);
break;
case USHORT_TOKEN:
funcObj->SetReturnValue(TYPE_USHORT);
break;
case CHAR_TOKEN:
funcObj->SetReturnValue(TYPE_CHAR);
break;
case INT_TOKEN:
funcObj->SetReturnValue(TYPE_INT);
break;
case UINT_TOKEN:
funcObj->SetReturnValue(TYPE_UINT);
break;
case JSVAL_TOKEN:
funcObj->SetReturnValue(TYPE_JSVAL);
break;
// string type
case STRING_TOKEN:
funcObj->SetReturnValue(TYPE_STRING);
break;
case VOID_TOKEN:
funcObj->SetReturnValue(TYPE_VOID);
break;
case UNKNOWN_TOKEN:
funcObj->SetReturnValue(TYPE_UNKNOWN);
break;
// scoped name
case IDENTIFIER_TOKEN:
//if (aSpecification.ContainInterface(aToken->stringID)) {
funcObj->SetReturnValue(TYPE_OBJECT, aToken->stringID);
break;
//}
case XPIDL_TOKEN:
{
Token* token = mScanner->NextToken();
if (IDENTIFIER_TOKEN == token->id) {
funcObj->SetReturnValue(TYPE_XPIDL_OBJECT, token->stringID);
break;
}
}
default:
delete funcObj;
throw AttributeParsingException("Unknown type.");
}
Token *token;
TrimComments();
// must be the function name
token = mScanner->NextToken();
if (IDENTIFIER_TOKEN == token->id) {
funcObj->SetName(token->stringID);
TrimComments();
// must be "("
token = mScanner->PeekToken();
if (FUNC_PARAMS_SPEC_BEGIN_TOKEN == token->id) {
try {
int anyOptional = 0;
while (FUNC_PARAMS_SPEC_END_TOKEN != token->id &&
ELLIPSIS_TOKEN != token->id &&
(FUNC_PARAMS_SPEC_BEGIN_TOKEN == token->id ||
SEPARATOR_TOKEN == token->id)
) {
mScanner->NextToken(); // eat the last peeked symbol
TrimComments();
if ((FUNC_PARAMS_SPEC_END_TOKEN == mScanner->PeekToken()->id) ||
(ELLIPSIS_TOKEN == mScanner->PeekToken()->id)) {
break;
}
// parse all arguments
IdlParameter *param = ParseFunctionParameter(aSpecification);
if (param->GetIsOptional()) {
anyOptional = 1;
}
else if (anyOptional) {
throw ParameterParsingException("Non-optional parameter cannot follow optional parameters");
}
funcObj->AddParameter(param);
TrimComments();
token = mScanner->PeekToken();
}
if (mScanner->PeekToken()->id == ELLIPSIS_TOKEN) {
mScanner->NextToken();
funcObj->SetHasEllipsis(1);
TrimComments();
}
mScanner->NextToken(); // eat ')'
}
catch (ParameterParsingException &) {
delete funcObj;
throw;
}
// is it throwing an exception?
TrimComments();
token = mScanner->PeekToken();
//XXX this is how exceptions are declared now. This should change
// to the correct way so that this while loop can be deleted
while (INTERFACE_TOKEN == token->id) {
mScanner->NextToken(); // eat "interface"
TrimComments();
token = mScanner->NextToken(); // must be the exception name
if (IDENTIFIER_TOKEN == token->id) {
funcObj->AddException(token->stringID);
TrimComments();
mScanner->NextToken(); // eat '{'
TrimComments();
mScanner->NextToken(); // eat '}'
TrimComments();
token = mScanner->PeekToken();
if (SEPARATOR_TOKEN == token->id) {
mScanner->NextToken(); // eat ','
TrimComments();
token = mScanner->PeekToken(); // should be next exception
}
}
else {
delete funcObj;
throw FunctionParsingException("Undeclared exception name.");
}
}
if (RAISES_TOKEN == token->id) {
mScanner->NextToken(); // eat "raises"
TrimComments();
token = mScanner->PeekToken();
if (IDENTIFIER_TOKEN == token->id) {
while (IDENTIFIER_TOKEN == token->id) {
mScanner->NextToken(); // eat exception name
funcObj->AddException(token->stringID);
TrimComments();
token = mScanner->PeekToken();
if (SEPARATOR_TOKEN == token->id) {
mScanner->NextToken(); // eat ','
TrimComments();
token = mScanner->PeekToken(); // should be next exception
}
}
}
else {
mScanner->NextToken(); // Must be '('
while (FUNC_PARAMS_SPEC_BEGIN_TOKEN == token->id ||
SEPARATOR_TOKEN == token->id) {
TrimComments();
token = mScanner->NextToken(); // must be the exception name
if (IDENTIFIER_TOKEN == token->id) {
funcObj->AddException(token->stringID);
TrimComments();
token = mScanner->NextToken(); // must be ',' or ')'
}
else {
delete funcObj;
throw FunctionParsingException("Undeclared exception name.");
}
}
if (FUNC_PARAMS_SPEC_END_TOKEN != token->id) {
delete funcObj;
throw FunctionParsingException("Missing ')'. Exceptions declaration non terminated.");
}
TrimComments();
token = mScanner->PeekToken();
}
}
}
else {
delete funcObj;
throw FunctionParsingException("Missing '('. Parameters list undefined.");
}
}
else {
delete funcObj;
throw FunctionParsingException("Missing identifier. Function name undefined.");
}
return funcObj;
}
/**
* Parse a function argument
*
*/
IdlParameter* IdlParser::ParseFunctionParameter(IdlSpecification &aSpecification)
{
IdlParameter *argObj = new IdlParameter();
Token *token = mScanner->NextToken();
if (token->id == OPTIONAL_TOKEN) {
argObj->SetIsOptional(1);
token = mScanner->NextToken();
}
// the paramenter attribute (in, out, inout)
switch(token->id) {
// base type
case INPUT_PARAM_TOKEN:
#if defined XP_UNIX || defined XP_MAC || defined XP_BEOS
argObj->SetAttribute(IdlParameter::INPUT);
#else
argObj->SetAttribute(IdlParameter.INPUT);
#endif
break;
case OUTPUT_PARAM_TOKEN:
#if defined XP_UNIX || defined XP_MAC || defined XP_BEOS
argObj->SetAttribute(IdlParameter::OUTPUT);
#else
argObj->SetAttribute(IdlParameter.OUTPUT);
#endif
break;
case INOUT_PARAM_TOKEN:
#if defined XP_UNIX || defined XP_MAC || defined XP_BEOS
argObj->SetAttribute(IdlParameter::INOUT);
#else
argObj->SetAttribute(IdlParameter.INOUT);
#endif
break;
default:
delete argObj;
throw ParameterParsingException("Parameter attribute (in, out or inout) undefined.");
}
TrimComments();
token = mScanner->NextToken();
// must be a known type
switch(token->id) {
// base type
case BOOLEAN_TOKEN:
argObj->SetType(TYPE_BOOLEAN);
break;
case FLOAT_TOKEN:
argObj->SetType(TYPE_FLOAT);
break;
case DOUBLE_TOKEN:
argObj->SetType(TYPE_DOUBLE);
break;
case LONG_TOKEN:
argObj->SetType(TYPE_LONG);
break;
case LONG_LONG_TOKEN:
argObj->SetType(TYPE_LONG_LONG);
break;
case SHORT_TOKEN:
argObj->SetType(TYPE_SHORT);
break;
case ULONG_TOKEN:
argObj->SetType(TYPE_ULONG);
break;
case ULONG_LONG_TOKEN:
argObj->SetType(TYPE_ULONG_LONG);
break;
case USHORT_TOKEN:
argObj->SetType(TYPE_USHORT);
break;
case CHAR_TOKEN:
argObj->SetType(TYPE_CHAR);
break;
case INT_TOKEN:
argObj->SetType(TYPE_INT);
break;
case UINT_TOKEN:
argObj->SetType(TYPE_UINT);
break;
case JSVAL_TOKEN:
argObj->SetType(TYPE_JSVAL);
break;
// string type
case STRING_TOKEN:
argObj->SetType(TYPE_STRING);
break;
case UNKNOWN_TOKEN:
argObj->SetType(TYPE_UNKNOWN);
break;
// scoped name
case IDENTIFIER_TOKEN:
//if (aSpecification.ContainInterface(token->stringID)) {
argObj->SetType(TYPE_OBJECT);
argObj->SetTypeName(token->stringID);
break;
//}
case XPIDL_TOKEN:
token = mScanner->NextToken();
if (IDENTIFIER_TOKEN == token->id) {
argObj->SetType(TYPE_XPIDL_OBJECT);
argObj->SetTypeName(token->stringID);
break;
}
case FUNC_TOKEN:
token = mScanner->NextToken();
if (IDENTIFIER_TOKEN == token->id) {
argObj->SetType(TYPE_FUNC);
argObj->SetTypeName(token->stringID);
break;
}
default:
delete argObj;
throw ParameterParsingException("Unknow type in parameters list.");
}
TrimComments();
// must be the argument name
token = mScanner->NextToken();
if (IDENTIFIER_TOKEN == token->id) {
argObj->SetName(token->stringID);
}
else {
delete argObj;
throw ParameterParsingException("Missing identifier. Parameter name undefined.");
}
return argObj;
}
/**
* Skip all following comments
*
*/
void IdlParser::TrimComments()
{
while (COMMENT_TOKEN == mScanner->PeekToken()->id) {
mScanner->NextToken();
}
}