Lua 루아 5.4 참조 매뉴얼

저자: Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
번역: wariua

Copyright © 2020 Lua.org, PUC-Rio. 루아 라이선스 하에서 자유롭게 사용 가능.

1 – 소개

루아(Lua)는 강력하고 효율적이며 가벼운 내장형 스크립트 언어다. 절차적 프로그래밍, 객체 지향 프로그래밍, 함수형 프로그래밍, 데이터 주도 프로그래밍, 그리고 데이터 기술(description)을 지원한다.

루아에서는 단순한 절차적 문법이 연관 배열 및 확장식 의미론을 기반으로 한 데이터 기술 요소와 결합된다. 루아는 동적 타입 방식이고, 레지스터 기반 가상 머신으로 바이트코드를 해석해서 실행하며, 세대식 쓰레기 수집으로 메모리를 자동 관리한다. 그래서 설정, 스크립트, 빠른 프로토타입 만들기에 이상적이다.

루아는 라이브러리로 구현되어 있으며, 표준 C와 C++의 공통 부분집합인 순수 C로 작성되어 있다. 루아 배포판에는 lua라는 호스트 프로그램이 포함되어 있는데, 루아 라이브러리를 이용해 완전한 단독형 루아 인터프리터를 제공한다. 이를 대화식 사용이나 배치 처리에 쓸 수 있다. 루아는 강력하고 가벼운 내장형 스크립트 언어로도, 또 강력하면서 가볍고 효율적인 단독 언어로도 쓸 수 있게 만들어졌다.

확장형 언어이기에 루아에는 "main" 프로그램 개념이 없다. 감싸는 프로그램 내지 호스트라 부르는 호스트 클라이언트에 내장되어 동작한다. (많은 경우 이 호스트는 단독형 lua 프로그램이다.) 호스트 프로그램에서는 함수를 호출해서 루아 코드 조각을 실행할 수 있고, 루아 변수를 읽고 쓸 수 있으며, 루아 코드에서 호출할 C 함수를 등록할 수 있다. C 함수 사용을 통해 광범위한 분야에 대처할 수 있도록 루아를 보강할 수 있으며, 그래서 문법적 틀을 공유하는 맞춤형 프로그래밍 언어를 만들 수 있다.

루아는 자유 소프트웨어이며 라이선스에서 선언하는 것처럼 늘 그렇듯 어떤 보증도 없이 제공된다. 이 매뉴얼에서 다루는 구현체를 루아의 공식 웹 사이트인 www.lua.org 에서 얻을 수 있다.

여느 참조 매뉴얼과 마찬가지로 이 문서는 많은 부분에서 건조하다. 루아 설계에 숨어 있는 결정들에 대한 논의는 루아 웹 사이트에 있는 기술 논문들을 보라. 루아 프로그래밍에 대한 자세한 소개는 Roberto의 책 Programming in Lua를 보라. (번역서: 프로그래밍 루아)

2 – 기본 개념

이 절에선 언어의 기본 개념들을 설명한다.

2.1 – 값과 타입

루아는 동적 타입 언어다. 즉, 변수에는 타입이 없고 값에만 타입이 있다. 언어 내에 타입 정의라는 것이 없다. 모든 값들이 각자의 타입을 가지고 있다.

루아에서 모든 값들은 일급(first-class) 값이다. 즉, 모든 값들을 변수에 저장하고, 다른 함수에 인자로 전달하고, 결과로 반환할 수 있다.

루아에는 여덟 가지 기본 타입이 있다. 닐(nil), 불리언, , 문자열, 함수, userdata, 스레드, 테이블이다. 타입에는 값이 nil 하나만 있는데, 그 값의 주된 특징은 다른 어떤 값과도 다르다는 점이다. 많은 경우 유용한 값이 없음을 나타낸다. 불리언 타입에는 falsetrue라는 두 값이 있다. nilfalse는 조건을 거짓으로 만든다. 둘을 합쳐서 거짓 값이라고 한다. 그 외 다른 값들은 조건을 참으로 만든다.

타입은 두 가지 서브타입 정수실수를 이용해 정수와 실수(부동소수점수)를 나타낸다. 표준 루아에서는 64비트 정수와 배정밀도(64비트) 부동소수점수를 쓴다. 하지만 32비트 정수 및/또는 단정밀도(32비트) 부동소수점수를 쓰도록 루아를 컴파일할 수도 있다. 정수와 실수 모두에 32비트를 쓰는 방식은 특히 작은 머신과 임베디드 시스템에서 매력적이다. (luaconf.h 파일의 LUA_32BITS 매크로 참고.)

따로 언급돼 있지 않다면 정수 조작 시 넘침이 발생하면 일반적인 2의 보수 산술 규칙에 따라 값이 되감긴다. (다시 말해 수학적 결과와 모듈로 2n로 같은 표현 가능한 유일한 정수가 실제 결과다. 여기서 n은 정수 타입의 비트 수다.)

루아에는 각 서브타입이 언제 쓰이는가에 대한 명확한 규칙이 있지만 필요에 따라 둘 사이에 자동으로 변환을 하기도 한다. (3.4.3절 참고.) 따라서 프로그래머가 정수와 실수 간의 차이를 대강 무시하기로 할 수도 있고 각 수의 표현을 완전히 통제하기로 할 수도 있다.

문자열 타입은 불변 바이트 열을 나타낸다. 루아는 8비트 처리가 깔끔하다. 즉, 문자열에 어떤 8비트 값도 담을 수 있으며 0('\0')을 포함시킬 수도 있다. 루아는 또한 인코딩에 불가지론적이다. 즉, 문자열 내용물에 대해 어떤 가정도 하지 않는다. 루아의 모든 문자열은 그 길이가 루아 정수에 들어가야 한다.

루아에서는 루아로 작성된 함수와 C로 작성된 함수를 호출(및 조작)할 수 있다. (3.4.10절 참고.) 둘 모두 함수 타입으로 나타낸다.

userdata 타입은 임의의 C 데이터를 루아 변수에 저장할 수 있도록 하기 위한 것이다. userdata 값은 날것 그대로의 메모리 블록을 나타낸다. userdata에는 두 종류가 있는데, full userdata는 루아에서 관리하는 메모리 블럭을 가진 객체이고, light userdata는 그냥 C 포인터 값이다. 루아에서 userdata에는 할당과 동일성 검사를 제외하고 어떤 연산도 미리 정의되어 있지 않다. 메타테이블을 사용하면 프로그래머가 full userdata 값에 대한 연산을 정의할 수 있다. (2.4절 참고.) 루아 내에서는 userdata 값을 생성하거나 변경할 수 없으며 C API를 통해서만 가능하다. 이는 호스트 프로그램과 C 라이브러리가 소유한 데이터의 무결성을 보장하기 위해서다.

스레드 타입은 독립적인 실행 스레드를 나타내며 코루틴을 구현하는 데 쓴다. (2.6절 참고.) 루아 스레드는 운영 체제 스레드와는 무관하다. 루아는 자체 스레드를 지원하지 않는 경우를 포함한 모든 시스템에서 코루틴을 지원한다.

테이블 타입은 연관 배열을 구현한 것이다. 즉, 인덱스로 정수만이 아니라 nil과 NaN을 제외한 모든 루아 값을 사용할 수 있는 배열이다. (NaN(Not a Number)0/0처럼 정의되어 있지 않은 수치 결과를 나타내기 위해 IEEE 754 표준에서 쓰는 특수한 부동소수점 값이다.) 테이블이 혼성일 수 있다. 즉, (nil을 빼고) 모든 타입의 값을 담을 수 있다. nil 값이 연계된 키는 테이블에 포함되는 것으로 보지 않는다. 달리 말해, 테이블에 포함되어 있지 않은 키에는 모두 nil 값이 연계되어 있는 것이다.

테이블은 루아에서 유일한 데이터 구조화 장치다. 테이블을 이용해 평범한 배열이나 리스트, 심볼 테이블, 집합, 레코드, 그래프, 트리 등을 표현할 수 있다. 루아에서 레코드를 표현할 때는 필드 이름을 인덱스로 사용한다. 언어에서 a["name"]와 더불어 문법적 양념 a.name을 통해서 그 표현을 지원한다. 루아에는 테이블을 만들 수 있는 여러 편리한 방법이 있다. (3.4.9절 참고.)

인덱스와 마찬가지로 테이블 필드 값으로 어떤 타입이든 가능하다. 특히 함수가 일급 값이기 때문에 함수를 테이블 필드에 담을 수 있다. 그래서 테이블이 메소드를 가질 수도 있다. (3.4.11절 참고.)

테이블 인덱스는 언어의 raw 동일 정의를 따른다. a[i]a[j]라는 식이 있을 때, ij가 raw 동일(즉 메타메소드 빼고 동일)이면, 그리고 그 경우에만 두 식이 같은 테이블 항목을 나타낸다. 특별히 정수 값을 가진 실수는 대응하는 정수와 동일하다. (예를 들어 1.0 == 1이다.) 모호함을 피하기 위해 어떤 정수와 같은 실수를 키로 쓰면 그 정수로 변환된다. 예를 들어 a[2.0] = true라고 작성하면 테이블에 들어가는 실제 키는 정수 2가 된다.

테이블, 함수, 스레드, (full) userdata 값은 객체다. 변수가 이 값을 실제로 담는 게 아니라 참조할 뿐이다. 할당, 매개변수 전달, 함수 반환을 하면 언제나 그 값의 참조를 조작하는 것이며, 그 연산에 어떤 종류의 복사도 수반되지 않는다.

라이브러리 함수 type은 주어진 값의 타입을 나타내는 문자열을 반환한다. (type 참고.)

2.2 – 환경과 전역 환경

3.2절3.3.3절에서 논의하겠지만 유휴 이름 (즉 어떤 선언에도 결속되지 않은 이름) var에 대한 참조는 _ENV.var로 구문 변환된다. 그리고 _ENV라는 외부 지역 변수의 유효 범위 안에서 각 청크를 컴파일하므로 (3.3.3절 참고) 청크 내에서 _ENV 자체는 절대 유휴 이름일 수 없다.

이런 외부 _ENV 변수의 존재와 유휴 이름 변환에도 불구하고 _ENV는 특별할 것 없는 이름이다. 특히 그 이름으로 새 변수와 매개변수를 정의할 수 있다. 유휴 이름에 대한 각 참조에서는 루아의 일반적인 가시성 규칙에 따라서 그 프로그램 위치에서 보이는 _ENV를 사용한다. (3.5절 참고.)

_ENV의 값으로 쓰는 테이블을 모두 환경(environment)이라고 부른다.

루아에서는 전역 환경이라는 특별한 환경을 둔다. C 레지스트리의 특수 인덱스에 그 값을 유지한다. (4.3절 참고.) 그리고 같은 값으로 전역 변수 _G를 초기화한다. (_G는 내부에서 절대 쓰지 않으며, 그래서 그 값을 바꿔도 직접 작성한 코드에만 영향을 끼치게 된다.)

루아에서 청크를 적재할 때 그 _ENV 변수의 기본값은 전역 환경이다. (load 참고.) 따라서 기본적으로 루아 코드의 유휴 이름은 전역 환경 내의 항목들을 가리키고, 그래서 전역 변수라고도 한다. 더불어 모든 표준 라이브러리가 전역 환경에 적재되고 그 함수들 일부가 그 환경 상에서 동작한다. load를 (또는 loadfile을) 이용해 다른 환경으로 청크를 적재할 수 있다. (C에서는 청크를 적재한 다음 그 첫 번째 upvalue의 값을 바꿔야 한다. lua_setupvalue 참고.)

2.3 – 오류 처리

루아의 여러 동작들이 오류를 던질 수 있다. 오류는 정상적인 프로그램 흐름을 중단시키게 되며, 그 오류를 잡으면 흐름을 이어갈 수 있다.

루아 코드에서 error 함수를 호출해서 명시적으로 오류를 던질 수 있다. (이 함수는 절대 반환하지 않는다.)

루아에서 오류를 잡기 위해선 pcall을 (또는 xpcall을) 사용해 보호 호출(protected call)을 할 수 있다. pcall 함수는 주어진 함수를 보호 모드로 호출해 준다. 그 함수를 실행하는 중에 오류가 발생하면 실행이 멈추고 즉시 제어가 pcall로 되돌아가고, 거기서 상태 코드를 반환한다.

루아는 내장식 확장 언어이므로 모든 루아 동작은 호스트 프로그램의 C 코드에서 이뤄지는 호출로 시작한다. (단독형 루아를 사용할 때는 lua 응용이 호스트 프로그램이다.) 일반적으로 그 호출은 보호되며, 따라서 루아 청크를 컴파일하거나 실행하는 도중에 따로 보호 안 된 오류가 발생하면 제어가 호스트로 되돌아간다. 거기서 오류 메시지 찍기 같은 적절한 대처를 할 수 있다.

오류가 있을 때마다 그 오류에 대한 정보를 담은 오류 객체가 전파된다. 루아 자체에서는 오류 객체가 문자열인 오류만 생성하지만 프로그램들에선 어떤 오류 객체 값으로도 오류를 생성할 수 있다. 그런 오류 객체를 처리하는 것은 그 루아 프로그램 내지 호스트의 몫이다. 꼭 문자열이어야 하는 게 아닌데도 오류 객체를 오류 메시지라고 하는 경우가 많은데, 역사적 이유 때문이다.

xpcall을 (또는 C에서 lua_pcall을) 사용할 때 오류 발생 시 호출될 메시지 핸들러를 줄 수 있다. 그 함수는 원본 오류 객체로 호출되어 새 오류 객체를 반환한다. 오류 때문에 스택이 해제되기 전에 호출되므로 오류에 대해 더 많은 정보를 모을 수 있다. 예를 들어 스택을 조사하거나 스택 트레이스백을 만들 수 있다. 이 메시지 핸들러 자체도 보호 호출의 보호를 받으며, 그래서 메시지 핸들러 내에서 오류가 발생하면 다시 메시지 핸들러가 불리게 된다. 그 고리가 너무 길게 이어지면 루아에서 끊고서 적당한 메시지를 반환한다. 정규 런타임 오류에만 메시지 핸들러가 호출된다. 메모리 할당 오류나 종료자 내지 다른 메시지 핸들러 실행 중의 오류에는 호출되지 않는다.

루아에는 경고 체계도 있다. (warn 참고.) 오류와 달리 경고는 프로그램 실행에 어떤 영향도 주지 않는다. 보통은 사용자에게 메시지를 내놓을 뿐이며, 그 동작을 C에서 조정할 수도 있다. (lua_setwarnf 참고.)

2.4 – 메타테이블과 메타메소드

루아의 모든 값에는 메타테이블(metatable)이 있을 수 있다. 메타테이블은 평범한 루아 테이블이며 특정 상황들에서 기반 값의 동작을 규정한다. 메타테이블의 개별 필드를 설정해서 값 동작의 여러 측면을 바꿀 수 있다. 예를 들어 수가 아닌 값이 덧셈의 피연산자일 때 루아에서는 그 값의 메타테이블에서 "__add" 필드에 함수가 있는지 확인한다. 있으면 루아가 그 함수를 호출해서 덧셈을 수행한다.

메타테이블의 각 이벤트에 대한 키는 이벤트 이름 앞에 밑줄 두 개가 붙은 문자열이다. 그 키에 대응하는 값을 메타값(metavalue)이라고 한다. 대부분의 경우에는 메타값이 함수여야 하며, 그 함수를 메타메소드(metamethod)라고 한다. 앞의 예에서 키는 문자열 "__add"이고 메타메소드는 덧셈 수행 함수다. 따로 명시한 경우가 아니면 메타메소드가 실제로는 임의의 호출 가능 값일 수 있는데, 함수일 수도 있고 메타메소드 __call이 있는 값일 수도 있다.

getmetatable 함수를 이용해 원하는 값의 메타테이블을 질의할 수 있다. 루아에서는 raw 접근을 이용해 메타테이블 내의 메타메소드를 질의한다. (rawget 참고.)

setmetatable 함수를 이용해 테이블의 메타테이블을 교체할 수 있다. 루아 코드에서는 디버그 라이브러리 사용을 제외하면 (6.10절 참고) 다른 타입들의 메타테이블을 바꿀 수 없다.

테이블과 full userdata에는 개별적으로 메타테이블이 있다. 다만 여러 테이블 및 userdata가 메타테이블을 공유할 수도 있다. 다른 타입 값들은 타입별로 하나씩 있는 메타테이블을 공유한다. 즉, 수 전체에 메타테이블 하나가 있고, 문자열 전체에 하나가 있고, 하는 식이다. 기본적으로는 값에 메타테이블이 없다. 하지만 문자열 라이브러리에서는 문자열 타입에 메타테이블을 설정한다. (6.4절 참고.)

메타테이블로 제어하는 연산들의 자세한 목록이 다음에 있다. 해당 키로 각 이벤트를 식별한다. 관행적으로 루아에서 쓰는 메타테이블 키는 모두 밑줄 두 개에 라틴 소문자들이 붙은 것이다.

위 목록에 더해서 인터프리터에서 신경을 쓰는 메타테이블 키로 __gc (2.5.3절 참고), __close (3.3.8절 참고), __mode (2.5.4절 참고), __name이 있다. (__name 항목이 문자열을 담고 있는 경우 tostring 및 오류 메시지에서 이용할 수 있다.)

단항 연산자(반수, 길이, 비트 NOT)에서는 두 번째 피연산자를 첫 번째와 같은 더미 값으로 채워서 메타메소드를 계산하고 호출한다. 이 추가 피연산자는 (그 연산자들이 이항 연산자처럼 동작하게 만들어서) 루아의 내부 동작을 단순하게 만들기 위한 것이며 향후 버전에서 제거될 수도 있다. 대부분 경우에 이 추가 피연산자는 별 의미가 없다.

메타테이블도 정규 테이블이기 때문에 위에 밝힌 이벤트 이름뿐 아니라 임의의 필드를 담을 수 있다. 표준 라이브러리의 일부 함수들은 (예: tostring) 메타테이블의 다른 필드들을 자체 용도로 이용한다.

테이블을 어떤 객체의 메타테이블로 설정하기 전에 필요한 모든 메타메소드를 추가해 두는 게 좋다. 특히 __gc 메타메소드는 이 순서를 따를 때만 제대로 동작한다. (2.5.3절 참고.) 또한 객체 생성 직후에 그 메타테이블을 설정하는 게 좋다.

2.5 – 쓰레기 수집

루아는 자동 메모리 관리를 수행한다. 즉, 새 객체를 위해 메모리를 할당하는 것이나 그 객체가 더는 필요 없을 때 해제하는 것에 대해 신경 쓸 필요가 없다. 루아에서 쓰레기 수집기를 실행해 죽은 객체를 모두 수집하는 방식으로 메모리를 자동 관리한다. 문자열, 테이블, userdata, 함수, 스레드, 내부 구조체 등, 루아에서 사용하는 모든 메모리가 자동 관리 대상이다.

정상적 프로그램 실행 중에는 더 이상 객체에 대한 접근이 없을 것이라고 수집기에서 판단하면 죽은 객체라고 본다. ("정상적 실행"에 포함되지 않는 경우로는 죽은 객체를 부활시킬 수 있는 종료자 (2.5.3절 참고), 그리고 디버그 라이브러리 사용 동작이 있다.) 객체가 죽었다고 수집기에서 확신할 수 있는 시점이 프로그래머의 예상과 다를 수도 있다는 점에 유의하라. 정상적 프로그램 실행 중 여전히 접근이 이뤄질 수도 있는 객체를 루아에서 수집하지 않는다는 것, 그리고 루아에서 접근 불가능한 객체가 언젠간 수집된다는 것이 보장될 뿐이다. (여기서 루아에서 접근 불가능하다는 것은 어떤 변수나 살아 있는 객체도 그 객체를 참조하고 있지 않다는 뜻이다.) 루아에서는 C 코드에 대해 전혀 알 수 없기 때문에 레지스트리(4.3절)를 통해 접근 가능한 객체를 절대 수집하지 않으며, 전역 환경(2.2절)도 거기에 포함된다.

루아의 쓰레기 수집기(GC)는 점진(incremental) 방식과 세대(generational) 방식 중 하나로 동작할 수 있다.

대부분 경우에는 기본 GC 동작 방식과 기본 매개변수로 충분하다. 하지만 메모리를 할당하고 해제하는 데 많은 시간을 쓰는 프로그램에서는 다른 설정이 도움이 될 수 있다. 다만 GC 동작 방식이 플랫폼 및 루아 버전 측면에서 이식성이 없다는 점을 유념해야 한다. 따라서 최적의 설정 역시도 이식성이 없다.

C에서 lua_gc를 호출하거나 루아에서 collectgarbage를 호출해서 GC 모드와 매개변수를 바꿀 수 있다. 그 함수들을 사용해 수집기를 직접 제어할 수도 (예를 들어 멈추거나 다시 시작할 수도) 있다.

2.5.1 – 점진식 쓰레기 수집

점진 방식에서는 각 GC 사이클마다 프로그램 실행 사이사이의 작은 단계들로 나눠서 mark-and-sweep 수집을 수행한다. 이 모드에서 쓰레기 수집 사이클을 제어하는 세 가지 수치가 있는데, 쓰레기 수집 휴지 시간, 쓰레기 수집 단계 비율, 쓰레기 수집 단계 크기다.

쓰레기 수집 휴지 시간은 수집기가 얼마나 오래 기다렸다가 새 주기를 시작할지 제어한다. 메모리 사용량이 이전 수집 후 사용량의 n%에 도달하면 수집기가 새 사이클을 시작한다. 값이 크면 수집기가 덜 적극적이 된다. 100 이하 값은 기다리지 않고 새 주기를 시작하는 걸 뜻한다. 200 값은 총 사용 메모리가 두 배가 될 때까지 기다렸다가 새 주기를 시작한다는 뜻이다. 기본값은 200이고 최댓값은 1000이다.

쓰레기 수집 단계 비율은 메모리 할당 대비 수집기의 속도, 즉 1킬로바이트 메모리 할당에 대해 몇 개 항목을 mark 및 sweep할지를 제어한다. 값이 크면 수집기가 더 적극적이 되며 또 각 점진 단계가 더 커진다. 100보다 작은 값은 사용하지 않는 게 좋다. 수집기가 너무 느려지며 수집기가 사이클을 절대 마치지 못하게 될 수 있기 때문이다. 기본값은 100이고 최댓값은 1000이다.

쓰레기 수집 단계 크기는 각 점진 단계의 크기, 즉 인터프리터에서 몇 바이트를 할당한 다음에 단계를 수행할지를 제어한다. 이 매개변수는 로그 방식이다. 즉 n 값은 인터프리터가 단계들 간에 2n 바이트를 할당하고 각 단계 동안 그에 상당하는 작업을 수행한다는 뜻이다. 큰 값(가령 60)을 쓰면 수집기가 stop-the-world (비점진식) 수집기가 된다. 기본값은 13으로, 약 8킬로바이트의 단계를 뜻한다.

2.5.2 – 세대식 쓰레기 수집

세대식 방식에서는 최근 생성된 객체만 순회하는 소규모 수집을 자주 수행한다. 소규모 수집 후에도 메모리 사용량이 여전히 한계치보다 높으면 모든 객체를 순회하는 stop-the-world 방식 대규모 수집을 한다. 세대식 모드에는 두 가지 매개변수가 있는데, 소규모 비율대규모 비율이다.

소규모 비율은 소규모 수집의 빈도를 제어한다. 소규모 비율이 x이면 메모리가 이전 대규모 수집 후의 메모리 사용량보다 x% 커졌을 때 새로 소규모 수집을 하게 된다. 예를 들어 비율이 20이면 메모리 사용량이 이전 대규모 수집 후의 사용량보다 20% 크게 될 때 소규모 수집을 하게 된다. 기본값은 20이고 최댓값은 200이다.

대규모 비율은 대규모 수집의 빈도를 제어한다. 대규모 비율이 x이면 메모리가 이전 대규모 수집 후의 메모리 사용량보다 x% 커졌을 때 새로 대규모 수집을 하게 된다. 예를 들어 비율이 100이면 메모리 사용량이 이전 대규모 수집 후의 사용량의 두 배가 될 때 대규모 수집을 하게 된다. 기본값은 100이고 최댓값은 1000이다.

2.5.3 – 쓰레기 수집 메타메소드

테이블에, 그리고 C API로 full userdata에도 쓰레기 수집 메타메소드를 설정할 수 있다. (2.4절 참고.) 대응하는 테이블 내지 userdata가 죽어 있다고 쓰레기 수집기에서 탐지했을 때 종료자(finalizer)라고도 하는 그 메타메소드가 호출된다. 종료자를 이용하면 루아의 쓰레기 수집을 파일이나 네트워크 내지 데이터베이스 연결 닫기, 자체 메모리 해제 같은 외부 자원 관리에 연계할 수 있다.

수집 때 마무리 작업이 필요한 객체(테이블이나 userdata)에는 마무리를 하라는 표시를 해 주어야 한다. 객체에 메타테이블을 설정하는데 그 메타테이블에 문자열 "__gc"가 인덱스인 필드가 있으면 객체에 마무리 표시를 하는 것이다. 참고로 __gc 필드 없는 메타테이블을 설정하고서 나중에 메타테이블에 그 필드를 만들어도 객체에 마무리 표시가 되지 않는다.

표시가 붙은 객체가 쓰레기가 죽을 때는 쓰레기 수집기가 즉시 수집하지 않는다. 대신 루아에서 어떤 목록에 그 객체를 넣어 둔다. 그리고 수집 후에 그 목록을 살펴본다. 목록의 각 객체마다 객체의 __gc 메타메소드를 확인한다. 존재하면 그 객체를 단일 인자로 해서 호출한다.

각 쓰레기 수집 사이클 마지막에서 그 주기에 수집한 객체들에 대해 마무리 표시를 한 것과 반대 순서로 종료자를 호출한다. 즉, 처음 호출되는 종료자는 프로그램에서 마지막으로 표시한 객체에 연계된 종료자다. 종료자 실행은 정규 코드 실행 중의 어느 시점에서든 이뤄질 수 있다.

수집 중인 객체를 종료자에서 계속 사용해야 하기 때문에 그 객체를 (그리고 그 객체를 통해서만 접근 가능한 다른 객체들을) 루아에서 부활시켜야 한다. 일반적으로 이 부활은 일시적이며 다음 쓰레기 수집 주기에 그 객체 메모리가 해제된다. 하지만 종료자에서 그 객체를 어떤 전역 위치에 (가령 전역 변수에) 저장한다면 부활이 영구적이 된다. 그리고 종료자에서 마무리 중인 객체에 다시 마무리 표시를 하면 그 객체가 죽어 있는 다음번 주기에 종료자가 호출된다. 어찌 됐든, 객체가 죽어 있고 마무리 표시가 되어 있지 않은 GC 주기에서만 객체 메모리가 해제된다.

상태를 닫을 때 (lua_close 참고) 루아에서는 마무리 표시가 된 모든 객체의 종료자를 표시 반대 순서로 호출한다. 그 단계에서 어느 종료자가 객체에 수집 표시를 하더라도 그 표시는 아무 효과가 없다.

종료자는 양보를 할 수 없다. 그것만 빼면 뭐든지 할 수 있는데, 예를 들어 오류를 던지거나, 새 객체를 생성하거나, 심지어 쓰레기 수집기를 돌릴 수도 있다. 하지만 예측 불가능한 시점에 실행될 수 있으므로 종료자에서는 연계 자원을 올바로 해제하기 위해 필요한 최소한의 일만 하는 게 일반적으로 좋다.

종료자 실행 중 오류가 생기면 경고가 발생한다. 즉 오류가 전파되지 않는다.

2.5.4 – 약한 테이블

약한 테이블이란 약한 참조가 원소인 테이블이다. 약한 참조는 쓰레기 수집 시 무시된다. 다시 말해 어느 객체에 대한 참조가 약한 참조뿐이면 쓰레기 수집기가 그 객체를 수집하게 된다.

약한 테이블은 키가 약할 수도 있고, 값이 약할 수도 있고, 둘 모두 약할 수도 있다. 값이 약한 테이블은 값이 수집되는 것은 허용하지만 키가 수집되는 것은 막는다. 키와 값 모두 약한 테이블은 키와 값 모두의 수집을 허용한다. 어느 경우든 키나 값이 수집되면 그 쌍이 통째로 테이블에서 제거된다. 테이블 메타테이블의 __mode 필드로 테이블의 약함 방식을 제어한다. 이 메타값이 존재하는 경우, 키가 약한 테이블에는 "k", 값이 약한 테이블에는 "v", 키와 값 모두 약한 테이블에는 "kv"여야 한다.

키가 약하고 값이 강한 테이블을 이페머론(ephemeron) 테이블이라고도 한다. 이페머론 테이블에서는 키가 도달 가능한 경우에만 그 값이 도달 가능하다고 본다. 특히 어느 키에 대한 유일한 참조가 그 값을 통한 것이면 그 쌍을 제거한다.

테이블의 약함 방식을 변경한 효과가 다음 수집 주기에서야 나타날 수도 있다. 특히 강한 방식으로 바꾸는 경우에는 변경 효과가 나타나기 전까지 루아에서 그 테이블의 일부 항목을 계속 수집할 수도 있다.

명시적 생성을 하는 객체만 약한 테이블에서 제거된다. 수나 경량 C 함수 같은 값은 쓰레기 수집 대상이 아니고, 따라서 (연계된 값이 수집되지 않는 한) 약한 테이블에서 제거되지 않는다. 문자열은 쓰레기 수집의 대상이지만 명시적 생성을 하지 않으며 값으로 동일 여부를 확인한다. 즉 객체보다는 값에 가깝게 동작한다. 따라서 약한 테이블에서 제거되지 않는다.

부활한 객체는 (즉 마무리 중인 객체 및 마무리 중인 객체를 통해서만 접근 가능한 객체는) 약한 테이블에서 특별한 방식으로 다룬다. 약한 값 때문에 제거될 때는 종료자 실행 전에 제거되지만 약한 키 때문에 제거될 때는 종료자 실행 후에 그 객체가 실제로 해제되는 다음 주기에서야 제거된다. 이런 동작 덕분에 종료자에서 약한 테이블을 통해 객체에 연계된 자원에 접근할 수 있다.

어느 수집 주기에 부활한 객체들 중에 약한 테이블이 있는 경우 다음 주기까지 그 테이블이 완전히 사라지지 않을 수도 있다.

2.6 – 코루틴

루아는 협력적 멀티스레딩이라고도 하는 코루틴을 지원한다. 루아에서 코루틴은 독립적 실행 흐름을 나타낸다. 하지만 멀티스레드 시스템의 스레드와 달리 코루틴은 명시적인 양보 함수 호출을 통해서만 실행을 멈춘다.

coroutine.create를 호출해서 코루틴을 만든다. 유일한 인자는 함수이고 그게 코루틴의 메인 함수다. create 함수는 새 코루틴을 만들어서 핸들(스레드 타입 객체)을 반환하기만 한다. 즉, 코루틴을 시작하지는 않는다.

coroutine.resume을 호출해서 코루틴을 실행한다. coroutine.create가 반환한 스레드를 첫 번째 인자로 해서 처음으로 coroutine.resume을 호출할 때 코루틴이 자기 메인 함수를 호출하며 실행을 시작한다. coroutine.resume으로 전달한 추가 인자들이 그 함수의 인자로 전달된다. 코루틴이 실행을 시작하고 나면 종료하거나 양보(yield)할 때까지 돈다.

코루틴은 두 가지 방식으로 실행을 끝마칠 수 있다. 메인 함수가 (명시적으로, 또는 마지막 인스트럭션 후에 암묵적으로) 반환할 때 정상적으로 종료하거나, 보호 안 된 오류가 있을 때 비정상적으로 종료한다. 정상 종료인 경우 coroutine.resumetrue를, 그리고 코루틴 메인 함수가 반환한 값들이 있으면 함께 반환한다. 오류 발생 시 coroutine.resumefalse를, 그리고 그 오류 객체를 반환한다. 이 경우 코루틴에서 스택을 해제하지 않으며, 따라서 디버그 API로 사후 오류 조사를 할 수 있다.

coroutine.yield를 호출해서 코루틴이 실행을 양보한다. 코루틴이 양보하면 대응하는 coroutine.resume이 즉시 반환한다. 중첩 함수 호출 안에서 (즉 메인 함수 안이 아니라 메인 함수에서 직간접으로 호출한 함수 안에서) 양보가 이뤄질 때도 마찬가지이다. 양보하는 경우 coroutine.resumetrue를, 그리고 coroutine.yield에 전달한 값들이 있으면 함께 반환한다. 같은 코루틴을 다음에 재개할 때는 양보했던 지점에서 실행이 이어지며, coroutine.resume에 전달한 추가 인자들이 있으면 coroutine.yield 호출이 반환한다.

coroutine.create와 마찬가지로 coroutine.wrap 함수도 코루틴을 만든다. 하지만 코루틴 자체를 반환하는 것이 아니라 함수를 반환하며, 그 함수 호출 시 코루틴이 재개된다. 그 함수로 전달한 인자들이 있으면 coroutine.resume 추가 인자가 된다. coroutine.wrapcoroutine.resume이 반환한 값들을 첫 번째 값(불리언 오류 코드)만 빼고 전부 반환한다. coroutine.resume과 달리 coroutine.wrap으로 생성된 함수는 오류를 호출자에게 전파한다. 이 경우 그 함수에서 코루틴을 닫는 동작도 한다. (coroutine.close 참고.)

코루틴 동작 방식에 대한 예로 다음 코드를 살펴보자.

     function foo (a)
       print("foo", a)
       return coroutine.yield(2*a)
     end
     
     co = coroutine.create(function (a,b)
           print("co-body", a, b)
           local r = foo(a+1)
           print("co-body", r)
           local r, s = coroutine.yield(a+b, a-b)
           print("co-body", r, s)
           return b, "end"
     end)
     
     print("main", coroutine.resume(co, 1, 10))
     print("main", coroutine.resume(co, "r"))
     print("main", coroutine.resume(co, "x", "y"))
     print("main", coroutine.resume(co, "x", "y"))

실행하면 다음 출력이 나온다.

     co-body 1       10
     foo     2
     main    true    4
     co-body r
     main    true    11      -9
     co-body x       y
     main    true    10      end
     main    false   cannot resume dead coroutine

C API를 통해서도 코루틴을 생성하고 조작할 수 있다. lua_newthread, lua_resume, lua_yield 함수를 보라.

3 – 언어

