[ 
https://issues.apache.org/jira/browse/DAFFODIL-2473?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17338432#comment-17338432
 ] 

Mike Beckerle commented on DAFFODIL-2473:
-----------------------------------------

Pretty close. let's just look at the shifts first.

Best way to get feedback on code is to create a pull request, if you are just 
looking for initial feedback just name it with "WIP: ..." for work-in-progress.

The shift operations take two arguments, so should extend FNTwoArgs. The 2nd 
argument is the shift count, always an unsignedInt.

I suggest we define the logical shifts, if the shiftCount is greater than the 
width of the integer, the result is 0. For arithmetic shift right if the type 
is signed, and the value is negative, then arithmetic shift right will 
sign-extend the sign bit, so any shift equal to or greater than the integer 
width will produce -1 as the value.

In your code in the comment thread above, you don't need the first cases for  
NodeInfo.Decimal nor float nor double, as those will be picked up by your final 
`case _ => ...`

Your error message should say "leftShift not supported for type".

Outside of the logic to do the operation which you have above, there is also 
informing the Daffodil schema compiler about the new functions.

If you look at the definition of FNRound, that is defined for numeric types by 
using a class called FNOneArgMathExpr which has  member inherentType and method 
targetTypeForSubexpression  which inform the Daffodil schema compiler what the 
constraints are on the argument and result type for the function.

We need to do something similar, but inform the Daffodil schema compiler that 
your shifts are defined for two args, the first of which is either 
unsignedLong, signed long, or the types derived from those. The second arg is 
always an unsignedInt.

So I think you should copy the FNTwoArgsMathExpr case class and modify to 
create case class DFDLXShiftExpr

DFDLX  is used here not FN, because these functions are daffodil extensions of 
the DFDL standard, so will go in a namespace we normally bind the "dfdlx" 
prefix to.  We will propose these functions for eventual inclusion in the DFDL 
specification at which point we'll put them in the regular dfdl namespace.

That case class will extend FunctionCallBase, and must provide methods that 
supply type info for the Daffodil schema compiler like this:
{code:java}
case class DFDLXShiftExpr(nameAsParsed: String, fnQName: RefQName,
  args: List[Expression], constructor: List[CompiledDPath] => RecipeOp)
  extends FunctionCallBase(nameAsParsed, fnQName, args) {  

/**
 * Gives the inherent type of the result. This should match the type of the 
first 
 * argument, which we check here must be some subtype of unsignedLong or signed 
long.
 */
override lazy val inherentType = {
    val argInherentType = args(0).inherentType
    checkArgCount(2)

    schemaDefinitionUnless(
      argInherentType.isSubtypeOf(NodeInfo.PrimType.UnsignedLong) ||
      argInherentType.isSubtypeOf(Nodenfo.PrimType.Long),
      "First argument must be either unsignedLong, signed long, or a subtype of 
those, but was %s.",
      argInherentType)

    argInherentType
  }  

/**
 * Informs the schema compiler what the expressions for args should be required
 * to compile into. When this doesn't match the inherent type of the argument 
expression
 * then daffodil may insert a conversion (if one is defined for the two types). 
 */
override def targetTypeForSubexpression(subexp: Expression): NodeInfo.Kind = {
    if (subexp == args(0))
      inherentType // above that is constrained to be long or unsignedLong or 
derived from those
    else if (subexp == args(1))
      NodeInfo.UnsignedInt // 2nd argument is always unsignedInt. 
    else
      Assert.invariantFailed("subexpression %s is not an 
argument.".format(subexp))
  }
}{code}
(I can't guarantee that compiles. I just did it in this editor.)

Given the above, these would plug into the expression compilation if you look 
for this in Expression.scala:
{code:java}
case (RefQName(_, "round", FUNC), args) =>
  FNOneArgMathExpr(functionQNameString, functionQName, args,
    FNRound(_, _))
{code}
Your shifts would plug in similarly like:
{code:java}
case (RefQName(_, "leftShift", DFDLX), args) =>
  DFDLXShiftExpr(functionQNameString, functionQName, args,
    DFDLXLeftShift(_, _))
{code}
Similarly for DFDLXRightShift, DFDLXArithmeticRightShift.  (Note here I renamed 
your FNLeftShift to DFDLXLeftShift.)

Next comment will be about testing.

 

 

 

> Need bit-wise AND, OR, NOT, and shift operations
> ------------------------------------------------
>
>                 Key: DAFFODIL-2473
>                 URL: https://issues.apache.org/jira/browse/DAFFODIL-2473
>             Project: Daffodil
>          Issue Type: New Feature
>          Components: Back End, Front End
>    Affects Versions: 3.0.0
>            Reporter: Mike Beckerle
>            Priority: Critical
>
> There are a number of data representations DFDL cannot handle because it 
> cannot manipulate numbers with sufficient flexibility in expressions.
> We need AND, OR, NOT, maybe XOR, and shift left, shift right, and probably 
> arithmetic shift right (which does sign-extension of signed numbers). We 
> should add functions for the whole set of them.
> On signed numbers with specific sizes (long, int, short, byte) these should 
> behave as if the data was binary in 2s complement representation, i.e., as if 
> the most-significant-bit was playing the role of 2s complement sign.
> These operations should all be undefined (Schema Def Error) on decimal, 
> integer, and non-negative integer values, as well as float and double.
> Specifically, these operations are defined on long and its subtypes, and 
> unsignedLong and its subtypes only.
>  
>  
>  



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to