summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil <theseaisinhere+git@gmail.com>2011-05-07 16:15:11 -0500
committerIan Price <ianprice90@googlemail.com>2013-09-09 17:01:24 +0100
commitf4c44a3ba7f88e8171e1e2bd14b82d00b5912977 (patch)
tree53895bbda10c0c7771e3f82261dbd4acb75877c4
parentfaa16f99898a329eba0eaff0ab520eb0f9adbecb (diff)
downloadguile-f4c44a3ba7f88e8171e1e2bd14b82d00b5912977.tar.gz
Add some documentation. Function calls now properly handle multiple
values resulting from a function call as the last argument. doc/ref/api-languages.texi: Add a small blurb about Lua. module/language/lua/compile-tree-il.scm: Function calls now properly handle multiple values resulting from a function call as the last argument.
-rw-r--r--doc/ref/api-languages.texi26
-rw-r--r--module/language/lua/compile-tree-il.scm91
-rw-r--r--module/language/lua/notes.org19
-rw-r--r--module/language/lua/parser.scm3
-rw-r--r--module/language/lua/runtime.scm5
-rw-r--r--test-suite/tests/lua-eval-2.test5
-rw-r--r--test-suite/tests/lua-eval-3.test16
-rw-r--r--test-suite/tests/lua-eval.test3
-rw-r--r--test-suite/tests/lua-lexer.test8
9 files changed, 130 insertions, 46 deletions
diff --git a/doc/ref/api-languages.texi b/doc/ref/api-languages.texi
index fb42987d9..87d362951 100644
--- a/doc/ref/api-languages.texi
+++ b/doc/ref/api-languages.texi
@@ -9,7 +9,7 @@
In addition to Scheme, a user may write a Guile program in an increasing
number of other languages. Currently supported languages include Emacs
-Lisp and ECMAScript.
+Lisp, ECMAScript, and Lua.
Guile is still fundamentally a Scheme, but it tries to support a wide
variety of language building-blocks, so that other languages can be
@@ -24,6 +24,7 @@ Virtual Machine}.)
* Using Other Languages:: How to use other languages.
* Emacs Lisp:: The dialect of Lisp used in Emacs.
* ECMAScript:: As seen on television.
+* Lua:: A flexible scripting language.
@end menu
@@ -270,6 +271,29 @@ perhaps by some more responsible hacker.
In the meantime, the charitable user might investigate such invocations
as @code{,L ecmascript} and @code{cat test-suite/tests/ecmascript.test}.
+@node Lua
+@subsection Lua
+
+@url{http://www.lua.org,Lua}
+is a powerful scripting language similar in many ways to Scheme.
+Support for Lua 5.1 was added to Guile to make Guile a more attractive
+option for extending programs, and to make it possible for projects
+already using Lua to switch to Guile without giving up support for Lua.
+
+This section of the manual documents Guile's implementation of Lua. For
+documentation of the Lua language, please see
+@url{http://www.lua.org/docs.html,Lua's official documentation}.
+
+Guile's implementation of Lua is intended to behave exactly like the
+reference implementation of Lua 5.1, but problems are to be expected. If
+your Lua programs act strangely, it may very well be a problem with
+Guile's Lua.
+
+Notes:
+
+collectgarbage is not fully supported. Attempting to use collectgarbage
+with an argument other than ``collect'' will result in a warning being
+printed.
@c Local Variables:
@c TeX-master: "guile.texi"
diff --git a/module/language/lua/compile-tree-il.scm b/module/language/lua/compile-tree-il.scm
index dcd2956cc..48c1a58b1 100644
--- a/module/language/lua/compile-tree-il.scm
+++ b/module/language/lua/compile-tree-il.scm
@@ -20,6 +20,7 @@
(define-module (language lua compile-tree-il)
#:use-module (language tree-il)
+ #:use-module (srfi srfi-1)
#:use-module (srfi srfi-39)
#:use-module ((system base syntax) #:select (record-case))
#:use-module (rnrs control)
@@ -35,20 +36,45 @@
(define (ref-runtime src name)
+ "Shorthand for referring to a variable in the (language lua runtime) module"
(make-module-ref src *runtime-name* name #t))
(define (make-runtime-application src name arguments)
- "Apply a function in the (language lua runtime) module"
+ "Shorthand for creating an application of a function in the (language lua runtime) module"
(make-application src (ref-runtime src name) arguments))
(define (make-table-ref src table index)
+ "Shorthand for calling the index function in (language lua runtime)"
(make-runtime-application src 'index
(list table (if (symbol? index) (make-const src (symbol->string index)) index))))
(define (make-table-set! src table index exp)
+ "Shorthand for calling the new-index! function in (language lua runtime)"
(make-runtime-application src 'new-index!
(list table (if (symbol? index) (make-const src (symbol->string index)) index) exp)))
+;; Calling conventions
+(define* (make-plain-lambda-case src args gensyms body #:optional alternate)
+ (make-lambda-case src args #f #f #f '() (or gensyms args) body alternate))
+
+(define* (make-plain-lambda src args gensyms body #:optional alternate)
+ (make-lambda src '()
+ (make-plain-lambda-case src args gensyms body alternate)))
+
+(define (make-arg-ignoring-lambda src body)
+ (make-lambda src '()
+ (make-lambda-case src '() #f '_ #f '() (list (gensym "_"))
+ body #f)))
+
+(define (make-catch-all-lambda src body rest-gensym)
+ (make-lambda src '()
+ (make-lambda-case src '() #f 'rest #f '() (list rest-gensym)
+ body #f)))
+
+(define (make-argless-lambda src body)
+ (make-plain-lambda src '() #f body))
+
+
;; FIXME: use prompt and abort rather than catch and throw
(define (apply-named-lua-function src name get-body)
(let* ((name (gensym (string-append " " name)))
@@ -81,24 +107,15 @@
(make-application src (make-lexical-ref src loop loop) '())))
(make-void src)))))
-;; calling conventions
-(define* (make-plain-lambda-case src args gensyms body #:optional alternate)
- (make-lambda-case src args #f #f #f '() (or gensyms args) body alternate))
+(define (could-result-in-multiple-values? x)
+ (if (not (null? x))
+ (let ((last-expr (last x)))
+ (or (ast-function-call? last-expr) (ast-variable-arguments? last-expr)))
+ #f))
-(define* (make-plain-lambda src args gensyms body #:optional alternate)
- (make-lambda src '()
- (make-plain-lambda-case src args gensyms body alternate)))
-
-(define (make-arg-ignoring-lambda src body)
- (make-lambda src '()
- (make-lambda-case src '() #f '_ #f '() (list (gensym "_"))
- body #f)))
-
-(define (make-argless-lambda src body)
- (make-plain-lambda src '() #f body))
-
-(define (adjust-to-single-value src exp)
- "adjust an expression so that it only returns one result; the rest are
+;; TODO REMOVE
+#;(define (adjust-to-single-value src exp)
+ "Adjust an expression so that it only returns one result; the rest are
dropped silently"
;; Rely on the truncating behavior of returning multiple values to a
;; singly-valued continuation.
@@ -153,12 +170,40 @@ dropped silently"
#f))))
((ast-function-call src operator operands)
- #| (let* ((proc (compile operator))
- (args (make-application src (make-primitive-ref src 'list) (map-compile operands)))
- (app-args (make-application src (make-primitive-ref src 'list) (list proc args)))
- (app (make-application src (make-primitive-ref src 'apply) (list (make-primitive-ref src 'apply) app-args)))) |#
(let* ((proc (compile operator))
- (app (make-application src proc (map-compile operands))))
+ ;; will be #t if the the last expression in the list is a
+ ;; function call or variable arguments, which means we need
+ ;; to account for #<values>
+ (need-to-apply-multiple-values? (could-result-in-multiple-values? operands))
+ (args (map-compile operands)))
+ (define app
+ (if need-to-apply-multiple-values?
+ ;; Get the last function's (the one that could result in
+ ;; multiple values) return values using call-with-values
+ ;; and a function that takes variable arguments. Then
+ ;; append those variable arguments to the rest of the
+ ;; expression, and apply the first function to it)
+ (make-application src
+ (make-primitive-ref src 'call-with-values)
+ (list
+ (make-argless-lambda src (make-sequence src (last-pair args)))
+ (let ((rest-gensym (gensym "rest")))
+ (make-catch-all-lambda src
+ (make-application src (make-primitive-ref src 'apply)
+ (list
+ proc
+ (make-application src
+ (make-module-ref src '(srfi srfi-1) 'append! #t)
+ (list
+ (make-application src (make-primitive-ref src 'list) (drop-right args 1))
+ (make-lexical-ref src 'rest rest-gensym)))))
+ rest-gensym))))
+
+ (make-application src proc args)))
+
+ ;; If this is function is a global variable, prepend a call to
+ ;; check-global-function to make sure it's defined before
+ ;; applying it
(if (ast-global-ref? operator)
(make-sequence
src (list
diff --git a/module/language/lua/notes.org b/module/language/lua/notes.org
index 4e24cb95f..70f833bd5 100644
--- a/module/language/lua/notes.org
+++ b/module/language/lua/notes.org
@@ -5,17 +5,32 @@ This is an org-mode todo list of stuff that needs to be done for Guile Lua.
CLOSED: [2011-04-19 Tue 19:36]
** DONE Standard library functions: math.modf, math.fmod
CLOSED: [2011-04-21 Thu 15:43]
-** TODO Variable arguments and multiple returns
+** TODO Assignment cannot be naive left-to-right
+ a,b = b,a should work correctly
+** STARTED Multiple values
+ What's the deal? In Lua, the rightmost expression in a
+ comma-delimited list (such as in a function application, or the
+ right-hand side of an assignment) may result in multiple values.
+
+** TODO Variable arguments
+
+** TODO Function environments (getfenv and setfenv)
** TODO Use prompt and abort instead of throw and catch
** TODO Standard library function: module
** TODO Standard library function: table.sort
** TODO Get the official Lua 5.1 test suite running
+** TODO Lua working at the REPL
+** TODO Document some stuff
* Eh
** TODO Standard library function: math.frexp
Pending some additions to Guile's numeric tower.
+** TODO Use module binders
** TODO Better testing of standard library modules io, os
-** TODO Function environments (getfenv and setfenv)
+** TODO compile-tree-il.scm should be rewritten
+ Right now it's a jungle of tree-il constructors. There's a lot of
+ boilerplate code that could be made much nicer using macros and
+ parse-tree-il.
* Differences
Here are some difference in Guile Lua's behavior that should not cause
diff --git a/module/language/lua/parser.scm b/module/language/lua/parser.scm
index b602d20ab..dbe73f66f 100644
--- a/module/language/lua/parser.scm
+++ b/module/language/lua/parser.scm
@@ -351,7 +351,7 @@
(enforce-next! #\))
;; finished
save))
- (else (syntax-error (get-source-info) "unexpected symbol ~a" token))))
+ (else (syntax-error (get-source-info) "unexpected token ~a" token))))
;; index -> '[' expression ']'
(define (index)
@@ -598,7 +598,6 @@
;; FIXME: does a left-to-right assignment, so x, y = y, x probably
;; doesn't work. Also does not appear to handle the x, y = foo() case.
- ;;
(define (parse-assignment src left right)
;; and then parses it, branching to handle overflows on either side if necessary
(make-ast-sequence
diff --git a/module/language/lua/runtime.scm b/module/language/lua/runtime.scm
index 6a0541273..496f5122c 100644
--- a/module/language/lua/runtime.scm
+++ b/module/language/lua/runtime.scm
@@ -332,10 +332,7 @@
(runtime-error "~a" (if (null? opts) "assertion failed" (car opts)))))
;; NOTE: collectgarbage cannot be fully implemented because it expects
-;; an incremental garbage collector that matches lua's interface; libgc
-;; can be incremental but i don't think we can turn that on from guile
-;; currently, and even if we could i'm not sure that libgc exposes what
-;; lua wants
+;; an incremental garbage collector that matches lua's interface
(define-global collectgarbage
(lambda* (opt #:optional (arg #nil))
(define (ignore) (runtime-warning "collectgarbage cannot respect command ~a" opt))
diff --git a/test-suite/tests/lua-eval-2.test b/test-suite/tests/lua-eval-2.test
index 928cebe86..0787a3f94 100644
--- a/test-suite/tests/lua-eval-2.test
+++ b/test-suite/tests/lua-eval-2.test
@@ -18,9 +18,6 @@
(define-module (test-lua)
#:use-module (ice-9 format)
- #:use-module (language tree-il)
- #:use-module (srfi srfi-1)
- #:use-module (srfi srfi-8)
#:use-module (system base compile)
#:use-module (test-suite lib)
@@ -102,7 +99,7 @@
(test "print \"hello world\"; return true")
;; variable arguments
- #;(test "function test(...) print(...) end test(1,2)")
+ (test "function test(...) print(...) end test(1,2)")
;; numeric for loop
(test "for x = 1,2,1 do print(true) end return true")
diff --git a/test-suite/tests/lua-eval-3.test b/test-suite/tests/lua-eval-3.test
index 533d4a85b..16a4935b3 100644
--- a/test-suite/tests/lua-eval-3.test
+++ b/test-suite/tests/lua-eval-3.test
@@ -18,9 +18,6 @@
(define-module (test-lua)
#:use-module (ice-9 format)
- #:use-module (language tree-il)
- #:use-module (srfi srfi-1)
- #:use-module (srfi srfi-8)
#:use-module (system base compile)
#:use-module (test-suite lib)
@@ -41,9 +38,22 @@
((_ string)
(test string #t)))))
+#|
;; make sure logical expressions don't evaluate expressions twice
;;; y will equal 2 in case of extra eval
(test "y = 0 function tmp() y = y + 1 return true end assert(tmp() or tmp()) return y == 1")
;;; y will equal 4 in case of extra eval
(test "y = 0 function void(x) end function tmp() y = y + 2 return false end; function tmp2() y = y + 1 return true end; void(tmp() and tmp2()) return y == 2")
+|#
+ 1
))
+
+
+(define (from-string string)
+ (compile ((make-parser (open-input-string string)))
+ #:from 'lua
+ #:to 'value))
+
+;(format #t "~a\n" (from-string "function tmp() return 4,5 end print(1,2,3,tmp())"))
+
+(format #t "~a\n" (from-string "function tmp(...) print(1,2,3,...) end tmp(4,5)"))
diff --git a/test-suite/tests/lua-eval.test b/test-suite/tests/lua-eval.test
index 7008314aa..96bff7285 100644
--- a/test-suite/tests/lua-eval.test
+++ b/test-suite/tests/lua-eval.test
@@ -18,9 +18,6 @@
(define-module (test-lua)
#:use-module (ice-9 format)
- #:use-module (language tree-il)
- #:use-module (srfi srfi-1)
- #:use-module (srfi srfi-8)
#:use-module (system base compile)
#:use-module (test-suite lib)
diff --git a/test-suite/tests/lua-lexer.test b/test-suite/tests/lua-lexer.test
index 77094a0df..51e9efabf 100644
--- a/test-suite/tests/lua-lexer.test
+++ b/test-suite/tests/lua-lexer.test
@@ -6,12 +6,12 @@
;;;; modify it under the terms of the GNU Lesser General Public
;;;; License as published by the Free Software Foundation; either
;;;; version 3 of the License, or (at your option) any later version.
-;;;;
+;;;;
;;;; This library is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;;; Lesser General Public License for more details.
-;;;;
+;;;;
;;;; You should have received a copy of the GNU Lesser General Public
;;;; License along with this library; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
@@ -29,7 +29,7 @@
(call-with-input-string string make-lexer))
(lambda (get-source-info lex)
(lex))))
-
+
(let-syntax
((test
(syntax-rules (eof)
@@ -62,7 +62,7 @@ comment]]"))
(test "name" 'name)
(test "return" #:return)
(test ".." #:concat)
- (test "..." #:dots)
+ (test "..." #:vararg)
(test ";" #\;)
(test "-" #\-)
(test "+" #\+)