이 절에서는 루아의 어휘, 문법, 의미론을 기술한다. 다시 말해 어떤 토큰들이 유효한지, 그 토큰들을 어떻게 결합할 수 있는지, 그리고 그 조합이 무엇을 뜻하는지 설명한다.

흔히 하듯 확장 BNF 표기법을 이용해 언어 구성 요소들을 설명할 것이다. {a}는 a가 0개나 그보다 많이 있다는 뜻이고 [a]는 a가 선택적이라는 뜻이다. 비말단 심볼은 글꼴 꾸밈 없이 표시하며, 키워드는 kword처럼 표시하고, 다른 말단 심볼들은 ‘=’처럼 표시한다. 루아의 전체 문법을 이 매뉴얼 마지막의 9절에서 볼 수 있다.

3.1 – 어휘 규정

루아는 자유 형식 언어다. 두 토큰 사이 구분자 역할을 제외하면 어휘 요소(토큰)들 사이의 공백과 주석을 무시한다. 소스 코드에서 표준 ASCII 공백 문자들인 스페이스, 폼 피드, 개행, 캐리지 리턴, 수평 탭, 수직 탭을 공백으로 인식한다.

루아에서 이름(식별자라고도 함)은 라틴 글자, 아라비아 숫자, 밑줄로 이뤄진 어떤 열도 가능하되, 숫자로 시작할 수 없고 예약 단어가 아니어야 한다. 변수, 테이블 필드, 레이블을 지칭하는 데 식별자를 쓴다.

다음 키워드는 예약되어 있어서 이름으로 쓸 수 없다.

     and       break     do        else      elseif    end
     false     for       function  goto      if        in
     local     nil       not       or        repeat    return
     then      true      until     while

루아는 대소문자를 구별하는 언어다. 그래서 and는 예약 단어지만 AndAND는 그와 다른 유효한 이름이다. 관행 상 밑줄로 시작하고 이어서 한 개 이상의 대문자가 오는 (_VERSION 같은) 이름을 프로그램에서 만들지 않는 게 좋다.

다음이 나머지 토큰들을 나타낸다.

     +     -     *     /     %     ^     #
     &     ~     |     <<    >>    //
     ==    ~=    <=    >=    <     >     =
     (     )     {     }     [     ]     ::
     ;     :     ,     .     ..    ...

짝이 맞는 작은따옴표나 큰따옴표로 감싸서 짧은 리터럴 문자열을 만들 수 있다. 그 문자열에 '\a' (벨), '\b' (백스페이스), '\f' (폼 피드), '\n' (개행), '\r' (캐리지 리턴), '\t' (수평 탭), '\v' (수직 탭), '\\' (백슬래시), '\"' (큰따옴표), '\'' (작은따옴표) 같은 C 스타일 이스케이프 열이 포함될 수 있다. 백슬래시 다음에 행이 바뀌면 문자열 내에서 개행이 된다. 이스케이프 열 '\z'는 행 바꿈을 포함해서 이어지는 공백 문자들 구간을 건너뛰게 한다. 긴 리터럴 문자열을 내용에 개행이나 공백을 더하지 않으면서 여러 행으로 쪼개거나 들여 쓰는 데 유용하게 이용할 수 있다. 짧은 리터럴 문자열에는 이스케이프 안 된 줄 바꿈이나 유효한 이스케이프 열이 아닌 이스케이프가 포함될 수 없다.

짧은 리터럴 문자열 내 임의 바이트를 0을 포함해서 숫자 값으로 지정할 수 있다. 이스케이프 열 \xXX를 쓰는데, 여기서 XX는 정확히 두 개의 16진수 열이다. 또는 이스케이프 열 \ddd를 쓰는데, 여기서 ddd는 세 개까지의 10진수 열이다. (참고로 10진 이스케이프 열에 이어서 숫자가 오는 경우에는 정확히 세 개 숫자로 표현해야 한다.)

이스케이프 열 \u{XXX}를 이용해 UTF-8 인코딩 유니코드 문자를 리터럴 문자열에 집어넣을 수 있다. (감싸는 중괄호가 필수다.) 여기서 XXX는 문자 코드 포인트를 나타내는 한 개 이상의 16진수 열이다. 이 코드 포인트는 231보다 작은 어떤 값이든 가능하다. (루아에서는 자체적인 UTF-8 명세를 사용하며, 그래서 유효한 유니코드 코드 포인트들로 한정하지 않는다.)

