2012-11-03 14:20:06 +00:00
// GtkSharp.Generation.Parser.cs - The XML Parsing engine.
//
// Author: Mike Kestner <mkestner@speakeasy.net>
//
// Copyright (c) 2001-2003 Mike Kestner
// Copyright (c) 2003 Ximian Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// 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., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
namespace GtkSharp.Generation {
using System ;
2012-11-04 15:19:05 +00:00
using System.Collections.Generic ;
2012-11-03 14:20:06 +00:00
using System.IO ;
using System.Xml ;
2012-11-25 14:55:27 +00:00
using System.Xml.Schema ;
2012-11-03 14:20:06 +00:00
public class Parser {
2013-05-30 21:55:19 +00:00
const int curr_parser_version = 3 ;
2012-11-03 14:20:06 +00:00
2012-11-25 14:55:27 +00:00
private XmlDocument Load ( string filename , string schema_file )
2012-11-03 14:20:06 +00:00
{
XmlDocument doc = new XmlDocument ( ) ;
try {
2012-11-25 14:55:27 +00:00
XmlReaderSettings settings = new XmlReaderSettings ( ) ;
if ( ! String . IsNullOrEmpty ( schema_file ) ) {
settings . Schemas . Add ( null , schema_file ) ;
settings . ValidationType = ValidationType . Schema ;
settings . ValidationFlags | = XmlSchemaValidationFlags . ReportValidationWarnings ;
settings . ValidationEventHandler + = ValidationEventHandler ;
}
2012-11-03 14:20:06 +00:00
Stream stream = File . OpenRead ( filename ) ;
2012-11-25 14:55:27 +00:00
XmlReader reader = XmlReader . Create ( stream , settings ) ;
doc . Load ( reader ) ;
2012-11-03 14:20:06 +00:00
stream . Close ( ) ;
} catch ( XmlException e ) {
Console . WriteLine ( "Invalid XML file." ) ;
Console . WriteLine ( e ) ;
doc = null ;
}
return doc ;
}
2012-11-25 14:55:27 +00:00
private void ValidationEventHandler ( object sender , ValidationEventArgs e )
{
switch ( e . Severity )
{
case XmlSeverityType . Error :
Console . WriteLine ( "Error: {0}" , e . Message ) ;
break ;
case XmlSeverityType . Warning :
Console . WriteLine ( "Warning: {0}" , e . Message ) ;
break ;
}
}
2012-11-03 14:20:06 +00:00
public IGeneratable [ ] Parse ( string filename )
{
2012-11-25 14:55:27 +00:00
return Parse ( filename , null ) ;
}
public IGeneratable [ ] Parse ( string filename , string schema_file )
2013-10-09 18:00:14 +00:00
{
return Parse ( filename , schema_file , String . Empty ) ;
}
public IGeneratable [ ] Parse ( string filename , string schema_file , string gapidir )
2012-11-25 14:55:27 +00:00
{
XmlDocument doc = Load ( filename , schema_file ) ;
2012-11-03 14:20:06 +00:00
if ( doc = = null )
return null ;
XmlElement root = doc . DocumentElement ;
if ( ( root = = null ) | | ! root . HasChildNodes ) {
Console . WriteLine ( "No Namespaces found." ) ;
return null ;
}
int parser_version ;
if ( root . HasAttribute ( "parser_version" ) ) {
try {
parser_version = int . Parse ( root . GetAttribute ( "parser_version" ) ) ;
} catch {
Console . WriteLine ( "ERROR: Unable to parse parser_version attribute value \"{0}\" to a number. Input file {1} will be ignored" , root . GetAttribute ( "parser_version" ) , filename ) ;
return null ;
}
} else
parser_version = 1 ;
if ( parser_version > curr_parser_version )
Console . WriteLine ( "WARNING: The input file {0} was created by a parser that was released after this version of the generator. Consider updating the code generator if you experience problems." , filename ) ;
2012-11-04 15:19:05 +00:00
var gens = new List < IGeneratable > ( ) ;
2012-11-03 14:20:06 +00:00
foreach ( XmlNode child in root . ChildNodes ) {
XmlElement elem = child as XmlElement ;
if ( elem = = null )
continue ;
switch ( child . Name ) {
2013-08-07 21:36:38 +00:00
case "include" :
2013-10-09 18:00:14 +00:00
string xmlpath ;
if ( File . Exists ( Path . Combine ( gapidir , elem . GetAttribute ( "xml" ) ) ) )
xmlpath = Path . Combine ( gapidir , elem . GetAttribute ( "xml" ) ) ;
else if ( File . Exists ( elem . GetAttribute ( "xml" ) ) )
xmlpath = elem . GetAttribute ( "xml" ) ;
else {
Console . WriteLine ( "Parser: Could not find include " + elem . GetAttribute ( "xml" ) ) ;
break ;
}
IGeneratable [ ] curr_gens = Parse ( xmlpath ) ;
2013-08-07 21:36:38 +00:00
SymbolTable . Table . AddTypes ( curr_gens ) ;
break ;
2012-11-03 14:20:06 +00:00
case "namespace" :
gens . AddRange ( ParseNamespace ( elem ) ) ;
break ;
case "symbol" :
gens . Add ( ParseSymbol ( elem ) ) ;
break ;
default :
Console . WriteLine ( "Parser::Parse - Unexpected child node: " + child . Name ) ;
break ;
}
}
2012-11-04 15:19:05 +00:00
return gens . ToArray ( ) ;
2012-11-03 14:20:06 +00:00
}
2012-11-04 15:19:05 +00:00
private IList < IGeneratable > ParseNamespace ( XmlElement ns )
2012-11-03 14:20:06 +00:00
{
2012-11-04 15:19:05 +00:00
var result = new List < IGeneratable > ( ) ;
2012-11-03 14:20:06 +00:00
foreach ( XmlNode def in ns . ChildNodes ) {
XmlElement elem = def as XmlElement ;
if ( elem = = null )
continue ;
if ( elem . GetAttributeAsBoolean ( "hidden" ) )
continue ;
bool is_opaque = elem . GetAttributeAsBoolean ( "opaque" ) ;
2013-10-09 11:40:56 +00:00
bool is_native_struct = elem . GetAttributeAsBoolean ( "native" ) ;
2012-11-03 14:20:06 +00:00
switch ( def . Name ) {
case "alias" :
string aname = elem . GetAttribute ( "cname" ) ;
string atype = elem . GetAttribute ( "type" ) ;
if ( ( aname = = "" ) | | ( atype = = "" ) )
continue ;
result . Add ( new AliasGen ( aname , atype ) ) ;
break ;
case "boxed" :
2012-11-04 15:19:05 +00:00
if ( is_opaque ) {
result . Add ( new OpaqueGen ( ns , elem ) ) ;
} else {
result . Add ( new BoxedGen ( ns , elem ) ) ;
}
2012-11-03 14:20:06 +00:00
break ;
case "callback" :
result . Add ( new CallbackGen ( ns , elem ) ) ;
break ;
case "enum" :
result . Add ( new EnumGen ( ns , elem ) ) ;
break ;
case "interface" :
result . Add ( new InterfaceGen ( ns , elem ) ) ;
break ;
case "object" :
result . Add ( new ObjectGen ( ns , elem ) ) ;
break ;
case "class" :
result . Add ( new ClassGen ( ns , elem ) ) ;
break ;
2013-10-08 18:22:16 +00:00
case "union" :
result . Add ( new UnionGen ( ns , elem ) ) ;
break ;
2012-11-03 14:20:06 +00:00
case "struct" :
2012-11-04 15:19:05 +00:00
if ( is_opaque ) {
result . Add ( new OpaqueGen ( ns , elem ) ) ;
2013-10-09 11:40:56 +00:00
} else if ( is_native_struct ) {
result . Add ( new NativeStructGen ( ns , elem ) ) ;
2012-11-04 15:19:05 +00:00
} else {
result . Add ( new StructGen ( ns , elem ) ) ;
}
2012-11-03 14:20:06 +00:00
break ;
default :
Console . WriteLine ( "Parser::ParseNamespace - Unexpected node: " + def . Name ) ;
break ;
}
}
return result ;
}
2013-10-08 16:55:34 +00:00
internal static int GetVersion ( XmlElement document_element )
{
XmlElement root = document_element ;
return root . HasAttribute ( "parser_version" ) ? int . Parse ( root . GetAttribute ( "parser_version" ) ) : 1 ;
}
2012-11-03 14:20:06 +00:00
private IGeneratable ParseSymbol ( XmlElement symbol )
{
string type = symbol . GetAttribute ( "type" ) ;
string cname = symbol . GetAttribute ( "cname" ) ;
string name = symbol . GetAttribute ( "name" ) ;
IGeneratable result = null ;
if ( type = = "simple" ) {
if ( symbol . HasAttribute ( "default_value" ) )
result = new SimpleGen ( cname , name , symbol . GetAttribute ( "default_value" ) ) ;
else {
Console . WriteLine ( "Simple type element " + cname + " has no specified default value" ) ;
result = new SimpleGen ( cname , name , String . Empty ) ;
}
} else if ( type = = "manual" )
result = new ManualGen ( cname , name ) ;
else if ( type = = "ownable" )
result = new OwnableGen ( cname , name ) ;
else if ( type = = "alias" )
result = new AliasGen ( cname , name ) ;
else if ( type = = "marshal" ) {
string mtype = symbol . GetAttribute ( "marshal_type" ) ;
string call = symbol . GetAttribute ( "call_fmt" ) ;
string from = symbol . GetAttribute ( "from_fmt" ) ;
result = new MarshalGen ( cname , name , mtype , call , from ) ;
} else if ( type = = "struct" ) {
result = new ByRefGen ( symbol . GetAttribute ( "cname" ) , symbol . GetAttribute ( "name" ) ) ;
} else
Console . WriteLine ( "Parser::ParseSymbol - Unexpected symbol type " + type ) ;
return result ;
}
}
}