+2004-08-26 Atsushi Enomoto <atsushi@ximian.com>
+
+ * XPath2Expression.cs : in Compiler(), function call's arguments must
+ also be compiled.
+ * XQueryASTCompiler.cs : When function is external, it should not try
+ to compile body, and tries to handle it as a native CLI method (I
+ don't like this name resolution design very much, so it is likely
+ to be redesigned).
+ * XQueryCliFunction.cs : trivial code comment fix.
+ * XQueryFunction : added user-specified function call support.
+ When CLI function returned null, don't wrap null and just return
+ XQueryEmptySequence.
+ * XQueryFunctionCliImpl.cs : fn:nilled() requires certain node.
+ Implemented numeric functions (in the future they might be
+ rewritten to avoid boxing).
+ * XQueryTokenizer.cs : Skip XQuery comment inside default state.
+ PI and XML comment are not read correctly.
+
2004-08-25 Atsushi Enomoto <atsushi@ximian.com>
* XPath2Expression.cs :
#region CompileAndEvaluate
// It is instantiated per function call expression.
- // (e.g. the example below contains 3 FunctionCallExpression instances:
+ // (e.g. the example below contains 4 FunctionCallExpression instances:
// "replace(node-name (node-before(/*)), 'foo', node-name($var))"
internal class CustomFunctionCallExpr : FunctionCallExprBase
{
internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
{
CheckArguments (compiler);
+ for (int i = 0; i < Args.Count; i++)
+ Args [i] = Args [i].Compile (compiler);
return this;
}
if (main != null)
main.QueryBody.CheckReference (this);
foreach (FunctionDeclaration func in module.Prolog.Functions.Values) {
- func.FunctionBody.CheckReference (this);
+ if (!func.External)
+ func.FunctionBody.CheckReference (this);
CheckSchemaType (func.ReturnType);
foreach (XQueryFunctionArgument param in func.Parameters)
CheckSchemaType (param.Type);
private XQueryFunction CompileFunction (FunctionDeclaration func)
{
+ if (func.External)
+ return XQueryFunction.FromQName (func.Name);
return new XQueryUserFunction (func.Name, func.Parameters.ToArray (), func.FunctionBody.Expr, func.ReturnType);
}
// Ideas:\r
// declare function namespace cli = "http://mono-project.com/xquery/function/cli"\r
// declare variable v = cli:invoke (cli:new (Microsoft.CSharp:CSharpCodeProvider), CreateCompiler);\r
- // declare variable v2 = System:Math.Abs (0.5);\r
+ // declare variable v2 = System.Math:Abs (0.5);\r
//\r
\r
public class XQueryCliFunction : XQueryFunction\r
);
}
+ internal static XQueryCliFunction FromQName (XmlQualifiedName qname)
+ {
+ return XQueryCliFunction.CreateFromMethodInfo (
+ qname, FindNamedMethods (Type.GetType (qname.Namespace), qname.Name));
+ }
+
private static bool FilterImpl (MemberInfo m, object filterCriteria)
{
return m.Name == filterCriteria.ToString ();
for (int i = 0; i < args.Count; i++)
instParams [i] = Args [i].Type.ToRuntimeType (args [i].Evaluate (iter));
object o = Invoke (iter.Context, instParams);
+ if (o == null)
+ return new XPathEmptySequence (iter);
if (o is XPathSequence)
return (XPathSequence) o;
XPathItem item = o as XPathItem;
public static XmlQualifiedName FnNodeName (XPathNavigator arg)
{
if (arg == null)
- return XmlQualifiedName.Empty;
+ return null;
return arg.LocalName == String.Empty ?
XmlQualifiedName.Empty :
public static bool FnNilled (XPathNavigator arg)
{
if (arg == null)
- return false;
+ throw new XmlQueryException ("Function nilled() does not allow empty sequence parameter.");
IXmlSchemaInfo info = arg.NodeType == XPathNodeType.Element ? arg.SchemaInfo : null;
return info != null && info.IsNil;
return FnString (item);
}
+ [MonoTODO]
public static string FnString (object arg)
{
+ if (arg == null)
+ return String.Empty;
XPathNavigator nav = arg as XPathNavigator;
if (nav != null)
return nav.Value;
+ // FIXME: it should be exactly the same as "arg cast as xs:string"
XPathItem item = ToItem (arg);
return item != null ? XQueryConvert.ItemToString (item) : null;
}
+ [MonoTODO]
public static XPathAtomicValue FnData (object arg)
{
+ // FIXME: parameter should be object []
XPathNavigator nav = arg as XPathNavigator;
if (nav != null) {
XmlSchemaType st = nav.SchemaInfo != null ? nav.SchemaInfo.SchemaType : null;
// Numeric Operation
[MonoTODO]
- public static object FnAbs (ValueType arg)
- {
- throw new NotImplementedException ();
+ public static object FnAbs (object arg)
+ {
+ if (arg is int)
+ return System.Math.Abs ((int) arg);
+ if (arg is long)
+ return System.Math.Abs ((long) arg);
+ else if (arg is decimal)
+ return System.Math.Abs ((decimal) arg);
+ else if (arg is double)
+ return System.Math.Abs ((double) arg);
+ else if (arg is float)
+ return System.Math.Abs ((float) arg);
+ else if (arg is short)
+ return System.Math.Abs ((short) arg);
+ else if (arg is uint || arg is ulong || arg is ushort)
+ return arg;
+ return null;
}
[MonoTODO]
- public static object FnCeiling (ValueType arg)
+ public static object FnCeiling (object arg)
{
- throw new NotImplementedException ();
+ if (arg is decimal) {
+ decimal d = (decimal) arg;
+ decimal d2 = Decimal.Floor (d);
+ return d2 != d ? d2 + 1 : d2;
+ }
+ else if (arg is double || arg is float)
+ return System.Math.Ceiling ((double) arg);
+ else if (arg is int || arg is long || arg is short || arg is uint || arg is ulong || arg is ushort)
+ return arg;
+ return null;
}
[MonoTODO]
- public static object FnFloor (ValueType arg)
+ public static object FnFloor (object arg)
{
- throw new NotImplementedException ();
+ if (arg is decimal)
+ return Decimal.Floor ((decimal) arg);
+ else if (arg is double || arg is float)
+ return System.Math.Floor ((double) arg);
+ else if (arg is int || arg is long || arg is short || arg is uint || arg is ulong || arg is ushort)
+ return arg;
+ return null;
}
[MonoTODO]
- public static object FnRound (ValueType arg)
+ public static object FnRound (object arg)
{
- throw new NotImplementedException ();
+ if (arg is decimal)
+ return Decimal.Round ((decimal) arg, 0);
+ else if (arg is double || arg is float)
+ return System.Math.Round ((double) arg);
+ else if (arg is int || arg is long || arg is short || arg is uint || arg is ulong || arg is ushort)
+ return arg;
+ return null;
}
[MonoTODO]
- public static object FnRoundHalfToEven (ValueType arg)
+ public static object FnRoundHalfToEven (object arg)
{
throw new NotImplementedException ();
}
return FnNumber (ctx.CurrentItem);
}
- public static double FnNumber (XPathItem item)
+ public static double FnNumber (object arg)
{
- if (item == null)
+ if (arg == null)
throw new XmlQueryException ("Context item could not be ndetermined during number() evaluation.");
+ XPathItem item = ToItem (arg);
return XQueryConvert.ItemToDouble (item);
}
}
}
+ private int ParseXQueryComment ()
+ {
+ while (true) {
+ int c = ReadChar ();
+ if (c < 0)
+ throw Error ("Unexpected end of query text inside XML processing instruction content");
+ if (c == ':') {
+ if (PeekChar () == ')') {
+ ReadChar ();
+ tokenValue = CreateValueString ();
+ return Token.XML_PI_TO_END;
+ }
+ else
+ AddValueChar (':');
+ }
+ else
+ AddValueChar ((char) c);
+ }
+ }
+
private int ParseXmlPIContent ()
{
- // FIXME: handle ??> correctly
while (true) {
- int c = PeekChar ();
+ int c = ReadChar ();
if (c < 0)
throw Error ("Unexpected end of query text inside XML processing instruction content");
if (c == '?') {
- ReadChar ();
if (PeekChar () == '>') {
ReadChar ();
tokenValue = CreateValueString ();
{
// FIXME: handle ---> correctly
while (true) {
- int c = PeekChar ();
+ int c = ReadChar ();
if (c < 0)
throw Error ("Unexpected end of query text inside XML comment content");
if (c == '-') {
- ReadChar ();
if (PeekChar () == '-') {
ReadChar ();
if (PeekChar () == '>') {
{
// FIXME: handle ]]]> correctly
while (true) {
- int c = PeekChar ();
+ int c = ReadChar ();
if (c < 0)
throw Error ("Unexpected end of query text inside XML CDATA section content");
if (c == ']') {
ReadChar ();
return Token.PRAGMA_OPEN;
}
- return Token.OPEN_PAREN_COLON;
+ ParseXQueryComment ();
+ return ParseToken (); // start again
}
return Token.OPEN_PAREN;
case ')':