pure-lang-svn Mailing List for Pure (Page 23)
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-06-26 23:12:38
|
Revision: 316 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=316&view=rev Author: agraef Date: 2008-06-26 16:12:44 -0700 (Thu, 26 Jun 2008) Log Message: ----------- Update documentation. Modified Paths: -------------- pure/trunk/pure.1.in Modified: pure/trunk/pure.1.in =================================================================== --- pure/trunk/pure.1.in 2008-06-26 09:09:49 UTC (rev 315) +++ pure/trunk/pure.1.in 2008-06-26 23:12:44 UTC (rev 316) @@ -172,10 +172,10 @@ along with additional debugging information. .SH PURE OVERVIEW .PP -Pure is a fairly simple language. Programs are simply collections of -equational rules defining functions, \fBlet\fP commands binding global -variables, and expressions to be evaluated. Here's a simple example, entered -interactively in the interpreter: +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: .sp .nf > // my first Pure example @@ -185,7 +185,7 @@ 3628800 .fi .PP -The language is free-format (blanks are insignificant). As indicated, +The language is free-format (whitespace is insignificant). As indicated, definitions and expressions at the toplevel have to be terminated with a semicolon. Comments have the same syntax as in C++ (using // for line-oriented and /* ... */ for multiline comments; the latter may not be nested). Lines @@ -281,13 +281,14 @@ .IR "anonymous variable" . The case of identifiers is significant, but it doesn't carry any meaning (that's in contrast to languages like Prolog and Q, where variables must be -capitalized). Instead, Pure distinguishes function and variable symbols on the -left-hand side of an equation by the ``head = function'' rule: Any symbol -(except the anonymous variable) which occurs as the head symbol of a function -application is a function symbol, all other symbols are variables -- except -symbols explicitly declared as ``constant'' a.k.a. +capitalized). Instead, Pure distinguishes function and variable symbols by +their position on the left-hand side of an equation, using the ``head = +function'' rule: Any symbol (except the anonymous variable) which occurs as +the head symbol of a function application is a function symbol, all other +symbols are variables (except symbols explicitly declared as ``constant'' +a.k.a. .B nullary -symbols, see below. +symbols, see below). .TP .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 @@ -352,30 +353,47 @@ multiple lambda variables in one go, such as \e(x,y)\ ->\ x*y. .TP .B Case expressions: case\fR\ x\ \fBof\fR\ \fIrule\fR;\ ...\ \fBend -Matches an expression, discriminating over a number of different patterns; -similar to the Haskell \fBcase\fP construct. +Matches an expression, discriminating over a number of different cases, +similar to the Haskell \fBcase\fP construct. The expression x is matched in +turn against each left-hand side pattern in the rule list, and the first +pattern which matches x gives the value of the entire expression, by +evaluating the corresponding right-hand side with the variables in the pattern +bound to their corresponding values. .TP .B When expressions: \fRx\ \fBwhen\fR\ \fIrule\fR;\ ...\ \fBend An alternative way to bind local variables by matching a collection of subject terms against corresponding patterns. Similar to Aardappel's \fBwhen\fP -construct, but Pure allows more than one definition. Note that multiple -definitions in a \fBwhen\fP clause are processed from left to right, so that -later definitions may refer to the variables in earlier ones. In fact, a -\fBwhen\fP expression with multiple definitions is treated like several -nested \fBwhen\fP expressions, with the first binding being the ``outermost'' -one. +construct. A single binding such as x \fBwhen\fP u = v \fBend\fP is equivalent +to \fBcase\fP v \fBof\fP u = x \fBend\fP, but the former is often more +convenient to write. In difference to Aardappel, Pure also allows multiple +definitions in a single \fBwhen\fP clause, which are processed from left to +right, so that later definitions may refer to the variables in earlier +ones. In fact, a \fBwhen\fP expression with multiple definitions is treated +like several nested \fBwhen\fP expressions, with the first binding being the +``outermost'' one. .TP .B With expressions: \fRx\ \fBwith\fR\ \fIrule\fR;\ ...\ \fBend\fR -Defines local functions. Like Haskell's \fBwhere\fP construct, but can be used -anywhere inside an expression (just like Aardappel's \fBwhere\fP, but Pure -uses the keyword \fBwith\fP which better lines up with \fBcase\fP and -\fBwhen\fP). Also note that 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, in contrast to Haskell, does not distinguish between -defined functions and constructors and thus there is no magic to figure out -whether an equation is meant as a function definition or a pattern binding. +Defines local functions. Like Haskell's \fBwhere\fP construct, but it can be +used anywhere inside an expression (just like Aardappel's \fBwhere\fP, but +Pure uses the keyword \fBwith\fP which better lines up with \fBcase\fP and +\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 +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 Expressions are parsed according to the following precedence rules: Lambda binds most weakly, followed by .BR when , @@ -390,12 +408,11 @@ application binds stronger than all operators. Parentheses can be used to override default precedences and associativities as usual. .PP -At the toplevel, a Pure program basically consists of rules a.k.a. equations -defining functions, variable definitions a.k.a. global ``pattern bindings'', -and expressions to be evaluated. +At the toplevel, a Pure program basically consists of equations defining +functions, constant and variable definitions, and expressions to be evaluated. .TP .B Rules: \fIlhs\fR = \fIrhs\fR; -The basic form can also be augmented with a condition \fBif\ \fIguard\fR +The basic form can also be augmented with a condition \fBif\fP\ \fIguard\fP tacked on to the end of the rule (which restricts the applicability of the rule to the case that the guard evaluates to a nonzero integer), or the keyword @@ -407,24 +424,34 @@ RULE SYNTAX below for details. .TP .B Global variable bindings: let\fR \fIlhs\fR = \fIrhs\fR; -This binds every variable in the left-hand side pattern to the corresponding -subterm of the evaluated right-hand side. +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. .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. +.TP .B Toplevel expressions: \fIexpr\fR; A singleton expression at the toplevel, terminated with a semicolon, simply causes the given value to be evaluated (and the result to be printed, when running in interactive mode). .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 and -\fBlet\fP expressions for the purpose of performing pattern bindings (however, -for obvious reasons guards are not permitted in \fBwhen\fP and \fBlet\fP -expressions). 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.) +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 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.) .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 `_' @@ -877,9 +904,9 @@ Change the current working dir. .TP .B "clear \fR[\fIsymbol\fP ...]\fP" -Purge the definitions of the given symbols (functions or global variables). If -no symbols are given, purge \fIall\fP definitions (after confirmation) made -after the most recent +Purge the definitions of the given symbols (functions, constants or global +variables). If no symbols are given, purge \fIall\fP definitions (after +confirmation) made after the most recent .B save command (or the beginning of the interactive session). See the \fBDEFINITION LEVELS AND OVERRIDE MODE\fP section below for details. @@ -1238,7 +1265,72 @@ convenience. Moreover, the prelude also provides operations to recognize and decompose function applications. .PP -.B Numeric types. +.B Constant and variable 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. +.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: +.sp +.nf +> foo x = c*x; +> foo 99; +c*99 +> let c = 2; foo 99; +198 +> let c = 3; foo 99; +297 +.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: +.sp +.nf +> def d = 2; +> bar x = d*x; +> list foo bar +bar x = 2*x; +foo x = c*x; +> bar 99; +198 +> def d = 3; +<stdin>:9.0-8: symbol 'd' is already defined as a constant +.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 +> clear d +> def d = 3; +> list 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 Numeric calculations. If possible, you should always decorate numeric variables on the left-hand sides of function definitions with the appropriate type tags, like .B ::int @@ -1257,7 +1349,7 @@ = 1 \fBotherwise\fP; .fi .PP -Talking about the built-in types, please note that +Also note that .B int (the machine integers) and .B bigint @@ -1268,6 +1360,35 @@ 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 +> extern double atan(double); +> def pi = 4*atan 1.0; +> foo x = 2*pi*x; +> list 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 +> def running_on_windows = index sysinfo "mingw32" >= 0; +> foo x = something x if running_on_windows; +> = something_else x otherwise; +.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 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-26 09:09:41
|
Revision: 315 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=315&view=rev Author: agraef Date: 2008-06-26 02:09:49 -0700 (Thu, 26 Jun 2008) Log Message: ----------- Update documentation. Modified Paths: -------------- pure/trunk/pure.1.in Modified: pure/trunk/pure.1.in =================================================================== --- pure/trunk/pure.1.in 2008-06-26 08:57:06 UTC (rev 314) +++ pure/trunk/pure.1.in 2008-06-26 09:09:49 UTC (rev 315) @@ -134,8 +134,9 @@ paths; this can be helpful to debug tricky variable binding issues); .TP .B 4 (0x4) -adds abstract code snippets (matching automata etc.; you probably want to see -this only when working on the guts of the interpreter). +adds descriptions of the matching automata for the left-hand sides of +equations (you probably want to see this only when working on the guts of the +interpreter). .TP .B 8 (0x8) dumps the ``real'' output code (LLVM assembler, which is as close to the @@ -952,12 +953,14 @@ formats. This command recognizes the following options. Options may be combined, thus, e.g., \fBlist\fP -tvl is the same as \fBlist\fP -t -v -l. .TP -.B -c -Annotate printed definitions with compiled code (matching automata). Works -like the +.B -a +Disassembles pattern matching automata. Works like the .B -v4 option of the interpreter. .TP +.B -c +Print information about constant symbols. +.TP .B -d Disassembles LLVM IR, showing the generated LLVM assembler code of a function. Works like the @@ -971,7 +974,7 @@ option of the interpreter. .TP .B -f -Print information about function symbols only. +Print information about function symbols. .TP .B -g Indicates that the following symbols are actually shell glob patterns and that @@ -997,10 +1000,19 @@ definition levels. .TP .B -v -Print information about variable symbols only. +Print information about variable symbols. .PP +If none of the +.BR -c , +.B -f +and +.B -v +options are specified, then all kinds of symbols (constants, functions, +variables) are printed, otherwise only the specified categories will be +listed. +.PP Note that some of the options (in particular, -.B -c +.B -a and .BR -d ) may produce excessive amounts of information. By setting the This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-26 08:56:58
|
Revision: 314 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=314&view=rev Author: agraef Date: 2008-06-26 01:57:06 -0700 (Thu, 26 Jun 2008) Log Message: ----------- Fix up list command to properly deal with the new constant symbol category. Modified Paths: -------------- pure/trunk/ChangeLog pure/trunk/lexer.ll Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-06-26 08:14:31 UTC (rev 313) +++ pure/trunk/ChangeLog 2008-06-26 08:57:06 UTC (rev 314) @@ -1,5 +1,9 @@ 2008-06-26 Albert Graef <Dr....@t-...> + * lexer.ll: Fix up list command to properly deal with the new + constant symbol category. -c now lists constant symbols, the + previous -c option (print matching automata) was renamed to -a. + * interpreter.cc et al: Implement constant definitions, as discussed on the mailing list. These work like variable definitions (using the new 'def' keyword in lieu of 'let'), but Modified: pure/trunk/lexer.ll =================================================================== --- pure/trunk/lexer.ll 2008-06-26 08:14:31 UTC (rev 313) +++ pure/trunk/lexer.ll 2008-06-26 08:57:06 UTC (rev 314) @@ -331,8 +331,9 @@ if (!interp.interactive) REJECT; uint8_t s_verbose = interpreter::g_verbose; uint8_t tflag = 0; - bool cflag = false, dflag = false, eflag = false, gflag = false; - bool fflag = false, vflag = false, lflag = false, sflag = false; + bool aflag = false, dflag = false, eflag = false; + bool cflag = false, fflag = false, vflag = false; + bool gflag = false, lflag = false, sflag = false; const char *s = yytext+4; if (*s && !isspace(*s)) REJECT; yylloc->step(); @@ -345,6 +346,7 @@ if (s[0] != '-' || !s[1] || !strchr("cdefghlstv", s[1])) break; while (*++s) { switch (*s) { + case 'a': aflag = true; break; case 'c': cflag = true; break; case 'd': dflag = true; break; case 'e': eflag = true; break; @@ -363,13 +365,13 @@ case 'h': 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\ --c Annotate printed definitions with compiled code snippets. Useful\n\ - for debugging purposes.\n\ +-a Disassembles pattern matching automata. Useful for debugging purposes.\n\ +-c Print information about constant symbols.\n\ -d Disassembles LLVM IR, showing the generated LLVM assembler code of a\n\ - function.\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 only.\n\ +-f Print information about function symbols.\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\ @@ -379,7 +381,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 only.\n"; +-v Print information about variable symbols.\n"; goto out; default: cerr << "list: invalid option character '" << *s << "'\n"; @@ -389,19 +391,22 @@ } args.l.erase(args.l.begin(), arg); if (eflag) interpreter::g_verbose |= verbosity::envs; - if (cflag) interpreter::g_verbose |= verbosity::code; + if (aflag) interpreter::g_verbose |= verbosity::code; if (dflag) interpreter::g_verbose |= verbosity::dump; - if (!fflag && !vflag) fflag = vflag = true; + if (!cflag && !fflag && !vflag) cflag = fflag = vflag = true; if (lflag) sflag = true; { - size_t maxsize = 0, nfuns = 0, nvars = 0, nrules = 0; + size_t maxsize = 0, nfuns = 0, nvars = 0, ncsts = 0, nrules = 0; list<env_sym> l; set<int32_t> syms; for (env::const_iterator it = interp.globenv.begin(); it != interp.globenv.end(); ++it) { int32_t f = it->first; const env_info& e = it->second; const symbol& sym = interp.symtab.sym(f); - if (!((e.t == env_info::fun)?fflag:vflag)) continue; + if (!((e.t == env_info::fun)?fflag: + (e.t == env_info::cvar)?cflag: + (e.t == env_info::fvar)?vflag:0)) + continue; bool matches = e.temp >= tflag; if (!matches && !sflag && args.l.empty() && e.t == env_info::fun && fflag) { @@ -456,7 +461,7 @@ } } l.sort(env_compare); - if (!l.empty() && (cflag||dflag)) interp.compile(); + if (!l.empty() && (aflag||dflag)) interp.compile(); // we first dump the entire listing into a string and then output that // string through more ostringstream sout; @@ -489,7 +494,7 @@ sout << "let " << sym.s << " = " << *(pure_expr**)jt->second.val << ";\n"; } else if (jt->second.t == env_info::cvar) { - nvars++; + ncsts++; if (sflag) { sout << sym.s << string(maxsize-sym.s.size(), ' ') << " cst"; @@ -517,7 +522,7 @@ sout << sym.s << string(maxsize-sym.s.size(), ' ') << " fun"; if (lflag) { sout << " " << rules << ";"; - if (cflag && m) sout << endl << *m; + if (aflag && m) sout << endl << *m; if (dflag && fenv != interp.globalfuns.end() && fenv->second.f) interp.print_defs(sout, fenv->second); } else { @@ -534,7 +539,7 @@ } } if (n > 0) { - if (cflag && m) sout << *m << endl; + if (aflag && m) sout << *m << endl; if (dflag && fenv != interp.globalfuns.end() && fenv->second.f) interp.print_defs(sout, fenv->second); nrules += n; @@ -544,12 +549,22 @@ } } if (sflag) { - if (fflag && vflag) + if (fflag && vflag && cflag) + sout << ncsts << " constants, " << nvars << " variables, " + << nfuns << " functions, " << nrules << " rules\n"; + else if (fflag && cflag) + sout << ncsts << " constants, " << nfuns << " functions, " + << nrules << " rules\n"; + else if (fflag && vflag) sout << nvars << " variables, " << nfuns << " functions, " << nrules << " rules\n"; + else if (cflag && vflag) + sout << ncsts << " constants, " << nvars << " variables\n"; + else if (cflag) + sout << ncsts << " constants\n"; else if (vflag) sout << nvars << " variables\n"; - else + else if (fflag) sout << nfuns << " functions, " << nrules << " rules\n"; } FILE *fp; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-26 08:14:22
|
Revision: 313 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=313&view=rev Author: agraef Date: 2008-06-26 01:14:31 -0700 (Thu, 26 Jun 2008) Log Message: ----------- Add missing description of -d to list -h. Modified Paths: -------------- pure/trunk/lexer.ll Modified: pure/trunk/lexer.ll =================================================================== --- pure/trunk/lexer.ll 2008-06-25 23:02:21 UTC (rev 312) +++ pure/trunk/lexer.ll 2008-06-26 08:14:31 UTC (rev 313) @@ -365,6 +365,8 @@ Options may be combined, e.g., list -tvl is the same as list -t -v -l.\n\ -c Annotate printed definitions with compiled code snippets. Useful\n\ for debugging purposes.\n\ +-d Disassembles LLVM IR, showing the generated LLVM assembler code of a\n\ + function.\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 only.\n\ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-25 23:02:17
|
Revision: 312 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=312&view=rev Author: agraef Date: 2008-06-25 16:02:21 -0700 (Wed, 25 Jun 2008) Log Message: ----------- Add regression test for constant definitions. Added Paths: ----------- pure/trunk/test/test013.log pure/trunk/test/test013.pure Added: pure/trunk/test/test013.log =================================================================== --- pure/trunk/test/test013.log (rev 0) +++ pure/trunk/test/test013.log 2008-06-25 23:02:21 UTC (rev 312) @@ -0,0 +1,10 @@ +def pi = 4*atan 1.0; +foo x/*0:1*/ = 3.14159265358979*x/*0:1*/; +{ + rule #0: foo x = 3.14159265358979*x + state 0: #0 + <var> state 1 + state 1: #0 +} +foo 2; +6.28318530717959 Added: pure/trunk/test/test013.pure =================================================================== --- pure/trunk/test/test013.pure (rev 0) +++ pure/trunk/test/test013.pure 2008-06-25 23:02:21 UTC (rev 312) @@ -0,0 +1,9 @@ + +// constant definition example + +extern double atan(double); +def pi = 4*atan 1.0; + +foo x = pi*x; + +foo 2; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-25 23:00:44
|
Revision: 311 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=311&view=rev Author: agraef Date: 2008-06-25 16:00:24 -0700 (Wed, 25 Jun 2008) Log Message: ----------- Implement constant definitions. 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/expr.cc pure/trunk/expr.hh pure/trunk/interpreter.cc pure/trunk/interpreter.hh pure/trunk/lexer.ll pure/trunk/parser.yy pure/trunk/printer.cc pure/trunk/pure.cc pure/trunk/test/test004.log Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/ChangeLog 2008-06-25 23:00:24 UTC (rev 311) @@ -1,3 +1,13 @@ +2008-06-26 Albert Graef <Dr....@t-...> + + * interpreter.cc et al: Implement constant definitions, as + discussed on the mailing list. These work like variable + definitions (using the new 'def' keyword in lieu of 'let'), but + constants cannot be redefined (unless you first clear an existing + definition), and constant values are directly substituted into the + right-hand sides of equations rather than being evaluated at + runtime. + 2008-06-25 Albert Graef <Dr....@t-...> * examples/sort.c: Add another example for the runtime API. Modified: pure/trunk/etc/pure-mode.el.in =================================================================== --- pure/trunk/etc/pure-mode.el.in 2008-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/etc/pure-mode.el.in 2008-06-25 23:00:24 UTC (rev 311) @@ -164,8 +164,8 @@ (list "\\<\\(catch\\|throw\\)\\>" 0 'font-lock-builtin-face) (list (concat "\\<\\(" - "case\\|e\\(lse\\|nd\\|xtern\\)\\|i\\(f\\|nfix[lr]?\\)\\|let\\|" - "nullary\\|o\\(f\\|therwise\\)\\|p\\(refix\\|ostfix\\)\\|" + "case\\|def\\|e\\(lse\\|nd\\|xtern\\)\\|i\\(f\\|nfix[lr]?\\)\\|" + "let\\|nullary\\|o\\(f\\|therwise\\)\\|p\\(refix\\|ostfix\\)\\|" "then\\|using\\|w\\(hen\\|ith\\)" "\\)\\>") 0 'font-lock-keyword-face)) @@ -178,8 +178,8 @@ (list "\\<\\(catch\\|throw\\)\\>" 0 'font-lock-builtin-face) (list (concat "\\<\\(" - "case\\|e\\(lse\\|nd\\|xtern\\)\\|i\\(f\\|nfix[lr]?\\)\\|let\\|" - "nullary\\|o\\(f\\|therwise\\)\\|p\\(refix\\|ostfix\\)\\|" + "case\\|def\\|e\\(lse\\|nd\\|xtern\\)\\|i\\(f\\|nfix[lr]?\\)\\|" + "let\\|nullary\\|o\\(f\\|therwise\\)\\|p\\(refix\\|ostfix\\)\\|" "then\\|using\\|w\\(hen\\|ith\\)" "\\)\\>") 0 'font-lock-keyword-face)) Modified: pure/trunk/etc/pure.lang =================================================================== --- pure/trunk/etc/pure.lang 2008-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/etc/pure.lang 2008-06-25 23:00:24 UTC (rev 311) @@ -4,8 +4,8 @@ $DESCRIPTION=Pure # Pure keywords. -$KW_LIST(kwa)=infix infixl infixr prefix postfix nullary case else end extern -if let of otherwise then using when with +$KW_LIST(kwa)=infix infixl infixr prefix postfix nullary case 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-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/etc/pure.vim 2008-06-25 23:00:24 UTC (rev 311) @@ -33,7 +33,7 @@ " keywords syn keyword pureKeyword infix infixl infixr prefix postfix nullary -syn keyword pureKeyword case else end extern if let of otherwise then +syn keyword pureKeyword case 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-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/etc/pure.xml 2008-06-25 23:00:24 UTC (rev 311) @@ -4,6 +4,7 @@ <highlighting> <list name="keywords"> <item> case </item> + <item> def </item> <item> else </item> <item> end </item> <item> extern </item> Modified: pure/trunk/expr.cc =================================================================== --- pure/trunk/expr.cc 2008-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/expr.cc 2008-06-25 23:00:24 UTC (rev 311) @@ -234,6 +234,10 @@ ttag = e.ttag; p = new path(*e.p); break; + case cvar: + cval = new expr; + *cval = *e.cval; + break; case fvar: val = e.val; break; @@ -256,6 +260,9 @@ case lvar: delete p; break; + case cvar: + delete cval; + break; case fvar: break; case fun: @@ -272,6 +279,10 @@ ttag = e.ttag; p = new path(*e.p); break; + case cvar: + cval = new expr; + *cval = *e.cval; + break; case fvar: val = e.val; break; @@ -294,6 +305,9 @@ case lvar: delete p; break; + case cvar: + delete cval; + break; case fvar: break; case fun: Modified: pure/trunk/expr.hh =================================================================== --- pure/trunk/expr.hh 2008-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/expr.hh 2008-06-25 23:00:24 UTC (rev 311) @@ -485,7 +485,7 @@ /* Environment entries. */ struct env_info { - enum { none, lvar, fvar, fun } t; + enum { none, lvar, cvar, fvar, fun } t; uint8_t temp; union { // local variable binding (lvar): @@ -493,6 +493,8 @@ int8_t ttag; path *p; }; + // constant definition (cvar): + expr *cval; // free variable definition (fvar): void *val; // pointer to memory location holding a runtime expression // function definition (fun): @@ -505,6 +507,8 @@ env_info() : t(none) { } env_info(int8_t _ttag, path _p, uint8_t _temp = 0) : t(lvar), temp(_temp), ttag(_ttag), p(new path(_p)) { } + env_info(expr x, uint8_t _temp = 0) + : t(cvar), temp(_temp), cval(new expr) { *cval = x; } env_info(void *v, uint8_t _temp = 0) : t(fvar), temp(_temp), val(v) { } env_info(uint32_t c, rulel r, uint8_t _temp = 0) Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/interpreter.cc 2008-06-25 23:00:24 UTC (rev 311) @@ -537,8 +537,11 @@ int32_t f = it->first; const symbol& sym = symtab.sym(f); env::const_iterator jt = globenv.find(f); - if (jt != globenv.end() && jt->second.t == env_info::fun) { + if (jt != globenv.end() && jt->second.t == env_info::cvar) { restore_globals(g); + throw err("symbol '"+sym.s+"' is already defined as a constant"); + } else if (jt != globenv.end() && jt->second.t == env_info::fun) { + restore_globals(g); throw err("symbol '"+sym.s+"' is already defined as a function"); } else if (externals.find(f) != externals.end()) { restore_globals(g); @@ -559,6 +562,139 @@ return res; } +// Define global constants (macro definitions). + +pure_expr *interpreter::const_defn(expr pat, expr x) +{ + globals g; + save_globals(g); + pure_expr *e, *res = const_defn(pat, x, e); + if (!res && e) pure_free(e); + restore_globals(g); + return res; +} + +static expr pure_expr_to_expr(pure_expr *x) +{ + // FIXME: We might want to do stack checks here. + switch (x->tag) { + case EXPR::APP: + return expr(pure_expr_to_expr(x->data.x[0]), + pure_expr_to_expr(x->data.x[1])); + case EXPR::INT: + return expr(EXPR::INT, x->data.i); + case EXPR::BIGINT: { + // The expr constructor globbers its mpz_t argument, so take a copy. + mpz_t z; + mpz_init_set(z, x->data.z); + return expr(EXPR::BIGINT, z); + } + case EXPR::DBL: + return expr(EXPR::DBL, x->data.d); + case EXPR::STR: + return expr(EXPR::STR, x->data.s); + case EXPR::PTR: + if (x->data.p != 0) + // Only null pointer constants permitted right now. + throw err("pointer must be null in constant definition"); + return expr(EXPR::PTR, x->data.p); + default: + assert(x->tag > 0); + if (x->data.clos && x->data.clos->local) + // There's no way we can capture a local function in a compile time + // expression right now, so we have to forbid this, too. + throw err("anonymous closure not permitted in constant definition"); + return expr(x->tag); + } +} + +static expr subterm(expr x, const path& p) +{ + for (size_t i = 0, n = p.len(); i < n; i++) { + assert(x.tag() == EXPR::APP); + x = p[i]?x.xval2():x.xval1(); + } + return x; +} + +pure_expr *interpreter::const_defn(expr pat, expr x, pure_expr*& e) +{ + globals g; + save_globals(g); + compile(); + env vars; + expr lhs = bind(vars, pat), rhs = x; + build_env(vars, lhs); + for (env::const_iterator it = vars.begin(); it != vars.end(); ++it) { + int32_t f = it->first; + const symbol& sym = symtab.sym(f); + env::const_iterator jt = globenv.find(f); + if (jt != globenv.end() && jt->second.t == env_info::cvar) { + restore_globals(g); + throw err("symbol '"+sym.s+"' is already defined as a constant"); + } else if (jt != globenv.end() && jt->second.t == env_info::fvar) { + restore_globals(g); + throw err("symbol '"+sym.s+"' is already defined as a variable"); + } else if (jt != globenv.end() && jt->second.t == env_info::fun) { + restore_globals(g); + throw err("symbol '"+sym.s+"' is already defined as a function"); + } else if (externals.find(f) != externals.end()) { + restore_globals(g); + throw err("symbol '"+sym.s+ + "' is already declared as an extern function"); + } + } + compile(rhs); + pure_expr *res = doeval(rhs, e); + if (!res) return 0; + // convert the result back to a compile time expression + expr u = pure_expr_to_expr(res); + // match against the left-hand side + matcher m(rule(lhs, rhs)); + if (m.match(u)) { + // bind variables accordingly + for (env::const_iterator it = vars.begin(); it != vars.end(); ++it) { + assert(it->second.t == env_info::lvar && it->second.p); + int32_t f = it->first; + expr v = subterm(u, *it->second.p); + globenv[f] = env_info(v, temp); + } + } else { + pure_freenew(res); + res = 0; + } + restore_globals(g); + return res; +} + +void interpreter::const_defn(int32_t tag, pure_expr *x) +{ + assert(tag > 0 && x); + globals g; + save_globals(g); + symbol& sym = symtab.sym(tag); + env::const_iterator jt = globenv.find(tag); + if (jt != globenv.end() && jt->second.t == env_info::cvar) { + restore_globals(g); + throw err("symbol '"+sym.s+"' is already defined as a constant"); + } else if (jt != globenv.end() && jt->second.t == env_info::fvar) { + restore_globals(g); + throw err("symbol '"+sym.s+"' is already defined as a variable"); + } else if (jt != globenv.end() && jt->second.t == env_info::fun) { + restore_globals(g); + throw err("symbol '"+sym.s+"' is already defined as a function"); + } else if (externals.find(tag) != externals.end()) { + restore_globals(g); + throw err("symbol '"+sym.s+ + "' is already declared as an extern function"); + } + // convert the value to a compile time expression + expr u = pure_expr_to_expr(x); + // bind the variable + globenv[tag] = env_info(u, temp); + restore_globals(g); +} + // Process pending fundefs. void interpreter::mark_dirty(int32_t f) @@ -844,6 +980,29 @@ cout << ((double)clocks)/(double)CLOCKS_PER_SEC << "s\n"; } +void interpreter::define_const(rule *r) +{ + 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"; + if (!res) { + ostringstream msg; + if (e) { + msg << "unhandled exception '" << e << "' while evaluating '" + << "def " << r->lhs << " = " << r->rhs << "'"; + pure_free(e); + } else + msg << "failed match while evaluating '" + << "def " << r->lhs << " = " << r->rhs << "'"; + throw err(msg.str()); + } + delete r; + pure_freenew(res); + if (interactive && stats) + cout << ((double)clocks)/(double)CLOCKS_PER_SEC << "s\n"; +} + void interpreter::clearsym(int32_t f) { // Check whether this symbol was already compiled; in that case @@ -962,7 +1121,9 @@ env::iterator it = e.find(f); const symbol& sym = symtab.sym(f); if (it != e.end()) { - if (it->second.t == env_info::fvar) + if (it->second.t == env_info::cvar) + throw err("symbol '"+sym.s+"' is already defined as a constant"); + else if (it->second.t == env_info::fvar) throw err("symbol '"+sym.s+"' is already defined as a variable"); else if (it->second.argc != argc) { ostringstream msg; @@ -1288,7 +1449,12 @@ // not a bound variable if (x.ttag() != 0) throw err("error in expression (misplaced type tag)"); - return x; + it = globenv.find(sym.f); + if (it != globenv.end() && it->second.t == env_info::cvar) + // substitute constant value + return *it->second.cval; + else + return x; } const env_info& info = it->second; return expr(EXPR::VAR, sym.f, idx, info.ttag, *info.p); @@ -1677,8 +1843,11 @@ save_globals(g); symbol& sym = symtab.sym(tag); env::const_iterator jt = globenv.find(tag); - if (jt != globenv.end() && jt->second.t == env_info::fun) { + if (jt != globenv.end() && jt->second.t == env_info::cvar) { restore_globals(g); + throw err("symbol '"+sym.s+"' is already defined as a constant"); + } else if (jt != globenv.end() && jt->second.t == env_info::fun) { + restore_globals(g); throw err("symbol '"+sym.s+"' is already defined as a function"); } else if (externals.find(tag) != externals.end()) { restore_globals(g); @@ -3427,7 +3596,9 @@ case EXPR::STR: return sbox(x.sval()); case EXPR::PTR: - assert(0 && "not implemented"); + // FIXME: Only null pointers are supported right now. + assert(x.pval() == 0); + return pbox(x.pval()); // application: case EXPR::APP: if (x.ttag() != 0) { @@ -3764,6 +3935,11 @@ return call("pure_string_dup", s); } +Value *interpreter::pbox(void *p) +{ + return call("pure_pointer", p); +} + // Variable access. static uint32_t argno(uint32_t n, path &p) @@ -3987,6 +4163,12 @@ return call(name, p); } +Value *interpreter::call(string name, void *p) +{ + assert(p==0); + return call(name, ConstantPointerNull::get(VoidPtrTy)); +} + Value *interpreter::call(string name, Value *x, const char *s) { Env& e = act_env(); Modified: pure/trunk/interpreter.hh =================================================================== --- pure/trunk/interpreter.hh 2008-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/interpreter.hh 2008-06-25 23:00:24 UTC (rev 311) @@ -310,24 +310,39 @@ /* Evaluate an expression and define global variables. This works like eval() above, but also binds the variables in pat to the corresponding values. Also, these routines throw a C++ exception of the err type if any - of the variable symbols to be defined is already bound to a function. - Otherwise the result is the evaluated expression to be matched. Returns a - null pointer if an exception occurred during the evaluation or if the - pattern failed to match. Both the result and the exception value (if any) - are to be freed by the caller. */ + of the variable symbols to be defined is already bound to a different + kind of symbol. Otherwise the result is the evaluated expression to be + matched. Returns a null pointer if an exception occurred during the + evaluation or if the pattern failed to match. Both the result and the + exception value (if any) are to be freed by the caller. */ pure_expr *defn(expr pat, expr x); pure_expr *defn(expr pat, expr x, pure_expr*& e); /* Bind a global variable to a given value. This binds the given variable symbol directly to the given value, without matching and evaluating - anything. It is still checked whether the variable symbol is already - bound to a function, in which case an err exception is thrown. */ + anything. It is still checked that the variable symbol is not already + bound to a different kind of symbol, otherwise an err exception is + thrown. */ void defn(int32_t tag, pure_expr *x); void defn(const char *varname, pure_expr *x) { defn(symtab.sym(varname).f, x); } + /* Constant definitions. These work like the variable definition methods + above, but define constant symbols which are directly substituted into + the right-hand sides of equations rather than being evaluated at + runtime. The right-hand side expression is evaluated and matched against + the left-hand side pattern as usual. Unlike variables, existing constant + symbols cannot be redefined, so they have to be cleared before you can + give them new values. */ + + pure_expr *const_defn(expr pat, expr x); + pure_expr *const_defn(expr pat, expr x, pure_expr*& e); + void const_defn(int32_t tag, pure_expr *x); + void const_defn(const char *varname, pure_expr *x) + { const_defn(symtab.sym(varname).f, x); } + /* Process pending compilations of function definitions. This is also done - automatically when eval() or defn() is invoked. */ + automatically when eval() or defn()/const_defn() is invoked. */ void compile(); /* Errors and warnings. These are for various types of messages from the @@ -352,6 +367,7 @@ void compile(expr x); void declare(prec_t prec, fix_t fix, list<string> *ids); void define(rule *r); + void define_const(rule *r); void exec(expr *x); void clear(int32_t f = 0); void clearsym(int32_t f); @@ -466,6 +482,7 @@ llvm::Value *call(string name, const mpz_t& z); llvm::Value *call(string name, double d); llvm::Value *call(string name, const char *s); + llvm::Value *call(string name, void *p); llvm::Value *call(string name, llvm::Value *x, const mpz_t& z); llvm::Value *call(string name, llvm::Value *x, const char *s); void make_bigint(const mpz_t& z, llvm::Value*& sz, llvm::Value*& ptr); Modified: pure/trunk/lexer.ll =================================================================== --- pure/trunk/lexer.ll 2008-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/lexer.ll 2008-06-25 23:00:24 UTC (rev 311) @@ -131,9 +131,9 @@ now. */ static const char *commands[] = { - "cd", "clear", "extern", "help", "infix", "infixl", "infixr", "let", "list", - "ls", "nullary", "override", "postfix", "prefix", "pwd", "quit", "run", - "save", "stats", "underride", "using", 0 + "cd", "clear", "def", "extern", "help", "infix", "infixl", "infixr", "let", + "list", "ls", "nullary", "override", "postfix", "prefix", "pwd", "quit", + "run", "save", "stats", "underride", "using", 0 }; static char * @@ -399,7 +399,7 @@ int32_t f = it->first; const env_info& e = it->second; const symbol& sym = interp.symtab.sym(f); - if (!((e.t == env_info::fvar)?vflag:fflag)) continue; + if (!((e.t == env_info::fun)?fflag:vflag)) continue; bool matches = e.temp >= tflag; if (!matches && !sflag && args.l.empty() && e.t == env_info::fun && fflag) { @@ -486,6 +486,17 @@ } else sout << "let " << sym.s << " = " << *(pure_expr**)jt->second.val << ";\n"; + } else if (jt->second.t == env_info::cvar) { + nvars++; + if (sflag) { + sout << sym.s << string(maxsize-sym.s.size(), ' ') + << " cst"; + if (lflag) sout << " " << sym.s << " = " + << *jt->second.cval << ";"; + sout << endl; + } else + sout << "def " << sym.s << " = " << *jt->second.cval + << ";\n"; } else { if (xt != interp.externals.end()) { const ExternInfo& info = xt->second; @@ -743,6 +754,7 @@ prefix yylval->fix = prefix; return token::FIX; postfix yylval->fix = postfix; return token::FIX; nullary return token::NULLARY; +def return token::DEF; let return token::LET; case return token::CASE; of return token::OF; Modified: pure/trunk/parser.yy =================================================================== --- pure/trunk/parser.yy 2008-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/parser.yy 2008-06-25 23:00:24 UTC (rev 311) @@ -98,6 +98,7 @@ %token NULLARY "nullary" %token <fix> FIX "fixity" +%token DEF "def" %token LET "let" %token CASE "case" %token OF "of" @@ -274,6 +275,8 @@ { action(interp.exec($1), delete $1); } | LET simple_rule { action(interp.define($2), delete $2); } +| DEF simple_rule +{ action(interp.define_const($2), delete $2); } | rule { rulel *rl = 0; action(interp.add_rules(interp.globenv, Modified: pure/trunk/printer.cc =================================================================== --- pure/trunk/printer.cc 2008-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/printer.cc 2008-06-25 23:00:24 UTC (rev 311) @@ -421,6 +421,9 @@ } break; } + case env_info::cvar: + os << "def " << sym.s << " = " << *info.cval; + break; case env_info::fvar: os << "let " << sym.s << " = " << *(pure_expr**)info.val; break; @@ -628,8 +631,6 @@ assert(x); //os << "{" << x->refc << "}"; switch (x->tag) { - case 0: - return os << "<<anonymous closure " << (void*)x << ">>"; case EXPR::INT: return os << x->data.i; case EXPR::BIGINT: { @@ -744,8 +745,11 @@ return os << pure_paren(95, u) << " " << pure_paren(100, v); } default: { - assert(x->tag > 0); + if (x->tag == 0) + return os << "<<closure " << (void*)x << ">>"; const symbol& sym = interpreter::g_interp->symtab.sym(x->tag); + if (x->data.clos && x->data.clos->local) + return os << "<<closure " << sym.s << ">>"; if (sym.prec < 10) return os << '(' << sym.s << ')'; else Modified: pure/trunk/pure.cc =================================================================== --- pure/trunk/pure.cc 2008-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/pure.cc 2008-06-25 23:00:24 UTC (rev 311) @@ -47,9 +47,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", "extern", "help", "infix", "infixl", "infixr", "let", "list", - "ls", "nullary", "override", "postfix", "prefix", "pwd", "quit", "run", - "save", "stats", "underride", "using", 0 + "cd", "clear", "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/test004.log =================================================================== --- pure/trunk/test/test004.log 2008-06-25 07:39:52 UTC (rev 310) +++ pure/trunk/test/test004.log 2008-06-25 23:00:24 UTC (rev 311) @@ -35,15 +35,15 @@ foo 99; 99 foo2 99; -bar 100 +<<closure bar>> 100 foo2 98; -bar 98 +<<closure bar>> 98 foo3 99; -bar +<<closure bar>> foo3 99 98; -bar 98 +<<closure bar>> 98 foo3 99 99; -bar 100 +<<closure bar>> 100 loop = loop; count n/*0:1*/ = ct/*0*/ n/*0:1*/ with ct n/*0:1*/::int = n/*0:1*/ if n/*0:1*/<=0; ct n/*0:1*/::int = ct/*1*/ (n/*0:1*/-1) { rule #0: ct n::int = n if n<=0 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-25 07:39:50
|
Revision: 310 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=310&view=rev Author: agraef Date: 2008-06-25 00:39:52 -0700 (Wed, 25 Jun 2008) Log Message: ----------- Comment change. Modified Paths: -------------- pure/trunk/interpreter.cc Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-06-24 23:46:23 UTC (rev 309) +++ pure/trunk/interpreter.cc 2008-06-25 07:39:52 UTC (rev 310) @@ -2745,9 +2745,7 @@ // expression. /* NOTE: The environment is allocated dynamically, so that its child environments survive for the entire lifetime of any embedded closures, - which might still be called at a later time. XXXFIXME: This leaks memory - right now. How do we keep track of environments that might still be - needed? */ + which might still be called at a later time. */ Env *save_fptr = fptr; fptr = new Env(0, 0, x, false); fptr->refc = 1; Env &f = *fptr; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 23:46:14
|
Revision: 309 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=309&view=rev Author: agraef Date: 2008-06-24 16:46:23 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Add sort.c example. Modified Paths: -------------- pure/trunk/ChangeLog Added Paths: ----------- pure/trunk/examples/sort.c Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-06-24 22:45:02 UTC (rev 308) +++ pure/trunk/ChangeLog 2008-06-24 23:46:23 UTC (rev 309) @@ -1,3 +1,10 @@ +2008-06-25 Albert Graef <Dr....@t-...> + + * examples/sort.c: Add another example for the runtime API. + This one shows how to implement a C function in a module to be + loaded by the Pure interpreter, which in turn calls other C and + Pure functions. + 2008-06-24 Albert Graef <Dr....@t-...> * configure.ac: Bump version number. @@ -6,6 +13,8 @@ completion. * examples/poor.c: Add an example for the new public runtime API. + Shows how to interface to the Pure interpreter in a standalone C + application. * interpreter.cc/h, runtime.cc/h, lib/strings.pure: Add error reporting to the eval() routine. Added: pure/trunk/examples/sort.c =================================================================== --- pure/trunk/examples/sort.c (rev 0) +++ pure/trunk/examples/sort.c 2008-06-24 23:46:23 UTC (rev 309) @@ -0,0 +1,110 @@ + +/* Sort a Pure list using the C qsort() function. 2008-06-25 AG */ + +/* Another example using the runtime API. It implements an external function + 'sort' which can be loaded inside the Pure interpreter. The function, to be + invoked as 'sort p xs', calls the qsort() routine from the C library to + sort a Pure list xs using a given Pure predicate p, which compares two + elements x and y and returns a truth value indicating whether x is less + than y. The example illustrates how we can program a C function to be + called from Pure which in turn calls other Pure functions, and takes + generic pure_expr* values as arguments and returns them as results. */ + +/* To compile (Linux): 'gcc -shared -o sort.so sort.c -lpure'. This will + create a dynamic library ready to be loaded by the Pure interpreter. + (Replace .so with .dylib or .dll on OSX and Windows, respectively. On OSX, + you also have to replace -shared with -dynamiclib. On Windows you might + wish to add the '-Wl,--enable-auto-import' linker option.) + + I suggest that you also set up your LD_LIBRARY_PATH environment variable + (DYLD_LIBRARY_PATH on OSX) so that the dynamic loader finds sort.so without + further ado. Something like 'export LD_LIBRARY_PATH=.' should do the trick. + Windows doesn't need this since it always searches the current directory + for dlls. + + Now start the interpreter and enter the following to "dlopen" sort.so and + declare the sort function: + + > using "lib:sort"; + > extern expr* sort(expr* p, expr *xs); + + The sort function is now ready to be called as 'sort p xs', e.g.: + + > sort (<) (1..10); + [1,2,3,4,5,6,7,8,9,10] + > sort (>) (1..10); + [10,9,8,7,6,5,4,3,2,1] + + Have some fun with random lists, comparing our sort function with the one + from hello.pure. (The rand function is also declared in hello.pure; it is + just the rand() function from the C library.) + + > run hello.pure + Hello, world! + > let xs = [rand; i = 1..100000]; + > stats + > #sort (<) xs; + 100000 + 1.05s + > #qsort (<) xs; + 100000 + 14.05s + + The above results are for my Athlon 2500+. YMMV, but most likely you'll get + similar results indicating that the C implementation is much faster. That's + because the quicksort algorithm in hello.pure juggles around with lists, + whereas the C quicksort routine uses vectors and sorts the elements + in-place. */ + +#include <stdlib.h> +#include <pure/runtime.h> + +/* Set up a C callback which in turn invokes a Pure predicate to perform the + comparison of list elements. */ + +static pure_expr* cmp_p; +static int cmp(const void *xp, const void *yp) +{ + pure_expr *x = *(pure_expr**)xp, *y = *(pure_expr**)yp; + /* We use pure_appl to invoke the Pure predicate stored in cmp_p on the list + elements x and y passed by the qsort() routine. */ + pure_expr *p = pure_appl(cmp_p, 2, x, y); + int res = pure_is_int(p, &res) && res; /* x<y? */ + pure_freenew(p); /* collect temporary */ + if (res) + res = -1; + else { + /* Invoke cmp_p another time to perform the reverse comparison. */ + p = pure_appl(cmp_p, 2, y, x); + res = pure_is_int(p, &res) && res; /* y<x? */ + pure_freenew(p); /* collect temporary */ + /* Note that if both tests failed then the elements are either equal or + incomparable, in which case res==0. */ + } + return res; +} + +pure_expr *sort(pure_expr *p, pure_expr *xs) +{ + size_t size; + pure_expr **elems; + /* Deconstruct the list argument which is passed as a pure_expr* value. + This yields a vector of pure_expr* elements which can be passed to the + qsort() routine. */ + if (pure_is_listv(xs, &size, &elems)) { + pure_expr *ys; + /* Invoke qsort() to sort the elems vector. */ + cmp_p = p; + qsort(elems, size, sizeof(pure_expr*), cmp); + /* Construct a new list value from the sorted vector, to be returned as + the function result. */ + ys = pure_listv(size, elems); + /* The elems vector returned by pure_is_listv is malloc'ed, free it now so + that we don't leak memory. */ + free(elems); + return ys; + } else + /* The xs argument wasn't a proper list value, return a NULL pointer to + indicate failure. This will make the 'sort p xs' call a normal form. */ + return 0; +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 22:44:55
|
Revision: 308 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=308&view=rev Author: agraef Date: 2008-06-24 15:45:02 -0700 (Tue, 24 Jun 2008) Log Message: ----------- String returned by str() is malloc'ed, must free it. Modified Paths: -------------- pure/trunk/examples/poor.c Modified: pure/trunk/examples/poor.c =================================================================== --- pure/trunk/examples/poor.c 2008-06-24 22:41:06 UTC (rev 307) +++ pure/trunk/examples/poor.c 2008-06-24 22:45:02 UTC (rev 308) @@ -33,8 +33,9 @@ while (fgets(buf, sizeof(buf), stdin)) { pure_expr *x = eval(buf); if (x) { - printf("%s\n", str(x)); - pure_freenew(x); + char *s = str(x); + printf("%s\n", s); + pure_freenew(x); free(s); } else if (lasterr()) fputs(lasterr(), stderr); fputs("? ", stdout); fflush(stdout); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 22:40:58
|
Revision: 307 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=307&view=rev Author: agraef Date: 2008-06-24 15:41:06 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Comment changes. Modified Paths: -------------- pure/trunk/examples/poor.c Modified: pure/trunk/examples/poor.c =================================================================== --- pure/trunk/examples/poor.c 2008-06-24 22:28:02 UTC (rev 306) +++ pure/trunk/examples/poor.c 2008-06-24 22:41:06 UTC (rev 307) @@ -1,20 +1,23 @@ /* Poor man's Pure interpreter. 2008-06-24 AG */ -/* This is an example for calling Pure from C/C++ applications. Using the - public runtime API of Pure 0.5 or later, it implements a little command - loop which reads lines of Pure code from standard input, evaluates them and - prints the results, until it encounters end-of-file. +/* This is an example for calling Pure from a standalone C/C++ application + which is *not* hosted by the command line version of the Pure interpreter, + but uses the public runtime API of Pure 0.5 or later to create its own + interpreter instance. The program implements a little command loop which + reads Pure code from standard input, evaluates it and prints the results. Compile this with 'gcc -o poor poor.c -lpure', and run the resulting executable as './poor [args ...]'. You can use the same command line arguments as with the real Pure interpreter, including any Pure scripts to be loaded at startup. Input is line-oriented, so you can't continue definitions across lines, but in return you don't have to terminate each - line with a ';' either, the eval() function already takes care of that. + line with a ';' either, the eval() function already takes care of that. To + terminate the program just type the end-of-file character at the beginning + of a line. - Please note that the interpreter interface provided by the runtime API is - rather minimalistic right now. In particular, the interpreter always runs + Please note that the interface to interpreter instances created with the + runtime API is rather minimalistic right now. The interpreter always runs in non-interactive mode (thus none of the interactive commands will work) and eval() only returns the result of the last computed expression (this is what gets printed in the read-eval-print loop). */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 22:27:54
|
Revision: 306 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=306&view=rev Author: agraef Date: 2008-06-24 15:28:02 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Comment changes. Modified Paths: -------------- pure/trunk/examples/poor.c Modified: pure/trunk/examples/poor.c =================================================================== --- pure/trunk/examples/poor.c 2008-06-24 15:57:36 UTC (rev 305) +++ pure/trunk/examples/poor.c 2008-06-24 22:28:02 UTC (rev 306) @@ -1,18 +1,24 @@ -/* Poor man's Pure interpreter. */ +/* Poor man's Pure interpreter. 2008-06-24 AG */ -/* This is an example for the C/C++->Pure interface. It implements a silly - little command loop which reads Pure code, evaluates it, and prints the - results. Compile this with 'gcc -o poor poor.c -lpure', and run as - './poor args...'. You can use the same command line options as with the - real Pure interpreter, including any Pure scripts to be loaded at startup. +/* This is an example for calling Pure from C/C++ applications. Using the + public runtime API of Pure 0.5 or later, it implements a little command + loop which reads lines of Pure code from standard input, evaluates them and + prints the results, until it encounters end-of-file. - Please note that the interface to the interpreter, as provided by the - public runtime API, is rather minimalistic right now. In particular, the - interpreter will always run in non-interactive mode (thus none of the - interactive commands will work) and eval() will only return the last - computed expression. */ + Compile this with 'gcc -o poor poor.c -lpure', and run the resulting + executable as './poor [args ...]'. You can use the same command line + arguments as with the real Pure interpreter, including any Pure scripts to + be loaded at startup. Input is line-oriented, so you can't continue + definitions across lines, but in return you don't have to terminate each + line with a ';' either, the eval() function already takes care of that. + Please note that the interpreter interface provided by the runtime API is + rather minimalistic right now. In particular, the interpreter always runs + in non-interactive mode (thus none of the interactive commands will work) + and eval() only returns the result of the last computed expression (this is + what gets printed in the read-eval-print loop). */ + #include <stdio.h> #include <pure/runtime.h> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 15:58:29
|
Revision: 301 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=301&view=rev Author: agraef Date: 2008-06-24 08:21:36 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Bugfix: include external symbols in command completion. Modified Paths: -------------- pure/trunk/ChangeLog pure/trunk/lexer.ll pure/trunk/pure.cc Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-06-24 14:53:08 UTC (rev 300) +++ pure/trunk/ChangeLog 2008-06-24 15:21:36 UTC (rev 301) @@ -1,5 +1,8 @@ 2008-06-24 Albert Graef <Dr....@t-...> + * pure.cc, lexer.ll: Bugfix: include external symbols in command + completion. + * interpreter.cc/h, runtime.cc/h, lib/strings.pure: Add error reporting to the eval() routine. Modified: pure/trunk/lexer.ll =================================================================== --- pure/trunk/lexer.ll 2008-06-24 14:53:08 UTC (rev 300) +++ pure/trunk/lexer.ll 2008-06-24 15:21:36 UTC (rev 301) @@ -141,14 +141,18 @@ { static int list_index, len; static env::iterator it, end; + static extmap::iterator xit, xend; const char *name; + assert(interpreter::g_interp); + interpreter& interp = *interpreter::g_interp; /* New match. */ if (!state) { list_index = 0; - assert(interpreter::g_interp); - it = interpreter::g_interp->globenv.begin(); - end = interpreter::g_interp->globenv.end(); + it = interp.globenv.begin(); + end = interp.globenv.end(); + xit = interp.externals.begin(); + xend = interp.externals.end(); len = strlen(text); } @@ -164,12 +168,21 @@ symbol list. */ while (it != end) { assert(it->first > 0); - symbol& sym = interpreter::g_interp->symtab.sym(it->first); + symbol& sym = interp.symtab.sym(it->first); it++; if (strncmp(sym.s.c_str(), text, len) == 0) return strdup(sym.s.c_str()); } + /* Also process the declared externals which don't have any rules yet. */ + while (xit != xend) { + assert(xit->first > 0); + symbol& sym = interp.symtab.sym(xit->first); + xit++; + if (strncmp(sym.s.c_str(), text, len) == 0) + return strdup(sym.s.c_str()); + } + /* If no names matched, then return NULL. */ return 0; } Modified: pure/trunk/pure.cc =================================================================== --- pure/trunk/pure.cc 2008-06-24 14:53:08 UTC (rev 300) +++ pure/trunk/pure.cc 2008-06-24 15:21:36 UTC (rev 301) @@ -54,19 +54,25 @@ /* Generator functions for command completion. */ +typedef map<int32_t,ExternInfo> extmap; + static char * command_generator(const char *text, int state) { static int list_index, len; static env::iterator it, end; + static extmap::iterator xit, xend; const char *name; + assert(interpreter::g_interp); + interpreter& interp = *interpreter::g_interp; /* New match. */ if (!state) { list_index = 0; - assert(interpreter::g_interp); - it = interpreter::g_interp->globenv.begin(); - end = interpreter::g_interp->globenv.end(); + it = interp.globenv.begin(); + end = interp.globenv.end(); + xit = interp.externals.begin(); + xend = interp.externals.end(); len = strlen(text); } @@ -82,12 +88,21 @@ symbol list. */ while (it != end) { assert(it->first > 0); - symbol& sym = interpreter::g_interp->symtab.sym(it->first); + symbol& sym = interp.symtab.sym(it->first); it++; if (strncmp(sym.s.c_str(), text, len) == 0) return strdup(sym.s.c_str()); } + /* Also process the declared externals which don't have any rules yet. */ + while (xit != xend) { + assert(xit->first > 0); + symbol& sym = interp.symtab.sym(xit->first); + xit++; + if (strncmp(sym.s.c_str(), text, len) == 0) + return strdup(sym.s.c_str()); + } + /* If no names matched, then return NULL. */ return 0; } @@ -97,12 +112,16 @@ { static int len; static env::iterator it, end; + static extmap::iterator xit, xend; + assert(interpreter::g_interp); + interpreter& interp = *interpreter::g_interp; /* New match. */ if (!state) { - assert(interpreter::g_interp); - it = interpreter::g_interp->globenv.begin(); - end = interpreter::g_interp->globenv.end(); + it = interp.globenv.begin(); + end = interp.globenv.end(); + xit = interp.externals.begin(); + xend = interp.externals.end(); len = strlen(text); } @@ -110,12 +129,21 @@ symbol list. */ while (it != end) { assert(it->first > 0); - symbol& sym = interpreter::g_interp->symtab.sym(it->first); + symbol& sym = interp.symtab.sym(it->first); it++; if (strncmp(sym.s.c_str(), text, len) == 0) return strdup(sym.s.c_str()); } + /* Also process the declared externals which don't have any rules yet. */ + while (xit != xend) { + assert(xit->first > 0); + symbol& sym = interp.symtab.sym(xit->first); + xit++; + if (strncmp(sym.s.c_str(), text, len) == 0) + return strdup(sym.s.c_str()); + } + /* If no names matched, then return NULL. */ return 0; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 15:57:28
|
Revision: 305 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=305&view=rev Author: agraef Date: 2008-06-24 08:57:36 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Add C->Pure example. Modified Paths: -------------- pure/trunk/Makefile.in Modified: pure/trunk/Makefile.in =================================================================== --- pure/trunk/Makefile.in 2008-06-24 15:51:55 UTC (rev 304) +++ pure/trunk/Makefile.in 2008-06-24 15:57:36 UTC (rev 305) @@ -110,7 +110,7 @@ config/aclocal.m4 config/config.guess config/config.sub config/install-sh \ $(SOURCE) $(EXTRA_SOURCE) w3centities.c \ pure.cc pure.1 pure.1.in etc/pure-mode.el.in etc/pure.* \ -examples/*.pure lib/*.pure test/*.pure test/*.log +examples/*.pure examples/*.c lib/*.pure test/*.pure test/*.log .PHONY: all html dvi ps pdf clean realclean depend install uninstall strip \ dist distcheck cleanlogs logs check config This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 15:51:47
|
Revision: 304 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=304&view=rev Author: agraef Date: 2008-06-24 08:51:55 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Add C->Pure example. Modified Paths: -------------- pure/trunk/ChangeLog Added Paths: ----------- pure/trunk/examples/poor.c Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-06-24 15:38:12 UTC (rev 303) +++ pure/trunk/ChangeLog 2008-06-24 15:51:55 UTC (rev 304) @@ -5,6 +5,8 @@ * pure.cc, lexer.ll: Bugfix: include external symbols in command completion. + * examples/poor.c: Add an example for the new public runtime API. + * interpreter.cc/h, runtime.cc/h, lib/strings.pure: Add error reporting to the eval() routine. Added: pure/trunk/examples/poor.c =================================================================== --- pure/trunk/examples/poor.c (rev 0) +++ pure/trunk/examples/poor.c 2008-06-24 15:51:55 UTC (rev 304) @@ -0,0 +1,35 @@ + +/* Poor man's Pure interpreter. */ + +/* This is an example for the C/C++->Pure interface. It implements a silly + little command loop which reads Pure code, evaluates it, and prints the + results. Compile this with 'gcc -o poor poor.c -lpure', and run as + './poor args...'. You can use the same command line options as with the + real Pure interpreter, including any Pure scripts to be loaded at startup. + + Please note that the interface to the interpreter, as provided by the + public runtime API, is rather minimalistic right now. In particular, the + interpreter will always run in non-interactive mode (thus none of the + interactive commands will work) and eval() will only return the last + computed expression. */ + +#include <stdio.h> +#include <pure/runtime.h> + +int main(int argc, char *argv[]) +{ + pure_interp *interp = pure_create_interp(argc, argv); + char buf[10000]; + fputs("? ", stdout); fflush(stdout); + while (fgets(buf, sizeof(buf), stdin)) { + pure_expr *x = eval(buf); + if (x) { + printf("%s\n", str(x)); + pure_freenew(x); + } else if (lasterr()) + fputs(lasterr(), stderr); + fputs("? ", stdout); fflush(stdout); + } + puts("[quit]"); + return 0; +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 15:38:05
|
Revision: 303 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=303&view=rev Author: agraef Date: 2008-06-24 08:38:12 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Fix up rule to regenerate configury. Modified Paths: -------------- pure/trunk/Makefile.in Modified: pure/trunk/Makefile.in =================================================================== --- pure/trunk/Makefile.in 2008-06-24 15:33:43 UTC (rev 302) +++ pure/trunk/Makefile.in 2008-06-24 15:38:12 UTC (rev 303) @@ -205,14 +205,9 @@ # regenerate configure et al -config: configure config.h.in +config: + autoconf -I config && autoheader -I config -configure: configure.ac config/aclocal.m4 - autoconf -I config - -config.h.in: configure.ac config/aclocal.m4 - autoheader -I config - # installation install: pure$(EXE) etc/pure-mode.el pure.1 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 15:36:00
|
Revision: 302 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=302&view=rev Author: agraef Date: 2008-06-24 08:33:43 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Bump version number. Modified Paths: -------------- pure/trunk/ChangeLog pure/trunk/configure pure/trunk/configure.ac Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-06-24 15:21:36 UTC (rev 301) +++ pure/trunk/ChangeLog 2008-06-24 15:33:43 UTC (rev 302) @@ -1,5 +1,7 @@ 2008-06-24 Albert Graef <Dr....@t-...> + * configure.ac: Bump version number. + * pure.cc, lexer.ll: Bugfix: include external symbols in command completion. Modified: pure/trunk/configure =================================================================== --- pure/trunk/configure 2008-06-24 15:21:36 UTC (rev 301) +++ pure/trunk/configure 2008-06-24 15:33:43 UTC (rev 302) @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.61 for pure 0.4. +# Generated by GNU Autoconf 2.61 for pure 0.5. # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. @@ -572,8 +572,8 @@ # Identity of this package. PACKAGE_NAME='pure' PACKAGE_TARNAME='pure' -PACKAGE_VERSION='0.4' -PACKAGE_STRING='pure 0.4' +PACKAGE_VERSION='0.5' +PACKAGE_STRING='pure 0.5' PACKAGE_BUGREPORT='' # Factoring default headers for most tests. @@ -1198,7 +1198,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures pure 0.4 to adapt to many kinds of systems. +\`configure' configures pure 0.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1263,7 +1263,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of pure 0.4:";; + short | recursive ) echo "Configuration of pure 0.5:";; esac cat <<\_ACEOF @@ -1356,7 +1356,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -pure configure 0.4 +pure configure 0.5 generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1370,7 +1370,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by pure $as_me 0.4, which was +It was created by pure $as_me 0.5, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ @@ -5764,7 +5764,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by pure $as_me 0.4, which was +This file was extended by pure $as_me 0.5, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -5813,7 +5813,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -pure config.status 0.4 +pure config.status 0.5 configured by $0, generated by GNU Autoconf 2.61, with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" Modified: pure/trunk/configure.ac =================================================================== --- pure/trunk/configure.ac 2008-06-24 15:21:36 UTC (rev 301) +++ pure/trunk/configure.ac 2008-06-24 15:33:43 UTC (rev 302) @@ -2,7 +2,7 @@ dnl To regenerate the configury after changes: dnl autoconf -I config && autoheader -I config -AC_INIT(pure, 0.4) +AC_INIT(pure, 0.5) AC_CONFIG_AUX_DIR(config) dnl AC_CONFIG_MACRO_DIR(config) AC_CONFIG_HEADERS(config.h) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 14:53:06
|
Revision: 300 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=300&view=rev Author: agraef Date: 2008-06-24 07:53:08 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Updated ChangeLog. Modified Paths: -------------- pure/trunk/ChangeLog Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-06-24 14:49:19 UTC (rev 299) +++ pure/trunk/ChangeLog 2008-06-24 14:53:08 UTC (rev 300) @@ -1,5 +1,11 @@ 2008-06-24 Albert Graef <Dr....@t-...> + * interpreter.cc/h, runtime.cc/h, lib/strings.pure: Add error + reporting to the eval() routine. + + * interpreter.cc: Bugfix to make recursive source file parses work + inside eval(). + * runtime.h, runtime.cc: Refactored the runtime library to provide a semantically complete public API for module writers. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 14:49:12
|
Revision: 299 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=299&view=rev Author: agraef Date: 2008-06-24 07:49:19 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Bugfix: source_s must be saved during a recursive parse. Modified Paths: -------------- pure/trunk/interpreter.cc Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-06-24 14:36:02 UTC (rev 298) +++ pure/trunk/interpreter.cc 2008-06-24 14:49:19 UTC (rev 299) @@ -398,6 +398,7 @@ string l_source = source; int l_nerrs = nerrs; uint8_t l_temp = temp; + const char *l_source_s = source_s; // save global data uint8_t s_verbose = g_verbose; bool s_interactive = g_interactive; @@ -408,6 +409,7 @@ // initialize nerrs = 0; source = s; declare_op = false; + source_s = 0; errmsg.clear(); if (check && !interactive) temp = 0; bool ok = lex_begin(); @@ -432,6 +434,7 @@ source = l_source; nerrs = l_nerrs; temp = l_temp; + source_s = l_source_s; // return last computed result, if any return result; } @@ -449,6 +452,7 @@ bool l_interactive = interactive; string l_source = source; int l_nerrs = nerrs; + const char *l_source_s = source_s; // save global data uint8_t s_verbose = g_verbose; bool s_interactive = g_interactive; @@ -479,6 +483,7 @@ source = l_source; source_s = 0; nerrs = l_nerrs; + source_s = l_source_s; // return last computed result, if any return result; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 14:36:04
|
Revision: 298 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=298&view=rev Author: agraef Date: 2008-06-24 07:36:02 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Fix some C compilation quirks and add some error reporting to the eval function. Modified Paths: -------------- pure/trunk/interpreter.cc pure/trunk/interpreter.hh pure/trunk/lib/strings.pure pure/trunk/runtime.cc pure/trunk/runtime.h Modified: pure/trunk/interpreter.cc =================================================================== --- pure/trunk/interpreter.cc 2008-06-24 12:48:18 UTC (rev 297) +++ pure/trunk/interpreter.cc 2008-06-24 14:36:02 UTC (rev 298) @@ -333,30 +333,46 @@ interpreter::error(const yy::location& l, const string& m) { nerrs++; - cout.flush(); - if (!source_s) cerr << l << ": " << m << endl; + if (source_s) { + ostringstream msg; + msg << l << ": " << m << endl; + errmsg += msg.str(); + } else { + cout.flush(); + cerr << l << ": " << m << endl; + } } void interpreter::error(const string& m) { nerrs++; - cout.flush(); - if (!source_s) cerr << m << endl; + if (source_s) { + ostringstream msg; + msg << m << endl; + errmsg += msg.str(); + } else { + cout.flush(); + cerr << m << endl; + } } void interpreter::warning(const yy::location& l, const string& m) { - cout.flush(); - if (!source_s) cerr << l << ": " << m << endl; + if (!source_s) { + cout.flush(); + cerr << l << ": " << m << endl; + } } void interpreter::warning(const string& m) { - cout.flush(); - if (!source_s) cerr << m << endl; + if (!source_s) { + cout.flush(); + cerr << m << endl; + } } // Run the interpreter on a source file, collection of source files, or on @@ -392,6 +408,7 @@ // initialize nerrs = 0; source = s; declare_op = false; + errmsg.clear(); if (check && !interactive) temp = 0; bool ok = lex_begin(); if (ok) { @@ -443,6 +460,7 @@ nerrs = 0; source = ""; declare_op = false; source_s = s.c_str(); + errmsg.clear(); bool ok = lex_begin(); if (ok) { yy::parser parser(*this); Modified: pure/trunk/interpreter.hh =================================================================== --- pure/trunk/interpreter.hh 2008-06-24 12:48:18 UTC (rev 297) +++ pure/trunk/interpreter.hh 2008-06-24 14:36:02 UTC (rev 298) @@ -262,6 +262,7 @@ // Interpreter state. For internal use only. int nerrs; // current error count + string errmsg; // last reported error (runstr) string source; // the source being parsed const char *source_s; // source pointer if input comes from a string set<string> sources; // the list of all scripts which have been loaded @@ -293,7 +294,9 @@ pure_expr *run(const list<string>& sources, bool check = true); /* This works like run() above, but takes the source directly from a - string. */ + string. No error messages will be printed, instead any errors reported + during the most recent invokation of this method are available in + errmsg. */ pure_expr *runstr(const string& source); /* Evaluate a (compile time) expression and return the (runtime expression) Modified: pure/trunk/lib/strings.pure =================================================================== --- pure/trunk/lib/strings.pure 2008-06-24 12:48:18 UTC (rev 297) +++ pure/trunk/lib/strings.pure 2008-06-24 14:36:02 UTC (rev 298) @@ -23,10 +23,14 @@ eval function does the opposite, by parsing and returning the value of an expression specified as a string in Pure syntax. (In fact, eval goes well beyond this, as it can parse and execute arbitrary Pure code. In that case - it will return the last computed expression, if any.) */ + it will return the last computed expression, if any.) Errors are reported + with the lasterr routine. This string value will be nonempty iff an error + was encountered during the most recent invokation of eval(). In that case + each reported error message is terminated with a newline character. */ extern void* str(expr*) = pure_str; extern expr* eval(char*); // IMPURE! +extern char* lasterr(); str x = cstring (pure_str x); Modified: pure/trunk/runtime.cc =================================================================== --- pure/trunk/runtime.cc 2008-06-24 12:48:18 UTC (rev 297) +++ pure/trunk/runtime.cc 2008-06-24 14:36:02 UTC (rev 298) @@ -814,7 +814,7 @@ #include <llvm/Target/TargetOptions.h> extern "C" -pure_interp *pure_create_interp(int argc, const char *argv[]) +pure_interp *pure_create_interp(int argc, char *argv[]) { // This is pretty much the same as pure.cc:main(), except that some options // are ignored and there's no user interaction. @@ -847,7 +847,7 @@ #endif // scan the command line options list<string> myargs; - for (const char **args = ++argv; *args; ++args) + for (char **args = ++argv; *args; ++args) if (*args == string("-h")) /* ignored */; else if (*args == string("-i")) @@ -1984,12 +1984,20 @@ { assert(s); interpreter& interp = *interpreter::g_interp; + interp.errmsg.clear(); pure_expr *res = interp.runstr(string(s)+";"); interp.result = 0; if (res) pure_unref_internal(res); return res; } +extern "C" +const char *lasterr() +{ + interpreter& interp = *interpreter::g_interp; + return interp.errmsg.c_str(); +} + static uint32_t mpz_hash(const mpz_t z) { uint32_t h = 0; Modified: pure/trunk/runtime.h =================================================================== --- pure/trunk/runtime.h 2008-06-24 12:48:18 UTC (rev 297) +++ pure/trunk/runtime.h 2008-06-24 14:36:02 UTC (rev 298) @@ -250,9 +250,9 @@ the library API (see below) to first unparse the expression in the source interpreter and then reparse it in the target interpreter. */ -typedef struct pure_interp; // Pure interpreter handles (opaque). +typedef struct _pure_interp pure_interp; // Pure interpreter handles (opaque). -pure_interp *pure_create_interp(int argc, const char *argv[]); +pure_interp *pure_create_interp(int argc, char *argv[]); void pure_delete_interp(pure_interp *interp); void pure_switch_interp(pure_interp *interp); @@ -444,12 +444,19 @@ /* Convert a Pure expression to a string and vice versa. Note that eval() will actually parse and execute any Pure source, so it can be used, e.g., to add new rules to the executing program at runtime. The result of eval() is the - last computed expression (NULL if none). The result of str() is a malloc'ed - string in the system encoding which must be freed by the caller. */ + last computed expression, NULL if none; in the latter case you can inspect + the result of lasterr() below to determine whether there were any errors. + The result of str() is a malloc'ed string in the system encoding which must + be freed by the caller. */ char *str(const pure_expr *x); pure_expr *eval(const char *s); +/* After an invokation of eval(), this returns error messages from the + interpreter (an empty string if none). */ + +const char *lasterr(); + /* Compute a 32 bit hash code of a Pure expression. This makes it possible to use arbitary Pure values as keys in a hash table. */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 12:48:09
|
Revision: 297 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=297&view=rev Author: agraef Date: 2008-06-24 05:48:18 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Updated ChangeLog. Modified Paths: -------------- pure/trunk/ChangeLog Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-06-24 12:41:37 UTC (rev 296) +++ pure/trunk/ChangeLog 2008-06-24 12:48:18 UTC (rev 297) @@ -1,3 +1,15 @@ +2008-06-24 Albert Graef <Dr....@t-...> + + * runtime.h, runtime.cc: Refactored the runtime library to provide + a semantically complete public API for module writers. + + These operations are meant to be used by client modules or + standalone applications which need to create their own Pure + interpreters and/or require direct access to Pure expression + data. See the PUBLIC API section in runtime.h for details. Modules + created with this API must be linked against the runtime library + (libpure.so). + 2008-06-23 Albert Graef <Dr....@t-...> * runtime.h, runtime.cc: Make pure_invoke() callable from C. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 12:41:28
|
Revision: 296 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=296&view=rev Author: agraef Date: 2008-06-24 05:41:37 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Finish off public runtime API with some operations to create standalone interpreters. Modified Paths: -------------- pure/trunk/runtime.cc pure/trunk/runtime.h Modified: pure/trunk/runtime.cc =================================================================== --- pure/trunk/runtime.cc 2008-06-24 10:38:29 UTC (rev 295) +++ pure/trunk/runtime.cc 2008-06-24 12:41:37 UTC (rev 296) @@ -801,6 +801,144 @@ pure_unref_internal(x); } +#ifndef HOST +#define HOST "unknown" +#endif +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "0.0" +#endif +#ifndef PURELIB +#define PURELIB "/usr/local/lib/pure-" PACKAGE_VERSION +#endif + +#include <llvm/Target/TargetOptions.h> + +extern "C" +pure_interp *pure_create_interp(int argc, const char *argv[]) +{ + // This is pretty much the same as pure.cc:main(), except that some options + // are ignored and there's no user interaction. + char base; + interpreter *_interp = new interpreter, &interp = *_interp; + int count = 0; + bool want_prelude = true, have_prelude = false; + // This is used in advisory stack checks. + if (!interpreter::baseptr) interpreter::baseptr = &base; + // get some settings from the environment + const char *env; + if ((env = getenv("HOME"))) + interp.histfile = string(env)+"/.pure_history"; + if ((env = getenv("PURE_PS"))) + interp.ps = string(env); + if ((env = getenv("PURE_STACK"))) { + char *end; + 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 USE_FASTCC + // This global option is needed to get tail call optimization (you'll also + // need to have USE_FASTCC in interpreter.hh enabled). + llvm::PerformTailCallOpt = true; +#endif + // scan the command line options + list<string> myargs; + for (const char **args = ++argv; *args; ++args) + if (*args == string("-h")) + /* ignored */; + else if (*args == string("-i")) + /* ignored */; + else if (*args == string("-n")) + want_prelude = false; + else if (*args == string("-q")) + /* ignored */; + 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); + if (*end) { + cerr << "pure_create_interp: invalid option " << *args << endl; + delete _interp; + return 0; + } + } else if (*args == string("-x")) { + while (*++args) myargs.push_back(*args); + break; + } else if (*args == string("--")) { + while (*++args) myargs.push_back(*args); + break; + } else if (**args == '-') { + cerr << "pure_create_interp: invalid option " << *args << endl; + delete _interp; + return 0; + } + 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); + have_prelude = true; + interp.run(prelude); + interp.compile(); + } + } + // load scripts specified on the command line + for (; *argv; ++argv) + if (string(*argv).substr(0,2) == "-v") { + uint8_t level = 1; + string s = string(*argv).substr(2); + if (!s.empty()) level = (uint8_t)strtoul(s.c_str(), 0, 0); + interp.verbose = level; + } else if (*argv == string("-x")) { + if (*++argv) { + count++; interp.modname = *argv; + interp.run(*argv); + } else { + cerr << "pure_create_interp: missing script name\n"; + delete _interp; + return 0; + } + break; + } else if (*argv == string("--")) + break; + else if (**argv == '-') + ; + else if (**argv) { + if (count++ == 0) interp.modname = *argv; + interp.run(*argv); + } + interp.symtab.init_builtins(); + return (pure_interp*)_interp; +} + +extern "C" +void pure_delete_interp(pure_interp *interp) +{ + assert(interp); + interpreter *_interp = (interpreter*)interp; + if (interpreter::g_interp == _interp) + interpreter::g_interp = 0; + delete _interp; +} + +extern "C" +void pure_switch_interp(pure_interp *interp) +{ + assert(interp); + interpreter::g_interp = (interpreter*)interp; +} + /* END OF PUBLIC API. *******************************************************/ extern "C" Modified: pure/trunk/runtime.h =================================================================== --- pure/trunk/runtime.h 2008-06-24 10:38:29 UTC (rev 295) +++ pure/trunk/runtime.h 2008-06-24 12:41:37 UTC (rev 296) @@ -221,6 +221,41 @@ void pure_ref(pure_expr *x); void pure_unref(pure_expr *x); +/* The following routines provide standalone C/C++ applications with fully + initialized interpreter instances which can be used together with the + operations listed above. This is only needed for modules which are not to + be loaded by the command line version of the interpreter. + + The argc, argv parameters passed to pure_create_interp specify the command + line arguments of the interpreter instance. This includes any scripts that + are to be loaded on startup as well as any other options understood by the + command line version of the interpreter (options like -i and -q won't have + any effect, though, and the interpreter will always be in non-interactive + mode). The argv vector must be NULL-terminated, and argv[0] should be set + to the name of the hosting application (usually the main program of the + application). + + An application may use multiple interpreter instances, but only a single + instance can be active at any one time. By default, the first created + instance will be active, but you can switch between different instances + with the pure_switch_interp function. The pure_delete_interp routine + destroys an interpreter instance; if the destroyed instance is currently + active, the active instance will be undefined afterwards, so you'll have to + either create or switch to another instance before calling any other + operations. + + Note that when using different interpreter instances in concert, it is + *not* possible to pass pure_expr* values created with one interpreter + instance to another. Instead, you can use the str and eval functions from + the library API (see below) to first unparse the expression in the source + interpreter and then reparse it in the target interpreter. */ + +typedef struct pure_interp; // Pure interpreter handles (opaque). + +pure_interp *pure_create_interp(int argc, const char *argv[]); +void pure_delete_interp(pure_interp *interp); +void pure_switch_interp(pure_interp *interp); + /* END OF PUBLIC API. *******************************************************/ /* Stuff below this line is for internal use by the Pure interpreter. Don't This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 10:38:20
|
Revision: 295 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=295&view=rev Author: agraef Date: 2008-06-24 03:38:29 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Add convenience functions to (de)construct a function application from/to a function object and a number of argument expressions. Modified Paths: -------------- pure/trunk/runtime.cc pure/trunk/runtime.h Modified: pure/trunk/runtime.cc =================================================================== --- pure/trunk/runtime.cc 2008-06-24 09:54:51 UTC (rev 294) +++ pure/trunk/runtime.cc 2008-06-24 10:38:29 UTC (rev 295) @@ -458,6 +458,27 @@ return pure_apply2(fun, arg); } +extern "C" +pure_expr *pure_appl(pure_expr *fun, size_t argc, ...) +{ + if (argc == 0) return fun; + va_list ap; + va_start(ap, argc); + pure_expr **args = (pure_expr**)alloca(argc*sizeof(pure_expr*)); + for (size_t i = 0; i < argc; i++) + args[i] = va_arg(ap, pure_expr*); + return pure_appv(fun, argc, args); +} + +extern "C" +pure_expr *pure_appv(pure_expr *fun, size_t argc, pure_expr **args) +{ + pure_expr *y = fun; + for (size_t i = 0; i < argc; i++) + y = pure_apply2(y, args[i]); + return y; +} + static inline pure_expr *mk_nil() { interpreter& interp = *interpreter::g_interp; @@ -627,6 +648,35 @@ return false; } +extern "C" +bool pure_is_appv(pure_expr *x, pure_expr **_fun, + size_t *_argc, pure_expr ***_args) +{ + assert(x); + pure_expr *u = x, *y, *z; + size_t argc = 0; + while (pure_is_app(u, &y, &z)) { + argc++; + u = y; + } + if (_fun) *_fun = u; + if (_argc) *_argc = argc; + if (_args) + if (argc > 0) { + pure_expr **args = (pure_expr**)malloc(argc*sizeof(pure_expr*)); + assert(args); + size_t i = argc; + u = x; + while (pure_is_app(u, &y, &z)) { + args[--i] = z; + u = y; + } + *_args = args; + } else + *_args = 0; + return true; +} + static inline bool is_nil(pure_expr *x) { interpreter& interp = *interpreter::g_interp; @@ -666,6 +716,7 @@ extern "C" bool pure_is_listv(pure_expr *x, size_t *_size, pure_expr ***_elems) { + assert(x); pure_expr *u = x, *y, *z; size_t size = 0; while (is_cons(u, y, z)) { @@ -675,8 +726,9 @@ if (!is_nil(u)) return false; if (_size) *_size = size; if (_elems) - if (size>0) { + if (size > 0) { pure_expr **elems = (pure_expr**)malloc(size*sizeof(pure_expr*)); + assert(elems); size_t i = 0; u = x; while (is_cons(u, y, z)) { @@ -692,6 +744,7 @@ extern "C" bool pure_is_tuplev(pure_expr *x, size_t *_size, pure_expr ***_elems) { + assert(x); /* FIXME: This implementation assumes that tuples are right-recursive. If we change the tuple implementation in the prelude then this code has to be adapted accordingly. */ @@ -704,6 +757,7 @@ if (_size) *_size = size; if (_elems) { pure_expr **elems = (pure_expr**)malloc(size*sizeof(pure_expr*)); + assert(elems); size_t i = 0; u = x; while (is_pair(u, y, z)) { Modified: pure/trunk/runtime.h =================================================================== --- pure/trunk/runtime.h 2008-06-24 09:54:51 UTC (rev 294) +++ pure/trunk/runtime.h 2008-06-24 10:38:29 UTC (rev 295) @@ -116,6 +116,14 @@ pure_expr *pure_app(pure_expr *fun, pure_expr *arg); +/* Convenience functions to construct an application of the given function to + a vector or varargs list of argument expressions. The vectors are owned by + the caller and won't be freed. References on the argument expressions are + counted automatically. */ + +pure_expr *pure_appl(pure_expr *fun, size_t argc, ...); +pure_expr *pure_appv(pure_expr *fun, size_t argc, pure_expr **args); + /* Convenience functions to construct Pure list and tuple values from a vector or a varargs list of element expressions. (Internally these are actually represented as function applications.) The vectors are owned by the caller @@ -166,10 +174,23 @@ bool pure_is_app(const pure_expr *x, pure_expr **fun, pure_expr **arg); -/* Convenience functions to deconstruct lists and tuples. Returned element - vectors are malloc'd and must be freed by the caller. Note that +/* Convenience function to decompose a function application into a function + and a vector of argument expressions. The returned element vectors are + malloc'ed and must be freed by the caller (unless the number of arguments + is zero in which case the returned vector will be NULL). Note that this + function always yields true, since a singleton expression which is not an + application is considered to be a function applied to zero arguments. In + such a case you can check the returned function object with pure_is_symbol + to see whether it actually is a symbol or closure. */ + +bool pure_is_appv(pure_expr *x, pure_expr **fun, + size_t *argc, pure_expr ***args); + +/* Convenience functions to deconstruct lists and tuples. The returned element + vectors are malloc'ed and must be freed by the caller (unless the number of + elements is zero in which case the returned vector will be NULL). Note that pure_is_tuplev will always return true, since a singleton expression, which - is not either a pair or (), is considered a tuple of size 1. */ + is not either a pair or (), is considered to be a tuple of size 1. */ bool pure_is_listv(pure_expr *x, size_t *size, pure_expr ***elems); bool pure_is_tuplev(pure_expr *x, size_t *size, pure_expr ***elems); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 09:54:42
|
Revision: 294 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=294&view=rev Author: agraef Date: 2008-06-24 02:54:51 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Implement list/tuple convenience operations. Modified Paths: -------------- pure/trunk/runtime.cc pure/trunk/runtime.h Modified: pure/trunk/runtime.cc =================================================================== --- pure/trunk/runtime.cc 2008-06-24 08:56:30 UTC (rev 293) +++ pure/trunk/runtime.cc 2008-06-24 09:54:51 UTC (rev 294) @@ -458,13 +458,76 @@ return pure_apply2(fun, arg); } -// XXXTODO +static inline pure_expr *mk_nil() +{ + interpreter& interp = *interpreter::g_interp; + return pure_const(interp.symtab.nil_sym().f); +} -pure_expr *pure_listl(size_t size, ...); -pure_expr *pure_listv(size_t size, pure_expr **elems); -pure_expr *pure_tuplel(size_t size, ...); -pure_expr *pure_tuplev(size_t size, pure_expr **elems); +static inline pure_expr *mk_cons(pure_expr *x, pure_expr *y) +{ + interpreter& interp = *interpreter::g_interp; + pure_expr *f = pure_const(interp.symtab.cons_sym().f); + return pure_apply2(pure_apply2(f, x), y); +} +static inline pure_expr *mk_void() +{ + interpreter& interp = *interpreter::g_interp; + return pure_const(interp.symtab.void_sym().f); +} + +static inline pure_expr *mk_pair(pure_expr *x, pure_expr *y) +{ + interpreter& interp = *interpreter::g_interp; + pure_expr *f = pure_const(interp.symtab.pair_sym().f); + return pure_apply2(pure_apply2(f, x), y); +} + +extern "C" +pure_expr *pure_listl(size_t size, ...) +{ + if (size == 0) return mk_nil(); + va_list ap; + va_start(ap, size); + pure_expr **elems = (pure_expr**)alloca(size*sizeof(pure_expr*)); + for (size_t i = 0; i < size; i++) + elems[i] = va_arg(ap, pure_expr*); + return pure_listv(size, elems); +} + +extern "C" +pure_expr *pure_listv(size_t size, pure_expr **elems) +{ + pure_expr *y = mk_nil(); + for (size_t i = size; i-- > 0; ) + y = mk_cons(elems[i], y); + return y; +} + +extern "C" +pure_expr *pure_tuplel(size_t size, ...) +{ + if (size == 0) return mk_void(); + va_list ap; + va_start(ap, size); + pure_expr **elems = (pure_expr**)alloca(size*sizeof(pure_expr*)); + for (size_t i = 0; i < size; i++) + elems[i] = va_arg(ap, pure_expr*); + return pure_tuplev(size, elems); +} + +extern "C" +pure_expr *pure_tuplev(size_t size, pure_expr **elems) +{ + if (size == 0) return mk_void(); + pure_expr *y = elems[--size]; + for (size_t i = size; i-- > 0; ) + y = mk_pair(elems[i], y); + return y; +} + +extern "C" bool pure_is_symbol(const pure_expr *x, int32_t *sym) { assert(x); @@ -475,6 +538,7 @@ return false; } +extern "C" bool pure_is_int(const pure_expr *x, int32_t *i) { assert(x); @@ -485,6 +549,7 @@ return false; } +extern "C" bool pure_is_mpz(const pure_expr *x, mpz_t *z) { assert(x); @@ -495,6 +560,7 @@ return false; } +extern "C" bool pure_is_double(const pure_expr *x, double *d) { assert(x); @@ -505,6 +571,7 @@ return false; } +extern "C" bool pure_is_pointer(const pure_expr *x, void **p) { assert(x); @@ -515,6 +582,7 @@ return false; } +extern "C" bool pure_is_string(const pure_expr *x, const char **s) { assert(x); @@ -525,6 +593,7 @@ return false; } +extern "C" bool pure_is_string_dup(const pure_expr *x, char **s) { assert(x); @@ -535,6 +604,7 @@ return false; } +extern "C" bool pure_is_cstring_dup(const pure_expr *x, char **s) { assert(x); @@ -545,6 +615,7 @@ return false; } +extern "C" bool pure_is_app(const pure_expr *x, pure_expr **fun, pure_expr **arg) { assert(x); @@ -556,12 +627,96 @@ return false; } -// XXXTODO +static inline bool is_nil(pure_expr *x) +{ + interpreter& interp = *interpreter::g_interp; + return x->tag == interp.symtab.nil_sym().f; +} -bool pure_is_listv(const pure_expr *x, size_t *size, pure_expr ***elems); -bool pure_is_tuplev(const pure_expr *x, size_t *size, pure_expr ***elems); +static inline bool is_cons(pure_expr *x, pure_expr*& y, pure_expr*& z) +{ + interpreter& interp = *interpreter::g_interp; + if (x->tag == EXPR::APP && x->data.x[0]->tag == EXPR::APP && + x->data.x[0]->data.x[0]->tag == interp.symtab.cons_sym().f) { + y = x->data.x[0]->data.x[1]; + z = x->data.x[1]; + return true; + } else + return false; +} +static inline bool is_void(pure_expr *x) +{ + interpreter& interp = *interpreter::g_interp; + return x->tag == interp.symtab.void_sym().f; +} + +static inline bool is_pair(pure_expr *x, pure_expr*& y, pure_expr*& z) +{ + interpreter& interp = *interpreter::g_interp; + if (x->tag == EXPR::APP && x->data.x[0]->tag == EXPR::APP && + x->data.x[0]->data.x[0]->tag == interp.symtab.pair_sym().f) { + y = x->data.x[0]->data.x[1]; + z = x->data.x[1]; + return true; + } else + return false; +} + extern "C" +bool pure_is_listv(pure_expr *x, size_t *_size, pure_expr ***_elems) +{ + pure_expr *u = x, *y, *z; + size_t size = 0; + while (is_cons(u, y, z)) { + size++; + u = z; + } + if (!is_nil(u)) return false; + if (_size) *_size = size; + if (_elems) + if (size>0) { + pure_expr **elems = (pure_expr**)malloc(size*sizeof(pure_expr*)); + size_t i = 0; + u = x; + while (is_cons(u, y, z)) { + elems[i++] = y; + u = z; + } + *_elems = elems; + } else + *_elems = 0; + return true; +} + +extern "C" +bool pure_is_tuplev(pure_expr *x, size_t *_size, pure_expr ***_elems) +{ + /* FIXME: This implementation assumes that tuples are right-recursive. If we + change the tuple implementation in the prelude then this code has to be + adapted accordingly. */ + pure_expr *u = x, *y, *z; + size_t size = 1; + while (is_pair(u, y, z)) { + size++; + u = z; + } + if (_size) *_size = size; + if (_elems) { + pure_expr **elems = (pure_expr**)malloc(size*sizeof(pure_expr*)); + size_t i = 0; + u = x; + while (is_pair(u, y, z)) { + elems[i++] = y; + u = z; + } + elems[i++] = u; + *_elems = elems; + } + return true; +} + +extern "C" pure_expr *pure_new(pure_expr *x) { return pure_new_internal(x); @@ -1564,24 +1719,6 @@ return x; } -static inline bool is_nil(pure_expr *xs) -{ - interpreter& interp = *interpreter::g_interp; - return xs->tag == interp.symtab.nil_sym().f; -} - -static inline bool is_cons(pure_expr *xs, pure_expr*& y, pure_expr*& ys) -{ - interpreter& interp = *interpreter::g_interp; - if (xs->tag == EXPR::APP && xs->data.x[0]->tag == EXPR::APP && - xs->data.x[0]->data.x[0]->tag == interp.symtab.cons_sym().f) { - y = xs->data.x[0]->data.x[1]; - ys = xs->data.x[1]; - return true; - } else - return false; -} - extern "C" pure_expr *string_concat_list(pure_expr *xs) { Modified: pure/trunk/runtime.h =================================================================== --- pure/trunk/runtime.h 2008-06-24 08:56:30 UTC (rev 293) +++ pure/trunk/runtime.h 2008-06-24 09:54:51 UTC (rev 294) @@ -171,8 +171,8 @@ pure_is_tuplev will always return true, since a singleton expression, which is not either a pair or (), is considered a tuple of size 1. */ -bool pure_is_listv(const pure_expr *x, size_t *size, pure_expr ***elems); -bool pure_is_tuplev(const pure_expr *x, size_t *size, pure_expr ***elems); +bool pure_is_listv(pure_expr *x, size_t *size, pure_expr ***elems); +bool pure_is_tuplev(pure_expr *x, size_t *size, pure_expr ***elems); /* Memory management. */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 08:56:22
|
Revision: 293 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=293&view=rev Author: agraef Date: 2008-06-24 01:56:30 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Clean up the public API and implement most operations. Modified Paths: -------------- pure/trunk/runtime.cc pure/trunk/runtime.h Modified: pure/trunk/runtime.cc =================================================================== --- pure/trunk/runtime.cc 2008-06-24 00:31:37 UTC (rev 292) +++ pure/trunk/runtime.cc 2008-06-24 08:56:30 UTC (rev 293) @@ -300,62 +300,82 @@ /* PUBLIC API. **************************************************************/ -// XXXTODO +extern "C" +int32_t pure_sym(const char *s) +{ + assert(s); + interpreter& interp = *interpreter::g_interp; + const symbol& sym = interp.symtab.sym(s); + return sym.f; +} -int32_t pure_sym(const char *s); -int32_t pure_getsym(const char *s); -const char *pure_sym_pname(int32_t sym); -int8_t pure_sym_nprec(int32_t sym); +extern "C" +int32_t pure_getsym(const char *s) +{ + assert(s); + interpreter& interp = *interpreter::g_interp; + const symbol* sym = interp.symtab.lookup(s); + if (sym) + return sym->f; + else + return 0; +} -pure_expr *pure_symbol(int32_t sym); - extern "C" -pure_expr *pure_int(int32_t i) +const char *pure_sym_pname(int32_t tag) { - pure_expr *x = new_expr(); - x->tag = EXPR::INT; - x->data.i = i; - MEMDEBUG_NEW(x) - return x; + assert(tag>0); + interpreter& interp = *interpreter::g_interp; + const symbol& sym = interp.symtab.sym(tag); + return sym.s.c_str(); } extern "C" -pure_expr *pure_long(int64_t l) +int8_t pure_sym_nprec(int32_t tag) { - int sgn = (l>0)?1:(l<0)?-1:0; - uint64_t v = (uint64_t)(l>=0?l:-l); - if (sizeof(mp_limb_t) == 8) { - // 8 byte limbs, value fits in a single limb. - limb_t u[1] = { v }; - return pure_bigint(sgn, u); - } else { - // 4 byte limbs, put least significant word in the first limb. - limb_t u[2] = { (uint32_t)v, (uint32_t)(v>>32) }; - return pure_bigint(sgn+sgn, u); - } + assert(tag>0); + interpreter& interp = *interpreter::g_interp; + const symbol& sym = interp.symtab.sym(tag); + return nprec(sym.prec, sym.fix); } -static void make_bigint(mpz_t z, int32_t size, const limb_t *limbs) +extern "C" +pure_expr *pure_symbol(int32_t tag) { - // FIXME: For efficiency, we poke directly into the mpz struct here, this - // might need to be reviewed for future GMP revisions. - int sz = size>=0?size:-size, sgn = size>0?1:size<0?-1:0, sz0 = 0; - // normalize: the most significant limb should be nonzero - for (int i = 0; i < sz; i++) if (limbs[i] != 0) sz0 = i+1; - sz = sz0; size = sgn*sz; - mpz_init(z); - if (sz > 0) _mpz_realloc(z, sz); - assert(sz == 0 || z->_mp_d); - for (int i = 0; i < sz; i++) z->_mp_d[i] = limbs[i]; - z->_mp_size = size; + assert(tag>0); + interpreter& interp = *interpreter::g_interp; + const symbol& sym = interp.symtab.sym(tag); + // Check for an existing global variable for this symbol. + GlobalVar& v = interp.globalvars[tag]; + if (!v.v) { + // The variable doesn't exist yet (we have a new symbol), create it. + string lab; + // Create a name for the variable (cf. interpreter::mkvarlabel). + if (sym.prec < 10 || sym.fix == nullary) + lab = "$("+sym.s+")"; + else + lab = "$"+sym.s; + // Create a global variable bound to the symbol for now. + v.v = new llvm::GlobalVariable + (interp.ExprPtrTy, false, llvm::GlobalVariable::InternalLinkage, 0, + lab.c_str(), interp.module); + interp.JIT->addGlobalMapping(v.v, &v.x); + v.x = pure_new(pure_const(tag)); + // Since we just created this variable, it doesn't have any closure bound + // to it yet, so it's safe to just return the symbol as is. + return v.x; + } else + // The symbol already exists, so there might be a parameterless closure + // bound to it and thus we need to evaluate it. + return pure_call(v.x); } extern "C" -pure_expr *pure_bigint(int32_t size, const limb_t *limbs) +pure_expr *pure_int(int32_t i) { pure_expr *x = new_expr(); - x->tag = EXPR::BIGINT; - make_bigint(x->data.z, size, limbs); + x->tag = EXPR::INT; + x->data.i = i; MEMDEBUG_NEW(x) return x; } @@ -432,29 +452,112 @@ return x; } +extern "C" +pure_expr *pure_app(pure_expr *fun, pure_expr *arg) +{ + return pure_apply2(fun, arg); +} + // XXXTODO -pure_expr *pure_app(pure_expr *fun, pure_expr *arg); - pure_expr *pure_listl(size_t size, ...); pure_expr *pure_listv(size_t size, pure_expr **elems); pure_expr *pure_tuplel(size_t size, ...); pure_expr *pure_tuplev(size_t size, pure_expr **elems); -bool pure_is_symbol(const pure_expr *x, int32_t *sym); -bool pure_is_int(const pure_expr *x, int32_t *i); -bool pure_is_long(const pure_expr *x, int64_t *l); -bool pure_is_bigint(const pure_expr *x, int32_t *size, limb_t **limbs); -bool pure_is_mpz(const pure_expr *x, mpz_t *z); -bool pure_is_double(const pure_expr *x, double *d); -bool pure_is_pointer(const pure_expr *x, void **p); +bool pure_is_symbol(const pure_expr *x, int32_t *sym) +{ + assert(x); + if (x->tag >= 0) { + if (sym) *sym = x->tag; + return true; + } else + return false; +} -bool pure_is_string(const pure_expr *x, const char **sym); -bool pure_is_string_dup(const pure_expr *x, char **sym); -bool pure_is_cstring_dup(const pure_expr *x, char **sym); +bool pure_is_int(const pure_expr *x, int32_t *i) +{ + assert(x); + if (x->tag == EXPR::INT) { + if (i) *i = x->data.i; + return true; + } else + return false; +} -bool pure_is_app(const pure_expr *x, pure_expr **fun, pure_expr **arg); +bool pure_is_mpz(const pure_expr *x, mpz_t *z) +{ + assert(x); + if (x->tag == EXPR::BIGINT) { + if (z) mpz_init_set(*z, x->data.z); + return true; + } else + return false; +} +bool pure_is_double(const pure_expr *x, double *d) +{ + assert(x); + if (x->tag == EXPR::DBL) { + if (d) *d = x->data.d; + return true; + } else + return false; +} + +bool pure_is_pointer(const pure_expr *x, void **p) +{ + assert(x); + if (x->tag == EXPR::PTR) { + if (p) *p = x->data.p; + return true; + } else + return false; +} + +bool pure_is_string(const pure_expr *x, const char **s) +{ + assert(x); + if (x->tag == EXPR::STR) { + if (s) *s = x->data.s; + return true; + } else + return false; +} + +bool pure_is_string_dup(const pure_expr *x, char **s) +{ + assert(x); + if (x->tag == EXPR::STR) { + if (s) *s = strdup(x->data.s); + return true; + } else + return false; +} + +bool pure_is_cstring_dup(const pure_expr *x, char **s) +{ + assert(x); + if (x->tag == EXPR::STR) { + if (s) *s = fromutf8(x->data.s); + return true; + } else + return false; +} + +bool pure_is_app(const pure_expr *x, pure_expr **fun, pure_expr **arg) +{ + assert(x); + if (x->tag == EXPR::APP) { + if (fun) *fun = x->data.x[0]; + if (arg) *arg = x->data.x[1]; + return true; + } else + return false; +} + +// XXXTODO + bool pure_is_listv(const pure_expr *x, size_t *size, pure_expr ***elems); bool pure_is_tuplev(const pure_expr *x, size_t *size, pure_expr ***elems); @@ -537,6 +640,47 @@ } extern "C" +pure_expr *pure_long(int64_t l) +{ + int sgn = (l>0)?1:(l<0)?-1:0; + uint64_t v = (uint64_t)(l>=0?l:-l); + if (sizeof(mp_limb_t) == 8) { + // 8 byte limbs, value fits in a single limb. + limb_t u[1] = { v }; + return pure_bigint(sgn, u); + } else { + // 4 byte limbs, put least significant word in the first limb. + limb_t u[2] = { (uint32_t)v, (uint32_t)(v>>32) }; + return pure_bigint(sgn+sgn, u); + } +} + +static void make_bigint(mpz_t z, int32_t size, const limb_t *limbs) +{ + // FIXME: For efficiency, we poke directly into the mpz struct here, this + // might need to be reviewed for future GMP revisions. + int sz = size>=0?size:-size, sgn = size>0?1:size<0?-1:0, sz0 = 0; + // normalize: the most significant limb should be nonzero + for (int i = 0; i < sz; i++) if (limbs[i] != 0) sz0 = i+1; + sz = sz0; size = sgn*sz; + mpz_init(z); + if (sz > 0) _mpz_realloc(z, sz); + assert(sz == 0 || z->_mp_d); + for (int i = 0; i < sz; i++) z->_mp_d[i] = limbs[i]; + z->_mp_size = size; +} + +extern "C" +pure_expr *pure_bigint(int32_t size, const limb_t *limbs) +{ + pure_expr *x = new_expr(); + x->tag = EXPR::BIGINT; + make_bigint(x->data.z, size, limbs); + MEMDEBUG_NEW(x) + return x; +} + +extern "C" int32_t pure_cmp_bigint(pure_expr *x, int32_t size, const limb_t *limbs) { assert(x && x->tag == EXPR::BIGINT); Modified: pure/trunk/runtime.h =================================================================== --- pure/trunk/runtime.h 2008-06-24 00:31:37 UTC (rev 292) +++ pure/trunk/runtime.h 2008-06-24 08:56:30 UTC (rev 293) @@ -83,33 +83,16 @@ const char *pure_sym_pname(int32_t sym); int8_t pure_sym_nprec(int32_t sym); -/* Expression constructors. Atomic objects are constructed with the following - routines: +/* Expression constructors. pure_symbol takes the integer code of a symbol and + returns that symbol as a Pure value. If the symbol is a global variable + bound to a value then that value is returned, if it's a parameterless + function then it is evaluated, giving the return value of the function as + the result. pure_int, pure_mpz, pure_double and pure_pointer construct a + Pure machine int, bigint, floating point value and pointer from a 32 bit + integer, (copy of a) GMP mpz_t, double and C pointer, respectively. */ - - pure_symbol: Takes the integer code of a symbol and returns that symbol - as a Pure value. If the symbol is a global variable or parameterless - function then it is evaluated, giving the value of the variable or the - return value of the function as the result. - - - pure_int: Constructs a Pure machine int from a 32 bit integer value. - - - pure_long: Constructs a Pure bigint from a 64 bit integer value. - - - pure_bigint: Constructs a Pure bigint from a vector of limbs. The size - argument may be negative to denote a negative number, its absolute value - is the number of elements in the limbs vector (the vector is owned by the - caller and won't be be freed). - - - pure_mpz: Constructs a Pure bigint from a (copy of a) GMP mpz_t. - - - pure_double: Constructs a Pure floating point number from a double value. - - - pure_pointer: Constructs a Pure pointer from a C pointer (void*). */ - pure_expr *pure_symbol(int32_t sym); pure_expr *pure_int(int32_t i); -pure_expr *pure_long(int64_t l); -pure_expr *pure_bigint(int32_t size, const limb_t *limbs); pure_expr *pure_mpz(const mpz_t z); pure_expr *pure_double(double d); pure_expr *pure_pointer(void *p); @@ -144,40 +127,40 @@ pure_expr *pure_tuplel(size_t size, ...); pure_expr *pure_tuplev(size_t size, pure_expr **elems); -/* Expression deconstructors for all the expression types above. These all +/* Expression deconstructors for all of the expression types above. These return a bool value indicating whether the given expression is of the - corresponding type and, if so, set the remaining parameter pointers to the + corresponding type and, if so, set the remaining pointers to the corresponding values. Parameter pointers may be NULL in which case they are - not set and only the result of the type check is returned. + not set. - NOTES: pure_is_symbol will return true not only for constant and unbound - variable symbols, but also for arbitrary closures including local and - anonymous functions. In the case of an anonymous closure, the returned - symbol will be 0. You can check whether an expression actually represents a - named or anonymous closure using the funp and lambdap predicates from the - library API (see below). + Notes: - pure_is_long checks whether the result actually fits into a 64 bit integer. - pure_is_bigint mallocs the returned limb vector (if limbs!=NULL); the - caller is responsible for freeing it. */ + - pure_is_mpz takes a pointer to an uninitialized mpz_t and initializes it + with a copy of the Pure bigint. + - pure_is_symbol will return true not only for (constant and unbound + variable) symbols, but also for arbitrary closures including local and + anonymous functions. In the case of an anonymous closure, the returned + symbol will be 0. You can check whether an expression actually represents + a named or anonymous closure using the funp and lambdap predicates from + the library API (see below). */ + bool pure_is_symbol(const pure_expr *x, int32_t *sym); bool pure_is_int(const pure_expr *x, int32_t *i); -bool pure_is_long(const pure_expr *x, int64_t *l); -bool pure_is_bigint(const pure_expr *x, int32_t *size, limb_t **limbs); bool pure_is_mpz(const pure_expr *x, mpz_t *z); bool pure_is_double(const pure_expr *x, double *d); bool pure_is_pointer(const pure_expr *x, void **p); -/* String results are copied with the _dup routines (it is then the caller's - responsibility to free them when appropriate). pure_is_cstring_dup also - converts the string to the system encoding. The string value returned by - pure_is_string points directly to the string data in the Pure expression - and must not be changed by the caller. */ +/* String deconstructors. Here the string results are copied if using the _dup + routines (it is then the caller's responsibility to free them when + appropriate). pure_is_cstring_dup also converts the string to the system + encoding. The string value returned by pure_is_string points directly to + the string data in the Pure expression and must not be changed by the + caller. */ -bool pure_is_string(const pure_expr *x, const char **sym); -bool pure_is_string_dup(const pure_expr *x, char **sym); -bool pure_is_cstring_dup(const pure_expr *x, char **sym); +bool pure_is_string(const pure_expr *x, const char **s); +bool pure_is_string_dup(const pure_expr *x, char **s); +bool pure_is_cstring_dup(const pure_expr *x, char **s); /* Deconstruct literal applications. */ @@ -228,6 +211,11 @@ pure_expr *pure_clos(bool local, bool thunked, int32_t tag, uint32_t n, void *f, void *e, uint32_t m, /* m x pure_expr* */ ...); +/* Additional bigint constructors. */ + +pure_expr *pure_long(int64_t l); +pure_expr *pure_bigint(int32_t size, const limb_t *limbs); + /* Compare a bigint or string expression against a constant value. This is used by the pattern matching code. */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ag...@us...> - 2008-06-24 00:31:27
|
Revision: 292 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=292&view=rev Author: agraef Date: 2008-06-23 17:31:37 -0700 (Mon, 23 Jun 2008) Log Message: ----------- Overhaul of the str function. Modified Paths: -------------- pure/trunk/lib/strings.pure pure/trunk/runtime.cc pure/trunk/runtime.h pure/trunk/test/prelude.log Modified: pure/trunk/lib/strings.pure =================================================================== --- pure/trunk/lib/strings.pure 2008-06-23 23:38:50 UTC (rev 291) +++ pure/trunk/lib/strings.pure 2008-06-24 00:31:37 UTC (rev 292) @@ -22,12 +22,14 @@ the print representation of an expression in Pure syntax, as a string. The eval function does the opposite, by parsing and returning the value of an expression specified as a string in Pure syntax. (In fact, eval goes well - beyond this, as it can parse and execute arbitrary Pure code. But in that - case you will not always get a result expression.) */ + beyond this, as it can parse and execute arbitrary Pure code. In that case + it will return the last computed expression, if any.) */ -extern expr* str(expr*); +extern void* str(expr*) = pure_str; extern expr* eval(char*); // IMPURE! +str x = cstring (pure_str x); + /* Convert between Unicode character codes and single character strings. */ extern expr* string_chr(int); Modified: pure/trunk/runtime.cc =================================================================== --- pure/trunk/runtime.cc 2008-06-23 23:38:50 UTC (rev 291) +++ pure/trunk/runtime.cc 2008-06-24 00:31:37 UTC (rev 292) @@ -1494,13 +1494,13 @@ } extern "C" -pure_expr *str(const pure_expr *x) +char *str(const pure_expr *x) { assert(x); ostringstream os; try { os << x; - return pure_string_dup(os.str().c_str()); + return strdup(os.str().c_str()); } catch (err &e) { return 0; } Modified: pure/trunk/runtime.h =================================================================== --- pure/trunk/runtime.h 2008-06-23 23:38:50 UTC (rev 291) +++ pure/trunk/runtime.h 2008-06-24 00:31:37 UTC (rev 292) @@ -400,9 +400,10 @@ /* Convert a Pure expression to a string and vice versa. Note that eval() will actually parse and execute any Pure source, so it can be used, e.g., to add new rules to the executing program at runtime. The result of eval() is the - last computed expression (NULL if none). */ + last computed expression (NULL if none). The result of str() is a malloc'ed + string in the system encoding which must be freed by the caller. */ -pure_expr *str(const pure_expr *x); +char *str(const pure_expr *x); pure_expr *eval(const char *s); /* Compute a 32 bit hash code of a Pure expression. This makes it possible to Modified: pure/trunk/test/prelude.log =================================================================== --- pure/trunk/test/prelude.log 2008-06-23 23:38:50 UTC (rev 291) +++ pure/trunk/test/prelude.log 2008-06-24 00:31:37 UTC (rev 292) @@ -235,6 +235,7 @@ put_string x/*0:01*/ y/*0:1*/::string = pointer_put_string x/*0:01*/ y/*0:1*/; put_pointer x/*0:01*/ y/*0:1*/::string = pointer_put_pointer x/*0:01*/ y/*0:1*/; put_pointer x/*0:01*/ y/*0:1*/ = pointer_put_pointer x/*0:01*/ y/*0:1*/; +str x/*0:1*/ = cstring (pure_str x/*0:1*/); chr n/*0:1*/::int = string_chr n/*0:1*/ if n/*0:1*/>0; ord s/*0:1*/::string = string_ord s/*0:1*/ if #s/*0:1*/==1; string s/*0:1*/ = pure_string s/*0:1*/; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |