Commits

Kirill Simonov committed 1d42703

Added hints for lookup errors.

Comments (0)

Files changed (9)

src/htsql/tr/bind.py

 """
 
 
-from ..util import maybe, tupleof
+from ..util import maybe, listof, tupleof, similar
 from ..adapter import Adapter, Protocol, adapts
 from ..domain import (BooleanDomain, IntegerDomain, DecimalDomain,
                       FloatDomain, UntypedDomain)
                       SubstitutionRecipe, BindingRecipe, ClosedRecipe,
                       PinnedRecipe, AmbiguousRecipe)
 from .lookup import (lookup_attribute, lookup_reference, lookup_complement,
+                     lookup_attribute_set, lookup_reference_set,
                      expand, direct, guess_name, lookup_command)
 from .coerce import coerce
 
         raise BindError("unable to bind a node", self.syntax.mark)
 
 
+def hint_choices(choices):
+    # Generate a hint from a list of choices.
+    assert isinstance(choices, listof(unicode))
+    if not choices:
+        return None
+    chunks = ["did you mean:"]
+    if len(choices) == 1:
+        chunks.append("'%s'" % choices[0].encode('utf-8'))
+    else:
+        chunks.append(", ".join("'%s'" % choice.encode('utf-8')
+                                for choice in choices[:-1]))
+        chunks.append("or")
+        chunks.append("'%s'" % choices[-1].encode('utf-8'))
+    return " ".join(chunks)
+
+
 class BindQuery(Bind):
 
     adapts(QuerySyntax)
         recipe = lookup_reference(self.state.scope,
                                   self.syntax.identifier.value)
         if recipe is None:
+            model = self.syntax.identifier.value.lower()
+            names = lookup_reference_set(self.state.scope)
+            choices = [u"$"+name for name in sorted(names)
+                                 if similar(model, name)]
+            hint = hint_choices(choices)
             raise BindError("unrecognized reference '%s'"
-                            % self.syntax, self.syntax.mark)
+                            % self.syntax, self.syntax.mark,
+                            hint=hint)
         return self.state.use(recipe, self.syntax)
 
 
 
     def __call__(self):
         # The default implementation; override in subclasses.
+        hint = None
+        # Generate a hint with a list of alternative names.
+        model = self.name.lower()
+        arity = None
+        if self.arguments is not None:
+            arity = len(self.arguments)
+        attributes = lookup_attribute_set(self.state.scope)
+        global_attributes = set()
+        for component in BindByName.implementations():
+            for component_name in component.names:
+                component_arity = -1
+                if isinstance(component_name, tuple):
+                    component_name, component_arity = component_name
+                if isinstance(component_name, str):
+                    component_name = component_name.decode('utf-8')
+                component_name = component_name.lower()
+                global_attributes.add((component_name, component_arity))
+        all_attributes = sorted(attributes|global_attributes)
+        if hint is None and arity is None:
+            names = lookup_reference_set(self.state.scope)
+            if model in names:
+                hint = "did you mean: a reference '$%s'" % model.encode('utf-8')
+        if hint is None and arity is None:
+            if any(model == sample
+                   for sample, sample_arity in all_attributes
+                   if sample_arity is not None):
+                hint = "did you mean: a function '%s'" % model.encode('utf-8')
+        if hint is None and arity is None:
+            choices = [sample
+                       for sample, sample_arity in all_attributes
+                       if sample_arity is None and sample != model
+                            and similar(model, sample)]
+            hint = hint_choices(choices)
+        if hint is None and arity is not None \
+                and not isinstance(self.syntax, OperatorSyntax):
+            arities = [sample_arity
+                       for sample, sample_arity in all_attributes
+                       if sample == model and
+                            sample_arity not in [None, -1, arity]]
+            if arities:
+                required_arity = []
+                arities.sort()
+                if len(arities) == 1:
+                    required_arity.append(str(arities[0]))
+                else:
+                    required_arity.append(", ".join(str(sample_arity)
+                                    for sample_arity in arities[:-1]))
+                    required_arity.append("or")
+                    required_arity.append(str(arities[-1]))
+                if required_arity[-1] == "1":
+                    required_arity.append("argument")
+                else:
+                    required_arity.append("arguments")
+                required_arity = " ".join(required_arity)
+                raise BindError("function '%s' requires %s; got %s"
+                                % (self.syntax.identifier,
+                                   required_arity, arity),
+                                self.syntax.mark)
+        if hint is None and arity is not None:
+            if any(model == sample
+                   for sample, sample_arity in all_attributes
+                   if sample_arity is None):
+                hint = "did you mean: an attribute '%s'" % model.encode('utf-8')
+        if hint is None and arity is not None:
+            choices = [sample
+                       for sample, sample_arity in all_attributes
+                       if sample_arity in [-1, arity] and sample != model
+                            and similar(model, sample)]
+            hint = hint_choices(choices)
+        scope_name = guess_name(self.state.scope)
+        if scope_name is not None:
+            scope_name = scope_name.encode('utf-8')
         if isinstance(self.syntax, (FunctionSyntax, MappingSyntax)):
             raise BindError("unrecognized function '%s'"
                             % self.syntax.identifier,
-                            self.syntax.mark)
+                            self.syntax.mark, hint=hint)
         if isinstance(self.syntax, OperatorSyntax):
             raise BindError("unrecognized operator '%s'"
                             % self.syntax.symbol.encode('utf-8'),
-                            self.syntax.mark)
+                            self.syntax.mark, hint=hint)
         if isinstance(self.syntax, IdentifierSyntax):
-            raise BindError("unrecognized attribute '%s'" % self.syntax,
-                            self.syntax.mark)
+            raise BindError("unrecognized attribute '%s'%s"
+                            % (self.syntax,
+                               " in scope of '%s'" % scope_name
+                               if scope_name is not None else ""),
+                            self.syntax.mark, hint=hint)
 
 
 class BindByRecipe(Adapter):

src/htsql/tr/lookup.py

 from ..util import Clonable, Printable, maybe
 from ..adapter import Adapter, adapts, adapts_many
 from ..model import (HomeNode, TableNode, Arc, TableArc, ChainArc, ColumnArc,
-                     SyntaxArc, AmbiguousArc)
+                     SyntaxArc, InvalidArc, AmbiguousArc)
 from ..classify import classify, relabel, normalize
 from .syntax import IdentifierSyntax
 from .binding import (Binding, ScopingBinding, ChainingBinding, WrappingBinding,
                                 ",".join(["_"]*self.arity))
 
 
+class AttributeSetProbe(Probe):
+    """
+    Represents a request for a set of all attributes with their arities.
+    """
+
+
 class ReferenceProbe(Probe):
     """
     Represents a request for a reference.
         return "?$%s" % self.key.encode('utf-8')
 
 
