pure-lang-svn Mailing List for Pure (Page 11)
Status: Beta
Brought to you by:
agraef
You can subscribe to this list here.
2008 |
Jan
|
Feb
|
Mar
|
Apr
(5) |
May
(141) |
Jun
(184) |
Jul
(97) |
Aug
(232) |
Sep
(196) |
Oct
|
Nov
|
Dec
|
---|
From: <ag...@us...> - 2008-08-27 00:32:20
|
Revision: 620 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=620&view=rev Author: agraef Date: 2008-08-27 00:32:31 +0000 (Wed, 27 Aug 2008) Log Message: ----------- Add support for private symbols to symbol table. Modified Paths: -------------- pure/trunk/symtable.cc pure/trunk/symtable.hh Modified: pure/trunk/symtable.cc =================================================================== --- pure/trunk/symtable.cc 2008-08-26 22:37:56 UTC (rev 619) +++ pure/trunk/symtable.cc 2008-08-27 00:32:31 UTC (rev 620) @@ -42,42 +42,88 @@ segfault_sym(); } -symbol* symtable::lookup(const string& s) +symbol* symtable::lookup(const string& s, int32_t modno) { - map<string, symbol>::iterator it = tab.find(s); - if (it == tab.end()) + sym_map& m = tab[modno]; + sym_map::iterator it = m.find(s); + if (it == m.end() && modno >= 0) { + m = tab[-1]; + it = m.find(s); + } + if (it == m.end()) return 0; else return &it->second; } -symbol& symtable::sym(const string& s) +symbol& symtable::sym(const string& s, int32_t modno) { - symbol& _sym = tab[s]; + symbol* _symp = lookup(s, modno); + if (_symp) modno = _symp->modno; + symbol& _sym = tab[modno][s]; if (_sym.f == 0) { if ((uint32_t)++fno > rtab.capacity()) rtab.reserve(rtab.capacity()+1024); - _sym = symbol(s, fno); + _sym = symbol(s, fno, modno); //cout << "new symbol " << _sym.f << ": " << _sym.s << endl; rtab[fno] = &_sym; } return _sym; } -symbol& symtable::sym(const string& s, prec_t prec, fix_t fix) +symbol& symtable::sym(const string& s, prec_t prec, fix_t fix, int32_t modno) { assert(prec <= 10); - symbol& _sym = tab[s]; + symbol* _symp = lookup(s, modno); + if (_symp) modno = _symp->modno; + symbol& _sym = tab[modno][s]; if (_sym.f == 0) { if ((uint32_t)++fno > rtab.capacity()) rtab.reserve(rtab.capacity()+1024); - _sym = symbol(s, fno, prec, fix); + _sym = symbol(s, fno, prec, fix, modno); //cout << "new symbol " << _sym.f << ": " << _sym.s << endl; rtab[fno] = &_sym; } return _sym; } +symbol* symtable::xlookup(const string& s, int32_t modno) +{ + sym_map& m = tab[modno]; + sym_map::iterator it = m.find(s); + if (it == m.end()) + return 0; + else + return &it->second; +} + +symbol& symtable::xsym(const string& s, int32_t modno) +{ + symbol& _sym = tab[modno][s]; + if (_sym.f == 0) { + if ((uint32_t)++fno > rtab.capacity()) + rtab.reserve(rtab.capacity()+1024); + _sym = symbol(s, fno, modno); + //cout << "new symbol " << _sym.f << ": " << _sym.s << endl; + rtab[fno] = &_sym; + } + return _sym; +} + +symbol& symtable::xsym(const string& s, prec_t prec, fix_t fix, int32_t modno) +{ + assert(prec <= 10); + symbol& _sym = tab[modno][s]; + if (_sym.f == 0) { + if ((uint32_t)++fno > rtab.capacity()) + rtab.reserve(rtab.capacity()+1024); + _sym = symbol(s, fno, prec, fix, modno); + //cout << "new symbol " << _sym.f << ": " << _sym.s << endl; + rtab[fno] = &_sym; + } + return _sym; +} + symbol& symtable::sym(int32_t f) { assert(f > 0 && (uint32_t)f < rtab.size()); Modified: pure/trunk/symtable.hh =================================================================== --- pure/trunk/symtable.hh 2008-08-26 22:37:56 UTC (rev 619) +++ pure/trunk/symtable.hh 2008-08-27 00:32:31 UTC (rev 620) @@ -20,19 +20,24 @@ string s; // print name prec_t prec; // precedence level fix_t fix; // fixity + int32_t modno; // module key for private symbol, -1 for global symbol symbol() : // constructor for dummy entries - f(0), s(""), prec(10), fix(infix) { } - symbol(const string& _s, int _f) : - f(_f), s(_s), prec(10), fix(infix) { x = expr(f); } - symbol(const string& _s, int _f, prec_t _prec, fix_t _fix) : - f(_f), s(_s), prec(_prec), fix(_fix) { x = expr(f); } + f(0), s(""), prec(10), fix(infix), modno(-1) { } + symbol(const string& _s, int _f, int32_t _modno = -1) : + f(_f), s(_s), prec(10), fix(infix), modno(_modno) { x = expr(f); } + symbol(const string& _s, int _f, prec_t _prec, fix_t _fix, + int32_t _modno = -1) : + f(_f), s(_s), prec(_prec), fix(_fix), modno(_modno) { x = expr(f); } }; /* Symbol table. */ +typedef map<string, symbol> sym_map; +typedef map<int32_t, sym_map> sym_tab; + class symtable { int32_t fno; - map<string, symbol> tab; + sym_tab tab; vector<symbol*> rtab; public: symtable(); @@ -42,11 +47,21 @@ // get current number of symbols in table (symbols are always numbered // consecutively from 1 to nsyms()) int32_t nsyms() { return fno; } - // look up an existing symbol (return 0 if not in table) - symbol* lookup(const string& s); + /* The following routines first search for a symbol in the given module, + failing that they will also search for a global symbol. (If modno==-1 + then only global symbols will be searched.) */ + // look up an existing symbol in given module (return 0 if not in table) + symbol* lookup(const string& s, int32_t modno = -1); // get a symbol by its name (create if necessary) - symbol& sym(const string& s); - symbol& sym(const string& s, prec_t prec, fix_t fix); + symbol& sym(const string& s, int32_t modno = -1); + symbol& sym(const string& s, prec_t prec, fix_t fix, int32_t modno = -1); + /* These work like the above, but will only return exact matches in the + given module. */ + symbol* xlookup(const string& s, int32_t modno = -1); + symbol& xsym(const string& s, int32_t modno = -1); + symbol& xsym(const string& s, prec_t prec, fix_t fix, int32_t modno = -1); + // get a symbol by its number + symbol& sym(int32_t f); // retrieve various builtin symbols (create when necessary) symbol& nil_sym(); symbol& cons_sym(); @@ -80,8 +95,6 @@ symbol& failed_cond_sym() { return sym("failed_cond"); } symbol& signal_sym() { return sym("signal"); } symbol& segfault_sym() { return sym("stack_fault"); } - // get a symbol by its number - symbol& sym(int32_t f); }; #endif // ! SYMTABLE_HH This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-26 22:37:46
|
Revision: 619 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=619&view=rev Author: agraef Date: 2008-08-26 22:37:56 +0000 (Tue, 26 Aug 2008) Log Message: ----------- Refactoring of symbol table code. Modified Paths: -------------- pure/trunk/lexer.ll pure/trunk/pure.cc pure/trunk/symtable.hh Modified: pure/trunk/lexer.ll =================================================================== --- pure/trunk/lexer.ll 2008-08-26 16:10:07 UTC (rev 618) +++ pure/trunk/lexer.ll 2008-08-26 22:37:56 UTC (rev 619) @@ -143,7 +143,7 @@ command_generator(const char *text, int state) { static int list_index, len; - static symbol_map::iterator it, end; + static int32_t f, n; const char *name; assert(interpreter::g_interp); interpreter& interp = *interpreter::g_interp; @@ -154,8 +154,7 @@ /* Must do this here, so that symbols are entered into the globalvars table. */ interp.compile(); - it = interp.symtab.tab.begin(); - end = interp.symtab.tab.end(); + f = 1; n = interp.symtab.nsyms(); len = strlen(text); } @@ -169,18 +168,17 @@ /* Return the next name which partially matches from the symbol list. */ - while (it != end) { - int32_t f = it->second.f; + while (f <= n) { /* Skip non-toplevel symbols. */ if (interp.globenv.find(f) == interp.globenv.end() && interp.macenv.find(f) == interp.macenv.end() && interp.globalvars.find(f) == interp.globalvars.end() && interp.externals.find(f) == interp.externals.end()) { - it++; + f++; continue; } - const string& s = it->first; - it++; + const string& s = interp.symtab.sym(f).s; + f++; if (strncmp(s.c_str(), text, len) == 0) return strdup(s.c_str()); } Modified: pure/trunk/pure.cc =================================================================== --- pure/trunk/pure.cc 2008-08-26 16:10:07 UTC (rev 618) +++ pure/trunk/pure.cc 2008-08-26 22:37:56 UTC (rev 619) @@ -67,7 +67,7 @@ command_generator(const char *text, int state) { static int list_index, len; - static symbol_map::iterator it, end; + static int32_t f, n; const char *name; assert(interpreter::g_interp); interpreter& interp = *interpreter::g_interp; @@ -78,8 +78,7 @@ /* Must do this here, so that symbols are entered into the globalvars table. */ interp.compile(); - it = interp.symtab.tab.begin(); - end = interp.symtab.tab.end(); + f = 1; n = interp.symtab.nsyms(); len = strlen(text); } @@ -93,18 +92,17 @@ /* Return the next name which partially matches from the symbol list. */ - while (it != end) { - int32_t f = it->second.f; + while (f <= n) { /* Skip non-toplevel symbols. */ if (interp.globenv.find(f) == interp.globenv.end() && interp.macenv.find(f) == interp.macenv.end() && interp.globalvars.find(f) == interp.globalvars.end() && interp.externals.find(f) == interp.externals.end()) { - it++; + f++; continue; } - const string& s = it->first; - it++; + const string& s = interp.symtab.sym(f).s; + f++; if (strncmp(s.c_str(), text, len) == 0) return strdup(s.c_str()); } @@ -117,7 +115,7 @@ symbol_generator(const char *text, int state) { static int len; - static symbol_map::iterator it, end; + static int32_t f, n; assert(interpreter::g_interp); interpreter& interp = *interpreter::g_interp; @@ -126,25 +124,23 @@ /* Must do this here, so that symbols are entered into the globalvars table. */ interp.compile(); - it = interp.symtab.tab.begin(); - end = interp.symtab.tab.end(); + f = 1; n = interp.symtab.nsyms(); len = strlen(text); } /* Return the next name which partially matches from the symbol list. */ - while (it != end) { - int32_t f = it->second.f; + while (f <= n) { /* Skip non-toplevel symbols. */ if (interp.globenv.find(f) == interp.globenv.end() && interp.macenv.find(f) == interp.macenv.end() && interp.globalvars.find(f) == interp.globalvars.end() && interp.externals.find(f) == interp.externals.end()) { - it++; + f++; continue; } - const string& s = it->first; - it++; + const string& s = interp.symtab.sym(f).s; + f++; if (strncmp(s.c_str(), text, len) == 0) return strdup(s.c_str()); } Modified: pure/trunk/symtable.hh =================================================================== --- pure/trunk/symtable.hh 2008-08-26 16:10:07 UTC (rev 618) +++ pure/trunk/symtable.hh 2008-08-26 22:37:56 UTC (rev 619) @@ -32,13 +32,16 @@ class symtable { int32_t fno; -public: map<string, symbol> tab; vector<symbol*> rtab; +public: symtable(); // add default declarations for the builtin constants and operators (to be // invoked *after* possibly reading the prelude) void init_builtins(); + // get current number of symbols in table (symbols are always numbered + // consecutively from 1 to nsyms()) + int32_t nsyms() { return fno; } // look up an existing symbol (return 0 if not in table) symbol* lookup(const string& s); // get a symbol by its name (create if necessary) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-26 16:09:58
|
Revision: 618 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=618&view=rev Author: agraef Date: 2008-08-26 16:10:07 +0000 (Tue, 26 Aug 2008) Log Message: ----------- Bugfix in macro substitution involving the catch special form. Modified Paths: -------------- pure/trunk/interpreter.cc Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-08-26 09:43:31 UTC (rev 617) +++ pure/trunk/interpreter.cc 2008-08-26 16:10:07 UTC (rev 618) @@ -2197,9 +2197,9 @@ if (y.xval1().tag() == EXPR::APP && y.xval1().xval1().tag() == symtab.catch_sym().f) { expr u = macred(x, y.xval1().xval2(), idx); - expr v = macred(x, y.xval2(), idx); if (++idx == 0) throw err("error in expression (too many nested closures)"); + expr v = macred(x, y.xval2(), idx); return expr(symtab.catch_sym().x, u, v); } else { expr u = macred(x, y.xval1(), idx), This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-26 09:43:22
|
Revision: 617 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=617&view=rev Author: agraef Date: 2008-08-26 09:43:31 +0000 (Tue, 26 Aug 2008) Log Message: ----------- Update documentation. Modified Paths: -------------- pure/trunk/pure.1.in Modified: pure/trunk/pure.1.in =================================================================== --- pure/trunk/pure.1.in 2008-08-26 00:24:38 UTC (rev 616) +++ pure/trunk/pure.1.in 2008-08-26 09:43:31 UTC (rev 617) @@ -188,16 +188,16 @@ with additional debugging information. .SH PURE OVERVIEW .PP -Pure is a fairly simple but very powerful language. Programs are collections -of equational rules defining functions, and expressions to be -evaluated. Moreover, the \fBconst\fP and \fBlet\fP commands can be used to -assign the value of an expression to a global constant or a variable, and the -\fBdef\fP command can be used to define macros (a kind of ``preprocessing'' -functions to be executed at compile time). +Pure is a fairly simple yet powerful language. Programs are basically +collections of rewriting rules and expressions to be evaluated. For +convenience, it is also possible to define global variables and constants, and +for advanced uses Pure offers macro functions as a kind of preprocessing +facility. These are all described below and in the following sections. .PP -Here's a simple example, entered interactively in the interpreter (note that -the ``>'' symbol at the beginning of each input line is the interpreter's -default command prompt): +Here's a first example which demonstrates how to define a simple recursive +function in Pure, entered interactively in the interpreter (note that the +``>'' symbol at the beginning of each input line is the interpreter's default +command prompt): .sp .nf > // my first Pure example @@ -215,6 +215,15 @@ Unix-like systems this allows you to add a ``shebang'' to your main script in order to turn it into an executable program. .PP +There are a few reserved keywords which cannot be used as identifiers. These +are: case const def else end extern if infix infixl infixr let nullary of +otherwise postfix prefix then using when with. +.PP +Pure is a terse language. You won't see many declarations, and often your +programs will read more like a collection of algebraic specifications (which +in fact they are, only that the specifications are executable). This is +intended and keeps the code tidy and clean. +.PP On the surface, Pure is quite similar to other modern functional languages like Haskell and ML. But under the hood it is a much more dynamic language, more akin to Lisp. In particular, Pure is dynamically typed, so functions can @@ -274,9 +283,11 @@ .I "call by value" semantics. Pure also has a few built-in special forms (most notably, conditional expressions, the short-circuit logical connectives && and || and -the sequencing operator $$) which take some of their arguments using -.I "call by name" -semantics. +the sequencing operator $$) which take some of their arguments unevaluated, +using +.IR "call by name" . +(User-defined special forms can be created with macros. More about that +later.) .PP The Pure language provides built-in support for machine integers (32 bit), bigints (implemented using GMP), floating point values (double precision @@ -490,11 +501,11 @@ .fi .PP .B Toplevel. -At the toplevel, a Pure program basically consists of equations defining -functions (also called ``rules''), constant and variable bindings, and -expressions to be evaluated: +At the toplevel, a Pure program basically consists of rewriting rules (which +are used to define functions and macros), constant and variable definitions, +and expressions to be evaluated: .TP -.B Rules: \fIlhs\fR = \fIrhs\fR; \fBdef\fR \fIlhs\fR = \fIrhs\fR; +.B Rules: \fIlhs\fR = \fIrhs\fR; The basic form can also be augmented with a condition \fBif\fP\ \fIguard\fP tacked on to the end of the rule (which restricts the applicability of the rule to the case that the guard evaluates to a nonzero integer), or the @@ -505,22 +516,23 @@ treats this as a comment). Pure also provides some abbreviations for factoring out common left-hand or right-hand sides in collections of rules; see section RULE SYNTAX below for details. -.sp +.TP +.B Macro rules: def\fR \fIlhs\fR = \fIrhs\fR; A rule starting with the keyword .B def defines a .I macro -function. Such functions are executed at compile time to rewrite expression on -the right-hand side of other definitions, and are typically used to handle -user-defined special forms and simple kinds of optimizations to be performed -at ``preprocessing'' time. Macro rules are described in their own section, see -MACROS below. +function. No guards or multiple left-hand and right-hand sides are permitted +here. Macro rules are used to preprocess expressions on the right-hand side of +other definitions at compile time, and are typically employed to implement +user-defined special forms and simple kinds of optimizations rules. See the +MACROS section below for details and examples. .TP .B Global variable bindings: let\fR \fIlhs\fR = \fIrhs\fR; Binds every variable in the left-hand side pattern to the corresponding -subterm of the evaluated right-hand side. This works like a \fBwhen\fP clause, -but serves to bind \fIglobal\fP variables occurring free on the right-hand -side of other function and variable definitions. +subterm of the right-hand side (after evaluating it). This works like a +\fBwhen\fP clause, but serves to bind \fIglobal\fP variables occurring free on +the right-hand side of other function and variable definitions. .TP .B Constant bindings: const\fR \fIlhs\fR = \fIrhs\fR; An alternative form of \fBlet\fP which defines constants rather than @@ -528,7 +540,7 @@ .B nullary symbols which simply stand for themselves!) Like \fBlet\fP, this construct binds the variable symbols on the left-hand side to the corresponding values -on the evaluated right-hand side. The difference is that +on the right-hand side (after evaluation). The difference is that .B const symbols can only be defined once, after which their values are substituted directly into the right-hand sides of other definitions, rather than being @@ -597,11 +609,11 @@ .fi .PP This works pretty much like global variables in imperative languages, but note -that in Pure the value of a global variable can \fInot\fP be changed inside a -function definition. Thus referential transparency is unimpaired; while the -value of an expression depending on a global variable may change between -different computations, the variable will always take the same value in a -single evaluation. +that in Pure the value of a global variable can \fIonly\fP be changed with a +.B let +command at the toplevel. Thus referential transparency is unimpaired; while +the value of a global variable may change between different toplevel +expressions, it will always take the same value in a single evaluation. .PP Similarly, you can also add new equations to an existing function at any time: .sp @@ -620,20 +632,18 @@ 3628800 .fi .PP -(In interactive mode, it is even possible to completely erase constant, -variable and function definitions. See section INTERACTIVE USAGE for details.) +(In interactive mode, it is even possible to completely erase a definition, +see section INTERACTIVE USAGE for details.) .PP So, while the meaning of a local symbol never changes once its definition has -been processed, the definition of global functions and variables may well -evolve while the program is being processed. When you evaluate an expression, -the interpreter will always use the +been processed, toplevel definitions may well evolve while the program is +being processed, and the interpreter will always use the .I latest -definitions of all global constants, variables and functions used in the -expression, up to the current point in the source where the expression is -evaluated. (This also applies to scripts read from a file, thus you have to -make sure that all required functions, constants and variables have been -defined at each point in a script where an expression is evaluated or assigned -to a global variable or constant.) +definitions at a given point in the source when an expression is +evaluated. This means that, even in a script file, you have to define all +symbols needed in an evaluation +.I before +entering the expression to be evaluated. .PP .B Examples. Here are a few examples of simple Pure programs (see the following section for @@ -732,27 +742,27 @@ \fBend\fP; .fi .SH RULE SYNTAX -Basically, the same rule syntax is used to define functions at the toplevel -and in \fBwith\fP expressions, as well as inside \fBcase\fP, \fBwhen\fP, -\fBlet\fP and \fBconst\fP constructs for the purpose of binding variable -values (however, for obvious reasons guards are not permitted in \fBwhen\fP, -\fBlet\fP and \fBconst\fP clauses). When matching against a function call or -the subject term in a \fBcase\fP expression, the rules are always considered -in the order in which they are written, and the first matching rule (whose -guard evaluates to a nonzero value, if applicable) is picked. (Again, the -\fBwhen\fP construct is treated differently, because each rule is actually a -separate definition.) +Basically, the same rule syntax is used in all kinds of global and local +definitions. However, some constructs (specifically, \fBwhen\fP, \fBlet\fP, +\fBconst\fP and \fBdef\fP) use a restricted rule syntax where no guards or +multiple left-hand and right-hand sides are permitted. When matching against a +function or macro call, or the subject term in a \fBcase\fP expression, the +rules are always considered in the order in which they are written, and the +first matching rule (whose guard evaluates to a nonzero value, if applicable) +is picked. (Again, the \fBwhen\fP construct is treated differently, because +each rule is actually a separate definition.) .PP In any case, the left-hand side pattern must not contain repeated variables (i.e., rules must be ``left-linear''), except for the anonymous variable `_' which matches an arbitrary value without binding a variable symbol. .PP -A left-hand side variable may be followed by one of the special type tags -\fB::int\fP, \fB::bigint\fP, \fB::double\fP, \fB::string\fP, to indicate that -it can only match a constant value of the corresponding built-in type. (This -is useful if you want to write rules matching \fIany\fP object of one of these -types; note that there is no way to write out all ``constructors'' for the -built-in types, as there are infinitely many.) +A left-hand side variable (including the anonymous variable) may be followed +by one of the special type tags \fB::int\fP, \fB::bigint\fP, \fB::double\fP, +\fB::string\fP, to indicate that it can only match a constant value of the +corresponding built-in type. (This is useful if you want to write rules +matching \fIany\fP object of one of these types; note that there is no way to +write out all ``constructors'' for the built-in types, as there are infinitely +many.) .PP Pure also supports Haskell-style ``as'' patterns of the form .IB variable @ pattern @@ -836,32 +846,34 @@ \fBcase\fP ans \fBof\fP "y" | "Y" = 1; _ = 0; \fBend\fP; .fi .SH MACROS -As already mentioned, macros are a special type of functions to be executed as -a kind of ``preprocessing stage'' at compile time. They are useful for many -things, such as the definition of user-defined special forms and optimization -rules to be applied to the source program in its symbolic form. +Macros are a special type of functions to be executed as a kind of +``preprocessing stage'' at compile time. In Pure these are typically used to +define custom special forms and to perform inlining of simple function calls. .PP Whereas the macro facilities of most programming languages simply provide a kind of textual substitution mechanism, Pure macros operate on symbolic expressions and are implemented by the same kind of rewriting rules that are -also used to define ordinary functions in Pure. However, macro rules start out -with the keyword +also used to define ordinary functions in Pure. In difference to these, macro +rules start out with the keyword .BR def , and only simple kinds of rules without any guards or multiple left-hand and -right-hand sides are permitted. Thus, syntactically, a macro definition looks -just like a variable or constant definition, using +right-hand sides are permitted. +.PP +Syntactically, a macro definition looks just like a variable or constant +definition, using .B def in lieu of .B let or .BR const , -but they are processed in an entirely different way. +but they are processed in a different way. Macros are substituted into the +right-hand sides of function, constant and variable definitions. All macro +substitution happens before constant substitutions and the actual compilation +step. Macros can be defined in terms of other macros (also recursively), and +will be expanded using the leftmost-innermost reduction strategy (i.e., macro +calls in macro arguments are expanded before the macro gets applied to its +parameters). .PP -Macros are substituted into the right-hand sides of function, constant and -variable definitions, pretty much like constants are substituted into -definitions. All macro substitution happens before constant substitutions and -the actual compilation step. -.PP Here is a simple example, showing a rule which expands saturated calls of the .B succ function (defined in the prelude) at compile time: @@ -873,27 +885,44 @@ foo x::int = x+1+1; .fi .PP -This can be useful to help the compiler generate better code. (E.g., if you -have a look at the assembler code for the above function, you'll see that it's -basically just a single integer increment instruction, plus the usual -(un)boxing of the integer argument and the result value.) +Rules like these can be useful to help the compiler generate better +code. E.g., try the following interactive command to have a look at the +assembler code for the above `foo' function (\fIwarning:\fP this is not for +the faint at heart): +.sp +.nf +> \fBlist\fP -d foo +.fi .PP +You'll see that (ignoring the function header and the boilerplate code for +boxing and unboxing Pure expressions generated by the compiler) it essentially +boils down to just a single integer increment instruction: +.sp +.nf + ... + %intval = load i32* %1 ; <i32> [#uses=1] + add i32 %intval, 2 ; <i32>:2 [#uses=1] + ... +.fi +.PP Note that a macro may have the same name as an ordinary Pure function, which -is useful for optimizing calls to an existing Pure function, as shown in the -example above. As a slightly more practical example, as of Pure 0.6 the -following rule has been added to the prelude to eliminate saturated function -compositions: +is useful for optimizing calls to an existing function, as shown in the +example above. As a somewhat more practical example, since Pure 0.6 the +following rule has been added to the prelude to eliminate saturated instances +of the right-associative function application operator: .sp .nf -\fBdef\fP (f.g) x = f (g x); +\fBdef\fP f $ x = f x; .fi .sp -Example: +Like in Haskell, this low-priority operator is handy to write cascading +function calls. With the above macro rule, these will be ``inlined'' as +ordinary function applications automagically. Example: .sp .nf -> foo x = (succ.succ) x; +> foo x = bar $ bar $ 2*x; > \fBlist\fP foo -foo x = x+1+1; +foo x = bar (bar (2*x)); .fi .PP Macros can also be recursive, consist of multiple rules and make use of @@ -910,59 +939,58 @@ Note that, whereas the right-hand side of a constant definition really gets evaluated to a normal form at the time the definition is processed, the only things that get evaluated during macro substitution are other macros. The -right-hand side may be an arbitrarily complex Pure expression involving -conditional expressions, binding clauses, etc., but these are +right-hand side may be an arbitrary Pure expression involving conditional +expressions, lambdas, binding clauses, etc., but these are .I not -be evaluated during macro substitution, they just become part of the macro +evaluated during macro substitution, they just become part of the macro expansion (after substituting the macro parameters). For instance, here is a useful little macro `timex', which employs the system function `clock' to report the cpu time in seconds needed to evaluate a given expression, along with the computed result: .sp .nf -> using system; +> \fBusing\fP system; > \fBdef\fP timex x = (clock-t0)/CLOCKS_PER_SEC,y \fBwhen\fP t0 = clock; y = x \fBend\fP; -> sum = foldl (+) 0; -> timex $ sum (1..100000); -0.21,705082704 +> sum = foldl (+) 0L; +> timex $ sum (1L..100000L); +0.43,5000050000L .fi .PP The `timex' macro also provides a useful example of how you can use macros to -define your own special forms, since macro arguments are always called by -name. (Note that the above definition of `timex' wouldn't work as an ordinary -function definition, since the x parameter would have been evaluated already -before it is passed to `timex', making `timex' always return a zero time -value. Try it.) +define your own special forms, since the (expanded) macro arguments are +effectively called by name at runtime. (Note that the above definition of +`timex' wouldn't work as an ordinary function definition, since the x +parameter would have been evaluated already before it is passed to `timex', +making `timex' always return a zero time value. Try it.) .PP -A final remark about the scoping rules used in macros is in order. Pure macros -are lexically scoped, i.e., symbols on the right-hand-side of a macro -definition can never refer to anything outside of the macro definition, and -macro parameter substitution also takes into account binding constructs, such -as +Finally, note that Pure macros are lexically scoped, i.e., symbols on the +right-hand-side of a macro definition can never refer to anything outside the +macro definition, and macro parameter substitution also takes into account +binding constructs, such as .B with and .B when clauses, in the right-hand side of the definition. Macro facilities with these -properties are also known as +pleasant properties are also known as .I hygienic macros. They are not susceptible to so-called ``name capture,'' which makes -macros in less sophisticated languages bug-ridden, hard to use and mostly -useless. +macros in less sophisticated languages bug-ridden and hard to use. .PP Despite their simplicity and ease of use, Pure's macros are an incredibly powerful feature. But with power comes responsibility. If over-used, or used in inappropriate ways, macros can make your code incromprehensible and bloated, and a buggy macro may well kick the Pure compiler into an endless -loop. In other words, macros are a good way to shoot yourself in the foot. So -use them with care, ``or else!'' +loop (usually resulting in a stack overflow at compile time). In other words, +macros are a good way to shoot yourself in the foot. So use them thoughtfully +and with care. .SH DECLARATIONS -As you probably noticed, Pure is very terse. That's because, in contrast to -hopelessly verbose languages like Java, you don't declare much stuff in Pure, -you just define it and be done with it. Usually, all necessary information -about the defined symbols is inferred automatically. However, there are a few -toplevel constructs which let you declare special symbol attributes and manage -programs consisting of several source modules. These are: operator and -constant symbol declarations, +You probably noticed by now that Pure is a very terse language. That's +because, in contrast to hopelessly verbose languages like Java, you don't +declare much stuff in Pure, you just define it and be done with it. Usually, +all necessary information about the defined symbols is inferred +automatically. However, there are a few toplevel constructs which let you +declare special symbol attributes and manage programs consisting of several +source modules. These are: operator and constant symbol declarations, .B extern declarations for external C functions (described in the C INTERFACE section), and @@ -1005,8 +1033,8 @@ Causes each given script to be included, at the position of the .B using clause, but only if the script was not included already. Note that the -constants, variables and functions defined by the included script are then -available anywhere in the program, not just the module that contains the +constants, variables, functions and macros defined by the included script are +then available anywhere in the program, not just the module that contains the .B using clause. .sp @@ -1375,8 +1403,8 @@ Change the current working dir. .TP .B "clear \fR[\fIsymbol\fP ...]\fP" -Purge the definitions of the given symbols (functions, constants or global -variables). If no symbols are given, purge \fIall\fP definitions (after +Purge the definitions of the given symbols (functions, macros, constants or +global variables). If no symbols are given, purge \fIall\fP definitions (after confirmation) made after the most recent .B save command (or the beginning of the interactive session). See the DEFINITION @@ -1490,6 +1518,9 @@ Long format, prints definitions along with the summary symbol information. This implies \fB-s\fP. .TP +.B -m +Print information about defined macros. +.TP .B -s Summary format, print just summary information about listed symbols. .TP @@ -1507,11 +1538,12 @@ .PP If none of the .BR -c , -.B -f +.BR -f , +.B -m and .B -v -options are specified, then all kinds of symbols (constants, functions, -variables) are printed, otherwise only the specified categories will be +options are specified, then all kinds of symbols (constants, functions, macros +and variables) are printed, otherwise only the specified categories will be listed. .PP Note that some of the options (in particular, @@ -1823,9 +1855,9 @@ When definining a function in terms of constant values which have to be computed beforehand, it's usually better to use a .B const -definition (rather than defining a variable or a parameterless function) for -that purpose, since this will often allow the compiler to generate better code -using constant folding and similar techniques. Example: +definition (rather than defining a variable or a parameterless function or +macro) for that purpose, since this will often allow the compiler to generate +better code using constant folding and similar techniques. Example: .sp .nf > \fBextern\fP double atan(double); @@ -1836,13 +1868,26 @@ .fi .PP (If you take a look at the disassembled code for this function, you will find -that the value 2*3.14159265358979 has actually been computed at compile time.) +that the value 2*3.14159265358979 = 6.28318530717959 has actually been +computed at compile time.) .PP -Also, the LLVM backend will eliminate dead code automagically, which enables -you to employ a constant computed at runtime to configure your code for -different environments, without any runtime penalties: +Note that constant definitions differ from parameterless macros in that the +right-hand side of the definition is in fact evaluated at compile time. E.g., +compare the above with the following macro definition: .sp .nf +> \fBclear\fP pi foo +> \fBdef\fP pi = 4*atan 1.0; +> foo x = 2*pi*x; +> \fBlist\fP foo +foo x = 2*(4*atan 1.0)*x; +.fi +.PP +The LLVM backend also eliminates dead code automagically, which enables you to +employ a constant computed at runtime to configure your code for different +environments, without any runtime penalties: +.sp +.nf \fBconst\fP win = index sysinfo "mingw32" >= 0; check boy = bad boy \fBif\fP win; = good boy \fBotherwise\fP; @@ -1892,7 +1937,7 @@ (You'll also have to purge any existing definition of a variable if you want to redefine it as a constant, or vice versa, since Pure won't let you redefine an existing constant or variable as a different kind of symbol. The same also -holds if a symbol is currently defined as a function.) +holds if a symbol is currently defined as a function or a macro.) .PP .B External C functions. The interpreter always takes your This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-26 00:24:31
|
Revision: 616 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=616&view=rev Author: agraef Date: 2008-08-26 00:24:38 +0000 (Tue, 26 Aug 2008) Log Message: ----------- Fix typo. Modified Paths: -------------- pure/trunk/interpreter.cc Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-08-26 00:05:35 UTC (rev 615) +++ pure/trunk/interpreter.cc 2008-08-26 00:24:38 UTC (rev 616) @@ -2194,8 +2194,8 @@ return y; // application: case EXPR::APP: - if (x.xval1().tag() == EXPR::APP && - x.xval1().xval1().tag() == symtab.catch_sym().f) { + if (y.xval1().tag() == EXPR::APP && + y.xval1().xval1().tag() == symtab.catch_sym().f) { expr u = macred(x, y.xval1().xval2(), idx); expr v = macred(x, y.xval2(), idx); if (++idx == 0) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-26 00:05:29
|
Revision: 615 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=615&view=rev Author: agraef Date: 2008-08-26 00:05:35 +0000 (Tue, 26 Aug 2008) Log Message: ----------- Update test logs. Modified Paths: -------------- pure/trunk/test/test015.log pure/trunk/test/test018.log pure/trunk/test/test020.log pure/trunk/test/test021.log Modified: pure/trunk/test/test015.log =================================================================== --- pure/trunk/test/test015.log 2008-08-26 00:01:19 UTC (rev 614) +++ pure/trunk/test/test015.log 2008-08-26 00:05:35 UTC (rev 615) @@ -196,36 +196,36 @@ state 1: #0 }) (11..20)); { - rule #0: c = hdict$zipwith (=>) (catmap (\i -> [(i,double i,str i)]) (1..10)) (1..10) + rule #0: c = hdict (zipwith (=>) (catmap (\i -> [(i,double i,str i)]) (1..10)) (1..10)) state 0: #0 <var> state 1 state 1: #0 } -let c = hdict$zipwith (=>) (catmap (\i/*0:*/ -> [(i/*0:*/,double i/*0:*/,str i/*0:*/)] { +let c = hdict (zipwith (=>) (catmap (\i/*0:*/ -> [(i/*0:*/,double i/*0:*/,str i/*0:*/)] { rule #0: i = [(i,double i,str i)] state 0: #0 <var> state 1 state 1: #0 -}) (1..10)) (1..10); +}) (1..10)) (1..10)); { - rule #0: d = hdict$zipwith (=>) (catmap (\i -> [(i,double i,str i)]) (11..20)) (11..20) + rule #0: d = hdict (zipwith (=>) (catmap (\i -> [(i,double i,str i)]) (11..20)) (11..20)) state 0: #0 <var> state 1 state 1: #0 } -let d = hdict$zipwith (=>) (catmap (\i/*0:*/ -> [(i/*0:*/,double i/*0:*/,str i/*0:*/)] { +let d = hdict (zipwith (=>) (catmap (\i/*0:*/ -> [(i/*0:*/,double i/*0:*/,str i/*0:*/)] { rule #0: i = [(i,double i,str i)] state 0: #0 <var> state 1 state 1: #0 -}) (11..20)) (11..20); +}) (11..20)) (11..20)); { - rule #0: e = dict$zipwith (=>) (map str (1..10)) (map str (1..10)) + rule #0: e = dict (zipwith (=>) (map str (1..10)) (map str (1..10))) state 0: #0 <var> state 1 state 1: #0 } -let e = dict$zipwith (=>) (map str (1..10)) (map str (1..10)); +let e = dict (zipwith (=>) (map str (1..10)) (map str (1..10))); a; Dict (bin 4 4.0 (-1) (bin 2 2.0 0 (bin 1 1.0 0 nil nil) (bin 3 3.0 0 nil nil)) (bin 8 8.0 0 (bin 6 6.0 0 (bin 5 5.0 0 nil nil) (bin 7 7.0 0 nil nil)) (bin 9 9.0 (-1) nil (bin 10 10.0 0 nil nil)))) b; Modified: pure/trunk/test/test018.log =================================================================== --- pure/trunk/test/test018.log 2008-08-26 00:01:19 UTC (rev 614) +++ pure/trunk/test/test018.log 2008-08-26 00:05:35 UTC (rev 615) @@ -70,15 +70,15 @@ "80000000" sprintf "%x" (-4294967295L); "1" -ord$sprintf "%c" 255; +ord (sprintf "%c" 255); 255 -ord$sprintf "%c" 255L; +ord (sprintf "%c" 255L); 255 sscanf "ffffffff" "%x"; -1 -uint$sscanf "ffffffff" "%x"; +uint (sscanf "ffffffff" "%x"); 4294967295L sscanf "4294967295" "%u"; -1 -uint$sscanf "4294967295" "%u"; +uint (sscanf "4294967295" "%u"); 4294967295L Modified: pure/trunk/test/test020.log =================================================================== --- pure/trunk/test/test020.log 2008-08-26 00:01:19 UTC (rev 614) +++ pure/trunk/test/test020.log 2008-08-26 00:05:35 UTC (rev 615) @@ -37,8 +37,8 @@ state 1: #0 }) x; let double_format = "%#0.3g"; -test (f/*0:101*/,x/*0:1101*/,y/*0:111*/) = puts$format (f/*0:101*/,x/*0:1101*/,y/*0:111*/,check (f/*0:101*/,x/*0:1101*/,y/*0:111*/) (catch __error__ (f/*1:101*/ x/*1:1101*/ y/*1:111*/))); -test (f/*0:101*/,x/*0:11*/) = puts$format (f/*0:101*/,x/*0:11*/,check (f/*0:101*/,x/*0:11*/) (catch __error__ (f/*1:101*/ x/*1:11*/))); +test (f/*0:101*/,x/*0:1101*/,y/*0:111*/) = puts (format (f/*0:101*/,x/*0:1101*/,y/*0:111*/,check (f/*0:101*/,x/*0:1101*/,y/*0:111*/) (catch __error__ (f/*1:101*/ x/*1:1101*/ y/*1:111*/)))); +test (f/*0:101*/,x/*0:11*/) = puts (format (f/*0:101*/,x/*0:11*/,check (f/*0:101*/,x/*0:11*/) (catch __error__ (f/*1:101*/ x/*1:11*/)))); check _/*0:01*/ z/*0:1*/ = z/*0:1*/ if numberp z/*0:1*/; check (f/*0:0101*/,x/*0:01101*/,y/*0:0111*/) (g@_/*0:100*/ u/*0:101*/ v/*0:11*/) = __failed__ if f/*0:0101*/===g/*0:100*/&&x/*0:01101*/===u/*0:101*/&&y/*0:0111*/===v/*0:11*/; check (f/*0:0101*/,x/*0:011*/) (g@_/*0:10*/ u/*0:11*/) = __failed__ if f/*0:0101*/===g/*0:10*/&&x/*0:011*/===u/*0:11*/; @@ -211,8 +211,8 @@ state 19: #0 #1 } { - rule #0: test (f,x,y) = puts$format (f,x,y,check (f,x,y) (catch __error__ (f x y))) - rule #1: test (f,x) = puts$format (f,x,check (f,x) (catch __error__ (f x))) + rule #0: test (f,x,y) = puts (format (f,x,y,check (f,x,y) (catch __error__ (f x y)))) + rule #1: test (f,x) = puts (format (f,x,check (f,x) (catch __error__ (f x)))) state 0: #0 #1 <app> state 1 state 1: #0 #1 Modified: pure/trunk/test/test021.log =================================================================== --- pure/trunk/test/test021.log 2008-08-26 00:01:19 UTC (rev 614) +++ pure/trunk/test/test021.log 2008-08-26 00:05:35 UTC (rev 615) @@ -1,6 +1,6 @@ let double_format = "%#0.3g"; -test (f/*0:101*/,x/*0:1101*/,y/*0:111*/) = puts$format (f/*0:101*/,x/*0:1101*/,y/*0:111*/,check (f/*0:101*/,x/*0:1101*/,y/*0:111*/) (catch __error__ (f/*1:101*/ x/*1:1101*/ y/*1:111*/))); -test (f/*0:101*/,x/*0:11*/) = puts$format (f/*0:101*/,x/*0:11*/,check (f/*0:101*/,x/*0:11*/) (catch __error__ (f/*1:101*/ x/*1:11*/))); +test (f/*0:101*/,x/*0:1101*/,y/*0:111*/) = puts (format (f/*0:101*/,x/*0:1101*/,y/*0:111*/,check (f/*0:101*/,x/*0:1101*/,y/*0:111*/) (catch __error__ (f/*1:101*/ x/*1:1101*/ y/*1:111*/)))); +test (f/*0:101*/,x/*0:11*/) = puts (format (f/*0:101*/,x/*0:11*/,check (f/*0:101*/,x/*0:11*/) (catch __error__ (f/*1:101*/ x/*1:11*/)))); check _/*0:01*/ z/*0:1*/ = z/*0:1*/ if numberp z/*0:1*/; check (f/*0:0101*/,x/*0:01101*/,y/*0:0111*/) (g@_/*0:100*/ u/*0:101*/ v/*0:11*/) = __failed__ if f/*0:0101*/===g/*0:100*/&&x/*0:01101*/===u/*0:101*/&&y/*0:0111*/===v/*0:11*/; check (f/*0:0101*/,x/*0:011*/) (g@_/*0:10*/ u/*0:11*/) = __failed__ if f/*0:0101*/===g/*0:10*/&&x/*0:011*/===u/*0:11*/; @@ -193,8 +193,8 @@ state 19: #0 #1 } { - rule #0: test (f,x,y) = puts$format (f,x,y,check (f,x,y) (catch __error__ (f x y))) - rule #1: test (f,x) = puts$format (f,x,check (f,x) (catch __error__ (f x))) + rule #0: test (f,x,y) = puts (format (f,x,y,check (f,x,y) (catch __error__ (f x y)))) + rule #1: test (f,x) = puts (format (f,x,check (f,x) (catch __error__ (f x)))) state 0: #0 #1 <app> state 1 state 1: #0 #1 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-26 00:01:13
|
Revision: 614 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=614&view=rev Author: agraef Date: 2008-08-26 00:01:19 +0000 (Tue, 26 Aug 2008) Log Message: ----------- Update test logs. Modified Paths: -------------- pure/trunk/test/prelude.log Modified: pure/trunk/test/prelude.log =================================================================== --- pure/trunk/test/prelude.log 2008-08-26 00:00:13 UTC (rev 613) +++ pure/trunk/test/prelude.log 2008-08-26 00:01:19 UTC (rev 614) @@ -9,6 +9,8 @@ curry3 f/*0:0001*/ x/*0:001*/ y/*0:01*/ z/*0:1*/ = f/*0:0001*/ (x/*0:001*/,y/*0:01*/,z/*0:1*/); uncurry f/*0:01*/ (x/*0:101*/,y/*0:11*/) = f/*0:01*/ x/*0:101*/ y/*0:11*/; uncurry3 f/*0:01*/ (x/*0:101*/,y/*0:1101*/,z/*0:111*/) = f/*0:01*/ x/*0:101*/ y/*0:1101*/ z/*0:111*/; +def f/*0:01*/$x/*0:1*/ = f/*0:01*/ x/*0:1*/; +def (f/*0:001*/.g/*0:01*/) x/*0:1*/ = f/*0:001*/ (g/*0:01*/ x/*0:1*/); (x/*0:0101*/=>v/*0:011*/)==(y/*0:101*/=>w/*0:11*/) = if x/*0:0101*/==y/*0:101*/ then v/*0:011*/==w/*0:11*/ else 0; (x/*0:0101*/=>v/*0:011*/)!=(y/*0:101*/=>w/*0:11*/) = if x/*0:0101*/!=y/*0:101*/ then 1 else v/*0:011*/!=w/*0:11*/; x/*0:01*/,() = x/*0:01*/; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-26 00:00:13
|
Revision: 613 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=613&view=rev Author: agraef Date: 2008-08-26 00:00:13 +0000 (Tue, 26 Aug 2008) Log Message: ----------- Macro regression tests. Modified Paths: -------------- pure/trunk/ChangeLog Added Paths: ----------- pure/trunk/test/test022.log pure/trunk/test/test022.pure Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-08-25 23:58:55 UTC (rev 612) +++ pure/trunk/ChangeLog 2008-08-26 00:00:13 UTC (rev 613) @@ -1,5 +1,7 @@ 2008-08-26 Albert Graef <Dr....@t-...> + * test/test022.pure: Add macro test script. + * lib/prelude.pure: Add optimization rules for ($) and (.) so that they are expanded at compile time if possible. Added: pure/trunk/test/test022.log =================================================================== --- pure/trunk/test/test022.log (rev 0) +++ pure/trunk/test/test022.log 2008-08-26 00:00:13 UTC (rev 613) @@ -0,0 +1,100 @@ +def foo (bar x/*0:11*/) = foo x/*0:11*/+1; +def foo x/*0:1*/ = x/*0:1*/; +x; +x +x+1; +x+1 +x+1+1; +x+1+1 +x+1+1+1; +x+1+1+1 +def goo (bar x/*0:11*/) = goo x/*1:11*/+y/*0:*/ when y/*0:*/ = x/*0:11*/+1 end with bar x/*0:1*/ = 0 end; +def goo x/*0:1*/ = x/*0:1*/; +(baz/*2*/ x/*2:*/+y/*0:*/ when y/*0:*/ = baz/*1*/ x/*1:*/+1 { + rule #0: y = baz x+1 + state 0: #0 + <var> state 1 + state 1: #0 +} end with bar x/*0:1*/ = 0 { + rule #0: bar x = 0 + state 0: #0 + <var> state 1 + state 1: #0 +} end)+y/*0:*/ when y/*0:*/ = bar (baz/*0*/ x/*0:*/)+1 { + rule #0: y = bar (baz x)+1 + state 0: #0 + <var> state 1 + state 1: #0 +} end with bar x/*0:1*/ = 0 { + rule #0: bar x = 0 + state 0: #0 + <var> state 1 + state 1: #0 +} end with baz x/*0:1*/ = x/*0:1*/+1 { + rule #0: baz x = x+1 + state 0: #0 + <var> state 1 + state 1: #0 +} end when x/*0:*/ = 99 { + rule #0: x = 99 + state 0: #0 + <var> state 1 + state 1: #0 +} end; +201+(bar 100+1) +(baz/*2*/ y/*2:*/+y/*0:*/ when y/*0:*/ = baz/*1*/ y/*1:*/+1 { + rule #0: y = baz y+1 + state 0: #0 + <var> state 1 + state 1: #0 +} end with bar x/*0:1*/ = 0 { + rule #0: bar x = 0 + state 0: #0 + <var> state 1 + state 1: #0 +} end)+y/*0:*/ when y/*0:*/ = bar (baz/*0*/ y/*0:*/)+1 { + rule #0: y = bar (baz y)+1 + state 0: #0 + <var> state 1 + state 1: #0 +} end with bar x/*0:1*/ = 0 { + rule #0: bar x = 0 + state 0: #0 + <var> state 1 + state 1: #0 +} end with baz x/*0:1*/ = x/*0:1*/+1 { + rule #0: baz x = x+1 + state 0: #0 + <var> state 1 + state 1: #0 +} end when y/*0:*/ = 99 { + rule #0: y = 99 + state 0: #0 + <var> state 1 + state 1: #0 +} end; +201+(bar 100+1) +bar/*0*/ (bar/*0*/ x/*0:*/) with bar x/*0:1*/ = x/*0:1*/+1 { + rule #0: bar x = x+1 + state 0: #0 + <var> state 1 + state 1: #0 +} end when x/*0:*/ = 99 { + rule #0: x = 99 + state 0: #0 + <var> state 1 + state 1: #0 +} end; +101 +bar/*0*/ (bar/*0*/ y/*0:*/) with bar x/*0:1*/ = x/*0:1*/+1 { + rule #0: bar x = x+1 + state 0: #0 + <var> state 1 + state 1: #0 +} end when y/*0:*/ = 99 { + rule #0: y = 99 + state 0: #0 + <var> state 1 + state 1: #0 +} end; +101 Added: pure/trunk/test/test022.pure =================================================================== --- pure/trunk/test/test022.pure (rev 0) +++ pure/trunk/test/test022.pure 2008-08-26 00:00:13 UTC (rev 613) @@ -0,0 +1,30 @@ + +// Macro substitution tests. (Pure 0.6) + +/* This macro just removes a 'bar' from its argument and turns it into '+1'. + This is done recursively so that bar (...(n times)...(bar x)...) turns + into x+1+...(n times)...+1. */ + +def foo (bar x) = foo x+1; +def foo x = x; + +foo x; +foo (bar x); +foo (bar (bar x)); +foo (bar (bar (bar x))); + +/* Test for possible name capture issues. Pure is supposed to have hygienic + macros. If everything is all right, these tests should both return + 201+(bar 100+1). */ + +def goo (bar x) = goo x+y when y = x+1 end with bar x = 0 end; +def goo x = x; + +goo (bar (bar (baz x))) with baz x = x+1 end when x = 99 end; +goo (bar (bar (baz y))) with baz x = x+1 end when y = 99 end; + +/* These will return just 101, since the 'bar' is locally bound, so the first + goo rule doesn't apply. */ + +goo (bar (bar x)) with bar x = x+1 end when x = 99 end; +goo (bar (bar y)) with bar x = x+1 end when y = 99 end; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-25 23:58:48
|
Revision: 612 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=612&view=rev Author: agraef Date: 2008-08-25 23:58:55 +0000 (Mon, 25 Aug 2008) Log Message: ----------- Add optimization rules for some combinators. Modified Paths: -------------- pure/trunk/ChangeLog pure/trunk/lib/prelude.pure Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-08-25 23:56:04 UTC (rev 611) +++ pure/trunk/ChangeLog 2008-08-25 23:58:55 UTC (rev 612) @@ -1,3 +1,8 @@ +2008-08-26 Albert Graef <Dr....@t-...> + + * lib/prelude.pure: Add optimization rules for ($) and (.) so that + they are expanded at compile time if possible. + 2008-08-25 Albert Graef <Dr....@t-...> * parser.yy, lexer.ll, interpreter.cc: Added macro substitution Modified: pure/trunk/lib/prelude.pure =================================================================== --- pure/trunk/lib/prelude.pure 2008-08-25 23:56:04 UTC (rev 611) +++ pure/trunk/lib/prelude.pure 2008-08-25 23:58:55 UTC (rev 612) @@ -91,6 +91,12 @@ uncurry3 f (x,y,z) = f x y z; +/* Some convenient optimization rules which eliminate saturated calls of the + function composition combinators. */ + +def f $ x = f x; +def (f . g) x = f (g x); + /* "Mapsto" operator. This constructor is declared here so that it can be used in other standard library modules to denote special kind of pairs which map keys to values. Here we only define equality of such pairs. */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-25 23:55:57
|
Revision: 611 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=611&view=rev Author: agraef Date: 2008-08-25 23:56:04 +0000 (Mon, 25 Aug 2008) Log Message: ----------- Update documentation. Modified Paths: -------------- pure/trunk/pure.1.in Modified: pure/trunk/pure.1.in =================================================================== --- pure/trunk/pure.1.in 2008-08-25 20:27:34 UTC (rev 610) +++ pure/trunk/pure.1.in 2008-08-25 23:56:04 UTC (rev 611) @@ -494,7 +494,7 @@ functions (also called ``rules''), constant and variable bindings, and expressions to be evaluated: .TP -.B Rules: \fIlhs\fR = \fIrhs\fR; +.B Rules: \fIlhs\fR = \fIrhs\fR; \fBdef\fR \fIlhs\fR = \fIrhs\fR; The basic form can also be augmented with a condition \fBif\fP\ \fIguard\fP tacked on to the end of the rule (which restricts the applicability of the rule to the case that the guard evaluates to a nonzero integer), or the @@ -734,14 +734,14 @@ .SH RULE SYNTAX Basically, the same rule syntax is used to define functions at the toplevel and in \fBwith\fP expressions, as well as inside \fBcase\fP, \fBwhen\fP, -\fBlet\fP and \fBconst\fP constructs for the purpose of binding variable values -(however, for obvious reasons guards are not permitted in \fBwhen\fP, -\fBlet\fP and \fBconst\fP clauses). When matching against a function call or the -subject term in a \fBcase\fP expression, the rules are always considered in -the order in which they are written, and the first matching rule (whose guard -evaluates to a nonzero value, if applicable) is picked. (Again, the \fBwhen\fP -construct is treated differently, because each rule is actually a separate -definition.) +\fBlet\fP and \fBconst\fP constructs for the purpose of binding variable +values (however, for obvious reasons guards are not permitted in \fBwhen\fP, +\fBlet\fP and \fBconst\fP clauses). When matching against a function call or +the subject term in a \fBcase\fP expression, the rules are always considered +in the order in which they are written, and the first matching rule (whose +guard evaluates to a nonzero value, if applicable) is picked. (Again, the +\fBwhen\fP construct is treated differently, because each rule is actually a +separate definition.) .PP In any case, the left-hand side pattern must not contain repeated variables (i.e., rules must be ``left-linear''), except for the anonymous variable `_' @@ -836,7 +836,125 @@ \fBcase\fP ans \fBof\fP "y" | "Y" = 1; _ = 0; \fBend\fP; .fi .SH MACROS -To be written. +As already mentioned, macros are a special type of functions to be executed as +a kind of ``preprocessing stage'' at compile time. They are useful for many +things, such as the definition of user-defined special forms and optimization +rules to be applied to the source program in its symbolic form. +.PP +Whereas the macro facilities of most programming languages simply provide a +kind of textual substitution mechanism, Pure macros operate on symbolic +expressions and are implemented by the same kind of rewriting rules that are +also used to define ordinary functions in Pure. However, macro rules start out +with the keyword +.BR def , +and only simple kinds of rules without any guards or multiple left-hand and +right-hand sides are permitted. Thus, syntactically, a macro definition looks +just like a variable or constant definition, using +.B def +in lieu of +.B let +or +.BR const , +but they are processed in an entirely different way. +.PP +Macros are substituted into the right-hand sides of function, constant and +variable definitions, pretty much like constants are substituted into +definitions. All macro substitution happens before constant substitutions and +the actual compilation step. +.PP +Here is a simple example, showing a rule which expands saturated calls of the +.B succ +function (defined in the prelude) at compile time: +.sp +.nf +> \fBdef\fP succ x = x+1; +> foo x::int = succ (succ x); +> \fBlist\fP foo +foo x::int = x+1+1; +.fi +.PP +This can be useful to help the compiler generate better code. (E.g., if you +have a look at the assembler code for the above function, you'll see that it's +basically just a single integer increment instruction, plus the usual +(un)boxing of the integer argument and the result value.) +.PP +Note that a macro may have the same name as an ordinary Pure function, which +is useful for optimizing calls to an existing Pure function, as shown in the +example above. As a slightly more practical example, as of Pure 0.6 the +following rule has been added to the prelude to eliminate saturated function +compositions: +.sp +.nf +\fBdef\fP (f.g) x = f (g x); +.fi +.sp +Example: +.sp +.nf +> foo x = (succ.succ) x; +> \fBlist\fP foo +foo x = x+1+1; +.fi +.PP +Macros can also be recursive, consist of multiple rules and make use of +pattern-matching like ordinary function definitions. Example: +.sp +.nf +> \fBdef\fP foo (bar x) = foo x+1; +> \fBdef\fP foo x = x; +> baz = foo (bar (bar (bar x))); +> \fBlist\fP baz +baz = x+1+1+1; +.fi +.PP +Note that, whereas the right-hand side of a constant definition really gets +evaluated to a normal form at the time the definition is processed, the only +things that get evaluated during macro substitution are other macros. The +right-hand side may be an arbitrarily complex Pure expression involving +conditional expressions, binding clauses, etc., but these are +.I not +be evaluated during macro substitution, they just become part of the macro +expansion (after substituting the macro parameters). For instance, here is a +useful little macro `timex', which employs the system function `clock' to +report the cpu time in seconds needed to evaluate a given expression, along +with the computed result: +.sp +.nf +> using system; +> \fBdef\fP timex x = (clock-t0)/CLOCKS_PER_SEC,y \fBwhen\fP t0 = clock; y = x \fBend\fP; +> sum = foldl (+) 0; +> timex $ sum (1..100000); +0.21,705082704 +.fi +.PP +The `timex' macro also provides a useful example of how you can use macros to +define your own special forms, since macro arguments are always called by +name. (Note that the above definition of `timex' wouldn't work as an ordinary +function definition, since the x parameter would have been evaluated already +before it is passed to `timex', making `timex' always return a zero time +value. Try it.) +.PP +A final remark about the scoping rules used in macros is in order. Pure macros +are lexically scoped, i.e., symbols on the right-hand-side of a macro +definition can never refer to anything outside of the macro definition, and +macro parameter substitution also takes into account binding constructs, such +as +.B with +and +.B when +clauses, in the right-hand side of the definition. Macro facilities with these +properties are also known as +.I hygienic +macros. They are not susceptible to so-called ``name capture,'' which makes +macros in less sophisticated languages bug-ridden, hard to use and mostly +useless. +.PP +Despite their simplicity and ease of use, Pure's macros are an incredibly +powerful feature. But with power comes responsibility. If over-used, or used +in inappropriate ways, macros can make your code incromprehensible and +bloated, and a buggy macro may well kick the Pure compiler into an endless +loop. In other words, macros are a good way to shoot yourself in the foot. So +use them with care, ``or else!'' .SH DECLARATIONS As you probably noticed, Pure is very terse. That's because, in contrast to hopelessly verbose languages like Java, you don't declare much stuff in Pure, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-25 20:27:27
|
Revision: 610 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=610&view=rev Author: agraef Date: 2008-08-25 20:27:34 +0000 (Mon, 25 Aug 2008) Log Message: ----------- Update documentation. Modified Paths: -------------- pure/trunk/pure.1.in Modified: pure/trunk/pure.1.in =================================================================== --- pure/trunk/pure.1.in 2008-08-25 20:25:57 UTC (rev 609) +++ pure/trunk/pure.1.in 2008-08-25 20:27:34 UTC (rev 610) @@ -835,6 +835,8 @@ .nf \fBcase\fP ans \fBof\fP "y" | "Y" = 1; _ = 0; \fBend\fP; .fi +.SH MACROS +To be written. .SH DECLARATIONS As you probably noticed, Pure is very terse. That's because, in contrast to hopelessly verbose languages like Java, you don't declare much stuff in Pure, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-25 20:26:41
|
Revision: 608 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=608&view=rev Author: agraef Date: 2008-08-25 20:24:03 +0000 (Mon, 25 Aug 2008) Log Message: ----------- Update documentation. Modified Paths: -------------- pure/trunk/pure.1.in Modified: pure/trunk/pure.1.in =================================================================== --- pure/trunk/pure.1.in 2008-08-25 19:56:07 UTC (rev 607) +++ pure/trunk/pure.1.in 2008-08-25 20:24:03 UTC (rev 608) @@ -191,8 +191,9 @@ Pure is a fairly simple but very powerful language. Programs are collections of equational rules defining functions, and expressions to be evaluated. Moreover, the \fBconst\fP and \fBlet\fP commands can be used to -assign the value of an expression to a global constant or a variable, -respectively. +assign the value of an expression to a global constant or a variable, and the +\fBdef\fP command can be used to define macros (a kind of ``preprocessing'' +functions to be executed at compile time). .PP Here's a simple example, entered interactively in the interpreter (note that the ``>'' symbol at the beginning of each input line is the interpreter's @@ -504,6 +505,16 @@ treats this as a comment). Pure also provides some abbreviations for factoring out common left-hand or right-hand sides in collections of rules; see section RULE SYNTAX below for details. +.sp +A rule starting with the keyword +.B def +defines a +.I macro +function. Such functions are executed at compile time to rewrite expression on +the right-hand side of other definitions, and are typically used to handle +user-defined special forms and simple kinds of optimizations to be performed +at ``preprocessing'' time. Macro rules are described in their own section, see +MACROS below. .TP .B Global variable bindings: let\fR \fIlhs\fR = \fIrhs\fR; Binds every variable in the left-hand side pattern to the corresponding This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-25 20:25:51
|
Revision: 609 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=609&view=rev Author: agraef Date: 2008-08-25 20:25:57 +0000 (Mon, 25 Aug 2008) Log Message: ----------- Bump version number. (Needs reconfigure.) Modified Paths: -------------- pure/trunk/ChangeLog pure/trunk/configure pure/trunk/configure.ac Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-08-25 20:24:03 UTC (rev 608) +++ pure/trunk/ChangeLog 2008-08-25 20:25:57 UTC (rev 609) @@ -17,6 +17,8 @@ macro definition can never refer to anything outside the macro definition. (These are also known as "hygienic" macros.) + * configure.ac: Bump version number. (Needs reconfigure.) + 2008-08-24 Albert Graef <Dr....@t-...> * 0.5 release. Modified: pure/trunk/configure =================================================================== --- pure/trunk/configure 2008-08-25 20:24:03 UTC (rev 608) +++ pure/trunk/configure 2008-08-25 20:25:57 UTC (rev 609) @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.61 for pure 0.5. +# Generated by GNU Autoconf 2.61 for pure 0.6. # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. @@ -572,8 +572,8 @@ # Identity of this package. PACKAGE_NAME='pure' PACKAGE_TARNAME='pure' -PACKAGE_VERSION='0.5' -PACKAGE_STRING='pure 0.5' +PACKAGE_VERSION='0.6' +PACKAGE_STRING='pure 0.6' PACKAGE_BUGREPORT='' # Factoring default headers for most tests. @@ -1199,7 +1199,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures pure 0.5 to adapt to many kinds of systems. +\`configure' configures pure 0.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1264,7 +1264,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of pure 0.5:";; + short | recursive ) echo "Configuration of pure 0.6:";; esac cat <<\_ACEOF @@ -1357,7 +1357,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -pure configure 0.5 +pure configure 0.6 generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1371,7 +1371,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by pure $as_me 0.5, which was +It was created by pure $as_me 0.6, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ @@ -5870,7 +5870,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by pure $as_me 0.5, which was +This file was extended by pure $as_me 0.6, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -5919,7 +5919,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -pure config.status 0.5 +pure config.status 0.6 configured by $0, generated by GNU Autoconf 2.61, with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" Modified: pure/trunk/configure.ac =================================================================== --- pure/trunk/configure.ac 2008-08-25 20:24:03 UTC (rev 608) +++ pure/trunk/configure.ac 2008-08-25 20:25:57 UTC (rev 609) @@ -2,7 +2,7 @@ dnl To regenerate the configury after changes: dnl autoconf -I config && autoheader -I config -AC_INIT(pure, 0.5) +AC_INIT(pure, 0.6) AC_CONFIG_AUX_DIR(config) dnl AC_CONFIG_MACRO_DIR(config) AC_CONFIG_HEADERS(config.h) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-25 19:56:02
|
Revision: 607 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=607&view=rev Author: agraef Date: 2008-08-25 19:56:07 +0000 (Mon, 25 Aug 2008) Log Message: ----------- Implement macro substitution facility. Modified Paths: -------------- pure/trunk/ChangeLog pure/trunk/interpreter.cc pure/trunk/interpreter.hh Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-08-25 19:53:35 UTC (rev 606) +++ pure/trunk/ChangeLog 2008-08-25 19:56:07 UTC (rev 607) @@ -1,3 +1,22 @@ +2008-08-25 Albert Graef <Dr....@t-...> + + * parser.yy, lexer.ll, interpreter.cc: Added macro substitution + facility. Pure macros are meta functions executed at compile time, + which are defined by any number of equations (rewriting rules) + prefixed with the 'def' keyword, e.g.: + + def foo (bar x) = foo x+1; + def foo x = x; + + Only simple, unconditional rules are supported by now, but these + are quite powerful already, since, as shown above, the macro + parameters can be arbitrary patterns and macro definitions can + also be recursive. + + Pure macros are lexically scoped, i.e., symbols on the rhs of a + macro definition can never refer to anything outside the macro + definition. (These are also known as "hygienic" macros.) + 2008-08-24 Albert Graef <Dr....@t-...> * 0.5 release. Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-08-25 19:53:35 UTC (rev 606) +++ pure/trunk/interpreter.cc 2008-08-25 19:56:07 UTC (rev 607) @@ -739,8 +739,8 @@ globals g; save_globals(g); compile(); - // promote type tags and substitute constants: - env vars; expr u = csubst(subst(vars, x)); + // promote type tags and substitute macros and constants: + env vars; expr u = csubst(macsubst(subst(vars, x))); compile(u); x = u; pure_expr *res = doeval(u, e); @@ -766,8 +766,8 @@ save_globals(g); compile(); env vars; - // promote type tags and substitute constants: - expr rhs = csubst(subst(vars, x)); + // promote type tags and substitute macros and constants: + expr rhs = csubst(macsubst(subst(vars, x))); expr lhs = bind(vars, pat); build_env(vars, lhs); for (env::const_iterator it = vars.begin(); it != vars.end(); ++it) { @@ -866,8 +866,8 @@ save_globals(g); compile(); env vars; - // promote type tags and substitute constants: - expr rhs = csubst(subst(vars, x)); + // promote type tags and substitute macros and constants: + expr rhs = csubst(macsubst(subst(vars, x))); expr lhs = bind(vars, pat); build_env(vars, lhs); for (env::const_iterator it = vars.begin(); it != vars.end(); ++it) { @@ -1404,10 +1404,10 @@ assert(!r.lhs.is_null()); closure(r, false); if (toplevel) { - // substitute constants: + // substitute macros and constants: expr u = expr(r.lhs), - v = expr(csubst(r.rhs)), - w = expr(csubst(r.qual)); + v = expr(csubst(macsubst(r.rhs))), + w = expr(csubst(macsubst(r.qual))); r = rule(u, v, w); compile(r.rhs); compile(r.qual); @@ -1788,6 +1788,103 @@ } } +expr interpreter::fsubst(const env& funs, expr x, uint8_t idx) +{ + if (x.is_null()) return x; + switch (x.tag()) { + // constants: + case EXPR::VAR: + case EXPR::FVAR: + case EXPR::INT: + case EXPR::BIGINT: + case EXPR::DBL: + case EXPR::STR: + case EXPR::PTR: + return x; + // application: + case EXPR::APP: + if (x.xval1().tag() == EXPR::APP && + x.xval1().xval1().tag() == symtab.catch_sym().f) { + expr u = fsubst(funs, x.xval1().xval2(), idx); + if (++idx == 0) + throw err("error in expression (too many nested closures)"); + expr v = fsubst(funs, x.xval2(), idx); + return expr(symtab.catch_sym().x, u, v); + } else { + expr u = fsubst(funs, x.xval1(), idx), + v = fsubst(funs, x.xval2(), idx); + return expr(u, v); + } + // conditionals: + case EXPR::COND: { + expr u = fsubst(funs, x.xval1(), idx), + v = fsubst(funs, x.xval2(), idx), + w = fsubst(funs, x.xval3(), idx); + return expr::cond(u, v, w); + } + // nested closures: + case EXPR::LAMBDA: { + if (++idx == 0) + throw err("error in expression (too many nested closures)"); + expr u = x.xval1(), v = fsubst(funs, x.xval2(), idx); + return expr::lambda(u, v); + } + case EXPR::CASE: { + expr u = fsubst(funs, x.xval(), idx); + if (++idx == 0) + throw err("error in expression (too many nested closures)"); + const rulel *r = x.rules(); + rulel *s = new rulel; + for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) { + expr u = it->lhs, v = fsubst(funs, it->rhs, idx), + w = fsubst(funs, it->qual, idx); + s->push_back(rule(u, v, w)); + } + return expr::cases(u, s); + } + case EXPR::WHEN: { + const rulel *r = x.rules(); + rulel *s = new rulel; + for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) { + expr u = it->lhs, v = fsubst(funs, it->rhs, idx); + s->push_back(rule(u, v)); + if (++idx == 0) + throw err("error in expression (too many nested closures)"); + } + expr u = fsubst(funs, x.xval(), idx); + return expr::when(u, s); + } + case EXPR::WITH: { + expr u = fsubst(funs, x.xval(), idx); + if (++idx == 0) + throw err("error in expression (too many nested closures)"); + const env *e = x.fenv(); + env *f = new env; + for (env::const_iterator it = e->begin(); it != e->end(); ++it) { + int32_t g = it->first; + const env_info& info = it->second; + const rulel *r = info.rules; + rulel s; + for (rulel::const_iterator jt = r->begin(); jt != r->end(); ++jt) { + expr u = jt->lhs, v = fsubst(funs, jt->rhs, idx), + w = fsubst(funs, jt->qual, idx); + s.push_back(rule(u, v, w)); + } + (*f)[g] = env_info(info.argc, s, info.temp); + } + return expr::with(u, f); + } + default: + assert(x.tag() > 0); + const symbol& sym = symtab.sym(x.tag()); + env::const_iterator it = funs.find(sym.f); + if (it != funs.end()) + return expr(EXPR::FVAR, sym.f, idx); + else + return x; + } +} + expr interpreter::csubst(expr x) { if (x.is_null()) return x; @@ -1883,9 +1980,26 @@ } } -expr interpreter::fsubst(const env& funs, expr x, uint8_t idx) +/* Perform simple macro substitutions on a compile time expression. Does + applicative-order (depth-first) evaluation using the defined macro + substitution rules (which are simple, unconditional term rewriting + rules). Everything else but macro applications is considered constant + here. When we match a macro call, we perform the corresponding reduction + and evaluate the result recursively. + + Note that in contrast to compiled rewriting rules this is essentially a + little term rewriting interpreter here, so it's kind of slow compared to + compiled code, but for macro substitution it should be good enough. (We + can't use compiled code here, since the runtime expression data structure + cannot represent special kinds of expressions like anonymous closures, with + and when clauses, etc.) */ + +expr interpreter::macsubst(expr x) { + char test; if (x.is_null()) return x; + if (stackmax > 0 && stackdir*(&test - baseptr) >= stackmax) + throw err("recursion too deep in macro expansion"); switch (x.tag()) { // constants: case EXPR::VAR: @@ -1897,63 +2011,245 @@ case EXPR::PTR: return x; // application: + case EXPR::APP: { + expr u = macsubst(x.xval1()), + v = macsubst(x.xval2()); + expr w = expr(u, v); + return macval(w); + } + // conditionals: + case EXPR::COND: { + expr u = macsubst(x.xval1()), + v = macsubst(x.xval2()), + w = macsubst(x.xval3()); + return expr::cond(u, v, w); + } + // nested closures: + case EXPR::LAMBDA: { + expr u = x.xval1(), v = macsubst(x.xval2()); + return expr::lambda(u, v); + } + case EXPR::CASE: { + expr u = macsubst(x.xval()); + const rulel *r = x.rules(); + rulel *s = new rulel; + for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) { + expr u = it->lhs, v = macsubst(it->rhs), + w = macsubst(it->qual); + s->push_back(rule(u, v, w)); + } + return expr::cases(u, s); + } + case EXPR::WHEN: { + const rulel *r = x.rules(); + rulel *s = new rulel; + for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) { + expr u = it->lhs, v = macsubst(it->rhs); + s->push_back(rule(u, v)); + } + expr u = macsubst(x.xval()); + return expr::when(u, s); + } + case EXPR::WITH: { + expr u = macsubst(x.xval()); + const env *e = x.fenv(); + env *f = new env; + for (env::const_iterator it = e->begin(); it != e->end(); ++it) { + int32_t g = it->first; + const env_info& info = it->second; + const rulel *r = info.rules; + rulel s; + for (rulel::const_iterator jt = r->begin(); jt != r->end(); ++jt) { + expr u = jt->lhs, v = macsubst(jt->rhs), + w = macsubst(jt->qual); + s.push_back(rule(u, v, w)); + } + (*f)[g] = env_info(info.argc, s, info.temp); + } + return expr::with(u, f); + } + default: + assert(x.tag() > 0); + return macval(x); + } +} + +/* Perform a single macro reduction step. */ + +expr interpreter::varsubst(expr x, uint8_t offs) +{ + char test; + if (x.is_null()) return x; + if (stackmax > 0 && stackdir*(&test - baseptr) >= stackmax) + throw err("recursion too deep in macro expansion"); + switch (x.tag()) { + case EXPR::VAR: + case EXPR::FVAR: + if (((uint32_t)x.vidx()) + offs > 0xff) + throw err("error in expression (too many nested closures)"); + if (x.tag() == EXPR::VAR) + return expr(EXPR::VAR, x.vtag(), x.vidx()+offs, x.ttag(), x.vpath()); + else + return expr(EXPR::FVAR, x.vtag(), x.vidx()+offs); + // constants: + case EXPR::INT: + case EXPR::BIGINT: + case EXPR::DBL: + case EXPR::STR: + case EXPR::PTR: + return x; + // application: + case EXPR::APP: { + expr u = varsubst(x.xval1(), offs), + v = varsubst(x.xval2(), offs); + expr w = expr(u, v); + return macval(w); + } + // conditionals: + case EXPR::COND: { + expr u = varsubst(x.xval1(), offs), + v = varsubst(x.xval2(), offs), + w = varsubst(x.xval3(), offs); + return expr::cond(u, v, w); + } + // nested closures: + case EXPR::LAMBDA: { + expr u = x.xval1(), v = varsubst(x.xval2(), offs); + return expr::lambda(u, v); + } + case EXPR::CASE: { + expr u = varsubst(x.xval(), offs); + const rulel *r = x.rules(); + rulel *s = new rulel; + for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) { + expr u = it->lhs, v = varsubst(it->rhs, offs), + w = varsubst(it->qual, offs); + s->push_back(rule(u, v, w)); + } + return expr::cases(u, s); + } + case EXPR::WHEN: { + const rulel *r = x.rules(); + rulel *s = new rulel; + for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) { + expr u = it->lhs, v = varsubst(it->rhs, offs); + s->push_back(rule(u, v)); + } + expr u = varsubst(x.xval(), offs); + return expr::when(u, s); + } + case EXPR::WITH: { + expr u = varsubst(x.xval(), offs); + const env *e = x.fenv(); + env *f = new env; + for (env::const_iterator it = e->begin(); it != e->end(); ++it) { + int32_t g = it->first; + const env_info& info = it->second; + const rulel *r = info.rules; + rulel s; + for (rulel::const_iterator jt = r->begin(); jt != r->end(); ++jt) { + expr u = jt->lhs, v = varsubst(jt->rhs, offs), + w = varsubst(jt->qual, offs); + s.push_back(rule(u, v, w)); + } + (*f)[g] = env_info(info.argc, s, info.temp); + } + return expr::with(u, f); + } + default: + assert(x.tag() > 0); + return x; + } +} + +expr interpreter::macred(expr x, expr y, uint8_t idx) +{ + char test; + if (y.is_null()) return y; + if (stackmax > 0 && stackdir*(&test - baseptr) >= stackmax) + throw err("recursion too deep in macro expansion"); + switch (y.tag()) { + // constants: + case EXPR::FVAR: + case EXPR::INT: + case EXPR::BIGINT: + case EXPR::DBL: + case EXPR::STR: + case EXPR::PTR: + return y; + // lhs variable + case EXPR::VAR: + if (y.vidx() == idx) { + /* Substitute the macro variables, which are the lhs values whose idx + match the current idx. Note that the deBruijn indices inside the + substituted value must then be shifted by idx, to accommodate for any + local environments inside the macro definition. */ + expr v = varsubst(subterm(x, y.vpath()), idx); +#if DEBUG>1 + std::cerr << "macro var: " << y << " = " << v + << " (" << (uint32_t)idx << ")" << endl; +#endif + return v; + } else + return y; + // application: case EXPR::APP: if (x.xval1().tag() == EXPR::APP && x.xval1().xval1().tag() == symtab.catch_sym().f) { - expr u = fsubst(funs, x.xval1().xval2(), idx); + expr u = macred(x, y.xval1().xval2(), idx); + expr v = macred(x, y.xval2(), idx); if (++idx == 0) throw err("error in expression (too many nested closures)"); - expr v = fsubst(funs, x.xval2(), idx); return expr(symtab.catch_sym().x, u, v); } else { - expr u = fsubst(funs, x.xval1(), idx), - v = fsubst(funs, x.xval2(), idx); + expr u = macred(x, y.xval1(), idx), + v = macred(x, y.xval2(), idx); return expr(u, v); } // conditionals: case EXPR::COND: { - expr u = fsubst(funs, x.xval1(), idx), - v = fsubst(funs, x.xval2(), idx), - w = fsubst(funs, x.xval3(), idx); + expr u = macred(x, y.xval1(), idx), + v = macred(x, y.xval2(), idx), + w = macred(x, y.xval3(), idx); return expr::cond(u, v, w); } // nested closures: case EXPR::LAMBDA: { if (++idx == 0) throw err("error in expression (too many nested closures)"); - expr u = x.xval1(), v = fsubst(funs, x.xval2(), idx); + expr u = y.xval1(), v = macred(x, y.xval2(), idx); return expr::lambda(u, v); } case EXPR::CASE: { - expr u = fsubst(funs, x.xval(), idx); + expr u = macred(x, y.xval(), idx); if (++idx == 0) throw err("error in expression (too many nested closures)"); - const rulel *r = x.rules(); + const rulel *r = y.rules(); rulel *s = new rulel; for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) { - expr u = it->lhs, v = fsubst(funs, it->rhs, idx), - w = fsubst(funs, it->qual, idx); + expr u = it->lhs, v = macred(x, it->rhs, idx), + w = macred(x, it->qual, idx); s->push_back(rule(u, v, w)); } return expr::cases(u, s); } case EXPR::WHEN: { - const rulel *r = x.rules(); + const rulel *r = y.rules(); rulel *s = new rulel; for (rulel::const_iterator it = r->begin(); it != r->end(); ++it) { - expr u = it->lhs, v = fsubst(funs, it->rhs, idx); + expr u = it->lhs, v = macred(x, it->rhs, idx); s->push_back(rule(u, v)); if (++idx == 0) throw err("error in expression (too many nested closures)"); } - expr u = fsubst(funs, x.xval(), idx); + expr u = macred(x, y.xval(), idx); return expr::when(u, s); } case EXPR::WITH: { - expr u = fsubst(funs, x.xval(), idx); + expr u = macred(x, y.xval(), idx); if (++idx == 0) throw err("error in expression (too many nested closures)"); - const env *e = x.fenv(); + const env *e = y.fenv(); env *f = new env; for (env::const_iterator it = e->begin(); it != e->end(); ++it) { int32_t g = it->first; @@ -1961,8 +2257,8 @@ const rulel *r = info.rules; rulel s; for (rulel::const_iterator jt = r->begin(); jt != r->end(); ++jt) { - expr u = jt->lhs, v = fsubst(funs, jt->rhs, idx), - w = fsubst(funs, jt->qual, idx); + expr u = jt->lhs, v = macred(x, jt->rhs, idx), + w = macred(x, jt->qual, idx); s.push_back(rule(u, v, w)); } (*f)[g] = env_info(info.argc, s, info.temp); @@ -1970,16 +2266,50 @@ return expr::with(u, f); } default: - assert(x.tag() > 0); - const symbol& sym = symtab.sym(x.tag()); - env::const_iterator it = funs.find(sym.f); - if (it != funs.end()) - return expr(EXPR::FVAR, sym.f, idx); - else - return x; + assert(y.tag() > 0); + return y; } } +/* Evaluate a macro call. */ + +static exprl get_args(expr x) +{ + expr y, z; + exprl xs; + while (x.is_app(y, z)) xs.push_front(z), x = y; + return xs; +} + +expr interpreter::macval(expr x) +{ + char test; + if (x.is_null()) return x; + if (stackmax > 0 && stackdir*(&test - baseptr) >= stackmax) + throw err("recursion too deep in macro expansion"); + int32_t f; uint32_t argc = count_args(x, f); + if (f <= 0) return x; + env::iterator it = macenv.find(f); + if (it == macenv.end()) return x; + env_info &info = it->second; + if (argc != info.argc) return x; + if (!info.m) + info.m = new matcher(*info.rules, info.argc+1); + assert(info.m); + exprl args = get_args(x); + assert(args.size() == argc); + state *st = info.m->match(args); + if (st) { + assert(!st->r.empty()); + expr y = macred(x, info.m->r[st->r.front()].rhs); +#if DEBUG>1 + std::cerr << "macro expansion: " << x << " -> " << y << endl; +#endif + return macsubst(y); + } + return x; +} + expr* interpreter::uminop(expr *op, expr *x) { if (op->tag() != symtab.sym("-").f) { Modified: pure/trunk/interpreter.hh =================================================================== --- pure/trunk/interpreter.hh 2008-08-25 19:53:35 UTC (rev 606) +++ pure/trunk/interpreter.hh 2008-08-25 19:56:07 UTC (rev 607) @@ -450,8 +450,12 @@ void promote_ttags(expr f, expr x, expr u, expr v); expr bind(env& vars, expr x, bool b = true, path p = path()); expr subst(const env& vars, expr x, uint8_t idx = 0); + expr fsubst(const env& funs, expr x, uint8_t idx = 0); expr csubst(expr x); - expr fsubst(const env& funs, expr x, uint8_t idx = 0); + expr macsubst(expr x); + expr varsubst(expr x, uint8_t offs); + expr macred(expr x, expr y, uint8_t idx = 0); + expr macval(expr x); void closure(expr& l, expr& r, bool b = true); void closure(rule& r, bool b = true); expr *uminop(expr *op, expr *x); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-25 19:53:32
|
Revision: 606 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=606&view=rev Author: agraef Date: 2008-08-25 19:53:35 +0000 (Mon, 25 Aug 2008) Log Message: ----------- Implement matching operation on expression lists. Modified Paths: -------------- pure/trunk/matcher.cc pure/trunk/matcher.hh Modified: pure/trunk/matcher.cc =================================================================== --- pure/trunk/matcher.cc 2008-08-25 10:25:09 UTC (rev 605) +++ pure/trunk/matcher.cc 2008-08-25 19:53:35 UTC (rev 606) @@ -126,6 +126,14 @@ return 0; } +state *matcher::match(state *st, const exprl& x) +{ + for (exprl::const_iterator it = x.begin(), end = x.end(); + it != end && st; it++) + st = match(st, *it); + return st; +} + /* TA construction algorithm. */ state *matcher::make(const rule& ru, uint32_t skip) Modified: pure/trunk/matcher.hh =================================================================== --- pure/trunk/matcher.hh 2008-08-25 10:25:09 UTC (rev 605) +++ pure/trunk/matcher.hh 2008-08-25 19:53:35 UTC (rev 606) @@ -161,7 +161,7 @@ state *match(const exprl& xs) { assert(start!=0); return match(start, xs); } state *match(state *st, expr x); - state *match(state *st, const exprl& x); // XXXTODO + state *match(state *st, const exprl& x); private: // these are used internally by the TA construction algorithm This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-25 10:25:06
|
Revision: 605 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=605&view=rev Author: agraef Date: 2008-08-25 10:25:09 +0000 (Mon, 25 Aug 2008) Log Message: ----------- Add macro infrastructure. Modified Paths: -------------- pure/trunk/interpreter.cc pure/trunk/interpreter.hh pure/trunk/lexer.ll pure/trunk/parser.yy pure/trunk/pure.cc Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-08-24 23:46:59 UTC (rev 604) +++ pure/trunk/interpreter.cc 2008-08-25 10:25:09 UTC (rev 605) @@ -773,9 +773,12 @@ for (env::const_iterator it = vars.begin(); it != vars.end(); ++it) { int32_t f = it->first; const symbol& sym = symtab.sym(f); - env::const_iterator jt = globenv.find(f); - if (jt != globenv.end() && jt->second.t == env_info::cvar) { + env::const_iterator jt = globenv.find(f), kt = macenv.find(f); + if (kt != macenv.end()) { restore_globals(g); + throw err("symbol '"+sym.s+"' is already defined as a macro"); + } else if (jt != globenv.end() && jt->second.t == env_info::cvar) { + restore_globals(g); throw err("symbol '"+sym.s+"' is already defined as a constant"); } else if (jt != globenv.end() && jt->second.t == env_info::fun) { restore_globals(g); @@ -870,9 +873,12 @@ for (env::const_iterator it = vars.begin(); it != vars.end(); ++it) { int32_t f = it->first; const symbol& sym = symtab.sym(f); - env::const_iterator jt = globenv.find(f); - if (jt != globenv.end() && jt->second.t == env_info::cvar) { + env::const_iterator jt = globenv.find(f), kt = macenv.find(f); + if (kt != macenv.end()) { restore_globals(g); + throw err("symbol '"+sym.s+"' is already defined as a macro"); + } else if (jt != globenv.end() && jt->second.t == env_info::cvar) { + restore_globals(g); throw err("symbol '"+sym.s+"' is already defined as a constant"); } else if (jt != globenv.end() && jt->second.t == env_info::fvar) { restore_globals(g); @@ -916,9 +922,12 @@ globals g; save_globals(g); symbol& sym = symtab.sym(tag); - env::const_iterator jt = globenv.find(tag); - if (jt != globenv.end() && jt->second.t == env_info::cvar) { + env::const_iterator jt = globenv.find(tag), kt = macenv.find(tag); + if (kt != macenv.end()) { restore_globals(g); + throw err("symbol '"+sym.s+"' is already defined as a macro"); + } else if (jt != globenv.end() && jt->second.t == env_info::cvar) { + restore_globals(g); throw err("symbol '"+sym.s+"' is already defined as a constant"); } else if (jt != globenv.end() && jt->second.t == env_info::fvar) { restore_globals(g); @@ -1289,8 +1298,11 @@ globenv.erase(it); clearsym(f); } + it = macenv.find(f); + if (it != macenv.end()) + macenv.erase(it); } else if (f == 0 && temp > 0) { - // purge all temporary functions and variables + // purge all temporary symbols for (env::iterator it = globenv.begin(); it != globenv.end(); ) { env::iterator jt = it; ++it; int32_t f = jt->first; @@ -1314,6 +1326,30 @@ } } } + for (env::iterator it = macenv.begin(); it != macenv.end(); ) { + env::iterator jt = it; ++it; + env_info& info = jt->second; + if (info.temp >= temp) + macenv.erase(jt); + else { + // purge temporary rules for non-temporary macros + bool d = false; + rulel& r = *info.rules; + for (rulel::iterator it = r.begin(); it != r.end(); ) + if (it->temp >= temp) { + d = true; + it = r.erase(it); + } else + ++it; + if (d) { + assert(!r.empty()); + if (info.m) { + delete info.m; + info.m = 0; + } + } + } + } if (temp > 1) --temp; } } @@ -1429,6 +1465,48 @@ delete r; } +void interpreter::add_macro_rule(rule *r) +{ + assert(!r->lhs.is_null() && r->qual.is_null()); + closure(*r, false); + int32_t f; uint32_t argc = count_args(r->lhs, f); + if (f <= 0) + throw err("error in macro definition (invalid head symbol)"); + env::iterator it = macenv.find(f), jt = globenv.find(f); + const symbol& sym = symtab.sym(f); + if (jt != globenv.end()) { + if (it->second.t == env_info::cvar) + throw err("symbol '"+sym.s+"' is already defined as a constant"); + else if (it->second.t == env_info::fvar) + throw err("symbol '"+sym.s+"' is already defined as a variable"); + } else if (it != macenv.end()) { + if (it->second.argc != argc) { + ostringstream msg; + msg << "symbol '" << sym.s + << "' was previously defined with " << it->second.argc << " args"; + throw err(msg.str()); + } + } + env_info &info = macenv[f]; + if (info.t == env_info::none) + info = env_info(argc, rulel(), temp); + assert(info.argc == argc); + r->temp = temp; + if (override) { + rulel::iterator p = info.rules->begin(); + for (; p != info.rules->end() && p->temp >= temp; p++) ; + info.rules->insert(p, *r); + } else + info.rules->push_back(*r); + if ((verbose&verbosity::defs) != 0) cout << "def " << *r << ";\n"; + if (info.m) { + // this will be recomputed the next time the macro is needed + delete info.m; + info.m = 0; + } + delete r; +} + void interpreter::closure(expr& l, expr& r, bool b) { env vars; @@ -2187,9 +2265,12 @@ globals g; save_globals(g); symbol& sym = symtab.sym(tag); - env::const_iterator jt = globenv.find(tag); - if (jt != globenv.end() && jt->second.t == env_info::cvar) { + env::const_iterator jt = globenv.find(tag), kt = macenv.find(tag); + if (kt != macenv.end()) { restore_globals(g); + throw err("symbol '"+sym.s+"' is already defined as a macro"); + } else if (jt != globenv.end() && jt->second.t == env_info::cvar) { + restore_globals(g); throw err("symbol '"+sym.s+"' is already defined as a constant"); } else if (jt != globenv.end() && jt->second.t == env_info::fun) { restore_globals(g); Modified: pure/trunk/interpreter.hh =================================================================== --- pure/trunk/interpreter.hh 2008-08-24 23:46:59 UTC (rev 604) +++ pure/trunk/interpreter.hh 2008-08-25 10:25:09 UTC (rev 605) @@ -331,6 +331,7 @@ clock_t clocks; // last evaluation time, if stats is set exprl last; // last processed lhs collection env globenv; // global function and variable environment + env macenv; // global macro environment funset dirty; // "dirty" function entries which need a recompile pure_mem *mem; // runtime expression memory pure_expr *exps; // head of the free list (available expression nodes) @@ -444,6 +445,7 @@ void add_rule(rulel &rl, rule &r, bool b); void add_rule(env &e, rule &r, bool toplevel = false); void add_simple_rule(rulel &rl, rule *r); + void add_macro_rule(rule *r); void promote_ttags(expr f, expr x, expr u); void promote_ttags(expr f, expr x, expr u, expr v); expr bind(env& vars, expr x, bool b = true, path p = path()); Modified: pure/trunk/lexer.ll =================================================================== --- pure/trunk/lexer.ll 2008-08-24 23:46:59 UTC (rev 604) +++ pure/trunk/lexer.ll 2008-08-25 10:25:09 UTC (rev 605) @@ -111,11 +111,12 @@ struct env_sym { const symbol* sym; - env::const_iterator it; + env::const_iterator it, jt; extmap::const_iterator xt; env_sym(const symbol& _sym, env::const_iterator _it, + env::const_iterator _jt, extmap::const_iterator _xt) - : sym(&_sym), it(_it), xt(_xt) { } + : sym(&_sym), it(_it), jt(_jt), xt(_xt) { } }; static bool env_compare(env_sym s, env_sym t) @@ -172,6 +173,7 @@ int32_t f = it->second.f; /* Skip non-toplevel symbols. */ if (interp.globenv.find(f) == interp.globenv.end() && + interp.macenv.find(f) == interp.macenv.end() && interp.globalvars.find(f) == interp.globalvars.end() && interp.externals.find(f) == interp.externals.end()) { it++; @@ -361,7 +363,7 @@ uint8_t s_verbose = interpreter::g_verbose; uint8_t tflag = 0; bool aflag = false, dflag = false, eflag = false; - bool cflag = false, fflag = false, vflag = false; + bool cflag = false, fflag = false, mflag = false, vflag = false; bool gflag = false, lflag = false, sflag = false; const char *s = yytext+4; if (*s && !isspace(*s)) REJECT; @@ -372,7 +374,7 @@ // process option arguments for (arg = args.l.begin(); arg != args.l.end(); arg++) { const char *s = arg->c_str(); - if (s[0] != '-' || !s[1] || !strchr("acdefghlstv", s[1])) break; + if (s[0] != '-' || !s[1] || !strchr("acdefghlmstv", s[1])) break; while (*++s) { switch (*s) { case 'a': aflag = true; break; @@ -382,6 +384,7 @@ case 'f': fflag = true; break; case 'g': gflag = true; break; case 'l': lflag = true; break; + case 'm': mflag = true; break; case 's': sflag = true; break; case 'v': vflag = true; break; case 't': @@ -406,6 +409,7 @@ -h Print this list.\n\ -l Long format, prints definitions along with the summary symbol\n\ information. This implies -s.\n\ +-m Print information about defined macros.\n\ -s Summary format, print just summary information about listed symbols.\n\ -t[level] List only symbols and definitions at the given temporary level\n\ (the current level by default) or above. Level 1 denotes all temporary\n\ @@ -422,10 +426,12 @@ if (eflag) interpreter::g_verbose |= verbosity::envs; if (aflag) interpreter::g_verbose |= verbosity::code; if (dflag) interpreter::g_verbose |= verbosity::dump; - if (!cflag && !fflag && !vflag) cflag = fflag = vflag = true; + if (!cflag && !fflag && !mflag && !vflag) + cflag = fflag = mflag = vflag = true; if (lflag) sflag = true; { - size_t maxsize = 0, nfuns = 0, nvars = 0, ncsts = 0, nrules = 0; + size_t maxsize = 0, nfuns = 0, nmacs = 0, nvars = 0, ncsts = 0, + nrules = 0, mrules = 0; list<env_sym> l; set<int32_t> syms; for (env::const_iterator it = interp.globenv.begin(); it != interp.globenv.end(); ++it) { @@ -462,7 +468,8 @@ } if (!matches) continue; syms.insert(f); - l.push_back(env_sym(sym, it, interp.externals.find(f))); + l.push_back(env_sym(sym, it, interp.macenv.find(f), + interp.externals.find(f))); if (sym.s.size() > maxsize) maxsize = sym.s.size(); } if (fflag && tflag == 0) { @@ -484,11 +491,52 @@ } } if (!matches) continue; - l.push_back(env_sym(sym, interp.globenv.end(), it)); + l.push_back(env_sym(sym, interp.globenv.end(), + interp.macenv.find(f), it)); if (sym.s.size() > maxsize) maxsize = sym.s.size(); } } } + if (mflag) { + // also list any symbols defined as macros, unless they've already been + // considered + for (env::const_iterator it = interp.macenv.begin(); + it != interp.macenv.end(); ++it) { + int32_t f = it->first; + if (syms.find(f) == syms.end()) { + const env_info& e = it->second; + const symbol& sym = interp.symtab.sym(f); + bool matches = e.temp >= tflag; + if (!matches && !sflag && args.l.empty()) { + // if not in summary mode, also list temporary rules for a + // non-temporary symbol + rulel::const_iterator r; + for (r = e.rules->begin(); r != e.rules->end(); r++) + if (r->temp >= tflag) { + matches = true; + break; + } + } + if (!matches) continue; + if (!args.l.empty()) { + // see whether we actually want the defined symbol to be listed + matches = false; + for (arg = args.l.begin(); arg != args.l.end(); ++arg) { + if (gflag ? (!fnmatch(arg->c_str(), sym.s.c_str(), 0)) : + (*arg == sym.s)) { + matches = true; + break; + } + } + } + if (!matches) continue; + syms.insert(f); + l.push_back(env_sym(sym, interp.globenv.end(), it, + interp.externals.end())); + if (sym.s.size() > maxsize) maxsize = sym.s.size(); + } + } + } l.sort(env_compare); if (!l.empty() && (aflag||dflag)) interp.compile(); // we first dump the entire listing into a string and then output that @@ -499,9 +547,9 @@ const symbol& sym = *it->sym; int32_t ftag = sym.f; map<int32_t,Env>::iterator fenv = interp.globalfuns.find(ftag); - const env::const_iterator jt = it->it; + const env::const_iterator jt = it->it, kt = it->jt; const extmap::const_iterator xt = it->xt; - if (jt == interp.globenv.end()) { + if (jt == interp.globenv.end() && kt == interp.macenv.end()) { assert(xt != interp.externals.end()); const ExternInfo& info = xt->second; sout << info << ";"; @@ -511,7 +559,8 @@ } else sout << endl; ++nfuns; - } else if (jt->second.t == env_info::fvar) { + } else if (jt != interp.globenv.end() && + jt->second.t == env_info::fvar) { nvars++; if (sflag) { sout << sym.s << string(maxsize-sym.s.size(), ' ') @@ -522,7 +571,8 @@ } else sout << "let " << sym.s << " = " << *(pure_expr**)jt->second.val << ";\n"; - } else if (jt->second.t == env_info::cvar) { + } else if (jt != interp.globenv.end() && + jt->second.t == env_info::cvar) { ncsts++; if (sflag) { sout << sym.s << string(maxsize-sym.s.size(), ' ') @@ -553,7 +603,7 @@ } sout << " " << (int)sym.prec << " " << sym.s << ";\n"; } - if (xt != interp.externals.end()) { + if (fflag && xt != interp.externals.end()) { const ExternInfo& info = xt->second; sout << info << ";"; if ((!sflag||lflag) && dflag) { @@ -562,58 +612,85 @@ } else sout << endl; } - uint32_t argc = jt->second.argc; - const rulel& rules = *jt->second.rules; - const matcher *m = jt->second.m; - if (sflag) { - ++nfuns; nrules += rules.size(); - sout << sym.s << string(maxsize-sym.s.size(), ' ') << " fun"; - if (lflag) { - sout << " " << rules << ";"; - if (aflag && m) sout << endl << *m; - if (dflag && fenv != interp.globalfuns.end() && fenv->second.f) - fenv->second.print(sout); + if (mflag && kt != interp.macenv.end()) { + uint32_t argc = kt->second.argc; + const rulel& rules = *kt->second.rules; + const matcher *m = kt->second.m; + if (sflag) { + ++nmacs; mrules += rules.size(); + sout << sym.s << string(maxsize-sym.s.size(), ' ') << " mac"; + if (lflag) { + sout << " " << rules << ";"; + if (aflag && m) sout << endl << *m; + } else { + sout << " " << argc << " args, " << rules.size() << " rules"; + } + sout << endl; } else { - sout << " " << argc << " args, " << rules.size() << " rules"; + size_t n = 0; + for (rulel::const_iterator it = rules.begin(); + it != rules.end(); ++it) { + if (it->temp >= tflag) { + sout << "def " << *it << ";\n"; + ++n; + } + } + if (n > 0) { + if (aflag && m) sout << *m << endl; + mrules += n; + ++nmacs; + } } - sout << endl; - } else { - size_t n = 0; - for (rulel::const_iterator it = rules.begin(); - it != rules.end(); ++it) { - if (it->temp >= tflag) { - sout << *it << ";\n"; - ++n; + } + if (fflag && jt != interp.globenv.end()) { + uint32_t argc = jt->second.argc; + const rulel& rules = *jt->second.rules; + const matcher *m = jt->second.m; + if (sflag) { + ++nfuns; nrules += rules.size(); + sout << sym.s << string(maxsize-sym.s.size(), ' ') << " fun"; + if (lflag) { + sout << " " << rules << ";"; + if (aflag && m) sout << endl << *m; + if (dflag && fenv != interp.globalfuns.end() && fenv->second.f) + fenv->second.print(sout); + } else { + sout << " " << argc << " args, " << rules.size() << " rules"; } + sout << endl; + } else { + size_t n = 0; + for (rulel::const_iterator it = rules.begin(); + it != rules.end(); ++it) { + if (it->temp >= tflag) { + sout << *it << ";\n"; + ++n; + } + } + if (n > 0) { + if (aflag && m) sout << *m << endl; + if (dflag && fenv != interp.globalfuns.end() && fenv->second.f) + fenv->second.print(sout); + nrules += n; + ++nfuns; + } } - if (n > 0) { - if (aflag && m) sout << *m << endl; - if (dflag && fenv != interp.globalfuns.end() && fenv->second.f) - fenv->second.print(sout); - nrules += n; - ++nfuns; - } } } } if (sflag) { - if (fflag && vflag && cflag) - sout << ncsts << " constants, " << nvars << " variables, " - << nfuns << " functions, " << nrules << " rules\n"; - else if (fflag && cflag) - sout << ncsts << " constants, " << nfuns << " functions, " - << nrules << " rules\n"; - else if (fflag && vflag) - sout << nvars << " variables, " << nfuns << " functions, " - << nrules << " rules\n"; - else if (cflag && vflag) - sout << ncsts << " constants, " << nvars << " variables\n"; - else if (cflag) - sout << ncsts << " constants\n"; - else if (vflag) - sout << nvars << " variables\n"; - else if (fflag) - sout << nfuns << " functions, " << nrules << " rules\n"; + ostringstream summary; + if (cflag) + summary << ncsts << " constants, "; + if (vflag) + summary << nvars << " variables, "; + if (mflag) + summary << nmacs << " macros (" << mrules << " rules), "; + if (fflag) + summary << nfuns << " functions (" << nrules << " rules), "; + string s = summary.str(); + if (!s.empty()) + sout << s.substr(0, s.size()-2) << endl; } FILE *fp; const char *more = getenv("PURE_MORE"); Modified: pure/trunk/parser.yy =================================================================== --- pure/trunk/parser.yy 2008-08-24 23:46:59 UTC (rev 604) +++ pure/trunk/parser.yy 2008-08-25 10:25:09 UTC (rev 605) @@ -279,6 +279,8 @@ { action(interp.define($2), delete $2); } | CONST simple_rule { action(interp.define_const($2), delete $2); } +| DEF simple_rule +{ action(interp.add_macro_rule($2), delete $2); } | rule { rulel *rl = 0; action(interp.add_rules(interp.globenv, @@ -632,7 +634,8 @@ catch (err &e) { if (rl) delete rl; interp.error(yyloc, e.what()); } } ; -/* Same for simple rules (pattern binding in 'when' clauses, no guards). */ +/* Same for simple rules (pattern binding in 'when' clauses or 'let', 'const', + 'def', no guards in these cases). */ simple_rule : expr '=' expr Modified: pure/trunk/pure.cc =================================================================== --- pure/trunk/pure.cc 2008-08-24 23:46:59 UTC (rev 604) +++ pure/trunk/pure.cc 2008-08-25 10:25:09 UTC (rev 605) @@ -97,6 +97,7 @@ int32_t f = it->second.f; /* Skip non-toplevel symbols. */ if (interp.globenv.find(f) == interp.globenv.end() && + interp.macenv.find(f) == interp.macenv.end() && interp.globalvars.find(f) == interp.globalvars.end() && interp.externals.find(f) == interp.externals.end()) { it++; @@ -136,6 +137,7 @@ int32_t f = it->second.f; /* Skip non-toplevel symbols. */ if (interp.globenv.find(f) == interp.globenv.end() && + interp.macenv.find(f) == interp.macenv.end() && interp.globalvars.find(f) == interp.globalvars.end() && interp.externals.find(f) == interp.externals.end()) { it++; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-24 23:46:49
|
Revision: 604 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=604&view=rev Author: agraef Date: 2008-08-24 23:46:59 +0000 (Sun, 24 Aug 2008) Log Message: ----------- Add some remarks about the purity of Pure. Modified Paths: -------------- pure/trunk/pure.1.in Modified: pure/trunk/pure.1.in =================================================================== --- pure/trunk/pure.1.in 2008-08-24 12:59:31 UTC (rev 603) +++ pure/trunk/pure.1.in 2008-08-24 23:46:59 UTC (rev 604) @@ -1545,10 +1545,24 @@ > \fBunderride\fP .fi .SH CAVEATS AND NOTES -This section is a grab bag of useful tips and tricks, common pitfalls, quirks -and limitations of the current implementation and information on how to deal -with them. +This section is a grab bag of casual remarks, useful tips and tricks, and +information on common pitfalls, quirks and limitations of the current +implementation and how to deal with them. .PP +.B Purity. +People keep asking me what's so ``pure'' about Pure. The long and apologetic +answer is that at its core, Pure is in fact purely algebraic and purely +functional. Pure doesn't get in your way if you want to call external +operations with side effects (it does allow you to call any C function after +all), but with a few exceptions the standard library operations are free of +those. Just stay away from operations marked ``IMPURE'' in the library sources +(most notably, eval and catch/throw) and avoid the system module, then your +program will behave according to the semantics of term rewriting. +.PP +The short answer is that I simply liked the name, and there wasn't any +programming language named ``Pure'' yet (quite a feat nowadays), so there's +one now. :) +.PP .B Debugging. There's no symbolic debugger yet. So .BR printf (3) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-24 12:59:21
|
Revision: 603 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=603&view=rev Author: agraef Date: 2008-08-24 12:59:31 +0000 (Sun, 24 Aug 2008) Log Message: ----------- Comment change. Modified Paths: -------------- pure/trunk/examples/sort.c Modified: pure/trunk/examples/sort.c =================================================================== --- pure/trunk/examples/sort.c 2008-08-24 12:46:27 UTC (rev 602) +++ pure/trunk/examples/sort.c 2008-08-24 12:59:31 UTC (rev 603) @@ -17,12 +17,6 @@ On Windows you might wish to add the '-Wl,--enable-auto-import' linker option.) - I suggest that you also set up your LD_LIBRARY_PATH environment variable - (DYLD_LIBRARY_PATH on OSX) so that the dynamic loader finds sort.so without - further ado. Something like 'export LD_LIBRARY_PATH=.' should do the trick. - Windows doesn't need this since it always searches the current directory - for dlls. - Now start the interpreter and enter the following to "dlopen" sort.so and declare the sort function: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-24 12:46:17
|
Revision: 602 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=602&view=rev Author: agraef Date: 2008-08-24 12:46:27 +0000 (Sun, 24 Aug 2008) Log Message: ----------- Comment change. Modified Paths: -------------- pure/trunk/pure.cc Modified: pure/trunk/pure.cc =================================================================== --- pure/trunk/pure.cc 2008-08-24 12:42:34 UTC (rev 601) +++ pure/trunk/pure.cc 2008-08-24 12:46:27 UTC (rev 602) @@ -232,7 +232,6 @@ want_prelude = true, have_prelude = false; // This is used in advisory stack checks. interpreter::baseptr = &base; - // make sure that SIGPIPE is ignored /* Set up handlers for all standard POSIX termination signals (except SIGKILL which is unmaskable). SIGPIPE is ignored by default, all others are mapped to Pure exceptions of the form 'signal SIG', so that they can This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-24 12:42:24
|
Revision: 601 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=601&view=rev Author: agraef Date: 2008-08-24 12:42:34 +0000 (Sun, 24 Aug 2008) Log Message: ----------- Snapshot of Pure 0.5. Added Paths: ----------- pure/releases/pure-0.5/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-24 09:57:28
|
Revision: 600 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=600&view=rev Author: agraef Date: 2008-08-24 09:57:38 +0000 (Sun, 24 Aug 2008) Log Message: ----------- do operations now implemented with $$. Modified Paths: -------------- pure/trunk/ChangeLog pure/trunk/lib/prelude.pure pure/trunk/test/prelude.log Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-08-24 02:19:25 UTC (rev 599) +++ pure/trunk/ChangeLog 2008-08-24 09:57:38 UTC (rev 600) @@ -2,6 +2,8 @@ * 0.5 release. + * lib/prelude.pure: do operations now implemented with $$. + * test/test020.pure, test/test021.pure: Cosmetic changes, added math.pure tests for checking exact/inexact/symbolic results. Modified: pure/trunk/lib/prelude.pure =================================================================== --- pure/trunk/lib/prelude.pure 2008-08-24 02:19:25 UTC (rev 599) +++ pure/trunk/lib/prelude.pure 2008-08-24 09:57:38 UTC (rev 600) @@ -227,7 +227,7 @@ any p (x:xs) = if p x then 1 else any p xs; do f [] = (); -do f (x:xs) = do f xs when _ = f x end; +do f (x:xs) = f x $$ do f xs; drop n::int [] = []; drop n::int (x:xs) @@ -403,11 +403,11 @@ accum us _ _ _ = reverse us; end; -dowith f (x:xs) (y:ys) = dowith f xs ys when _ = f x y end; +dowith f (x:xs) (y:ys) = f x y $$ dowith f xs ys; dowith f _ _ = () otherwise; dowith3 f (x:xs) (y:ys) (z:zs) - = dowith3 f xs ys zs when _ = f x y z end; + = f x y z $$ dowith3 f xs ys zs; dowith3 f _ _ _ = () otherwise; unzip [] = [],[]; Modified: pure/trunk/test/prelude.log =================================================================== --- pure/trunk/test/prelude.log 2008-08-24 02:19:25 UTC (rev 599) +++ pure/trunk/test/prelude.log 2008-08-24 09:57:38 UTC (rev 600) @@ -299,12 +299,7 @@ any p/*0:01*/ [] = 0; any p/*0:01*/ (x/*0:101*/:xs/*0:11*/) = if p/*0:01*/ x/*0:101*/ then 1 else any p/*0:01*/ xs/*0:11*/; do f/*0:01*/ [] = (); -do f/*0:01*/ (x/*0:101*/:xs/*0:11*/) = do f/*1:01*/ xs/*1:11*/ when _/*0:*/ = f/*0:01*/ x/*0:101*/ { - rule #0: _ = f x - state 0: #0 - <var> state 1 - state 1: #0 -} end; +do f/*0:01*/ (x/*0:101*/:xs/*0:11*/) = f/*0:01*/ x/*0:101*/$$do f/*0:01*/ xs/*0:11*/; drop n/*0:01*/::int [] = []; drop n/*0:01*/::int (x/*0:101*/:xs/*0:11*/) = drop (n/*0:01*/-1) xs/*0:11*/ if n/*0:01*/>0; drop n/*0:01*/::int (x/*0:101*/:xs/*0:11*/) = x/*0:101*/:xs/*0:11*/; @@ -1072,19 +1067,9 @@ <var> state 43 state 43: #0 #1 } end; -dowith f/*0:001*/ (x/*0:0101*/:xs/*0:011*/) (y/*0:101*/:ys/*0:11*/) = dowith f/*1:001*/ xs/*1:011*/ ys/*1:11*/ when _/*0:*/ = f/*0:001*/ x/*0:0101*/ y/*0:101*/ { - rule #0: _ = f x y - state 0: #0 - <var> state 1 - state 1: #0 -} end; +dowith f/*0:001*/ (x/*0:0101*/:xs/*0:011*/) (y/*0:101*/:ys/*0:11*/) = f/*0:001*/ x/*0:0101*/ y/*0:101*/$$dowith f/*0:001*/ xs/*0:011*/ ys/*0:11*/; dowith f/*0:001*/ _/*0:01*/ _/*0:1*/ = (); -dowith3 f/*0:0001*/ (x/*0:00101*/:xs/*0:0011*/) (y/*0:0101*/:ys/*0:011*/) (z/*0:101*/:zs/*0:11*/) = dowith3 f/*1:0001*/ xs/*1:0011*/ ys/*1:011*/ zs/*1:11*/ when _/*0:*/ = f/*0:0001*/ x/*0:00101*/ y/*0:0101*/ z/*0:101*/ { - rule #0: _ = f x y z - state 0: #0 - <var> state 1 - state 1: #0 -} end; +dowith3 f/*0:0001*/ (x/*0:00101*/:xs/*0:0011*/) (y/*0:0101*/:ys/*0:011*/) (z/*0:101*/:zs/*0:11*/) = f/*0:0001*/ x/*0:00101*/ y/*0:0101*/ z/*0:101*/$$dowith3 f/*0:0001*/ xs/*0:0011*/ ys/*0:011*/ zs/*0:11*/; dowith3 f/*0:0001*/ _/*0:001*/ _/*0:01*/ _/*0:1*/ = (); unzip [] = [],[]; unzip ((x/*0:10101*/,y/*0:1011*/):us/*0:11*/) = x/*1:10101*/:xs/*0:01*/,y/*1:1011*/:ys/*0:1*/ when xs/*0:01*/,ys/*0:1*/ = accum/*0*/ [] [] us/*0:11*/ { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-24 02:19:15
|
Revision: 599 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=599&view=rev Author: agraef Date: 2008-08-24 02:19:25 +0000 (Sun, 24 Aug 2008) Log Message: ----------- Add a note about math tests failing on Windows due to broken math routines in Microsoft's C library. Modified Paths: -------------- pure/trunk/INSTALL Modified: pure/trunk/INSTALL =================================================================== --- pure/trunk/INSTALL 2008-08-24 02:09:25 UTC (rev 598) +++ pure/trunk/INSTALL 2008-08-24 02:19:25 UTC (rev 599) @@ -104,7 +104,10 @@ $ make check If all is well, all tests should pass. If not, email the author or the Pure -mailing list for help. +mailing list for help. (Note that under MS Windows this step is expected to +fail on some math-related tests such as test020.pure which stress-test the +system's math routines, because some of these are broken in Microsoft's C +library.) STEP 6. The Pure interpreter should be ready to go now. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-24 02:09:15
|
Revision: 598 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=598&view=rev Author: agraef Date: 2008-08-24 02:09:25 +0000 (Sun, 24 Aug 2008) Log Message: ----------- Comment changes. Modified Paths: -------------- pure/trunk/test/test020.pure pure/trunk/test/test021.pure Modified: pure/trunk/test/test020.pure =================================================================== --- pure/trunk/test/test020.pure 2008-08-24 01:31:00 UTC (rev 597) +++ pure/trunk/test/test020.pure 2008-08-24 02:09:25 UTC (rev 598) @@ -1,5 +1,9 @@ // math.pure tests by Eddie Rucker +/* CAVEAT: This test may fail on some systems (most notably, Windows) which + lack a POSIX-conformant implementation of the mathematical functions in the + C library. */ + using math; // unary operations @@ -43,8 +47,10 @@ format (f,x,z) = str f+","+show x+","+show z; show x::double -= str x if infp x || nanp x; // fix Windoze quirks -= sprintf double_format 0.0 if x==0.0; // work around +/-0.0 issues += str x if infp x || nanp x; // Windoze compatibility +// Kludge: Some systems have -0.0, some don't, on some it's broken. Simply +// ignore the sign of floating point zeros for now. += sprintf double_format 0.0 if x==0.0; = sprintf double_format x otherwise; show (x+:y) = show x+"+:"+show y; Modified: pure/trunk/test/test021.pure =================================================================== --- pure/trunk/test/test021.pure 2008-08-24 01:31:00 UTC (rev 597) +++ pure/trunk/test/test021.pure 2008-08-24 02:09:25 UTC (rev 598) @@ -22,8 +22,10 @@ format (f,x,z) = str f+","+show x+","+show z; show x::double -= str x if infp x || nanp x; // fix Windoze quirks -= sprintf double_format 0.0 if x==0.0; // work around +/-0.0 issues += str x if infp x || nanp x; // Windoze compatibility +// Kludge: Some systems have -0.0, some don't, on some it's broken. Simply +// ignore the sign of floating point zeros for now. += sprintf double_format 0.0 if x==0.0; = sprintf double_format x otherwise; show (x+:y) = show x+"+:"+show y; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-24 01:30:51
|
Revision: 597 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=597&view=rev Author: agraef Date: 2008-08-24 01:31:00 +0000 (Sun, 24 Aug 2008) Log Message: ----------- Windows compatibility fixes. Modified Paths: -------------- pure/trunk/test/test020.log pure/trunk/test/test020.pure pure/trunk/test/test021.log pure/trunk/test/test021.pure Modified: pure/trunk/test/test020.log =================================================================== --- pure/trunk/test/test020.log 2008-08-24 00:11:34 UTC (rev 596) +++ pure/trunk/test/test020.log 2008-08-24 01:31:00 UTC (rev 597) @@ -45,6 +45,8 @@ check _/*0:01*/ z/*0:1*/ = z/*0:1*/; format (f/*0:101*/,x/*0:1101*/,y/*0:11101*/,z/*0:1111*/) = str f/*0:101*/+","+show x/*0:1101*/+","+show y/*0:11101*/+","+show z/*0:1111*/; format (f/*0:101*/,x/*0:1101*/,z/*0:111*/) = str f/*0:101*/+","+show x/*0:1101*/+","+show z/*0:111*/; +show x/*0:1*/::double = str x/*0:1*/ if infp x/*0:1*/||nanp x/*0:1*/; +show x/*0:1*/::double = sprintf double_format 0.0 if x/*0:1*/==0.0; show x/*0:1*/::double = sprintf double_format x/*0:1*/; show (x/*0:101*/+:y/*0:11*/) = show x/*0:101*/+"+:"+show y/*0:11*/; show (x/*0:101*/<:y/*0:11*/) = show x/*0:101*/+"<:"+show y/*0:11*/; @@ -244,41 +246,43 @@ state 15: #0 #1 } { - rule #0: show x::double = sprintf double_format x - rule #1: show (x+:y) = show x+"+:"+show y - rule #2: show (x<:y) = show x+"<:"+show y - rule #3: show x = str x - state 0: #0 #1 #2 #3 + rule #0: show x::double = str x if infp x||nanp x + rule #1: show x::double = sprintf double_format 0.0 if x==0.0 + rule #2: show x::double = sprintf double_format x + rule #3: show (x+:y) = show x+"+:"+show y + rule #4: show (x<:y) = show x+"<:"+show y + rule #5: show x = str x + state 0: #0 #1 #2 #3 #4 #5 <var> state 1 <var>::double state 2 <app> state 3 - state 1: #3 - state 2: #0 #3 - state 3: #1 #2 #3 + state 1: #5 + state 2: #0 #1 #2 #5 + state 3: #3 #4 #5 <var> state 4 <app> state 6 - state 4: #3 + state 4: #5 <var> state 5 - state 5: #3 - state 6: #1 #2 #3 + state 5: #5 + state 6: #3 #4 #5 <var> state 7 +: state 10 <: state 13 - state 7: #3 + state 7: #5 <var> state 8 - state 8: #3 + state 8: #5 <var> state 9 - state 9: #3 - state 10: #1 #3 + state 9: #5 + state 10: #3 #5 <var> state 11 - state 11: #1 #3 + state 11: #3 #5 <var> state 12 - state 12: #1 #3 - state 13: #2 #3 + state 12: #3 #5 + state 13: #4 #5 <var> state 14 - state 14: #2 #3 + state 14: #4 #5 <var> state 15 - state 15: #2 #3 + state 15: #4 #5 } { rule #0: tests = puts "*** UNARY ***"$$void (catmap (\f -> catmap (\x -> [test (f,x)]) x) f)$$puts "*** BINARY ***"$$void (catmap (\f -> catmap (\x -> [test (f,x)]) x2) f2) @@ -2329,7 +2333,7 @@ (*),-1,1,-1 (*),-1,-1,1 (*),-1,0,0 -(*),-1,0.00,-0.00 +(*),-1,0.00,0.00 (*),-1,1.20,-1.20 (*),-1,-1.20,1.20 (*),-1,1L%3L,(-1L)%3L @@ -2355,14 +2359,14 @@ (*),0,0,0 (*),0,0.00,0.00 (*),0,1.20,0.00 -(*),0,-1.20,-0.00 +(*),0,-1.20,0.00 (*),0,1L%3L,0L%1L (*),0,(-1L)%4L,0L%1L (*),0,1+:2,0+:0 (*),0,-1+:2,0+:0 (*),0,1+:-2,0+:0 -(*),0,-1.20+:4.30,-0.00+:0.00 -(*),0,1.20+:-4.30,0.00+:-0.00 +(*),0,-1.20+:4.30,0.00+:0.00 +(*),0,1.20+:-4.30,0.00+:0.00 (*),0,1L%2L+:1,0L%1L+:0 (*),0,1L%2L+:3L%4L,0L%1L+:0L%1L (*),0,3<:1,0<:1 @@ -2375,18 +2379,18 @@ (*),0,nan,nan (*),0,x,__failed__ (*),0.00,1,0.00 -(*),0.00,-1,-0.00 +(*),0.00,-1,0.00 (*),0.00,0,0.00 (*),0.00,0.00,0.00 (*),0.00,1.20,0.00 -(*),0.00,-1.20,-0.00 +(*),0.00,-1.20,0.00 (*),0.00,1L%3L,0.00 -(*),0.00,(-1L)%4L,-0.00 +(*),0.00,(-1L)%4L,0.00 (*),0.00,1+:2,0.00+:0.00 -(*),0.00,-1+:2,-0.00+:0.00 -(*),0.00,1+:-2,0.00+:-0.00 -(*),0.00,-1.20+:4.30,-0.00+:0.00 -(*),0.00,1.20+:-4.30,0.00+:-0.00 +(*),0.00,-1+:2,0.00+:0.00 +(*),0.00,1+:-2,0.00+:0.00 +(*),0.00,-1.20+:4.30,0.00+:0.00 +(*),0.00,1.20+:-4.30,0.00+:0.00 (*),0.00,1L%2L+:1,0.00+:0.00 (*),0.00,1L%2L+:3L%4L,0.00+:0.00 (*),0.00,3<:1,0.00<:1 @@ -2424,8 +2428,8 @@ (*),1.20,x,__failed__ (*),-1.20,1,-1.20 (*),-1.20,-1,1.20 -(*),-1.20,0,-0.00 -(*),-1.20,0.00,-0.00 +(*),-1.20,0,0.00 +(*),-1.20,0.00,0.00 (*),-1.20,1.20,-1.44 (*),-1.20,-1.20,1.44 (*),-1.20,1L%3L,-0.400 @@ -2473,7 +2477,7 @@ (*),(-1L)%4L,1,(-1L)%4L (*),(-1L)%4L,-1,1L%4L (*),(-1L)%4L,0,0L%1L -(*),(-1L)%4L,0.00,-0.00 +(*),(-1L)%4L,0.00,0.00 (*),(-1L)%4L,1.20,-0.300 (*),(-1L)%4L,-1.20,0.300 (*),(-1L)%4L,1L%3L,(-1L)%12L @@ -2521,7 +2525,7 @@ (*),-1+:2,1,-1+:2 (*),-1+:2,-1,1+:-2 (*),-1+:2,0,0+:0 -(*),-1+:2,0.00,-0.00+:0.00 +(*),-1+:2,0.00,0.00+:0.00 (*),-1+:2,1.20,-1.20+:2.40 (*),-1+:2,-1.20,1.20+:-2.40 (*),-1+:2,1L%3L,(-1L)%3L+:2L%3L @@ -2545,7 +2549,7 @@ (*),1+:-2,1,1+:-2 (*),1+:-2,-1,-1+:2 (*),1+:-2,0,0+:0 -(*),1+:-2,0.00,0.00+:-0.00 +(*),1+:-2,0.00,0.00+:0.00 (*),1+:-2,1.20,1.20+:-2.40 (*),1+:-2,-1.20,-1.20+:2.40 (*),1+:-2,1L%3L,1L%3L+:(-2L)%3L @@ -2568,8 +2572,8 @@ (*),1+:-2,x,__failed__ (*),-1.20+:4.30,1,-1.20+:4.30 (*),-1.20+:4.30,-1,1.20+:-4.30 -(*),-1.20+:4.30,0,-0.00+:0.00 -(*),-1.20+:4.30,0.00,-0.00+:0.00 +(*),-1.20+:4.30,0,0.00+:0.00 +(*),-1.20+:4.30,0.00,0.00+:0.00 (*),-1.20+:4.30,1.20,-1.44+:5.16 (*),-1.20+:4.30,-1.20,1.44+:-5.16 (*),-1.20+:4.30,1L%3L,-0.400+:1.43 @@ -2592,8 +2596,8 @@ (*),-1.20+:4.30,x,__failed__ (*),1.20+:-4.30,1,1.20+:-4.30 (*),1.20+:-4.30,-1,-1.20+:4.30 -(*),1.20+:-4.30,0,0.00+:-0.00 -(*),1.20+:-4.30,0.00,0.00+:-0.00 +(*),1.20+:-4.30,0,0.00+:0.00 +(*),1.20+:-4.30,0.00,0.00+:0.00 (*),1.20+:-4.30,1.20,1.44+:-5.16 (*),1.20+:-4.30,-1.20,-1.44+:5.16 (*),1.20+:-4.30,1L%3L,0.400+:-1.43 @@ -2899,7 +2903,7 @@ (/),1,3.10<:2.50,0.323<:-2.50 (/),1,2L%3L<:2,1.50<:-2 (/),1,1L%2L<:3L%4L,2.00<:(-3L)%4L -(/),1,-inf,-0.00 +(/),1,-inf,0.00 (/),1,nan,nan (/),1,x,__failed__ (/),-1,1,-1.00 @@ -2927,17 +2931,17 @@ (/),-1,nan,nan (/),-1,x,__failed__ (/),0,1,0.00 -(/),0,-1,-0.00 +(/),0,-1,0.00 (/),0,0,nan (/),0,0.00,nan (/),0,1.20,0.00 -(/),0,-1.20,-0.00 +(/),0,-1.20,0.00 (/),0,1L%3L,0.00 -(/),0,(-1L)%4L,-0.00 +(/),0,(-1L)%4L,0.00 (/),0,1+:2,0.00+:0.00 (/),0,-1+:2,0.00+:0.00 (/),0,1+:-2,0.00+:0.00 -(/),0,-1.20+:4.30,-0.00+:0.00 +(/),0,-1.20+:4.30,0.00+:0.00 (/),0,1.20+:-4.30,0.00+:0.00 (/),0,1L%2L+:1,0.00+:0.00 (/),0,1L%2L+:3L%4L,0.00+:0.00 @@ -2947,21 +2951,21 @@ (/),0,3.10<:2.50,0.00<:-2.50 (/),0,2L%3L<:2,0.00<:-2 (/),0,1L%2L<:3L%4L,0.00<:(-3L)%4L -(/),0,-inf,-0.00 +(/),0,-inf,0.00 (/),0,nan,nan (/),0,x,__failed__ (/),0.00,1,0.00 -(/),0.00,-1,-0.00 +(/),0.00,-1,0.00 (/),0.00,0,nan (/),0.00,0.00,nan (/),0.00,1.20,0.00 -(/),0.00,-1.20,-0.00 +(/),0.00,-1.20,0.00 (/),0.00,1L%3L,0.00 -(/),0.00,(-1L)%4L,-0.00 +(/),0.00,(-1L)%4L,0.00 (/),0.00,1+:2,0.00+:0.00 -(/),0.00,-1+:2,-0.00+:0.00 +(/),0.00,-1+:2,0.00+:0.00 (/),0.00,1+:-2,0.00+:0.00 -(/),0.00,-1.20+:4.30,-0.00+:0.00 +(/),0.00,-1.20+:4.30,0.00+:0.00 (/),0.00,1.20+:-4.30,0.00+:0.00 (/),0.00,1L%2L+:1,0.00+:0.00 (/),0.00,1L%2L+:3L%4L,0.00+:0.00 @@ -2971,7 +2975,7 @@ (/),0.00,3.10<:2.50,0.00<:-2.50 (/),0.00,2L%3L<:2,0.00<:-2 (/),0.00,1L%2L<:3L%4L,0.00<:(-3L)%4L -(/),0.00,-inf,-0.00 +(/),0.00,-inf,0.00 (/),0.00,nan,nan (/),0.00,x,__failed__ (/),1.20,1,1.20 @@ -2995,7 +2999,7 @@ (/),1.20,3.10<:2.50,0.387<:-2.50 (/),1.20,2L%3L<:2,1.80<:-2 (/),1.20,1L%2L<:3L%4L,2.40<:(-3L)%4L -(/),1.20,-inf,-0.00 +(/),1.20,-inf,0.00 (/),1.20,nan,nan (/),1.20,x,__failed__ (/),-1.20,1,-1.20 @@ -3043,7 +3047,7 @@ (/),1L%3L,3.10<:2.50,0.108<:-2.50 (/),1L%3L,2L%3L<:2,0.500<:-2 (/),1L%3L,1L%2L<:3L%4L,0.667<:(-3L)%4L -(/),1L%3L,-inf,-0.00 +(/),1L%3L,-inf,0.00 (/),1L%3L,nan,nan (/),1L%3L,x,__failed__ (/),(-1L)%4L,1,-0.250 @@ -3091,7 +3095,7 @@ (/),1+:2,3.10<:2.50,0.128+:-0.710 (/),1+:2,2L%3L<:2,2.10+:-2.61 (/),1+:2,1L%2L<:3L%4L,4.19+:1.56 -(/),1+:2,-inf,-0.00+:-0.00 +(/),1+:2,-inf,0.00+:0.00 (/),1+:2,nan,nan+:nan (/),1+:2,x,__failed__ (/),-1+:2,1,-1.00+:2.00 @@ -3115,7 +3119,7 @@ (/),-1+:2,3.10<:2.50,0.645+:-0.324 (/),-1+:2,2L%3L<:2,3.35+:0.116 (/),-1+:2,1L%2L<:3L%4L,1.26+:4.29 -(/),-1+:2,-inf,0.00+:-0.00 +(/),-1+:2,-inf,0.00+:0.00 (/),-1+:2,nan,nan+:nan (/),-1+:2,x,__failed__ (/),1+:-2,1,1.00+:-2.00 @@ -3139,7 +3143,7 @@ (/),1+:-2,3.10<:2.50,-0.645+:0.324 (/),1+:-2,2L%3L<:2,-3.35+:-0.116 (/),1+:-2,1L%2L<:3L%4L,-1.26+:-4.29 -(/),1+:-2,-inf,-0.00+:0.00 +(/),1+:-2,-inf,0.00+:0.00 (/),1+:-2,nan,nan+:nan (/),1+:-2,x,__failed__ (/),-1.20+:4.30,1,-1.20+:4.30 @@ -3163,7 +3167,7 @@ (/),-1.20+:4.30,3.10<:2.50,1.14+:-0.880 (/),-1.20+:4.30,2L%3L<:2,6.61+:-1.05 (/),-1.20+:4.30,1L%2L<:3L%4L,4.11+:7.93 -(/),-1.20+:4.30,-inf,0.00+:-0.00 +(/),-1.20+:4.30,-inf,0.00+:0.00 (/),-1.20+:4.30,nan,nan+:nan (/),-1.20+:4.30,x,__failed__ (/),1.20+:-4.30,1,1.20+:-4.30 @@ -3187,7 +3191,7 @@ (/),1.20+:-4.30,3.10<:2.50,-1.14+:0.880 (/),1.20+:-4.30,2L%3L<:2,-6.61+:1.05 (/),1.20+:-4.30,1L%2L<:3L%4L,-4.11+:-7.93 -(/),1.20+:-4.30,-inf,-0.00+:0.00 +(/),1.20+:-4.30,-inf,0.00+:0.00 (/),1.20+:-4.30,nan,nan+:nan (/),1.20+:-4.30,x,__failed__ (/),1L%2L+:1,1,0.500+:1.00 @@ -3211,7 +3215,7 @@ (/),1L%2L+:1,3.10<:2.50,0.0638+:-0.355 (/),1L%2L+:1,2L%3L<:2,1.05+:-1.31 (/),1L%2L+:1,1L%2L<:3L%4L,2.09+:0.782 -(/),1L%2L+:1,-inf,-0.00+:-0.00 +(/),1L%2L+:1,-inf,0.00+:0.00 (/),1L%2L+:1,nan,nan+:nan (/),1L%2L+:1,x,__failed__ (/),1L%2L+:3L%4L,1,0.500+:0.750 @@ -3235,7 +3239,7 @@ (/),1L%2L+:3L%4L,3.10<:2.50,0.0156+:-0.290 (/),1L%2L+:3L%4L,2L%3L<:2,0.711+:-1.15 (/),1L%2L+:3L%4L,1L%2L<:3L%4L,1.75+:0.416 -(/),1L%2L+:3L%4L,-inf,-0.00+:-0.00 +(/),1L%2L+:3L%4L,-inf,0.00+:0.00 (/),1L%2L+:3L%4L,nan,nan+:nan (/),1L%2L+:3L%4L,x,__failed__ (/),3<:1,1,3.00<:1 @@ -3259,7 +3263,7 @@ (/),3<:1,3.10<:2.50,0.968<:-1.50 (/),3<:1,2L%3L<:2,4.50<:-1 (/),3<:1,1L%2L<:3L%4L,6.00<:1L%4L -(/),3<:1,-inf,-0.00<:1 +(/),3<:1,-inf,0.00<:1 (/),3<:1,nan,nan<:1 (/),3<:1,x,__failed__ (/),3<:-2.14,1,3.00<:-2.14 @@ -3283,7 +3287,7 @@ (/),3<:-2.14,3.10<:2.50,0.968<:1.64 (/),3<:-2.14,2L%3L<:2,4.50<:2.14 (/),3<:-2.14,1L%2L<:3L%4L,6.00<:-2.89 -(/),3<:-2.14,-inf,-0.00<:-2.14 +(/),3<:-2.14,-inf,0.00<:-2.14 (/),3<:-2.14,nan,nan<:-2.14 (/),3<:-2.14,x,__failed__ (/),3.00<:-3,1,3.00<:-3 @@ -3307,7 +3311,7 @@ (/),3.00<:-3,3.10<:2.50,0.968<:0.783 (/),3.00<:-3,2L%3L<:2,4.50<:1.28 (/),3.00<:-3,1L%2L<:3L%4L,6.00<:2.53 -(/),3.00<:-3,-inf,-0.00<:-3 +(/),3.00<:-3,-inf,0.00<:-3 (/),3.00<:-3,nan,nan<:-3 (/),3.00<:-3,x,__failed__ (/),3.10<:2.50,1,3.10<:2.50 @@ -3331,7 +3335,7 @@ (/),3.10<:2.50,3.10<:2.50,1.00<:0.00 (/),3.10<:2.50,2L%3L<:2,4.65<:0.500 (/),3.10<:2.50,1L%2L<:3L%4L,6.20<:1.75 -(/),3.10<:2.50,-inf,-0.00<:2.50 +(/),3.10<:2.50,-inf,0.00<:2.50 (/),3.10<:2.50,nan,nan<:2.50 (/),3.10<:2.50,x,__failed__ (/),2L%3L<:2,1,0.667<:2 @@ -3355,7 +3359,7 @@ (/),2L%3L<:2,3.10<:2.50,0.215<:-0.500 (/),2L%3L<:2,2L%3L<:2,1.00<:0 (/),2L%3L<:2,1L%2L<:3L%4L,1.33<:5L%4L -(/),2L%3L<:2,-inf,-0.00<:2 +(/),2L%3L<:2,-inf,0.00<:2 (/),2L%3L<:2,nan,nan<:2 (/),2L%3L<:2,x,__failed__ (/),1L%2L<:3L%4L,1,0.500<:3L%4L @@ -3379,7 +3383,7 @@ (/),1L%2L<:3L%4L,3.10<:2.50,0.161<:-1.75 (/),1L%2L<:3L%4L,2L%3L<:2,0.750<:(-5L)%4L (/),1L%2L<:3L%4L,1L%2L<:3L%4L,1.00<:0L%1L -(/),1L%2L<:3L%4L,-inf,-0.00<:3L%4L +(/),1L%2L<:3L%4L,-inf,0.00<:3L%4L (/),1L%2L<:3L%4L,nan,nan<:3L%4L (/),1L%2L<:3L%4L,x,__failed__ (/),-inf,1,-inf @@ -3470,8 +3474,8 @@ (^),1,1L%2L+:1,1.00+:0.00 (^),1,1L%2L+:3L%4L,1.00+:0.00 (^),1,3<:1,1.00<:0.00 -(^),1,3<:-2.14,1.00<:-0.00 -(^),1,3.00<:-3,1.00<:-0.00 +(^),1,3<:-2.14,1.00<:0.00 +(^),1,3.00<:-3,1.00<:0.00 (^),1,3.10<:2.50,1.00<:0.00 (^),1,2L%3L<:2,1.00<:0.00 (^),1,1L%2L<:3L%4L,1.00<:0.00 @@ -3696,8 +3700,8 @@ (^),-1+:2,x,__failed__ (^),1+:-2,1,1.00+:-2.00 (^),1+:-2,-1,0.200+:0.400 -(^),1+:-2,0,1.00+:-0.00 -(^),1+:-2,0.00,1.00+:-0.00 +(^),1+:-2,0,1.00+:0.00 +(^),1+:-2,0.00,1.00+:0.00 (^),1+:-2,1.20,0.630+:-2.55 (^),1+:-2,-1.20,0.0913+:0.370 (^),1+:-2,1L%3L,1.22+:-0.472 @@ -3744,8 +3748,8 @@ (^),-1.20+:4.30,x,__failed__ (^),1.20+:-4.30,1,1.20+:-4.30 (^),1.20+:-4.30,-1,0.0602+:0.216 -(^),1.20+:-4.30,0,1.00+:-0.00 -(^),1.20+:-4.30,0.00,1.00+:-0.00 +(^),1.20+:-4.30,0,1.00+:0.00 +(^),1.20+:-4.30,0.00,1.00+:0.00 (^),1.20+:-4.30,1.20,0.0748+:-6.02 (^),1.20+:-4.30,-1.20,0.00206+:0.166 (^),1.20+:-4.30,1L%3L,1.49+:-0.691 @@ -3840,8 +3844,8 @@ (^),3<:1,x,__failed__ (^),3<:-2.14,1,3.00<:-2.14 (^),3<:-2.14,-1,0.333<:2.14 -(^),3<:-2.14,0,1.00<:-0.00 -(^),3<:-2.14,0.00,1.00<:-0.00 +(^),3<:-2.14,0,1.00<:0.00 +(^),3<:-2.14,0.00,1.00<:0.00 (^),3<:-2.14,1.20,3.74<:-2.57 (^),3<:-2.14,-1.20,0.268<:2.57 (^),3<:-2.14,1L%3L,1.44<:-0.714 @@ -3864,8 +3868,8 @@ (^),3<:-2.14,x,__failed__ (^),3.00<:-3,1,3.00<:-3.00 (^),3.00<:-3,-1,0.333<:3.00 -(^),3.00<:-3,0,1.00<:-0.00 -(^),3.00<:-3,0.00,1.00<:-0.00 +(^),3.00<:-3,0,1.00<:0.00 +(^),3.00<:-3,0.00,1.00<:0.00 (^),3.00<:-3,1.20,3.74<:2.68 (^),3.00<:-3,-1.20,0.268<:-2.68 (^),3.00<:-3,1L%3L,1.44<:-1.00 @@ -3959,7 +3963,7 @@ (^),1L%2L<:3L%4L,nan,nan<:nan (^),1L%2L<:3L%4L,x,__failed__ (^),-inf,1,-inf -(^),-inf,-1,-0.00 +(^),-inf,-1,0.00 (^),-inf,0,1.00 (^),-inf,0.00,1.00 (^),-inf,1.20,inf Modified: pure/trunk/test/test020.pure =================================================================== --- pure/trunk/test/test020.pure 2008-08-24 00:11:34 UTC (rev 596) +++ pure/trunk/test/test020.pure 2008-08-24 01:31:00 UTC (rev 597) @@ -42,7 +42,11 @@ format (f,x,y,z) = str f+","+show x+","+show y+","+show z; format (f,x,z) = str f+","+show x+","+show z; -show x::double = sprintf double_format x; +show x::double += str x if infp x || nanp x; // fix Windoze quirks += sprintf double_format 0.0 if x==0.0; // work around +/-0.0 issues += sprintf double_format x otherwise; + show (x+:y) = show x+"+:"+show y; show (x<:y) = show x+"<:"+show y; show x = str x otherwise; Modified: pure/trunk/test/test021.log =================================================================== --- pure/trunk/test/test021.log 2008-08-24 00:11:34 UTC (rev 596) +++ pure/trunk/test/test021.log 2008-08-24 01:31:00 UTC (rev 597) @@ -7,6 +7,8 @@ check _/*0:01*/ z/*0:1*/ = z/*0:1*/; format (f/*0:101*/,x/*0:1101*/,y/*0:11101*/,z/*0:1111*/) = str f/*0:101*/+","+show x/*0:1101*/+","+show y/*0:11101*/+","+show z/*0:1111*/; format (f/*0:101*/,x/*0:1101*/,z/*0:111*/) = str f/*0:101*/+","+show x/*0:1101*/+","+show z/*0:111*/; +show x/*0:1*/::double = str x/*0:1*/ if infp x/*0:1*/||nanp x/*0:1*/; +show x/*0:1*/::double = sprintf double_format 0.0 if x/*0:1*/==0.0; show x/*0:1*/::double = sprintf double_format x/*0:1*/; show (x/*0:101*/+:y/*0:11*/) = show x/*0:101*/+"+:"+show y/*0:11*/; show (x/*0:101*/<:y/*0:11*/) = show x/*0:101*/+"<:"+show y/*0:11*/; @@ -226,41 +228,43 @@ state 15: #0 #1 } { - rule #0: show x::double = sprintf double_format x - rule #1: show (x+:y) = show x+"+:"+show y - rule #2: show (x<:y) = show x+"<:"+show y - rule #3: show x = str x - state 0: #0 #1 #2 #3 + rule #0: show x::double = str x if infp x||nanp x + rule #1: show x::double = sprintf double_format 0.0 if x==0.0 + rule #2: show x::double = sprintf double_format x + rule #3: show (x+:y) = show x+"+:"+show y + rule #4: show (x<:y) = show x+"<:"+show y + rule #5: show x = str x + state 0: #0 #1 #2 #3 #4 #5 <var> state 1 <var>::double state 2 <app> state 3 - state 1: #3 - state 2: #0 #3 - state 3: #1 #2 #3 + state 1: #5 + state 2: #0 #1 #2 #5 + state 3: #3 #4 #5 <var> state 4 <app> state 6 - state 4: #3 + state 4: #5 <var> state 5 - state 5: #3 - state 6: #1 #2 #3 + state 5: #5 + state 6: #3 #4 #5 <var> state 7 +: state 10 <: state 13 - state 7: #3 + state 7: #5 <var> state 8 - state 8: #3 + state 8: #5 <var> state 9 - state 9: #3 - state 10: #1 #3 + state 9: #5 + state 10: #3 #5 <var> state 11 - state 11: #1 #3 + state 11: #3 #5 <var> state 12 - state 12: #1 #3 - state 13: #2 #3 + state 12: #3 #5 + state 13: #4 #5 <var> state 14 - state 14: #2 #3 + state 14: #4 #5 <var> state 15 - state 15: #2 #3 + state 15: #4 #5 } { rule #0: tests = puts "*** EXACT/INEXACT ***"$$do test (catmap (\op -> catmap (\a -> [(op,2,a)]) [2+:3,2<:3,2%3]) [(+),(-),(*),(%),(/),(^)])$$do test (catmap (\op -> catmap (\a -> [(op,a,2)]) [2+:3,2<:3,2%3]) [(+),(-),(*),(%),(/),(^)])$$puts "*** SYMBOLIC ***"$$do test (catmap (\op -> catmap (\a -> [(op,x,a)]) [2+:3,2<:3,2%3]) [(+),(-),(*),(%),(/),(^)])$$do test (catmap (\op -> catmap (\a -> [(op,a,x)]) [2+:3,2<:3,2%3]) [(+),(-),(*),(%),(/),(^)]) Modified: pure/trunk/test/test021.pure =================================================================== --- pure/trunk/test/test021.pure 2008-08-24 00:11:34 UTC (rev 596) +++ pure/trunk/test/test021.pure 2008-08-24 01:31:00 UTC (rev 597) @@ -21,7 +21,11 @@ format (f,x,y,z) = str f+","+show x+","+show y+","+show z; format (f,x,z) = str f+","+show x+","+show z; -show x::double = sprintf double_format x; +show x::double += str x if infp x || nanp x; // fix Windoze quirks += sprintf double_format 0.0 if x==0.0; // work around +/-0.0 issues += sprintf double_format x otherwise; + show (x+:y) = show x+"+:"+show y; show (x<:y) = show x+"<:"+show y; show x = str x otherwise; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-24 00:11:24
|
Revision: 596 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=596&view=rev Author: agraef Date: 2008-08-24 00:11:34 +0000 (Sun, 24 Aug 2008) Log Message: ----------- Cosmetic changes. Modified Paths: -------------- pure/trunk/test/test020.log pure/trunk/test/test020.pure pure/trunk/test/test021.log pure/trunk/test/test021.pure Modified: pure/trunk/test/test020.log =================================================================== --- pure/trunk/test/test020.log 2008-08-23 23:56:43 UTC (rev 595) +++ pure/trunk/test/test020.log 2008-08-24 00:11:34 UTC (rev 596) @@ -49,6 +49,27 @@ show (x/*0:101*/+:y/*0:11*/) = show x/*0:101*/+"+:"+show y/*0:11*/; show (x/*0:101*/<:y/*0:11*/) = show x/*0:101*/+"<:"+show y/*0:11*/; show x/*0:1*/ = str x/*0:1*/; +tests = puts "*** UNARY ***"$$void (catmap (\f/*0:*/ -> catmap (\x/*0:*/ -> [test (f/*1:*/,x/*0:*/)] { + rule #0: x = [test (f,x)] + state 0: #0 + <var> state 1 + state 1: #0 +}) x { + rule #0: f = catmap (\x -> [test (f,x)]) x + state 0: #0 + <var> state 1 + state 1: #0 +}) f)$$puts "*** BINARY ***"$$void (catmap (\f/*0:*/ -> catmap (\x/*0:*/ -> [test (f/*1:*/,x/*0:*/)] { + rule #0: x = [test (f,x)] + state 0: #0 + <var> state 1 + state 1: #0 +}) x2 { + rule #0: f = catmap (\x -> [test (f,x)]) x2 + state 0: #0 + <var> state 1 + state 1: #0 +}) f2); { rule #0: check _ z = z if numberp z rule #1: check (f,x,y) (g@_ u v) = __failed__ if f===g&&x===u&&y===v @@ -259,6 +280,10 @@ <var> state 15 state 15: #2 #3 } +{ + rule #0: tests = puts "*** UNARY ***"$$void (catmap (\f -> catmap (\x -> [test (f,x)]) x) f)$$puts "*** BINARY ***"$$void (catmap (\f -> catmap (\x -> [test (f,x)]) x2) f2) + state 0: #0 +} *** UNARY *** sqrt,1,1.00 sqrt,-1,nan @@ -5157,25 +5182,5 @@ pow,x,-inf,__failed__ pow,x,nan,__failed__ pow,x,x,__failed__ -puts "*** UNARY ***"$$void (catmap (\f/*0:*/ -> catmap (\x/*0:*/ -> [test (f/*1:*/,x/*0:*/)] { - rule #0: x = [test (f,x)] - state 0: #0 - <var> state 1 - state 1: #0 -}) x { - rule #0: f = catmap (\x -> [test (f,x)]) x - state 0: #0 - <var> state 1 - state 1: #0 -}) f)$$puts "*** BINARY ***"$$void (catmap (\f/*0:*/ -> catmap (\x/*0:*/ -> [test (f/*1:*/,x/*0:*/)] { - rule #0: x = [test (f,x)] - state 0: #0 - <var> state 1 - state 1: #0 -}) x2 { - rule #0: f = catmap (\x -> [test (f,x)]) x2 - state 0: #0 - <var> state 1 - state 1: #0 -}) f2); +tests; () Modified: pure/trunk/test/test020.pure =================================================================== --- pure/trunk/test/test020.pure 2008-08-23 23:56:43 UTC (rev 595) +++ pure/trunk/test/test020.pure 2008-08-24 00:11:34 UTC (rev 596) @@ -47,5 +47,8 @@ show (x<:y) = show x+"<:"+show y; show x = str x otherwise; +tests = puts "*** UNARY ***" $$ void [test (f,x); f=f; x=x] $$ puts "*** BINARY ***" $$ void [test (f,x); f=f2; x=x2]; + +tests; Modified: pure/trunk/test/test021.log =================================================================== --- pure/trunk/test/test021.log 2008-08-23 23:56:43 UTC (rev 595) +++ pure/trunk/test/test021.log 2008-08-24 00:11:34 UTC (rev 596) @@ -11,6 +11,47 @@ show (x/*0:101*/+:y/*0:11*/) = show x/*0:101*/+"+:"+show y/*0:11*/; show (x/*0:101*/<:y/*0:11*/) = show x/*0:101*/+"<:"+show y/*0:11*/; show x/*0:1*/ = str x/*0:1*/; +tests = puts "*** EXACT/INEXACT ***"$$do test (catmap (\op/*0:*/ -> catmap (\a/*0:*/ -> [(op/*1:*/,2,a/*0:*/)] { + rule #0: a = [(op,2,a)] + state 0: #0 + <var> state 1 + state 1: #0 +}) [2+:3,2<:3,2%3] { + rule #0: op = catmap (\a -> [(op,2,a)]) [2+:3,2<:3,2%3] + state 0: #0 + <var> state 1 + state 1: #0 +}) [(+),(-),(*),(%),(/),(^)])$$do test (catmap (\op/*0:*/ -> catmap (\a/*0:*/ -> [(op/*1:*/,a/*0:*/,2)] { + rule #0: a = [(op,a,2)] + state 0: #0 + <var> state 1 + state 1: #0 +}) [2+:3,2<:3,2%3] { + rule #0: op = catmap (\a -> [(op,a,2)]) [2+:3,2<:3,2%3] + state 0: #0 + <var> state 1 + state 1: #0 +}) [(+),(-),(*),(%),(/),(^)])$$puts "*** SYMBOLIC ***"$$do test (catmap (\op/*0:*/ -> catmap (\a/*0:*/ -> [(op/*1:*/,x,a/*0:*/)] { + rule #0: a = [(op,x,a)] + state 0: #0 + <var> state 1 + state 1: #0 +}) [2+:3,2<:3,2%3] { + rule #0: op = catmap (\a -> [(op,x,a)]) [2+:3,2<:3,2%3] + state 0: #0 + <var> state 1 + state 1: #0 +}) [(+),(-),(*),(%),(/),(^)])$$do test (catmap (\op/*0:*/ -> catmap (\a/*0:*/ -> [(op/*1:*/,a/*0:*/,x)] { + rule #0: a = [(op,a,x)] + state 0: #0 + <var> state 1 + state 1: #0 +}) [2+:3,2<:3,2%3] { + rule #0: op = catmap (\a -> [(op,a,x)]) [2+:3,2<:3,2%3] + state 0: #0 + <var> state 1 + state 1: #0 +}) [(+),(-),(*),(%),(/),(^)]); { rule #0: check _ z = z if numberp z rule #1: check (f,x,y) (g@_ u v) = __failed__ if f===g&&x===u&&y===v @@ -221,6 +262,10 @@ <var> state 15 state 15: #2 #3 } +{ + rule #0: tests = puts "*** EXACT/INEXACT ***"$$do test (catmap (\op -> catmap (\a -> [(op,2,a)]) [2+:3,2<:3,2%3]) [(+),(-),(*),(%),(/),(^)])$$do test (catmap (\op -> catmap (\a -> [(op,a,2)]) [2+:3,2<:3,2%3]) [(+),(-),(*),(%),(/),(^)])$$puts "*** SYMBOLIC ***"$$do test (catmap (\op -> catmap (\a -> [(op,x,a)]) [2+:3,2<:3,2%3]) [(+),(-),(*),(%),(/),(^)])$$do test (catmap (\op -> catmap (\a -> [(op,a,x)]) [2+:3,2<:3,2%3]) [(+),(-),(*),(%),(/),(^)]) + state 0: #0 +} *** EXACT/INEXACT *** (+),2,2+:3,4+:3 (+),2,2<:3,0.0200+:0.282 @@ -295,45 +340,5 @@ (^),2+:3,x,__failed__ (^),2<:3,x,__failed__ (^),2L%3L,x,__failed__ -puts "*** EXACT/INEXACT ***"$$do test (catmap (\op/*0:*/ -> catmap (\a/*0:*/ -> [(op/*1:*/,2,a/*0:*/)] { - rule #0: a = [(op,2,a)] - state 0: #0 - <var> state 1 - state 1: #0 -}) [2+:3,2<:3,2%3] { - rule #0: op = catmap (\a -> [(op,2,a)]) [2+:3,2<:3,2%3] - state 0: #0 - <var> state 1 - state 1: #0 -}) [(+),(-),(*),(%),(/),(^)])$$do test (catmap (\op/*0:*/ -> catmap (\a/*0:*/ -> [(op/*1:*/,a/*0:*/,2)] { - rule #0: a = [(op,a,2)] - state 0: #0 - <var> state 1 - state 1: #0 -}) [2+:3,2<:3,2%3] { - rule #0: op = catmap (\a -> [(op,a,2)]) [2+:3,2<:3,2%3] - state 0: #0 - <var> state 1 - state 1: #0 -}) [(+),(-),(*),(%),(/),(^)])$$puts "*** SYMBOLIC ***"$$do test (catmap (\op/*0:*/ -> catmap (\a/*0:*/ -> [(op/*1:*/,x,a/*0:*/)] { - rule #0: a = [(op,x,a)] - state 0: #0 - <var> state 1 - state 1: #0 -}) [2+:3,2<:3,2%3] { - rule #0: op = catmap (\a -> [(op,x,a)]) [2+:3,2<:3,2%3] - state 0: #0 - <var> state 1 - state 1: #0 -}) [(+),(-),(*),(%),(/),(^)])$$do test (catmap (\op/*0:*/ -> catmap (\a/*0:*/ -> [(op/*1:*/,a/*0:*/,x)] { - rule #0: a = [(op,a,x)] - state 0: #0 - <var> state 1 - state 1: #0 -}) [2+:3,2<:3,2%3] { - rule #0: op = catmap (\a -> [(op,a,x)]) [2+:3,2<:3,2%3] - state 0: #0 - <var> state 1 - state 1: #0 -}) [(+),(-),(*),(%),(/),(^)]); +tests; () Modified: pure/trunk/test/test021.pure =================================================================== --- pure/trunk/test/test021.pure 2008-08-23 23:56:43 UTC (rev 595) +++ pure/trunk/test/test021.pure 2008-08-24 00:11:34 UTC (rev 596) @@ -26,6 +26,7 @@ show (x<:y) = show x+"<:"+show y; show x = str x otherwise; +tests = puts "*** EXACT/INEXACT ***" $$ // These should all return exact results, except +/- with polar operands, as // well as / and ^ which always return inexact results. @@ -35,3 +36,5 @@ // If everything is all right here, these should all print __failed__. do test [op,x,a;op=[(+),(-),(*),(%),(/),(^)];a=[2+:3,2<:3,2%3]] $$ do test [op,a,x;op=[(+),(-),(*),(%),(/),(^)];a=[2+:3,2<:3,2%3]]; + +tests; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |