)abbrev domain DLIST DataList
++ This domain provides some nice functions on lists
DataList(S : OrderedSet) : Exports == Implementation where
  Exports == ListAggregate(S) with
    coerce : List S -> %
      ++ coerce(l) creates a datalist from l
    coerce : % -> List S
      ++ coerce(x) returns the list of elements in x
    datalist : List S -> %
      ++ datalist(l) creates a datalist from l
    elt : (%,"unique") -> %
      ++ \spad{l.unique} returns \spad{l} with duplicates removed.
      ++ Note: \spad{l.unique = removeDuplicates(l)}.
    elt : (%,"sort") -> %
      ++ \spad{l.sort} returns \spad{l} with elements sorted.
      ++ Note: \spad{l.sort = sort(l)}
    elt : (%,"count") -> NonNegativeInteger
      ++ \spad{l."count"} returns the number of elements in \spad{l}.
  Implementation == List(S) add
    elt(x,"unique") == removeDuplicates(x)
    elt(x,"sort") == sort(x)
    elt(x,"count") == #x
    coerce(x : List S) == x pretend %
    coerce(x : %) : List S == x pretend (List S)
    coerce(x : %) : OutputForm == (x :: List S) :: OutputForm
    datalist(x : List S) == x::%

)abbrev domain ICARD IndexCard
++ This domain implements a container of information
++ about the FriCAS library
IndexCard() : Exports == Implementation where
  Exports == OrderedSet with
    elt : (%, Symbol) -> String
      ++ elt(ic, s) selects a particular field from \spad{ic}.  Valid fields
      ++ are \spad{name, nargs, exposed, type, abbreviation, kind, origin,
      ++ params, condition, doc}.
    display : % -> Void
      ++ display(ic) prints a summary of the information contained in \spad{ic}.
    fullDisplay : % -> Void
      ++ fullDisplay(ic) prints all of the information contained in \spad{ic}.
    coerce : String -> %
      ++ coerce(s) converts \spad{s} into an \spad{IndexCard}.  Warning: if
      ++ \spad{s} is not of the right format then an error will occur when using
      ++ it.
  Implementation == add

    import from OutputForm

    x < y == (x pretend String) < (y pretend String)
    x = y == (x pretend String) = (y pretend String)

    db_name ==> dbName$Lisp

    db_part(x : %, n : Integer, k : Integer) : String ==
        dbPart(x, n, k)$Lisp

    alql_get_kind(x : %) : String ==
        xs := x pretend String
        xs(1) = char("a") or xs(1) = char("o") =>
            db_part(x, 5, 1)(1..1)
        xs(1..1)

    alql_get_origin(x : %) : String ==
        field := db_part(x, 5, 1)
        k := position(char("("), field, 3)
        k < 1 => field(2..)
        field(2..(k - 1))

    alql_get_params(x : %) : String ==
        field := db_part(x, 5, 1)
        k := position(char("("), field)
        k < 1 => ""
        field(k..)

    display(x) ==
        name : OutputForm := db_name(x)
        type : OutputForm := message(db_part(x, 4, 1))
        output(hconcat(name, hconcat(message(" : "), type)))$OutputPackage

    fullDisplay(x) ==
        name : OutputForm := db_name(x)
        type : OutputForm := message(db_part(x, 4, 1))
        origin : OutputForm := hconcat(message(alql_get_origin(x)),
                                       message(alql_get_params(x)))
        fromPart : OutputForm := hconcat(message(" from "), origin)
        condition : String := db_part(x, 6, 1)
        ifPart : OutputForm :=
            condition = "" => empty()
            hconcat(message(" if "), message(condition))
        exposed? : String := db_part(x, 3, 1)(1..1)
        exposedPart : OutputForm :=
            exposed? = "n" => message(" (unexposed)")
            empty()
        firstPart := hconcat(name, hconcat(message(" : "), type))
        secondPart := hconcat(fromPart, hconcat(ifPart, exposedPart))
        output(hconcat(firstPart, secondPart))$OutputPackage

    coerce(s : String) : % == (s pretend %)

    coerce(x) : OutputForm == (x pretend String)::OutputForm

    elt(x, s) ==
        s = 'name => db_name(x)
        s = 'nargs => db_part(x, 2, 1)
        s = 'exposed => db_part(x, 3, 1)(1..1)
        s = 'type => db_part(x, 4, 1)
        s = 'abbreviation => db_part(x, 5, 1)
        s = 'kind => alql_get_kind(x)
        s = 'origin => alql_get_origin(x)
        s = 'params => alql_get_params(x)
        s = 'condition => db_part(x, 6, 1)
        s = 'doc => dbComments(x)$Lisp
        error "unknown selector"

)abbrev domain DBASE Database
++ This domain implements a simple view of a database whose fields are
++ indexed by symbols
Database(S) : Exports == Implementation where
  S : OrderedSet with
    elt : (%, Symbol) -> String
        ++ elt(x, s) returns an element of x indexed by s
    display : % -> Void
        ++ display(x) displays x in some form
    fullDisplay : % -> Void
        ++ fullDisplay(x) displays x in detail
  Exports == SetCategory with
    elt : (%, QueryEquation) -> %
      ++ elt(db, q) returns all elements of \spad{db} which satisfy \spad{q}.
    elt : (%, Symbol) -> DataList String
      ++ elt(db, s) returns the \spad{s} field of each element of \spad{db}.
    _+: (%, %) -> %
      ++ db1+db2 returns the merge of databases db1 and db2
    _-: (%, %) -> %
      ++ db1-db2 returns the difference of databases db1 and db2 i.e. consisting
      ++ of elements in db1 but not in db2
    coerce : List S -> %
      ++ coerce(l) makes a database out of a list
    display : % -> Void
      ++ display(db) prints a summary line for each entry in \spad{db}.
    fullDisplay : % -> Void
      ++ fullDisplay(db) prints full details of each entry in \spad{db}.
    fullDisplay : (%, PositiveInteger, PositiveInteger) -> Void
      ++ fullDisplay(db, start, end ) prints full details of entries in the range
      ++ \spad{start..end} in \spad{db}.
  Implementation == List S add
    s : Symbol
    Rep := List S
    coerce(u : List S) : % == u@%
    elt(data : %, s : Symbol) == [x.s for x in data] :: DataList(String)
    elt(data : %, eq : QueryEquation) ==
      field := variable eq
      val := value eq
      [x for x in data | stringMatches?(val, x.field)$Lisp]
    x+y==removeDuplicates! merge(x, y)
    x-y==mergeDifference(copy(x::Rep), y::Rep)$MergeThing(S)
    coerce(data) : OutputForm == (#data):: OutputForm
    display(data) ==  for x in data repeat display x
    fullDisplay(data) == for x in data repeat fullDisplay x
    fullDisplay(data, n, m) == for x in data for i in 1..m repeat
      if i >= n then fullDisplay x

)abbrev domain QEQUAT QueryEquation
++ This domain implements simple database queries
QueryEquation() : Exports == Implementation where
  Exports == CoercibleTo(OutputForm) with
    equation : (Symbol, String) -> %
      ++ equation(s,"a") creates a new equation.
    variable : % -> Symbol
      ++ variable(q) returns the variable (i.e. left hand side) of \spad{q}.
    value : % -> String
      ++ value(q) returns the value (i.e. right hand side) of \spad{q}.
  Implementation == add
    Rep := Record(var : Symbol, val : String)
    coerce(u) == coerce(u.var)$Symbol = coerce(u.val)$String
    equation(x, s) == [x, s]
    variable q == q.var
    value q == q.val

)abbrev package MTHING MergeThing
++ This package exports tools for merging lists
MergeThing(S : OrderedSet) : Exports == Implementation where
  Exports == with
    mergeDifference : (List(S), List(S)) -> List(S)
        ++ mergeDifference(l1, l2) returns a list of elements in l1 not present in l2.
        ++ Assumes lists are ordered and all x in l2 are also in l1.
  Implementation == add
    mergeDifference1 : (List S, S, List S) -> List S
    mergeDifference(x, y) ==
      empty?(x) or empty?(y) => x
      mergeDifference1(x, y.first, y.rest)
      x.first = y.first => x.rest
      x
    mergeDifference1(x, fy, ry) ==
      rx := x
      while not(empty?(rx)) repeat
        rx := rx.rest
        frx := rx.first
        while fy < frx repeat
          empty?(ry) => return x
          fy := first ry
          ry := rest ry
        frx = fy =>
          x.rest := rx.rest
          empty?(ry) => return x
          fy := ry.first
          ry := ry.rest
        x := rx

)abbrev package OPQUERY OperationsQuery
++ This package exports tools to create FriCAS Library information databases.
OperationsQuery() : Exports == Implementation where
  Exports == with
    getDatabase : String -> Database(IndexCard)
      ++ getDatabase("char") returns a list of appropriate entries in the
      ++ browser database.  The legal values for "char" are "o" (operations),
      ++ "k" (constructors), "d" (domains), "c" (categories) or "p" (packages).
  Implementation == add
    getDatabase(s) == getBrowseDatabase(s)$Lisp

--Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
--All rights reserved.
--
--Redistribution and use in source and binary forms, with or without
--modification, are permitted provided that the following conditions are
--met:
--
--    - Redistributions of source code must retain the above copyright
--      notice, this list of conditions and the following disclaimer.
--
--    - Redistributions in binary form must reproduce the above copyright
--      notice, this list of conditions and the following disclaimer in
--      the documentation and/or other materials provided with the
--      distribution.
--
--    - Neither the name of The Numerical ALgorithms Group Ltd. nor the
--      names of its contributors may be used to endorse or promote products
--      derived from this software without specific prior written permission.
--
--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
--IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
--TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
--PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
--OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
--EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
--PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
--PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
--LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
--NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