긴 괄호로 감싸는 긴 형식을 이용해 리터럴 문자열을 정의할 수도 있다. 먼저 n단계 여는 긴 괄호를 정의하자면, 여는 대괄호 다음에 등호 n개가 오고 다시 여는 대괄호가 오는 것이다. 그래서 0단계짜리 여는 긴 괄호는 [[라고 쓰고 1단계짜리 여는 긴 괄호는 [=[로 쓰는 식이다. 닫는 긴 괄호도 비슷하게 정의한다. 예를 들어 4단계짜리 닫는 긴 괄호는 ]====]로 쓴다. 긴 리터럴은 임의 단계의 여는 긴 괄호로 시작하고 같은 단계의 닫는 긴 괄호로 끝난다. 같은 단계의 닫는 괄호를 제외한 어떤 텍스트도 담을 수 있다. 이 괄호 형태로 된 리터럴은 여러 행에 걸쳐 있을 수 있고, 그 안에서 어떤 이스케이프 열도 해석하지 않으며, 다른 단계의 긴 괄호를 무시한다. 그리고 모든 종류의 행 종료 열(캐리지 리턴, 개행, 캐리지 리턴 다음 개행, 개행 다음 캐리지 리턴)이 그냥 개행으로 변환된다. 여는 긴 괄호 바로 다음에 개행이 올 때는 그 개행을 문자열에 포함시키지 않는다.

예를 들어 ASCII를 쓰는 ('a'를 97로, 개행을 10으로, '1'을 49로 인코딩하는) 시스템에서 아래 다섯 가지 리터럴 문자열은 같은 문자열을 나타낸다.

     a = 'alo\n123"'
     a = "alo\n123\""
     a = '\97lo\10\04923"'
     a = [[alo
     123"]]
     a = [==[
     alo
     123"]==]

명확히 위 규칙들에 해당되지 않는 리터럴 문자열 내 바이트는 그대로 표현된다. 하지만 루아가 텍스트 모드로 파일을 열어서 파싱하므로 일부 제어 문자가 시스템 파일 함수에서 문제가 될 수도 있다. 따라서 텍스트 아닌 데이터를 표현할 때는 바이너리 문자에 대한 명확한 이스케이프 열을 담은 따옴표 리터럴을 쓰는 것이 안전하다.

숫자 상수(즉 숫자)를 선택적으로 소수 부분이나 'e' 내지 'E' 글자로 표시한 10진수 지수와 함께 쓸 수 있다. 0x0X로 시작하는 16진수 상수도 받는다. 16진수 상수에서도 선택적으로 소수 부분이나 'p' 내지 'P' 글자로 표시한 2진수 지수를 받는다.

소수점이나 지수가 있는 숫자 상수는 실수를 나타낸다. 그렇지 않고 값이 정수 범위에 들어가거나 16진수 상수면 정수를 나타낸다. 그도 아니면 (즉 넘치는 10진수 정수면) 실수를 나타낸다. 소수점과 지수가 없는 16진수는 항상 정수 값을 나타낸다. 그 값이 넘치는 경우에는 유효한 정수에 들어가도록 값을 되감는다.

다음은 유효한 정수 상수의 예이다.

     3   345   0xff   0xBEBADA

다음은 유효한 실수 상수의 예이다.

     3.0     3.1416     314.16e-2     0.31416E1     34e1
     0x0.1E  0xA23p-4   0X1.921FB54442D18P+1

문자열 밖 어디서든 하이픈 두 개(--)로 주석이 시작된다. -- 바로 다음 텍스트가 여는 긴 괄호가 아니면 그 주석은 짧은 주석이고 그 행 끝까지 이어진다. 맞으면 긴 주석이고 대응하는 닫는 긴 괄호까지 이어진다.

3.2 – 변수

변수는 값을 저장하는 장소다. 루아에는 세 가지 변수가 있는데, 전역 변수, 지역 변수, 그리고 테이블 필드다.

한 이름이 전역 변수 또는 지역 변수를 (또는 지역 변수의 한 종류인 함수의 형식 매개변수를) 나타낼 수 있다.

	var ::= Name

Name은 식별자를 나타낸다. (3.1절 참고.)

명시적으로 지역으로 선언하지 않는 한 (3.3.7절 참고) 변수 이름을 전역으로 상정한다. 지역 변수에는 문법적 스코프가 적용된다. 그리고 지역 변수의 유효 범위 내에 정의된 함수에서 그 변수에 자유롭게 접근할 수 있다. (3.5절 참고.)

첫 할당을 하기 전에 변수의 값은 nil이다.

테이블 인덱스 접근에는 대괄호를 쓴다.

	var ::= prefixexp ‘[’ exp ‘]

메타테이블을 통해 테이블 필드 접근의 의미를 바꿀 수 있다. (2.4절 참고.)

var.Name 구문은 var["Name"]에 대한 문법적 양념일 뿐이다.

	var ::= prefixexp ‘.’ Name

전역 변수 x에 대한 접근은 _ENV.x와 동등하다. 청크를 컴파일하는 방식 때문에 변수 _ENV 자체는 절대 전역이 아니다. (2.2절 참고.)

3.3 –

루아에서는 다른 전통 언어들과 비슷한 거의 관행적인 문(statement)들을 지원한다. 블록, 할당, 제어 구조, 함수 호출, 변수 선언 등을 포함한다.

3.3.1 – 블록

블록은 순차적으로 실행되는 문들의 목록이다.

	block ::= {stat}

루아에는 빈 문이 있어서 세미콜론으로 문을 분리하거나 세미콜론으로 블록을 시작하거나 세미콜론 두 개를 연달아 쓸 수 있다.

	stat ::= ‘;

함수 호출과 할당 모두 열린 괄호로 시작할 수 있는데, 이 점이 루아 문법에서 모호함을 만든다. 다음 코드 조각을 보자.

     a = b + c
     (print or io.write)('done')

문법적으로 이를 두 가지 방식으로 볼 수 있다.

     a = b + c(print or io.write)('done')
     
     a = b + c; (print or io.write)('done')

현행 파서에서는 이런 경우를 항상 첫 번째 방식으로 보아서 열린 괄호를 호출 인자들의 시작으로 해석한다. 이런 모호함을 피하기 위해 괄호로 시작하는 문 앞에 항상 세미콜론을 붙이는 게 좋다.

     ;(print or io.write)('done')

블록 양 끝에 명시적인 표시를 해서 단일 문을 만들 수 있다.

	stat ::= do block end

명시적 블록은 변수 선언의 유효 범위를 제어하는 데 유용하다. 때로는 다른 블록 중간에 return 문을 추가하는 데 쓰기도 한다. (3.3.4절 참고.)

3.3.2 – 청크

루아의 컴파일 단위를 청크(chunk)라고 부른다. 문법적으로 청크는 그냥 블록이다.

	chunk ::= block

루아에서는 청크를 이름 없는 가변 인자 함수의 몸체인 것처럼 다룬다. (3.4.11절 참고.) 그렇기에 청크에서 지역 변수를 정의할 수 있고, 인자를 받고 값을 반환할 수 있다. 그리고 그 익명 함수가 _ENV라는 외부 지역 변수의 유효 범위 안에 있는 것으로 해서 컴파일한다. 그래서 그 함수에는 이용 여부와 상관없이 언제나 유일한 외부 변수 _ENV가 있다. (2.2절 참고.)

파일에, 또는 호스트 프로그램 내 문자열에 청크를 저장할 수 있다. 실행을 위해선 먼저 루아에서 청크를 적재하는데, 청크의 코드를 가상 머신 인스트럭션으로 사전 컴파일한다. 그러고서 컴파일된 코드를 가상 머신 인터프리터로 실행한다.

청크를 바이너리 형태로 사전 컴파일해 둘 수도 있다. 자세한 내용은 luac 프로그램과 string.dump 함수를 보라. 소스 형태 프로그램과 컴파일 형태 프로그램은 서로 대체 가능하다. 루아가 파일 종류를 자동으로 탐지해서 그에 맞게 동작한다. (load 참고.)

3.3.3 – 할당

루아에서는 다중 할당이 가능하다. 그래서 할당 문법에서 왼쪽에 변수 목록이 오고 오른쪽에 식 목록이 온다. 두 목록 모두 쉼표로 항목을 구분한다.

	stat ::= varlist ‘=’ explist
	varlist ::= var {‘,’ var}
	explist ::= exp {‘,’ exp}

식은 3.4절에서 논의한다.

할당을 하기 전에 변수 목록 길이에 맞춰 값 목록을 조정한다. 값이 필요한 것보다 많으면 남는 값들을 버린다. 값이 필요한 것보다 적으면 nil로 채워서 목록을 확장한다. 식 목록이 함수 호출로 끝나는 경우에는 그 호출이 반환한 모든 값들을 (호출에 괄호 쳐진 경우는 제외. 3.4절 참고) 값 목록에 넣은 후 조정한다.

할당 문에서는 먼저 모든 식들을 평가한 다음에 할당을 수행한다. 그래서 다음 코드가 있을 때,

     i = 3
     i, a[i] = i+1, 20

a[3]이 20으로 설정되고 a[4]는 영향을 받지 않는다. a[i] 안의 i를 (3으로) 평가한 다음에 4를 할당하기 때문이다. 마찬가지로 다음 행은

     x, y = y, x

xy의 값을 교환한다. 그리고 다음은

     x, y, z = y, z, x

x, y, z의 값을 순환시킨다.

전역 이름에 대한 할당 x = val은 할당 _ENV.x = val과 동등하다. (2.2절 참고.)

테이블 필드와 (실제로는 역시 테이블 필드인) 전역 변수에 대한 할당의 의미를 메타테이블을 통해 바꿀 수 있다. (2.4절 참고.)

3.3.4 – 제어 구조

제어 구조 if, while, repeat의 문법은 익숙한 형태이며 의미도 많이 쓰는 대로다.

	stat ::= while exp do block end
	stat ::= repeat block until exp
	stat ::= if exp then block {elseif exp then block} [else block] end

루아에는 두 가지 종류의 for 문도 있다. (3.3.5절 참고.)

제어 구조의 조건 식은 어떤 값이든 반환할 수 있다. falsenil은 거짓이 된다. nilfalse 외의 모든 값은 참이 된다. 특히 수 0과 빈 문자열도 참이 된다.

repeatuntil 루프에서 내부 블록은 until 키워드에서 끝나는 것이 아니라 조건 식 다음에서 끝난다. 따라서 루프 블록 내에 선언된 지역 변수를 조건에서 사용할 수 있다.

goto 문은 레이블로 프로그램 제어를 옮긴다. 구문 처리 상의 이유로 루아에서는 레이블도 문으로 본다.

	stat ::= goto Name
	stat ::= label
	label ::= ‘::’ Name ‘::

레이블이 정의된 블록 전체에서 그 레이블이 보인다. 단, 중첩 함수 안에서는 보이지 않는다. 지역 변수의 유효 범위 안으로 들어가는 것만 아니면 보이는 모든 레이블로 goto 점프할 수 있다. 어떤 레이블이 보이는 곳에서 같은 이름의 레이블을 선언하지 말아야 한다. 그 다른 레이블이 감싸는 블록에 정의된 것이라도 마찬가지다.

레이블과 빈 문은 아무 동작도 수행하지 않으므로 void 문이라고 한다.

break 문은 while, repeat, for 루프의 실행을 끝내고 루프 다음의 문으로 건너뛴다.

	stat ::= break

break는 가장 안쪽 루프를 끝낸다.

return 문을 이용해 함수나 (익명 함수인 것처럼 다루는) 청크에서 값을 반환한다. 함수에서 값을 여러 개 반환할 수 있다. 그래서 return 문의 문법은 다음과 같다.

	stat ::= return [explist] [‘;’]

return 문은 블록 마지막 문으로만 쓸 수 있다. 블록 중간에서 return 해야 한다면 do return end처럼 확실한 내부 블록을 쓸 수 있다. 그러면 return이 (안쪽) 블록의 마지막 문이 되기 때문이다.

3.3.5 – for 문

for 문에는 수열형과 일반형, 두 가지 형태가 있다.

수열형 for 루프

수열형 for 루프는 제어 변수가 등차수열을 거치는 동안 코드 블록을 반복한다. 문법은 다음과 같다.

	stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end

주어진 식별자(Name)가 제어 변수를 나타내는데, 루프 몸체(블록)에 지역인 새 변수다.

루프의 시작은 세 가지 제어 식을 한 번씩 평가하는 것이다. 그 값을 각각 초기 값, 제한 값, 단계 값이라고 한다. 단계 값이 없으면 1인 것으로 한다.

초기 값과 단계 값이 모두 정수인 경우에는 정수로 루프를 돈다. 참고로 제한 값은 정수일 필요가 없다. 그렇지 않은 경우에는 세 값을 실수로 변환해서 실수로 루프를 돈다. 이 경우 부동소수점 정확도에 유의해야 한다.

초기화 후에는 제어 변수 값이 초기 값으로 시작해서 단계 값이 나타내는 차이의 등차수열을 거치며 루프 몸체를 반복한다. 단계 값이 음수면 감소하는 수열이 되고, 단계 값이 0과 같으면 오류를 던진다. 값이 제한 값 이하인 동안 (음수 단계 값에선 이상인 동안) 루프가 계속된다. 초기 값이 이미 제한 값보다 크면 (단계 값이 음수일 때는 작으면) 몸체를 실행하지 않는다.

정수 루프에서 절대 제어 변수를 되감지 않는다. 오버플로우가 발생하면 루프를 끝낸다.

루프 도중에 제어 변수의 값을 바꾸지 말아야 한다. 루프 다음에 그 값이 필요하다면 루프에서 나가기 전에 다른 변수에 할당해 두면 된다.

일반형 for 루프

일반형 for 문은 반복자(iterator)라는 함수를 기반으로 동작한다. 각 반복마다 반복자 함수를 호출해서 새 값을 만들어 내며, 그 새 값이 nil이면 멈춘다. 일반형 for 루프의 문법은 다음과 같다.

	stat ::= for namelist in explist do block end
	namelist ::= Name {‘,’ Name}

다음 for 문이

     for var_1, ···, var_n in explist do body end

다음처럼 동작한다.

이름 var_i는 루프 몸체에 지역인 루프 변수들을 선언한다. 그 변수들 중 첫 번째가 제어 변수다.

루프의 시작은 explist를 평가하는 것이다. 네 개 값이 나오는데, 반복자 함수, 상태, 제어 변수의 초기 값, 닫기 값이다.

그리고 각 반복마다 상태와 제어 변수를 인자로 해서 반복자 함수를 호출한다. 그리고 그 호출 결과를 다중 할당 규칙에 따라 (3.3.3절 참고) 루프 변수들에 할당한다. 제어 변수가 nil이 되면 루프가 종결된다. 아니면 몸체를 실행하고 루프가 다음 반복으로 넘어간다.

닫기 값은 자동 닫힘 변수(3.3.8절)처럼 동작하는데, 이를 이용해 루프가 끝날 때 자원을 해제할 수 있다. 그것 말고는 루프에 영향을 주지 않는다.

루프 도중에 제어 변수의 값을 바꾸지 말아야 한다.

3.3.6 – 함수 호출 문

부대 효과를 위해서 함수 호출을 문으로 실행할 수 있다.

	stat ::= functioncall

이 경우 반환되는 값은 모두 버린다. 함수 호출을 3.4.10절에서 설명한다.

3.3.7 – 지역 선언

블록 내 어디에서도 지역 변수를 선언할 수 있다. 선언에 초기화가 포함될 수 있다.

	stat ::= local attnamelist [‘=’ explist]
	attnamelist ::=  Name attrib {‘,’ Name attrib}

초기 할당이 있는 경우 다중 할당과 동작 방식이 같다. (3.3.3절 참고.) 아니라면 모든 변수가 nil로 초기화된다.

각 변수 이름 뒤에 속성이 (이름을 꺾쇠괄호로 감싸서) 올 수 있다.

	attrib ::= [‘<’ Name ‘>’]

사용 가능한 속성이 두 가지 있다. const는 상수 변수, 즉 초기화 후에는 다시 할당할 수 없는 변수를 선언한다. close는 자동 닫힘 변수(3.3.8절)를 선언한다. 변수 목록에는 자동 닫힘 변수가 최대 1개 있을 수 있다.

청크도 블록이므로 (3.3.2절 참고) 청크 안의 명시적 블록 밖에서 지역 변수를 선언할 수 있다.

지역 변수 가시성 규칙을 3.5절에서 설명한다.

3.3.8 – 자동 닫힘 변수

자동 닫힘(to-be-closed) 변수는 상수 지역 변수처럼 동작하되, 변수가 유효 범위를 벗어날 때 항상 그 값이 닫힌다. 유효 범위를 벗어나는 경우로는 정상적인 블록 종결, break/goto/return을 통해 블록 마치기, 오류로 인한 블록 마치기 등이 있다.

여기서 값을 닫는다는 것은 __close 메타메소드를 호출한다는 뜻이다. 메타메소드 호출 시 값 자체가 첫 번째 인자로 전달되고, 해당 시 종료를 유발한 오류 객체가 두 번째 인자로 전달된다. 오류가 없었으면 두 번째 인자가 nil이다.

자동 닫힘 변수에 할당하는 값은 __close 메타메소드가 있거나 거짓 값이어야 한다. (자동 닫힘 값이 nil이나 false이면 무시한다.)

여러 자동 닫힘 변수가 동시에 유효 범위를 벗어나게 되면 선언된 것과 반대 순서로 닫힌다.

닫기 메소드 실행 중 오류가 발생하면 그 변수가 정의된 정규 코드 안의 오류인 것처럼 처리한다. 다만 루아에서 그 메소드를 한 번 더 호출할 수 있다.

오류 처리 후에도 남은 다른 닫기 메소드들을 호출한다. 그 메소드들에서 오류가 발생하면 해당 메소드를 중단하고 경고를 내고는 그냥 무시한다. 즉 첫 오류만 보고된다.

코루틴이 양보를 하고서 다시 재개되지 않으면 일부 변수가 절대 유효 범위를 벗어나지 않을 수 있고, 그래서 절대 닫히지 않게 된다. (코루틴 안에서 만들어졌고 코루틴이 양보한 시점에 유효 범위 안에 있던 변수들이 그렇다.) 마찬가지로, 코루틴이 오류로 끝나는 경우에는 스택을 해제하지 않으며, 그래서 어떤 변수도 닫히지 않는다. 두 경우 모두 종료자를 쓰거나 coroutine.close를 호출해서 변수를 닫을 수 있다. 단, coroutine.wrap을 통해 코루틴을 만든 경우에는 오류 발생 시 해당 함수가 코루틴을 닫아 준다.

3.4 –

루아의 기본 식(expression)은 다음과 같다.

	exp ::= prefixexp
	exp ::= nil | false | true
	exp ::= Numeral
	exp ::= LiteralString
	exp ::= functiondef
	exp ::= tableconstructor
	exp ::= ‘...’
	exp ::= exp binop exp
	exp ::= unop exp
	prefixexp ::= var | functioncall | ‘(’ exp ‘)

숫자와 리터럴 문자열을 3.1절에서 설명한다. 변수를 3.2절에서 설명한다. 함수 정의를 3.4.11절에서 설명한다. 함수 호출을 3.4.10절에서 설명한다. 테이블 생성자를 3.4.9절에서 설명한다. 점 세 개('...')로 표시하는 가변 인자 식은 가변 인자 함수 바로 안에서만 사용할 수 있다. 3.4.11절에서 설명한다.

이항 연산자는 산술 연산자(3.4.1절), 비트 연산자(3.4.2절), 관계 연산자(3.4.4절), 논리 연산자(3.4.5절), 접합 연산자(3.4.6절)로 이뤄진다. 단항 연산자는 단항 마이너스(3.4.1절), 단항 비트 NOT(3.4.2절), 단항 논리 not(3.4.5절), 단항 길이 연산자(3.4.7절)로 이뤄진다.

함수 호출과 가변 인자 식은 결과 값이 여러 개일 수 있다. 함수 호출을 문으로 쓰는 경우에는 (3.3.6절 참고) 그 반환 목록을 0개 항목으로 조정한다. 즉 반환된 값을 모두 폐기한다. 식 목록의 마지막 (또는 유일한) 항목으로 쓸 때는 (식을 괄호로 감싼 경우가 아니면) 어떤 조정도 하지 않는다. 그 외 모든 경우에서 루아는 첫 번째 값을 빼고 모두 폐기해서, 또는 값이 없으면 nil을 하나 추가해서 결과 목록을 1개 항목으로 조정한다.

몇 가지 예를 들면 다음과 같다.

     f()                -- 결과를 0개로 조정
     g(f(), x)          -- f() 결과를 1개로 조정
     g(x, f())          -- x와 f()의 결과 모두를 g가 받음
     a,b,c = f(), x     -- f() 결과를 1개로 조정 (c는 nil을 받음)
     a,b = ...          -- a는 첫 번째 가변 인자를 받고, b는
                        -- 두 번째를 받음 (대응하는 인자가 없으면
                        -- a와 b 모두 nil을 받을 수 있음)
     
     a,b,c = x, f()     -- f() 결과를 2개로 조정
     a,b,c = f()        -- f() 결과를 3개로 조정
     return f()         -- f()의 결과 모두를 반환
     return ...         -- 받은 가변 인자 모두를 반환
     return x,y,f()     -- x, y, 그리고 f()의 결과 모두를 반환
     {f()}              -- f()의 결과 모두를 가지고 리스트 생성
     {...}              -- 가변 인자 모두를 가지고 리스트 생성
     {f(), nil}         -- f() 결과를 1개로 조정

괄호로 감싼 식은 항상 단일 값이 나온다. 즉, (f(x,y,z))f가 여러 값을 반환하더라도 항상 단일 값이다. ((f(x,y,z))의 값은 f가 반환하는 첫 번째 값이다. f가 아무 값도 반환하지 않으면 nil이다.)

3.4.1 – 산술 연산자

루아에서는 다음 산술 연산자를 지원한다.

누승과 실수 나눗셈을 제외하고 산술 연산의 동작 방식은 동일하다. 두 피연산자 모두 정수면 정수 연산을 수행하며 결과가 정수다. 그렇지 않고 두 피연산자가 수이면 실수로 변환한다. 머신의 실수 산술 규칙(보통 IEEE 754 표준)에 따라 연산을 수행하며 결과가 실수다. (산술 연산의 문자열을 문자열 라이브러리가 숫자로 강제한다. 자세한 내용은 3.4.3절 참고.)

누승과 실수 나눗셈(/)은 피연산자를 항상 실수로 변환하며 결과가 항상 실수이다. 누승에 ISO C 함수 pow를 사용하므로 정수 아닌 지수도 가능하다.

내림 나눗셈(//)은 몫을 음의 무한대 쪽으로 내림하는 나눗셈이다. 그러면 피연산자들로 나눗셈 한 값의 바닥(floor) 값이 나온다.

모듈로는 몫을 음의 무한대 쪽으로 내림하는 나눗셈(내림 나눗셈)의 나머지로 정의한다.

정수 산술에서 넘침이 발생하는 경우 모든 연산에서 값이 되감긴다.

3.4.2 – 비트 연산자

루아에서는 다음 비트 연산자를 지원한다.

모든 비트 연산은 피연산자를 정수로 변환하여 (3.4.3절 참고) 그 정수의 모든 비트에 대해 동작하며 결과가 정수다.

오른쪽 시프트와 왼쪽 시프트 모두 비는 비트를 0으로 채운다. 변위가 음수면 반대 방향으로 민다. 변위의 절대값이 정수의 비트 수와 같거나 그보다 크면 (모든 비트가 밀리므로) 결과가 0이다.

3.4.3 – 타입 강제와 변환

루아에서는 일부 타입과 표현들 간에 런타임 자동 변환을 어느 정도 제공한다. 비트 연산자는 항상 실수 피연산자를 정수로 변환한다. 누승과 실수 나눗셈에서는 항상 정수 피연산자를 실수로 변환한다. 다른 모든 산술 연산은 정수와 실수가 섞인 수들에 적용 시 정수 피연산자를 실수로 변환한다. C API에서도 필요에 따라 정수를 실수로, 또는 실수를 정수로 변환한다. 그리고 문자열 접합에서는 문자열 외에도 수를 인자로 받는다.

정수에서 실수로 변환 시 정수 값을 실수로 정확히 표현할 수 있으면 그 실수 표현이 결과가 된다. 그렇지 않으면 표현 가능한 가장 가까운 위나 아래의 값으로 변환한다. 이 변환은 절대 실패하지 않는다.

실수에서 정수로 변환할 때는 실수를 정수로 정확히 표현할 수 있는지 (즉 실수가 정수인 값을 가지고 있고 그 값이 정수 표현 범위 내에 있는지) 확인한다. 그렇다면 그 정수 표현이 결과가 된다. 아니면 변환에 실패한다.

여러 곳에서 필요시 문자열을 수로 강제 변환한다. 특히 문자열 라이브러리에서는 모든 산술 연산에서 문자열을 수로 강제해 보는 메타메소드를 설정한다. 변환이 실패하면 다른 피연산자의 메타메소드를 (존재한다면) 호출하고, 아니면 오류를 던진다. 다만 비트 연산에서는 이런 강제 변환을 하지 않는다.

그렇지만 이런 암묵적 강제 변환이 항상 적용되는 것은 아니므로 어떤 경우든 의존하지 않는 게 바람직하다. 특히 "1"==1은 거짓이고 "1"<1은 오류를 던진다. (3.4.4절 참고.) 이런 변환 동작은 주로 호환성 때문에 남아 있는 것이며 향후의 언어 버전에서 제거될 수 있다.

문자열에서 수로 변환할 때는 그 구문과 루아 단어 분석기(lexer) 규칙에 따라 정수나 실수로 변환한다. 문자열에 앞뒤의 공백과 부호가 있을 수 있다. 문자열에서 수로 변환 시 소수점으로 마침표와 더불어 현재 로캘의 표시도 받아들인다. (하지만 루아 단어 분석기는 마침표만 받는다.) 문자열이 유효한 수가 아니면 변환이 실패한다. 필요시 이 첫 단계의 결과를 위의 실수 정수 변환 규칙에 따라 구체적인 수 서브타입으로 변환할 수 있다.

수에서 문자열로 변환할 때는 따로 명세가 없는 사람이 읽을 수 있는 형식을 사용한다. 특정 방식으로 변환하려면 string.format 함수를 쓰면 된다.

3.4.4 – 관계 연산자

루아에서는 다음 관계 연산자를 지원한다.

이 연산자들은 항상 false 또는 true를 내놓는다.

같음(==)에서는 먼저 피연산자 타입을 비교한다. 타입이 다르면 결과가 false다. 그렇지 않으면 피연산자들의 값을 비교한다. 문자열은 바이트 내용물이 같으면 서로 같은 것이다. 수는 같은 수학적 값을 나타내면 서로 같은 것이다.

테이블, userdata, 스레드는 참조로 비교한다. 즉, 두 객체는 동일 객체인 경우에만 서로 같다고 본다. 그래서 새 객체(테이블, userdata, 스레드)를 만들 때마다 그 새 객체는 이전의 모든 객체와 다르게 된다. 함수는 그 자체와는 항상 같다. 탐지 가능한 차이(상이한 동작, 상이한 정의)가 있는 함수는 항상 서로 다르다. 따로 생성되었지만 탐지 가능한 차이가 없는 함수는 (내부 캐싱 세부 동작에 따라) 같다고 분류될 수도 있고 아닐 수도 있다.

__eq 메타메소드를 이용하면 테이블과 userdata를 비교하는 방식을 바꿀 수 있다. (2.4절 참고.)

같음 비교에서는 문자열을 수로, 또는 그 반대로 변환하지 않는다. 따라서 "0"==0을 평가하면 false이고, t[0]t["0"]은 서로 다른 테이블 항목을 나타낸다.

연산자 ~=는 같음(==)의 정확히 반대다.

순서 연산자의 동작 방식은 이렇다. 두 인자 모두 수이면 서브타입과 상관없이 수학적 값에 따라 비교한다. 그렇지 않고 두 인자 모두 문자열이면 현재 로캘에 따라 그 값을 비교한다. 그 외 경우에는 메타메소드 __lt__le 호출을 시도한다. (2.4절 참고.) 비교 식 a > bb < a로 바뀌고 a >= bb <= a로 바뀐다.

IEEE 754 표준에 따라 특수 값 NaN은 스스로를 포함한 어떤 값보다 작지도, 같지도, 크지도 않다고 본다.

3.4.5 – 논리 연산자

루아의 논리 연산자는 and, or, not이다. 제어 구조와 마찬가지로 (3.3.4절 참고) 논리 연산자에서는 falsenil을 거짓으로 여기고 그 외는 모두 참으로 여긴다.

부정 연산자 not은 항상 false 또는 true를 반환한다. 논리곱 연산자 and는 첫 번째 인자의 값이 falsenil이면 그 인자를 반환하고, 그렇지 않으면 두 번째 인자를 반환한다. 논리합 연산자 or는 첫 번째 인자의 값이 nilfalse와 다르면 그 인자를 반환하고, 그렇지 않으면 두 번째 인자를 반환한다. andor 모두에서 단락 평가 방식을 쓴다. 즉, 필요한 경우에만 두 번째 피연산자를 평가한다. 몇 가지 예를 들면 다음과 같다.

     10 or 20            --> 10
     10 or error()       --> 10
     nil or "a"          --> "a"
     nil and 10          --> nil
     false and error()   --> false
     false and nil       --> false
     false or nil        --> nil
     10 and 20           --> 20

3.4.6 – 접합

루아의 문자열 접합 연산자는 점 두 개('..')로 나타낸다. 두 피연산자 모두 문자열이나 수이면 따로 명세가 없는 규칙에 따라 (3.4.3절 참고) 수를 문자열로 변환한다. 그렇지 않으면 메타메소드 __concat을 호출한다. (2.4절 참고.)

3.4.7 – 길이 연산자

길이 연산자는 단항 전위 연산자 #로 표시한다.

문자열의 길이는 문자열의 바이트 수이다. (즉, 각 문자가 한 바이트일 때 일반적인 문자열 길이와 같은 의미다.)

테이블에 길이 연산자를 적용하면 그 테이블의 경계를 반환한다. 테이블 t경계(border)란 다음 조건을 충족시키는 자연수다.

     (border == 0 or t[border] ~= nil) and t[border + 1] == nil

다시 말해 경계란 테이블에 존재하는 (자연수) 인덱스로서 바로 다음 인덱스가 없는 것이다. (인덱스 1이 없으면 0이다.)

경계가 딱 한 개인 테이블을 열(sequence)이라고 한다. 예를 들어 테이블 {10, 20, 30, 40, 50}은 경계가 하나뿐(5)이므로 열이다. 테이블 {10, 20, 30, nil, 50}은 경계가 둘(3과 5)이므로 열이 아니다. (인덱스 4의 nil구멍이라고 한다.) 테이블 {nil, 20, 30, nil, nil, 60, nil}은 경계 셋(0, 3, 6)과 구멍 셋(인덱스 1, 4, 5)이 있으므로 역시 열이 아니다. 테이블 {}는 경계가 0인 열이다. 참고로 자연수 아닌 키는 테이블이 열인지 여부에 영향을 주지 않는다.

t가 열일 때 #t는 그 유일한 경계를 반환한다. 그 값은 열의 길이라는 직관적 개념에 대응한다. t가 열이 아닐 때 #t는 그 경계들 중 아무 값이나 반환할 수 있다. (정확히 어느 값인지는 테이블을 내부적으로 표현하는 방식에 따라 달라지는데, 그 역시 테이블을 어떻게 채웠는지와 수 아닌 키들의 메모리 주소에 따라 달라질 수 있다.)

테이블 길이 계산의 최악 실행 시간이 O(log n)이라고 보장된다. 여기서 n은 테이블에서 가장 큰 자연수 키이다.

프로그램에서 메타메소드 __len을 통해 문자열을 제외한 모든 값의 길이 연산자 동작을 바꿀 수 있다. (2.4절 참고.)

3.4.8 – 우선순위

루아의 연산자 우선순위는 아래 표를 따른다. 우선도가 점점 높아지는 순서다.

     or
     and
     <     >     <=    >=    ~=    ==
     |
     ~
     &
     <<    >>
     ..
     +     -
     *     /     //    %
     단항 연산자 (not   #     -     ~)
     ^

언제나처럼 괄호를 써서 식의 우선순위를 바꿀 수 있다. 접합('..') 및 누승('^') 연산자는 우측부터 결합이다. 다른 이항 연산자는 모두 좌측부터 결합이다.

3.4.9 – 테이블 생성자

테이블 생성자는 테이블을 만드는 식이다. 생성자를 평가할 때마다 새 테이블이 만들어진다. 생성자를 이용해 빈 테이블을 만들 수도 있고 테이블을 만들면서 일부 필드를 초기화할 수도 있다. 생성자의 일반 문법은 다음과 같다.

	tableconstructor ::= ‘{’ [fieldlist] ‘}’
	fieldlist ::= field {fieldsep field} [fieldsep]
	field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
	fieldsep ::= ‘,’ | ‘;

[exp1] = exp2 형태의 각 필드는 새 테이블에 키가 exp1이고 값이 exp2인 항목을 추가한다. name = exp 형태의 필드는 ["name"] = exp와 동등하다. exp 형태의 필드는 [i] = exp와 동등한데, 여기서 i는 1부터 시작하는 연속된 정수이며, 다른 형태의 필드들은 이 수에 영향을 주지 않는다. 예를 들어 다음은

     a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }

다음과 동등하다.

     do
       local t = {}
       t[f(1)] = g
       t[1] = "x"         -- 1번째 exp
       t[2] = "y"         -- 2번째 exp
       t.x = 1            -- t["x"] = 1
       t[3] = f(x)        -- 3번째 exp
       t[30] = 23
       t[4] = 45          -- 4번째 exp
       a = t
     end

생성자 내 할당 순서는 규정되어 있지 않다. (그 순서가 의미 있는 경우는 반복되는 키가 있을 때뿐일 것이다.)

목록의 마지막 필드가 exp 형태이고 그 식이 함수 호출이나 가변 인자 식인 경우에는 그 식이 반환하는 모든 값들이 차례로 리스트에 들어간다. (3.4.10절 참고.)

필드 목록 끝에 선택적으로 구분자가 올 수 있는데, 그래서 코드를 자동 생성하기가 편해진다.

3.4.10 – 함수 호출

루아에서 함수 호출의 문법은 다음과 같다.

	functioncall ::= prefixexp args

함수 호출에서는 먼저 prefixexp와 args를 평가한다. prefixexp의 값이 함수 타입이면 주어진 인자들로 그 함수를 호출한다. 그렇지 않은 경우 prefixexp의 __call 메타메소드가 존재하면 호출한다. prefixexp의 값을 첫 번째 인자로 하고 이어서 원래의 호출 인자들이 온다. (2.4절 참고.)

다음 형태를 이용해 메소드를 흉내낼 수 있다.

	functioncall ::= prefixexp ‘:’ Name args

호출 식 v:name(args)v.name(v,args)에 대한 문법적 양념이다. 단, v가 한 번만 평가된다.

인자 문법은 다음과 같다.

	args ::= ‘(’ [explist] ‘)’
	args ::= tableconstructor
	args ::= LiteralString

모든 인자 식을 호출 전에 평가한다. f{fields} 형태 호출은 f({fields})에 대한 문법적 양념이다. 즉, 인자 목록이 새 테이블 하나인 경우다. f'string' 형태 호출은 (또는 f"string"이나 f[[string]])는) f('string')에 대한 문법적 양념이다. 즉, 인자 목록이 리터럴 문자열 하나인 경우다.

자동 닫힘 변수 유효 범위가 아닌 곳에 있는 return functioncall 형태의 호출을 꼬리 호출이라고 한다. 루아는 진정(proper) 꼬리 호출(진정 꼬리 재귀)을 구현한다. 꼬리 호출에서는 피호출 함수가 호출측 함수의 스택 항목을 재사용한다. 따라서 프로그램에서 실행 가능한 꼬리 호출 중첩 횟수에 아무 제한이 없다. 하지만 꼬리 호출은 호출측 함수에 대한 디버그 정보를 모두 지워 버린다. 참고로 특정 구문에서만, 즉 return의 인자가 함수 호출 하나뿐이고 자동 닫힘 변수의 유효 범위 밖인 경우에만 꼬리 호출이 일어난다. 어떤 중간 동작 없이 피호출 함수의 반환 결과를 호출측 함수가 그대로 반환하게 하는 구문이다. 따라서 다음 예는 꼬리 호출이 아니다.

     return (f(x))        -- 결과 1개로 조정
     return 2 * f(x)      -- 결과에 2 곱함
     return x, f(x)       -- 결과에 추가
     f(x); return         -- 결과를 버림
     return x or f(x)     -- 결과 1개로 조정

3.4.11 – 함수 정의

함수 정의 문법은 다음과 같다.

	functiondef ::= function funcbody
	funcbody ::= ‘(’ [parlist] ‘)’ block end

다음 문법적 양념은 함수 정의를 간편하게 만들어 준다.

	stat ::= function funcname funcbody
	stat ::= local function Name funcbody
	funcname ::= Name {‘.’ Name} [‘:’ Name]

다음 문은

     function f () body end

다음으로 바뀐다.

     f = function () body end

다음 문은

     function t.a.b.c.f () body end

다음으로 바뀐다.

     t.a.b.c.f = function () body end

다음 문은

     local function f () body end

다음으로 바뀐다.

     local f; f = function () body end

다음으로 바뀌는 것이 아니다.

     local f = function () body end

(함수 몸체에 f에 대한 참조가 있을 때만 차이가 생긴다.)

함수 정의는 실행 가능한 식이고 그 값은 함수 타입이다. 루아에서 청크를 사전 컴파일할 때 함수 몸체들도 모두 사전 컴파일하되 생성은 하지 않는다. 그러고 나서 루아에서 그 함수 정의를 실행할 때마다 함수를 인스턴스화(즉 마무리(close))한다. 그 함수 인스턴스, 즉 클로저(closure)가 식의 최종 값이다.

매개변수는 인자 값으로 초기화된 지역 변수처럼 동작한다.

	parlist ::= namelist [‘,’ ‘...’] | ‘...

루아 함수 호출 시 인자 목록이 매개변수 목록 길이에 맞게 조정된다. 단, 매개변수 목록 끝에 점 세 개('...')가 있는 가변 인자 함수에서는 아니다. 가변 인자 함수에서는 인자 목록을 조정하지 않는다. 초과 인자를 모두 모아서 역시 점 세 개로 쓰는 가변 인자 식을 통해 함수에 제공한다. 그 식의 값은 실제 초과 인자 전체의 목록인데, 다중 결과 함수에서와 비슷하다. 가변 인자 식을 다른 식 내에서나 식 목록 중간에서 사용하는 경우에는 그 가변 인자 식의 반환 목록이 단일 항목으로 조정된다. 식 목록의 마지막 항목으로 사용하는 경우에는 (그 마지막 식을 괄호로 감싸지 않는 한) 어떤 조정도 이뤄지지 않는다.

예를 들어 다음 정의가 있다고 하자.

     function f(a, b) end
     function g(a, b, ...) end
     function r() return 1,2,3 end

그러면 인자가 매개변수 및 가변 인자 식으로 다음과 같이 매핑된다.

     호출             매개변수
     
     f(3)             a=3, b=nil
     f(3, 4)          a=3, b=4
     f(3, 4, 5)       a=3, b=4
     f(r(), 10)       a=1, b=10
     f(r())           a=1, b=2
     
     g(3)             a=3, b=nil, ... -->  (없음)
     g(3, 4)          a=3, b=4,   ... -->  (없음)
     g(3, 4, 5, 8)    a=3, b=4,   ... -->  5  8
     g(5, r())        a=5, b=1,   ... -->  2  3

return 문을 이용해 결과를 반환한다. (3.3.4절 참고.) 제어가 return 문을 만나지 않고 함수 끝에 도달한 경우에는 함수가 아무 결과도 반환하지 않는다.

함수가 반환할 수 있는 값 개수에 대해 시스템마다 다른 제한이 있다. 그 제한치가 1000보다 크다는 것이 보장된다.

콜론 문법을 이용해 메소드를 흉내낼 수 있으며, 암묵적인 추가 매개변수 self가 함수에 더해진다. 그래서 다음 문은

     function t.a.b.c:f (params) body end

다음에 대한 문법적 양념이다.

     t.a.b.c.f = function (self, params) body end

3.5 – 가시성 규칙

루아는 문법적 스코프(lexical scope)를 쓰는 언어다. 지역 변수의 유효 범위는 선언 다음의 첫 번째 문에서 시작해서 그 선언을 포함하는 가장 안쪽 블록의 비어 있지 않은 마지막 문까지 이어진다. 다음 예를 보자.

     x = 10                -- 전역 변수
     do                    -- 새 블록
       local x = x         -- 값 10으로 새 'x'
       print(x)            --> 10
       x = x+1
       do                  -- 또 다른 블록
         local x = x+1     -- 또 다른 'x'
         print(x)          --> 12
       end
       print(x)            --> 11
     end
     print(x)              --> 10  (전역 변수)

local x = x 같은 선언을 보면, 아직은 선언하려는 새 x의 유효 범위 안이 아니므로 두 번째 x가 바깥의 변수를 가리키게 된다.

문법적 스코프 규칙 때문에 지역 변수의 유효 범위 내에 정의된 함수에서 그 변수에 자유롭게 접근할 수 있다. 안쪽 함수에서 이용하는 지역 변수를 그 함수 내에서 upvalue라고 (또는 외부 지역 변수, 혹은 그냥 외부 변수라고) 부른다.

local 문을 실행할 때마다 새 지역 변수를 정의하게 된다. 다음 예를 보자.

     a = {}
     local x = 20
     for i = 1, 10 do
       local y = 0
       a[i] = function () y = y + 1; return x + y end
     end

루프에서 클로저 열 개를 (즉 익명 함수 인스턴스 열 개를) 만든다. 모든 클로저가 같은 x를 공유하면서 각기 다른 y 변수를 쓴다.

4 – 응용 프로그램 인터페이스

이 절에서는 루아의 C API를 설명한다. 호스트 프로그램에서 루아와 의사소통하는 데 이 C 함수들을 이용할 수 있다. 모든 API 함수와 관련 타입 및 상수들이 헤더 파일 lua.h에 선언되어 있다.

API의 어떤 항목이든 "함수"라는 용어를 쓰더라도 실제로는 매크로일 수 있다. 따로 언급하지 않으면 그런 매크로에서는 각 인자를 정확히 한 번만 사용하며 (언제나 루아 상태인 첫 번째 인자는 제외) 그래서 숨겨진 부작용을 전혀 만들어 내지 않는다.

대부분의 C 라이브러리들처럼 루아 API 함수에서도 인자의 유효성이나 무모순성을 검사하지 않는다. 하지만 매크로 LUA_USE_APICHECK를 정의해서 루아를 컴파일하여 이 동작 방식을 바꿀 수 있다.

루아 라이브러리는 완전하게 재진입 가능하다. 즉, 전역 변수가 전혀 없다. 필요한 정보는 모두 루아 상태라고 하는 동적 구조체 안에 둔다.

각 루아 상태에는 한 개 이상의 스레드가 있는데, 각 스레드는 독립적인 협력적 실행 흐름에 대응한다. lua_State 타입은 (그 이름과 달리) 스레드를 가리킨다. (그 스레드를 통해서 연계된 루아 상태를 간접적으로 가리키기는 한다.)

라이브러리의 모든 함수에 첫 번째 인자로 스레드 포인터를 주어야 한다. 단, 무에서부터 루아 상태를 만들어서 새 상태의 주 스레드에 대한 포인터를 반환하는 lua_newstate는 예외다.

4.1 – 스택

가상 스택을 이용해 루아와 C가 값을 주고받는다. 이 스택의 각 항목이 루아 값(nil, 수, 문자열 등)을 나타낸다. API 함수들에 주는 루아 상태 매개변수를 통해 함수에서 이 스택에 접근할 수 있다.

루아에서 C를 호출할 때마다 피호출 함수가 새 스택을 받는다. 이 스택은 이전의 스택과, 그리고 아직 활성인 C 함수의 스택과 독립적이다. 처음에 이 스택은 C 함수를 위한 인자들을 담고 있다. C 함수에서 여기에 임시 루아 값을 저장할 수 있으며 호출자에게 반환할 결과를 여기 집어넣어야 한다. (lua_CFunction 참고.)

편의를 위해 API의 대다수 질의 연산에서는 스택 접근을 엄격하게 규제하지 않는다. 인덱스를 써서 스택 내의 어느 항목이든 참조할 수 있다. 양수 인덱스는 절대적 스택 위치를 나타내며 스택 바닥 1에서 시작한다. 음수 인덱스는 스택 상단을 기준으로 한 위치를 나타낸다. 구체적으로 스택에 n개 항목이 있을 때 인덱스 1은 첫 번째 항목을 (즉 스택에 가장 먼저 넣은 항목을) 나타내고 인덱스 n이 마지막 항목을 나타낸다. 인덱스 -1 역시 마지막 항목을 (즉 상단의 항목을) 나타내고 인덱스 -n이 첫 번째 항목을 나타낸다.

4.1.1 – 스택 크기

루아 API를 다룰 때 무모순성을 보장할 책임은 사용자에게 있다. 특히 스택 오버플로우를 책임지고 통제해야 한다. 함수 lua_checkstack을 사용해서 스택에 새 항목을 집어넣을 공간이 있도록 할 수 있다.

루아에서 C를 부를 때는 항상 스택에 최소 LUA_MINSTACK개의 추가 슬롯이 있도록 보장한다. LUA_MINSTACK은 20으로 정의되어 있으며, 따라서 코드에서 루프를 돌며 스택에 항목을 넣는 경우가 아니면 일반적으로 스택 공간에 신경 쓸 필요가 없다.

결과 개수가 정해져 있지 않은 루아 함수를 호출할 때 (lua_call 참고) 스택에 전체 결과를 위한 공간이 있도록 루아에서 보장하지만 그 이상의 공간은 보장하지 않는다. 따라서 그런 호출 후 스택에 뭔가를 집어넣기 전에는 lua_checkstack을 쓰는 게 좋다.

4.1.2 – 유효 인덱스와 허용 인덱스

API에서 스택 인덱스를 받는 함수는 모두 유효 인덱스 또는 허용 인덱스로 동작한다.

유효 인덱스란 변경 가능한 루아 값을 저장하고 있는 위치를 가리키는 인덱스다. 1번에서 스택 상단까지의 인덱스(1 ≤ abs(index) ≤ top)와 더불어 스택에 있지 않지만 C 코드에서 접근 가능한 어떤 위치를 나타내는 가상 인덱스(pseudo-index)로 이뤄진다. 레지스트리(4.3절)와 C 함수의 upvalue(4.2절)에 접근할 때 가상 인덱스를 쓴다.

명확한 변경 가능 위치가 필요한 게 아니라 값이 필요할 뿐인 함수(예를 들면 질의 함수)는 허용 인덱스로 호출할 수 있다. 허용 인덱스는 어떤 유효 인덱스일 수도 있고 스택에 할당된 공간 내의 스택 상단 너머 어떤 양수 인덱스일 수도 있다. 즉, 스택 크기까지의 인덱스다. (0은 절대 허용 인덱스가 아니다.) 현재 C 함수 내의 실제 upvalue(4.2절) 개수보다 큰 upvalue 인덱스도 (유효하지는 않지만) 허용 인덱스다. 따로 언급한 경우를 제외하고 API의 함수들은 허용 인덱스로 동작한다.

허용 인덱스는 스택 값 질의 시 스택 상단을 확인하는 추가 검사를 피하게 해 준다. 예를 들어 C 함수에서 세 번째 인자를 질의할 때 세 번째 인자가 있는지 여부, 즉 3이 유효 인덱스인지 여부를 확인해 볼 필요가 없다.

허용 인덱스로 호출 가능한 함수에서 유효 인덱스 아닌 위치는 가상 타입 LUA_TNONE인 값을 담고 있는 것처럼 처리한다. 그 값은 nil 값처럼 작동한다.

4.2 – C 클로저

C 함수를 생성할 때 어떤 값들을 연계해서 C 클로저를 만들 수 있다. (lua_pushcclosure 참고.) 그 값들을 upvalue라고 하며 호출된 함수에서 언제나 접근 가능하다.

C 함수 호출 시 그 upvalue들은 언제나 특정 가상 인덱스에 위치하게 된다. 매크로 lua_upvalueindex가 그 가상 인덱스를 만들어 준다. 함수에 연계된 첫 번째 upvalue가 lua_upvalueindex(1)에 있는 식이다. 현재 함수의 upvalue 개수보다 큰 (하지만 클로저 upvalue 최대 개수에 1을 더한 값인 256보다는 크지 않은) n으로 lua_upvalueindex(n)에 접근하면 허용이지만 유효하지 않은 인덱스가 나온다.

C 클로저에서 해당 upvalue의 값을 바꿀 수도 있다.

4.5 – 레지스트리

루아에는 레지스트리라는 미리 정의된 테이블이 있다. C 코드에서 이 테이블에 어떤 루아 값이든 저장할 수 있다. 레지스트리 테이블은 항상 가상 인덱스 LUA_REGISTRYINDEX로 접근 가능하다. 어느 C 라이브러리에서든 이 테이블에 값을 저장할 수 있되, 충돌을 피하기 위해 다른 라이브러리들과 다른 키를 고르도록 신경을 써야 한다. 보통 라이브러리 이름을 담은 문자열이나 코드 내 C 객체의 주소인 light userdata, 또는 코드에서 생성한 루아 객체를 키로 쓰면 된다. 변수 이름에서처럼 밑줄로 시작하고 이어서 대문자 글자들이 오는 문자열 키는 루아 자체 용도로 예약되어 있다.

레지스트리 내의 정수 키는 참조 메커니즘(luaL_ref)과 몇 가지 사전 정의 값들에 쓰인다. 따라서 다른 용도로 레지스트리의 정수 키를 사용해서는 안 된다.

루아 상태를 새로 생성하면 그 레지스트리에는 몇 가지 미리 정의된 값들이 있다. 그 사전 정의 값들의 인덱스는 lua.h에 상수로 정의되어 있는 정수 키다. 다음 상수가 정의되어 있다.

4.4 – C에서의 오류 처리

내부적으로 루아는 C의 longjmp 기능을 이용해 오류를 처리한다. (루아를 C++로 컴파일하면 예외를 이용한다. 소스 코드에서 LUAI_THROW로 검색하면 자세한 내용이 나온다.) 루아에서 메모리 할당 오류나 타입 오류 같은 오류를 만나면 오류를 던진다. 즉, 긴 점프를 한다. 보호 환경에서는 setjmp를 사용해 복원 지점을 지정한다. 그러면 오류 발생 시 가장 최근의 활성 복원 지점으로 점프한다.

C 함수 내에서 lua_error를 호출해서 명시적으로 오류를 던질 수 있다.

API의 함수 대부분이 이를테면 메모리 할당 오류 때문에 오류를 던질 수 있다. 각 함수별 설명에 오류를 던질 수 있는지 여부가 나와 있다.

보호 환경 밖에서 오류가 생기면 루아에서 패닉 함수를 호출하고서 (lua_atpanic 참고) abort를 호출해서 호스트 응용을 끝낸다. 끝내는 것을 막으려면 패닉 함수에서 (이를테면 루아 밖의 자체 복원 지점으로 긴 점프를 해서) 절대 반환하지 않으면 된다.

이름에서 알 수 있듯 패닉 함수는 최후의 수단이다. 따라서 가급적 쓰지 않는 게 좋다. 일반적으로 루아에서 루아 상태를 가지고 C 함수를 호출할 때는 이미 보호 상태일 것이기에 C 함수에서 그 루아 상태에 무엇이든 할 수 있다. 하지만 C 코드에서 다른 루아 상태에 (예를 들어 그 함수의 루아 상태 인자, 레지스트리에 저장된 루아 상태, lua_newthread의 결과에) 작업을 하는 경우에는 오류를 던질 수 없는 API 호출에만 그 상태를 써야 한다.

패닉 함수는 메시지 핸들러인 것처럼 돈다. (2.3절 참고.) 특별히 스택 상단에 오류 객체가 있다. 하지만 스택 공간에 대해선 어떤 보장도 없다. 패닉 함수에서 스택에 뭔가를 집어넣으려면 먼저 가용 공간을 확인해야 한다. (4.1.1절 참고.)

4.4.1 – 상태 코드

오류를 보고하는 여러 API 함수들에서는 다음 상태 코드를 이용해 다양한 오류 내지 기타 상태를 나타낸다.

헤더 파일 lua.h에 이 상수들이 정의되어 있다.

4.5 – C에서의 양보 처리

코루틴 양보에 루아 내부적으로 C의 longjmp 기능을 이용한다. 그래서 C 함수 foo에서 어떤 API 함수를 호출했는데 그 API 함수에서 (직접적으로, 또는 양보하는 다른 함수를 호출해서 간접적으로) 양보하면 더 이상 루아에서 foo로 반환할 수 없다. longjmp 때문에 C 스택에서 프레임이 없어지기 때문이다.

이런 문제를 피하기 위해 API 호출을 거쳐서 양보하려고 할 때는 루아에서 항상 오류를 던진다. 단, 세 함수 lua_yieldk, lua_callk, lua_pcallk가 예외인데, 이 함수들은 양보 후 실행을 이어 갈 속행 함수를 (k라는 매개변수로) 받는다.

속행을 설명하기 위해 용어를 좀 정하겠다. 루아에서 호출하는 C 함수가 있고, 이를 시작 함수라고 할 것이다. 이 시작 함수가 C API의 그 세 함수 중 하나를 호출하는데, 이를 피호출 함수라고 할 것이다. 그 피호출 함수에서 현재 스레드를 양보한다. 피호출 함수가 lua_yieldk일 때, 또는 피호출 함수가 lua_callklua_pcallk이고 거기서 호출하는 함수에서 양보를 할 때 그렇게 될 수 있다.

피호출 함수 실행 중에 동작 스레드가 양보를 한다고 하자. 그 스레드가 재개된 후 피호출 함수 실행이 마침내 끝나게 된다. 하지만 피호출 함수가 시작 함수로 반환할 수가 없다. 양보 때문에 C 스택에서 그 함수의 프레임이 파기되었기 때문이다. 그래서 피호출 함수 인자로 받았던 속행 함수를 대신 호출한다. 이름에서 알 수 있듯 속행 함수는 시작 함수의 일을 이어서 하게 된다.

설명을 위해 다음과 같은 함수를 생각해 보자.

     int original_function (lua_State *L) {
       ...     /* code 1 */
       status = lua_pcall(L, n, m, h);  /* 루아 호출 */
       ...     /* code 2 */
     }

lua_pcall이 실행할 루아 코드에서 양보를 할 수 있게 하고 싶다고 하자. 그러면 먼저 함수를 다음처럼 고쳐 쓴다.

     int k (lua_State *L, int status, lua_KContext ctx) {
       ...  /* code 2 */
     }
     
     int original_function (lua_State *L) {
       ...     /* code 1 */
       return k(L, lua_pcall(L, n, m, h), ctx);
     }

위 코드에서 새 함수 k가 (lua_KFunction 타입의) 속행 함수다. 시작 함수에서 lua_pcall 호출 후 하던 작업을 모두 하게 된다. 다음으로, lua_pcall이 실행하는 루아 코드가 어떻게든 (오류나 양보로) 중단되면 루아에서 k를 호출해야 한다고 알려 줘야 한다. 따라서 lua_pcalllua_pcallk로 바꿔서 코드를 다음처럼 고쳐 쓴다.

     int original_function (lua_State *L) {
       ...     /* code 1 */
       return k(L, lua_pcallk(L, n, m, h, ctx2, k), ctx1);
     }

속행 함수를 외부에서 명시적으로도 호출하는 것에 주목하자. 루아에서는 필요할 때만, 즉 오류가 발생했거나 양보 후 재개하는 경우에만 속행 함수를 호출하게 된다. 호출된 함수가 한 번도 양보하지 않고 정상적으로 반환하면 lua_pcallk도 (그리고 lua_callk도) 정상적으로 반환하게 된다. (물론 그 경우에 속행 함수를 호출하지 않고 시작 함수 안에서 같은 작업을 직접 할 수도 있다.)

속행 함수에는 루아 상태 말고도 매개변수가 두 개 더 있는데, 호출의 최종 상태, 그리고 lua_pcallk에 원래 전달됐던 문맥 값(ctx)이다. 루아에서는 이 문맥 값을 사용하지 않고 시작 함수에서 속행 함수로 전달하기만 한다. lua_pcallk인 경우에 상태 값은 lua_pcallk가 반환했을 값과 같되, 양보 후 실행되는 것이면 (LUA_OK가 아니라) LUA_YIELD다. lua_yieldklua_callk인 경우에는 루아에서 속행 함수를 호출할 때 상태가 항상 LUA_YIELD다. (이 두 함수에서는 오류 경우에 루아에서 속행 함수를 호출하지 않는다. 오류 처리를 하는 함수가 아니기 때문이다.) 비슷한 방식으로 lua_callk 사용 시에는 LUA_OK를 상태로 해서 속행 함수를 호출해야 할 것이다. (lua_yieldk인 경우에는 속행 함수를 직접 호출하는 것이 별 의미가 없다. 보통 lua_yieldk가 반환하지 않기 때문이다.)

루아는 속행 함수를 시작 함수인 것처럼 다룬다. 속행 함수가 시작 함수와 같은 루아 스택을 받으며, 그 스택은 피호출 함수가 반환했을 때와 같은 상태다. (예를 들어 lua_callk 후에 스택에서 함수와 인자들이 제거되고 호출 결과로 교체된다.) 또한 upvalue들이 같다. 그리고 무엇을 반환하든 루아에서 이를 시작 함수의 반환처럼 처리한다.

4.6 – 함수와 타입

C API의 모든 함수와 타입을 알파벳 순서로 나열한다. 각 함수에는 이 문단 오른편과 같은 표시가 있다. [-o, +p, x]

첫 번째 필드 o는 함수가 스택에서 항목을 몇 개나 꺼내는가이다. 두 번째 필드 p는 함수가 스택에 항목을 몇 개나 집어넣는가이다. (어떤 함수든 항상 인자를 꺼낸 뒤에 결과를 집어넣는다.) x|y 형태인 필드는 함수가 상황에 따라 x개 또는 y개 항목을 집어넣을 (꺼낼) 수 있다는 뜻이다. 물음표 '?'는 인자만 봐서는 함수가 몇 개 항목을 꺼내는지/집어넣는지 알 수 없다는 뜻이다. (이를테면 스택 내용에 따라 달라질 수 있다.) 세 번째 필드 x는 함수가 오류를 던질 수 있는지를 알려 준다. '-'는 함수가 절대 오류를 던지지 않는다는 뜻이다. 'm'은 함수가 메모리 부족 오류만 던질 수 있다는 뜻이다. 'v'는 함수가 텍스트에서 설명하는 오류를 던질 수 있다는 뜻이다. 'e'는 함수가 직접 또는 메타메소드를 통해 임의의 루아 코드를 실행할 수 있으며, 그래서 어떤 오류도 던질 수 있다는 뜻이다.


lua_absindex

[-0, +0, –]

int lua_absindex (lua_State *L, int idx);

허용 인덱스 idx를 동등한 절대 인덱스로 (즉 스택 상단 위치와 무관한 인덱스로) 변환한다.


lua_Alloc

typedef void * (*lua_Alloc) (void *ud,
                             void *ptr,
                             size_t osize,
                             size_t nsize);

루아 상태에서 쓰는 메모리 할당 함수의 타입. realloc과 비슷하되 완전히 같지는 않은 기능성을 할당자 함수가 제공해야 한다. 인자는 lua_newstate에 전달했던 불투명 포인터인 ud, 할당/재할당/해제하려는 블록에 대한 포인터인 ptr, 블록의 원래 크기 또는 할당하려는 것에 대한 어떤 정보인 osize, 블록의 새 크기인 nsize다.

ptrNULL이 아닐 때 osizeptr이 가리키는 블록의 크기다. 즉, 할당이나 재할당 때 주었던 크기다.

ptrNULL일 때 osize는 루아에서 할당하려는 객체의 종류를 나타낸다. osizeLUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD 중 하나면 루아에서 그 타입의 새 객체를 만들려는 것이다. osize가 다른 어떤 값이면 루아에서 다른 뭔가를 위한 메모리를 할당하려는 것이다.

루아에서는 할당자 함수에 대해 다음 동작을 가정한다.

nsize가 0일 때 할당자가 free처럼 동작한 다음 NULL을 반환해야 한다.

nsize가 0이 아닐 때 할당자가 realloc처럼 동작해야 한다. 그리고 요청을 만족시킬 수 없으면, 그리고 그 경우에만 할당자가 NULL을 반환한다.

다음은 간단한 할당자 함수 구현이다. 보조 라이브러리의 luaL_newstate에서 쓰는 것이다.

     static void *l_alloc (void *ud, void *ptr, size_t osize,
                                                size_t nsize) {
       (void)ud;  (void)osize;  /* 사용 안 함 */
       if (nsize == 0) {
         free(ptr);
         return NULL;
       }
       else
         return realloc(ptr, nsize);
     }

참고로 free(NULL)에 아무 효력이 없으며 realloc(NULL,size)malloc(size)과 동등함을 표준 C에서 보장한다.


lua_arith

[-(2|1), +1, e]

void lua_arith (lua_State *L, int op);

스택 상단에 있는 두 값에 대해 (반수나 NOT은 한 값에 대해) 산술 연산이나 비트 연산을 수행한다. 상단 쪽 값을 두 번째 피연산자로 하며, 값들을 꺼내고 연산 결과를 집어넣는다. 대응하는 루아 연산자의 처리 방식을 따른다. (즉 메타메소드를 호출할 수도 있다.)

op 값은 다음 상수들 중 하나여야 한다.


lua_atpanic

[-0, +0, –]

lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);

새 패닉 함수를 설정하고 이전 함수를 반환한다. (4.4절 참고.)


lua_call

[-(nargs+1), +nresults, e]

void lua_call (lua_State *L, int nargs, int nresults);

함수를 호출한다. 정규 루아 호출처럼 lua_call에서는 __call 메타메소드를 존중한다. 따라서 여기서 "함수"라는 단어는 모든 호출 가능한 값을 뜻한다.

호출을 하려면 규약을 따라야 한다. 먼저 호출할 함수를 스택에 집어넣는다. 다음으로 호출 인자들을 정순서로 집어넣는다. 즉, 첫 번째 인자를 첫 번째로 집어넣는다. 마지막으로 lua_call을 호출한다. nargs는 스택에 집어넣은 인자 개수다. 함수가 반환할 때 인자와 함수 값 모두가 스택에서 빠지고 호출 결과가 스택에 들어간다. 그 결과가 nresults개로 조정된다. 단, nresultsLUA_MULTRET이면 함수 결과 모두가 들어간다. 반환되는 값들이 스택 공간에 들어갈 수 있도록 루아에서 처리를 해 준다. 하지만 그 이상은 어떤 스택 공간도 보장하지 않는다. 함수 결과들은 정순서로 스택에 들어간다. (첫 번째 결과를 첫 번째로 집어넣는다.) 그래서 호출 후 스택 상단에 마지막 결과가 있게 된다.

함수 호출 및 실행 중에 오류가 발생하면 (longjmp로) 위로 전파된다.

다음 루아 코드와 동등한 일을 호스트 프로그램에서 어떻게 할 수 있는지 이어지는 예가 보여 준다.

     a = f("how", t.x, 14)

다음은 C 코드다.

     lua_getglobal(L, "f");                            /* 호출할 함수 */
     lua_pushliteral(L, "how");                         /* 1번째 인자 */
     lua_getglobal(L, "t");                       /* 인덱싱 할 테이블 */
     lua_getfield(L, -1, "x");      /* t.x 결과 집어넣기 (2번째 인자) */
     lua_remove(L, -2);                          /* 스택에서 't' 제거 */
     lua_pushinteger(L, 14);                            /* 3번째 인자 */
     lua_call(L, 3, 1);             /* 3개 인자와 1개 결과로 'f' 호출 */
     lua_setglobal(L, "a");                          /* 전역 'a' 설정 */

참고로 위 코드는 평형이다. 즉, 마지막에 스택이 처음 구성으로 돌아간다. 이는 좋은 프로그래밍 습관이다.


lua_callk

[-(nargs + 1), +nresults, e]

void lua_callk (lua_State *L,
                int nargs,
                int nresults,
                lua_KContext ctx,
                lua_KFunction k);

이 함수는 정확히 lua_call처럼 동작하되 피호출 함수에서 양보를 할 수 있다. (4.5절 참고.)


lua_CFunction

typedef int (*lua_CFunction) (lua_State *L);

C 함수 타입.

C 함수에서 루아와 올바로 의사소통하려면 매개변수 및 결과 전달 방식을 규정하는 규약을 따라야 한다. C 함수가 루아로부터 인자를 받을 때는 스택에서 정순서로 (첫 번째 인자를 첫 번째로 집어넣기) 받는다. 그래서 함수 시작에서 lua_gettop(L)을 호출하면 함수가 받은 인자 개수를 반환한다. 첫 번째 인자가 (있다면) 1번 인덱스에 있고 마지막 인자가 lua_gettop(L) 인덱스에 있다. C 함수에서 루아로 값을 반환할 때는 정순서로 스택에 집어넣고 (첫 번째 결과를 첫 번째로 집어넣기) C에서 결과 개수를 반환하면 된다. 스택에서 결과 아래에 다른 값이 있으면 루아에서 적절히 폐기한다. 루아 함수와 마찬가지로 루아가 호출하는 C 함수도 여러 결과를 반환할 수 있다.

예를 들어 다음 함수는 가변 개수의 수 인자를 받아서 평균과 합을 반환한다.

     static int foo (lua_State *L) {
       int n = lua_gettop(L);    /* 인자 개수 */
       lua_Number sum = 0.0;
       int i;
       for (i = 1; i <= n; i++) {
         if (!lua_isnumber(L, i)) {
           lua_pushliteral(L, "incorrect argument");
           lua_error(L);
         }
         sum += lua_tonumber(L, i);
       }
       lua_pushnumber(L, sum/n);        /* 첫 번째 결과 */
       lua_pushnumber(L, sum);          /* 두 번째 결과 */
       return 2;                           /* 결과 개수 */
     }

lua_checkstack

[-0, +0, –]

int lua_checkstack (lua_State *L, int n);

스택에 최소 n개의 추가 슬롯이 있도록 만든다. 즉, 스택에 n개까지 값을 안전하게 집어넣을 수 있게 만든다. 스택이 고정된 최대 크기(보통 최소 수천 항목)보다 커지게 되거나 추가 공간을 위한 메모리를 할당할 수 없어서 요청을 만족시킬 수 없으면 거짓을 반환한다. 이 함수는 절대 스택을 줄이지 않는다. 즉, 스택에 추가 슬롯 공간이 이미 있으면 그대로 둔다.


lua_close

[-0, +0, –]

void lua_close (lua_State *L);

메인 스레드에서 모든 활성 자동 닫힘 변수를 닫고, (해당하는 쓰레기 수집 메타메소드가 있으면 호출하여) 지정한 루아 상태의 모든 객체를 해제하고, 그 상태가 쓰는 모든 동적 메모리를 해제한다.

여러 플랫폼에서는 이 함수를 호출할 필요가 없을 수 있는데, 호스트 프로그램이 끝날 때 모든 자원이 알아서 해제되기 때문이다. 반면 오래 돌면서 여러 상태를 만드는 데몬이나 웹 서버 같은 프로그램에서는 상태가 필요 없게 되면 즉시 닫아야 할 것이다.


lua_compare

[-0, +0, e]

int lua_compare (lua_State *L, int index1, int index2, int op);

두 루아 값을 비교한다. 인덱스 index1의 값이 인덱스 index2의 값과 비교하여 op를 만족시키는 경우 1을 반환하며, 비교 시 대응하는 루아 연산자의 동작 방식을 따른다. (즉 메타메소드를 호출할 수도 있다.) 만족시키지 않으면 0을 반환한다. 인덱스가 하나라도 유효하지 않을 때도 0을 반환한다.

op 값은 다음 상수들 중 하나여야 한다.


lua_concat

[-n, +1, e]

void lua_concat (lua_State *L, int n);

스택 상단의 n개 값들을 접합하고, 그 값들을 꺼내고, 결과를 상단에 둔다. n이 1이면 결과는 스택의 그 단일 값이다. (즉, 함수가 아무것도 하지 않는다.) n이 0이면 결과는 빈 문자열이다. 루아의 일반적 동작 방식에 따라 접합을 수행한다. (3.4.6절 참고.)


lua_copy

[-0, +0, –]

void lua_copy (lua_State *L, int fromidx, int toidx);

인덱스 fromidx의 항목을 유효 인덱스 toidx로 복사하여 그 위치의 값을 교체한다. 다른 위치의 값들은 영향을 받지 않는다.


lua_createtable

[-0, +1, m]

void lua_createtable (lua_State *L, int narr, int nrec);

빈 테이블을 새로 만들어서 스택에 집어넣는다. 매개변수 narr은 테이블에 수열로 얼마나 많은 항목이 있을지에 대한 힌트다. 매개변수 nrec는 테이블에 기타 항목들이 얼마나 많이 있을지에 대한 힌트다. 루아에서 이런 힌트를 이용해 새 테이블에 메모리를 미리 할당해 둘 수도 있다. 테이블에 항목이 몇 개일지 미리 알 때 이런 사전 할당이 성능에 도움이 될 수 있다. 그렇지 않다면 함수 lua_newtable을 쓸 수 있다.


lua_dump

[-0, +0, –]

int lua_dump (lua_State *L,
                        lua_Writer writer,
                        void *data,
                        int strip);

함수를 바이너리 청크 형태로 덤프한다. 스택 상단의 루아 함수를 받아서 바이너리 청크를 만들어 내는데, 그 청크를 다시 적재하면 덤프한 것과 동등한 함수가 나온다. lua_dump에서 청크의 부분들을 만들어 내면서 지정한 data로 함수 writer를 호출해서 기록을 한다.

strip이 참이면 공간 절약을 위해 함수에 대한 디버그 정보를 이진 표현에 모두 포함시키지 않을 수도 있다.

기록 함수 마지막 호출이 반환한 오류 코드가 반환 값이다. 0은 오류 없음을 뜻한다.

이 함수는 스택에서 루아 함수를 꺼내지 않는다.


lua_error

[-1, +0, v]

int lua_error (lua_State *L);

스택 상단의 값을 오류 객체로 사용해 루아 오류를 던진다. 이 함수는 긴 점프를 하기 때문에 절대 반환하지 않는다. (luaL_error 참고.)


lua_gc

[-0, +0, –]

int lua_gc (lua_State *L, int what, ...);

쓰레기 수집기를 제어한다.

이 함수는 매개변수 what의 값에 따라 여러 가지 작업을 수행한다. 옵션에 추가 인자가 필요한 경우 옵션 뒤에 나와 있다.

이 옵션들에 대한 더 자세한 내용은 collectgarbage를 보라.


lua_getallocf

[-0, +0, –]

lua_Alloc lua_getallocf (lua_State *L, void **ud);

지정한 상태의 메모리 할당 함수를 반환한다. udNULL이 아니면 메모리 할당자 함수 설정 때 준 불투명 포인터를 *ud에 저장한다.


lua_getfield

[-0, +1, e]

int lua_getfield (lua_State *L, int index, const char *k);

t[k]를 스택에 집어넣는다. 여기서 t는 지정한 인덱스에 있는 값이다. 루아 내에서처럼 이 함수가 "index" 이벤트에 대한 메타메소드를 유발할 수 있다. (2.4절 참고.)

집어넣은 값의 타입을 반환한다.


lua_getextraspace

[-0, +0, –]

void *lua_getextraspace (lua_State *L);

지정한 루아 상태에 연계된 가외 메모리 영역에 대한 포인터를 반환한다. 응용에서 이 영역을 임의 용도로 쓸 수 있다. 루아에서는 이 영역을 사용하지 않는다.

신규 스레드마다 주 스레드의 영역을 복사해서 이 영역을 초기화한다.

기본적으로 이 영역의 크기는 void 포인터만큼이다. 하지만 이 영역의 크기를 다르게 해서 루아를 다시 컴파일할 수 있다. (luaconf.hLUA_EXTRASPACE 참고.)


lua_getglobal

[-0, +1, e]

int lua_getglobal (lua_State *L, const char *name);

전역 name의 값을 스택에 집어넣는다. 그 값의 타입을 반환한다.


lua_geti

[-0, +1, e]

int lua_geti (lua_State *L, int index, lua_Integer i);

t[i]를 스택에 집어넣는다. 여기서 t는 지정한 인덱스에 있는 값이다. 루아 내에서처럼 이 함수가 "index" 이벤트에 대한 메타메소드를 유발할 수 있다. (2.4절 참고.)

집어넣은 값의 타입을 반환한다.


lua_getmetatable

[-0, +(0|1), –]

int lua_getmetatable (lua_State *L, int index);

지정한 인덱스에 있는 값에 메타테이블이 있으면 그 메타테이블을 스택에 집어넣고 1을 반환한다. 그렇지 않으면 0을 반환하고 스택에 아무것도 집어넣지 않는다.


lua_gettable

[-1, +1, e]

int lua_gettable (lua_State *L, int index);

t[k]를 스택에 집어넣는다. 여기서 t는 지정한 인덱스에 있는 값이고 k는 스택 상단에 있는 값이다.

이 함수는 스택에서 키를 꺼내고 그 자리에 결과 값을 집어넣는다. 루아 내에서처럼 이 함수가 "index" 이벤트에 대한 메타메소드를 유발할 수 있다. (2.4절 참고.)

집어넣은 값의 타입을 반환한다.


lua_gettop

[-0, +0, –]

int lua_gettop (lua_State *L);

스택 상단 항목의 인덱스를 반환한다. 인덱스가 1부터 시작하므로 그 결과는 스택 내 항목 수와 같다. 특히 0은 빈 스택을 뜻한다.


lua_getiuservalue

[-0, +1, –]

int lua_getiuservalue (lua_State *L, int index, int n);

지정한 인덱스에 있는 full userdata에 연계된 n 번째 사용자 값을 스택에 집어넣고, 집어넣은 값의 타입을 반환한다.

userdata에 그 값이 없으면 nil을 집어넣고 LUA_TNONE을 반환한다.


lua_insert

[-1, +1, –]

void lua_insert (lua_State *L, int index);

상단 항목을 지정한 유효 인덱스로 옮기고 그 인덱스 위의 항목들을 빈 공간으로 밀어 올린다. 가상 인덱스로는 이 함수를 호출할 수 없다. 가상 인덱스는 실제 스택 위치가 아니기 때문이다.


lua_Integer

typedef ... lua_Integer;

루아 정수 타입.

기본적으로 이 타입은 long long(보통 64비트 2의 보수 정수)이다. 하지만 long이나 int(보통 32비트 2의 보수 정수)로 바꿀 수 있다. (luaconf.hLUA_INT_TYPE 참고.)

이 타입에 맞는 최솟값과 최댓값으로 상수 LUA_MININTEGERLUA_MAXINTEGER를 루아에서 정의하고 있기도 하다.


lua_isboolean

[-0, +0, –]

int lua_isboolean (lua_State *L, int index);

지정한 인덱스에 있는 값이 불리언이면 1을 반환하고 아니면 0을 반환한다.


lua_iscfunction

[-0, +0, –]

int lua_iscfunction (lua_State *L, int index);

지정한 인덱스에 있는 값이 C 함수면 1을 반환하고 아니면 0을 반환한다.


lua_isfunction

[-0, +0, –]

int lua_isfunction (lua_State *L, int index);

지정한 인덱스에 있는 값이 (C 또는 루아) 함수면 1을 반환하고 아니면 0을 반환한다.


lua_isinteger

[-0, +0, –]

int lua_isinteger (lua_State *L, int index);

지정한 인덱스에 있는 값이 정수면 (즉 값이 수이고 정수로 표현되어 있으면) 1을 반환하고 아니면 0을 반환한다.


lua_islightuserdata

[-0, +0, –]

int lua_islightuserdata (lua_State *L, int index);

지정한 인덱스에 있는 값이 light userdata면 1을 반환하고 아니면 0을 반환한다.


lua_isnil

[-0, +0, –]

int lua_isnil (lua_State *L, int index);

지정한 인덱스에 있는 값이 nil이면 1을 반환하고 아니면 0을 반환한다.


lua_isnone

[-0, +0, –]

int lua_isnone (lua_State *L, int index);

지정한 인덱스가 유효하지 않으면 1을 반환하고 아니면 0을 반환한다.


lua_isnoneornil

[-0, +0, –]

int lua_isnoneornil (lua_State *L, int index);

지정한 인덱스가 유효하지 않거나 그 인덱스에 있는 값이 nil이면 1을 반환하고 아니면 0을 반환한다.


lua_isnumber

[-0, +0, –]

int lua_isnumber (lua_State *L, int index);

지정한 인덱스에 있는 값이 수이거나 수로 변환 가능한 문자열이면 1을 반환하고 아니면 0을 반환한다.


lua_isstring

[-0, +0, –]

int lua_isstring (lua_State *L, int index);

지정한 인덱스에 있는 값이 문자열이거나 (언제나 문자열로 변환 가능한) 수이면 1을 반환하고 아니면 0을 반환한다.


lua_istable

[-0, +0, –]

int lua_istable (lua_State *L, int index);

지정한 인덱스에 있는 값이 테이블이면 1을 반환하고 아니면 0을 반환한다.


lua_isthread

[-0, +0, –]

int lua_isthread (lua_State *L, int index);

지정한 인덱스에 있는 값이 스레드면 1을 반환하고 아니면 0을 반환한다.


lua_isuserdata

[-0, +0, –]

int lua_isuserdata (lua_State *L, int index);

지정한 인덱스에 있는 값이 (full 또는 light) userdata면 1을 반환하고 아니면 0을 반환한다.


lua_isyieldable

[-0, +0, –]

int lua_isyieldable (lua_State *L);

지정한 코루틴이 양보할 수 있으면 1을 반환하고 아니면 0을 반환한다.


lua_KContext

typedef ... lua_KContext;

속행 함수 문맥을 위한 타입. 수 타입이어야 한다. intptr_t가 사용 가능하면 이 타입이 intptr_t로 정의되어 있으며, 그래서 포인터도 저장할 수 있다. 그렇지 않으면 ptrdiff_t로 정의되어 있다.


lua_KFunction

typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);

속행 함수 타입. (4.5절 참고.)


lua_len

[-0, +1, e]

void lua_len (lua_State *L, int index);

지정한 인덱스에 있는 값의 길이를 반환한다. 루아의 '#' 연산자(3.4.7절)와 동등하며 "length" 이벤트에 대한 메타메소드를 유발할 수 있다. (2.4절 참고.) 결과를 스택에 집어넣는다.


lua_load

[-0, +1, –]

int lua_load (lua_State *L,
              lua_Reader reader,
              void *data,
              const char *chunkname,
              const char *mode);

루아 청크를 적재하고 실행은 하지 않는다. 오류가 없으면 lua_load는 청크를 루아 함수로 컴파일하여 스택 상단에 집어넣는다. 그렇지 않으면 오류 메시지를 집어넣는다.

lua_load 함수는 사용자가 제공한 reader 함수를 사용해 청크를 읽어 들인다. (lua_Reader 참고.) data 인자는 읽기 함수에게 전달하는 불투명한 값이다.

chunkname 인자는 청크에 이름을 준다. 오류 메시지와 디버그 정보(4.7절)에 쓰인다.

청크가 텍스트인지 바이너리인지 lua_load에서 자동으로 탐지해서 그에 맞게 적재한다. (luac 프로그램 참고.) 문자열 modeload 함수에서처럼 동작하며, 추가로 NULL 값이 문자열 "bt"와 동등하다.

lua_load 내부적으로 스택을 사용한다. 따라서 읽기 함수에서 반환할 때는 항상 스택이 변경 없는 상태여야 한다.

lua_loadLUA_OKLUA_ERRSYNTAX, LUA_ERRMEM을 반환할 수 있다. 또한 읽기 함수가 던진 오류에 대응하는 다른 값을 반환할 수도 있다. (4.4.1절 참고.)

결과 함수에 upvalue가 있는 경우 레지스트리(4.3절)의 LUA_RIDX_GLOBALS 인덱스에 저장돼 있는 전역 환경의 값을 첫 번째 upvalue에 설정한다. 메인 청크를 적재할 때 그 upvalue가 _ENV 변수가 된다. (2.2절 참고.) 다른 upvalue들은 nil로 초기화한다.


lua_newstate

[-0, +0, –]

lua_State *lua_newstate (lua_Alloc f, void *ud);

독자적인 상태를 새로 만들고 그 메인 스레드를 반환한다. 스레드를 만들 수 없으면 (메모리 부족) NULL을 반환한다. 인자 f는 할당자 함수다. 루아에서 이 상태를 위한 모든 메모리 할당이 그 함수를 통해 이뤄지게 된다. (lua_Alloc 참고.) 두 번째 인자인 ud는 불투명 포인터이며 할당자 호출 때마다 전달된다.


lua_newtable

[-0, +1, m]

void lua_newtable (lua_State *L);

빈 테이블을 새로 만들어서 스택에 집어넣는다. lua_createtable(L, 0, 0)과 동등하다.


lua_newthread

[-0, +1, m]

lua_State *lua_newthread (lua_State *L);

스레드를 새로 만들어서 스택에 집어넣고 그 새 스레드를 나타내는 lua_State 포인터를 반환한다. 이 함수가 반환하는 새 스레드는 원래 스레드와 전역 환경은 공유하지만 독립적인 실행 스택이 있다.

여느 루아 객체와 마찬가지로 스레드도 쓰레기 수집의 대상이다.


lua_newuserdatauv

[-0, +1, m]

void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue);

이 함수는 사용자 값이라고 부르는 nuvalue 연계 루아 값으로 full userdata를 새로 만들고 size 바이트짜리 메모리 블록을 연계시켜서 스택에 집어넣는다. (lua_setiuservaluelua_getiuservalue 함수로 그 사용자 값을 설정하고 읽을 수 있다.)

그 메모리 블록의 주소를 반환한다.


lua_next

[-1, +(2|0), v]

int lua_next (lua_State *L, int index);

스택에서 키를 꺼내고 지정한 인덱스에 있는 테이블에서 가져온 키–값 쌍을, 즉 지정한 키 "다음"의 쌍을 스택에 집어넣는다. 테이블에 항목이 더 없으면 lua_next가 0을 반환하고, 아무것도 집어넣지 않는다.

보통 테이블 순회는 다음 같은 형태다.

     /* 스택의 인덱스 't'에 테이블 있음 */
     lua_pushnil(L);  /* 첫 번째 키 */
     while (lua_next(L, t) != 0) {
       /* '키'(인덱스 -2)와 '값'(인덱스 -1) 사용 */
       printf("%s - %s\n",
              lua_typename(L, lua_type(L, -2)),
              lua_typename(L, lua_type(L, -1)));
       /* '값' 제거. '키'는 다음 반복을 위해 유지 */
       lua_pop(L, 1);
     }

테이블을 순회하는 동안에 키가 확실히 문자열임을 아는 경우가 아니면 키에 직접 lua_tolstring을 호출하는 걸 피해야 한다. lua_tolstring이 지정한 인덱스에 있는 값을 바꿀 수도 있기 때문에 다음 lua_next 호출에 혼란을 줄 수 있다.

지정한 키가 nil도 아니고 테이블에 있지도 않으면 함수가 오류를 던질 수 있다. 순회 중 테이블을 변경하는 것에 대한 주의 사항은 함수 next를 보라.


lua_Number

typedef ... lua_Number;

루아 실수 타입.

기본적으로 이 타입은 double이다. 하지만 단정밀도 float이나 long double로 바꿀 수 있다. (luaconf.hLUA_FLOAT_TYPE 참고.)


lua_numbertointeger

int lua_numbertointeger (lua_Number n, lua_Integer *p);

루아 실수를 루아 정수로 변환 시도한다. 실수 n이 정수인 값을 가지고 있어야 한다. 그 값이 루아 정수 범위 내에 있으면 정수로 변환하여 *p에 할당한다. 그리고 변환에 성공했는지를 나타내는 불리언을 결과로 내놓는다. (참고로 그 범위 검사를 이 매크로 없이 제대로 하기는 올림/내림 때문에 까다로울 수 있다.)

이 매크로에서 인자를 여러 번 평가할 수도 있다.


lua_pcall

[-(nargs + 1), +(nresults|1), –]

int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);

보호 모드로 함수를 (또는 호출 가능한 객체를) 호출한다.

nargsnresults의 의미는 lua_call과 같다. 호출 중에 오류가 없으면 lua_pcall은 정확히 lua_call처럼 동작한다. 하지만 오류가 있으면 lua_pcall이 오류를 잡아서 스택에 값 하나(오류 객체)를 집어넣고 오류 코드를 반환한다. lua_call과 마찬가지로 lua_pcall은 항상 함수와 그 인자들을 스택에서 제거한다.

msgh가 0이면 스택으로 반환된 오류 객체가 정확히 원래의 오류 객체다. 그렇지 않으면 msgh메시지 핸들러의 스택 인덱스다. (이 인덱스는 가상 인덱스일 수 없다.) 런타임 오류 발생 시 오류 객체로 그 핸들러가 호출되며 그 반환 값이 lua_pcall이 스택으로 반환하는 객체가 된다.

보통은 오류 객체에 스택 트레이스백 같은 디버그 정보를 추가하는 데 메시지 핸들러를 쓴다. lua_pcall 반환 후에는 스택이 이미 풀렸으므로 그런 정보를 수집할 수 없다.

lua_pcall 함수는 상태 코드 LUA_OK, LUA_ERRRUN, LUA_ERRMEM, LUA_ERRERR 중 하나를 반환한다.


lua_pcallk

[-(nargs + 1), +(nresults|1), –]

int lua_pcallk (lua_State *L,
                int nargs,
                int nresults,
                int msgh,
                lua_KContext ctx,
                lua_KFunction k);

이 함수는 정확히 lua_pcall처럼 동작하되, 피호출 함수에서 양보를 할 수 있다. (4.5절 참고.)


lua_pop

[-n, +0, –]

void lua_pop (lua_State *L, int n);

스택에서 n개 항목을 꺼낸다.


lua_pushboolean

[-0, +1, –]

void lua_pushboolean (lua_State *L, int b);

값이 b인 불리언 값을 스택에 집어넣는다.


lua_pushcclosure

[-n, +1, m]

void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

새 C 클로저를 스택에 집어넣는다. 이 함수는 C 함수 포인터를 받아서 함수 타입 루아 값을 스택에 집어넣는다. 그 값을 호출하면 대응하는 C 함수가 불린다. 매개변수 n은 이 함수의 upvalue가 몇 개나 될지를 나타낸다. (4.2절 참고.)

루아에서 호출 가능해야 하는 함수는 모두 정확한 규약에 따라 매개변수를 받고 결과를 반환해야 한다. (lua_CFunction 참고.)

C 함수를 만들 때 거기에 어떤 값들을 연계하는 게 가능하며, 그 값들을 upvalue라고 부른다. 호출된 함수에서 언제나 그 upvalue에 접근 가능하다. 그 연계를 C 클로저(4.2절)라고 한다. C 클로저를 만들려면 먼저 그 upvalue의 초기값을 스택에 집어넣어야 한다. (upvalue가 여러 개일 때는 첫 번째 값을 첫 번째로 집어넣는다.) 그리고 lua_pushcclosure를 호출해서 C 함수를 만들어 스택에 집어넣는데, 인자 n은 그 함수에 얼마나 많은 값을 연계하려는지를 나타낸다. 또한 lua_pushcclosure는 스택에서 그 값들을 꺼낸다.

n의 최댓값은 255다.

n이 0일 때 이 함수는 경량 C 함수를 만드는데, 그냥 C 함수에 대한 포인터다. 그 경우에는 절대 메모리 오류를 던지지 않는다.


lua_pushcfunction

[-0, +1, –]

void lua_pushcfunction (lua_State *L, lua_CFunction f);

C 함수를 스택에 집어넣는다. 이 함수는 upvalue 없는 lua_pushcclosure와 동등하다.


lua_pushfstring

[-0, +1, v]

const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

서식을 준 문자열을 스택에 집어넣고 그 문자열에 대한 포인터를 반환한다. ISO C 함수 sprintf와 비슷하지만 두 가지 중요한 차이가 있다. 첫째로, 결과를 위한 공간을 할당해 주지 않아도 된다. 결과는 루아 문자열이며 루아에서 메모리 할당을 (그리고 쓰레기 수집을 통해 해제까지) 대신 해 준다. 둘째로, 변환 지정자에 상당히 제약이 있다. 플래그, 폭, 정밀도가 없다. 변환 지정자로 가능한 것은 '%%' (문자 '%' 삽입), '%s' (영 종료 문자열 삽입, 크기 제약 없음), '%f' (lua_Number 삽입), '%I' (lua_Integer 삽입), '%p' (포인터 삽입), '%d' (int 삽입), '%c' (int를 한 바이트 문자로 삽입), '%U' (long int를 UTF-8 바이트 열로 삽입)이 전부다.

메모리 넘침이나 유효하지 않은 변환 지정자 때문에 이 함수가 오류를 던질 수 있다.


lua_pushglobaltable

[-0, +1, –]

void lua_pushglobaltable (lua_State *L);

전역 환경을 스택에 집어넣는다.


lua_pushinteger

[-0, +1, –]

void lua_pushinteger (lua_State *L, lua_Integer n);

값이 n인 정수를 스택에 집어넣는다.


lua_pushlightuserdata

[-0, +1, –]

void lua_pushlightuserdata (lua_State *L, void *p);

light userdata를 스택에 집어넣는다.

루아에서 userdata는 C의 값을 나타낸다. light userdatavoid* 포인터를 나타낸다. (수와 마찬가지로) 하나의 값이다. 따로 생성하지 않고, 개별 메타테이블이 없으며, (생성된 적이 없으므로) 수집되지 않는다. 한 light userdata는 동일한 C 주소를 가진 "모든" light userdata와 같다.


lua_pushliteral

[-0, +1, m]

const char *lua_pushliteral (lua_State *L, const char *s);

이 매크로는 lua_pushstring과 동등하다. 단, s가 리터럴 문자열일 때만 써야 한다. (이 경우 루아에서 최적화를 할 수 있다.)


lua_pushlstring

[-0, +1, m]

const char *lua_pushlstring (lua_State *L, const char *s, size_t len);

s가 가리키는 크기 len인 문자열을 스택에 집어넣는다. 루아에서 지정한 문자열의 내부 사본을 만들거나 재사용하기 때문에 함수 반환 즉시 s에 있는 메모리를 해제하거나 재사용할 수 있다. 문자열에는 0을 포함해 임의의 이진 데이터가 들어갈 수 있다.

문자열의 내부 사본에 대한 포인터를 반환한다.


lua_pushnil

[-0, +1, –]

void lua_pushnil (lua_State *L);

nil 값을 스택에 집어넣는다.


lua_pushnumber

[-0, +1, –]

void lua_pushnumber (lua_State *L, lua_Number n);

값이 n인 실수를 스택에 집어넣는다.


lua_pushstring

[-0, +1, m]

const char *lua_pushstring (lua_State *L, const char *s);

s가 가리키는 영 종료 문자열을 스택에 집어넣는다. 루아에서 지정한 문자열의 내부 사본을 만들거나 재사용하기 때문에 함수 반환 즉시 s에 있는 메모리를 해제하거나 재사용할 수 있다.

문자열의 내부 사본에 대한 포인터를 반환한다.

sNULL이면 nil을 집어넣고 NULL을 반환한다.


lua_pushthread

[-0, +1, –]

int lua_pushthread (lua_State *L);

L이 나타내는 스레드를 스택에 집어넣는다. 그 스레드가 상태의 주 스레드면 1을 반환한다.


lua_pushvalue

[-0, +1, –]

void lua_pushvalue (lua_State *L, int index);

지정한 인덱스에 있는 항목의 사본을 스택에 집어넣는다.


lua_pushvfstring

[-0, +1, v]

const char *lua_pushvfstring (lua_State *L,
                              const char *fmt,
                              va_list argp);

lua_pushfstring과 동등하되, 가변 개수 인자 대신 va_list를 받는다.


lua_rawequal

[-0, +0, –]

int lua_rawequal (lua_State *L, int index1, int index2);

인덱스 index1index2의 두 값이 단순 비교로 같으면 (즉 __eq 메타메소드 호출 없이 같으면) 1을 반환한다. 그렇지 않으면 0을 반환한다. 인덱스가 하나라도 유효하지 않을 때에도 0을 반환한다.


lua_rawget

[-1, +1, –]

int lua_rawget (lua_State *L, int index);

lua_gettable과 비슷하되, (메타메소드 안 쓰는) raw 접근을 한다.


lua_rawgeti

[-0, +1, –]

int lua_rawgeti (lua_State *L, int index, lua_Integer n);

t[n]을 스택에 집어넣는다. 여기서 t는 지정한 인덱스에 있는 테이블이다. 접근이 raw 방식이다. 즉, __index 메타값을 쓰지 않는다.

집어넣은 값의 타입을 반환한다.


lua_rawgetp

[-0, +1, –]

int lua_rawgetp (lua_State *L, int index, const void *p);

t[k]를 스택에 집어넣는다. 여기서 t는 지정한 인덱스에 있는 테이블이고 k는 포인터 p를 light userdata로 나타낸 것이다. 접근이 raw 방식이다. 즉, __index 메타값을 쓰지 않는다.

집어넣은 값의 타입을 반환한다.


lua_rawlen

[-0, +0, –]

lua_Unsigned lua_rawlen (lua_State *L, int index);

지정한 인덱스에 있는 값의 raw "길이"를 반환한다. 문자열에선 문자열 길이다. 테이블에선 메타메소드 안 쓴 길이 연산자('#') 결과다. userdata에선 그 userdata를 위해 할당한 메모리 블록의 크기다. 다른 값에는 0을 반환한다.


lua_rawset

[-2, +0, m]

void lua_rawset (lua_State *L, int index);

lua_settable과 비슷하되, (메타메소드 안 쓰는) raw 할당을 한다.


lua_rawseti

[-1, +0, m]

void lua_rawseti (lua_State *L, int index, lua_Integer i);

t[i] = v와 동등한 일을 한다. 여기서 t는 지정한 인덱스에 있는 테이블이고 v는 스택 상단에 있는 값이다.

이 함수는 스택에서 값을 꺼낸다. 할당이 raw 방식이다. 즉, __newindex 메타값을 쓰지 않는다.


lua_rawsetp

[-1, +0, m]

void lua_rawsetp (lua_State *L, int index, const void *p);

t[p] = v와 동등한 일을 한다. 여기서 t는 지정한 인덱스에 있는 테이블이고 p는 light userdata로 표현한 것이며 v는 스택 상단에 있는 값이다.

이 함수는 스택에서 값을 꺼낸다. 할당이 raw 방식이다. 즉, __newindex 메타값을 쓰지 않는다.


lua_Reader

typedef const char * (*lua_Reader) (lua_State *L,
                                    void *data,
                                    size_t *size);

lua_load에서 사용하는 읽기 함수다. lua_load에서 청크 조각이 더 필요할 때마다 읽기 함수를 호출하며, data 매개변수를 전달한다. 읽기 함수에서는 새 청크 조각이 있는 메모리 블록에 대한 포인터를 반환하고 size를 블록 크기로 설정해야 한다. 그 블록은 읽기 함수가 다시 호출될 때까지는 존재해야 한다. 읽기 함수에서 청크 끝을 알리려면 NULL을 반환하거나 size를 0으로 설정해야 한다. 읽기 함수는 0보다 큰 어떤 크기의 조각도 반환할 수 있다.


lua_register

[-0, +0, e]

void lua_register (lua_State *L, const char *name, lua_CFunction f);

C 함수 f를 전역 name의 새 값으로 설정한다. 매크로로 정의되어 있다.

     #define lua_register(L,n,f) \
            (lua_pushcfunction(L, f), lua_setglobal(L, n))

lua_remove

[-1, +0, –]

void lua_remove (lua_State *L, int index);

지정한 유효 인덱스에 있는 항목을 제거하고 그 인덱스 위의 항목들을 밀어 내려서 구멍을 채운다. 가상 인덱스로 이 함수를 호출할 수 없다. 가상 인덱스는 실제 스택 위치가 아니기 때문이다.


lua_replace

[-1, +0, –]

void lua_replace (lua_State *L, int index);

상단 항목을 지정한 유효 인덱스로 옮기되 항목을 밀어 올리지 않는다. (그래서 그 지정 인덱스에 있는 값을 교체하게 된다.) 그리고 그 상단 항목을 꺼낸다.


lua_resetthread

[-0, +?, –]

int lua_resetthread (lua_State *L);

스레드를 재설정한다. 호출 스택을 비우고 미처리 자동 닫힘 변수를 모두 닫는다. 닫기 메소드에서 오류가 없었으면 상태 코드 LUA_OK를 반환하고, 아니면 오류 상태를 반환한다. 오류인 경우 스택 상단에 오류 객체가 남는다.


lua_resume

[-?, +?, –]

int lua_resume (lua_State *L, lua_State *from, int nargs,
                          int *nresults);

지정한 스레드 L에서 코루틴을 시작하고 재개한다.

코루틴을 시작하려면 메인 함수와 인자를 스레드의 빈 스택에 집어넣고서 nargs를 인자 개수로 해서 lua_resume을 호출하면 된다. 코루틴이 실행을 중지하거나 완료할 때 이 호출이 반환한다. 반환 시 *nresults가 갱신되며, lua_yield에 준, 또는 몸체 함수에서 반환한 *nresults 개 값이 스택 상단에 들어 있다. 코루틴이 양보한 경우 lua_resumeLUA_YIELD를 반환하고, 코루틴이 오류 없이 실행을 마친 경우 LUA_OK를 반환하고, 오류가 발생한 경우 오류 코드(4.4.1절)를 반환한다. 오류가 발생한 경우 스택 상단에 오류 객체가 있다.

코루틴을 재개하려면 yield에게 받은 *nresults 개 값을 스택에서 제거하고 yield의 결과로 전달할 값들을 밀어넣은 다음 lua_resume을 호출하면 된다.

매개변수 fromL을 재개하고 있는 코루틴을 나타낸다. 그런 코루틴이 없으면 이 매개변수가 NULL일 수 있다.


lua_rotate

[-0, +0, –]

void lua_rotate (lua_State *L, int idx, int n);

유효 인덱스 idx와 스택 상단 사이의 스택 항목들을 회전시킨다. 양수 n에 대해선 상단 방향으로 n 위치만큼, 음수 n에 대해선 하단 방향으로 -n 위치만큼 항목들을 회전시킨다. n의 절대값이 회전시키려는 구간의 길이보다 크면 안 된다. 가상 인덱스로 이 함수를 호출할 수 없다. 가상 인덱스는 실제 스택 위치가 아니기 때문이다.


lua_setallocf

[-0, +0, –]

void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);

지정한 상태의 할당자 함수를 f로 바꾸고 사용자 데이터를 ud로 한다.


lua_setfield

[-1, +0, e]

void lua_setfield (lua_State *L, int index, const char *k);

t[k] = v와 동등한 일을 한다. 여기서 t는 지정한 인덱스에 있는 값이고 v는 스택 상단에 있는 값이다.

이 함수는 스택에서 값을 꺼낸다. 루아 내에서처럼 이 함수가 "newindex" 이벤트에 대한 메타메소드를 유발할 수 있다. (2.4절 참고.)


lua_setglobal

[-1, +0, e]

void lua_setglobal (lua_State *L, const char *name);

스택에서 값을 꺼내서 전역 name의 새 값으로 설정한다.


lua_seti

[-1, +0, e]

void lua_seti (lua_State *L, int index, lua_Integer n);

t[n] = v와 동등한 일을 한다. 여기서 t는 지정한 인덱스에 있는 값이고 v는 스택 상단에 있는 값이다.

이 함수는 스택에서 값을 꺼낸다. 루아 내에서처럼 이 함수가 "newindex" 이벤트에 대한 메타메소드를 유발할 수 있다. (2.4절 참고.)


lua_setiuservalue

[-1, +0, –]

int lua_setiuservalue (lua_State *L, int index, int n);

스택에서 값을 꺼내서 지정한 인덱스에 있는 full userdata에 연계된 n 번째 사용자 값의 새 값으로 설정한다. 그 userdata에 그 값이 없으면 0을 반환한다.


lua_setmetatable

[-1, +0, –]

int lua_setmetatable (lua_State *L, int index);

스택에서 테이블 또는 nil을 꺼내서 그 값을 지정한 인덱스에 있는 값의 새 메타테이블로 설정한다. (nil은 메타테이블을 없애는 것이다.)

(이 함수가 반환하는 int는 역사적 이유 때문에 현재는 항상 1이다.)


lua_settable

[-2, +0, e]

void lua_settable (lua_State *L, int index);

t[k] = v와 동등한 일을 한다. 여기서 t는 지정한 인덱스에 있는 값이고 v는 스택 상단에 있는 값이며 k는 상단 바로 아래의 값이다.

이 함수는 스택에서 키와 값 모두를 꺼낸다. 루아 내에서처럼 이 함수가 "newindex" 이벤트에 대한 메타메소드를 유발할 수 있다. (2.4절 참고.)


lua_settop

[-?, +?, –]

void lua_settop (lua_State *L, int index);

임의 인덱스 또는 0을 받아서 그 인덱스를 스택 상단으로 설정한다. 새로운 상단이 이전보다 높으면 새 항목을 nil로 채운다. index가 0이면 모든 스택 항목을 제거한다.


lua_setwarnf

[-0, +0, –]

void lua_setwarnf (lua_State *L, lua_WarnFunction f, void *ud);

루아에서 경고를 찍는 데 사용할 경고 함수를 설정한다. (lua_WarnFunction 참고.) ud 매개변수는 경고 함수로 전달할 ud 값을 설정한다.


lua_State

typedef struct lua_State lua_State;

스레드를, 그리고 (그 스레드를 통해) 간접적으로 루아 인터프리터의 전체 상태를 가리키는 불투명한 자료 구조. 루아 라이브러리는 완전하게 재진입 가능하다. 즉, 전역 변수가 전혀 없다. 이 자료 구조를 통해 상태에 대한 모든 정보에 접근할 수 있다.

라이브러리의 모든 함수에 첫 번째 인자로 이 구조체에 대한 포인터를 주어야 한다. 단, 무에서부터 루아 상태를 만드는 lua_newstate는 예외다.


lua_status

[-0, +0, –]

int lua_status (lua_State *L);

스레드 L의 상태를 반환한다.

정상 스레드면 상태가 LUA_OK, 스레드가 lua_resume 실행을 오류로 끝마쳤으면 오류 코드, 스레드가 중지되어 있으면 LUA_YIELD다.

상태가 LUA_OK인 스레드에서만 함수들을 호출할 수 있다. 상태가 LUA_OKLUA_YIELD인 스레드를 재개할 수 있다. (각기 새 코루틴을 시작하거나 코루틴을 재개한다.)


lua_stringtonumber

[-0, +1, –]

size_t lua_stringtonumber (lua_State *L, const char *s);

영 종료 문자열 s를 수로 변환하고, 그 수를 스택에 집어넣고, 문자열의 총 크기, 즉 길이 더하기 1을 반환한다. 변환 결과는 루아 어휘 규정에 따라 정수나 실수가 될 수 있다. (3.1절 참고.) 문자열에 전후 공백과 부호가 있을 수 있다. 문자열이 유효한 수가 아니면 0을 반환하며 아무것도 집어넣지 않는다. (따라서 결과를 불리언으로 쓸 수도 있다. 변환이 성공하면 참이다.)


lua_toboolean

[-0, +0, –]

int lua_toboolean (lua_State *L, int index);

지정한 인덱스에 있는 루아 값을 C 불리언 값(0 또는 1)으로 변환한다. 루아의 여느 검사와 마찬가지로 falsenil을 제외한 모든 루아 값에 대해 lua_toboolean이 참을 반환하고 둘 중 하나면 거짓을 반환한다. (진짜 불리언인 값만 받아들이고 싶다면 lua_isboolean으로 값의 타입을 확인하면 된다.)


lua_tocfunction

[-0, +0, –]

lua_CFunction lua_tocfunction (lua_State *L, int index);

지정한 인덱스에 있는 값을 C 함수로 변환한다. 그 값이 C 함수여야 한다. 아니면 NULL을 반환한다.


lua_toclose

[-0, +0, v]

void lua_toclose (lua_State *L, int index);

스택의 지정한 인덱스를 자동 닫힘 "변수"로 표시한다. (3.3.8절 참고.) 루아의 자동 닫힘 변수와 마찬가지로 스택의 그 인덱스에 있는 값이 유효 범위를 벗어날 때 닫히게 된다. C 함수 맥락에서 유효 범위를 벗어난다는 것은 함수가 루아로 반환하거나, 오류가 발생했거나, lua_settop이나 lua_pop을 통해 스택에서 그 인덱스가 제거되는 경우를 뜻한다. 자동 닫힘으로 표시된 인덱스를 lua_settoplua_pop이 아닌 다른 API 함수로 스택에서 제거하지 말아야 한다.

활성인 자동 닫힘 인덱스와 같거나 그보다 작은 인덱스로 이 함수를 호출하지 말아야 한다.

이 함수가 메모리 부족 오류를 던질 수 있다. 그 경우 지정한 인덱스의 값이 이미 표시가 되었으므로 즉시 닫히게 된다.


lua_tointeger

[-0, +0, –]

lua_Integer lua_tointeger (lua_State *L, int index);

isnumNULLlua_tointegerx와 동등하다.


lua_tointegerx

[-0, +0, –]

lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);

지정한 인덱스에 있는 루아 값을 부호 있는 정수 타입 lua_Integer로 변환한다. 루아 값이 정수거나 정수로 변환 가능한 수나 문자열이어야 한다. (3.4.3절 참고.) 아니면 lua_tointegerx가 0을 반환한다.

isnumNULL이 아니면 가리키는 위치에 동작 성공 여부를 나타내는 불리언 값을 할당한다.


lua_tolstring

[-0, +0, m]

const char *lua_tolstring (lua_State *L, int index, size_t *len);

지정한 인덱스에 있는 루아 값을 C 문자열로 변환한다. lenNULL이 아니면 *len에 문자열 길이를 설정한다. 루아 값이 문자열이나 수여야 한다. 아니면 함수가 NULL을 반환한다. 값이 수인 경우 lua_tolstring스택의 실제 값을 문자열로 바꾼다. (테이블 순회 중 키에 lua_tolstring을 적용하면 이런 변경이 lua_next에 혼란을 준다.)

lua_tolstring은 루아 상태 내 문자열에 대한 포인터를 반환한다. 이 문자열에는 (C에서처럼) 항상 마지막 문자 뒤에 0('\0')이 있다. 하지만 내용 중간에도 다른 0이 있을 수 있다.

루아에 쓰레기 수집기가 있기 때문에 lua_tolstring이 반환한 포인터가 해당 루아 값이 스택에서 제거된 후에 유효하리라는 보장이 없다.


