Report on deserialization errors in normalize()

Change-Id: Icf44406a63c5257c49a56d2c36f9fb0f3d6b5a89
diff --git a/lib/Krawfish/Koral/Query.pm b/lib/Krawfish/Koral/Query.pm
index ba310ce..dcdbd32 100644
--- a/lib/Krawfish/Koral/Query.pm
+++ b/lib/Krawfish/Koral/Query.pm
@@ -9,7 +9,7 @@
 with 'Krawfish::Koral::Report';
 
 # TODO:
-#   Share a role with Koral::Corpus
+#   Share a role with Koral::Corpus and Koral::Report::Failure
 requires qw/normalize
             optimize
             identify
@@ -52,7 +52,6 @@
 #   This is now double with Krawfish::Koral!
 
 use constant {
-  CONTEXT => 'http://korap.ids-mannheim.de/ns/koral/0.6/context.jsonld',
   DEBUG => 0
 };
 
@@ -335,12 +334,12 @@
 #############################
 
 # Serialize
-sub to_koral_query {
-  my $self = shift;
-  my $koral = $self->to_koral_fragment;
-  $koral->{'@context'} = CONTEXT;
-  $koral;
-};
+#sub to_koral_query {
+#  my $self = shift;
+#  my $koral = $self->to_koral_fragment;
+#  $koral->{'@context'} = CONTEXT;
+#  $koral;
+#};
 
 
 sub to_neutral {
diff --git a/lib/Krawfish/Koral/Query/Builder.pm b/lib/Krawfish/Koral/Query/Builder.pm
index 9323f0f..18a3593 100644
--- a/lib/Krawfish/Koral/Query/Builder.pm
+++ b/lib/Krawfish/Koral/Query/Builder.pm
@@ -20,6 +20,8 @@
 use Krawfish::Koral::Query::Filter;
 use Krawfish::Koral::Query::Match;
 
+use Krawfish::Koral::Query::Failure;
+
 use Krawfish::Koral::Query::Constraint::Position;
 use Krawfish::Koral::Query::Constraint::ClassBetween;
 use Krawfish::Koral::Query::Constraint::NotBetween;
@@ -264,6 +266,13 @@
 };
 
 
+# Return Failure object
+sub failure {
+  shift;
+  Krawfish::Koral::Query::Failure->new(shift);
+};
+
+
 # No match
 sub nowhere {
   Krawfish::Koral::Query::Nowhere->new;
@@ -438,8 +447,8 @@
     return Krawfish::Koral::Query::Nowhere->from_koral;
   };
 
-  warn "Type $type no term or termGroup";
-  return;
+  # Return failure with error message
+  return $self->failure($kq)->error(000 => 'Type no term or termGroup', $type);
 };
 
 
diff --git a/lib/Krawfish/Koral/Query/Failure.pm b/lib/Krawfish/Koral/Query/Failure.pm
new file mode 100644
index 0000000..eaee0d9
--- /dev/null
+++ b/lib/Krawfish/Koral/Query/Failure.pm
@@ -0,0 +1,74 @@
+package Krawfish::Koral::Query::Failure;
+use Role::Tiny::With;
+use strict;
+use warnings;
+
+with 'Krawfish::Koral::Query';
+
+sub new {
+  my $class = shift;
+  bless {
+    raw => shift
+  }, $class;
+};
+
+sub type {
+  'failure';
+};
+
+sub is_leaf {
+  1;
+};
+
+sub to_string {
+  '!!!';
+};
+
+sub normalize {
+  $_[0];
+};
+
+sub finalize {
+  $_[0];
+};
+
+sub identify {
+  $_[0];
+};
+
+sub optimize {
+  return;
+};
+
+sub operand {
+  undef;
+};
+
+sub operands {
+  [];
+};
+
+sub remove_classes {
+  $_[0];
+};
+
+sub min_span {
+  -1;
+};
+
+sub max_span {
+  -1;
+};
+
+sub to_koral_fragment {
+  return shift->{raw}
+};
+
+sub from_koral {
+  my $self = shift;
+  return $self->new(shift);
+};
+
+
+
+1;
diff --git a/lib/Krawfish/Koral/Query/Token.pm b/lib/Krawfish/Koral/Query/Token.pm
index 2f62203..9810ee2 100644
--- a/lib/Krawfish/Koral/Query/Token.pm
+++ b/lib/Krawfish/Koral/Query/Token.pm
@@ -84,7 +84,16 @@
 
   # There is an operand defined
   if ($self->operand) {
+
     my $op = $self->operand->normalize;
+
+    # Operand has an error
+    if ($op->has_error) {
+      $self->copy_info_from($op);
+      return;
+    };
+
+
     if ($op->is_nowhere) {
       $self->operands([]);
       $self->is_nowhere(1);
@@ -106,6 +115,7 @@
 };
 
 
+# Finalize query
 sub finalize {
   my $self = shift;
 
@@ -125,6 +135,7 @@
 };
 
 
+# Optimize query
 sub optimize {
   my ($self, $segment) = @_;
 
diff --git a/lib/Krawfish/Koral/Report.pm b/lib/Krawfish/Koral/Report.pm
index 646c4e6..28fa479 100644
--- a/lib/Krawfish/Koral/Report.pm
+++ b/lib/Krawfish/Koral/Report.pm
@@ -4,6 +4,11 @@
 use Role::Tiny;
 use Krawfish::Log;
 
+# TODO:
+#   This is now double with Krawfish::Koral::Query!
+use constant {
+  CONTEXT => 'http://korap.ids-mannheim.de/ns/koral/0.6/context.jsonld'
+};
 
 requires qw/error
             warning
@@ -109,4 +114,33 @@
 };
 
 
+sub to_koral_report {
+  my ($self, $type) = @_;
+  return $self->_info($type);
+};
+
+
+# Wrap the fragment in context
+sub to_koral_query {
+  my $self = shift;
+  my $koral = $self->to_koral_fragment;
+  $koral->{'@context'} = CONTEXT;
+
+  if ($self->has_warning) {
+    $koral->{warnings} = $self->to_koral_report('warning')
+  };
+
+  if ($self->has_error) {
+    $koral->{errors} = $self->to_koral_report('error')
+  };
+
+  if ($self->has_message) {
+    $koral->{messages} = $self->to_koral_report('message')
+  };
+
+  return $koral;
+};
+
+
+
 1;
diff --git a/lib/Krawfish/Koral/Result/Inflatable.pm b/lib/Krawfish/Koral/Result/Inflatable.pm
index c664cfb..54bd082 100644
--- a/lib/Krawfish/Koral/Result/Inflatable.pm
+++ b/lib/Krawfish/Koral/Result/Inflatable.pm
@@ -2,23 +2,9 @@
 use strict;
 use warnings;
 use Role::Tiny;
+
 requires qw/inflate
             to_string
             to_koral_fragment/;
 
-# TODO:
-#   This is now double with Krawfish::Koral::Query!
-use constant {
-  CONTEXT => 'http://korap.ids-mannheim.de/ns/koral/0.6/context.jsonld'
-};
-
-
-# Wrap the fragment in context
-sub to_koral_query {
-  my $self = shift;
-  my $koral = $self->to_koral_fragment;
-  $koral->{'@context'} = CONTEXT;
-  return $koral;
-};
-
 1;