Пример #1
0
  private void processPositional(
      RuleBuildContext context,
      Query query,
      Declaration[] params,
      List<Integer> declrIndexes,
      List<Integer> varIndexes,
      List<Object> arguments,
      List<Declaration> requiredDeclarations,
      InternalReadAccessor arrayReader,
      Pattern pattern,
      BaseDescr base,
      String expression,
      ConstraintConnectiveDescr result) {
    int position = ((ExprConstraintDescr) base).getPosition();
    if (position >= arguments.size()) {
      context.addError(
          new DescrBuildError(
              context.getParentDescr(),
              base,
              null,
              "Unable to parse query '"
                  + query.getName()
                  + "', as postion "
                  + (position - 1)
                  + " for expression '"
                  + expression
                  + "' does not exist on query size "
                  + arguments.size()));
      return;
    }
    if (isVariable(expression)) {
      // is this already bound?
      Declaration declr = context.getDeclarationResolver().getDeclaration(query, expression);
      if (declr != null) {
        // it exists, so it's an input
        arguments.set(position, declr);
        declrIndexes.add(position);
        requiredDeclarations.add(declr);
      } else {
        // it doesn't exist, so it's an output
        arguments.set(position, Variable.v);

        varIndexes.add(position);

        declr = pattern.addDeclaration(expression);

        // this bit is different, notice its the ArrayElementReader that we wire up to, not the
        // declaration.
        ArrayElementReader reader =
            new ArrayElementReader(
                arrayReader, position, params[position].getExtractor().getExtractToClass());

        declr.setReadAccessor(reader);
      }
    } else {
      // it's an expression and thus an input
      MVELDumper.MVELDumperContext mvelCtx = new MVELDumper.MVELDumperContext();
      String rewrittenExpr =
          context.getCompilerFactory().getExpressionProcessor().dump(result, mvelCtx);
      arguments.set(position, MVEL.eval(rewrittenExpr)); // for now we just work with literals
    }
  }
  private Accumulator[] buildExternalFunctions(
      final RuleBuildContext context,
      final AccumulateDescr accumDescr,
      MVELDialect dialect,
      Map<String, Declaration> decls,
      Map<String, Declaration> sourceOuterDeclr,
      BoundIdentifiers boundIds,
      boolean readLocalsFromTuple) {
    Accumulator[] accumulators;
    List<AccumulateFunctionCallDescr> functions = accumDescr.getFunctions();

    accumulators = new Accumulator[functions.size()];
    // creating the custom array reader
    InternalReadAccessor arrayReader = new SelfReferenceClassFieldReader(Object[].class, "this");

    int index = 0;
    Pattern pattern = (Pattern) context.getDeclarationResolver().peekBuildStack();
    for (AccumulateFunctionCallDescr func : functions) {
      // build an external function executor
      AccumulateFunction function =
          context.getConfiguration().getAccumulateFunction(func.getFunction());
      if (function == null) {
        // might have been imported in the package
        function =
            context
                .getKnowledgeBuilder()
                .getPackage()
                .getAccumulateFunctions()
                .get(func.getFunction());
      }
      if (function == null) {
        context.addError(
            new DescrBuildError(
                accumDescr,
                context.getRuleDescr(),
                null,
                "Unknown accumulate function: '"
                    + func.getFunction()
                    + "' on rule '"
                    + context.getRuleDescr().getName()
                    + "'. All accumulate functions must be registered before building a resource."));
        return null;
      }

      final AnalysisResult analysis =
          dialect.analyzeExpression(
              context,
              accumDescr,
              func.getParams().length > 0 ? func.getParams()[0] : "\"\"",
              boundIds);

      MVELCompilationUnit unit =
          dialect.getMVELCompilationUnit(
              func.getParams().length > 0 ? func.getParams()[0] : "\"\"",
              analysis,
              getUsedDeclarations(decls, analysis),
              getUsedDeclarations(sourceOuterDeclr, analysis),
              null,
              context,
              "drools",
              KnowledgeHelper.class,
              readLocalsFromTuple,
              MVELCompilationUnit.Scope.CONSTRAINT);

      accumulators[index] = new MVELAccumulatorFunctionExecutor(unit, function);
      // if there is a binding, create the binding
      if (func.getBind() != null) {
        if (context
            .getDeclarationResolver()
            .isDuplicated(context.getRule(), func.getBind(), function.getResultType().getName())) {
          if (!func.isUnification()) {
            context.addError(
                new DescrBuildError(
                    context.getParentDescr(),
                    accumDescr,
                    null,
                    "Duplicate declaration for variable '"
                        + func.getBind()
                        + "' in the rule '"
                        + context.getRule().getName()
                        + "'"));
          } else {
            Declaration inner =
                context.getDeclarationResolver().getDeclaration(context.getRule(), func.getBind());
            Constraint c =
                new MvelConstraint(
                    Collections.singletonList(context.getPkg().getName()),
                    accumDescr.isMultiFunction()
                        ? "this[ " + index + " ] == " + func.getBind()
                        : "this == " + func.getBind(),
                    new Declaration[] {inner},
                    null,
                    IndexUtil.ConstraintType.EQUAL,
                    context
                        .getDeclarationResolver()
                        .getDeclaration(context.getRule(), func.getBind()),
                    accumDescr.isMultiFunction()
                        ? new ArrayElementReader(arrayReader, index, function.getResultType())
                        : new SelfReferenceClassFieldReader(function.getResultType(), "this"),
                    true);
            ((MutableTypeConstraint) c).setType(Constraint.ConstraintType.BETA);
            pattern.addConstraint(c);
            index++;
          }
        } else {
          Declaration declr = pattern.addDeclaration(func.getBind());
          if (accumDescr.isMultiFunction()) {
            declr.setReadAccessor(
                new ArrayElementReader(arrayReader, index, function.getResultType()));
          } else {
            declr.setReadAccessor(
                new SelfReferenceClassFieldReader(function.getResultType(), "this"));
          }
        }
      }
      index++;
    }
    return accumulators;
  }
Пример #3
0
  @SuppressWarnings("unchecked")
  private void processBinding(
      RuleBuildContext context,
      BaseDescr descr,
      Declaration[] params,
      List<Integer> declrIndexes,
      List<Integer> varIndexes,
      List<Object> arguments,
      List<Declaration> requiredDeclarations,
      InternalReadAccessor arrayReader,
      Pattern pattern,
      BindingDescr bind,
      ConstraintConnectiveDescr result) {
    Declaration declr =
        context.getDeclarationResolver().getDeclaration(context.getRule(), bind.getVariable());
    if (declr != null) {
      // check right maps to a slot, otherwise we can't reverse this and should error
      int pos = getPos(bind.getExpression(), params);
      if (pos >= 0) {
        // slot exist, reverse and continue
        String slot = bind.getExpression();
        String var = bind.getVariable();
        bind.setVariable(slot);
        bind.setExpression(var);
      } else {
        // else error, we cannot find the slot to unify against
      }
    }

    // left does not already exist, is it a slot?
    int pos = getPos(bind.getVariable(), params);
    if (pos >= 0) {
      // it's an input on a slot, is the input using bindings?
      declr =
          context.getDeclarationResolver().getDeclaration(context.getRule(), bind.getExpression());
      if (declr != null) {
        arguments.set(pos, declr);
        declrIndexes.add(pos);
        requiredDeclarations.add(declr);
      } else {
        // it must be a literal/expression
        // it's an expression and thus an input
        DrlExprParser parser = new DrlExprParser(context.getConfiguration().getLanguageLevel());
        ConstraintConnectiveDescr bresult = parser.parse(bind.getExpression());
        if (parser.hasErrors()) {
          for (DroolsParserException error : parser.getErrors()) {
            context.addError(
                new DescrBuildError(
                    context.getParentDescr(),
                    descr,
                    null,
                    "Unable to parser pattern expression:\n" + error.getMessage()));
          }
          return;
        }

        MVELDumper.MVELDumperContext mvelCtx = new MVELDumper.MVELDumperContext();
        String expr = context.getCompilerFactory().getExpressionProcessor().dump(bresult, mvelCtx);
        try {
          Object o = MVEL.eval(expr);
          arguments.set(pos, o); // for now we just work with literals
        } catch (Exception e) {
          context.addError(
              new DescrBuildError(
                  context.getParentDescr(), descr, null, "Unable to compile expression:\n" + expr));
        }
      }
    } else {
      // this is creating a new output binding
      // we know it doesn't exist, as we already checked for left == var
      declr = pattern.addDeclaration(bind.getVariable());

      pos = getPos(bind.getExpression(), params);
      if (pos < 0) {
        // error this must be a binding on a slot
        context.addError(
            new DescrBuildError(
                context.getParentDescr(),
                descr,
                null,
                "named argument does not exist:\n" + bind.getExpression()));
        return;
      }

      // this bit is different, notice its the ArrayElementReader that we wire up to, not the
      // declaration.
      ArrayElementReader reader =
          new ArrayElementReader(arrayReader, pos, params[pos].getExtractor().getExtractToClass());

      // Should the reader be registered like the others? Probably yes...
      // PatternBuilder.registerReadAccessor(  );

      declr.setReadAccessor(reader);

      varIndexes.add(pos);
      arguments.set(pos, Variable.v);
    }
  }
Пример #4
0
 public void setDeclaration(Declaration declaration) {
   declaration.setReadAccessor(getReadAccessor());
   this.declaration = declaration;
 }