lua_tonumber

[-0, +0, –]

lua_Number lua_tonumber (lua_State *L, int index);

isnumNULLlua_tonumberx와 동등하다.


lua_tonumberx

[-0, +0, –]

lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);

지정한 인덱스에 있는 루아 값을 C 타입 lua_Number로 변환한다. (lua_Number 참고.) 루아 값이 수이거나 수로 변환 가능한 문자열이어야 한다. (3.4.3절 참고.) 아니면 lua_tonumberx가 0을 반환한다.

isnumNULL이 아니면 가리키는 위치에 동작 성공 여부를 나타내는 불리언 값을 할당한다.


lua_topointer

[-0, +0, –]

const void *lua_topointer (lua_State *L, int index);

지정한 인덱스에 있는 값을 범용 C 포인터(void*)로 변환한다. 그 값은 userdata, 테이블, 스레드, 문자열, 함수일 수 있다. 아니면 lua_topointerNULL을 반환한다. 다른 객체는 포인터도 서로 다르게 된다. 포인터를 원래 값으로 역변환하는 방법은 없다.

보통은 해싱과 디버그 정보 용도로만 이 함수를 쓴다.


lua_tostring

[-0, +0, m]

const char *lua_tostring (lua_State *L, int index);

lenNULLlua_tolstring과 동등하다.


lua_tothread

[-0, +0, –]

lua_State *lua_tothread (lua_State *L, int index);

지정한 인덱스에 있는 값을 (lua_State*로 나타낸) 루아 스레드로 변환한다. 그 값이 스레드여야 한다. 아니면 함수가 NULL을 반환한다.


lua_touserdata

[-0, +0, –]

void *lua_touserdata (lua_State *L, int index);

지정한 인덱스에 있는 값이 full userdata면 그 메모리 블록 주소를 반환한다. 값이 light userdata면 그 값(포인터)을 반환한다. 그 외 경우에는 NULL을 반환한다.


lua_type

[-0, +0, –]

int lua_type (lua_State *L, int index);

지정한 유효 인덱스에 있는 값의 타입을 반환한다. 유효하지 않지만 허용인 인덱스에 대해선 LUA_TNONE을 반환한다. lua_type이 반환하는 타입은 lua.h에 정의된 상수로 나타낸다. LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, LUA_TLIGHTUSERDATA 중 하나다.


lua_typename

[-0, +0, –]

const char *lua_typename (lua_State *L, int tp);

lua_type의 반환 값 중 하나인 tp 값이 나타내는 타입의 이름을 반환한다.


lua_Unsigned

typedef ... lua_Unsigned;

lua_Integer의 부호 없는 버전.


lua_upvalueindex

[-0, +0, –]

int lua_upvalueindex (int i);

동작 중인 함수의 i 번째 upvalue를 나타내는 가상 인덱스를 반환한다. (4.2절 참고.) i[1,256] 범위 안에 있어야 한다.


lua_version

[-0, +0, –]

lua_Number lua_version (lua_State *L);

이 코어의 버전 번호를 반환한다.


lua_WarnFunction

typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);

루아에서 경고를 찍기 위해 호출하는 경고 함수의 타입이다. 첫 번째 매개변수는 lua_setwarnf로 설정한 불투명 포인터다. 두 번째 매개변수는 경고 메시지다. 세 번째 매개변수는 그 메시지가 다음 호출의 메시지와 이어져야 하는지 여부를 나타내는 불리언이다.

경고에 대한 자세한 내용은 warn 참고.


lua_warning

[-0, +0, –]

void lua_warning (lua_State *L, const char *msg, int tocont);

지정한 메시지로 경고를 찍는다. tocont를 참으로 한 호출의 메시지는 또 다른 호출의 메시지와 이어지게 된다.

경고에 대한 자세한 내용은 warn 참고.


lua_Writer

typedef int (*lua_Writer) (lua_State *L,
                           const void* p,
                           size_t sz,
                           void* ud);

lua_dump에서 사용하는 쓰기 함수의 타입이다. lua_dump에서 청크 조각을 하나씩 만들어 낼 때마다 쓰기 함수를 호출하며, 기록할 버퍼(p)와 그 크기(sz), lua_dump에 준 ud 매개변수를 전달한다.

쓰기 함수는 오류 코드를 반환한다. 0은 오류 없음을 뜻한다. 다른 값은 오류를 뜻하며 lua_dump가 더는 쓰기 함수를 호출하지 않게 한다.


lua_xmove

[-?, +?, –]

void lua_xmove (lua_State *from, lua_State *to, int n);

한 상태의 스레드들 간에 값을 교환한다.

이 함수는 스택 from에서 값을 n개 꺼내서 스택 to에 집어넣는다.


lua_yield

[-?, +?, v]

int lua_yield (lua_State *L, int nresults);

이 함수는 lua_yieldk와 동등하되 속행이 없다. (4.5절 참고.) 그래서 스레드가 실행을 재개할 때, lua_yield 호출 함수를 호출했던 함수에서 실행을 이어 간다. 예상 밖의 상황을 피하려면 꼬리 호출에서만 이 함수를 호출하는 게 좋다.


lua_yieldk

[-?, +?, v]

int lua_yieldk (lua_State *L,
                int nresults,
                lua_KContext ctx,
                lua_KFunction k);

코루틴(스레드)을 양보한다.

C 함수에서 lua_yieldk를 호출하면 동작 중인 코루틴이 실행을 중지하며 그 코루틴을 시작했던 lua_resume 호출이 반환한다. 매개변수 nresultslua_resume에게 결과로 전달할 스택의 값 개수다.

코루틴이 다시 실행을 재개할 때 지정한 속행 함수 k를 루아에서 호출해서 양보를 한 C 함수의 실행을 이어 간다. (4.5절 참고.) 그 속행 함수가 받는 스택은 이전 함수의 스택에서 nresults개 결과가 없어지고 lua_resume이 받은 인자로 교체된 것이다. 또한 lua_yieldk에 준 ctx 값을 속행 함수가 받는다.

일반적으로 이 함수는 반환하지 않는다. 나중에 코루틴이 실행을 재개할 때 속행 함수로 실행이 이어지기 때문이다. 하지만 한 가지 특별한 경우가 있는데, 행 훅이나 카운트 훅(4.7절) 안에서 이 함수를 호출할 때다. 그 경우 속행 없이 (아마도 lua_yield 형태로), 그리고 결과도 없이 lua_yieldk를 호출해야 하며 호출 바로 다음에서 훅이 반환해야 한다. 그러면 루아에서 양보를 하고, 다시 코루틴이 실행을 재개할 때 훅을 유발했던 (루아) 함수의 실행을 정상적으로 이어 가게 된다.

속행 함수 없는 미처리 C 호출(C 호출 경계라고 함)이 있는 스레드에서 호출하거나 재개에 의해 동작 중이 아닌 스레드(보통 메인 스레드)에서 호출하는 경우 이 함수가 오류를 던질 수 있다.

4.7 – 디버그 인터페이스

루아에는 어떤 디버깅 장치도 내장되어 있지 않다. 대신 함수와 을 통해서 특별한 인터페이스를 제공한다. 이 인터페이스를 이용해 인터프리터의 "내부 정보"가 필요한 다양한 디버거나 프로파일러, 기타 도구들을 만들 수 있다.


lua_Debug

typedef struct lua_Debug {
  int event;
  const char *name;           /* (n) */
  const char *namewhat;       /* (n) */
  const char *what;           /* (S) */
  const char *source;         /* (S) */
  size_t srclen;              /* (S) */
  int currentline;            /* (l) */
  int linedefined;            /* (S) */
  int lastlinedefined;        /* (S) */
  unsigned char nups;         /* (u) upvalue 개수 */
  unsigned char nparams;      /* (u) 매개변수 개수 */
  char isvararg;              /* (u) */
  char istailcall;            /* (t) */
  unsigned short ftransfer;   /* (r) 첫 번째 전송 값의 인덱스 */
  unsigned short ntransfer;   /* (r) 전송 값 개수 */
  char short_src[LUA_IDSIZE]; /* (S) */
  /* private part */
  기타 필드
} lua_Debug;

함수나 활성 레코드에 대한 여러 정보를 담는 데 쓰는 구조체. lua_getstack에서 이후 사용을 위해 이 구조체의 비공개 부분만을 채운다. lua_Debug의 다른 필드들에 유용한 정보를 채우려면 lua_getinfo를 호출해야 한다.

lua_Debug의 필드들의 의미는 다음과 같다.


lua_gethook

[-0, +0, –]

lua_Hook lua_gethook (lua_State *L);

현재 훅 함수를 반환한다.


lua_gethookcount

[-0, +0, –]

int lua_gethookcount (lua_State *L);

현재 훅 카운트를 반환한다.


lua_gethookmask

[-0, +0, –]

int lua_gethookmask (lua_State *L);

현재 훅 마스크를 반환한다.


lua_getinfo

[-(0|1), +(0|1|2), m]

int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);

특정 함수 내지 함수 호출에 대한 정보를 얻는다.

함수 호출에 대한 정보를 얻으려면 매개변수 ar이 앞선 lua_getstack 호출로 채웠거나 훅 인자로 받은 (lua_Hook 참고) 유효한 활성 레코드여야 한다.

함수에 대한 정보를 얻으려면 함수를 스택에 집어넣고 what 문자열이 '>' 문자로 시작하게 하면 된다. (이 경우에 lua_getinfo가 스택 상단에서 그 함수를 꺼낸다.) 예를 들어 어느 행에 함수 f를 정의되어 있는지 알기 위해 다음과 같이 코드를 작성할 수 있다.

     lua_Debug ar;
     lua_getglobal(L, "f");  /* 전역 'f' 얻기 */
     lua_getinfo(L, ">S", &ar);
     printf("%d\n", ar.linedefined);

what 문자열의 각 문자가 ar 구조체에서 채울 필드나 스택에 집어넣을 값을 선택한다.

what에 잘못된 옵션이 있으면 함수가 0을 반환한다. 그 경우에도 유효한 옵션들은 제대로 처리한다.


lua_getlocal

[-0, +(0|1), –]

const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);

지정한 활성 레코드 내지 함수의 지역 변수나 임시 값에 대한 정보를 얻는다.

첫 번째 경우에는 매개변수 ar이 앞선 lua_getstack 호출로 채웠거나 훅 인자로 받은 (lua_Hook 참고) 유효한 활성 레코드여야 한다. 인덱스 n으로 어떤 지역 변수를 조사할지 선택한다. 변수 인덱스와 이름에 대한 자세한 내용은 debug.getlocal 참고.

lua_getlocal은 변수의 값을 스택에 집어넣고 그 이름을 반환한다.

두 번째 경우에는 arNULL이어야 하고 조사할 함수가 스택 상단에 있어야 한다. 이 경우 (어느 변수가 활성인지에 대한 정보가 없으므로) 루아 함수의 매개변수들만 보이며 스택에는 아무 값도 집어넣지 않는다.

인덱스가 활성 지역 변수 개수보다 크면 NULL을 반환한다. (그리고 아무것도 집어넣지 않는다.)


lua_getstack

[-0, +0, –]

int lua_getstack (lua_State *L, int level, lua_Debug *ar);

인터프리터 런타임 스택에 대한 정보를 얻는다.

이 함수는 해당 단계에서 실행 중인 함수 활성 레코드의 식별 정보를 lua_Debug의 해당 부분에 채운다. 0번 단계가 현재 돌고 있는 함수고 n+1 번 단계는 n 번 단계를 호출한 함수다. (꼬리 호출은 스택에서 자리를 차지하지 않으므로 제외된다.) 스택 깊이보다 큰 단계 값으로 호출하면 lua_getstack이 0을 반환한다. 아니면 1을 반환한다.


lua_getupvalue

[-0, +(0|1), –]

const char *lua_getupvalue (lua_State *L, int funcindex, int n);

인덱스 funcindex에 있는 클로저의 n 번째 upvalue에 대한 정보를 얻는다. 그 upvalue의 값을 스택에 집어넣고 이름을 반환한다. 인덱스 n이 upvalue 개수보다 크면 NULL을 반환한다. (그리고 아무것도 집어넣지 않는다.)

upvalue에 대한 자세한 내용은 debug.getupvalue를 보라.


lua_Hook

typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);

디버그용 훅 함수 타입.

훅이 불릴 때 ar 인자에 event 필드가 있어서 그 훅을 유발한 이벤트로 설정되어 있다. 상수 LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKTAILCALL, LUA_HOOKLINE, LUA_HOOKCOUNT로 이벤트를 나타낸다. 또한 행 이벤트에서는 currentline 필드도 설정되어 있다. ar의 그 외 필드의 값을 얻으려면 훅에서 lua_getinfo를 호출해야 한다.

호출 이벤트에서는 event가 일반적인 값 LUA_HOOKCALL일 수도 있고 꼬리 호출에 대한 LUA_HOOKTAILCALL일 수도 있다. 꼬리 호출인 경우에는 대응하는 반환 이벤트가 없다.

훅을 실행하는 동안 루아에서는 다른 훅 호출을 꺼 둔다. 그래서 훅에서 루아를 다시 호출해서 함수나 청크를 실행하는 경우 훅 호출 없이 실행이 이뤄진다.

훅 함수에는 속행이 있을 수 없다. 즉, 널이 아닌 klua_yieldk, lua_pcallk, lua_callk를 호출할 수 없다.

훅 함수는 정해진 조건 하에서만 양보를 할 수 있는데, 일단 카운트 이벤트와 행 이벤트에서만 양보할 수 있다. 양보를 하려면 훅 함수에서 nresults를 0으로 해서 (즉 값 없이) lua_yield를 호출하여 실행을 마쳐야 한다.


lua_setcstacklimit

[-0, +0, –]

int (lua_setcstacklimit) (lua_State *L, unsigned int limit);

C 스택의 새 제한치를 설정한다. 이 제한치는 루아에서 중첩 호출이 얼마나 깊어질 수 있는지 통제하는 것인데, 스택 넘침을 피하기 위한 것이다. 성공 시 이전 제한치를 반환하고 오류 시 0을 반환한다. 자세한 내용은 표준 라이브러리의 대응 함수인 debug.setcstacklimit을 보라.


lua_sethook

[-0, +0, –]

void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);

디버그용 훅 함수를 설정한다.

인자 f는 훅 함수다. mask는 어떤 이벤트에 훅이 불릴지 지정하며, 상수 LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, LUA_MASKCOUNT를 비트 OR 해서 구성한다. count 인자는 마스크에 LUA_MASKCOUNT가 들어 있을 때만 의미가 있다. 각 이벤트에 대해 아래 설명처럼 훅이 호출된다.

mask를 0으로 설정하면 훅을 끈다.


lua_setlocal

[-(0|1), +0, –]

const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);

해당 활성 레코드의 지역 변수의 값을 설정한다. 스택 상단의 값을 변수에 할당하고 그 이름을 반환한다. 또한 그 값을 스택에서 꺼낸다.

인덱스가 활성 지역 변수 개수보다 크면 NULL을 반환한다. (그리고 아무것도 꺼내지 않는다.)

매개변수 arnlua_getlocal 함수에서와 같다.


lua_setupvalue

[-(0|1), +0, –]

const char *lua_setupvalue (lua_State *L, int funcindex, int n);

클로저의 upvalue의 값을 설정한다. 스택 상단의 값을 upvalue에 할당하고 그 이름을 반환한다. 또한 그 값을 스택에서 꺼낸다.

인덱스 n이 upvalue 개수보다 크면 NULL을 반환한다. (그리고 아무것도 꺼내지 않는다.)

매개변수 funcindexnlua_getupvalue 함수에서와 같다.


lua_upvalueid

[-0, +0, –]

void *lua_upvalueid (lua_State *L, int funcindex, int n);

인덱스 funcindex에 있는 클로저에서 n 번째 upvalue의 고유 식별자를 반환한다.

이 고유 식별자를 이용하면 upvalue를 여러 클로저에서 공유하는지 여부를 프로그램에서 확인할 수 있다. upvalue를 공유하는 (즉 같은 외부 지역 변수에 접근하는) 루아 클로저들은 각각의 upvalue 인덱스에 대해 동일한 ID를 반환하게 된다.

매개변수 funcindexnlua_getupvalue 함수에서와 같다. 단, n이 upvalue 개수보다 클 수 없다.


lua_upvaluejoin

[-0, +0, –]

void lua_upvaluejoin (lua_State *L, int funcindex1, int n1,
                                    int funcindex2, int n2);

인덱스 funcindex1에 있는 루아 클로저의 n1 번째 upvalue가 인덱스 funcindex2에 있는 루아 클로저의 n2 번째 upvalue를 가리키게 만든다.

5 – 보조 라이브러리

보조 라이브러리에는 C와 루아를 연결해 주는 여러 편의 함수들이 있다. 기본 API가 C와 루아 사이의 모든 상호작용을 위한 기초 함수를 제공한다면 보조 라이브러리는 몇 가지 흔한 작업을 위한 고수준 함수를 제공한다.

보조 라이브러리의 모든 함수와 타입은 헤더 파일 lauxlib.h에 정의되어 있으며 앞에 luaL_이 붙어 있다.

보조 라이브러리의 모든 함수는 기본 API를 바탕으로 만들어진 것이고, 그래서 그 API가 할 수 없는 것을 해 주지는 못한다. 그렇지만 보조 라이브러리 사용은 코드의 무모순성을 강화해 준다.

보조 라이브러리의 여러 함수에서는 내부적으로 스택 슬롯 몇 개를 추가로 쓴다. 보조 라이브러리 함수에서 슬롯을 다섯 개 미만으로 쓸 때는 스택 크기를 확인하지 않는다. 즉, 슬롯이 충분히 있다고 그냥 가정한다.

보조 라이브러리의 여러 함수들은 C 함수 인자를 검사하는 데 쓰인다. 오류 메시지가 인자에 맞춰져 있으므로 (예: "bad argument #1") 다른 스택 값에는 이 함수를 쓰지 말아야 한다.

이름이 luaL_check*인 함수들은 검사가 통과 안 되면 항상 오류를 던진다.

5.1 – 함수와 타입

보조 라이브러리의 모든 함수와 타입을 알파벳 순서로 나열한다.


luaL_addchar

[-?, +?, m]

void luaL_addchar (luaL_Buffer *B, char c);

바이트 c를 버퍼 B에 추가한다. (luaL_Buffer 참고.)


luaL_addgsub

[-0, +0, m]

const void luaL_addgsub (luaL_Buffer *B, const char *s,
                         const char *p, const char *r);

문자열 s에서 문자열 p를 모두 문자열 r로 바꾼 사본을 버퍼 B에 추가한다. (luaL_Buffer 참고.)


luaL_addlstring

[-?, +?, m]

void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);

s가 가리키는 길이 l인 문자열을 버퍼 B에 추가한다. (luaL_Buffer 참고.) 문자열 내에 0이 있을 수 있다.


luaL_addsize

[-?, +?, –]

void luaL_addsize (luaL_Buffer *B, size_t n);

버퍼 영역으로 미리 복사한 (luaL_prepbuffer 참고) 길이 n인 문자열을 버퍼 B에 추가한다.


luaL_addstring

[-?, +?, m]

void luaL_addstring (luaL_Buffer *B, const char *s);

s가 가리키는 영 종료 문자열을 버퍼 B에 추가한다. (luaL_Buffer 참고.)


luaL_addvalue

[-1, +?, m]

void luaL_addvalue (luaL_Buffer *B);

스택 상단의 값을 버퍼 B에 추가한다. (luaL_Buffer 참고.) 그 값을 꺼낸다.

문자열 버퍼 함수들 중 유일하게 스택에 따로 항목(버퍼에 추가할 값)을 두고 호출할 수 있는 (그리고 그래야 하는) 함수다.


luaL_argcheck

[-0, +0, v]

void luaL_argcheck (lua_State *L,
                    int cond,
                    int arg,
                    const char *extramsg);

cond가 참인지 확인한다. 참이 아니면 표준 메시지로 오류를 던진다. (luaL_argerror 참고.)


luaL_argerror

[-0, +0, v]

int luaL_argerror (lua_State *L, int arg, const char *extramsg);

호출한 C 함수의 arg 번째 인자에 대한 문제를 보고하는 오류를 던진다. extramsg를 포함하는 다음 표준 메시지를 사용한다.

     bad argument #arg to '함수명' (extramsg)

이 함수는 절대 반환하지 않는다.


luaL_argexpected

[-0, +0, v]

void luaL_argexpected (lua_State *L,
                       int cond,
                       int arg,
                       const char *tname);

cond가 참인지 확인한다. 참이 아니면 표준 메시지로 arg 번째 인자의 타입에 대한 오류를 던진다. (luaL_typeerror 참고.)


luaL_Buffer

typedef struct luaL_Buffer luaL_Buffer;

문자열 버퍼 타입.

문자열 버퍼를 이용해 C 코드에서 루아 문자열을 조금씩 만들어 갈 수 있다. 사용 패턴은 다음과 같다.

결과 문자열의 최대 크기를 미리 알고 있다면 다음과 같이 버퍼를 사용할 수 있다.

정상 동작 중에 문자열 버퍼에서 쓰는 스택 슬롯 수가 바뀔 수도 있다. 따라서 버퍼 사용 중에는 스택 상단이 어디인지 알고 있다고 가정할 수 없다. 두 버퍼 동작 호출 사이에서 스택을 사용하려면 사용 방식이 평형이어야 가능하다. 즉, 어떤 버퍼 동작을 호출했을 때의 스택이 이전 버퍼 동작 직후와 같은 높이여야 한다. (이 규칙의 유일한 예외가 luaL_addvalue다.) luaL_pushresult를 호출하면 스택이 버퍼를 초기화했던 때의 높이로 돌아가고 거기에 최종 문자열이 더해진다.


luaL_buffaddr

[-0, +0, –]

char *luaL_buffaddr (luaL_Buffer *B);

버퍼 B의 현재 내용물의 주소를 반환한다. (luaL_Buffer 참고.) 버퍼에 뭔가 추가하면 이 주소가 유효하지 않게 될 수 있다는 점에 유의하라.


luaL_buffinit

[-0, +0, –]

void luaL_buffinit (lua_State *L, luaL_Buffer *B);

버퍼 B를 초기화한다. (luaL_Buffer 참고.) 이 함수는 어떤 공간도 할당해 두지 않는다. 버퍼가 변수로 선언되어 있어야 한다.


luaL_bufflen

[-0, +0, –]

size_t luaL_bufflen (luaL_Buffer *B);

버퍼 B의 현재 내용물의 길이를 반환한다. (luaL_Buffer 참고.)


luaL_buffinitsize

[-?, +?, m]

char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz);

luaL_buffinit, luaL_prepbuffsize 연속 호출과 동등하다.


luaL_buffsub

[-0, +0, –]

void luaL_buffsub (luaL_Buffer *B, int n);

버퍼 B에서 n 바이트를 제거한다. (luaL_Buffer 참고.) 버퍼에 적어도 그 만큼의 바이트가 있어야 한다.


luaL_callmeta

[-0, +(0|1), e]

int luaL_callmeta (lua_State *L, int obj, const char *e);

메타메소드를 호출한다.

인덱스 obj에 있는 객체에 메타메소드가 있고 그 메타메소드에 필드 e가 있으면 객체를 유일한 인자로 해서 그 필드를 호출한다. 이 경우 함수가 참을 반환하며 호출 반환 값을 스택 상단에 집어넣는다. 메타테이블이 없거나 메타메소드가 없으면 함수가 거짓을 반환하며 스택에 아무 값도 집어넣지 않는다.


luaL_checkany

[-0, +0, v]

void luaL_checkany (lua_State *L, int arg);

arg 위치에 어떤 타입이든 (nil 포함) 함수 인자가 있는지 확인한다.


luaL_checkinteger

[-0, +0, v]

lua_Integer luaL_checkinteger (lua_State *L, int arg);

arg 번째 함수 인자가 정수인지 (또는 정수로 변환할 수 있는지) 확인하고 그 정수를 반환한다.


luaL_checklstring

[-0, +0, v]

const char *luaL_checklstring (lua_State *L, int arg, size_t *l);

arg 번째 함수 인자가 문자열인지 확인하고 그 문자열을 반환한다. lNULL이 아니면 가리키는 공간에 문자열 길이를 채운다.

이 함수는 lua_tolstring을 써서 결과를 얻는다. 따라서 그 함수의 모든 변환 방식과 주의 사항이 여기에도 적용된다.


luaL_checknumber

[-0, +0, v]

lua_Number luaL_checknumber (lua_State *L, int arg);

arg 번째 함수 인자가 수인지 확인하고 그 수를 lua_Number로 변환해서 반환한다.


luaL_checkoption

[-0, +0, v]

int luaL_checkoption (lua_State *L,
                      int arg,
                      const char *def,
                      const char *const lst[]);

arg 번째 함수 인자가 문자열인지 확인하고 (NULL로 끝나는) lst 배열에서 그 문자열을 탐색한다. 배열에서 문자열을 발견한 인덱스를 반환한다. 인자가 문자열이 아니거나 그 문자열을 찾을 수 없으면 오류를 던진다.

defNULL이 아니면 인자 arg가 없거나 그 인자가 nil일 때 기본값으로 def를 쓴다.

문자열을 C 열거형으로 매핑하는 데 유용한 함수다. (선택지를 나타내는 데 수가 아니라 문자열을 쓰는 게 루아 라이브러리들의 일반적 관행이다.)


luaL_checkstack

[-0, +0, v]

void luaL_checkstack (lua_State *L, int sz, const char *msg);

스택을 top + sz개 항목 크기로 키운다. 스택이 그 크기로 커질 수 없으면 오류를 던진다. msg는 오류 메시지에 들어갈 추가 텍스트다. (NULL이면 추가 텍스트 없음.)


luaL_checkstring

[-0, +0, v]

const char *luaL_checkstring (lua_State *L, int arg);

arg 번째 함수 인자가 문자열인지 확인하고 그 문자열을 반환한다.

이 함수는 lua_tolstring을 써서 결과를 얻는다. 따라서 그 함수의 모든 변환 방식과 주의 사항이 여기에도 적용된다.


luaL_checktype

[-0, +0, v]

void luaL_checktype (lua_State *L, int arg, int t);

arg 번째 함수 인자가 타입 t인지 확인한다. t의 타입 표현 방식에 대해선 lua_type을 보라.


luaL_checkudata

[-0, +0, v]

void *luaL_checkudata (lua_State *L, int arg, const char *tname);

