Commit 91a579d87e6ffebdba7d258ed7a6657e0127f8fd

Authored by Alain Prouté
1 parent 6a899680

*** empty log message ***

anubis_dev/compiler/src/lex.yy.c
... ... @@ -971,6 +971,7 @@ char *path_prefix(char *name)
971 971 int i = strlen(name);
972 972 if (i >= path_prefix_length-5)
973 973 {
  974 + err_line_col(linecol());
974 975 fprintf(errfile,
975 976 msgtext_file_path_too_long[language],
976 977 name);
... ... @@ -1028,6 +1029,7 @@ FILE *fopensrc(char *name)
1028 1029 /* if path is absolute do not try the libraries */
1029 1030 if (name[0] == '/' || name[0] == '\\')
1030 1031 {
  1032 + err_line_col(linecol());
1031 1033 fprintf(errfile,
1032 1034 msgtext_cannot_find_src_file[language],
1033 1035 name,
... ... @@ -1066,6 +1068,7 @@ FILE *fopensrc(char *name)
1066 1068 }
1067 1069  
1068 1070 /* The file is not found: send a message and exit */
  1071 + err_line_col(linecol());
1069 1072 fprintf(errfile,
1070 1073 msgtext_cannot_find_src_file[language],
1071 1074 name,
... ... @@ -1172,6 +1175,7 @@ void add_to_already_included(char *name)
1172 1175 //printf("Adding '%s'.\n",name);
1173 1176 if (next_already_included == max_already_included)
1174 1177 {
  1178 + err_line_col(linecol());
1175 1179 fprintf(errfile,
1176 1180 msgtext_too_many_files[language]);
1177 1181 anb_exit(1);
... ... @@ -1390,7 +1394,7 @@ static char *rec_name(char *s, int del)
1390 1394 /* state STRTL is used when a string is too long. */
1391 1395 /* states CONF and CONFCOM are used to read 'compiler.conf'.*/
1392 1396 /* the lexer ----------------------------------------------------------------------------*/
1393   -#line 1394 "lex.yy.c"
  1397 +#line 1398 "lex.yy.c"
1394 1398  
1395 1399 /* Macros after this point can all be overridden by user definitions in
1396 1400 * section 1.
... ... @@ -1555,9 +1559,9 @@ YY_DECL
1555 1559 register char *yy_cp, *yy_bp;
1556 1560 register int yy_act;
1557 1561  
1558   -#line 562 "lexer.y"
  1562 +#line 566 "lexer.y"
1559 1563  
1560   -#line 1561 "lex.yy.c"
  1564 +#line 1565 "lex.yy.c"
1561 1565  
1562 1566 if ( yy_init )
1563 1567 {
... ... @@ -1643,27 +1647,27 @@ do_action: /* This label is used only to access EOF actions. */
1643 1647  
1644 1648 case 1:
1645 1649 YY_RULE_SETUP
1646   -#line 563 "lexer.y"
  1650 +#line 567 "lexer.y"
1647 1651 { comlevel = 1; BEGIN COM; }
1648 1652 YY_BREAK
1649 1653 case 2:
1650 1654 YY_RULE_SETUP
1651   -#line 564 "lexer.y"
  1655 +#line 568 "lexer.y"
1652 1656 { comlevel++; }
1653 1657 YY_BREAK
1654 1658 case 3:
1655 1659 YY_RULE_SETUP
1656   -#line 565 "lexer.y"
  1660 +#line 569 "lexer.y"
1657 1661 { comlevel--; if (!comlevel) { BEGIN PAR; } }
1658 1662 YY_BREAK
1659 1663 case 4:
1660 1664 YY_RULE_SETUP
1661   -#line 566 "lexer.y"
  1665 +#line 570 "lexer.y"
1662 1666 { }
1663 1667 YY_BREAK
1664 1668 case 5:
1665 1669 YY_RULE_SETUP
1666   -#line 567 "lexer.y"
  1670 +#line 571 "lexer.y"
1667 1671 { }
1668 1672 YY_BREAK
1669 1673 case 6:
... ... @@ -1671,17 +1675,17 @@ case 6:
1671 1675 yy_c_buf_p = yy_cp -= 1;
1672 1676 YY_DO_BEFORE_ACTION; /* set up yytext again */
1673 1677 YY_RULE_SETUP
1674   -#line 568 "lexer.y"
  1678 +#line 572 "lexer.y"
1675 1679 { /* dbl_slash_comment(yytext+2); */ }
1676 1680 YY_BREAK
1677 1681 case 7:
1678 1682 YY_RULE_SETUP
1679   -#line 569 "lexer.y"
  1683 +#line 573 "lexer.y"
1680 1684 { BEGIN STR; str_index = 0; }
1681 1685 YY_BREAK
1682 1686 case 8:
1683 1687 YY_RULE_SETUP
1684   -#line 570 "lexer.y"
  1688 +#line 574 "lexer.y"
1685 1689 { BEGIN PAR;
1686 1690 str_buf[str_index] = 0;
1687 1691 yylval.expr = new_string(str_buf);
... ... @@ -1689,598 +1693,598 @@ YY_RULE_SETUP
1689 1693 YY_BREAK
1690 1694 case 9:
1691 1695 YY_RULE_SETUP
1692   -#line 574 "lexer.y"
  1696 +#line 578 "lexer.y"
1693 1697 { store_str_char('\"'); }
1694 1698 YY_BREAK
1695 1699 case 10:
1696 1700 YY_RULE_SETUP
1697   -#line 575 "lexer.y"
  1701 +#line 579 "lexer.y"
1698 1702 { store_str_char('\n'); }
1699 1703 YY_BREAK
1700 1704 case 11:
1701 1705 YY_RULE_SETUP
1702   -#line 576 "lexer.y"
  1706 +#line 580 "lexer.y"
1703 1707 { store_str_char('\r'); }
1704 1708 YY_BREAK
1705 1709 case 12:
1706 1710 YY_RULE_SETUP
1707   -#line 577 "lexer.y"
  1711 +#line 581 "lexer.y"
1708 1712 { store_str_char('\t'); }
1709 1713 YY_BREAK
1710 1714 case 13:
1711 1715 YY_RULE_SETUP
1712   -#line 578 "lexer.y"
  1716 +#line 582 "lexer.y"
1713 1717 { store_str_char('\\'); }
1714 1718 YY_BREAK
1715 1719 case 14:
1716 1720 YY_RULE_SETUP
1717   -#line 579 "lexer.y"
  1721 +#line 583 "lexer.y"
1718 1722 { store_str_char('\n'); }
1719 1723 YY_BREAK
1720 1724 case 15:
1721 1725 YY_RULE_SETUP
1722   -#line 580 "lexer.y"
  1726 +#line 584 "lexer.y"
1723 1727 { store_str_char(yytext[0]); }
1724 1728 YY_BREAK
1725 1729 case 16:
1726 1730 YY_RULE_SETUP
1727   -#line 581 "lexer.y"
  1731 +#line 585 "lexer.y"
1728 1732 { BEGIN PAR; }
1729 1733 YY_BREAK
1730 1734 case 17:
1731 1735 YY_RULE_SETUP
1732   -#line 582 "lexer.y"
  1736 +#line 586 "lexer.y"
1733 1737 { }
1734 1738 YY_BREAK
1735 1739 case 18:
1736 1740 YY_RULE_SETUP
1737   -#line 583 "lexer.y"
  1741 +#line 587 "lexer.y"
1738 1742 { }
1739 1743 YY_BREAK
1740 1744 case 19:
1741 1745 YY_RULE_SETUP
1742   -#line 584 "lexer.y"
  1746 +#line 588 "lexer.y"
1743 1747 { yylval.integer = (int)(unsigned char)yytext[1]; return yy__char; }
1744 1748 YY_BREAK
1745 1749 case 20:
1746 1750 YY_RULE_SETUP
1747   -#line 585 "lexer.y"
  1751 +#line 589 "lexer.y"
1748 1752 { yylval.integer = (int)'\n'; return yy__char; }
1749 1753 YY_BREAK
1750 1754 case 21:
1751 1755 YY_RULE_SETUP
1752   -#line 586 "lexer.y"
  1756 +#line 590 "lexer.y"
1753 1757 { yylval.integer = (int)'\r'; return yy__char; }
1754 1758 YY_BREAK
1755 1759 case 22:
1756 1760 YY_RULE_SETUP
1757   -#line 587 "lexer.y"
  1761 +#line 591 "lexer.y"
1758 1762 { yylval.integer = (int)'\t'; return yy__char; }
1759 1763 YY_BREAK
1760 1764 case 23:
1761 1765 YY_RULE_SETUP
1762   -#line 588 "lexer.y"
  1766 +#line 592 "lexer.y"
1763 1767 { yylval.integer = (int)'\"'; return yy__char; }
1764 1768 YY_BREAK
1765 1769 case 24:
1766 1770 YY_RULE_SETUP
1767   -#line 589 "lexer.y"
  1771 +#line 593 "lexer.y"
1768 1772 { yylval.integer = (int)'\\'; return yy__char; }
1769 1773 YY_BREAK
1770 1774 case 25:
1771 1775 YY_RULE_SETUP
1772   -#line 590 "lexer.y"
  1776 +#line 594 "lexer.y"
1773 1777 { yylval.integer = (int)'\''; return yy__char; }
1774 1778 YY_BREAK
1775 1779 case 26:
1776 1780 YY_RULE_SETUP
1777   -#line 591 "lexer.y"
  1781 +#line 595 "lexer.y"
1778 1782 { yylval.expr = linecol(); return yy__lpar; }
1779 1783 YY_BREAK
1780 1784 case 27:
1781 1785 YY_RULE_SETUP
1782   -#line 592 "lexer.y"
  1786 +#line 596 "lexer.y"
1783 1787 { yylval.expr = linecol(); return yy__rpar; }
1784 1788 YY_BREAK
1785 1789 case 28:
1786 1790 YY_RULE_SETUP
1787   -#line 593 "lexer.y"
  1791 +#line 597 "lexer.y"
1788 1792 { yylval.expr = linecol(); return yy__rpar; }
1789 1793 YY_BREAK
1790 1794 case 29:
1791 1795 YY_RULE_SETUP
1792   -#line 594 "lexer.y"
  1796 +#line 598 "lexer.y"
1793 1797 { yylval.expr = linecol(); return yy__lbrace; }
1794 1798 YY_BREAK
1795 1799 case 30:
1796 1800 YY_RULE_SETUP
1797   -#line 595 "lexer.y"
  1801 +#line 599 "lexer.y"
1798 1802 { yylval.expr = linecol(); return yy__rbrace; }
1799 1803 YY_BREAK
1800 1804 case 31:
1801 1805 YY_RULE_SETUP
1802   -#line 596 "lexer.y"
  1806 +#line 600 "lexer.y"
1803 1807 { yylval.expr = linecol(); return yy__rbrace; }
1804 1808 YY_BREAK
1805 1809 case 32:
1806 1810 YY_RULE_SETUP
1807   -#line 597 "lexer.y"
  1811 +#line 601 "lexer.y"
1808 1812 { yylval.expr = linecol(); return yy__lbracket; }
1809 1813 YY_BREAK
1810 1814 case 33:
1811 1815 YY_RULE_SETUP
1812   -#line 598 "lexer.y"
  1816 +#line 602 "lexer.y"
1813 1817 { yylval.expr = linecol(); return yy__rbracket; }
1814 1818 YY_BREAK
1815 1819 case 34:
1816 1820 YY_RULE_SETUP
1817   -#line 599 "lexer.y"
  1821 +#line 603 "lexer.y"
1818 1822 { yylval.expr = linecol(); return yy__rbracket; }
1819 1823 YY_BREAK
1820 1824 case 35:
1821 1825 YY_RULE_SETUP
1822   -#line 600 "lexer.y"
  1826 +#line 604 "lexer.y"
1823 1827 { yylval.expr = linecol(); return yy__colon; }
1824 1828 YY_BREAK
1825 1829 case 36:
1826 1830 YY_RULE_SETUP
1827   -#line 601 "lexer.y"
  1831 +#line 605 "lexer.y"
1828 1832 { yylval.expr = linecol(); return yy__semicolon; }
1829 1833 YY_BREAK
1830 1834 case 37:
1831 1835 YY_RULE_SETUP
1832   -#line 602 "lexer.y"
  1836 +#line 606 "lexer.y"
1833 1837 { yylval.expr = linecol(); return yy__minus; }
1834 1838 YY_BREAK
1835 1839 case 38:
1836 1840 YY_RULE_SETUP
1837   -#line 603 "lexer.y"
  1841 +#line 607 "lexer.y"
1838 1842 { yylval.expr = linecol(); return yy__dot; }
1839 1843 YY_BREAK
1840 1844 case 39:
1841 1845 YY_RULE_SETUP
1842   -#line 604 "lexer.y"
  1846 +#line 608 "lexer.y"
1843 1847 { yylval.expr = linecol(); return yy__percent; }
1844 1848 YY_BREAK
1845 1849 case 40:
1846 1850 YY_RULE_SETUP
1847   -#line 605 "lexer.y"
  1851 +#line 609 "lexer.y"
1848 1852 { yylval.expr = linecol(); return yy__comma; }
1849 1853 YY_BREAK
1850 1854 case 41:
1851 1855 YY_RULE_SETUP
1852   -#line 606 "lexer.y"
  1856 +#line 610 "lexer.y"
1853 1857 { yylval.expr = linecol(); return yy__tilde; }
1854 1858 YY_BREAK
1855 1859 case 42:
1856 1860 YY_RULE_SETUP
1857   -#line 607 "lexer.y"
  1861 +#line 611 "lexer.y"
1858 1862 { yylval.expr = linecol(); return yy__equals; }
1859 1863 YY_BREAK
1860 1864 case 43:
1861 1865 YY_RULE_SETUP
1862   -#line 608 "lexer.y"
  1866 +#line 612 "lexer.y"
1863 1867 { yylval.expr = linecol(); return yy__non_equal; }
1864 1868 YY_BREAK
1865 1869 case 44:
1866 1870 YY_RULE_SETUP
1867   -#line 609 "lexer.y"
  1871 +#line 613 "lexer.y"
1868 1872 { yylval.expr = linecol(); return yy__plus; }
1869 1873 YY_BREAK
1870 1874 case 45:
1871 1875 YY_RULE_SETUP
1872   -#line 610 "lexer.y"
  1876 +#line 614 "lexer.y"
1873 1877 { yylval.expr = linecol(); return yy__star; }
1874 1878 YY_BREAK
1875 1879 case 46:
1876 1880 YY_RULE_SETUP
1877   -#line 611 "lexer.y"
  1881 +#line 615 "lexer.y"
1878 1882 { yylval.expr = linecol(); return yy__carret; }
1879 1883 YY_BREAK
1880 1884 case 47:
1881 1885 YY_RULE_SETUP
1882   -#line 612 "lexer.y"
  1886 +#line 616 "lexer.y"
1883 1887 { yylval.expr = linecol(); return yy__ampersand; }
1884 1888 YY_BREAK
1885 1889 case 48:
1886 1890 YY_RULE_SETUP
1887   -#line 613 "lexer.y"
  1891 +#line 617 "lexer.y"
1888 1892 { yylval.expr = linecol(); return yy__vbar; }
1889 1893 YY_BREAK
1890 1894 case 49:
1891 1895 YY_RULE_SETUP
1892   -#line 614 "lexer.y"
  1896 +#line 618 "lexer.y"
1893 1897 { yylval.expr = linecol(); return yy__right_shift; }
1894 1898 YY_BREAK
1895 1899 case 50:
1896 1900 YY_RULE_SETUP
1897   -#line 615 "lexer.y"
  1901 +#line 619 "lexer.y"
1898 1902 { yylval.expr = linecol(); return yy__left_shift; }
1899 1903 YY_BREAK
1900 1904 case 51:
1901 1905 YY_RULE_SETUP
1902   -#line 616 "lexer.y"
  1906 +#line 620 "lexer.y"
1903 1907 { yylval.expr = linecol(); return yy__implies; }
1904 1908 YY_BREAK
1905 1909 case 52:
1906 1910 YY_RULE_SETUP
1907   -#line 617 "lexer.y"
  1911 +#line 621 "lexer.y"
1908 1912 { yylval.expr = linecol(); return yy__forall; }
1909 1913 YY_BREAK
1910 1914 case 53:
1911 1915 YY_RULE_SETUP
1912   -#line 618 "lexer.y"
  1916 +#line 622 "lexer.y"
1913 1917 { yylval.expr = linecol(); return yy__exists; }
1914 1918 YY_BREAK
1915 1919 case 54:
1916 1920 YY_RULE_SETUP
1917   -#line 619 "lexer.y"
  1921 +#line 623 "lexer.y"
1918 1922 { yylval.expr = linecol(); return yy__exists_unique; }
1919 1923 YY_BREAK
1920 1924 case 55:
1921 1925 YY_RULE_SETUP
1922   -#line 620 "lexer.y"
  1926 +#line 624 "lexer.y"
1923 1927 { yylval.expr = linecol(); return yy__description; }
1924 1928 YY_BREAK
1925 1929 case 56:
1926 1930 YY_RULE_SETUP
1927   -#line 621 "lexer.y"
  1931 +#line 625 "lexer.y"
1928 1932 { yylval.expr = linecol(); return yy__slash; }
1929 1933 YY_BREAK
1930 1934 case 57:
1931 1935 YY_RULE_SETUP
1932   -#line 622 "lexer.y"
  1936 +#line 626 "lexer.y"
1933 1937 { yylval.expr = linecol(); return yy__mod; }
1934 1938 YY_BREAK
1935 1939 case 58:
1936 1940 YY_RULE_SETUP
1937   -#line 623 "lexer.y"
  1941 +#line 627 "lexer.y"
1938 1942 { yylval.expr = linecol(); return yy__less; }
1939 1943 YY_BREAK
1940 1944 case 59:
1941 1945 YY_RULE_SETUP
1942   -#line 624 "lexer.y"
  1946 +#line 628 "lexer.y"
1943 1947 { yylval.expr = linecol(); return yy__greater; }
1944 1948 YY_BREAK
1945 1949 case 60:
1946 1950 YY_RULE_SETUP
1947   -#line 625 "lexer.y"
  1951 +#line 629 "lexer.y"
1948 1952 { yylval.expr = linecol(); return yy__lessoreq; }
1949 1953 YY_BREAK
1950 1954 case 61:
1951 1955 YY_RULE_SETUP
1952   -#line 626 "lexer.y"
  1956 +#line 630 "lexer.y"
1953 1957 { yylval.expr = linecol(); return yy__greateroreq; }
1954 1958 YY_BREAK
1955 1959 case 62:
1956 1960 YY_RULE_SETUP
1957   -#line 627 "lexer.y"
  1961 +#line 631 "lexer.y"
1958 1962 { yylval.expr = linecol(); return yy__write; }
1959 1963 YY_BREAK
1960 1964 case 63:
1961 1965 YY_RULE_SETUP
1962   -#line 628 "lexer.y"
  1966 +#line 632 "lexer.y"
1963 1967 { yylval.expr = linecol(); return yy__exchange; }
1964 1968 YY_BREAK
1965 1969 case 64:
1966 1970 YY_RULE_SETUP
1967   -#line 629 "lexer.y"
  1971 +#line 633 "lexer.y"
1968 1972 { yylval.expr = linecol(); return yy__arrow; }
1969 1973 YY_BREAK
1970 1974 case 65:
1971 1975 YY_RULE_SETUP
1972   -#line 630 "lexer.y"
  1976 +#line 634 "lexer.y"
1973 1977 { yylval.expr = linecol(); return yy__arroww; }
1974 1978 YY_BREAK
1975 1979 case 66:
1976 1980 YY_RULE_SETUP
1977   -#line 631 "lexer.y"
  1981 +#line 635 "lexer.y"
1978 1982 { yylval.expr = linecol(); return yy__mapsto; }
1979 1983 YY_BREAK
1980 1984 case 67:
1981 1985 YY_RULE_SETUP
1982   -#line 632 "lexer.y"
  1986 +#line 636 "lexer.y"
1983 1987 { yylval.expr = linecol(); return yy__mapstoo; }
1984 1988 YY_BREAK
1985 1989 case 68:
1986 1990 YY_RULE_SETUP
1987   -#line 633 "lexer.y"
  1991 +#line 637 "lexer.y"
1988 1992 { yylval.expr = linecol(); return yy__dots; }
1989 1993 YY_BREAK
1990 1994 case 69:
1991 1995 YY_RULE_SETUP
1992   -#line 634 "lexer.y"
  1996 +#line 638 "lexer.y"
1993 1997 { yylval.expr = linecol(); return yy__rpar_arrow; }
1994 1998 YY_BREAK
1995 1999 case 70:
1996 2000 YY_RULE_SETUP
1997   -#line 635 "lexer.y"
  2001 +#line 639 "lexer.y"
1998 2002 { yylval.expr = linecol(); return yy__type_String; }
1999 2003 YY_BREAK
2000 2004 case 71:
2001 2005 YY_RULE_SETUP
2002   -#line 636 "lexer.y"
  2006 +#line 640 "lexer.y"
2003 2007 { yylval.expr = linecol(); return yy__type_ByteArray; }
2004 2008 YY_BREAK
2005 2009 case 72:
2006 2010 YY_RULE_SETUP
2007   -#line 637 "lexer.y"
  2011 +#line 641 "lexer.y"
2008 2012 { yylval.expr = linecol(); return yy__type_Int32; }
2009 2013 YY_BREAK
2010 2014 case 73:
2011 2015 YY_RULE_SETUP
2012   -#line 638 "lexer.y"
  2016 +#line 642 "lexer.y"
2013 2017 { yylval.expr = linecol(); return yy__type_Omega; }
2014 2018 YY_BREAK
2015 2019 case 74:
2016 2020 YY_RULE_SETUP
2017   -#line 639 "lexer.y"
  2021 +#line 643 "lexer.y"
2018 2022 { yylval.expr = linecol(); return yy__bit_width; }
2019 2023 YY_BREAK
2020 2024 case 75:
2021 2025 YY_RULE_SETUP
2022   -#line 640 "lexer.y"
  2026 +#line 644 "lexer.y"
2023 2027 { yylval.expr = linecol(); return yy__indirect; }
2024 2028 YY_BREAK
2025 2029 case 76:
2026 2030 YY_RULE_SETUP
2027   -#line 641 "lexer.y"
  2031 +#line 645 "lexer.y"
2028 2032 { if (reading_predef)
2029 2033 { yylval.expr = linecol(); return yy__vcopy; }
2030 2034 else lexical_error(); }
2031 2035 YY_BREAK
2032 2036 case 77:
2033 2037 YY_RULE_SETUP
2034   -#line 644 "lexer.y"
  2038 +#line 648 "lexer.y"
2035 2039 { if (reading_predef)
2036 2040 { yylval.expr = linecol(); return yy__load_module; }
2037 2041 else lexical_error(); }
2038 2042 YY_BREAK
2039 2043 case 78:
2040 2044 YY_RULE_SETUP
2041   -#line 647 "lexer.y"
  2045 +#line 651 "lexer.y"
2042 2046 { if (reading_predef)
2043 2047 { yylval.expr = linecol(); return yy__serialize; }
2044 2048 else lexical_error(); }
2045 2049 YY_BREAK
2046 2050 case 79:
2047 2051 YY_RULE_SETUP
2048   -#line 650 "lexer.y"
  2052 +#line 654 "lexer.y"
2049 2053 { if (reading_predef)
2050 2054 { yylval.expr = linecol(); return yy__unserialize; }
2051 2055 else lexical_error(); }
2052 2056 YY_BREAK
2053 2057 case 80:
2054 2058 YY_RULE_SETUP
2055   -#line 653 "lexer.y"
  2059 +#line 657 "lexer.y"
2056 2060 { yylval.expr = linecol(); return yy__type_Float; }
2057 2061 YY_BREAK
2058 2062 case 81:
2059 2063 YY_RULE_SETUP
2060   -#line 654 "lexer.y"
  2064 +#line 658 "lexer.y"
2061 2065 { if (reading_predef)
2062 2066 { yylval.expr = linecol(); return yy__type_Listener; }
2063 2067 else lexical_error(); }
2064 2068 YY_BREAK
2065 2069 case 82:
2066 2070 YY_RULE_SETUP
2067   -#line 657 "lexer.y"
  2071 +#line 661 "lexer.y"
2068 2072 { if (reading_predef)
2069 2073 { yylval.expr = linecol(); return yy__StructPtr; }
2070 2074 else lexical_error(); }
2071 2075 YY_BREAK
2072 2076 case 83:
2073 2077 YY_RULE_SETUP
2074   -#line 660 "lexer.y"
  2078 +#line 664 "lexer.y"
2075 2079 { if (reading_predef)
2076 2080 { yylval.expr = linecol(); return yy__avm; }
2077 2081 else lexical_error(); }
2078 2082 YY_BREAK
2079 2083 case 84:
2080 2084 YY_RULE_SETUP
2081   -#line 663 "lexer.y"
  2085 +#line 667 "lexer.y"
2082 2086 { yylval.expr = linecol(); return yy__if; }
2083 2087 YY_BREAK
2084 2088 case 85:
2085 2089 YY_RULE_SETUP
2086   -#line 664 "lexer.y"
  2090 +#line 668 "lexer.y"
2087 2091 { yylval.expr = linecol(); return yy__proof; }
2088 2092 YY_BREAK
2089 2093 case 86:
2090 2094 YY_RULE_SETUP
2091   -#line 665 "lexer.y"
  2095 +#line 669 "lexer.y"
2092 2096 { yylval.expr = linecol(); return yy__type_Proof; }
2093 2097 YY_BREAK
2094 2098 case 87:
2095 2099 YY_RULE_SETUP
2096   -#line 666 "lexer.y"
  2100 +#line 670 "lexer.y"
2097 2101 { yylval.expr = linecol(); return yy__since; }
2098 2102 YY_BREAK
2099 2103 case 88:
2100 2104 YY_RULE_SETUP
2101   -#line 667 "lexer.y"
  2105 +#line 671 "lexer.y"
2102 2106 { return yy__is; }
2103 2107 YY_BREAK
2104 2108 case 89:
2105 2109 YY_RULE_SETUP
2106   -#line 668 "lexer.y"
  2110 +#line 672 "lexer.y"
2107 2111 { yylval.expr = linecol(); return yy__then; }
2108 2112 YY_BREAK
2109 2113 case 90:
2110 2114 YY_RULE_SETUP
2111   -#line 669 "lexer.y"
  2115 +#line 673 "lexer.y"
2112 2116 { yylval.expr = linecol(); return yy__alert; }
2113 2117 YY_BREAK
2114 2118 case 91:
2115 2119 YY_RULE_SETUP
2116   -#line 670 "lexer.y"
  2120 +#line 674 "lexer.y"
2117 2121 { yylval.expr = linecol(); return yy__protect; }
2118 2122 YY_BREAK
2119 2123 case 92:
2120 2124 YY_RULE_SETUP
2121   -#line 671 "lexer.y"
  2125 +#line 675 "lexer.y"
2122 2126 { yylval.expr = linecol(); return yy__lock; }
2123 2127 YY_BREAK
2124 2128 case 93:
2125 2129 YY_RULE_SETUP
2126   -#line 672 "lexer.y"
  2130 +#line 676 "lexer.y"
2127 2131 { yylval.expr = linecol(); return yy__succeeds; }
2128 2132 YY_BREAK
2129 2133 case 94:
2130 2134 YY_RULE_SETUP
2131   -#line 673 "lexer.y"
  2135 +#line 677 "lexer.y"
2132 2136 { yylval.expr = linecol(); return yy__succeeds_as; }
2133 2137 YY_BREAK
2134 2138 case 95:
2135 2139 YY_RULE_SETUP
2136   -#line 674 "lexer.y"
  2140 +#line 678 "lexer.y"
2137 2141 { yylval.expr = linecol(); return yy__wait_for; }
2138 2142 YY_BREAK
2139 2143 case 96:
2140 2144 YY_RULE_SETUP
2141   -#line 675 "lexer.y"
  2145 +#line 679 "lexer.y"
2142 2146 { yylval.expr = linecol(); return yy__checking_every; }
2143 2147 YY_BREAK
2144 2148 case 97:
2145 2149 YY_RULE_SETUP
2146   -#line 676 "lexer.y"
  2150 +#line 680 "lexer.y"
2147 2151 { yylval.expr = linecol(); return yy__delegate; }
2148 2152 YY_BREAK
2149 2153 case 98:
2150 2154 YY_RULE_SETUP
2151   -#line 677 "lexer.y"
  2155 +#line 681 "lexer.y"
2152 2156 { yylval.expr = linecol(); return yy__else; }
2153 2157 YY_BREAK
2154 2158 case 99:
2155 2159 YY_RULE_SETUP
2156   -#line 678 "lexer.y"
  2160 +#line 682 "lexer.y"
2157 2161 { yylval.expr = linecol(); return yy__with; }
2158 2162 YY_BREAK
2159 2163 case 100:
2160 2164 YY_RULE_SETUP
2161   -#line 679 "lexer.y"
  2165 +#line 683 "lexer.y"
2162 2166 { yylval.expr = linecol(); return yy__alt_number; }
2163 2167 YY_BREAK
2164 2168 case 101:
2165 2169 YY_RULE_SETUP
2166   -#line 680 "lexer.y"
  2170 +#line 684 "lexer.y"
2167 2171 { yylval.expr = linecol(); return yy__RAddr; }
2168 2172 YY_BREAK
2169 2173 case 102:
2170 2174 YY_RULE_SETUP
2171   -#line 681 "lexer.y"
  2175 +#line 685 "lexer.y"
2172 2176 { yylval.expr = linecol(); return yy__WAddr; }
2173 2177 YY_BREAK
2174 2178 case 103:
2175 2179 YY_RULE_SETUP
2176   -#line 682 "lexer.y"
  2180 +#line 686 "lexer.y"
2177 2181 { yylval.expr = linecol(); return yy__RWAddr; }
2178 2182 YY_BREAK
2179 2183 case 104:
2180 2184 YY_RULE_SETUP
2181   -#line 683 "lexer.y"
  2185 +#line 687 "lexer.y"
2182 2186 { yylval.expr = linecol(); return yy__GAddr; }
2183 2187 YY_BREAK
2184 2188 case 105:
2185 2189 YY_RULE_SETUP
2186   -#line 684 "lexer.y"
  2190 +#line 688 "lexer.y"
2187 2191 { yylval.expr = linecol(); return yy__Var; }
2188 2192 YY_BREAK
2189 2193 case 106:
2190 2194 YY_RULE_SETUP
2191   -#line 685 "lexer.y"
  2195 +#line 689 "lexer.y"
2192 2196 { yylval.expr = linecol(); return yy__MVar; }
2193 2197 YY_BREAK
2194 2198 case 107:
2195 2199 YY_RULE_SETUP
2196   -#line 686 "lexer.y"
  2200 +#line 690 "lexer.y"
2197 2201 { yylval.expr = linecol(); return yy__connect_to_file; }
2198 2202 YY_BREAK
2199 2203 case 108:
2200 2204 YY_RULE_SETUP
2201   -#line 687 "lexer.y"
  2205 +#line 691 "lexer.y"
2202 2206 { yylval.expr = linecol(); return yy__connect_to_IP; }
2203 2207 YY_BREAK
2204 2208 case 109:
2205 2209 YY_RULE_SETUP
2206   -#line 688 "lexer.y"
  2210 +#line 692 "lexer.y"
2207 2211 { yylval.expr = linecol(); return yy__debug_avm; }
2208 2212 YY_BREAK
2209 2213 case 110:
2210 2214 YY_RULE_SETUP
2211   -#line 689 "lexer.y"
  2215 +#line 693 "lexer.y"
2212 2216 { yylval.expr = linecol(); return yy__terminal; }
2213 2217 YY_BREAK
2214 2218 case 111:
2215 2219 YY_RULE_SETUP
2216   -#line 690 "lexer.y"
  2220 +#line 694 "lexer.y"
2217 2221 { yylval.expr = linecol(); return yy__we_have; }
2218 2222 YY_BREAK
2219 2223 case 112:
2220 2224 YY_RULE_SETUP
2221   -#line 691 "lexer.y"
  2225 +#line 695 "lexer.y"
2222 2226 { yylval.expr = linecol();
2223 2227 return yy__enough; }
2224 2228 YY_BREAK
2225 2229 case 113:
2226 2230 YY_RULE_SETUP
2227   -#line 693 "lexer.y"
  2231 +#line 697 "lexer.y"
2228 2232 { yylval.expr = linecol(); return yy__let; }
2229 2233 YY_BREAK
2230 2234 case 114:
2231 2235 YY_RULE_SETUP
2232   -#line 694 "lexer.y"
  2236 +#line 698 "lexer.y"
2233 2237 { yylval.expr = linecol(); return yy__assume; }
2234 2238 YY_BREAK
2235 2239 case 115:
2236 2240 YY_RULE_SETUP
2237   -#line 695 "lexer.y"
  2241 +#line 699 "lexer.y"
2238 2242 { yylval.expr = linecol(); return yy__hence; }
2239 2243 YY_BREAK
2240 2244 case 116:
2241 2245 YY_RULE_SETUP
2242   -#line 696 "lexer.y"
  2246 +#line 700 "lexer.y"
2243 2247 { yylval.expr = linecol(); return yy__indeed; }
2244 2248 YY_BREAK
2245 2249 case 117:
2246 2250 YY_RULE_SETUP
2247   -#line 697 "lexer.y"
  2251 +#line 701 "lexer.y"
2248 2252 { BEGIN CONF; return yy__stop_after; }
2249 2253 YY_BREAK
2250 2254 case 118:
2251 2255 YY_RULE_SETUP
2252   -#line 698 "lexer.y"
  2256 +#line 702 "lexer.y"
2253 2257 { BEGIN CONF; return yy__djed; }
2254 2258 YY_BREAK
2255 2259 case 119:
2256 2260 YY_RULE_SETUP
2257   -#line 699 "lexer.y"
  2261 +#line 703 "lexer.y"
2258 2262 { return yy__verbose; }
2259 2263 YY_BREAK
2260 2264 case 120:
2261 2265 YY_RULE_SETUP
2262   -#line 700 "lexer.y"
  2266 +#line 704 "lexer.y"
2263 2267 { BEGIN CONF; return yy__language; }
2264 2268 YY_BREAK
2265 2269 case 121:
2266 2270 YY_RULE_SETUP
2267   -#line 701 "lexer.y"
  2271 +#line 705 "lexer.y"
2268 2272 { fprintf(errfile,msgtext_syntax_error_in_conf_file[language],
2269 2273 my_anubis_directory,lineno); anb_exit(1); }
2270 2274 YY_BREAK
2271 2275 case 122:
2272 2276 YY_RULE_SETUP
2273   -#line 703 "lexer.y"
  2277 +#line 707 "lexer.y"
2274 2278 { }
2275 2279 YY_BREAK
2276 2280 case 123:
2277 2281 YY_RULE_SETUP
2278   -#line 704 "lexer.y"
  2282 +#line 708 "lexer.y"
2279 2283 { }
2280 2284 YY_BREAK
2281 2285 case 124:
2282 2286 YY_RULE_SETUP
2283   -#line 705 "lexer.y"
  2287 +#line 709 "lexer.y"
2284 2288 {
2285 2289 yytext[yyleng-1] = 0;
2286 2290 yylval.expr = new_string(yytext+1);
... ... @@ -2289,118 +2293,118 @@ YY_RULE_SETUP
2289 2293 YY_BREAK
2290 2294 case 125:
2291 2295 YY_RULE_SETUP
2292   -#line 710 "lexer.y"
  2296 +#line 714 "lexer.y"
2293 2297 {
2294 2298 yylval.expr = new_string(yytext);
2295 2299 return yy__conf_symbol; }
2296 2300 YY_BREAK
2297 2301 case 126:
2298 2302 YY_RULE_SETUP
2299   -#line 713 "lexer.y"
  2303 +#line 717 "lexer.y"
2300 2304 { yylval.expr = new_integer(atoi(yytext)); return yy__conf_int; }
2301 2305 YY_BREAK
2302 2306 case 127:
2303 2307 YY_RULE_SETUP
2304   -#line 714 "lexer.y"
  2308 +#line 718 "lexer.y"
2305 2309 { }
2306 2310 YY_BREAK
2307 2311 case 128:
2308 2312 YY_RULE_SETUP
2309   -#line 715 "lexer.y"
  2313 +#line 719 "lexer.y"
2310 2314 { BEGIN CONFCOM; }
2311 2315 YY_BREAK
2312 2316 case 129:
2313 2317 YY_RULE_SETUP
2314   -#line 716 "lexer.y"
  2318 +#line 720 "lexer.y"
2315 2319 { BEGIN CONFCOM; fprintf(errfile,msgtext_syntax_error_in_conf_file[language],
2316 2320 my_anubis_directory,lineno); anb_exit(1); }
2317 2321 YY_BREAK
2318 2322 case 130:
2319 2323 YY_RULE_SETUP
2320   -#line 718 "lexer.y"
  2324 +#line 722 "lexer.y"
2321 2325 { printf(yytext); fflush(stdout); }
2322 2326 YY_BREAK
2323 2327 case 131:
2324 2328 YY_RULE_SETUP
2325   -#line 719 "lexer.y"
  2329 +#line 723 "lexer.y"
2326 2330 { BEGIN PAR; par_seen = 1; current_par_line = lineno;
2327 2331 yylval.expr = linecol(); return yy__type; }
2328 2332 YY_BREAK
2329 2333 case 132:
2330 2334 YY_RULE_SETUP
2331   -#line 721 "lexer.y"
  2335 +#line 725 "lexer.y"
2332 2336 { BEGIN PAR; par_seen = 1; current_par_line = lineno;
2333 2337 yylval.expr = linecol(); return yy__p_type; }
2334 2338 YY_BREAK
2335 2339 case 133:
2336 2340 YY_RULE_SETUP
2337   -#line 723 "lexer.y"
  2341 +#line 727 "lexer.y"
2338 2342 { BEGIN PAR; par_seen = 1; current_par_line = lineno;
2339 2343 yylval.expr = linecol(); return yy__variable; }
2340 2344 YY_BREAK
2341 2345 case 134:
2342 2346 YY_RULE_SETUP
2343   -#line 725 "lexer.y"
  2347 +#line 729 "lexer.y"
2344 2348 { BEGIN PAR; par_seen = 1; current_par_line = lineno;
2345 2349 yylval.expr = linecol(); return yy__p_variable; }
2346 2350 YY_BREAK
2347 2351 case 135:
2348 2352 YY_RULE_SETUP
2349   -#line 727 "lexer.y"
  2353 +#line 731 "lexer.y"
2350 2354 { BEGIN PAR; par_seen = 1; current_par_line = lineno;
2351 2355 yylval.expr = linecol(); return yy__theorem; }
2352 2356 YY_BREAK
2353 2357 case 136:
2354 2358 YY_RULE_SETUP
2355   -#line 729 "lexer.y"
  2359 +#line 733 "lexer.y"
2356 2360 { BEGIN PAR; par_seen = 1; current_par_line = lineno;
2357 2361 yylval.expr = linecol(); return yy__p_theorem; }
2358 2362 YY_BREAK
2359 2363 case 137:
2360 2364 YY_RULE_SETUP
2361   -#line 731 "lexer.y"
  2365 +#line 735 "lexer.y"
2362 2366 { BEGIN PAR; par_seen = 1; current_par_line = lineno;
2363 2367 yylval.expr = linecol(); return yy__operation; }
2364 2368 YY_BREAK
2365 2369 case 138:
2366 2370 YY_RULE_SETUP
2367   -#line 733 "lexer.y"
  2371 +#line 737 "lexer.y"
2368 2372 { BEGIN PAR; par_seen = 1; current_par_line = lineno;
2369 2373 yylval.expr = linecol(); return yy__g_operation; }
2370 2374 YY_BREAK
2371 2375 case 139:
2372 2376 YY_RULE_SETUP
2373   -#line 735 "lexer.y"
  2377 +#line 739 "lexer.y"
2374 2378 { BEGIN PAR; par_seen = 1; current_par_line = lineno;
2375 2379 yylval.expr = linecol(); return yy__operation; }
2376 2380 YY_BREAK
2377 2381 case 140:
2378 2382 YY_RULE_SETUP
2379   -#line 737 "lexer.y"
  2383 +#line 741 "lexer.y"
2380 2384 { BEGIN PAR; par_seen = 1; current_par_line = lineno;
2381 2385 yylval.expr = linecol(); return yy__g_operation; }
2382 2386 YY_BREAK
2383 2387 case 141:
2384 2388 YY_RULE_SETUP
2385   -#line 739 "lexer.y"
  2389 +#line 743 "lexer.y"
2386 2390 { BEGIN PAR; par_seen = 1; current_par_line = lineno;
2387 2391 yylval.expr = linecol(); return yy__p_operation; }
2388 2392 YY_BREAK
2389 2393 case 142:
2390 2394 YY_RULE_SETUP
2391   -#line 741 "lexer.y"
  2395 +#line 745 "lexer.y"
2392 2396 { if (polish) { yylval.expr = linecol(); BEGIN INCL; return yy__read; }
2393 2397 else if (!gindex && !errors) { BEGIN INCL; } }
2394 2398 YY_BREAK
2395 2399 case 143:
2396 2400 YY_RULE_SETUP
2397   -#line 743 "lexer.y"
  2401 +#line 747 "lexer.y"
2398 2402 { BEGIN PAR; par_seen = 1; current_par_line = lineno;
2399 2403 yylval.expr = linecol(); return yy__C_constr_for; }
2400 2404 YY_BREAK
2401 2405 case 144:
2402 2406 YY_RULE_SETUP
2403   -#line 745 "lexer.y"
  2407 +#line 749 "lexer.y"
2404 2408 { if (polish)
2405 2409 {
2406 2410 yylval.expr = new_string(yytext);
... ... @@ -2421,6 +2425,7 @@ YY_RULE_SETUP
2421 2425 else
2422 2426 { if (include_stack_ptr >= max_include)
2423 2427 {
  2428 + err_line_col(linecol());
2424 2429 fprintf(errfile,
2425 2430 msgtext_include_too_deeply[language],
2426 2431 max_include);
... ... @@ -2456,12 +2461,12 @@ YY_RULE_SETUP
2456 2461 YY_BREAK
2457 2462 case 145:
2458 2463 YY_RULE_SETUP
2459   -#line 797 "lexer.y"
  2464 +#line 802 "lexer.y"
2460 2465 { lexical_kwread_error(); }
2461 2466 YY_BREAK
2462 2467 case 146:
2463 2468 YY_RULE_SETUP
2464   -#line 798 "lexer.y"
  2469 +#line 803 "lexer.y"
2465 2470 { lexical_kwread_error(); }
2466 2471 YY_BREAK
2467 2472 case YY_STATE_EOF(INITIAL):
... ... @@ -2472,7 +2477,7 @@ case YY_STATE_EOF(STR):
2472 2477 case YY_STATE_EOF(STRTL):
2473 2478 case YY_STATE_EOF(CONF):
2474 2479 case YY_STATE_EOF(CONFCOM):
2475   -#line 799 "lexer.y"
  2480 +#line 804 "lexer.y"
2476 2481 { if (include_stack_ptr == 0)
2477 2482 {
2478 2483 yyterminate();
... ... @@ -2505,44 +2510,44 @@ case YY_STATE_EOF(CONFCOM):
2505 2510 YY_BREAK
2506 2511 case 147:
2507 2512 YY_RULE_SETUP
2508   -#line 828 "lexer.y"
  2513 +#line 833 "lexer.y"
2509 2514 { yylval.integer = atoi(yytext); return yy__integer; }
2510 2515 YY_BREAK
2511 2516 case 148:
2512 2517 YY_RULE_SETUP
2513   -#line 829 "lexer.y"
  2518 +#line 834 "lexer.y"
2514 2519 { yylval.expr = new_string(yytext); return yy__float; }
2515 2520 YY_BREAK
2516 2521 case 149:
2517 2522 YY_RULE_SETUP
2518   -#line 830 "lexer.y"
  2523 +#line 835 "lexer.y"
2519 2524 { yylval.expr = new_utvar(yytext+1); return yy__utvar; }
2520 2525 YY_BREAK
2521 2526 case 150:
2522 2527 YY_RULE_SETUP
2523   -#line 831 "lexer.y"
  2528 +#line 836 "lexer.y"
2524 2529 { yylval.expr = new_string(yytext); return yy__Symbol; }
2525 2530 YY_BREAK
2526 2531 case 151:
2527 2532 YY_RULE_SETUP
2528   -#line 832 "lexer.y"
  2533 +#line 837 "lexer.y"
2529 2534 { yylval.expr = new_string(yytext); return yy__symbol; }
2530 2535 YY_BREAK
2531 2536 case 152:
2532 2537 YY_RULE_SETUP
2533   -#line 833 "lexer.y"
  2538 +#line 838 "lexer.y"
2534 2539 { yylval.expr = new_string(rec_name(yytext,4));
2535 2540 return yy__rec_mapsto; }
2536 2541 YY_BREAK
2537 2542 case 153:
2538 2543 YY_RULE_SETUP
2539   -#line 835 "lexer.y"
  2544 +#line 840 "lexer.y"
2540 2545 { yylval.expr = new_string(rec_name(yytext,5));
2541 2546 return yy__rec_mapstoo; }
2542 2547 YY_BREAK
2543 2548 case 154:
2544 2549 YY_RULE_SETUP
2545   -#line 837 "lexer.y"
  2550 +#line 842 "lexer.y"
2546 2551 { if (reading_predef)
2547 2552 { yylval.expr = new_string(yytext); return yy__Symbol; }
2548 2553 else lexical_error();
... ... @@ -2550,7 +2555,7 @@ YY_RULE_SETUP
2550 2555 YY_BREAK
2551 2556 case 155:
2552 2557 YY_RULE_SETUP
2553   -#line 841 "lexer.y"
  2558 +#line 846 "lexer.y"
2554 2559 { if (reading_predef)
2555 2560 { yylval.expr = new_string(yytext); return yy__symbol; }
2556 2561 else lexical_error();
... ... @@ -2558,7 +2563,7 @@ YY_RULE_SETUP
2558 2563 YY_BREAK
2559 2564 case 156:
2560 2565 YY_RULE_SETUP
2561   -#line 845 "lexer.y"
  2566 +#line 850 "lexer.y"
2562 2567 { if (reading_predef)
2563 2568 { yylval.expr = new_string(yytext); return yy__symbol; }
2564 2569 else lexical_error();
... ... @@ -2566,35 +2571,35 @@ YY_RULE_SETUP
2566 2571 YY_BREAK
2567 2572 case 157:
2568 2573 YY_RULE_SETUP
2569   -#line 849 "lexer.y"
  2574 +#line 854 "lexer.y"
2570 2575 { }
2571 2576 YY_BREAK
2572 2577 case 158:
2573 2578 YY_RULE_SETUP
2574   -#line 850 "lexer.y"
  2579 +#line 855 "lexer.y"
2575 2580 { }
2576 2581 YY_BREAK
2577 2582 case 159:
2578 2583 YY_RULE_SETUP
2579   -#line 851 "lexer.y"
  2584 +#line 856 "lexer.y"
2580 2585 { lexical_error(); }
2581 2586 YY_BREAK
2582 2587 case 160:
2583 2588 YY_RULE_SETUP
2584   -#line 852 "lexer.y"
  2589 +#line 857 "lexer.y"
2585 2590 { if (gindex) store_external_comment('\n'); }
2586 2591 YY_BREAK
2587 2592 case 161:
2588 2593 YY_RULE_SETUP
2589   -#line 853 "lexer.y"
  2594 +#line 858 "lexer.y"
2590 2595 { if (gindex) store_external_comment(yytext[0]); }
2591 2596 YY_BREAK
2592 2597 case 162:
2593 2598 YY_RULE_SETUP
2594   -#line 854 "lexer.y"
  2599 +#line 859 "lexer.y"
2595 2600 ECHO;
2596 2601 YY_BREAK
2597   -#line 2598 "lex.yy.c"
  2602 +#line 2603 "lex.yy.c"
2598 2603  
2599 2604 case YY_END_OF_BUFFER:
2600 2605 {
... ... @@ -3484,7 +3489,7 @@ int main()
3484 3489 return 0;
3485 3490 }
3486 3491 #endif
3487   -#line 854 "lexer.y"
  3492 +#line 859 "lexer.y"
3488 3493  
3489 3494  
3490 3495  
... ...
anubis_dev/compiler/src/lexer.y
... ... @@ -137,6 +137,7 @@ char *path_prefix(char *name)
137 137 int i = strlen(name);
138 138 if (i >= path_prefix_length-5)
139 139 {
  140 + err_line_col(linecol());
140 141 fprintf(errfile,
141 142 msgtext_file_path_too_long[language],
142 143 name);
... ... @@ -194,6 +195,7 @@ FILE *fopensrc(char *name)
194 195 /* if path is absolute do not try the libraries */
195 196 if (name[0] == '/' || name[0] == '\\')
196 197 {
  198 + err_line_col(linecol());
197 199 fprintf(errfile,
198 200 msgtext_cannot_find_src_file[language],
199 201 name,
... ... @@ -232,6 +234,7 @@ FILE *fopensrc(char *name)
232 234 }
233 235  
234 236 /* The file is not found: send a message and exit */
  237 + err_line_col(linecol());
235 238 fprintf(errfile,
236 239 msgtext_cannot_find_src_file[language],
237 240 name,
... ... @@ -338,6 +341,7 @@ void add_to_already_included(char *name)
338 341 //printf("Adding '%s'.\n",name);
339 342 if (next_already_included == max_already_included)
340 343 {
  344 + err_line_col(linecol());
341 345 fprintf(errfile,
342 346 msgtext_too_many_files[language]);
343 347 anb_exit(1);
... ... @@ -762,6 +766,7 @@ static char *rec_name(char *s, int del)
762 766 else
763 767 { if (include_stack_ptr >= max_include)
764 768 {
  769 + err_line_col(linecol());
765 770 fprintf(errfile,
766 771 msgtext_include_too_deeply[language],
767 772 max_include);
... ...
anubis_dev/compiler/src/predef.aux
... ... @@ -4117,10 +4117,12 @@ nil),
4117 4117 cons(cons(cons(type_struct_ptr,
4118 4118 new_integer(3)),
4119 4119 new_string("handle")),
4120   -nil),
  4120 +cons(cons(type_Int32,
  4121 +new_string("max")),
  4122 +nil)),
4121 4123 no_term);
4122 4124  
4123   -new_op_scheme(18832910,0,
  4125 +new_op_scheme(18833934,0,
4124 4126 new_string("Bool"),
4125 4127 cons(new_string("£default_host_window_handling"),
4126 4128 nil),
... ... @@ -4163,7 +4165,7 @@ new_string("event_handler")),
4163 4165 nil))))),
4164 4166 no_term);
4165 4167  
4166   -new_op_scheme(18839566,0,
  4168 +new_op_scheme(18840590,0,
4167 4169 new_string("One"),
4168 4170 cons(new_string("£begin_paint"),
4169 4171 nil),
... ... @@ -4172,7 +4174,7 @@ new_string("window")),
4172 4174 nil),
4173 4175 no_term);
4174 4176  
4175   -new_op_scheme(18843150,0,
  4177 +new_op_scheme(18844174,0,
4176 4178 new_string("One"),
4177 4179 cons(new_string("£end_paint"),
4178 4180 nil),
... ... @@ -4181,7 +4183,7 @@ new_string("window")),
4181 4183 nil),
4182 4184 no_term);
4183 4185  
4184   -new_op_scheme(18847246,0,
  4186 +new_op_scheme(18848270,0,
4185 4187 new_string("Bool"),
4186 4188 cons(new_string("£handle_host_window_events"),
4187 4189 nil),
... ... @@ -4219,7 +4221,7 @@ new_string("eh")),
4219 4221 nil)))),
4220 4222 no_term);
4221 4223  
4222   -new_op_scheme(18864142,0,
  4224 +new_op_scheme(18865166,0,
4223 4225 new_string("Bool"),
4224 4226 cons(new_string("£default_host_window_handling"),
4225 4227 nil),
... ... @@ -4262,7 +4264,7 @@ new_string("event_handler")),
4262 4264 nil))))),
4263 4265 no_term);
4264 4266  
4265   -new_op_scheme(18875420,1,
  4267 +new_op_scheme(18876444,1,
4266 4268 new_string("One"),
4267 4269 cons(new_string("generic_host_window_handler"),
4268 4270 nil),
... ... @@ -4320,7 +4322,7 @@ nil),
4320 4322 nil),
4321 4323 nil)),0,1);
4322 4324  
4323   -new_op_scheme(18890766,0,
  4325 +new_op_scheme(18891790,0,
4324 4326 cons(app_ts,
4325 4327 cons(new_string("Maybe"),
4326 4328 cons(cons(app_ts,
... ... @@ -4348,7 +4350,7 @@ new_string("sort")),
4348 4350 nil)))))),
4349 4351 no_term);
4350 4352  
4351   -new_op_scheme(18898972,1,
  4353 +new_op_scheme(18899996,1,
4352 4354 cons(app_ts,
4353 4355 cons(new_string("Maybe"),
4354 4356 cons(new_string("HostWindow"),
... ... @@ -4402,7 +4404,7 @@ new_string("compress")),
4402 4404 nil)))))),
4403 4405 no_term);
4404 4406  
4405   -new_op_scheme(18915356,1,
  4407 +new_op_scheme(18916380,1,
4406 4408 new_string("One"),
4407 4409 cons(new_string("show"),
4408 4410 nil),
... ... @@ -4411,7 +4413,7 @@ new_string("win")),
4411 4413 nil),
4412 4414 no_term);
4413 4415  
4414   -new_op_scheme(18919452,1,
  4416 +new_op_scheme(18920476,1,
4415 4417 new_string("One"),
4416 4418 cons(new_string("hide"),
4417 4419 nil),
... ... @@ -4420,7 +4422,7 @@ new_string("win")),
4420 4422 nil),
4421 4423 no_term);
4422 4424  
4423   -new_op_scheme(18929180,1,
  4425 +new_op_scheme(18930204,1,
4424 4426 new_string("Bool"),
4425 4427 cons(new_string("queue_event"),
4426 4428 nil),
... ... @@ -4434,7 +4436,7 @@ new_string("e")),
4434 4436 nil)),
4435 4437 no_term);
4436 4438  
4437   -new_op_scheme(18939420,1,
  4439 +new_op_scheme(18940444,1,
4438 4440 new_string("One"),
4439 4441 cons(new_string("paint_rectangle"),
4440 4442 nil),
... ... @@ -4447,7 +4449,7 @@ new_string("color")),
4447 4449 nil))),
4448 4450 no_term);
4449 4451  
4450   -new_op_scheme(18945052,1,
  4452 +new_op_scheme(18946076,1,
4451 4453 new_string("One"),
4452 4454 cons(new_string("paint_rectangle"),
4453 4455 nil),
... ... @@ -4460,7 +4462,7 @@ new_string("color")),
4460 4462 nil))),
4461 4463 no_term);
4462 4464  
4463   -new_op_scheme(18962460,1,
  4465 +new_op_scheme(18963484,1,
4464 4466 new_string("One"),
4465 4467 cons(new_string("paint_image"),
4466 4468 nil),
... ... @@ -4477,7 +4479,7 @@ new_string("image")),
4477 4479 nil))))),
4478 4480 no_term);
4479 4481  
4480   -new_op_scheme(18969116,1,
  4482 +new_op_scheme(18970140,1,
4481 4483 new_string("One"),
4482 4484 cons(new_string("paint_image"),
4483 4485 nil),
... ... @@ -4494,7 +4496,7 @@ new_string("image")),
4494 4496 nil))))),
4495 4497 no_term);
4496 4498  
4497   -new_op_scheme(18975260,1,
  4499 +new_op_scheme(18976284,1,
4498 4500 new_string("One"),
4499 4501 cons(new_string("map_to_host_window"),
4500 4502 nil),
... ...
anubis_dev/compiler/src/show.c
... ... @@ -822,9 +822,10 @@ void show_symbol_ambiguity(FILE *fp,
822 822  
823 823 case operation: /* (operation <lc> <opid> <name> <parms> <type> . <types>) */
824 824 opid = integer_value(third(car(interp)));
  825 + show_type(fp,type_from_interpretation(car(interp),cdr(interp)),cdr(interp));
825 826 sprintf(buf,msgtext_file_line[language],string_content(operations[opid].file_name),
826 827 integer_value(operations[opid].line));
827   - fprintf(fp,"%s (%s)\n",string_content(forth(car(interp))),buf);
  828 + fprintf(fp," %s (%s)\n",string_content(forth(car(interp))),buf);
828 829 break;
829 830  
830 831 default: internal_error("not a symbol interpretation",interp);
... ...
anubis_dev/library/examples/paint.anubis
... ... @@ -63,7 +63,7 @@ define (HostWindow hw, HostWindowEvent(One) e) -&gt; List(Rectangle)
63 63 pointer_entering then [],
64 64 pointer_leaving then [],
65 65 key_down(ks,kk) then [],
66   - mouse_move(ks,x,y) then with r = rect(x,y,x+1,y+1),
  66 + mouse_move(ks,x,y) then with r = rect(x,y,x+4,y+2),
67 67 (if mouse_left(ks)
68 68 then paint_rectangle(buffer,r,rgb(255,255,0))
69 69 else unique);
... ... @@ -77,7 +77,7 @@ define (HostWindow hw, HostWindowEvent(One) e) -&gt; List(Rectangle)
77 77  
78 78  
79 79 Finally, here is our program. It first creates the buffer, then opens the host
80   - window. If the host windows has been opened, it must be shown by 'show', otherwise it
  80 + window. If the host window has been opened, it must be shown by 'show', otherwise it
81 81 remains invisible.
82 82  
83 83 global define One
... ...
anubis_dev/library/examples/runge_kutta.anubis
... ... @@ -34,20 +34,29 @@
34 34  
35 35 read tools/maybefloat.anubis
36 36  
  37 +define Maybe(Float) _1 = success(1).
  38 +define Maybe(Float) _2 = success(2).
  39 +define Maybe(Float) _3 = success(3).
  40 +
37 41 define Maybe(Float)
38 42 f
39 43 (
40 44 Maybe(Float) x,
41 45 Maybe(Float) y
42   - ) =
  46 + ) =
  47 + abs(x)^y.
  48 + x+y*y*y.
  49 + x*x + y.
  50 + x*x - y*y.
43 51 x - y*y.
44   - success(1)/y.
  52 + x - y*x*y.
  53 + _3 * ((y*y)^(_1/_3)).
45 54 sin(x*y).
46   - success(3)* ((y*y)^(success(1)/success(3))).
47   -
  55 + success(1)/y.
48 56 sin(y).
49 57  
50 58  
  59 +
51 60  
52 61 The Runge-Kutta method allows the computation of points on the graph of a solution
53 62 starting at some point of this graph. Starting at a point (x_0,y_0) in the domain of
... ...
anubis_dev/library/network/dns.anubis
... ... @@ -284,6 +284,9 @@ global define One
284 284 *** The command line tool.
285 285  
286 286 ---------------------------------------------------------------------------------------
  287 +
  288 +read tools/basis.anubis
  289 +read tools/connections.anubis
287 290  
288 291 //define One debogge(String s) = print(s).
289 292 define One debogge(String s) = unique.
... ...
anubis_dev/library/predefined.anubis
... ... @@ -3999,11 +3999,13 @@ define HostWindowEvent($E)
3999 3999 define List(HostWindowEvent($E))
4000 4000 £get_host_window_events
4001 4001 (
4002   - £StructPtr(HostWindow) handle
  4002 + £StructPtr(HostWindow) handle,
  4003 + Int32 max // maximal number of events to get
4003 4004 ) =
  4005 + if max =< 0 then [] else
4004 4006 if £window_event_pending(handle)
4005 4007 then with first = £get_host_window_event(handle),
4006   - others = £get_host_window_events(handle),
  4008 + others = £get_host_window_events(handle,max-1),
4007 4009 [first . others]
4008 4010 else [ ].
4009 4011  
... ... @@ -4103,7 +4105,7 @@ public define One
4103 4105 (HostWindow,HostWindowEvent($E)) -> List(Rectangle) event_handler,
4104 4106 List(HostWindowEvent($E)) -> List(HostWindowEvent($E)) compress
4105 4107 ) =
4106   - if £handle_host_window_events(compress(£get_host_window_events(£handle(window))),
  4108 + if £handle_host_window_events(compress(£get_host_window_events(£handle(window),200)),
4107 4109 window,paint_method,event_handler)
4108 4110 then unique
4109 4111 else wait_for_event;
... ...
anubis_dev/library/tools/sdbms.anubis
... ... @@ -9,7 +9,7 @@
9 9  
10 10 Author: Alain Prouté
11 11  
12   - Last revision: November 2005.
  12 + Last revision: January 2005.
13 13  
14 14  
15 15  
... ... @@ -17,27 +17,17 @@
17 17 ----------------------------------- Contents ------------------------------------------
18 18  
19 19 *** (1) Overview.
20   - *** (2) Data base and table structure.
21   - *** (2.1) Tables.
22   - *** (2.2) Data bases.
23   - *** (2.3) Initializing a data base and its tables.
24   - *** (2.4) Handling changes in table formats.
25   - *** (2.5) Row identifiers.
26   - *** (3) Using the data base.
27   - *** (3.1) Errors.
28   - *** (3.2) Adding rows to a table.
29   - *** (3.3) Getting rows from a table.
30   - *** (3.4) Testing a number of rows.
31   - *** (3.5) Updating rows in a table.
32   - *** (3.6) Deleting rows from a table.
33   - *** (3.7) Multi-tables queries.
34   - *** (4) Indexing.
35   - *** (4.1) Principles of indexing.
36   - *** (4.2) Main indexing.
37   - *** (4.3) Families of tables.
38   - *** (4.4) Secondary indexing.
39   - *** (4.5) Handling changes of your indexing methods.
40   - *** (5) Using it with 'web/making_a_web_site.anubis'.
  20 + *** (2) Errors.
  21 + *** (3) Tables and data bases.
  22 + *** (4) Managing changes in table formats.
  23 + *** (5) Row identifiers.
  24 + *** (6) Adding rows to a table.
  25 + *** (7) Getting rows from a table.
  26 + *** (8) Testing a number of rows.
  27 + *** (9) Updating rows in a table.
  28 + *** (10) Deleting rows from a table.
  29 + *** (11) Multi-tables queries.
  30 + *** (12) Using it with 'web/making_a_web_site.anubis'.
41 31  
42 32 ---------------------------------------------------------------------------------------
43 33  
... ... @@ -53,8 +43,8 @@
53 43  
54 44 - restructuring commands, like adding columns in a table, deleting columns, etc...
55 45  
56   - Normally, if a data base is restructured, programs using that database must themself be
57   - restructured, while the transformation of the data base by utilization commands does
  46 + Normally, if a data base is restructured, programs using that database must themselves
  47 + be restructured, while the transformation of the data base by utilization commands does
58 48 not require any modification of the programs which are using the data base.
59 49  
60 50 Our aim is to provide a data base mecanism, which is as much as possible in the spirit
... ... @@ -73,39 +63,48 @@
73 63 because it puts de facto at different levels aspects of data base management which are
74 64 otherwise consider of the same kind.
75 65  
76   -
77 66  
78 67  
79   - *** (2) Data base and table structure.
  68 +
  69 + *** (2) Errors.
  70 +
  71 + Errors may occur during the normal management of the data base.
  72 +
  73 +public type DBError:
  74 + file_not_found (String path),
  75 + file_reading_problem (String path),
  76 + file_type_problem (String path),
  77 + cannot_open_file (String path),
  78 + cannot_write_file (String path),
  79 + record_not_found.
  80 +
  81 +
  82 +
  83 +
80 84  
81 85  
82   - *** (2.1) Tables.
  86 + *** (3) Tables and data bases.
83 87  
84 88 The type of the rows of a table is up to you (but must be serializable). However, this
85 89 data base management system includes a mecanism for handling the possible changes in
86 90 the definition of the types of the rows of a table, in such a way that updating the
87 91 actual tables files on the disk is automatic. For this reason, the type scheme
88   - 'DBTable($Row,$HRow)' representing tables has two type parameters. The first one
89   - represents the current type of the rows of the table, the second one represents the
90   - history of all successive types of the rows of the table. With this mecanism, and if
91   - you repects some principles explained below, your program will always be able to read
92   - old tables saved in old formats. When tables are written to disk, they are always
93   - written in the most recent format.
94   -
95   - So, tables are represented by the following opaque type scheme, where the parameter
96   - '$Row' is the current type of the rows of the table, and '$HRow' ('H' like 'History')
97   - is a type containing the history of all successive formats of rows in the table:
  92 + 'DBTable' representing tables has two type parameters. The first one represents the
  93 + current type of the rows of the table, the second one represents the history of all
  94 + successive types of the rows of the table. With this mecanism, and if you repects some
  95 + principles explained below, your program will always be able to read old tables saved
  96 + in old formats.
  97 +
  98 + Tables are represented by the following opaque type scheme, where the parameter '$Row'
  99 + is the current type of the rows of the table, and '$HRow' ('H' like 'History') is a
  100 + type containing the history of all the successive formats of rows in the table:
98 101  
99 102 public type DBTable($Row,$HRow):...
100 103  
101   -
102   -
103   - *** (2.2) Data bases.
104   -
105 104 The first thing you have to do if you want to use this data base management system, is
106   - to define the type of your data base (you may have several of them). Since a data base
107   - is essentially a set of tables, the type of your data base should be something like
108   - this (at the beginning, you can use the same type for '$Row' and '$HRow'):
  105 + to define the type of your data base. Since a data base is essentially a set of
  106 + tables, the type of your data base should be something like this (at the beginning, you
  107 + can use the same type for '$Row' and '$HRow'):
109 108  
110 109 type MY_DB:
111 110 my_db(DBTable(Client,Client) clients,
... ... @@ -128,12 +127,7 @@ public type DBTable($Row,$HRow):...
128 127 public type DB($MY_DB):... (again an opaque type scheme)
129 128  
130 129 where the parameter '$MY_DB' may be instantiated to your type 'MY_DB'. Several
131   - instantiations allow the creation of several data bases (in general of different
132   - types).
133   -
134   -
135   -
136   - *** (2.3) Initializing a data base and its tables.
  130 + instantiations allow the creation of several data bases.
137 131  
138 132 Now, when you start your program (may be a web site), you need to start the data base
139 133 manager. This amounts to initialize each table, and use the initialized tables to
... ... @@ -145,7 +139,7 @@ public type DB($MY_DB):... (again an opaque type scheme)
145 139 init_dbtable ("suppliers", compare, identity, identity),
146 140 ...)),
147 141  
148   - where 'init_db' is:
  142 + where 'init_db' is declared as:
149 143  
150 144 public define DB($MY_DB)
151 145 init_db
... ... @@ -154,7 +148,7 @@ public define DB($MY_DB)
154 148 $MY_DB tables
155 149 ).
156 150  
157   - and where 'init_dbtable' is:
  151 + and where 'init_dbtable' is declared as:
