diff options
Diffstat (limited to 'system/doc')
50 files changed, 1499 insertions, 3656 deletions
diff --git a/system/doc/book.xml b/system/doc/book.xml deleted file mode 100644 index d1ec093019..0000000000 --- a/system/doc/book.xml +++ /dev/null @@ -1,52 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE book SYSTEM "book.dtd"> - -<book xmlns:xi="http://www.w3.org/2001/XInclude"> - <header titlestyle="normal"> - <copyright> - <year>1997</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>Erlang/OTP System Documentation</title> - <prepared>OTP Team</prepared> - <docno></docno> - <date>2009-08-21</date> - <rev>A</rev> - <file>book.xml</file> - </header> - <insidecover> - </insidecover> - <pagetext></pagetext> - <preamble> - <contents level="2"></contents> - </preamble> - <parts lift="no"> - <xi:include href="installation_guide/part.xml"/> - <xi:include href="system_principles/part.xml"/> - <xi:include href="embedded/part.xml"/> - <xi:include href="getting_started/part.xml"/> - <xi:include href="reference_manual/part.xml"/> - <xi:include href="getting_started/part.xml"/> - <xi:include href="efficiency_guide/part.xml"/> - <xi:include href="tutorial/part.xml"/> - <xi:include href="design_principles/part.xml"/> - <xi:include href="oam/part.xml"/> - </parts> - <listofterms></listofterms> - <index></index> -</book> - diff --git a/system/doc/extensions/Makefile b/system/doc/extensions/Makefile deleted file mode 100644 index cfc506f7e8..0000000000 --- a/system/doc/extensions/Makefile +++ /dev/null @@ -1,142 +0,0 @@ -# ``The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved via the world wide web at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# The Initial Developer of the Original Code is Ericsson Utvecklings AB. -# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -# AB. All Rights Reserved.'' -# -# $Id$ -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# ---------------------------------------------------- -# Application version -# ---------------------------------------------------- -include $(ERL_TOP)/erts/vsn.mk -#VSN=$(SYSTEM_VSN) - -# ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -include make.dep - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/doc/extensions - -# ---------------------------------------------------- -# Target Specs -# ---------------------------------------------------- -XML_PART_FILES = part.xml -XML_CHAPTER_FILES = \ - funs.xml \ - macros.xml \ - misc.xml \ - include.xml \ - records.xml \ - list_comprehensions.xml \ - bit_syntax.xml - -BOOK_FILES = book.xml - -GIF_FILES = note.gif - -PS_FILES = - -# ---------------------------------------------------- - -HTML_FILES = \ - $(XML_PART_FILES:%.xml=%.html) - -HTMLDIR = . -EXTRA_FILES = $(DEFAULT_GIF_FILES) \ - $(DEFAULT_HTML_FILES) \ - $(XML_CHAPTER_FILES:%.xml=%.html) - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = extensions-$(VSN).pdf -TOP_PS_FILE = extensions-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi $(ERL_TOP)/erts/vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi $(ERL_TOP)/erts/vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -XML_FLAGS += -DVIPS_FLAGS += - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) $(GIF_FILES) - -debug opt: - -clean_tex: - -rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_BOOK) - -clean: - rm -f *.html $(TEX_FILES_USERS_GUIDE) - rm -f $(TOP_PS_FILES) - rm -f errs core *~ $(LATEX_CLEAN) - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR) - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR) -endif -endif - -release_spec: - - - diff --git a/system/doc/extensions/bit_syntax.xml b/system/doc/extensions/bit_syntax.xml deleted file mode 100644 index d86f73cd9a..0000000000 --- a/system/doc/extensions/bit_syntax.xml +++ /dev/null @@ -1,403 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>2000</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>The Bit Syntax</title> - <prepared>Björn Gustavsson</prepared> - <responsible>Bjarne Däcker</responsible> - <docno>1</docno> - <approved>Bjarne DäKer</approved> - <checked></checked> - <date>00-06-21</date> - <rev>PA1</rev> - <file>bit_syntax.sgml</file> - </header> - <p>This section describes the "bit syntax" which was added to - the Erlang language in release 5.0 (R7). - Compared to the original bit syntax prototype - by Claes Wikström and Tony Rogvall (presented on the - Erlang User's Conference 1999), this implementation differs - primarily in the following respects, - </p> - <list type="ordered"> - <item> - <p>the character pairs '<<' and '>>' are used to delimit - a binary patterns and constructor (not '<' and '>' as in - the prototype), - </p> - </item> - <item> - <p>the tail syntax ('|Variable') has been eliminated, - </p> - </item> - <item> - <p>all size expressions must be bound, - </p> - </item> - <item> - <p>a type <c>unit:U</c> has been added, - </p> - </item> - <item> - <p>lists and tuples cannot be generated - </p> - </item> - <item> - <p>there are no paddings whatsoever. - </p> - </item> - </list> - - <section> - <title>Introduction</title> - <p>In Erlang a Bin is used for constructing binaries and - matching binary patterns. A Bin is written with the - following syntax:</p> - <code type="none"><![CDATA[ - <<E1, E2, ... En>> - ]]></code> - <p>A Bin is a low-level sequence of bytes. The purpose of a - Bin is to be able to, from a high level, - <em>construct</em> a binary, - </p> - <code type="none"><![CDATA[ - Bin = <<E1, E2, ... En>> - ]]></code> - <p>in which case all elements must be bound, or to - <em>match</em> a binary, - </p> - <code type="none"><![CDATA[ - <<E1, E2, ... En>> = Bin - ]]></code> - <p>where <c>Bin</c> is bound, and where the elements are bound or unbound, - as in any match. - </p> - <p>Each element specifies a certain <em>segment</em> of the binary. - A segment is is a set of contiguous bits of the binary (not - necessarily on a byte boundary). The first element specifies - the initial segment, the second element specifies the following - segment etc. - </p> - <p>The following examples illustrate how binaries are constructed - or matched, and how elements and tails are specified. - </p> - - <section> - <title>Examples</title> - <p><em>Example 1: </em>A binary can be constructed from a set of - constants or a string literal:</p> - <code type="none"><![CDATA[ - Bin11 = <<1, 17, 42>>, - Bin12 = <<"abc">> - ]]></code> - <p>yields binaries of size 3; <c>binary_to_list(Bin11)</c> - evaluates to <c>[1, 17, 42]</c>, and - <c>binary_to_list(Bin12)</c> evaluates to <c>[97, 98, 99]</c>. - </p> - <p><em>Example 2: </em>Similarly, a binary can be constructed - from a set of bound variables:</p> - <code type="none"><![CDATA[ - A = 1, B = 17, C = 42, - Bin2 = <<A, B, C:16>> - ]]></code> - <p>yields a binary of size 4, and <c>binary_to_list(Bin2)</c> - evaluates to <c>[1, 17, 00, 42]</c> too. Here we used a - <em>size expression</em> for the variable <c>C</c> in order to - specify a 16-bits segment of <c>Bin2</c>. - </p> - <p><em>Example 3: </em>A Bin can also be used for matching: if - <c>D</c>, <c>E</c>, and <c>F</c> are unbound variables, and - <c>Bin2</c> is bound as in the former example,</p> - <code type="none"><![CDATA[ - <<D:16, E, F/binary>> = Bin2 - ]]></code> - <p>yields <c>D = 273</c>, <c>E = 00</c>, and F binds to a binary - of size 1: <c>binary_to_list(F) = [42]</c>. - </p> - <p><em>Example 4: </em>The following is a more elaborate example - of matching, where <c>Dgram</c> is bound to the consecutive - bytes of an IP datagram of IP protocol version 4, and where we - want to extract the header and the data of the datagram:</p> - <code type="none"><![CDATA[ - -define(IP_VERSION, 4). - -define(IP_MIN_HDR_LEN, 5). - - DgramSize = byte_size(Dgram), - case Dgram of - <<?IP_VERSION:4, HLen:4, SrvcType:8, TotLen:16, - ID:16, Flgs:3, FragOff:13, - TTL:8, Proto:8, HdrChkSum:16, - SrcIP:32, - DestIP:32, RestDgram/binary>> when HLen >= 5, 4*HLen =< DgramSize -> - OptsLen = 4*(HLen - ?IP_MIN_HDR_LEN), - <<Opts:OptsLen/binary,Data/binary>> = RestDgram, - ... - end. - ]]></code> - <p>Here the segment corresponding to the <c>Opts</c> variable - has a <em>type modifier</em> specifying that <c>Opts</c> should - bind to a binary. All other variables have the default type - equal to unsigned integer. - </p> - <p>An IP datagram header is of variable length, and its length - - measured in the number of 32-bit words - is given in the segment - corresponding to <c>HLen</c>, the minimum value of which is - 5. It is the segment corresponding to <c>Opts</c> that is - variable: if <c>HLen</c> is equal to 5, <c>Opts</c> will be an - empty binary. - </p> - <p>The tail variables <c>RestDgram</c> and <c>Data</c> bind to - binaries, as all tail variables do. Both may bind to empty - binaries. - </p> - <p>If the first 4-bits segment of <c>Dgram</c> is not equal to - 4, or if <c>HLen</c> is less than 5, or if the size of - <c>Dgram</c> is less than <c>4*HLen</c>, the match of - <c>Dgram</c> fails. - </p> - </section> - </section> - - <section> - <title>A Lexical Note</title> - <p>Note that "<c><![CDATA[B=<<1>>]]></c>" will be interpreted as - "<c><![CDATA[B =< ;<1>>]]></c>", which is a syntax error. - The correct way to write the expression is "<c><![CDATA[B = <<1>>]]></c>".</p> - </section> - - <section> - <title>Segments</title> - <p>Each segment has the following general syntax:</p> - <p><c>Value:Size/TypeSpecifierList</c></p> - <p>Both the <c>Size</c> and the <c>TypeSpecifier</c> or both may be - omitted; thus the following variations are allowed: - </p> - <p><c>Value</c></p> - <p><c>Value:Size</c></p> - <p><c>Value/TypeSpecifierList</c></p> - <p>Default values will be used for missing specifications. The default - values are described in the section "Defaults" below. - </p> - <p>Used in binary construction, the <c>Value</c> part is any expression. - Used in binary matching, the <c>Value</c> part must be a literal or - variable. You can read more about the <c>Value</c> part in the - sections about constructing binaries and matching binaries. - </p> - <p>The <c>Size</c> part of the segment multiplied by the unit in the - <c>TypeSpecifierList</c> (described below) gives the number of bits - for the segment. In construction, <c>Size</c> is any expression that - evaluates to an integer. In matching, <c>Size</c> must be a constant - expression or a variable. - </p> - <p>The <c>TypeSpecifierList</c> is a list of type specifiers separated by - hyphens. - </p> - <taglist> - <tag>Type</tag> - <item>The type can be <c>integer</c>, <c>float</c>, or <c>binary</c>.</item> - <tag>Signedness</tag> - <item>The signedness specification can be either <c>signed</c> - or <c>unsigned</c>. Note that signedness only matters for matching.</item> - <tag>Endianness</tag> - <item>The endianness specification can be either <c>big</c>, - <c>little</c>, or <c>native</c>. Native-endian means that - the endian will be resolved at load time to be either - big-endian or little-endian, depending on what is "native" - for the CPU that the Erlang machine is run on.</item> - <tag>Unit</tag> - <item>The unit size is given as <c>unit:IntegerLiteral</c>. - The allowed range is 1-256. It will be multiplied by the <c>Size</c> - specifier to give the effective size of the segment.</item> - </taglist> - <p>Example: - </p> - <code type="none"> -X:4/little-signed-integer-unit:8 - </code> - <p>This element has a total size of 4*8 = 32 bits, and it contains a - signed integer in little-endian order.</p> - </section> - - <section> - <title>Defaults</title> - <p>The default type for a segment is <c>integer</c>. The default type - does <em>not</em> depend on the value, even if the value is a literal. - For instance, the default type in '<c><![CDATA[<<3.14>>]]></c>' is <c>integer</c>, - not <c>float</c>. - </p> - <p>The default <c>Size</c> depends on the type. - For <c>integer</c> it is 8. For <c>float</c> it is 64. - For <c>binary</c> it is all of the binary. In matching, this default - value is only valid for the very last element. All other binary elements - in matching must have a size specification. - </p> - <p>The default unit depends on the the type. - For <c>integer</c> and <c>float</c> it is 1. - For <c>binary</c> it is 8. - </p> - <p>The default signedness is <c>unsigned</c>. - </p> - <p>The default endianness is <c>big</c>.</p> - </section> - - <section> - <title>Constructing Binaries</title> - <p>This section describes the rules for constructing binaries using - the bit syntax. Unlike when constructing lists or tuples, the construction - of a binary can fail with a <c>badarg</c> exception. - </p> - <p>There can be zero or more segments in a binary to be constructed. - The expression '<c><![CDATA[<<>>]]></c>' constructs a zero length binary. - </p> - <p>Each segment in a binary can consist of zero or more bits. - There are no alignment rules for individual segments, but the total - number of bits in all segments must be evenly divisible by 8, - or in other words, the resulting binary must consist of a whole number - of bytes. An <c>badarg</c> exception will be thrown if the resulting - binary is not byte-aligned. Example: - </p> - <code type="none"><![CDATA[ -<<X:1,Y:6>> - ]]></code> - <p>The total number of bits is 7, which is not evenly divisible by 8; - thus, there will be <c>badarg</c> exception (and a compiler warning - as well). The following example - </p> - <code type="none"><![CDATA[ -<<X:1,Y:6,Z:1>> - ]]></code> - <p>will successfully construct a binary of 8 bits, or one byte. (Provided - that all of X, Y and Z are integers.) - </p> - <p>As noted earlier, segments have the following general syntax: - </p> - <p><c>Value:Size/TypeSpecifierList</c></p> - <p>When constructing binaries, <c>Value</c> and <c>Size</c> can be - any Erlang expression. However, for syntactical reasons, - both <c>Value</c> and <c>Size</c> must be enclosed in parenthesis - if the expression consists of anything more than a single literal - or variable. The following gives a compiler syntax error: - </p> - <code type="none"><![CDATA[ -<<X+1:8>> - ]]></code> - <p>This expression must be rewritten to - </p> - <code type="none"><![CDATA[ -<<(X+1):8>> - ]]></code> - <p>in order to be accepted by the compiler. - </p> - - <section> - <title>Including Literal Strings</title> - <p>As syntactic sugar, an literal string may be written instead of a - element.</p> - <code type="none"><![CDATA[ -<<"hello">> ]]></code> - <p>which is syntactic sugar for</p> - <code type="none"><![CDATA[ -<<$h,$e,$l,$l,$o>> ]]></code> - </section> - </section> - - <section> - <title>Matching Binaries</title> - <p>This section describes the rules for matching binaries using the - bit syntax. - </p> - <p>There can be zero or more segments in a binary binary pattern. - A binary pattern can occur in every place patterns are allowed, also - inside other patterns. Binary patterns cannot be nested. - </p> - <p>The pattern '<c><![CDATA[<<>>]]></c>' matches a zero length binary. - </p> - <p>Each segment in a binary can consist of zero or more bits. - </p> - <p>A segment of type <c>binary</c> must have a size evenly divisible by 8. - </p> - <p>This means that the following head will never match:</p> - <code type="none"><![CDATA[ -foo(<<X:7/binary,Y:1/binary>>) -> ]]></code> - <p>As noted earlier, segments have the following general syntax: - </p> - <p><c>Value:Size/TypeSpecifierList</c></p> - <p>When matching <c>Value</c> value must be either a variable or an integer - or floating point literal. Expressions are not allowed. - </p> - <p><c>Size</c> must be an integer literal, or a previously bound variable. - Note that the following is not allowed:</p> - <code type="none"><![CDATA[ -foo(N, <<X:N,T/binary>>) -> - {X,T}. ]]></code> - <p>The two occurrences of <c>N</c> are not related. The compiler - will complain that the <c>N</c> in the size field is unbound. - </p> - <p>The correct way to write this example is like this:</p> - <code type="none"><![CDATA[ -foo(N, Bin) -> - <<X:N,T/binary>> = Bin, - {X,T}. ]]></code> - - <section> - <title>Getting the Rest of the Binary</title> - <p>To match out the rest of binary, specify a binary field without size:</p> - <code type="none"><![CDATA[ -foo(<<A:8,Rest/binary>>) -> ]]></code> - <p>As always, the size of the tail must be evenly divisible by 8. - </p> - </section> - </section> - - <section> - <title>Traps and Pitfalls</title> - <p>Assume that we need a function that creates a binary out of a - list of triples of integers. A first (inefficient) version of such - a function could look like this:</p> - <code type="none"><![CDATA[ -triples_to_bin(T) -> - triples_to_bin(T, <<>>). - -triples_to_bin([{X,Y,Z} | T], Acc) -> - triples_to_bin(T, <<Acc/binary, X:32, Y:32, Z:32>>); % inefficient -triples_to_bin([], Acc) -> - Acc. ]]></code> - <p>The reason for the inefficiency of this function is that for - each triple, the binary constructed so far (<c>Acc</c>) is copied. - (Note: The original bit syntax prototype avoided the copy operation - by using segmented binaries, which are not implemented in R7.) - </p> - <p>The efficient way to write this function in R7 is:</p> - <code type="none"><![CDATA[ -triples_to_bin(T) -> - triples_to_bin(T, []). - -triples_to_bin([{X,Y,Z} | T], Acc) -> - triples_to_bin(T, [<<X:32, Y:32, Z:32>> | Acc]); -triples_to_bin([], Acc) -> - list_to_binary(lists:reverse(Acc)). ]]></code> - <p>Note that <c>list_to_binary/1</c> handles deep lists of binaries - and small integers. (This fact was previously undocumented.) - </p> - </section> -</chapter> - diff --git a/system/doc/extensions/book.xml b/system/doc/extensions/book.xml deleted file mode 100644 index ffdbe6cb44..0000000000 --- a/system/doc/extensions/book.xml +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE book SYSTEM "book.dtd"> - -<book> - <header titlestyle="normal"> - <copyright> - <year>1997</year> - <year>2007</year> - <holder>Ericsson AB, All Rights Reserved</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. - </legalnotice> - - <title>Erlang Extensions Since 4.4</title> - <prepared>OTP Team</prepared> - <docno></docno> - <date>1997-05-21</date> - <rev></rev> - <file>book.sgml</file> - </header> - <insidecover> - </insidecover> - <pagetext>Erlang Extensions Since 4.4</pagetext> - <preamble> - <contents level="2"></contents> - </preamble> - <parts lift="no"> - <include file="part"></include> - </parts> - <listofterms></listofterms> - <index></index> -</book> - diff --git a/system/doc/extensions/fun_test.erl b/system/doc/extensions/fun_test.erl deleted file mode 100644 index 8472fd87f8..0000000000 --- a/system/doc/extensions/fun_test.erl +++ /dev/null @@ -1,17 +0,0 @@ -%1 --module(fun_test). --export([t1/0, t2/0, t3/0, t4/0, double/1]). --import(lists, [map/2]). - -t1() -> map(fun(X) -> 2 * X end, [1,2,3,4,5]). - -t2() -> map(fun double/1, [1,2,3,4,5]). - -t3() -> map({?MODULE, double}, [1,2,3,4,5]). - -double(X) -> X * 2. -%1 - - -t4() -> - "hello world". diff --git a/system/doc/extensions/funparse.erl b/system/doc/extensions/funparse.erl deleted file mode 100644 index 5e23c90df9..0000000000 --- a/system/doc/extensions/funparse.erl +++ /dev/null @@ -1,74 +0,0 @@ --module(funparse). --compile(export_all). --import(lists, [reverse/1]). - -%17 -%% > hof:parse([a,c]). -%% {ok,{'and',{'or',1,{const,a}},{'or',1,{const,c}}}} -%% > hof:parse([a,d]). -%% {ok,{'and',{'or',1,{const,a}},{'or',2,{const,d}}}} -%% > hof:parse([b,c]). -%% {ok,{'and',{'or',2,{const,b}},{'or',1,{const,c}}}} -%% > hof:parse([b,d]). -%% {ok,{'and',{'or',2,{const,b}},{'or',2,{const,d}}}} -%% > hof:parse([a,b]). -%% fail -%17 - -%% Grammar = (a | b) & (c | d) - -%12 -parse(List) -> - (grammar())(List). -%12 - -%13 -grammar() -> - pand( - por(pconst(a), pconst(b)), - por(pconst(c), pconst(d))). -%13 - -%14 -pconst(X) -> - fun (T) -> - case T of - [X|T1] -> {ok, {const, X}, T1}; - _ -> fail - end - end. -%14 - -%15 -por(P1, P2) -> - fun (T) -> - case P1(T) of - {ok, R, T1} -> - {ok, {'or',1,R}, T1}; - fail -> - case P2(T) of - {ok, R1, T1} -> - {ok, {'or',2,R1}, T1}; - fail -> - fail - end - end - end. -%15 - -%16 -pand(P1, P2) -> - fun (T) -> - case P1(T) of - {ok, R1, T1} -> - case P2(T1) of - {ok, R2, T2} -> - {ok, {'and', R1, R2}}; - fail -> - fail - end; - fail -> - fail - end - end. -%16 diff --git a/system/doc/extensions/funs.xml b/system/doc/extensions/funs.xml deleted file mode 100644 index f9c003c8ee..0000000000 --- a/system/doc/extensions/funs.xml +++ /dev/null @@ -1,486 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>1997</year> - <year>2007</year> - <holder>Ericsson AB, All Rights Reserved</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. - </legalnotice> - - <title>Programming with Funs</title> - <prepared>Joe Armstrong</prepared> - <responsible>Bjarne Däcker</responsible> - <docno>1</docno> - <approved>Bjarne DäKer</approved> - <checked></checked> - <date>96-01-16</date> - <rev>PA1</rev> - <file>funs.sgml</file> - </header> - <p>This section introduces functional objects (Funs). That is a new data type introduced in Erlang 4.4. Functions which takes Funs as arguments, or which return Funs are called higher order functions.</p> - <list type="bulleted"> - <item>Funs can be passed as arguments to other functions, just like lists or tuples</item> - <item>functions can be written which return Funs, just like any other data object.</item> - </list> - - <section> - <title>Higher Order Functions </title> - <p>Funs encourages us to encapsulate common patterns of design into functional forms called higher order functions. These functions not only shortens programs, but also produce clearer programs because the intended meaning of the program is explicitly rather than implicitly stated.</p> - <p>The concepts of higher order functions and procedural abstraction are introduced with two brief examples.</p> - - <section> - <title>Example 1 - map</title> - <p>If we want to double every element in a list, we could write a function named <c>double</c>:</p> - <code type="none"> - -double([H|T]) -> [2*H|double(T)]; -double([]) -> [] </code> - <p>This function obviously doubles the argument entered as input as follows:</p> - <pre> - -> <input>double([1,2,3,4]).</input> -[2,4,6,8] </pre> - <p>We now add the function <c>add_one</c>, which adds one to every element in a list:</p> - <code type="none"> - -add_one([H|T]) -> [H+1|add_one(T)]; -add_one([]) -> []. </code> - <p>These functions, <c>double</c> and <c>add_one</c>, have a very similar structure. We can exploit this fact and write a function <c>map</c> which expresses this similarity:</p> - <codeinclude file="funs1.erl" tag="%1" type="erl"></codeinclude> - <p>We can now express the functions <c>double</c> and <c>add_one</c> in terms of <c>map</c> as follows:</p> - <code type="none"> - -double(L) -> map(fun(X) -> 2*X end, L). -add_one(L) -> map(fun(X) -> 1 + X end, L). </code> - <p><c>map(F, List)</c> is a function which takes a function <c>F</c> and a list <c>L</c> as arguments and - returns the new list which is obtained by applying <c>F</c> to each of the elements in <c>L</c>.</p> - <p>The process of abstracting out the common features of a number of different programs is called procedural abstraction. Procedural abstraction can be used in order to write several different functions which have a similar structure, but differ only in some minor detail. This is done as follows:</p> - <list type="ordered"> - <item>write one function which represents the common features of these functions</item> - <item>parameterize the difference in terms of functions which are passed as arguments to the common function.</item> - </list> - </section> - - <section> - <title>Example 2 - foreach</title> - <p>This example illustrates procedural abstraction. Initially, we show the following two examples written as conventional functions:</p> - <list type="ordered"> - <item>all elements of a list are printed onto a stream</item> - <item>a message is broadcast to a list of processes.</item> - </list> - <code type="none"> - -print_list(Stream, [H|T]) -> - io:format(Stream, "~p~n", [H]), - print_list(Stream, T); -print_on_list(Stream, []) -> - true. </code> - <code type="none"> - -broadcast(Msg, [Pid|Pids]) -> - Pid ! Msg, - broadcast(Msg, Pids); -broadcast(_, []) -> - true. </code> - <p>Both these functions have a very similar structure. They both iterate over a list doing something to each element in the list. The "something" has to be carried round as an extra argument to the function which does this.</p> - <p>The function <c>foreach</c> expresses this similarity:</p> - <codeinclude file="funs1.erl" tag="%2" type="erl"></codeinclude> - <p>Using <c>foreach</c>, <c>print_on_list</c> becomes:</p> - <code type="none"> - -foreach(fun(H) -> io:format(S, "~p~n~,[H]) end, L) </code> - <p><c>broadcast</c> becomes:</p> - <code type="none"> - -foreach(fun(Pid) -> Pid ! M end, L) </code> - <p><c>foreach</c> is evaluated for its side-effect and not its value. <c>foreach(Fun ,L)</c> calls <c>Fun(X)</c> for each element <c>X</c> in <c>L</c> and the processing occurs in the order in which the elements were defined in <c>L</c>. <c>map</c> does not define the order in which its elements are processed.</p> - </section> - </section> - - <section> - <title>Advantages of Higher Order Functions</title> - <p>Programming with higher order functions, such as <c>map</c> and <c>foreach</c>, has a number of advantages:</p> - <list type="bulleted"> - <item>It is much easier to understand the program and the intention of the programmer is clearly expressed in the code. The statement <c>foreach(fun(X) -></c> clearly indicates that the intention of this program is to do something to each element in the list <c>L</c>. We also know that the function which is passed as the first argument of <c>foreach</c> takes one argument <c>X</c>, which will be successively bound to each of the elements in <c>L</c>.</item> - <item>Functions which take Funs as arguments are much easier to re-use than other functions. </item> - </list> - </section> - - <section> - <title>The Syntax of Funs</title> - <p>Funs are written with the syntax:</p> - <code type="none"> - -F = fun (Arg1, Arg2, ... ArgN) -> - ... - end </code> - <p>This creates an anonymous function of <c>N</c> arguments and binds it to the variable <c>F</c>.</p> - <p>If we have already written a function in the same module and wish to pass this function as an argument, we can use the following syntax:</p> - <code type="none"> - -F = fun FunctionName/Arity </code> - <p>With this form of function reference, the function which is referred to does not need to be exported from the module.</p> - <p>We can also refer to a function defined in a different module with the following syntax:</p> - <code type="none"> - -F = {Module, FunctionName} </code> - <p>In this case, the function must be exported from the module in question.</p> - <p>The follow program illustrates the different ways of creating Funs:</p> - <codeinclude file="fun_test.erl" tag="%1" type="erl"></codeinclude> - <p>We can evaluate the fun <c>F</c> with the syntax:</p> - <code type="none"> - -F(Arg1, Arg2, ..., Argn) </code> - <p>To check whether a term is a Fun, use the test <c>function/1</c> - in a guard. Example:</p> - <code type="none"> -f(F, Args) when function(F) -> - apply(F, Args); -f(N, _) when integer(N) -> - N. </code> - <p>Funs are a distinct type. The BIFs erlang:fun_info/1,2 can - be used to retrieve information about a fun, and the BIF - erlang:fun_to_list/1 returns a textual representation of a fun. - The check_process_code/2 BIF returns true if the - process contains funs that depend on the old version of - a module.</p> - <note> - <p>In OTP R5 and earlier releases, funs were represented - using tuples.</p> - </note> - </section> - - <section> - <title>Variable Bindings within a Fun</title> - <p>The scope rules for variables which occur in Funs are as follows:</p> - <list type="bulleted"> - <item>All variables which occur in the head of a Fun are assumed to be "fresh" variables.</item> - <item>Variables which are defined before the Fun, and which occur in function calls or guard tests within the Fun, have the values they had outside the Fun.</item> - <item>No variables may be exported from a Fun.</item> - </list> - <p>The following examples illustrate these rules:</p> - <code type="none"> - -print_list(File, List) -> - {ok, Stream} = file:open(File, write), - foreach(fun(X) -> io:format(Stream,"~p~n",[X]) end, List), - file:close(Stream). </code> - <p>In the above example, the variable <c>X</c> which is defined in the head of the Fun is a new variable. The value of the variable <c>Stream</c> which is used within within the Fun gets its value from the - <c>file:open</c> line.</p> - <p>Since any variable which occurs in the head of a Fun is considered a new variable it would be equally valid to write:</p> - <code type="none"> - -print_list(File, List) -> - {ok, Stream} = file:open(File, write), - foreach(fun(File) -> - io:format(Stream,"~p~n",[File]) - end, List), - file:close(Stream). </code> - <p>In this example, <c>File</c> is used as the new variable instead of <c>X</c>. This is rather silly since code in the body of the Fun cannot refer to the variable <c>File</c> which is defined outside the Fun. Compiling this example will yield the diagnostic:</p> - <code type="none"> - -./FileName.erl:Line: Warning: variable 'File' - shadowed in 'lambda head' </code> - <p>This reminds us that the variable <c>File</c> which is defined inside the Fun collides with the variable <c>File</c> which is defined outside the Fun.</p> - <p>The rules for importing variables into a Fun has the consequence that certain pattern matching operations have to be moved into guard expressions and cannot be written in the head of the Fun. For example, we might write the following code if we intend the first clause of <c>F</c> to be evaluated when the value of its argument is <c>Y</c>:</p> - <code type="none"> - -f(...) -> - Y = ... - map(fun(X) when X == Y -> - ; - (_) -> - ... - end, ...) - ... </code> - <p>instead of</p> - <code type="none"> - -f(...) -> - Y = ... - map(fun(Y) -> - ; - (_) -> - ... - end, ...) - ... </code> - </section> - - <section> - <title>Funs and the Module Lists</title> - <p>The following examples show a dialogue with the Erlang shell. All the higher order functions discussed are exported from the module <c>lists</c>.</p> - - <section> - <title>map</title> - <codeinclude file="funs1.erl" tag="%1" type="erl"></codeinclude> - <p><c>map</c> takes a function of one argument and a list of terms. It returns the list obtained by applying the function to every argument in the list.</p> - <pre> - -1> <input>Double = fun(X) -> 2 * X end.</input> -#Fun<erl_eval> -2><input>lists:map(Double, [1,2,3,4,5]).</input> -[2,4,6,8,10] </pre> - <p>When a new Fun is defined in the shell, the value of the Fun is printed as <c><![CDATA[Fun#<erl_eval>]]></c></p> - </section> - - <section> - <title>any</title> - <codeinclude file="funs1.erl" tag="%4" type="erl"></codeinclude> - <p><c>any</c> takes a predicate <c>P</c> of one argument and a list of terms. A predicate is a function which returns <c>true</c> or <c>false</c>. <c>any</c> is true if there is a term <c>X</c> in the list such that <c>P(X)</c> is <c>true</c>.</p> - <p>We define a predicate <c>Big(X)</c> which is <c>true</c> if its argument is greater that 10.</p> - <pre> - -3> <input>Big = fun(X) -> if X > 10 -> true; true -> false end end.</input> -#Fun<erl_eval> -4><input>lists:any(Big, [1,2,3,4]).</input> -false. -5> <input>lists:any(Big, [1,2,3,12,5]).</input> -true. </pre> - </section> - - <section> - <title>all</title> - <codeinclude file="funs1.erl" tag="%3" type="erl"></codeinclude> - <p><c>all</c> has the same arguments as <c>any</c>. It is true if the predicate applied to all elements in the list is true.</p> - <pre> - -6><input>lists:all(Big, [1,2,3,4,12,6]).</input> -false -7><input>lists:all(Big, [12,13,14,15]).</input> -true </pre> - </section> - - <section> - <title>foreach</title> - <codeinclude file="funs1.erl" tag="%2" type="erl"></codeinclude> - <p><c>foreach</c> takes a function of one argument and a list of terms. The function is applied to each argument in the list. <c>foreach</c> returns <c>ok</c>. It is used for its side-effect only.</p> - <pre> - -8> <input>lists:foreach(fun(X) -> io:format("~w~n",[X]) end, [1,2,3,4]).</input> -1 -2 -3 -4 -true </pre> - </section> - - <section> - <title>foldl</title> - <codeinclude file="funs1.erl" tag="%8" type="erl"></codeinclude> - <p><c>foldl</c> takes a function of two arguments, an accumulator and a list. The function is called with two arguments. The first argument is the successive elements in the list, the second argument is the accumulator. The function must return a new accumulator which is used the next time the function is called.</p> - <p>If we have a list of lists <c>L = ["I","like","Erlang"]</c>, then we can sum the lengths of all the strings in <c>L</c> as follows:</p> - <pre> - -9> <input>L = ["I","like","Erlang"].</input> -["I","like","Erlang"] -10> <input>lists:foldl(fun(X, Sum) -> length(X) + Sum end, 0, L).</input> -11 </pre> - <p><c>foldl</c> works like a <c>while</c> loop in an imperative language:</p> - <code type="none"> - - L = ["I","like","Erlang"], - Sum = 0, - while( L != []){ - Sum += length(head(L)), - L = tail(L) - end </code> - </section> - - <section> - <title>mapfoldl</title> - <codeinclude file="funs1.erl" tag="%10" type="erl"></codeinclude> - <p><c>mapfoldl</c> simultaneously maps and folds over a list. The following example shows how to change all letters in <c>L</c> to upper case and count them.</p> - <p>First upcase:</p> - <pre> - -11> <input>Upcase = fun(X) when $a =< X, X =< $z -> X + $A - $a;</input> -<input>(X) -> X</input> -<input>end.</input> -#Fun<erl_eval> -12> <input>Upcase_word =</input> -<input>fun(X) -></input> -<input>lists:map(Upcase, X)</input> -<input>end.</input> -#Fun<erl_eval> -13><input>Upcase_word("Erlang").</input> -"ERLANG" -14><input>lists:map(Upcase_word, L).</input> -["I","LIKE","ERLANG"] </pre> - <p>Now we can do the fold and the map at the same time:</p> - <pre> - -14> <input>lists:mapfoldl(fun(Word, Sum) -></input> -14> <input>{Upcase_word(Word), Sum + length(Word)}</input> -14> <input>end, 0, L).</input> -{["I","LIKE","ERLANG"],11} </pre> - </section> - - <section> - <title>filter</title> - <codeinclude file="funs1.erl" tag="%9" type="erl"></codeinclude> - <p><c>filter</c> takes a predicate of one argument and a list and returns all element in the list which satisfy the predicate.</p> - <pre> - -15><input>lists:filter(Big, [500,12,2,45,6,7]).</input> -[500,12,45] </pre> - <p>When we combine maps and filters we can write very succinct and obviously correct code. For example, suppose we want to define a set difference function. We want to define <c>diff(L1, L2)</c> to be the difference between the lists <c>L1</c> and <c>L2</c>. - This is the list of all elements in L1 which are not contained in L2. This code can be written as follows:</p> - <code type="none"> - -diff(L1, L2) -> - filter(fun(X) -> not member(X, L2) end, L1). </code> - <p>The AND intersection of the list <c>L1</c> and <c>L2</c> is also easily defined:</p> - <code type="none"> - -intersection(L1,L2) -> filter(fun(X) -> member(X,L1) end, L2). </code> - </section> - - <section> - <title>takewhile</title> - <codeinclude file="funs1.erl" tag="%5" type="erl"></codeinclude> - <p><c>takewhile(P, L)</c> takes elements <c>X</c> from a list <c>L</c> as long as the predicate <c>P(X)</c> is true.</p> - <pre> - -16><input>lists:takewhile(Big, [200,500,45,5,3,45,6]).</input> -[200,500,45] </pre> - </section> - - <section> - <title>dropwhile</title> - <codeinclude file="funs1.erl" tag="%6" type="erl"></codeinclude> - <p><c>dropwhile</c> is the complement of <c>takewhile</c>.</p> - <pre> - -17> <input>lists:dropwhile(Big, [200,500,45,5,3,45,6]).</input> -[5,3,45,6] </pre> - </section> - - <section> - <title>splitlist</title> - <codeinclude file="funs1.erl" tag="%7" type="erl"></codeinclude> - <p><c>splitlist(P, L)</c> splits the list <c>L</c> into the two sub-lists <c>{L1, L2}</c>, where <c>L = takewhile(P, L)</c> and <c>L2 = dropwhile(P, L)</c>.</p> - <pre> - -18><input>lists:splitlist(Big, [200,500,45,5,3,45,6]).</input> -{[200,500,45],[5,3,45,6]} </pre> - </section> - - <section> - <title>first</title> - <codeinclude file="funs1.erl" tag="%11" type="erl"></codeinclude> - <p><c>first</c> returns <c>{true, R}</c>, where <c>R</c> is the first element in a list satisfying a predicate or <c>false</c>:</p> - <pre> - -19><input>lists:first(Big, [1,2,45,6,123]).</input> -{true,45} -20><input>lists:first(Big, [1,2,4,5]). </input> -false </pre> - </section> - </section> - - <section> - <title>Funs which Return Funs</title> - <p>So far, this section has only described functions which take Funs as arguments. It is also possible to write more powerful functions which themselves return Funs. The following examples illustrate these type of functions.</p> - - <section> - <title>Simple Higher Order Functions</title> - <p><c>Adder(X)</c> is a function which, given <c>X</c>, returns a new function <c>G</c> such that <c>G(K)</c> returns <c>K + X</c>.</p> - <pre> - -21> <input>Adder = fun(X) -> fun(Y) -> X + Y end end.</input> -#Fun<erl_eval> -22> <input>Add6 = Adder(6).</input> -#Fun<erl_eval> -23><input>Add6(10).</input> -16 </pre> - </section> - - <section> - <title>Infinite Lists</title> - <p>The idea is to write something like:</p> - <code type="none"> - --module(lazy). --export([ints_from/1]). -ints_from(N) -> - fun() -> - [N|ints_from(N+1)] - end. </code> - <p>Then we can proceed as follows:</p> - <code type="none"><![CDATA[ - -24> XX = lazy:ints_from(1). -#Fun<lazy> -25> XX(). -[1|#Fun<lazy>] -26> hd(XX()). -1 -27> Y = tl(XX()). -#Fun<lazy> -28> hd(Y()). -2 ]]></code> - <p>etc. - this is an example of "lazy embedding"</p> - </section> - - <section> - <title>Parsing</title> - <p>The following examples show parsers of the following type:</p> - <pre> -Parser(Toks) -> {ok, Tree, Toks1} | fail </pre> - <p><c>Toks</c> is the list of tokens to be parsed. A successful parse returns <c>{ok, Tree, Toks1}</c>, where <c>Tree</c> is a parse tree and <c>Toks1</c> is a tail of <c>Tree</c> which contains symbols encountered after the structure which was correctly parsed. Otherwise <c>fail</c> is returned.</p> - <p>The example which follows illustrates a simple, functional parser which parses the grammar:</p> - <pre> -(a | b) & (c | d) </pre> - <p>The following code defines a function <c>pconst(X)</c> in the module <c>funparse</c>, which returns a Fun which parses a list of tokens.</p> - <codeinclude file="funparse.erl" tag="%14" type="erl"></codeinclude> - <p>This function can be used as follows:</p> - <pre> -29><input>P1 = funparse:pconst(a).</input> -#Fun<hof> -30> <input>P1([a,b,c]).</input> -{ok,{const,a},[b,c]} -31> <input>P1([x,y,z]).</input> -fail </pre> - <p>Next, we define the two higher order functions <c>pand</c> and <c>por</c> which combine primitive parsers to produce more complex parsers. Firstly <c>pand</c>:</p> - <codeinclude file="funparse.erl" tag="%16" type="erl"></codeinclude> - <p>Given a parser <c>P1</c> for grammar <c>G1</c>, and a parser <c>P2</c> for grammar <c>G2</c>, <c>pand(P1, P2)</c> - returns a parser for the grammar which consists of sequences of tokens which satisfy <c>G1</c> followed by sequences of tokens which satisfy <c>G2</c>.</p> - <p><c>por(P1, P2)</c> returns a parser for the language described by the grammar <c>G1</c> or <c>G2</c>.</p> - <codeinclude file="funparse.erl" tag="%15" type="erl"></codeinclude> - <p>The original problem was to parse the grammar <c><![CDATA[(a | b) & (c | d)]]></c>. The following code addresses this problem: </p> - <codeinclude file="funparse.erl" tag="%13" type="erl"></codeinclude> - <p>The following code adds a parser interface to the grammar:</p> - <codeinclude file="funparse.erl" tag="%12" type="erl"></codeinclude> - <p>We can test this parser as follows:</p> - <pre> - -32> <input>funparse:parse([a,c]).</input> -{ok,{'and',{'or',1,{const,a}},{'or',1,{const,c}}}} -33> <input>funparse:parse([a,d]).</input> -{ok,{'and',{'or',1,{const,a}},{'or',2,{const,d}}}} -34> <input>funparse:parse([b,c]).</input> -{ok,{'and',{'or',2,{const,b}},{'or',1,{const,c}}}} -35> <input>funparse:parse([b,d]).</input> -{ok,{'and',{'or',2,{const,b}},{'or',2,{const,d}}}} -36> <input>funparse:parse([a,b]).</input> -fail </pre> - </section> - </section> -</chapter> - diff --git a/system/doc/extensions/funs1.erl b/system/doc/extensions/funs1.erl deleted file mode 100644 index b1a3e21525..0000000000 --- a/system/doc/extensions/funs1.erl +++ /dev/null @@ -1,125 +0,0 @@ --module(funs1). --compile(export_all). --import(lists, [reverse/1]). - -%1 -map(F, [H|T]) -> [F(H)|map(F, T)]; -map(F, []) -> []. -%1 - -%2 -foreach(F, [H|T]) -> - F(H), - foreach(F, T); -foreach(F, []) -> - ok. -%2 -% -%3 -all(Pred, [H|T]) -> - case Pred(H) of - true -> all(Pred, T); - false -> false - end; -all(Pred, []) -> - true. -%3 -%4 -any(Pred, [H|T]) -> - case Pred(H) of - true -> true; - false -> any(Pred, T) - end; -any(Pred, []) -> - false. -%4 -%5 -takewhile(Pred, [H|T]) -> - case Pred(H) of - true -> [H|takewhile(Pred, T)]; - false -> [] - end; -takewhile(Pred, []) -> - []. -%5 -%6 -dropwhile(Pred, [H|T]) -> - case Pred(H) of - true -> dropwhile(Pred, T); - false -> [H|T] - end; -dropwhile(Pred, []) -> - []. -%6 -%7 -splitlist(Pred, L) -> - splitlist(Pred, L, []). - -splitlist(Pred, [H|T], L) -> - case Pred(H) of - true -> splitlist(Pred, T, [H|L]); - false -> {reverse(L), [H|T]} - end; -splitlist(Pred, [], L) -> - {reverse(L), []}. -%7 - -flatmap(F, [Hd|Tail]) -> - F(Hd) ++ flatmap(F, Tail); -flatmap(F, []) -> []. - -%8 -foldl(F, Accu, [Hd|Tail]) -> - foldl(F, F(Hd, Accu), Tail); -foldl(F, Accu, []) -> Accu. -%8 -% -foldr(F, Accu, [Hd|Tail]) -> - F(Hd, foldr(F, Accu, Tail)); -foldr(F, Accu, []) -> Accu. -%9 -filter(F, [H|T]) -> - case F(H) of - true -> [H|filter(F, T)]; - false -> filter(F, T) - end; -filter(F, []) -> []. -%9 -%10 -mapfoldl(F, Accu0, [Hd|Tail]) -> - {R,Accu1} = F(Hd, Accu0), - {Rs,Accu2} = mapfoldl(F, Accu1, Tail), - {[R|Rs], Accu2}; -mapfoldl(F, Accu, []) -> {[], Accu}. -%10 -mapfoldr(F, Accu0, [Hd|Tail]) -> - {Rs,Accu1} = mapfoldr(F, Accu0, Tail), - {R,Accu2} = F(Hd, Accu1), - {[R|Rs],Accu2}; -mapfoldr(F, Accu, []) -> {[], Accu}. -%11 -first(Pred, [H|T]) -> - case Pred(H) of - true -> - {true, H}; - false -> - first(Pred, T) - end; -first(Pred, []) -> - false. -%11 -% -compose(F, G) -> - fun(X) -> - F(G(X)) - end. - -%20 -iterate(N, F) -> - iterate(N, N+1, F). - -iterate(Stop, Stop, _) -> - []; -iterate(N, Stop, Fun) -> - [Fun(N)|iterate(N+1, Stop, Fun)]. -%20 diff --git a/system/doc/extensions/include.xml b/system/doc/extensions/include.xml deleted file mode 100644 index cd78644b95..0000000000 --- a/system/doc/extensions/include.xml +++ /dev/null @@ -1,81 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>1999</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>Includes</title> - <prepared>Arndt Jonasson</prepared> - <docno>1</docno> - <date>99-01-25</date> - <rev>PA1</rev> - <file>include.sgml</file> - </header> - <p>There are two directives which can be used in Erlang source - files to cause the compiler to temporarily read input from another - source. They are typically used to provide macro definitions and - record definitions from header files. It is recommended to use the - file name extension <c>".hrl"</c> for files which are meant to be - included (the 'h' can be read as "header").</p> - <p>When locating header files a list of directory names, the - compiler include path, is used. In short the list contains the current - working directory of the file server, the base name of the compiled - file, and the directories given by the include option, in that order. - See <c>erlc(1)</c> and <c>compile(3)</c> for the details of the - compiler include path.</p> - - <section> - <title>The -include Directive</title> - <p>The first action taken by the <c>-include</c> directive is to - check if the format of the first path component of the specified - filename is <c>$VAR</c>, for some string <c>VAR</c>. If that is the - case, the value of the environment variable <c>VAR</c> as returned by - <c>os:getenv(VAR)</c> is substituted for the first path component. If - <c>os:getenv/1</c> returns <c>false</c>, the first path component is - left as is. If the filename is absolute (possibly after variable - substitution), the header file with that name is included. Otherwise, - the specified header file is searched for in the directories in the - compiler include path, starting with the first directory in the list. - The first file found while traversing the list is included. Examples:</p> - <code type="none"> - -include("my_records.hrl"). - -include("incdir/more_records.hrl"). - -include("/home/users/proj/recs.hrl"). - -include("$PROJ_ROOT/app1/defs.hrl"). </code> - </section> - - <section> - <title>The -include_lib Directive</title> - <p>The <c>-include_lib</c> directive first tries to find the - specified header file using the procedure employed for the - <c>-include</c> directive. If no header file can be found by searching - the compiler include path, the first path component of the specified - filename (possibly after variable substitution) is regarded as the - name of an application, and the directory of the current version of - the application is searched. Example:</p> - <code type="none"> - -include_lib("mnesia/include/mnemosyne.hrl"). </code> - <p>The compiler is instructed to look for the directory where the - current version of the <c>mnesia</c> application is installed, that is - <c>code:lib_dir(mnesia)</c>, and then search the subdirectory - <c>include</c> for the file <c>mnemosyne.hrl</c>.</p> - </section> -</chapter> - diff --git a/system/doc/extensions/list_comprehensions.erl b/system/doc/extensions/list_comprehensions.erl deleted file mode 100644 index 21ac562aa5..0000000000 --- a/system/doc/extensions/list_comprehensions.erl +++ /dev/null @@ -1,118 +0,0 @@ --module(t). --author('[email protected]'). - -%%-export([test/2]). --compile(export_all). - -%% Odd numbers. - -%%foo(L) -> [ X || X <- L, (X > X-1) == (X /= X-1) ]. - -bar(L) -> [ X || X <- L, integer(X), gt(X, 3) ]. - -bar(L, M) -> [ Y || X <- L, integer(X), gt(X, 3), - Y <- M, float(Y), gt(X, Y) - ]. - -baz(L) -> [ X || X <- L, atom(X) ]. - -buz(L, Min) -> [ X || Min > 3, X <- L, X >= Min ]. - -gt(X, Y) when X > Y -> true; -gt(X, Y) -> false. - -%% Turn a list into a set. -make_set([]) -> []; -make_set([H|T]) -> - [H|[ - Y || Y <- make_set(T), - Y =/= H - ]]. - -%% Return the Pythagorean triangles with sides -%% of total length less than N -pyth(N) -> - [ {A,B,C} || - A <- lists:seq(1,N), - B <- lists:seq(1,N), - C <- lists:seq(1,N), - A+B+C =< N, - A*A+B*B == C*C - ]. - -%% Cut the search space a bit.. -pyth2(N) -> - [ {A,B,C} || - A <- lists:seq(1,N), - B <- lists:seq(1,N-A+1), - C <- lists:seq(1,N-A-B+2), - A+B+C =< N, - A*A+B*B == C*C ]. - -%% Return the Cartesian product -cp() -> - [ {X,Y} || - X <- a(), - Y <- b() - ]. - -cp(A,B) when list(A),list(B) -> - [ {X,Y} || - X <- A, - Y <- B - ]. - -%a() -> 1/0. -a() -> [a,b]. -b() -> [1,2,3]. - -%% Return all permutations of a list -perms([]) -> [[]]; -perms(L) -> [ [H|T] || H <- L, T <- perms(L--[H]) ]. - -%% Quick sort -sort([X|Xs]) -> - sort([ Y || Y <- Xs, Y < X ]) ++ - [X] ++ - sort([ Y || Y <- Xs, Y >= X ]); -sort([]) -> []. - -%% Vector addition -vecAdd(Xs,Ys) -> - [ X+Y || {X,Y} <- zip(Xs,Ys) ]. - -zip([X|Xs],[Y|Ys]) -> [{X,Y}|zip(Xs,Ys)]; -zip([],[]) -> []. - -qsort([X|Xs]) -> - qsort(lt(X,Xs)) - ++ [X] ++ - qsort(ge(X,Xs)); -qsort([]) -> []. - -lt(X,[H|T]) when X>H -> [H|lt(X,T)]; -lt(X,[_|T]) -> lt(X,T); -lt(_,[]) -> []. - -ge(X,[H|T]) when X=<H -> [H|ge(X,T)]; -ge(X,[_|T]) -> ge(X,T); -ge(_,[]) -> []. - -test(1,N) -> statistics(runtime),test1(N),statistics(runtime); -test(2,N) -> statistics(runtime),test2(N),statistics(runtime); -test(3,N) -> statistics(runtime),test3(N),statistics(runtime). - -test1(0) -> true; -test1(N) -> - sort([21,12,45,1,3,87,55,77,11,20,6,99,91,13,14,15,66,62,69,71,67,82,83,84,87,86,85]), - test1(N-1). - -test2(0) -> true; -test2(N) -> - qsort([21,12,45,1,3,87,55,77,11,20,6,99,91,13,14,15,66,62,69,71,67,82,83,84,87,86,85]), - test2(N-1). - -test3(0) -> true; -test3(N) -> - lists:sort([21,12,45,1,3,87,55,77,11,20,6,99,91,13,14,15,66,62,69,71,67,82,83,84,87,86,85]), - test3(N-1). diff --git a/system/doc/extensions/list_comprehensions.xml b/system/doc/extensions/list_comprehensions.xml deleted file mode 100644 index 30e32da79c..0000000000 --- a/system/doc/extensions/list_comprehensions.xml +++ /dev/null @@ -1,205 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>1997</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>List Comprehensions</title> - <prepared>Joe Armstrong</prepared> - <responsible>Bjarne Däcker</responsible> - <docno>1</docno> - <approved>Bjarne DäKer</approved> - <checked></checked> - <date>96-09-10</date> - <rev>PA1</rev> - <file>list_comprehensions.sgml</file> - </header> - <p>List comprehensions are a feature of many modern functional programming languages. Subject to certain rules, they provide a succinct notation for generating elements in a list.</p> - <p>List comprehensions are analogous to set comprehensions - in Zermelo-Frankel set theory and are called ZF expressions in - Miranda. They are analogous to the <c>setof</c> and - <c>findall</c> predicates in Prolog.</p> - <p>List comprehensions are written with the following syntax: - </p> - <code type="none"> - -[Expression || Qualifier1, Qualifier2, ...] </code> - <p><c>Expression</c> is an arbitrary expression, and each <c>Qualifier</c> is either a generator or a filter.</p> - <list type="bulleted"> - <item>A <em>generator</em> written as <c><![CDATA[Pattern <- ListExpr]]></c>. <c>ListExpr</c> must be an expression which evaluates to a list of terms.</item> - <item>A <em>filter</em> is either a predicate or a boolean expression. A predicate is a function which returns <c>true</c> or <c>false</c>.</item> - </list> - - <section> - <title>Examples of List Comprehensions</title> - <p>We start with a simple example:</p> - <code type="none"><![CDATA[ - -> [X || X <- [1,2,a,3,4,b,5,6], X > 3]. -[a,4,b,5,6] ]]></code> - <p>This should be read as follows:</p> - <quote> - <p>The list of X such that X is taken from the list <c>[1,2,a,...]</c> and X is greater than 3.</p> - </quote> - <p>The notation <c><![CDATA[X <- [1,2,a,...]]]></c> is a generator and the expression <c>X > 3</c> is a filter.</p> - <p>An additional filter can be added in order to restrict the result to integers:</p> - <code type="none"><![CDATA[ - -> [X || X <- [1,2,a,3,4,b,5,6], integer(X), X > 3]. -[4,5,6] ]]></code> - <p>Generators can be combined. For example, the Cartesian product of two lists can be written as follows:</p> - <code type="none"><![CDATA[ - -> [{X, Y} || X <- [1,2,3], Y <- [a,b]]. -[{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}] ]]></code> - - <section> - <title>Quick Sort</title> - <p>The well known quick sort routine can be written as follows:</p> - <code type="none"><![CDATA[ - -sort([Pivot|T]) -> - sort([ X || X <- T, X < Pivot]) ++ - [Pivot] ++ - sort([ X || X <- T, X >= Pivot]); -sort([]) -> []. ]]></code> - <p>The expression <c><![CDATA[[X || X <- T, X < Pivot]]]></c> is the list of all elements in <c>T</c>, which are less than <c>Pivot</c>.</p> - <p><c><![CDATA[[X || X <- T, X >= Pivot]]]></c> is the list of all elements in <c>T</c>, which are greater or equal to <c>Pivot</c>.</p> - <p>To sort a list, we isolate the first element in the list and split the list into two sub-lists. The first sub-list contains all elements which are smaller than the first element in the list, the second contains all elements which are greater than or equal to the first element in the list. We then sort the sub-lists and combine the results.</p> - </section> - - <section> - <title>Permutations</title> - <p>The following example generates all permutations of the elements in a list:</p> - <code type="none"><![CDATA[ - -perms([]) -> [[]]; -perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])]. ]]></code> - <p>We take take <c>H</c> from <c>L</c> in all possible ways. The result is the set of all lists <c>[H|T]</c>, where <c>T</c> is the set of all possible permutations of <c>L</c> with <c>H</c> removed.</p> - <code type="none"> - -> perms([b,u,g]). -[[b,u,g],[b,g,u],[u,b,g],[u,g,b],[g,b,u],[g,u,b]] </code> - </section> - - <section> - <title>Pythagorean Triplets</title> - <p>Pythagorean triplets are sets of integers <c>{A,B,C}</c> such that <c>A**2 + B**2 = C**2</c>.</p> - <p>The function <c>pyth(N)</c> generates a list of all integers <c>{A,B,C}</c> such that <c>A**2 + B**2 = C**2</c> and where the sum of the sides is less than <c>N</c>.</p> - <code type="none"><![CDATA[ - -pyth(N) -> - [ {A,B,C} || - A <- lists:seq(1,N), - B <- lists:seq(1,N), - C <- lists:seq(1,N), - A+B+C =< N, - A*A+B*B == C*C - ]. ]]></code> - <pre> - -> <input>pyth(3).</input> -[]. -> <input>pyth(11).</input> -[]. -><input>pyth(12).</input> -[{3,4,5},{4,3,5}] -> <input>pyth(50).</input> -[{3,4,5}, - {4,3,5}, - {5,12,13}, - {6,8,10}, - {8,6,10}, - {8,15,17}, - {9,12,15}, - {12,5,13}, - {12,9,15}, - {12,16,20}, - {15,8,17}, - {16,12,20}]</pre> - <p>The following code reduces the search space and is more efficient:</p> - <code type="none"><![CDATA[ - -pyth1(N) -> - [{A,B,C} || - A <- lists:seq(1,N), - B <- lists:seq(1,N-A+1), - C <- lists:seq(1,N-A-B+2), - A+B+C =< N, - A*A+B*B == C*C ]. ]]></code> - </section> - - <section> - <title>Simplifications with List Comprehensions</title> - <p>As an example, list comprehensions can be used to simplify some of the functions in <c>lists.erl</c>:</p> - <code type="none"><![CDATA[ - -append(L) -> [X || L1 <- L, X <- L1]. -map(Fun, L) -> [Fun(X) || X <- L]. -filter(Pred, L) -> [X || X <- L, Pred(X)]. ]]></code> - </section> - </section> - - <section> - <title>Variable Bindings in List Comprehensions</title> - <p>The scope rules for variables which occur in list comprehensions are as follows:</p> - <list type="bulleted"> - <item>all variables which occur in a generator pattern are assumed to be "fresh" variables</item> - <item>any variables which are defined before the list comprehension and which are used in filters have the values they had before the list comprehension</item> - <item>no variables may be exported from a list comprehension.</item> - </list> - <p>As an example of these rules, suppose we want to write the function <c>select</c>, which selects certain elements from a list of tuples. We might write <c><![CDATA[select(X, L) -> [Y || {X, Y} <- L].]]></c> with the intention of extracting all tuples from <c>L</c> where the first item is <c>X</c>.</p> - <p>Compiling this yields the following diagnostic:</p> - <code type="none"> - -./FileName.erl:Line: Warning: variable 'X' shadowed in generate </code> - <p>This diagnostic warns us that the variable <c>X</c> in the pattern is not the same variable as the variable <c>X</c> which occurs in the function head.</p> - <p>Evaluating <c>select</c> yields the following result:</p> - <pre> - -> <input>select(b,[{a,1},{b,2},{c,3},{b,7}]).</input> -[1,2,3,7] </pre> - <p>This result is not what we wanted. To achieve the desired effect we must write <c>select</c> as follows:</p> - <code type="none"><![CDATA[ - -select(X, L) -> [Y || {X1, Y} <- L, X == X1]. ]]></code> - <p>The generator now contains unbound variables and the test has been moved into the filter. This now works as expected:</p> - <pre> - -> <input>select(b,[{a,1},{b,2},{c,3},{b,7}]).</input> -[2,7] </pre> - <p>One consequence of the rules for importing variables into a list comprehensions is that certain pattern matching operations have to be moved into the filters and cannot be written directly in the generators. To illustrate this, do <em>not</em> write as follows:</p> - <code type="none"><![CDATA[ - -f(...) -> - Y = ... - [ Expression || PatternInvolving Y <- Expr, ...] - ... ]]></code> - <p>Instead, write as follows:</p> - <code type="none"><![CDATA[ - -f(...) -> - Y = ... - [ Expression || PatternInvolving Y1 <- Expr, Y == Y1, ...] - ... - ]]></code> - </section> -</chapter> - diff --git a/system/doc/extensions/list_comrehensions.erl b/system/doc/extensions/list_comrehensions.erl deleted file mode 100644 index f6a23b5dca..0000000000 --- a/system/doc/extensions/list_comrehensions.erl +++ /dev/null @@ -1,75 +0,0 @@ --module(zf). - --compile(export_all). - - -%% Odd numbers. - -%%foo(L) -> [ X || X <- L, (X > X-1) == (X /= X-1) ]. - -boo() -> [X||X <- [1,2,a,3,4,b,5,6], X > 3]. -boo1() -> [X||X <- [1,2,a,3,4,b,5,6], integer(X),X > 3]. -boo2() -> [{X,Y} || X <- [1,2,3], Y <- [a,b]]. - -bar(L) -> [ X || X <- L, integer(X), gt(X, 3) ]. - -bar(L, M) -> [ Y || X <- L, integer(X), gt(X, 3), - Y <- M, float(Y), gt(X, Y) - ]. - -baz(L) -> [ X || X <- L, atom(X) ]. - -buz(L, Min) -> [ X || Min > 3, X <- L, X >= Min ]. - -gt(X, Y) when X > Y -> true; -gt(X, Y) -> false. - - -%% Return the Pythagorean triangles with sides -%% of total length less than N -pyth(N) -> - [ {A,B,C} || - A <- lists:seq(1,N), - B <- lists:seq(1,N), - C <- lists:seq(1,N), - A+B+C =< N, - A*A+B*B == C*C - ]. - -%% Cut the search space a bit.. -pyth2(N) -> - [ {A,B,C} || - A <- lists:seq(1,N), - B <- lists:seq(1,N-A+1), - C <- lists:seq(1,N-A-B+2), - A+B+C =< N, - A*A+B*B == C*C ]. - -%% Return the Cartesian product - -cp(A,B) -> - [ {X,Y} || - X <- A, - Y <- B - ]. - -%% Return all permutations of a list -perms([]) -> [[]]; -perms(L) -> [ [H|T] || H <- L, T <- perms(L--[H]) ]. - -%% Quick sort -sort([X|Xs]) -> - sort([ Y || Y <- Xs, Y < X ]) ++ - [X] ++ - sort([ Y || Y <- Xs, Y >= X ]); -sort([]) -> []. - -%% append - -append(L) -> [X||L1<-L,X<-L1]. - -map(Fun, L) -> [Fun(X)||X<-L]. - -filter(Pred, L) -> [X||X<-L,Pred(X)]. - -select(X, L) -> [Y || {X1,Y} <- L, X == X1]. diff --git a/system/doc/extensions/macros.xml b/system/doc/extensions/macros.xml deleted file mode 100644 index feb3de6102..0000000000 --- a/system/doc/extensions/macros.xml +++ /dev/null @@ -1,177 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>1997</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>Macros</title> - <prepared>Joe Armstrong</prepared> - <responsible>Bjarne Däcker</responsible> - <docno>1</docno> - <approved>Bjarne DäKer</approved> - <checked></checked> - <date>96-09-10</date> - <rev>PA1</rev> - <file>macros.sgml</file> - </header> - <p>Macros in Erlang are written with the following syntax:</p> - <code type="none"> - --define(Const, Replacement). --define(Fun(Var1, Var2,.., Var), Replacement). </code> - <p>Macros are expanded when the syntax <c>?MacroName</c> is encountered.</p> - <p>Consider the macro definition:</p> - <code type="none"> - --define(timeout, 200). </code> - <p>The expression <c>?timeout</c>, which can occur anywhere in the code which follows the macro definition, will be replaced by <c>200</c>.</p> - <p>Macros with arguments are written as follows:</p> - <code type="none"> - - -define(macro1(X, Y), {a, X, b, Y}). </code> - <p>This type of macro can be used as follows:</p> - <code type="none"> - -bar(X) -> - ?macro1(a, b), - ?macro1(X, 123) </code> - <p>This expands to:</p> - <code type="none"> - -bar(X) -> - {a,a,b,b}, - {a,X,b,123}. </code> - - <section> - <title>Macros and Tokens</title> - <p>Macro expansion works at a token level. We might define a macro as follows:</p> - <code type="none"> - --define(macro2(X, Y), {a,X,b,Y). </code> - <p>The replacement value of the macro is not a valid Erlang term because the closing right curly bracket is missing. <c>macro2</c> expands into a sequence of tokens <c>{</c>, <c>a</c>, <c>X</c> which are then pasted into the place where the macro is used.</p> - <p>We might use this macro as follows:</p> - <code type="none"> - -bar() -> - ?macro2(x,y)}. </code> - <p>This will expand into the valid sequence of tokens <c>{a,x,y,b}</c> before being parsed and compiled.</p> - <note> - <p>It is good programming practise to ensure that the replacement text of a macro is a valid Erlang syntactic form.</p> - </note> - </section> - - <section> - <title>Pre-Defined Macros</title> - <p>The following macros are pre-defined:</p> - <taglist> - <tag><c>?MODULE</c>. </tag> - <item>This macro returns the name of the current module. - </item> - <tag><c>?MODULE_STRING</c>. </tag> - <item>This macro returns the name of the current module, as a string.</item> - <tag><c>?FILE</c>.</tag> - <item>This macro returns the current file name.</item> - <tag><c>?LINE</c>.</tag> - <item>This macro returns the current line number.</item> - <tag><c>?MACHINE</c>.</tag> - <item>This macro returns the current machine name, - <c>'BEAM'</c>,</item> - </taglist> - </section> - - <section> - <title>Stringifying Macro Arguments</title> - <p>The construction <c>??Arg</c> for an argument to a macro expands to a - string containing the tokens of the argument, similar to the - <c>#arg</c> stringifying construction in C. This was added in Erlang - 5.0 (OTP R7A).</p> - <p>Example:</p> - <code type="none"> --define(TESTCALL(Call), io:format("Call ~s: ~w~n", [??Call, Call])). - -?TESTCALL(myfunction(1,2)), -?TESTCALL(you:function(2,1)).</code> - <p>results in</p> - <code type="none"> -io:format("Call ~s: ~w~n",["myfunction ( 1 , 2 )",m:myfunction(1,2)]), -io:format("Call ~s: ~w~n",["you : function ( 2 , 1 )",you:function(2,1)]).</code> - </section> - - <section> - <title>Flow Control in Macros</title> - <p>The following macro directives are supplied:</p> - <taglist> - <tag>-undef(Macro).</tag> - <item>Causes the macro to behave as if it had never been defined.</item> - <tag>-ifdef(Macro).</tag> - <item>Do the following lines if <c>Macro</c> is defined.</item> - <tag>-ifndef(Macro).</tag> - <item>Do the following lines if <c>Macro</c> is not defined.</item> - <tag>-else.</tag> - <item>"else" macro</item> - <tag>-endif.</tag> - <item>"endif" macro.</item> - </taglist> - <p>The conditional macros must be properly nested. They are usually grouped as follows:</p> - <code type="none"> - --ifdef(debug) --define(....) --else --define(...) --endif </code> - <p>The following example illustrates this grouping:</p> - <code type="none"> - --define(debug, true). --ifdef(debug). --define(trace(Str, X), io:format("Mod:~w line:~w ~p ~p~n", - [?MODULE,?LINE, Str, X])). --else. --define(trace(X, Y), true). --endif. </code> - <p>Given these definitions, the expression <c>?trace("X=", X).</c> in line 10 of the module <c>foo</c> expands to:</p> - <code type="none"> - -io:format("Mod:~w line:~w ~p ~p~n",[foo,100,"X=",[X]]), </code> - <p>If we remove the <c>-define(debug, true).</c> line, then the same expression expands to <c>true</c>.</p> - </section> - - <section> - <title>A Macro Expansion Utility</title> - <p>The following code can be used to expand a macro and display the result:</p> - <code type="none"> - --module(mexpand). --export([file/1]). --import(lists, [foreach/2]). -file(File) -> - case epp:parse_file(File ++ ".erl", [],[]) of - {ok, L} -> - {ok, Stream} = file:open(File ++ ".out", write), - foreach(fun(X) -> - io:format(Stream,"~s~n",[erl_pp:form(X)]) - end, L), - file:close(Stream) - end.</code> - <p>Alternatively, we can compile the file with the <c>'P'</c> option. <c>compile:file(File, ['P'])</c> produces a list file <c>File.P</c>, in which the result of any macro expansions can be seen.</p> - </section> -</chapter> - diff --git a/system/doc/extensions/make.dep b/system/doc/extensions/make.dep deleted file mode 100644 index fdac959667..0000000000 --- a/system/doc/extensions/make.dep +++ /dev/null @@ -1,21 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: bit_syntax.tex book.tex funs.tex include.tex \ - list_comprehensions.tex macros.tex misc.tex \ - part.tex records.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -funs.tex: fun_test.erl funparse.erl funs1.erl - diff --git a/system/doc/extensions/mexpand.erl b/system/doc/extensions/mexpand.erl deleted file mode 100644 index 261f99da46..0000000000 --- a/system/doc/extensions/mexpand.erl +++ /dev/null @@ -1,16 +0,0 @@ --module(mexpand). - --export([file/1]). - --import(lists, [foreach/2]). - -file(File) -> - case epp:parse_file(File ++ ".erl", [],[]) of - {ok, L} -> - {ok, Stream} = file:open(File ++ ".out", write), - foreach(fun(X) -> - io:format(Stream,"~s~n", - [erl_pp:form(X)]) - end, L), - file:close(Stream) - end. diff --git a/system/doc/extensions/misc.xml b/system/doc/extensions/misc.xml deleted file mode 100644 index 576f705278..0000000000 --- a/system/doc/extensions/misc.xml +++ /dev/null @@ -1,310 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>1999</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>Miscellaneous</title> - <prepared>Arndt Jonasson</prepared> - <docno>1</docno> - <date>99-01-25</date> - <rev>PA1</rev> - <file>misc.sgml</file> - </header> - <p>In this chapter, a number of miscellaneous features of Erlang - are described.</p> - - <section> - <title>Token Syntax</title> - <p>In Erlang 4.8 (OTP R5A) the syntax of Erlang tokens have been - extended to allow the use of the full ISO-8859-1 (Latin-1) character - set. This is noticeable in the following ways:</p> - <list type="bulleted"> - <item>All the Latin-1 printable characters can be used and are shown without - the escape backslash convention.</item> - <item>Atoms and variables can use all Latin-1 letters.</item> - </list> - <p>The new characters from Latin-1 have the following - classifications in Erlang:</p> - <table> - <row> - <cell align="left" valign="middle"><em>Octal</em></cell> - <cell align="left" valign="middle"><em>Decimal</em></cell> - <cell align="left" valign="middle"> </cell> - <cell align="left" valign="middle"><em>Class</em></cell> - </row> - <row> - <cell align="left" valign="middle">200 - 237</cell> - <cell align="left" valign="middle">128 - 159</cell> - <cell align="left" valign="middle"> </cell> - <cell align="left" valign="middle">Control characters</cell> - </row> - <row> - <cell align="left" valign="middle">240 - 277</cell> - <cell align="left" valign="middle">160 - 191</cell> - <cell align="right" valign="middle">- ¿</cell> - <cell align="left" valign="middle">Punctuation characters</cell> - </row> - <row> - <cell align="left" valign="middle">300 - 326</cell> - <cell align="left" valign="middle">192 - 214</cell> - <cell align="center" valign="middle">À - Ö</cell> - <cell align="left" valign="middle">Uppercase letters</cell> - </row> - <row> - <cell align="center" valign="middle">327</cell> - <cell align="center" valign="middle">215</cell> - <cell align="center" valign="middle">×</cell> - <cell align="left" valign="middle">Punctuation character</cell> - </row> - <row> - <cell align="left" valign="middle">330 - 336</cell> - <cell align="left" valign="middle">216 - 222</cell> - <cell align="center" valign="middle">Ø - Þ</cell> - <cell align="left" valign="middle">Uppercase letters</cell> - </row> - <row> - <cell align="left" valign="middle">337 - 366</cell> - <cell align="left" valign="middle">223 - 246</cell> - <cell align="center" valign="middle">ß - ö</cell> - <cell align="left" valign="middle">Lowercase letters</cell> - </row> - <row> - <cell align="center" valign="middle">367</cell> - <cell align="center" valign="middle">247</cell> - <cell align="center" valign="middle">÷</cell> - <cell align="left" valign="middle">Punctuation character</cell> - </row> - <row> - <cell align="left" valign="middle">370 - 377</cell> - <cell align="left" valign="middle">248 - 255</cell> - <cell align="center" valign="middle">ø - ÿ</cell> - <cell align="left" valign="middle">Lowercase letters</cell> - </row> - <tcaption>Character classes</tcaption> - </table> - </section> - - <section> - <title>String Concatenation</title> - <p>Two adjacent string literals are concatenated into one. This is done already - at compile-time, and doesn't incur any runtime overhead. Example:</p> - <code type="none"> - "string" "42" </code> - <p>is equivalent to</p> - <code type="none"> - "string42" </code> - <p>This feature is convenient in at least two situations:</p> - <list type="bulleted"> - <item>when one of the - strings is the result of a macro expansion;</item> - <item>when a string is very - long, and would otherwise either have to wrap, making the source code - harder to read, or force the use of some runtime append operation.</item> - </list> - </section> - - <section> - <title>The ++ list Concatenation Operator</title> - <p>Since list concatenation is a very common operation, it is convenient - to have a terse way of expressing it. The ++ operator appends its second - argument to its first. Example: - </p> - <code type="none"> - X = [1,2,3], - Y = [4,5], - X ++ Y. </code> - <p>results in <c>[1,2,3,4,5]</c>.</p> - <p>The ++ operator has precedence between the binary '+' operator and - the comparison operators. - </p> - </section> - - <section> - <title>The - - list Subtraction Operator</title> - <p>The - - operator produces a list which is a copy of the first - argument, subjected to the following procedure: for each element in - the second argument, its first occurrence in the first argument is - removed.</p> - <code type="none"> - X = [1,2,3,2,1,2], - Y = [2,1,2], - X -- Y. </code> - <p>results in <c>[3,1,2]</c>.</p> - <p>The - - operator has precedence between the binary '+' operator and - the comparison operators. - </p> - </section> - - <section> - <title>Bitwise Operator bnot</title> - <p>Apart from the binary bitwise operators <c>band</c>, <c>bor</c> - and <c>bxor</c>, there is a unary operator <c>bnot</c> with the same - precedence as the other unary operators + and -, i.e., higher than - the binary operators. Example:</p> - <code type="none"> - bnot 7. </code> - <p>returns -8. - </p> - </section> - - <section> - <title>Logical Operators</title> - <p>The atoms <c>true</c> and <c>false</c> are usually used for representing - Boolean values. With the binary operators <c>and</c>, <c>or</c> and - <c>xor</c>, and the unary operator <c>not</c>, Boolean values can be - combined. Example:</p> - <code type="none"> - - M1 = lists:member(A, List1), - M2 = lists:member(A, List2), - M1 and M2.</code> - <p>Note that the operators are strict, i.e., they always evaluate both - their arguments.</p> - <p><c>not</c> has the same priority as the other unary operators. The - binary logical operators have precedence between the <c>=</c> operator - and the comparison operators, the <c>and</c> operator having higher - precedence than <c>or</c> and <c>xor</c>. - </p> - </section> - - <section> - <title>Match Operator = In Patterns</title> - <p>This extension was added in Erlang 4.8 (OTP R5A).</p> - <p>The = operator is also called the `match' operator. The match operator - can now be used in a pattern, so that <c>P1 = P2</c> is a valid pattern, - where both <c>P1</c> and <c>P2</c> are patterns. This compound pattern - when matched against a term causes the term to be matched against both - <c>P1</c> and <c>P2</c>.</p> - <p>One use for this construction is to avoid reconstructing a term which - was part of an argument to a function. Example:</p> - <code type="none"> - f({'+',X,Y}=T) -> {X+Y,T}.</code> - <p>It also makes it possible to rewrite the construction</p> - <code type="none"> - f(X) when X == #rec{x=1, y=a} -> ... </code> - <p>as</p> - <code type="none"> - f(#rec{x=1, y=a} = X) -> ... </code> - <p>In the absence of optimization for the former case, the - latter case is more efficient. - </p> - </section> - - <section> - <title>Literal String Prefix in Patterns</title> - <p>This extension was added in Erlang 4.8 (OTP R5A).</p> - <p>A new construction is allowed in patterns, namely a literal - string as the first operand of the ++ operator. Example:</p> - <code type="none"> - f("prefix" ++ L) -> ... </code> - <p>This is syntactic sugar for the equivalent, but harder to read</p> - <code type="none"> - f([$p,$r,$e,$f,$i,$x | L]) -> ... </code> - </section> - - <section> - <title>Disjunctions in Guards</title> - <p>This extension was added in Erlang 4.9 (OTP R6A).</p> - <p>A new construction is allowed in guards, the disjunction operator - ';'. The construction is syntactic sugar which removes the bother of - writing the same body after several guards.</p> - <code type="none"> - f(X) when xxx ; yyy ; zzz -> - pop(X).</code> - <p>This is syntactic sugar for the equivalent</p> - <code type="none"> - f(X) when xxx -> - pop(X); - f(X) when yyy -> - pop(X); - f(X) when zzz -> - pop(X). </code> - <p>The abstract format has been changed accordingly to contain a list of - (conjunctive) guards where there was previously only one guard. - </p> - </section> - - <section> - <title>Expressions in Patterns</title> - <p>This extension was added in Erlang 5.0 (OTP R7A).</p> - <p>An arithmetic expression can be used within a pattern, if it uses - only numeric or bitwise operators, and if its value can be evaluated - to a constant at compile-time. This is especially useful when the - expression is defined by a macro. - </p> - <p>Example:</p> - <code type="none"> - case X of - {1+2, T} -> T - end.</code> - </section> - - <section> - <title>Boolean expresions in guards</title> - <p>This extension was added in Erlang 5.1 (OTP R8).</p> - <p>In guards, the use of <c>and</c>, <c>or</c> and <c>not</c> is - now allowed. Guard expressions can combine these with - parenthesis. This allows for more elaborate guards than what - may be given with <c>,</c> and <c>;</c>.</p> - <note> - <p>The guard expressions written with these operators are boolean - expressions, and the boolean functions <c>is_list</c>, - <c>is_integer</c> etc. should be used, rather than - <c>list</c>, <c>integer</c> etc.</p> - </note> - <p>Example 1:</p> - <code type="none"> - f(X) when not (is_tuple(X) or is_list(X)) -> - ... </code> - <p>Example 2:</p> - <code type="none"><![CDATA[ - g(A, B) when (A > 0) and (B > 0) and not (A*A < B*B) -> - ... ]]></code> - </section> - - <section> - <title>Short-circuit boolean expressions</title> - <p>This extension was added in Erlang 5.1 (OTP R8).</p> - <p>In a boolean expression it is unnecessary to always evaluate all - terms. If the first term gives a result that determines the - result, the second term is not needed. In Erlang two new - keywords handles boolean expressions without evaluating both - terms, if it's unnecessary. (This is called short-curcuit - boolean evaluation.)</p> - <p>The keyword <c>andalso</c> is a short-curcuit version of - <c>and</c>. The keyword <c>orelse</c> is a short-curcuit version - of <c>or</c>. They can be used in boolean expressions (not - guards) instead of <c>and</c> and <c>or</c>.</p> - <p>Example 1:</p> - <code type="none"> - case A >= -1.0 andalso math:sqrt(A+1) > B of </code> - <p>This will work even if <c>A</c> is less than <c>-1.0</c>, since - in that case, the second term (after <c>andalso</c>) is never - evaluated. (Of course, the same effects could have been done - using guards. In guards, evaluation is always short-circuited, - since guard tests are known to be free of side-effects.)</p> - <p>Example 2:</p> - <code type="none"> - OnlyOne = is_atom(L) orelse - (is_list(L) andalso length(L) == 1), </code> - </section> -</chapter> - diff --git a/system/doc/extensions/part.xml b/system/doc/extensions/part.xml deleted file mode 100644 index 56fd2c09a6..0000000000 --- a/system/doc/extensions/part.xml +++ /dev/null @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE part SYSTEM "part.dtd"> - -<part> - <header> - <copyright> - <year>1997</year> - <year>2007</year> - <holder>Ericsson AB, All Rights Reserved</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. - </legalnotice> - - <title>Erlang Extensions Since 4.4</title> - <prepared>OTP Team</prepared> - <docno></docno> - <date>1997-02-21</date> - <rev>E</rev> - <file>part.sgml</file> - </header> - <description> - <p>This chapter describes extensions made to the Erlang language - since version 4.4 (where nothing is said to the contrary, an extension - was added in version 4.4). - The chapter contains the following sections: - </p> - <list type="bulleted"> - <item>Records</item> - <item>Functional Objects (Funs)</item> - <item>List Comprehensions</item> - <item>Macros</item> - <item>File inclusion</item> - <item>Bit syntax</item> - <item>Miscellaneous</item> - </list> - </description> - <include file="records"></include> - <include file="funs"></include> - <include file="list_comprehensions"></include> - <include file="macros"></include> - <include file="include"></include> - <include file="bit_syntax"></include> - <include file="misc"></include> -</part> - diff --git a/system/doc/extensions/records.xml b/system/doc/extensions/records.xml deleted file mode 100644 index 21ec73ab77..0000000000 --- a/system/doc/extensions/records.xml +++ /dev/null @@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>1997</year> - <year>2007</year> - <holder>Ericsson AB, All Rights Reserved</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. - </legalnotice> - - <title>Records</title> - <prepared>Joe Armstrong</prepared> - <responsible>Bjarne Däcker</responsible> - <docno>1</docno> - <approved>Bjarne DäKer</approved> - <checked></checked> - <date>96-09-10</date> - <rev>PA1</rev> - <file>records.sgml</file> - </header> - <p>A record is a data structure intended for storing a fixed number of related data items. It is - similar to a <c>struct</c> in C, or a <c>record</c> in Pascal. </p> - <p>The main advantage of using records instead of tuples is that fields in a record are accessed by name, whereas fields in a tuple are accessed by position. To illustrate these differences, suppose that we want to represent a person with the <em>tuple</em><c>{Name, Address, Phone}</c>.</p> - <p>We must remember that the <c>Name</c> field is the first element of the tuple, the <c>Address</c> field is the second element, and so on, in order to write functions which manipulate this data. For example, to extract data from a variable <c>P</c> which contains such a tuple we might write the following code and then use pattern matching to extract the relevant fields.</p> - <code type="none"> - -Name = element(1, P), -Address = element(2, P), -... </code> - <p>Code like this is difficult to read and understand and errors occur if we get the numbering of the elements in the tuple wrong. If we change the data representation by re-ordering the fields, or by adding or removing a field, then all references to the person tuple, wherever they occur, must be checked and possibly modified.</p> - <p><em>Records</em> allow us to refer to the fields by name and not position. We use a record instead of a tuple to store the data . If we write a record definition of the type shown below, we can then refer to the fields of the record by name.</p> - <code type="none"> - --record(person, {name, phone, address}). </code> - <p>For example, if <c>P</c> is now a variable whose value is a <c>person</c> record, we can code as follows in order to access the name and address fields of the records.</p> - <code type="none"> - -Name = P#person.name, -Address = P#person.address, -... </code> - <p>In the following sections we describe the different operations which can be performed on records:</p> - - <section> - <title>Defining a Record</title> - <p>A record is defined with the following syntax:</p> - <code type="none"> - --record(RecordName, {Field1 [= DefaultValue1], - Field2 [= DefaultValue2], - ..., - FieldN [= DefaultValueN]}). </code> - <p>The record name and field names must be atoms. The optional default values, which are terms, are used if no value is supplied for a field when a new instance of the record is created. If the default value is not supplied, then the atom <c>undefined</c> is assumed.</p> - <p>For example, in the following record definition, the address field is <c>undefined</c>.</p> - <pre> --record(person, {name = "", phone = [], address}). </pre> - <p>This definition of a person will be used in many of the examples which follow.</p> - </section> - - <section> - <title>Including a Record Definition</title> - <p>If the record is used in several modules, its definition should be placed in a <c>.hrl</c> header file. Each module which uses the record definition should have a <c>-include(FileName).</c> statement. For example:</p> - <code type="none"> - --include("my_data_structures.hrl"). </code> - <note> - <p>The definition of the record must come before it is used.</p> - </note> - </section> - - <section> - <title>Creating a Record</title> - <p>A new record is created with the following syntax:</p> - <code type="none"> - -#RecordName{Field1=Expr1, - ..., - FieldM=ExprM}. </code> - <p>If any of the fields is omitted, then the default value supplied in the record definition is used. For example:</p> - <pre> -> #person{phone = [0,8,2,3,4,3,1,2], name = "Robert"}. -{person, "Robert", [0,8,2,3,4,3,1,2], undefined}. </pre> - <p>There is a new feature introduced in Erlang 5.1 (OTP release - R8), with which you can set a value to all fields in a record, - overriding the defaults in the record specification. The special - field <c>_</c>, means "all fields not explicitly specified".</p> - <pre> -> #person{name = "Jakob", _ = '_'} -{person, "Jakob", '_', '_'} </pre> - <p>It is primarily intended to be used in <c>ets:match/2</c> and - <c>mnesia:match_object/3</c>, to set record fields to the atom - <c>'_'</c>. (This is a wildcard in <c>ets:match/2</c>.)</p> - </section> - - <section> - <title>Selectors</title> - <p>The following syntax is used to select an individual field from a record:</p> - <code type="none"> - -Variable#RecordName.Field </code> - <note> - <p>The values contained in record names and fields must be constants, not variables.</p> - </note> - <note> - <p>For the purposes of illustration, we will demonstrate the use of records using an imaginary dialogue with the Erlang shell. Currently the Erlang evaluator does not support records so you may not be able to reproduce this dialogue.</p> - </note> - <pre> - -> <input>P = #person{name = "Joe", phone = [0,8,2,3,4,3,1,2]}.</input> -{person, "Joe", [0,8,2,3,4,3,1,2], undefined} -> <input>P#person.name.</input> -"Joe" </pre> - <note> - <p>Selectors for records are allowed in guards.</p> - </note> - </section> - - <section> - <title>Updating a Record</title> - <p>The following syntax is used to create a new copy of the record with some of the fields changed. Only the fields to be changed need to be referred to, all other fields retain their old values.</p> - <code type="none"> - -OldVariable#RecordName{Field1 = NewValue1, - ..., - FieldM = NewValueM} </code> - <p>For example:</p> - <pre> -> P1 = #person{name="Joe", phone=[1,2,3], address="A street"}. -{person, "Joe", [1,2,3], "A street"} -> P2 = P1#person{name="Robert"}. -{person, "Robert", [1,2,3], "A street"} </pre> - </section> - - <section> - <title>Type Testing</title> - <p>The following guard test is used to test the type of a record:</p> - <code type="none"> - -record(Variable, RecordName) </code> - <p>The following example shows that the guard succeeds if <c>P</c> is record of type <c>person</c>.</p> - <pre> -foo(P) when record(P, person) -> a_person; -foo(_) -> not_a_person. </pre> - <note> - <p>This test checks that <c>P</c> is a tuple of arity <c>N + 1</c>, where <c>N</c> is the number - of fields in the record, and the first element in the tuple is the atom <c>person</c>.</p> - </note> - </section> - - <section> - <title>Pattern Matching</title> - <p>Matching can be used in combination with records as shown in the following example:</p> - <pre> -> P = #person{name="Joe", phone=[0,0,7], address="A street"}. -{person, "Joe", [0,0,7], "A street"} -> #person{name = Name} = P, Name. -"Joe" </pre> - <p>The following function takes a list of <c>person</c> records and searches for the phone number of a person with a particular name:</p> - <code type="none"> - -find_phone([#person{name=Name, phone=Phone} | _], Name) -> - {found, Phone}; -find_phone([_| T], Name) -> - find_phone(T, Name); -find_phone([], Name) -> - not_found. </code> - <note> - <p>The fields referred to in the pattern can be given in any order.</p> - </note> - </section> - - <section> - <title>Nested Records</title> - <p>The value of a field in a record might be an instance of a record. Retrieval of nested data can be done stepwise, or in a single step, as shown in the following example:</p> - <pre> --record(name, {first = "Robert", last = "Ericsson"}). --record(person, {name = #name{}, phone}). - -demo() -> - P = #person{name= #name{first="Robert",last="Virding"}, phone=123}, - First = (P#person.name)#name.first. </pre> - <note> - <p>In this example, <c>demo()</c> evaluates to <c>"Robert"</c>.</p> - </note> - </section> - - <section> - <title>Internal Representation of Records</title> - <p>It is often desirable to write generic functions which will work on any record, not just a record of a particular type. For this reason, records are represented internally as tuples and the ordering of the fields in the tuple is strictly defined.</p> - <p>For example, the record <c>-record(person, {name, phone, address}).</c> is represented internally by the tuple <c>{person, X, Y, Z}</c>.</p> - <p>The arity of the tuple is one more than the number of fields in the tuple. The first element of the tuple is the name of the record, and the elements of the tuple are the fields in the record. The variables <c>X</c>, <c>Y</c> and <c>Z</c> will store the data contained in the record fields.</p> - <p>The following two functions determine the indices in the tuple which refer to the named fields in the record:</p> - <list type="bulleted"> - <item><c>record_info(fields, Rec) -> [Names]</c>. This function returns the names of the fields in the record <c>Rec</c>. For example, <c>record_info(fields, person)</c> evaluates to <c>[name, address, phone]</c>.</item> - <item><c>record_info(size, Rec) -> Size</c>. This function returns the size of the record <c>Rec</c> when represented as a tuple, which is one more than the number of fields. For example, <c>record_info(size, person)</c> returns <c>4</c>.</item> - </list> - <p>In addition, <c>#Rec.Name</c> returns the index in the tuple representation of <c>Name</c> of the record <c>Rec</c>.</p> - <note> - <p><c>Name</c> must be an atom.</p> - </note> - <p>For example, the following test function <c>test()</c> might return the result shown:</p> - <pre> -test() -> - {record_info(fields, person), - record_info(size, person), - #person.name}. </pre> - <pre> -> <input>Mod:test().</input> -{[name,address,phone],4,2} </pre> - <p>The order in which records map onto tuples is implementation dependent.</p> - <note> - <p><c>record_info</c> is a pseudo-function which cannot be exported from the module where it occurs.</p> - </note> - </section> - - <section> - <title>Example</title> - <pre> -%% File: person.hrl - -%%----------------------------------------------------------- -%% Data Type: person -%% where: -%% name: A string (default is undefined). -%% age: An integer (default is undefined). -%% phone: A list of integers (default is []). -%% dict: A dictionary containing various information -%% about the person. -%% A {Key, Value} list (default is the empty list). -%%------------------------------------------------------------ --record(person, {name, age, phone = [], dict = []}). - </pre> - <pre> --module(person). --include("person.hrl"). --compile(export_all). % For test purposes only. - -%% This creates an instance of a person. -%% Note: The phone number is not supplied so the -%% default value [] will be used. - -make_hacker_without_phone(Name, Age) -> - #person{name = Name, age = Age, - dict = [{computer_knowledge, excellent}, - {drinks, coke}]}. - -%% This demonstrates matching in arguments - -print(#person{name = Name, age = Age, - phone = Phone, dict = Dict}) -> - io:format("Name: ~s, Age: ~w, Phone: ~w ~n" - "Dictionary: ~w.~n", [Name, Age, Phone, Dict]). - -%% Demonstrates type testing, selector, updating. - -birthday(P) when record(P, person) -> - P#person{age = P#person.age + 1}. - -register_two_hackers() -> - Hacker1 = make_hacker_without_phone("Joe", 29), - OldHacker = birthday(Hacker1), - % The central_register_server should have - % an interface function for this. - central_register_server ! {register_person, Hacker1}, - central_register_server ! {register_person, - OldHacker#person{name = "Robert", - phone = [0,8,3,2,4,5,3,1]}}. </pre> - </section> -</chapter> - diff --git a/system/doc/extensions/warning.gif b/system/doc/extensions/warning.gif Binary files differdeleted file mode 100644 index 96af52360e..0000000000 --- a/system/doc/extensions/warning.gif +++ /dev/null diff --git a/system/doc/images/.gitignore b/system/doc/images/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/system/doc/images/.gitignore +++ /dev/null diff --git a/system/doc/pics/Makefile b/system/doc/pics/Makefile deleted file mode 100644 index fc5996259d..0000000000 --- a/system/doc/pics/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -# -# Copyright (C) 1996,1997 Ericsson Telecommunications -# Author: Lars Thorsen -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/doc - -# ---------------------------------------------------- -# Target Specs -# ---------------------------------------------------- -# -# Common macros -# - -GIF_FILES= \ - min_head.gif \ - ps.gif - -# ---------------------------------------------------- -# Target Specs -# ---------------------------------------------------- - -docs: - -pdf: - -ps: - -debug opt: - - - -clean: - @echo "No action" >/dev/null - -# -# Release Targets -# -include $(ERL_TOP)/make/otp_release_targets.mk - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/pics - $(INSTALL_DATA) $(GIF_FILES) $(RELSYSDIR)/pics -endif -endif - -release_spec: diff --git a/system/doc/pics/app.gif b/system/doc/pics/app.gif Binary files differdeleted file mode 100644 index 345d5795b1..0000000000 --- a/system/doc/pics/app.gif +++ /dev/null diff --git a/system/doc/pics/ede.gif b/system/doc/pics/ede.gif Binary files differdeleted file mode 100644 index 7a51766898..0000000000 --- a/system/doc/pics/ede.gif +++ /dev/null diff --git a/system/doc/pics/ede_logo.gif b/system/doc/pics/ede_logo.gif Binary files differdeleted file mode 100644 index f7c902791b..0000000000 --- a/system/doc/pics/ede_logo.gif +++ /dev/null diff --git a/system/doc/pics/min_head.gif b/system/doc/pics/min_head.gif Binary files differdeleted file mode 100644 index 67948a6378..0000000000 --- a/system/doc/pics/min_head.gif +++ /dev/null diff --git a/system/doc/pics/notes.gif b/system/doc/pics/notes.gif Binary files differdeleted file mode 100644 index e000cca26a..0000000000 --- a/system/doc/pics/notes.gif +++ /dev/null diff --git a/system/doc/pics/otp.gif b/system/doc/pics/otp.gif Binary files differdeleted file mode 100644 index 48c4ca9c02..0000000000 --- a/system/doc/pics/otp.gif +++ /dev/null diff --git a/system/doc/pics/otp_logo.gif b/system/doc/pics/otp_logo.gif Binary files differdeleted file mode 100644 index d1a1f7f72d..0000000000 --- a/system/doc/pics/otp_logo.gif +++ /dev/null diff --git a/system/doc/pics/ps.gif b/system/doc/pics/ps.gif Binary files differdeleted file mode 100644 index 186dfc7e24..0000000000 --- a/system/doc/pics/ps.gif +++ /dev/null diff --git a/system/doc/pics/ref_man.gif b/system/doc/pics/ref_man.gif Binary files differdeleted file mode 100644 index b13c4efd53..0000000000 --- a/system/doc/pics/ref_man.gif +++ /dev/null diff --git a/system/doc/pics/user_guide.gif b/system/doc/pics/user_guide.gif Binary files differdeleted file mode 100644 index e6275a803d..0000000000 --- a/system/doc/pics/user_guide.gif +++ /dev/null diff --git a/system/doc/reference_manual/macros.xml b/system/doc/reference_manual/macros.xml index a1ba182eff..9dd5fc79bd 100644 --- a/system/doc/reference_manual/macros.xml +++ b/system/doc/reference_manual/macros.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2009</year> + <year>2003</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -13,12 +13,12 @@ compliance with the License. You should have received a copy of the Erlang Public License along with this software. If not, it can be retrieved online at http://www.erlang.org/. - + Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. - + </legalnotice> <title>The Preprocessor</title> @@ -140,6 +140,38 @@ bar(X) -> </section> <section> + <title>Macros Overloading</title> + <p>It is possible to overload macros, except for predefined + macros. An overloaded macro has more than one definition, + each with a different number of arguments.</p> + <p>The feature was added in Erlang 5.7.5/OTP R13B04.</p> + <p>A macro <c>?Func(Arg1,...,ArgN)</c> with a (possibly empty) + list of arguments results in an error message if there is at + least one definition of <c>Func</c> with arguments, but none + with N arguments.</p> + <p>Assuming these definitions:</p> + <code type="none"> +-define(F0(), c). +-define(F1(A), A). +-define(C, m:f).</code> + <p>the following will not work:</p> + <code type="none"> +f0() -> + ?F0. % No, an empty list of arguments expected. + +f1(A) -> + ?F1(A, A). % No, exactly one argument expected.</code> + <p>On the other hand,</p> + <code> +f() -> + ?C().</code> + <p>will expand to</p> + <code> +f() -> + m:f().</code> + </section> + + <section> <title>Flow Control in Macros</title> <p>The following macro directives are supplied:</p> <taglist> diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml index f4885be480..0dbc0ab56b 100644 --- a/system/doc/reference_manual/modules.xml +++ b/system/doc/reference_manual/modules.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2009</year> + <year>2003</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -13,12 +13,12 @@ compliance with the License. You should have received a copy of the Erlang Public License along with this software. If not, it can be retrieved online at http://www.erlang.org/. - + Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. - + </legalnotice> <title>Modules</title> @@ -170,17 +170,21 @@ fact(0) -> % | <section> <title>Types and function specifications</title> - <p>The current release implements types and function specifications - as described in + <p>A similar syntax as for module attributes is used for + specifying types and function specifications. + </p> + <pre> +-type my_type() :: atom() | integer(). +-spec my_function(integer()) -> integer(). + </pre> + <p>Read more in <seealso marker="typespec">Types and Function specifications</seealso>. + </p> + <p> + The desciption is based on <url href="http://www.erlang.org/eeps/eep-0008.html">EEP8 - -Types and function specifications</url>. - - <note> - <p>The implementation and EEP8 may not exactly correspond to - each other. In a future release, type and function specifications - will be described in this reference manual.</p> - </note> - </p> + Types and function specifications</url> + which will not be further updated. + </p> </section> </section> diff --git a/system/doc/reference_manual/part.xml b/system/doc/reference_manual/part.xml index aebeaf335a..8151f4c4e1 100644 --- a/system/doc/reference_manual/part.xml +++ b/system/doc/reference_manual/part.xml @@ -4,7 +4,7 @@ <part xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>2003</year><year>2009</year> + <year>2003</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -13,12 +13,12 @@ compliance with the License. You should have received a copy of the Erlang Public License along with this software. If not, it can be retrieved online at http://www.erlang.org/. - + Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. - + </legalnotice> <title>Erlang Reference Manual</title> @@ -32,6 +32,7 @@ <xi:include href="patterns.xml"/> <xi:include href="modules.xml"/> <xi:include href="functions.xml"/> + <xi:include href="typespec.xml"/> <xi:include href="expressions.xml"/> <xi:include href="macros.xml"/> <xi:include href="records.xml"/> diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml new file mode 100755 index 0000000000..a3660713e4 --- /dev/null +++ b/system/doc/reference_manual/typespec.xml @@ -0,0 +1,464 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Types and Function Specifications</title> + <prepared>Kostis Sagonas, Tobias Lindahl, Kenneth Lundin</prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>typespec.xml</file> + </header> + + <section> + <title>Introduction of Types</title> + <p> + Although Erlang is a dynamically typed language this section describes + an extension to the Erlang language for declaring sets of Erlang terms + to form a particular type, effectively forming a specific sub-type of the + set of all Erlang terms. + </p> + <p> + Subsequently, these types can be used to specify types of record fields + and the argument and return types of functions. + </p> + <p> + Type information can be used to document function interfaces, + provide more information for bug detection tools such as <c>Dialyzer</c>, + and can be exploited by documentation tools such as <c>Edoc</c> for + generating program documentation of various forms. + It is expected that the type language described in this document will + supersede and replace the purely comment-based <c>@type</c> and + <c>@spec</c> declarations used by <c>Edoc</c>. + </p> + <warning> + The syntax and semantics described here is still preliminary and might be + slightly changed and extended before it becomes officially supported. + The plan is that this will happen in R14B. + </warning> + </section> + <section> + <marker id="syntax"></marker> + <title>Types and their Syntax</title> + <p> + Types describe sets of Erlang terms. + Types consist and are built from a set of predefined types (e.g. <c>integer()</c>, + <c>atom()</c>, <c>pid()</c>, ...) described below. + Predefined types represent a typically infinite set of Erlang terms which + belong to this type. + For example, the type <c>atom()</c> stands for the set of all Erlang atoms. + </p> + <p> + For integers and atoms, we allow for singleton types (e.g. the integers <c>-1</c> + and <c>42</c> or the atoms <c>'foo'</c> and <c>'bar'</c>). + + All other types are built using unions of either predefined types or singleton + types. In a type union between a type and one of its sub-types the sub-type is + absorbed by the super-type and the union is subsequently treated as if the + sub-type was not a constituent of the union. For example, the type union: + </p> + <pre> + atom() | 'bar' | integer() | 42</pre> + <p> + describes the same set of terms as the type union: + </p> + <pre> +atom() | integer()</pre> + <p> + Because of sub-type relations that exist between types, types form a lattice + where the topmost element, any(), denotes the set of all Erlang terms and + the bottom-most element, none(), denotes the empty set of terms. + </p> + <p> + The set of predefined types and the syntax for types is given below: + </p> + <pre><![CDATA[ +Type :: any() %% The top type, the set of all Erlang terms. + | none() %% The bottom type, contains no terms. + | pid() + | port() + | ref() + | [] %% nil + | Atom + | Binary + | float() + | Fun + | Integer + | List + | Tuple + | Union + | UserDefined %% described in Section 2 + +Union :: Type1 | Type2 + +Atom :: atom() + | Erlang_Atom %% 'foo', 'bar', ... + +Binary :: binary() %% <<_:_ * 8>> + | <<>> + | <<_:Erlang_Integer>> %% Base size + | <<_:_*Erlang_Integer>> %% Unit size + | <<_:Erlang_Integer, _:_*Erlang_Integer>> + +Fun :: fun() %% any function + | fun((...) -> Type) %% any arity, returning Type + | fun(() -> Type) + | fun((TList) -> Type) + +Integer :: integer() + | Erlang_Integer %% ..., -1, 0, 1, ... 42 ... + | Erlang_Integer..Erlang_Integer %% specifies an integer range + +List :: list(Type) %% Proper list ([]-terminated) + | improper_list(Type1, Type2) %% Type1=contents, Type2=termination + | maybe_improper_list(Type1, Type2) %% Type1 and Type2 as above + +Tuple :: tuple() %% stands for a tuple of any size + | {} + | {TList} + +TList :: Type + | Type, TList +]]></pre> + <p> + Because lists are commonly used, they have shorthand type notations. + The type <c>list(T)</c> has the shorthand <c>[T]</c>. The shorthand <c>[T,...]</c> stands for + the set of non-empty proper lists whose elements are of type <c>T</c>. + The only difference between the two shorthands is that <c>[T]</c> may be an + empty list but <c>[T,...]</c> may not. + </p> + <p> + Notice that the shorthand for <c>list()</c>, i.e. the list of elements of unknown type, + is <c>[_]</c> (or <c>[any()]</c>), not <c>[]</c>. + The notation <c>[]</c> specifies the singleton type for the empty list. + </p> + <p> + For convenience, the following types are also built-in. + They can be thought as predefined aliases for the type unions also shown in + the table. (Some type unions below slightly abuse the syntax of types.) + </p> + <table> + <row> + <cell><b>Built-in type</b></cell><cell><b>Stands for</b></cell> + </row> + <row> + <cell><c>term()</c></cell><cell><c>any()</c></cell> + </row> + <row> + <cell><c>bool()</c></cell><cell><c>'false' | 'true'</c></cell> + </row> + <row> + <cell><c>byte()</c></cell><cell><c>0..255</c></cell> + </row> + <row> + <cell><c>char()</c></cell><cell><c>0..16#10ffff</c></cell> + </row> + <row> + <cell><c>non_neg_integer()</c></cell><cell><c>0..</c></cell> + </row> + <row> + <cell><c>pos_integer()</c></cell><cell><c>1..</c></cell> + </row> + <row> + <cell><c>neg_integer()</c></cell><cell><c>..-1</c></cell> + </row> + <row> + <cell><c>number()</c></cell><cell><c>integer() | float()</c></cell> + </row> + <row> + <cell><c>list()</c></cell><cell><c>[any()]</c></cell> + </row> + <row> + <cell><c>maybe_improper_list()</c></cell><cell><c>maybe_improper_list(any(), any())</c></cell> + </row> + <row> + <cell><c>maybe_improper_list(T)</c></cell><cell><c>maybe_improper_list(T, any())</c></cell> + </row> + <row> + <cell><c>string()</c></cell><cell><c>[char()]</c></cell> + </row> + <row> + <cell><c>nonempty_string()</c></cell><cell><c>[char(),...]</c></cell> + </row> + <row> + <cell><c>iolist()</c></cell><cell><c>maybe_improper_list( +char() | binary() | iolist(), binary() | [])</c></cell> + </row> + <row> + <cell><c>module()</c></cell><cell><c>atom()</c></cell> + </row> + <row> + <cell><c>mfa()</c></cell><cell><c>{atom(),atom(),byte()}</c></cell> + </row> + <row> + <cell><c>node()</c></cell><cell><c>atom()</c></cell> + </row> + <row> + <cell><c>timeout()</c></cell><cell><c>'infinity' | non_neg_integer()</c></cell> + </row> + <row> + <cell><c>no_return()</c></cell><cell><c>none()</c></cell> + </row> + </table> + + <p> + Users are not allowed to define types with the same names as the predefined or + built-in ones. + This is checked by the compiler and its violation results in a compilation + error. + (For bootstrapping purposes, it can also result to just a warning if this + involves a built-in type which has just been introduced.) + </p> + <note> + The following built-in list types also exist, + but they are expected to be rarely used. Hence, they have long names: + </note> + <pre> +nonempty_maybe_improper_list(Type) :: nonempty_maybe_improper_list(Type, any()) +nonempty_maybe_improper_list() :: nonempty_maybe_improper_list(any()) + </pre> + <p> + where the following two types + define the set of Erlang terms one would expect: + </p> + <pre> +nonempty_improper_list(Type1, Type2) +nonempty_maybe_improper_list(Type1, Type2) + </pre> + <p> + Also for convenience, we allow for record notation to be used. + Records are just shorthands for the corresponding tuples. + </p> + <pre> +Record :: #Erlang_Atom{} + | #Erlang_Atom{Fields} + </pre> + <p> + Records have been extended to possibly contain type information. + This is described in the sub-section <seealso marker="#typeinrecords">"Type information in record declarations"</seealso> below. + </p> + </section> + + <section> + <title>Type declarations of user-defined types</title> + <p> + As seen, the basic syntax of a type is an atom followed by closed + parentheses. New types are declared using '-type' compiler attributes + as in the following: + </p> + <pre> +-type my_type() :: Type. + </pre> + <p> + where the type name is an atom (<c>'my_type'</c> in the above) followed by + parenthesis. Type is a type as defined in the previous section. + A current restriction is that Type can contain only predefined types + or user-defined types which have been previously defined. + This restriction is enforced by the compiler and results in a + compilation error. (A similar restriction currently exists for records). + </p> + <p> + This means that currently general recursive types cannot be defined. + Lifting this restriction is future work. + </p> + <p> + Type declarations can also be parameterized by including type variables + between the parentheses. The syntax of type variables is the same as + Erlang variables (starts with an upper case letter). + Naturally, these variables can - and should - appear on the RHS of the + definition. A concrete example appears below: + </p> + <pre> +-type orddict(Key, Val) :: [{Key, Val}]. + </pre> + + </section> + + <marker id="typeinrecords"/> + <section> + <title> + Type information in record declarations + </title> + <p> + The types of record fields can be specified in the declaration of the + record. The syntax for this is: + </p> + <pre> +-record(rec, {field1 :: Type1, field2, field3 :: Type3}). + </pre> + <p> + For fields without type annotations, their type defaults to any(). + I.e., the above is a shorthand for: + </p> + <pre> +-record(rec, {field1 :: Type1, field2 :: any(), field3 :: Type3}). + </pre> + <p> + In the presence of initial values for fields, + the type must be declared after the initialization as in the following: + </p> + <pre> +-record(rec, {field1 = [] :: Type1, field2, field3 = 42 :: Type3}). + </pre> + <p> + Naturally, the initial values for fields should be compatible + with (i.e. a member of) the corresponding types. + This is checked by the compiler and results in a compilation error + if a violation is detected. For fields without initial values, + the singleton type <c>'undefined'</c> is added to all declared types. + In other words, the following two record declarations have identical + effects: + </p> + <pre> +-record(rec, {f1 = 42 :: integer(), + f2 :: float(), + f3 :: 'a' | 'b'). + +-record(rec, {f1 = 42 :: integer(), + f2 :: 'undefined' | float(), + f3 :: 'undefined' | 'a' | 'b'). + </pre> + <p> + For this reason, it is recommended that records contain initializers, + whenever possible. + </p> + <p> + Any record, containing type information or not, once defined, + can be used as a type using the syntax: + </p> + <pre> +#rec{} + </pre> + <p> + In addition, the record fields can be further specified when using + a record type by adding type information about the field in the following + manner: + </p> + <pre> +#rec{some_field :: Type} + </pre> + <p> + Any unspecified fields are assumed to have the type in the original + record declaration. + </p> + </section> + + <section> + <title>Specifications (contracts) for functions</title> + <p> + A contract (or specification) for a function is given using the new + compiler attribute <c>'-spec'</c>. The basic format is as follows: + </p> + <pre> +-spec Module:Function(ArgType1, ..., ArgTypeN) -> ReturnType. + </pre> + <p> + The arity of the function has to match the number of arguments, + or else a compilation error occurs. + </p> + <p> + This form can also be used in header files (.hrl) to declare type + information for exported functions. + Then these header files can be included in files that (implicitly or + explicitly) import these functions. + </p> + <p> + For most uses within a given module, the following shorthand is allowed: + </p> + <pre> +-spec Function(ArgType1, ..., ArgTypeN) -> ReturnType. + </pre> + <p> + Also, for documentation purposes, argument names can be given: + </p> + <pre> +-spec Function(ArgName1 :: Type1, ..., ArgNameN :: TypeN) -> RT. + </pre> + <p> + A function specification can be overloaded. + That is, it can have several types, separated by a semicolon (<c>;</c>): + </p> + <pre> +-spec foo(T1, T2) -> T3 + ; (T4, T5) -> T6. + </pre> + <p> + A current restriction, which currently results in a warning + (OBS: not an error) by the compiler, is that the domains of the argument + types cannot be overlapping. + For example, the following specification results in a warning: + </p> + <pre> +-spec foo(pos_integer()) -> pos_integer() + ; (integer()) -> integer(). + </pre> + <p> + Type variables can be used in specifications to specify relations for + the input and output arguments of a function. + For example, the following specification defines the type of a + polymorphic identity function: + </p> + <pre> +-spec id(X) -> X. + </pre> + <p> + However, note that the above specification does not restrict the input + and output type in any way. + We can constrain these types by guard-like subtype constraints: + </p> + <pre> +-spec id(X) -> X when is_subtype(X, tuple()). + </pre> + <p> + and provide bounded quantification. Currently, + the <c>is_subtype/2</c> guard is the only guard which can + be used in a <c>'-spec'</c> attribute. + </p> + <p> + The scope of an <c>is_subtype/2</c> constraint is the + <c>(...) -> RetType</c> + specification after which it appears. To avoid confusion, + we suggest that different variables are used in different constituents of + an overloaded contract as in the example below: + </p> + <pre> +-spec foo({X, integer()}) -> X when is_subtype(X, atom()) + ; ([Y]) -> Y when is_subtype(Y, number()). + </pre> + <p> + Some functions in Erlang are not meant to return; + either because they define servers or because they are used to + throw exceptions as the function below: + </p> + <pre> +my_error(Err) -> erlang:throw({error, Err}). + </pre> + <p> + For such functions we recommend the use of the special no_return() + type for their "return", via a contract of the form: + </p> + <pre> +-spec my_error(term()) -> no_return(). + </pre> + </section> +</chapter> + diff --git a/system/doc/top/bin/otp_man_index b/system/doc/top/bin/otp_man_index index bb913b25df..57a0f12d32 120000..100755 --- a/system/doc/top/bin/otp_man_index +++ b/system/doc/top/bin/otp_man_index @@ -1 +1,106 @@ -../../../../internal_tools/integration/scripts/otp_man_index
\ No newline at end of file +#!/opt/local/bin/perl + +use File::Find; +use strict; + +######################################### +# Usage: +# $ cd $ERLANG_RELEASE +# otp_man_index > doc/man_index.html +######################################### + +my (@list,$info); + +find(\&wanted,'.'); + +header(); + +foreach $info (sort {lc($a->[0]) cmp lc($b->[0])} @list) { + my ($module,$application,$dir,$path) = @$info; + + my $idx = -f "$dir/index.html" ? "$dir/index.html" : "$dir/../index.html"; + # Remove .html extension from module name, if there is one + if ($module =~ /(\w+).html$/) { + $module = "$1"; + } + print " <TR>\n"; + print " <TD><A HREF=\"../$path\">$module</A></TD>\n"; + print " <TD><A HREF=\"../$idx\">$application</A></TD>\n"; + print " </TR>\n"; +} + +footer(); + +########################################################################### + +sub wanted { + return unless /\.html$/ and -f $_; + + open(FILE,$_) or die "ERROR: Can't open $File::Find::name: $!\n"; + my $line; + + while (defined ($line = <FILE>)) { + if ($line =~ /<!-- refpage -->/) { + close FILE; + my $path = $File::Find::name; + $path =~ s/\.\///; # Remove './' prefix + my $dir = $File::Find::dir; + $dir =~ s/\.\///; # Remove './' prefix + $dir =~ m&([^/]+)/doc/html$&; + my $application = $1; + push(@list, [$_,$application,$dir,$path]); + return; + } + } + close FILE; +} + + +sub header { + print <<EOS; +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<!-- This file was generated by the otp_man_index script --> +<HTML> +<HEAD> + <link rel="stylesheet" href="otp_doc.css" type="text/css"/> + <TITLE>Erlang/OTP Manual Page Index</TITLE> +</HEAD> +<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#FF00FF" + ALINK="#FF0000"> +<CENTER> +<!-- A HREF="http://www.erlang.org/"> +<img alt="Erlang logo" src="erlang-logo.png"/ > +</A><BR --> +<SMALL> +[<A HREF="index.html">Up</A> | +<A HREF="http://www.erlang.org/">Erlang</A>] +</SMALL><BR> +<P><FONT SIZE="+4">Manual Page Index</FONT><BR> +</CENTER> +<CENTER> +<P> +<TABLE BORDER=1> +<TR> + <TH>Manual Page</TH><TH>Application</TH> +</TR> +EOS +} + +sub footer { + my $year = (localtime)[5] + 1900; + print <<EOS; +</TABLE> +</CENTER> +<P> +<CENTER> +<HR> +<SMALL> +Copyright © 1991-$year +<a href="http://www.ericsson.com/technology/opensource/erlang/"> +Ericsson AB</a> +</SMALL> +</CENTER> +</BODY> +</HTML> +EOS +} diff --git a/system/doc/top/src/erl_html_tools.erl b/system/doc/top/src/erl_html_tools.erl index 35a199b08d..d93516768e 120000..100644 --- a/system/doc/top/src/erl_html_tools.erl +++ b/system/doc/top/src/erl_html_tools.erl @@ -1 +1,727 @@ -../../../../internal_tools/integration/scripts/make_index/erl_html_tools.erl
\ No newline at end of file +%% ``The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved via the world wide web at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +-module(erl_html_tools). + +%% This file contains tools for updating HTML files in an installed system +%% depending on the installed applications. Currently the only use is +%% to update the top index file. + + +%% ------ VERY IMPORTANT ------ +%% +%% Original location for this file: +%% /clearcase/otp/internal_tools/integration/scripts/make_index/ +%% When updating this file, copy the source to +%% /home/otp/patch/share/program/ +%% and place .beam files (compiled with correct release) in all +%% /home/otp/patch/share/program/<release> +%% for releases >= R9C +%% +%% ---------------------------- + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% This program generate the top index files for the OTP documentation. +% Part of the HTML code is in templates, like "index.html.src" and +% part is written out from this module. So the program and the templates +% has to match. +% +% The templates are searched from the current directory, a directory +% "templates" relative to the current directory or at RootDir. +% +% RootDir is given as an argument or assumed to be code:root_dir(), +% i.e. the root of the system running this program. +% +% The output is put into DestDir or RootDir if not given. +% +% The functions to call are +% +% top_index() +% top_index([RootDir]) +% top_index([RootDir,DestDir,OtpRel]) +% top_index(RootDir) +% top_index(RootDir, DestDir, OtpRel) +% +% where RootDir can be a string or an atom. +% +% +% USING THIS SCRIPT FROM THE UNIX COMMAND LINE +% -------------------------------------------- +% If the Erlang started is the same as the Erlang to create index.html +% for the use +% +% % erl -noshell -s erl_html_tools top_index +% +% If you want to create an index for another Erlang installation or +% documentation located separate from the object code, then use +% +% % erl -noshell -s erl_html_tools top_index /path/to/erlang/root +% +% +% COLLECTING INFORMATION +% ---------------------- +% This script assumes that all applications have an "info" file +% in their top directory. This file should have some keywords with +% values defined. The keys are 'group' and 'short' (for "short +% description). See the OTP applications for examples. +% +% Some HTML code is generated by this program, others are taken from +% the file "index.html.src" that may be located in the patch directory +% or in the "$ERLANG_ROOT/doc/" directory. +% +% The code for creating the top index page assumes all applications +% have a file "info" with some fields filled in +% +% short: Text Short text describing the application +% group: tag [Heading] Group tag optionally followed by a description. +% Only one app need to describe the group but +% more than one can. +% +% FIXME: Check that there is documentation for the application, not just +% an info file. +% FIXME: Use records, it is now unreadable :-( +% FIXME: Use a separate URL and URLIndexFile +% FIXME: Pass the OTP release name as an argument instead of in +% process dictionary (for elegance). + +-export([top_index/0,top_index/1,top_index/3,top_index_silent/3]). + +% This is the order groups are inserted into the file. Groups +% not in this list is inserted in undefined order. + +group_order() -> + [ + basic, + dat, + oam, + orb, + comm, + tools + ]. + +top_index() -> + top_index(code:root_dir()). + +top_index([RootDir]) when atom(RootDir) -> + top_index(atom_to_list(RootDir)); +top_index([RootDir,DestDir,OtpRel]) + when is_atom(RootDir), is_atom(DestDir), is_atom(OtpRel) -> + top_index(atom_to_list(RootDir), atom_to_list(DestDir), atom_to_list(OtpRel)); +top_index(RootDir) -> + {_,RelName} = init:script_id(), + top_index(RootDir, filename:join(RootDir, "doc"), RelName). + +top_index(RootDir, DestDir, OtpRel) -> + report("****\nRootDir: ~p", [RootDir]), + report("****\nDestDir: ~p", [DestDir]), + report("****\nOtpRel: ~p", [OtpRel]), + + put(otp_release, OtpRel), + + Templates = find_templates(["","templates",DestDir]), + report("****\nTemplates: ~p", [Templates]), + Bases = [{"../lib/", filename:join(RootDir,"lib")}, + {"../", RootDir}], + Groups = find_information(Bases), + report("****\nGroups: ~p", [Groups]), + process_templates(Templates, DestDir, Groups). + +top_index_silent(RootDir, DestDir, OtpRel) -> + put(silent,true), + Result = top_index(RootDir, DestDir, OtpRel), + erase(silent), + Result. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Main loop - process templates +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +process_templates([], _DestDir, _Groups) -> + report("\n", []); +process_templates([Template | Templates], DestDir, Groups) -> + report("****\nIN-FILE: ~s", [Template]), + BaseName = filename:basename(Template, ".src"), + case lists:reverse(filename:rootname(BaseName)) of + "_"++_ -> + %% One template expands to several output files. + process_multi_template(BaseName, Template, DestDir, Groups); + _ -> + %% Standard one-to-one template. + OutFile = filename:join(DestDir, BaseName), + subst_file("", OutFile, Template, Groups) + end, + process_templates(Templates, DestDir, Groups). + + +process_multi_template(BaseName0, Template, DestDir, Info) -> + Ext = filename:extension(BaseName0), + BaseName1 = filename:basename(BaseName0, Ext), + [_|BaseName2] = lists:reverse(BaseName1), + BaseName = lists:reverse(BaseName2), + Groups0 = [{[$_|atom_to_list(G)],G} || G <- group_order()], + Groups = [{"",basic}|Groups0], + process_multi_template_1(Groups, BaseName, Ext, Template, DestDir, Info). + +process_multi_template_1([{Suffix,Group}|Gs], BaseName, Ext, Template, DestDir, Info) -> + OutFile = filename:join(DestDir, BaseName++Suffix++Ext), + subst_file(Group, OutFile, Template, Info), + process_multi_template_1(Gs, BaseName, Ext, Template, DestDir, Info); +process_multi_template_1([], _, _, _, _, _) -> ok. + +subst_file(Group, OutFile, Template, Info) -> + report("\nOUTFILE: ~s", [OutFile]), + case subst_template(Group, Template, Info) of + {ok,Text,_NewInfo} -> + case file:open(OutFile, [write]) of + {ok, Stream} -> + file:write(Stream, Text), + file:close(Stream); + Error -> + error("Can't write to file ~s: ~w", [OutFile,Error]) + end; + Error -> + error("Can't write to file ~s: ~w", [OutFile,Error]) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Find the templates +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +find_templates(SearchPaths) -> + find_templates(SearchPaths, SearchPaths). + +find_templates([SearchPath | SearchPaths], AllSearchPaths) -> + case filelib:wildcard(filename:join(SearchPath, "*.html.src")) of + [] -> + find_templates(SearchPaths, AllSearchPaths); + Result -> + Result + end; +find_templates([], AllSearchPaths) -> + error("No templates found in ~p",[AllSearchPaths]). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% This function read all application names and if present all "info" files. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +find_information(Bases) -> + Paths = find_application_paths(Bases), +% report("****\nPaths: ~p", [Paths]), + Apps = find_application_infos(Paths), +% report("****\nApps: ~p", [Apps]), + form_groups(Apps). + +% The input is a list of tuples of the form +% +% IN: [{BaseURL,SearchDir}, ...] +% +% and the output is a list +% +% OUT: [{Appname,AppVersion,AppPath,IndexUTL}, ...] +% +% We know URL ends in a slash. + +find_application_paths([]) -> + []; +find_application_paths([{URL,Dir} | Paths]) -> + Sub1 = "doc/html/index.html", +%% Sub2 = "doc/index.html", + case file:list_dir(Dir) of + {ok, Dirs} -> + AppDirs = + lists:filter( + fun(E) -> + is_match(E, "^[A-Za-z0-9_]+-[0-9\\.]+") + end, Dirs), + AppPaths = + lists:map( + fun(AppDir) -> + {ok,[App,Ver]} = regexp:split(AppDir, "-"), + DirPath = filename:join(Dir,AppDir), + AppURL = URL ++ AppDir, + {App,Ver,DirPath,AppURL ++ "/" ++ Sub1} +%% case file:read_file_info( +%% filename:join(DirPath, Sub1)) of +%% {ok, _} -> +%% {App,Ver,DirPath,AppURL ++ "/" ++ Sub1}; +%% _ -> +%% {App,Ver,DirPath,AppURL ++ "/" ++ Sub2} +%% end + end, AppDirs), + AppPaths ++ find_application_paths(Paths) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Find info for one application. +% Read the "info" file for each application. Look at "group" and "short". +% key words. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% IN: [{Appname,AppVersion,AppPath,IndexUTL}, ...] +% OUT: [{Group,Heading,[{AppName,[{AppVersion,Path,URL,Text} | ...]} +% | ...]}, ...] + +find_application_infos([]) -> + []; +find_application_infos([{App,Ver,AppPath,IndexURL} | Paths]) -> + case read_info(filename:join(AppPath,"info")) of + {error,_Reason} -> + warning("No info for app ~p", [AppPath]), + find_application_infos(Paths); + Db -> + {Group,Heading} = + case lists:keysearch("group", 1, Db) of + {value, {_, G0}} -> + % This value may be in two parts, + % tag and desciption + case string:str(G0," ") of + 0 -> + {list_to_atom(G0),""}; + N -> + {list_to_atom(string:substr(G0,1,N-1)), + string:substr(G0,N+1)} + end; + false -> + error("No group given",[]) + end, + Text = + case lists:keysearch("short", 1, Db) of + {value, {_, G1}} -> + G1; + false -> + "" + end, + [{Group,Heading,{App,{Ver,AppPath,IndexURL,Text}}} + | find_application_infos(Paths)] + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Group into one list element for each group name. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% IN : {Group,Heading,{AppName,{AppVersion,Path,URL,Text}}} +% OUT: {Group,Heading,[{AppName,[{AppVersion,Path,URL,Text} | ...]} | ...]} + +form_groups(Apps) -> + group_apps(lists:sort(Apps)). + +group_apps([{Group,Heading,AppInfo} | Info]) -> + group_apps(Info, Group, Heading, [AppInfo]); +group_apps([]) -> + []. + +% First description +group_apps([{Group,"",AppInfo} | Info], Group, Heading, AppInfos) -> + group_apps(Info, Group, Heading, [AppInfo | AppInfos]); +group_apps([{Group,Heading,AppInfo} | Info], Group, "", AppInfos) -> + group_apps(Info, Group, Heading, [AppInfo | AppInfos]); +% Exact match +group_apps([{Group,Heading,AppInfo} | Info], Group, Heading, AppInfos) -> + group_apps(Info, Group, Heading, [AppInfo | AppInfos]); +% Different descriptions +group_apps([{Group,_OtherHeading,AppInfo} | Info], Group, Heading, AppInfos) -> + warning("Group ~w descriptions differ",[Group]), + group_apps(Info, Group, Heading, [AppInfo | AppInfos]); +group_apps(Info, Group, Heading, AppInfos) -> + [{Group,Heading,combine_apps(AppInfos)} | group_apps(Info)]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Group into one list element for each application name. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% IN : {AppName,{AppVersion,Path,URL,Text}} +% OUT: {AppName,[{AppVersion,Path,URL,Text} | ...]} + +combine_apps(Apps) -> + combine_apps(Apps,[],[]). + +combine_apps([{AppName,{Vsn1,Path1,URL1,Text1}}, + {AppName,{Vsn2,Path2,URL2,Text2}} | Apps], AppAcc, Acc) -> + combine_apps([{AppName,{Vsn2,Path2,URL2,Text2}} | Apps], + [{Vsn1,Path1,URL1,Text1} | AppAcc], + Acc); +combine_apps([{AppName,{Vsn1,Path1,URL1,Text1}}, + {NewAppName,{Vsn2,Path2,URL2,Text2}} | Apps], AppAcc, Acc) -> + App = lists:sort(fun vsncmp/2,[{Vsn1,Path1,URL1,Text1}|AppAcc]), + combine_apps([{NewAppName,{Vsn2,Path2,URL2,Text2}} | Apps], + [], + [{AppName,App}|Acc]); +combine_apps([{AppName,{Vsn,Path,URL,Text}}], AppAcc, Acc) -> + App = lists:sort(fun vsncmp/2,[{Vsn,Path,URL,Text}|AppAcc]), + [{AppName,App}|Acc]. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Open a template and fill in the missing parts +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% IN : {Group,Heading,[{AppName,[{AppVersion,Path,URL,Text} | ...]} | ...]} +% OUT: String that is the HTML code + +subst_template(Group, File, Info) -> + case file:open(File, read) of + {ok,Stream} -> + Res = subst_template_1(Group, Stream, Info), + file:close(Stream), + Res; + {error,Reason} -> + {error, Reason} + end. + +subst_template_1(Group, Stream, Info) -> + case file:read(Stream, 100000) of + {ok, Template} -> + Fun = fun(Match, _) -> {subst(Match, Info, Group),Info} end, + gsub(Template, "#[A-Za-z0-9]+#", Fun, Info); + {error, Reason} -> + {error, Reason} + end. + +get_version(Info) -> + case lists:keysearch('runtime', 1, Info) of + {value, {_,_,Apps}} -> + case lists:keysearch("erts", 1, Apps) of + {value, {_,[{Vers,_,_,_} | _]}} -> + Vers; + _ -> + "" + end; + _ -> + "" + end. + +subst("#release#", _Info, _Group) -> + get(otp_release); +subst("#version#", Info, _Group) -> + get_version(Info); +subst("#copyright#", _Info, _Group) -> + "copyright Copyright © 1991-2004"; +subst("#groups#", Info, _Group) -> + [ + "<table border=0 width=\"90%\" cellspacing=3 cellpadding=5>\n", + subst_groups(Info), + "</table>\n" + ]; +subst("#applinks#", Info, Group) -> + subst_applinks(Info, Group); +subst(KeyWord, Info, _Group) -> + case search_appname(KeyWord -- "##", Info) of + {ok,URL} -> + URL; + _ -> + warning("Can't substitute keyword ~s~n",[KeyWord]), + "" + end. + +search_appname(App, [{_Group,_,Apps} | Groups]) -> + case lists:keysearch(App, 1, Apps) of + {value, {_,[{_Vers,_Path,URL,_Text} | _]}} -> + {ok,lists:sublist(URL, length(URL) - length("/index.html"))}; + _ -> + search_appname(App, Groups) + end; +search_appname(_App, []) -> + {error,noapp}. + +subst_applinks(Info, Group) -> + subst_applinks_1(group_order(), Info, Group). + +subst_applinks_1([G|Gs], Info0, Group) -> + case lists:keysearch(G, 1, Info0) of + {value,{G,Heading,Apps}} -> + Info = lists:keydelete(G, 1, Info0), + ["\n<li>",Heading,"\n<ul>\n", + html_applinks(Apps),"\n</ul></li>\n"| + subst_applinks_1(Gs, Info, Group)]; + false -> + warning("No applications in group ~w\n", [G]), + subst_applinks_1(Gs, Info0, Group) + end; +subst_applinks_1([], [], _) -> []; +subst_applinks_1([], Info, _) -> + error("Info left:\n", [Info]), + []. + +html_applinks([{Name,[{_,_,URL,_}|_]}|AppNames]) -> + ["<li><a href=\"",URL,"\">",Name, + "</a></li>\n"|html_applinks(AppNames)]; +html_applinks([]) -> []. + + +% Info: [{Group,Heading,[{AppName,[{AppVersion,Path,URL,Text} | ..]} | ..]} ..] + +subst_groups(Info0) -> + {Html1,Info1} = subst_known_groups(group_order(), Info0, ""), + {Html2,Info} = subst_unknown_groups(Info1, Html1, []), + Fun = fun({_Group,_GText,Applist}, Acc) -> Applist ++ Acc end, + case lists:foldl(Fun, [], Info) of + [] -> + Html2; + Apps -> + [Html2,group_table("Misc Applications",Apps)] + end. + + +subst_known_groups([], Info, Text) -> + {Text,Info}; +subst_known_groups([Group | Groups], Info0, Text0) -> + case lists:keysearch(Group, 1, Info0) of + {value,{_,Heading,Apps}} -> + Text = group_table(Heading,Apps), + Info = lists:keydelete(Group, 1, Info0), + subst_known_groups(Groups, Info, Text0 ++ Text); + false -> + warning("No applications in group ~w~n",[Group]), + subst_known_groups(Groups, Info0, Text0) + end. + + +subst_unknown_groups([], Text0, Left) -> + {Text0,Left}; +subst_unknown_groups([{Group,"",Apps} | Groups], Text0, Left) -> + warning("No text describes ~w",[Group]), + subst_unknown_groups(Groups, Text0, [{Group,"",Apps} | Left]); +subst_unknown_groups([{_Group,Heading,Apps} | Groups], Text0, Left) -> + Text = group_table(Heading,Apps), + subst_unknown_groups(Groups, Text0 ++ Text, Left). + + +group_table(Heading,Apps) -> + [ + " <tr>\n", + " <td colspan=2 class=header>\n", + " <font size=\"+1\"><b>",Heading,"</b></font>\n", + " </td>\n", + " </tr>\n", + subst_apps(Apps), + " <tr>\n", + " <td colspan=2><font size=1> </font></td>\n", + " </tr>\n" + ]. + +% Count and split the applications in half to get the right sort +% order in the table. + +subst_apps([{App,VersionInfo} | Apps]) -> + [subst_app(App, VersionInfo) | subst_apps(Apps)]; +subst_apps([]) -> + []. + + +subst_app(App, [{VSN,_Path,Link,Text}]) -> + [ + " <tr class=app>\n", + " <td align=left valign=top>\n", + " <table border=0 width=\"100%\" cellspacing=0 cellpadding=0>\n", + " <tr class=app>\n", + " <td align=left valign=top>\n", + " <a href=\"",Link,"\" target=\"_top\">",uc(App),"</a>\n", + " <a href=\"",Link,"\" target=\"_top\">",VSN,"</a>\n", + " </td>\n", + " </tr>\n", + " </table>\n" + " </td>\n", + " <td align=left valign=top>\n", + Text,"\n", + " </td>\n", + " </tr>\n" + ]; +subst_app(App, [{VSN,_Path,Link,Text} | VerInfos]) -> + [ + " <tr class=app>\n", + " <td align=left valign=top>\n", + " <table border=0 width=\"100%\" cellspacing=0 cellpadding=0>\n", + " <tr class=app>\n", + " <td align=left valign=top>\n", + " <a href=\"",Link,"\" target=\"_top\">",uc(App), + "</a> <br>\n", + " <a href=\"",Link,"\" target=\"_top\">",VSN,"</a>\n", + " </td>\n", + " <td align=right valign=top width=50>\n", + " <table border=0 width=40 cellspacing=0 cellpadding=0>\n", + " <tr class=app>\n", + " <td align=left valign=top class=appnums>\n", + subst_vsn(VerInfos), + " </td>\n", + " </tr>\n", + " </table>\n" + " </td>\n", + " </tr>\n", + " </table>\n" + " </td>\n", + " <td align=left valign=top>\n", + Text,"\n", + " </td>\n", + " </tr>\n" + ]. + + +subst_vsn([{VSN,_Path,Link,_Text} | VSNs]) -> + [ + " <font size=\"2\"><a class=anum href=\"",Link,"\" target=\"_top\">", + VSN, + "</a></font><br>\n", + subst_vsn(VSNs) + ]; +subst_vsn([]) -> + "". + + +% Yes, this is very inefficient an is done for every comarision +% in the sort but it doesn't matter in this case. + +vsncmp({Vsn1,_,_,_}, {Vsn2,_,_,_}) -> + L1 = [list_to_integer(N1) || N1 <- string:tokens(Vsn1, ".")], + L2 = [list_to_integer(N2) || N2 <- string:tokens(Vsn2, ".")], + L1 > L2. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% GENERIC FUNCTIONS, NOT SPECIFIC FOR GENERATING INDEX.HTML +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Read the "info" file into a list of Key/Value pairs +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +read_info(File) -> + case file:open(File, read) of + {ok,Stream} -> + Res = + case file:read(Stream,10000) of + {ok, Text} -> + Lines = string:tokens(Text, "\n\r"), + KeyValues0 = lines_to_key_value(Lines), + combine_key_value(KeyValues0); + {error, Reason} -> + {error, Reason} + end, + file:close(Stream), + Res; + {error,Reason} -> + {error,Reason} + end. + +combine_key_value([{Key,Value1},{Key,Value2} | KeyValues]) -> + combine_key_value([{Key,Value1 ++ "\n" ++ Value2} | KeyValues]); +combine_key_value([KeyValue | KeyValues]) -> + [KeyValue | combine_key_value(KeyValues)]; +combine_key_value([]) -> + []. + +lines_to_key_value([]) -> + []; +lines_to_key_value([Line | Lines]) -> + case regexp:first_match(Line, "^[a-zA-Z_\\-]+:") of + nomatch -> + case regexp:first_match(Line, "[\041-\377]") of + nomatch -> + lines_to_key_value(Lines); + _ -> + warning("skipping line \"~s\"",[Line]), + lines_to_key_value(Lines) + end; + {match, _, Length} -> + Value0 = lists:sublist(Line, Length+1, length(Line) - Length), + {ok, Value1, _} = regexp:sub(Value0, "^[ \t]*", ""), + {ok, Value, _} = regexp:sub(Value1, "[ \t]*$", ""), + Key = lists:sublist(Line, Length-1), + [{Key,Value} | lines_to_key_value(Lines)] + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Extensions to the 'regexp' module. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +is_match(Ex, Re) -> + case regexp:first_match(Ex, Re) of + {match, _, _} -> + true; + nomatch -> + false + end. + +%% -type gsub(String, RegExp, Fun, Acc) -> subres(). +%% Substitute every match of the regular expression RegExp with the +%% string returned from the function Fun(Match, Acc). Accept pre-parsed +%% regular expressions. Acc is an argument to the Fun. The Fun should return +%% a tuple {Replacement, NewAcc}. + +gsub(String, RegExp, Fun, Acc) when list(RegExp) -> + case regexp:parse(RegExp) of + {ok,RE} -> gsub(String, RE, Fun, Acc); + {error,E} -> {error,E} + end; +gsub(String, RE, Fun, Acc) -> + {match,Ss} = regexp:matches(String, RE), + {NewString, NewAcc} = sub_repl(Ss, Fun, Acc, String, 1), + {ok,NewString,NewAcc}. + + +% New code that uses fun for finding the replacement. Also uses accumulator +% to pass argument between the calls to the fun. +sub_repl([{St,L}|Ss], Fun, Acc0, S, Pos) -> + Match = string:substr(S, St, L), + {Rep, Acc} = Fun(Match, Acc0), + {Rs, NewAcc} = sub_repl(Ss, Fun, Acc, S, St+L), + {string:substr(S, Pos, St-Pos) ++ Rep ++ Rs, NewAcc}; +sub_repl([], _Fun, Acc, S, Pos) -> {string:substr(S, Pos), Acc}. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Error and warnings +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +error(Format, Args) -> + io:format("ERROR: " ++ Format ++ "\n", Args), + exit(1). + +warning(Format, Args) -> + case get(silent) of + true -> ok; + _ -> io:format("WARNING: " ++ Format ++ "\n", Args) + end. + +report(Format, Args) -> + case get(silent) of + true -> ok; + _ -> io:format(Format ++ "\n", Args) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Extensions to the 'string' module. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +uc(String) -> + lists:reverse(uc(String, [])). + +uc([], Acc) -> + Acc; +uc([H | T], Acc) when is_integer(H), [97] =< H, H =< $z -> + uc(T, [H - 32 | Acc]); +uc([H | T], Acc) -> + uc(T, [H | Acc]). diff --git a/system/doc/top/src/erlresolvelinks.erl b/system/doc/top/src/erlresolvelinks.erl index 8d277ad17a..a891b67421 120000..100644 --- a/system/doc/top/src/erlresolvelinks.erl +++ b/system/doc/top/src/erlresolvelinks.erl @@ -1 +1,144 @@ -../../../../internal_tools/integration/scripts/resolve_links/erlresolvelinks.erl
\ No newline at end of file +-module(erlresolvelinks). + +%% ------ VERY IMPORTANT ------ +%% +%% Original location for this file: +%% /clearcase/otp/internal_tools/integration/scripts/resolve_links/ +%% When updating this file, copy the source to +%% /usr/local/otp/patch/share/program/ +%% and place .beam files (compiled with correct release) in all +%% /usr/local/otp/patch/share/program/<release> +%% for releases >= R10B +%% +%% ---------------------------- + +-export([make/1, do_make/1, do_make/2, do_make/3]). +-include_lib("kernel/include/file.hrl"). + +-define(JAVASCRIPT_NAME, "erlresolvelinks.js"). + +make([RootDir]) -> + do_make(RootDir); +make([RootDir, DestDir]) -> + do_make(RootDir, DestDir); +make([RootDir, DestDir, Name]) -> + do_make(RootDir, DestDir, Name). + +do_make(RootDir) -> + DestDir = filename:join(RootDir, "doc"), + do_make(RootDir, DestDir). + +do_make(RootDir, DestDir) -> + do_make(RootDir, DestDir, ?JAVASCRIPT_NAME). + +do_make(RootDir, DestDir, Name) -> + %% doc/Dir + %% erts-Vsn + %% lib/App-Vsn + DocDirs0 = get_dirs(filename:join([RootDir, "doc"])), + DocDirs = lists:map(fun(Dir) -> + D = filename:join(["doc", Dir]), + {D, D} end, DocDirs0), + + ErtsDirs = latest_app_dirs(RootDir, ""), + AppDirs = latest_app_dirs(RootDir, "lib"), + + AllAppDirs = + lists:map( + fun({App, AppVsn}) -> {App, filename:join([AppVsn, "doc", "html"])} + end, ErtsDirs ++ AppDirs), + + AllDirs = DocDirs ++ AllAppDirs, + {ok, Fd} = file:open(filename:join([DestDir, Name]), [write]), + UTC = calendar:universal_time(), + io:fwrite(Fd, "/* Generated by ~s at ~w UTC */\n", + [atom_to_list(?MODULE), UTC]), + io:fwrite(Fd, "function erlhref(ups, app, rest) {\n", []), + io:fwrite(Fd, " switch(app) {\n", []), + lists:foreach( + fun({Tag, Dir}) -> + io:fwrite(Fd, " case ~p:\n", [Tag]), + io:fwrite(Fd, " location.href=ups + \"~s/\" + rest;\n", + [Dir]), + io:fwrite(Fd, " break;\n", []) + end, AllDirs), + io:fwrite(Fd, " default:\n", []), + io:fwrite(Fd, " location.href=ups + \"Unresolved\";\n", []), + io:fwrite(Fd, " }\n", []), + io:fwrite(Fd, "}\n", []), + file:close(Fd), + ok. + +get_dirs(Dir) -> + {ok, Files} = file:list_dir(Dir), + AFiles = + lists:map(fun(File) -> {File, filename:join([Dir, File])} end, Files), + lists:zf(fun is_dir/1, AFiles). + +is_dir({File, AFile}) -> + {ok, FileInfo} = file:read_file_info(AFile), + case FileInfo#file_info.type of + directory -> + {true, File}; + _ -> + false + end. + +latest_app_dirs(RootDir, Dir) -> + ADir = filename:join(RootDir, Dir), + RDirs0 = get_dirs(ADir), + RDirs1 = lists:filter(fun is_app_dir/1, RDirs0), + %% Build a list of {{App, VsnNumList}, AppVsn} + SDirs0 = + lists:map(fun(AppVsn) -> + [App, VsnStr] = string:tokens(AppVsn, "-"), + VsnNumList = vsnstr_to_numlist(VsnStr), + {{App, VsnNumList}, AppVsn} end, + RDirs1), + SDirs1 = lists:keysort(1, SDirs0), + App2Dirs = lists:foldr(fun({{App, _VsnNumList}, AppVsn}, Acc) -> + case lists:keymember(App, 1, Acc) of + true -> + Acc; + false -> + [{App, AppVsn}| Acc] + end + end, [], SDirs1), + lists:map(fun({App, AppVsn}) -> {App, filename:join([Dir, AppVsn])} end, + App2Dirs). + +is_app_dir(Dir) -> + case string:tokens(Dir, "-") of + [_Name, Rest] -> + is_vsnstr(Rest); + _ -> + false + end. + +is_vsnstr(Str) -> + case string:tokens(Str, ".") of + [_] -> + false; + Toks -> + lists:all(fun is_numstr/1, Toks) + end. + +is_numstr(Cs) -> + lists:all(fun(C) when $0 =< C, C =< $9 -> + true; + (_) -> + false + end, Cs). + +%% We know: + +vsnstr_to_numlist(VsnStr) -> + lists:map(fun(NumStr) -> list_to_integer(NumStr) end, + string:tokens(VsnStr, ".")). + + + + + + + diff --git a/system/doc/top/src/permuted_index.erl b/system/doc/top/src/permuted_index.erl deleted file mode 120000 index e65338a517..0000000000 --- a/system/doc/top/src/permuted_index.erl +++ /dev/null @@ -1 +0,0 @@ -../../../../internal_tools/integration/scripts/make_index/permuted_index.erl
\ No newline at end of file diff --git a/system/doc/top/templates/erlang.gif b/system/doc/top/templates/erlang.gif Binary files differdeleted file mode 100644 index 91fd4b9647..0000000000 --- a/system/doc/top/templates/erlang.gif +++ /dev/null diff --git a/system/doc/top/templates/first.html.src b/system/doc/top/templates/first.html.src deleted file mode 100644 index edef1c0e5c..0000000000 --- a/system/doc/top/templates/first.html.src +++ /dev/null @@ -1,104 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <title>Erlang/OTP #release# Documentation</title> - <style type="text/css"> -<!-- - BODY { background: white } - - BODY { font-family: Verdana, Arial, Helvetica, sans-serif } - TH { font-family: Verdana, Arial, Helvetica, sans-serif } - TD { font-family: Verdana, Arial, Helvetica, sans-serif } - P { font-family: Verdana, Arial, Helvetica, sans-serif } - - .header { background: #222; color: #fff } - .app { background: #ccc } ---> - </style> -</head> -<body bgcolor=white text="#000000" link="#0000ff" vlink="#ff00ff" - alink="#ff0000"> -<center> -<p> -<font size="+1">Welcome to Erlang/OTP, a complete<br> -development environment<br> -for concurrent programming.</font> -</p> -</center> -<br> -<br> -<br> -<p><b> -<font size"+1"> -Some hints that may get you started faster -</font> -</b></p> - -<ul> - -<li>In addition the the documentation here Erlang is described in the book -<a href="http://www.pragprog.com/titles/jaerlang" target="_top">"Programming Erlang"</a>, ISBN 978-1-934356-00-5 which we really recommend as a start.<br/ > -The complete language is also described in the <a href="reference_manual/part_frame.html" target="_top">Erlang Reference Manual</a>. An Erlang tutorial can be found in <a href="getting_started/part_frame.html" target="_top">Getting Started With Erlang</a>. -</li> -<li>Erlang/OTP is divided into a number of OTP <a -href="applications.html">applications</a>. An application normally contains -Erlang <a href="man_index.html">modules</a>. Some OTP applications, -such as the C interface <em>Erl_Interface</em>, are written in other languages and have no Erlang -modules. - -<p> -Note that functions that are not imported or prefixed with a module -name belong to the module -<a href="#kernel#/erlang.html" target="_top">erlang</a> -(in the <em>Kernel</em> application). -</p> -<p> -<li>On a Unix system you can view the manual pages from the command -line using -<pre> - % erl -man <module> -</pre> -<p> - -<li> You can of course use any editor you like to write Erlang -programs, but if you use Emacs there exists editing support such as -indentation, syntax highlighting, electric commands, module name -verification, comment support including paragraph filling, skeletons, -tags support and more. See the <a href="#tools#/index.html" -target="_top">Tools</a> application for details. -<p> -There is also an -<a href="http://erlide.sourceforge.net" target="_top"> -Erlang plugin (ErlIde) for Eclipse</a> if you prefer a more graphical -environment. ErlIde is under development and should at the time -of writing this be quite stable and useful. -<li>When developing with Erlang/OTP you usually test your programs -from the interactive shell (see <a href="getting_started/part_frame.html" -target="_top">Getting Started With Erlang</a>) where you can call individual -functions. There is also a number of tools available, such as the graphical <a -href="#debugger#/index.html" target="_top">Debugger</a>, the process -manager <a href="#pman#/index.html" target="_top">Pman</a> and table -viewer <a href="#tv#/index.html" target="_top">TV</a>. -<p> Also note that there are some shell features like history list -(control-p and control-n), inline editing (emacs key bindings) and -module and function name completion (tab) if the module is loaded. -<p> - -<li>OpenSource users can ask questions -and share experiences on the <a href="http://www.erlang.org/faq.html" -target="_top">Erlang questions mailing list</a>. <p> - -<li>Before asking a question you can browse the <a -href="http://www.erlang.org/pipermail/erlang-questions/" -target="_top">mailing list archive</a> and read the <a -href="http://www.erlang.org/faq/faq.html" target="_top">Frequently -Asked Questions</a>. <p> - -<li>Additional information and links of interest for Erlang programmers can be found on the Erlang Open Source site -<a href="http://www.erlang.org/" target="_top">http://www.erlang.org</a>. -<p> - -</ul> - -</body> -</html> diff --git a/system/doc/top/templates/flip_closed.gif b/system/doc/top/templates/flip_closed.gif Binary files differdeleted file mode 100755 index 9a27c7c25d..0000000000 --- a/system/doc/top/templates/flip_closed.gif +++ /dev/null diff --git a/system/doc/top/templates/flip_google.gif b/system/doc/top/templates/flip_google.gif Binary files differdeleted file mode 100755 index 3f0543c2bb..0000000000 --- a/system/doc/top/templates/flip_google.gif +++ /dev/null diff --git a/system/doc/top/templates/flip_open.gif b/system/doc/top/templates/flip_open.gif Binary files differdeleted file mode 100755 index 9dda60e73a..0000000000 --- a/system/doc/top/templates/flip_open.gif +++ /dev/null diff --git a/system/doc/top/templates/flip_static.gif b/system/doc/top/templates/flip_static.gif Binary files differdeleted file mode 100755 index 2b3ddb5382..0000000000 --- a/system/doc/top/templates/flip_static.gif +++ /dev/null diff --git a/system/doc/top/templates/flipmenu.js b/system/doc/top/templates/flipmenu.js deleted file mode 100755 index 92a5a58a06..0000000000 --- a/system/doc/top/templates/flipmenu.js +++ /dev/null @@ -1,342 +0,0 @@ -// ######################################################################
-
-// ## flipMenu 5.0.0 (c) J. Reijers
-// ## Last modifications: 23 March 2007
-
-// ######################################################################
-
-// ## Degree of indentation from the left.
- flipIndentation = "5px";
-
-// ## Padding inbetween menu items.
- flipVerticalPadding = "4px";
-
-// ## Margin between the left of the browser and the menu.
- flipLeftMargin = "16px";
-
-// ## Margin between the top of the browser and the menu.
- flipTopMargin = "10px";
-
-// ## Allow multiple menus to fold out without closing all the other open ones.
- flipOpenMultipleMenus = false;
-
-// ## Preserve the current state of the menu (requires cookies).
- flipSaveMenuState = true;
-
-// ## Use custom images for bullets
- flipImages = true;
-
-// ## Images to use (specify full path)
- flipImg_open = "flip_open.gif";
- flipImg_closed = "flip_closed.gif";
- flipImg_static = "flip_static.gif";
-
-// ## Initialise all flipMenus onload
- flipInitOnLoad = true;
-
-// ## Message to display in status bar while loading
- flipLoadingMessage = "Loading...";
-
-// ######################################################################
-
-function alterSize(someSize, alterAmount) {
- someSize = String(someSize);
- var tmpNr = parseFloat(someSize.replace(/\D/g, ""));
- var tmpChar = someSize.replace(/\d/g, "");
- return isNaN(tmpNr) ? someSize : ((tmpNr + alterAmount) + tmpChar);
-}
-
-isIE = (String(navigator.appVersion).indexOf("MSIE") > -1);
-if (!isIE) flipIndentation = alterSize(flipIndentation, -16);
-if (!isIE) flipLeftMargin = alterSize(flipLeftMargin, -16);
-
-document.write(
- "<style type=\"text/css\">" +
-
- "ul.flipMenu { margin-top: " + flipTopMargin + "; margin-left: " + flipLeftMargin + "; " + (flipImages ? "" : "list-style-type: none;") + " }" +
- "ul.flipMenu ul, ul.flipMenu li { padding-top: " + flipVerticalPadding + "; margin-left: " + flipIndentation + "; margin-right: 0px; " + (flipImages ? "" : "list-style-type: none;") + " }" +
-
- "li.flipFolderOpen { cursor: pointer; " + (flipImages ? "list-style-image: url(" + flipImg_open + ");" : "") + " }" +
- "li.flipFolderClosed { cursor: pointer; " + (flipImages ? "list-style-image: url(" + flipImg_closed + ");" : "") + " }" +
-
- "</style>"
-);
-
-if (flipImages) {
- aFlipPreloads = [];
- aFlipPreloads[0] = new Image;
- aFlipPreloads[0].src = flipImg_open;
- aFlipPreloads[1] = new Image;
- aFlipPreloads[1].src = flipImg_closed;
- aFlipPreloads[2] = new Image;
- aFlipPreloads[2].src = flipImg_static;
-}
-
-function addEvent(someObj, someEvent, someFunction) {
- if (someObj.addEventListener) { someObj.addEventListener(someEvent, someFunction, true); return true; } else if (someObj.attachEvent) return someObj.attachEvent("on" + someEvent, someFunction); else return false;
-}
-
-function openCloseFlip(theItem, newSetting, openParents) {
- if (theItem.flipID) {
- if (openParents) {
- var tmpItem = theItem;
- while (tmpItem.parentElement || tmpItem.parentNode) {
- tmpItem = (tmpItem.parentElement) ? tmpItem.parentElement : tmpItem.parentNode;
- openCloseFlip(tmpItem, newSetting);
- }
- }
- if ((theItem.className == "flipFolderOpen" && newSetting == "closed") || (theItem.className == "flipFolderClosed" && newSetting == "open")) {
- if (!theItem.childrenInitialised) {
- for (var j = 0; j < theItem.childNodes.length; j++) if (theItem.childNodes[j].nodeName == "UL" && !theItem.childNodes[j].initialised) initFlip(theItem.childNodes[j]);
- theItem.childrenInitialised = true;
- }
- theItem.getElementsByTagName("UL")[0].style.display = (newSetting == "open") ? "" : "none";
- theItem.className = newSetting == "open" ? "flipFolderOpen" : "flipFolderClosed";
- }
- }
-}
-
-function openFlip(theItem, openParents) {
- openCloseFlip(theItem, "open", openParents);
-}
-
-function closeFlip(theItem, closeParents) {
- openCloseFlip(theItem, "closed", closeParents);
-}
-
-function toggleFlip(theElement) {
- if (theElement.flipID) {
- var theItem = theElement;
- var isContained = true;
- } else {
- if (theElement && theElement.button > 0) return false;
- var theItem = (isIE) ? event.srcElement : theElement.target;
-
- var isContained = false;
- if (theItem.className == "flipFolderOpen" || theItem.className == "flipFolderClosed") isContained = true; else while (theItem.parentElement || theItem.parentNode) {
- if (theItem.className == "flipStatic" || theItem.className == "flipFolderOpen" || theItem.className == "flipFolderClosed") {
- isContained = (theItem.className == "flipFolderOpen" || theItem.className == "flipFolderClosed");
- break;
- }
- theItem = (theItem.parentElement) ? theItem.parentElement : theItem.parentNode;
- }
- }
-
- var toOpenFlip = (isContained && theItem.className == "flipFolderClosed");
-
- if (!flipOpenMultipleMenus && (toOpenFlip || theItem.className == "flipStatic")) {
- if (theItem.parentElement || theItem.parentNode) {
- var parentUL = (theItem.parentElement) ? theItem.parentElement : theItem.parentNode;
- for (var i = 0; i < parentUL.childNodes.length; i++) closeFlip(parentUL.childNodes[i]);
- }
- }
-
- if (isContained) {
- if (toOpenFlip) openFlip(theItem); else closeFlip(theItem);
- }
-}
-
-function setAllFlips(startElement, newSetting) {
- if (typeof startElement == "undefined") var startElement = document;
- if (typeof newSetting == "undefined") var newSetting = "closed";
-
- var aUL = startElement.getElementsByTagName("UL");
- for (var i = 0; i < aUL.length; i++) {
- var parentFlip = aUL[i].parentElement ? aUL[i].parentElement : aUL[i].parentNode;
- openCloseFlip(parentFlip, newSetting);
- }
-}
-
-function openAllFlips(startElement) {
- setAllFlips(startElement, "open");
-}
-
-function closeAllFlips(startElement) {
- setAllFlips(startElement, "closed");
-}
-
-function initFlip(startElement) {
- if (!document.createElement) return false;
-
- if (!startElement || !startElement.nodeName) {
- var aUL = document.getElementsByTagName("UL");
- for (var i = 0; i < aUL.length; i++) {
- if (flipLoadingMessage != "") window.status = flipLoadingMessage + " " + parseInt((i / (aUL.length - 1)) * 100, 10) + "%";
- var curUL = aUL[i];
- if (curUL.className == "flipMenu") {
- initFlip(curUL);
-
- // ## Fix text selecting problem in Mozilla
- curUL.onselectstart = new Function("return false");
- curUL.onmousedown = new Function("return false");
- curUL.onclick = new Function("return true");
- }
- }
-
- if (flipSaveMenuState) loadMenuState();
-
- if (flipLoadingMessage != "") window.status = "";
- return true;
- }
-
- if (startElement.className == "flipMenu") startElement.style.display = "";
-
- if (!startElement.childNodes || startElement.childNodes.length == 0) return false;
-
- if (typeof flipIDCur == "undefined") flipIDCur = 0;
- if (!startElement.initialised) {
- var aUL = startElement.getElementsByTagName("UL");
- for (var i = 0; i < aUL.length; i++) aUL[i].style.display = "none";
- }
-
- for (var i = 0; i < startElement.childNodes.length; i++) {
- var curNode = startElement.childNodes[i];
- if (curNode.nodeName == "LI") {
- flipIDCur++;
- curNode.flipID = flipIDCur;
-
- var nodeHasChildren = curNode.getElementsByTagName("UL").length > 0;
- if (nodeHasChildren) {
- if (flipImages && curNode.flipClosed) curNode.style.listStyleImage = "url(" + curNode.flipClosed + ")";
-
- if (curNode.className == null || curNode.className == "") curNode.className = "flipFolderClosed";
- } else {
- curNode.className = "flipStatic";
- if (flipImages && !curNode.style.listStyleImage) {
- if (!curNode.flipStatic) curNode.flipStatic = flipImg_static;
- curNode.style.listStyleImage = "url(" + curNode.flipStatic + ")";
- }
- }
-
- if (!curNode.flipOpen) curNode.flipOpen = flipImg_open;
- if (!curNode.flipClosed) curNode.flipClosed = flipImg_closed;
-
- if (curNode.flipIsOpen) openFlip(curNode);
- }
- }
-
- startElement.initialised = true;
-}
-
-function rootOfFlip(flipID, startElement) {
-
- function containsFlip(startElement, flipID) {
- var flipFound = false;
- var i = 0;
- while (i < startElement.childNodes.length && !flipFound) {
- var curNode = startElement.childNodes[i];
- flipFound = (curNode.flipID == flipID) ? true : containsFlip(curNode, flipID);
- i++;
- }
- return flipFound;
- }
-
- var rootFlip = null;
-
- if (!startElement || !startElement.nodeName) {
- var aUL = document.getElementsByTagName("UL");
- var i = 0;
- while (rootFlip == null && i < aUL.length) {
- var curUL = aUL[i];
- if (curUL.nodeName == "UL" && curUL.className == "flipMenu") rootFlip = rootOfFlip(flipID, curUL);
- i++;
- }
- return rootFlip;
- }
-
- if (startElement.childNodes) for (var i = 0; i < startElement.childNodes.length; i++) {
- var curNode = startElement.childNodes[i];
- if (curNode.flipID == flipID || containsFlip(curNode, flipID)) rootFlip = curNode;
- }
-
- return rootFlip;
-}
-
-function getCookie(cookieName) {
- var allCookies = document.cookie;
- var indexStr = allCookies.indexOf(cookieName + "=");
- if (indexStr == -1) return "";
- indexStr = allCookies.indexOf("=", indexStr) + 1;
- var endStr = allCookies.indexOf(";", indexStr);
- if (endStr == -1) endStr = allCookies.length;
- return unescape(allCookies.substring(indexStr, endStr));
-}
-
-function inArray(someID, someArray) {
- for (var i = 0; i < someArray.length; i++) if (someArray[i] == someID) return true;
- return false;
-}
-
-function getMenuState(startElement) {
- if (!startElement.childNodes || startElement.childNodes.length == 0) return "";
-
- var openItems = "";
- var aUL = startElement.getElementsByTagName("UL");
- for (var i = 0; i < aUL.length; i++) {
- var curNode = aUL[i];
- var parentFlip = (curNode.parentElement) ? curNode.parentElement : curNode.parentNode;
- if (curNode.style.display == "" && parentFlip.flipID) openItems += " " + parentFlip.flipID;
- }
- return openItems;
-}
-
-function putMenuState(startElement) {
- if (!startElement.childNodes || startElement.childNodes.length == 0) return false;
-
- var aUL = startElement.getElementsByTagName("UL");
- for (var i = 0; i < aUL.length; i++) {
- var curNode = aUL[i];
- var parentFlip = (curNode.parentElement) ? curNode.parentElement : curNode.parentNode;
- if (inArray(parentFlip.flipID, aOpenItems)) {
- openFlip(parentFlip);
- if (typeof prevFlipRoot == "undefined") {
- var testRoot = rootOfFlip(parentFlip.flipID);
- if (testRoot.flipID == parentFlip.flipID) prevFlipRoot = testRoot;
- }
- }
- }
-}
-
-function saveMenuState() {
- if (flipSaveMenuState) {
- var aUL = document.getElementsByTagName("UL");
- for (var i = 0; i < aUL.length; i++) {
- var curUL = aUL[i];
- var curID = curUL.id ? curUL.id : i;
- if (curUL.className == "flipMenu") document.cookie = cookiePrefix + curID + "=" + getMenuState(curUL) + ";";
- }
- }
-}
-
-function loadMenuState() {
- var aUL = document.getElementsByTagName("UL");
- for (var i = 0; i < aUL.length; i++) {
- var curUL = aUL[i];
- var curID = curUL.id ? curUL.id : i;
- if (curUL.className == "flipMenu") {
- var savedState = String(getCookie(cookiePrefix + curID));
- if (savedState != "") {
- aOpenItems = savedState.split(" ");
- putMenuState(curUL);
- }
- }
- }
-
- addEvent(window, "unload", saveMenuState);
-}
-
-function clearMenuState(flipMenuID) {
- if (typeof flipMenuID == "undefined") {
- var aUL = document.getElementsByTagName("UL");
- for (var i = 0; i < aUL.length; i++) {
- var curUL = aUL[i];
- var curID = curUL.id ? curUL.id : i;
- if (curUL.className == "flipMenu") document.cookie = cookiePrefix + curID + "=;";
- }
- } else document.cookie = cookiePrefix + flipMenuID + "=;";
-}
-
-cookiePrefix = document.location.pathname + "_";
-
-addEvent(document, "click", toggleFlip);
-if (flipInitOnLoad) addEvent(window, "load", initFlip);
diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src index 935bb11c80..257a656316 100644 --- a/system/doc/top/templates/index.html.src +++ b/system/doc/top/templates/index.html.src @@ -2,7 +2,7 @@ <!-- %CopyrightBegin% -Copyright Ericsson AB 2001-2009. All Rights Reserved. +Copyright Ericsson AB 2009-2010. All Rights Reserved. The contents of this file are subject to the Erlang Public License, Version 1.1, (the "License"); you may not use this file except in @@ -169,7 +169,7 @@ Asked Questions</a>. <p> <center> <small> -Copyright © 1999-2009 +Copyright © 1999-2010 <a href="http://www.ericsson.com">Ericsson AB</a> </small> </center> diff --git a/system/doc/top/templates/otp_top.css b/system/doc/top/templates/otp_top.css deleted file mode 100644 index 1c6d27bd8d..0000000000 --- a/system/doc/top/templates/otp_top.css +++ /dev/null @@ -1,53 +0,0 @@ - BODY { background: white } - - BODY { font-family: Verdana, Arial, Helvetica, sans-serif } - TH { font-family: Verdana, Arial, Helvetica, sans-serif } - TD { font-family: Verdana, Arial, Helvetica, sans-serif } - P { font-family: Verdana, Arial, Helvetica, sans-serif } - - .header { background: #222; color: #fff } - .top { background: #efe } - .otp { background: #efe } - .erlang { background: #ffe } - .otp2 { background: #efe } - .app { background: #ffe } - - a:link { color: blue; text-decoration: none } - a:active { color: blue; text-decoration: none } - a:visited { color: blue; text-decoration: none } - body { - margin: 0; - padding: 0; - border: 0; - overflow: scroll; - height: 100%; - max-height: 100% - } - #container { - width: 100%; - margin: 10px auto; - background-color: #fff; - } - #leftnav { - float: left; - width: 200px; - margin: 0; - padding: 1em; - } - #content { - margin-left: 220px; /* set left value to WidthOfFrameDiv */ - border-left: 1px solid red; - } - - .innertube { - margin: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */ - } - - * html body{ /* IE6 hack */ - padding: 0 0 0 200px; /* Set value to (0 0 0 WidthOfFrameDiv)*/ - } - * html #maincontent{ /* IE6 hack*/ - height: 100%; - width: 100%; - } - diff --git a/system/doc/top/templates/system.html.src b/system/doc/top/templates/system.html.src deleted file mode 100644 index 761bc96ed0..0000000000 --- a/system/doc/top/templates/system.html.src +++ /dev/null @@ -1,281 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <title>Erlang/OTP #release#</title> - <style type="text/css"> -<!-- - BODY { background: white } - - BODY { font-family: Verdana, Arial, Helvetica, sans-serif } - TH { font-family: Verdana, Arial, Helvetica, sans-serif } - TD { font-family: Verdana, Arial, Helvetica, sans-serif } - P { font-family: Verdana, Arial, Helvetica, sans-serif } - - .header { background: #222; color: #fff } - .app { background: #ccc } - - a.anum:link { color: green; text-decoration: none } - a.anum:active { color: green; text-decoration: none } - a.anum:visited { color: green; text-decoration: none } - - a:link { text-decoration: none } - a:active { text-decoration: none } - a:visited { text-decoration: none } ---> - </style> -</head> - -<body bgcolor=white text="#000000" link="#0000ff" vlink="#ff00ff" - alink="#ff0000"> -<center> -<table border=0 width="90%" cellspacing=3 cellpadding=5> - - <tr> - <td colspan=2 class=header> - <font size="+1"><b>General</b></font> - </td> - </tr> - - <tr class=app> - <td align=left valign=top> - <table border=0 width="100%" cellspacing=0 cellpadding=0> - <tr class=app> - <td align=left valign=top> - <a href="system_architecture_intro/part_frame.html" target="_top" - name=system_architecture_intro> - Introduction - </a> - </td> - <td align=right valign=top width=50> - </td> - </tr> - </table> - </td> - <td align=left valign=top> -About Erlang, OTP, Erlang/OTP and this documentation - </td> - </tr> - - <tr class=app> - <td align=left valign=top> - <table border=0 width="100%" cellspacing=0 cellpadding=0> - <tr class=app> - <td align=left valign=top> - <a href="installation_guide/part_frame.html" target="_top" - name=installation_guide> - Installation Guide - </a> - </td> - <td align=right valign=top width=50> - </td> - </tr> - </table> - </td> - <td align=left valign=top> -The Erlang/OTP Installation Guide - </td> - </tr> - - <tr class=app> - <td align=left valign=top> - <table border=0 width="100%" cellspacing=0 cellpadding=0> - <tr class=app> - <td align=left valign=top> - <a href="system_principles/part_frame.html" target="_top" - name=system_principles> - System Principles - </a> - </td> - <td align=right valign=top width=20> - </td> - </tr> - </table> - </td> - <td align=left valign=top> -Starting, stopping and configuring the Erlang runtime system - </td> - </tr> - - <tr class=app> - <td align=left valign=top> - <table border=0 width="100%" cellspacing=0 cellpadding=0> - <tr class=app> - <td align=left valign=top> - <a href="embedded/part_frame.html" target="_top" name=embedded> - Embedded System - </a> - </td> - <td align=right valign=top width=50> - </td> - </tr> - </table> - </td> - <td align=left valign=top> -Erlang in an Embedded System - </td> - </tr> - - <tr> - <td colspan=2><font size=1> </font></td> - </tr> - -<!-- ====================================================================== --> - - <tr> - <td colspan=2 class=header> - <font size="+1"><b>Programming in Erlang</b></font> - </td> - </tr> - - <tr class=app> - <td align=left valign=top> - <table border=0 width="100%" cellspacing=0 cellpadding=0> - <tr class=app> - <td align=left valign=top> - <a href="reference_manual/part_frame.html" target="_top" name=reference_manual> - Erlang Reference Manual - </a> - </td> - <td align=right valign=top width=50> - </td> - </tr> - </table> - </td> - <td align=left valign=top> -Description of data types, language constructs and more - </td> - </tr> - - <tr class=app> - <td align=left valign=top> - <table border=0 width="100%" cellspacing=0 cellpadding=0> - <tr class=app> - <td align=left valign=top> - <a href="getting_started/part_frame.html" target="_top" name=getting_started> - Getting Started - </a> - </td> - <td align=right valign=top width=50> - </td> - </tr> - </table> - </td> - <td align=left valign=top> -Getting started with Erlang - </td> - </tr> - - <tr class=app> - <td align=left valign=top> - <table border=0 width="100%" cellspacing=0 cellpadding=0> - <tr class=app> - <td align=left valign=top> - <a href="programming_examples/part_frame.html" target="_top" name=programming_examples> - Programming Examples - </a> - </td> - <td align=right valign=top width=50> - </td> - </tr> - </table> - </td> - <td align=left valign=top> -Examples of using records, funs, list comprehensions and the bit syntax - </td> - </tr> - - <tr class=app> - <td align=left valign=top> - <table border=0 width="100%" cellspacing=0 cellpadding=0> - <tr class=app> - <td align=left valign=top> - <a href="efficiency_guide/part_frame.html" target="_top" name=efficiency_guide>Efficiency Guide</a> - </td> - <td align=right valign=top width=20> - </td> - </tr> - </table> - </td> - <td align=left valign=top> -Learn how to write efficient programs in Erlang - </td> - </tr> - - <tr class=app> - <td align=left valign=top> - <table border=0 width="100%" cellspacing=0 cellpadding=0> - <tr class=app> - <td align=left valign=top> - <a href="tutorial/part_frame.html" target="_top" name=tutorial>Interoperability Tutorial</a> - </td> - <td align=right valign=top width=20> - </td> - </tr> - </table> - </td> - <td align=left valign=top> -About interoperating with programs written in other programming languages - </td> - </tr> - - <tr> - <td colspan=2><font size=1> </font></td> - </tr> - -<!-- ====================================================================== --> - - <tr> - <td colspan=2 class=header> - <font size="+1"><b>Working with OTP</b></font> - </td> - </tr> - - <tr class=app> - <td align=left valign=top> - <table border=0 width="100%" cellspacing=0 cellpadding=0> - <tr class=app> - <td align=left valign=top> - <a href="design_principles/part_frame.html" target="_top" - name=design_principles> - Design Principles - </a> - </td> - <td align=right valign=top width=20> - </td> - </tr> - </table> - </td> - <td align=left valign=top> -Structure your programs with applications, supervisors and generic behaviors (gen_server, gen_event and gen_fsm). -Also use the built in error logger. - </td> - </tr> - - <tr class=app> - <td align=left valign=top> - <table border=0 width="100%" cellspacing=0 cellpadding=0> - <tr class=app> - <td align=left valign=top> - <a href="oam/part_frame.html" target="_top" name=oam>OAM Principles</a> - </td> - <td align=right valign=top width=20> - </td> - </tr> - </table> - </td> - <td align=left valign=top> -OTP Operation and Management Principles - </td> - </tr> - - <tr> - <td colspan=2><font size=1> </font></td> - </tr> - -</table> - -</center> -</body> -</html> - - diff --git a/system/doc/top/templates/toc_.html.src b/system/doc/top/templates/toc_.html.src deleted file mode 100644 index 5e79bc0ac8..0000000000 --- a/system/doc/top/templates/toc_.html.src +++ /dev/null @@ -1,105 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <title>Erlang/OTP #release#</title> - <style type="text/css"> -<!-- - BODY { background: white } - - BODY { font-family: Verdana, Arial, Helvetica, sans-serif } - TH { font-family: Verdana, Arial, Helvetica, sans-serif } - TD { font-family: Verdana, Arial, Helvetica, sans-serif } - P { font-family: Verdana, Arial, Helvetica, sans-serif } - - .header { background: #222; color: #fff } - .top { background: #efe } - .otp { background: #efe } - .erlang { background: #ffe } - .otp2 { background: #efe } - .app { background: #ffe } - - a:link { color: blue; text-decoration: none } - a:active { color: blue; text-decoration: none } - a:visited { color: blue; text-decoration: none } ---> - </style> -</head> - -<body bgcolor=white text="#000000" link="#0000ff" vlink="#ff00ff" - alink="#ff0000"> -<center> -<font size="+1"><b>Erlang/OTP #release#</b></font><br> -</center> - -<div class=top> -<small><a href="glossary.html" target=body>Glossary</a> | -<a href="man_index.html" target=body>Modules</a> | -<a href="permuted_index/pidxa.html" target=body>Index</a></small> -<p> -<small><a href="highlights.html" target=body>Release highlights</a><br> -<a href="incompatible.html" target=body>Potential incompatibilities</a> -</small> -</div> - -<p> -<div class=otp> -Erlang/OTP -<br> -·<small><a href="installation_guide/part_frame.html" target="_top" - name=installation_guide>Installation Guide</a></small> - -<br> -·<small><a href="system_principles/part_frame.html" target="_top" - name=system_principles>System Principles</a></small> - -<br> -·<small><a href="embedded/part_frame.html" target="_top" name=embedded>Embedded System</a></small> - -</div> - -<p> -<div class=erlang> -Erlang Programming -<br> -·<small><a href="getting_started/part_frame.html" target="_top" name=getting_started>Getting -Started</a></small> - -<br> -·<small><a href="reference_manual/part_frame.html" target="_top" name=reference_manual>Erlang -Reference Manual</a></small> - -<br> -·<small><a href="programming_examples/part_frame.html" target="_top" name=programming_examples>Programming -Examples</a></small> - -<br> -·<small><a href="efficiency_guide/part_frame.html" target="_top" name=efficiency_guide>Efficiency Guide</a></small> - -<br> -·<small><a href="tutorial/part_frame.html" target="_top" name=tutorial>Interoperability Tutorial</a></small> -</div> - -<p> -<div class=otp2> -Working with OTP -<br> -·<small><a href="design_principles/part_frame.html" target="_top" - name=design_principles>Design Principles</a> -</small> - -<br> -·<small><a href="oam/part_frame.html" target="_top" name=oam>OAM Principles</a></small> - -</div> - -<p> -<div class=app> -Applications -<small>#applinks#</small> -</div> - -<p> -<a href="http://www.erlang.se/" target=body>http://www.erlang.se</a> - -</body> -</html> |