arg 번째 함수 인자가 타입이 tname인 (luaL_newmetatable 참고) userdata인지 확인하고 그 userdata의 메모리 블록 주소를 (lua_touserdata 참고) 반환한다.


luaL_checkversion

[-0, +0, v]

void luaL_checkversion (lua_State *L);

호출을 하고 있는 코드와 호출되는 루아 라이브러리가 같은 루아 버전을 쓰고 있으며 같은 수 타입을 쓰는지 확인한다.


luaL_dofile

[-0, +?, m]

int luaL_dofile (lua_State *L, const char *filename);

지정한 파일을 적재해서 실행한다. 다음 매크로로 정의되어 있다.

     (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))

아무 오류도 없으면 LUA_OK를 반환하고 오류 발생 시 오류 코드를 반환한다. (4.4.1절 참고.)


luaL_dostring

[-0, +?, –]

int luaL_dostring (lua_State *L, const char *str);

지정한 문자열을 적재해서 실행한다. 다음 매크로로 정의되어 있다.

     (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))

아무 오류도 없으면 LUA_OK를 반환하고 오류 발생 시 오류 코드를 반환한다. (4.4.1절 참고.)


luaL_error

[-0, +0, v]

int luaL_error (lua_State *L, const char *fmt, ...);

오류를 던진다. fmt로 오류 메시지 형식을 받고 추가 인자를 받을 수 있으며, lua_pushfstring과 같은 규칙을 따른다. 또한 오류가 발생한 파일 이름과 행 번호에 대한 정보가 있으면 메시지 앞쪽에 추가한다.

이 함수는 절대 반환하지 않는다. 하지만 C 함수에서 관용구처럼 return luaL_error(args)라고 쓴다.


luaL_execresult

[-0, +3, m]

int luaL_execresult (lua_State *L, int stat);

표준 라이브러리의 프로세스 관련 함수들(os.execute, io.close)을 위한 반환 값을 만들어 낸다.


luaL_fileresult

[-0, +(1|3), m]

int luaL_fileresult (lua_State *L, int stat, const char *fname);

표준 라이브러리의 파일 관련 함수들(io.open, os.rename, file:seek 등)을 위한 반환 값을 만들어 낸다.


luaL_getmetafield

[-0, +(0|1), m]

int luaL_getmetafield (lua_State *L, int obj, const char *e);

인덱스 obj에 있는 객체의 메타테이블의 필드 e를 스택에 집어넣고 집어넣은 값의 타입을 반환한다. 그 객체에 메타테이블이 없거나 메타테이블에 그 필드가 없으면 아무 것도 집어넣지 않고 LUA_TNIL을 반환한다.


luaL_getmetatable

[-0, +1, m]

int luaL_getmetatable (lua_State *L, const char *tname);

레지스트리에서 이름 tname에 연계되어 있는 (luaL_newmetatable 참고) 메타테이블을 스택에 집어넣는다. 그 이름에 연계된 메타테이블이 없으면 nil을 집어넣는다. 집어넣은 값의 타입을 반환한다.


luaL_getsubtable

[-0, +1, e]

int luaL_getsubtable (lua_State *L, int idx, const char *fname);

인덱스 idx에 있는 값 t에 대해 t[fname]이 테이블이도록 하고서 그 테이블을 스택에 집어넣는다. 테이블이 있던 경우에는 참을 반환하고 새 테이블을 만든 경우에는 거짓을 반환한다.


luaL_gsub

[-0, +1, m]

const char *luaL_gsub (lua_State *L,
                       const char *s,
                       const char *p,
                       const char *r);

문자열 s에서 문자열 p를 모두 문자열 r로 바꾼 사본을 만든다. 결과 문자열을 스택에 집어넣고 그 문자열을 반환한다.


luaL_len

[-0, +0, e]

lua_Integer luaL_len (lua_State *L, int index);

지정한 인덱스에 있는 값의 "길이"를 수로 반환한다. 루아의 '#' 연산자(3.4.7절)와 동등하다. 연산 결과가 정수가 아니면 오류를 던진다. (메타메소드를 통해서만 그런 경우가 발생할 수 있다.)


luaL_loadbuffer

[-0, +1, –]

int luaL_loadbuffer (lua_State *L,
                     const char *buff,
                     size_t sz,
                     const char *name);

modeNULLluaL_loadbufferx와 동등하다.


luaL_loadbufferx

[-0, +1, –]

int luaL_loadbufferx (lua_State *L,
                      const char *buff,
                      size_t sz,
                      const char *name,
                      const char *mode);

버퍼의 루아 청크를 적재한다. lua_load를 사용해 buff가 가리키는 sz 크기 버퍼에 있는 청크를 적재한다.

이 함수는 lua_load와 같은 결과들을 반환한다. name은 청크 이름이며 디버그 정보와 오류 메시지에 쓰인다. 문자열 modelua_load 함수에서처럼 동작한다.


luaL_loadfile

[-0, +1, m]

int luaL_loadfile (lua_State *L, const char *filename);

modeNULLluaL_loadfilex와 동등하다.


luaL_loadfilex

[-0, +1, m]

int luaL_loadfilex (lua_State *L, const char *filename,
                                            const char *mode);

파일에서 루아 청크를 적재한다. lua_load를 사용해 이름이 filename인 파일에 있는 청크를 적재한다. filenameNULL이면 표준 입력을 읽어서 적재한다. 파일 첫 행이 #로 시작하면 그 행을 무시한다.

문자열 modelua_load 함수에서처럼 동작한다.

이 함수는 lua_load와 같은 결과들을 반환하거나 파일 관련 오류 시 LUA_ERRFILE을 반환한다.

lua_load처럼 이 함수는 청크 적재만 하고 실행은 하지 않는다.


luaL_loadstring

[-0, +1, –]

int luaL_loadstring (lua_State *L, const char *s);

문자열에서 루아 청크를 적재한다. lua_load를 사용해 영 종료 문자열 s에 있는 청크를 적재한다.

이 함수는 lua_load와 같은 결과들을 반환한다.

또한 lua_load처럼 이 함수는 청크 적재만 하고 실행은 하지 않는다.


luaL_newlib

[-0, +1, m]

void luaL_newlib (lua_State *L, const luaL_Reg l[]);

새 테이블을 만들어서 목록 l의 함수들을 거기 등록한다.

다음 매크로로 구현되어 있다.

     (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))

배열 l이 배열 포인터가 아니라 실제 배열이어야 한다.


luaL_newlibtable

[-0, +1, m]

void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);

배열 l의 전체 항목을 저장하기에 최적인 크기로 새 테이블을 만든다. (실제로 저장하지는 않는다.) luaL_setfuncs와 함께 쓰기 위한 것이다. (luaL_newlib 참고.)

매크로로 구현되어 있다. 배열 l이 배열 포인터가 아니라 실제 배열이어야 한다.


luaL_newmetatable

[-0, +1, m]

int luaL_newmetatable (lua_State *L, const char *tname);

레지스트리에 키 tname이 이미 있으면 0을 반환한다. 그렇지 않으면 userdata의 메타테이블로 쓸 새 테이블을 만들고, 그 테이블에 __name = tname 쌍을 추가하고, 레지스트리에 [tname] = 새 테이블 쌍을 추가하고, 1을 반환한다.

두 경우 모두에서 레지스트리에서 tname에 연계되어 있는 최종 값을 스택에 집어넣는다.


luaL_newstate

[-0, +0, –]

lua_State *luaL_newstate (void);

새 루아 상태를 만든다. 표준 C 할당 함수 기반 할당자로 lua_newstate를 호출하고서, 치명적 오류 시 표준 오류 출력에 오류 메시지를 찍는 경고 함수와 패닉 함수(4.4절)를 설정한다.

새 상태를 반환한다. 메모리 할당 오류 발생 시 NULL을 반환한다.


luaL_openlibs

[-0, +0, e]

void luaL_openlibs (lua_State *L);

지정한 상태 안에서 표준 루아 라이브러리 모두를 연다.


luaL_opt

[-0, +0, –]

T luaL_opt (L, func, arg, dflt);

이 매크로는 다음과 같이 정의되어 있다.

     (lua_isnoneornil(L,(arg)) ? (dflt) : func(L,(arg)))

말로 하자면, arg 번째 인자가 nil이거나 없으면 기본값 dflt가 매크로 결과가 된다. 아니면 상태 L과 인자 인덱스 arg를 인자로 해서 func를 호출한 결과를 내놓는다. 식 dflt를 필요시에만 평가한다는 점에 유의하라.


luaL_optinteger

[-0, +0, v]

lua_Integer luaL_optinteger (lua_State *L,
                             int arg,
                             lua_Integer d);

arg 번째 함수 인자가 정수면 (또는 정수로 변환 가능하면) 그 정수를 반환한다. 그 인자가 없거나 nil이면 d를 반환한다. 그 외 경우에는 오류를 던진다.


luaL_optlstring

[-0, +0, v]

const char *luaL_optlstring (lua_State *L,
                             int arg,
                             const char *d,
                             size_t *l);

arg 번째 함수 인자가 문자열이면 그 문자열을 반환한다. 그 인자가 없거나 nil이면 d를 반환한다. 그 외 경우에는 오류를 던진다.

lNULL이 아니면 가리키는 위치에 결과의 길이를 채운다. 결과가 NULL이면 (d를 반환하는데 d == NULL일 때만 가능) 길이가 0이라고 본다.

이 함수는 lua_tolstring을 써서 결과를 얻는다. 따라서 그 함수의 모든 변환 방식과 주의 사항이 여기에도 적용된다.


luaL_optnumber

[-0, +0, v]

lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number d);

arg 번째 함수 인자가 수이면 그 수를 lua_Number로 반환한다. 그 인자가 없거나 nil이면 d를 반환한다. 그 외 경우에는 오류를 던진다.


luaL_optstring

[-0, +0, v]

const char *luaL_optstring (lua_State *L,
                            int arg,
                            const char *d);

arg 번째 함수 인자가 문자열이면 그 문자열을 반환한다. 그 인자가 없거나 nil이면 d를 반환한다. 그 외 경우에는 오류를 던진다.


luaL_prepbuffer

[-?, +?, m]

char *luaL_prepbuffer (luaL_Buffer *B);

미리 정의된 크기 LUAL_BUFFERSIZE를 쓰는 luaL_prepbuffsize와 동등하다.


luaL_prepbuffsize

[-?, +?, m]

char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz);

크기가 sz인 공간의 주소를 반환한다. 그리로 문자열을 복사해서 버퍼 B에 덧붙일 수 있다. (luaL_Buffer 참고.) 그 공간에 문자열을 복사한 후에 문자열 크기로 luaL_addsize를 호출해야 실제로 버퍼에 추가된다.


luaL_pushfail

[-0, +1, –]

void luaL_pushfail (lua_State *L);

fail 값을 스택에 집어넣는다. (6장 참고.)


luaL_pushresult

[-?, +1, m]

void luaL_pushresult (luaL_Buffer *B);

버퍼 B 사용을 마치고 최종 문자열을 스택 상단에 둔다.


luaL_pushresultsize

[-?, +1, m]

void luaL_pushresultsize (luaL_Buffer *B, size_t sz);

luaL_addsize, luaL_pushresult 연속 호출과 동등하다.


luaL_ref

[-1, +0, m]

int luaL_ref (lua_State *L, int t);

스택 상단에 있는 객체에 대한 참조를 인덱스 t에 있는 테이블에 만들고 그 참조를 반환한다. (그리고 그 객체를 꺼낸다.)

참조는 유일한 정수 키다. 테이블 t에 직접 정수 키를 추가하지 않는 한 luaL_ref는 반환하는 키의 유일성을 보장한다. lua_rawgeti(L, t, r) 호출로 참조 r이 가리키는 객체를 가져올 수 있다. luaL_unref 함수로 참조를 해제한다.

스택 상단의 객체가 nil이면 luaL_ref는 상수 LUA_REFNIL을 반환한다. 상수 LUA_NOREFluaL_ref가 반환하는 어떤 참조와도 다르다고 보장된다.


luaL_Reg

typedef struct luaL_Reg {
  const char *name;
  lua_CFunction func;
} luaL_Reg;

luaL_setfuncs로 등록할 함수 배열을 위한 타입. name은 함수 이름이고 func는 함수 포인터다. luaL_Reg의 배열은 namefunc가 모두 NULL인 경계 항목으로 끝나야 한다.


luaL_requiref

[-0, +1, e]

void luaL_requiref (lua_State *L, const char *modname,
                    lua_CFunction openf, int glb);

package.loaded[modname]이 참이 아니면 문자열 modname을 인자로 해서 openf 함수를 호출한다. 그리고 그 함수가 require를 통해 호출된 것처럼 호출 결과를 package.loaded[modname]에 설정한다.

glb가 참이면 전역 modname에도 모듈을 저장한다.

모듈의 사본을 스택에 둔다.


luaL_setfuncs

[-nup, +0, m]

void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);

배열 l의 모든 함수들을 (luaL_Reg 참고) 스택 상단에 있는 (위에 upvalue가 있을 수도 있음. 아래 내용 참고) 테이블에 등록한다.

nup가 0이 아니면 스택에 라이브러리 테이블 위에 미리 들어가 있는 nup 개 값의 사본으로 초기화한 nup 개 upvalue로 모든 함수들을 생성한다. 등록 후 스택에서 그 값들을 꺼낸다.


luaL_setmetatable

[-0, +0, –]

void luaL_setmetatable (lua_State *L, const char *tname);

스택 상단에 있는 객체의 메타테이블을 레지스트리에서 이름 tname에 연계된 메타테이블로 설정한다. (luaL_newmetatable 참고.)


luaL_Stream

typedef struct luaL_Stream {
  FILE *f;
  lua_CFunction closef;
} luaL_Stream;

표준 I/O 라이브러리에서 쓰는 파일 핸들의 표준 표현이다.

파일 핸들은 LUA_FILEHANDLE이라는 메타테이블을 가진 full userdata로 구현되어 있다. (LUA_FILEHANDLE은 실제 메타테이블 이름을 나타내는 매크로다.) I/O 라이브러리에서 그 메타테이블을 만든다. (luaL_newmetatable 참고.)

그 userdata는 시작 부분이 luaL_Stream 구조체여야 한다. 그 초반 구조 뒤에 다른 데이터를 담을 수 있다. 필드 f는 대응하는 C 스트림에 대한 포인터다. (또는 생성 미완료 핸들을 나타내는 NULL일 수 있다.) 필드 closef는 핸들이 닫히거나 수집될 때 호출되어 스트림을 닫아 줄 루아 함수를 가리킨다. 이 함수는 파일 핸들을 유일한 인자로 받으며 성공 시 참 값을, 또는 오류 시 거짓 값과 오류 메시지를 반환해야 한다. 루아에서 이 필드를 호출한 다음 필드 값을 NULL로 바꿔서 핸들이 닫혔음을 표시한다.


luaL_testudata

[-0, +0, m]

void *luaL_testudata (lua_State *L, int arg, const char *tname);

이 함수는 luaL_checkudata처럼 동작하되, 검사 실패 시 오류를 던지는 대신 NULL을 반환한다.


luaL_tolstring

[-0, +1, e]

const char *luaL_tolstring (lua_State *L, int idx, size_t *len);

지정한 인덱스에 있는 어떤 루아 값이든 적당한 형식의 C 문자열로 변환한다. 결과 문자열을 스택에 집어넣고 반환도 한다. 또한 lenNULL이 아니면 *len에 문자열 길이를 설정한다.

그 값에 메타테이블이 있고 __tostring 필드가 있으면 luaL_tolstring에서 값을 인자로 해서 해당 메타메소드를 호출하여 호출 결과를 자기 결과로 쓴다.


luaL_traceback

[-0, +1, m]

void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
                     int level);

스택 L1의 트레이스백을 만들어서 집어넣는다. msgNULL이 아니면 트레이스백 앞쪽에 덧붙인다. level 매개변수는 어느 단계에서 트레이스백을 시작할지를 나타낸다.


luaL_typeerror

[-0, +0, v]

const char *luaL_typeerror (lua_State *L,
                                      int arg,
                                      const char *tname);

호출한 C 함수의 arg 번째 인자에 대한 타입 오류를 표준 메시지를 써서 던진다. tname은 기대 타입의 "이름"이다. 이 함수는 절대 반환하지 않는다.


luaL_typename

[-0, +0, –]

const char *luaL_typename (lua_State *L, int index);

지정한 인덱스에 있는 값의 타입 이름을 반환한다.


luaL_unref

[-0, +0, –]

void luaL_unref (lua_State *L, int t, int ref);

인덱스 t에 있는 테이블에서 참조 ref를 해제한다. (luaL_ref 참고.) 테이블에서 항목을 제거하여 피참조 객체가 수집될 수 있게 한다. 참조 ref도 해제하여 다시 쓸 수 있게 한다.

refLUA_NOREFLUA_REFNIL이면 luaL_unref가 아무것도 하지 않는다.


luaL_where

[-0, +1, m]

void luaL_where (lua_State *L, int lvl);

호출 스택 lvl 번 단계에서의 현재 제어 위치를 나타내는 문자열을 스택에 집어넣는다. 이 문자열은 보통 다음 형식이다.

     청크이름:현재행:

0번 단계가 동작 중인 함수이고 1번 단계가 그 동작 중 함수를 호출한 함수인 식이다.

오류 메시지 시작 부분을 만드는 데 이 함수가 쓰인다.

6 – 표준 라이브러리

표준 루아 라이브러리들은 C API를 통해 C로 구현된 유용한 함수들을 제공한다. 그 중 일부는 언어에 필수적인 서비스를 제공한다. (예: type, getmetatable.) 다른 일부는 외부 서비스에 접근할 수 있게 해 준다. (예: I/O.) 또 다른 일부는 루아 자체로도 구현할 수 있지만 C로 구현할 만한 다른 이유가 있었던 것들이다. (예: table.sort.)

모든 라이브러리들은 공식 C API를 통해 구현되어 있으며 별도의 C 모듈로 제공된다. 따로 언급이 없으면 이 라이브러리 함수들에선 인자 개수를 기대 매개변수 개수에 맞게 조정하지 않는다. 예를 들면 foo(arg)라고 나와 있는 함수를 인자 없이 호출하지 말아야 한다.

fail 표시는 어떤 실패를 나타내는 거짓 값을 뜻한다. (현재는 failnil과 같지만 이후 버전에서 바뀔 수도 있다. 이 함수들의 성공 여부를 검사할 때 항상 (status == nil) 방식이 아니라 (not status) 방식을 쓰기를 권장한다.)

현재 루아에는 다음 표준 라이브러리가 있다.

기본 라이브러리와 패키지 라이브러리를 제외한 다른 라이브러리들은 모든 함수를 전역 테이블의 필드나 객체의 메소드로 제공한다.

C 호스트 프로그램에서 이 라이브러리들에 접근하려면 luaL_openlibs를 호출하면 된다. 그러면 모든 표준 라이브러리들을 연다. 또는 개별적으로 열기 위해 호스트 프로그램에서 luaL_requiref를 사용해 luaopen_base (기본 라이브러리), luaopen_package (패키지 라이브러리), luaopen_coroutine (코루틴 라이브러리), luaopen_string (문자열 라이브러리), luaopen_utf8 (UTF-8 라이브러리), luaopen_table (테이블 라이브러리), luaopen_math (수학 라이브러리), luaopen_io (I/O 라이브러리), luaopen_os (운영 체제 라이브러리), luaopen_debug (디버그 라이브러리)를 부를 수 있다. lualib.h에 이 함수들이 선언되어 있다.

6.1 – 기본 함수

기본 라이브러리는 루아 핵심 함수들을 제공한다. 응용에 이 라이브러리를 포함시키지 않는다면 그 요소들 중 일부를 대신하는 구현을 제공해야 하는지 여부를 조심스럽게 점검해 봐야 할 것이다.


assert (v [, message])

인자 v의 값이 거짓(즉 nil이나 false)이면 오류를 던진다. 그렇지 않으면 인자 전체를 반환한다. 오류 경우에는 message가 오류 객체가 된다. 그 인자가 없으면 "assertion failed!"를 쓴다.


collectgarbage ([opt [, arg]])

이 함수는 쓰레기 수집기에 대한 포괄적 인터페이스다. 첫 번째 인자 opt에 따라서 다양한 기능을 수행한다.

쓰레기 수집 동작과 일부 옵션에 대한 자세한 설명은 2.5절을 보라.


dofile ([filename])

지정한 파일을 열어서 그 내용을 루아 청크로서 실행한다. 인자 없이 호출 시 dofile은 표준 입력(stdin)의 내용을 실행한다. 청크가 반환한 모든 값을 반환한다. 오류 발생 시 dofile은 그 오류를 호출자에게 전파한다. (즉 dofile은 보호 모드로 돌지 않는다.)


error (message [, level])

@{message}를 오류 객체로 해서 오류를 던진다. (2.3절 참고.) 이 함수는 절대 반환하지 않는다.

메시지가 문자열이면 일반적으로 error에서 메시지 시작 부분에 오류 위치에 대한 약간의 정보를 추가한다. level 인자는 그 오류 위치를 어떻게 얻을 수 있는지를 나타낸다. 단계가 1(기본값)이면 error 함수를 호출한 지점이 오류 위치다. 그리고 단계 2는 error를 호출한 함수를 호출했던 위치를 나타내는 식이다. 단계를 0으로 주면 메시지에 오류 위치 정보를 추가하지 않는다.


_G

전역 환경(2.2절)을 가지고 있는 전역 변수다. (함수가 아니다.) 루아 자체에서는 이 변수를 쓰지 않는다. 값을 바꿔도 어느 환경에도 영향을 주지 않으며 그 반대도 마찬가지다.


getmetatable (object)

object에 메타테이블이 없으면 nil을 반환한다. 그렇지 않고 객체의 메타테이블에 __metatable 필드가 있으면 연계된 값을 반환한다. 그 외 경우에는 지정한 객체의 메타테이블을 반환한다.


ipairs (t)

세 값(반복자 함수, 테이블 t, 0)을 반환한다. 그래서 다음과 같이 쓰면

     for i,v in ipairs(t) do body end

(1,t[1]), (2,t[2]), ... 식으로 해서 없는 인덱스를 만날 때까지 모든 키–값 쌍에 대해 반복하게 된다.


load (chunk [, chunkname [, mode [, env]]])

청크를 적재한다.

chunk가 문자열이면 그 문자열이 청크다. chunk가 함수면 load에서 그 함수를 반복 호출해서 청크 조각들을 얻는다. 각 chunk 호출에서는 이전 결과들에 이어지는 문자열을 반환해야 한다. 빈 문자열 내지 nil을 반환하거나 아무 값도 반환하지 않는 것으로 청크 끝을 나타낸다.

구문 오류가 없으면 load는 컴파일한 청크를 함수 형태로 반환한다. 그렇지 않으면 fail과 오류 메시지를 반환한다.

메인 청크를 적재할 때는 결과 함수에 항상 정확히 한 개의 upvalue, 즉 _ENV 변수가 있게 된다. (2.2절 참고.) 하지만 함수로부터 만든 바이너리 청크를 적재할 때는 (string.dump 참고) 결과 함수에 임의 개수의 upvalue가 있을 수 있으며, 첫 번째 upvalue가 _ENV 변수가 된다는 보장이 없다. (메인 함수가 아닌 경우에는 _ENV upvalue가 없을 수도 있다.)

어떻든지 간에 결과 함수에 upvalue가 있는 경우에 env 매개변수가 있으면 그 값을, 아니면 전역 환경의 값을 첫 번째 upvalue에 설정한다. 다른 upvalue들은 nil로 초기화한다. 모든 upvalue는 새것이다. 즉 다른 함수와 공유하지 않는다.

chunkname은 오류 메시지와 디버그 정보(4.7절)에서 청크 이름으로 쓴다. 없을 때는 chunk가 문자열이면 chunk를 쓰고 아니면 "=(load)"를 쓴다.

문자열 mode는 청크가 텍스트나 바이너리(즉 사전 컴파일한 청크)일 수 있는지를 제어한다. 문자열 "b"(바이너리 청크만), "t"(텍스트 청크만), "bt"(바이너리와 텍스트 모두)일 수 있다. 기본은 "bt"다.

루아에서는 바이너리 청크의 무모순성을 검사하지 않는다. 악의적으로 조작된 바이너리 청크 때문에 인터프리터가 죽을 수도 있다.


loadfile ([filename [, mode [, env]]])

load와 비슷하되, 파일 filename으로부터, 또는 파일 이름을 안 주면 표준 입력으로부터 청크를 얻는다.


next (table [, index])

프로그램에서 테이블의 모든 필드를 순회할 수 있게 해 준다. 첫 번째 인자는 테이블이고 두 번째 인자는 그 테이블 내의 인덱스다. next를 호출하면 테이블의 다음 인덱스와 그 연계 값을 반환한다. 두 번째 인자를 nil로 해서 호출하면 시작 인덱스와 그 연계 값을 반환한다. 마지막 인덱스로 호출하거나 빈 테이블에서 nil로 호출하면 nil을 반환한다. 두 번째 인자가 없으면 nil로 해석한다. 그래서 next(t)라고 해서 테이블이 비어 있는지 확인할 수 있다.

인덱스가 나오는 순서가 명세되어 있지 않으며 숫자 인덱스도 마찬가지다. (번호순으로 테이블을 순회하려면 수열형 for를 쓰면 된다.)

순회 도중에 테이블에 존재하지 않던 필드에 값을 할당하는 경우 next의 동작 방식이 규정되어 있지 않다. 하지만 기존 필드를 변경하는 건 괜찮다. 특히 기존 필드들을 nil로 설정할 수도 있다.


pairs (t)

t에 메타메소드 __pairs가 있으면 t를 인자로 해서 호출하고 그 호출의 처음 세 개 결과를 반환한다.

그렇지 않으면 next 함수, 테이블 t, nil, 이렇게 세 값을 반환한다. 그래서 다음과 같이 쓰면

     for k,v in pairs(t) do body end

테이블 t의 모든 키–값 쌍에 대해 반복하게 된다.

테이블 순회 중 변경에 대한 주의 사항은 함수 next를 보라.


pcall (f [, arg1, ···])

주어진 인자들을 가지고 함수 f보호 모드로 호출한다. f 안에서 오류가 발생하더라도 전파되지 않는다는 뜻이다. 대신 pcall이 그 오류를 잡아서 상태 코드를 반환한다. 첫 번째 결과는 상태 코드(불리언)인데 호출이 오류 없이 성공하면 참이다. 그 경우 호출의 모든 결과를 pcall이 첫 번째 결과 뒤에 붙여서 반환한다. 오류 발생 시에는 pcallfalse와 오류 객체를 반환한다. pcall에 잡힌 오류는 메시지 핸들러를 호출하지 않는 점에 유의하라.


print (···)

임의 개수의 인자를 받아서 tostring과 같은 규칙을 따라 각 인자를 문자열로 변환해서 그 값들을 stdout으로 찍는다.

print 함수는 서식 출력을 위한 것이 아니다. 디버깅 등을 위해 간단히 값을 표시하는 방법일 뿐이다. 출력을 완전히 제어하려면 string.formatio.write를 쓰면 된다.


rawequal (v1, v2)

__eq 메타메소드 호출 없이 v1v2와 같은지 확인한다. 불리언을 반환한다.


rawget (table, index)

__index 메타메소드를 쓰지 않고 table[index]의 진짜 값을 얻는다. table은 테이블이어야 하며 index는 아무 값이나 가능하다.


rawlen (v)

__len 메타메소드 호출 없이 객체 v의 길이를 반환한다. v는 테이블이나 문자열이어야 한다. 정수를 반환한다.


rawset (table, index, value)

__newindex 메타메소드를 쓰지 않고 table[index]의 진짜 값을 value로 설정한다. table은 테이블이어야 한다. indexnil과 NaN를 제외한 아무 값이나 가능하고 value는 아무 루아 값이나 가능하다.

이 함수는 table을 반환한다.


select (index, ···)

index가 수이면 index 번째 인자 뒤의 모든 인자들을 반환한다. 음수는 끝부터 거꾸로 인덱스를 센다. (-1이 마지막 인자다.) 수가 아니면 index가 문자열 "#"이어야 하며 받은 나머지 인자들의 총개수를 반환한다.


setmetatable (table, metatable)

지정한 테이블의 메타테이블을 설정한다. metatablenil이면 지정한 테이블의 메타테이블을 제거한다. 원래 있던 메타테이블에 __metatable 필드가 있으면 오류를 던진다.

이 함수는 table을 반환한다.

루아 코드에서 다른 타입들의 메타테이블을 바꾸려면 디버그 라이브러리(6.10절)를 사용해야 한다.


tonumber (e [, base])

base 없이 호출 시 tonumber는 인자를 수로 변환하려고 시도한다. 인자가 이미 수이거나 수로 변환 가능한 문자열이면 그 수를 반환한다. 그렇지 않으면 fail을 반환한다.

문자열 변환 결과는 루아 어휘 규정에 따라 정수나 실수가 될 수 있다. (3.1절 참고.) 문자열에 전후 공백과 부호가 있을 수 있다.

base를 주어서 호출 시 e는 그 진법에서 정수로 해석되는 문자열이어야 한다. 기수로 2에서 36까지 어떤 정수도 가능하다. 10을 넘는 진법에서는 (대문자 또는 소문자) 글자 'A'가 10을 나타내고 'B'가 11을 나타내고, 그런 식으로 'Z'는 35를 나타낸다. 지정한 진법에서 문자열 e가 유효한 수가 아니면 함수가 fail을 반환한다.


tostring (v)

어떤 타입의 값이든 받아서 사람이 읽을 수 있는 형식의 문자열로 변환한다.

v의 메타테이블에 __tostring 필드가 있으면 해당 값을 v를 인자로 해서 호출하여 호출 결과를 tostring의 결과로 쓴다. 그렇지 않고 v의 메타테이블에 문자열 값을 가진 __name 필드가 있으면 그 문자열을 tostring의 최종 결과로 쓸 수도 있다.

수가 변환되는 방식을 완전히 제어하려면 string.format을 쓰면 된다.


type (v)

인자의 타입을 문자열 형태로 반환한다. 가능한 결과는 "nil" (값 nil이 아니라 문자열), "number", "string", "boolean", "table", "function", "thread", "userdata"이다.


_VERSION

동작 중인 루아 버전을 담은 문자열을 가지고 있는 전역 변수다. (함수가 아니다.) 현재 이 변수의 값은 "Lua 5.4"다.


warn (msg1, ···)

인자들(문자열이어야 함)을 모두 이어 붙여서 만든 메시지로 경고를 찍는다.

'@'로 시작하는 한 조각짜리 메시지는 제어 메시지, 즉 경고 시스템 자체를 위한 메시지인 것으로 약속되어 있다. 특히 루아의 표준 경고 함수에서는 경고 찍기를 멈추는 "@off"와 찍기를 (재)시작하는 "@on"을 인식한다. 모르는 제어 메시지는 무시한다.


xpcall (f, msgh [, arg1, ···])

이 함수는 pcall과 비슷하되, 새 메시지 핸들러 msgh를 설정한다.

6.2 – 코루틴 조작

이 라이브러리는 코루틴을 조작하는 동작들로 이뤄져 있으며 테이블 coroutine 안에 들어 있다. 코루틴에 대한 일반적 설명은 2.6절을 보라.


coroutine.close (co)

코루틴 co를 닫는다. 즉 미처리 자동 닫힘 변수를 모두 닫고 코루틴을 죽은 상태로 만든다. 지정한 코루틴은 죽어 있거나 정지 상태여야 한다. 변수를 닫는 중 오류가 발생하면 false와 오류 객체를 반환한다. 아니면 true를 반환한다.


coroutine.create (f)

f를 몸체로 해서 새 코루틴을 만든다. f는 함수여야 한다. "thread" 타입 객체인 새 코루틴을 반환한다.


coroutine.isyieldable ([co])

코루틴 co가 양보할 수 있으면 참을 반환한다. co의 기본값은 동작 중인 코루틴이다.

코루틴이 양보할 수 있으려면 메인 스레드가 아니고 양보 불가능한 C 함수 안에 있지 않으면 된다.


coroutine.resume (co [, val1, ···])

코루틴 co의 실행을 시작하거나 이어 나간다. 코루틴을 처음 재개할 때 그 몸체 실행을 시작한다. val1, ... 값들이 몸체 함수에게 인자로 전달된다. 코루틴이 양보를 하고 난 후에 resume 하면 코루틴을 재시작한다. val1, ... 값들이 yield의 결과로 전달된다.

코루틴이 오류 없이 돌면 true에 더해서 (코루틴이 양보할 때) yield로 전달된 값들이나 (코루틴이 끝날 때) 몸체 함수가 반환한 값들을 resume이 반환한다. 오류가 있으면 false와 오류 메시지를 반환한다.


coroutine.running ()

동작 중인 코루틴에 더해서 불리언을 반환하는데, 동작 중인 코루틴이 메인 코루틴일 때 참이다.


coroutine.status (co)

코루틴 co의 상태를 문자열로 반환한다. 코루틴이 동작 중이면 (즉 status를 호출한 바로 그 코루틴이면) "running"이고, 코루틴이 yield 호출 내에서 정지되어 있거나 아직 동작을 시작하지 않았으면 "suspended"고, 코루틴이 활성이지만 동작 중이 아니면 (즉 다른 코루틴을 재개했으면) "normal"이고, 코루틴이 몸체 함수를 끝마쳤거나 오류로 중단되었으면 "dead"다.


coroutine.wrap (f)

f를 몸체로 해서 새 코루틴을 만든다. f는 함수여야 한다. 함수를 반환하는데, 그 함수를 호출할 때마다 코루틴을 재개한다. 그 함수에 인자를 주면 resume에 준 추가 인자처럼 동작한다. 그리고 처음의 불리언을 빼고 resume이 반환하는 것과 같은 값들을 반환한다. 오류 발생 시 함수에서 코루틴을 닫고 오류를 전파한다.


coroutine.yield (···)

호출한 코루틴의 실행을 정지한다. yield에 인자를 주면 resume의 추가 결과로 전달된다.

6.3 – 모듈

패키지 라이브러리는 루아에서 모듈을 적재하기 위한 기본 요소들을 제공한다. 전역 환경으로 직접 내보내는 함수는 require 하나다. 나머지는 모두 테이블 package를 통해 내보낸다.


require (modname)

지정한 모듈을 적재한다. 먼저 package.loaded 테이블을 확인해서 modname이 이미 적재되어 있는지 알아본다. 그 경우에는 package.loaded[modname]에 저장된 값을 require가 반환한다. (이 경우 두 번째 결과가 없다는 점이 모듈을 적재할 필요가 없었다는 것을 나타낸다.) 아닌 경우에는 그 모듈을 위한 적재 함수를 찾아 본다.

require에서 적재 함수를 찾는 동작은 package.searchers 테이블에 따라 이뤄진다. 이 테이블의 각 항목은 특정 방식으로 모듈을 찾는 탐색 함수다. 이 테이블을 바꾸면 require에서 모듈을 찾는 방식을 바꿀 수 있다. 다음 설명은 package.searchers의 기본 설정을 기준으로 한 것이다.

require에서 먼저 package.preload[modname]을 확인한다. 값이 있으면 (함수여야 하는) 그 값이 적재 함수다. 그렇지 않으면 package.path에 저장된 경로를 이용해 루아 적재 함수를 탐색한다. 그것도 실패하면 package.cpath에 저장된 경로를 이용해 C 적재 함수를 탐색한다. 그것도 실패하면 일체형 적재 함수를 시도한다. (package.searchers 참고.)

적재 함수를 찾으면 modname, 그리고 탐색 함수가 반환한 추가 값인 적재 데이터를 인자로 해서 require에서 적재 함수를 호출한다. 모듈에 유용한 어떤 값이든 적재 데이터가 될 수 있다. 기본 탐색 함수들에서 적재 데이터는 어디서 적재 함수를 찾았는지 나타낸다. (예를 들어 적재 함수가 파일에서 왔다면 그 추가 값은 파일 이름이다.) 적재 함수가 nil 아닌 값을 반환하면 require에서 그 반환 값을 package.loaded[modname]에 할당한다. 적재 함수가 nil 아닌 값을 반환하지 않고 package.loaded[modname]에 어떤 값도 할당하지 않았으면 require에서 그 항목에 true를 할당한다. 어느 경우든 package.loaded[modname]의 최종 값을 require가 반환한다. 그 값에 더해서 탐색 함수가 반환한 적재 데이터를 두 번째 결과로 반환하는데, 그 값은 require가 모듈을 어떻게 찾았는지를 나타낸다.

모듈 적재나 실행 중 오류가 있거나 모듈 적재 함수를 찾을 수 없는 경우에는 require가 오류를 던진다.


package.config

패키지의 컴파일 시점 설정들을 기술하는 문자열. 이 문자열은 다음 행들이 차례로 이어진 것이다.


package.cpath

require에서 C 적재 함수 탐색에 쓰는 경로를 담은 문자열.

루아 경로 package.path와 같은 방식으로 C 경로 package.cpath를 초기화한다. 환경 변수 LUA_CPATH_5_4나 환경 변수 LUA_CPATH를, 아니면 luaconf.h에 정의된 기본 경로를 사용한다.


package.loaded

어느 모듈이 이미 적재되어 있는지를 제어하기 위해 require에서 쓰는 테이블. 모듈 modnamerequire 했는데 package.loaded[modname]이 거짓이 아니면 그냥 거기 저장되어 있는 값을 반환한다.

이 변수는 실제 테이블에 대한 참조일 뿐이다. 이 변수에 할당을 해도 require에서 쓰는 테이블은 바뀌지 않는다.


package.loadlib (libname, funcname)

호스트 프로그램을 C 라이브러리 libname과 동적으로 링크 한다.

funcname이 "*"이면 라이브러리와 링크해서 그 라이브러리가 내보내는 심볼들을 다른 동적 링크 라이브러리에서 이용할 수 있게 만들기만 한다. 그렇지 않으면 라이브러리에서 함수 funcname을 찾아서 C 함수 형태로 반환한다. 따라서 funcnamelua_CFunction 원형을 따라야 한다. (lua_CFunction 참고.)

이 함수는 패키지 및 모듈 시스템을 완전히 건너뛰는 저수준 함수다. require와 달리 경로 탐색을 수행하지 않으며 자동으로 확장자를 추가하지 않는다. libname은 필요시 경로와 확장자까지 포함한 완전한 C 라이브러리 파일 이름이어야 한다. funcname은 C 라이브러리에서 내보내는 바로 그 이름이어야 한다. (사용하는 C 컴파일러와 링커에 따라 달라질 수 있다.)

이 기능을 표준 C에서 지원하지 않는다. 그래서 일부 플랫폼에서만 (윈도우, 리눅스, 맥 OS X, 솔라리스, BSD, 기타 dlfcn 표준을 지원하는 유닉스 시스템) 사용 가능하다.


package.path

require에서 루아 적재 함수 탐색에 쓰는 경로를 담은 문자열.

루아가 시작할 때 이 변수를 환경 변수 LUA_PATH_5_4나 환경 변수 LUA_PATH의 값으로 초기화한다. 그 환경 변수들이 정의되어 있지 않으면 luaconf.h에 정의된 기본 경로로 초기화한다. 환경 변수 값 내에 ";;"가 있으면 기본 경로로 바뀐다.


package.preload

개별 모듈을 위한 적재 함수들을 저장하는 테이블. (require 참고.)

이 변수는 실제 테이블에 대한 참조일 뿐이다. 이 변수에 할당을 해도 require에서 쓰는 테이블은 바뀌지 않는다.


package.searchers

모듈을 찾는 방식을 제어하기 위해 require에서 쓰는 테이블.

이 테이블의 각 항목은 탐색 함수다. 모듈을 찾을 때 require에서 이 탐색 함수 각각을 오름차순으로, 모듈 이름(require가 받은 인자)을 유일한 인자로 해서 호출한다. 탐색 함수에서 모듈을 찾으면 또 다른 함수인 모듈 적재 함수와 함께 적재 데이터를 추가로 반환하는데, 그 값이 적재 함수로 전달되고 require의 두 번째 결과로 반환된다. 모듈을 찾을 수 없으면 이유를 설명하는 문자열을 (설명할 게 없으면 nil을) 반환한다.

루아에서 네 가지 탐색 함수로 이 테이블을 초기화한다.

첫 번째 탐색 함수는 package.preload 테이블 안의 적재 함수를 찾아 보기만 한다.

두 번째 탐색 함수는 package.path에 저장된 경로를 이용해 루아 라이브러리 적재 함수를 찾는다. 함수 package.searchpath에 기술한 대로 탐색이 이뤄진다.

세 번째 탐색 함수는 변수 package.cpath에서 얻은 경로를 이용해 C 라이브러리 적재 함수를 찾는다. 마찬가지로 함수 package.searchpath에 기술한 대로 탐색이 이뤄진다. 예를 들어 C 경로가 다음 문자열일 때

     "./?.so;./?.dll;/usr/local/?/init.so"

모듈 foo 탐색 함수는 파일 ./foo.so, ./foo.dll, /usr/local/foo/init.so를 차례대로 열어 보게 된다. 탐색 함수에서 C 라이브러리를 찾으면 먼저 동적 링크 기능을 이용해 응용을 그 라이브러리와 링크한다. 그러고 나서 적재 함수로 사용할 C 함수를 그 라이브러리 안에서 찾아 본다. 그 C 함수의 이름은 문자열 "luaopen_"에 모듈 이름 사본을 덧붙이고서 마침표를 밑줄로 바꾼 것이다. 그리고 모듈 이름에 하이픈이 있으면 첫 번째 하이픈과 이후 내용을 제거한다. 예를 들어 모듈 이름이 a.b.c-v2.1이면 함수 이름이 luaopen_a_b_c가 된다.

네 번째 탐색 함수는 일체형 적재 함수를 시도한다. 지정한 모듈의 최상위 단계 이름으로 라이브러리의 C 경로를 탐색한다. 예를 들어 a.b.c를 요청한 경우 a의 C 라이브러리를 찾게 된다. 발견하면 그 안에서 서브모듈의 열기 함수를 찾는다. 예컨대 luaopen_a_b_c를 찾게 된다. 이 기능을 이용하면 패키지에서 라이브러리 한 개에 여러 C 서브모듈을 집어넣으면서 각 서브모듈의 열기 함수를 그대로 쓸 수 있다.

첫 번째(preload)를 제외한 모든 탐색 함수는 package.searchpath가 반환한 모듈 발견 파일 경로를 추가 값으로 반환한다. 첫 번째 탐색 함수는 항상 문자열 ":preload:"를 반환한다.

탐색 함수에선 오류를 던지지 말아야 하고 루아에 어떤 부작용도 끼쳐선 안 된다. (C에는 예를 들어 응용을 라이브러리와 링크하면서 부작용을 끼칠 수도 있다.)


package.searchpath (name, path [, sep [, rep]])

지정한 path에서 지정한 name을 찾는다.

path템플릿들을 세미콜론으로 구분해 담은 문자열이다. 각 템플릿에 대해서 물음표가 들어 있으면 sep(기본값은 마침표)를 모두 rep(기본값은 시스템의 디렉터리 구분자)로 바꾼 name의 사본으로 치환하고서 결과로 나온 파일 이름으로 열기를 시도한다.

예를 들어 path가 다음 문자열인 경우에

     "./?.lua;./?.lc;/usr/local/?/init.lua"

이름을 foo.a로 해서 탐색하면 파일 ./foo/a.lua, ./foo/a.lc, /usr/local/foo/a/init.lua를 차례대로 열어 보게 된다.

읽기 모드로 열 수 있는 첫 번째 파일의 치환 후 이름을 (파일을 닫고서) 반환한다. 성공한 파일이 없으면 fail과 오류 메시지를 반환한다. (그 오류 메시지에는 열기를 시도한 모든 파일 이름이 나열되어 있다.)

6.4 – 문자열 조작

이 라이브러리는 부분 문자열 검색과 추출, 패턴 검사 같은 문자열 조작을 위한 일반적 함수들을 제공한다. 루아에서 문자열에 인덱스를 쓸 때는 첫 번째 글자가 1번 위치다. (C에서처럼 0번이 아니다.) 인덱스가 음수일 수도 있으며 문자열 끝을 기준으로 한 역방향 인덱스로 해석한다. 즉 마지막 문자가 -1번 위치에 있는 식이다.

문자열 라이브러리는 모든 함수를 테이블 string에 담아서 제공한다. 그리고 문자열에 대한 메타테이블을 설정하는데 거기서 __index 필드가 string 테이블을 가리킨다. 그래서 문자열 함수들을 객체 지향 스타일로 사용할 수 있다. 예를 들어 string.byte(s,i)s:byte(i)라고 쓸 수 있다.

문자열 라이브러리에서는 1바이트 문자 인코딩을 상정한다.


string.byte (s [, i [, j]])

문자 s[i], s[i+1], ..., s[j]의 내부용 수 코드들을 반환한다. i의 기본값은 1이고 j의 기본값은 i이다. string.sub 함수와 같은 규칙에 따라서 인덱스들을 정정한다.

수 코드가 반드시 플랫폼 간에 이식성이 있지는 않다.


string.char (···)

0개 이상의 정수를 받아서 길이가 인자 개수와 같은 문자열을 반환한다. 문자열 각 문자의 내부용 수 코드가 대응하는 인자와 같다.

수 코드가 반드시 플랫폼 간에 이식성이 있지는 않다.


string.dump (function [, strip])

주어진 함수의 이진 표현(바이너리 청크)을 담은 문자열을 반환한다. 이후 그 문자열에 load 하면 함수의 복사본을 (새 upvalue로) 반환한다. strip이 참 값이면 공간 절약을 위해 이진 표현에 함수에 대한 디버그 정보가 포함되지 않을 수도 있다.

upvalue가 있는 함수인 경우 upvalue 개수만 저장된다. (재)적재 때 그 upvalue들이 새 인스턴스를 받는다. (그 upvalue들이 초기화되는 방식에 대한 자세한 내용은 load를 보라. 디버그 라이브러리를 이용하면 원하는 방식으로 함수의 upvalue를 직렬화 및 재적재할 수 있다.)


string.find (s, pattern [, init [, plain]])

문자열 s에서 pattern의 첫 번째 일치 위치를 찾는다. (6.4.1절 참고.) 일치하는 부분을 발견하면 시작점과 끝점의 s 내 인덱스를 반환한다. 못 찾으면 fail을 반환한다. 세 번째의 선택적 수 인자 init은 탐색을 시작할 위치를 지정한다. 기본값은 1이며 음수일 수 있다. 네 번째의 선택적 인자 plaintrue 값을 주면 패턴 검사 기능을 끈다. 그래서 pattern 내의 어떤 문자도 특수하게 취급하지 않고 단순한 "부분 문자열 찾기" 동작을 한다.

패턴에 포획이 있으면 일치 성공 시 두 인덱스 뒤에 잡힌 값들을 함께 반환한다.


string.format (formatstring, ···)

문자열이어야 하는 첫 번째 인자에 따라서 가변 개수 인자들로 만든 서식 적용 문자열을 반환한다. 서식 문자열은 ISO C 함수 sprintf와 같은 규칙을 따른다. 다만 변환 지정자 및 수식자 *, h, L, l, n을 지원하지 않으며 추가로 지정자 q가 있다.

지정자 q는 불리언, nil, 수, 문자열을 루아 소스 코드에서 유효한 상수가 되는 방식으로 변환해 준다. 불리언과 nil은 자명한 방식으로 (true, false, nil) 바꾼다. 실수는 16진수로 표현해서 정밀도를 온전히 유지한다. 문자열은 큰따옴표 안에 넣으며 필요하면 이스케이프 열을 써서 그 결과를 루아 인터프리터가 안전하게 읽을 수 있도록 한다. 예를 들어 다음과 같이 호출하면

     string.format('%q', 'a string with "quotes" and \n new line')

다음 문자열이 나온다.

     "a string with \"quotes\" and \
      new line"

이 지정자는 수식자(플래그, 폭, 길이)를 지원하지 않는다.

변환 지정자 A, a, E, e, f, G, g는 모두 인자로 수를 기대한다. 지정자 c, d, i, o, u, X, x는 정수를 기대한다. C89 컴파일러로 루아를 컴파일하는 경우에는 지정자 Aa(16진법 실수)는 수식자를 지원하지 않는다.

지정자 s는 문자열을 기대한다. 인자가 문자열이 아니면 tostring과 같은 규칙에 따라 문자열로 변환한다. 지정자에 수식자가 있는 경우에는 대응하는 문자열 인자에 0이 포함돼 있지 않아야 한다.

지정자 plua_topointer가 반환한 포인터를 받는다. 테이블, userdata, 스레드, 문자열, 함수에 대해 유일한 문자열 식별자를 만들어 준다. 다른 값들(수, nil, 불리언)에 대해 이 지정자는 포인터 NULL을 나타내는 문자열을 내놓는다.


string.gmatch (s, pattern [, init])

반복자 함수를 반환한다. 호출할 때마다 그 함수는 문자열 s에 대한 pattern의 다음 포획 값들을 반환한다. (6.4.1절 참고.) pattern에 포획을 지정하지 않으면 각 호출마다 일치 부분 전체를 내놓는다. 세 번째의 선택적 수 인자 init은 탐색을 시작할 위치를 지정한다. 기본값은 1이며 음수일 수 있다.

예를 들어 다음 루프는 문자열 s의 단어를 모두 돌면서 한 줄에 한 단어씩 찍는다.

     s = "hello world from Lua"
     for w in string.gmatch(s, "%a+") do
       print(w)
     end

다음 예는 주어진 문자열에서 key=value 쌍을 모두 모아서 테이블에 넣는다.

     t = {}
     s = "from=world, to=Lua"
     for k, v in string.gmatch(s, "(%w+)=(%w+)") do
       t[k] = v
     end

이 함수에서는 패턴 시작의 '^'가 앵커 역할을 하지 않는다. 그러면 반복이 불가능해지기 때문이다.


string.gsub (s, pattern, repl [, n])

s에서 모든 (또는 지정한 경우 처음 n개) pattern을 치환 문자열 repl로 바꾼 사본을 반환한다. (6.4.1절 참고.) repl은 문자열, 테이블, 함수일 수 있다. 또한 gsub는 두 번째 값으로 치환 횟수를 반환한다. gsub라는 이름은 Global SUBstitution(전역 치환)에서 온 것이다.

repl이 문자열이면 그 값을 치환에 쓴다. 문자 %는 이스케이프 문자 기능을 하는데, repl 내에 %d 형태의 열이 있으면 (d는 1에서 9 사이) d 번째로 잡힌 부분 문자열의 값을 나타낸다. %0은 일치하는 부분 전체를 나타내고 %%% 한 개를 나타낸다.

repl이 테이블이면 일치가 있을 때마다 첫 번째 포획 값을 키로 해서 테이블에 질의한다.

repl이 함수면 일치가 있을 때마다 포획된 부분 문자열 모두를 순서대로 인자로 해서 그 함수를 호출한다.

어느 경우든 패턴에 포획을 지정하지 않으면 패턴 전체가 포획 안에 있는 것처럼 동작한다.

테이블 질의나 함수 호출의 반환 값이 문자열이나 수이면 치환 문자열로 쓴다. 그렇지 않고 falsenil이면 교체하지 않는 것이다. (즉 문자열 내의 그 일치 부분을 그대로 유지한다.)

몇 가지 예를 들면 다음과 같다.

     x = string.gsub("hello world", "(%w+)", "%1 %1")
     --> x="hello hello world world"
     
     x = string.gsub("hello world", "%w+", "%0 %0", 1)
     --> x="hello hello world"
     
     x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
     --> x="world hello Lua from"
     
     x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
     --> x="home = /home/roberto, user = roberto"
     
     x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
           return load(s)()
         end)
     --> x="4+5 = 9"
     
     local t = {name="lua", version="5.4"}
     x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
     --> x="lua-5.4.tar.gz"


string.len (s)

문자열을 받아서 그 길이를 반환한다. 빈 문자열 ""의 길이는 0이다. 문자열 내의 0도 산입된다. 따라서 "a\000bc\000"의 길이가 5다.


string.lower (s)

문자열을 받아서 대문자 글자가 모두 소문자로 바뀐 사본을 반환한다. 다른 글자들은 바뀌지 않는다. 무엇이 대문자 글자인지에 대한 정의는 현재 로캘에 따라 정해진다.


string.match (s, pattern [, init])

문자열 s에서 pattern의 첫 번째 일치 부분을 찾는다. (6.4.1절 참고.) 일치 부분을 발견하면 패턴의 포획 값들을 반환한다. 못 찾았으면 fail을 반환한다. pattern에 포획을 지정하지 않으면 일치 부분 전체를 반환한다. 세 번째의 선택적 수 인자 init은 탐색을 시작할 위치를 지정한다. 기본값이 1이며 음수일 수 있다.


string.pack (fmt, v1, v2, ···)

v1, v2 등을 형식 문자열 fmt에 따라 이진 형태로 직렬화한 (포장한) 이진 문자열을 반환한다. (6.4.2절 참고.)


string.packsize (fmt)

지정한 형식으로 string.pack 하면 나오는 문자열의 크기를 반환한다. 형식 문자열에 가변 길이 옵션인 's'나 'z'가 있을 수 없다. (6.4.2절 참고.)


string.rep (s, n [, sep])

문자열 s의 사본 n개를 문자열 sep를 구분자로 해서 이어 붙인 문자열을 반환한다. sep의 기본값은 빈 문자열(즉 구분자 없음)이다. n이 양수가 아니면 빈 문자열을 반환한다.

(이 함수 호출 한 번으로 머신의 메모리를 아주 쉽게 고갈시킬 수 있다는 점에 유의하라.)


string.reverse (s)

문자열 s를 뒤집은 문자열을 반환한다.


string.sub (s, i [, j])

i에서 시작해서 j까지 이어지는 s의 부분 문자열을 반환한다. ij가 음수일 수 있다. j가 없으면 (문자열 길이와 같은) -1로 상정한다. 특히 string.sub(s,1,j) 호출은 길이 js의 머리를 반환하고 string.sub(s, -i) (i는 양수) 호출은 길이 is의 꼬리를 반환한다.

음수 인덱스 변환 후에, i가 1보다 작으면 1로 정정한다. j가 문자열 길이보다 크면 그 길이로 정정한다. 이런 정정 후에 ij보다 크면 빈 문자열을 반환한다.


string.unpack (fmt, s [, pos])

형식 문자열 fmt에 따라 문자열 s에 포장된 (string.pack 참고) 값들을 반환한다. (6.4.2절 참고.) pos는 선택적이며 s의 어디부터 읽기를 시작할지 표시한다. (기본값은 1이다.) 읽은 값들 뒤에 s에서 아직 안 읽은 다음 첫 바이트의 인덱스를 함께 반환한다.


string.upper (s)

문자열을 받아서 소문자 글자가 모두 대문자로 바뀐 사본을 반환한다. 다른 글자들은 바뀌지 않는다. 무엇이 소문자 글자인지에 대한 정의는 현재 로캘에 따라 정해진다.

6.4.1 – 패턴

루아에서는 정규 문자열로 패턴을 기술한다. 패턴 검사 함수 string.find, string.gmatch, string.gsub, string.match에서 정규 문자열을 패턴으로 해석한다. 이 절에서는 그 문자열의 문법과 의미(즉 무엇에 일치하는지)를 설명한다.

문자 클래스:

문자 클래스를 사용해 문자들의 집합을 나타낸다. 다음 요소들로 문자 클래스를 기술할 수 있다.

한 글자로 나타내는 클래스 (%a, %c 등) 모두에 대해 대응하는 대문자 글자가 그 클래스의 여집합을 나타낸다. 예를 들어 %S는 공백이 아닌 모든 문자를 나타낸다.

글자, 공백, 기타 문자 그룹들의 정의는 현재 로캘에 따라 정해진다. 특히 클래스 [a-z]%l과 동등하지 않을 수도 있다.

패턴 항목:

다음이 패턴 항목이 될 수 있다.

패턴:

패턴은 일련의 패턴 항목들이다. 패턴 시작의 캐럿 '^'은 일치 부분을 대상 문자열 시작점에 고정시킨다. 패턴 끝의 '$'는 일치 부분을 대상 문자열 끝점에 고정시킨다. 다른 위치에서는 '^'과 '$'가 특별한 의미 없이 그 자체를 나타낸다.

포획:

패턴 안에 괄호로 둘러싸인 하위 패턴이 있을 수 있는데 그게 포획(capture)이다. 일치에 성공했을 때 포획 부분에 일치한 부분 문자열을 향후 사용을 위해 저장(포획)해 둔다. 왼쪽 괄호에 따라서 포획에 번호가 붙는다. 예를 들어 패턴 "(a*(.)%w(%s*))"가 있을 때, 대상 문자열에서 "a*(.)%w(%s*)"에 일치한 부분이 첫 번째 포획 값으로 저장되어 1번이 되고, "."에 일치한 문자가 2번으로 포획되고, "%s*"에 일치한 부분이 3번이 된다.

특별히 포획 ()는 현재 문자열 위치를 (수 값으로) 포획한다. 예를 들어 문자열 "flaaap"에 패턴 "()aa()"를 적용하면 3과 5가 포획된다.

연속 일치:

함수 string.gsub와 반복자 string.gmatch는 지정한 패턴으로 대상에서 여러 번 일치 부분을 찾는다. 그 함수들에서는 이전 일치 부분의 끝에서 최소 한 바이트 뒤에서 끝나는 경우에만 새 일치 부분이 유효하다고 본다. 달리 말해 패턴 머신에서 어떤 일치 부분 바로 다음의 빈 문자열을 일치 부분으로 받아들이지 않는다. 예를 들어 다음 코드의 결과를 생각해 보자.

     > string.gsub("abc", "()a*()", print);
     --> 1   2
     --> 3   3
     --> 4   4

두 번째와 세 번째 결과는 'b' 다음의 빈 문자열과 'c' 다음의 빈 문자열이 걸려서 나온 것이다. 'a' 다음의 빈 문자열은 걸리지 않는데, 이전 일치 부분과 같은 위치에서 끝나게 되기 때문이다.

6.4.2 – 포장 형식 문자열

string.pack, string.packsize, string.unpack의 첫 번째 인자는 만들거나 읽으려는 구조체의 레이아웃을 기술하는 형식 문자열이다.

형식 문자열은 일련의 변환 옵션들이다. 가능한 변환 옵션은 다음과 같다.

("[n]"은 선택적인 정숫값을 뜻한다.) 패딩, 공백, 설정을 (옵션 "xX <=>!"를) 제외한 각 옵션은 string.pack의 인자 한 개 내지 string.unpack의 결과 한 개에 대응한다.

옵션 "!n", "sn", "in", "In"에서 n은 1에서 16까지 아무 정수나 가능하다. 모든 정수 옵션마다 오버플로우 검사를 한다. 즉, string.pack에서는 받은 값이 지정한 크기에 들어가는지 확인하며 string.unpack에서는 읽은 값이 루아 정수에 들어가는지 확인한다. 부호 없는 옵션에서는 루아 정수를 부호 없는 값으로 다룬다.

모든 형식 문자열은 앞에 "!1="가 붙은 것처럼, 즉 최대 정렬 크기 1(정렬 없음)과 시스템 기본 엔디안으로 시작한다.

시스템 기본 엔디안에서는 시스템 전체가 빅 엔디안 아니면 리틀 엔디안이라고 상정한다. 포장 함수들은 복합 엔디안 형식의 동작을 올바로 흉내내지 못한다.

정렬 방식을 설명하자면, 각 옵션에 대해 옵션 크기와 최대 정렬 크기 중 작은 값의 배수인 오프셋에서 데이터가 시작할 때까지 패딩을 추가한다. 그 작은 값은 2의 거듭제곱수여야 한다. 옵션 "c"와 "z"는 따로 정렬을 맞추지 않으며, 옵션 "s"는 앞머리 정수의 정렬을 따른다.

모든 패딩을 string.pack에서 0으로 채운다. 그리고 string.unpack에서 무시한다.

6.5 – UTF-8 지원

이 라이브러리는 기초적인 UTF-8 인코딩 지원을 제공한다. 모든 함수를 테이블 utf8에 담아서 제공한다. 인코딩 처리 외의 유니코드 지원은 제공하지 않는다. 문자 분류처럼 문자의 의미가 필요한 동작은 지원 범위에 포함되지 않는다.

따로 명시하지 않았으면 바이트 위치를 매개변수로 받는 함수에서는 받은 위치가 바이트 열의 시작이거나 아니면 대상 문자열 길이 더하기 1이라고 상정한다. 문자열 라이브러리에서처럼 음수 인덱스는 문자열 끝부터 거꾸로 센다.

바이트 열을 만들어 내는 함수들은 원래 UTF-8 명세에 정의된 대로 0x7FFFFFFF까지의 모든 값을 받는다. 즉 여섯 바이트까지의 바이트 열이 나올 수 있다.

바이트 열을 해석하는 함수들은 유효한 (올바른 형식이고 과잉 길이가 아닌) 열만 받아들인다. 기본적으로 유효한 유니코드 코드 포인트가 나오는 바이트 열만 받으며 10FFFF보다 큰 값과 서러게이트는 거부한다. 불리언 인자 lax가 있는 경우 이를 가지고 검사를 완화해서 0x7FFFFFFF까지의 모든 값을 받아들이게 할 수 있다. (형식이 올바르지 않거나 과잉 길이인 열은 여전히 거부된다.)


utf8.char (···)

0개 이상의 정수를 받아서 각각을 대응하는 UTF-8 바이트 열로 변환하고 그 열들을 모두 이어 붙인 문자열을 반환한다.


utf8.charpattern

패턴 (즉 함수가 아니라 문자열) "[\0-\x7F\xC2-\xF4][\x80-0xBF]*"다. (6.4.1절 참고.) 대상이 유효한 UTF-8 문자열이라고 하면 정확히 한 개의 UTF-8 바이트 열에 일치한다.


utf8.codes (s [, lax])

다음과 같이 쓰면

     for p, c in utf8.codes(s) do body end

문자열 s의 모든 UTF-8 문자에 대해 반복하도록 값을 반환한다. 각 문자에서 p는 (바이트 단위) 위치이고 c는 코드 포인트다. 유효하지 않은 바이트 열을 만나면 오류를 던진다.


utf8.codepoint (s [, i [, j [, lax]]])

s에서 바이트 위치 ij 사이에서 (두 위치 포함) 시작하는 모든 문자들의 코드 포인트를 (정수로) 반환한다. i의 기본값은 1이고 j의 기본값은 i다. 유효하지 않은 바이트 열을 만나면 오류를 던진다.


utf8.len (s [, i [, j [, lax]]])

문자열 s에서 위치 ij 사이에서 (두 위치 포함) 시작하는 UTF-8 문자들의 수를 반환한다. i의 기본값은 1이고 j의 기본값은 -1이다. 유효하지 않은 바이트 열을 발견하면 fail과 첫 번째 비유효 바이트의 위치를 반환한다.


utf8.offset (s, n [, i])

s에서 (위치 i부터 세어서) n 번째 문자의 인코딩이 시작되는 (바이트 단위) 위치를 반환한다. n이 음수면 i 번 위치 앞의 문자를 뜻한다. i의 기본값은 n이 음수가 아니면 1이고, 음수면 #s + 1이다. 그래서 utf8.offset(s, -n)이라고 하면 문자열 끝에서 n 번째 문자의 오프셋을 얻게 된다. 지정한 문자가 대상 문자열 안이나 끝 바로 다음에 있지 않으면 fail을 반환한다.

특별히 n이 0일 때는 si 번째 바이트를 포함하는 문자의 인코딩 시작점을 반환한다.

이 함수에서는 s가 유효한 UTF-8 문자열이라고 가정한다.

6.6 – 테이블 조작

이 라이브러리는 테이블 조작을 위한 일반적 함수들을 제공한다. 모든 함수를 테이블 table에 담아서 제공한다.

동작에 테이블 길이가 필요한 경우마다 길이 연산자에 대한 주의 사항이 모두 적용된다. (3.4.7절 참고.) 모든 함수에서 인자로 받은 테이블의 수 아닌 키는 무시한다.


table.concat (list [, sep [, i [, j]]])

모든 항목이 문자열이나 수인 리스트를 받아서 문자열 list[i]..sep..list[i+1] ··· sep..list[j]를 반환한다. sep의 기본값은 빈 문자열이고, i의 기본값은 1이며, j의 기본값은 #list다. ij보다 크면 빈 문자열을 반환한다.


table.insert (list, [pos,] value)

listpos 위치에 항목 value를 삽입한다. 기존 항목 list[pos], list[pos+1], ···, list[#list]를 뒤로 민다. pos의 기본값이 #list+1이다. 그래서 table.insert(t,x) 호출이 리스트 t 끝에 x를 집어넣는다.


table.move (a1, f, e, t [,a2])

다중 할당 a2[t],··· = a1[f],···,a1[e]와 동등한 동작을 수행하여 테이블 a1의 항목들을 테이블 a2로 옮긴다. a2의 기본값은 a1이다. 도착 범위가 출발 범위와 겹칠 수 있다. 옮길 항목 개수가 루아 정수에 들어가는 값이어야 한다.

도착 테이블 a2를 반환한다.


table.pack (···)

모든 인자를 키 1, 2, 3, ...에 차례로 저장하고 필드 "n"에 인자 총개수를 넣은 새 테이블을 반환한다. 참고로 일부 인자가 nil이면 결과로 나오는 테이블이 열이 아닐 수도 있다.


table.remove (list [, pos])

list에서 pos 위치에 있는 항목을 제거하고 그 값을 반환한다. pos가 1과 #list 사이의 정수면 항목 list[pos+1], list[pos+2], ···, list[#list]를 앞으로 밀어서 항목 list[#list]를 없앤다. #list가 0일 때는 pos가 0일 수 있고 #list + 1일 수도 있다.

pos의 기본값이 #list다. 그래서 table.remove(l) 호출이 리스트 l의 마지막 항목을 제거한다.


table.sort (list [, comp])

list[1]부터 list[#list]까지 리스트 항목들을 지정한 순서로 제자리에서 정렬한다. comp는 있다면 리스트의 항목 두 개를 받는 함수여야 하는데, 첫 번째 항목이 최종 순서에서 두 번째 항목보다 앞에 가야 할 때 참을 반환한다. (즉 정렬 후에 i < j이면 not comp(list[j],list[i])여야 한다.) comp가 없으면 표준 루아 연산자 <를 대신 쓴다.

참고로 comp 함수가 리스트 내 항목들에 대한 순부분 순서를 정의해야 한다. 즉, 비대칭성과 추이성이 있어야 한다. 안 그러면 어떤 유효한 정렬도 가능하지 않다.

정렬 알고리즘이 안정적이지 않다. 즉, 해당하는 순서에서 같다고 보는 항목들의 상대적 위치가 정렬에 의해 바뀔 수도 있다.


table.unpack (list [, i [, j]])

받은 리스트의 항목들을 반환한다. 이 함수는 다음과 동등하다.

     return list[i], list[i+1], ···, list[j]

i의 기본값은 1이고 j#list다.

6.7 – 수학 함수

이 라이브러리는 기초적인 수학 함수들을 제공한다. 모든 함수와 상수를 테이블 math에 담아서 제공한다. "정수/실수"라고 표기한 함수는 정수 인자에 대해 정수 결과를 내놓고 정수 아닌 인자에 대해 실수 결과를 내놓는다. 올림/내림 함수 math.ceil, math.floor, math.modf는 결과가 정수 범위에 들어가면 정수를 반환하고 아니면 실수를 반환한다.


math.abs (x)

x-x 중 큰 값을 반환한다. (정수/실수)


math.acos (x)

x의 아크코사인을 반환한다. (라디안)


math.asin (x)

x의 아크사인을 반환한다. (라디안)


math.atan (y [, x])

y/x의 아크탄젠트를 반환하되 (라디안), 두 인자의 부호를 이용해 결과 값의 사분면을 알아낸다. x가 0인 경우도 올바로 처리한다.

x의 기본값은 1이다. 그래서 math.atan(y) 호출이 y의 아크탄젠트를 반환한다.


math.ceil (x)

x보다 크거나 같은 가장 작은 정수 값을 반환한다.


math.cos (x)

x의 코사인을 반환한다. (라디안)


math.deg (x)

각도 x를 라디안에서 도 단위로 변환한다.


math.exp (x)

ex 값을 반환한다. (e는 자연로그의 밑이다.)


math.floor (x)

x보다 작거나 같은 가장 큰 정수 값을 반환한다.


math.fmod (x, y)

몫을 0을 향해 내림/올림하는 방식으로 xy로 나눈 나머지를 반환한다. (정수/실수)


math.huge

실수 값 HUGE_VAL. 다른 어떤 수 값보다 큰 값이다.


math.log (x [, base])

지정한 밑으로 x의 로그 값을 반환한다. base의 기본값은 e이다. (즉 x의 자연로그를 반환한다.)


math.max (x, ···)

루아 연산자 <에 따라 값이 가장 큰 인자를 반환한다.


math.maxinteger

정수 중 가장 값이 큰 정수.


math.min (x, ···)

루아 연산자 <에 따라 값이 가장 작은 인자를 반환한다.


math.mininteger

정수 중 가장 값이 작은 정수.


math.modf (x)

x의 정수 부분과 x의 소수 부분을 반환한다. 두 번째 결과는 항상 실수다.


math.pi

π 값.


math.rad (x)

각도 x를 도 단위에서 라디안으로 변환한다.


math.random ([m [, n]])

인자 없이 호출 시 [0,1) 범위에 균등하게 분포하는 유사난수 실수를 반환한다. 두 정수 mn으로 호출 시 [m, n] 범위에 균등하게 분포하는 유사난수 정수를 반환한다. 양수 n에 대해 math.random(n) 호출은 math.random(1,n)과 동등하다. math.random(0) 호출은 모든 비트가 유사 난수인 정수를 내놓는다.

xoshiro256** 알고리즘을 써서 유사 난수인 64비트 정수를 만들어 내고, 그 값이 인자 0인 호출의 결과가 된다. 다른 결과들(범위 및 실수)은 그 정수들에서 편향 없이 추출한 값이다.

루아에서는 인자 없는 math.randomseed 호출과 동등한 방식으로 유사 난수 생성기를 초기화한다. 따라서 프로그램이 실행될 때마다 math.random이 만들어 내는 결과 수열이 달라지게 된다.


math.randomseed ([x [, y]])

인자를 적어도 한 개 줘서 호출하면 정수 매개변수 xy를 합쳐 128비트 시드로 만들어서 유사 난수 생성기를 다시 초기화하는 데 쓴다. 시드가 같으면 만들어 내는 수열이 같다. y의 기본값은 0이다.

인자 없이 호출하면 약한 수준의 난수성으로 시드를 생성한다.

이 함수는 실제 사용한 두 시드 요소를 반환한다. 그 값들을 다시 설정하면 수열이 반복된다.

초기 상태에 적절한 수준의 난수성을 주려면 (또는 반대로 가령 프로그램 디버깅 시 정해진 수열이 나오게 하려면) 명시적 인자로 math.randomseed를 호출해 주어야 한다.


math.sin (x)

x의 사인을 반환한다. (라디안)


math.sqrt (x)

x의 제곱근을 반환한다. (식 x^0.5로도 이 값을 계산할 수 있다.)


math.tan (x)

x의 탄젠트를 반환한다. (라디안)


math.tointeger (x)

x가 정수로 변환 가능하면 그 정수를 반환한다. 그렇지 않으면 fail을 반환한다.


math.type (x)

x가 정수면 "integer"를 반환하고, 실수면 "float"을 반환하고, x가 수가 아니면 fail을 반환한다.


math.ult (m, n)

불리언을 반환한다. 부호 없는 정수로 비교할 때 정수 m이 정수 n보다 작으면, 그리고 그 경우에만 참이다.

6.8 – 입출력 기능

I/O 라이브러리에서는 두 가지 파일 조작 방식을 제공한다. 첫 번째는 암묵적 파일 핸들을 사용하는 것이다. 즉, 기본 입력 파일과 기본 출력 파일을 설정하는 동작이 있고 모든 입출력 동작이 그 기본 파일에서 이뤄진다. 두 번째 방식은 명시적인 파일 핸들을 쓰는 것이다.

암묵적 파일 핸들을 쓸 때는 모든 동작이 테이블 io에 담겨서 제공된다. 명시적 파일 핸들을 쓸 때는 io.open 동작이 파일 핸들을 반환하고 그 파일 핸들의 메소드 형태로 모든 동작이 제공된다.

파일 핸들의 메타테이블에 있는 메타메소드 __gc__close는 호출 시 파일 닫기를 시도한다.

테이블 io에는 또한 미리 정의된 파일 핸들 io.stdin, io.stdout, io.stderr가 있는데, 그 의미는 C에서와 같다. I/O 라이브러리에서는 이 파일들을 절대 닫지 않는다.

따로 명시하지 않았으면 모든 I/O 함수는 실패 시 fail, 그리고 두 번째 결과로 오류 메시지와 세 번째 결과로 시스템별 오류 코드를 반환한다. 성공 시에는 어떤 거짓 아닌 값을 반환한다. 오류 발생 시 오류 메시지와 오류 코드 계산에 전역 C 변수 errno를 이용하기 때문에 POSIX를 준수하지 않는 시스템에서는 스레드에 안전하지 않을 수 있다.


io.close ([file])

file:close()와 동등하다. file이 없으면 기본 출력 파일을 닫는다.


io.flush ()

io.output():flush()와 동등하다.


io.input ([file])

파일 이름으로 호출하면 그 파일을 (텍스트 모드로) 열어서 그 핸들을 기본 입력 파일로 설정한다. 파일 핸들로 호출하면 그 파일 핸들을 기본 입력 파일로 설정하기만 한다. 인자 없이 호출하면 현재의 기본 입력 파일을 반환한다.

오류 발생 시 이 함수는 오류 코드를 반환하는 대신 오류를 던진다.


io.lines ([filename, ···])

지정한 파일 이름을 읽기 모드로 열어서 반복자 함수를 반환한다. 그 함수는 열린 파일의 file:lines(···)처럼 동작한다. 반복자 함수는 아무 값이라도 읽기에 실패하면 자동으로 파일을 닫는다. io.lines는 반복자 말고도 세 개 값을 더 반환하는데, 자리를 채우기 위한 nil 값 두 개와 새로 생긴 파일 핸들이다. 따라서 일반형 for 루프에 사용 시 오류나 break로 루프가 중단될 때도 파일이 닫힌다.

(파일 이름 없는) io.lines() 호출은 io.input():lines("l")와 동등하다. 즉, 기본 입력 파일의 행들에 대해 반복한다. 이 경우에는 루프가 끝날 때 반복자가 파일을 닫지 않는다.

파일 여는 중 오류 발생 시 이 함수는 오류 코드를 반환하는 대신 오류를 던진다.


io.open (filename [, mode])

문자열 mode에 지정한 방식으로 파일을 연다. 성공 시 새 파일 핸들을 반환한다.

mode 문자열은 다음 중 하나일 수 있다.

mode 문자열 끝에 'b'가 있을 수도 있다. 일부 시스템에서 파일을 바이너리 모드로 열기 위해 필요하다.


io.output ([file])

io.input과 비슷하되, 기본 출력 파일에 대해 동작한다.


io.popen (prog [, mode])

이 함수는 시스템 의존적이며 모든 플랫폼에서 사용 가능하지는 않다.

별도 프로세스로 프로그램 prog를 시작하고 파일 핸들을 반환한다. 그 핸들을 사용해 (mode가 기본값인 "r"이면) 그 프로그램으로부터 데이터를 읽거나 (mode"w"이면) 그 프로그램으로 데이터를 쓸 수 있다.


io.read (···)

io.input():read(···)와 동등하다.


io.tmpfile ()

성공 시 임시 파일에 대한 핸들을 반환한다. 이 파일은 수정 모드로 열려 있으며 프로그램이 끝날 때 자동으로 삭제된다.


io.type (obj)

obj가 유효한 파일 핸들인지 확인한다. obj가 열린 파일 핸들이면 "file"을 반환하고, obj가 닫힌 파일 핸들이면 "closed file"을 반환하며, obj가 파일 핸들이 아니면 fail을 반환한다.


io.write (···)

io.output():write(···)와 동등하다.


file:close ()

file을 닫는다. 참고로 파일 핸들이 쓰레기로 수집될 때 파일이 자동으로 닫힌다. 하지만 얼마나 지나서 그렇게 될지 예측할 수 없다.

io.popen으로 만든 파일 핸들을 닫을 때 file:closeos.execute와 같은 값들을 반환한다.


file:flush ()

file에 쓴 데이터를 저장한다.


file:lines (···)

반복자 함수를 반환한다. 호출할 때마다 그 함수는 지정한 형식에 따라 파일을 읽어 들인다. 형식을 주지 않으면 기본으로 "l"을 쓴다. 예를 들어 다음처럼 쓰면

     for c in file:lines(1) do body end

현재 위치부터 파일의 모든 문자들에 대해 반복하게 된다. io.lines와 달리 이 함수는 루프가 끝날 때 파일을 닫지 않는다.


file:read (···)

지정한 형식들에 따라 파일 file을 읽는다. 각 형식에 대해 읽어 들인 문자들을 가지고 문자열이나 수를 반환하며, 지정한 형식으로 데이터를 읽을 수 없으면 fail을 반환한다. (그 경우 이어지는 형식들은 읽지 않는다.) 인자 없이 호출할 때의 기본 형식은 다음 행 읽기다. (아래 참고.)

사용 가능한 형식은 다음과 같다.

형식 "l"과 "L"은 텍스트 파일에만 써야 할 것이다.


file:seek ([whence [, offset]])

파일 위치를 다음과 같이 문자열 whence로 나타낸 기준점에 offset을 더한 위치로 설정하고, 파일 시작점을 기준으로 한 파일 위치를 얻는다.

성공 시 seek은 파일 시작점부터 바이트 단위로 잰 최종 파일 위치를 반환한다. 실패하면 fail과 오류 설명 문자열을 반환한다.

whence의 기본값은 "cur"이고 offset은 0이다. 그래서 file:seek() 호출은 현재 파일 위치를 변경 없이 반환한다. file:seek("set") 호출은 위치를 파일 시작으로 설정한다. (그리고 0을 반환한다.) file:seek("end") 호출은 위치를 파일 끝으로 설정하고 파일 크기를 반환한다.


file:setvbuf (mode [, size])

파일의 버퍼링 방식을 설정한다. 세 가지 방식이 있다.

뒤의 두 경우에서 size는 바이트 단위 버퍼 크기 힌트다. 기본값은 적절한 크기다.

각 방식의 구체적인 동작 방식에는 이식성이 없다. 자세한 내용은 사용 플랫폼의 ISO C 함수 setvbuf를 확인해 보라.


file:write (···)

인자 각각의 값을 file에 쓴다. 인자는 문자열이나 수여야 한다.

성공 시 이 함수는 file을 반환한다.

6.9 – 운영 체제 기능

이 라이브러리는 테이블 os를 통해 구현되어 있다.


os.clock ()

프로그램이 사용한 CPU 시간의 초 단위 근삿값을 반환한다. ISO C 함수 clock이 반환하는 그 값이다.


os.date ([format [, time]])

문자열 format의 형식에 따라서 날짜와 시간을 담은 문자열 내지 테이블을 반환한다.

time 인자가 있으면 그 시간을 사용한다. (이 값에 대한 설명은 os.time 함수를 보라.) 없으면 현재 시간을 사용한다.

format이 '!'으로 시작하면 협정 세계시를 사용한다. 선택적인 이 문자 다음에 format이 문자열 "*t"이면 테이블을 반환한다. 그 테이블에는 year, month (1–12), day (1–31), hour (0–23), min (0–59), sec (0–61, 윤초 때문), wday (주별 날 번호, 1–7, 일요일이 1), yday (연별 날 번호, 1–366), isdst (일광 절약 플래그, 불리언) 필드가 있다. 마지막 필드는 해당 정보를 얻을 수 없으면 없을 수도 있다.

format이 "*t"가 아니면 ISO C 함수 strftime과 같은 규칙에 따라 서식을 준 문자열로 일시를 반환한다.

format이 없는 경우 기본값은 "%c"이며, 현재 로캘을 이용해 사람이 읽을 수 있는 날짜 및 시간 표현을 내놓는다.

C 함수 gmtime과 C 함수 localtime을 쓰기 때문에 POSIX를 준수하지 않는 시스템에서는 이 함수가 스레드에 안전하지 않을 수 있다.


os.difftime (t2, t1)

시간 t1부터 시간 t2까지의 차이를 초 단위로 반환한다. (시간 값들은 os.time이 반환한 것이다.) POSIX, 윈도우, 기타 일부 시스템에서 이 값은 t2-t1 그대로다.


os.execute ([command])

이 함수는 ISO C 함수 system과 동등하다. command를 운영 체제 셸로 전달해서 실행하게 한다. 명령이 성공적으로 종료되었으면 첫 번째 결과가 true고, 아니면 fail이다. 그 첫 번째 결과에 더해서 다음과 같이 문자열과 수를 반환한다.

command 없이 호출 시 os.execute는 불리언을 반환하는데, 셸이 사용 가능한 경우 참이다.


os.exit ([code [, close]])

ISO C 함수 exit을 호출해서 호스트 프로그램을 종료한다. codetrue면 상태로 EXIT_SUCCESS를 반환한다. codefalse면 상태로 EXIT_FAILURE를 반환한다. code가 수이면 상태가 그 수를 반환한다. code의 기본값은 true다.

선택적인 두 번째 인자 close가 참이면 끝내기 전에 루아 상태를 닫는다.


os.getenv (varname)

프로세스 환경 변수 varname의 값을 반환한다. 그 변수가 정의되어 있지 않으면 fail을 반환한다.


os.remove (filename)

지정한 이름의 파일을 (POSIX 시스템에서는 빈 디렉터리도 가능) 삭제한다. 실패하면 fail에 더해서 오류 설명 문자열과 오류 코드를 반환한다. 아니면 참을 반환한다.


os.rename (oldname, newname)

이름이 oldname인 파일이나 디렉터리의 이름을 newname으로 바꾼다. 실패하면 fail에 더해서 오류 설명 문자열과 오류 코드를 반환한다. 아니면 참을 반환한다.


os.setlocale (locale [, category])

프로그램의 현재 로캘을 설정한다. locale은 로캘을 지정하는 시스템별 문자열이다. category는 바꿀 범주를 나타내는 선택적 문자열이다. "all", "collate", "ctype", "monetary", "numeric", "time" 중 하나이며, 기본 범주는 "all"이다. 새 로캘의 이름을 반환하며, 요청에 응할 수 없으면 fail을 반환한다.

locale이 빈 문자열이면 현재 로캘을 구현체에서 정의한 시스템 기본 로캘로 설정한다. locale이 문자열 "C"이면 현재 로캘을 표준 C 로캘로 설정한다.

첫 번째 인자를 nil로 해서 호출하면 지정한 범주에 대해 현재 로캘의 이름을 반환하기만 한다.

C 함수 setlocale을 이용하기 때문에 스레드에 안전하지 않을 수 있다.


os.time ([table])

인자 없이 호출하면 현재 시간을 반환한다. 아니면 지정한 테이블에 명시된 지역 날짜 및 시간을 나타내는 시간을 반환한다. 그 테이블에는 year, month, day 필드가 꼭 있어야 하며, hour (기본값 12), min (기본값 0), sec (기본값 0), isdst (기본값 nil) 필드가 있을 수 있다. 다른 필드들은 무시한다. 이 필드들에 대한 설명은 os.date 함수를 보라.

함수 호출 시 이 필드들의 값이 반드시 유효 범위 내에 있어야 하는 것은 아니다. 예를 들어 sec이 -10이면 다른 필드들이 가리키는 시간에서 10초 전을 뜻한다. hour가 1000이면 다른 필드들이 가리키는 시간에서 1000시간 후를 뜻한다.

반환하는 값이 수인데 그 의미가 시스템에 따라 다르다. POSIX, 윈도우, 기타 일부 시스템에서 이 수는 어떤 기준 시간("에포크") 이후로 지난 초의 수를 센 것이다. 다른 시스템에서는 그 의미가 명세되어 있지 않으므로 time이 반환한 수를 os.dateos.difftime의 인자로만 쓸 수 있다.

테이블을 줘서 호출하면 os.date 함수 설명에 나온 모든 필드들을 정규화해 주기도 한다. 그래서 그 값들이 호출 전과 같은 시간을 나타내되 유효 범위 안에 있게 된다.


os.tmpname ()

임시 파일에 쓸 수 있는 파일 이름을 문자열로 반환한다. 사용 전에 파일을 명시적으로 열어야 하며 더는 필요 없을 때 명시적으로 삭제해야 한다.

POSIX 시스템에서 이 함수는 보안상 위험을 피하기 위해 (이름을 얻는 시점과 파일을 생성하는 시점 사이에 다른 누군가가 잘못된 권한으로 그 파일을 생성할 수도 있다.) 그 이름으로 파일을 만들기까지 한다. 사용하려면 마찬가지로 파일을 열어야 하며 (사용하지 않은 경우에도) 파일을 삭제해야 한다.

가능하다면 프로그램이 끝날 때 파일을 자동으로 삭제해 주는 io.tmpfile을 쓰는 게 바람직할 수 있다.

6.10 – 디버그 라이브러리

이 라이브러리는 디버그 인터페이스(4.7절)의 기능들을 루아 프로그램에 제공한다. 이 라이브러리를 사용할 때는 주의를 기울여야 한다. 여러 함수가 루아 코드에 대한 기본적인 가정(예를 들면 외부에서 함수의 지역 변수에 접근할 수 없고, 루아 코드에서 userdata 메타데이터를 바꿀 수 없고, 루아 프로그램이 죽지 않음)을 깨며, 그래서 안전했을 코드를 위험한 상태로 만들 수 있다. 또한 이 라이브러리의 일부 함수들은 느릴 수 있다.

이 라이브러리의 모든 함수들을 debug 테이블에 담아서 제공한다. 스레드를 대상으로 동작하는 함수들에는 대상 스레드를 나타내는 선택적인 첫 번째 인자가 있다. 기본값은 항상 현재 스레드다.


debug.debug ()

대화형 모드로 들어가서 사용자가 입력하는 각 문자열을 실행한다. 간단한 명령들과 다른 디버그 기능들을 이용해 전역 및 지역 변수를 조사하고, 그 값을 바꾸고, 식을 평가하는 등의 일을 할 수 있다. 단어 cont만 있는 행을 입력하면 이 함수가 끝나고 호출자가 실행을 이어 나간다.

참고로 debug.debug에서의 명령은 문법적으로 어떤 함수에도 포함되지 않으며, 따라서 지역 변수에 직접 접근하지 못한다.


debug.gethook ([thread])

스레드의 현재 훅 설정을 debug.sethook 함수로 설정한 대로 세 값(현재 훅 함수, 현재 훅 마스크, 현재 훅 카운트)으로 반환한다.

활성 훅이 없으면 fail을 반환한다.


debug.getinfo ([thread,] f [, what])

함수에 대한 정보를 담은 테이블을 반환한다. f의 값으로 직접 함수를 줄 수도 있고 수를 줄 수도 있다. 수는 지정한 스레드의 호출 스택 f번 단계에서 실행 중인 함수를 뜻한다. 0번 단계는 현재 함수(getinfo 자체)이고 1번 단계는 getinfo를 호출한 함수인 식이다. (꼬리 호출은 스택에서 자리를 차지하지 않으므로 제외된다.) f가 활성 함수 개수보다 큰 수이면 getinfofail을 반환한다.

lua_getinfo가 반환하는 모든 필드가 반환되는 테이블에 담길 수 있으며, 문자열 what으로 어느 필드들을 채울지 지정한다. what의 기본값은 유효 행 테이블을 제외하고 가능한 모든 정보를 얻는 것이다. 옵션 'f'가 있으면 func라는 필드에 함수 자체를 추가한다. 옵션 'L'이 있으면 activelines라는 필드에 유효 행 테이블을 추가한다.

예를 들어 식 debug.getinfo(1,"n").name은 적당한 이름이 있으면 현재 함수의 이름을 반환하며, 식 debug.getinfo(print)print 함수에 대해 얻을 수 있는 모든 정보를 담은 테이블을 반환한다.


debug.getlocal ([thread,] f, local)

스택의 f 단계에 있는 함수에서 인덱스가 local인 지역 변수의 이름과 값을 반환한다. 이 함수는 명시적인 지역 변수뿐만 아니라 매개변수와 임시 값에도 접근할 수 있다.

첫 번째 매개변수 내지 지역 변수의 인덱스가 1이고 코드에 선언된 순서대로 이어지는 식이며, 함수의 현재 유효 범위에서 활성인 변수들만 센다. 컴파일 시점 상수는 컴파일러가 최적화해 버렸다면 이 목록에 등장하지 않을 수도 있다. 음수 인덱스는 가변 인자를 가리킨다. -1이 첫 번째 가변 인자다. 지정한 인덱스의 변수가 없으면 fail을 반환하며, 범위 밖의 단계로 호출하면 오류를 던진다. (debug.getinfo를 호출해서 단계가 유효한지 확인할 수 있다.)

'(' (여는 괄호)로 시작하는 변수 이름은 이름을 모르는 변수(루프 제어 변수 같은 내부 변수나 디버그 정보 없이 저장된 청크에서 온 변수)를 나타낸다.

매개변수 f가 함수일 수도 있다. 그 경우 getlocal은 그 함수 매개변수들의 이름만 반환한다.


debug.getmetatable (value)

지정한 value의 메타테이블을 반환한다. 메타테이블을 가지고 있지 않으면 nil을 반환한다.


debug.getregistry ()

레지스트리 테이블을 반환한다. (4.3절 참고.)


debug.getupvalue (f, up)

함수 f에서 인덱스가 up인 upvalue의 이름과 값을 반환한다. 지정한 인덱스의 upvalue가 없으면 fail을 반환한다.

(루아 함수의 경우 upvalue는 함수에서 사용하여 그 결과로 클로저에 포함된 외부의 지역 변수다.)

C 함수의 경우 이 함수는 모든 upvalue에 이름으로 빈 문자열 ""을 쓴다.

변수 이름 '?' (물음표)는 이름을 모르는 변수(디버그 정보 없이 저장된 청크에서 온 변수)를 나타낸다.


debug.getuservalue (u, n)

userdata u에 연계된 n 번째 사용자 값과 불리언을 반환하는데, 그 userdata에 그 값이 없는 경우 불리언 값이 false다.


debug.setcstacklimit (limit)

C 스택의 새 제한치를 설정한다. 이 제한치는 루아에서 중첩 호출이 얼마나 깊어질 수 있는지 통제하는 것인데, 스택 넘침을 피하기 위한 것이다. 제한치가 너무 작으면 무의미하게 재귀 호출을 제약한다. 제한치가 너무 크면 인터프리터가 스택 넘침으로 죽을 가능성이 생긴다. 아쉽게도 어떤 플랫폼에서 안전한 가장 큰 제한치를 미리 알 수 있는 방법은 없다.

루아 코드에서 이뤄진 각 호출을 한 단위로 계산한다. 다른 동작들(예: C에서 루아로 이뤄진 호출이나 코루틴 재개하기)은 더 높은 비용으로 계산할 수 있다.

이 함수에는 다음 제약이 있다.

이 제약을 따르지 않고 호출하면 거짓 값을 반환한다. 올바로 호출하면 이전 제한치를 반환한다.


debug.sethook ([thread,] hook, mask [, count])

지정한 함수를 디버그 훅으로 설정한다. 문자열 mask와 수 count로 언제 훅이 호출되어야 하는지 지정한다. 문자열 mask에서 다음 문자들을 조합할 수 있다.

그리고 count가 0이 아니면 count 개 인스트럭션마다 훅이 호출된다.

인자 없이 호출하면 훅을 끈다.

훅이 호출될 때 받는 첫 번째 매개변수는 그 호출을 유발한 이벤트를 기술하는 문자열이다. "call", "tail call", "return", "line", "count" 중 하나다. 행 이벤트에서는 훅의 두 번째 매개변수로 새 행 번호를 받는다. 훅 안에서 단계를 2로 해서 getinfo를 호출하면 실행 중인 함수에 대한 추가 정보를 얻을 수 있다. (0번 단계는 getinfo 함수고 1번 단계는 훅 함수다.)


debug.setlocal ([thread,] level, local, value)

스택의 level 단계에 있는 함수에서 인덱스가 local인 지역 변수에 값 value를 할당한다. 지정한 인덱스의 지역 변수가 없으면 fail을 반환하며, 범위 밖의 level로 호출하면 오류를 던진다. (getinfo를 호출해서 단계가 유효한지 확인할 수 있다.) 그 외 경우에는 그 지역 변수의 이름을 반환한다.

변수 인덱스와 이름에 대한 자세한 내용은 debug.getlocal을 보라.


debug.setmetatable (value, table)

(nil일 수 있는) 지정한 table을 지정한 value의 메타테이블로 설정한다. value를 반환한다.


debug.setupvalue (f, up, value)

함수 f에서 인덱스가 up인 upvalue에 값 value를 할당한다. 지정한 인덱스의 upvalue가 없으면 fail을 반환한다. 그 외 경우에는 그 upvalue의 이름을 반환한다.

upvalue에 대한 자세한 내용은 debug.getupvalue를 보라.


debug.setuservalue (udata, value, n)

지정한 value를 지정한 udata에 연계된 n 번째 사용자 값으로 설정한다. udata가 full userdata여야 한다.

udata를 반환한다. userdata에 그 값이 없으면 fail을 반환한다.


debug.traceback ([thread,] [message [, level]])

message가 있는데 문자열이 아니고 nil도 아니면 다른 처리 없이 message를 반환한다. 그렇지 않으면 호출 스택의 트레이스백을 담은 문자열을 반환한다. 선택적인 문자열 message를 트레이스백 앞쪽에 덧붙인다. 선택적인 수 level은 어느 단계에서 트레이스백을 시작할지를 나타낸다. (기본값은 1, 즉 traceback을 호출한 함수다.)


debug.upvalueid (f, n)

지정한 함수의 n 번째 upvalue에 대한 고유 식별자를 (light userdata 형태로) 반환한다.

이 고유 식별자를 이용하면 upvalue를 여러 클로저에서 공유하는지 여부를 프로그램에서 확인할 수 있다. upvalue를 공유하는 (즉 같은 외부 지역 변수에 접근하는) 루아 클로저들은 각각의 upvalue 인덱스에 대해 동일한 ID를 반환하게 된다.


debug.upvaluejoin (f1, n1, f2, n2)

루아 클로저 f1n1 번째 upvalue가 루아 클로저 f2n2 번째 upvalue를 가리키게 만든다.

7 – 단독형 루아

루아는 호스트 C 프로그램에 내장되는 확장 언어로 설계되었지만 단독 언어로도 자주 쓰인다. 단독 언어 루아를 위한 lua라는 인터프리터가 표준 배포 파일에 딸려 있다. 단독 인터프리터에는 모든 표준 라이브러리가 포함되어 있다. 사용법은 이렇다.

     lua [options] [script [args]]

옵션은 이렇다.

lua는 옵션들을 처리한 후 주어진 script를 실행한다. lua를 인자 없이 호출하면 표준 입력(stdin)이 터미널일 때는 lua -v -i처럼 동작하고 아닐 때는 lua -처럼 동작한다.

-E 옵션 없이 호출 시 인터프리터는 인자 실행에 앞서 환경 변수 LUA_INIT_5_4를 (버전 붙은 이름이 정의되어 있지 않으면 LUA_INIT을) 확인한다. 변수 내용이 @파일명 형식이면 lua가 그 파일을 실행한다. 그렇지 않으면 lua가 그 문자열 자체를 실행한다.

-E 옵션을 줘서 호출 시 루아는 어떤 환경 변수도 확인하지 않는다. 특히 package.pathpackage.cpath의 값을 luaconf.h에 정의된 기본 경로로 설정한다.

옵션 -e, -l, -W는 등장한 순서대로 처리한다. 예를 들어 다음과 같이 호출 시,

     $ lua -e 'a=1' -llib1 script.lua

먼저 a를 1로 설정하고, 다음으로 라이브러리 lib1을 require 하고, 마지막으로 인자 없이 script.lua 파일을 실행한다. (여기서 $는 셸 프롬프트다. 사용자마다 다를 수 있다.)

코드 실행 전에 lua는 모든 명령행 인자를 arg라는 전역 테이블에 모은다. 스크립트 이름이 인덱스 0으로 가고 스크립트 이름 다음의 첫 번째 인자가 인덱스 1로 가고 하는 식이다. 그리고 스크립트 이름 앞의 인자들이 (즉 인터프리터 이름과 그 옵션들이) 음수 인덱스로 간다. 예를 들어 다음 호출에서,

     $ lua -la b.lua t1 t2

테이블이 다음과 같다.

     arg = { [-2] = "lua", [-1] = "-la",
             [0] = "b.lua",
             [1] = "t1", [2] = "t2" }

호출에 script가 없으면 인터프리터가 인덱스 0으로 가고 다른 인자들이 뒤따른다. 예를 들어 다음 호출이

     $ lua -e "print(arg[1])"

"-e"를 찍는다. script가 있으면 인자 arg[1], ···, arg[#arg]로 그 스크립트가 호출된다. 루아의 여느 청크들처럼 스크립트를 가변 인자 함수로 컴파일한다.

대화형 모드에서 루아는 반복해서 프롬프트를 표시하고 행 입력을 기다린다. 행을 읽은 후 루아는 먼저 식으로 해석하려고 시도한다. 성공하면 그 값을 찍는다. 아니면 그 행을 문으로 해석한다. 적어 준 문이 불완전하면 인터프리터가 다른 프롬프트를 표시하며 문이 완성되기를 기다린다.

전역 변수 _PROMPT가 문자열을 담고 있으면 그 값을 프롬프트로 쓴다. 마찬가지로 전역 변수 _PROMPT2가 문자열을 담고 있으면 그 값을 (문이 미완성인 동안 보이는) 보조 프롬프트로 쓴다.

스크립트에서 보호 안 된 오류가 발생하면 인터프리터가 그 오류를 표준 오류 스트림으로 보고한다. 오류 객체가 문자열이 아니지만 메타메소드 __tostring을 가지고 있으면 인터프리터가 그 메타메소드를 호출해서 최종 메시지를 만든다. 그렇지 않으면 인터프리터가 오류 객체를 문자열로 변환하고 스택 트레이스백을 덧붙인다. 경고가 켜져 있을 때는 경고를 표준 오류 출력으로 그냥 찍는다.

정상적으로 끝날 때 인터프리터에서 메인 루아 상태를 닫는다. (lua_close 참고.) 이 단계를 피하고 싶으면 스크립트에서 os.exit 호출로 종료하면 된다.

유닉스 시스템에서 루아를 스크립트 인터프리터로 쓸 수 있게 하기 위해 루아는 파일 첫 행이 #로 시작하면 그 행을 건너뛴다. 그래서 chmod +x 하고 다음처럼 #! 형식을 쓰면 루아 스크립트를 실행 프로그램으로 만들 수 있다.

     #!/usr/local/bin/lua

당연히 루아 인터프리터 위치는 머신마다 다를 수 있다. PATH 안에 lua가 있다면 다음이 더 이식성 좋은 방식이다.

     #!/usr/bin/env lua

8 – 이전 버전과 호환되지 않는 점

프로그램을 루아 5.3에서 루아 5.4로 옮기면서 발견할 수 있는 비호환 사항들을 나열한다.

어떤 사항들은 적절한 옵션을 써서 루아를 컴파일하는 것으로 (파일 luaconf.h 참고) 피할 수 있다. 하지만 그 호환성 옵션들은 향후에 모두 없어질 것이다. 이런 호환성 옵션들이 없어질 때 대개 호환성 이슈들이 발생한다. 따라서 기회 있을 때마다 모든 호환성 옵션을 끄고 컴파일한 루아 버전으로 코드를 확인해 보는 게 좋다. 그러면 루아 새 버전으로 옮기는 게 쉬워진다.

루아 버전이 바뀔 때 상수의 숫자 값이나 매크로 함수의 구현처럼 프로그램 소스 코드 변경이 필요치 않은 방식으로는 언제든 C API가 바뀔 수 있다. 따라서 절대로 루아 버전들 간에 바이너리가 호환된다고 가정해선 안 된다. 항상 루아 API 사용 프로그램을 새 버전으로 다시 컴파일해야 한다.

또한 루아 버전이 바뀌면서 언제든 사전 컴파일 청크의 내부 표현 방식이 바뀔 수 있다. 즉, 루아 버전들 간에 사전 컴파일 청크가 호환되지 않는다.

공식 배포본 내의 표준 경로가 버전들 간에 바뀔 수 있다.

8.1 – 언어에서 바뀐 점

8.2 – 라이브러리에서 바뀐 점

8.3 – API에서 바뀐 점

9 – 루아 전체 문법

다음은 확장 BNF로 된 루아의 전체 문법이다. 확장 BNF에서 늘 그렇듯 {A}는 0개 이상의 A를 뜻하고 [A]는 선택적인 A를 뜻한다. (연산자 우선순위는 3.4.8절 참고. 말단 Name, Numeral, LiteralString에 대한 설명은 3.1절 참고.)


	chunk ::= block

	block ::= {stat} [retstat]

	stat ::=  ‘;’ | 
		 varlist ‘=’ explist | 
		 functioncall | 
		 label | 
		 break | 
		 goto Name | 
		 do block end | 
		 while exp do block end | 
		 repeat block until exp | 
		 if exp then block {elseif exp then block} [else block] end | 
		 for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end | 
		 for namelist in explist do block end | 
		 function funcname funcbody | 
		 local function Name funcbody | 
		 local attnamelist [‘=’ explist] 

	attnamelist ::=  Name attrib {‘,’ Name attrib}

	attrib ::= [‘<’ Name ‘>’]

	retstat ::= return [explist] [‘;’]

	label ::= ‘::’ Name ‘::’

	funcname ::= Name {‘.’ Name} [‘:’ Name]

	varlist ::= var {‘,’ var}

	var ::=  Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name 

	namelist ::= Name {‘,’ Name}

	explist ::= exp {‘,’ exp}

	exp ::=  nil | false | true | Numeral | LiteralString | ‘...’ | functiondef | 
		 prefixexp | tableconstructor | exp binop exp | unop exp 

	prefixexp ::= var | functioncall | ‘(’ exp ‘)’

	functioncall ::=  prefixexp args | prefixexp ‘:’ Name args 

	args ::=  ‘(’ [explist] ‘)’ | tableconstructor | LiteralString 

	functiondef ::= function funcbody

	funcbody ::= ‘(’ [parlist] ‘)’ block end

	parlist ::= namelist [‘,’ ‘...’] | ‘...’

	tableconstructor ::= ‘{’ [fieldlist] ‘}’

	fieldlist ::= field {fieldsep field} [fieldsep]

	field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp

	fieldsep ::= ‘,’ | ‘;’

	binop ::=  ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘//’ | ‘^’ | ‘%’ | 
		 ‘&’ | ‘~’ | ‘|’ | ‘>>’ | ‘<<’ | ‘..’ | 
		 ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ | 
		 and | or

	unop ::= ‘-’ | not | ‘#’ | ‘~