+class ReferenceSetProbe(Probe):
+    """
+    Represents a request for a set of all references.
+    """
+
+
 class ComplementProbe(Probe):
     """
     Represents a request for a complement link.
         return None
 
 
+class LookupAttributeSet(Lookup):
+    # Generate a set of all available attributes.
+
+    adapts(Binding, AttributeSetProbe)
+
+    def __call__(self):
+        # No attributes by default.
+        return set()
+
+
+class LookupReferenceSet(Lookup):
+    # Generate a set of all available references.
+
+    adapts(Binding, ReferenceSetProbe)
+
+    def __call__(self):
+        # No references by default.
+        return set()
+
+
 class GuessName(Lookup):
     # Generate an attribute name from a binging node.
 
         return None
 
 
+class LookupReferenceSetInScoping(Lookup):
+    # Find all available references in a scoping node.
+
+    adapts(ScopingBinding, ReferenceSetProbe)
+
+    def __call__(self):
+        # Delegate reference lookups to the parent binding.
+        if self.binding.base is not None:
+            return lookup(self.binding.base, self.probe)
+        # Stop at the root binding.
+        return set()
+
+
 class LookupInChaining(Lookup):
     # Pass all lookup requests (except name guesses)
     # through chaining nodes.
     # Everything but `GuessNameProbe`.  Can't use `Probe`
     # since it causes ambiguous ordering of components.
     adapts_many((ChainingBinding, AttributeProbe),
+                (ChainingBinding, AttributeSetProbe),
                 (ChainingBinding, ReferenceProbe),
+                (ChainingBinding, ReferenceSetProbe),
                 (ChainingBinding, ComplementProbe),
                 (ChainingBinding, ExpansionProbe),
                 (ChainingBinding, GuessTitleProbe),
         return recipe
 
 
+class LookupAttributeSetInHome(Lookup):
+    # Attributes of the *home* scope represent database tables.
+
+    adapts(HomeBinding, AttributeSetProbe)
+
+    def __call__(self):
+        attributes = set()
+        labels = classify(HomeNode())
+        for label in labels:
+            # Skip invalid labels.
+            if isinstance(label.arc, InvalidArc):
+                continue
+            attributes.add((label.name, label.arity))
+        return attributes
+
+
 class ExpandHome(Lookup):
     # The home class contains no public attributes.
 
         return recipe
 
 
+class LookupAttributeSetInTable(Lookup):
+    # Produce a set of all labels available in a table scope.
+
+    adapts(TableBinding, AttributeSetProbe)
+
+    def __call__(self):
+        attributes = set()
+        labels = classify(TableNode(self.binding.table))
+        for label in labels:
+            # Skip invalid labels.
+            if isinstance(label.arc, InvalidArc):
+                continue
+            attributes.add((label.name, label.arity))
+        return attributes
+
+
 class ExpandTable(Lookup):
     # Extract all the columns of the table.
 
     adapts(ColumnBinding, AttributeProbe)
 
     def __call__(self):
-        # Ignore probes for parameterized attributes.
-        if self.probe.arity is not None:
-            return None
         # If there is an associated link node, delegate the request to it.
         if self.binding.link is not None:
             return lookup(self.binding.link, self.probe)
         return None
 
 
+class LookupAttributeSetInColumn(Lookup):
+    # Find all available attributes in a column scope.
+
+    adapts(ColumnBinding, AttributeSetProbe)
+
+    def __call__(self):
+        if self.binding.link is not None:
+            return lookup(self.binding.link, self.probe)
+        return set()
+
+
 class ExpandColumn(Lookup):
     # Produce all public members in a column scope.
     #
     # Find an attribute or a complement link in a complement scope.
 
     adapts_many((ComplementBinding, AttributeProbe),
+                (ComplementBinding, AttributeSetProbe),
                 (ComplementBinding, ComplementProbe))
 
     def __call__(self):
 class LookupAttributeInCover(Lookup):
     # Find an attribute in a cover scope.
 
-    adapts(CoverBinding, AttributeProbe)
+    adapts_many((CoverBinding, AttributeProbe),
+                (CoverBinding, AttributeSetProbe))
 
     def __call__(self):
         # Delegate all lookup requests to the seed flow.
     # Find an attribute or a complement link in a fork scope.
 
     adapts_many((ForkBinding, AttributeProbe),
+                (ForkBinding, AttributeSetProbe),
                 (ForkBinding, ComplementProbe))
 
     def __call__(self):
 class LookupAttributeInLink(Lookup):
     # Find an attribute in a link scope.
 
-    adapts(LinkBinding, AttributeProbe)
+    adapts_many((LinkBinding, AttributeProbe),
+                (LinkBinding, AttributeSetProbe),
+                (LinkBinding, ComplementProbe))
 
     def __call__(self):
         # Delegate all lookup probes to the seed scope.
         return super(LookupAttributeInDefinition, self).__call__()
 
 
+class LookupAttributeSetInDefinition(Lookup):
+    # Find all attributes in a definition binding.
+
+    adapts(DefinitionBinding, AttributeSetProbe)
+
+    def __call__(self):
+        attributes = super(LookupAttributeSetInDefinition, self).__call__()
+        if not self.binding.is_reference:
+            attributes.add((normalize(self.binding.name), self.binding.arity))
+        return attributes
+
+
 class LookupReferenceInDefinition(Lookup):
     # Find a reference in a definition binding.
 
         return super(LookupReferenceInDefinition, self).__call__()
 
 
+class LookupReferenceSetInDefinition(Lookup):
+    # Find all references in a definition binding.
+
+    adapts(DefinitionBinding, ReferenceSetProbe)
+
+    def __call__(self):
+        references = super(LookupReferenceSetInDefinition, self).__call__()
+        if self.binding.is_reference:
+            references.add(normalize(self.binding.name))
+        return references
+
+
 class ExpandSelection(Lookup):
     # Expand a selector operation.
 
 
     # All recipe-generating lookup requests.
     adapts_many((RerouteBinding, AttributeProbe),
+                (RerouteBinding, AttributeSetProbe),
                 (RerouteBinding, ReferenceProbe),
+                (RerouteBinding, ReferenceSetProbe),
                 (RerouteBinding, ComplementProbe),
                 (RerouteBinding, ExpansionProbe))
 
 class LookupReferenceInReferenceReroute(Lookup):
     # Probe for a reference in a reference reroute binding.
 
-    adapts(ReferenceRerouteBinding, ReferenceProbe)
+    adapts_many((ReferenceRerouteBinding, ReferenceProbe),
+                (ReferenceRerouteBinding, ReferenceSetProbe))
 
     def __call__(self):
         # Reroute the probe to the target binding.
     return lookup(binding, probe)
 
 
+def lookup_attribute_set(binding):
+    """
+    Produces a set of all available attributes and their arities.
+    """
+    probe = AttributeSetProbe()
+    return lookup(binding, probe)
+
+
 def lookup_reference(binding, name):
     """
     Finds a reference in the scope of the given binding.
     return lookup(binding, probe)
 
 