158 152  
159 153 public define DBTable($Row,$HRow)
160 154 init_dbtable
... ... @@ -167,9 +161,9 @@ public define DBTable($Row,$HRow)
167 161  
168 162 Notice that the name 'table_name' above becomes part of the names of the files
169 163 containing the tables (located in the directory 'data_base_directory' above).
170   - 'init_dbtable' does not load the table from the disk. A table is loaded only when
  164 + 'init_table' does not load the table from the disk. A table is loaded only when
171 165 needed. If the table does not exist on the disk, 'init_table' creates an empty table
172   - of the right type. 'init_dbtable' should be executed only once per table, when your
  166 + of the right type. 'init_table' should be executed only once per table, when your
173 167 program starts.
174 168  
175 169 The 'compare' function is used for sorting the rows of the table. The table is sorted
... ... @@ -182,7 +176,7 @@ public define DBTable($Row,$HRow)
182 176 ordering the table. You can always reorder the result of 'get_rows' for any purpose.
183 177  
184 178 The 'update' and 'store' functions are used for automating the changes of format of the
185   - tables. This is explained below in the section 'Handling changes in table formats'. At
  179 + tables. This is explained below in the section 'Managing changes in table formats'. At
186 180 the beginning, while the two types '$Row' and '$HRow' are identical, you can use the
187 181 function 'identity' (actually a scheme of function, defined in 'tools/basis.anubis')
188 182 for both 'update' and 'store'.
... ... @@ -194,39 +188,11 @@ public define DBTable($Row,$HRow)
194 188 dynamically typed) data base system. Of course, you can use several such data bases in
195 189 a program.
196 190  
197   - For security reasons, you may want to protect some informations in a table so that this
198   - information cannot be modified. For example, in a 'products' table the reference of the
199   - product should perhaps not be modified. In order to ensure this, you just have to
200   - provide one more argument to 'init_dbtable':
201   -
202   -public define DBTable($Row,$HRow)
203   - init_dbtable
204   - (
205   - String table_name,
206   - ($Row,$Row) -> Bool compare,
207   - $HRow -> $Row update,
208   - $Row -> $HRow store,
209   - $Row -> $L locked
210   - ).
211 191  
212   - The new argument 'locked' is of type '$Row -> $L' where $L is any serializable
213   - type. When the system is on the point to update a row in a table it first checks if
214   - 'locked(r1) = locked(r2)', where 'r1' and 'r2' are the previous and new values of the
215   - row. If this check fails the row is not updated.
216 192  
217   - For example, for initializing your table of products, locking the two fields 'supplier'
218   - and 'name', you just have to provide a function of type:
219 193  
220   - Product -> (String,String)
221 194  
222   - extracting the supplier name and product name from the row.
223   -
224   -
225   -
226   -
227   -
228   -
229   - *** (2.4) Handling changes in table formats.
  195 + *** (4) Managing changes in table formats.
