1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-02 21:10:27 +02:00

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.
This commit is contained in:
Phil 2011-05-07 16:15:11 -05:00 committed by Ian Price
parent faa16f9989
commit f4c44a3ba7
9 changed files with 130 additions and 46 deletions

View file

@ -9,7 +9,7 @@
In addition to Scheme, a user may write a Guile program in an increasing In addition to Scheme, a user may write a Guile program in an increasing
number of other languages. Currently supported languages include Emacs 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 Guile is still fundamentally a Scheme, but it tries to support a wide
variety of language building-blocks, so that other languages can be 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. * Using Other Languages:: How to use other languages.
* Emacs Lisp:: The dialect of Lisp used in Emacs. * Emacs Lisp:: The dialect of Lisp used in Emacs.
* ECMAScript:: As seen on television. * ECMAScript:: As seen on television.
* Lua:: A flexible scripting language.
@end menu @end menu
@ -270,6 +271,29 @@ perhaps by some more responsible hacker.
In the meantime, the charitable user might investigate such invocations In the meantime, the charitable user might investigate such invocations
as @code{,L ecmascript} and @code{cat test-suite/tests/ecmascript.test}. 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 Local Variables:
@c TeX-master: "guile.texi" @c TeX-master: "guile.texi"

View file

@ -20,6 +20,7 @@
(define-module (language lua compile-tree-il) (define-module (language lua compile-tree-il)
#:use-module (language tree-il) #:use-module (language tree-il)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-39) #:use-module (srfi srfi-39)
#:use-module ((system base syntax) #:select (record-case)) #:use-module ((system base syntax) #:select (record-case))
#:use-module (rnrs control) #:use-module (rnrs control)
@ -35,20 +36,45 @@
(define (ref-runtime src name) (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)) (make-module-ref src *runtime-name* name #t))
(define (make-runtime-application src name arguments) (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)) (make-application src (ref-runtime src name) arguments))
(define (make-table-ref src table index) (define (make-table-ref src table index)
"Shorthand for calling the index function in (language lua runtime)"
(make-runtime-application src 'index (make-runtime-application src 'index
(list table (if (symbol? index) (make-const src (symbol->string index)) index)))) (list table (if (symbol? index) (make-const src (symbol->string index)) index))))
(define (make-table-set! src table index exp) (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! (make-runtime-application src 'new-index!
(list table (if (symbol? index) (make-const src (symbol->string index)) index) exp))) (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 ;; FIXME: use prompt and abort rather than catch and throw
(define (apply-named-lua-function src name get-body) (define (apply-named-lua-function src name get-body)
(let* ((name (gensym (string-append " " name))) (let* ((name (gensym (string-append " " name)))
@ -81,24 +107,15 @@
(make-application src (make-lexical-ref src loop loop) '()))) (make-application src (make-lexical-ref src loop loop) '())))
(make-void src))))) (make-void src)))))
;; calling conventions (define (could-result-in-multiple-values? x)
(define* (make-plain-lambda-case src args gensyms body #:optional alternate) (if (not (null? x))
(make-lambda-case src args #f #f #f '() (or gensyms args) body alternate)) (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) ;; TODO REMOVE
(make-lambda src '() #;(define (adjust-to-single-value src exp)
(make-plain-lambda-case src args gensyms body alternate))) "Adjust an expression so that it only returns one result; the rest are
(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
dropped silently" dropped silently"
;; Rely on the truncating behavior of returning multiple values to a ;; Rely on the truncating behavior of returning multiple values to a
;; singly-valued continuation. ;; singly-valued continuation.
@ -153,12 +170,40 @@ dropped silently"
#f)))) #f))))
((ast-function-call src operator operands) ((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)) (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) (if (ast-global-ref? operator)
(make-sequence (make-sequence
src (list src (list

View file

@ -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] CLOSED: [2011-04-19 Tue 19:36]
** DONE Standard library functions: math.modf, math.fmod ** DONE Standard library functions: math.modf, math.fmod
CLOSED: [2011-04-21 Thu 15:43] 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 Use prompt and abort instead of throw and catch
** TODO Standard library function: module ** TODO Standard library function: module
** TODO Standard library function: table.sort ** TODO Standard library function: table.sort
** TODO Get the official Lua 5.1 test suite running ** TODO Get the official Lua 5.1 test suite running
** TODO Lua working at the REPL
** TODO Document some stuff
* Eh * Eh
** TODO Standard library function: math.frexp ** TODO Standard library function: math.frexp
Pending some additions to Guile's numeric tower. Pending some additions to Guile's numeric tower.
** TODO Use module binders
** TODO Better testing of standard library modules io, os ** 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 * Differences
Here are some difference in Guile Lua's behavior that should not cause Here are some difference in Guile Lua's behavior that should not cause

View file

@ -351,7 +351,7 @@
(enforce-next! #\)) (enforce-next! #\))
;; finished ;; finished
save)) save))
(else (syntax-error (get-source-info) "unexpected symbol ~a" token)))) (else (syntax-error (get-source-info) "unexpected token ~a" token))))
;; index -> '[' expression ']' ;; index -> '[' expression ']'
(define (index) (define (index)
@ -598,7 +598,6 @@
;; FIXME: does a left-to-right assignment, so x, y = y, x probably ;; 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. ;; doesn't work. Also does not appear to handle the x, y = foo() case.
;;
(define (parse-assignment src left right) (define (parse-assignment src left right)
;; and then parses it, branching to handle overflows on either side if necessary ;; and then parses it, branching to handle overflows on either side if necessary
(make-ast-sequence (make-ast-sequence

View file

@ -332,10 +332,7 @@
(runtime-error "~a" (if (null? opts) "assertion failed" (car opts))))) (runtime-error "~a" (if (null? opts) "assertion failed" (car opts)))))
;; NOTE: collectgarbage cannot be fully implemented because it expects ;; NOTE: collectgarbage cannot be fully implemented because it expects
;; an incremental garbage collector that matches lua's interface; libgc ;; an incremental garbage collector that matches lua's interface
;; 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
(define-global collectgarbage (define-global collectgarbage
(lambda* (opt #:optional (arg #nil)) (lambda* (opt #:optional (arg #nil))
(define (ignore) (runtime-warning "collectgarbage cannot respect command ~a" opt)) (define (ignore) (runtime-warning "collectgarbage cannot respect command ~a" opt))

View file

@ -18,9 +18,6 @@
(define-module (test-lua) (define-module (test-lua)
#:use-module (ice-9 format) #: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 (system base compile)
#:use-module (test-suite lib) #:use-module (test-suite lib)
@ -102,7 +99,7 @@
(test "print \"hello world\"; return true") (test "print \"hello world\"; return true")
;; variable arguments ;; variable arguments
#;(test "function test(...) print(...) end test(1,2)") (test "function test(...) print(...) end test(1,2)")
;; numeric for loop ;; numeric for loop
(test "for x = 1,2,1 do print(true) end return true") (test "for x = 1,2,1 do print(true) end return true")

View file

@ -18,9 +18,6 @@
(define-module (test-lua) (define-module (test-lua)
#:use-module (ice-9 format) #: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 (system base compile)
#:use-module (test-suite lib) #:use-module (test-suite lib)
@ -41,9 +38,22 @@
((_ string) ((_ string)
(test string #t))))) (test string #t)))))
#|
;; make sure logical expressions don't evaluate expressions twice ;; make sure logical expressions don't evaluate expressions twice
;;; y will equal 2 in case of extra eval ;;; 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") (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 ;;; 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") (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)"))

View file

@ -18,9 +18,6 @@
(define-module (test-lua) (define-module (test-lua)
#:use-module (ice-9 format) #: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 (system base compile)
#:use-module (test-suite lib) #:use-module (test-suite lib)

View file

@ -6,12 +6,12 @@
;;;; modify it under the terms of the GNU Lesser General Public ;;;; modify it under the terms of the GNU Lesser General Public
;;;; License as published by the Free Software Foundation; either ;;;; License as published by the Free Software Foundation; either
;;;; version 3 of the License, or (at your option) any later version. ;;;; version 3 of the License, or (at your option) any later version.
;;;; ;;;;
;;;; This library is distributed in the hope that it will be useful, ;;;; This library is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;;; Lesser General Public License for more details. ;;;; Lesser General Public License for more details.
;;;; ;;;;
;;;; You should have received a copy of the GNU Lesser General Public ;;;; You should have received a copy of the GNU Lesser General Public
;;;; License along with this library; if not, write to the Free Software ;;;; License along with this library; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
@ -29,7 +29,7 @@
(call-with-input-string string make-lexer)) (call-with-input-string string make-lexer))
(lambda (get-source-info lex) (lambda (get-source-info lex)
(lex)))) (lex))))
(let-syntax (let-syntax
((test ((test
(syntax-rules (eof) (syntax-rules (eof)
@ -62,7 +62,7 @@ comment]]"))
(test "name" 'name) (test "name" 'name)
(test "return" #:return) (test "return" #:return)
(test ".." #:concat) (test ".." #:concat)
(test "..." #:dots) (test "..." #:vararg)
(test ";" #\;) (test ";" #\;)
(test "-" #\-) (test "-" #\-)
(test "+" #\+) (test "+" #\+)