+def lookup_reference_set(binding):
+    """
+    Produces a set of all available references.
+    """
+    probe = ReferenceSetProbe()
+    return lookup(binding, probe)
+
+
 def lookup_complement(binding):
     """
     Extracts a complement link from the scope of the given binding.

src/htsql/util.py

         return tt.tm_isdst > 0
 
 
+#
+# String similarity.
+#
+
+
+def similar(model, sample):
+    """
+    Checks if `sample` is similar to `model`.
+    """
+    assert isinstance(model, unicode)
+    assert isinstance(sample, unicode)
+    if not model or not sample:
+        return False
+    if len(model) > 1 and sample.startswith(model):
+        return True
+    M = len(model)
+    N = len(sample)
+    threshold = 1+M/5
+    INF = threshold+1
+    if abs(M-N) > threshold:
+        return False
+    distance = {}
+    for i in range(min(M, threshold)+1):
+        distance[i, 0] = i
+    for j in range(min(N, threshold)+1):
+        distance[0, j] = j
+    for i in range(1, M+1):
+        for j in range(max(1, i-threshold), min(N, i+threshold)+1):
+            k = distance.get((i-1, j-1), INF)
+            if model[i-1] != sample[j-1]:
+                k += 1
+            if (i > 1 and j > 1 and model[i-2] == sample[j-1]
+                                and model[i-1] == sample[j-2]):
+                k = min(k, distance.get((i-2, j-2), INF)+1)
+            k = min(k, distance.get((i-1, j), INF)+1,
+                       distance.get((i, j-1), INF)+1)
+            if k <= threshold:
+                distance[i, j] = k
+    return ((M, N) in distance)
+
+

test/input/error.yaml

   - uri: /program.program
     expect: 400
 
+- title: Lookup Hints
+  tests:
+  # invalid reference with a hint
+  - uri: /school?code=$scool_code
+          :where $school_code:='art'
+    expect: 400
+  # invalid reference with no hints
+  - uri: /school?code=$code
+          :where $school_code:='art'
+    expect: 400
+  # invalid reference with many hints
+  - uri: /school?code=$scool_code
+          :where ($school_code1:='art', $school_code2:='eng', $school_code3:='mus')
+    expect: 400
+  # invalid attribute; missing $
+  - uri: /school?code=school_code
+          :where $school_code:='art'
+    expect: 400
+  # invalid attribute; missing ()
+  - uri: /school{code, count{department}}
+    expect: 400
+  # invalid attribute; local typo
+  - uri: /school{code, count(depatrment)}
+    expect: 400
+  # invalid attribute; global typo
+  - uri: /department?school.code==nulll
+    expect: 400
+  # invalid attribute; no hints
+  - uri: /school{code, count(student)}
+    expect: 400
+  # invalid function; wrong number of arguments
+  - uri: /program.define(student_by_year($year) := student?year(start_date)=$year)
+            {code, count(student_by_year())}
+    expect: 400
+  - uri: /program.define(student_by_year($year) := student?year(start_date)=$year,
+                         student_by_year() := student_by_year(2011))
+            {code, count(student_by_year(2009,2010))}
+    expect: 400
+  # invalid function; extra ()
+  - uri: /department{school(), code}
+    expect: 400
+  # invalid function; local typo
+  - uri: /program.define(student_by_year($year) := student?year(start_date)=$year)
+            {code, count(students_by_year(2010))}
+    expect: 400
+  # invalid function; global typo
+  - uri: /cont(program)
+    expect: 400
+  # invalid function; no hints
+  - uri: /program{code, count(student_by_year(2010))}
+    expect: 400
 
+

test/output/mssql.yaml

           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'level':
+            bind error: unrecognized attribute 'level' in scope of 'course':
                 /department.define(course(level) := course?no>=level*100 &no<(level+1)*100) {name, count(course(1)), count(course(2)), count(course(3)), count(course(4))}
                                                                ^^^^^
         - uri: /department.define(course($level) := course?no>=$level*100 &no<($level+1)*100)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'instructor':
+            bind error: unrecognized attribute 'instructor' in scope of 'student':
                 /student.instructor
                          ^^^^^^^^^^
         - uri: /school?code='mus'
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'name':
+            bind error: unrecognized attribute 'name' in scope of 'school_code':
                 /department^school_code{school_code.name, name}
                                                     ^^^^
         - uri: /program.part_of.*
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /avg(school.count(program))
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /avg(school.count(program))
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /count(program)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'enrollment':
+            bind error: unrecognized attribute 'enrollment' in scope of 'student':
                 /student{name, count(enrollment)}
                                      ^^^^^^^^^^
         - uri: /max(confidential.pay_grade)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'ssn':
+            bind error: unrecognized attribute 'ssn' in scope of 'confidential':
                 /confidential.ssn
                               ^^^
         - uri: /student{name, dob, school.code, program.code, exists(instructor)}.limit(1)
             bind error: unrecognized attribute 'active_students':
                 /active_students
                  ^^^^^^^^^^^^^^^
+            (did you mean: a function 'active_students')
         - uri: /active_students(2010)
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0 arguments; got 1:
                 /active_students(2010)
                  ^^^^^^^^^^^^^^^^^^^^^
         - uri: /students_by_year
             bind error: unrecognized attribute 'students_by_year':
                 /students_by_year
                  ^^^^^^^^^^^^^^^^
+            (did you mean: a function 'students_by_year')
         - uri: /students_by_year()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'students_by_year':
+            bind error: function 'students_by_year' requires 1 argument; got 0:
                 /students_by_year()
                  ^^^^^^^^^^^^^^^^^^
         - uri: /program?exists(includes)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'program_via_part_of':
+            bind error: unrecognized attribute 'program_via_part_of' in scope of 'program':
                 /program?exists(program_via_part_of)
                                 ^^^^^^^^^^^^^^^^^^^
         - uri: /student?count(class)>55
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'name':
+            bind error: unrecognized attribute 'name' in scope of 'student':
                 /student.name
                          ^^^^
         - uri: /(program?code='gart').active_students()
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'active_students':
+            bind error: unrecognized attribute 'active_students' in scope of 'program':
                 /program.active_students
                          ^^^^^^^^^^^^^^^
+            (did you mean: a function 'active_students')
         - uri: /program.active_students(2010)
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0 arguments; got 1:
                 /program.active_students(2010)
                          ^^^^^^^^^^^^^^^^^^^^^
         - uri: /program.students_by_year
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'students_by_year':
+            bind error: unrecognized attribute 'students_by_year' in scope of 'program':
                 /program.students_by_year
                          ^^^^^^^^^^^^^^^^
+            (did you mean: a function 'students_by_year')
         - uri: /program.students_by_year()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'students_by_year':
+            bind error: function 'students_by_year' requires 1 argument; got 0:
                 /program.students_by_year()
                          ^^^^^^^^^^^^^^^^^^
         - uri: /active_students{name, gender, start_date}.limit(5)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0, 1 or 2 arguments; got 3:
                 /active_students(2009, 'm', 'phd')
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         - uri: /(program?code='gart').active_students{name, gender, start_date}
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0, 1 or 2 arguments; got 3:
                 /(program?code='gart').active_students(2009, 'm', 'phd')
                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         - uri: /student{name}?count(class)>55
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'enrollment':
+            bind error: unrecognized attribute 'enrollment' in scope of 'student':
                 /student.enrollment
                          ^^^^^^^^^^
         - uri: /student.id
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'id':
+            bind error: unrecognized attribute 'id' in scope of 'student':
                 /student.id
                          ^^
         - uri: /(student{name, dob}?date(start_date)>curr_date).limit(10)
                 /program.program
                          ^^^^^^^
             (try 'part_of' or 'program_via_part_of')
+      - id: lookup-hints
+        tests:
+        - uri: /school?code=$scool_code :where $school_code:='art'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized reference '$scool_code':
+                /school?code=$scool_code :where $school_code:='art'
+                             ^^^^^^^^^^^
+            (did you mean: '$school_code')
+        - uri: /school?code=$code :where $school_code:='art'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized reference '$code':
+                /school?code=$code :where $school_code:='art'
+                             ^^^^^
+        - uri: /school?code=$scool_code :where ($school_code1:='art', $school_code2:='eng',
+            $school_code3:='mus')
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized reference '$scool_code':
+                /school?code=$scool_code :where ($school_code1:='art', $school_code2:='eng', $school_code3:='mus')
+                             ^^^^^^^^^^^
+            (did you mean: '$school_code1', '$school_code2' or '$school_code3')
+        - uri: /school?code=school_code :where $school_code:='art'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'school_code' in scope of 'school':
+                /school?code=school_code :where $school_code:='art'
+                             ^^^^^^^^^^^
+            (did you mean: a reference '$school_code')
+        - uri: /school{code, count{department}}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'count' in scope of 'school':
+                /school{code, count{department}}
+                              ^^^^^
+            (did you mean: a function 'count')
+        - uri: /school{code, count(depatrment)}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'depatrment' in scope of 'school':
+                /school{code, count(depatrment)}
+                                    ^^^^^^^^^^
+            (did you mean: 'department')
+        - uri: /department?school.code==nulll
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'nulll' in scope of 'department':
+                /department?school.code==nulll
+                                         ^^^^^
+            (did you mean: 'null')
+        - uri: /school{code, count(student)}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'student' in scope of 'school':
+                /school{code, count(student)}
+                                    ^^^^^^^
+        - uri: /program.define(student_by_year($year) := student?year(start_date)=$year)
+            {code, count(student_by_year())}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: function 'student_by_year' requires 1 argument; got 0:
+                /program.define(student_by_year($year) := student?year(start_date)=$year) {code, count(student_by_year())}
+                                                                                                       ^^^^^^^^^^^^^^^^^
+        - uri: /program.define(student_by_year($year) := student?year(start_date)=$year,
+            student_by_year() := student_by_year(2011)) {code, count(student_by_year(2009,2010))}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: function 'student_by_year' requires 0 or 1 argument; got 2:
+                /program.define(student_by_year($year) := student?year(start_date)=$year, student_by_year() := student_by_year(2011)) {code, count(student_by_year(2009,2010))}
+                                                                                                                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
+        - uri: /department{school(), code}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'school':
+                /department{school(), code}
+                            ^^^^^^^^
+            (did you mean: an attribute 'school')
+        - uri: /program.define(student_by_year($year) := student?year(start_date)=$year)
+            {code, count(students_by_year(2010))}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'students_by_year':
+                /program.define(student_by_year($year) := student?year(start_date)=$year) {code, count(students_by_year(2010))}
+                                                                                                       ^^^^^^^^^^^^^^^^^^^^^^
+            (did you mean: 'student_by_year')
+        - uri: /cont(program)
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'cont':
+                /cont(program)
+                 ^^^^^^^^^^^^^
+            (did you mean: 'count')
+        - uri: /program{code, count(student_by_year(2010))}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'student_by_year':
+                /program{code, count(student_by_year(2010))}
+                                     ^^^^^^^^^^^^^^^^^^^^^

test/output/mysql.yaml

           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'level':
+            bind error: unrecognized attribute 'level' in scope of 'course':
                 /department.define(course(level) := course?no>=level*100 &no<(level+1)*100) {name, count(course(1)), count(course(2)), count(course(3)), count(course(4))}
                                                                ^^^^^
         - uri: /department.define(course($level) := course?no>=$level*100 &no<($level+1)*100)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'instructor':
+            bind error: unrecognized attribute 'instructor' in scope of 'student':
                 /student.instructor
                          ^^^^^^^^^^
         - uri: /school?code='mus'
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'name':
+            bind error: unrecognized attribute 'name' in scope of 'school_code':
                 /department^school_code{school_code.name, name}
                                                     ^^^^
         - uri: /program.part_of.*
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /avg(school.count(program))
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /avg(school.count(program))
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /school{code, count(department)}
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'enrollment':
+            bind error: unrecognized attribute 'enrollment' in scope of 'student':
                 /student{name, count(enrollment)}
                                      ^^^^^^^^^^
         - uri: /max(confidential.pay_grade)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'ssn':
+            bind error: unrecognized attribute 'ssn' in scope of 'confidential':
                 /confidential.ssn
                               ^^^
         - uri: /student{name, dob, school.code, program.code, exists(instructor)}.limit(1)
             bind error: unrecognized attribute 'active_students':
                 /active_students
                  ^^^^^^^^^^^^^^^
+            (did you mean: a function 'active_students')
         - uri: /active_students(2010)
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0 arguments; got 1:
                 /active_students(2010)
                  ^^^^^^^^^^^^^^^^^^^^^
         - uri: /students_by_year
             bind error: unrecognized attribute 'students_by_year':
                 /students_by_year
                  ^^^^^^^^^^^^^^^^
+            (did you mean: a function 'students_by_year')
         - uri: /students_by_year()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'students_by_year':
+            bind error: function 'students_by_year' requires 1 argument; got 0:
                 /students_by_year()
                  ^^^^^^^^^^^^^^^^^^
         - uri: /program?exists(includes)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'program_via_part_of':
+            bind error: unrecognized attribute 'program_via_part_of' in scope of 'program':
                 /program?exists(program_via_part_of)
                                 ^^^^^^^^^^^^^^^^^^^
         - uri: /student?count(class)>55
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'name':
+            bind error: unrecognized attribute 'name' in scope of 'student':
                 /student.name
                          ^^^^
         - uri: /(program?code='gart').active_students()
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'active_students':
+            bind error: unrecognized attribute 'active_students' in scope of 'program':
                 /program.active_students
                          ^^^^^^^^^^^^^^^
+            (did you mean: a function 'active_students')
         - uri: /program.active_students(2010)
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0 arguments; got 1:
                 /program.active_students(2010)
                          ^^^^^^^^^^^^^^^^^^^^^
         - uri: /program.students_by_year
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'students_by_year':
+            bind error: unrecognized attribute 'students_by_year' in scope of 'program':
                 /program.students_by_year
                          ^^^^^^^^^^^^^^^^
+            (did you mean: a function 'students_by_year')
         - uri: /program.students_by_year()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'students_by_year':
+            bind error: function 'students_by_year' requires 1 argument; got 0:
                 /program.students_by_year()
                          ^^^^^^^^^^^^^^^^^^
         - uri: /active_students{name, gender, start_date}.limit(5)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0, 1 or 2 arguments; got 3:
                 /active_students(2009, 'm', 'phd')
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         - uri: /(program?code='gart').active_students{name, gender, start_date}
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0, 1 or 2 arguments; got 3:
                 /(program?code='gart').active_students(2009, 'm', 'phd')
                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         - uri: /student{name}?count(class)>55
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'enrollment':
+            bind error: unrecognized attribute 'enrollment' in scope of 'student':
                 /student.enrollment
                          ^^^^^^^^^^
         - uri: /student.id
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'id':
+            bind error: unrecognized attribute 'id' in scope of 'student':
                 /student.id
                          ^^
         - uri: /(student{name, dob}?date(start_date)>curr_date).limit(10)
                 /program.program
                          ^^^^^^^
             (try 'part_of' or 'program_via_part_of')
+      - id: lookup-hints
+        tests:
+        - uri: /school?code=$scool_code :where $school_code:='art'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized reference '$scool_code':
+                /school?code=$scool_code :where $school_code:='art'
+                             ^^^^^^^^^^^
+            (did you mean: '$school_code')
+        - uri: /school?code=$code :where $school_code:='art'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized reference '$code':
+                /school?code=$code :where $school_code:='art'
+                             ^^^^^
+        - uri: /school?code=$scool_code :where ($school_code1:='art', $school_code2:='eng',
+            $school_code3:='mus')
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized reference '$scool_code':
+                /school?code=$scool_code :where ($school_code1:='art', $school_code2:='eng', $school_code3:='mus')
+                             ^^^^^^^^^^^
+            (did you mean: '$school_code1', '$school_code2' or '$school_code3')
+        - uri: /school?code=school_code :where $school_code:='art'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'school_code' in scope of 'school':
+                /school?code=school_code :where $school_code:='art'
+                             ^^^^^^^^^^^
+            (did you mean: a reference '$school_code')
+        - uri: /school{code, count{department}}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'count' in scope of 'school':
+                /school{code, count{department}}
+                              ^^^^^
+            (did you mean: a function 'count')
+        - uri: /school{code, count(depatrment)}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'depatrment' in scope of 'school':
+                /school{code, count(depatrment)}
+                                    ^^^^^^^^^^
+            (did you mean: 'department')
+        - uri: /department?school.code==nulll
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'nulll' in scope of 'department':
+                /department?school.code==nulll
+                                         ^^^^^
+            (did you mean: 'null')
+        - uri: /school{code, count(student)}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'student' in scope of 'school':
+                /school{code, count(student)}
+                                    ^^^^^^^
+        - uri: /program.define(student_by_year($year) := student?year(start_date)=$year)
+            {code, count(student_by_year())}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: function 'student_by_year' requires 1 argument; got 0:
+                /program.define(student_by_year($year) := student?year(start_date)=$year) {code, count(student_by_year())}
+                                                                                                       ^^^^^^^^^^^^^^^^^
+        - uri: /program.define(student_by_year($year) := student?year(start_date)=$year,
+            student_by_year() := student_by_year(2011)) {code, count(student_by_year(2009,2010))}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: function 'student_by_year' requires 0 or 1 argument; got 2:
+                /program.define(student_by_year($year) := student?year(start_date)=$year, student_by_year() := student_by_year(2011)) {code, count(student_by_year(2009,2010))}
+                                                                                                                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
+        - uri: /department{school(), code}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'school':
+                /department{school(), code}
+                            ^^^^^^^^
+            (did you mean: an attribute 'school')
+        - uri: /program.define(student_by_year($year) := student?year(start_date)=$year)
+            {code, count(students_by_year(2010))}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'students_by_year':
+                /program.define(student_by_year($year) := student?year(start_date)=$year) {code, count(students_by_year(2010))}
+                                                                                                       ^^^^^^^^^^^^^^^^^^^^^^
+            (did you mean: 'student_by_year')
+        - uri: /cont(program)
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'cont':
+                /cont(program)
+                 ^^^^^^^^^^^^^
+            (did you mean: 'count')
+        - uri: /program{code, count(student_by_year(2010))}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'student_by_year':
+                /program{code, count(student_by_year(2010))}
+                                     ^^^^^^^^^^^^^^^^^^^^^

test/output/oracle.yaml

           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'level':
+            bind error: unrecognized attribute 'level' in scope of 'course':
                 /department.define(course(level) := course?no>=level*100 &no<(level+1)*100) {name, count(course(1)), count(course(2)), count(course(3)), count(course(4))}
                                                                ^^^^^
         - uri: /department.define(course($level) := course?no>=$level*100 &no<($level+1)*100)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'instructor':
+            bind error: unrecognized attribute 'instructor' in scope of 'student':
                 /student.instructor
                          ^^^^^^^^^^
         - uri: /school?code='mus'
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'name':
+            bind error: unrecognized attribute 'name' in scope of 'school_code':
                 /department^school_code{school_code.name, name}
                                                     ^^^^
         - uri: /program.part_of.*
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /avg(school.count(program))
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /avg(school.count(program))
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /school{code, count(department)}
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'enrollment':
+            bind error: unrecognized attribute 'enrollment' in scope of 'student':
                 /student{name, count(enrollment)}
                                      ^^^^^^^^^^
         - uri: /max(confidential.pay_grade)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'ssn':
+            bind error: unrecognized attribute 'ssn' in scope of 'confidential':
                 /confidential.ssn
                               ^^^
         - uri: /student{name, dob, school.code, program.code, exists(instructor)}.limit(1)
             bind error: unrecognized attribute 'active_students':
                 /active_students
                  ^^^^^^^^^^^^^^^
+            (did you mean: a function 'active_students')
         - uri: /active_students(2010)
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0 arguments; got 1:
                 /active_students(2010)
                  ^^^^^^^^^^^^^^^^^^^^^
         - uri: /students_by_year
             bind error: unrecognized attribute 'students_by_year':
                 /students_by_year
                  ^^^^^^^^^^^^^^^^
+            (did you mean: a function 'students_by_year')
         - uri: /students_by_year()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'students_by_year':
+            bind error: function 'students_by_year' requires 1 argument; got 0:
                 /students_by_year()
                  ^^^^^^^^^^^^^^^^^^
         - uri: /program?exists(includes)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'program_via_part_of':
+            bind error: unrecognized attribute 'program_via_part_of' in scope of 'program':
                 /program?exists(program_via_part_of)
                                 ^^^^^^^^^^^^^^^^^^^
         - uri: /student?count(class)>55
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'name':
+            bind error: unrecognized attribute 'name' in scope of 'student':
                 /student.name
                          ^^^^
         - uri: /(program?code='gart').active_students()
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'active_students':
+            bind error: unrecognized attribute 'active_students' in scope of 'program':
                 /program.active_students
                          ^^^^^^^^^^^^^^^
+            (did you mean: a function 'active_students')
         - uri: /program.active_students(2010)
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0 arguments; got 1:
                 /program.active_students(2010)
                          ^^^^^^^^^^^^^^^^^^^^^
         - uri: /program.students_by_year
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'students_by_year':
+            bind error: unrecognized attribute 'students_by_year' in scope of 'program':
                 /program.students_by_year
                          ^^^^^^^^^^^^^^^^
+            (did you mean: a function 'students_by_year')
         - uri: /program.students_by_year()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'students_by_year':
+            bind error: function 'students_by_year' requires 1 argument; got 0:
                 /program.students_by_year()
                          ^^^^^^^^^^^^^^^^^^
         - uri: /active_students{name, gender, start_date}.limit(5)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0, 1 or 2 arguments; got 3:
                 /active_students(2009, 'm', 'phd')
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         - uri: /(program?code='gart').active_students{name, gender, start_date}
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0, 1 or 2 arguments; got 3:
                 /(program?code='gart').active_students(2009, 'm', 'phd')
                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         - uri: /student{name}?count(class)>55
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'enrollment':
+            bind error: unrecognized attribute 'enrollment' in scope of 'student':
                 /student.enrollment
                          ^^^^^^^^^^
         - uri: /student.id
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'id':
+            bind error: unrecognized attribute 'id' in scope of 'student':
                 /student.id
                          ^^
         - uri: /(student{name, dob}?date(start_date)>curr_date).limit(10)
                 /program.program
                          ^^^^^^^
             (try 'part_of' or 'program_via_part_of')
+      - id: lookup-hints
+        tests:
+        - uri: /school?code=$scool_code :where $school_code:='art'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized reference '$scool_code':
+                /school?code=$scool_code :where $school_code:='art'
+                             ^^^^^^^^^^^
+            (did you mean: '$school_code')
+        - uri: /school?code=$code :where $school_code:='art'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized reference '$code':
+                /school?code=$code :where $school_code:='art'
+                             ^^^^^
+        - uri: /school?code=$scool_code :where ($school_code1:='art', $school_code2:='eng',
+            $school_code3:='mus')
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized reference '$scool_code':
+                /school?code=$scool_code :where ($school_code1:='art', $school_code2:='eng', $school_code3:='mus')
+                             ^^^^^^^^^^^
+            (did you mean: '$school_code1', '$school_code2' or '$school_code3')
+        - uri: /school?code=school_code :where $school_code:='art'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'school_code' in scope of 'school':
+                /school?code=school_code :where $school_code:='art'
+                             ^^^^^^^^^^^
+            (did you mean: a reference '$school_code')
+        - uri: /school{code, count{department}}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'count' in scope of 'school':
+                /school{code, count{department}}
+                              ^^^^^
+            (did you mean: a function 'count')
+        - uri: /school{code, count(depatrment)}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'depatrment' in scope of 'school':
+                /school{code, count(depatrment)}
+                                    ^^^^^^^^^^
+            (did you mean: 'department')
+        - uri: /department?school.code==nulll
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'nulll' in scope of 'department':
+                /department?school.code==nulll
+                                         ^^^^^
+            (did you mean: 'null')
+        - uri: /school{code, count(student)}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'student' in scope of 'school':
+                /school{code, count(student)}
+                                    ^^^^^^^
+        - uri: /program.define(student_by_year($year) := student?year(start_date)=$year)
+            {code, count(student_by_year())}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: function 'student_by_year' requires 1 argument; got 0:
+                /program.define(student_by_year($year) := student?year(start_date)=$year) {code, count(student_by_year())}
+                                                                                                       ^^^^^^^^^^^^^^^^^
+        - uri: /program.define(student_by_year($year) := student?year(start_date)=$year,
+            student_by_year() := student_by_year(2011)) {code, count(student_by_year(2009,2010))}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: function 'student_by_year' requires 0 or 1 argument; got 2:
+                /program.define(student_by_year($year) := student?year(start_date)=$year, student_by_year() := student_by_year(2011)) {code, count(student_by_year(2009,2010))}
+                                                                                                                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
+        - uri: /department{school(), code}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'school':
+                /department{school(), code}
+                            ^^^^^^^^
+            (did you mean: an attribute 'school')
+        - uri: /program.define(student_by_year($year) := student?year(start_date)=$year)
+            {code, count(students_by_year(2010))}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'students_by_year':
+                /program.define(student_by_year($year) := student?year(start_date)=$year) {code, count(students_by_year(2010))}
+                                                                                                       ^^^^^^^^^^^^^^^^^^^^^^
+            (did you mean: 'student_by_year')
+        - uri: /cont(program)
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'cont':
+                /cont(program)
+                 ^^^^^^^^^^^^^
+            (did you mean: 'count')
+        - uri: /program{code, count(student_by_year(2010))}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'student_by_year':
+                /program{code, count(student_by_year(2010))}
+                                     ^^^^^^^^^^^^^^^^^^^^^

test/output/pgsql.yaml

           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'level':
+            bind error: unrecognized attribute 'level' in scope of 'course':
                 /department.define(course(level) := course?no>=level*100 &no<(level+1)*100) {name, count(course(1)), count(course(2)), count(course(3)), count(course(4))}
                                                                ^^^^^
         - uri: /department.define(course($level) := course?no>=$level*100 &no<($level+1)*100)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'instructor':
+            bind error: unrecognized attribute 'instructor' in scope of 'student':
                 /student.instructor
                          ^^^^^^^^^^
         - uri: /school?code='mus'
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'name':
+            bind error: unrecognized attribute 'name' in scope of 'school_code':
                 /department^school_code{school_code.name, name}
                                                     ^^^^
         - uri: /program.part_of.*
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /avg(school.count(program))
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /avg(school.count(program))
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /count(program)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'enrollment':
+            bind error: unrecognized attribute 'enrollment' in scope of 'student':
                 /student{name, count(enrollment)}
                                      ^^^^^^^^^^
         - uri: /max(confidential.pay_grade)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'ssn':
+            bind error: unrecognized attribute 'ssn' in scope of 'confidential':
                 /confidential.ssn
                               ^^^
         - uri: /student{name, dob, school.code, program.code, exists(instructor)}.limit(1)
             bind error: unrecognized attribute 'active_students':
                 /active_students
                  ^^^^^^^^^^^^^^^
+            (did you mean: a function 'active_students')
         - uri: /active_students(2010)
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0 arguments; got 1:
                 /active_students(2010)
                  ^^^^^^^^^^^^^^^^^^^^^
         - uri: /students_by_year
             bind error: unrecognized attribute 'students_by_year':
                 /students_by_year
                  ^^^^^^^^^^^^^^^^
+            (did you mean: a function 'students_by_year')
         - uri: /students_by_year()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'students_by_year':
+            bind error: function 'students_by_year' requires 1 argument; got 0:
                 /students_by_year()
                  ^^^^^^^^^^^^^^^^^^
         - uri: /program?exists(includes)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'program_via_part_of':
+            bind error: unrecognized attribute 'program_via_part_of' in scope of 'program':
                 /program?exists(program_via_part_of)
                                 ^^^^^^^^^^^^^^^^^^^
         - uri: /student?count(class)>55
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'name':
+            bind error: unrecognized attribute 'name' in scope of 'student':
                 /student.name
                          ^^^^
         - uri: /(program?code='gart').active_students()
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'active_students':
+            bind error: unrecognized attribute 'active_students' in scope of 'program':
                 /program.active_students
                          ^^^^^^^^^^^^^^^
+            (did you mean: a function 'active_students')
         - uri: /program.active_students(2010)
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0 arguments; got 1:
                 /program.active_students(2010)
                          ^^^^^^^^^^^^^^^^^^^^^
         - uri: /program.students_by_year
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'students_by_year':
+            bind error: unrecognized attribute 'students_by_year' in scope of 'program':
                 /program.students_by_year
                          ^^^^^^^^^^^^^^^^
+            (did you mean: a function 'students_by_year')
         - uri: /program.students_by_year()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'students_by_year':
+            bind error: function 'students_by_year' requires 1 argument; got 0:
                 /program.students_by_year()
                          ^^^^^^^^^^^^^^^^^^
         - uri: /active_students{name, gender, start_date}.limit(5)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0, 1 or 2 arguments; got 3:
                 /active_students(2009, 'm', 'phd')
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         - uri: /(program?code='gart').active_students{name, gender, start_date}
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0, 1 or 2 arguments; got 3:
                 /(program?code='gart').active_students(2009, 'm', 'phd')
                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         - uri: /student{name}?count(class)>55
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'enrollment':
+            bind error: unrecognized attribute 'enrollment' in scope of 'student':
                 /student.enrollment
                          ^^^^^^^^^^
         - uri: /student.id
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'id':
+            bind error: unrecognized attribute 'id' in scope of 'student':
                 /student.id
                          ^^
         - uri: /(student{name, dob}?date(start_date)>curr_date).limit(10)
                 /program.program
                          ^^^^^^^
             (try 'part_of' or 'program_via_part_of')
+      - id: lookup-hints
+        tests:
+        - uri: /school?code=$scool_code :where $school_code:='art'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized reference '$scool_code':
+                /school?code=$scool_code :where $school_code:='art'
+                             ^^^^^^^^^^^
+            (did you mean: '$school_code')
+        - uri: /school?code=$code :where $school_code:='art'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized reference '$code':
+                /school?code=$code :where $school_code:='art'
+                             ^^^^^
+        - uri: /school?code=$scool_code :where ($school_code1:='art', $school_code2:='eng',
+            $school_code3:='mus')
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized reference '$scool_code':
+                /school?code=$scool_code :where ($school_code1:='art', $school_code2:='eng', $school_code3:='mus')
+                             ^^^^^^^^^^^
+            (did you mean: '$school_code1', '$school_code2' or '$school_code3')
+        - uri: /school?code=school_code :where $school_code:='art'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'school_code' in scope of 'school':
+                /school?code=school_code :where $school_code:='art'
+                             ^^^^^^^^^^^
+            (did you mean: a reference '$school_code')
+        - uri: /school{code, count{department}}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'count' in scope of 'school':
+                /school{code, count{department}}
+                              ^^^^^
+            (did you mean: a function 'count')
+        - uri: /school{code, count(depatrment)}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'depatrment' in scope of 'school':
+                /school{code, count(depatrment)}
+                                    ^^^^^^^^^^
+            (did you mean: 'department')
+        - uri: /department?school.code==nulll
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'nulll' in scope of 'department':
+                /department?school.code==nulll
+                                         ^^^^^
+            (did you mean: 'null')
+        - uri: /school{code, count(student)}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized attribute 'student' in scope of 'school':
+                /school{code, count(student)}
+                                    ^^^^^^^
+        - uri: /program.define(student_by_year($year) := student?year(start_date)=$year)
+            {code, count(student_by_year())}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: function 'student_by_year' requires 1 argument; got 0:
+                /program.define(student_by_year($year) := student?year(start_date)=$year) {code, count(student_by_year())}
+                                                                                                       ^^^^^^^^^^^^^^^^^
+        - uri: /program.define(student_by_year($year) := student?year(start_date)=$year,
+            student_by_year() := student_by_year(2011)) {code, count(student_by_year(2009,2010))}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: function 'student_by_year' requires 0 or 1 argument; got 2:
+                /program.define(student_by_year($year) := student?year(start_date)=$year, student_by_year() := student_by_year(2011)) {code, count(student_by_year(2009,2010))}
+                                                                                                                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
+        - uri: /department{school(), code}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'school':
+                /department{school(), code}
+                            ^^^^^^^^
+            (did you mean: an attribute 'school')
+        - uri: /program.define(student_by_year($year) := student?year(start_date)=$year)
+            {code, count(students_by_year(2010))}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'students_by_year':
+                /program.define(student_by_year($year) := student?year(start_date)=$year) {code, count(students_by_year(2010))}
+                                                                                                       ^^^^^^^^^^^^^^^^^^^^^^
+            (did you mean: 'student_by_year')
+        - uri: /cont(program)
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'cont':
+                /cont(program)
+                 ^^^^^^^^^^^^^
+            (did you mean: 'count')
+        - uri: /program{code, count(student_by_year(2010))}
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            bind error: unrecognized function 'student_by_year':
+                /program{code, count(student_by_year(2010))}
+                                     ^^^^^^^^^^^^^^^^^^^^^

test/output/sqlite.yaml

           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'level':
+            bind error: unrecognized attribute 'level' in scope of 'course':
                 /department.define(course(level) := course?no>=level*100 &no<(level+1)*100) {name, count(course(1)), count(course(2)), count(course(3)), count(course(4))}
                                                                ^^^^^
         - uri: /department.define(course($level) := course?no>=$level*100 &no<($level+1)*100)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'instructor':
+            bind error: unrecognized attribute 'instructor' in scope of 'student':
                 /student.instructor
                          ^^^^^^^^^^
         - uri: /school?code='mus'
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'name':
+            bind error: unrecognized attribute 'name' in scope of 'school_code':
                 /department^school_code{school_code.name, name}
                                                     ^^^^
         - uri: /program.part_of.*
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /avg(school.count(program))
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /avg(school.count(program))
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'department':
+            bind error: unrecognized attribute 'department' in scope of 'school':
                 /avg(school.count(department))
                                   ^^^^^^^^^^
         - uri: /school{code, count(department)}
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'enrollment':
+            bind error: unrecognized attribute 'enrollment' in scope of 'student':
                 /student{name, count(enrollment)}
                                      ^^^^^^^^^^
         - uri: /max(confidential.pay_grade)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'ssn':
+            bind error: unrecognized attribute 'ssn' in scope of 'confidential':
                 /confidential.ssn
                               ^^^
         - uri: /student{name, dob, school.code, program.code, exists(instructor)}.limit(1)
             bind error: unrecognized attribute 'active_students':
                 /active_students
                  ^^^^^^^^^^^^^^^
+            (did you mean: a function 'active_students')
         - uri: /active_students(2010)
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0 arguments; got 1:
                 /active_students(2010)
                  ^^^^^^^^^^^^^^^^^^^^^
         - uri: /students_by_year
             bind error: unrecognized attribute 'students_by_year':
                 /students_by_year
                  ^^^^^^^^^^^^^^^^
+            (did you mean: a function 'students_by_year')
         - uri: /students_by_year()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'students_by_year':
+            bind error: function 'students_by_year' requires 1 argument; got 0:
                 /students_by_year()
                  ^^^^^^^^^^^^^^^^^^
         - uri: /program?exists(includes)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'program_via_part_of':
+            bind error: unrecognized attribute 'program_via_part_of' in scope of 'program':
                 /program?exists(program_via_part_of)
                                 ^^^^^^^^^^^^^^^^^^^
         - uri: /student?count(class)>55
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'name':
+            bind error: unrecognized attribute 'name' in scope of 'student':
                 /student.name
                          ^^^^
         - uri: /(program?code='gart').active_students()
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'active_students':
+            bind error: unrecognized attribute 'active_students' in scope of 'program':
                 /program.active_students
                          ^^^^^^^^^^^^^^^
+            (did you mean: a function 'active_students')
         - uri: /program.active_students(2010)
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0 arguments; got 1:
                 /program.active_students(2010)
                          ^^^^^^^^^^^^^^^^^^^^^
         - uri: /program.students_by_year
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'students_by_year':
+            bind error: unrecognized attribute 'students_by_year' in scope of 'program':
                 /program.students_by_year
                          ^^^^^^^^^^^^^^^^
+            (did you mean: a function 'students_by_year')
         - uri: /program.students_by_year()
           status: 400 Bad Request
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'students_by_year':
+            bind error: function 'students_by_year' requires 1 argument; got 0:
                 /program.students_by_year()
                          ^^^^^^^^^^^^^^^^^^
         - uri: /active_students{name, gender, start_date}.limit(5)
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0, 1 or 2 arguments; got 3:
                 /active_students(2009, 'm', 'phd')
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         - uri: /(program?code='gart').active_students{name, gender, start_date}
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized function 'active_students':
+            bind error: function 'active_students' requires 0, 1 or 2 arguments; got 3:
                 /(program?code='gart').active_students(2009, 'm', 'phd')
                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         - uri: /student{name}?count(class)>55
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'enrollment':
+            bind error: unrecognized attribute 'enrollment' in scope of 'student':
                 /student.enrollment
                          ^^^^^^^^^^
         - uri: /student.id
           headers:
           - [Content-Type, text/plain; charset=UTF-8]
           body: |
-            bind error: unrecognized attribute 'id':
+            bind error: unrecognized attribute 'id' in scope of 'student':
                 /student.id
                          ^^
         - uri: /(student{name, dob}?date(start_date)>curr_date).limit(10)