230 196  
231 197 Up to here the types used as instantiations of '$Row' and '$HRow' are the same one.
232 198 That's OK, and you have begun to distribute your program and your users have created
... ... @@ -275,7 +241,7 @@ public define DBTable($Row,$HRow)
275 241 String address),
276 242 version_2(String name,
277 243 String address,
278   - Int32 age).
  244 + Int32 age).
279 245  
280 246 Important notice: When a change intervenes in the type of rows of the table, the
281 247 alternative representing the new type of rows must be added at the end of the type
... ... @@ -319,7 +285,7 @@ public define DBTable($Row,$HRow)
319 285 Of course, in the case of a row in the old format (version_1), we need a default value
320 286 for the age. We have chosen 0 in the example, but you may choose anything. In any
321 287 traditional data base system, when you add a column to a table, you need to fill this
322   - column with a default value, even if this default value is 'NULL'.
  288 + column with a default value, even if this default value is 'NULL' (not filled at all).
323 289  
324 290 The other function does not require default values in principle, because it is mainly a
325 291 conversion between the current version and the latest one (i.e. essentially the same
... ... @@ -336,12 +302,12 @@ public define DBTable($Row,$HRow)
336 302 The type used for storing the data on the disk is always 'HClient' (hence the name of
337 303 the function 'store'), and according to the above function they are stored as
338 304 'version_2(...)'. The type 'Client' is used only internally. This is required for
339   - being able to handle file containing different versions of the tables.
  305 + being able of handling file containing different versions of the tables.
340 306  
341 307  
342 308  
343 309  
344   - *** (2.5) Row identifiers.
  310 + *** (5) Row identifiers.
345 311  
346 312 The system generates an identifier for each newly created row in a table. It is
347 313 warranted that not two rows in the same table can have the same row identifier. Row
... ... @@ -354,8 +320,8 @@ public type DBRowId($Row):...
354 320 between tables.
355 321  
356 322 The type scheme 'DBRowId' should be considered as absolutely opaque. The author
357   - reserves the possibility of modifying the definition this type in the future. Hence,
358   - use only the public interface for manipulating data of this type.
  323 + reserves the possibility of modifying this type in the future. Hence, use only the
  324 + public interface for manipulating data of this type.
359 325  
360 326 It would have been possible to define the type 'DBRowId' without the parameter, but in
361 327 this case, identifiers corresponding to tables of different types could not be
... ... @@ -366,27 +332,8 @@ public type DBRowId($Row):...
366 332  
367 333  
368 334  
369   -
370   -
371   -
372   - *** (3) Using the data base.
373   -
374   - *** (3.1) Errors.
375   -
376   - Errors may occur during the normal management of the data base.
377   -
378   -public type DBError:
379   - file_not_found (String path),
380   - file_reading_problem (String path),
381   - file_type_problem (String path),
382   - cannot_open_file (String path),
383   - cannot_write_file (String path),
384   - record_not_found.
385   -
386   -
387   -
388 335  
389   - *** (3.2) Adding rows to a table.
  336 + *** (6) Adding rows to a table.
390 337  
391 338 Adding rows to a table is performed by the following function:
392 339  
... ... @@ -398,9 +345,6 @@ public define Result(DBError,List(DBRowId($Row)))
398 345 List($Row) new_rows
399 346 ).
400 347  
401   - Notice that the argument 'the_table' above is supposed to be an implicit destructor of
402   - the type which instantiates '$MY_DB'. This is why it is a function.
403   -
404 348 For example, you may write:
405 349  
406 350 add_rows(my_data_base,clients,[row1,row2,row3])
... ... @@ -421,19 +365,19 @@ public define Result(DBError,DBRowId($Row))
421 365  
422 366  
423 367  
424   - *** (3.3) Getting rows from a table.
  368 + *** (7) Getting rows from a table.
425 369  
426 370 In order to get rows from a table, you have two methods:
427 371  
428 372 (1) you know the row identifiers of the rows you want,
429   - (2) you want to get all the rows satisfying some condition.
  373 + (2) you want to get all rows satisfying some condition.
430 374  
431 375 You get rows in the form of:
432 376  
433 377 public type DBRow($Row):
434 378 dbrow(DBRowId($Row) row_id,
435 379 Int32 version,
436   - $Row row).
  380 + $Row row).
437 381  
438 382 A datum of type DBRow($Row) contains the identifier of the row, a version number and
439 383 the row itself. The version number is 0 when the row is created (by 'add_row' or
... ... @@ -448,9 +392,8 @@ public define Result(DBError,DBRow($Row))
448 392 DBRowId($Row) row_id
449 393 ).
450 394  
451   - If no error occurs, the function returns the row whose row identifier is given. The
452   - next one can be used for getting several rows by their row identifiers. With the
453   - variant below you can get several rows in one operation.
  395 + If no error occurs, the function returns the wanted row. The next one can be used for
  396 + getting several rows.
454 397  
455 398 public define Result(DBError,List(DBRow($Row)))
456 399 get_rows
... ... @@ -460,9 +403,6 @@ public define Result(DBError,List(DBRow($Row)))
460 403 List(DBRowId($Row)) row_ids
461 404 ).
462 405  
463   - Now, if you prefer to use a condition instead of a list of row identifiers, use this
464   - one:
465   -
466 406 public define Result(DBError,List(DBRow($Row)))
467 407 get_rows
468 408 (
... ... @@ -488,7 +428,7 @@ public define Result(DBError,List(DBRow($Row)))
488 428  
489 429  
490 430  
491   - *** (3.4) Testing a number of rows.
  431 + *** (8) Testing a number of rows.
492 432  
493 433 It may be useful to get the number of rows satisfying some condition in a table. It may
494 434 also be useful to know if a table contains more rows satisfying a condition than a
... ... @@ -524,7 +464,7 @@ public define Result(DBError,Bool)
524 464  
525 465  
526 466  
527   - *** (3.5) Updating rows in a table.
  467 + *** (9) Updating rows in a table.
528 468  
529 469 Updating rows in a table is generally the consequence of a previous reading of these
530 470 rows. Indeed, interactive programs will first show the row to be updated to a human
... ... @@ -595,7 +535,7 @@ public define Result(DBError,List(DBUpdateResult($Row)))
595 535  
596 536  
597 537  
598   - *** (3.6) Deleting rows from a table.
  538 + *** (10) Deleting rows from a table.
599 539  
600 540 public define Result(DBError,$Row)
601 541 delete_row
... ... @@ -625,7 +565,7 @@ public define Result(DBError,List($Row))
625 565  
626 566  
627 567  
628   - *** (3.7) Multi-tables queries.
  568 + *** (11) Multi-tables queries.
629 569  
630 570 The SQL language has an important feature which is the 'SELECT' command. We need
631 571 something analogous to the SQL query:
... ... @@ -656,7 +596,7 @@ public define Result(DBError,List($Row))
656 596 (essentially the security provided by the strong typing mecanism), and the flexibility
657 597 of usual data bases could be realized only with a more elaborate version of Anubis,
658 598 including meta-programming, and maybe another virtual machine able to optimize on the
659   - fly. All these new features are part of the Anubis2 project.
  599 + fly. All these new features are part of the Anubis2/Paradize project.
660 600  
661 601 For the time being, we content ourself with the following recursive querying
662 602 mecanism. Actually, the recursion is on the number of tables concerned by the query.
... ... @@ -700,285 +640,68 @@ public define List($Out)
700 640 named "Yoyo". Here is the query (which returns a list of type 'List(String)'):
701 641  
702 642 query(my_data_base,
703   - clients, // begin with the table 'clients'
704   - (DBRow(Client) clt) |-> country(row(clt)) = "France", // consider only French clients
705   - (DBRow(Client) clt, One u) |-> name(row(clt)), // keep only the name of the client
706   - (DBRow(Client) clt) |-> // the subquery for this client 'clt'
707   - query(my_data_base,
708   - commands, // continue with the table 'commands'
709   - (DBRow(Command) cmd) |-> row_id(clt) = client_id(row(cmd)),
710   - (DBRow(Command) cmd, One u) |-> u, // do not keep anything from 'commands'
711   - (DBRow(Command) cmd) |->
712   - query(my_data_base,
713   - products,
714   - (DBRow(Product) prd) |-> row_id(prd) = product_id(cmd) &
715   - name(row(prd)) = "Yoyo",
716   - (DBRow(Product) prd, One u) |-> u,
717   - (DBRow(Product) prd) |-> unique)))
718   -
719   - This is actually not more complicated than:
  643 + clients, // begin with the table 'clients'
  644 + (DBRow(Client) clt) |-> // consider only French clients
  645 + country(row(clt)) = "France",
  646 + (DBRow(Client) clt, One u) |-> // keep only the name of the client
  647 + name(row(clt)),
  648 + (DBRow(Client) clt) |-> // the subquery for this client 'clt'
  649 + query(my_data_base,
  650 + commands, // continue with the table 'commands'
  651 + (DBRow(Command) cmd) |->
  652 + row_id(clt) = client_id(row(cmd)),
  653 + (DBRow(Command) cmd, One u) |-> u, // do not keep anything from 'commands'
  654 + (DBRow(Command) cmd) |->
  655 + query(my_data_base,
  656 + products,
  657 + (DBRow(Product) prd) |->
  658 + row_id(prd) = product_id(cmd) &
  659 + name(row(prd)) = "Yoyo",
  660 + (DBRow(Product) prd, One u) |-> u,
  661 + (DBRow(Product) prd) |-> unique)))
  662 +
  663 + Of course, this is more complicated than:
720 664  
721 665 SELECT clients.name
722 666 FROM clients, commands_2005, products
723 667 WHERE clients.id = commands_2005.client_id AND
724 668 commands_2005.product_id = products.id AND
725   - products.name = "Yoyo" AND
726   - client.country = "France"
  669 + products.name = "Yoyo"
727 670  
728   - just a little heavier to write down, but meta-programming could automatically transform
729   - the later into the former (in the future).
  671 + but meta-programming could automatically transform the later into the former (in the
  672 + future).
730 673  
731 674 Now, the query may also be more efficient (computed faster) if the tables are put in a
732   - different order.
733   -
734   -
735   -
736   -
737   -
738   -
739   -
740   -
741   -
742   - *** (4) Indexing.
743   -
744   - In order to speed up the access to the data, especially when dealing with big tables,
745   - and also to optimize memory usage, you may need an indexing system.
746   -
747   -
748   -
749   - *** (4.1) Principles of indexing.
750   -
751   - An index is some way of reaching rows of a table more quickly than by just having a
752   - look at all rows until the wanted rows are found. This is similar to a dictionary. When
753   - you are looking for a word in a dictionary, you don't start at the beginning and check
754   - all words until you find yours. You have some more efficient process.
755   -
756   - Notice however that this process is specific to the method used for selecting items
757   - from the dictionary. In this case, the items you want to find are selected 'by
758   - name'. Since items in the dictionary are ordered by name, the search may be performed
759   - quickly. However, what about finding all words, the definition of which contains the
760   - word 'dog' ? This is much more difficult, and requires a priori a complete search item
761   - by item.
762   -
763   - In order to solve this problem, the dictionary could have an 'index' (in general it
764   - does not have one), within which you should easily find the word 'dog', and get a list
765   - of pages or item numbers or item names whose definition contains the word 'dog'. You
766   - may also want to find all words of containing the string 'gap' in their name. In this
767   - case, you need yet another kind of index.
768   -
769   - From this dictionary story, we should remember two things:
770   -
771   - 1. The dictionary is ordered in such a way that finding an item 'by name' is easy,
772   - 2. If we want to find items according to other criteria, we need an extra index
773   - (maybe one for each criterium).
774   -
775   - The way the dictionary is ordered could be called the 'main indexing'. Each extra
776   - index may be calld a 'secondary indexing'. The same principles apply to data bases,
777   - except that instead of ordering items by alphabetical order we use 'hashing methods'.
778   -
779   -
780   - *** (4.2) Main indexing.
781   -
782   - Given a table in your data base, you may ignore indexing or decide some 'main' way of
783   - indexing the table. We begin by an example. Consider the 'clients' table. Each client
784   - has a name, and several other data attached to him. In general, when you are looking
785   - for a client, you got the name of that client (alternatively you may have a 'client
786   - number'). Hence searching a client is most often performed 'by name'. So, you may
787   - decide that the main indexing of the 'clients' table should speed up the search 'by
788   - name'. In that case the 'search criterion' will be represented by the function mapping
789   - a row of the table to the 'name' field. This function may be for example the implicit
790   - destructor 'name', which is of type:
791   -
792   - Client -> String
793   -
794   - In order to take this 'main indexing' into account, use the following variant of
795   - 'init_dbtable', for initializing your table:
796   -
797   -public define DBTable($Row,$HRow)
798   - init_dbtable
799   - (
800   - String table_name,
801   - ($Row,$Row) -> Bool compare,
802   - $HRow -> $Row update,
803   - $Row -> $HRow store,
804   - $Row -> $L locked,
805   - $Row -> $N main_search_criterion
806   - ).
807   -
808   - Actually, you have a big freedom in choosing the type '$N'. The only constraint is that
809   - it must be serializable.
810   -
811   - Now, when you want to get rows from that table using this main indexing, you have to
812   - use variants 'get_rows'. Indeed, instead of giving row identifiers or search
813   - criterions, you give a datum of type 'DBIndexVal($N)'. Notice that unlike the search by
814   - row identifiers, the search by index may produce several rows for the same index
815   - value. Hence, 'get_row' is not concerned by indexing. Only 'get_rows' (and similarly
816   - 'update_rows' and 'delete_rows') is concerned.
817   -
818   -
819   -public type DBIndexVal($Row,$N):... (an opaque type)
820   -
821   -public define Result(DBError,List(DBRow($Row)))
822   - get_rows
823   - (
824   - DB($MY_DB) the_data_base,
825   - $MY_DB -> DBTable($Row,$HRow) the_table,
826   - DBIndexVal($Row,$N) main_index_value
827   - ).
828   -
829   -
830   - The same principles apply to other utilization functions:
831   -
832   -public define Result(DBError,Int32)
833   - get_number_of_rows
834   - (
835   - DB($MY_DB) the_data_base,
836   - $MY_DB -> DBTable($Row,$HRow) the_table,
837   - DBIndexVal($Row,$N) main_index_value
838   - ).
839   -
840   -public define Result(DBError,Bool)
841   - has_more_rows_than
842   - (
843   - DB($MY_DB) the_data_base,
844   - $MY_DB -> DBTable($Row,$HRow) the_table,
845   - DBIndexVal($Row,$N) main_index_value,
846   - Int32 n
847   - ).
848   -
849   -public define Result(DBError,List(DBUpdateResult($Row)))
850   - update_rows
851   - (
852   - DB($MY_DB) the_data_base,
853   - $MY_DB -> DBTable($Row,$HRow) the_table,
854   - DBIndexVal($Row,$N) main_index_value,
855   - DBRow($Row) -> Maybe($Row) how
856   - ).
857   -
858   -public define Result(DBError,$Row)
859   - delete_rows
860   - (
861   - DB($MY_DB) the_data_base,
862   - $MY_DB -> DBTable($Row,$HRow) the_table,
863   - DBIndexVal($Row,$N) main_index_value
864   - ).
865   -
  675 + different order. For example, we may consider the following equivalent query (with the
  676 + tables in reverse order):
866 677  
  678 + query(my_data_base,
  679 + products,
  680 + (DBRow(Product) prd) |-> name(row(prd)) = "Yoyo",
  681 + (DBRow(Product) prd, String cltname) |-> cltname,
  682 + (DBRow(Product) prd) |->
  683 + query(my_data_base,
  684 + commands,
  685 + (DBRow(Command) cmd) |->
  686 + row_id(prd) = product_id(row(cmd)),
  687 + (DBRow(Command) cmd, String cltname) |-> cltname,
  688 + (DBRow(Command) cmd) |->
  689 + query(my_data_base,
  690 + clients,
  691 + (DBRow(Client) clt) |->
  692 + country(row(clt)) = "France" &
  693 + row_id(clt) = client_id(row(cmd)),
  694 + (DBRow(Client) clt, One u) |-> name(row(clt)),
  695 + (DBRow(Client) clt) |-> unique)))
  696 +
  697 + This one may be more efficient than the first one. The order into which the tables are
  698 + looked up may be important for performances.
867 699  
868 700  
869   - *** (4.3) Families of tables.
870 701  
871   - It may be the case that you prefer to use a family of small tables (of the same type)
872   - instead of a big unique table. For example, if you are managing products in a shop, you
873   - may have a very big number of products, each one with many informations, and want (say)
874   - one table by product.
875   -
876   - Actually, this is just a matter of performances and memory management. The only thing
877   - you have to do in order to split your big table into a lot of small tables is just to
878   - have a main index. The table will be automatically split into a familly of smaller
879   - tables. The number of these tables may change during exploitation of your table,
880   - depending on the number of rows. In any case, it is automatic.
881   -
882   - Nevertheless, the type '$N' of main index values must be such that rows are
883   - sufficiently separated from each other. At the limit, if you choose 'One' for this
884   - type, all rows will have the same index value, and the system will not be able to
885   - create more than one file for the whole table. So, 'One' is a very bad choice. In
886   - practice, for a table of products, the name of the product, or the supplier reference
887   - for that product should provide a good main indexation, which will allow the system to
888   - split the table into almost as many files as there are possible values for this index.
889   -
890   -
891   -
892   - *** (4.4) Secondary indexing.
893   -
894   - Now, you may also have to perform searches according to several criteria in a given
895   - table. Hence, you may need 'secondary' indexing methods.
896   -
897   - Secondary indexes are not part of the table (unlike main indexing, they have no
898   - influence on how the table is implemented). Hence, secondary indexes must be
899   - initialized by themself. Secondary indexes for a table whose row type is '$Row' are
900   - data of the following type:
901   -
902   -public type DBSecondaryIndex($Row,$S):... (an opaque type)
903   -
904   -
905   - A secondary index is initialized by:
906   -
907   -public define DBSecondaryIndex($Row,$S)
908   - init_dbindex
909   - (
910   - String index_name, // used as part of a file name
911   - DB($MY_DB) the_data_base,
912   - $MY_DB -> DBTable($Row,$HRow) the_table,
913   - $Row -> $S secondary_search_criterion
914   - ).
915   -
916   - As for tables, the initialization of an index must be performed only once when your
917   - program starts.
918   -
919   - Now, you also need variants of 'get_rows', etc... for searching according to secondary
920   - indexing. Here they are.
921   -
922   -public define Result(DBError,List(DBRow($Row)))
923   - get_rows
924   - (
925   - DB($MY_DB) the_data_base,
926   - $MY_DB -> DBTable($Row,$HRow) the_table,
927   - DBSecondaryIndex($Row,$S) index,
928   - DBIndexVal($Row,$S) secondary_index_value
929   - ).
930   -
931   -public define Result(DBError,Int32)
932   - get_number_of_rows
933   - (
934   - DB($MY_DB) the_data_base,
935   - $MY_DB -> DBTable($Row,$HRow) the_table,
936   - DBSecondaryIndex($Row,$S) index,
937   - DBIndexVal($Row,$S) secondary_index_value
938   - ).
939   -
940   -public define Result(DBError,Bool)
941   - has_more_rows_than
942   - (
943   - DB($MY_DB) the_data_base,
944   - $MY_DB -> DBTable($Row,$HRow) the_table,
945   - DBSecondaryIndex($Row,$S) index,
946   - DBIndexVal($Row,$S) secondary_index_value,
947   - Int32 n
948   - ).
949   -
950   -public define Result(DBError,List(DBUpdateResult($Row)))
951   - update_rows
952   - (
953   - DB($MY_DB) the_data_base,
954   - $MY_DB -> DBTable($Row,$HRow) the_table,
955   - DBSecondaryIndex($Row,$S) index,
956   - DBIndexVal($Row,$S) secondary_index_value,
957   - DBRow($Row) -> Maybe($Row) how
958   - ).
959   -
960   -public define Result(DBError,$Row)
961   - delete_rows
962   - (
963   - DB($MY_DB) the_data_base,
964   - $MY_DB -> DBTable($Row,$HRow) the_table,
965   - DBSecondaryIndex($Row,$S) index,
966   - DBIndexVal($Row,$S) secondary_index_value
967   - ).
968   -
969   -
970   -
971   -
972   -
973   -
974   - *** (4.5) Handling changes of your indexing methods.
975   -
976   -
977   -
978   -
979 702  
980 703  
981   - *** (5) Using it with 'web/making_a_web_site.anubis'.
  704 + *** (12) Using it with 'web/making_a_web_site.anubis'.
982 705  
983 706 You may want to use this data base manager in conjunction with our web site making
984 707 method. You should proceed as follows in order to start the data base and the web
... ... @@ -1066,204 +789,33 @@ public define Result(DBError,$Row)
1066 789 --- That's all for the public part ! --------------------------------------------------
1067 790  
1068 791  
1069   - ----------------------------------- Contents ------------------------------------------
1070   -
1071   - *** [1] Opaque types.
1072   - *** [1.1] Row identifiers.
1073   - *** [1.2] Tables.
1074   - *** [1.2.1] Type 1 (simple tables).
1075   - *** [1.2.2] Type 2 (hash-split tables).
1076   - *** [1.3] All tables.
1077   - *** [1.4] Data bases.
1078   - *** [1.5] Indexing.
1079   -
1080   - *** [2] Tools.
1081   - *** [2.1] Comparing rows.
1082   - *** [2.2] Removing an element from a list.
1083   - *** [2.3] Inserting elements in a sorted list.
1084   - *** [2.4] Removing repeated elements from a list.
1085   - *** [2.5] Flattening a list of lists.
1086   -
1087   - *** [3] Loading and saving table chunks.
1088   - *** [3.1] Loading a table chunk.
1089   - *** [3.1.1] Type 1 tables.
1090   - *** [3.1.2] Type 2 tables.
1091   - *** [3.2] Saving a table chunk.
1092   - *** [3.2.1] Type 1 tables.
1093   - *** [3.2.2] Type 2 tables.
1094   -
1095   - *** [4] Initializing a data base.
1096   -
1097   - *** [5] Utilization commands.
1098   - *** [5.1] Accessing a table.
1099   - *** [5.1.1] Type 1 tables.
1100   - *** [5.1.2] Type 2 tables.
1101   - *** [5.2] Adding rows to a table.
1102   - *** [5.2.1] Type 1 tables.
1103   - *** [5.2.2] Type 2 tables.
1104   - *** [5.3] Getting rows from a table.
1105   - *** [5.3.1] Type 1 tables.
1106   - *** [5.3.2] Type 2 tables.
1107   - *** [5.4] Getting a number of rows.
1108   - *** [5.4.1] Type 1 tables.
1109   - *** [5.4.2] Type 2 tables.
1110   - *** [5.5] Updating rows.
1111   - *** [5.5.1] Type 1 tables.
1112   - *** [5.5.2] Type 2 tables.
1113   - *** [5.6] Deleting rows.
1114   - *** [5.6.1] Type 1 tables.
1115   - *** [5.6.2] Type 2 tables.
1116   - *** [5.7] Multi-tables queries.
1117   -
1118   - *** [6] Indexing.
1119   -
1120   - ---------------------------------------------------------------------------------------
1121   -
1122   -read tools/basis.anubis required for 'qsort'
1123   -read tools/hashtable.anubis because hashtables are better than lists for performances
1124   -
1125   -
1126   -
1127   -
1128   - *** [1] Opaque types.
1129   -
1130   -
1131   - *** [1.1] Row identifiers.
1132   -
1133 792 Row identifiers are just integers, but this may change in the future, because integers
1134 793 may not be enough.
1135 794  
1136 795 public type DBRowId($Row):
1137 796 dbrowid(Int32 index).
1138 797  
1139   -
1140   -
1141   -
1142   - *** [1.2] Tables.
1143   -
1144   - There are several types of tables (different implementations in memory and on disk). A
1145   - type 1 table is saved into a single file. A type 2 table is split into chunks and each
1146   - chunk is saved into a separate file.
1147   -
1148   - Tables or table chunks are loaded into memory only on demand. During the loading the
1149   - format is changed to some format appropriate for the memory.
1150   -
1151   -
1152   - *** [1.2.1] Type 1 (simple tables).
1153   -
1154   - Type 1 (simple tables) is good for small tables (tables with very few rows). The table
1155   - is saved into a single file. It is loaded only on demand.
1156   -
1157 798 When a table is loaded, a boolean variable 'changed' indicates if it has to be saved. A
1158 799 integer variable contains the counter for creating identifiers for new rows. Another
1159 800 variable contains the list of all loaded rows.
1160 801  
1161   -type DBLoadedTable1($Row,$HRow):
  802 +type DBLoadedTable($Row,$HRow):
1162 803 table(String table_name,
1163 804 (DBRow($Row),DBRow($Row)) -> Bool compare,
1164 805 $Row -> $HRow store,
1165 806 Var(Bool) changed_v,
1166 807 Var(Int32) counter_v,
1167 808 Var(List(DBRow($Row))) rows_v).
1168   -
1169   - Now, tables in the data base are either loaded or not.
1170   -
1171   -type DBTableState1($Row,$HRow):
1172   - not_loaded (String table_name,
1173   - ($Row,$Row) -> Bool compare,
1174   - $HRow -> $Row update,
1175   - $Row -> $HRow store),
1176   - loaded (DBLoadedTable1($Row,$HRow)).
1177   -
1178   - Now a table is just a variable containing either a non loaded table or a loaded table.
1179   -
1180   -
1181   -
1182   -
1183   -
1184   -
1185   -
1186   -
1187   - *** [1.2.2] Type 2 (hash-split tables).
1188   -
1189   - split_table(String table_name,
1190   - (DBRow($Row),DBRow($Row)) -> Bool compare,
1191   - Var(Bool) changed_v,
1192   - Var(Int32) counter_v,
1193   - HashTable(Int32,List(DBRow($Row))) rows).
1194   -
1195   -
1196 809  
  810 + Of course, tables are not saved on disk as 'DBLoadedTable($Row,$HRow)' because variable
  811 + types (and functional types for the time being) are not serializable, and also because
  812 + data of type '$Row' are not saved on the disk. Tables are saved as data of type
  813 + 'DBSavedTable($HRow)'.
1197 814  
  815 +type DBSavedTable($HRow):
  816 + myversion_1(Int32 counter,
  817 + List(DBRow($HRow)) rows).
1198 818  
1199   - *** [1.3] Table file formats.
1200   -
1201   - Of course, tables are not saved on disk as 'DBLoadedTable1($Row,$HRow)' because
1202   - variable types (and functional types for the time being) are not serializable, and also
1203   - because data of type '$Row' are not saved on the disk. Tables are saved as data of
1204   - type 'TableFileContent($HRow)'.
1205   -
1206   -type TableFileContent($HRow):
1207   - type_1(Int32 counter,
1208   - List(DBRow($HRow)) rows).
1209   -
1210   -
1211   -
1212   -
1213   -
1214   - *** [1.3] All tables.
1215   -
1216   -public type DBTable($Row,$HRow):
1217   - db_table_1(Var(DBTableState1($Row,$HRow))).
1218   - db_table_2(Var(DBTableState2($Row,$HRow))).
1219   -
1220   -
1221   -
1222   - *** [1.4] Data bases.
1223   -
1224   - The data base itself is made of the directory path for table files, and the set of
1225   - tables (loaded or not).
1226   -
1227   -public type DB($MY_DB):
1228   - db(String directory,
1229   - $MY_DB tables).
1230   -
1231   -
1232   -
1233   -
1234   -
1235   - *** [1.5] Indexing.
1236   -
1237   -public type DBIndexVal($Row,$N):
1238   - index_val($N).
1239   -
1240   -
1241   -type DBLoadedIndex($Row,$S):
1242   - index(String index_name,
1243   - String directory_name,
1244   - Var(Bool) changed_v,
1245   - Var(HashTable(Int32,List(Int32))) entries).
1246   -
1247   -type IndexState($Row,$S):
1248   - not_loaded(String index_name,
1249   - String directory_name,
1250   - $Row -> $S secondary_search_criterion),
1251   - loaded(DBLoadedIndex($Row,$S)).
1252   -
1253   -public type DBSecondaryIndex($Row,$N):
1254   - secondary_index(Var(IndexState($Row,$N))).
1255   -
1256   -
1257   -
1258   -
1259   -
1260   -
1261   -
1262   - *** [2] Tools.
1263   -
1264   -
1265   -
1266   - *** [2.1] Comparing rows.
1267 819  
1268 820 We will have to compare the rows of a loaded table. The function able to compare loaded
1269 821 rows must be constructed from the function comparing nude rows. This is the job of the
... ... @@ -1279,116 +831,23 @@ define (DBRow($Row),DBRow($Row)) -&gt; Bool
1279 831 if dbr2 is dbrow(id2,v2,r2) then
1280 832 compare(r1,r2).
1281 833  
1282   -
1283   -
1284   -
1285   - *** [2.2] Removing an element from a list.
1286   -
1287   -define List($T)
1288   - remove
1289   - (
1290   - $T x,
1291   - List($T) l
1292   - ) =
1293   - if l is
1294   - {
1295   - [ ] then [ ],
1296   - [h . t] then
1297   - if x = h
1298   - then t
1299   - else [h . remove(x,t)]
1300   - }.
1301   -
1302   -
1303   -
1304   -
1305   - *** [2.3] Inserting elements in a sorted list.
1306   -
1307   - The next function receives two lists (of the same type) which are both already sorted.
1308   - It inserts the elements of the first list at the right place in the second list.
1309   -
1310   -define List($T)
1311   - insert // insert elements of l1 into l2
1312   - (
1313   - List($T) l1,
1314   - List($T) l2,
1315   - ($T,$T) -> Bool less
1316   - ) =
1317   - if l1 is
1318   - {
1319   - [ ] then l2,
1320   - [h1 . t1] then
1321   - if l2 is
1322   - {
1323   - [ ] then l1,
1324   - [h2 . t2] then
1325   - if less(h1,h2)
1326   - then [h1 . insert(t1,l2,less)]
1327   - else [h2 . insert(l1,t2,less)]
1328   - }
1329   - }.
1330   -
1331   -
1332   -
1333   -
1334   -
1335   - *** [2.4] Removing repeated elements from a list.
1336   -
1337   -define List($Out)
1338   - remove_repetitions
1339   - (
1340   - List($Out) l
1341   - ) =
1342   - if l is
1343   - {
1344   - [ ] then [ ],
1345   - [h . t] then
1346   - if member(t,h)
1347   - then remove_repetitions(t)
1348   - else [h . remove_repetitions(t)]
1349   - }.
1350   -
1351   -
1352   -
1353   - *** [2.5] Flattening a list of lists.
1354   -
1355   -define List($T)
1356   - flatten
1357   - (
1358   - List(List($T)) l
1359   - ) =
1360   - if l is
1361   - {
1362   - [ ] then [ ],
1363   - [h . t] then h + flatten(t)
1364   - }.
1365   -
1366   -
1367   -
1368   -
1369   -
1370   - *** [3] Loading and saving table chunks.
1371   -
1372   -
1373   - *** [3.1] Loading a table chunk.
1374   -
1375   -
1376   - *** [3.1.1] Type 1 tables.
1377 834  
1378 835 Tables need to be installed (which involves installing all rows).
1379 836  
1380   -define DBLoadedTable1($Row,$HRow)
  837 +read tools/basis.anubis required for 'qsort'
  838 +
  839 +define DBLoadedTable($Row,$HRow)
1381 840 install_table
1382 841 (
1383 842 String table_name,
1384 843 ($Row,$Row) -> Bool compare,
1385 844 $HRow -> $Row update,
1386 845 $Row -> $HRow store,
1387   - TableFileContent($HRow) st
  846 + DBSavedTable($HRow) st
1388 847 ) =
1389 848 if st is
1390 849 {
1391   - type_1(count,rows) then
  850 + myversion_1(count,rows) then
1392 851 with db_compare = dbrow(compare),
1393 852 updated_rows = map((DBRow($HRow) dbr) |->
1394 853 if dbr is dbrow(row_id,version,row)
... ... @@ -1404,15 +863,6 @@ define DBLoadedTable1($Row,$HRow)
1404 863 }.
1405 864  
1406 865  
1407   -
1408   - *** [3.1.2] Type 2 tables.
1409   -
1410   -
1411   -
1412   - *** [3.2] Saving a table chunk.
1413   -
1414   -
1415   - *** [3.2.1] Type 1 tables.
1416 866  
1417 867 Saving a table on the disk (the table also persists in memory).
1418 868  
... ... @@ -1420,11 +870,11 @@ define Result(DBError,One)
1420 870 save_table
1421 871 (
1422 872 String dbdir,
1423   - DBLoadedTable1($Row,$HRow) t
  873 + DBLoadedTable($Row,$HRow) t
1424 874 ) =
1425 875 if t is table(table_name,compare,store,changed_v,counter_v,rows_v) then
1426 876 with path = dbdir+"/"+table_name,
1427   - if protect save((TableFileContent($HRow))type_1(*counter_v,
  877 + if protect save((DBSavedTable($HRow))myversion_1(*counter_v,
1428 878 map((DBRow($Row) dbr) |->
1429 879 if dbr is dbrow(row_id,version,row) then
1430 880 if row_id is dbrowid(i) then
... ... @@ -1439,15 +889,29 @@ define Result(DBError,One)
1439 889  
1440 890  
1441 891  
1442   - *** [3.2.2] Type 2 tables.
  892 + Tables in the data base are either loaded or not.
  893 +
  894 +type DBTableState($Row,$HRow):
  895 + not_loaded (String table_name,
  896 + ($Row,$Row) -> Bool compare,
  897 + $HRow -> $Row update,
  898 + $Row -> $HRow store),
  899 + loaded (DBLoadedTable($Row,$HRow)).
1443 900  
  901 + Now a table is just a variable containing either a non loaded table or a loaded table.
1444 902  
  903 +public type DBTable($Row,$HRow):
  904 + db_table(Var(DBTableState($Row,$HRow))).
1445 905  
1446 906  
  907 + The data base itself is made of the directory path for table files, and the set of
  908 + tables (loaded or not).
1447 909  
1448   -
1449   - *** [4] Initializing a data base.
  910 +public type DB($MY_DB):
  911 + db(String directory,
  912 + $MY_DB tables).
1450 913  
  914 +
1451 915 public define DB($MY_DB)
1452 916 init_db
1453 917 (
... ... @@ -1457,9 +921,6 @@ public define DB($MY_DB)
1457 921 forget(make_directory(data_base_directory,default_directory_mode));
1458 922 db(data_base_directory,tables).
1459 923  
1460   -
1461   -
1462   -
1463 924 public define DBTable($Row,$HRow)
1464 925 init_dbtable
1465 926 (
... ... @@ -1468,41 +929,28 @@ public define DBTable($Row,$HRow)
1468 929 $HRow -> $Row update,
1469 930 $Row -> $HRow store
1470 931 ) =
1471   - db_table_1(var(not_loaded(table_name,compare,update,store))).
1472   -
1473   -
1474   -
1475   -
1476   -
  932 + db_table(var(not_loaded(table_name,compare,update,store))).
1477 933  
1478   - *** [5] Utilization commands.
1479   -
1480   -
1481   -
1482   - *** [5.1] Accessing a table.
1483 934  
1484 935 Given a data base and a table in the form of a destructor of type MY_DB, the next
1485 936 function returns the table in the form of a loaded table.
1486 937  
1487   -
1488   - *** [5.1.1] Type 1 tables.
1489   -
1490   -define Result(DBError,DBLoadedTable1($Row,$HRow))
  938 +define Result(DBError,DBLoadedTable($Row,$HRow))
1491 939 get_table
1492 940 (
1493 941 DB($MY_DB) the_data_base,
1494 942 $MY_DB -> DBTable($Row,$HRow) the_table,
1495 943 ) =
1496 944 if the_data_base is db(dbdir,my_db) then
1497   - if the_table(my_db) is db_table_1(table_v) then
  945 + if the_table(my_db) is db_table(table_v) then
1498 946 if *table_v is
1499 947 {
1500 948 not_loaded(table_name,compare,update,store) then
1501 949 with file_path = dbdir+"/"+table_name,
1502   - if (RetrieveResult(TableFileContent($HRow)))retrieve(file_path) is
  950 + if (RetrieveResult(DBSavedTable($HRow)))retrieve(file_path) is
1503 951 {
1504 952 cannot_find_file then
1505   - with new_table = install_table(table_name,compare,update,store,type_1(0,[])),
  953 + with new_table = install_table(table_name,compare,update,store,myversion_1(0,[])),
1506 954 table_v <- loaded(new_table);
1507 955 ok(new_table),
1508 956  
... ... @@ -1519,21 +967,37 @@ define Result(DBError,DBLoadedTable1($Row,$HRow))
1519 967 }.
1520 968  
1521 969  
  970 + Inserting rows. The next function receives two lists (of the same type) which are both
  971 + already sorted. It inserts the elements of the first list at the right place in the
  972 + second list.
1522 973  
  974 +define List($T)
  975 + insert // insert elements of l1 into l2
  976 + (
  977 + List($T) l1,
  978 + List($T) l2,
  979 + ($T,$T) -> Bool less
  980 + ) =
  981 + if l1 is
  982 + {
  983 + [ ] then l2,
  984 + [h1 . t1] then
  985 + if l2 is
  986 + {
  987 + [ ] then l1,
  988 + [h2 . t2] then
  989 + if less(h1,h2)
  990 + then [h1 . insert(t1,l2,less)]
  991 + else [h2 . insert(l1,t2,less)]
  992 + }
  993 + }.
1523 994  
  995 +
1524 996  
1525   - *** [5.1.2] Type 2 tables.
1526   -
1527   -
1528   - *** [5.2] Adding rows to a table.
1529   -
1530   - *** [5.2.1] Type 1 tables.
1531   -
1532   -
1533   - The table contains a list of 'DBRow($Row)' which is already sorted. The new rows arrive
1534   - as data of type '$Row', and need first to be sorted. Then they are transformed into
1535   - 'DBRow($Row)' and inserted in the table. Hence, we need to compare data of type
1536   - 'DBRow($Row)'.
  997 + Adding rows. The table contains a list of 'DBRow($Row)' which is already sorted. The
  998 + new rows arrive as data of type '$Row', and need first to be sorted. Then they are
  999 + transformed into 'DBRow($Row)' and inserted in the table. Hence, we need to compare
  1000 + data of type 'DBRow($Row)'.
1537 1001  
1538 1002 The next function gets a list of nude rows (of type '$Row'), and transforms it into a
1539 1003 list of loaded rows, creating a new identifier for each row. This function is run
... ... @@ -1611,20 +1075,10 @@ public define Result(DBError,DBRowId($Row))
1611 1075 }
1612 1076 }.
1613 1077  
1614   -
1615   -
1616   -
1617   - *** [5.2.2] Type 2 tables.
1618   -
1619   -
1620   -
1621 1078  
1622   - *** [5.3] Getting rows from a table.
1623 1079  
1624 1080  
1625 1081  
1626   - *** [5.3.1] Type 1 tables.
1627   -
1628 1082 Getting a row by its identifier.
1629 1083  
1630 1084 define Result(DBError,DBRow($Row))
... ... @@ -1663,6 +1117,21 @@ public define Result(DBError,DBRow($Row))
1663 1117 Getting rows by their identifiers.
1664 1118  
1665 1119  
  1120 +define List($T)
  1121 + remove
  1122 + (
  1123 + $T x,
  1124 + List($T) l
  1125 + ) =
  1126 + if l is
  1127 + {
  1128 + [ ] then [ ],
  1129 + [h . t] then
  1130 + if x = h
  1131 + then t
  1132 + else [h . remove(x,t)]
  1133 + }.
  1134 +
1666 1135 define Result(DBError,List(DBRow($Row)))
1667 1136 get_rows
1668 1137 (
... ... @@ -1750,15 +1219,6 @@ public define Result(DBError,List(DBRow($Row)))
1750 1219 (DBRow($Row) r) |-> which(row(r))).
1751 1220  
1752 1221  
1753   - *** [5.3.2] Type 2 tables.
1754   -
1755   -
1756   -
1757   -
1758   - *** [5.4] Getting a number of rows.
1759   -
1760   -
1761   - *** [5.4.1] Type 1 tables.
1762 1222  
1763 1223 Getting a number of rows.
1764 1224  
... ... @@ -1829,16 +1289,8 @@ public define Result(DBError,Bool)
1829 1289 }.
1830 1290  
1831 1291  
1832   - *** [5.4.2] Type 2 tables.
1833   -
1834 1292  
1835 1293  
1836   -
1837   - *** [5.5] Updating rows.
1838   -
1839   -
1840   - *** [5.5.1] Type 1 tables.
1841   -
1842 1294 Updating rows. Rows which satisfy the 'which' condition are first extracted from the
1843 1295 table and updated by 'how'. Then the list of updated rows is sorted, and reinserted
1844 1296 into the table. Subsequently, the table is saved.
... ... @@ -1994,16 +1446,8 @@ public define Result(DBError,List(DBUpdateResult($Row)))
1994 1446 }
1995 1447 }.
1996 1448  
1997   -
1998   -
1999   - *** [5.5.2] Type 2 tables.
2000 1449  
2001 1450  
2002   - *** [5.6] Deleting rows.
2003   -
2004   -
2005   - *** [5.6.1] Type 1 tables.
2006   -
2007 1451 Deleting rows.
2008 1452  
2009 1453  
... ... @@ -2097,12 +1541,37 @@ public define Result(DBError,List($Row))
2097 1541  
2098 1542  
2099 1543  
2100   - *** [5.6.2] Type 2 tables.
2101 1544  
2102 1545  
2103   - *** [5.7] Multi-tables queries.
  1546 +
  1547 + Multi-tables queries.
2104 1548  
2105 1549  
  1550 +define List($Out)
  1551 + remove_repetitions
  1552 + (
  1553 + List($Out) l
  1554 + ) =
  1555 + if l is
  1556 + {
  1557 + [ ] then [ ],
  1558 + [h . t] then
  1559 + if member(t,h)
  1560 + then remove_repetitions(t)
  1561 + else [h . remove_repetitions(t)]
  1562 + }.
  1563 +
  1564 +
  1565 +define List($T)
  1566 + flatten
  1567 + (
  1568 + List(List($T)) l
  1569 + ) =
  1570 + if l is
  1571 + {
  1572 + [ ] then [ ],
  1573 + [h . t] then h + flatten(t)
  1574 + }.
2106 1575  
2107 1576 public define List($Out)
2108 1577 query
... ... @@ -2125,9 +1594,6 @@ public define List($Out)
2125 1594  
2126 1595  
2127 1596  
2128   -
2129   - *** [6] Indexing.
2130   -
2131 1597  
2132 1598  
2133 1599  
... ...
anubis_dev/library/tools/sdbms1.anubis 0 → 100644
  1 +
  2 +
  3 + The Anubis/Paradize Project.
  4 +
  5 + A Simple Data Base Management System.
  6 +
  7 + Copyright (c) Alain Prouté 2004-2005.
  8 +
  9 +
  10 + Author: Alain Prouté
  11 +
  12 + Last revision: January 2005.
  13 +
  14 +
  15 +
  16 +
  17 + ----------------------------------- Contents ------------------------------------------
  18 +
  19 + *** (1) Overview.
  20 + *** (2) Errors.
  21 + *** (3) Tables and data bases.
  22 + *** (4) Managing changes in table formats.
  23 + *** (5) Row identifiers.
  24 + *** (6) Adding rows to a table.
  25 + *** (7) Getting rows from a table.
  26 + *** (8) Testing a number of rows.
  27 + *** (9) Updating rows in a table.
  28 + *** (10) Deleting rows from a table.
  29 + *** (11) Multi-tables queries.
  30 + *** (12) Using it with 'web/making_a_web_site.anubis'.
  31 +
  32 + ---------------------------------------------------------------------------------------
  33 +
  34 +
  35 +
  36 +
  37 + *** (1) Overview.
  38 +
  39 + Relational data base management systems provide two kinds of commands:
  40 +
  41 + - utilization commands, like adding, updating or deleting rows in a table, or
  42 + querying using the SQL command 'SELECT'.
  43 +
  44 + - restructuring commands, like adding columns in a table, deleting columns, etc...
  45 +
  46 + Normally, if a data base is restructured, programs using that database must themselves
  47 + be restructured, while the transformation of the data base by utilization commands does
  48 + not require any modification of the programs which are using the data base.
  49 +
  50 + Our aim is to provide a data base mecanism, which is as much as possible in the spirit
  51 + of Anubis. Our first demand is that cells in a table should be able to contain data of
  52 + any (serializable) Anubis type (one type per column of the table of course). More
  53 + precisely, if T is a type, we want to consider tables whose rows are data of type T. A
  54 + consequence of this is that adding a column to a table requires a modification of an
  55 + Anubis type, hence a modification of the program using the data base. But this is
  56 + precisely in the spirit of Anubis, because this will force a corresponding modification
  57 + of the program, so ensuring more security.
  58 +
  59 + This data base management program is highly experimental. Indeed, the obligation of
  60 + deciding everything about types of data at compile time, introduces a rigidity which
  61 + renders the mimicking of the usual data base manipulations quite difficult (at least as
  62 + far as the SELECT command is concerned). Nevertheless, it's an interesting adventure
  63 + because it puts de facto at different levels aspects of data base management which are
  64 + otherwise consider of the same kind.
  65 +
  66 +
  67 +
  68 +
  69 + *** (2) Errors.
  70 +
  71 + Errors may occur during the normal management of the data base.
  72 +
  73 +public type DBError:
  74 + file_not_found (String path),
  75 + file_reading_problem (String path),
  76 + file_type_problem (String path),
  77 + cannot_open_file (String path),
  78 + cannot_write_file (String path),
  79 + record_not_found.
  80 +
  81 +
  82 +
  83 +
  84 +
  85 +
  86 + *** (3) Tables and data bases.
  87 +
  88 + The type of the rows of a table is up to you (but must be serializable). However, this
  89 + data base management system includes a mecanism for handling the possible changes in
  90 + the definition of the types of the rows of a table, in such a way that updating the
  91 + actual tables files on the disk is automatic. For this reason, the type scheme
  92 + 'DBTable' representing tables has two type parameters. The first one represents the
  93 + current type of the rows of the table, the second one represents the history of all
  94 + successive types of the rows of the table. With this mecanism, and if you repects some
  95 + principles explained below, your program will always be able to read old tables saved
  96 + in old formats.
  97 +
  98 + Tables are represented by the following opaque type scheme, where the parameter '$Row'
  99 + is the current type of the rows of the table, and '$HRow' ('H' like 'History') is a
  100 + type containing the history of all the successive formats of rows in the table:
  101 +
  102 +public type DBTable($Row,$HRow):...
  103 +
  104 + The first thing you have to do if you want to use this data base management system, is
  105 + to define the type of your data base. Since a data base is essentially a set of
  106 + tables, the type of your data base should be something like this (at the beginning, you
  107 + can use the same type for '$Row' and '$HRow'):
  108 +
  109 + type MY_DB:
  110 + my_db(DBTable(Client,Client) clients,
  111 + DBTable(Product,Product) products,
  112 + DBTable(Supplier,Supplier) suppliers,
  113 + ...).
  114 +
  115 + where the types 'Client', 'Product', ... have been previously defined by you. Notice
  116 + that a datum of type 'Client' is just an entire row in the 'clients' table. Hence,
  117 + 'Client' is probably a type with just one alternative and the components needed for a
  118 + 'client', like 'name', 'address', etc...
  119 +
  120 + What if the type $Row has several alternatives ? This means that your table has several
  121 + sorts of rows. But in this case, you should perhaps better use several
  122 + tables. Nevertheless, this makes no problem.
  123 +
  124 + Actually, a datum of type MY_DB is not the whole data base. The system requires more
  125 + informations. This is the reason why the actual type of the data base is:
  126 +
  127 +public type DB($MY_DB):... (again an opaque type scheme)
  128 +
  129 + where the parameter '$MY_DB' may be instantiated to your type 'MY_DB'. Several
  130 + instantiations allow the creation of several data bases.
  131 +
  132 + Now, when you start your program (may be a web site), you need to start the data base
  133 + manager. This amounts to initialize each table, and use the initialized tables to
  134 + initialize the data base itself:
  135 +
  136 + with my_data_base = init_db(my_data_base_directory,
  137 + my_db(init_dbtable ("clients", compare, identity, identity),
  138 + init_dbtable ("products", compare, identity, identity),
  139 + init_dbtable ("suppliers", compare, identity, identity),
  140 + ...)),
  141 +
  142 + where 'init_db' is declared as:
  143 +
  144 +public define DB($MY_DB)
  145 + init_db
  146 + (
  147 + String data_base_directory,
  148 + $MY_DB tables
  149 + ).
  150 +
  151 + and where 'init_dbtable' is declared as:
  152 +
  153 +public define DBTable($Row,$HRow)
  154 + init_dbtable
  155 + (
  156 + String table_name,
  157 + ($Row,$Row) -> Bool compare,
  158 + $HRow -> $Row update,
  159 + $Row -> $HRow store
  160 + ).
  161 +
  162 + Notice that the name 'table_name' above becomes part of the names of the files
  163 + containing the tables (located in the directory 'data_base_directory' above).
  164 + 'init_table' does not load the table from the disk. A table is loaded only when
  165 + needed. If the table does not exist on the disk, 'init_table' creates an empty table
  166 + of the right type. 'init_table' should be executed only once per table, when your
  167 + program starts.
  168 +
  169 + The 'compare' function is used for sorting the rows of the table. The table is sorted
  170 + when it is read from the disk, and whenever a row is added or updated, it is placed at
  171 + the right position in the table according to the order defined by the 'compare'
  172 + function. More precisely, if 'r1' and 'r2' are rows in the table, and if
  173 + 'compare(r1,r2)' is 'true', 'r1' is placed before 'r2' in the table. When you get rows
  174 + from the table (using 'get_rows' declared below) you get your rows in the order defined
  175 + by the 'compare' function. Of course, the 'compare' function is just a default way of
  176 + ordering the table. You can always reorder the result of 'get_rows' for any purpose.
  177 +
  178 + The 'update' and 'store' functions are used for automating the changes of format of the
  179 + tables. This is explained below in the section 'Managing changes in table formats'. At
  180 + the beginning, while the two types '$Row' and '$HRow' are identical, you can use the
  181 + function 'identity' (actually a scheme of function, defined in 'tools/basis.anubis')
  182 + for both 'update' and 'store'.
  183 +
  184 + At that point you have the datum 'my_data_base' at hand, which is of type 'DB($MY_DB)',
  185 + and which represents the whole data base. The preparation above determines the whole
  186 + structure of the data base. With a datum of type 'DB($MY_DB)' at hand, the Anubis
  187 + compiler is able to detect many errors that would not be detected by an untyped (or
  188 + dynamically typed) data base system. Of course, you can use several such data bases in
  189 + a program.
  190 +
  191 +
  192 +
  193 +
  194 +
  195 + *** (4) Managing changes in table formats.
  196 +
  197 + Up to here the types used as instantiations of '$Row' and '$HRow' are the same one.
  198 + That's OK, and you have begun to distribute your program and your users have created
  199 + tables whose types are your types 'Client', 'Product' etc... If you simply modify the
  200 + definition of (say) the type 'Client', your new program will not work with the tables
  201 + created by your users, which is obviously a catastrophe. Fortunately, there is a
  202 + remedy, and here it is.
  203 +
  204 + Assume that you want to change the definition of the type 'Client', because you need
  205 + more columns in the table of clients. As an example, assume that your type 'Client'
  206 + was first defined as:
  207 +
  208 + type Client:
  209 + client(String name,
  210 + String address).
  211 +
  212 + and you want to add a new component (column of the table):
  213 +
  214 + Int32 age
  215 +
  216 +
  217 + --- Step 1:
  218 +
  219 + The first thing to do is to make two copies of your original type, because from now on,
  220 + the types '$Row' and '$HRow' are no more identical:
  221 +
  222 + type Client: // current type of rows of 'clients' table
  223 + client(String name,
  224 + String address).
  225 +
  226 + type HClient: // history of type of rows of 'clients' table
  227 + client(String name,
  228 + String address).
  229 +
  230 +
  231 + --- Step 2:
  232 +
  233 + The first alternative of 'HClient' should never be changed, because it represents an
  234 + 'historical' way of representing clients. The only thing that you can do is change the
  235 + name of the alternative. We recommend to name it 'version_1', and to use the name
  236 + 'version_2' for the second alternative representing the new type of rows. Hence, the
  237 + type 'HClient' becomes:
  238 +
  239 + type HClient:
  240 + version_1(String name,
  241 + String address),
  242 + version_2(String name,
  243 + String address,
  244 + Int32 age).
  245 +
  246 + Important notice: When a change intervenes in the type of rows of the table, the
  247 + alternative representing the new type of rows must be added at the end of the type
  248 + 'HClient' (or any other instance of '$HRow'). This is because in serialized data the
  249 + alternative names are lost, and replaced by their number in the list of
  250 + alternatives. Also notice that another method will be required if you create more than
  251 + 256 versions.
  252 +
  253 + The type 'Client' must also be changed in order to reflect the new format:
  254 +
  255 + type Client:
  256 + client(String name,
  257 + String address,
  258 + Int32 age).
  259 +
  260 +
  261 +
  262 +
  263 + --- Step 3:
  264 +
  265 + Now, we need 'conversion' functions in both directions between 'Client' and
  266 + 'HClient'. Presisely, we need the functions:
  267 +
  268 + (HClient -> Client)update
  269 + (Client -> HClient)store
  270 +
  271 + The function 'update' gets an 'historical' row (hence of type 'HClient') and must
  272 + transform it into a row in the current format. In our example, it could be:
  273 +
  274 + define Client
  275 + update
  276 + (
  277 + HClient hc
  278 + ) =
  279 + if hc is
  280 + {
  281 + version_1(name,addr) then client(name,addr,0),
  282 + version_2(name,addr,age) then client(name,addr,age)
  283 + }.
  284 +
  285 + Of course, in the case of a row in the old format (version_1), we need a default value
  286 + for the age. We have chosen 0 in the example, but you may choose anything. In any
  287 + traditional data base system, when you add a column to a table, you need to fill this
  288 + column with a default value, even if this default value is 'NULL' (not filled at all).
  289 +
  290 + The other function does not require default values in principle, because it is mainly a
  291 + conversion between the current version and the latest one (i.e. essentially the same
  292 + one):
  293 +
  294 + define HClient
  295 + store
  296 + (
  297 + Client c
  298 + ) =
  299 + if c is client(name,addr,age) then version_2(name,addr,age).
  300 +
  301 +
  302 + The type used for storing the data on the disk is always 'HClient' (hence the name of
  303 + the function 'store'), and according to the above function they are stored as
  304 + 'version_2(...)'. The type 'Client' is used only internally. This is required for
  305 + being able of handling file containing different versions of the tables.
  306 +
  307 +
  308 +
  309 +
  310 + *** (5) Row identifiers.
  311 +
  312 + The system generates an identifier for each newly created row in a table. It is
  313 + warranted that not two rows in the same table can have the same row identifier. Row
  314 + identifiers are of type 'DBRowId($Row)' (an opaque type scheme).
  315 +
  316 +public type DBRowId($Row):...
  317 +
  318 + (where '$Row' is the type of rows of the table). It is possible to use it as a
  319 + component in the type of rows in another table. This is how you can create 'links'
  320 + between tables.
  321 +
  322 + The type scheme 'DBRowId' should be considered as absolutely opaque. The author
  323 + reserves the possibility of modifying this type in the future. Hence, use only the
  324 + public interface for manipulating data of this type.
  325 +
  326 + It would have been possible to define the type 'DBRowId' without the parameter, but in
  327 + this case, identifiers corresponding to tables of different types could not be
  328 + distinguished by the compiler. The role of the parameter '$Row' is to identify the
  329 + type of the table to which the identifier refers. Introducing this parameter enhances
  330 + the security because it forbids the use of a row identifier with a table to which it
  331 + cannot actually apply.
  332 +
  333 +
  334 +
  335 +
  336 + *** (6) Adding rows to a table.
  337 +
  338 + Adding rows to a table is performed by the following function:
  339 +
  340 +public define Result(DBError,List(DBRowId($Row)))
  341 + add_rows
  342 + (
  343 + DB($MY_DB) the_data_base,
  344 + $MY_DB -> DBTable($Row,$HRow) the_table,
  345 + List($Row) new_rows
  346 + ).
  347 +
  348 + For example, you may write:
  349 +
  350 + add_rows(my_data_base,clients,[row1,row2,row3])
  351 +
  352 + where 'row1','row2' and 'row3' are of type 'Client'. The function returns (if no error
  353 + occurs) the list of the row identifiers of the newly created rows.
  354 +
  355 + The following variant is more convenient for adding just one row.
  356 +
  357 +public define Result(DBError,DBRowId($Row))
  358 + add_row
  359 + (
  360 + DB($MY_DB) the_data_base,
  361 + $MY_DB -> DBTable($Row,$HRow) the_table,
  362 + $Row new_row
  363 + ).
  364 +
  365 +
  366 +
  367 +
  368 + *** (7) Getting rows from a table.
  369 +
  370 + In order to get rows from a table, you have two methods:
  371 +
  372 + (1) you know the row identifiers of the rows you want,
  373 + (2) you want to get all rows satisfying some condition.
  374 +
  375 + You get rows in the form of:
  376 +
  377 +public type DBRow($Row):
  378 + dbrow(DBRowId($Row) row_id,
  379 + Int32 version,
  380 + $Row row).
  381 +
  382 + A datum of type DBRow($Row) contains the identifier of the row, a version number and
  383 + the row itself. The version number is 0 when the row is created (by 'add_row' or
  384 + 'add_rows' above) and is incremented by 1 each time the row is updated. This may be
  385 + used to detect the fact that the row has been modified between two operations.
  386 +
  387 +public define Result(DBError,DBRow($Row))
  388 + get_row
  389 + (
  390 + DB($MY_DB) the_data_base,
  391 + $MY_DB -> DBTable($Row,$HRow) the_table,
  392 + DBRowId($Row) row_id
  393 + ).
  394 +
  395 + If no error occurs, the function returns the wanted row. The next one can be used for
  396 + getting several rows.
  397 +
  398 +public define Result(DBError,List(DBRow($Row)))
  399 + get_rows
  400 + (
  401 + DB($MY_DB) the_data_base,
  402 + $MY_DB -> DBTable($Row,$HRow) the_table,
  403 + List(DBRowId($Row)) row_ids
  404 + ).
  405 +
  406 +public define Result(DBError,List(DBRow($Row)))
  407 + get_rows
  408 + (
  409 + DB($MY_DB) the_data_base,
  410 + $MY_DB -> DBTable($Row,$HRow) the_table,
  411 + $Row -> Bool which
  412 + ).
  413 +
  414 + This function returns the list of all rows from the table which satisfy the given
  415 + condition 'which'.
  416 +
  417 + Now, the test 'which' may also be performed on the complete row:
  418 +
  419 +public define Result(DBError,List(DBRow($Row)))
  420 + get_rows
  421 + (
  422 + DB($MY_DB) the_data_base,
  423 + $MY_DB -> DBTable($Row,$HRow) the_table,
  424 + DBRow($Row) -> Bool which
  425 + ).
  426 +
  427 +
  428 +
  429 +
  430 +
  431 + *** (8) Testing a number of rows.
  432 +
  433 + It may be useful to get the number of rows satisfying some condition in a table. It may
  434 + also be useful to know if a table contains more rows satisfying a condition than a
  435 + given number.
  436 +
  437 +public define Result(DBError,Int32)
  438 + get_number_of_rows
  439 + (
  440 + DB($MY_DB) the_data_base,
  441 + $MY_DB -> DBTable($Row,$HRow) the_table,
  442 + DBRow($Row) -> Bool which
  443 + ).
  444 +
  445 + This function returns the number of rows satisfying the condition 'which'.
  446 +
  447 +public define Result(DBError,Bool)
  448 + has_more_rows_than
  449 + (
  450 + DB($MY_DB) the_data_base,
  451 + $MY_DB -> DBTable($Row,$HRow) the_table,
  452 + DBRow($Row) -> Bool which,
  453 + Int32 n
  454 + ).
  455 +
  456 + This function returns 'ok(true)' if the table has strictly more than 'n' rows satifying
  457 + the condition, 'ok(false)' if it has at most 'n' rows satisfying the condition.
  458 +
  459 + Note: of course, these functions could be simulated using 'get_rows', but they may be
  460 + much more efficient, especially the last one when 'n' is much less than the number of
  461 + rows satisfying the condition, because it does not need to examine the whole table.
  462 +
  463 +
  464 +
  465 +
  466 +
  467 + *** (9) Updating rows in a table.
  468 +
  469 + Updating rows in a table is generally the consequence of a previous reading of these
  470 + rows. Indeed, interactive programs will first show the row to be updated to a human
  471 + user (phase 1). The user is supposed to modify the data by hand. When the data are
  472 + modified, they may be put in the table in order to replace the previous values (phase
  473 + 2).
  474 +
  475 + This makes a problem because, the same data may have been modified by another human
  476 + user (or in some automatic way) in the meantime (i.e. between phase 1 and phase 2).
  477 + Hence, phase 2 should perhaps not be performed if the data have been modified in the
  478 + meantime. For this reason, when you want to update one or several rows in a table, you
  479 + do not provide the new values, but a function (denoted 'how' below) of type:
  480 +
  481 + DBRow($Row) -> Maybe($Row)
  482 +
  483 + This function is supposed to remember the version number of the row got during phase 1.
  484 + It receives as its argument the new row as it stands in the data base when phase 2
  485 + begins. It should compare the version number with the one it remembers and decide if
  486 + the row must be updated or not. If the row must not be updated, the function 'how'
  487 + must return 'failure'. If on the contrary, the row must be updated, it must return the
  488 + value 'success(r)', where 'r' is the new value of the row.
  489 +
  490 + Now, if no error occurs, the 'update_row' function returns a datum of type:
  491 +
  492 +public type DBUpdateResult($Row):
  493 + not_updated (DBRow($Row) the_row),
  494 + updated (DBRow($Row) the_row).
  495 +
  496 + i.e. the result is either 'not_updated(r)' or 'updated(r)'. It is 'not_updated(r)'
  497 + when the row has not been updated, i.e. when the 'how' function has returned
  498 + 'failure', and it is 'updated(r)' if the row has been updated. In both cases, 'r' is
  499 + the new current value of the row as recorded in the table.
  500 +
  501 + Again, you may just want to update the row(s) the id(s) of which you have at hand, or
  502 + update all rows satisfying some condition.
  503 +
  504 +public define Result(DBError,DBUpdateResult($Row))
  505 + update_row
  506 + (
  507 + DB($MY_DB) the_data_base,
  508 + $MY_DB -> DBTable($Row,$HRow) the_table,
  509 + DBRowId($Row) row_id,
  510 + DBRow($Row) -> Maybe($Row) how
  511 + ).
  512 +
  513 +public define Result(DBError,List(DBUpdateResult($Row)))
  514 + update_rows
  515 + (
  516 + DB($MY_DB) the_data_base,
  517 + $MY_DB -> DBTable($Row,$HRow) the_table,
  518 + List(DBRowId($Row)) row_ids,
  519 + DBRow($Row) -> Maybe($Row) how
  520 + ).
  521 +
  522 +public define Result(DBError,List(DBUpdateResult($Row)))
  523 + update_rows
  524 + (
  525 + DB($MY_DB) the_data_base,
  526 + $MY_DB -> DBTable($Row,$HRow) the_table,
  527 + $Row -> Bool which,
  528 + DBRow($Row) -> Maybe($Row) how
  529 + ).
  530 +
  531 + For the last function 'update_rows', only the rows which satify the 'which' condition
  532 + are eventually updated. Of course the function returns a list of
  533 + 'DBUpdateResult($Row)', one for each row satisfying the 'which' condition.
  534 +
  535 +
  536 +
  537 +
  538 + *** (10) Deleting rows from a table.
  539 +
  540 +public define Result(DBError,$Row)
  541 + delete_row
  542 + (
  543 + DB($MY_DB) the_data_base,
  544 + $MY_DB -> DBTable($Row,$HRow) the_table,
  545 + DBRowId($Row) row_id
  546 + ).
  547 +
  548 + If no error occurs, the row is deleted from the table, and returned by the function as
  549 + 'ok(row)'. You may forget this result, but you may also use it for archiving purpose
  550 + for example.
  551 +
  552 +public define Result(DBError,List($Row))
  553 + delete_rows
  554 + (
  555 + DB($MY_DB) the_data_base,
  556 + $MY_DB -> DBTable($Row,$HRow) the_table,
  557 + $Row -> Bool which
  558 + ).
  559 +
  560 + The rows satisfying the condition 'which' are deleted from the table. Of course, the
  561 + result, if no error occurs, is the list of the deleted rows.
  562 +
  563 +
  564 +
  565 +
  566 +
  567 +
  568 + *** (11) Multi-tables queries.
  569 +
  570 + The SQL language has an important feature which is the 'SELECT' command. We need
  571 + something analogous to the SQL query:
  572 +
  573 + SELECT column_1 ... column_k
  574 + FROM table_1 ... table_n
  575 + WHERE condition
  576 +
  577 + From a purely mathematical viewpoint, the above query means the following. Consider the
  578 + tables 'table_1' ... 'table_n' as relations between data types (i.e subsets of
  579 + cartesian products of data types, where each row of the table is precisely an element
  580 + of the relation, and each column is a data type). Make the cartesian products 'P' of
  581 + these relations. Then consider the subset of 'P' of those elements which satisfy the
  582 + 'condition'. Finally, apply the canonical projection towards the cartesian product of
  583 + the data types represented by 'column_1' ... 'column_k'. This is the result of the
  584 + query.
  585 +
  586 + Of course, the above description, even if probably the simplest possible one from a
  587 + theoretical viewpoint, is not efficient from the computational viewpoint. This is
  588 + mainly because the cartesian product of the relations 'table_1' ... 'table_n' may be
  589 + very big. This big product is first reduced by applying the condition, and further
  590 + reduced by the canonical projection. The question is how can we do for computing
  591 + without these big intermediate data.
  592 +
  593 + Usual data bases first optimize the query before it is executed. With Anubis, we cannot
  594 + optimize the query, except if it is given in a symbolic form. This is not the way we
  595 + have chosen, at least for the time being. Actually, combining the advantages of Anubis
  596 + (essentially the security provided by the strong typing mecanism), and the flexibility
  597 + of usual data bases could be realized only with a more elaborate version of Anubis,
  598 + including meta-programming, and maybe another virtual machine able to optimize on the
  599 + fly. All these new features are part of the Anubis2/Paradize project.
  600 +
  601 + For the time being, we content ourself with the following recursive querying
  602 + mecanism. Actually, the recursion is on the number of tables concerned by the query.
  603 +
  604 +public define List($Out)
  605 + query
  606 + (
  607 + DB($MY_DB) the_data_base,
  608 + $MY_DB -> DBTable($Row,$HRow) the_first_table,
  609 + DBRow($Row) -> Bool the_first_condition,
  610 + (DBRow($Row),$In) -> $Out the_first_selection,
  611 + DBRow($Row) -> List($In) the_subquery
  612 + ).
  613 +
  614 + The parameter '$Row' represents the type of the rows of the first table (we assume
  615 + there is at least one table concerned by the query). This table (the first table) will
  616 + be looked at first, and only the rows satisfying the condition 'the_first_condition'
  617 + are considered. For each such row of the first table, a subquery ('the_subquery') is
  618 + executed. Notice that the subquery takes that row as an argument. The subquery
  619 + concernes only the remaining tables (i.e. all the tables concerned by the original
  620 + query, except the first one). It returns a list of results of type 'List($In)'. Now,
  621 + the row of the first table is paired to each element of this list, and the projection
  622 + 'the_first_projection' is applied. This yields a list of type 'List($Out)', one for
  623 + each selected row of the first table. Finally, all these lists are merged together (and
  624 + repetitions are removed).
  625 +
  626 + Well, an example is probably required. Here it is. We consider the tables 'clients',
  627 + 'commands' and 'products' , whose types of rows are respectively: 'Client', 'Command'
  628 + and 'Product'. It is assumed that the type 'Command' has (among others) the
  629 + components:
  630 +
  631 + client_id of type DBRowId(Client)
  632 + product_id of type DBRowId(Product)
  633 +
  634 + so that to each command (probably only a 'command item') corresponds a client and a
  635 + product. Also, the types 'Client' and 'Product' have a component 'name' (of type
  636 + String), giving the name of the client or of the product. The type 'Client' also has a
  637 + component 'country'.
  638 +
  639 + We want to get the list of all clients living in France, who have bought the product
  640 + named "Yoyo". Here is the query (which returns a list of type 'List(String)'):
  641 +
  642 + query(my_data_base,
  643 + clients, // begin with the table 'clients'
  644 + (DBRow(Client) clt) |-> // consider only French clients
  645 + country(row(clt)) = "France",
  646 + (DBRow(Client) clt, One u) |-> // keep only the name of the client
  647 + name(row(clt)),
  648 + (DBRow(Client) clt) |-> // the subquery for this client 'clt'
  649 + query(my_data_base,
  650 + commands, // continue with the table 'commands'
  651 + (DBRow(Command) cmd) |->
  652 + row_id(clt) = client_id(row(cmd)),
  653 + (DBRow(Command) cmd, One u) |-> u, // do not keep anything from 'commands'
  654 + (DBRow(Command) cmd) |->
  655 + query(my_data_base,
  656 + products,
  657 + (DBRow(Product) prd) |->
  658 + row_id(prd) = product_id(cmd) &
  659 + name(row(prd)) = "Yoyo",
  660 + (DBRow(Product) prd, One u) |-> u,
  661 + (DBRow(Product) prd) |-> unique)))
  662 +
  663 + Of course, this is more complicated than:
  664 +
  665 + SELECT clients.name
  666 + FROM clients, commands_2005, products
  667 + WHERE clients.id = commands_2005.client_id AND
  668 + commands_2005.product_id = products.id AND
  669 + products.name = "Yoyo"
  670 +
  671 + but meta-programming could automatically transform the later into the former (in the
  672 + future).
  673 +
  674 + Now, the query may also be more efficient (computed faster) if the tables are put in a
  675 + different order. For example, we may consider the following equivalent query (with the
  676 + tables in reverse order):
  677 +
  678 + query(my_data_base,
  679 + products,
  680 + (DBRow(Product) prd) |-> name(row(prd)) = "Yoyo",
  681 + (DBRow(Product) prd, String cltname) |-> cltname,
  682 + (DBRow(Product) prd) |->
  683 + query(my_data_base,
  684 + commands,
  685 + (DBRow(Command) cmd) |->
  686 + row_id(prd) = product_id(row(cmd)),
  687 + (DBRow(Command) cmd, String cltname) |-> cltname,
  688 + (DBRow(Command) cmd) |->
  689 + query(my_data_base,
  690 + clients,
  691 + (DBRow(Client) clt) |->
  692 + country(row(clt)) = "France" &
  693 + row_id(clt) = client_id(row(cmd)),
  694 + (DBRow(Client) clt, One u) |-> name(row(clt)),
  695 + (DBRow(Client) clt) |-> unique)))
  696 +
  697 + This one may be more efficient than the first one. The order into which the tables are
  698 + looked up may be important for performances.
  699 +
  700 +
  701 +
  702 +
  703 +
  704 + *** (12) Using it with 'web/making_a_web_site.anubis'.
  705 +
  706 + You may want to use this data base manager in conjunction with our web site making
  707 + method. You should proceed as follows in order to start the data base and the web
  708 + site.
  709 +
  710 + You should not define the actions of your web site at the top level, like this:
  711 +
  712 + define State
  713 + act_do_something
  714 + (
  715 + HTTP_Info http_info,
  716 + List(Web_arg) lwa,
  717 + State previous
  718 + )= ...
  719 +
  720 + What you should do (for each action) is defining a function which constructs the above
  721 + one using the data base, like this:
  722 +
  723 + define (HTTP_Info http_info,
  724 + List(Web_arg) lwa,
  725 + State previous) -> State
  726 + make_act_do_something
  727 + (
  728 + DB(MY_DB) my_data_base
  729 + ) =
  730 + (HTTP_Info http_info,
  731 + List(Web_arg) lwa,
  732 + State previous) |->
  733 + ... here the body of the function may use the data base ...
  734 +
  735 +
  736 + Now, when defining the list of all actions of your web site, you need to provide the
  737 + data base:
  738 +
  739 + define List(Web_Action(State))
  740 + make_actions
  741 + (
  742 + DB(MY_DB) my_data_base
  743 + ) =
  744 + [
  745 + http_action("do_something",
  746 + make_allow_something(my_data_base),
  747 + make_act_do_something(my_data_base)),
  748 + ...etc...
  749 + ].
  750 +
  751 +
  752 + Finally, when you start the whole stuff, do as follows. First start the data base:
  753 +
  754 + with my_data_base = (DB(MY_DB))init_db(...),
  755 +
  756 + Next, construct the list of actions of the web site:
  757 +
  758 + with actions = make_actions(my_data_base),
  759 +
  760 + finally, start the web sites:
  761 +
  762 + start_web_sites
  763 + (0,
  764 + 80,
  765 + 443,
  766 + "georges",
  767 + [
  768 + make_web_site_description
  769 + (common_name,
  770 + default_state,
  771 + actions, // here the actions constructed above are used (hence the data base)
  772 + compute_page,
  773 + ... etc...)
  774 + ])
  775 +
  776 + Of course, if you have several web sites, you may also have several data bases, but the
  777 + method is essentially the same one. You may also need several data bases for a single
  778 + web site.
  779 +
  780 + Recall that the function 'compute_page' should perhaps not use the data base, because
  781 + otherwise, the page sent to the client may be incoherent with the state saved on the
  782 + server's disk.
  783 +
  784 +
  785 +
  786 +
  787 +
  788 +
  789 + --- That's all for the public part ! --------------------------------------------------
  790 +
  791 +
  792 + Row identifiers are just integers, but this may change in the future, because integers
  793 + may not be enough.
  794 +
  795 +public type DBRowId($Row):
  796 + dbrowid(Int32 index).
  797 +
  798 + When a table is loaded, a boolean variable 'changed' indicates if it has to be saved. A
  799 + integer variable contains the counter for creating identifiers for new rows. Another
  800 + variable contains the list of all loaded rows.
  801 +
  802 +type DBLoadedTable($Row,$HRow):
  803 + table(String table_name,
  804 + (DBRow($Row),DBRow($Row)) -> Bool compare,
  805 + $Row -> $HRow store,
  806 + Var(Bool) changed_v,
  807 + Var(Int32) counter_v,
  808 + Var(List(DBRow($Row))) rows_v).
  809 +
  810 + Of course, tables are not saved on disk as 'DBLoadedTable($Row,$HRow)' because variable
  811 + types (and functional types for the time being) are not serializable, and also because
  812 + data of type '$Row' are not saved on the disk. Tables are saved as data of type
  813 + 'DBSavedTable($HRow)'.
  814 +
  815 +type DBSavedTable($HRow):
  816 + myversion_1(Int32 counter,
  817 + List(DBRow($HRow)) rows).
  818 +
  819 +
  820 + We will have to compare the rows of a loaded table. The function able to compare loaded
  821 + rows must be constructed from the function comparing nude rows. This is the job of the
  822 + following 'function maker':
  823 +
  824 +define (DBRow($Row),DBRow($Row)) -> Bool
  825 + dbrow
  826 + (
  827 + ($Row,$Row) -> Bool compare
  828 + ) =
  829 + (DBRow($Row) dbr1, DBRow($Row) dbr2) |->
  830 + if dbr1 is dbrow(id1,v1,r1) then
  831 + if dbr2 is dbrow(id2,v2,r2) then
  832 + compare(r1,r2).
  833 +
  834 +
  835 + Tables need to be installed (which involves installing all rows).
  836 +
  837 +read tools/basis.anubis required for 'qsort'
  838 +
  839 +define DBLoadedTable($Row,$HRow)
  840 + install_table
  841 + (
  842 + String table_name,
  843 + ($Row,$Row) -> Bool compare,
  844 + $HRow -> $Row update,
  845 + $Row -> $HRow store,
  846 + DBSavedTable($HRow) st
  847 + ) =
  848 + if st is
  849 + {
  850 + myversion_1(count,rows) then
  851 + with db_compare = dbrow(compare),
  852 + updated_rows = map((DBRow($HRow) dbr) |->
  853 + if dbr is dbrow(row_id,version,row)
  854 + then if row_id is dbrowid(i)
  855 + then dbrow(dbrowid(i),version,update(row)),
  856 + rows),
  857 + table(table_name,
  858 + db_compare,
  859 + store,
  860 + var(false),
  861 + var(count),
  862 + var(qsort(updated_rows,db_compare)))
  863 + }.
  864 +
  865 +
  866 +
  867 + Saving a table on the disk (the table also persists in memory).
  868 +
  869 +define Result(DBError,One)
  870 + save_table
  871 + (
  872 + String dbdir,
  873 + DBLoadedTable($Row,$HRow) t
  874 + ) =
  875 + if t is table(table_name,compare,store,changed_v,counter_v,rows_v) then
  876 + with path = dbdir+"/"+table_name,
  877 + if protect save((DBSavedTable($HRow))myversion_1(*counter_v,
  878 + map((DBRow($Row) dbr) |->
  879 + if dbr is dbrow(row_id,version,row) then
  880 + if row_id is dbrowid(i) then
  881 + dbrow(dbrowid(i),version,store(row)),
  882 + *rows_v)),
  883 + path) is
  884 + {
  885 + cannot_open_file then error(cannot_open_file(path)),
  886 + write_error then error(cannot_write_file(path))
  887 + ok then changed_v <- false; ok(unique)
  888 + }.
  889 +
  890 +
  891 +
  892 + Tables in the data base are either loaded or not.
  893 +
  894 +type DBTableState($Row,$HRow):
  895 + not_loaded (String table_name,
  896 + ($Row,$Row) -> Bool compare,
  897 + $HRow -> $Row update,
  898 + $Row -> $HRow store),
  899 + loaded (DBLoadedTable($Row,$HRow)).
  900 +
  901 + Now a table is just a variable containing either a non loaded table or a loaded table.
  902 +
  903 +public type DBTable($Row,$HRow):
  904 + db_table(Var(DBTableState($Row,$HRow))).
  905 +
  906 +
  907 + The data base itself is made of the directory path for table files, and the set of
  908 + tables (loaded or not).
  909 +
  910 +public type DB($MY_DB):
  911 + db(String directory,
  912 + $MY_DB tables).
  913 +
  914 +
  915 +public define DB($MY_DB)
  916 + init_db
  917 + (
  918 + String data_base_directory,
  919 + $MY_DB tables
  920 + ) =
  921 + forget(make_directory(data_base_directory,default_directory_mode));
  922 + db(data_base_directory,tables).
  923 +
  924 +public define DBTable($Row,$HRow)
  925 + init_dbtable
  926 + (
  927 + String table_name,
  928 + ($Row,$Row) -> Bool compare,
  929 + $HRow -> $Row update,
  930 + $Row -> $HRow store
  931 + ) =
  932 + db_table(var(not_loaded(table_name,compare,update,store))).
  933 +
  934 +
  935 + Given a data base and a table in the form of a destructor of type MY_DB, the next
  936 + function returns the table in the form of a loaded table.
  937 +
  938 +define Result(DBError,DBLoadedTable($Row,$HRow))
  939 + get_table
  940 + (
  941 + DB($MY_DB) the_data_base,
  942 + $MY_DB -> DBTable($Row,$HRow) the_table,
  943 + ) =
  944 + if the_data_base is db(dbdir,my_db) then
  945 + if the_table(my_db) is db_table(table_v) then
  946 + if *table_v is
  947 + {
  948 + not_loaded(table_name,compare,update,store) then
  949 + with file_path = dbdir+"/"+table_name,
  950 + if (RetrieveResult(DBSavedTable($HRow)))retrieve(file_path) is
  951 + {
  952 + cannot_find_file then
  953 + with new_table = install_table(table_name,compare,update,store,myversion_1(0,[])),
  954 + table_v <- loaded(new_table);
  955 + ok(new_table),
  956 +
  957 + read_error then error(file_reading_problem(file_path)),
  958 + type_error then error(file_type_problem(file_path)),
  959 + ok(t) then
  960 + with new_table = install_table(table_name,compare,update,store,t),
  961 + table_v <- loaded(new_table);
  962 + ok(new_table)
  963 + },
  964 +
  965 + loaded(t) then
  966 + ok(t)
  967 + }.
  968 +
  969 +
  970 + Inserting rows. The next function receives two lists (of the same type) which are both
  971 + already sorted. It inserts the elements of the first list at the right place in the
  972 + second list.
  973 +
  974 +define List($T)
  975 + insert // insert elements of l1 into l2
  976 + (
  977 + List($T) l1,
  978 + List($T) l2,
  979 + ($T,$T) -> Bool less
  980 + ) =
  981 + if l1 is
  982 + {
  983 + [ ] then l2,
  984 + [h1 . t1] then
  985 + if l2 is
  986 + {
  987 + [ ] then l1,
  988 + [h2 . t2] then
  989 + if less(h1,h2)
  990 + then [h1 . insert(t1,l2,less)]
  991 + else [h2 . insert(l1,t2,less)]
  992 + }
  993 + }.
  994 +
  995 +
  996 +
  997 + Adding rows. The table contains a list of 'DBRow($Row)' which is already sorted. The
  998 + new rows arrive as data of type '$Row', and need first to be sorted. Then they are
  999 + transformed into 'DBRow($Row)' and inserted in the table. Hence, we need to compare
  1000 + data of type 'DBRow($Row)'.
  1001 +
  1002 + The next function gets a list of nude rows (of type '$Row'), and transforms it into a
  1003 + list of loaded rows, creating a new identifier for each row. This function is run
  1004 + 'protected'.
  1005 +
  1006 +define DBRow($Row)
  1007 + load_row
  1008 + (
  1009 + $Row row,
  1010 + Var(Int32) counter_v
  1011 + ) =
  1012 + protect
  1013 + with c1 = *counter_v,
  1014 + counter_v <- c1+1;
  1015 + dbrow(dbrowid(c1),0,row).
  1016 +
  1017 +define List(DBRow($Row))
  1018 + load_rows
  1019 + (
  1020 + List($Row) rows,
  1021 + Var(Int32) counter_v
  1022 + ) =
  1023 + map(($Row r) |-> load_row(r,counter_v),
  1024 + rows).
  1025 +
  1026 +
  1027 + Finally, in order to add rows to a table, we have to load them (using 'load_rows'
  1028 + above), to sort them, and to insert them in the table. The table is subsequently
  1029 + saved.
  1030 +
  1031 +public define Result(DBError,List(DBRowId($Row)))
  1032 + add_rows
  1033 + (
  1034 + DB($MY_DB) the_data_base,
  1035 + $MY_DB -> DBTable($Row,$HRow) the_table,
  1036 + List($Row) new_rows
  1037 + ) =
  1038 + if get_table(the_data_base,the_table) is
  1039 + {
  1040 + error(msg) then error(msg),
  1041 + ok(loaded_table) then protect
  1042 + if loaded_table is table(table_name,compare,store,changed_v,counter_v,rows_v) then
  1043 + with new_loaded_rows = qsort(load_rows(new_rows,counter_v),compare),
  1044 + new_table_rows = insert(new_loaded_rows,*rows_v,compare),
  1045 + changed_v <- true;
  1046 + rows_v <- new_table_rows;
  1047 + if save_table(directory(the_data_base),loaded_table) is
  1048 + {
  1049 + error(msg) then error(msg),
  1050 + ok(_) then ok(map(row_id,new_loaded_rows))
  1051 + }
  1052 + }.
  1053 +
  1054 +
  1055 +public define Result(DBError,DBRowId($Row))
  1056 + add_row
  1057 + (
  1058 + DB($MY_DB) the_data_base,
  1059 + $MY_DB -> DBTable($Row,$HRow) the_table,
  1060 + $Row new_row
  1061 + ) =
  1062 + if get_table(the_data_base,the_table) is
  1063 + {
  1064 + error(msg) then error(msg),
  1065 + ok(loaded_table) then protect
  1066 + if loaded_table is table(table_name,compare,store,changed_v,counter_v,rows_v) then
  1067 + with new_loaded_row = load_row(new_row,counter_v),
  1068 + new_table_rows = insert([new_loaded_row],*rows_v,compare),
  1069 + changed_v <- true;
  1070 + rows_v <- new_table_rows;
  1071 + if save_table(directory(the_data_base),loaded_table) is
  1072 + {
  1073 + error(msg) then error(msg),
  1074 + ok(_) then ok(row_id(new_loaded_row))
  1075 + }
  1076 + }.
  1077 +
  1078 +
  1079 +
  1080 +
  1081 +
  1082 + Getting a row by its identifier.
  1083 +
  1084 +define Result(DBError,DBRow($Row))
  1085 + get_row
  1086 + (
  1087 + List(DBRow($Row)) rows,
  1088 + DBRowId($Row) row_id
  1089 + ) =
  1090 + if rows is
  1091 + {
  1092 + [ ] then error(record_not_found),
  1093 + [row1 . others] then if row1 is dbrow(id,ver,row) then
  1094 + if row_id = id
  1095 + then ok(row1)
  1096 + else get_row(others,row_id)
  1097 + }.
  1098 +
  1099 +
  1100 +public define Result(DBError,DBRow($Row))
  1101 + get_row
  1102 + (
  1103 + DB($MY_DB) the_data_base,
  1104 + $MY_DB -> DBTable($Row,$HRow) the_table,
  1105 + DBRowId($Row) row_id
  1106 + ) =
  1107 + if get_table(the_data_base,the_table) is
  1108 + {
  1109 + error(msg) then error(msg),
  1110 + ok(loaded_table) then if loaded_table is
  1111 + table(table_name,compare,store,changed_v,counter_v,rows_v) then
  1112 + get_row(*rows_v,row_id)
  1113 + }.
  1114 +
  1115 +
  1116 +
  1117 + Getting rows by their identifiers.
  1118 +
  1119 +
  1120 +define List($T)
  1121 + remove
  1122 + (
  1123 + $T x,
  1124 + List($T) l
  1125 + ) =
  1126 + if l is
  1127 + {
  1128 + [ ] then [ ],
  1129 + [h . t] then
  1130 + if x = h
  1131 + then t
  1132 + else [h . remove(x,t)]
  1133 + }.
  1134 +
  1135 +define Result(DBError,List(DBRow($Row)))
  1136 + get_rows
  1137 + (
  1138 + List(DBRow($Row)) rows,
  1139 + List(DBRowId($Row)) row_ids,
  1140 + List(DBRow($Row)) so_far
  1141 + ) =
  1142 + if rows is
  1143 + {
  1144 + [ ] then ok(reverse(so_far)),
  1145 + [row1 . others] then
  1146 + if row_ids is
  1147 + {
  1148 + [ ] then ok(reverse(so_far)),
  1149 + [_._] then
  1150 + if row1 is dbrow(id,_,_) then
  1151 + if member(row_ids,id)
  1152 + then get_rows(others,remove(id,row_ids),[row1 . so_far])
  1153 + else get_rows(others,row_ids,so_far)
  1154 + }
  1155 + }.
  1156 +
  1157 +public define Result(DBError,List(DBRow($Row)))
  1158 + get_rows
  1159 + (
  1160 + DB($MY_DB) the_data_base,
  1161 + $MY_DB -> DBTable($Row,$HRow) the_table,
  1162 + List(DBRowId($Row)) row_ids
  1163 + ) =
  1164 + if get_table(the_data_base,the_table) is
  1165 + {
  1166 + error(msg) then error(msg),
  1167 + ok(loaded_table) then if loaded_table is
  1168 + table(table_name,compare,store,changed_v,counter_v,rows_v) then
  1169 + get_rows(*rows_v,row_ids,[])
  1170 + }.
  1171 +
  1172 +
  1173 +
  1174 +
  1175 + Getting rows satifying a condition.
  1176 +
  1177 +
  1178 +
  1179 +define Result(DBError,List(DBRow($Row)))
  1180 + get_rows
  1181 + (
  1182 + List(DBRow($Row)) rows,
  1183 + DBRow($Row) -> Bool which,
  1184 + List(DBRow($Row)) so_far
  1185 + ) =
  1186 + if rows is
  1187 + {
  1188 + [ ] then ok(reverse(so_far)),
  1189 + [row1 . others] then
  1190 + if which(row1)
  1191 + then get_rows(others,which,[row1 . so_far])
  1192 + else get_rows(others,which,so_far)
  1193 + }.
  1194 +
  1195 +public define Result(DBError,List(DBRow($Row)))
  1196 + get_rows
  1197 + (
  1198 + DB($MY_DB) the_data_base,
  1199 + $MY_DB -> DBTable($Row,$HRow) the_table,
  1200 + DBRow($Row) -> Bool which
  1201 + ) =
  1202 + if get_table(the_data_base,the_table) is
  1203 + {
  1204 + error(msg) then error(msg),
  1205 + ok(loaded_table) then if loaded_table is
  1206 + table(table_name,compare,store,changed_v,counter_v,rows_v) then
  1207 + get_rows(*rows_v,which,[])
  1208 + }.
  1209 +
  1210 +
  1211 +public define Result(DBError,List(DBRow($Row)))
  1212 + get_rows
  1213 + (
  1214 + DB($MY_DB) the_data_base,
  1215 + $MY_DB -> DBTable($Row,$HRow) the_table,
  1216 + $Row -> Bool which
  1217 + ) =
  1218 + get_rows(the_data_base,the_table,
  1219 + (DBRow($Row) r) |-> which(row(r))).
  1220 +
  1221 +
  1222 +
  1223 + Getting a number of rows.
  1224 +
  1225 +define Result(DBError,Int32)
  1226 + count_rows
  1227 + (
  1228 + List(DBRow($Row)) rows,
  1229 + DBRow($Row) -> Bool which,
  1230 + Int32 so_far
  1231 + ) =
  1232 + if rows is
  1233 + {
  1234 + [ ] then ok(so_far),
  1235 + [h . t] then
  1236 + if which(h)
  1237 + then count_rows(t,which,so_far+1)
  1238 + else count_rows(t,which,so_far)
  1239 + }.
  1240 +
  1241 +public define Result(DBError,Int32)
  1242 + get_number_of_rows
  1243 + (
  1244 + DB($MY_DB) the_data_base,
  1245 + $MY_DB -> DBTable($Row,$HRow) the_table,
  1246 + DBRow($Row) -> Bool which
  1247 + ) =
  1248 + if get_table(the_data_base,the_table) is
  1249 + {
  1250 + error(msg) then error(msg),
  1251 + ok(loaded_table) then if loaded_table is
  1252 + table(table_name,compare,store,changed_v,counter_v,rows_v) then
  1253 + count_rows(*rows_v,which,0)
  1254 + }.
  1255 +
  1256 +
  1257 +define Result(DBError,Bool)
  1258 + has_more_rows_than
  1259 + (
  1260 + List(DBRow($Row)) rows,
  1261 + DBRow($Row) -> Bool which,
  1262 + Int32 n
  1263 + ) =
  1264 + if rows is
  1265 + {
  1266 + [ ] then ok(false),
  1267 + [h . t] then
  1268 + if which(h)
  1269 + then if n =< 0
  1270 + then ok(true)
  1271 + else has_more_rows_than(t,which,n-1)
  1272 + else has_more_rows_than(t,which,n)
  1273 + }.
  1274 +
  1275 +public define Result(DBError,Bool)
  1276 + has_more_rows_than
  1277 + (
  1278 + DB($MY_DB) the_data_base,
  1279 + $MY_DB -> DBTable($Row,$HRow) the_table,
  1280 + DBRow($Row) -> Bool which,
  1281 + Int32 n
  1282 + ) =
  1283 + if get_table(the_data_base,the_table) is
  1284 + {
  1285 + error(msg) then error(msg),
  1286 + ok(loaded_table) then if loaded_table is
  1287 + table(table_name,compare,store,changed_v,counter_v,rows_v) then
  1288 + has_more_rows_than(*rows_v,which,n)
  1289 + }.
  1290 +
  1291 +
  1292 +
  1293 +
  1294 + Updating rows. Rows which satisfy the 'which' condition are first extracted from the
  1295 + table and updated by 'how'. Then the list of updated rows is sorted, and reinserted
  1296 + into the table. Subsequently, the table is saved.
  1297 +
  1298 + The next function receives a list and a test applicable to elements of that list. It
  1299 + separates the list into the list of those elements which satisfy the test, and the list
  1300 + of those element which do not satisfy the test.
  1301 +
  1302 +define (
  1303 + List($T), // those satisfying the test
  1304 + List($T) // those not satisfying the test
  1305 + )
  1306 + separ_list
  1307 + (
  1308 + List($T) l,
  1309 + $T -> Bool test
  1310 + ) =
  1311 + if l is
  1312 + {
  1313 + [ ] then ([],[]),
  1314 + [h . t] then if separ_list(t,test) is (others_yes,others_no) then
  1315 + if test(h)
  1316 + then ([h . others_yes],others_no)
  1317 + else (others_yes,[h . others_no])
  1318 + }.
  1319 +
  1320 + The same one for separating only one element.
  1321 +
  1322 +define (
  1323 + Maybe($T), // separated element
  1324 + List($T) // other elements
  1325 + )
  1326 + separ_element
  1327 + (
  1328 + List($T) l,
  1329 + $T -> Bool test
  1330 + ) =
  1331 + if l is
  1332 + {
  1333 + [ ] then (failure,[]),
  1334 + [h . t] then
  1335 + if test(h)
  1336 + then (success(h),t)
  1337 + else if separ_element(t,test) is (mb_e,t1) then (mb_e,[h . t1])
  1338 + }.
  1339 +
  1340 +
  1341 +
  1342 +
  1343 +public define Result(DBError,DBUpdateResult($Row))
  1344 + update_row
  1345 + (
  1346 + DB($MY_DB) the_data_base,
  1347 + $MY_DB -> DBTable($Row,$HRow) the_table,
  1348 + DBRowId($Row) row_id,
  1349 + DBRow($Row) -> Maybe($Row) how
  1350 + ) =
  1351 + if get_table(the_data_base,the_table) is
  1352 + {
  1353 + error(msg) then error(msg),
  1354 + ok(loaded_table) then if loaded_table is
  1355 + table(table_name,compare,store,changed_v,counter_v,rows_v) then protect
  1356 + changed_v <- true;
  1357 + if separ_element(*rows_v,(DBRow($Row) r) |->
  1358 + if r is dbrow(rid,ver,row) then rid = row_id)
  1359 + is (mb_extracted_row,other_rows) then
  1360 + if mb_extracted_row is
  1361 + {
  1362 + failure then error(record_not_found),
  1363 + success(idrow) then
  1364 + if how(idrow) is
  1365 + {
  1366 + failure then ok(not_updated(idrow)),
  1367 + success(new_row) then
  1368 + with new_idrow = dbrow(row_id,version(idrow)+1,new_row),
  1369 + rows_v <- insert([new_idrow],other_rows,compare);
  1370 + if save_table(directory(the_data_base),loaded_table) is
  1371 + {
  1372 + error(msg) then error(msg),
  1373 + ok(_) then ok(updated(new_idrow))
  1374 + }
  1375 + }
  1376 + }
  1377 + }.
  1378 +
  1379 +
  1380 +public define Result(DBError,List(DBUpdateResult($Row)))
  1381 + update_rows
  1382 + (
  1383 + DB($MY_DB) the_data_base,
  1384 + $MY_DB -> DBTable($Row,$HRow) the_table,
  1385 + List(DBRowId($Row)) row_ids,
  1386 + DBRow($Row) -> Maybe($Row) how
  1387 + ) =
  1388 + if get_table(the_data_base,the_table) is
  1389 + {
  1390 + error(msg) then error(msg),
  1391 + ok(loaded_table) then if loaded_table is
  1392 + table(table_name,compare,store,changed_v,counter_v,rows_v) then protect
  1393 + changed_v <- true;
  1394 + if separ_list(*rows_v,(DBRow($Row) r) |->
  1395 + if r is dbrow(row_id,ver,row) then member(row_ids,row_id))
  1396 + is (extracted_rows,other_rows) then
  1397 + with updated_rows = qsort(map((DBRow($Row) r) |->
  1398 + if how(r) is
  1399 + {
  1400 + failure then not_updated(r)
  1401 + success(new_r) then updated(dbrow(row_id(r),version(r)+1,new_r))
  1402 + },
  1403 + extracted_rows),
  1404 + (DBUpdateResult($Row) ur1, DBUpdateResult($Row) ur2) |->
  1405 + compare(the_row(ur1),the_row(ur2))),
  1406 + rows_v <- insert(map(the_row,updated_rows),other_rows,compare);
  1407 + if save_table(directory(the_data_base),loaded_table) is
  1408 + {
  1409 + error(msg) then error(msg),
  1410 + ok(_) then ok(updated_rows)
  1411 + }
  1412 + }.
  1413 +
  1414 +
  1415 +public define Result(DBError,List(DBUpdateResult($Row)))
  1416 + update_rows
  1417 + (
  1418 + DB($MY_DB) the_data_base,
  1419 + $MY_DB -> DBTable($Row,$HRow) the_table,
  1420 + $Row -> Bool which,
  1421 + DBRow($Row) -> Maybe($Row) how
  1422 + ) =
  1423 + if get_table(the_data_base,the_table) is
  1424 + {
  1425 + error(msg) then error(msg),
  1426 + ok(loaded_table) then if loaded_table is
  1427 + table(table_name,compare,store,changed_v,counter_v,rows_v) then protect
  1428 + changed_v <- true;
  1429 + if separ_list(*rows_v,(DBRow($Row) r) |->
  1430 + if r is dbrow(row_id,ver,row) then which(row))
  1431 + is (extracted_rows,other_rows) then
  1432 + with updated_rows = qsort(map((DBRow($Row) r) |->
  1433 + if how(r) is
  1434 + {
  1435 + failure then not_updated(r),
  1436 + success(new_r) then updated(dbrow(row_id(r),version(r)+1,new_r))
  1437 + },
  1438 + extracted_rows),
  1439 + (DBUpdateResult($Row) ur1, DBUpdateResult($Row) ur2) |->
  1440 + compare(the_row(ur1),the_row(ur2))),
  1441 + rows_v <- insert(map(the_row,updated_rows),other_rows,compare);
  1442 + if save_table(directory(the_data_base),loaded_table) is
  1443 + {
  1444 + error(msg) then error(msg),
  1445 + ok(_) then ok(updated_rows)
  1446 + }
  1447 + }.
  1448 +
  1449 +
  1450 +
  1451 + Deleting rows.
  1452 +
  1453 +
  1454 +define Result(DBError,
  1455 + ($Row, // the deleted row
  1456 + List(DBRow($Row))) // the remaining rows
  1457 + )
  1458 + delete_row
  1459 + (
  1460 + List(DBRow($Row)) l,
  1461 + DBRowId($Row) row_id
  1462 + ) =
  1463 + if l is
  1464 + {
  1465 + [ ] then error(record_not_found),
  1466 + [h . t] then if h is dbrow(i,v,r) then
  1467 + if i = row_id
  1468 + then ok((row(h),t))
  1469 + else if delete_row(t,row_id) is
  1470 + {
  1471 + error(msg) then error(msg),
  1472 + ok(result1) then if result1 is (deleted,remaining) then
  1473 + ok((deleted,[h . remaining]))
  1474 + }
  1475 + }.
  1476 +
  1477 +public define Result(DBError,$Row)
  1478 + delete_row
  1479 + (
  1480 + DB($MY_DB) the_data_base,
  1481 + $MY_DB -> DBTable($Row,$HRow) the_table,
  1482 + DBRowId($Row) row_id
  1483 + ) =
  1484 + if get_table(the_data_base,the_table) is
  1485 + {
  1486 + error(msg) then error(msg),
  1487 + ok(loaded_table) then if loaded_table is
  1488 + table(table_name,compare,store,changed_v,counter_v,rows_v) then protect
  1489 + if delete_row(*rows_v,row_id) is
  1490 + {
  1491 + error(msg) then error(msg),
  1492 + ok(d_rows) then if d_rows is (deleted,rows) then
  1493 + changed_v <- true;
  1494 + rows_v <- rows;
  1495 + if save_table(directory(the_data_base),loaded_table) is
  1496 + {
  1497 + error(msg) then error(msg),
  1498 + ok(_) then ok(deleted)
  1499 + }
  1500 + }
  1501 + }.
  1502 +
  1503 +define (List($Row),List(DBRow($Row))) // (deleted rows, remaining rows)
  1504 + delete_rows
  1505 + (
  1506 + List(DBRow($Row)) rows,
  1507 + $Row -> Bool which
  1508 + ) =
  1509 + if rows is
  1510 + {
  1511 + [ ] then ([ ],[ ]),
  1512 + [row1 . others] then
  1513 + if delete_rows(others,which) is (deleted_others,remaining_others) then
  1514 + if row1 is dbrow(id,ver,row) then
  1515 + if which(row)
  1516 + then ([row . deleted_others],remaining_others)
  1517 + else (deleted_others,[row1 . remaining_others])
  1518 + }.
  1519 +
  1520 +public define Result(DBError,List($Row))
  1521 + delete_rows
  1522 + (
  1523 + DB($MY_DB) the_data_base,
  1524 + $MY_DB -> DBTable($Row,$HRow) the_table,
  1525 + $Row -> Bool which
  1526 + ) =
  1527 + if get_table(the_data_base,the_table) is
  1528 + {
  1529 + error(msg) then error(msg),
  1530 + ok(loaded_table) then if loaded_table is
  1531 + table(table_name,compare,store,changed_v,counter_v,rows_v) then protect
  1532 + if delete_rows(*rows_v,which) is (deleted,remaining) then
  1533 + changed_v <- true;
  1534 + rows_v <- remaining;
  1535 + if save_table(directory(the_data_base),loaded_table) is
  1536 + {
  1537 + error(msg) then error(msg),
  1538 + ok(_) then ok(deleted)
  1539 + }
  1540 + }.
  1541 +
  1542 +
  1543 +
  1544 +
  1545 +
  1546 +
  1547 + Multi-tables queries.
  1548 +
  1549 +
  1550 +define List($Out)
  1551 + remove_repetitions
  1552 + (
  1553 + List($Out) l
  1554 + ) =
  1555 + if l is
  1556 + {
  1557 + [ ] then [ ],
  1558 + [h . t] then
  1559 + if member(t,h)
  1560 + then remove_repetitions(t)
  1561 + else [h . remove_repetitions(t)]
  1562 + }.
  1563 +
  1564 +
  1565 +define List($T)
  1566 + flatten
  1567 + (
  1568 + List(List($T)) l
  1569 + ) =
  1570 + if l is
  1571 + {
  1572 + [ ] then [ ],
  1573 + [h . t] then h + flatten(t)
  1574 + }.
  1575 +
  1576 +public define List($Out)
  1577 + query
  1578 + (
  1579 + DB($MY_DB) the_data_base,
  1580 + $MY_DB -> DBTable($Row,$HRow) the_first_table,
  1581 + DBRow($Row) -> Bool the_first_condition,
  1582 + (DBRow($Row),$In) -> $Out the_first_selection,
  1583 + DBRow($Row) -> List($In) the_subquery
  1584 + ) =
  1585 + if get_rows(the_data_base,the_first_table,the_first_condition) is
  1586 + {
  1587 + error(msg) then [ ],
  1588 + ok(rows) then
  1589 + remove_repetitions(flatten(
  1590 + map((DBRow($Row) row) |->
  1591 + map(($In i) |-> the_first_selection(row,i),the_subquery(row)),
  1592 + rows)))
  1593 + }.
  1594 +
  1595 +
  1596 +
  1597 +
  1598 +
  1599 +
... ...
anubis_dev/library/tools/sdbms2.anubis
... ... @@ -49,9 +49,9 @@
49 49  
50 50 *** (2) Data base and table structure.
51 51 *** (2.1) Data base roots.
52   - *** (2.2) Tables.
53   - *** (2.3) Indexing.
54   - *** (2.4) Errors.
  52 + *** (2.2) Errors and informations.
  53 + *** (2.3) Tables.
  54 + *** (2.4) Indexing.
55 55 *** (2.5) Initializing a table.
56 56 *** (2.6) Initializing an index.
57 57 *** (2.7) Data bases.
... ... @@ -118,11 +118,11 @@ public type DB2Info:... (see below)
118 118 In order to create a data base root, use the following tool:
119 119  
120 120 public define DB2Root
121   - root
  121 + make_root
122 122 (
123 123 String directory, // where the files will be located
124 124 Int32 kilo_bytes, // maximal number of kilo bytes in memory
125   - Int32 delay, // maximal synchronization delay between memory and files
  125 + Int32 delay, // maximal synchronisation delay between memory and files
126 126 Var(Bool) shutdown_v, // shutdown flag
127 127 DB2Error -> One warn, // warning function for administrator
128 128 DB2Info -> One inform // information function for administrator
... ... @@ -131,19 +131,19 @@ public define DB2Root
131 131 Create as many data base roots as you have data bases in your project. Choose distinct
132 132 directories for all data base roots.
133 133  
134   - 'kilo_bytes' determines the maximal number of kilo bytes the data base may occupy in
  134 + 'kilo_bytes' determines the maximal number of kilobytes the data base may occupy in
135 135 memory (RAM). When the memory occupied by the data base becomes greater than this
136 136 value, those chunks and tables which have been used the less recently are unloaded from
137 137 memory.
138 138  
139 139 'delay' is the maximal number of seconds which may elapse between a modification of a
140   - table in the memory and the synchronization with the data on the disk.
  140 + table in the memory and the synchronisation with the data on the disk.
141 141  
142 142 The dynamic variable 'shutdown_v' is the 'shutdown flag'. When the tables are
143 143 initialized this variable receives the value 'false'. As soon as you put the value
144 144 'true' in this variable, all the table which have been initialized with this root are
145 145 shutdown, which means that no more utilization command may work, and that the data on
146   - the disk are synchronized with the content of the memory. You should probably create
  146 + the disk are synchronised with the content of the memory. You should probably create
147 147 only one such variable for all the data bases of your program, i.e. even if you create
148 148 several data base roots, you should provide the same shutdown flag to all these
149 149 roots. Nevertheless, if you want to shutdown your data bases at distinct times, use
... ... @@ -184,16 +184,49 @@ public type DB2Info:
184 184 loading_chunk (String path),
185 185 unloading_chunk (String path),
186 186 beginning_chunk_synchronisation (String path),
187   - ending_chunk_synchronisation (String path),
188   - beginning_table_move (String path, Int32 old_bits, Int32 new_bits),
189   - ending_table_move (String path, Int32 old_bits, Int32 new_bits).
  187 + ending_chunk_synchronisation (String path).
190 188  
191 189  
192 190 Data of these types are transmitted to the functions 'warn' and 'inform', that you must
193 191 provide when you create your data base root.
  192 +
  193 + For your convenience we provide the following formating functions transforming data of
  194 + type DB2Error and DB2Info into English sentences:
194 195  
  196 +public define String
  197 + en_format
  198 + (
  199 + DB2Error e
  200 + ) =
  201 + if e is
  202 + {
  203 + file_not_found(p) then "File not found: '"+p+"'",
  204 + file_reading_problem(p) then "Cannot read file: '"+p+"'",
  205 + file_type_problem(p) then "Incompatible type: '"+p+"'",
  206 + cannot_open_file(p) then "Cannot open file: '"+p+"'",
  207 + cannot_write_file(p) then "Cannot write into file: '"+p+"'",
  208 + cannot_find_index(d,t,i) then "Cannot find index: '"+d+"/t_"+t+"["+i+"]"
  209 + }.
195 210  
196 211  
  212 +public define String
  213 + en_format
  214 + (
  215 + DB2Info i
  216 + ) =
  217 + if i is
  218 + {
  219 + creating_table(p) then "Creating table: '"+p+"'",
  220 + loading_table(p) then "Loading table: '"+p+"'",
  221 + unloading_table(p) then "Unloading table: '"+p+"'",
  222 + beginning_table_synchronisation(p) then "Beginning table synchronisation: '"+p+"'",
  223 + ending_table_synchronisation(p) then "Ending table synchronisation: '"+p+"'",
  224 + creating_chunk(p) then "Creating chunk: '"+p+"'",
  225 + loading_chunk(p) then "Loading chunk: '"+p+"'",
  226 + unloading_chunk(p) then "Unloading chunk: '"+p+"'",
  227 + beginning_chunk_synchronisation(p) then "Beginning chunk synchronisation: '"+p+"'",
  228 + ending_chunk_synchronisation(p) then "Ending chunk synchronisation: '"+p+"'"
  229 + }.
197 230  
198 231  
199 232 *** (2.3) Tables.
... ... @@ -749,41 +782,50 @@ public define List(Result(DB2Error,$Row))
749 782 *** [1.1] Chunks.
750 783 *** [1.2] Secondary indexes.
751 784 *** [1.3] Tables.
752   -
753 785 *** [2] Initializing.
754 786 *** [2.1] Roots.
755 787 *** [2.2] Tables.
756 788 *** [2.3] Indexes.
757   -
758 789 *** [3] Tools for getting tables, chunks and indexes.
  790 + *** [3.5] Loading a secondary index.
759 791 *** [3.1] Loading a table.
760 792 *** [3.2] Getting a table.
761 793 *** [3.3] Loading a chunk.
762 794 *** [3.4] Getting a chunk.
763   - *** [3.5] Loading a secondary index.
764 795 *** [3.6] Getting a secondary index.
765   -
766 796 *** [4] Adding rows.
767   - *** [4.1] Computing the size of a row.
768 797 *** [4.2] Adding a set of rows.
769 798 *** [4.3] The public tool 'add_rows'.
770 799 *** [4.4] The public tool 'add_row'.
771   -
772 800 *** [5] Row selection.
773   -
774 801 *** [6] Acting on rows.
775 802 *** [6.1] Acting on selected rows of a chunk.
776   - *** [6.2] Acting on a chunk.
777   - *** [6.3] Acting by condition.
778   - *** [6.4] Acting by primary index.
779   - *** [6.5] Acting by secondary index.
780   -
  803 + *** [6.2] Waiting for the end of chunk synchronisation.
  804 + *** [6.3] Acting on a chunk.
  805 + *** [6.4] Acting by condition.
  806 + *** [6.5] Acting by primary index.
  807 + *** [6.6] Acting by secondary index.
  808 + *** [6.7] Waiting for the end of table synchronisation.
  809 + *** [6.8] Acting in general.
781 810 *** [7] Utilization commands.
782 811 *** [7.1] 'get_rows'.
783 812 *** [7.2] 'update_rows'.
784 813 *** [7.3] 'delete_rows'.
785   -
786   - *** [8] Synchronizing memory with disk.
  814 + *** [8] Synchronising memory with disk.
  815 + *** [8.1] Synchronising a table file.
  816 + *** [8.2] Synchronising chunk files.
  817 + *** [8.2.1] One chunk.
  818 + *** [8.2.2] One 'new' chunks (moving table).
  819 + *** [8.2.2.1] 'Increasing' case.
  820 + *** [8.2.2.2] 'Decreasing' case.
  821 + *** [8.2.2.3] Both cases.
  822 + *** [8.2.3] All chunks.
  823 + *** [8.4] Synchronising everything.
  824 + *** [8.5] Asking for delayed synchronisation.
  825 + *** [9] Changing the number of bits of hash.
  826 + *** [9.1] Hashing.
  827 + *** [9.2] Deciding to change the number of bits of hash.
  828 + *** [9.3] Performing a change.
787 829  
788 830 ---------------------------------------------------------------------------------------
789 831  
... ... @@ -834,7 +876,7 @@ type Chunk($Row):
834 876 because, when memory becomes low, we need to unload some chunks. We unload those chunks
835 877 which have not been used since the longuest time.
836 878  
837   - The 'changed_v' flag means when 'true' that the chunk is not synchronized with its file
  879 + The 'changed_v' flag means when 'true' that the chunk is not synchronised with its file
838 880 on the disk. The flag 'transfered_v' is used when the table is moving (see below). Of
839 881 course, the component 'rows_v' contains the list of all rows in this chunk. Normally a
840 882 very short list.
... ... @@ -1213,7 +1255,7 @@ define Result(DB2Error,LoadedTable($Row,$HRow))
1213 1255 store,
1214 1256 locked,
1215 1257 var(unchanged), // changed_v
1216   - 0, // bits_of_hash
  1258 + 10, // bits_of_hash
1217 1259 mvar(1,not_loaded), // only 1 chunk
1218 1260 index_name(primary_index),
1219 1261 hash_row(primary_index),
... ... @@ -1300,7 +1342,7 @@ define Result(DB2Error,LoadedChunk($Row))
1300 1342 cannot_find_file then
1301 1343 with c = (LoadedChunk($Row))lchunk(
1302 1344 var(now), // last used
1303   - var(changed), // not synchronized with disk
  1345 + var(changed), // not synchronised with disk
1304 1346 var(false), // transfered
1305 1347 var([])), // rows
1306 1348 chunks(hash) <- loaded(c);
... ... @@ -1315,7 +1357,7 @@ define Result(DB2Error,LoadedChunk($Row))
1315 1357 ok(cf) then if cf is chunk(rows) then
1316 1358 with c = (LoadedChunk($Row))lchunk(
1317 1359 var(now), // last used
1318   - var(unchanged), // synchronized with disk
  1360 + var(unchanged), // synchronised with disk
1319 1361 var(false), // transfered
1320 1362 var(map(update,rows))),
1321 1363 chunks(hash) <- loaded(c);
... ... @@ -1480,13 +1522,19 @@ public define Result(DB2Error,One)
1480 1522  
1481 1523  
1482 1524 *** [5] Row selection.
  1525 +
  1526 + Rows in a table may be selected (regardless of the type of action) via several
  1527 + different methods.
1483 1528  
1484   -public type DB2Select($Row):
1485   - cond($Row -> Bool which),
1486   - prim(ByteArray serialized_model),
1487   - secd(String secondary_index_name,
  1529 +public type DB2Select($Row): // an opaque type
  1530 + cond($Row -> Bool which), // by condition
  1531 + prim(ByteArray serialized_model), // by primary index
  1532 + secd(String secondary_index_name, // by secondary index
1488 1533 ByteArray serialized_model).
1489 1534  
  1535 +
  1536 + Interface constructors for this opaque type.
  1537 +
1490 1538 public define DB2Select($Row)
1491 1539 condition
1492 1540 (
... ... @@ -1495,6 +1543,9 @@ public define DB2Select($Row)
1495 1543 cond(which).
1496 1544  
1497 1545  
  1546 + Of course, the types $Primary and $Secondary must disappear from the selection
  1547 + method. This is why we serialize the given model.
  1548 +
1498 1549 public define DB2Select($Row)
1499 1550 primary
1500 1551 (
... ... @@ -1515,6 +1566,7 @@ public define DB2Select($Row)
1515 1566  
1516 1567  
1517 1568  
  1569 +
1518 1570 *** [6] Acting on rows.
1519 1571  
1520 1572 We need to be able to act in several different ways on a set of rows, selected by a
... ... @@ -1525,16 +1577,18 @@ public define DB2Select($Row)
1525 1577 - deleting rows.
1526 1578  
1527 1579  
1528   - The type below records what can happen to a row:
  1580 + The type below records what can happen to a row after the action is performed:
1529 1581  
1530 1582 type NewRow($Row):
1531   - deleted,
1532   - unchanged,
1533   - changed($Row new_row).
  1583 + deleted, // the row has been deleted
  1584 + unchanged, // the row did not change
  1585 + changed($Row new_row). // the value of the row has been changed,
  1586 + // and here is the new value
  1587 +
1534 1588  
1535 1589 The function which acts on a row has type:
1536 1590  
1537   - $Row -> (NewRow($Row),Maybe($Result))
  1591 + $Row -> (NewRow($Row),Maybe($Result))
1538 1592  
1539 1593 regardless of the sort of action performed. It returns eventually a new row (this is
1540 1594 considered as a change of value).
... ... @@ -1545,9 +1599,19 @@ type NewRow($Row):
1545 1599 define One
1546 1600 ask_for_delayed_synchronisation // defined below in this file
1547 1601 (
1548   - LoadedTable($Row,$HRow) the_table,
  1602 + LoadedTable($Row,$HRow) the_table
1549 1603 ).
1550 1604  
  1605 +define One
  1606 + ask_for_delayed_synchronisation // defined below in this file
  1607 + (
  1608 + LoadedChunk($Row) the_chunk
  1609 + ).
  1610 +
  1611 + This function starts a virtual machine for delayed synchronisation, except if one is
  1612 + already started.
  1613 +
  1614 +
1551 1615  
1552 1616  
1553 1617  
... ... @@ -1603,8 +1667,30 @@ define (List($Row), // new rows of chunk
1603 1667  
1604 1668  
1605 1669  
  1670 + *** [6.2] Waiting for the end of chunk synchronisation.
1606 1671  
1607   - *** [6.2] Acting on a chunk.
  1672 + The next 'waiting' function is used to forbid operation on a chunk while it is
  1673 + synchronising.
  1674 +
  1675 +define One
  1676 + wait_for_end_of_synchronisation
  1677 + (
  1678 + Var(ChunkSynState) st_v
  1679 + ) =
  1680 + if *st_v is
  1681 + {
  1682 + unchanged then unique,
  1683 + changed then unique,
  1684 + synchronising then
  1685 + checking every 1 millisecond,
  1686 + wait for *st_v /= synchronising then
  1687 + unique
  1688 + }.
  1689 +
  1690 +
  1691 +
  1692 +
  1693 + *** [6.3] Acting on a chunk.
1608 1694  
1609 1695 This is the interface to the previous function. We are given a chunk and an action. The
1610 1696 chunk is updated.
... ... @@ -1616,40 +1702,21 @@ define List($Result)
1616 1702 LoadedChunk($Row) c,
1617 1703 $Row -> (NewRow($Row),Maybe($Result)) act
1618 1704 ) =
  1705 + protect
1619 1706 if c is lchunk(lu_v,st_v,tr_v,rows_v) then
1620   - wait_for_end_of_synchronization(st_v);
1621   - if act_on_chunk_rows(*rows_v,act) is (new_rows,result,changed) then
  1707 + wait_for_end_of_synchronisation(st_v);
  1708 + if act_on_chunk_rows(*rows_v,act) is (new_rows,result,ch) then
1622 1709 rows_v <- new_rows;
1623 1710 lu_v <- now;
  1711 + (if ch then st_v <- changed else unique);
  1712 + result.
1624 1713  
1625   -
1626   - if changed
1627   - then
1628   - (
1629   -
1630   - )
1631   - else
1632   - (
1633   - )
1634   - if *st_v is
1635   - {
1636   - unchanged then
1637   - changed then
1638   - synchronizing then
1639   - };
1640   - result.
1641   -
1642   -
1643   - then unique else
1644   - (ch_v <- changed);
1645   - ask_for_delayed_synchronisation(the_table));
1646   - result.
1647   -
  1714 +
1648 1715  
1649 1716  
1650 1717  
1651 1718  
1652   - *** [6.3] Acting by condition.
  1719 + *** [6.4] Acting by condition.
1653 1720  
1654 1721 We want to act on all rows of a table (actually we apply 'act' to all rows, but 'act'
1655 1722 may not select some rows). We have to work on all chunks. Hence, the function is a loop
... ... @@ -1708,7 +1775,7 @@ define List(Result(DB2Error,$Result))
1708 1775  
1709 1776  
1710 1777  
1711   - *** [6.4] Acting by primary index.
  1778 + *** [6.5] Acting by primary index.
1712 1779  
1713 1780 We are given the serialization 'serialized_model' of the primary datum to be searched
1714 1781 for. From this serialization and the number of bits of hash, we compute the hash of the
... ... @@ -1741,7 +1808,7 @@ define List(Result(DB2Error,$Result))
1741 1808  
1742 1809  
1743 1810  
1744   - *** [6.5] Acting by secondary index.
  1811 + *** [6.6] Acting by secondary index.
1745 1812  
1746 1813 We are again given a serialization of a secondary datum to be searched for. We first
1747 1814 hash this datum so as to get a secondary hash 's_hash'. We are also given the name of
... ... @@ -1788,9 +1855,9 @@ define List(Result(DB2Error,$Result))
1788 1855  
1789 1856  
1790 1857  
1791   - *** [6.7] Waiting for the end of the synchronisation.
  1858 + *** [6.7] Waiting for the end of table synchronisation.
1792 1859  
1793   - The newt 'waiting' function is used to forbid operations on a table while it is
  1860 + The next 'waiting' function is used to forbid operations on a table while it is
1794 1861 synchronising.
1795 1862  
1796 1863 define One
... ... @@ -1853,6 +1920,14 @@ define List(Result(DB2Error,$Result))
1853 1920  
1854 1921  
1855 1922  
  1923 +
  1924 +
  1925 +
  1926 +
  1927 +
  1928 +
  1929 +
  1930 +
1856 1931 *** [7] Utilization commands.
1857 1932  
1858 1933  
... ... @@ -1947,6 +2022,7 @@ public define List(Result(DB2Error,$Row))
1947 2022  
1948 2023 *** [8.1] Synchronising a table file.
1949 2024  
  2025 + Getting the list of all entries from a multiple variable.
1950 2026  
1951 2027 define List($T)
1952 2028 to_list
... ... @@ -1999,10 +2075,11 @@ define One
1999 2075  
2000 2076  
2001 2077 *** [8.2] Synchronising chunk files.
2002   -
2003   -
  2078 +
2004 2079 *** [8.2.1] One chunk.
2005 2080  
  2081 + Synchronising a single chunk file.
  2082 +
2006 2083 define One
2007 2084 synchronise_chunk_file
2008 2085 (
... ...