pure-lang-svn Mailing List for Pure (Page 14)
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-20 06:43:29
|
Revision: 545 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=545&view=rev Author: agraef Date: 2008-08-20 06:43:39 +0000 (Wed, 20 Aug 2008) Log Message: ----------- Windows compatibility fixes. Modified Paths: -------------- pure/trunk/interpreter.cc pure/trunk/pure.cc pure/trunk/runtime.cc Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-08-20 01:14:23 UTC (rev 544) +++ pure/trunk/interpreter.cc 2008-08-20 06:43:39 UTC (rev 545) @@ -431,6 +431,29 @@ } #endif +static string unixize(const string& s) +{ + string t = s; +#ifdef _WIN32 + for (size_t i = 0, n = t.size(); i<n; i++) + if (t[i] == '\\') + t[i] = '/'; +#endif + return t; +} + +static bool relname(const string& s) +{ + if (s.empty()) return true; +#ifdef _WIN32 + size_t pos = fname.find('/'); + return pos == string::npos || pos == 0 || + pos == 2 && s[1] == ':'; +#else + return s[0]!='/'; +#endif +} + #define BUFSIZE 1024 static string searchdir(const string& srcdir, const string& libdir, @@ -444,11 +467,11 @@ perror("getcwd"); return script; } - string workdir = cwd; + string workdir = unixize(cwd); if (!workdir.empty() && workdir[workdir.size()-1] != '/') workdir += "/"; string fname; - if (script[0] != '/') { + if (relname(script)) { // resolve relative pathname if (!search) { fname = workdir+script; @@ -472,7 +495,7 @@ } else fname = script; found: - if (fname[0] != '/') fname = workdir+fname; + if (relname(fname)) fname = workdir+fname; char buf[BUFSIZE]; #ifndef _WIN32 if (chklink(fname)) { @@ -494,7 +517,7 @@ // canonicalize the pathname string dir = dirname(fname), name = basename(fname); if (chdir(dir.c_str())==0 && getcwd(buf, BUFSIZE)) { - string dir = buf; + string dir = unixize(buf); if (!dir.empty() && dir[dir.size()-1] != '/') dir += "/"; fname = dir+name; @@ -519,11 +542,11 @@ perror("getcwd"); return lib; } - string workdir = cwd; + string workdir = unixize(cwd); if (!workdir.empty() && workdir[workdir.size()-1] != '/') workdir += "/"; string fname; - if (lib[0] != '/') { + if (relname(lib)) { // resolve relative pathname if (!search) { fname = workdir+lib; @@ -560,8 +583,9 @@ #define DLLEXT ".so" #endif -pure_expr* interpreter::run(const string &s, bool check) +pure_expr* interpreter::run(const string &_s, bool check) { + string s = unixize(_s); // check for library modules size_t p = s.find(":"); if (p != string::npos && s.substr(0, p) == "lib") { Modified: pure/trunk/pure.cc =================================================================== --- pure/trunk/pure.cc 2008-08-20 01:14:23 UTC (rev 544) +++ pure/trunk/pure.cc 2008-08-20 06:43:39 UTC (rev 545) @@ -191,7 +191,11 @@ { size_t pos = 0; while (pos != string::npos) { +#ifdef _WIN32 + size_t end = path.find(';', pos); +#else size_t end = path.find(':', pos); +#endif string s; if (end == string::npos) { s = path.substr(pos); @@ -207,6 +211,17 @@ } } +static string unixize(const string& s) +{ + string t = s; +#ifdef _WIN32 + for (size_t i = 0, n = t.size(); i<n; i++) + if (t[i] == '\\') + t[i] = '/'; +#endif + return t; +} + int main(int argc, char *argv[]) { @@ -260,7 +275,7 @@ if (!*end) interpreter::stackmax = n*1024; } if ((env = getenv("PURELIB"))) { - string s = env; + string s = unixize(env); if (!s.empty() && s[s.size()-1] != '/') s.append("/"); interp.libdir = s; } else @@ -294,6 +309,7 @@ } s = *args; } + s = unixize(s); if (!s.empty()) { if (s[s.size()-1] != '/') s.append("/"); interp.includedirs.push_back(s); @@ -307,6 +323,7 @@ } s = *args; } + s = unixize(s); if (!s.empty()) { if (s[s.size()-1] != '/') s.append("/"); interp.librarydirs.push_back(s); @@ -330,8 +347,10 @@ interp.error(prog + ": invalid option " + *args); return 1; } - if ((env = getenv("PURE_INCLUDE"))) add_path(interp.includedirs, env); - if ((env = getenv("PURE_LIBRARY"))) add_path(interp.librarydirs, env); + if ((env = getenv("PURE_INCLUDE"))) + add_path(interp.includedirs, unixize(env)); + if ((env = getenv("PURE_LIBRARY"))) + add_path(interp.librarydirs, unixize(env)); interp.init_sys_vars(PACKAGE_VERSION, HOST, myargs); if (want_prelude) { // load the prelude if we can find it Modified: pure/trunk/runtime.cc =================================================================== --- pure/trunk/runtime.cc 2008-08-20 01:14:23 UTC (rev 544) +++ pure/trunk/runtime.cc 2008-08-20 06:43:39 UTC (rev 545) @@ -892,7 +892,11 @@ { size_t pos = 0; while (pos != string::npos) { +#ifdef _WIN32 + size_t end = path.find(';', pos); +#else size_t end = path.find(':', pos); +#endif string s; if (end == string::npos) { s = path.substr(pos); @@ -908,6 +912,17 @@ } } +static string unixize(const string& s) +{ + string t = s; +#ifdef _WIN32 + for (size_t i = 0, n = t.size(); i<n; i++) + if (t[i] == '\\') + t[i] = '/'; +#endif + return t; +} + extern "C" pure_interp *pure_create_interp(int argc, char *argv[]) { @@ -931,7 +946,7 @@ if (!*end) interpreter::stackmax = n*1024; } if ((env = getenv("PURELIB"))) { - string s = env; + string s = unixize(env); if (!s.empty() && s[s.size()-1] != '/') s.append("/"); interp.libdir = s; } else @@ -963,6 +978,7 @@ } s = *args; } + s = unixize(s); if (!s.empty()) { if (s[s.size()-1] != '/') s.append("/"); interp.includedirs.push_back(s); @@ -977,6 +993,7 @@ } s = *args; } + s = unixize(s); if (!s.empty()) { if (s[s.size()-1] != '/') s.append("/"); interp.librarydirs.push_back(s); @@ -1002,8 +1019,10 @@ delete _interp; return 0; } - if ((env = getenv("PURE_INCLUDE"))) add_path(interp.includedirs, env); - if ((env = getenv("PURE_LIBRARY"))) add_path(interp.librarydirs, env); + if ((env = getenv("PURE_INCLUDE"))) + add_path(interp.includedirs, unixize(env)); + if ((env = getenv("PURE_LIBRARY"))) + add_path(interp.librarydirs, unixize(env)); interp.init_sys_vars(PACKAGE_VERSION, HOST, myargs); if (want_prelude) { // load the prelude if we can find it This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-20 01:14:13
|
Revision: 544 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=544&view=rev Author: agraef Date: 2008-08-20 01:14:23 +0000 (Wed, 20 Aug 2008) Log Message: ----------- Fix formatting glitch. Modified Paths: -------------- pure/trunk/pure.1.in Modified: pure/trunk/pure.1.in =================================================================== --- pure/trunk/pure.1.in 2008-08-19 12:19:54 UTC (rev 543) +++ pure/trunk/pure.1.in 2008-08-20 01:14:23 UTC (rev 544) @@ -456,7 +456,7 @@ following prompt/input interaction: .sp .nf -> using system; +> \fBusing\fP system; > puts "Enter a number:" $$ scanf "%g"; Enter a number: 21 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-19 12:19:45
|
Revision: 543 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=543&view=rev Author: agraef Date: 2008-08-19 12:19:54 +0000 (Tue, 19 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-19 11:46:50 UTC (rev 542) +++ pure/trunk/pure.1.in 2008-08-19 12:19:54 UTC (rev 543) @@ -589,16 +589,15 @@ .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 -(to print its value, or to bind it to a variable symbol), the interpreter will -always use the +evolve while the program is being processed. When you evaluate an expression, +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. Thus you have to make sure that, when you evaluate an expression, -all the functions, constants and variables it uses have already been defined -at this point in the source (no matter whether the source is being entered -interactively, or read from a script). +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.) .PP .B Examples. Here are a few examples of simple Pure programs (see the following section for This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-19 11:46:45
|
Revision: 542 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=542&view=rev Author: agraef Date: 2008-08-19 11:46:50 +0000 (Tue, 19 Aug 2008) Log Message: ----------- Leopard 'echo' fixes, 2nd attempt. Modified Paths: -------------- pure/trunk/Makefile.in Modified: pure/trunk/Makefile.in =================================================================== --- pure/trunk/Makefile.in 2008-08-19 11:04:51 UTC (rev 541) +++ pure/trunk/Makefile.in 2008-08-19 11:46:50 UTC (rev 542) @@ -41,7 +41,10 @@ CXX = @CXX@ INSTALL = @INSTALL@ + +ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ # Linker flags and required libraries. These are determined automatically by # configure, but if necessary you can also change these on the command line. @@ -264,8 +267,8 @@ check: pure @ echo Running tests. - @ (export @LD_LIB_PATH@=.; export PURELIB=$(srcdir)/lib; echo $(ECHO_N) "prelude.pure: "; if ./pure $(ECHO_N) -v$(level) $(srcdir)/lib/prelude.pure 2>&1 | diff -q - $(srcdir)/test/prelude.log > /dev/null; then echo passed; else echo FAILED; fi) - @ (export @LD_LIB_PATH@=.; export PURELIB=$(srcdir)/lib; for x in $(notdir $(tests)); do echo $(ECHO_N) "$$x: "; if ./pure -v$(level) < $(srcdir)/test/$$x 2>&1 | diff -q - $(srcdir)/test/"`basename $$x .pure`.log" > /dev/null; then echo passed; else echo FAILED; fi; done) + @ (export @LD_LIB_PATH@=.; export PURELIB=$(srcdir)/lib; echo $(ECHO_N) "prelude.pure: $(ECHO_C)"; if ./pure -n -v$(level) $(srcdir)/lib/prelude.pure 2>&1 | diff -q - $(srcdir)/test/prelude.log > /dev/null; then echo "$(ECHO_T)passed"; else echo "$(ECHO_T)FAILED"; fi) + @ (export @LD_LIB_PATH@=.; export PURELIB=$(srcdir)/lib; for x in $(notdir $(tests)); do echo $(ECHO_N) "$$x: $(ECHO_C)"; if ./pure -v$(level) < $(srcdir)/test/$$x 2>&1 | diff -q - $(srcdir)/test/"`basename $$x .pure`.log" > /dev/null; then echo "$(ECHO_T)passed"; else echo "$(ECHO_T)FAILED"; fi; done) # DO NOT DELETE This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-19 11:04:42
|
Revision: 541 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=541&view=rev Author: agraef Date: 2008-08-19 11:04:51 +0000 (Tue, 19 Aug 2008) Log Message: ----------- Cosmetic changes. Modified Paths: -------------- pure/trunk/lexer.ll Modified: pure/trunk/lexer.ll =================================================================== --- pure/trunk/lexer.ll 2008-08-19 11:04:21 UTC (rev 540) +++ pure/trunk/lexer.ll 2008-08-19 11:04:51 UTC (rev 541) @@ -395,12 +395,12 @@ cout << "list command help: list [options ...] [symbol ...]\n\ Options may be combined, e.g., list -tvl is the same as list -t -v -l.\n\ -a Disassembles pattern matching automata. Useful for debugging purposes.\n\ --c Print information about constant symbols.\n\ +-c Print information about defined constants.\n\ -d Disassembles LLVM IR, showing the generated LLVM assembler code of a\n\ function. Useful for debugging purposes.\n\ -e Annotate printed definitions with lexical environment information\n\ (de Bruijn indices, subterm paths). Useful for debugging purposes.\n\ --f Print information about function symbols.\n\ +-f Print information about defined functions.\n\ -g Indicates that the following symbols are actually shell glob patterns\n\ and that all matching symbols should be listed.\n\ -h Print this list.\n\ @@ -410,7 +410,7 @@ -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\ definitions, level 0 *all* definitions (the default if -t is omitted).\n\ --v Print information about variable symbols.\n"; +-v Print information about defined variables.\n"; goto out; default: cerr << "list: invalid option character '" << *s << "'\n"; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-19 11:04:12
|
Revision: 540 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=540&view=rev Author: agraef Date: 2008-08-19 11:04:21 +0000 (Tue, 19 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-19 08:01:20 UTC (rev 539) +++ pure/trunk/pure.1.in 2008-08-19 11:04:21 UTC (rev 540) @@ -189,11 +189,11 @@ .SH PURE OVERVIEW .PP Pure is a fairly simple language. Programs are collections of equational rules -defining functions, \fBdef\fP and \fBlet\fP commands binding global constant -and variable symbols, and expressions to be evaluated. 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): +defining functions, \fBconst\fP and \fBlet\fP commands binding global +constants and variables, and expressions to be evaluated. 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): .sp .nf > // my first Pure example @@ -314,14 +314,18 @@ .B nullary symbols, see below). .TP -.B Operator and constant symbols: \fRx+y, x==y, \fBnot\fP\ x +.B Operator and constant symbols: \fRx+y, x==y, \fBnot\fP\ x, [] As indicated, these take the form of an identifier or a sequence of ASCII punctuation symbols, as defined in the source using corresponding -\fBprefix\fP, \fBpostfix\fP and \fBinfix\fP declarations, which are discussed -in section DECLARATIONS. Enclosing an operator in parentheses, such as (+) or -(\fBnot\fP), turns it into an ordinary function symbol. Symbols can also be -defined as \fBnullary\fP to denote special constant symbols. See below for -further details. +\fBprefix\fP, \fBpostfix\fP, \fBinfix\fP and \fBnullary\fP declarations, which +are discussed in section DECLARATIONS. Enclosing an operator in parentheses, +such as (+) or (\fBnot\fP), turns it into an ordinary function symbol. Symbols +declared as \fBnullary\fP denote special constant symbols which simply stand +for themselves. Technically, these are just ordinary identifiers; however, the +.B nullary +attribute tells the compiler that when such an identifier occurs on the +left-hand side of an equation, it is to be interpreted as a constant rather +than a variable (see above). .TP .B Lists and tuples: \fR[x,y,z], x..y, x:xs, x,y,z The necessary constructors to build lists and tuples are actually defined in @@ -482,13 +486,17 @@ but serves to bind \fIglobal\fP variables occurring free on the right-hand side of other function and variable definitions. .TP -.B Constant bindings: def\fR \fIlhs\fR = \fIrhs\fR; -An alternative form of \fBlet\fP which binds constant symbols rather than -variables. Like \fBlet\fP, this binds the variables on the left-hand side to -the corresponding values on the evaluated right-hand side. The difference is -that constant symbols can only be defined once, after which their values are -substituted directly into the right-hand sides of other definitions, rather -than being evaluated at runtime. +.B Constant bindings: const\fR \fIlhs\fR = \fIrhs\fR; +An alternative form of \fBlet\fP which defines constants rather than +variables. (These are not to be confused with +.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 +.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 +looked up at runtime. .TP .B Toplevel expressions: \fIexpr\fR; A singleton expression at the toplevel, terminated with a semicolon, simply @@ -527,9 +535,9 @@ 109,119 .fi .PP -Global bindings of constant, variable and function symbols work a bit -differently, though. Like many languages which are to be used interactively, -Pure binds global symbols +Global bindings of variable and function symbols work a bit differently, +though. Like many languages which are to be used interactively, Pure binds +global symbols .IR dynamically , so that they can be changed easily at any time during an interactive session. This is mainly a convenience for interactive usage, but works the @@ -580,21 +588,17 @@ variable and function definitions. 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 my well +been processed, the definition of global functions and variables may well evolve while the program is being processed. When you evaluate an expression -(to print its value, or to bind it to a variable or constant symbol), the -interpreter will always use the +(to print its value, or to bind it to a variable symbol), 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. Thus you have to make sure that, when you evaluate an expression, all the functions, constants and variables it uses have already been defined at this point in the source (no matter whether the source is being entered -interactively, or read from a script). (Note that constant symbols work a bit -differently from variables in that their values are not supposed to change -once they have been defined, and the values will be substituted into other -definitions rather than being looked up at runtime. But you still have to -define them before they can be used.) +interactively, or read from a script). .PP .B Examples. Here are a few examples of simple Pure programs (see the following section for @@ -634,6 +638,24 @@ \fBend\fP; .fi .PP +Here is an example showing how constants are defined and used. Constant +definitions take pretty much the same form as variable definitions with +.B let +(see above), but work more like the definition of a parameterless function +whose value is precomputed at compile time: +.sp +.nf +> \fBextern\fP double atan(double); +> \fBconst\fP pi = 4*atan 1.0; +> pi; +3.14159265358979 +> foo x = 2*pi*x; +> \fBlist\fP foo +foo x = 2*3.14159265358979*x; +> foo 1; +6.28318530717958 +.fi +.PP A little list comprehension example (Erathosthenes' classical prime sieve): .sp .nf @@ -677,9 +699,9 @@ .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 \fBdef\fP constructs for the purpose of binding variable values +\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 \fBdef\fP clauses). When matching against a function call or the +\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 @@ -1285,7 +1307,7 @@ option of the interpreter. .TP .B -c -Print information about constant symbols. +Print information about defined constants. .TP .B -d Disassembles LLVM IR, showing the generated LLVM assembler code of a @@ -1300,7 +1322,7 @@ option of the interpreter. .TP .B -f -Print information about function symbols. +Print information about defined functions. .TP .B -g Indicates that the following symbols are actually shell glob patterns and that @@ -1326,7 +1348,7 @@ levels. .TP .B -v -Print information about variable symbols. +Print information about defined variables. .PP If none of the .BR -c , @@ -1497,9 +1519,9 @@ > \fBunderride\fP .fi .SH CAVEATS AND NOTES -This section deals with some common pitfalls, as well as quirks and -limitations of the current implementation, and lists some useful tips and -tricks. +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. .PP .B Debugging. There's no symbolic debugger yet. So @@ -1558,30 +1580,31 @@ convenience. .PP .B With or when? -A common source of confusion for Haskell renegades is that Pure provides two +A common source of confusion for Haskellers is that Pure provides two different constructs to bind local function and variable symbols, -respectively, namely -.BR with , -which is used for local function definitions, and -.BR when , -which binds local variables. This distinction is necessary because Pure does -not segregate defined functions and constructors, and thus there is no magic -to figure out whether an equation like `foo x = y' by itself is meant as a -definition of a function foo with formal parameter x and return value y, or a -definition binding the local variable x by matching the constructor pattern -foo x against the value y. The +respectively. This distinction is necessary because Pure does not segregate +defined functions and constructors, and thus there is no magic to figure out +whether an equation like `foo x = y' by itself is meant as a definition of a +function foo with formal parameter x and return value y, or a definition +binding the local variable x by matching the constructor pattern foo x against +the value y. The .B with construct does the former, .B when the latter. .PP -Another pitfall is that, since +Another pitfall is that .B with and .B when -clauses are tacked on to the end of the expression they belong to, they have -to be read in reverse, if you want to figure out what is actually going on -there. Also note that since +clauses are tacked on to the end of the expression they belong to, which +mimics mathematical notation but may be unfamilar if you're more accustomed to +languages from the Algol/Pascal/C family. If you want to figure out what is +actually going on there, it's usually best to read nested scopes ``in +reverse'' (proceeding from the rightmost/outermost to the leftmost/innermost +clause). +.PP +Also note that since .B with and .B when @@ -1625,16 +1648,17 @@ constant like `0' only matches machine integers, not bigints; for the latter you'll have to use the ``big L'' notation `0L'. .PP -.B Working with constants. +.B Constant definitions. When definining a function in terms of constant values which have to be -computed beforehand, it's usually better to use a constant symbol (rather than -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: +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: .sp .nf > \fBextern\fP double atan(double); -> \fBdef\fP pi = 4*atan 1.0; +> \fBconst\fP pi = 4*atan 1.0; > foo x = 2*pi*x; > \fBlist\fP foo foo x = 2*3.14159265358979*x; @@ -1648,47 +1672,46 @@ different environments, without any runtime penalties: .sp .nf -> \fBdef\fP running_on_windows = index sysinfo "mingw32" >= 0; -> foo x = something x \fBif\fP running_on_windows; -> = something_else x \fBotherwise\fP; +\fBconst\fP win = index sysinfo "mingw32" >= 0; +check boy = bad boy \fBif\fP win; + = good boy \fBotherwise\fP; .fi .PP -In this case the code for one of the branches of foo will be completely -eliminated, depending on whether your script runs on Windows or not. +In this case the code for one of the branches of `check' will be completely +eliminated, depending on the outcome of the configuration check. .PP On the other hand, constant definitions are somewhat limited in scope compared -to variable definitions, since the value bound to the constant symbol must be -usable at compile time, so that it can be substituted into other -definitions. Thus, while there is no \fIa priori\fP restriction on the -computations you can perform to obtain the value of the constant, the value -must not be a pointer object (other than the null pointer), or an anonymous -closure (which also rules out local functions, because these cannot be -referred to by their names at the toplevel), or an aggregate value containing -any such values. +to variable definitions, since the bound value must be usable at compile time, +so that it can be substituted into other definitions. Thus, while there is no +\fIa priori\fP restriction on the computations you can perform to obtain the +value of the constant, the value must not be a pointer object (other than the +null pointer), or an anonymous closure (which also rules out local functions, +because these cannot be referred to by their names at the toplevel), or an +aggregate value containing any such values. .PP -Constant symbols also differ from variables in that they cannot be redefined -(that's their purpose after all) and will only take effect on subsequent +Constants also differ from variables in that they cannot be redefined (that's +their purpose after all) and will only take effect on subsequent definitions. E.g.: .sp .nf -> \fBdef\fP c = 2; +> \fBconst\fP c = 2; > foo x = c*x; > \fBlist\fP foo foo x = 2*x; > foo 99; 198 -> \fBdef\fP c = 3; +> \fBconst\fP c = 3; <stdin>:5.0-8: symbol 'c' is already defined as a constant .fi .PP Well, in fact this not the full truth because in interactive mode it \fIis\fP -possible to redefine constant symbols after all, if the old definition is -first purged with the \fBclear\fP command. However, this won't affect any -other existing definitions: +possible to redefine constants after all, if the old definition is first +purged with the \fBclear\fP command. However, this won't affect any other +existing definitions: .sp .nf > \fBclear\fP c -> \fBdef\fP c = 3; +> \fBconst\fP c = 3; > bar x = c*x; > \fBlist\fP foo bar foo x = 2*x; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-19 08:01:13
|
Revision: 539 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=539&view=rev Author: agraef Date: 2008-08-19 08:01:20 +0000 (Tue, 19 Aug 2008) Log Message: ----------- Renamed the 'def' keyword to 'const'. Modified Paths: -------------- pure/trunk/ChangeLog pure/trunk/etc/pure-mode.el.in pure/trunk/etc/pure.lang pure/trunk/etc/pure.vim pure/trunk/etc/pure.xml pure/trunk/examples/hello.pure pure/trunk/examples/libor/date.pure pure/trunk/interpreter.cc pure/trunk/lexer.ll pure/trunk/lib/math.pure pure/trunk/lib/prelude.pure pure/trunk/parser.yy pure/trunk/printer.cc pure/trunk/pure.cc pure/trunk/test/prelude.log pure/trunk/test/test013.log pure/trunk/test/test013.pure Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/ChangeLog 2008-08-19 08:01:20 UTC (rev 539) @@ -1,3 +1,11 @@ +2008-08-19 Albert Graef <Dr....@t-...> + + * parser.yy, lexer.ll, printer.cc, etc.: Renamed the 'def' keyword + to 'const', as originally proposed by Eddie Rucker. ('def' is + still a reserved keyword, since it's soon going to be used for + macro definitions.) Scripts and syntax highlighting files in the + distribution have been updated accordingly. + 2008-08-18 Albert Graef <Dr....@t-...> * interpreter.cc (codegen): Generate tail-recursive code for Modified: pure/trunk/etc/pure-mode.el.in =================================================================== --- pure/trunk/etc/pure-mode.el.in 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/etc/pure-mode.el.in 2008-08-19 08:01:20 UTC (rev 539) @@ -164,7 +164,7 @@ ; (list "\\<\\(catch\\|throw\\)\\>" 0 'font-lock-builtin-face) (list (concat "\\<\\(" - "def\\|extern\\|infix[lr]?\\|" + "const\\|def\\|extern\\|infix[lr]?\\|" "let\\|nullary\\|p\\(refix\\|ostfix\\)\\|" "using" "\\)\\>") @@ -178,7 +178,7 @@ (list "\\<\\(catch\\|throw\\)\\>" 0 'font-lock-builtin-face) (list (concat "\\<\\(" - "case\\|def\\|e\\(lse\\|nd\\|xtern\\)\\|i\\(f\\|nfix[lr]?\\)\\|" + "case\\|const\\|def\\|e\\(lse\\|nd\\|xtern\\)\\|i\\(f\\|nfix[lr]?\\)\\|" "let\\|nullary\\|o\\(f\\|therwise\\)\\|p\\(refix\\|ostfix\\)\\|" "then\\|using\\|w\\(hen\\|ith\\)" "\\)\\>") Modified: pure/trunk/etc/pure.lang =================================================================== --- pure/trunk/etc/pure.lang 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/etc/pure.lang 2008-08-19 08:01:20 UTC (rev 539) @@ -4,8 +4,8 @@ $DESCRIPTION=Pure # Pure keywords. -$KW_LIST(kwa)=infix infixl infixr prefix postfix nullary case def else end -extern if let of otherwise then using when with +$KW_LIST(kwa)=infix infixl infixr prefix postfix nullary case const def else +end extern if let of otherwise then using when with # These aren't really keywords but we want them to stick out anyway. $KW_LIST(kwb)=catch throw Modified: pure/trunk/etc/pure.vim =================================================================== --- pure/trunk/etc/pure.vim 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/etc/pure.vim 2008-08-19 08:01:20 UTC (rev 539) @@ -33,7 +33,7 @@ " keywords syn keyword pureKeyword infix infixl infixr prefix postfix nullary -syn keyword pureKeyword case def else end extern if let of otherwise then +syn keyword pureKeyword case const def else end extern if let of otherwise then syn keyword pureKeyword using when with syn keyword pureSpecial catch throw syn keyword pureType bigint bool char short int long double Modified: pure/trunk/etc/pure.xml =================================================================== --- pure/trunk/etc/pure.xml 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/etc/pure.xml 2008-08-19 08:01:20 UTC (rev 539) @@ -11,6 +11,7 @@ <item> end </item> </list> <list name="keywords"> + <item> const </item> <item> def </item> <item> else </item> <item> extern </item> Modified: pure/trunk/examples/hello.pure =================================================================== --- pure/trunk/examples/hello.pure 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/examples/hello.pure 2008-08-19 08:01:20 UTC (rev 539) @@ -47,11 +47,11 @@ // Pattern matching definition with 'let'. let x, y = square x, square (x+2); x; y; -// We also have constant definitions using 'def' in lieu of 'let'. These -// cannot be redefined and are substituted directly into other definitions. -// Try something like 'foo x = pi*x;' and then 'list foo' to see the -// difference. -def pi = 3.14159265358979; +// We also have constant definitions using 'const' in lieu of 'let'. These +// symbols cannot be redefined and are substituted directly into other +// definitions. Try something like 'foo x = pi*x;' and then 'list foo' to see +// the difference. +const pi = 3.14159265358979; /* Variations on a theme: The factorial. This illustrates various different ways to define a simple recursive function. */ Modified: pure/trunk/examples/libor/date.pure =================================================================== --- pure/trunk/examples/libor/date.pure 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/examples/libor/date.pure 2008-08-19 08:01:20 UTC (rev 539) @@ -12,18 +12,18 @@ // diytime = c_time (pointer 0); // some constants in whole days -def mdayposix = 1856305;// Mayan day for the posix epoch 1 Jan 1970 -def jdayposix = 2440588;// Julian day (since 1 Jan 4713 BC) for the posix epoch -def cycledays = 1872000;// end of cycle: total days in 13 Baktuns +const mdayposix = 1856305;// Mayan day for the posix epoch 1 Jan 1970 +const jdayposix = 2440588;// Julian day (since 1 Jan 4713 BC) for the posix epoch +const cycledays = 1872000;// end of cycle: total days in 13 Baktuns // some constants in whole seconds -def secsinday = 86400; // number of seconds in a day -def trueyear = 31556941;// current true year (divisible by 13) -def myyear = 31556943;// div by 2277, secsinday compatible, 365.2424 days -def gregyear = 31556952;// div by 40824, mean gregorian year, 365.2425 days -def lunarmonth = 2551443; // duration of the lunar synodic month -def fullmoon = 1213810200;// 18th June 2008, 17:30, full moon in posix seconds -def venussyn = 50450688;// duration of the Venus synodic cycle -def venusinf = 1187409600;// 18th August 2007, 4am Venus inferior conjunction +const secsinday = 86400; // number of seconds in a day +const trueyear = 31556941;// current true year (divisible by 13) +const myyear = 31556943;// div by 2277, secsinday compatible, 365.2424 days +const gregyear = 31556952;// div by 40824, mean gregorian year, 365.2425 days +const lunarmonth = 2551443; // duration of the lunar synodic month +const fullmoon = 1213810200;// 18th June 2008, 17:30, full moon in posix seconds +const venussyn = 50450688;// duration of the Venus synodic cycle +const venusinf = 1187409600;// 18th August 2007, 4am Venus inferior conjunction /******************************************************************************/ // first some functions generally useful in Pure: Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/interpreter.cc 2008-08-19 08:01:20 UTC (rev 539) @@ -1217,16 +1217,16 @@ last.clear(); pure_expr *e, *res = const_defn(r->lhs, r->rhs, e); if ((verbose&verbosity::defs) != 0) - cout << "def " << r->lhs << " = " << r->rhs << ";\n"; + cout << "const " << r->lhs << " = " << r->rhs << ";\n"; if (!res) { ostringstream msg; if (e) { msg << "unhandled exception '" << e << "' while evaluating '" - << "def " << r->lhs << " = " << r->rhs << "'"; + << "const " << r->lhs << " = " << r->rhs << "'"; pure_free(e); } else msg << "failed match while evaluating '" - << "def " << r->lhs << " = " << r->rhs << "'"; + << "const " << r->lhs << " = " << r->rhs << "'"; throw err(msg.str()); } delete r; Modified: pure/trunk/lexer.ll =================================================================== --- pure/trunk/lexer.ll 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/lexer.ll 2008-08-19 08:01:20 UTC (rev 539) @@ -131,9 +131,9 @@ now. */ static const char *commands[] = { - "cd", "clear", "def", "extern", "help", "infix", "infixl", "infixr", "let", - "list", "ls", "nullary", "override", "postfix", "prefix", "pwd", "quit", - "run", "save", "stats", "underride", "using", 0 + "cd", "clear", "const", "def", "extern", "help", "infix", "infixl", + "infixr", "let", "list", "ls", "nullary", "override", "postfix", "prefix", + "pwd", "quit", "run", "save", "stats", "underride", "using", 0 }; typedef map<string, symbol> symbol_map; @@ -531,7 +531,7 @@ << *jt->second.cval << ";"; sout << endl; } else - sout << "def " << sym.s << " = " << *jt->second.cval + sout << "const " << sym.s << " = " << *jt->second.cval << ";\n"; } else { if (sym.fix == nullary) @@ -819,6 +819,7 @@ prefix yylval->fix = prefix; return token::FIX; postfix yylval->fix = postfix; return token::FIX; nullary return token::NULLARY; +const return token::CONST; def return token::DEF; let return token::LET; case return token::CASE; Modified: pure/trunk/lib/math.pure =================================================================== --- pure/trunk/lib/math.pure 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/lib/math.pure 2008-08-19 08:01:20 UTC (rev 539) @@ -20,7 +20,7 @@ /* IEEE floating point infinities and NaNs. */ -def inf = 1.0e307 * 1.0e307; def nan = inf-inf; +const inf = 1.0e307 * 1.0e307; const nan = inf-inf; /* Random number generator. This uses the Mersenne twister, in order to avoid bad generators present in some C libraries. Returns pseudo random ints in @@ -48,7 +48,7 @@ /* Euler's number. */ -def e = exp 1.0; +const e = exp 1.0; /* Trigonometric functions. */ @@ -71,7 +71,7 @@ /* Ludolph's number. */ -def pi = 4.0*atan 1.0; +const pi = 4.0*atan 1.0; /* Hyperbolic functions. */ @@ -111,7 +111,7 @@ /* The imaginary unit. */ -def i = 0+:1; +const i = 0+:1; /* The following operations all work with both the rectangular and the polar representation, promoting real inputs to complex where appropriate. When Modified: pure/trunk/lib/prelude.pure =================================================================== --- pure/trunk/lib/prelude.pure 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/lib/prelude.pure 2008-08-19 08:01:20 UTC (rev 539) @@ -67,7 +67,7 @@ /* The truth values. These are just integers in Pure, but sometimes it's convenient to refer to them using these symbolic constants. */ -def false = 0; def true = 1; +const false, true = 0, 1; /* Pull in the primitives (arithmetic etc.) and the standard string functions. Note that the math and system modules are *not* included here, so you have Modified: pure/trunk/parser.yy =================================================================== --- pure/trunk/parser.yy 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/parser.yy 2008-08-19 08:01:20 UTC (rev 539) @@ -99,6 +99,7 @@ %token <fix> FIX "fixity" %token DEF "def" +%token CONST "const" %token LET "let" %token CASE "case" %token OF "of" @@ -276,7 +277,7 @@ { action(interp.exec($1), delete $1); } | LET simple_rule { action(interp.define($2), delete $2); } -| DEF simple_rule +| CONST simple_rule { action(interp.define_const($2), delete $2); } | rule { rulel *rl = 0; Modified: pure/trunk/printer.cc =================================================================== --- pure/trunk/printer.cc 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/printer.cc 2008-08-19 08:01:20 UTC (rev 539) @@ -432,7 +432,7 @@ break; } case env_info::cvar: - os << "def " << sym.s << " = " << *info.cval; + os << "const " << sym.s << " = " << *info.cval; break; case env_info::fvar: os << "let " << sym.s << " = " << *(pure_expr**)info.val; Modified: pure/trunk/pure.cc =================================================================== --- pure/trunk/pure.cc 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/pure.cc 2008-08-19 08:01:20 UTC (rev 539) @@ -54,9 +54,9 @@ #define LICENSE "This program is free software distributed under the GNU Public License\n(GPL V3 or later). Please see the COPYING file for details.\n" static const char *commands[] = { - "cd", "clear", "def", "extern", "help", "infix", "infixl", "infixr", "let", - "list", "ls", "nullary", "override", "postfix", "prefix", "pwd", "quit", - "run", "save", "stats", "underride", "using", 0 + "cd", "clear", "const", "def", "extern", "help", "infix", "infixl", + "infixr", "let", "list", "ls", "nullary", "override", "postfix", "prefix", + "pwd", "quit", "run", "save", "stats", "underride", "using", 0 }; /* Generator functions for command completion. */ Modified: pure/trunk/test/prelude.log =================================================================== --- pure/trunk/test/prelude.log 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/test/prelude.log 2008-08-19 08:01:20 UTC (rev 539) @@ -1,5 +1,4 @@ -def false = 0; -def true = 1; +const false,true = 0,1; f/*0:01*/$x/*0:1*/ = f/*0:01*/ x/*0:1*/; (f/*0:001*/.g/*0:01*/) x/*0:1*/ = f/*0:001*/ (g/*0:01*/ x/*0:1*/); void _/*0:1*/ = (); Modified: pure/trunk/test/test013.log =================================================================== --- pure/trunk/test/test013.log 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/test/test013.log 2008-08-19 08:01:20 UTC (rev 539) @@ -1,4 +1,4 @@ -def pi = 4*atan 1.0; +const pi = 4*atan 1.0; foo x/*0:1*/ = 3.14159265358979*x/*0:1*/; { rule #0: foo x = 3.14159265358979*x Modified: pure/trunk/test/test013.pure =================================================================== --- pure/trunk/test/test013.pure 2008-08-19 07:12:56 UTC (rev 538) +++ pure/trunk/test/test013.pure 2008-08-19 08:01:20 UTC (rev 539) @@ -2,7 +2,7 @@ // constant definition example extern double atan(double); -def pi = 4*atan 1.0; +const pi = 4*atan 1.0; foo x = pi*x; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-19 07:12:47
|
Revision: 538 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=538&view=rev Author: agraef Date: 2008-08-19 07:12:56 +0000 (Tue, 19 Aug 2008) Log Message: ----------- Renamed the const combinator to cst. Modified Paths: -------------- pure/trunk/lib/prelude.pure pure/trunk/test/prelude.log Modified: pure/trunk/lib/prelude.pure =================================================================== --- pure/trunk/lib/prelude.pure 2008-08-19 06:57:19 UTC (rev 537) +++ pure/trunk/lib/prelude.pure 2008-08-19 07:12:56 UTC (rev 538) @@ -82,7 +82,7 @@ void _ = (); id x = x; -const x y = x; +cst x y = x; flip f x y = f y x; curry f x y = f (x,y); Modified: pure/trunk/test/prelude.log =================================================================== --- pure/trunk/test/prelude.log 2008-08-19 06:57:19 UTC (rev 537) +++ pure/trunk/test/prelude.log 2008-08-19 07:12:56 UTC (rev 538) @@ -4,7 +4,7 @@ (f/*0:001*/.g/*0:01*/) x/*0:1*/ = f/*0:001*/ (g/*0:01*/ x/*0:1*/); void _/*0:1*/ = (); id x/*0:1*/ = x/*0:1*/; -const x/*0:01*/ y/*0:1*/ = x/*0:01*/; +cst x/*0:01*/ y/*0:1*/ = x/*0:01*/; flip f/*0:001*/ x/*0:01*/ y/*0:1*/ = f/*0:001*/ y/*0:1*/ x/*0:01*/; curry f/*0:001*/ x/*0:01*/ y/*0:1*/ = f/*0:001*/ (x/*0:01*/,y/*0:1*/); 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*/); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-19 06:57:09
|
Revision: 537 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=537&view=rev Author: agraef Date: 2008-08-19 06:57:19 +0000 (Tue, 19 Aug 2008) Log Message: ----------- Remove CLOCKS_PER_SEC to eliminate platform dependencies. Modified Paths: -------------- pure/trunk/test/test017.log pure/trunk/test/test017.pure Modified: pure/trunk/test/test017.log =================================================================== --- pure/trunk/test/test017.log 2008-08-19 06:23:50 UTC (rev 536) +++ pure/trunk/test/test017.log 2008-08-19 06:57:19 UTC (rev 537) @@ -1,4 +1,4 @@ -timex f/*0:1*/ = (clock-t0/*1:*/)/1000000,res/*0:*/ when t0/*0:*/ = clock; res/*0:*/ = f/*1:1*/ () { +timex f/*0:1*/ = clock-t0/*1:*/,res/*0:*/ when t0/*0:*/ = clock; res/*0:*/ = f/*1:1*/ () { rule #0: res = f () state 0: #0 <var> state 1 @@ -12,7 +12,7 @@ foo n/*0:1*/ = if n/*0:1*/<=0 then n/*0:1*/ else foo (n/*0:1*/-1); bar x/*0:1*/ = catch id (throw x/*1:1*/); { - rule #0: timex f = (clock-t0)/1000000,res when t0 = clock; res = f () end + rule #0: timex f = clock-t0,res when t0 = clock; res = f () end state 0: #0 <var> state 1 state 1: #0 Modified: pure/trunk/test/test017.pure =================================================================== --- pure/trunk/test/test017.pure 2008-08-19 06:23:50 UTC (rev 536) +++ pure/trunk/test/test017.pure 2008-08-19 06:57:19 UTC (rev 537) @@ -1,7 +1,7 @@ using system; -timex f = (clock-t0)/CLOCKS_PER_SEC, res when t0 = clock; res = f () end; +timex f = clock-t0, res when t0 = clock; res = f () end; foo n = if n<=0 then n else foo (n-1); // burn some cycles bar x = catch id (throw x); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-19 06:23:42
|
Revision: 536 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=536&view=rev Author: agraef Date: 2008-08-19 06:23:50 +0000 (Tue, 19 Aug 2008) Log Message: ----------- Add a stack check to 'def' constant conversion. Modified Paths: -------------- pure/trunk/interpreter.cc pure/trunk/interpreter.hh Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-08-18 23:38:38 UTC (rev 535) +++ pure/trunk/interpreter.cc 2008-08-19 06:23:50 UTC (rev 536) @@ -788,9 +788,11 @@ return res; } -static expr pure_expr_to_expr(pure_expr *x) +expr interpreter::pure_expr_to_expr(pure_expr *x) { - // FIXME: We might want to do stack checks here. + char test; + if (stackmax > 0 && stackdir*(&test - baseptr) >= stackmax) + throw err("expression too deep in constant definition"); switch (x->tag) { case EXPR::APP: return expr(pure_expr_to_expr(x->data.x[0]), Modified: pure/trunk/interpreter.hh =================================================================== --- pure/trunk/interpreter.hh 2008-08-18 23:38:38 UTC (rev 535) +++ pure/trunk/interpreter.hh 2008-08-19 06:23:50 UTC (rev 536) @@ -504,6 +504,7 @@ Builder& act_builder() { return act_env().builder; } pure_expr *const_value(expr x); pure_expr *const_app_value(expr x); + expr pure_expr_to_expr(pure_expr *x); pure_expr *doeval(expr x, pure_expr*& e); pure_expr *dodefn(env vars, expr lhs, expr rhs, pure_expr*& e); llvm::Value *codegen(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-18 23:38:28
|
Revision: 535 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=535&view=rev Author: agraef Date: 2008-08-18 23:38:38 +0000 (Mon, 18 Aug 2008) Log Message: ----------- Better complex sqrt definition, suggested by Eddie Rucker. Modified Paths: -------------- pure/trunk/lib/math.pure Modified: pure/trunk/lib/math.pure =================================================================== --- pure/trunk/lib/math.pure 2008-08-18 23:01:53 UTC (rev 534) +++ pure/trunk/lib/math.pure 2008-08-18 23:38:38 UTC (rev 535) @@ -185,8 +185,8 @@ /* Complex sqrt. */ -sqrt (x+:y) = sqrt r * (cos t +: sin t) - when r = sqrt (x*x+y*y); t = atan2 y x/2 end; +sqrt (x+:y) = sqrt ((r+x)/2) +: sqrt ((r-x)/2) + when r = sqrt (x*x+y*y) end; sqrt (r<:t) = sqrt r <: t/2; // Complex square roots of negative reals. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-18 23:01:45
|
Revision: 534 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=534&view=rev Author: agraef Date: 2008-08-18 23:01:53 +0000 (Mon, 18 Aug 2008) Log Message: ----------- Some reorganization and cosmetic changes. Also added some remarks concerning scoping rules. Modified Paths: -------------- pure/trunk/pure.1.in Modified: pure/trunk/pure.1.in =================================================================== --- pure/trunk/pure.1.in 2008-08-18 17:43:57 UTC (rev 533) +++ pure/trunk/pure.1.in 2008-08-18 23:01:53 UTC (rev 534) @@ -252,12 +252,16 @@ .I "call by name" semantics. .PP +.B Expression syntax. The Pure language provides built-in support for machine integers (32 bit), bigints (implemented using GMP), floating point values (double precision IEEE), character strings (UTF-8 encoded) and generic C pointers (these don't have a syntactic representation in Pure, though, so they need to be created with external C functions). Truth values are encoded as machine integers (as -you might expect, zero denotes ``false'' and any non-zero value ``true''). +you might expect, zero denotes +.B false +and any non-zero value +.BR true ). .PP Expressions consist of the following elements: .TP @@ -398,28 +402,7 @@ \fBwhen\fP). Several functions can be defined in a single \fBwith\fP clause, and the definitions may consist of as many equations as you want. .PP -Like in most modern functional languages, local functions and variables always -use -.IR "lexical binding" , -i.e., the value of a local name is completely determined by the surrounding -program text. -.PP -Syntactically, the equational rules in definitions always look the same (see -RULE SYNTAX below), therefore it is important to note the differences between -\fBwith\fP expressions which define local functions, and the local variable -bindings performed by \fBcase\fP and \fBwhen\fP expressions; the latter are -also called \fIpattern bindings\fP. -.PP -While Haskell lets you do \fIboth\fP function definitions and pattern bindings -in its \fBwhere\fP clauses, in Pure you have to use \fBwith\fP for the former -and \fBwhen\fP for the latter. This is necessary because Pure does not -distinguish between defined functions and constructors, and thus there is no -magic to figure out whether an equation like `foo x = y' by itself is meant as -a definition of a function foo with formal parameter x and return value y, or -a definition binding the local variable x by matching the constructor pattern -foo x against the value y. -.PP -.B Expression syntax. +.B Operators and precedence. Expressions are parsed according to the following precedence rules: Lambda binds most weakly, followed by .BR when , @@ -495,9 +478,9 @@ .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 pattern binding in -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 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. .TP .B Constant bindings: def\fR \fIlhs\fR = \fIrhs\fR; An alternative form of \fBlet\fP which binds constant symbols rather than @@ -512,9 +495,110 @@ causes the given value to be evaluated (and the result to be printed, when running in interactive mode). .PP +.B Scoping rules. +A few remarks about the scope of identifiers and other symbols are in order +here. Like most modern functional languages, Pure uses +.I lexical +or +.I static +binding for local functions and variables. What this means is that the binding +of a local name is completely determined at compile time by the surrounding +program text, and does not change as the program is being executed. In +particular, if a function returns another (anonymous or local) function, the +returned function captures the environment it was created in, i.e., it becomes +a (lexical) +.IR closure . +For instance, the following function, when invoked with a single argument x, +returns another function which adds x to its argument: +.sp +.nf +> foo x = bar \fBwith\fP bar y = x+y \fBend\fP; +> \fBlet\fP f = foo 99; f; +<<closure bar>> +> f 10, f 20; +109,119 +.fi +.PP +This works the same no matter what other bindings of `x' may be in effect when +the closure is invoked: +.sp +.nf +> \fBlet\fP x = 77; f 10, f 20 \fBwhen\fP x = 88 \fBend\fP; +109,119 +.fi +.PP +Global bindings of constant, variable and function symbols work a bit +differently, though. Like many languages which are to be used interactively, +Pure binds global symbols +.IR dynamically , +so that they can be changed easily at any time during an interactive +session. This is mainly a convenience for interactive usage, but works the +same no matter whether the source code is entered interactively or being read +from a script, in order to ensure consistent behaviour between interactive +and batch mode operation. +.PP +So, for instance, you can easily bind a global variable to a new value by just +entering a corresponding +.B let +command: +.sp +.nf +> foo x = c*x; +> foo 99; +c*99 +> \fBlet\fP c = 2; foo 99; +198 +> \fBlet\fP c = 3; foo 99; +297 +.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. +.PP +Similarly, you can also add new equations to an existing function at any time: +.sp +.nf +> fact 0 = 1; +> fact n::int = n*fact (n-1) \fBif\fP n>0; +> fact 10; +3628800 +> fact 10.0; +fact 10.0 +> fact 1.0 = 1.0; +> fact n::double = n*fact (n-1) \fBif\fP n>1; +> fact 10.0; +3628800.0 +> fact 10; +3628800 +.fi +.PP +(In interactive mode, it is even possible to completely erase constant, +variable and function definitions. 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 my well +evolve while the program is being processed. When you evaluate an expression +(to print its value, or to bind it to a variable or constant symbol), 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. Thus you have to make sure that, when you evaluate an expression, +all the functions, constants and variables it uses have already been defined +at this point in the source (no matter whether the source is being entered +interactively, or read from a script). (Note that constant symbols work a bit +differently from variables in that their values are not supposed to change +once they have been defined, and the values will be substituted into other +definitions rather than being looked up at runtime. But you still have to +define them before they can be used.) +.PP .B Examples. -Here are a few examples showing how the above constructs are used (see the -following section for a closer discussion of the rule syntax). +Here are a few examples of simple Pure programs (see the following section for +a closer discussion of the rule syntax). .PP The factorial: .sp @@ -593,14 +677,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 \fBdef\fP constructs for the purpose of performing pattern -bindings (however, for obvious reasons guards are not permitted in \fBwhen\fP, +\fBlet\fP and \fBdef\fP constructs for the purpose of binding variable values +(however, for obvious reasons guards are not permitted in \fBwhen\fP, \fBlet\fP and \fBdef\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 -pattern binding.) +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 `_' @@ -1413,8 +1497,9 @@ > \fBunderride\fP .fi .SH CAVEATS AND NOTES -This section deals with common pitfalls and describes other quirks and -limitations of the current implementation. +This section deals with some common pitfalls, as well as quirks and +limitations of the current implementation, and lists some useful tips and +tricks. .PP .B Debugging. There's no symbolic debugger yet. So @@ -1436,24 +1521,33 @@ .fi .PP This is because the spine of a function application is not available when the -function is called at runtime. ``As'' patterns in pattern bindings are not -affected by this restriction since the entire value to be matched is available -at runtime. For instance: +function is called at runtime. ``As'' patterns in pattern bindings +(\fBcase\fP, \fBwhen\fP) are not affected by this restriction since the entire +value to be matched is available at runtime. For instance: .sp .nf > \fBcase\fP bar 99 \fBof\fP y@(bar x) = y,x+1; \fBend\fP; bar 99,100 .fi .PP -.B Manipulating function applications. -The ``head = function'' rule means that the head symbol f of an application f -x1 ... xn occurring on (or inside) the left-hand side of an equation, pattern -binding, or pattern-matching lambda expression, is always interpreted as a -literal function symbol (not a variable). This implies that you cannot match -the ``function'' component of an application against a variable, at least not -directly. However, an anonymous ``as'' pattern like f@_ will do the trick, -since the anonymous variable is always recognized, even if it occurs as the -head symbol of a function application. +.B Head = function. +``As'' patterns are also a useful device if you need to manipulate function +applications in a generic way. Note that the ``head = function'' rule means +that the head symbol f of an application f x1 ... xn occurring on (or inside) +the left-hand side of an equation, variable binding, or pattern-matching +lambda expression, is always interpreted as a literal function symbol (not a +variable). This implies that you cannot match the ``function'' component of an +application against a variable, at least not directly. An anonymous ``as'' +pattern like f@_ does the trick, however, since the anonymous variable is +always recognized, even if it occurs as the head symbol of a function +application. Here's a little example which demonstrates how you can convert a +function application to a list containing the function and all arguments: +.sp +.nf +> foo x = a [] x \fBwith\fP a xs (x@_ y) = a (y:xs) x; a xs x = x:xs \fBend\fP; +> foo (a b c d); +[a,b,c,d] +.fi .PP This may seem a little awkward, but as a matter of fact the ``head = function'' rule is quite useful since it covers the common cases without @@ -1463,6 +1557,40 @@ the anonymous ``as'' pattern trick is a small price to pay for that convenience. .PP +.B With or when? +A common source of confusion for Haskell renegades is that Pure provides two +different constructs to bind local function and variable symbols, +respectively, namely +.BR with , +which is used for local function definitions, and +.BR when , +which binds local variables. This distinction is necessary because Pure does +not segregate defined functions and constructors, and thus there is no magic +to figure out whether an equation like `foo x = y' by itself is meant as a +definition of a function foo with formal parameter x and return value y, or a +definition binding the local variable x by matching the constructor pattern +foo x against the value y. The +.B with +construct does the former, +.B when +the latter. +.PP +Another pitfall is that, since +.B with +and +.B when +clauses are tacked on to the end of the expression they belong to, they have +to be read in reverse, if you want to figure out what is actually going on +there. Also note that since +.B with +and +.B when +are part of the expression, not the rule syntax, these clauses cannot span +both the right-hand side and the guard of a rule. Usually it's easy to work +around this with conditional and +.B case +expressions, though. +.PP .B Numeric calculations. If possible, you should decorate numeric variables on the left-hand sides of function definitions with the appropriate type tags, like @@ -1483,8 +1611,8 @@ .fi .PP (This obviously becomes unwieldy if you have to deal with several numeric -arguments, however, so in this case it is usually better to just use a -polymorphic rule.) +arguments of different types, however, so in this case it is usually better to +just use a polymorphic rule.) .PP Also note that .B int @@ -1497,10 +1625,12 @@ constant like `0' only matches machine integers, not bigints; for the latter you'll have to use the ``big L'' notation `0L'. .PP -When definining a function in terms of numeric values bound to a symbol, it's -usually better to use a constant symbol rather than a variable for that -purpose, since this will often allow the compiler to generate better code -using constant folding and similar techniques. Example: +.B Working with constants. +When definining a function in terms of constant values which have to be +computed beforehand, it's usually better to use a constant symbol (rather than +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: .sp .nf > \fBextern\fP double atan(double); @@ -1526,109 +1656,50 @@ In this case the code for one of the branches of foo will be completely eliminated, depending on whether your script runs on Windows or not. .PP -.B Global definitions. -Defined constants (symbols bound with \fBdef\fP) are somewhat limited in scope -compared to (\fBlet\fP-bound) variable definitions, since the value bound to -the constant symbol must be usable at compile time, so that it can be -substituted into other definitions. Thus, while there is no \fIa priori\fP -restriction on the computations you can perform to obtain the value of the -constant, the value must not be a pointer object (other than the null -pointer), or an anonymous closure (which also rules out local functions, -because these cannot be referred to by their names at the toplevel), or an -aggregate value containing any such values. +On the other hand, constant definitions are somewhat limited in scope compared +to variable definitions, since the value bound to the constant symbol must be +usable at compile time, so that it can be substituted into other +definitions. Thus, while there is no \fIa priori\fP restriction on the +computations you can perform to obtain the value of the constant, the value +must not be a pointer object (other than the null pointer), or an anonymous +closure (which also rules out local functions, because these cannot be +referred to by their names at the toplevel), or an aggregate value containing +any such values. .PP -Global variables are also more versatile in that they can be redefined at any -time, which will immediately affect all uses of the variable in function -definitions. For instance: +Constant symbols also differ from variables in that they cannot be redefined +(that's their purpose after all) and will only take effect on subsequent +definitions. E.g.: .sp .nf +> \fBdef\fP c = 2; > foo x = c*x; +> \fBlist\fP foo +foo x = 2*x; > foo 99; -c*99 -> \fBlet\fP c = 2; foo 99; 198 -> \fBlet\fP c = 3; foo 99; -297 +> \fBdef\fP c = 3; +<stdin>:5.0-8: symbol 'c' is already defined as a constant .fi .PP -This works pretty much like global variables in imperative languages, but 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. -.PP -Constant symbols work differently in that they cannot be redefined (that's -their purpose after all) and will only take effect on subsequent -definitions. E.g., continuing the previous example: +Well, in fact this not the full truth because in interactive mode it \fIis\fP +possible to redefine constant symbols after all, if the old definition is +first purged with the \fBclear\fP command. However, this won't affect any +other existing definitions: .sp .nf -> \fBdef\fP d = 2; -> bar x = d*x; +> \fBclear\fP c +> \fBdef\fP c = 3; +> bar x = c*x; > \fBlist\fP foo bar -bar x = 2*x; -foo x = c*x; -> bar 99; -198 -> \fBdef\fP d = 3; -<stdin>:9.0-8: symbol 'd' is already defined as a constant +foo x = 2*x; +bar x = 3*x; .fi .PP -Well, in fact it \fIis\fP possible to redefine constant symbols when running -the interpreter in interactive mode, but only after the old definition is -purged with the \fBclear\fP command, and this won't affect any other existing -definitions: -.sp -.nf -> \fBclear\fP d -> \fBdef\fP d = 3; -> \fBlist\fP bar -bar x = 2*x; -.fi -.PP (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.) .PP -.B Local definitions. -In the PURE OVERVIEW section, we briefly mentioned that local function and -variable bindings always use -.I static -a.k.a. -.I lexical scoping -in Pure, which is in line with most other modern FPLs. What this means is that -the bindings of local functions and variables are determined statically by the -surrounding program text, rather than the environment an expression is -executed in. (In contrast, -.I global -functions and variables are always bound -.I dynamically -in Pure, so that they can easily be changed at any time during an interactive -session.) In particular, if a function returns another (anonymous or local) -function, the returned function captures the environment it was created in, -i.e., it becomes a lexical -.IR closure . -.PP -For instance, the following function, when invoked with a single argument x, -creates another function which adds x to its argument: -.sp -.nf -> foo x = bar \fBwith\fP bar y = x+y \fBend\fP; -> \fBlet\fP f = foo 99; f; -<<closure bar>> -> f 10, f 20; -109,119 -.fi -.PP -This works no matter what other bindings of `x' may be in effect when the -closure is invoked: -.sp -.nf -> \fBlet\fP x = 77; f 10, f 20 \fBwhen\fP x = 88 \fBend\fP; -109,119 -.fi -.PP .B External C functions. The interpreter always takes your .B extern This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-18 17:43:49
|
Revision: 533 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=533&view=rev Author: agraef Date: 2008-08-18 17:43:57 +0000 (Mon, 18 Aug 2008) Log Message: ----------- Add missing rules for pow function, reported by Eddie Rucker. Modified Paths: -------------- pure/trunk/lib/math.pure Modified: pure/trunk/lib/math.pure =================================================================== --- pure/trunk/lib/math.pure 2008-08-18 17:30:58 UTC (rev 532) +++ pure/trunk/lib/math.pure 2008-08-18 17:43:57 UTC (rev 533) @@ -468,6 +468,9 @@ = 1L%1L otherwise; pow (x%y) n::double = pow (x/y) n; pow (x%y) (n%m) = pow (x/y) (n/m); +pow x::int (n%m) | +pow x::bigint (n%m) | +pow x::double (n%m) = pow x (n/m); // Negative powers of integers. pow x::int n::int | This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-18 17:30:50
|
Revision: 532 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=532&view=rev Author: agraef Date: 2008-08-18 17:30:58 +0000 (Mon, 18 Aug 2008) Log Message: ----------- Fix glitch in complex sqrt, reported by Eddie Rucker. Modified Paths: -------------- pure/trunk/lib/math.pure Modified: pure/trunk/lib/math.pure =================================================================== --- pure/trunk/lib/math.pure 2008-08-18 11:47:30 UTC (rev 531) +++ pure/trunk/lib/math.pure 2008-08-18 17:30:58 UTC (rev 532) @@ -32,7 +32,7 @@ extern double sqrt(double) = c_sqrt; -sqrt x::double = c_sqrt x if x>=0; +sqrt x::double = c_sqrt x if x>=0; sqrt x::int | sqrt x::bigint = sqrt (double x); /* Exponential function and logarithms. */ @@ -185,7 +185,8 @@ /* Complex sqrt. */ -sqrt (x+:y) = sqrt (x*x+y*y) * (cos (t/2) +: sin (t/2)); +sqrt (x+:y) = sqrt r * (cos t +: sin t) + when r = sqrt (x*x+y*y); t = atan2 y x/2 end; sqrt (r<:t) = sqrt r <: t/2; // Complex square roots of negative reals. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-18 11:47:21
|
Revision: 531 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=531&view=rev Author: agraef Date: 2008-08-18 11:47:30 +0000 (Mon, 18 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-18 10:32:13 UTC (rev 530) +++ pure/trunk/pure.1.in 2008-08-18 11:47:30 UTC (rev 531) @@ -247,8 +247,8 @@ first, i.e., using .I "call by value" semantics. Pure also has a few built-in special forms (most notably, -conditional expressions and the short-circuit logical connectives && and ||) -which take some of their arguments using +conditional expressions, the short-circuit logical connectives && and || and +the sequencing operator $$) which take some of their arguments using .I "call by name" semantics. .PP @@ -265,14 +265,16 @@ The usual C'ish notations for integers (decimal, hexadecimal, octal), floating point values and double-quoted strings are all provided, although the Pure syntax differs in some minor ways, as discussed in the following. First, there -is a special notation for denoting bigints. Note that an integer constant that -is too large to fit into a machine integer will be interpreted as a bigint -automatically. Moreover, as in Python an integer literal immediately followed -by the uppercase letter ``L'' will always be interpreted as a bigint constant, -even if it fits into a machine integer. This notation is also used when -printing bigint constants. Second, character escapes in Pure strings have a -more flexible syntax borrowed from the author's Q language, which provides -notations to specify any Unicode character. In particular, the notation +is a special notation for denoting bigints. Integer constants that are too +large to fit into machine integers will be interpreted as bigints +automatically. Moreover, integer literals immediately followed by the +uppercase letter ``L'' will always be interpreted as bigint constants, even if +they fit into machine integers. This notation is also used when printing +bigint constants. +.sp +Second, character escapes in Pure strings have a more flexible syntax borrowed +from the author's Q language, which provides notations to specify any Unicode +character. In particular, the notation .BR \e\fIn\fP , where \fIn\fP is an integer literal written in decimal (no prefix), hexadecimal (`0x' prefix) or octal (`0' prefix) notation, denotes the Unicode @@ -314,8 +316,8 @@ \fBprefix\fP, \fBpostfix\fP and \fBinfix\fP declarations, which are discussed in section DECLARATIONS. Enclosing an operator in parentheses, such as (+) or (\fBnot\fP), turns it into an ordinary function symbol. Symbols can also be -defined as \fBnullary\fP to denote special constant symbols. See the prelude -for examples. +defined as \fBnullary\fP to denote special constant symbols. See below for +further details. .TP .B Lists and tuples: \fR[x,y,z], x..y, x:xs, x,y,z The necessary constructors to build lists and tuples are actually defined in @@ -325,18 +327,19 @@ the same as x:y:z:[]. Moreover, the prelude also provides an infix `..' operator to denote arithmetic sequences such as 1..10 or 1.0,1.2..3.0. .sp -Pure's tuples are a bit unusual: They are constructed by just ``paring'' +Pure's tuples are a bit unusual: They are constructed by just ``pairing'' things using the `,' operator, for which the empty tuple acts as a neutral -element (i.e., (),x is just x, as is x,()). The pairing operator is -(right-)associative, meaning that x,(y,z) == x,y,z == (x,y),z, which implies -that tuples are completely flat and thus there are no nested tuples (tuples of -tuples). If you need such constructs then you should use lists instead. Also -note that parentheses are generally only used to group expressions and are -\fInot\fP part of the tuple syntax in Pure. There's one exception to this -rule, however, namely that in order to include a tuple in a bracketed list you -have to put it inside parentheses. E.g., [(1,2),3,(4,5)] is a three element -list consisting of the tuple 1,2, the integer 3, and another tuple -4,5. Likewise, [(1,2,3)] is list with a single element, the tuple 1,2,3. +element (i.e., (),x is just x, as is x,()). Pairs always associate to the +right, meaning that x,y,z == x,(y,z) == (x,y),z, where x,(y,z) is the +normalized representation. This implies that tuples are always flat, i.e., +there are no nested tuples (tuples of tuples); if you need such constructs +then you should use lists instead. Also note that parentheses are generally +only used to group expressions and are \fInot\fP part of the tuple syntax in +Pure. There's one exception to this rule, however, namely that in order to +include a tuple in a bracketed list you have to put it inside +parentheses. E.g., [(1,2),3,(4,5)] is a three element list consisting of the +tuple 1,2, the integer 3, and another tuple 4,5. Likewise, [(1,2,3)] is list +with a single element, the tuple 1,2,3. .TP .B List comprehensions: \fR[x,y; x = 1..n; y = 1..m; x<y] Pure also has list comprehensions which generate lists from an expression and @@ -359,10 +362,7 @@ .B Conditional expressions: if\fR\ x\ \fBthen\fR\ y\ \fBelse\fR\ z Evaluates to y or z depending on whether x is ``true'' (i.e., a nonzero integer). An exception is generated if the condition is not an -integer. Conditional expressions are special forms with call-by-name arguments -y and z; only one of the branches is actually evaluated. (The logical -operators && and || are treated in a similar fashion, in order to implement -short-circuit semantics.) +integer. .TP .B Lambdas: \fR\ex\ ->\ y These work pretty much like in Haskell. More than one variable may be bound @@ -398,6 +398,12 @@ \fBwhen\fP). Several functions can be defined in a single \fBwith\fP clause, and the definitions may consist of as many equations as you want. .PP +Like in most modern functional languages, local functions and variables always +use +.IR "lexical binding" , +i.e., the value of a local name is completely determined by the surrounding +program text. +.PP Syntactically, the equational rules in definitions always look the same (see RULE SYNTAX below), therefore it is important to note the differences between \fBwith\fP expressions which define local functions, and the local variable @@ -413,6 +419,7 @@ a definition binding the local variable x by matching the constructor pattern foo x against the value y. .PP +.B Expression syntax. Expressions are parsed according to the following precedence rules: Lambda binds most weakly, followed by .BR when , @@ -427,8 +434,8 @@ application binds stronger than all operators. Parentheses can be used to override default precedences and associativities as usual. .PP -The common operator symbols like +, -, *, / etc. are declared at the beginning -of the prelude, see the +The common operator symbols like +, -, *, / etc. are all declared at the +beginning of the prelude, see the .B prelude.pure script for a list of these. Arithmetic, relational and logical operators usually follow C conventions. However, out of necessity some of Pure's @@ -445,6 +452,31 @@ instead of `&' and `|', because the latter is reserved as a special symbol in rules, see RULE SYNTAX below. .PP +.B Special forms. +As already mentioned, some operators are actually implemented as special +forms. In particular, the conditional expression \fBif\fP x \fBthen\fP y +\fBelse\fP z is a special form with call-by-name arguments y and z; only one +of the branches is actually evaluated, depending on the value of x. Similarly, +the logical connectives && and || evaluate their operands in +.I short-circuit +mode just like in C. Thus, e.g., x&&y immediately becomes false if x evaluates +to false, without ever evaluating y. +.PP +Another important special form is the sequencing operator $$, which evaluates +its left operand, immediately throws the result away and then goes on to +evaluate the right operand which gives the result of the entire +expression. This operator is useful to write imperative-style code such as the +following prompt/input interaction: +.sp +.nf +> using system; +> puts "Enter a number:" $$ scanf "%g"; +Enter a number: +21 +21.0 +.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: @@ -480,6 +512,7 @@ causes the given value to be evaluated (and the result to be printed, when running in interactive mode). .PP +.B Examples. Here are a few examples showing how the above constructs are used (see the following section for a closer discussion of the rule syntax). .PP @@ -488,6 +521,8 @@ .nf fact n = n*fact (n-1) \fBif\fP n>0; = 1 \fBotherwise\fP; + +\fBlet\fP facts = map fact (1..10); facts; .fi .PP The Fibonacci numbers: @@ -500,10 +535,21 @@ \fBend\fP; \fBend\fP; -\fBlet\fP fibs = map fib (1..30); -fibs; +\fBlet\fP fibs = map fib (1..30); fibs; .fi .PP +It is worth noting here that in most cases Pure performs tail call +optimization so that tail-recursive definitions like the following will be +executed in constant stack space (see the CAVEATS AND NOTES section for more +details on this). +.sp +.nf +// tail-recursive factorial using an "accumulating parameter" +fact n = loop 1 n \fBwith\fP + loop p n = \fBif\fP n>0 \fBthen\fP loop (p*n) (n-1) \fBelse\fP p; +\fBend\fP; +.fi +.PP A little list comprehension example (Erathosthenes' classical prime sieve): .sp .nf @@ -1377,13 +1423,6 @@ .B system standard library module) should be your friend. ;-) .PP -.B Special forms. -Special forms are recognized at compile time only. Thus the catch function as -well as the short-circuit logical connectives && and || are only treated as -special forms in direct (saturated) calls. They can still be used if you pass -them around as function values or partial applications, but in this case they -lose all their special call-by-name argument processing. -.PP .B ``As'' patterns. In the current implementation, ``as'' patterns cannot be placed on the ``spine'' of a function definition. Thus rules like the following, which have @@ -1424,7 +1463,70 @@ the anonymous ``as'' pattern trick is a small price to pay for that convenience. .PP -.B Constant and variable definitions. +.B Numeric calculations. +If possible, you should decorate numeric variables on the left-hand sides of +function definitions with the appropriate type tags, like +.B ::int +or +.BR ::double . +This often helps the compiler to generate better code and makes your programs +run faster. The `|' syntax makes it easy to add the necessary specializations +of existing rules to your program. E.g., taking the polymorphic implementation +of the factorial as an example, you only have to add a left-hand side with the +appropriate type tag to make that definition go as fast as possible for the +special case of machine integers: +.sp +.nf +fact n::int | +fact n = n*fact(n-1) \fBif\fP n>0; + = 1 \fBotherwise\fP; +.fi +.PP +(This obviously becomes unwieldy if you have to deal with several numeric +arguments, however, so in this case it is usually better to just use a +polymorphic rule.) +.PP +Also note that +.B int +(the machine integers) and +.B bigint +(the GMP ``big'' integers) are really different kinds of objects, and thus if +you want to define a function operating on both kinds of integers, you'll also +have to provide equations for both. This also applies to equations matching +against constant values of these types; in particular, a small integer +constant like `0' only matches machine integers, not bigints; for the latter +you'll have to use the ``big L'' notation `0L'. +.PP +When definining a function in terms of numeric values bound to a symbol, it's +usually better to use a constant symbol rather than a variable 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); +> \fBdef\fP pi = 4*atan 1.0; +> foo x = 2*pi*x; +> \fBlist\fP foo +foo x = 2*3.14159265358979*x; +.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.) +.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: +.sp +.nf +> \fBdef\fP running_on_windows = index sysinfo "mingw32" >= 0; +> foo x = something x \fBif\fP running_on_windows; +> = something_else x \fBotherwise\fP; +.fi +.PP +In this case the code for one of the branches of foo will be completely +eliminated, depending on whether your script runs on Windows or not. +.PP +.B Global definitions. Defined constants (symbols bound with \fBdef\fP) are somewhat limited in scope compared to (\fBlet\fP-bound) variable definitions, since the value bound to the constant symbol must be usable at compile time, so that it can be @@ -1489,69 +1591,44 @@ an existing constant or variable as a different kind of symbol. The same also holds if a symbol is currently defined as a function.) .PP -.B Numeric calculations. -If possible, you should decorate numeric variables on the left-hand sides of -function definitions with the appropriate type tags, like -.B ::int -or -.BR ::double . -This often helps the compiler to generate better code and makes your programs -run faster. The `|' syntax makes it easy to add the necessary specializations -of existing rules to your program. E.g., taking the polymorphic implementation -of the factorial as an example, you only have to add a left-hand side with the -appropriate type tag to make that definition go as fast as possible for the -special case of machine integers: -.sp -.nf -fact n::int | -fact n = n*fact(n-1) \fBif\fP n>0; - = 1 \fBotherwise\fP; -.fi +.B Local definitions. +In the PURE OVERVIEW section, we briefly mentioned that local function and +variable bindings always use +.I static +a.k.a. +.I lexical scoping +in Pure, which is in line with most other modern FPLs. What this means is that +the bindings of local functions and variables are determined statically by the +surrounding program text, rather than the environment an expression is +executed in. (In contrast, +.I global +functions and variables are always bound +.I dynamically +in Pure, so that they can easily be changed at any time during an interactive +session.) In particular, if a function returns another (anonymous or local) +function, the returned function captures the environment it was created in, +i.e., it becomes a lexical +.IR closure . .PP -(This obviously becomes unwieldy if you have to deal with several numeric -arguments, however, so in this case it is usually better to just use a -polymorphic rule.) -.PP -Also note that -.B int -(the machine integers) and -.B bigint -(the GMP ``big'' integers) are really different kinds of objects, and thus if -you want to define a function operating on both kinds of integers, you'll also -have to provide equations for both. This also applies to equations matching -against constant values of these types; in particular, a small integer -constant like `0' only matches machine integers, not bigints; for the latter -you'll have to use the ``big L'' notation `0L'. -.PP -When definining a function in terms of numeric values bound to a symbol, it's -usually better to use a constant symbol rather than a variable for that -purpose, since this will often allow the compiler to generate better code -using constant folding and similar techniques. Example: +For instance, the following function, when invoked with a single argument x, +creates another function which adds x to its argument: .sp .nf -> \fBextern\fP double atan(double); -> \fBdef\fP pi = 4*atan 1.0; -> foo x = 2*pi*x; -> \fBlist\fP foo -foo x = 2*3.14159265358979*x; +> foo x = bar \fBwith\fP bar y = x+y \fBend\fP; +> \fBlet\fP f = foo 99; f; +<<closure bar>> +> f 10, f 20; +109,119 .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.) -.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: +This works no matter what other bindings of `x' may be in effect when the +closure is invoked: .sp .nf -> \fBdef\fP running_on_windows = index sysinfo "mingw32" >= 0; -> foo x = something x if running_on_windows; -> = something_else x otherwise; +> \fBlet\fP x = 77; f 10, f 20 \fBwhen\fP x = 88 \fBend\fP; +109,119 .fi .PP -In this case the code for one of the branches of foo will be completely -eliminated, depending on whether your script runs on Windows or not. -.PP .B External C functions. The interpreter always takes your .B extern @@ -1569,6 +1646,13 @@ routines and data structures which do all the checks necessary to ensure that only the right kind of data is passed to C routines. .PP +.B Special forms. +Special forms are recognized at compile time only. Thus the catch function as +well as the logical connectives && and || and the sequencing operator $$ are +only treated as special forms in direct (saturated) calls. They can still be +used if you pass them around as function values or partial applications, but +in this case they lose all their special call-by-name argument processing. +.PP .B Stack size and tail recursion. Pure programs may need a considerable amount of stack space to handle recursive function calls, and the interpreter itself also takes its toll. So @@ -1597,26 +1681,30 @@ loop = loop; .fi .PP -In the current implementation, a tail call will be eliminated \fIonly\fP if -the call is done \fIdirectly\fP, i.e., through an explicit call, not through a -(global or local) function variable. Otherwise the call will be handled by the -runtime system which is written in C and can't do proper tail calls because C -can't (at least not in a portable way). This also affects mutually recursive -global function calls, since there the calls are handled in an indirect way, -too, through an anonymous global variable. (This is done so that a global -function definition can be changed at any time during an interactive session, -without having to recompile the entire program.) However, mutual tail -recursion does work with \fIlocal\fP functions, so it's easy to work around -this limitation. -.PP -Scheme programmers should note that conditional expressions -(\fBif\fP-\fBthen\fP-\fBelse\fP) are tail-recursive in both branches, just -like in Scheme, while the logical operators && and || are +This also works if your definition involves function parameters, guards and +multiple equations, of course. Moreover, conditional expressions +(\fBif\fP-\fBthen\fP-\fBelse\fP) are tail-recursive in both branches, and the +sequence operator $$ is tail-recursive in its second operand. Note, however, +that the logical operators && and || are .I not -tail-recursive. This is because in Pure the logical operators always return a -proper truth value (0 or 1) which wouldn't be possible with tail call -semantics. +tail-recursive in Pure, because they are required to +.I always +yield a proper truth value (0 or 1), which wouldn't be possible with tail call +semantics. (The rationale behind this design decision is that it allows the +compiler to generate much better code for logical expressions.) .PP +There is one additional restriction in the current implementation, namely that +a tail call will be eliminated \fIonly\fP if the call is done \fIdirectly\fP, +i.e., through an explicit call, not through a (global or local) function +variable. Otherwise the call will be handled by the runtime system which is +written in C and can't do proper tail calls because C can't (at least not in a +portable way). This also affects mutually recursive global function calls, +since there the calls are handled in an indirect way, too, through an +anonymous global variable. (This is done so that a global function definition +can be changed at any time during an interactive session, without having to +recompile the entire program.) However, mutual tail recursion does work with +\fIlocal\fP functions, so it's easy to work around this limitation. +.PP .B Handling of asynchronous signals. As described in section EXCEPTION HANDLING, signals delivered to the process can be caught and handled with Pure's exception handling facilities. Like @@ -1627,24 +1715,33 @@ to your loop to make it interruptible. For instance: .sp .nf -loop = loop \fBwhen\fP _ = check \fBend\fP; +loop = check $$ loop; check = (); .fi .PP -(Of course, the `check' function can actually do any processing required by -your application. In that case you'd probably want the `loop' function to -carry around some ``state'' argument which is modified by the `check' -routine.) To handle signals while the above loop is executing, add an -exception handler like the following: +To handle signals while the above loop is executing, you can add an exception +handler like the following: .sp .nf -loop = loop \fBwhen\fP _ = catch handle check \fBend\fP +loop = catch handle check $$ loop \fBwith\fP handle (signal k) = catch handle (...) \fBend\fP; .fi .PP -By these means the entire loop remains tail-recursive. (Note the `catch -handle' around the signal processing code which is needed for safety because -another signal may arrive while the signal handler is being executed.) +(Note the `catch handle' around the signal processing code which is needed for +safety because another signal may arrive while the signal handler is being +executed.) +.PP +Of course, in a real application the `check' function would most likely have +to do some actual processing, too. In that case you'd probably want the `loop' +function to carry around some ``state'' argument to be processed by the +`check' routine, which then returns an updated state value for the next +iteration. This can be implemented as follows: +.sp +.nf +loop x = loop (catch handle (check x)) +\fBwith\fP handle (signal k) = catch handle (...) \fBend\fP; +check x = ...; +.fi .SH FILES .TP .B ~/.pure_history @@ -1664,21 +1761,17 @@ time. .TP .B PURE_INCLUDE -Additional directories to be searched for included scripts (default: -none). Uses the same colon-separated format as the -.B PATH -variable. +Additional directories (in colon-separated format) to be searched for included +scripts. .TP .B PURE_LIBRARY -Additional directories to be searched for dynamic libraries (default: -none). Uses the same colon-separated format as the -.B PATH -variable. +Additional directories (in colon-separated format) to be searched for dynamic +libraries. .TP .B PURE_MORE Shell command to be used for paging through output of the .B list -command, when the interpreter runs in interactive mode (default: none). +command, when the interpreter runs in interactive mode. .TP .B PURE_PS Command prompt used in the interactive command loop (">\ " by default). This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-18 10:32:03
|
Revision: 530 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=530&view=rev Author: agraef Date: 2008-08-18 10:32:13 +0000 (Mon, 18 Aug 2008) Log Message: ----------- Add fflush function. Modified Paths: -------------- pure/trunk/lib/system.pure Modified: pure/trunk/lib/system.pure =================================================================== --- pure/trunk/lib/system.pure 2008-08-18 07:43:01 UTC (rev 529) +++ pure/trunk/lib/system.pure 2008-08-18 10:32:13 UTC (rev 530) @@ -127,7 +127,7 @@ extern FILE* fopen(char* name, char* mode); extern FILE* popen(char* cmd, char* mode); -extern int fclose(FILE* fp), int pclose(FILE* fp); +extern int fflush(FILE* fp), int fclose(FILE* fp), int pclose(FILE* fp); extern char* fgets(void* buf, int size, FILE* fp) = c_fgets; extern char* gets(void* buf) = c_gets; extern int fputs(char* s, FILE* fp), int puts(char* s); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-18 07:42:51
|
Revision: 529 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=529&view=rev Author: agraef Date: 2008-08-18 07:43:01 +0000 (Mon, 18 Aug 2008) Log Message: ----------- Cosmetic changes. Modified Paths: -------------- pure/trunk/examples/recursive.pure pure/trunk/examples/signal.pure Modified: pure/trunk/examples/recursive.pure =================================================================== --- pure/trunk/examples/recursive.pure 2008-08-18 07:26:36 UTC (rev 528) +++ pure/trunk/examples/recursive.pure 2008-08-18 07:43:01 UTC (rev 529) @@ -39,10 +39,10 @@ using system; main n::int -= printf "Ack(3,%d): %d\n" (n, ack 3 n), - printf "Fib(%.1f): %.1f\n" (27.0+n, fib (27.0+n)), - printf "Tak(%d,%d,%d): %d\n" (m*3, m*2, m, tak (m*3) (m*2) m), - printf "Fib(3): %d\n" (fib 3), += printf "Ack(3,%d): %d\n" (n, ack 3 n) $$ + printf "Fib(%.1f): %.1f\n" (27.0+n, fib (27.0+n)) $$ + printf "Tak(%d,%d,%d): %d\n" (m*3, m*2, m, tak (m*3) (m*2) m) $$ + printf "Fib(3): %d\n" (fib 3) $$ printf "Tak(3.0,2.0,1.0): %.1f\n" (tak 3.0 2.0 1.0) when m = n-1 end; Modified: pure/trunk/examples/signal.pure =================================================================== --- pure/trunk/examples/signal.pure 2008-08-18 07:26:36 UTC (rev 528) +++ pure/trunk/examples/signal.pure 2008-08-18 07:43:01 UTC (rev 529) @@ -15,10 +15,9 @@ /* Running this function enters an endless loop reporting all signals delivered to the process. */ -test = printf "Running as pid %d, try to kill me!\n" getpid, loop; +test = printf "Running as pid %d, try to kill me!\n" getpid $$ loop; -loop = loop when _ = catch sig check end -with +loop = catch sig check $$ loop with sig (signal k) = printf "Hey, I got signal %d.\n" k; end; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-18 07:26:26
|
Revision: 528 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=528&view=rev Author: agraef Date: 2008-08-18 07:26:36 +0000 (Mon, 18 Aug 2008) Log Message: ----------- Cosmetic changes. Modified Paths: -------------- pure/trunk/lib/system.pure Modified: pure/trunk/lib/system.pure =================================================================== --- pure/trunk/lib/system.pure 2008-08-18 07:02:41 UTC (rev 527) +++ pure/trunk/lib/system.pure 2008-08-18 07:26:36 UTC (rev 528) @@ -146,7 +146,7 @@ check s = return s if null t; = return t otherwise; done s::string = feof f || ferror f || not null s && last s == "\n"; - return x = x when _ = free buf end; + return x = free buf $$ x; end; end; @@ -161,7 +161,7 @@ = read_a_file f buf (t+s) otherwise; check s = return s if null t; = return t otherwise; - return x = x when _ = free buf end; + return x = free buf $$ x; end; end; @@ -169,7 +169,7 @@ directly, the runtime provides us with some functions which only process a single argument at a time. Our wrapper functions take or return a tuple of values, and check these against the format specifiers. Only simple formats - derived from %dioux, %efg, %s and %p are supported right now. */ + derived from %cdioux, %efg, %s and %p are supported right now. */ /* printf/fprintf: Normally, these return the result of the underlying C routines (number of characters written, or negative on error). However, in @@ -263,17 +263,17 @@ "g", x::double = pure_snprintf_double buf size s x; "s", x::string = pure_snprintf_string buf size s x; "p", x::string | "p", x::pointer = pure_snprintf_pointer buf size s x; - _ = throw (printf_value_error s arg) when _ = free buf end; + _ = free buf $$ throw (printf_value_error s arg); end; u = if res>=0 then u + cstring buf - else (throw printf_error res when _ = free buf end); + else free buf $$ throw printf_error res; end; do_sprintf (u,args) (printf_format_str s) = u, args when size = #s+1000; buf = check_buf (malloc size); res = pure_snprintf buf size s; u = if res>=0 then u + cstring buf - else (throw printf_error res when _ = free buf end); + else free buf $$ throw printf_error res; end; do_sprintf (u,_) _ = throw printf_arg_error; check_buf buf = throw printf_malloc_error if null buf; @@ -325,7 +325,7 @@ // Note: In difference to C scanf, the return value is the number of read // characters here, with -1 denoting an error condition. res = if res>=0 then res - else (throw (scanf_error ret) when _ = free buf end); + else free buf $$ throw (scanf_error ret); val = case t of "n" = nread+get_int buf; "d" = get_int buf; @@ -416,7 +416,7 @@ // Note: In difference to C scanf, the return value is the number of read // characters here, with -1 denoting an error condition. res = if res>=0 then res - else (throw (scanf_error ret) when _ = free buf end); + else free buf $$ throw (scanf_error ret); val = case t of "n" = nread+get_int buf; "d" = get_int buf; @@ -484,7 +484,7 @@ when globptr = calloc 1 GLOB_SIZE; result = c_glob pat flags (pointer 0) globptr; result = if result==0 then globlist globptr else result; - _ = globfree globptr, free globptr; + _ = globfree globptr $$ free globptr; end; /* POSIX regex matching (regcomp and regexec). The C functions have a somewhat @@ -559,7 +559,7 @@ when result = regcomp regptr pat cflags; result = if result==0 then match else regerr result (decode result); - _ = regfree regptr, free regptr; + _ = regfree regptr $$ free regptr; end with match = result when n, matches = regmatches regptr cflags; @@ -643,7 +643,7 @@ end when n, matches = regmatches regptr cflags end) else regerr result (decode result); - _ = regfree regptr, free regptr; + _ = regfree regptr $$ free regptr; end with decode n::int = cstring buf when size = regerror n regptr (pointer 0) 0; @@ -684,7 +684,7 @@ end when n, matches = regmatches regptr cflags end) else regerr result (decode result); - _ = regfree regptr, free regptr; + _ = regfree regptr $$ free regptr; end with decode n::int = cstring buf when size = regerror n regptr (pointer 0) 0; @@ -722,7 +722,7 @@ end when n, matches = regmatches regptr cflags end) else regerr result (decode result); - _ = regfree regptr, free regptr; + _ = regfree regptr $$ free regptr; end with decode n::int = cstring buf when size = regerror n regptr (pointer 0) 0; @@ -754,7 +754,7 @@ end when n, matches = regmatches regptr cflags end) else regerr result (decode result); - _ = regfree regptr, free regptr; + _ = regfree regptr $$ free regptr; end with decode n::int = cstring buf when size = regerror n regptr (pointer 0) 0; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-18 07:02:34
|
Revision: 527 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=527&view=rev Author: agraef Date: 2008-08-18 07:02:41 +0000 (Mon, 18 Aug 2008) Log Message: ----------- Add tail-recursive sequence operator. Modified Paths: -------------- pure/trunk/ChangeLog pure/trunk/interpreter.cc pure/trunk/lib/prelude.pure pure/trunk/lib/primitives.pure pure/trunk/symtable.cc pure/trunk/symtable.hh Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-08-17 22:56:36 UTC (rev 526) +++ pure/trunk/ChangeLog 2008-08-18 07:02:41 UTC (rev 527) @@ -1,3 +1,11 @@ +2008-08-18 Albert Graef <Dr....@t-...> + + * interpreter.cc (codegen): Generate tail-recursive code for + sequence operator. + + * lib/prelude.pure, lib/primitives.pure: Definition of $$ sequence + operator. + 2008-08-17 Albert Graef <Dr....@t-...> * pure.cc, interpreter.cc/h, runtime.cc: Overhaul of the script Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-08-17 22:56:36 UTC (rev 526) +++ pure/trunk/interpreter.cc 2008-08-18 07:02:41 UTC (rev 527) @@ -4233,7 +4233,12 @@ (v = funcall(e, n, x))) // recursive call to a global function return v; - else if (n == 2 && f.tag() == symtab.catch_sym().f) { + else if (n == 2 && f.ftag() == symtab.seq_sym().f) { + // sequence operator + Value *u = codegen(x.xval1().xval2()); + act_builder().CreateCall(module->getFunction("pure_freenew"), u); + return codegen(x.xval2()); + } else if (n == 2 && f.tag() == symtab.catch_sym().f) { // catch an exception; create a little anonymous closure to be called // through pure_catch() expr h = x.xval1().xval2(), y = x.xval2(); Modified: pure/trunk/lib/prelude.pure =================================================================== --- pure/trunk/lib/prelude.pure 2008-08-17 22:56:36 UTC (rev 526) +++ pure/trunk/lib/prelude.pure 2008-08-18 07:02:41 UTC (rev 527) @@ -45,6 +45,7 @@ /* Operators. Note that the parser will automagically give unary minus the same precedence level as the corresponding binary operator. */ +infixl 0 $$ ; // sequence operator infixr 0 $ ; // right-associative application infixr 1 , ; // pair (tuple) infix 2 => ; // mapsto constructor Modified: pure/trunk/lib/primitives.pure =================================================================== --- pure/trunk/lib/primitives.pure 2008-08-17 22:56:36 UTC (rev 526) +++ pure/trunk/lib/primitives.pure 2008-08-18 07:02:41 UTC (rev 527) @@ -201,12 +201,14 @@ x::double==y::int = x==y; x::double!=y::int = x!=y; -/* Logical connectives. Please note that these will be short-circuited only as - explicit calls! But we still want them to work if they are applied - partially, so we add these rules here. */ +/* Logical connectives and sequences. Please note that these enjoy + call-by-name and short-circuit evaluation only as explicit calls! But we + still want them to work if they are applied partially, so we add these + rules here. */ x::int&&y::int = x&&y; x::int||y::int = x||y; +x$$y = y; /* Bigint arithmetic. */ Modified: pure/trunk/symtable.cc =================================================================== --- pure/trunk/symtable.cc 2008-08-17 22:56:36 UTC (rev 526) +++ pure/trunk/symtable.cc 2008-08-18 07:02:41 UTC (rev 527) @@ -120,6 +120,15 @@ return sym(",", 1, infixr); } +symbol& symtable::seq_sym() +{ + symbol *_sym = lookup("$$"); + if (_sym) + return *_sym; + else + return sym("$$", 0, infixl); +} + symbol& symtable::not_sym() { symbol *_sym = lookup("not"); Modified: pure/trunk/symtable.hh =================================================================== --- pure/trunk/symtable.hh 2008-08-17 22:56:36 UTC (rev 526) +++ pure/trunk/symtable.hh 2008-08-18 07:02:41 UTC (rev 527) @@ -49,6 +49,7 @@ symbol& cons_sym(); symbol& void_sym(); symbol& pair_sym(); + symbol& seq_sym(); symbol& neg_sym() { return sym("neg"); } symbol& not_sym(); symbol& bitnot_sym(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-17 22:56:27
|
Revision: 526 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=526&view=rev Author: agraef Date: 2008-08-17 22:56:36 +0000 (Sun, 17 Aug 2008) Log Message: ----------- Fix up help message of the interpreter. Modified Paths: -------------- pure/trunk/pure.cc Modified: pure/trunk/pure.cc =================================================================== --- pure/trunk/pure.cc 2008-08-17 22:55:53 UTC (rev 525) +++ pure/trunk/pure.cc 2008-08-17 22:56:36 UTC (rev 526) @@ -32,8 +32,9 @@ #define COPYRIGHT "Copyright (c) 2008 by Albert Graef" #define USAGE \ -"Usage: pure [-h] [-i] [-n] [-q] [-v[level]] [script ...] [-- args ...]\n\ - pure [-h] [-i] [-n] [-q] [-v[level]] -x script [args ...]\n\ +"Usage: pure [options ...] [script ...] [-- args ...]\n\ + pure [options ...] -x script [args ...]\n\ +Options:\n\ -h: Print this message and exit.\n\ -i: Force interactive mode (read commands from stdin).\n\ -I: Add directory to search for included source files.\n\ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-17 22:55:43
|
Revision: 525 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=525&view=rev Author: agraef Date: 2008-08-17 22:55:53 +0000 (Sun, 17 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-17 21:10:10 UTC (rev 524) +++ pure/trunk/pure.1.in 2008-08-17 22:55:53 UTC (rev 525) @@ -2,9 +2,9 @@ .SH NAME pure \- the Pure interpreter .SH SYNOPSIS -\fBpure\fP [-h] [-i] [-n] [-q] [-v[\fIlevel\fP]] [\fIscript\fP ...] [-- \fIargs\fP ...] +\fBpure\fP [\fIoptions\fP ...] [\fIscript\fP ...] [-- \fIargs\fP ...] .br -\fBpure\fP [-h] [-i] [-n] [-q] [-v[\fIlevel\fP]] -x \fIscript\fP [\fIargs\fP ...] +\fBpure\fP [\fIoptions\fP ...] -x \fIscript\fP [\fIargs\fP ...] .SH OPTIONS .TP .B -h @@ -13,13 +13,19 @@ .B -i Force interactive mode (read commands from stdin). .TP +.BI -I directory +Add a directory to be searched for included source scripts. +.TP +.BI -L directory +Add a directory to be searched for dynamic libraries. +.TP .B -n Suppress automatic inclusion of the prelude. .TP .B -q Quiet startup (suppresses sign-on message in interactive mode). .TP -.B -v +.BR -v [\fIlevel\fP] Set verbosity level. See below for details. .TP .B -x @@ -59,8 +65,8 @@ read using .BR readline (3) (providing completion for all commands listed in section INTERACTIVE USAGE -below, as well as for global function and variable symbols) and, when exiting -the interpreter, the command history is stored in +below, as well as for symbols defined in the running program) and, when +exiting the interpreter, the command history is stored in .BR ~/.pure_history , from where it is restored the next time you run the interpreter. .PP @@ -106,13 +112,22 @@ .B prelude.pure is loaded by the interpreter prior to any other other definitions, unless the .B -n -option is specified. The prelude as well as other source scripts specified -with a relative pathname are first searched for in the current directory and -then in the directory specified with the +option is specified. The prelude is searched for in the directory specified +with the .B PURELIB environment variable. If the .B PURELIB -variable is not set, a system-specific default is used. +variable is not set, a system-specific default is used. Other source scripts +specified on the command line are searched for in the current directory if a +relative pathname is given. In addition, the executed program may load other +scripts and libraries via a +.B using +declaration in the source, which are searched for in a number of locations, +including the directories named with the +.B -I +and +.B -L +options; see the sections DECLARATIONS and C INTERFACE below for details. .PP The .B -v @@ -313,15 +328,15 @@ Pure's tuples are a bit unusual: They are constructed by just ``paring'' things using the `,' operator, for which the empty tuple acts as a neutral element (i.e., (),x is just x, as is x,()). The pairing operator is -associative, which implies that tuples are completely flat (i.e., x,(y,z) is -just x,y,z, as is (x,y),z). This means that there are no nested tuples (tuples -of tuples), if you need such constructs then you should use lists -instead. Also note that parentheses are generally only used to group -expressions and are \fInot\fP part of the tuple syntax in Pure. There's one -exception to this rule, however, namely that in order to include a tuple in a -bracketed list you have to put it inside parentheses. E.g., [(1,2),3,(4,5)] is -a three element list consisting of the tuple 1,2, the integer 3, and another -tuple 4,5. Likewise, [(1,2,3)] is list with a single element, the tuple 1,2,3. +(right-)associative, meaning that x,(y,z) == x,y,z == (x,y),z, which implies +that tuples are completely flat and thus there are no nested tuples (tuples of +tuples). If you need such constructs then you should use lists instead. Also +note that parentheses are generally only used to group expressions and are +\fInot\fP part of the tuple syntax in Pure. There's one exception to this +rule, however, namely that in order to include a tuple in a bracketed list you +have to put it inside parentheses. E.g., [(1,2),3,(4,5)] is a three element +list consisting of the tuple 1,2, the integer 3, and another tuple +4,5. Likewise, [(1,2,3)] is list with a single element, the tuple 1,2,3. .TP .B List comprehensions: \fR[x,y; x = 1..n; y = 1..m; x<y] Pure also has list comprehensions which generate lists from an expression and @@ -692,22 +707,28 @@ filename (possibly including path and/or filename extension), or as an identifier. In the latter case, the .B .pure -filename extension is added automatically. In both cases, the script is -searched for first in the directory of the script containing the +filename extension is added automatically. In both cases, the interpreter +performs a search to locate the script, unless an absolute pathname was +given. It first searches the directory of the script containing the .B using -clause, then the directory named by the +clause (or the current working directory if the clause was read from standard +input, as is the case, e.g., in an interactive session), then the directories +named in +.B -I +options on the command line (in the given order), then the colon-separated +list of directories in the +.B PURE_INCLUDE +environment variable, and finally the directory named by the .B PURELIB -environment variable, and finally in the current working directory. This is -different from the standard search order used for scripts specified on the -command line, where the current directory is searched prior to the -.B PURELIB -directory. The search order employed here lets you install a script into any -directory, along with any other required non-library scripts, and run the -script from there. (Note that this will only work if the +environment variable. Note that the current working directory is \fInot\fP +searched by default (unless the .B using -clause is contained in a script file, but not if the clause is read from -standard input or entered interactively. In the latter case the normal search -order is used.) +clause is read from standard input), but of course you can force this by +adding the option +.B -I. +to the command line, or by including `.' in the +.B PURE_INCLUDE +variable. .sp For the purpose of comparing and loading scripts, the interpreter always uses the canonicalized full pathname of the script, following symbolic links to the @@ -724,8 +745,8 @@ In this case the script search performed in .B using clauses will use the real script directory and thus other required scripts can -be located in the script directory as usual. This is the recommended practice -for installing standalone Pure applications in source form which are to be run +be located in the script directory. This is the recommended practice for +installing standalone Pure applications in source form which are to be run directly from the shell. .PP Note that the @@ -980,11 +1001,23 @@ .B extern declarations. .PP -Shared libraries opened with \fBusing\fP clauses are searched for on the usual -system linker path (\fBLD_LIBRARY_PATH\fP on Linux). The necessary filename -suffix (e.g., \fB.so\fP on Linux or \fB.dll\fP on Windows) will also be -supplied automatically. You can also specify a full pathname for the library -if you prefer that. If a library file cannot be found, or if an +Shared libraries opened with \fBusing\fP clauses are searched for in the same +way as source scripts (see section DECLARATIONS above), using the +.B -L +option and the +.B PURE_LIBRARY +environment variable in place of +.B -I +and +.BR PURE_INCLUDE . +If the library isn't found by these means, the interpreter will also consider +other platform-specific locations searched by the dynamic linker, such as the +system library directories and +.B LD_LIBRARY_PATH +on Linux. The necessary filename suffix (e.g., \fB.so\fP on Linux or +\fB.dll\fP on Windows) will be supplied automatically when needed. Of course +you can also specify a full pathname for the library if you prefer that. If a +library file cannot be found, or if an .B extern declaration names a function symbol which cannot be resolved, an appropriate error message is printed. @@ -1071,9 +1104,9 @@ Loads the given script file and adds its definitions to the current environment. This works more or less like a .B using -clause, but uses the standard search order and loads the script -``anonymously'', as if the contents of the script had been typed at the -command prompt. That is, +clause, but only searches for the script in the current directory and loads +the script ``anonymously'', as if the contents of the script had been typed at +the command prompt. That is, .B run doesn't check whether the script is being used already and it puts the definitions on the current temporary level (so that @@ -1625,11 +1658,23 @@ .SH ENVIRONMENT .TP .B PURELIB -Directory to search for source files, including the prelude. If +Directory to search for library scripts, including the prelude. If .B PURELIB is not set, it defaults to some default location specified at installation time. .TP +.B PURE_INCLUDE +Additional directories to be searched for included scripts (default: +none). Uses the same colon-separated format as the +.B PATH +variable. +.TP +.B PURE_LIBRARY +Additional directories to be searched for dynamic libraries (default: +none). Uses the same colon-separated format as the +.B PATH +variable. +.TP .B PURE_MORE Shell command to be used for paging through output of the .B list This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-17 21:10:01
|
Revision: 524 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=524&view=rev Author: agraef Date: 2008-08-17 21:10:10 +0000 (Sun, 17 Aug 2008) Log Message: ----------- Overhaul of the script and library search algorithms. Modified Paths: -------------- pure/trunk/ChangeLog pure/trunk/interpreter.cc pure/trunk/interpreter.hh pure/trunk/pure.cc pure/trunk/runtime.cc Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-08-17 20:50:56 UTC (rev 523) +++ pure/trunk/ChangeLog 2008-08-17 21:10:10 UTC (rev 524) @@ -1,5 +1,61 @@ 2008-08-17 Albert Graef <Dr....@t-...> + * pure.cc, interpreter.cc/h, runtime.cc: Overhaul of the script + and library search algorithms. + + The prelude is now *always* searched for in PURELIB only, to + prevent code injection issues. Thus to use a custom prelude you'll + have to set the PURELIB environment variable accordingly, or + employ the '-n' option and explicitly specify the prelude on the + command line. + + Scripts specified on the command line or with the 'run' command + will *only* be searched for in the current directory. + + In addition to the PURELIB environment variable, new -I/-L command + line options and PURE_INCLUDE/PURE_LIBRARY environment variables + are now available to specify additional directories to search for + source files and dynamic libraries specified using relative + pathnames in 'using' clauses. + + For source scripts opened with a 'using' clause, the interpreter + searches the following directories in the given order: + + - the directory of the script containing the 'using' clause (or + the current working directory if the 'using' clause is read from + standard input), + + - directories specified with -I, in the order in which they are + specified on the command line, + + - directories specified in colon-separated format in the + PURE_INCLUDE variable, in the order in which they are specified, + + - the PURELIB directory. + + Similarly, dynamic libraries are searched for in: + + - the directory of the script containing the 'using' clause (or + the current working directory if the 'using' clause is read from + standard input), + + - directories specified with -L, in the order in which they are + specified on the command line, + + - directories specified in colon-separated format in the + PURE_LIBRARY variable, in the order in which they are specified, + + - the PURELIB directory, + + - other platform-specific locations searched by the dynamic + linker, such as system library directories and LD_LIBRARY_PATH on + Linux. + + Note that in either case the current working directory is *not* + searched by default (unless the 'using' clause is read from + standard input), but of course you can force this by adding '.' to + the corresponding search path. + * parser.yy, printer.cc et al: Revised list-of-tuples syntax. In order to include a tuple in a proper list value you can simply put the tuple inside parentheses now. Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-08-17 20:50:56 UTC (rev 523) +++ pure/trunk/interpreter.cc 2008-08-17 21:10:10 UTC (rev 524) @@ -58,7 +58,7 @@ interpreter::interpreter() : verbose(0), interactive(false), ttymode(false), override(false), stats(false), temp(0), - ps("> "), lib(""), histfile("/.pure_history"), modname("pure"), + ps("> "), libdir(""), histfile("/.pure_history"), modname("pure"), nerrs(0), source_s(0), result(0), mem(0), exps(0), tmps(0), module(0), JIT(0), FPM(0), fptr(0) { @@ -434,7 +434,8 @@ #define BUFSIZE 1024 static string searchdir(const string& srcdir, const string& libdir, - const string& script) + const list<string>& include_dirs, + const string& script, bool search = true) { char cwd[BUFSIZE]; if (script.empty()) @@ -449,23 +450,23 @@ string fname; if (script[0] != '/') { // resolve relative pathname - if (srcdir.empty()) { + if (!search) { fname = workdir+script; if (chkfile(fname)) goto found; - if (!libdir.empty()) { - fname = libdir+script; - if (chkfile(fname)) goto found; - } fname = script; } else { - fname = srcdir+script; + fname = (srcdir.empty()?workdir:srcdir)+script; if (chkfile(fname)) goto found; + for (list<string>::const_iterator dir = include_dirs.begin(), + end = include_dirs.end(); dir != end; dir++) + if (!dir->empty()) { + fname = *dir+script; + if (chkfile(fname)) goto found; + } if (!libdir.empty()) { fname = libdir+script; if (chkfile(fname)) goto found; } - fname = workdir+script; - if (chkfile(fname)) goto found; fname = script; } } else @@ -505,6 +506,53 @@ return fname; } +/* Library search. */ + +static string searchlib(const string& srcdir, const string& libdir, + const list<string>& library_dirs, + const string& lib, bool search = true) +{ + char cwd[BUFSIZE]; + if (lib.empty()) + return lib; + else if (!getcwd(cwd, BUFSIZE)) { + perror("getcwd"); + return lib; + } + string workdir = cwd; + if (!workdir.empty() && workdir[workdir.size()-1] != '/') + workdir += "/"; + string fname; + if (lib[0] != '/') { + // resolve relative pathname + if (!search) { + fname = workdir+lib; + if (chkfile(fname)) goto found; + fname = lib; + } else { + fname = (srcdir.empty()?workdir:srcdir)+lib; + if (chkfile(fname)) goto found; + for (list<string>::const_iterator dir = library_dirs.begin(), + end = library_dirs.end(); dir != end; dir++) + if (!dir->empty()) { + fname = *dir+lib; + if (chkfile(fname)) goto found; + } + if (!libdir.empty()) { + fname = libdir+lib; + if (chkfile(fname)) goto found; + } + fname = lib; + } + } else + fname = lib; + found: +#if DEBUG>1 + std::cerr << "search '" << lib << "', found as '" << fname << "'\n"; +#endif + return fname; +} + // Run the interpreter on a source file, collection of source files, or on // string data. @@ -523,17 +571,19 @@ if (name.substr(name.size()-strlen(DLLEXT)) != DLLEXT) dllname += DLLEXT; // First try to open the library under the given name. - if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently(name.c_str(), &msg)) + string aname = searchlib(srcdir, libdir, librarydirs, name); + if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently(aname.c_str(), &msg)) return 0; else if (dllname == name) throw err(msg); + aname = searchlib(srcdir, libdir, librarydirs, dllname); // Now try the name with DLLEXT added. - else if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(dllname.c_str(), &msg)) + if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(aname.c_str(), &msg)) throw err(msg); return 0; } // ordinary source file - string fname = searchdir(srcdir, lib, s); + string fname = searchdir(srcdir, libdir, includedirs, s, check); if (check && sources.find(fname) != sources.end()) // already loaded, skip return 0; Modified: pure/trunk/interpreter.hh =================================================================== --- pure/trunk/interpreter.hh 2008-08-17 20:50:56 UTC (rev 523) +++ pure/trunk/interpreter.hh 2008-08-17 21:10:10 UTC (rev 524) @@ -313,10 +313,13 @@ bool stats; // stats mode (print execution times) uint8_t temp; // temporary level (purgable definitions) string ps; // prompt string - string lib; // library dir to search for source files + string libdir; // library dir to search for source files string histfile; // command history file string modname; // name of output (LLVM) module + // Additional directories to search for sources and libraries. + list<string> includedirs, librarydirs; + // Interpreter state. For internal use only. int nerrs; // current error count string errmsg; // last reported error (runstr) @@ -338,12 +341,14 @@ *************************************************************************/ /* Parse and execute the given source file (stdin if empty), or the given - list of files. If check is true (the default), only load the script if it - wasn't included before. Returns the last computed expression (if any). - (This expression is owned by the interpreter and must *not* be freed by - the caller.) This is the main interface function. If interactive is - true, readline is used to get interactive input from the user, using ps - as the prompt string. Please note that due to some global data shared by + list of files. If check is true (the default), a full search is performed + for relative pathnames (checking include directories and PURELIB to + locate the script file) and the script is only loaded if it wasn't + included before. Returns the last computed expression (if any). (This + expression is owned by the interpreter and must *not* be freed by the + caller.) This is the main interface function. If interactive is true, + readline is used to get interactive input from the user, using ps as the + prompt string. Please note that due to some global data shared by different interpreter instances, you can't run two interpreters concurrently right now. (It is possible to run them sequentially, though.) */ Modified: pure/trunk/pure.cc =================================================================== --- pure/trunk/pure.cc 2008-08-17 20:50:56 UTC (rev 523) +++ pure/trunk/pure.cc 2008-08-17 21:10:10 UTC (rev 524) @@ -36,16 +36,20 @@ pure [-h] [-i] [-n] [-q] [-v[level]] -x script [args ...]\n\ -h: Print this message and exit.\n\ -i: Force interactive mode (read commands from stdin).\n\ +-I: Add directory to search for included source files.\n\ +-L: Add directory to search for dynamic libraries.\n\ -n: Suppress automatic inclusion of the prelude.\n\ -q: Quiet startup (suppresses sign-on message).\n\ -v: Set verbosity level (useful for debugging purposes).\n\ -x: Execute script with given command line arguments.\n\ --: Stop option processing, pass remaining args in argv variable.\n\ Environment:\n\ -PURELIB: Directory to search for source scripts including the prelude.\n\ -PURE_MORE: Shell command for paging through output of the 'list' command.\n\ -PURE_PS: Command prompt to be used in the interactive command loop.\n\ -PURE_STACK: Maximum stack size in kilobytes (default: 0 = unlimited).\n" +PURELIB: Directory to search for library scripts and the prelude.\n\ +PURE_INCLUDE: Path to search for included source files.\n\ +PURE_LIBRARY: Path to search for dynamic libraries.\n\ +PURE_MORE: Shell command for paging through output of the 'list' command.\n\ +PURE_PS: Command prompt to be used in the interactive command loop.\n\ +PURE_STACK: Maximum stack size in kilobytes (default: 0 = unlimited).\n" #define LICENSE "This program is free software distributed under the GNU Public License\n(GPL V3 or later). Please see the COPYING file for details.\n" static const char *commands[] = { @@ -182,6 +186,26 @@ return !stat(s.c_str(), &st) && !S_ISDIR(st.st_mode); } +static void add_path(list<string>& dirs, const string& path) +{ + size_t pos = 0; + while (pos != string::npos) { + size_t end = path.find(':', pos); + string s; + if (end == string::npos) { + s = path.substr(pos); + pos = end; + } else { + s = path.substr(pos, end-pos); + pos = end+1; + } + if (!s.empty()) { + if (s[s.size()-1] != '/') s.append("/"); + dirs.push_back(s); + } + } +} + int main(int argc, char *argv[]) { @@ -234,11 +258,13 @@ size_t n = strtoul(env, &end, 0); if (!*end) interpreter::stackmax = n*1024; } - if ((env = getenv("PURELIB"))) - interp.lib = string(env)+"/"; - else - interp.lib = string(PURELIB)+"/"; - string prelude = interp.lib+string("prelude.pure"); + if ((env = getenv("PURELIB"))) { + string s = env; + if (!s.empty() && s[s.size()-1] != '/') s.append("/"); + interp.libdir = s; + } else + interp.libdir = string(PURELIB)+"/"; + string prelude = interp.libdir+string("prelude.pure"); #if USE_FASTCC // This global option is needed to get tail call optimization (you'll also // need to have USE_FASTCC in interpreter.hh enabled). @@ -258,8 +284,34 @@ want_prelude = false; else if (*args == string("-q")) quiet = true; - else if (string(*args).substr(0,2) == "-v") { + else if (string(*args).substr(0,2) == "-I") { string s = string(*args).substr(2); + if (s.empty()) { + if (!*++args) { + interp.error(prog + ": -I lacks directory argument"); + return 1; + } + s = *args; + } + if (!s.empty()) { + if (s[s.size()-1] != '/') s.append("/"); + interp.includedirs.push_back(s); + } + } else if (string(*args).substr(0,2) == "-L") { + string s = string(*args).substr(2); + if (s.empty()) { + if (!*++args) { + interp.error(prog + ": -L lacks directory argument"); + return 1; + } + s = *args; + } + if (!s.empty()) { + if (s[s.size()-1] != '/') s.append("/"); + interp.librarydirs.push_back(s); + } + } else if (string(*args).substr(0,2) == "-v") { + string s = string(*args).substr(2); if (s.empty()) continue; char *end; strtoul(s.c_str(), &end, 0); @@ -277,16 +329,14 @@ interp.error(prog + ": invalid option " + *args); return 1; } + if ((env = getenv("PURE_INCLUDE"))) add_path(interp.includedirs, env); + if ((env = getenv("PURE_LIBRARY"))) add_path(interp.librarydirs, env); interp.init_sys_vars(PACKAGE_VERSION, HOST, myargs); if (want_prelude) { // load the prelude if we can find it - if (chkfile("prelude.pure")) { - prelude = "prelude.pure"; + if (chkfile(prelude)) { have_prelude = true; - } else if (chkfile(prelude)) // try again in the PURELIB directory - have_prelude = true; - if (have_prelude) { - interp.run(prelude); + interp.run(prelude, false); interp.compile(); } } @@ -300,7 +350,7 @@ } else if (*argv == string("-x")) { if (*++argv) { count++; interp.modname = *argv; - interp.run(*argv); + interp.run(*argv, false); } else { interp.error(prog + ": missing script name"); return 1; @@ -308,11 +358,15 @@ break; } else if (*argv == string("--")) break; - else if (**argv == '-') + else if (string(*argv).substr(0,2) == "-I" || + string(*argv).substr(0,2) == "-L") { + string s = string(*argv).substr(2); + if (s.empty()) ++argv; + } else if (**argv == '-') ; else if (**argv) { if (count++ == 0) interp.modname = *argv; - interp.run(*argv); + interp.run(*argv, false); } if (count > 0 && !force_interactive) { if (interp.verbose&verbosity::dump) interp.compile(); @@ -345,7 +399,7 @@ histfile = strdup(interp.histfile.c_str()); } interp.temp = 1; - interp.run(""); + interp.run("", false); if (interp.ttymode) cout << endl; return 0; } Modified: pure/trunk/runtime.cc =================================================================== --- pure/trunk/runtime.cc 2008-08-17 20:50:56 UTC (rev 523) +++ pure/trunk/runtime.cc 2008-08-17 21:10:10 UTC (rev 524) @@ -879,6 +879,35 @@ #include <llvm/Target/TargetOptions.h> +#include <sys/types.h> +#include <sys/stat.h> + +static inline bool chkfile(const string& s) +{ + struct stat st; + return !stat(s.c_str(), &st) && !S_ISDIR(st.st_mode); +} + +static void add_path(list<string>& dirs, const string& path) +{ + size_t pos = 0; + while (pos != string::npos) { + size_t end = path.find(':', pos); + string s; + if (end == string::npos) { + s = path.substr(pos); + pos = end; + } else { + s = path.substr(pos, end-pos); + pos = end+1; + } + if (!s.empty()) { + if (s[s.size()-1] != '/') s.append("/"); + dirs.push_back(s); + } + } +} + extern "C" pure_interp *pure_create_interp(int argc, char *argv[]) { @@ -901,11 +930,13 @@ size_t n = strtoul(env, &end, 0); if (!*end) interpreter::stackmax = n*1024; } - if ((env = getenv("PURELIB"))) - interp.lib = string(env)+"/"; - else - interp.lib = string(PURELIB)+"/"; - string prelude = interp.lib+string("prelude.pure"); + if ((env = getenv("PURELIB"))) { + string s = env; + if (!s.empty() && s[s.size()-1] != '/') s.append("/"); + interp.libdir = s; + } else + interp.libdir = string(PURELIB)+"/"; + string prelude = interp.libdir+string("prelude.pure"); #if USE_FASTCC // This global option is needed to get tail call optimization (you'll also // need to have USE_FASTCC in interpreter.hh enabled). @@ -922,8 +953,36 @@ want_prelude = false; else if (*args == string("-q")) /* ignored */; - else if (string(*args).substr(0,2) == "-v") { + else if (string(*args).substr(0,2) == "-I") { string s = string(*args).substr(2); + if (s.empty()) { + if (!*++args) { + cerr << "pure_create_interp: -I lacks directory argument\n"; + delete _interp; + return 0; + } + s = *args; + } + if (!s.empty()) { + if (s[s.size()-1] != '/') s.append("/"); + interp.includedirs.push_back(s); + } + } else if (string(*args).substr(0,2) == "-L") { + string s = string(*args).substr(2); + if (s.empty()) { + if (!*++args) { + cerr << "pure_create_interp: -L lacks directory argument\n"; + delete _interp; + return 0; + } + s = *args; + } + if (!s.empty()) { + if (s[s.size()-1] != '/') s.append("/"); + interp.librarydirs.push_back(s); + } + } else if (string(*args).substr(0,2) == "-v") { + string s = string(*args).substr(2); if (s.empty()) continue; char *end; strtoul(s.c_str(), &end, 0); @@ -943,19 +1002,14 @@ delete _interp; return 0; } + if ((env = getenv("PURE_INCLUDE"))) add_path(interp.includedirs, env); + if ((env = getenv("PURE_LIBRARY"))) add_path(interp.librarydirs, env); interp.init_sys_vars(PACKAGE_VERSION, HOST, myargs); if (want_prelude) { // load the prelude if we can find it - FILE *fp = fopen("prelude.pure", "r"); - if (fp) - prelude = "prelude.pure"; - else - // try again in the PURELIB directory - fp = fopen(prelude.c_str(), "r"); - if (fp) { - fclose(fp); + if (chkfile(prelude)) { have_prelude = true; - interp.run(prelude); + interp.run(prelude, false); interp.compile(); } } @@ -969,7 +1023,7 @@ } else if (*argv == string("-x")) { if (*++argv) { count++; interp.modname = *argv; - interp.run(*argv); + interp.run(*argv, false); } else { cerr << "pure_create_interp: missing script name\n"; delete _interp; @@ -978,11 +1032,15 @@ break; } else if (*argv == string("--")) break; - else if (**argv == '-') + else if (string(*argv).substr(0,2) == "-I" || + string(*argv).substr(0,2) == "-L") { + string s = string(*argv).substr(2); + if (s.empty()) ++argv; + } else if (**argv == '-') ; else if (**argv) { if (count++ == 0) interp.modname = *argv; - interp.run(*argv); + interp.run(*argv, false); } interp.symtab.init_builtins(); return (pure_interp*)_interp; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-17 20:50:46
|
Revision: 523 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=523&view=rev Author: agraef Date: 2008-08-17 20:50:56 +0000 (Sun, 17 Aug 2008) Log Message: ----------- Bugfix: handle the case that the interpreter wasn't created successfully. Modified Paths: -------------- pure/trunk/examples/poor.c Modified: pure/trunk/examples/poor.c =================================================================== --- pure/trunk/examples/poor.c 2008-08-17 18:20:28 UTC (rev 522) +++ pure/trunk/examples/poor.c 2008-08-17 20:50:56 UTC (rev 523) @@ -29,6 +29,7 @@ { pure_interp *interp = pure_create_interp(argc, argv); char buf[10000]; + if (!interp) return 1; fputs("? ", stdout); fflush(stdout); while (fgets(buf, sizeof(buf), stdin)) { pure_expr *x = eval(buf); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-17 18:20:17
|
Revision: 522 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=522&view=rev Author: agraef Date: 2008-08-17 18:20:28 +0000 (Sun, 17 Aug 2008) Log Message: ----------- Bugfix in lexer initialization. Modified Paths: -------------- pure/trunk/lexer.ll Modified: pure/trunk/lexer.ll =================================================================== --- pure/trunk/lexer.ll 2008-08-17 12:57:39 UTC (rev 521) +++ pure/trunk/lexer.ll 2008-08-17 18:20:28 UTC (rev 522) @@ -884,18 +884,21 @@ interpreter::lex_begin(const string& fname) { yy_flex_debug = (verbose&verbosity::lexer) != 0 && !source_s; + FILE *fp; if (source_s) - yyin = 0; + fp = 0; else if (source.empty()) - yyin = stdin; - else if (!(yyin = fopen(fname.c_str(), "r"))) + fp = stdin; + else if (!(fp = fopen(fname.c_str(), "r"))) //error("cannot open '" + source + "'"); perror(source.c_str()); - if (source_s || yyin) { + if (source_s || fp) { + yyin = fp; yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE)); BEGIN(INITIAL); - } - return source_s || yyin; + return true; + } else + return false; } void This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-08-17 12:57:29
|
Revision: 521 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=521&view=rev Author: agraef Date: 2008-08-17 12:57:39 +0000 (Sun, 17 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-17 11:46:10 UTC (rev 520) +++ pure/trunk/pure.1.in 2008-08-17 12:57:39 UTC (rev 521) @@ -308,19 +308,20 @@ ``conses'', and `,' produces ``pairs''. As indicated, Pure provides the usual syntactic sugar for list values in brackets, such as [x,y,z], which is exactly the same as x:y:z:[]. Moreover, the prelude also provides an infix `..' -operator to denote arithmetic sequences such as 1..10 or 1.0,1.2..3.0. Pure's -tuples are a bit unusual: They are constructed by just ``paring'' things using -the `,' operator, for which the empty tuple acts as a neutral element (i.e., -(),x is just x, as is x,()). The pairing operator is associative, which -implies that tuples are completely flat (i.e., x,(y,z) is just x,y,z, as is -(x,y),z). This means that there are no nested tuples (tuples of tuples), if -you need such constructs then you should use lists instead. Also note that the -parentheses are \fInot\fP part of the tuple syntax in Pure, although you -\fIcan\fP use parentheses, just as with any other expression, for the usual -purpose of grouping expressions and overriding default precedences and -associativity. This means that a list of tuples will be printed (and must also -be entered) using the ``canonical'' representation (x1,y1):(x2,y2):...:[] -rather than [(x1,y1),(x2,y2),...] (which denotes just [x1,y1,x2,y2,...]). +operator to denote arithmetic sequences such as 1..10 or 1.0,1.2..3.0. +.sp +Pure's tuples are a bit unusual: They are constructed by just ``paring'' +things using the `,' operator, for which the empty tuple acts as a neutral +element (i.e., (),x is just x, as is x,()). The pairing operator is +associative, which implies that tuples are completely flat (i.e., x,(y,z) is +just x,y,z, as is (x,y),z). This means that there are no nested tuples (tuples +of tuples), if you need such constructs then you should use lists +instead. Also note that parentheses are generally only used to group +expressions and are \fInot\fP part of the tuple syntax in Pure. There's one +exception to this rule, however, namely that in order to include a tuple in a +bracketed list you have to put it inside parentheses. E.g., [(1,2),3,(4,5)] is +a three element list consisting of the tuple 1,2, the integer 3, and another +tuple 4,5. Likewise, [(1,2,3)] is list with a single element, the tuple 1,2,3. .TP .B List comprehensions: \fR[x,y; x = 1..n; y = 1..m; x<y] Pure also has list comprehensions which generate lists from an expression and @@ -330,7 +331,8 @@ comprehensions are in fact syntactic sugar for a combination of nested lambdas, conditional expressions and ``catmaps'' (a list operation which combines list concatenation and mapping a function over a list, defined in the -prelude), but they are often much easier to write. +prelude), but they are often much easier to write. Some examples of list +comprehensions can be found below at the end of this section. .TP .B Function applications: \fRfoo\ x\ y\ z As in other modern FPLs, these are written simply as juxtaposition (i.e., in @@ -834,7 +836,7 @@ .sp .nf > queens 8; -(1,1):(2,5):(3,8):(4,6):(5,3):(6,7):(7,2):(8,4):[] +[(1,1),(2,5),(3,8),(4,6),(5,3),(6,7),(7,2),(8,4)] .fi .SH C INTERFACE Accessing C functions from Pure programs is dead simple. You just need an @@ -1332,6 +1334,9 @@ > \fBunderride\fP .fi .SH CAVEATS AND NOTES +This section deals with common pitfalls and describes other quirks and +limitations of the current implementation. +.PP .B Debugging. There's no symbolic debugger yet. So .BR printf (3) @@ -1339,18 +1344,6 @@ .B system standard library module) should be your friend. ;-) .PP -.B Tuples and parentheses. -Please note that parentheses are really only used to group expressions and are -\fInot\fP part of the tuple syntax; tuples are in fact not really part of the -Pure language at all, but are implemented in the prelude. As you can see -there, the pairing operator `,' used to construct tuples is -(right-)associative. We call these the ``poor man's tuples'' since they are -always flat and thus there are no nested tuples (if you need this then you -should use lists instead). This also implies that an expression like -[(1,2),(3,4)] is in fact exactly the same as [1,2,3,4]. If you want to denote -a list of tuples, you must use the syntax (1,2):(3,4):[] instead; this is also -the notation used when the interpreter prints such objects. -.PP .B Special forms. Special forms are recognized at compile time only. Thus the catch function as well as the short-circuit logical connectives && and || are only treated as @@ -1464,8 +1457,8 @@ holds if a symbol is currently defined as a function.) .PP .B Numeric calculations. -If possible, you should always decorate numeric variables on the left-hand -sides of function definitions with the appropriate type tags, like +If possible, you should decorate numeric variables on the left-hand sides of +function definitions with the appropriate type tags, like .B ::int or .BR ::double . @@ -1482,6 +1475,10 @@ = 1 \fBotherwise\fP; .fi .PP +(This obviously becomes unwieldy if you have to deal with several numeric +arguments, however, so in this case it is usually better to just use a +polymorphic rule.) +.PP Also note that .B int (the machine integers) and @@ -1534,7 +1531,7 @@ routines, since currently there is no type checking for these; any pointer type other than char* and expr* is effectively treated as void*. This considerably simplifies lowlevel programming and interfacing to C libraries, -but also makes it very easy to have your program segfault all over the place! +but also makes it very easy to have your program segfault all over the place. Therefore it is highly recommended that you wrap your lowlevel code in Pure routines and data structures which do all the checks necessary to ensure that only the right kind of data is passed to C routines. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |